aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--alck.173
-rw-r--r--alck.h3
-rw-r--r--gram.y44
-rw-r--r--lex.l89
4 files changed, 164 insertions, 45 deletions
diff --git a/alck.1 b/alck.1
index 6e842ae..dfbb83f 100644
--- a/alck.1
+++ b/alck.1
@@ -13,7 +13,7 @@
.\"
.\" 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
@@ -29,10 +29,14 @@ 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.
@@ -79,6 +83,10 @@ 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
@@ -95,6 +103,55 @@ enable lexical analizer debugging.
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
@@ -112,19 +169,9 @@ option or the end of command line.
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.
diff --git a/alck.h b/alck.h
index 9af8db6..3d152f4 100644
--- a/alck.h
+++ b/alck.h
@@ -56,7 +56,8 @@ 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);
diff --git a/gram.y b/gram.y
index 4da7cb2..271c50d 100644
--- a/gram.y
+++ b/gram.y
@@ -20,7 +20,8 @@
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 */
@@ -100,7 +101,7 @@ email : string
YYERROR;
}
$$ = NULL;
- read_include(&$$, $2);
+ freadlist(&$$, $2);
}
;
@@ -111,7 +112,7 @@ string: IDENT
%%
int
-yyerror (char *s)
+yyerror(char *s)
{
parserror(file_name, line_num, "%s", s);
error_count++;
@@ -174,15 +175,17 @@ usage()
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");
}
@@ -210,17 +213,14 @@ main(int argc, char **argv)
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++;
@@ -252,11 +252,9 @@ main(int argc, char **argv)
}
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);
@@ -285,24 +283,30 @@ main(int argc, char **argv)
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();
diff --git a/lex.l b/lex.l
index 85bd53f..e197957 100644
--- a/lex.l
+++ b/lex.l
@@ -196,12 +196,15 @@ lex_debug(int 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",
@@ -211,18 +214,82 @@ read_include(SLIST **plist, char *name)
}
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);
+}

Return to:

Send suggestions and report system problems to the System administrator.