Imported Upstream version 2.4.3
[platform/upstream/audit.git] / src / auditd-config.c
1 /* auditd-config.c -- 
2  * Copyright 2004-2011,2013-14 Red Hat Inc., Durham, North Carolina.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  * Authors:
20  *   Steve Grubb <sgrubb@redhat.com>
21  * 
22  */
23
24 #include "config.h"
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <sys/stat.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <dirent.h>
31 #include <ctype.h>
32 #include <stdlib.h>
33 #include <netdb.h>
34 #include <fcntl.h>      /* O_NOFOLLOW needs gnu defined */
35 #include <libgen.h>
36 #include <arpa/inet.h>
37 #include <limits.h>     /* INT_MAX */
38 #include "auditd-config.h"
39 #include "libaudit.h"
40 #include "private.h"
41
42 #define TCP_PORT_MAX 65535
43
44 /* Local prototypes */
45 struct nv_pair
46 {
47         const char *name;
48         const char *value;
49         const char *option;
50 };
51
52 struct kw_pair 
53 {
54         const char *name;
55         int (*parser)(struct nv_pair *, int, struct daemon_conf *);
56         int max_options;
57 };
58
59 struct nv_list
60
61         const char *name;
62         int option;
63 };
64
65 static char *get_line(FILE *f, char *buf, unsigned size, int *lineno,
66                 const char *file);
67 static int nv_split(char *buf, struct nv_pair *nv);
68 static const struct kw_pair *kw_lookup(const char *val);
69 static int log_file_parser(struct nv_pair *nv, int line, 
70                 struct daemon_conf *config);
71 static int num_logs_parser(struct nv_pair *nv, int line, 
72                 struct daemon_conf *config);
73 static int log_group_parser(struct nv_pair *nv, int line, 
74                 struct daemon_conf *config);
75 static int qos_parser(struct nv_pair *nv, int line, 
76                 struct daemon_conf *config);
77 static int dispatch_parser(struct nv_pair *nv, int line,
78                 struct daemon_conf *config);
79 static int name_format_parser(struct nv_pair *nv, int line,
80                 struct daemon_conf *config);
81 static int name_parser(struct nv_pair *nv, int line,
82                 struct daemon_conf *config);
83 static int max_log_size_parser(struct nv_pair *nv, int line, 
84                 struct daemon_conf *config);
85 static int max_log_size_action_parser(struct nv_pair *nv, int line, 
86                 struct daemon_conf *config);
87 static int log_format_parser(struct nv_pair *nv, int line, 
88                 struct daemon_conf *config);
89 static int flush_parser(struct nv_pair *nv, int line,
90                 struct daemon_conf *config);
91 static int freq_parser(struct nv_pair *nv, int line,
92                 struct daemon_conf *config);
93 static int space_left_parser(struct nv_pair *nv, int line, 
94                 struct daemon_conf *config);
95 static int space_action_parser(struct nv_pair *nv, int line, 
96                 struct daemon_conf *config);
97 static int action_mail_acct_parser(struct nv_pair *nv, int line, 
98                 struct daemon_conf *config);
99 static int admin_space_left_parser(struct nv_pair *nv, int line, 
100                 struct daemon_conf *config);
101 static int admin_space_left_action_parser(struct nv_pair *nv, int line, 
102                 struct daemon_conf *config);
103 static int disk_full_action_parser(struct nv_pair *nv, int line, 
104                 struct daemon_conf *config);
105 static int disk_error_action_parser(struct nv_pair *nv, int line, 
106                 struct daemon_conf *config);
107 static int priority_boost_parser(struct nv_pair *nv, int line,
108                 struct daemon_conf *config);
109 static int tcp_listen_port_parser(struct nv_pair *nv, int line,
110                 struct daemon_conf *config);
111 static int tcp_listen_queue_parser(struct nv_pair *nv, int line,
112                 struct daemon_conf *config);
113 static int tcp_max_per_addr_parser(struct nv_pair *nv, int line,
114                 struct daemon_conf *config);
115 static int use_libwrap_parser(struct nv_pair *nv, int line,
116                 struct daemon_conf *config);
117 static int tcp_client_ports_parser(struct nv_pair *nv, int line,
118                 struct daemon_conf *config);
119 static int tcp_client_max_idle_parser(struct nv_pair *nv, int line,
120                 struct daemon_conf *config);
121 static int enable_krb5_parser(struct nv_pair *nv, int line,
122                 struct daemon_conf *config);
123 static int krb5_principal_parser(struct nv_pair *nv, int line,
124                 struct daemon_conf *config);
125 static int krb5_key_file_parser(struct nv_pair *nv, int line,
126                 struct daemon_conf *config);
127 static int sanity_check(struct daemon_conf *config);
128
129 static const struct kw_pair keywords[] = 
130 {
131   {"log_file",                 log_file_parser,                 0 },
132   {"log_format",               log_format_parser,               0 },
133   {"log_group",                log_group_parser,                0 },
134   {"flush",                    flush_parser,                    0 },
135   {"freq",                     freq_parser,                     0 },
136   {"num_logs",                 num_logs_parser,                 0 },
137   {"dispatcher",               dispatch_parser,                 0 },
138   {"name_format",              name_format_parser,              0 },
139   {"name",                     name_parser,                     0 },
140   {"disp_qos",                 qos_parser,                      0 },
141   {"max_log_file",             max_log_size_parser,             0 },
142   {"max_log_file_action",      max_log_size_action_parser,      0 },
143   {"space_left",               space_left_parser,               0 },
144   {"space_left_action",        space_action_parser,             1 },
145   {"action_mail_acct",         action_mail_acct_parser,         0 },
146   {"admin_space_left",         admin_space_left_parser,         0 },
147   {"admin_space_left_action",  admin_space_left_action_parser,  1 },
148   {"disk_full_action",         disk_full_action_parser,         1 },
149   {"disk_error_action",        disk_error_action_parser,        1 },
150   {"priority_boost",           priority_boost_parser,           0 },
151   {"tcp_listen_port",          tcp_listen_port_parser,          0 },
152   {"tcp_listen_queue",         tcp_listen_queue_parser,         0 },
153   {"tcp_max_per_addr",         tcp_max_per_addr_parser,         0 },
154   {"use_libwrap",              use_libwrap_parser,              0 },
155   {"tcp_client_ports",         tcp_client_ports_parser,         0 },
156   {"tcp_client_max_idle",      tcp_client_max_idle_parser,      0 },
157   {"enable_krb5",              enable_krb5_parser,              0 },
158   {"krb5_principal",           krb5_principal_parser,           0 },
159   {"krb5_key_file",            krb5_key_file_parser,            0 },
160   { NULL,                      NULL }
161 };
162
163 static const struct nv_list log_formats[] =
164 {
165   {"raw",  LF_RAW },
166   {"nolog", LF_NOLOG },
167   { NULL,  0 }
168 };
169
170 static const struct nv_list flush_techniques[] =
171 {
172   {"none",        FT_NONE },
173   {"incremental", FT_INCREMENTAL },
174   {"data",        FT_DATA },
175   {"sync",        FT_SYNC },
176   { NULL,         0 }
177 };
178
179 static const struct nv_list failure_actions[] =
180 {
181   {"ignore",  FA_IGNORE },
182   {"syslog",  FA_SYSLOG },
183   {"rotate",  FA_ROTATE },
184   {"email",   FA_EMAIL },
185   {"exec",    FA_EXEC },
186   {"suspend", FA_SUSPEND },
187   {"single",  FA_SINGLE },
188   {"halt",    FA_HALT },
189   { NULL,     0 }
190 };
191
192 // Future ideas: e-mail, run command
193 static const struct nv_list size_actions[] =
194 {
195   {"ignore",  SZ_IGNORE },
196   {"syslog",  SZ_SYSLOG },
197   {"suspend", SZ_SUSPEND },
198   {"rotate",  SZ_ROTATE },
199   {"keep_logs", SZ_KEEP_LOGS},
200   { NULL,     0 }
201 };
202
203 static const struct nv_list qos_options[] =
204 {
205   {"lossy",     QOS_NON_BLOCKING },
206   {"lossless",  QOS_BLOCKING },
207   { NULL,     0 }
208 };
209
210 static const struct nv_list node_name_formats[] =
211 {
212   {"none",      N_NONE },
213   {"hostname",  N_HOSTNAME },
214   {"fqd",       N_FQD },
215   {"numeric",   N_NUMERIC },
216   {"user",      N_USER },
217   { NULL,  0 }
218 };
219
220 static const struct nv_list yes_no_values[] =
221 {
222   {"yes",  1 },
223   {"no", 0 },
224   { NULL,  0 }
225 };
226
227 const char *email_command = "/usr/lib/sendmail";
228 static int allow_links = 0;
229
230
231 void set_allow_links(int allow)
232 {
233         allow_links = allow;
234 }
235
236 /*
237  * Set everything to its default value
238 */
239 void clear_config(struct daemon_conf *config)
240 {
241         config->qos = QOS_NON_BLOCKING;
242         config->sender_uid = 0;
243         config->sender_pid = 0;
244         config->sender_ctx = NULL;
245         config->log_file = strdup("/var/log/audit/audit.log");
246         config->log_format = LF_RAW;
247         config->log_group = 0;
248         config->priority_boost = 4;
249         config->flush =  FT_NONE;
250         config->freq = 0;
251         config->num_logs = 0L;
252         config->dispatcher = NULL;
253         config->node_name_format = N_NONE;
254         config->node_name = NULL;
255         config->max_log_size = 0L;
256         config->max_log_size_action = SZ_IGNORE;
257         config->space_left = 0L;
258         config->space_left_action = FA_IGNORE;
259         config->space_left_exe = NULL;
260         config->action_mail_acct = strdup("root");
261         config->admin_space_left= 0L;
262         config->admin_space_left_action = FA_IGNORE;
263         config->admin_space_left_exe = NULL;
264         config->disk_full_action = FA_IGNORE;
265         config->disk_full_exe = NULL;
266         config->disk_error_action = FA_SYSLOG;
267         config->disk_error_exe = NULL;
268         config->tcp_listen_port = 0;
269         config->tcp_listen_queue = 5;
270         config->tcp_max_per_addr = 1;
271         config->use_libwrap = 1;
272         config->tcp_client_min_port = 0;
273         config->tcp_client_max_port = TCP_PORT_MAX;
274         config->tcp_client_max_idle = 0;
275         config->enable_krb5 = 0;
276         config->krb5_principal = NULL;
277         config->krb5_key_file = NULL;
278 }
279
280 static log_test_t log_test = TEST_AUDITD;
281 int load_config(struct daemon_conf *config, log_test_t lt)
282 {
283         int fd, rc, mode, lineno = 1;
284         struct stat st;
285         FILE *f;
286         char buf[160];
287
288         clear_config(config);
289         log_test = lt;
290
291         /* open the file */
292         mode = O_RDONLY;
293         if (allow_links == 0)
294                 mode |= O_NOFOLLOW;
295         rc = open(CONFIG_FILE, mode);
296         if (rc < 0) {
297                 if (errno != ENOENT) {
298                         audit_msg(LOG_ERR, "Error opening config file (%s)", 
299                                 strerror(errno));
300                         return 1;
301                 }
302                 audit_msg(LOG_WARNING,
303                         "Config file %s doesn't exist, skipping", CONFIG_FILE);
304                 return 0;
305         }
306         fd = rc;
307
308         /* check the file's permissions: owned by root, not world writable,
309          * not symlink.
310          */
311         audit_msg(LOG_DEBUG, "Config file %s opened for parsing", 
312                         CONFIG_FILE);
313         if (fstat(fd, &st) < 0) {
314                 audit_msg(LOG_ERR, "Error fstat'ing config file (%s)", 
315                         strerror(errno));
316                 close(fd);
317                 return 1;
318         }
319         if (st.st_uid != 0) {
320                 audit_msg(LOG_ERR, "Error - %s isn't owned by root", 
321                         CONFIG_FILE);
322                 close(fd);
323                 return 1;
324         }
325         if ((st.st_mode & S_IWOTH) == S_IWOTH) {
326                 audit_msg(LOG_ERR, "Error - %s is world writable", 
327                         CONFIG_FILE);
328                 close(fd);
329                 return 1;
330         }
331         if (!S_ISREG(st.st_mode)) {
332                 audit_msg(LOG_ERR, "Error - %s is not a regular file", 
333                         CONFIG_FILE);
334                 close(fd);
335                 return 1;
336         }
337
338         /* it's ok, read line by line */
339         f = fdopen(fd, "rm");
340         if (f == NULL) {
341                 audit_msg(LOG_ERR, "Error - fdopen failed (%s)", 
342                         strerror(errno));
343                 close(fd);
344                 return 1;
345         }
346
347         while (get_line(f, buf, sizeof(buf), &lineno, CONFIG_FILE)) {
348                 // convert line into name-value pair
349                 const struct kw_pair *kw;
350                 struct nv_pair nv;
351                 rc = nv_split(buf, &nv);
352                 switch (rc) {
353                         case 0: // fine
354                                 break;
355                         case 1: // not the right number of tokens.
356                                 audit_msg(LOG_ERR, 
357                                 "Wrong number of arguments for line %d in %s", 
358                                         lineno, CONFIG_FILE);
359                                 break;
360                         case 2: // no '=' sign
361                                 audit_msg(LOG_ERR, 
362                                         "Missing equal sign for line %d in %s", 
363                                         lineno, CONFIG_FILE);
364                                 break;
365                         default: // something else went wrong... 
366                                 audit_msg(LOG_ERR, 
367                                         "Unknown error for line %d in %s", 
368                                         lineno, CONFIG_FILE);
369                                 break;
370                 }
371                 if (nv.name == NULL) {
372                         lineno++;
373                         continue;
374                 }
375                 if (nv.value == NULL) {
376                         fclose(f);
377                         audit_msg(LOG_ERR,
378                                 "Not processing any more lines in %s",
379                                 CONFIG_FILE);
380                         return 1;
381                 }
382
383                 /* identify keyword or error */
384                 kw = kw_lookup(nv.name);
385                 if (kw->name == NULL) {
386                         audit_msg(LOG_ERR, 
387                                 "Unknown keyword \"%s\" in line %d of %s", 
388                                 nv.name, lineno, CONFIG_FILE);
389                         fclose(f);
390                         return 1;
391                 }
392
393                 /* Check number of options */
394                 if (kw->max_options == 0 && nv.option != NULL) {
395                         audit_msg(LOG_ERR, 
396                                 "Keyword \"%s\" has invalid option "
397                                 "\"%s\" in line %d of %s", 
398                                 nv.name, nv.option, lineno, CONFIG_FILE);
399                         fclose(f);
400                         return 1;
401                 }
402
403                 /* dispatch to keyword's local parser */
404                 rc = kw->parser(&nv, lineno, config);
405                 if (rc != 0) {
406                         fclose(f);
407                         return 1; // local parser puts message out
408                 }
409
410                 lineno++;
411         }
412
413         fclose(f);
414         if (lineno > 1)
415                 return sanity_check(config);
416         return 0;
417 }
418
419 static char *get_line(FILE *f, char *buf, unsigned size, int *lineno,
420         const char *file)
421 {
422         int too_long = 0;
423
424         while (fgets_unlocked(buf, size, f)) {
425                 /* remove newline */
426                 char *ptr = strchr(buf, 0x0a);
427                 if (ptr) {
428                         if (!too_long) {
429                                 *ptr = 0;
430                                 return buf;
431                         }
432                         // Reset and start with the next line
433                         too_long = 0;
434                         *lineno = *lineno + 1;
435                 } else {
436                         // If a line is too long skip it.
437                         // Only output 1 warning
438                         if (!too_long)
439                                 audit_msg(LOG_ERR,
440                                         "Skipping line %d in %s: too long",
441                                         *lineno, file);
442                         too_long = 1;
443                 }
444         }
445         return NULL;
446 }
447
448 static int nv_split(char *buf, struct nv_pair *nv)
449 {
450         /* Get the name part */
451         char *ptr;
452
453         nv->name = NULL;
454         nv->value = NULL;
455         nv->option = NULL;
456         ptr = audit_strsplit(buf);
457         if (ptr == NULL)
458                 return 0; /* If there's nothing, go to next line */
459         if (ptr[0] == '#')
460                 return 0; /* If there's a comment, go to next line */
461         nv->name = ptr;
462
463         /* Check for a '=' */
464         ptr = audit_strsplit(NULL);
465         if (ptr == NULL)
466                 return 1;
467         if (strcmp(ptr, "=") != 0)
468                 return 2;
469
470         /* get the value */
471         ptr = audit_strsplit(NULL);
472         if (ptr == NULL)
473                 return 1;
474         nv->value = ptr;
475
476         /* See if there's an option */
477         ptr = audit_strsplit(NULL);
478         if (ptr) {
479                 nv->option = ptr;
480
481                 /* Make sure there's nothing else */
482                 ptr = audit_strsplit(NULL);
483                 if (ptr)
484                         return 1;
485         }
486
487         /* Everything is OK */
488         return 0;
489 }
490
491 static const struct kw_pair *kw_lookup(const char *val)
492 {
493         int i = 0;
494         while (keywords[i].name != NULL) {
495                 if (strcasecmp(keywords[i].name, val) == 0)
496                         break;
497                 i++;
498         }
499         return &keywords[i];
500 }
501  
502 static int log_file_parser(struct nv_pair *nv, int line,
503         struct daemon_conf *config)
504 {
505         char *dir = NULL, *tdir;
506         DIR *d;
507         int fd, mode;
508         struct stat buf;
509
510         audit_msg(LOG_DEBUG, "log_file_parser called with: %s", nv->value);
511
512         /* get dir from name. */
513         tdir = strdup(nv->value);
514         if (tdir)
515                 dir = dirname(tdir);
516         if (dir == NULL || strlen(dir) < 4) { //  '/var' is shortest dirname
517                 audit_msg(LOG_ERR, 
518                         "The directory name: %s is too short - line %d", 
519                         dir, line);
520                 free((void *)tdir);
521                 return 1;
522         }
523
524         /* verify the directory path exists */
525         d = opendir(dir);
526         if (d == NULL) {
527                 audit_msg(LOG_ERR, "Could not open dir %s (%s)", dir, 
528                         strerror(errno));
529                 free((void *)tdir);
530                 return 1;
531         }
532         free((void *)tdir);
533         closedir(d);
534
535         /* if the file exists, see that its regular, owned by root, 
536          * and not world anything */
537         if (log_test == TEST_AUDITD)
538                 mode = O_APPEND;
539         else
540                 mode = O_RDONLY;
541
542         fd = open(nv->value, mode);
543         if (fd < 0) {
544                 if (errno == ENOENT) {
545                         fd = create_log_file(nv->value);
546                         if (fd < 0) 
547                                 return 1;
548                 } else {
549                         audit_msg(LOG_ERR, "Unable to open %s (%s)", nv->value, 
550                                         strerror(errno));
551                         return 1;
552                 }
553         }
554         if (fstat(fd, &buf) < 0) {
555                 audit_msg(LOG_ERR, "Unable to stat %s (%s)", 
556                                         nv->value, strerror(errno));
557                 close(fd);
558                 return 1;
559         }
560         close(fd);
561         if (!S_ISREG(buf.st_mode)) {
562                 audit_msg(LOG_ERR, "%s is not a regular file", nv->value);
563                 return 1;
564         }
565         if (buf.st_uid != 0) {
566                 audit_msg(LOG_ERR, "%s is not owned by root", nv->value);
567                 return 1;
568         }
569         if ( (buf.st_mode & (S_IXUSR|S_IWGRP|S_IXGRP|S_IRWXO)) ) {
570                 audit_msg(LOG_ERR, "%s permissions should be 0600 or 0640",
571                                 nv->value);
572                 return 1;
573         }
574         if ( !(buf.st_mode & S_IWUSR) ) {
575                 audit_msg(LOG_ERR, "audit log is not writable by owner");
576                 return 1;
577         }
578
579         free((void *)config->log_file);
580         config->log_file = strdup(nv->value);
581         if (config->log_file == NULL)
582                 return 1;
583         return 0;
584 }
585
586 static int num_logs_parser(struct nv_pair *nv, int line, 
587                 struct daemon_conf *config)
588 {
589         const char *ptr = nv->value;
590         unsigned long i;
591
592         audit_msg(LOG_DEBUG, "num_logs_parser called with: %s", nv->value);
593
594         /* check that all chars are numbers */
595         for (i=0; ptr[i]; i++) {
596                 if (!isdigit(ptr[i])) {
597                         audit_msg(LOG_ERR, 
598                                 "Value %s should only be numbers - line %d",
599                                 nv->value, line);
600                         return 1;
601                 }
602         }
603
604         /* convert to unsigned long */
605         errno = 0;
606         i = strtoul(nv->value, NULL, 10);
607         if (errno) {
608                 audit_msg(LOG_ERR, 
609                         "Error converting string to a number (%s) - line %d",
610                         strerror(errno), line);
611                 return 1;
612         }
613         if (i > 99) {
614                 audit_msg(LOG_ERR, "num_logs must be 99 or less");
615                 return 1;
616         }
617         config->num_logs = i;
618         return 0;
619 }
620
621 static int qos_parser(struct nv_pair *nv, int line, 
622                 struct daemon_conf *config)
623 {
624         int i;
625
626         audit_msg(LOG_DEBUG, "qos_parser called with: %s", nv->value);
627         for (i=0; qos_options[i].name != NULL; i++) {
628                 if (strcasecmp(nv->value, qos_options[i].name) == 0) {
629                         config->qos = qos_options[i].option;
630                         return 0;
631                 }
632         }
633         audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line);
634         return 1;
635 }
636
637 static int dispatch_parser(struct nv_pair *nv, int line,
638         struct daemon_conf *config)
639 {
640         char *dir = NULL, *tdir;
641         int fd;
642         struct stat buf;
643
644         audit_msg(LOG_DEBUG, "dispatch_parser called with: %s", nv->value);
645         if (nv->value == NULL) {
646                 config->dispatcher = NULL;
647                 return 0;
648         }
649
650         /* get dir from name. */
651         tdir = strdup(nv->value);
652         if (tdir)
653                 dir = dirname(tdir);
654         if (dir == NULL || strlen(dir) < 4) { //  '/var' is shortest dirname
655                 audit_msg(LOG_ERR,
656                         "The directory name: %s is too short - line %d",
657                         dir, line);
658                 free(tdir);
659                 return 1;
660         }
661
662         free((void *)tdir);
663
664         /* Bypass the perms check if group is not root since
665          * this will fail under normal circumstances */
666         if ((config->log_group != 0 && getuid() != 0) ||
667                                 (log_test == TEST_SEARCH)) 
668                 goto bypass;
669
670         /* if the file exists, see that its regular, owned by root,
671          * and not world anything */
672         fd = open(nv->value, O_RDONLY);
673         if (fd < 0) {
674                 audit_msg(LOG_ERR, "Unable to open %s (%s)", nv->value,
675                         strerror(errno));
676                 return 1;
677         }
678         if (fstat(fd, &buf) < 0) {
679                 audit_msg(LOG_ERR, "Unable to stat %s (%s)", nv->value,
680                         strerror(errno));
681                 close(fd);
682                 return 1;
683         }
684         close(fd);
685         if (!S_ISREG(buf.st_mode)) {
686                 audit_msg(LOG_ERR, "%s is not a regular file", nv->value);
687                 return 1;
688         }
689         if (buf.st_uid != 0) {
690                 audit_msg(LOG_ERR, "%s is not owned by root", nv->value);
691                 return 1;
692         }
693         if ((buf.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) !=
694                            (S_IRWXU|S_IRGRP|S_IXGRP) && 
695             (buf.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) !=
696                            (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
697                 audit_msg(LOG_ERR, "%s permissions should be 0750 or 0755",
698                                 nv->value);
699                 return 1;
700         }
701 bypass:
702         free((void *)config->dispatcher);
703         config->dispatcher = strdup(nv->value);
704         if (config->dispatcher == NULL)
705                 return 1;
706         return 0;
707 }
708
709 static int name_format_parser(struct nv_pair *nv, int line,
710                 struct daemon_conf *config)
711 {
712         int i;
713
714         audit_msg(LOG_DEBUG, "name_format_parser called with: %s", nv->value);
715         for (i=0; node_name_formats[i].name != NULL; i++) {
716                 if (strcasecmp(nv->value, node_name_formats[i].name) == 0) {
717                         config->node_name_format = node_name_formats[i].option;
718                         return 0;
719                 }
720         }
721         audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line);
722         return 1;
723 }
724
725 static int name_parser(struct nv_pair *nv, int line,
726                 struct daemon_conf *config)
727 {
728         audit_msg(LOG_DEBUG, "name_parser called with: %s", nv->value);
729         if (nv->value == NULL)
730                 config->node_name = NULL;
731         else
732                 config->node_name = strdup(nv->value);
733         return 0;
734 }
735
736 static int max_log_size_parser(struct nv_pair *nv, int line, 
737                 struct daemon_conf *config)
738 {
739         const char *ptr = nv->value;
740         unsigned long i;
741
742         audit_msg(LOG_DEBUG, "max_log_size_parser called with: %s", nv->value);
743
744         /* check that all chars are numbers */
745         for (i=0; ptr[i]; i++) {
746                 if (!isdigit(ptr[i])) {
747                         audit_msg(LOG_ERR, 
748                                 "Value %s should only be numbers - line %d",
749                                 nv->value, line);
750                         return 1;
751                 }
752         }
753
754         /* convert to unsigned long */
755         errno = 0;
756         i = strtoul(nv->value, NULL, 10);
757         if (errno) {
758                 audit_msg(LOG_ERR, 
759                         "Error converting string to a number (%s) - line %d",
760                         strerror(errno), line);
761                 return 1;
762         }
763         config->max_log_size = i;
764         return 0;
765 }
766
767 static int max_log_size_action_parser(struct nv_pair *nv, int line, 
768                 struct daemon_conf *config)
769 {
770         int i;
771
772         audit_msg(LOG_DEBUG, "max_log_size_action_parser called with: %s",
773                 nv->value);
774         for (i=0; size_actions[i].name != NULL; i++) {
775                 if (strcasecmp(nv->value, size_actions[i].name) == 0) {
776                         config->max_log_size_action = size_actions[i].option;
777                         return 0;
778                 }
779         }
780         audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line);
781         return 1;
782 }
783
784 static int log_format_parser(struct nv_pair *nv, int line, 
785                 struct daemon_conf *config)
786 {
787         int i;
788
789         audit_msg(LOG_DEBUG, "log_format_parser called with: %s", nv->value);
790         for (i=0; log_formats[i].name != NULL; i++) {
791                 if (strcasecmp(nv->value, log_formats[i].name) == 0) {
792                         config->log_format = log_formats[i].option;
793                         return 0;
794                 }
795         }
796         audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line);
797         return 1;
798 }
799
800 static int log_group_parser(struct nv_pair *nv, int line, 
801                 struct daemon_conf *config)
802 {
803         gid_t gid = 0;
804         
805         audit_msg(LOG_DEBUG, "log_group_parser called with: %s",
806                                                         nv->value);
807         if (isdigit(nv->value[0])) {
808                 errno = 0;
809                 gid = strtoul(nv->value,NULL,10);
810                 if (errno) {
811                         audit_msg(LOG_ERR,
812                     "Numeric group ID conversion error (%s) for %s - line %d\n",
813                                 strerror(errno), nv->value, line);
814                         return 1;
815                 }
816         } else {
817                 struct group *gr ;
818
819                 gr = getgrnam(nv->value);
820                 if (gr == NULL) {
821                         audit_msg(LOG_ERR,
822                          "Group ID is non-numeric and unknown (%s) - line %d\n",
823                                 nv->value, line);
824                         return 1;
825                 }
826                 gid = gr->gr_gid;
827         }
828         config->log_group = gid;
829         return 0;
830 }
831
832 static int flush_parser(struct nv_pair *nv, int line,
833                 struct daemon_conf *config)
834 {
835         int i;
836
837         audit_msg(LOG_DEBUG, "flush_parser called with: %s", nv->value);
838         for (i=0; flush_techniques[i].name != NULL; i++) {
839                 if (strcasecmp(nv->value, flush_techniques[i].name) == 0) {
840                         config->flush = flush_techniques[i].option;
841                         return 0;
842                 }
843         }
844         audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line);
845         return 1;
846 }
847
848 static int freq_parser(struct nv_pair *nv, int line,
849                 struct daemon_conf *config)
850 {
851         const char *ptr = nv->value;
852         unsigned long i;
853
854         audit_msg(LOG_DEBUG, "freq_parser called with: %s", nv->value);
855
856         /* check that all chars are numbers */
857         for (i=0; ptr[i]; i++) {
858                 if (!isdigit(ptr[i])) {
859                         audit_msg(LOG_ERR, 
860                                 "Value %s should only be numbers - line %d",
861                                 nv->value, line);
862                         return 1;
863                 }
864         }
865
866         /* convert to unsigned int */
867         errno = 0;
868         i = strtoul(nv->value, NULL, 10);
869         if (errno) {
870                 audit_msg(LOG_ERR, 
871                         "Error converting string to a number (%s) - line %d",
872                         strerror(errno), line);
873                 return 1;
874         }
875         /* Check its range */
876         if (i > INT_MAX) {
877                 audit_msg(LOG_ERR, 
878                         "Error - converted number (%s) is too large - line %d",
879                         nv->value, line);
880                 return 1;
881         }
882         config->freq = (unsigned int)i;
883         return 0;
884 }
885
886 static int space_left_parser(struct nv_pair *nv, int line, 
887                 struct daemon_conf *config)
888 {
889         const char *ptr = nv->value;
890         unsigned long i;
891
892         audit_msg(LOG_DEBUG, "space_left_parser called with: %s", nv->value);
893
894         /* check that all chars are numbers */
895         for (i=0; ptr[i]; i++) {
896                 if (!isdigit(ptr[i])) {
897                         audit_msg(LOG_ERR, 
898                                 "Value %s should only be numbers - line %d",
899                                 nv->value, line);
900                         return 1;
901                 }
902         }
903
904         /* convert to unsigned long */
905         errno = 0;
906         i = strtoul(nv->value, NULL, 10);
907         if (errno) {
908                 audit_msg(LOG_ERR, 
909                         "Error converting string to a number (%s) - line %d",
910                         strerror(errno), line);
911                 return 1;
912         }
913         config->space_left = i;
914         return 0;
915 }
916
917 static int check_exe_name(const char *val, int line)
918 {
919         struct stat buf;
920
921         if (val == NULL) {
922                 audit_msg(LOG_ERR, "Executable path needed for line %d", line);
923                 return -1;
924         }
925
926         if (*val != '/') {
927                 audit_msg(LOG_ERR, "Absolute path needed for %s - line %d",
928                         val, line);
929                 return -1;
930         }
931
932         if (stat(val, &buf) < 0) {
933                 audit_msg(LOG_ERR, "Unable to stat %s (%s) - line %d", val,
934                         strerror(errno), line);
935                 return -1;
936         }
937         if (!S_ISREG(buf.st_mode)) {
938                 audit_msg(LOG_ERR, "%s is not a regular file - line %d", val,
939                         line);
940                 return -1;
941         }
942         if (buf.st_uid != 0) {
943                 audit_msg(LOG_ERR, "%s is not owned by root - line %d", val,
944                         line);
945                 return -1;
946         }
947         if ((buf.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) !=
948                            (S_IRWXU|S_IRGRP|S_IXGRP) &&
949             (buf.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) !=
950                            (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
951                 audit_msg(LOG_ERR,
952                         "%s permissions should be 0750 or 0755 - line %d",
953                         val, line);
954                 return -1;
955         }
956         return 0;
957 }
958
959 static int space_action_parser(struct nv_pair *nv, int line, 
960                 struct daemon_conf *config)
961 {
962         int i;
963
964         audit_msg(LOG_DEBUG, "space_action_parser called with: %s", nv->value);
965         for (i=0; failure_actions[i].name != NULL; i++) {
966                 if (strcasecmp(nv->value, failure_actions[i].name) == 0) {
967                         if (failure_actions[i].option == FA_EMAIL) {
968                                 if (access(email_command, X_OK)) {
969                                         audit_msg(LOG_ERR,
970                 "Email option is specified but %s doesn't seem executable.",
971                                                  email_command);
972                                 }
973                         } else if (failure_actions[i].option == FA_EXEC) {
974                                 if (check_exe_name(nv->option, line))
975                                         return 1;
976                                 config->space_left_exe = strdup(nv->option);
977                         }
978                         config->space_left_action = failure_actions[i].option;
979                         return 0;
980                 }
981         }
982         audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line);
983         return 1;
984 }
985
986 // returns 0 if OK, 1 on temp error, 2 on permanent error
987 static int validate_email(const char *acct)
988 {
989         int i, len;
990         char *ptr1;
991
992         if (acct == NULL)
993                 return 2;
994
995         len = strlen(acct);
996         if (len < 2) {
997                 audit_msg(LOG_ERR,
998                     "email: %s is too short, expecting at least 2 characters",
999                          acct);
1000                 return 2;
1001         }
1002
1003         // look for illegal char
1004         for (i=0; i<len; i++) {
1005                 if (! (isalnum(acct[i]) || (acct[i] == '@') ||
1006                                 (acct[i]=='.') || (acct[i]=='-') ||
1007                                 (acct[i] == '_')) ) {
1008                         audit_msg(LOG_ERR, "email: %s has illegal character",
1009                                 acct);
1010                         return 2;
1011                 }
1012         }
1013
1014         if ((ptr1 = strchr(acct, '@'))) {
1015                 char *ptr2;
1016                 struct hostent *t_addr;
1017
1018                 ptr2 = strrchr(acct, '.');        // get last dot - sb after @
1019                 if ((ptr2 == NULL) || (ptr1 > ptr2)) {
1020                         audit_msg(LOG_ERR, "email: %s should have . after @",
1021                                 acct);
1022                         return 2;
1023                 }
1024
1025                 t_addr = gethostbyname(ptr1+1);
1026                 if (t_addr == 0) {
1027                         if ((h_errno == HOST_NOT_FOUND) ||
1028                                         (h_errno == NO_RECOVERY)) {
1029                                         audit_msg(LOG_ERR,
1030                                 "validate_email: failed looking up host for %s",
1031                                         ptr1+1);
1032                                 // FIXME: gethostbyname is having trouble
1033                                 // telling when we have a temporary vs permanent
1034                                 // dns failure. So, for now, treat all as temp
1035                                 return 1;
1036                         }
1037                         else if (h_errno == TRY_AGAIN)
1038                                 audit_msg(LOG_DEBUG,
1039                 "validate_email: temporary failure looking up domain for %s",
1040                                         ptr1+1);
1041                                 return 1;
1042                 }
1043         }
1044         return 0;
1045 }
1046
1047 static int action_mail_acct_parser(struct nv_pair *nv, int line, 
1048                 struct daemon_conf *config)
1049 {
1050         char *tmail;
1051         
1052         audit_msg(LOG_DEBUG, "action_mail_acct_parser called with: %s",
1053                                                         nv->value);
1054         tmail = strdup(nv->value);
1055         if (tmail == NULL)
1056                 return 1;
1057
1058         if (validate_email(tmail) > 1) {
1059                 free(tmail);
1060                 return 1;
1061         }
1062
1063
1064         if (config->action_mail_acct)
1065                 free((void *)config->action_mail_acct);
1066         config->action_mail_acct = tmail;
1067         return 0;
1068 }
1069
1070 static int admin_space_left_parser(struct nv_pair *nv, int line, 
1071                 struct daemon_conf *config)
1072 {
1073         const char *ptr = nv->value;
1074         unsigned long i;
1075
1076         audit_msg(LOG_DEBUG, "admin_space_left_parser called with: %s",
1077                                                         nv->value);
1078
1079         /* check that all chars are numbers */
1080         for (i=0; ptr[i]; i++) {
1081                 if (!isdigit(ptr[i])) {
1082                         audit_msg(LOG_ERR, 
1083                                 "Value %s should only be numbers - line %d",
1084                                 nv->value, line);
1085                         return 1;
1086                 }
1087         }
1088
1089         /* convert to unsigned long */
1090         errno = 0;
1091         i = strtoul(nv->value, NULL, 10);
1092         if (errno) {
1093                 audit_msg(LOG_ERR, 
1094                         "Error converting string to a number (%s) - line %d",
1095                         strerror(errno), line);
1096                 return 1;
1097         }
1098         config->admin_space_left = i;
1099         return 0;
1100 }
1101
1102 static int admin_space_left_action_parser(struct nv_pair *nv, int line, 
1103                 struct daemon_conf *config)
1104 {
1105         int i;
1106
1107         audit_msg(LOG_DEBUG, "admin_space_left_action_parser called with: %s",
1108                                                                 nv->value);
1109         for (i=0; failure_actions[i].name != NULL; i++) {
1110                 if (strcasecmp(nv->value, failure_actions[i].name) == 0) {
1111                         if (failure_actions[i].option == FA_EMAIL) {
1112                                 if (access(email_command, X_OK)) {
1113                                         audit_msg(LOG_ERR,
1114                 "Email option is specified but %s doesn't seem executable.",
1115                                                  email_command);
1116                                 }
1117                         } else if (failure_actions[i].option == FA_EXEC) {
1118                                 if (check_exe_name(nv->option, line))
1119                                         return 1;
1120                                 config->admin_space_left_exe = 
1121                                                         strdup(nv->option);
1122                         }
1123                         config->admin_space_left_action = 
1124                                                 failure_actions[i].option;
1125                         return 0;
1126                 }
1127         }
1128         audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line);
1129         return 1;
1130 }
1131
1132 static int disk_full_action_parser(struct nv_pair *nv, int line, 
1133                 struct daemon_conf *config)
1134 {
1135         int i;
1136
1137         audit_msg(LOG_DEBUG, "disk_full_action_parser called with: %s",
1138                                                                 nv->value);
1139         for (i=0; failure_actions[i].name != NULL; i++) {
1140                 if (strcasecmp(nv->value, failure_actions[i].name) == 0) {
1141                         if (failure_actions[i].option == FA_EMAIL) {
1142                                 audit_msg(LOG_ERR, 
1143                         "Illegal option %s for disk_full_action - line %d",
1144                                         nv->value, line);
1145                                 return 1;
1146                         } else if (failure_actions[i].option == FA_EXEC) {
1147                                 if (check_exe_name(nv->option, line))
1148                                         return 1;
1149                                 config->disk_full_exe = strdup(nv->option);
1150                         }
1151                         config->disk_full_action = failure_actions[i].option;
1152                         return 0;
1153                 }
1154         }
1155         audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line);
1156         return 1;
1157 }
1158
1159 static int disk_error_action_parser(struct nv_pair *nv, int line, 
1160                 struct daemon_conf *config)
1161 {
1162         int i;
1163
1164         audit_msg(LOG_DEBUG, "disk_error_action_parser called with: %s",
1165                                                                 nv->value);
1166         for (i=0; failure_actions[i].name != NULL; i++) {
1167                 if (strcasecmp(nv->value, failure_actions[i].name) == 0) {
1168                         if (failure_actions[i].option == FA_EMAIL ||
1169                                 failure_actions[i].option == FA_ROTATE) {
1170                                 audit_msg(LOG_ERR, 
1171                         "Illegal option %s for disk_error_action - line %d",
1172                                         nv->value, line);
1173                                 return 1;
1174                         } else if (failure_actions[i].option == FA_EXEC) {
1175                                 if (check_exe_name(nv->option, line))
1176                                         return 1;
1177                                 config->disk_error_exe = strdup(nv->option);
1178                         }
1179                         config->disk_error_action = failure_actions[i].option;
1180                         return 0;
1181                 }
1182         }
1183         audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line);
1184         return 1;
1185 }
1186
1187 static int priority_boost_parser(struct nv_pair *nv, int line,
1188         struct daemon_conf *config)
1189 {
1190         const char *ptr = nv->value;
1191         unsigned long i;
1192
1193         audit_msg(LOG_DEBUG, "priority_boost_parser called with: %s",
1194                                                                 nv->value);
1195
1196         /* check that all chars are numbers */
1197         for (i=0; ptr[i]; i++) {
1198                 if (!isdigit(ptr[i])) {
1199                         audit_msg(LOG_ERR, 
1200                                 "Value %s should only be numbers - line %d",
1201                                 nv->value, line);
1202                         return 1;
1203                 }
1204         }
1205
1206         /* convert to unsigned int */
1207         errno = 0;
1208         i = strtoul(nv->value, NULL, 10);
1209         if (errno) {
1210                 audit_msg(LOG_ERR, 
1211                         "Error converting string to a number (%s) - line %d",
1212                         strerror(errno), line);
1213                 return 1;
1214         }
1215         /* Check its range */
1216         if (i > INT_MAX) {
1217                 audit_msg(LOG_ERR, 
1218                         "Error - converted number (%s) is too large - line %d",
1219                         nv->value, line);
1220                 return 1;
1221         }
1222         config->priority_boost = (unsigned int)i;
1223         return 0;
1224 }
1225
1226 static int tcp_listen_port_parser(struct nv_pair *nv, int line,
1227         struct daemon_conf *config)
1228 {
1229         const char *ptr = nv->value;
1230         unsigned long i;
1231
1232         audit_msg(LOG_DEBUG, "tcp_listen_port_parser called with: %s",
1233                   nv->value);
1234
1235 #ifndef USE_LISTENER
1236         audit_msg(LOG_DEBUG,
1237                 "Listener support is not enabled, ignoring value at line %d",
1238                 line);
1239         return 0;
1240 #else
1241         /* check that all chars are numbers */
1242         for (i=0; ptr[i]; i++) {
1243                 if (!isdigit(ptr[i])) {
1244                         audit_msg(LOG_ERR, 
1245                                 "Value %s should only be numbers - line %d",
1246                                 nv->value, line);
1247                         return 1;
1248                 }
1249         }
1250
1251         /* convert to unsigned int */
1252         errno = 0;
1253         i = strtoul(nv->value, NULL, 10);
1254         if (errno) {
1255                 audit_msg(LOG_ERR, 
1256                         "Error converting string to a number (%s) - line %d",
1257                         strerror(errno), line);
1258                 return 1;
1259         }
1260         /* Check its range */
1261         if (i > TCP_PORT_MAX) {
1262                 audit_msg(LOG_ERR, 
1263                         "Error - converted number (%s) is too large - line %d",
1264                         nv->value, line);
1265                 return 1;
1266         }
1267         if (i < 1) {
1268                 audit_msg(LOG_ERR, 
1269                         "Error - converted number (%s) is too small - line %d",
1270                         nv->value, line);
1271                 return 1;
1272         }
1273         config->tcp_listen_port = (unsigned int)i;
1274         return 0;
1275 #endif
1276 }
1277
1278 static int tcp_listen_queue_parser(struct nv_pair *nv, int line,
1279         struct daemon_conf *config)
1280 {
1281         const char *ptr = nv->value;
1282         unsigned long i;
1283
1284         audit_msg(LOG_DEBUG, "tcp_listen_queue_parser called with: %s",
1285                   nv->value);
1286
1287 #ifndef USE_LISTENER
1288         audit_msg(LOG_DEBUG,
1289                 "Listener support is not enabled, ignoring value at line %d",
1290                 line);
1291         return 0;
1292 #else
1293         /* check that all chars are numbers */
1294         for (i=0; ptr[i]; i++) {
1295                 if (!isdigit(ptr[i])) {
1296                         audit_msg(LOG_ERR, 
1297                                 "Value %s should only be numbers - line %d",
1298                                 nv->value, line);
1299                         return 1;
1300                 }
1301         }
1302
1303         /* convert to unsigned int */
1304         errno = 0;
1305         i = strtoul(nv->value, NULL, 10);
1306         if (errno) {
1307                 audit_msg(LOG_ERR, 
1308                         "Error converting string to a number (%s) - line %d",
1309                         strerror(errno), line);
1310                 return 1;
1311         }
1312         /* Check its range.  While this value is technically
1313            unlimited, it's limited by the kernel, and we limit it here
1314            for sanity. */
1315         if (i > TCP_PORT_MAX) {
1316                 audit_msg(LOG_ERR, 
1317                         "Error - converted number (%s) is too large - line %d",
1318                         nv->value, line);
1319                 return 1;
1320         }
1321         if (i < 1) {
1322                 audit_msg(LOG_ERR, 
1323                         "Error - converted number (%s) is too small - line %d",
1324                         nv->value, line);
1325                 return 1;
1326         }
1327         config->tcp_listen_queue = (unsigned int)i;
1328         return 0;
1329 #endif
1330 }
1331
1332
1333 static int tcp_max_per_addr_parser(struct nv_pair *nv, int line,
1334         struct daemon_conf *config)
1335 {
1336         const char *ptr = nv->value;
1337         unsigned long i;
1338
1339         audit_msg(LOG_DEBUG, "tcp_max_per_addr_parser called with: %s",
1340                   nv->value);
1341
1342 #ifndef USE_LISTENER
1343         audit_msg(LOG_DEBUG,
1344                 "Listener support is not enabled, ignoring value at line %d",
1345                 line);
1346         return 0;
1347 #else
1348         /* check that all chars are numbers */
1349         for (i=0; ptr[i]; i++) {
1350                 if (!isdigit(ptr[i])) {
1351                         audit_msg(LOG_ERR, 
1352                                 "Value %s should only be numbers - line %d",
1353                                 nv->value, line);
1354                         return 1;
1355                 }
1356         }
1357
1358         /* convert to unsigned int */
1359         errno = 0;
1360         i = strtoul(nv->value, NULL, 10);
1361         if (errno) {
1362                 audit_msg(LOG_ERR, 
1363                         "Error converting string to a number (%s) - line %d",
1364                         strerror(errno), line);
1365                 return 1;
1366         }
1367         /* Check its range.  While this value is technically
1368            unlimited, it's limited by the kernel, and we limit it here
1369            for sanity. */
1370         if (i > 1024) {
1371                 audit_msg(LOG_ERR, 
1372                         "Error - converted number (%s) is too large - line %d",
1373                         nv->value, line);
1374                 return 1;
1375         }
1376         if (i < 1) {
1377                 audit_msg(LOG_ERR, 
1378                         "Error - converted number (%s) is too small - line %d",
1379                         nv->value, line);
1380                 return 1;
1381         }
1382         config->tcp_max_per_addr = (unsigned int)i;
1383         return 0;
1384 #endif
1385 }
1386
1387 static int use_libwrap_parser(struct nv_pair *nv, int line,
1388         struct daemon_conf *config)
1389 {
1390         unsigned long i;
1391
1392         audit_msg(LOG_DEBUG, "use_libwrap_parser called with: %s",
1393                   nv->value);
1394
1395         for (i=0; yes_no_values[i].name != NULL; i++) {
1396                 if (strcasecmp(nv->value, yes_no_values[i].name) == 0) {
1397                         config->use_libwrap = yes_no_values[i].option;
1398                         return 0;
1399                 }
1400         }
1401         audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line);
1402         return 1;
1403 }
1404
1405 static int tcp_client_ports_parser(struct nv_pair *nv, int line,
1406         struct daemon_conf *config)
1407 {
1408         const char *ptr = nv->value;
1409         unsigned long i, minv, maxv;
1410         const char *saw_dash = NULL;
1411
1412         audit_msg(LOG_DEBUG, "tcp_listen_queue_parser called with: %s",
1413                   nv->value);
1414
1415 #ifndef USE_LISTENER
1416         audit_msg(LOG_DEBUG,
1417                 "Listener support is not enabled, ignoring value at line %d",
1418                 line);
1419         return 0;
1420 #else
1421         /* check that all chars are numbers, with an optional inclusive '-'. */
1422         for (i=0; ptr[i]; i++) {
1423                 if (i > 0 && ptr[i] == '-' && ptr[i+1] != '\0') {
1424                         saw_dash = ptr + i;
1425                         continue;
1426                 }
1427                 if (!isdigit(ptr[i])) {
1428                         audit_msg(LOG_ERR, 
1429                                 "Value %s should only be numbers, or "
1430                                 "two numbers separated by a dash - line %d",
1431                                 nv->value, line);
1432                         return 1;
1433                 }
1434         }
1435         for (; ptr[i]; i++) {
1436                 if (!isdigit(ptr[i])) {
1437                         audit_msg(LOG_ERR, 
1438                                 "Value %s should only be numbers, or "
1439                                 "two numbers separated by a dash - line %d",
1440                                 nv->value, line);
1441                         return 1;
1442                 }
1443         }
1444
1445         /* convert to unsigned int */
1446         errno = 0;
1447         maxv = minv = strtoul(nv->value, NULL, 10);
1448         if (errno) {
1449                 audit_msg(LOG_ERR, 
1450                         "Error converting string to a number (%s) - line %d",
1451                         strerror(errno), line);
1452                 return 1;
1453         }
1454         if (saw_dash) {
1455                 maxv = strtoul(saw_dash + 1, NULL, 10);
1456                 if (errno) {
1457                         audit_msg(LOG_ERR, 
1458                           "Error converting string to a number (%s) - line %d",
1459                                   strerror(errno), line);
1460                         return 1;
1461                 }
1462         }
1463         /* Check their ranges. */
1464         if (minv > TCP_PORT_MAX) {
1465                 audit_msg(LOG_ERR, 
1466                         "Error - converted number (%ld) is too large - line %d",
1467                           minv, line);
1468                 return 1;
1469         }
1470         if (maxv > TCP_PORT_MAX) {
1471                 audit_msg(LOG_ERR, 
1472                         "Error - converted number (%ld) is too large - line %d",
1473                           maxv, line);
1474                 return 1;
1475         }
1476         if (minv > maxv) {
1477                 audit_msg(LOG_ERR, 
1478                      "Error - converted range (%ld-%ld) is reversed - line %d",
1479                           minv, maxv, line);
1480                 return 1;
1481         }
1482         config->tcp_client_min_port = (unsigned int)minv;
1483         config->tcp_client_max_port = (unsigned int)maxv;
1484         return 0;
1485 #endif
1486 }
1487
1488 static int tcp_client_max_idle_parser(struct nv_pair *nv, int line,
1489         struct daemon_conf *config)
1490 {
1491         const char *ptr = nv->value;
1492         unsigned long i;
1493
1494         audit_msg(LOG_DEBUG, "tcp_client_max_idle_parser called with: %s",
1495                   nv->value);
1496
1497 #ifndef USE_LISTENER
1498         audit_msg(LOG_DEBUG,
1499                 "Listener support is not enabled, ignoring value at line %d",
1500                 line);
1501         return 0;
1502 #else
1503         /* check that all chars are numbers */
1504         for (i=0; ptr[i]; i++) {
1505                 if (!isdigit(ptr[i])) {
1506                         audit_msg(LOG_ERR, 
1507                                 "Value %s should only be numbers - line %d",
1508                                 nv->value, line);
1509                         return 1;
1510                 }
1511         }
1512
1513         /* convert to unsigned int */
1514         errno = 0;
1515         i = strtoul(nv->value, NULL, 10);
1516         if (errno) {
1517                 audit_msg(LOG_ERR, 
1518                         "Error converting string to a number (%s) - line %d",
1519                         strerror(errno), line);
1520                 return 1;
1521         }
1522         /* Check its range.  While this value is technically
1523            unlimited, it's limited by the kernel, and we limit it here
1524            for sanity. */
1525         if (i > INT_MAX) {
1526                 audit_msg(LOG_ERR, 
1527                         "Error - converted number (%s) is too large - line %d",
1528                         nv->value, line);
1529                 return 1;
1530         }
1531         config->tcp_client_max_idle = (unsigned int)i;
1532         return 0;
1533 #endif
1534 }
1535
1536 static int enable_krb5_parser(struct nv_pair *nv, int line,
1537         struct daemon_conf *config)
1538 {
1539         audit_msg(LOG_DEBUG, "enable_krb5_parser called with: %s",
1540                   nv->value);
1541
1542 #ifndef USE_GSSAPI
1543         audit_msg(LOG_DEBUG,
1544                 "GSSAPI support is not enabled, ignoring value at line %d",
1545                 line);
1546         return 0;
1547 #else
1548         unsigned long i;
1549
1550         for (i=0; yes_no_values[i].name != NULL; i++) {
1551                 if (strcasecmp(nv->value, yes_no_values[i].name) == 0) {
1552                         config->enable_krb5 = yes_no_values[i].option;
1553                         return 0;
1554                 }
1555         }
1556         audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line);
1557         return 1;
1558 #endif
1559 }
1560
1561 static int krb5_principal_parser(struct nv_pair *nv, int line,
1562         struct daemon_conf *config)
1563 {
1564         audit_msg(LOG_DEBUG,"krb5_principal_parser called with: %s",nv->value);
1565 #ifndef USE_GSSAPI
1566         audit_msg(LOG_DEBUG,
1567                 "GSSAPI support is not enabled, ignoring value at line %d",
1568                 line);
1569 #else
1570         config->krb5_principal = strdup(nv->value);
1571 #endif
1572         return 0;
1573 }
1574
1575 static int krb5_key_file_parser(struct nv_pair *nv, int line,
1576         struct daemon_conf *config)
1577 {
1578         audit_msg(LOG_DEBUG, "krb5_key_file_parser called with: %s", nv->value);
1579 #ifndef USE_GSSAPI
1580         audit_msg(LOG_DEBUG,
1581                 "GSSAPI support is not enabled, ignoring value at line %d",
1582                 line);
1583 #else
1584         config->krb5_key_file = strdup(nv->value);
1585 #endif
1586         return 0;
1587 }
1588
1589 /*
1590  * This function is where we do the integrated check of the audit config
1591  * options. At this point, all fields have been read. Returns 0 if no
1592  * problems and 1 if problems detected.
1593  */
1594 static int sanity_check(struct daemon_conf *config)
1595 {
1596         /* Error checking */
1597         if (config->space_left <= config->admin_space_left) {
1598                 audit_msg(LOG_ERR, 
1599             "Error - space_left(%lu) must be larger than admin_space_left(%lu)",
1600                     config->space_left, config->admin_space_left);
1601                 return 1;
1602         }
1603         if (config->flush == FT_INCREMENTAL && config->freq == 0) {
1604                 audit_msg(LOG_ERR, 
1605                 "Error - incremental flushing chosen, but 0 selected for freq");
1606                 return 1;
1607         }
1608         /* Warnings */
1609         if (config->flush > FT_INCREMENTAL && config->freq != 0) {
1610                 audit_msg(LOG_WARNING, 
1611            "Warning - freq is non-zero and incremental flushing not selected.");
1612         }
1613         return 0;
1614 }
1615
1616 const char *audit_lookup_format(int fmt)
1617 {
1618         int i;
1619
1620         for (i=0; log_formats[i].name != NULL; i++) {
1621                 if (log_formats[i].option == fmt)
1622                         return log_formats[i].name;
1623         }
1624         return NULL;
1625 }
1626
1627 int create_log_file(const char *val)
1628 {
1629         int fd;
1630
1631         umask(S_IRWXO);
1632         fd = open(val, O_CREAT|O_EXCL|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP);
1633         if (fd < 0) 
1634                 audit_msg(LOG_ERR, "Unable to create %s (%s)", val,
1635                         strerror(errno));
1636         return fd;
1637 }
1638
1639 void free_config(struct daemon_conf *config)
1640 {
1641         free((void *)config->sender_ctx);
1642         free((void *)config->log_file);
1643         free((void *)config->dispatcher);
1644         free((void *)config->node_name);
1645         free((void *)config->action_mail_acct);
1646         free((void *)config->space_left_exe);
1647         free((void *)config->admin_space_left_exe);
1648         free((void *)config->disk_full_exe);
1649         free((void *)config->disk_error_exe);
1650         free((void *)config->krb5_principal);
1651         free((void *)config->krb5_key_file);
1652 }
1653
1654 int resolve_node(struct daemon_conf *config)
1655 {
1656         int rc = 0;
1657         char tmp_name[255];
1658
1659         /* Get the host name representation */
1660         switch (config->node_name_format)
1661         {
1662                 case N_NONE:
1663                         break;
1664                 case N_HOSTNAME:
1665                         if (gethostname(tmp_name, sizeof(tmp_name))) {
1666                                 audit_msg(LOG_ERR,
1667                                         "Unable to get machine name");
1668                                 rc = -1;
1669                         } else
1670                                 config->node_name = strdup(tmp_name);
1671                         break;
1672                 case N_USER:
1673                         if (config->node_name == NULL) {
1674                                 audit_msg(LOG_ERR, "User defined name missing");
1675                                 rc = -1;
1676                         }
1677                         break;
1678                 case N_FQD:
1679                         if (gethostname(tmp_name, sizeof(tmp_name))) {
1680                                 audit_msg(LOG_ERR,
1681                                         "Unable to get machine name");
1682                                 rc = -1;
1683                         } else {
1684                                 int rc2;
1685                                 struct addrinfo *ai;
1686                                 struct addrinfo hints;
1687
1688                                 memset(&hints, 0, sizeof(hints));
1689                                 hints.ai_flags = AI_ADDRCONFIG | AI_CANONNAME;
1690                                 hints.ai_socktype = SOCK_STREAM;
1691
1692                                 rc2 = getaddrinfo(tmp_name, NULL, &hints, &ai);
1693                                 if (rc2 != 0) {
1694                                         audit_msg(LOG_ERR,
1695                                         "Cannot resolve hostname %s (%s)",
1696                                         tmp_name, gai_strerror(rc));
1697                                         rc = -1;
1698                                         break;
1699                                 }
1700                                 config->node_name = strdup(ai->ai_canonname);
1701                                 freeaddrinfo(ai);
1702                         }
1703                         break;
1704                 case N_NUMERIC:
1705                         if (gethostname(tmp_name, sizeof(tmp_name))) {
1706                                 audit_msg(LOG_ERR,
1707                                                 "Unable to get machine name");
1708                                 rc = -1;
1709                         } else {
1710                                 int rc2;
1711                                 struct addrinfo *ai;
1712                                 struct addrinfo hints;
1713
1714                                 audit_msg(LOG_DEBUG,
1715                                         "Resolving numeric address for %s",
1716                                         tmp_name);
1717                                 memset(&hints, 0, sizeof(hints));
1718                                 hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
1719                                 hints.ai_socktype = SOCK_STREAM;
1720
1721                                 rc2 = getaddrinfo(tmp_name, NULL, &hints, &ai);
1722                                 if (rc2) {
1723                                         audit_msg(LOG_ERR,
1724                                         "Cannot resolve hostname %s (%s)",
1725                                         tmp_name, gai_strerror(rc2));
1726                                         rc = -1;
1727                                         break;
1728                                 }
1729                                 inet_ntop(ai->ai_family,
1730                                                 ai->ai_family == AF_INET ?
1731                 (void *) &((struct sockaddr_in *)ai->ai_addr)->sin_addr :
1732                 (void *) &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr,
1733                                                 tmp_name, INET6_ADDRSTRLEN);
1734                                 freeaddrinfo(ai);
1735                                 config->node_name = strdup(tmp_name);
1736                         }
1737                         break;
1738         }
1739         if (rc == 0 && config->node_name)
1740                 audit_msg(LOG_DEBUG, "Resolved node name: %s",
1741                                 config->node_name);
1742         return rc;
1743 }
1744