static void recursive_alias_expand (const char *name, mu_list_t exlist, mu_list_t origlist) { alias_t al; mu_iterator_t itr; if ((al = alias_lookup (name)) == NULL) { if (mu_list_locate (exlist, (void*)name, NULL) == MU_ERR_NOENT) mu_list_append (exlist, (void*)name); return; } mu_list_get_iterator (al->list, &itr); for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { char *word; mu_iterator_current (itr, (void **)&word); if (mu_list_locate (origlist, word, NULL) == MU_ERR_NOENT) { mu_list_push (origlist, word); recursive_alias_expand (word, exlist, origlist); mu_list_pop (origlist, NULL); } } mu_iterator_destroy (&itr); }
int mu_list_foreach_dir (mu_list_t list, int dir, mu_list_action_t action, void *cbdata) { mu_iterator_t itr; int status = 0; if (list == NULL || action == NULL) return EINVAL; status = mu_list_get_iterator (list, &itr); if (status) return status; status = mu_iterator_ctl (itr, mu_itrctl_set_direction, &dir); if (status == 0) for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { void *item; mu_iterator_current (itr, &item); if ((status = action (item, cbdata))) break; } mu_iterator_destroy (&itr); return status; }
static int is_known_folder (mu_url_t url, mu_folder_t *pfolder) { int ret = 0; mu_folder_t folder = NULL; mu_iterator_t iterator; if (url == NULL || pfolder == NULL) return ret; if (mu_list_get_iterator (known_folder_list, &iterator) != 0) return ret; for (mu_iterator_first (iterator); !mu_iterator_is_done (iterator); mu_iterator_next (iterator)) { mu_iterator_current (iterator, (void **)&folder); /* Check if the same URL type. */ if (folder && folder->url && mu_url_is_same_scheme (url, folder->url) && mu_url_is_same_user (url, folder->url) && mu_url_is_same_host (url, folder->url) && mu_url_is_same_path (url, folder->url) && mu_url_is_same_port (url, folder->url)) { ret = 1; break; } } if (ret) *pfolder = folder; mu_iterator_destroy (&iterator); return ret; }
void mu_sieve_require (mu_list_t slist) { int status; mu_iterator_t itr; status = mu_list_get_iterator (slist, &itr); if (status) { mu_sv_compile_error (&mu_sieve_locus, _("cannot create iterator: %s"), mu_strerror (status)); return; } for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { char *name; int (*reqfn) (mu_sieve_machine_t mach, const char *name) = NULL; const char *text = NULL; mu_iterator_current (itr, (void **)&name); if (strncmp (name, "comparator-", 11) == 0) { name += 11; reqfn = mu_sieve_require_comparator; text = _("required comparator"); } else if (strncmp (name, "test-", 5) == 0) /* GNU extension */ { name += 5; reqfn = mu_sieve_require_test; text = _("required test"); } else if (strcmp (name, "relational") == 0) /* RFC 3431 */ { reqfn = mu_sieve_require_relational; text = ""; } else { reqfn = mu_sieve_require_action; text = _("required action"); } if (reqfn (mu_sieve_machine, name)) { mu_sv_compile_error (&mu_sieve_locus, _("source for the %s %s is not available"), text, name); } } mu_iterator_destroy (&itr); }
/* FIXME: The checker interface should be redone. Until then this function is commented out. Problems: 1. Checkers are called per group, there's no way to call them per tag. 2. See FIXMEs in the code. */ static int index_checker (const char *name, mu_list_t tags, mu_list_t args) { mu_iterator_t itr; mu_sieve_runtime_tag_t *match = NULL; int err; if (!tags || mu_list_get_iterator (tags, &itr)) return 0; err = 0; for (mu_iterator_first (itr); !err && !mu_iterator_is_done (itr); mu_iterator_next (itr)) { mu_sieve_runtime_tag_t *t; mu_iterator_current (itr, (void **)&t); if (strcmp (t->tag, "index") == 0) { if (match) { /* FIXME: 1. This function must be public. 2. locus should be included in t */ mu_sv_compile_error (&mu_sieve_locus, _("index specified twice in call to `%s'"), name); err = 1; break; } } } mu_iterator_destroy (&itr); if (err) return 1; if (match) { if (match->arg->v.number < 1) { // See FIXME above mu_sv_compile_error (&mu_sieve_locus, _("invalid index value: %s"), match->arg->v.string); return 1; } } return 0; }
/* Computes an intersection of two lists and returns it in PDEST. The resulting list contains elements from A that are also encountered in B (as per comparison function of the latter). If DUP_ITEM is not NULL, it is used to create copies of items to be stored in PDEST. In this case, the destroy_item function of B is also attached to PDEST. Otherwise, if DUP_ITEM is NULL, pointers to elements are stored and no destroy_item function is assigned. */ int mu_list_intersect_dup (mu_list_t *pdest, mu_list_t a, mu_list_t b, int (*dup_item) (void **, void *, void *), void *dup_closure) { mu_list_t dest; int rc; mu_iterator_t itr; rc = mu_list_create (&dest); if (rc) return rc; mu_list_set_comparator (dest, b->comp); if (dup_item) mu_list_set_destroy_item (dest, b->destroy_item); rc = mu_list_get_iterator (a, &itr); if (rc) { mu_list_destroy (&dest); return rc; } rc = 0; for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { void *data; mu_iterator_current (itr, &data); if (mu_list_locate (b, data, NULL) == 0) { void *new_data; if (dup_item && data) { rc = dup_item (&new_data, data, dup_closure); if (rc) break; } else new_data = data; mu_list_append (dest, new_data); /* FIXME: Check return, and? */ } } mu_iterator_destroy (&itr); *pdest = dest; return rc; }
static void ali_print_name_list (mu_list_t list, int off) { mu_iterator_t itr; char *item; mu_list_get_iterator (list, &itr); if (list_mode) { mu_iterator_first (itr); mu_iterator_current (itr, (void **)&item); printf ("%s\n", item); for (mu_iterator_next (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { int len; mu_iterator_current (itr, (void **)&item); len = off + strlen (item); printf ("%*.*s\n", len, len, item); } } else { int ncol = getcols (); int n = off; mu_iterator_first (itr); for (;;) { int len; mu_iterator_current (itr, (void **)&item); len = strlen (item) + 2; if (n + len > ncol) n = printf ("\n "); len = printf ("%s", item); mu_iterator_next (itr); if (!mu_iterator_is_done (itr)) len += printf (", "); else break; n += len; } printf ("\n"); } mu_iterator_destroy (&itr); }
int mu_smtp_capa_iterator (mu_smtp_t smtp, mu_iterator_t *itr) { if (!smtp || !itr) return EINVAL; if (MU_SMTP_FISSET (smtp, _MU_SMTP_ERR)) return MU_ERR_FAILURE; if (!smtp->capa) { int rc = mu_smtp_ehlo (smtp); if (rc) return rc; } if (!MU_SMTP_FISSET (smtp, _MU_SMTP_ESMTP)) return MU_ERR_FAILURE; return mu_list_get_iterator (smtp->capa, itr); }
int mu_registrar_get_iterator (mu_iterator_t *pitr) { int status = 0; if (pitr == NULL) return MU_ERR_OUT_PTR_NULL; mu_monitor_wrlock (®istrar_monitor); if (registrar_list == NULL) { status = mu_list_create (®istrar_list); if (status) return status; } status = mu_list_get_iterator (registrar_list, pitr); mu_monitor_unlock (®istrar_monitor); return status; }
sieve_comparator_record_t * _lookup (mu_list_t list, const char *name) { mu_iterator_t itr; sieve_comparator_record_t *reg; if (!list || mu_list_get_iterator (list, &itr)) return NULL; for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { mu_iterator_current (itr, (void **)®); if (strcmp (reg->name, name) == 0) break; else reg = NULL; } mu_iterator_destroy (&itr); return reg; }
static int sub_msgno_last (mu_msgset_t mset, size_t beg) { int rc; struct mu_msgrange *range; if (beg == 1) mu_list_clear (mset->list); else { mu_iterator_t itr; rc = mu_list_get_iterator (mset->list, &itr); if (rc) return rc; rc = 1; rc = mu_iterator_ctl (itr, mu_itrctl_set_direction, &rc); if (rc) { mu_iterator_destroy (&itr); return rc; } for (mu_iterator_first (itr); rc == 0 && !mu_iterator_is_done (itr); mu_iterator_next (itr)) { mu_iterator_current (itr, (void **)&range); if (range->msg_beg > beg) rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); else if (range->msg_beg == beg) { rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); break; } else break; } mu_iterator_destroy (&itr); } return 0; }
void _mu_onexit_run (void) { mu_iterator_t itr; int rc, status = 0; if (!onexit_list) return; rc = mu_list_get_iterator (onexit_list, &itr); if (rc) { mu_error (_("cannot create iterator, onexit aborted: %s"), mu_strerror (rc)); mu_stream_destroy (&mu_strerr); _exit (127); } for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { struct onexit_closure *cp; int rc = mu_iterator_current (itr, (void**)&cp); if (rc) { status = 127; mu_error (_("cannot obtain current item while traversing the" " onexit action list: %s"), mu_strerror (rc)); } else cp->function (cp->data); mu_iterator_ctl (itr, mu_itrctl_delete, NULL); } mu_iterator_destroy (&itr); mu_list_destroy (&onexit_list); if (status) _exit (status); }
int mu_sieve_match_part_checker (const char *name, mu_list_t tags, mu_list_t args) { mu_iterator_t itr; mu_sieve_runtime_tag_t *match = NULL; mu_sieve_runtime_tag_t *comp = NULL; mu_sieve_runtime_tag_t *tmp; mu_sieve_comparator_t compfun = NULL; char *compname = "false"; int matchtype; int err = 0; if (!tags || mu_list_get_iterator (tags, &itr)) return 0; for (mu_iterator_first (itr); !err && !mu_iterator_is_done (itr); mu_iterator_next (itr)) { mu_sieve_runtime_tag_t *t; mu_iterator_current (itr, (void **)&t); if (strcmp (t->tag, "is") == 0 || strcmp (t->tag, "contains") == 0 || strcmp (t->tag, "matches") == 0 || strcmp (t->tag, "regex") == 0 || strcmp (t->tag, "count") == 0 || strcmp (t->tag, "value") == 0) { if (match) { mu_sv_compile_error (&mu_sieve_locus, _("match type specified twice in call to `%s'"), name); err = 1; } else match = t; } else if (strcmp (t->tag, "comparator") == 0) comp = t; } mu_iterator_destroy (&itr); if (err) return 1; if (!match || strcmp (match->tag, "is") == 0) matchtype = MU_SIEVE_MATCH_IS; else if (strcmp (match->tag, "contains") == 0) matchtype = MU_SIEVE_MATCH_CONTAINS; else if (strcmp (match->tag, "matches") == 0) matchtype = MU_SIEVE_MATCH_MATCHES; else if (strcmp (match->tag, "regex") == 0) matchtype = MU_SIEVE_MATCH_REGEX; else { char *str = match->arg->v.string; if (strcmp (match->tag, "count") == 0) { mu_sieve_value_t *val; char *str; size_t count; if (comp && strcmp (comp->arg->v.string, "i;ascii-numeric")) { mu_sv_compile_error (&mu_sieve_locus, /* TRANSLATORS: Do not translate ':count'. It is the name of a Sieve tag */ _("comparator %s is incompatible with " ":count in call to `%s'"), comp->arg->v.string, name); return 1; } matchtype = MU_SIEVE_MATCH_LAST; /* to not leave it undefined */ compfun = comp_false; val = mu_sieve_value_get (args, 1); if (!val) return 1; /* shouldn't happen */ /* NOTE: Type of v is always SVT_STRING_LIST */ mu_list_count (val->v.list, &count); if (count > 1) { mu_sv_compile_error (&mu_sieve_locus, _("second argument must be a list of one element")); return 1; } mu_list_get (val->v.list, 0, (void **) &str); count = strtoul (str, &str, 10); if (*str) { mu_sv_compile_error (&mu_sieve_locus, _("second argument cannot be converted to number")); return 1; } } else matchtype = MU_SIEVE_MATCH_EQ; if (mu_sieve_str_to_relcmp (str, NULL, NULL)) { mu_sv_compile_error (&mu_sieve_locus, _("invalid relational match `%s' in call to `%s'"), str, name); return 1; } } if (!compfun) { compname = comp ? comp->arg->v.string : "i;ascii-casemap"; compfun = mu_sieve_comparator_lookup (mu_sieve_machine, compname, matchtype); if (!compfun) { mu_sv_compile_error (&mu_sieve_locus, _("comparator `%s' is incompatible with match type `%s' in call to `%s'"), compname, match ? match->tag : "is", name); return 1; } } tmp = mu_sieve_malloc (mu_sieve_machine, sizeof (*tmp)); tmp->tag = TAG_COMPFUN; tmp->arg = mu_sieve_value_create (SVT_POINTER, compfun); mu_list_append (tags, tmp); if (matchtype == MU_SIEVE_MATCH_REGEX) { /* To speed up things, compile all patterns at once. Notice that it is supposed that patterns are in arg 2 */ mu_sieve_value_t *val, *newval; struct regex_data rd; int rc; if (mu_list_get (args, 1, (void**)&val)) return 0; rd.flags = REG_EXTENDED; if (strcmp (compname, "i;ascii-casemap") == 0) rd.flags |= REG_ICASE; mu_list_create (&rd.list); rc = mu_sieve_vlist_do (val, _regex_compile, &rd); mu_sieve_machine_add_destructor (mu_sieve_machine, _free_reglist, rd.list); if (rc) return rc; newval = mu_sieve_value_create (SVT_STRING_LIST, rd.list); mu_list_replace (args, val, newval); } #ifndef FNM_CASEFOLD else if (matchtype == MU_SIEVE_MATCH_MATCHES && strcmp (compname, "i;ascii-casemap") == 0) { int rc; mu_sieve_value_t *val; if (mu_list_get (args, 1, (void**)&val)) return 0; rc = mu_sieve_vlist_do (val, _pattern_upcase, NULL); if (rc) return rc; } #endif return 0; }
int mu_msgset_sub_range (mu_msgset_t mset, size_t beg, size_t end, int mode) { int rc; mu_iterator_t itr; struct mu_msgrange *mr; if (!mset) return EINVAL; if (mu_list_is_empty (mset->list)) return MU_ERR_NOENT; if (end && beg > end) { size_t t = end; end = beg; beg = t; } rc = _mu_msgset_translate_pair (mset, mode, &beg, &end); if (rc == MU_ERR_NOENT) return 0; else if (rc) return rc; rc = mu_msgset_aggregate (mset); if (rc) return rc; if (end == MU_MSGNO_LAST) return sub_msgno_last (mset, beg); /* Test border cases */ rc = mu_list_head (mset->list, (void**)&mr); if (rc) return rc; if (end < mr->msg_beg) return 0; if (beg < mr->msg_beg) beg = mr->msg_beg; rc = mu_list_tail (mset->list, (void**) &mr); if (mr->msg_end != MU_MSGNO_LAST) { if (beg > mr->msg_end) return 0; if (end > mr->msg_end) end = mr->msg_end; } rc = mu_list_get_iterator (mset->list, &itr); if (rc) return rc; for (mu_iterator_first (itr); rc == 0 && !mu_iterator_is_done (itr); mu_iterator_next (itr)) { mu_iterator_current (itr, (void **)&mr); if (mr->msg_end == MU_MSGNO_LAST) { /* This is the last element in list. */ if (mr->msg_beg == beg) rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); else if (mr->msg_beg > beg) mr->msg_beg = end + 1; break; } if (mr->msg_beg == beg && mr->msg_end == end) /* See case 2 above */ { rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); break; } else if (mr->msg_beg <= beg && beg <= mr->msg_end) { if (mr->msg_beg <= end && end <= mr->msg_end) /* Case 3 */ { /* Split the range */ if (end != mr->msg_end) { struct mu_msgrange *newrange = calloc (1, sizeof (*newrange)); if (!newrange) { rc = ENOMEM; break; } newrange->msg_beg = end + 1; newrange->msg_end = mr->msg_end; rc = mu_iterator_ctl (itr, mu_itrctl_insert, newrange); if (rc) { free (newrange); break; } } if (mr->msg_beg == beg) rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); else mr->msg_end = beg - 1; break; } else if (mr->msg_beg == beg) /* Case 4 */ { beg = mr->msg_end; rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); } else { size_t n = mr->msg_end; mr->msg_end = beg - 1; beg = n; } } else if (mr->msg_beg <= end && end <= mr->msg_end) /* Case 5 */ { mr->msg_beg = end + 1; if (mr->msg_beg >= mr->msg_end) rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); break; } else if (beg <= mr->msg_beg && mr->msg_beg <= end) { rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); } } mu_iterator_destroy (&itr); return rc; }
/* Switch to the given UID/GID */ int mu_switch_to_privs (uid_t uid, gid_t gid, mu_list_t retain_groups) { int rc = 0; gid_t *emptygidset; size_t size = 1, j = 1; mu_iterator_t itr; if (uid == 0) return 0; /* Create a list of supplementary groups */ mu_list_count (retain_groups, &size); size++; emptygidset = xmalloc (size * sizeof emptygidset[0]); emptygidset[0] = gid ? gid : getegid (); if (mu_list_get_iterator (retain_groups, &itr) == 0) { for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) mu_iterator_current (itr, (void **)(emptygidset + j++)); mu_iterator_destroy (&itr); } /* Reset group permissions */ if (geteuid () == 0 && setgroups (j, emptygidset)) { mu_error(_("setgroups(1, %lu) failed: %s"), (unsigned long) emptygidset[0], mu_strerror (errno)); rc = 1; } free (emptygidset); /* Switch to the user's gid. On some OSes the effective gid must be reset first */ #if defined(HAVE_SETEGID) if ((rc = setegid (gid)) < 0) mu_error (_("setegid(%lu) failed: %s"), (unsigned long) gid, mu_strerror (errno)); #elif defined(HAVE_SETREGID) if ((rc = setregid (gid, gid)) < 0) mu_error (_("setregid(%lu,%lu) failed: %s"), (unsigned long) gid, (unsigned long) gid, mu_strerror (errno)); #elif defined(HAVE_SETRESGID) if ((rc = setresgid (gid, gid, gid)) < 0) mu_error (_("setresgid(%lu,%lu,%lu) failed: %s"), (unsigned long) gid, (unsigned long) gid, (unsigned long) gid, mu_strerror (errno)); #endif if (rc == 0 && gid != 0) { if ((rc = setgid (gid)) < 0 && getegid () != gid) mu_error (_("setgid(%lu) failed: %s"), (unsigned long) gid, mu_strerror (errno)); if (rc == 0 && getegid () != gid) { mu_error (_("Cannot set effective gid to %lu"), (unsigned long) gid); rc = 1; } } /* Now reset uid */ if (rc == 0 && uid != 0) { uid_t euid; if (setuid (uid) || geteuid () != uid || (getuid () != uid && (geteuid () == 0 || getuid () == 0))) { #if defined(HAVE_SETREUID) if (geteuid () != uid) { if (setreuid (uid, -1) < 0) { mu_error (_("setreuid(%lu,-1) failed: %s"), (unsigned long) uid, mu_strerror (errno)); rc = 1; } if (setuid (uid) < 0) { mu_error (_("second setuid(%lu) failed: %s"), (unsigned long) uid, mu_strerror (errno)); rc = 1; } } else #endif { mu_error (_("setuid(%lu) failed: %s"), (unsigned long) uid, mu_strerror (errno)); rc = 1; } } euid = geteuid (); if (uid != 0 && setuid (0) == 0) { mu_error (_("seteuid(0) succeeded when it should not")); rc = 1; } else if (uid != euid && setuid (euid) == 0) { mu_error (_("Cannot drop non-root setuid privileges")); rc = 1; } } return rc; }