%{ /* GNU Mailutils -- a suite of utilities for electronic mail Copyright (C) 2003-2007, 2010-2012, 2014-2017 Free Software Foundation, Inc. GNU Mailutils is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNU Mailutils is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Mailutils. If not, see . */ #include #include #include #include #include #include struct mh_alias { char *name; mu_list_t rcpt_list; int inclusive; }; static mu_list_t alias_list; static mu_list_t list_create_or_die (void) { int status; mu_list_t list; status = mu_list_create (&list); if (status) { mu_error (_("can't create list: %s"), mu_strerror (status)); exit (1); } return list; } static char * ali_list_to_string (mu_list_t *plist) { size_t n; char *string; mu_list_count (*plist, &n); if (n == 1) { mu_list_get (*plist, 0, (void **)&string); } else { char *p; size_t length = 0; mu_iterator_t itr; mu_list_get_iterator (*plist, &itr); for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next(itr)) { char *s; mu_iterator_current (itr, (void**) &s); length += strlen (s) + 1; } string = mu_alloc (length + 1); p = string; for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next(itr)) { char *s; mu_iterator_current (itr, (void**) &s); strcpy (p, s); p += strlen (s); *p++ = ' '; } *--p = 0; mu_iterator_destroy (&itr); } mu_list_destroy (plist); return string; } static void ali_append (struct mh_alias *ali) { if (ali) { if (!alias_list) alias_list = list_create_or_die (); mu_list_append (alias_list, ali); } } static mu_list_t unix_group_to_list (char *name); static mu_list_t unix_gid_to_list (char *name); static mu_list_t unix_passwd_to_list (void); int yyerror (char *s); int yylex (void); %} %union { char *string; mu_list_t list; struct mh_alias *alias; } %token EOL %token STRING %type address_list address_group string_list %type address %type alias %locations %% input : alias_list ; alias_list : alias { ali_append ($1); } | alias_list EOL alias { ali_append ($3); } ; alias : /* empty */ { $$ = NULL; } | STRING ':' { ali_verbatim (1); } address_group { ali_verbatim (0); $$ = mu_alloc (sizeof (*$$)); $$->name = $1; $$->rcpt_list = $4; $$->inclusive = 0; } | STRING ';' { ali_verbatim (1); } address_group { ali_verbatim (0); $$ = mu_alloc (sizeof (*$$)); $$->name = $1; $$->rcpt_list = $4; $$->inclusive = 1; } ; address_group: address_list | '=' STRING { $$ = unix_group_to_list ($2); free ($2); } | '+' STRING { $$ = unix_gid_to_list ($2); free ($2); } | '*' { $$ = unix_passwd_to_list (); } ; address_list : address { $$ = list_create_or_die (); mu_list_append ($$, $1); } | address_list ',' address { mu_list_append ($1, $3); $$ = $1; } ; address : string_list { $$ = ali_list_to_string (&$1); } ; string_list : STRING { mu_list_create(&$$); mu_list_append($$, $1); } | string_list STRING { mu_list_append($1, $2); $$ = $1; } ; %% static mu_list_t ali_list_dup (mu_list_t src) { mu_list_t dst; mu_iterator_t itr; if (mu_list_create (&dst)) return NULL; if (mu_list_get_iterator (src, &itr)) { mu_list_destroy (&dst); return NULL; } for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { void *data; mu_iterator_current (itr, (void **)&data); mu_list_append (dst, data); } mu_iterator_destroy (&itr); return dst; } static int ali_member (mu_list_t list, const char *name) { mu_iterator_t itr; int found = 0; if (mu_list_get_iterator (list, &itr)) return 0; for (mu_iterator_first (itr); !found && !mu_iterator_is_done (itr); mu_iterator_next (itr)) { char *item; mu_address_t tmp; mu_iterator_current (itr, (void **)&item); if (strcmp (item, name) == 0) found = 1; else if (mu_address_create (&tmp, item) == 0) { found = mu_address_contains_email (tmp, name); mu_address_destroy (&tmp); } } mu_iterator_destroy (&itr); return found; } int aliascmp (const char *pattern, const char *name) { int len = strlen (pattern); if (len > 1 && pattern[len - 1] == '*') return strncmp (pattern, name, len - 2); return strcmp (pattern, name); } static int mh_alias_get_internal (const char *name, mu_iterator_t start, mu_list_t *return_list, int *inclusive); int alias_expand_list (mu_list_t name_list, mu_iterator_t orig_itr, int *inclusive) { mu_iterator_t itr; if (mu_list_get_iterator (name_list, &itr)) return 1; for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { char *name; mu_list_t exlist; mu_iterator_current (itr, (void **)&name); if (mh_alias_get_internal (name, orig_itr, &exlist, inclusive) == 0) { /* Insert exlist after name */ mu_iterator_ctl (itr, mu_itrctl_insert_list, exlist); mu_list_destroy (&exlist); /* Remove name */ mu_iterator_ctl (itr, mu_itrctl_delete, NULL); } } mu_iterator_destroy (&itr); return 0; } /* Look up the named alias. If found, return the list of recipient names associated with it */ static int mh_alias_get_internal (const char *name, mu_iterator_t start, mu_list_t *return_list, int *inclusive) { mu_iterator_t itr; int rc = 1; if (!start) { if (mu_list_get_iterator (alias_list, &itr)) return 1; mu_iterator_first (itr); } else { mu_iterator_dup (&itr, start); mu_iterator_next (itr); } for (; !mu_iterator_is_done (itr); mu_iterator_next (itr)) { struct mh_alias *alias; mu_iterator_current (itr, (void **)&alias); if (aliascmp (alias->name, name) == 0) { if (inclusive) *inclusive |= alias->inclusive; *return_list = ali_list_dup (alias->rcpt_list); alias_expand_list (*return_list, itr, inclusive); rc = 0; break; } } mu_iterator_destroy (&itr); return rc; } int mh_alias_get (const char *name, mu_list_t *return_list) { return mh_alias_get_internal (name, NULL, return_list, NULL); } int mh_alias_get_address (const char *name, mu_address_t *paddr, int *incl) { mu_iterator_t itr; mu_list_t list; if (incl) *incl = 0; if (mh_alias_get_internal (name, NULL, &list, incl)) return 1; if (mu_list_is_empty (list)) { mu_list_destroy (&list); return 1; } if (mu_list_get_iterator (list, &itr) == 0) { for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { char *item; mu_address_t a; char *ptr = NULL; mu_iterator_current (itr, (void **)&item); if (mu_address_create (&a, item)) { mu_error (_("Error expanding aliases -- invalid address `%s'"), item); } else { if (incl && *incl) mu_address_set_personal (a, 1, name); mu_address_union (paddr, a); mu_address_destroy (&a); } if (ptr) free (ptr); } mu_iterator_destroy (&itr); } mu_list_destroy (&list); return 0; } /* Look up the given user name in the aliases. Return the list of alias names this user is member of */ int mh_alias_get_alias (const char *uname, mu_list_t *return_list) { mu_iterator_t itr; int rc = 1; if (mu_list_get_iterator (alias_list, &itr)) return 1; for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { struct mh_alias *alias; mu_iterator_current (itr, (void **)&alias); if (ali_member (alias->rcpt_list, uname)) { if (*return_list == NULL && mu_list_create (return_list)) break; mu_list_append (*return_list, alias->name); rc = 0; } } mu_iterator_destroy (&itr); return rc; } void mh_alias_enumerate (mh_alias_enumerator_t fun, void *data) { mu_iterator_t itr; int rc = 0; if (mu_list_get_iterator (alias_list, &itr)) return ; for (mu_iterator_first (itr); rc == 0 && !mu_iterator_is_done (itr); mu_iterator_next (itr)) { struct mh_alias *alias; mu_list_t tmp; mu_iterator_current (itr, (void **)&alias); tmp = ali_list_dup (alias->rcpt_list); alias_expand_list (tmp, itr, NULL); rc = fun (alias->name, tmp, data); mu_list_destroy (&tmp); } mu_iterator_destroy (&itr); } static mu_list_t unix_group_to_list (char *name) { struct group *grp = getgrnam (name); mu_list_t lst = list_create_or_die (); if (grp) { char **p; for (p = grp->gr_mem; *p; p++) mu_list_append (lst, mu_strdup (*p)); } return lst; } static mu_list_t unix_gid_to_list (char *name) { struct group *grp = getgrnam (name); mu_list_t lst = list_create_or_die (); if (grp) { struct passwd *pw; setpwent(); while ((pw = getpwent ())) { if (pw->pw_gid == grp->gr_gid) mu_list_append (lst, mu_strdup (pw->pw_name)); } endpwent(); } return lst; } static mu_list_t unix_passwd_to_list () { mu_list_t lst = list_create_or_die (); struct passwd *pw; setpwent(); while ((pw = getpwent ())) { if (pw->pw_uid > 200) mu_list_append (lst, mu_strdup (pw->pw_name)); } endpwent(); return lst; } int mh_read_aliases (void) { const char *p; p = mh_global_profile_get ("Aliasfile", NULL); if (p) { struct mu_wordsplit ws; if (mu_wordsplit (p, &ws, MU_WRDSF_DEFFLAGS)) { mu_error (_("cannot split line `%s': %s"), p, mu_wordsplit_strerror (&ws)); } else { size_t i; for (i = 0; i < ws.ws_wordc; i++) mh_alias_read (ws.ws_wordv[i], 1); mu_wordsplit_free (&ws); } } mh_alias_read (DEFAULT_ALIAS_FILE, 0); return 0; }