2 * Copyright (c) 1997-2014 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.
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * File: am-utils/amd/info_exec.c
41 * Get info from executable map
43 * Original from Erik Kline, 2004.
48 #endif /* HAVE_CONFIG_H */
54 /* forward declarations */
55 int exec_init(mnt_map *m, char *map, time_t *tp);
56 int exec_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp);
63 fgets_timed(char *s, int size, int rdfd, int secs)
70 if (!s || size < 0 || rdfd < 0)
77 start = clocktime(NULL);
78 while (s[i] != '\n' && i < size-1) {
79 s[i+1] = '\0'; /* places the requisite trailing '\0' */
81 /* ready for reading */
82 rval = read(rdfd, (void *)(s+i), 1);
90 } else if (rval == 0) {
92 } else if (rval < 0 && errno != EAGAIN && errno != EINTR) {
93 plog(XLOG_WARNING, "fgets_timed read error: %m");
98 now = clocktime(NULL) - start;
102 timeo.tv_sec = secs - now;
104 /* timed out (now>=secs) */
105 plog(XLOG_WARNING, "executable map read timed out (> %d secs)", secs);
113 rval = select(rdfd+1, &fds, NULL, NULL, &timeo);
115 /* error selecting */
116 plog(XLOG_WARNING, "fgets_timed select error: %m");
121 } else if (rval == 0) {
123 plog(XLOG_WARNING, "executable map read timed out (> %d secs)", secs);
133 return (rval == 0 ? s : 0);
138 read_line(char *buf, int size, int fd)
142 while (fgets_timed(buf, size, fd, gopt.exec_map_timeout)) {
143 int len = strlen(buf);
145 if (len > 1 && buf[len - 2] == '\\' &&
146 buf[len - 1] == '\n') {
161 * Try to locate a value in a query answer
164 exec_parse_qanswer(mnt_map *m, int fd, char *map, char *key, char **pval, time_t *tp)
166 char qanswer[INFO_MAX_LINE_LEN], *dc = NULL;
170 while (read_line(qanswer, sizeof(qanswer), fd)) {
173 int len = strlen(qanswer);
177 * Make sure we got the whole line
179 if (qanswer[len - 1] != '\n') {
180 plog(XLOG_WARNING, "line %d in \"%s\" is too long", line_no, map);
183 qanswer[len - 1] = '\0';
189 hash = strchr(qanswer, '#');
194 * Find beginning of value (query answer)
196 for (cp = qanswer; *cp && !isascii((unsigned char)*cp) && !isspace((unsigned char)*cp); cp++)
199 /* Ignore blank lines */
204 * Return a copy of the data
206 if (m->cfm && (m->cfm->cfm_flags & CFM_SUN_MAP_SYNTAX))
207 dc = sun_entry2amd(key, cp);
211 dlog("%s returns %s", key, dc);
218 * If the last read didn't get a whole line then
219 * throw away the remainder before continuing...
222 while (fgets_timed(qanswer, sizeof(qanswer), fd, gopt.exec_map_timeout) &&
223 !strchr(qanswer, '\n')) ;
240 if ((val = fcntl(fd, F_GETFL, 0)) < 0) {
241 plog(XLOG_WARNING, "set_nonblock fcntl F_GETFL error: %m");
246 if (fcntl(fd, F_SETFL, val) < 0) {
247 plog(XLOG_WARNING, "set_nonblock fcntl F_SETFL error: %m");
256 exec_map_open(char *emap, char *key)
259 int pdes[2], nullfd, i;
269 if ((nullfd = open("/dev/null", O_WRONLY|O_NOCTTY)) < 0)
272 if (pipe(pdes) < 0) {
277 switch ((p1 = vfork())) {
279 /* parent: fork error */
289 /* child #1: fork error */
292 /* child #2: init will reap our status */
293 if (pdes[1] != STDOUT_FILENO) {
294 dup2(pdes[1], STDOUT_FILENO);
298 if (nullfd != STDERR_FILENO) {
299 dup2(nullfd, STDERR_FILENO);
303 for (i=0; i<FD_SETSIZE; i++)
304 if (i != STDOUT_FILENO && i != STDERR_FILENO)
307 /* make the write descriptor non-blocking */
308 if (!set_nonblock(STDOUT_FILENO)) {
309 close(STDOUT_FILENO);
313 execve(emap, argv, NULL);
314 exit(errno); /* in case execve failed */
325 /* anti-zombie insurance */
326 while (waitpid(p1, 0, 0) < 0)
330 /* make the read descriptor non-blocking */
331 if (!set_nonblock(pdes[0])) {
341 * Check for various permissions on executable map without trying to
342 * fork a new executable-map process.
344 * return: >0 (errno) if failed
348 exec_check_perm(char *map)
352 /* sanity and permission checks */
354 dlog("exec_check_permission got a NULL map");
357 if (stat(map, &sb)) {
358 plog(XLOG_ERROR, "map \"%s\" stat failure: %m", map);
361 if (!S_ISREG(sb.st_mode)) {
362 plog(XLOG_ERROR, "map \"%s\" should be regular file", map);
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);
369 if (!(sb.st_mode & S_IXUSR)) {
370 plog(XLOG_ERROR, "map \"%s\" should be executable", map);
373 if (sb.st_mode & (S_ISUID|S_ISGID)) {
374 plog(XLOG_ERROR, "map \"%s\" should not be setuid/setgid", map);
377 if (sb.st_mode & S_IWOTH) {
378 plog(XLOG_ERROR, "map \"%s\" should not be world writeable", map);
382 return 0; /* all is well */
387 exec_init(mnt_map *m, char *map, time_t *tp)
390 * Basically just test that the executable map can be found
391 * and has proper permissions.
393 return exec_check_perm(map);
398 exec_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
402 if ((ret = exec_check_perm(map)) != 0) {
411 dlog("exec_search \"%s\", key: \"%s\"", map, key);
412 mapfd = exec_map_open(map, key);
416 *tp = clocktime(NULL);
418 return exec_parse_qanswer(m, mapfd, map, key, pval, tp);