diff options
author | Greg Cox <gcox@fibbsbozza.local> | 2014-07-29 18:52:12 -0400 |
---|---|---|
committer | Greg Cox <gcox@fibbsbozza.local> | 2014-07-29 18:52:12 -0400 |
commit | 4273dd06ff3e52094d6b267d00e8c51dd74de364 (patch) | |
tree | 425d127da5dbec7013999ed01b469fc3f72992d9 /lib | |
parent | f05e7016320f4671fbf86cc5abc277efea20f79e (diff) | |
parent | 6f3d5825b203b75aef8d68bf0d117e7a1a4c0616 (diff) | |
download | monitoring-plugins-4273dd06ff3e52094d6b267d00e8c51dd74de364.tar.gz |
Merge remote-tracking branch 'upstream/master'
Conflicts:
plugins/netutils.c
Diffstat (limited to 'lib')
-rw-r--r-- | lib/parse_ini.c | 492 | ||||
-rw-r--r-- | lib/parse_ini.h | 42 | ||||
-rw-r--r-- | lib/tests/test_utils.c | 8 | ||||
-rw-r--r-- | lib/utils_base.c | 17 | ||||
-rw-r--r-- | lib/utils_base.h | 3 | ||||
-rw-r--r-- | lib/utils_cmd.c | 3 |
6 files changed, 274 insertions, 291 deletions
diff --git a/lib/parse_ini.c b/lib/parse_ini.c index 76953e9e..25abc89b 100644 --- a/lib/parse_ini.c +++ b/lib/parse_ini.c | |||
@@ -22,16 +22,15 @@ | |||
22 | *****************************************************************************/ | 22 | *****************************************************************************/ |
23 | 23 | ||
24 | #include "common.h" | 24 | #include "common.h" |
25 | #include "idpriv.h" | ||
25 | #include "utils_base.h" | 26 | #include "utils_base.h" |
26 | #include "parse_ini.h" | 27 | #include "parse_ini.h" |
27 | #include <ctype.h> | ||
28 | 28 | ||
29 | #include <ctype.h> | ||
29 | #include <sys/types.h> | 30 | #include <sys/types.h> |
30 | #include <sys/stat.h> | 31 | #include <sys/stat.h> |
31 | #include <unistd.h> | 32 | #include <unistd.h> |
32 | 33 | ||
33 | /* TODO: die like N::P if config file is not found */ | ||
34 | |||
35 | /* np_ini_info contains the result of parsing a "locator" in the format | 34 | /* np_ini_info contains the result of parsing a "locator" in the format |
36 | * [stanza_name][@config_filename] (check_foo@/etc/foo.ini, for example) | 35 | * [stanza_name][@config_filename] (check_foo@/etc/foo.ini, for example) |
37 | */ | 36 | */ |
@@ -40,254 +39,314 @@ typedef struct { | |||
40 | char *stanza; | 39 | char *stanza; |
41 | } np_ini_info; | 40 | } np_ini_info; |
42 | 41 | ||
42 | static char *default_ini_file_names[] = { | ||
43 | "monitoring-plugins.ini", | ||
44 | "plugins.ini", | ||
45 | "nagios-plugins.ini", | ||
46 | NULL | ||
47 | }; | ||
48 | |||
49 | static char *default_ini_path_names[] = { | ||
50 | "/usr/local/etc/monitoring-plugins/monitoring-plugins.ini", | ||
51 | "/usr/local/etc/monitoring-plugins.ini", | ||
52 | "/etc/monitoring-plugins/monitoring-plugins.ini", | ||
53 | "/etc/monitoring-plugins.ini", | ||
54 | /* deprecated path names (for backward compatibility): */ | ||
55 | "/etc/nagios/plugins.ini", | ||
56 | "/usr/local/nagios/etc/plugins.ini", | ||
57 | "/usr/local/etc/nagios/plugins.ini", | ||
58 | "/etc/opt/nagios/plugins.ini", | ||
59 | "/etc/nagios-plugins.ini", | ||
60 | "/usr/local/etc/nagios-plugins.ini", | ||
61 | "/etc/opt/nagios-plugins.ini", | ||
62 | NULL | ||
63 | }; | ||
64 | |||
43 | /* eat all characters from a FILE pointer until n is encountered */ | 65 | /* eat all characters from a FILE pointer until n is encountered */ |
44 | #define GOBBLE_TO(f, c, n) do { (c)=fgetc((f)); } while((c)!=EOF && (c)!=(n)) | 66 | #define GOBBLE_TO(f, c, n) do { (c)=fgetc((f)); } while((c)!=EOF && (c)!=(n)) |
45 | 67 | ||
46 | /* internal function that returns the constructed defaults options */ | 68 | /* internal function that returns the constructed defaults options */ |
47 | static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts); | 69 | static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts); |
70 | |||
48 | /* internal function that converts a single line into options format */ | 71 | /* internal function that converts a single line into options format */ |
49 | static int add_option(FILE *f, np_arg_list **optlst); | 72 | static int add_option(FILE *f, np_arg_list **optlst); |
50 | /* internal function to find default file */ | ||
51 | static char* default_file(void); | ||
52 | /* internal function to test files access */ | ||
53 | static int test_file(const char* env, int len, const char* file, char* temp_file); | ||
54 | 73 | ||
55 | /* parse_locator decomposes a string of the form | 74 | /* internal functions to find default file */ |
75 | static char *default_file(void); | ||
76 | static char *default_file_in_path(void); | ||
77 | |||
78 | /* | ||
79 | * Parse_locator decomposes a string of the form | ||
56 | * [stanza][@filename] | 80 | * [stanza][@filename] |
57 | * into its seperate parts | 81 | * into its seperate parts. |
58 | */ | 82 | */ |
59 | static void parse_locator(const char *locator, const char *def_stanza, np_ini_info *i){ | 83 | static void |
60 | size_t locator_len=0, stanza_len=0; | 84 | parse_locator(const char *locator, const char *def_stanza, np_ini_info *i) |
85 | { | ||
86 | size_t locator_len = 0, stanza_len = 0; | ||
61 | 87 | ||
62 | /* if locator is NULL we'll use default values */ | 88 | /* if locator is NULL we'll use default values */ |
63 | if(locator){ | 89 | if (locator != NULL) { |
64 | locator_len=strlen(locator); | 90 | locator_len = strlen(locator); |
65 | stanza_len=strcspn(locator, "@"); | 91 | stanza_len = strcspn(locator, "@"); |
66 | } | 92 | } |
67 | /* if a non-default stanza is provided */ | 93 | /* if a non-default stanza is provided */ |
68 | if(stanza_len>0){ | 94 | if (stanza_len > 0) { |
69 | i->stanza=(char*)malloc(sizeof(char)*(stanza_len+1)); | 95 | i->stanza = malloc(sizeof(char) * (stanza_len + 1)); |
70 | strncpy(i->stanza, locator, stanza_len); | 96 | strncpy(i->stanza, locator, stanza_len); |
71 | i->stanza[stanza_len]='\0'; | 97 | i->stanza[stanza_len] = '\0'; |
72 | } else { /* otherwise we use the default stanza */ | 98 | } else /* otherwise we use the default stanza */ |
73 | i->stanza=strdup(def_stanza); | 99 | i->stanza = strdup(def_stanza); |
74 | } | ||
75 | /* if there is no @file part */ | ||
76 | if(stanza_len==locator_len){ | ||
77 | i->file=default_file(); | ||
78 | if(strcmp(i->file, "") == 0){ | ||
79 | die(STATE_UNKNOWN, _("Cannot find '%s' or '%s' in any standard location.\n"), NP_DEFAULT_INI_FILENAME1, NP_DEFAULT_INI_FILENAME2); | ||
80 | } | ||
81 | } else { | ||
82 | i->file=strdup(&(locator[stanza_len+1])); | ||
83 | } | ||
84 | 100 | ||
85 | if(i->file==NULL || i->stanza==NULL){ | 101 | if (i->stanza == NULL) |
86 | die(STATE_UNKNOWN, _("malloc() failed!\n")); | 102 | die(STATE_UNKNOWN, _("malloc() failed!\n")); |
87 | } | 103 | |
104 | /* check whether there's an @file part */ | ||
105 | i->file = stanza_len == locator_len | ||
106 | ? default_file() | ||
107 | : strdup(&(locator[stanza_len + 1])); | ||
108 | if (i->file == NULL || i->file[0] == '\0') | ||
109 | die(STATE_UNKNOWN, | ||
110 | _("Cannot find config file in any standard location.\n")); | ||
88 | } | 111 | } |
89 | 112 | ||
90 | /* this is the externally visible function used by extra_opts */ | 113 | /* |
91 | np_arg_list* np_get_defaults(const char *locator, const char *default_section){ | 114 | * This is the externally visible function used by extra_opts. |
92 | FILE *inifile=NULL; | 115 | */ |
93 | np_arg_list *defaults=NULL; | 116 | np_arg_list * |
117 | np_get_defaults(const char *locator, const char *default_section) | ||
118 | { | ||
119 | FILE *inifile = NULL; | ||
120 | np_arg_list *defaults = NULL; | ||
94 | np_ini_info i; | 121 | np_ini_info i; |
122 | int is_suid_plugin = mp_suid(); | ||
95 | 123 | ||
96 | parse_locator(locator, default_section, &i); | 124 | if (is_suid_plugin && idpriv_temp_drop() == -1) |
97 | /* if a file was specified or if we're using the default file */ | 125 | die(STATE_UNKNOWN, _("Cannot drop privileges: %s\n"), |
98 | if(i.file != NULL && strlen(i.file) > 0){ | 126 | strerror(errno)); |
99 | if(strcmp(i.file, "-")==0){ | ||
100 | inifile=stdin; | ||
101 | } else { | ||
102 | inifile=fopen(i.file, "r"); | ||
103 | } | ||
104 | if(inifile==NULL) die(STATE_UNKNOWN, "%s\n", _("Can't read config file")); | ||
105 | if(read_defaults(inifile, i.stanza, &defaults)==FALSE) | ||
106 | die(STATE_UNKNOWN, _("Invalid section '%s' in config file '%s'\n"), i.stanza, i.file); | ||
107 | 127 | ||
108 | free(i.file); | 128 | parse_locator(locator, default_section, &i); |
109 | if(inifile!=stdin) fclose(inifile); | 129 | inifile = strcmp(i.file, "-") == 0 ? stdin : fopen(i.file, "r"); |
110 | } | 130 | |
131 | if (inifile == NULL) | ||
132 | die(STATE_UNKNOWN, _("Can't read config file: %s\n"), | ||
133 | strerror(errno)); | ||
134 | if (read_defaults(inifile, i.stanza, &defaults) == FALSE) | ||
135 | die(STATE_UNKNOWN, | ||
136 | _("Invalid section '%s' in config file '%s'\n"), i.stanza, | ||
137 | i.file); | ||
138 | |||
139 | free(i.file); | ||
140 | if (inifile != stdin) | ||
141 | fclose(inifile); | ||
111 | free(i.stanza); | 142 | free(i.stanza); |
143 | if (is_suid_plugin && idpriv_temp_restore() == -1) | ||
144 | die(STATE_UNKNOWN, _("Cannot restore privileges: %s\n"), | ||
145 | strerror(errno)); | ||
146 | |||
112 | return defaults; | 147 | return defaults; |
113 | } | 148 | } |
114 | 149 | ||
115 | /* read_defaults is where the meat of the parsing takes place. | 150 | /* |
151 | * The read_defaults() function is where the meat of the parsing takes place. | ||
116 | * | 152 | * |
117 | * note that this may be called by a setuid binary, so we need to | 153 | * Note that this may be called by a setuid binary, so we need to |
118 | * be extra careful about user-supplied input (i.e. avoiding possible | 154 | * be extra careful about user-supplied input (i.e. avoiding possible |
119 | * format string vulnerabilities, etc) | 155 | * format string vulnerabilities, etc). |
120 | */ | 156 | */ |
121 | static int read_defaults(FILE *f, const char *stanza, np_arg_list **opts){ | 157 | static int |
122 | int c, status=FALSE; | 158 | read_defaults(FILE *f, const char *stanza, np_arg_list **opts) |
159 | { | ||
160 | int c, status = FALSE; | ||
123 | size_t i, stanza_len; | 161 | size_t i, stanza_len; |
124 | enum { NOSTANZA, WRONGSTANZA, RIGHTSTANZA } stanzastate=NOSTANZA; | 162 | enum { NOSTANZA, WRONGSTANZA, RIGHTSTANZA } stanzastate = NOSTANZA; |
125 | 163 | ||
126 | stanza_len=strlen(stanza); | 164 | stanza_len = strlen(stanza); |
127 | 165 | ||
128 | /* our little stanza-parsing state machine. */ | 166 | /* our little stanza-parsing state machine */ |
129 | while((c=fgetc(f))!=EOF){ | 167 | while ((c = fgetc(f)) != EOF) { |
130 | /* gobble up leading whitespace */ | 168 | /* gobble up leading whitespace */ |
131 | if(isspace(c)) continue; | 169 | if (isspace(c)) |
132 | switch(c){ | 170 | continue; |
171 | switch (c) { | ||
133 | /* globble up coment lines */ | 172 | /* globble up coment lines */ |
134 | case ';': | 173 | case ';': |
135 | case '#': | 174 | case '#': |
136 | GOBBLE_TO(f, c, '\n'); | 175 | GOBBLE_TO(f, c, '\n'); |
137 | break; | 176 | break; |
138 | /* start of a stanza. check to see if it matches */ | 177 | /* start of a stanza, check to see if it matches */ |
139 | case '[': | 178 | case '[': |
140 | stanzastate=WRONGSTANZA; | 179 | stanzastate = WRONGSTANZA; |
141 | for(i=0; i<stanza_len; i++){ | 180 | for (i = 0; i < stanza_len; i++) { |
142 | c=fgetc(f); | 181 | c = fgetc(f); |
143 | /* Strip leading whitespace */ | 182 | /* strip leading whitespace */ |
144 | if(i==0) for(c; isspace(c); c=fgetc(f)); | 183 | if (i == 0) |
145 | /* nope, read to the end of the line */ | 184 | for (; isspace(c); c = fgetc(f)) |
146 | if(c!=stanza[i]) { | 185 | continue; |
147 | GOBBLE_TO(f, c, '\n'); | 186 | /* nope, read to the end of the line */ |
148 | break; | 187 | if (c != stanza[i]) { |
149 | } | 188 | GOBBLE_TO(f, c, '\n'); |
150 | } | 189 | break; |
151 | /* if it matched up to here and the next char is ']'... */ | ||
152 | if(i==stanza_len){ | ||
153 | c=fgetc(f); | ||
154 | /* Strip trailing whitespace */ | ||
155 | for(c; isspace(c); c=fgetc(f)); | ||
156 | if(c==']') stanzastate=RIGHTSTANZA; | ||
157 | } | 190 | } |
158 | break; | 191 | } |
192 | /* if it matched up to here and the next char is ']'... */ | ||
193 | if (i == stanza_len) { | ||
194 | c = fgetc(f); | ||
195 | /* strip trailing whitespace */ | ||
196 | for (; isspace(c); c = fgetc(f)) | ||
197 | continue; | ||
198 | if (c == ']') | ||
199 | stanzastate = RIGHTSTANZA; | ||
200 | } | ||
201 | break; | ||
159 | /* otherwise, we're in the body of a stanza or a parse error */ | 202 | /* otherwise, we're in the body of a stanza or a parse error */ |
160 | default: | 203 | default: |
161 | switch(stanzastate){ | 204 | switch (stanzastate) { |
162 | /* we never found the start of the first stanza, so | 205 | /* we never found the start of the first stanza, so |
163 | * we're dealing with a config error | 206 | * we're dealing with a config error |
164 | */ | 207 | */ |
165 | case NOSTANZA: | 208 | case NOSTANZA: |
166 | die(STATE_UNKNOWN, "%s\n", _("Config file error")); | 209 | die(STATE_UNKNOWN, "%s\n", |
167 | break; | 210 | _("Config file error")); |
168 | /* we're in a stanza, but for a different plugin */ | 211 | /* we're in a stanza, but for a different plugin */ |
169 | case WRONGSTANZA: | 212 | case WRONGSTANZA: |
170 | GOBBLE_TO(f, c, '\n'); | 213 | GOBBLE_TO(f, c, '\n'); |
171 | break; | 214 | break; |
172 | /* okay, this is where we start taking the config */ | 215 | /* okay, this is where we start taking the config */ |
173 | case RIGHTSTANZA: | 216 | case RIGHTSTANZA: |
174 | ungetc(c, f); | 217 | ungetc(c, f); |
175 | if(add_option(f, opts)){ | 218 | if (add_option(f, opts)) { |
176 | die(STATE_UNKNOWN, "%s\n", _("Config file error")); | 219 | die(STATE_UNKNOWN, "%s\n", |
177 | } | 220 | _("Config file error")); |
178 | status=TRUE; | ||
179 | break; | ||
180 | } | 221 | } |
222 | status = TRUE; | ||
181 | break; | 223 | break; |
224 | } | ||
225 | break; | ||
182 | } | 226 | } |
183 | } | 227 | } |
184 | return status; | 228 | return status; |
185 | } | 229 | } |
186 | 230 | ||
187 | /* | 231 | /* |
188 | * read one line of input in the format | 232 | * Read one line of input in the format |
189 | * ^option[[:space:]]*(=[[:space:]]*value)? | 233 | * ^option[[:space:]]*(=[[:space:]]*value)? |
190 | * and creates it as a cmdline argument | 234 | * and create it as a cmdline argument |
191 | * --option[=value] | 235 | * --option[=value] |
192 | * appending it to the linked list optbuf. | 236 | * appending it to the linked list optbuf. |
193 | */ | 237 | */ |
194 | static int add_option(FILE *f, np_arg_list **optlst){ | 238 | static int |
195 | np_arg_list *opttmp=*optlst, *optnew; | 239 | add_option(FILE *f, np_arg_list **optlst) |
196 | char *linebuf=NULL, *lineend=NULL, *optptr=NULL, *optend=NULL; | 240 | { |
197 | char *eqptr=NULL, *valptr=NULL, *spaceptr=NULL, *valend=NULL; | 241 | np_arg_list *opttmp = *optlst, *optnew; |
198 | short done_reading=0, equals=0, value=0; | 242 | char *linebuf = NULL, *lineend = NULL, *optptr = NULL, *optend = NULL; |
199 | size_t cfg_len=0, read_sz=8, linebuf_sz=0, read_pos=0; | 243 | char *eqptr = NULL, *valptr = NULL, *valend = NULL; |
200 | size_t opt_len=0, val_len=0; | 244 | short done_reading = 0, equals = 0, value = 0; |
245 | size_t cfg_len = 0, read_sz = 8, linebuf_sz = 0, read_pos = 0; | ||
246 | size_t opt_len = 0, val_len = 0; | ||
201 | 247 | ||
202 | /* read one line from the file */ | 248 | /* read one line from the file */ |
203 | while(!done_reading){ | 249 | while (!done_reading) { |
204 | /* grow if necessary */ | 250 | /* grow if necessary */ |
205 | if(linebuf==NULL || read_pos+read_sz >= linebuf_sz){ | 251 | if (linebuf == NULL || read_pos + read_sz >= linebuf_sz) { |
206 | linebuf_sz=(linebuf_sz>0)?linebuf_sz<<1:read_sz; | 252 | linebuf_sz = linebuf_sz > 0 ? linebuf_sz << 1 : read_sz; |
207 | linebuf=realloc(linebuf, linebuf_sz); | 253 | linebuf = realloc(linebuf, linebuf_sz); |
208 | if(linebuf==NULL) die(STATE_UNKNOWN, _("malloc() failed!\n")); | 254 | if (linebuf == NULL) |
255 | die(STATE_UNKNOWN, _("malloc() failed!\n")); | ||
209 | } | 256 | } |
210 | if(fgets(&linebuf[read_pos], read_sz, f)==NULL) done_reading=1; | 257 | if (fgets(&linebuf[read_pos], (int)read_sz, f) == NULL) |
258 | done_reading = 1; | ||
211 | else { | 259 | else { |
212 | read_pos=strlen(linebuf); | 260 | read_pos = strlen(linebuf); |
213 | if(linebuf[read_pos-1]=='\n') { | 261 | if (linebuf[read_pos - 1] == '\n') { |
214 | linebuf[--read_pos]='\0'; | 262 | linebuf[--read_pos] = '\0'; |
215 | done_reading=1; | 263 | done_reading = 1; |
216 | } | 264 | } |
217 | } | 265 | } |
218 | } | 266 | } |
219 | lineend=&linebuf[read_pos]; | 267 | lineend = &linebuf[read_pos]; |
220 | /* all that to read one line. isn't C fun? :) now comes the parsing :/ */ | 268 | /* all that to read one line, isn't C fun? :) now comes the parsing :/ */ |
221 | 269 | ||
222 | /* skip leading whitespace */ | 270 | /* skip leading whitespace */ |
223 | for(optptr=linebuf; optptr<lineend && isspace(*optptr); optptr++); | 271 | for (optptr = linebuf; optptr < lineend && isspace(*optptr); optptr++) |
272 | continue; | ||
224 | /* continue to '=' or EOL, watching for spaces that might precede it */ | 273 | /* continue to '=' or EOL, watching for spaces that might precede it */ |
225 | for(eqptr=optptr; eqptr<lineend && *eqptr!='='; eqptr++){ | 274 | for (eqptr = optptr; eqptr < lineend && *eqptr != '='; eqptr++) { |
226 | if(isspace(*eqptr) && optend==NULL) optend=eqptr; | 275 | if (isspace(*eqptr) && optend == NULL) |
227 | else optend=NULL; | 276 | optend = eqptr; |
277 | else | ||
278 | optend = NULL; | ||
228 | } | 279 | } |
229 | if(optend==NULL) optend=eqptr; | 280 | if (optend == NULL) |
281 | optend = eqptr; | ||
230 | --optend; | 282 | --optend; |
231 | /* ^[[:space:]]*=foo is a syntax error */ | 283 | /* ^[[:space:]]*=foo is a syntax error */ |
232 | if(optptr==eqptr) die(STATE_UNKNOWN, "%s\n", _("Config file error")); | 284 | if (optptr == eqptr) |
285 | die(STATE_UNKNOWN, "%s\n", _("Config file error")); | ||
233 | /* continue from '=' to start of value or EOL */ | 286 | /* continue from '=' to start of value or EOL */ |
234 | for(valptr=eqptr+1; valptr<lineend && isspace(*valptr); valptr++); | 287 | for (valptr = eqptr + 1; valptr < lineend && isspace(*valptr); |
288 | valptr++) | ||
289 | continue; | ||
235 | /* continue to the end of value */ | 290 | /* continue to the end of value */ |
236 | for(valend=valptr; valend<lineend; valend++); | 291 | for (valend = valptr; valend < lineend; valend++) |
292 | continue; | ||
237 | --valend; | 293 | --valend; |
238 | /* Finally trim off trailing spaces */ | 294 | /* finally trim off trailing spaces */ |
239 | for(valend; isspace(*valend); valend--); | 295 | for (; isspace(*valend); valend--) |
296 | continue; | ||
240 | /* calculate the length of "--foo" */ | 297 | /* calculate the length of "--foo" */ |
241 | opt_len=1+optend-optptr; | 298 | opt_len = (size_t)(1 + optend - optptr); |
242 | /* 1-character params needs only one dash */ | 299 | /* 1-character params needs only one dash */ |
243 | if(opt_len==1) | 300 | if (opt_len == 1) |
244 | cfg_len=1+(opt_len); | 301 | cfg_len = 1 + (opt_len); |
245 | else | 302 | else |
246 | cfg_len=2+(opt_len); | 303 | cfg_len = 2 + (opt_len); |
247 | /* if valptr<lineend then we have to also allocate space for "=bar" */ | 304 | /* if valptr<lineend then we have to also allocate space for "=bar" */ |
248 | if(valptr<lineend) { | 305 | if (valptr < lineend) { |
249 | equals=value=1; | 306 | equals = value = 1; |
250 | val_len=1+valend-valptr; | 307 | val_len = (size_t)(1 + valend - valptr); |
251 | cfg_len+=1+val_len; | 308 | cfg_len += 1 + val_len; |
252 | } | 309 | } |
253 | /* if valptr==valend then we have "=" but no "bar" */ | 310 | /* if valptr==valend then we have "=" but no "bar" */ |
254 | else if(valptr==lineend) { | 311 | else if (valptr == lineend) { |
255 | equals=1; | 312 | equals = 1; |
256 | cfg_len+=1; | 313 | cfg_len += 1; |
257 | } | 314 | } |
258 | /* A line with no equal sign isn't valid */ | 315 | /* a line with no equal sign isn't valid */ |
259 | if(equals==0) die(STATE_UNKNOWN, "%s\n", _("Config file error")); | 316 | if (equals == 0) |
317 | die(STATE_UNKNOWN, "%s\n", _("Config file error")); | ||
260 | 318 | ||
261 | /* okay, now we have all the info we need, so we create a new np_arg_list | 319 | /* okay, now we have all the info we need, so we create a new np_arg_list |
262 | * element and set the argument... | 320 | * element and set the argument... |
263 | */ | 321 | */ |
264 | optnew=(np_arg_list *)malloc(sizeof(np_arg_list)); | 322 | optnew = malloc(sizeof(np_arg_list)); |
265 | optnew->next=NULL; | 323 | optnew->next = NULL; |
266 | 324 | ||
267 | read_pos=0; | 325 | read_pos = 0; |
268 | optnew->arg=(char *)malloc(cfg_len+1); | 326 | optnew->arg = malloc(cfg_len + 1); |
269 | /* 1-character params needs only one dash */ | 327 | /* 1-character params needs only one dash */ |
270 | if(opt_len==1) { | 328 | if (opt_len == 1) { |
271 | strncpy(&optnew->arg[read_pos], "-", 1); | 329 | strncpy(&optnew->arg[read_pos], "-", 1); |
272 | read_pos+=1; | 330 | read_pos += 1; |
273 | } else { | 331 | } else { |
274 | strncpy(&optnew->arg[read_pos], "--", 2); | 332 | strncpy(&optnew->arg[read_pos], "--", 2); |
275 | read_pos+=2; | 333 | read_pos += 2; |
276 | } | 334 | } |
277 | strncpy(&optnew->arg[read_pos], optptr, opt_len); read_pos+=opt_len; | 335 | strncpy(&optnew->arg[read_pos], optptr, opt_len); |
278 | if(value) { | 336 | read_pos += opt_len; |
279 | optnew->arg[read_pos++]='='; | 337 | if (value) { |
280 | strncpy(&optnew->arg[read_pos], valptr, val_len); read_pos+=val_len; | 338 | optnew->arg[read_pos++] = '='; |
339 | strncpy(&optnew->arg[read_pos], valptr, val_len); | ||
340 | read_pos += val_len; | ||
281 | } | 341 | } |
282 | optnew->arg[read_pos]='\0'; | 342 | optnew->arg[read_pos] = '\0'; |
283 | 343 | ||
284 | /* ...and put that to the end of the list */ | 344 | /* ...and put that to the end of the list */ |
285 | if(*optlst==NULL) { | 345 | if (*optlst == NULL) |
286 | *optlst=optnew; | 346 | *optlst = optnew; |
287 | } else { | 347 | else { |
288 | while(opttmp->next!=NULL) { | 348 | while (opttmp->next != NULL) |
289 | opttmp=opttmp->next; | 349 | opttmp = opttmp->next; |
290 | } | ||
291 | opttmp->next = optnew; | 350 | opttmp->next = optnew; |
292 | } | 351 | } |
293 | 352 | ||
@@ -295,71 +354,42 @@ static int add_option(FILE *f, np_arg_list **optlst){ | |||
295 | return 0; | 354 | return 0; |
296 | } | 355 | } |
297 | 356 | ||
298 | static char* default_file(void){ | 357 | static char * |
299 | struct stat sb; | 358 | default_file(void) |
300 | char *np_env=NULL, *default_file=NULL; | 359 | { |
301 | char temp_file[MAX_INPUT_BUFFER]; | 360 | char **p, *ini_file; |
302 | size_t len; | 361 | |
303 | 362 | if ((ini_file = getenv("MP_CONFIG_FILE")) != NULL || | |
304 | if((np_env=getenv("NAGIOS_CONFIG_PATH"))!=NULL) { | 363 | (ini_file = default_file_in_path()) != NULL) |
305 | /* skip any starting colon... */ | 364 | return ini_file; |
306 | while(*np_env==':') np_env++; | 365 | for (p = default_ini_path_names; *p != NULL; p++) |
307 | /* Look for NP_DEFAULT_INI_FILENAME1 and NP_DEFAULT_INI_FILENAME2 in | 366 | if (access(*p, F_OK) == 0) |
308 | * every PATHs defined (colon-separated). | 367 | return *p; |
309 | */ | 368 | return NULL; |
310 | while((len=strcspn(np_env,":"))>0){ | ||
311 | /* Test NP_DEFAULT_INI_FILENAME[1-2] in current np_env token */ | ||
312 | if(test_file(np_env,len,NP_DEFAULT_INI_FILENAME1,temp_file)==1 || | ||
313 | test_file(np_env,len,NP_DEFAULT_INI_FILENAME2,temp_file)==1){ | ||
314 | default_file=strdup(temp_file); | ||
315 | break; | ||
316 | } | ||
317 | |||
318 | /* Move on to the next token */ | ||
319 | np_env+=len; | ||
320 | while(*np_env==':') np_env++; | ||
321 | } /* while(...) */ | ||
322 | } /* if(getenv("NAGIOS_CONFIG_PATH")) */ | ||
323 | |||
324 | /* Look for NP_DEFAULT_INI_FILENAME1 in NP_DEFAULT_INI_NAGIOS_PATH[1-4] */ | ||
325 | if(!default_file){ | ||
326 | if(test_file(NP_DEFAULT_INI_NAGIOS_PATH1,strlen(NP_DEFAULT_INI_NAGIOS_PATH1),NP_DEFAULT_INI_FILENAME1,temp_file)==1 || | ||
327 | test_file(NP_DEFAULT_INI_NAGIOS_PATH2,strlen(NP_DEFAULT_INI_NAGIOS_PATH2),NP_DEFAULT_INI_FILENAME1,temp_file)==1 || | ||
328 | test_file(NP_DEFAULT_INI_NAGIOS_PATH3,strlen(NP_DEFAULT_INI_NAGIOS_PATH3),NP_DEFAULT_INI_FILENAME1,temp_file)==1 || | ||
329 | test_file(NP_DEFAULT_INI_NAGIOS_PATH4,strlen(NP_DEFAULT_INI_NAGIOS_PATH4),NP_DEFAULT_INI_FILENAME1,temp_file)==1) | ||
330 | default_file=strdup(temp_file); | ||
331 | } | ||
332 | |||
333 | /* Look for NP_DEFAULT_INI_FILENAME2 in NP_DEFAULT_INI_PATH[1-3] */ | ||
334 | if(!default_file){ | ||
335 | if(test_file(NP_DEFAULT_INI_PATH1,strlen(NP_DEFAULT_INI_PATH1),NP_DEFAULT_INI_FILENAME2,temp_file)==1 || | ||
336 | test_file(NP_DEFAULT_INI_PATH2,strlen(NP_DEFAULT_INI_PATH2),NP_DEFAULT_INI_FILENAME2,temp_file)==1 || | ||
337 | test_file(NP_DEFAULT_INI_PATH3,strlen(NP_DEFAULT_INI_PATH3),NP_DEFAULT_INI_FILENAME2,temp_file)==1) | ||
338 | default_file=strdup(temp_file); | ||
339 | } | ||
340 | |||
341 | /* Return default_file or empty string (should return NULL if we want plugins | ||
342 | * to die there)... | ||
343 | */ | ||
344 | if(default_file) | ||
345 | return default_file; | ||
346 | return ""; | ||
347 | } | 369 | } |
348 | 370 | ||
349 | /* put together len bytes from env and the filename and test for its | 371 | static char * |
350 | * existence. Returns 1 if found, 0 if not and -1 if test wasn't performed. | 372 | default_file_in_path(void) |
351 | */ | 373 | { |
352 | static int test_file(const char* env, int len, const char* file, char* temp_file){ | 374 | char *config_path, **file; |
353 | 375 | char *dir, *ini_file, *tokens; | |
354 | /* test if len + filelen + '/' + '\0' fits in temp_file */ | 376 | |
355 | if((len+strlen(file)+2)>MAX_INPUT_BUFFER) return -1; | 377 | if ((config_path = getenv("NAGIOS_CONFIG_PATH")) == NULL) |
356 | 378 | return NULL; | |
357 | strncpy(temp_file,env,len); | 379 | /* shall we spit out a warning that NAGIOS_CONFIG_PATH is deprecated? */ |
358 | temp_file[len]='\0'; | 380 | |
359 | strncat(temp_file,"/",len+1); | 381 | if ((tokens = strdup(config_path)) == NULL) |
360 | strncat(temp_file,file,len+strlen(file)+1); | 382 | die(STATE_UNKNOWN, "%s\n", _("Insufficient Memory")); |
361 | 383 | for (dir = strtok(tokens, ":"); dir != NULL; dir = strtok(NULL, ":")) { | |
362 | if(access(temp_file, F_OK) == 0) return 1; | 384 | for (file = default_ini_file_names; *file != NULL; file++) { |
363 | return 0; | 385 | if ((asprintf(&ini_file, "%s/%s", dir, *file)) < 0) |
386 | die(STATE_UNKNOWN, "%s\n", _("Insufficient Memory")); | ||
387 | if (access(ini_file, F_OK) == 0) { | ||
388 | free(tokens); | ||
389 | return ini_file; | ||
390 | } | ||
391 | } | ||
392 | } | ||
393 | free(tokens); | ||
394 | return NULL; | ||
364 | } | 395 | } |
365 | |||
diff --git a/lib/parse_ini.h b/lib/parse_ini.h index a3a494ef..e37601b5 100644 --- a/lib/parse_ini.h +++ b/lib/parse_ini.h | |||
@@ -13,50 +13,10 @@ typedef struct np_arg_el { | |||
13 | struct np_arg_el *next; | 13 | struct np_arg_el *next; |
14 | } np_arg_list; | 14 | } np_arg_list; |
15 | 15 | ||
16 | /* FIXME: This is in plugins/common.c. Should be eventually moved to lib/ | ||
17 | * (although for this particular one a configure settings should be ideal) | ||
18 | */ | ||
19 | #ifndef MAX_INPUT_BUFFER | ||
20 | # define MAX_INPUT_BUFFER 8192 | ||
21 | #endif /* MAX_INPUT_BUFFER */ | ||
22 | |||
23 | /* Filenames (see below) */ | ||
24 | #ifndef NP_DEFAULT_INI_FILENAME1 | ||
25 | # define NP_DEFAULT_INI_FILENAME1 "plugins.ini" | ||
26 | #endif /* NP_DEFAULT_INI_FILENAME1 */ | ||
27 | #ifndef NP_DEFAULT_INI_FILENAME2 | ||
28 | # define NP_DEFAULT_INI_FILENAME2 "nagios-plugins.ini" | ||
29 | #endif /* NP_DEFAULT_INI_FILENAME2 */ | ||
30 | |||
31 | /* Config paths ending in nagios (search for NP_DEFAULT_INI_FILENAME1) */ | ||
32 | #ifndef NP_DEFAULT_INI_NAGIOS_PATH1 | ||
33 | # define NP_DEFAULT_INI_NAGIOS_PATH1 "/etc/nagios" | ||
34 | #endif /* NP_DEFAULT_INI_NAGIOS_PATH1 */ | ||
35 | #ifndef NP_DEFAULT_INI_NAGIOS_PATH2 | ||
36 | # define NP_DEFAULT_INI_NAGIOS_PATH2 "/usr/local/nagios/etc" | ||
37 | #endif /* NP_DEFAULT_INI_NAGIOS_PATH2 */ | ||
38 | #ifndef NP_DEFAULT_INI_NAGIOS_PATH3 | ||
39 | # define NP_DEFAULT_INI_NAGIOS_PATH3 "/usr/local/etc/nagios" | ||
40 | #endif /* NP_DEFAULT_INI_NAGIOS_PATH3 */ | ||
41 | #ifndef NP_DEFAULT_INI_NAGIOS_PATH4 | ||
42 | # define NP_DEFAULT_INI_NAGIOS_PATH4 "/etc/opt/nagios" | ||
43 | #endif /* NP_DEFAULT_INI_NAGIOS_PATH4 */ | ||
44 | |||
45 | /* Config paths not ending in nagios (search for NP_DEFAULT_INI_FILENAME2) */ | ||
46 | #ifndef NP_DEFAULT_INI_PATH1 | ||
47 | # define NP_DEFAULT_INI_PATH1 "/etc" | ||
48 | #endif /* NP_DEFAULT_INI_PATH1 */ | ||
49 | #ifndef NP_DEFAULT_INI_PATH2 | ||
50 | # define NP_DEFAULT_INI_PATH2 "/usr/local/etc" | ||
51 | #endif /* NP_DEFAULT_INI_PATH2 */ | ||
52 | #ifndef NP_DEFAULT_INI_PATH3 | ||
53 | # define NP_DEFAULT_INI_PATH3 "/etc/opt" | ||
54 | #endif /* NP_DEFAULT_INI_PATH3 */ | ||
55 | |||
56 | /* np_load_defaults: load the default configuration (if present) for | 16 | /* np_load_defaults: load the default configuration (if present) for |
57 | * a plugin from the ini file | 17 | * a plugin from the ini file |
58 | */ | 18 | */ |
59 | np_arg_list* np_get_defaults(const char *locator, const char *default_section); | 19 | np_arg_list *np_get_defaults(const char *locator, const char *default_section); |
60 | 20 | ||
61 | #endif /* _PARSE_INI_H_ */ | 21 | #endif /* _PARSE_INI_H_ */ |
62 | 22 | ||
diff --git a/lib/tests/test_utils.c b/lib/tests/test_utils.c index 356887d5..f35b7e27 100644 --- a/lib/tests/test_utils.c +++ b/lib/tests/test_utils.c | |||
@@ -21,6 +21,7 @@ | |||
21 | 21 | ||
22 | #include "tap.h" | 22 | #include "tap.h" |
23 | 23 | ||
24 | #include <unistd.h> | ||
24 | #include <sys/types.h> | 25 | #include <sys/types.h> |
25 | #include <sys/stat.h> | 26 | #include <sys/stat.h> |
26 | 27 | ||
@@ -29,6 +30,7 @@ | |||
29 | int | 30 | int |
30 | main (int argc, char **argv) | 31 | main (int argc, char **argv) |
31 | { | 32 | { |
33 | char state_path[1024]; | ||
32 | range *range; | 34 | range *range; |
33 | double temp; | 35 | double temp; |
34 | thresholds *thresholds = NULL; | 36 | thresholds *thresholds = NULL; |
@@ -345,9 +347,10 @@ main (int argc, char **argv) | |||
345 | 347 | ||
346 | np_enable_state("allowedchars_in_keyname", 77); | 348 | np_enable_state("allowedchars_in_keyname", 77); |
347 | temp_state_key = this_monitoring_plugin->state; | 349 | temp_state_key = this_monitoring_plugin->state; |
350 | sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/allowedchars_in_keyname", (unsigned long)geteuid()); | ||
348 | ok( !strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name" ); | 351 | ok( !strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name" ); |
349 | ok( !strcmp(temp_state_key->name, "allowedchars_in_keyname"), "Got key name with valid chars" ); | 352 | ok( !strcmp(temp_state_key->name, "allowedchars_in_keyname"), "Got key name with valid chars" ); |
350 | ok( !strcmp(temp_state_key->_filename, "/usr/local/nagios/var/check_test/allowedchars_in_keyname"), "Got internal filename" ); | 353 | ok( !strcmp(temp_state_key->_filename, state_path), "Got internal filename" ); |
351 | 354 | ||
352 | 355 | ||
353 | /* Don't do this test just yet. Will die */ | 356 | /* Don't do this test just yet. Will die */ |
@@ -359,12 +362,13 @@ main (int argc, char **argv) | |||
359 | 362 | ||
360 | np_enable_state("funnykeyname", 54); | 363 | np_enable_state("funnykeyname", 54); |
361 | temp_state_key = this_monitoring_plugin->state; | 364 | temp_state_key = this_monitoring_plugin->state; |
365 | sprintf(state_path, "/usr/local/nagios/var/%lu/check_test/funnykeyname", (unsigned long)geteuid()); | ||
362 | ok( !strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name" ); | 366 | ok( !strcmp(temp_state_key->plugin_name, "check_test"), "Got plugin name" ); |
363 | ok( !strcmp(temp_state_key->name, "funnykeyname"), "Got key name" ); | 367 | ok( !strcmp(temp_state_key->name, "funnykeyname"), "Got key name" ); |
364 | 368 | ||
365 | 369 | ||
366 | 370 | ||
367 | ok( !strcmp(temp_state_key->_filename, "/usr/local/nagios/var/check_test/funnykeyname"), "Got internal filename" ); | 371 | ok( !strcmp(temp_state_key->_filename, state_path), "Got internal filename" ); |
368 | ok( temp_state_key->data_version==54, "Version set" ); | 372 | ok( temp_state_key->data_version==54, "Version set" ); |
369 | 373 | ||
370 | temp_state_data = np_state_read(); | 374 | temp_state_data = np_state_read(); |
diff --git a/lib/utils_base.c b/lib/utils_base.c index 04c4b4f9..addf26bd 100644 --- a/lib/utils_base.c +++ b/lib/utils_base.c | |||
@@ -300,19 +300,6 @@ char *np_escaped_string (const char *string) { | |||
300 | 300 | ||
301 | int np_check_if_root(void) { return (geteuid() == 0); } | 301 | int np_check_if_root(void) { return (geteuid() == 0); } |
302 | 302 | ||
303 | int np_warn_if_not_root(void) { | ||
304 | int status = np_check_if_root(); | ||
305 | if(!status) { | ||
306 | printf(_("Warning: ")); | ||
307 | printf(_("This plugin must be either run as root or setuid root.\n")); | ||
308 | printf(_("To run as root, you can use a tool like sudo.\n")); | ||
309 | printf(_("To set the setuid permissions, use the command:\n")); | ||
310 | /* XXX could we use something like progname? */ | ||
311 | printf("\tchmod u+s yourpluginfile\n"); | ||
312 | } | ||
313 | return status; | ||
314 | } | ||
315 | |||
316 | /* | 303 | /* |
317 | * Extract the value from key/value pairs, or return NULL. The value returned | 304 | * Extract the value from key/value pairs, or return NULL. The value returned |
318 | * can be free()ed. | 305 | * can be free()ed. |
@@ -489,7 +476,9 @@ void np_enable_state(char *keyname, int expected_data_version) { | |||
489 | this_state->state_data=NULL; | 476 | this_state->state_data=NULL; |
490 | 477 | ||
491 | /* Calculate filename */ | 478 | /* Calculate filename */ |
492 | asprintf(&temp_filename, "%s/%s/%s", _np_state_calculate_location_prefix(), this_monitoring_plugin->plugin_name, this_state->name); | 479 | asprintf(&temp_filename, "%s/%lu/%s/%s", |
480 | _np_state_calculate_location_prefix(), (unsigned long)geteuid(), | ||
481 | this_monitoring_plugin->plugin_name, this_state->name); | ||
493 | this_state->_filename=temp_filename; | 482 | this_state->_filename=temp_filename; |
494 | 483 | ||
495 | this_monitoring_plugin->state = this_state; | 484 | this_monitoring_plugin->state = this_state; |
diff --git a/lib/utils_base.h b/lib/utils_base.h index d69b0da1..42ae0c09 100644 --- a/lib/utils_base.h +++ b/lib/utils_base.h | |||
@@ -75,9 +75,6 @@ void die (int, const char *, ...) __attribute__((noreturn,format(printf, 2, 3))) | |||
75 | /* a simple check to see if we're running as root. | 75 | /* a simple check to see if we're running as root. |
76 | * returns zero on failure, nonzero on success */ | 76 | * returns zero on failure, nonzero on success */ |
77 | int np_check_if_root(void); | 77 | int np_check_if_root(void); |
78 | /* and a helpful wrapper around that. it returns the same status | ||
79 | * code from the above function, in case it's helpful for testing */ | ||
80 | int np_warn_if_not_root(void); | ||
81 | 78 | ||
82 | /* mp_suid() returns true if the real and effective uids differs, such as when | 79 | /* mp_suid() returns true if the real and effective uids differs, such as when |
83 | * running a suid plugin */ | 80 | * running a suid plugin */ |
diff --git a/lib/utils_cmd.c b/lib/utils_cmd.c index 4c6d0be1..9e214bd4 100644 --- a/lib/utils_cmd.c +++ b/lib/utils_cmd.c | |||
@@ -390,6 +390,9 @@ cmd_file_read ( char *filename, output *out, int flags) | |||
390 | 390 | ||
391 | if(out) | 391 | if(out) |
392 | out->lines = _cmd_fetch_output (fd, out, flags); | 392 | out->lines = _cmd_fetch_output (fd, out, flags); |
393 | |||
394 | if (close(fd) == -1) | ||
395 | die( STATE_UNKNOWN, _("Error closing %s: %s"), filename, strerror(errno) ); | ||
393 | 396 | ||
394 | return 0; | 397 | return 0; |
395 | } | 398 | } |