%{ /* ckaliases - verify syntax of sendmail-style alias files Copyright (C) 2005, 2007 Sergey Poznyakoff This program 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 of the License, or (at your option) any later version. This program 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 this program. If not, see . */ #include "ckaliases.h" SLIST *cw_list; /* List of domain names pertaining to Sendmail 'w' class */ static int restricted; /* prohibit use of `special' aliases (pipes, file redirections and includes */ int verbose; /* Verbose mode */ int error_count; /* Number of errors detected so far */ %} %union { char *string; SLIST *slist; }; %token IDENT EMAIL STRING LHS %token CONT %token EOL %token INCLUDE %type string lhs %type rhs emails email %% input : list ; list : alias | list EOL alias | list error EOL { yyclearin; yyerrok; } ; alias : /* empty */ | lhs rhs { regalias ($1, $2); } ; lhs : LHS ':' ; rhs : emails | rhs CONT emails { slist_append (&$1, $3); $$ = $1; } ; emails: email | emails ',' email { slist_append (&$1, $3); $$ = $1; } ; email : string { if (restricted && ($1[0] == '|' || $1[0] == '/')) { yyerror ("Construct not allowed"); YYERROR; } $$ = NULL; slist_add (&$$, $1); } | EMAIL { $$ = NULL; slist_add (&$$, $1); } | INCLUDE string { if (restricted) { yyerror ("Include statement is not allowed"); YYERROR; } $$ = NULL; read_include (&$$, $2); } ; string: IDENT | STRING ; %% int yyerror (char *s) { error_at_line (0, 0, file_name, line_num, "%s", s); error_count++; } void usage () { printf ("usage: ckaliases [OPTIONS] [FILES...]\n"); printf ("OPTIONS and FILES may be interspered.\n"); printf ("Valid options are:\n"); printf (" -d,--debug=SPEC Set debug level. SPEC consists of the following\n"); printf (" letters:\n"); printf (" y enable parser debugging\n"); printf (" l enable lexical analizer debugging\n"); printf (" Upper-case variants are also accepted. Prepending\n"); printf (" a letter with '-' reverts its sense\n"); printf (" -f, --files-from=FILE\n"); printf (" Read names of alias files from FILE\n"); printf (" -h, --help Display this help list\n"); printf (" -r, --restrict Restrict alias file syntax to aliases only (i.e.\n"); printf (" prohibit use of pipes and file redirections\n"); printf (" -u, --unrestrict Revert the effect of the previous -r option\n"); printf (" -v, --verbose Verbose mode\n"); printf (" -V, --version print program version and exit\n"); printf (" -w FILE Read contents of Sendmail `w' class from the given\n"); printf (" file.\n"); printf ("\n"); printf ("Report bugs to <%s>\n", PACKAGE_BUGREPORT); } struct option options[] = { { "debug", required_argument, NULL, 'd' }, { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, { "restrict", no_argument, NULL, 'r' }, { "unrestrict", no_argument, NULL, 'u' }, { "verbose", no_argument, NULL, 'v' }, { "files-from", required_argument, NULL, 'f' }, { NULL } }; int main (int argc, char **argv) { char *p; int c; int file_count = 0; int true = 1; char *cwfile = "/etc/mail/sendmail.cw"; SLIST *file_list; /* List of files to be read */ struct string_list *s; begin_aliases (); init_lex (); program_name = argv[0]; while ((c = getopt_long (argc, argv, "-d:f:hp:ruvw:", options, NULL)) != EOF) { switch (c) { case 1: if (!cw_list) read_include (&cw_list, cwfile); openaliases (optarg); yyparse (); file_count++; break; case 'd': for (p = optarg; *p; p++) { switch (*p) { case '-': true = 0; break; case 'y': case 'Y': yydebug = true; true = 1; break; case 'l': case 'L': lex_debug (true); true = 1; break; default: error (1, 0, "%s: unknown debug option %c", argv[0]); } } break; case 'f': if (!cw_list) read_include (&cw_list, cwfile); file_list = NULL; read_include (&file_list, optarg); if (file_list) { for (s = file_list->head; s; s = s->next) { openaliases_prefix (optarg, s->str); yyparse (); file_count++; } slist_destroy (&file_list); } break; case 'h': usage (); exit (0); case 'r': restricted = 1; break; case 'u': restricted = 0; break; case 'v': verbose++; break; case 'V': gsc_version ("ckaliases"); exit (0); case 'w': if (file_count) error (1, 0, "-w must be used before first non-option argument"); cwfile = optarg; break; default: exit (1); } } argc -= optind; argv += optind; if (!cw_list) read_include (&cw_list, cwfile); while (argc--) { openaliases (*argv++); yyparse (); file_count++; } if (!file_count) error (1, 0, "no files specified"); if (verbose) printf ("%d files\n", file_count); end_aliases (); check_aliases (); if (verbose) printf ("%lu errors\n", error_count); exit (error_count!=0); }