summaryrefslogtreecommitdiffstats
path: root/lib/parse_ini.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/parse_ini.c')
-rw-r--r--lib/parse_ini.c239
1 files changed, 145 insertions, 94 deletions
diff --git a/lib/parse_ini.c b/lib/parse_ini.c
index 1289aae2..db337622 100644
--- a/lib/parse_ini.c
+++ b/lib/parse_ini.c
@@ -40,26 +40,29 @@ typedef struct {
40 char *stanza; 40 char *stanza;
41} np_ini_info; 41} np_ini_info;
42 42
43static char *default_ini_file_names[] = {"monitoring-plugins.ini", "plugins.ini", "nagios-plugins.ini", NULL}; 43static char *default_ini_file_names[] = {"monitoring-plugins.ini", "plugins.ini",
44 "nagios-plugins.ini", NULL};
44 45
45static char *default_ini_path_names[] = { 46static char *default_ini_path_names[] = {
46 "/usr/local/etc/monitoring-plugins/monitoring-plugins.ini", "/usr/local/etc/monitoring-plugins.ini", 47 "/usr/local/etc/monitoring-plugins/monitoring-plugins.ini",
47 "/etc/monitoring-plugins/monitoring-plugins.ini", "/etc/monitoring-plugins.ini", 48 "/usr/local/etc/monitoring-plugins.ini", "/etc/monitoring-plugins/monitoring-plugins.ini",
49 "/etc/monitoring-plugins.ini",
48 /* deprecated path names (for backward compatibility): */ 50 /* deprecated path names (for backward compatibility): */
49 "/etc/nagios/plugins.ini", "/usr/local/nagios/etc/plugins.ini", "/usr/local/etc/nagios/plugins.ini", "/etc/opt/nagios/plugins.ini", 51 "/etc/nagios/plugins.ini", "/usr/local/nagios/etc/plugins.ini",
50 "/etc/nagios-plugins.ini", "/usr/local/etc/nagios-plugins.ini", "/etc/opt/nagios-plugins.ini", NULL}; 52 "/usr/local/etc/nagios/plugins.ini", "/etc/opt/nagios/plugins.ini", "/etc/nagios-plugins.ini",
53 "/usr/local/etc/nagios-plugins.ini", "/etc/opt/nagios-plugins.ini", NULL};
51 54
52/* eat all characters from a FILE pointer until n is encountered */ 55/* eat all characters from a FILE pointer until n is encountered */
53#define GOBBLE_TO(f, c, n) \ 56#define GOBBLE_TO(f, c, n) \
54 do { \ 57 do { \
55 (c) = fgetc((f)); \ 58 (c) = fgetc((f)); \
56 } while ((c) != EOF && (c) != (n)) 59 } while ((c) != EOF && (c) != (n))
57 60
58/* internal function that returns the constructed defaults options */ 61/* internal function that returns the constructed defaults options */
59static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts); 62static bool read_defaults(FILE *defaults_file, const char *stanza, np_arg_list **opts);
60 63
61/* internal function that converts a single line into options format */ 64/* internal function that converts a single line into options format */
62static int add_option(FILE *f, np_arg_list **optlst); 65static int add_option(FILE *filePointer, np_arg_list **optlst);
63 66
64/* internal functions to find default file */ 67/* internal functions to find default file */
65static char *default_file(void); 68static char *default_file(void);
@@ -71,7 +74,8 @@ static char *default_file_in_path(void);
71 * into its separate parts. 74 * into its separate parts.
72 */ 75 */
73static void parse_locator(const char *locator, const char *def_stanza, np_ini_info *i) { 76static void parse_locator(const char *locator, const char *def_stanza, np_ini_info *i) {
74 size_t locator_len = 0, stanza_len = 0; 77 size_t locator_len = 0;
78 size_t stanza_len = 0;
75 79
76 /* if locator is NULL we'll use default values */ 80 /* if locator is NULL we'll use default values */
77 if (locator != NULL) { 81 if (locator != NULL) {
@@ -87,8 +91,9 @@ static void parse_locator(const char *locator, const char *def_stanza, np_ini_in
87 i->stanza = strdup(def_stanza); 91 i->stanza = strdup(def_stanza);
88 } 92 }
89 93
90 if (i->stanza == NULL) 94 if (i->stanza == NULL) {
91 die(STATE_UNKNOWN, _("malloc() failed!\n")); 95 die(STATE_UNKNOWN, _("malloc() failed!\n"));
96 }
92 97
93 /* check whether there's an @file part */ 98 /* check whether there's an @file part */
94 if (stanza_len == locator_len) { 99 if (stanza_len == locator_len) {
@@ -99,39 +104,46 @@ static void parse_locator(const char *locator, const char *def_stanza, np_ini_in
99 i->file_string_on_heap = true; 104 i->file_string_on_heap = true;
100 } 105 }
101 106
102 if (i->file == NULL || i->file[0] == '\0') 107 if (i->file == NULL || i->file[0] == '\0') {
103 die(STATE_UNKNOWN, _("Cannot find config file in any standard location.\n")); 108 die(STATE_UNKNOWN, _("Cannot find config file in any standard location.\n"));
109 }
104} 110}
105 111
106/* 112/*
107 * This is the externally visible function used by extra_opts. 113 * This is the externally visible function used by extra_opts.
108 */ 114 */
109np_arg_list *np_get_defaults(const char *locator, const char *default_section) { 115np_arg_list *np_get_defaults(const char *locator, const char *default_section) {
110 FILE *inifile = NULL;
111 np_arg_list *defaults = NULL;
112 np_ini_info i;
113 int is_suid_plugin = mp_suid(); 116 int is_suid_plugin = mp_suid();
114 117
115 if (is_suid_plugin && idpriv_temp_drop() == -1) 118 if (is_suid_plugin && idpriv_temp_drop() == -1) {
116 die(STATE_UNKNOWN, _("Cannot drop privileges: %s\n"), strerror(errno)); 119 die(STATE_UNKNOWN, _("Cannot drop privileges: %s\n"), strerror(errno));
120 }
117 121
118 parse_locator(locator, default_section, &i); 122 FILE *inifile = NULL;
119 inifile = strcmp(i.file, "-") == 0 ? stdin : fopen(i.file, "r"); 123 np_ini_info ini_info;
124 parse_locator(locator, default_section, &ini_info);
125 inifile = strcmp(ini_info.file, "-") == 0 ? stdin : fopen(ini_info.file, "r");
120 126
121 if (inifile == NULL) 127 if (inifile == NULL) {
122 die(STATE_UNKNOWN, _("Can't read config file: %s\n"), strerror(errno)); 128 die(STATE_UNKNOWN, _("Can't read config file: %s\n"), strerror(errno));
123 if (!read_defaults(inifile, i.stanza, &defaults)) 129 }
124 die(STATE_UNKNOWN, _("Invalid section '%s' in config file '%s'\n"), i.stanza, i.file);
125 130
126 if (i.file_string_on_heap) { 131 np_arg_list *defaults = NULL;
127 free(i.file); 132 if (!read_defaults(inifile, ini_info.stanza, &defaults)) {
133 die(STATE_UNKNOWN, _("Invalid section '%s' in config file '%s'\n"), ini_info.stanza, ini_info.file);
134 }
135
136 if (ini_info.file_string_on_heap) {
137 free(ini_info.file);
128 } 138 }
129 139
130 if (inifile != stdin) 140 if (inifile != stdin) {
131 fclose(inifile); 141 fclose(inifile);
132 free(i.stanza); 142 }
133 if (is_suid_plugin && idpriv_temp_restore() == -1) 143 free(ini_info.stanza);
144 if (is_suid_plugin && idpriv_temp_restore() == -1) {
134 die(STATE_UNKNOWN, _("Cannot restore privileges: %s\n"), strerror(errno)); 145 die(STATE_UNKNOWN, _("Cannot restore privileges: %s\n"), strerror(errno));
146 }
135 147
136 return defaults; 148 return defaults;
137} 149}
@@ -143,54 +155,58 @@ np_arg_list *np_get_defaults(const char *locator, const char *default_section) {
143 * be extra careful about user-supplied input (i.e. avoiding possible 155 * be extra careful about user-supplied input (i.e. avoiding possible
144 * format string vulnerabilities, etc). 156 * format string vulnerabilities, etc).
145 */ 157 */
146static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts) { 158static bool read_defaults(FILE *defaults_file, const char *stanza, np_arg_list **opts) {
147 int c = 0;
148 bool status = false; 159 bool status = false;
149 size_t i, stanza_len;
150 enum { 160 enum {
151 NOSTANZA, 161 NOSTANZA,
152 WRONGSTANZA, 162 WRONGSTANZA,
153 RIGHTSTANZA 163 RIGHTSTANZA
154 } stanzastate = NOSTANZA; 164 } stanzastate = NOSTANZA;
155 165
156 stanza_len = strlen(stanza); 166 size_t stanza_len = strlen(stanza);
157 167
158 /* our little stanza-parsing state machine */ 168 /* our little stanza-parsing state machine */
159 while ((c = fgetc(f)) != EOF) { 169 int current_char = 0;
170 while ((current_char = fgetc(defaults_file)) != EOF) {
160 /* gobble up leading whitespace */ 171 /* gobble up leading whitespace */
161 if (isspace(c)) 172 if (isspace(current_char)) {
162 continue; 173 continue;
163 switch (c) { 174 }
175 switch (current_char) {
164 /* globble up comment lines */ 176 /* globble up comment lines */
165 case ';': 177 case ';':
166 case '#': 178 case '#':
167 GOBBLE_TO(f, c, '\n'); 179 GOBBLE_TO(defaults_file, current_char, '\n');
168 break; 180 break;
169 /* start of a stanza, check to see if it matches */ 181 /* start of a stanza, check to see if it matches */
170 case '[': 182 case '[': {
171 stanzastate = WRONGSTANZA; 183 stanzastate = WRONGSTANZA;
184 size_t i;
172 for (i = 0; i < stanza_len; i++) { 185 for (i = 0; i < stanza_len; i++) {
173 c = fgetc(f); 186 current_char = fgetc(defaults_file);
174 /* strip leading whitespace */ 187 /* strip leading whitespace */
175 if (i == 0) 188 if (i == 0) {
176 for (; isspace(c); c = fgetc(f)) 189 for (; isspace(current_char); current_char = fgetc(defaults_file)) {
177 continue; 190 }
191 }
178 /* nope, read to the end of the line */ 192 /* nope, read to the end of the line */
179 if (c != stanza[i]) { 193 if (current_char != stanza[i]) {
180 GOBBLE_TO(f, c, '\n'); 194 GOBBLE_TO(defaults_file, current_char, '\n');
181 break; 195 break;
182 } 196 }
183 } 197 }
198
184 /* if it matched up to here and the next char is ']'... */ 199 /* if it matched up to here and the next char is ']'... */
185 if (i == stanza_len) { 200 if (i == stanza_len) {
186 c = fgetc(f); 201 current_char = fgetc(defaults_file);
187 /* strip trailing whitespace */ 202 /* strip trailing whitespace */
188 for (; isspace(c); c = fgetc(f)) 203 for (; isspace(current_char); current_char = fgetc(defaults_file)) {
189 continue; 204 }
190 if (c == ']') 205 if (current_char == ']') {
191 stanzastate = RIGHTSTANZA; 206 stanzastate = RIGHTSTANZA;
207 }
192 } 208 }
193 break; 209 } break;
194 /* otherwise, we're in the body of a stanza or a parse error */ 210 /* otherwise, we're in the body of a stanza or a parse error */
195 default: 211 default:
196 switch (stanzastate) { 212 switch (stanzastate) {
@@ -201,12 +217,12 @@ static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts) {
201 die(STATE_UNKNOWN, "%s\n", _("Config file error")); 217 die(STATE_UNKNOWN, "%s\n", _("Config file error"));
202 /* we're in a stanza, but for a different plugin */ 218 /* we're in a stanza, but for a different plugin */
203 case WRONGSTANZA: 219 case WRONGSTANZA:
204 GOBBLE_TO(f, c, '\n'); 220 GOBBLE_TO(defaults_file, current_char, '\n');
205 break; 221 break;
206 /* okay, this is where we start taking the config */ 222 /* okay, this is where we start taking the config */
207 case RIGHTSTANZA: 223 case RIGHTSTANZA:
208 ungetc(c, f); 224 ungetc(current_char, defaults_file);
209 if (add_option(f, opts)) { 225 if (add_option(defaults_file, opts)) {
210 die(STATE_UNKNOWN, "%s\n", _("Config file error")); 226 die(STATE_UNKNOWN, "%s\n", _("Config file error"));
211 } 227 }
212 status = true; 228 status = true;
@@ -225,13 +241,12 @@ static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts) {
225 * --option[=value] 241 * --option[=value]
226 * appending it to the linked list optbuf. 242 * appending it to the linked list optbuf.
227 */ 243 */
228static int add_option(FILE *f, np_arg_list **optlst) { 244static int add_option(FILE *filePointer, np_arg_list **optlst) {
229 np_arg_list *opttmp = *optlst, *optnew; 245 char *linebuf = NULL;
230 char *linebuf = NULL, *lineend = NULL, *optptr = NULL, *optend = NULL; 246 bool done_reading = false;
231 char *eqptr = NULL, *valptr = NULL, *valend = NULL; 247 const size_t read_sz = 8;
232 short done_reading = 0, equals = 0, value = 0; 248 size_t linebuf_sz = 0;
233 size_t cfg_len = 0, read_sz = 8, linebuf_sz = 0, read_pos = 0; 249 size_t read_pos = 0;
234 size_t opt_len = 0, val_len = 0;
235 250
236 /* read one line from the file */ 251 /* read one line from the file */
237 while (!done_reading) { 252 while (!done_reading) {
@@ -239,74 +254,101 @@ static int add_option(FILE *f, np_arg_list **optlst) {
239 if (linebuf == NULL || read_pos + read_sz >= linebuf_sz) { 254 if (linebuf == NULL || read_pos + read_sz >= linebuf_sz) {
240 linebuf_sz = linebuf_sz > 0 ? linebuf_sz << 1 : read_sz; 255 linebuf_sz = linebuf_sz > 0 ? linebuf_sz << 1 : read_sz;
241 linebuf = realloc(linebuf, linebuf_sz); 256 linebuf = realloc(linebuf, linebuf_sz);
242 if (linebuf == NULL) 257 if (linebuf == NULL) {
243 die(STATE_UNKNOWN, _("malloc() failed!\n")); 258 die(STATE_UNKNOWN, _("malloc() failed!\n"));
259 }
244 } 260 }
245 if (fgets(&linebuf[read_pos], (int)read_sz, f) == NULL) 261
246 done_reading = 1; 262 if (fgets(&linebuf[read_pos], (int)read_sz, filePointer) == NULL) {
247 else { 263 done_reading = true;
264 } else {
248 read_pos = strlen(linebuf); 265 read_pos = strlen(linebuf);
249 if (linebuf[read_pos - 1] == '\n') { 266 if (linebuf[read_pos - 1] == '\n') {
250 linebuf[--read_pos] = '\0'; 267 linebuf[--read_pos] = '\0';
251 done_reading = 1; 268 done_reading = true;
252 } 269 }
253 } 270 }
254 } 271 }
255 lineend = &linebuf[read_pos]; 272
273 char *lineend = &linebuf[read_pos];
256 /* all that to read one line, isn't C fun? :) now comes the parsing :/ */ 274 /* all that to read one line, isn't C fun? :) now comes the parsing :/ */
257 275
258 /* skip leading whitespace */ 276 /* skip leading whitespace */
259 for (optptr = linebuf; optptr < lineend && isspace(*optptr); optptr++) 277 char *optptr = NULL;
260 continue; 278 for (optptr = linebuf; optptr < lineend && isspace(*optptr); optptr++) {
279 }
280
261 /* continue to '=' or EOL, watching for spaces that might precede it */ 281 /* continue to '=' or EOL, watching for spaces that might precede it */
282 char *eqptr = NULL;
283 char *optend = NULL;
262 for (eqptr = optptr; eqptr < lineend && *eqptr != '='; eqptr++) { 284 for (eqptr = optptr; eqptr < lineend && *eqptr != '='; eqptr++) {
263 if (isspace(*eqptr) && optend == NULL) 285 if (isspace(*eqptr) && optend == NULL) {
264 optend = eqptr; 286 optend = eqptr;
265 else 287 } else {
266 optend = NULL; 288 optend = NULL;
289 }
267 } 290 }
268 if (optend == NULL) 291
292 if (optend == NULL) {
269 optend = eqptr; 293 optend = eqptr;
294 }
295
270 --optend; 296 --optend;
297
271 /* ^[[:space:]]*=foo is a syntax error */ 298 /* ^[[:space:]]*=foo is a syntax error */
272 if (optptr == eqptr) 299 if (optptr == eqptr) {
273 die(STATE_UNKNOWN, "%s\n", _("Config file error")); 300 die(STATE_UNKNOWN, "%s\n", _("Config file error"));
301 }
302
274 /* continue from '=' to start of value or EOL */ 303 /* continue from '=' to start of value or EOL */
275 for (valptr = eqptr + 1; valptr < lineend && isspace(*valptr); valptr++) 304 char *valptr = NULL;
276 continue; 305 for (valptr = eqptr + 1; valptr < lineend && isspace(*valptr); valptr++) {
306 }
307
277 /* continue to the end of value */ 308 /* continue to the end of value */
278 for (valend = valptr; valend < lineend; valend++) 309 char *valend = NULL;
279 continue; 310 for (valend = valptr; valend < lineend; valend++) {
311 }
312
280 --valend; 313 --valend;
314
281 /* finally trim off trailing spaces */ 315 /* finally trim off trailing spaces */
282 for (; isspace(*valend); valend--) 316 for (; isspace(*valend); valend--) {
283 continue; 317 }
318
284 /* calculate the length of "--foo" */ 319 /* calculate the length of "--foo" */
285 opt_len = (size_t)(1 + optend - optptr); 320 size_t opt_len = (size_t)(1 + optend - optptr);
286 /* 1-character params needs only one dash */ 321 /* 1-character params needs only one dash */
287 if (opt_len == 1) 322 size_t cfg_len = 0;
323 if (opt_len == 1) {
288 cfg_len = 1 + (opt_len); 324 cfg_len = 1 + (opt_len);
289 else 325 } else {
290 cfg_len = 2 + (opt_len); 326 cfg_len = 2 + (opt_len);
327 }
328
329 size_t val_len = 0;
330 bool equals = false;
331 bool value = false;
291 /* if valptr<lineend then we have to also allocate space for "=bar" */ 332 /* if valptr<lineend then we have to also allocate space for "=bar" */
292 if (valptr < lineend) { 333 if (valptr < lineend) {
293 equals = value = 1; 334 equals = value = true;
294 val_len = (size_t)(1 + valend - valptr); 335 val_len = (size_t)(1 + valend - valptr);
295 cfg_len += 1 + val_len; 336 cfg_len += 1 + val_len;
296 } 337 } else if (valptr == lineend) {
297 /* if valptr==valend then we have "=" but no "bar" */ 338 /* if valptr==valend then we have "=" but no "bar" */
298 else if (valptr == lineend) { 339 equals = true;
299 equals = 1;
300 cfg_len += 1; 340 cfg_len += 1;
301 } 341 }
342
302 /* a line with no equal sign isn't valid */ 343 /* a line with no equal sign isn't valid */
303 if (equals == 0) 344 if (!equals) {
304 die(STATE_UNKNOWN, "%s\n", _("Config file error")); 345 die(STATE_UNKNOWN, "%s\n", _("Config file error"));
346 }
305 347
306 /* okay, now we have all the info we need, so we create a new np_arg_list 348 /* okay, now we have all the info we need, so we create a new np_arg_list
307 * element and set the argument... 349 * element and set the argument...
308 */ 350 */
309 optnew = malloc(sizeof(np_arg_list)); 351 np_arg_list *optnew = malloc(sizeof(np_arg_list));
310 optnew->next = NULL; 352 optnew->next = NULL;
311 353
312 read_pos = 0; 354 read_pos = 0;
@@ -329,11 +371,13 @@ static int add_option(FILE *f, np_arg_list **optlst) {
329 optnew->arg[read_pos] = '\0'; 371 optnew->arg[read_pos] = '\0';
330 372
331 /* ...and put that to the end of the list */ 373 /* ...and put that to the end of the list */
332 if (*optlst == NULL) 374 if (*optlst == NULL) {
333 *optlst = optnew; 375 *optlst = optnew;
334 else { 376 } else {
335 while (opttmp->next != NULL) 377 np_arg_list *opttmp = *optlst;
378 while (opttmp->next != NULL) {
336 opttmp = opttmp->next; 379 opttmp = opttmp->next;
380 }
337 opttmp->next = optnew; 381 opttmp->next = optnew;
338 } 382 }
339 383
@@ -344,7 +388,8 @@ static int add_option(FILE *f, np_arg_list **optlst) {
344static char *default_file(void) { 388static char *default_file(void) {
345 char *ini_file; 389 char *ini_file;
346 390
347 if ((ini_file = getenv("MP_CONFIG_FILE")) != NULL || (ini_file = default_file_in_path()) != NULL) { 391 if ((ini_file = getenv("MP_CONFIG_FILE")) != NULL ||
392 (ini_file = default_file_in_path()) != NULL) {
348 return ini_file; 393 return ini_file;
349 } 394 }
350 395
@@ -357,19 +402,25 @@ static char *default_file(void) {
357} 402}
358 403
359static char *default_file_in_path(void) { 404static char *default_file_in_path(void) {
360 char *config_path, **file; 405 char *config_path;
361 char *dir, *ini_file, *tokens; 406 char **file;
407 char *dir;
408 char *ini_file;
409 char *tokens;
362 410
363 if ((config_path = getenv("NAGIOS_CONFIG_PATH")) == NULL) 411 if ((config_path = getenv("NAGIOS_CONFIG_PATH")) == NULL) {
364 return NULL; 412 return NULL;
413 }
365 /* shall we spit out a warning that NAGIOS_CONFIG_PATH is deprecated? */ 414 /* shall we spit out a warning that NAGIOS_CONFIG_PATH is deprecated? */
366 415
367 if ((tokens = strdup(config_path)) == NULL) 416 if ((tokens = strdup(config_path)) == NULL) {
368 die(STATE_UNKNOWN, "%s\n", _("Insufficient Memory")); 417 die(STATE_UNKNOWN, "%s\n", _("Insufficient Memory"));
418 }
369 for (dir = strtok(tokens, ":"); dir != NULL; dir = strtok(NULL, ":")) { 419 for (dir = strtok(tokens, ":"); dir != NULL; dir = strtok(NULL, ":")) {
370 for (file = default_ini_file_names; *file != NULL; file++) { 420 for (file = default_ini_file_names; *file != NULL; file++) {
371 if ((asprintf(&ini_file, "%s/%s", dir, *file)) < 0) 421 if ((asprintf(&ini_file, "%s/%s", dir, *file)) < 0) {
372 die(STATE_UNKNOWN, "%s\n", _("Insufficient Memory")); 422 die(STATE_UNKNOWN, "%s\n", _("Insufficient Memory"));
423 }
373 if (access(ini_file, F_OK) == 0) { 424 if (access(ini_file, F_OK) == 0) {
374 free(tokens); 425 free(tokens);
375 return ini_file; 426 return ini_file;