diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2013-03-06 18:50:45 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2013-03-06 18:50:45 +0200 |
commit | 248a97fbf0656d12839ca8986287d216820c9849 (patch) | |
tree | e23c9635b7c752ca1b6ed95ecabc1590a18c548b | |
parent | 8f8a1c98f84669306d1489ddc5d55b6f589df9be (diff) | |
download | alck-248a97fbf0656d12839ca8986287d216820c9849.tar.gz alck-248a97fbf0656d12839ca8986287d216820c9849.tar.bz2 |
Remove site-specific defaults. Improve local-domain options.
* alck.1: Update.
* alck.h (read_include): Remove.
(freadlist, preadlist): New protos.
* gram.y (usage): Update output.
(main): Change -f to -T. Add -W option (read
class w from a command stdout). Change handling
of the -w option.
Remove cwfile - there's no longer a default for -w.
* lex.l (read_include): Rename to freadlist and rewrite.
(preadlist): New function.
-rw-r--r-- | alck.1 | 73 | ||||
-rw-r--r-- | alck.h | 3 | ||||
-rw-r--r-- | gram.y | 44 | ||||
-rw-r--r-- | lex.l | 89 |
4 files changed, 164 insertions, 45 deletions
@@ -10,13 +10,13 @@ .\" 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 Alck. If not, see <http://www.gnu.org/licenses/>. -.TH ALCK 1 "March 5, 2013" "ALCK" +.TH ALCK 1 "March 6, 2013" "ALCK" .SH NAME alck \- check MTA alias files .SH SYNOPSIS \fBalck\fR [\fB\-d\fR \fILEVEL\fR] [\fB\-T\fR \fIFILE\fR]\ [\-\fBruv\fR] [\fB\-w\fR \fIFILE\fR] \fIFILE\fR .sp @@ -26,16 +26,20 @@ alck \- check MTA alias files .SH DESCRIPTION .B Alck checks one or several .BR sendmail -style alias files for consistency. The following tests are performed: .TP +.B Multiply defined aliases +.TP .B Transitivity test This test discovers eventual circular dependencies. .TP .B Use of prohibited aliases +This test is optional. When enabled, it detects the use of pipes, +file redirects and includes in the input files. .PP The program returns 0 if all tests pass successfully. Otherwise, it diagnoses encountered problems and exits with error code 1. .PP The program takes a list of alias files to be checked from its command line. Command line options can be interspersed with filename @@ -76,12 +80,16 @@ and in that order. .PP In any case, if several alias files are supplied, .B alck treats them as parts of a single alias file. .SH OPTIONS +.SS General +These options affect the behavior of the program in general. They can +be specified anywhere in the command line and affect all options that +follow them. .TP \fB\-d\fR \fISPEC\fR Set debug level. The \fISPEC\fR can contain one or more of the following letters: .RS .TP @@ -92,12 +100,61 @@ enable parser debugging; enable lexical analizer debugging. .RE .sp Upper-case variants are also accepted. Prepending a letter with a dash (\fB\-\fR) reverts its sense. .TP +.B \-v +Verbosely report the results. +.SS Local domain names +The distinction between local and remote email addreses allows +.B alck +to detect circular dependencies between aliases. A local email +is any email that has no domain part, or whose domain part contains +a +.BR "local domain" . +For +.B Sendmail +local domains are those that constitute the +.B w +class. +.PP +The following two options supply local domain names to +.BR alck . +They must appear in the command line before any filenames or +.B \-T +options. +.TP +\fB\-w\fR \fIFILE\fR +Read local domain names from the given +.IR FILE . +The file should list each name on a separate line. Surrounding +whitespace is allowed. Empty lines and +comments (lines starting with the +.B # +character) are ignored. +.TP +\fB\-W\fR \fICOMMAND\fR +Run \fICOMMAND\fR and read local domain names from its standard +output. +.B Alck +will consider for inclusion only those lines that begin with +alphanumeric character and don't contain whitespace. Thus, it is +possible to read the local domain names from the +.B Sendmail +configuration with the following option: +.sp +.nf +.in +2 +-W "echo '$=w' | sendmail -bt" +.in +.fi +.SS Input options +Input options can be interspersed with the input file names. They are +processed in the order of their appearance. +.TP \fB\-T\fR \fIFILE\fR Read names of alias files from \fIFILE\fR. .TP .B \-r By default, the program allows any valid .B Sendmail @@ -109,25 +166,15 @@ it, until the eventual occurrence of the option or the end of command line. .TP .B \-u This options cancels the effect of the previous .B \-r option. -.TP -.B \-v -Verbosely report the results. -.TP -\fB\-w\fR \fIFILE\fR -Read contents of the -.BR Sendmail 's -.B w -class from the given -.IR FILE . -.PP +.SS Informational The following two options instruct the program to display a certain -kind of information and exit: +kind of information and exit. .TP .B \-h Display a terse help summary. .TP .B \-V Display the program version and copyright statement. @@ -53,13 +53,14 @@ typedef struct slist { char *slist_add(SLIST **plist, char *str); char *slist_add_n(SLIST **plist, char *str, size_t n); void slist_append(SLIST **pdst, SLIST * src); char *slist_member(SLIST *plist, char *name); void slist_destroy(SLIST **plist); -void read_include(SLIST **plist, char *name); +void freadlist(SLIST **plist, char *name); +void preadlist(SLIST **plist, char *progname); void regalias(char *name, SLIST *exp); void end_aliases(void); extern SLIST *cw_list; extern int verbose; @@ -17,13 +17,14 @@ #include "alck.h" #include <stdarg.h> char *program_name; SLIST *cw_list; /* List of domain names pertaining to Sendmail 'w' class */ -static int restricted; /* prohibit use of `special' aliases (pipes, + +static int restricted; /* prohibit the use of `special' aliases (pipes, file redirections and includes */ int verbose; /* Verbose mode */ int error_count; /* Number of errors detected so far */ %} %union { @@ -97,24 +98,24 @@ email : string { if (restricted) { yyerror("Include statement is not allowed"); YYERROR; } $$ = NULL; - read_include(&$$, $2); + freadlist(&$$, $2); } ; string: IDENT | STRING ; %% int -yyerror (char *s) +yyerror(char *s) { parserror(file_name, line_num, "%s", s); error_count++; } void * @@ -171,21 +172,23 @@ usage() printf(" -d 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 FILE Read names of alias files from FILE\n"); + printf(" -T FILE Read names of alias files from FILE\n"); printf(" -h Display this help list\n"); printf(" -r Restrict alias file syntax to aliases only (i.e.\n"); printf(" prohibit use of pipes and file redirections\n"); printf(" -u Revert the effect of the previous -r option\n"); printf(" -v Verbose mode\n"); printf(" -V print program version and exit\n"); - printf(" -w FILE Read contents of Sendmail `w' class from the given\n"); - printf(" file.\n"); + printf(" -w FILE Read local domain names from the FILE\n"); + printf(" -W PROG Run PROG and read local domain names from" + " its stdout\n"); + printf("\n"); printf("Report bugs to <%s>\n", "gray@gnu.org"); } static char license[] = "\ License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\ @@ -207,23 +210,20 @@ 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; init_lex(); program_name = argv[0]; - while ((c = getopt(argc, argv, "-d:f:hp:ruVvw:")) != EOF) { + while ((c = getopt(argc, argv, "-d:hp:rT:uVvW:w:")) != EOF) { switch (c) { case 1: - if (!cw_list) - read_include(&cw_list, cwfile); openaliases(optarg); yyparse(); file_count++; break; case 'd': @@ -249,17 +249,15 @@ main(int argc, char **argv) error("%s: unknown debug option %c", argv[0], c); } } break; - case 'f': - if (!cw_list) - read_include(&cw_list, cwfile); + case 'T': file_list = NULL; - read_include(&file_list, optarg); + freadlist(&file_list, optarg); if (file_list) { for (s = file_list->head; s; s = s->next) { openaliases_prefix(optarg, s->str); yyparse(); file_count++; } @@ -282,30 +280,36 @@ main(int argc, char **argv) case 'v': verbose++; break; case 'V': version(); - exit (0); + exit(0); case 'w': if (file_count) - error("-w must be used before first non-option argument"); - cwfile = optarg; + error("-w must be used before the first " + "non-option argument or -T option"); + freadlist(&cw_list, optarg); + break; + + case 'W': + if (file_count) + error("-W must be used before the first " + "non-option argument or -T option"); + preadlist(&cw_list, optarg); break; default: - exit (1); + exit(1); } } argc -= optind; argv += optind; - if (!cw_list) - read_include(&cw_list, cwfile); while (argc--) { openaliases(*argv++); yyparse(); file_count++; } @@ -193,36 +193,103 @@ void lex_debug(int debug) { yy_flex_debug = debug; } void -read_include(SLIST **plist, char *name) +freadlist(SLIST **plist, char *name) { char *p; char buffer[256]; - FILE *fp = fopen(name, "r"); - + FILE *fp; + int line = 0; + int skipeol = 0; + + fp = fopen(name, "r"); if (!fp) { parserror(file_name, line_num, "cannot open include file `%s': %s", name, strerror(errno)); error_count++; return; } while (p = fgets(buffer, sizeof buffer, fp)) { - char *q; - + size_t len = strlen(p); + + line++; + + if (len == 0) + continue; + if (p[len-1] != '\n') { + if (!feof(fp)) { + if (!skipeol) + parserror(name, line, + "line too long"); + error_count++; + skipeol = 1; + } + } else if (skipeol) + continue; + else { + p[--len] = 0; + skipeol = 0; + } + while (*p && isspace(*p)) p++; - if (*p == '#') + if (!*p || *p == '#') continue; - for (q = p + strlen(p) - 1; q > p && isspace(*q); q--) - ; - q[1] = 0; - if (*p) - slist_add(plist, p); + + slist_add(plist, p); } fclose(fp); } + +void +preadlist(SLIST **plist, char *progname) +{ + char *p; + char buffer[256]; + FILE *fp; + int line = 0; + int skipeol = 0; + + fp = popen(progname, "r"); + if (!fp) { + parserror(file_name, line_num, + "cannot run `%s': %s", + progname, strerror(errno)); + error_count++; + return; + } + while (p = fgets(buffer, sizeof buffer, fp)) { + size_t len = strlen(p); + char *q; + + line++; + + if (len == 0) + continue; + if (p[len-1] != '\n') { + if (!feof(fp)) { + if (!skipeol) + parserror(progname, line, + "line too long"); + error_count++; + skipeol = 1; + } + } else if (skipeol) + continue; + else { + p[--len] = 0; + skipeol = 0; + } + + if (!*p || !isalnum(*p) || p[strcspn(p, " \t")]) + continue; + + slist_add(plist, p); + } + pclose(fp); +} |