4 * Copyright (c) 1997-2009 Erez Zadok
5 * Copyright (c) 1990 Jan-Simon Pendry
6 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
7 * Copyright (c) 1990 The Regents of the University of California.
10 * This code is derived from software contributed to Berkeley by
11 * Jan-Simon Pendry at Imperial College, London.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgment:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * File: am-utils/amd/info_exec.c
47 * Get info from executable map
49 * Original from Erik Kline, 2004.
54 #endif /* HAVE_CONFIG_H */
60 /* forward declarations */
61 int exec_init(mnt_map
*m
, char *map
, time_t *tp
);
62 int exec_search(mnt_map
*m
, char *map
, char *key
, char **pval
, time_t *tp
);
69 fgets_timed(char *s
, int size
, int rdfd
, int secs
)
76 if (!s
|| size
< 0 || rdfd
< 0)
83 start
= clocktime(NULL
);
84 while (s
[i
] != '\n' && i
< size
-1) {
85 s
[i
+1] = '\0'; /* places the requisite trailing '\0' */
87 /* ready for reading */
88 rval
= read(rdfd
, (void *)(s
+i
), 1);
96 } else if (rval
== 0) {
98 } else if (rval
< 0 && errno
!= EAGAIN
&& errno
!= EINTR
) {
99 plog(XLOG_WARNING
, "fgets_timed read error: %m");
104 now
= clocktime(NULL
) - start
;
108 timeo
.tv_sec
= secs
- now
;
110 /* timed out (now>=secs) */
111 plog(XLOG_WARNING
, "executable map read timed out (> %d secs)", secs
);
119 rval
= select(rdfd
+1, &fds
, NULL
, NULL
, &timeo
);
121 /* error selecting */
122 plog(XLOG_WARNING
, "fgets_timed select error: %m");
127 } else if (rval
== 0) {
129 plog(XLOG_WARNING
, "executable map read timed out (> %d secs)", secs
);
139 return (rval
== 0 ? s
: 0);
144 read_line(char *buf
, int size
, int fd
)
148 while (fgets_timed(buf
, size
, fd
, gopt
.exec_map_timeout
)) {
149 int len
= strlen(buf
);
151 if (len
> 1 && buf
[len
- 2] == '\\' &&
152 buf
[len
- 1] == '\n') {
167 * Try to locate a value in a query answer
170 exec_parse_qanswer(mnt_map
*m
, int fd
, char *map
, char *key
, char **pval
, time_t *tp
)
172 char qanswer
[INFO_MAX_LINE_LEN
], *dc
= NULL
;
176 while (read_line(qanswer
, sizeof(qanswer
), fd
)) {
179 int len
= strlen(qanswer
);
183 * Make sure we got the whole line
185 if (qanswer
[len
- 1] != '\n') {
186 plog(XLOG_WARNING
, "line %d in \"%s\" is too long", line_no
, map
);
189 qanswer
[len
- 1] = '\0';
195 hash
= strchr(qanswer
, '#');
200 * Find beginning of value (query answer)
202 for (cp
= qanswer
; *cp
&& !isascii((unsigned char)*cp
) && !isspace((unsigned char)*cp
); cp
++)
205 /* Ignore blank lines */
210 * Return a copy of the data
212 if (m
->cfm
&& (m
->cfm
->cfm_flags
& CFM_SUN_MAP_SYNTAX
))
213 dc
= sun_entry2amd(key
, cp
);
217 dlog("%s returns %s", key
, dc
);
224 * If the last read didn't get a whole line then
225 * throw away the remainder before continuing...
228 while (fgets_timed(qanswer
, sizeof(qanswer
), fd
, gopt
.exec_map_timeout
) &&
229 !strchr(qanswer
, '\n')) ;
246 if ((val
= fcntl(fd
, F_GETFL
, 0)) < 0) {
247 plog(XLOG_WARNING
, "set_nonblock fcntl F_GETFL error: %m");
252 if (fcntl(fd
, F_SETFL
, val
) < 0) {
253 plog(XLOG_WARNING
, "set_nonblock fcntl F_SETFL error: %m");
262 exec_map_open(char *emap
, char *key
)
265 int pdes
[2], nullfd
, i
;
275 if ((nullfd
= open("/dev/null", O_WRONLY
|O_NOCTTY
)) < 0)
278 if (pipe(pdes
) < 0) {
283 switch ((p1
= vfork())) {
285 /* parent: fork error */
295 /* child #1: fork error */
298 /* child #2: init will reap our status */
299 if (pdes
[1] != STDOUT_FILENO
) {
300 dup2(pdes
[1], STDOUT_FILENO
);
304 if (nullfd
!= STDERR_FILENO
) {
305 dup2(nullfd
, STDERR_FILENO
);
309 for (i
=0; i
<FD_SETSIZE
; i
++)
310 if (i
!= STDOUT_FILENO
&& i
!= STDERR_FILENO
)
313 /* make the write descriptor non-blocking */
314 if (!set_nonblock(STDOUT_FILENO
)) {
315 close(STDOUT_FILENO
);
319 execve(emap
, argv
, NULL
);
320 exit(errno
); /* in case execve failed */
331 /* anti-zombie insurance */
332 while (waitpid(p1
, 0, 0) < 0)
336 /* make the read descriptor non-blocking */
337 if (!set_nonblock(pdes
[0])) {
347 * Check for various permissions on executable map without trying to
348 * fork a new executable-map process.
350 * return: >0 (errno) if failed
354 exec_check_perm(char *map
)
358 /* sanity and permission checks */
360 dlog("exec_check_permission got a NULL map");
363 if (stat(map
, &sb
)) {
364 plog(XLOG_ERROR
, "map \"%s\" stat failure: %m", map
);
367 if (!S_ISREG(sb
.st_mode
)) {
368 plog(XLOG_ERROR
, "map \"%s\" should be regular file", map
);
371 if (sb
.st_uid
!= 0) {
372 plog(XLOG_ERROR
, "map \"%s\" owned by uid %u (must be 0)", map
, (u_int
) sb
.st_uid
);
375 if (!(sb
.st_mode
& S_IXUSR
)) {
376 plog(XLOG_ERROR
, "map \"%s\" should be executable", map
);
379 if (sb
.st_mode
& (S_ISUID
|S_ISGID
)) {
380 plog(XLOG_ERROR
, "map \"%s\" should not be setuid/setgid", map
);
383 if (sb
.st_mode
& S_IWOTH
) {
384 plog(XLOG_ERROR
, "map \"%s\" should not be world writeable", map
);
388 return 0; /* all is well */
393 exec_init(mnt_map
*m
, char *map
, time_t *tp
)
396 * Basically just test that the executable map can be found
397 * and has proper permissions.
399 return exec_check_perm(map
);
404 exec_search(mnt_map
*m
, char *map
, char *key
, char **pval
, time_t *tp
)
408 if ((ret
= exec_check_perm(map
)) != 0) {
417 dlog("exec_search \"%s\", key: \"%s\"", map
, key
);
418 mapfd
= exec_map_open(map
, key
);
422 *tp
= clocktime(NULL
);
424 return exec_parse_qanswer(m
, mapfd
, map
, key
, pval
, tp
);