Am-Utils Cross Reference
am-utils/amd/info_exec.c

source navigation ]
diff markup ]
identifier search ]
freetext search ]
file search ]
 
Version: 6.0.1 ] [ 6.0.2 ] [ 6.0.3 ] [ 6.0.4 ] [ 6.0.5 ] [ 6.0.6 ] [ 6.0.7 ] [ 6.0.8 ] [ 6.0.9 ] [ 6.0.10 ] [ 6.1 ] [ 6.1.1 ]

  1 /*
  2  * Copyright (c) 1997-2005 Erez Zadok
  3  * Copyright (c) 1990 Jan-Simon Pendry
  4  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
  5  * Copyright (c) 1990 The Regents of the University of California.
  6  * All rights reserved.
  7  *
  8  * This code is derived from software contributed to Berkeley by
  9  * Jan-Simon Pendry at Imperial College, London.
 10  *
 11  * Redistribution and use in source and binary forms, with or without
 12  * modification, are permitted provided that the following conditions
 13  * are met:
 14  * 1. Redistributions of source code must retain the above copyright
 15  *    notice, this list of conditions and the following disclaimer.
 16  * 2. Redistributions in binary form must reproduce the above copyright
 17  *    notice, this list of conditions and the following disclaimer in the
 18  *    documentation and/or other materials provided with the distribution.
 19  * 3. All advertising materials mentioning features or use of this software
 20  *    must display the following acknowledgment:
 21  *      This product includes software developed by the University of
 22  *      California, Berkeley and its contributors.
 23  * 4. Neither the name of the University nor the names of its contributors
 24  *    may be used to endorse or promote products derived from this software
 25  *    without specific prior written permission.
 26  *
 27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 37  * SUCH DAMAGE.
 38  *
 39  *
 40  * File: am-utils/amd/info_exec.c
 41  *
 42  */
 43 
 44 /*
 45  * Get info from executable map
 46  *
 47  * Original from Erik Kline, 2004.
 48  */
 49 
 50 #ifdef HAVE_CONFIG_H
 51 # include <config.h>
 52 #endif /* HAVE_CONFIG_H */
 53 #include <am_defs.h>
 54 #include <amd.h>
 55 
 56 #define MAX_LINE_LEN            1500
 57 
 58 /* forward declarations */
 59 int exec_init(mnt_map *m, char *map, time_t *tp);
 60 int exec_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp);
 61 
 62 
 63 /*
 64  * a timed fgets()
 65  */
 66 static char *
 67 fgets_timed(char *s, int size, int rdfd, int secs)
 68 {
 69   fd_set fds;
 70   struct timeval timeo;
 71   time_t start, now;
 72   int rval=0, i=0;
 73 
 74   if (!s || size < 0 || rdfd < 0)
 75     return 0;
 76 
 77   s[0] = 0;
 78   if (size == 0)
 79     return s;
 80 
 81   start = clocktime();
 82   while (s[i] != '\n'  &&  i < size-1) {
 83     s[i+1] = 0; /* places the requisite trailing '\0' */
 84 
 85     /* ready for reading */
 86     rval = read(rdfd, (void *)(s+i), 1);
 87     if (rval == 1) {
 88       if (s[i] == 0) {
 89         rval = 0;
 90         break;
 91       }
 92       i++;
 93       continue;
 94     } else if (rval == 0) {
 95       break;
 96     } else if (rval < 0  &&  errno != EAGAIN  &&  errno != EINTR) {
 97       plog(XLOG_WARNING, "fgets_timed read error: %m");
 98       break;
 99     }
100 
101     timeo.tv_usec = 0;
102     now = clocktime() - start;
103     if (secs <= 0)
104       timeo.tv_sec = 0;
105     else if (now < secs)
106       timeo.tv_sec = secs - now;
107     else {
108       /* timed out (now>=secs) */
109       plog(XLOG_WARNING, "executable map read timed out (> %d secs)", secs);
110       rval = -1;
111       break;
112     }
113 
114     FD_ZERO(&fds);
115     FD_SET(rdfd, &fds);
116 
117     rval = select(rdfd+1, &fds, 0, 0, &timeo);
118     if (rval < 0) {
119       /* error selecting */
120       plog(XLOG_WARNING, "fgets_timed select error: %m");
121       if (errno == EINTR)
122         continue;
123       rval = -1;
124       break;
125     } else if (rval == 0) {
126       /* timed out */
127       plog(XLOG_WARNING, "executable map read timed out (> %d secs)", secs);
128       rval = -1;
129       break;
130     }
131   }
132 
133   if (rval > 0)
134     return s;
135 
136   close(rdfd);
137   return (rval == 0 ? s : 0);
138 }
139 
140 
141 static int
142 read_line(char *buf, int size, int fd)
143 {
144   int done = 0;
145 
146   while (fgets_timed(buf, size, fd, gopt.exec_map_timeout)) {
147     int len = strlen(buf);
148     done += len;
149     if (len > 1  &&  buf[len - 2] == '\\' &&
150         buf[len - 1] == '\n') {
151       buf += len - 2;
152       size -= len - 2;
153       *buf = '\n';
154       buf[1] = '\0';
155     } else {
156       return done;
157     }
158   }
159 
160   return done;
161 }
162 
163 
164 /*
165  * Try to locate a value in a query answer
166  */
167 static int
168 exec_parse_qanswer(int fd, char *map, char *key, char **pval, time_t *tp)
169 {
170   char qanswer[MAX_LINE_LEN], *dc = 0;
171   int chuck = 0;
172   int line_no = 0;
173 
174   while (read_line(qanswer, sizeof(qanswer), fd)) {
175     char *cp;
176     char *hash;
177     int len = strlen(qanswer);
178     line_no++;
179 
180     /*
181      * Make sure we got the whole line
182      */
183     if (qanswer[len - 1] != '\n') {
184       plog(XLOG_WARNING, "line %d in \"%s\" is too long", line_no, map);
185       chuck = 1;
186     } else {
187       qanswer[len - 1] = '\0';
188     }
189 
190     /*
191      * Strip comments
192      */
193     hash = strchr(qanswer, '#');
194     if (hash)
195       *hash = '\0';
196 
197     /*
198      * Find beginning of value (query answer)
199      */
200     for (cp = qanswer; *cp && !isascii((int)*cp) && !isspace((int)*cp); cp++)
201       ;;
202 
203     /* Ignore blank lines */
204     if (!*cp)
205       goto again;
206 
207     /*
208      * Return a copy of the data
209      */
210     dc = strdup(cp);
211     *pval = dc;
212     dlog("%s returns %s", key, dc);
213 
214     close(fd);
215     return 0;
216 
217   again:
218     /*
219      * If the last read didn't get a whole line then
220      * throw away the remainder before continuing...
221      */
222     if (chuck) {
223       while (fgets_timed(qanswer, sizeof(qanswer), fd, gopt.exec_map_timeout) &&
224              !strchr(qanswer, '\n')) ;
225       chuck = 0;
226     }
227   }
228 
229   return ENOENT;
230 }
231 
232 
233 static int
234 set_nonblock(int fd)
235 {
236   int val;
237 
238   if (fd < 0)
239      return 0;
240 
241   if ((val = fcntl(fd, F_GETFL, 0)) < 0) {
242     plog(XLOG_WARNING, "set_nonblock fcntl F_GETFL error: %m");
243     return 0;
244   }
245 
246   val |= O_NONBLOCK;
247   if (fcntl(fd, F_SETFL, val) < 0) {
248     plog(XLOG_WARNING, "set_nonblock fcntl F_SETFL error: %m");
249     return 0;
250   }
251 
252   return 1;
253 }
254 
255 
256 static int
257 exec_map_open(char *emap, char *key)
258 {
259   pid_t p1, p2;
260   int pdes[2], nullfd, i;
261   char *argv[3];
262 
263   if (!emap)
264     return 0;
265 
266   argv[0] = emap;
267   argv[1] = key;
268   argv[2] = NULL;
269 
270   if ((nullfd = open("/dev/null", O_WRONLY|O_NOCTTY)) < 0)
271     return -1;
272 
273   if (pipe(pdes) < 0) {
274     close(nullfd);
275     return -1;
276   }
277 
278   switch ((p1 = vfork())) {
279   case -1:
280     /* parent: fork error */
281     close(nullfd);
282     close(pdes[0]);
283     close(pdes[1]);
284     return -1;
285   case 0:
286     /* child #1 */
287     switch ((p2 = vfork())) {
288     case -1:
289       /* child #1: fork error */
290       exit(errno);
291     case 0:
292       /* child #2: init will reap our status */
293       if (pdes[1] != STDOUT_FILENO) {
294         dup2(pdes[1], STDOUT_FILENO);
295         close(pdes[1]);
296       }
297 
298       if (nullfd != STDERR_FILENO) {
299         dup2(nullfd, STDERR_FILENO);
300         close(nullfd);
301       }
302 
303       for (i=0; i<FD_SETSIZE; i++)
304         if (i != STDOUT_FILENO  &&  i != STDERR_FILENO)
305           close(i);
306 
307       /* make the write descriptor non-blocking */
308       if (!set_nonblock(STDOUT_FILENO)) {
309         close(STDOUT_FILENO);
310         exit(-1);
311       }
312 
313       execve(emap, argv, NULL);
314       exit(errno);              /* in case execve failed */
315     }
316 
317     /* child #1 */
318     exit(0);
319   }
320 
321   /* parent */
322   close(nullfd);
323   close(pdes[1]);
324 
325   /* anti-zombie insurance */
326   while (waitpid(p1,0,0) < 0)
327     if (errno != EINTR)
328       exit(errno);
329 
330   /* make the read descriptor non-blocking */
331   if (!set_nonblock(pdes[0])) {
332     close(pdes[0]);
333     return -1;
334   }
335 
336   return pdes[0];
337 }
338 
339 
340 /*
341  * Check for various permissions on executable map without trying to
342  * fork a new executable-map process.
343  *
344  * return: >0 (errno) if failed
345  *          0 if ok
346  */
347 static int
348 exec_check_perm(char *map)
349 {
350   struct stat sb;
351 
352   /* sanity and permission checks */
353   if (!map) {
354     dlog("exec_check_permission got a NULL map");
355     return EINVAL;
356   }
357   if (stat(map, &sb)) {
358     plog(XLOG_ERROR, "map \"%s\" stat failure: %m", map);
359     return errno;
360   }
361   if (!S_ISREG(sb.st_mode)) {
362     plog(XLOG_ERROR, "map \"%s\" should be regular file", map);
363     return EINVAL;
364   }
365   if (sb.st_uid != 0) {
366     plog(XLOG_ERROR, "map \"%s\" owned by uid %u (must be 0)", map, (u_int) sb.st_uid);
367     return EACCES;
368   }
369   if (!(sb.st_mode & S_IXUSR)) {
370     plog(XLOG_ERROR, "map \"%s\" should be executable", map);
371     return EACCES;
372   }
373   if (sb.st_mode & (S_ISUID|S_ISGID)) {
374     plog(XLOG_ERROR, "map \"%s\" should not be setuid/setgid", map);
375     return EACCES;
376   }
377   if (sb.st_mode & S_IWOTH) {
378     plog(XLOG_ERROR, "map \"%s\" should not be world writeable", map);
379     return EACCES;
380   }
381 
382   return 0;                     /* all is well */
383 }
384 
385 
386 int
387 exec_init(mnt_map *m, char *map, time_t *tp)
388 {
389   /*
390    * Basically just test that the executable map can be found
391    * and has proper permissions.
392    */
393   return exec_check_perm(map);
394 }
395 
396 
397 int
398 exec_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
399 {
400   int mapfd, ret;
401 
402   if ((ret = exec_check_perm(map)) != 0) {
403     return ret;
404   }
405 
406   if (!key)
407     return 0;
408 
409   if (logfp)
410     fflush(logfp);
411   dlog("exec_search \"%s\", key: \"%s\"", map, key);
412   mapfd = exec_map_open(map, key);
413 
414   if (mapfd >= 0) {
415     if (tp)
416       *tp = clocktime();
417 
418     return exec_parse_qanswer(mapfd, map, key, pval, tp);
419   }
420 
421   return errno;
422 }
423 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
This page is hosted at the Filesystems and Storage Lab at Stony Brook.