Imported Upstream version 2.4.3
[platform/upstream/audit.git] / audisp / plugins / zos-remote / zos-remote-config.c
1 /***************************************************************************
2  *   Copyright (C) 2007 International Business Machines  Corp.             *
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                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  *                                                                         *
20  * Authors:                                                                *
21  *   Klaus Heinrich Kiwi <klausk@br.ibm.com>                               *
22  *   based on code by Steve Grubb <sgrubb@redhat.com>                      *
23  ***************************************************************************/
24
25 #include "zos-remote-config.h"
26
27 #include <string.h>
28 #include <stdio.h>
29 #include <fcntl.h>
30 #include <sys/stat.h>
31 #include <errno.h>
32 #include <ctype.h>
33 #include <unistd.h>
34 #include <stdlib.h>
35 #include "zos-remote-log.h"
36
37 /* Local prototypes */
38 struct nv_pair
39 {
40         const char *name;
41         const char *value;
42         const char *option;
43 };
44
45 struct kw_pair
46 {
47         const char *name;
48         int (*parser) (struct nv_pair *, int, plugin_conf_t *);
49         int max_options;
50 };
51
52 struct nv_list
53 {
54         const char *name;
55         int option;
56 };
57
58 static char *get_line(FILE *, char *);
59 static int nv_split(char *, struct nv_pair *);
60 static const struct kw_pair *kw_lookup(const char *);
61 static int server_parser(struct nv_pair *, int, plugin_conf_t *);
62 static int port_parser(struct nv_pair *, int, plugin_conf_t *);
63 static int timeout_parser(struct nv_pair *, int, plugin_conf_t *);
64 static int user_parser(struct nv_pair *, int, plugin_conf_t *);
65 static int password_parser(struct nv_pair *, int, plugin_conf_t *);
66 static int q_depth_parser(struct nv_pair *, int, plugin_conf_t *);
67 static int sanity_check(plugin_conf_t *, const char *);
68
69 static const struct kw_pair keywords[] = {
70         {"server", server_parser, 0},
71         {"port", port_parser, 0},
72         {"timeout", timeout_parser, 0},
73         {"user", user_parser, 0},
74         {"password", password_parser, 0},
75         {"q_depth", q_depth_parser, 0},
76         {NULL, NULL, 0}
77 };
78
79
80
81 /*
82  * Set everything to its default value
83 */
84 void plugin_clear_config(plugin_conf_t * c)
85 {
86         c->server = NULL;
87         c->port = 0;
88         c->user = NULL;
89         c->password = NULL;
90         c->timeout = 15;
91         c->q_depth = 64;
92         /* not re-setting counter */
93 }
94
95 int plugin_load_config(plugin_conf_t * c, const char *file)
96 {
97         int fd, rc, mode, lineno = 1;
98         struct stat st;
99         FILE *f;
100         char buf[128];
101
102         plugin_clear_config(c);
103
104         /* open the file */
105         mode = O_RDONLY;
106         rc = open(file, mode);
107         if (rc < 0) {
108                 if (errno != ENOENT) {
109                         log_err("Error opening %s (%s)", file,
110                                 strerror(errno));
111                         return 1;
112                 }
113                 log_warn("Config file %s doesn't exist, skipping", file);
114                 return 1;
115         }
116         fd = rc;
117
118         /* check the file's permissions: owned by root, not world anything,
119          * not symlink.
120          */
121         if (fstat(fd, &st) < 0) {
122                 log_err("Error fstat'ing config file (%s)",
123                         strerror(errno));
124                 close(fd);
125                 return 1;
126         }
127         if (st.st_uid != 0) {
128                 log_err("Error - %s isn't owned by root", file);
129                 close(fd);
130                 return 1;
131         }
132         if ((st.st_mode & (S_IRUSR | S_IWUSR | S_IRGRP)) !=
133             (S_IRUSR | S_IWUSR | S_IRGRP)) {
134                 log_err("%s permissions should be 0640", file);
135                 close(fd);
136                 return 1;
137         }
138         if (!S_ISREG(st.st_mode)) {
139                 log_err("Error - %s is not a regular file", file);
140                 close(fd);
141                 return 1;
142         }
143
144         /* it's ok, read line by line */
145         f = fdopen(fd, "r");
146         if (f == NULL) {
147                 log_err("Error - fdopen failed (%s)", strerror(errno));
148                 close(fd);
149                 return 1;
150         }
151
152         while (get_line(f, buf)) {
153                 /* convert line into name-value pair */
154                 const struct kw_pair *kw;
155                 struct nv_pair nv;
156
157                 rc = nv_split(buf, &nv);
158                 switch (rc) {
159                 case 0:        /* fine */
160                         break;
161                 case 1:        /* not the right number of tokens. */
162                         log_err("Wrong number of arguments for line %d in %s", lineno, file);
163                         break;
164                 case 2:        /* no '=' sign */
165                         log_err("Missing equal sign for line %d in %s",
166                                 lineno, file);
167                         break;
168                 default:       /* something else went wrong... */
169                         log_err("Unknown error for line %d in %s",
170                                 lineno, file);
171                         break;
172                 }
173                 if (nv.name == NULL) {
174                         lineno++;
175                         continue;
176                 }
177                 if (nv.value == NULL) {
178                         fclose(f);
179                         return 1;
180                 }
181
182                 /* identify keyword or error */
183                 kw = kw_lookup(nv.name);
184                 if (kw->name == NULL) {
185                         log_err("Unknown keyword \"%s\" in line %d of %s",
186                                 nv.name, lineno, file);
187                         fclose(f);
188                         return 1;
189                 }
190
191                 /* Check number of options */
192                 if (kw->max_options == 0 && nv.option != NULL) {
193                         log_err("Keyword \"%s\" has invalid option "
194                                 "\"%s\" in line %d of %s",
195                                 nv.name, nv.option, lineno, file);
196                         fclose(f);
197                         return 1;
198                 }
199
200                 /* dispatch to keyword's local parser */
201                 rc = kw->parser(&nv, lineno, c);
202                 if (rc != 0) {
203                         fclose(f);
204                         return 1;       /* local parser puts message out */
205                 }
206
207                 lineno++;
208         }
209
210         fclose(f);
211         c->name = strdup(basename(file));
212         if (lineno > 1)
213                 return sanity_check(c, file);
214         return 0;
215 }
216
217 static char *get_line(FILE * f, char *buf)
218 {
219         if (fgets_unlocked(buf, 128, f)) {
220                 /* remove newline */
221                 char *ptr = strchr(buf, 0x0a);
222
223                 if (ptr)
224                         *ptr = 0;
225                 return buf;
226         }
227         return NULL;
228 }
229
230 static int nv_split(char *buf, struct nv_pair *nv)
231 {
232         /* Get the name part */
233         char *ptr, *saved = NULL;
234
235         nv->name = NULL;
236         nv->value = NULL;
237         nv->option = NULL;
238         ptr = strtok_r(buf, " ", &saved);
239         if (ptr == NULL)
240                 return 0;       /* If there's nothing, go to next line */
241         if (ptr[0] == '#')
242                 return 0;       /* If there's a comment, go to next line */
243         nv->name = ptr;
244
245         /* Check for a '=' */
246         ptr = strtok_r(NULL, " ", &saved);
247         if (ptr == NULL)
248                 return 1;
249         if (strcmp(ptr, "=") != 0)
250                 return 2;
251
252         /* get the value */
253         ptr = strtok_r(NULL, " ", &saved);
254         if (ptr == NULL)
255                 return 1;
256         nv->value = ptr;
257
258         /* See if there's an option */
259         ptr = strtok_r(NULL, " ", &saved);
260         if (ptr) {
261                 nv->option = ptr;
262
263                 /* Make sure there's nothing else */
264                 ptr = strtok_r(NULL, " ", &saved);
265                 if (ptr)
266                         return 1;
267         }
268
269         /* Everything is OK */
270         return 0;
271 }
272
273 static const struct kw_pair *kw_lookup(const char *val)
274 {
275         int i = 0;
276
277         while (keywords[i].name != NULL) {
278                 if (strcasecmp(keywords[i].name, val) == 0)
279                         break;
280                 i++;
281         }
282         return &keywords[i];
283 }
284
285
286 static int server_parser(struct nv_pair *nv, int line, plugin_conf_t * c)
287 {
288
289         if (nv->value == NULL)
290                 c->server = NULL;
291         else
292                 c->server = strdup(nv->value);
293
294         return 0;
295 }
296
297 static int port_parser(struct nv_pair *nv, int line, plugin_conf_t * c)
298 {
299         const char *ptr = nv->value;
300         unsigned long i;
301
302         /* check that all chars are numbers */
303         for (i = 0; ptr[i]; i++) {
304                 if (!isdigit(ptr[i])) {
305                         log_err("Value %s should only be numbers - line %d", nv->value, line);
306                         return 1;
307                 }
308         }
309
310         /* convert to unsigned long */
311         errno = 0;
312         i = strtoul(nv->value, NULL, 10);
313         if (errno) {
314                 log_err("Error converting string to a number (%s) - line %d", strerror(errno), line);
315                 return 1;
316         }
317
318         c->port = i;
319         return 0;
320
321 }
322
323 static int timeout_parser(struct nv_pair *nv, int line, plugin_conf_t * c)
324 {
325         const char *ptr = nv->value;
326         unsigned long i;
327
328         /* check that all chars are numbers */
329         for (i = 0; ptr[i]; i++) {
330                 if (!isdigit(ptr[i])) {
331                         log_err("Value %s should only be numbers - line %d", nv->value, line);
332                         return 1;
333                 }
334         }
335
336         /* convert to unsigned long */
337         errno = 0;
338         i = strtoul(nv->value, NULL, 10);
339         if (errno) {
340                 log_err("Error converting string to a number (%s) - line %d", strerror(errno), line);
341                 return 1;
342         }
343
344         c->timeout = i;
345         return 0;
346
347 }
348
349
350 static int user_parser(struct nv_pair *nv, int line, plugin_conf_t * c)
351 {
352
353         if (nv->value == NULL)
354                 c->user = NULL;
355         else
356                 c->user = strdup(nv->value);
357
358         return 0;
359 }
360
361 static int password_parser(struct nv_pair *nv, int line, plugin_conf_t * c)
362 {
363
364         if (nv->value == NULL)
365                 c->password = NULL;
366         else
367                 c->password = strdup(nv->value);
368
369         return 0;
370 }
371
372 static int q_depth_parser(struct nv_pair *nv, int line, plugin_conf_t * c)
373 {
374         const char *ptr = nv->value;
375         unsigned long i;
376
377         /* check that all chars are numbers */
378         for (i = 0; ptr[i]; i++) {
379                 if (!isdigit(ptr[i])) {
380                         log_err("Value %s should only be numbers - line %d", nv->value, line);
381                         return 1;
382                 }
383         }
384
385         /* convert to unsigned long */
386         errno = 0;
387         i = strtoul(nv->value, NULL, 10);
388         if (errno) {
389                 log_err("Error converting string to a number (%s) - line %d", strerror(errno), line);
390                 return 1;
391         }
392         
393         if (i < 16 || i > 99999) {
394                 log_err("q_depth must be between 16 and 99999");
395                 return 1;
396         }
397
398         c->q_depth = i;
399         return 0;
400
401 }
402
403
404 /*
405  * Check configuration.At this point, all fields have been read. 
406  * Returns 0 if no problems and 1 if problems detected.
407  */
408 static int sanity_check(plugin_conf_t * c, const char *file)
409 {
410         /* Error checking */
411         if (!c->server) {
412                 log_err("Error - no server hostname given");
413                 return 1;
414         }
415
416         if (!c->user) {
417                 log_err("Error - no bind user given");
418                 return 1;
419         }
420
421         if (!c->password) {
422                 log_err("Error - no password given");
423                 return 1;
424         }
425         
426         if (!c->timeout) {
427                 log_err("Error - timeout can't be zero");
428                 return 1;
429         }
430         return 0;
431 }
432
433 void plugin_free_config(plugin_conf_t * c)
434 {
435
436         if (c == NULL)
437                 return;
438
439         free((void *) c->server);
440         free((void *) c->user);
441         free((void *) c->password);
442         free((void *) c->name);
443 }