4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
24 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
35 #include <sys/param.h>
37 #include <rpcsvc/nfs_prot.h>
44 #include <sys/types.h>
47 #include "automount.h"
49 static int read_execout(char *, char **, char *, char *, int);
50 static int call_read_execout(char *, char *, char *, int);
51 static FILE *file_open(char *, char *, char **, char ***);
54 * Initialize the stack
57 init_files(char **stack
, char ***stkptr
)
60 * The call is bogus for automountd since the stack is
61 * is more appropriately initialized in the thread-private
64 if (stack
== NULL
&& stkptr
== NULL
)
66 (void) stack_op(INIT
, NULL
, stack
, stkptr
);
70 getmapent_files(char *key
, char *mapname
, struct mapline
*ml
,
71 char **stack
, char ***stkptr
, bool_t
*iswildcard
, bool_t isrestricted
)
75 char word
[MAXPATHLEN
+1], wordq
[MAXPATHLEN
+1];
76 char linebuf
[LINESZ
], lineqbuf
[LINESZ
];
79 char fname
[MAXFILENAMELEN
]; /* /etc prepended to mapname if reqd */
84 if ((fp
= file_open(mapname
, fname
, stack
, stkptr
)) == NULL
) {
85 nserr
= __NSW_UNAVAIL
;
89 if (stat(fname
, &stbuf
) < 0) {
90 nserr
= __NSW_UNAVAIL
;
95 * If the file has its execute bit on then
96 * assume it's an executable map.
97 * Execute it and pass the key as an argument.
98 * Expect to get a map entry on the stdout.
99 * Ignore the "x" bit on restricted maps.
101 if (!isrestricted
&& (stbuf
.st_mode
& S_IXUSR
)) {
105 trace_prt(1, "\tExecutable map: map=%s key=%s\n",
109 rc
= call_read_execout(key
, fname
, ml
->linebuf
, LINESZ
);
112 nserr
= __NSW_UNAVAIL
;
116 if (strlen(ml
->linebuf
) == 0) {
117 nserr
= __NSW_NOTFOUND
;
121 unquote(ml
->linebuf
, ml
->lineqbuf
);
122 nserr
= __NSW_SUCCESS
;
128 * It's just a normal map file.
129 * Search for the entry with the required key.
132 lp
= get_line(fp
, fname
, linebuf
, sizeof (linebuf
));
134 nserr
= __NSW_NOTFOUND
;
137 if (verbose
&& syntaxok
&& isspace(*(uchar_t
*)lp
)) {
140 "leading space in map entry \"%s\" in %s",
145 if ((getword(word
, wordq
, &lp
, &lq
, ' ', sizeof (word
))
146 == -1) || (word
[0] == '\0'))
148 if (strcmp(word
, key
) == 0)
150 if (word
[0] == '*' && word
[1] == '\0') {
155 if (word
[0] == '+') {
156 nserr
= getmapent(key
, word
+1, ml
, stack
, stkptr
,
157 iswildcard
, isrestricted
);
158 if (nserr
== __NSW_SUCCESS
)
164 * sanity check each map entry key against
165 * the lookup key as the map is searched.
167 if (verbose
&& syntaxok
) { /* sanity check entry */
171 syslog(LOG_ERR
, "bad key \"%s\" in "
172 "direct map %s\n", word
, mapname
);
175 if (strchr(word
, '/')) {
177 syslog(LOG_ERR
, "bad key \"%s\" in "
178 "indirect map %s\n", word
, mapname
);
184 (void) strcpy(ml
->linebuf
, lp
);
185 (void) strcpy(ml
->lineqbuf
, lq
);
186 nserr
= __NSW_SUCCESS
;
189 (void) stack_op(POP
, (char *)NULL
, stack
, stkptr
);
198 getmapkeys_files(char *mapname
, struct dir_entry
**list
, int *error
,
199 int *cache_time
, char **stack
, char ***stkptr
)
202 char word
[MAXPATHLEN
+1], wordq
[MAXPATHLEN
+1];
203 char linebuf
[LINESZ
], lineqbuf
[LINESZ
];
206 char fname
[MAXFILENAMELEN
]; /* /etc prepended to mapname if reqd */
209 struct dir_entry
*last
= NULL
;
212 trace_prt(1, "getmapkeys_files %s\n", mapname
);
214 *cache_time
= RDDIR_CACHE_TIME
;
215 if ((fp
= file_open(mapname
, fname
, stack
, stkptr
)) == NULL
) {
217 nserr
= __NSW_UNAVAIL
;
220 if (fseek(fp
, 0L, SEEK_SET
) == -1) {
222 nserr
= __NSW_UNAVAIL
;
226 if (stat(fname
, &stbuf
) < 0) {
228 nserr
= __NSW_UNAVAIL
;
233 * If the file has its execute bit on then
234 * assume it's an executable map.
235 * I don't know how to list executable maps, return
238 if (stbuf
.st_mode
& S_IXUSR
) {
240 nserr
= __NSW_SUCCESS
;
244 * It's just a normal map file.
245 * List entries one line at a time.
248 lp
= get_line(fp
, fname
, linebuf
, sizeof (linebuf
));
250 nserr
= __NSW_SUCCESS
;
253 if (syntaxok
&& isspace(*(uchar_t
*)lp
)) {
256 "leading space in map entry \"%s\" in %s",
261 if ((getword(word
, wordq
, &lp
, &lq
, ' ', MAXFILENAMELEN
)
262 == -1) || (word
[0] == '\0'))
265 * Wildcard entries should be ignored and this should be
266 * the last entry read to corroborate the search through
267 * files, i.e., search for key until a wildcard is reached.
269 if (word
[0] == '*' && word
[1] == '\0')
271 if (word
[0] == '+') {
275 getmapkeys(word
+1, list
, error
, cache_time
,
278 * the list may have been updated, therefore
279 * our 'last' may no longer be valid
285 if (add_dir_entry(word
, list
, &last
) != 0) {
289 assert(last
!= NULL
);
292 nserr
= __NSW_SUCCESS
;
295 (void) stack_op(POP
, (char *)NULL
, stack
, stkptr
);
301 * list of entries found
309 loadmaster_files(char *mastermap
, char *defopts
, char **stack
, char ***stkptr
)
313 char *line
, *dir
, *map
, *opts
;
314 char linebuf
[LINESZ
];
316 char fname
[MAXFILENAMELEN
]; /* /etc prepended to mapname if reqd */
319 if ((fp
= file_open(mastermap
, fname
, stack
, stkptr
)) == NULL
)
320 return (__NSW_UNAVAIL
);
322 while ((line
= get_line(fp
, fname
, linebuf
,
323 sizeof (linebuf
))) != NULL
) {
324 unquote(line
, lineq
);
325 if (macro_expand("", line
, lineq
, LINESZ
)) {
326 syslog(LOG_ERR
, "map %s: line too long (max %d chars)",
327 mastermap
, LINESZ
- 1);
331 while (*dir
&& isspace(*dir
))
337 while (*map
&& !isspace(*map
)) map
++;
343 while (*opts
&& isspace(*opts
))
350 * Check for no embedded blanks.
352 if (strcspn(opts
, " ") == strlen(opts
)) {
354 (void) loadmaster_map(dir
, opts
, stack
, stkptr
);
356 pr_msg("Warning: invalid entry for %s in %s ignored.\n", dir
, fname
);
361 while (*map
&& isspace(*map
))
366 while (*opts
&& !isspace(*opts
))
370 while (*opts
&& isspace(*opts
))
378 * Check for no embedded blanks.
380 if (strcspn(opts
, " ") == strlen(opts
)) {
381 dirinit(dir
, map
, opts
, 0, stack
, stkptr
);
383 pr_msg("Warning: invalid entry for %s in %s ignored.\n", dir
, fname
);
390 (void) stack_op(POP
, (char *)NULL
, stack
, stkptr
);
393 return (done
? __NSW_SUCCESS
: __NSW_NOTFOUND
);
397 loaddirect_files(char *map
, char *local_map
, char *opts
,
398 char **stack
, char ***stkptr
)
402 char *line
, *p1
, *p2
;
403 char linebuf
[LINESZ
];
404 char fname
[MAXFILENAMELEN
]; /* /etc prepended to mapname if reqd */
406 if ((fp
= file_open(map
, fname
, stack
, stkptr
)) == NULL
)
407 return (__NSW_UNAVAIL
);
409 while ((line
= get_line(fp
, fname
, linebuf
,
410 sizeof (linebuf
))) != NULL
) {
412 while (*p1
&& isspace(*p1
))
417 while (*p2
&& !isspace(*p2
))
422 (void) loaddirect_map(p1
, local_map
, opts
, stack
,
425 dirinit(p1
, local_map
, opts
, 1, stack
, stkptr
);
430 (void) stack_op(POP
, (char *)NULL
, stack
, stkptr
);
433 return (done
? __NSW_SUCCESS
: __NSW_NOTFOUND
);
437 * This procedure opens the file and pushes it onto the
438 * the stack. Only if a file is opened successfully, is
439 * it pushed onto the stack
442 file_open(char *map
, char *fname
, char **stack
, char ***stkptr
)
447 /* prepend an "/etc" */
448 (void) strcpy(fname
, "/etc/");
449 (void) strcat(fname
, map
);
451 (void) strcpy(fname
, map
);
454 fp
= fopen(fname
, "r");
457 if (!stack_op(PUSH
, fname
, stack
, stkptr
)) {
466 * reimplemnted to be MT-HOT.
469 stack_op(int op
, char *name
, char **stack
, char ***stkptr
)
472 char **stk_top
= &stack
[STACKSIZ
- 1];
475 * the stackptr points to the next empty slot
476 * for PUSH: put the element and increment stkptr
477 * for POP: decrement stkptr and free
482 for (ptr
= stack
; ptr
!= stk_top
; ptr
++)
487 for (ptr
= stack
; ptr
!= stk_top
; ptr
++)
490 trace_prt(1, " ERASE %s\n", *ptr
);
497 if (*stkptr
== stk_top
)
499 for (ptr
= stack
; ptr
!= *stkptr
; ptr
++)
500 if (*ptr
&& (strcmp(*ptr
, name
) == 0)) {
504 trace_prt(1, " PUSH %s\n", name
);
505 if ((**stkptr
= strdup(name
)) == NULL
) {
506 syslog(LOG_ERR
, "stack_op: Memory alloc failed : %m");
512 if (*stkptr
!= stack
)
515 syslog(LOG_ERR
, "Attempt to pop empty stack\n");
517 if (*stkptr
&& **stkptr
) {
519 trace_prt(1, " POP %s\n", **stkptr
);
521 **stkptr
= (char *)NULL
;
529 #define READ_EXECOUT_ARGS 3
532 * read_execout(char *key, char **lp, char *fname, char *line, int linesz)
533 * A simpler, multithreaded implementation of popen(). Used due to
534 * non multithreaded implementation of popen() (it calls vfork()) and a
535 * significant bug in execl().
536 * Returns 0 on OK or -1 on error.
539 read_execout(char *key
, char **lp
, char *fname
, char *line
, int linesz
)
544 char *args
[READ_EXECOUT_ARGS
];
548 syslog(LOG_ERR
, "read_execout: Cannot create pipe");
552 /* setup args for execv */
553 if (((args
[0] = strdup(fname
)) == NULL
) ||
554 ((args
[1] = strdup(key
)) == NULL
)) {
557 syslog(LOG_ERR
, "read_execout: Memory allocation failed");
563 trace_prt(1, "\tread_execout: forking .....\n");
565 switch ((child_pid
= fork1())) {
567 syslog(LOG_ERR
, "read_execout: Cannot fork");
575 if (fcntl(p
[1], F_DUPFD
, 1) != 1) {
577 "read_execout: dup of stdout failed");
581 execv(fname
, &args
[0]);
590 * wait for child to complete. Note we read after the
591 * child exits to guarantee a full pipe.
593 while (waitpid(child_pid
, &status
, 0) < 0) {
594 /* if waitpid fails with EINTR, restart */
595 if (errno
!= EINTR
) {
601 if ((fp0
= fdopen(p
[0], "r")) != NULL
) {
602 *lp
= get_line(fp0
, fname
, line
, linesz
);
617 trace_prt(1, "\tread_execout: map=%s key=%s line=%s\n",
626 automountd_do_exec_map(void *cookie
, char *argp
, size_t arg_size
,
627 door_desc_t
*dfd
, uint_t n_desc
)
634 command
= (command_t
*)argp
;
636 if (sizeof (*command
) != arg_size
) {
638 syslog(LOG_ERR
, "read_execout: invalid door arguments");
639 door_return((char *)&rc
, sizeof (rc
), NULL
, 0);
642 rc
= read_execout(command
->key
, &lp
, command
->file
, line
, LINESZ
);
646 * read_execout returned an error, return 0 to the door_client
647 * to indicate failure
650 door_return((char *)&rc
, sizeof (rc
), NULL
, 0);
652 door_return((char *)line
, LINESZ
, NULL
, 0);
654 trace_prt(1, "automountd_do_exec_map, door return failed %s, %s\n",
655 command
->file
, strerror(errno
));
656 door_return(NULL
, 0, NULL
, 0);
660 call_read_execout(char *key
, char *fname
, char *line
, int linesz
)
666 bzero(&command
, sizeof (command
));
667 (void) strlcpy(command
.file
, fname
, MAXPATHLEN
);
668 (void) strlcpy(command
.key
, key
, MAXOPTSLEN
);
671 trace_prt(1, "call_read_execout %s %s\n", fname
, key
);
672 darg
.data_ptr
= (char *)&command
;
673 darg
.data_size
= sizeof (command
);
674 darg
.desc_ptr
= NULL
;
679 ret
= door_call(did_exec_map
, &darg
);