17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 539d3e169Sevanl * Common Development and Distribution License (the "License"). 639d3e169Sevanl * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 227c478bd9Sstevel@tonic-gate * autod_mount.c 237c478bd9Sstevel@tonic-gate * 243bfb48feSsemery * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 257c478bd9Sstevel@tonic-gate * Use is subject to license terms. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <stdio.h> 317c478bd9Sstevel@tonic-gate #include <ctype.h> 327c478bd9Sstevel@tonic-gate #include <string.h> 337c478bd9Sstevel@tonic-gate #include <syslog.h> 347c478bd9Sstevel@tonic-gate #include <sys/types.h> 357c478bd9Sstevel@tonic-gate #include <sys/stat.h> 367c478bd9Sstevel@tonic-gate #include <sys/param.h> 377c478bd9Sstevel@tonic-gate #include <errno.h> 387c478bd9Sstevel@tonic-gate #include <pwd.h> 397c478bd9Sstevel@tonic-gate #include <netinet/in.h> 407c478bd9Sstevel@tonic-gate #include <netdb.h> 417c478bd9Sstevel@tonic-gate #include <sys/tiuser.h> 427c478bd9Sstevel@tonic-gate #include <locale.h> 437c478bd9Sstevel@tonic-gate #include <stdlib.h> 447c478bd9Sstevel@tonic-gate #include <unistd.h> 457c478bd9Sstevel@tonic-gate #include <sys/mntent.h> 467c478bd9Sstevel@tonic-gate #include <sys/mnttab.h> 477c478bd9Sstevel@tonic-gate #include <sys/wait.h> 487c478bd9Sstevel@tonic-gate #include <sys/mount.h> 497c478bd9Sstevel@tonic-gate #include <sys/fs/autofs.h> 507c478bd9Sstevel@tonic-gate #include <nfs/nfs.h> 517c478bd9Sstevel@tonic-gate #include <thread.h> 527c478bd9Sstevel@tonic-gate #include <limits.h> 537c478bd9Sstevel@tonic-gate #include <assert.h> 547c478bd9Sstevel@tonic-gate #include <fcntl.h> 55*8548bf79Snr123932 #include <strings.h> 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate #include "automount.h" 587c478bd9Sstevel@tonic-gate #include "replica.h" 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate static int unmount_mntpnt(struct mnttab *); 61*8548bf79Snr123932 static int call_fork_exec(char *, char *, char **, int); 627c478bd9Sstevel@tonic-gate static void remove_browse_options(char *); 637c478bd9Sstevel@tonic-gate static int inherit_options(char *, char **); 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate int 6639d3e169Sevanl do_mount1( 6739d3e169Sevanl char *mapname, 6839d3e169Sevanl char *key, 6939d3e169Sevanl char *subdir, 7039d3e169Sevanl char *mapopts, 7139d3e169Sevanl char *path, 7239d3e169Sevanl uint_t isdirect, 733bfb48feSsemery uid_t uid, 7439d3e169Sevanl action_list **alpp, 7539d3e169Sevanl int flags) 767c478bd9Sstevel@tonic-gate { 777c478bd9Sstevel@tonic-gate struct mapline ml; 787c478bd9Sstevel@tonic-gate struct mapent *me, *mapents = NULL; 797c478bd9Sstevel@tonic-gate char mntpnt[MAXPATHLEN]; 807c478bd9Sstevel@tonic-gate char spec_mntpnt[MAXPATHLEN]; 817c478bd9Sstevel@tonic-gate int err = 0; 827c478bd9Sstevel@tonic-gate char *private; /* fs specific data. eg prevhost in case of nfs */ 837c478bd9Sstevel@tonic-gate int mount_ok = 0; 847c478bd9Sstevel@tonic-gate ssize_t len; 857c478bd9Sstevel@tonic-gate action_list *alp, *prev, *tmp; 867c478bd9Sstevel@tonic-gate char root[MAXPATHLEN]; 877c478bd9Sstevel@tonic-gate int overlay = 1; 887c478bd9Sstevel@tonic-gate char next_subdir[MAXPATHLEN]; 897c478bd9Sstevel@tonic-gate bool_t mount_access = TRUE; 907c478bd9Sstevel@tonic-gate bool_t iswildcard; 917c478bd9Sstevel@tonic-gate bool_t isrestricted = hasrestrictopt(mapopts); 927c478bd9Sstevel@tonic-gate char *stack[STACKSIZ]; 937c478bd9Sstevel@tonic-gate char **stkptr = stack; 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate retry: 967c478bd9Sstevel@tonic-gate iswildcard = FALSE; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate /* initialize the stack of open files for this thread */ 997c478bd9Sstevel@tonic-gate stack_op(INIT, NULL, stack, &stkptr); 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate err = getmapent(key, mapname, &ml, stack, &stkptr, &iswildcard, 1027c478bd9Sstevel@tonic-gate isrestricted); 1037c478bd9Sstevel@tonic-gate if (err == 0) { 1047c478bd9Sstevel@tonic-gate mapents = parse_entry(key, mapname, mapopts, &ml, 1057c478bd9Sstevel@tonic-gate subdir, isdirect, mount_access); 1067c478bd9Sstevel@tonic-gate } 1077c478bd9Sstevel@tonic-gate 10839d3e169Sevanl if (trace) { 1097c478bd9Sstevel@tonic-gate struct mapfs *mfs; 1107c478bd9Sstevel@tonic-gate trace_prt(1, " do_mount1:\n"); 1117c478bd9Sstevel@tonic-gate for (me = mapents; me; me = me->map_next) { 1127c478bd9Sstevel@tonic-gate trace_prt(1, " (%s,%s)\t%s%s%s\n", 1137c478bd9Sstevel@tonic-gate me->map_fstype ? me->map_fstype : "", 1147c478bd9Sstevel@tonic-gate me->map_mounter ? me->map_mounter : "", 1157c478bd9Sstevel@tonic-gate path ? path : "", 1167c478bd9Sstevel@tonic-gate me->map_root ? me->map_root : "", 1177c478bd9Sstevel@tonic-gate me->map_mntpnt ? me->map_mntpnt : ""); 1187c478bd9Sstevel@tonic-gate trace_prt(0, "\t\t-%s\n", 1197c478bd9Sstevel@tonic-gate me->map_mntopts ? me->map_mntopts : ""); 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate for (mfs = me->map_fs; mfs; mfs = mfs->mfs_next) 1227c478bd9Sstevel@tonic-gate trace_prt(0, "\t\t%s:%s\tpenalty=%d\n", 1237c478bd9Sstevel@tonic-gate mfs->mfs_host ? mfs->mfs_host: "", 1247c478bd9Sstevel@tonic-gate mfs->mfs_dir ? mfs->mfs_dir : "", 1257c478bd9Sstevel@tonic-gate mfs->mfs_penalty); 1267c478bd9Sstevel@tonic-gate } 1277c478bd9Sstevel@tonic-gate } 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate *alpp = NULL; 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate /* 1327c478bd9Sstevel@tonic-gate * Each mapent in the list describes a mount to be done. 1337c478bd9Sstevel@tonic-gate * Normally there's just a single entry, though in the 1347c478bd9Sstevel@tonic-gate * case of /net mounts there may be many entries, that 1357c478bd9Sstevel@tonic-gate * must be mounted as a hierarchy. For each mount the 1367c478bd9Sstevel@tonic-gate * automountd must make sure the required mountpoint 1377c478bd9Sstevel@tonic-gate * exists and invoke the appropriate mount command for 1387c478bd9Sstevel@tonic-gate * the fstype. 1397c478bd9Sstevel@tonic-gate */ 1407c478bd9Sstevel@tonic-gate private = ""; 1417c478bd9Sstevel@tonic-gate for (me = mapents; me && !err; me = me->map_next) { 1427c478bd9Sstevel@tonic-gate len = snprintf(mntpnt, sizeof (mntpnt), "%s%s%s", path, 1437c478bd9Sstevel@tonic-gate mapents->map_root, me->map_mntpnt); 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate if (len >= sizeof (mntpnt)) { 1467c478bd9Sstevel@tonic-gate free_mapent(mapents); 1477c478bd9Sstevel@tonic-gate return (ENAMETOOLONG); 1487c478bd9Sstevel@tonic-gate } 1497c478bd9Sstevel@tonic-gate /* 1507c478bd9Sstevel@tonic-gate * remove trailing /'s from mountpoint to avoid problems 1517c478bd9Sstevel@tonic-gate * stating a directory with two or more trailing slashes. 1527c478bd9Sstevel@tonic-gate * This will let us mount directories from machines 1537c478bd9Sstevel@tonic-gate * which export with two or more slashes (apollo for instance). 1547c478bd9Sstevel@tonic-gate */ 1557c478bd9Sstevel@tonic-gate len -= 1; 1567c478bd9Sstevel@tonic-gate while (mntpnt[len] == '/') 1577c478bd9Sstevel@tonic-gate mntpnt[len--] = '\0'; 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate (void) strcpy(spec_mntpnt, mntpnt); 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate if (isrestricted && 1627c478bd9Sstevel@tonic-gate inherit_options(mapopts, &me->map_mntopts) != 0) { 1637c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "malloc of options failed"); 1647c478bd9Sstevel@tonic-gate free_mapent(mapents); 1657c478bd9Sstevel@tonic-gate return (EAGAIN); 1667c478bd9Sstevel@tonic-gate } 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate if (strcmp(me->map_fstype, MNTTYPE_NFS) == 0) { 1697c478bd9Sstevel@tonic-gate remove_browse_options(me->map_mntopts); 17039d3e169Sevanl if (flags == DOMOUNT_KERNEL) { 17139d3e169Sevanl alp = (action_list *)malloc( 17239d3e169Sevanl sizeof (action_list)); 17339d3e169Sevanl if (alp == NULL) { 17439d3e169Sevanl syslog(LOG_ERR, 17539d3e169Sevanl "malloc of alp failed"); 17639d3e169Sevanl continue; 17739d3e169Sevanl } 17839d3e169Sevanl memset(alp, 0, sizeof (action_list)); 17939d3e169Sevanl } else 18039d3e169Sevanl alp = NULL; 1817c478bd9Sstevel@tonic-gate err = 1823bfb48feSsemery mount_nfs(me, spec_mntpnt, private, overlay, uid, 18339d3e169Sevanl &alp); 1847c478bd9Sstevel@tonic-gate /* 1857c478bd9Sstevel@tonic-gate * We must retry if we don't have access to the 1867c478bd9Sstevel@tonic-gate * root file system and there are other 1877c478bd9Sstevel@tonic-gate * following mapents. The reason we can't 1887c478bd9Sstevel@tonic-gate * continue because the rest of the mapent list 1897c478bd9Sstevel@tonic-gate * depends on whether mount_access is TRUE or FALSE. 1907c478bd9Sstevel@tonic-gate */ 1917c478bd9Sstevel@tonic-gate if (err == NFSERR_ACCES && me->map_next != NULL) { 1927c478bd9Sstevel@tonic-gate /* 1937c478bd9Sstevel@tonic-gate * don't expect mount_access to be 1947c478bd9Sstevel@tonic-gate * FALSE here, but we do a check 1957c478bd9Sstevel@tonic-gate * anyway. 1967c478bd9Sstevel@tonic-gate */ 1977c478bd9Sstevel@tonic-gate if (mount_access == TRUE) { 1987c478bd9Sstevel@tonic-gate mount_access = FALSE; 1997c478bd9Sstevel@tonic-gate err = 0; 2007c478bd9Sstevel@tonic-gate free_mapent(mapents); 20139d3e169Sevanl if (alp) { 20239d3e169Sevanl free(alp); 20339d3e169Sevanl alp = NULL; 20439d3e169Sevanl } 2057c478bd9Sstevel@tonic-gate goto retry; 2067c478bd9Sstevel@tonic-gate } 2077c478bd9Sstevel@tonic-gate } 20839d3e169Sevanl if (alp) { 20939d3e169Sevanl if (*alpp == NULL) 21039d3e169Sevanl *alpp = alp; 21139d3e169Sevanl else { 21239d3e169Sevanl for (tmp = *alpp; tmp != NULL; 21339d3e169Sevanl tmp = tmp->next) 21439d3e169Sevanl prev = tmp; 21539d3e169Sevanl prev->next = alp; 21639d3e169Sevanl } 21739d3e169Sevanl } 2187c478bd9Sstevel@tonic-gate mount_ok = !err; 2197c478bd9Sstevel@tonic-gate } else if (strcmp(me->map_fstype, MNTTYPE_AUTOFS) == 0) { 2207c478bd9Sstevel@tonic-gate if (isdirect) { 2217c478bd9Sstevel@tonic-gate len = strlcpy(root, path, sizeof (root)); 2227c478bd9Sstevel@tonic-gate } else { 2237c478bd9Sstevel@tonic-gate len = snprintf(root, sizeof (root), "%s/%s", 2247c478bd9Sstevel@tonic-gate path, key); 2257c478bd9Sstevel@tonic-gate } 2267c478bd9Sstevel@tonic-gate if (len >= sizeof (root)) { 2277c478bd9Sstevel@tonic-gate free_mapent(mapents); 2287c478bd9Sstevel@tonic-gate return (ENAMETOOLONG); 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate alp = (action_list *)malloc(sizeof (action_list)); 2327c478bd9Sstevel@tonic-gate if (alp == NULL) { 2337c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "malloc of alp failed"); 2347c478bd9Sstevel@tonic-gate continue; 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate memset(alp, 0, sizeof (action_list)); 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate /* 2397c478bd9Sstevel@tonic-gate * get the next subidr, but only if its a modified 2407c478bd9Sstevel@tonic-gate * or faked autofs mount 2417c478bd9Sstevel@tonic-gate */ 2427c478bd9Sstevel@tonic-gate if (me->map_modified || me->map_faked) { 2437c478bd9Sstevel@tonic-gate len = snprintf(next_subdir, 2447c478bd9Sstevel@tonic-gate sizeof (next_subdir), "%s%s", subdir, 2457c478bd9Sstevel@tonic-gate me->map_mntpnt); 2467c478bd9Sstevel@tonic-gate } else { 2477c478bd9Sstevel@tonic-gate next_subdir[0] = '\0'; 2487c478bd9Sstevel@tonic-gate len = 0; 2497c478bd9Sstevel@tonic-gate } 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate if (trace > 2) 2527c478bd9Sstevel@tonic-gate trace_prt(1, " root=%s\t next_subdir=%s\n", 2537c478bd9Sstevel@tonic-gate root, next_subdir); 2547c478bd9Sstevel@tonic-gate if (len < sizeof (next_subdir)) { 2557c478bd9Sstevel@tonic-gate err = mount_autofs(me, spec_mntpnt, alp, 2567c478bd9Sstevel@tonic-gate root, next_subdir, key); 2577c478bd9Sstevel@tonic-gate } else { 2587c478bd9Sstevel@tonic-gate err = ENAMETOOLONG; 2597c478bd9Sstevel@tonic-gate } 2607c478bd9Sstevel@tonic-gate if (err == 0) { 2617c478bd9Sstevel@tonic-gate /* 2627c478bd9Sstevel@tonic-gate * append to action list 2637c478bd9Sstevel@tonic-gate */ 2647c478bd9Sstevel@tonic-gate mount_ok++; 2657c478bd9Sstevel@tonic-gate if (*alpp == NULL) 2667c478bd9Sstevel@tonic-gate *alpp = alp; 2677c478bd9Sstevel@tonic-gate else { 2687c478bd9Sstevel@tonic-gate for (tmp = *alpp; tmp != NULL; 2697c478bd9Sstevel@tonic-gate tmp = tmp->next) 2707c478bd9Sstevel@tonic-gate prev = tmp; 2717c478bd9Sstevel@tonic-gate prev->next = alp; 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate } else { 2747c478bd9Sstevel@tonic-gate free(alp); 2757c478bd9Sstevel@tonic-gate mount_ok = 0; 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate } else if (strcmp(me->map_fstype, MNTTYPE_LOFS) == 0) { 2787c478bd9Sstevel@tonic-gate remove_browse_options(me->map_mntopts); 2797c478bd9Sstevel@tonic-gate err = loopbackmount(me->map_fs->mfs_dir, spec_mntpnt, 2807c478bd9Sstevel@tonic-gate me->map_mntopts, overlay); 2817c478bd9Sstevel@tonic-gate mount_ok = !err; 2827c478bd9Sstevel@tonic-gate } else { 2837c478bd9Sstevel@tonic-gate remove_browse_options(me->map_mntopts); 2847c478bd9Sstevel@tonic-gate err = mount_generic(me->map_fs->mfs_dir, 2857c478bd9Sstevel@tonic-gate me->map_fstype, me->map_mntopts, 2867c478bd9Sstevel@tonic-gate spec_mntpnt, overlay); 2877c478bd9Sstevel@tonic-gate mount_ok = !err; 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate if (mapents) 2917c478bd9Sstevel@tonic-gate free_mapent(mapents); 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate /* 2947c478bd9Sstevel@tonic-gate * If an error occurred, 2957c478bd9Sstevel@tonic-gate * the filesystem doesn't exist, or could not be 2967c478bd9Sstevel@tonic-gate * mounted. Return EACCES to autofs indicating that 2977c478bd9Sstevel@tonic-gate * the mountpoint can not be accessed if this is not 2987c478bd9Sstevel@tonic-gate * a wildcard access. If it is a wildcard access we 2997c478bd9Sstevel@tonic-gate * return ENOENT since the lookup that triggered 3007c478bd9Sstevel@tonic-gate * this mount request will fail and the entry will not 3017c478bd9Sstevel@tonic-gate * be available. 3027c478bd9Sstevel@tonic-gate */ 3037c478bd9Sstevel@tonic-gate if (mount_ok) { 3047c478bd9Sstevel@tonic-gate /* 3057c478bd9Sstevel@tonic-gate * No error occurred, return 0 to indicate success. 3067c478bd9Sstevel@tonic-gate */ 3077c478bd9Sstevel@tonic-gate err = 0; 3087c478bd9Sstevel@tonic-gate } else { 3097c478bd9Sstevel@tonic-gate /* 3107c478bd9Sstevel@tonic-gate * The filesystem does not exist or could not be mounted. 3117c478bd9Sstevel@tonic-gate * Return ENOENT if the lookup was triggered by a wildcard 3127c478bd9Sstevel@tonic-gate * access. Wildcard entries only exist if they can be 3137c478bd9Sstevel@tonic-gate * mounted. They can not be listed otherwise (through 3147c478bd9Sstevel@tonic-gate * a readdir(2)). 3157c478bd9Sstevel@tonic-gate * Return EACCES if the lookup was not triggered by a 3167c478bd9Sstevel@tonic-gate * wildcard access. Map entries that are explicitly defined 3177c478bd9Sstevel@tonic-gate * in maps are visible via readdir(2), therefore we return 3187c478bd9Sstevel@tonic-gate * EACCES to indicate that the entry exists, but the directory 3197c478bd9Sstevel@tonic-gate * can not be opened. This is the same behavior of a Unix 3207c478bd9Sstevel@tonic-gate * directory that exists, but has its execute bit turned off. 3217c478bd9Sstevel@tonic-gate * The directory is there, but the user does not have access 3227c478bd9Sstevel@tonic-gate * to it. 3237c478bd9Sstevel@tonic-gate */ 3247c478bd9Sstevel@tonic-gate if (iswildcard) 3257c478bd9Sstevel@tonic-gate err = ENOENT; 3267c478bd9Sstevel@tonic-gate else 3277c478bd9Sstevel@tonic-gate err = EACCES; 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate return (err); 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate #define ARGV_MAX 16 3337c478bd9Sstevel@tonic-gate #define VFS_PATH "/usr/lib/fs" 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate int 3367c478bd9Sstevel@tonic-gate mount_generic(special, fstype, opts, mntpnt, overlay) 3377c478bd9Sstevel@tonic-gate char *special, *fstype, *opts, *mntpnt; 3387c478bd9Sstevel@tonic-gate int overlay; 3397c478bd9Sstevel@tonic-gate { 3407c478bd9Sstevel@tonic-gate struct mnttab m; 3417c478bd9Sstevel@tonic-gate struct stat stbuf; 3427c478bd9Sstevel@tonic-gate int i, res; 3437c478bd9Sstevel@tonic-gate char *newargv[ARGV_MAX]; 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate if (trace > 1) { 3467c478bd9Sstevel@tonic-gate trace_prt(1, " mount: %s %s %s %s\n", 3477c478bd9Sstevel@tonic-gate special, mntpnt, fstype, opts); 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate if (stat(mntpnt, &stbuf) < 0) { 3517c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Couldn't stat %s: %m", mntpnt); 3527c478bd9Sstevel@tonic-gate return (ENOENT); 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate i = 2; 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate if (overlay) 3587c478bd9Sstevel@tonic-gate newargv[i++] = "-O"; 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate /* 3617c478bd9Sstevel@tonic-gate * Use "quiet" option to suppress warnings about unsupported 3627c478bd9Sstevel@tonic-gate * mount options. 3637c478bd9Sstevel@tonic-gate */ 3647c478bd9Sstevel@tonic-gate newargv[i++] = "-q"; 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate if (opts && *opts) { 3677c478bd9Sstevel@tonic-gate m.mnt_mntopts = opts; 3687c478bd9Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_RO) != NULL) 3697c478bd9Sstevel@tonic-gate newargv[i++] = "-r"; 3707c478bd9Sstevel@tonic-gate newargv[i++] = "-o"; 3717c478bd9Sstevel@tonic-gate newargv[i++] = opts; 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate newargv[i++] = "--"; 3747c478bd9Sstevel@tonic-gate newargv[i++] = special; 3757c478bd9Sstevel@tonic-gate newargv[i++] = mntpnt; 3767c478bd9Sstevel@tonic-gate newargv[i] = NULL; 377*8548bf79Snr123932 res = call_fork_exec(fstype, "mount", newargv, verbose); 3787c478bd9Sstevel@tonic-gate if (res == 0 && trace > 1) { 3797c478bd9Sstevel@tonic-gate if (stat(mntpnt, &stbuf) == 0) { 3807c478bd9Sstevel@tonic-gate trace_prt(1, " mount of %s dev=%x rdev=%x OK\n", 3817c478bd9Sstevel@tonic-gate mntpnt, stbuf.st_dev, stbuf.st_rdev); 3827c478bd9Sstevel@tonic-gate } else { 3837c478bd9Sstevel@tonic-gate trace_prt(1, " failed to stat %s\n", mntpnt); 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate return (res); 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate 389*8548bf79Snr123932 void 390*8548bf79Snr123932 automountd_do_fork_exec(void *cookie, char *argp, size_t arg_size, 391*8548bf79Snr123932 door_desc_t *dfd, uint_t n_desc) 3927c478bd9Sstevel@tonic-gate { 3937c478bd9Sstevel@tonic-gate int stat_loc; 3947c478bd9Sstevel@tonic-gate int fd = 0; 3957c478bd9Sstevel@tonic-gate struct stat stbuf; 3967c478bd9Sstevel@tonic-gate int res; 3977c478bd9Sstevel@tonic-gate int child_pid; 398*8548bf79Snr123932 command_t *command; 399*8548bf79Snr123932 char *newargv[ARGV_MAX]; 400*8548bf79Snr123932 int i; 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate 403*8548bf79Snr123932 command = (command_t *)argp; 404*8548bf79Snr123932 if (sizeof (*command) != arg_size) { 405*8548bf79Snr123932 res = EINVAL; 406*8548bf79Snr123932 door_return((char *)&res, sizeof (res), NULL, 0); 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate switch ((child_pid = fork1())) { 4107c478bd9Sstevel@tonic-gate case -1: 4117c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Cannot fork: %m"); 412*8548bf79Snr123932 res = errno; 413*8548bf79Snr123932 break; 4147c478bd9Sstevel@tonic-gate case 0: 4157c478bd9Sstevel@tonic-gate /* 4167c478bd9Sstevel@tonic-gate * Child 4177c478bd9Sstevel@tonic-gate */ 4187c478bd9Sstevel@tonic-gate (void) setsid(); 419*8548bf79Snr123932 fd = open(command->console ? "/dev/console" : "/dev/null", 420*8548bf79Snr123932 O_WRONLY); 4217c478bd9Sstevel@tonic-gate if (fd != -1) { 4227c478bd9Sstevel@tonic-gate (void) dup2(fd, 1); 4237c478bd9Sstevel@tonic-gate (void) dup2(fd, 2); 4247c478bd9Sstevel@tonic-gate (void) close(fd); 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate 427*8548bf79Snr123932 for (i = 0; *command->argv[i]; i++) { 428*8548bf79Snr123932 newargv[i] = strdup(command->argv[i]); 429*8548bf79Snr123932 if (newargv[i] == (char *)NULL) { 430*8548bf79Snr123932 syslog(LOG_ERR, "failed to copy argument '%s'" 431*8548bf79Snr123932 " of %s: %m", command->argv[i], 432*8548bf79Snr123932 command->file); 433*8548bf79Snr123932 _exit(errno); 434*8548bf79Snr123932 } 435*8548bf79Snr123932 } 436*8548bf79Snr123932 newargv[i] = NULL; 437*8548bf79Snr123932 438*8548bf79Snr123932 (void) execv(command->file, newargv); 4397c478bd9Sstevel@tonic-gate if (errno == EACCES) 440*8548bf79Snr123932 syslog(LOG_ERR, "exec %s: %m", command->file); 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate _exit(errno); 4437c478bd9Sstevel@tonic-gate default: 4447c478bd9Sstevel@tonic-gate /* 4457c478bd9Sstevel@tonic-gate * Parent 4467c478bd9Sstevel@tonic-gate */ 4477c478bd9Sstevel@tonic-gate (void) waitpid(child_pid, &stat_loc, WUNTRACED); 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate if (WIFEXITED(stat_loc)) { 4507c478bd9Sstevel@tonic-gate if (trace > 1) { 4517c478bd9Sstevel@tonic-gate trace_prt(1, 4527c478bd9Sstevel@tonic-gate " fork_exec: returns exit status %d\n", 4537c478bd9Sstevel@tonic-gate WEXITSTATUS(stat_loc)); 4547c478bd9Sstevel@tonic-gate } 4557c478bd9Sstevel@tonic-gate 456*8548bf79Snr123932 res = WEXITSTATUS(stat_loc); 457*8548bf79Snr123932 } else if (WIFSIGNALED(stat_loc)) { 458*8548bf79Snr123932 if (trace > 1) 4597c478bd9Sstevel@tonic-gate trace_prt(1, 4607c478bd9Sstevel@tonic-gate " fork_exec: returns signal status %d\n", 4617c478bd9Sstevel@tonic-gate WTERMSIG(stat_loc)); 462*8548bf79Snr123932 res = 1; 4637c478bd9Sstevel@tonic-gate } else { 4647c478bd9Sstevel@tonic-gate if (trace > 1) 4657c478bd9Sstevel@tonic-gate trace_prt(1, 4667c478bd9Sstevel@tonic-gate " fork_exec: returns unknown status\n"); 467*8548bf79Snr123932 res = 1; 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate 4707c478bd9Sstevel@tonic-gate } 471*8548bf79Snr123932 door_return((char *)&res, sizeof (res), NULL, 0); 472*8548bf79Snr123932 trace_prt(1, "automountd_do_fork_exec, door return failed %s, %s\n", 473*8548bf79Snr123932 command->file, strerror(errno)); 474*8548bf79Snr123932 door_return(NULL, 0, NULL, 0); 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate int 4787c478bd9Sstevel@tonic-gate do_unmount1(ur) 4797c478bd9Sstevel@tonic-gate umntrequest *ur; 4807c478bd9Sstevel@tonic-gate { 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate struct mnttab m; 4837c478bd9Sstevel@tonic-gate int res = 0; 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate m.mnt_special = ur->mntresource; 4867c478bd9Sstevel@tonic-gate m.mnt_mountp = ur->mntpnt; 4877c478bd9Sstevel@tonic-gate m.mnt_fstype = ur->fstype; 4887c478bd9Sstevel@tonic-gate m.mnt_mntopts = ur->mntopts; 4897c478bd9Sstevel@tonic-gate /* 4907c478bd9Sstevel@tonic-gate * Special case for NFS mounts. 4917c478bd9Sstevel@tonic-gate * Don't want to attempt unmounts from 4927c478bd9Sstevel@tonic-gate * a dead server. If any member of a 4937c478bd9Sstevel@tonic-gate * hierarchy belongs to a dead server 4947c478bd9Sstevel@tonic-gate * give up (try later). 4957c478bd9Sstevel@tonic-gate */ 4967c478bd9Sstevel@tonic-gate if (strcmp(ur->fstype, MNTTYPE_NFS) == 0) { 4977c478bd9Sstevel@tonic-gate struct replica *list; 4987c478bd9Sstevel@tonic-gate int i, n; 4997c478bd9Sstevel@tonic-gate bool_t pubopt = FALSE; 5007c478bd9Sstevel@tonic-gate int nfs_port; 5017c478bd9Sstevel@tonic-gate int got_port; 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate /* 5047c478bd9Sstevel@tonic-gate * See if a port number was specified. If one was 5057c478bd9Sstevel@tonic-gate * specified that is too large to fit in 16 bits, truncate 5067c478bd9Sstevel@tonic-gate * the high-order bits (for historical compatibility). Use 5077c478bd9Sstevel@tonic-gate * zero to indicate "no port specified". 5087c478bd9Sstevel@tonic-gate */ 5097c478bd9Sstevel@tonic-gate got_port = nopt(&m, MNTOPT_PORT, &nfs_port); 5107c478bd9Sstevel@tonic-gate if (!got_port) 5117c478bd9Sstevel@tonic-gate nfs_port = 0; 5127c478bd9Sstevel@tonic-gate nfs_port &= USHRT_MAX; 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_PUBLIC)) 5157c478bd9Sstevel@tonic-gate pubopt = TRUE; 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate list = parse_replica(ur->mntresource, &n); 5187c478bd9Sstevel@tonic-gate if (list == NULL) { 5197c478bd9Sstevel@tonic-gate if (n >= 0) 5207c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Memory allocation failed: %m"); 5217c478bd9Sstevel@tonic-gate res = 1; 5227c478bd9Sstevel@tonic-gate goto done; 5237c478bd9Sstevel@tonic-gate } 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 5267c478bd9Sstevel@tonic-gate if (pingnfs(list[i].host, 1, NULL, 0, nfs_port, 5277c478bd9Sstevel@tonic-gate pubopt, list[i].path, NULL) != RPC_SUCCESS) { 5287c478bd9Sstevel@tonic-gate res = 1; 5297c478bd9Sstevel@tonic-gate free_replica(list, n); 5307c478bd9Sstevel@tonic-gate goto done; 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate free_replica(list, n); 5347c478bd9Sstevel@tonic-gate } 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate res = unmount_mntpnt(&m); 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate done: return (res); 5397c478bd9Sstevel@tonic-gate } 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate static int 5427c478bd9Sstevel@tonic-gate unmount_mntpnt(mnt) 5437c478bd9Sstevel@tonic-gate struct mnttab *mnt; 5447c478bd9Sstevel@tonic-gate { 5457c478bd9Sstevel@tonic-gate char *fstype = mnt->mnt_fstype; 5467c478bd9Sstevel@tonic-gate char *mountp = mnt->mnt_mountp; 5477c478bd9Sstevel@tonic-gate char *newargv[ARGV_MAX]; 5487c478bd9Sstevel@tonic-gate int res; 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate if (strcmp(fstype, MNTTYPE_NFS) == 0) { 5517c478bd9Sstevel@tonic-gate res = nfsunmount(mnt); 5527c478bd9Sstevel@tonic-gate } else if (strcmp(fstype, MNTTYPE_LOFS) == 0) { 5537c478bd9Sstevel@tonic-gate if ((res = umount(mountp)) < 0) 5547c478bd9Sstevel@tonic-gate res = errno; 5557c478bd9Sstevel@tonic-gate } else { 5567c478bd9Sstevel@tonic-gate newargv[2] = mountp; 5577c478bd9Sstevel@tonic-gate newargv[3] = NULL; 5587c478bd9Sstevel@tonic-gate 559*8548bf79Snr123932 res = call_fork_exec(fstype, "umount", newargv, verbose); 5607c478bd9Sstevel@tonic-gate if (res == ENOENT) { 5617c478bd9Sstevel@tonic-gate /* 5627c478bd9Sstevel@tonic-gate * filesystem specific unmount command not found 5637c478bd9Sstevel@tonic-gate */ 5647c478bd9Sstevel@tonic-gate if ((res = umount(mountp)) < 0) 5657c478bd9Sstevel@tonic-gate res = errno; 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate } 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate if (trace > 1) 5707c478bd9Sstevel@tonic-gate trace_prt(1, " unmount %s %s\n", 5717c478bd9Sstevel@tonic-gate mountp, res ? "failed" : "OK"); 5727c478bd9Sstevel@tonic-gate return (res); 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate /* 5767c478bd9Sstevel@tonic-gate * Remove the autofs specific options 'browse', 'nobrowse' and 5777c478bd9Sstevel@tonic-gate * 'restrict' from 'opts'. 5787c478bd9Sstevel@tonic-gate */ 5797c478bd9Sstevel@tonic-gate static void 5807c478bd9Sstevel@tonic-gate remove_browse_options(char *opts) 5817c478bd9Sstevel@tonic-gate { 5827c478bd9Sstevel@tonic-gate char *p, *pb; 5837c478bd9Sstevel@tonic-gate char buf[MAXOPTSLEN], new[MAXOPTSLEN]; 5847c478bd9Sstevel@tonic-gate char *placeholder; 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate new[0] = '\0'; 5877c478bd9Sstevel@tonic-gate (void) strcpy(buf, opts); 5887c478bd9Sstevel@tonic-gate pb = buf; 5897c478bd9Sstevel@tonic-gate while (p = (char *)strtok_r(pb, ",", &placeholder)) { 5907c478bd9Sstevel@tonic-gate pb = NULL; 5917c478bd9Sstevel@tonic-gate if (strcmp(p, MNTOPT_NOBROWSE) != 0 && 5927c478bd9Sstevel@tonic-gate strcmp(p, MNTOPT_BROWSE) != 0 && 5937c478bd9Sstevel@tonic-gate strcmp(p, MNTOPT_RESTRICT) != 0) { 5947c478bd9Sstevel@tonic-gate if (new[0] != '\0') 5957c478bd9Sstevel@tonic-gate (void) strcat(new, ","); 5967c478bd9Sstevel@tonic-gate (void) strcat(new, p); 5977c478bd9Sstevel@tonic-gate } 5987c478bd9Sstevel@tonic-gate } 5997c478bd9Sstevel@tonic-gate (void) strcpy(opts, new); 6007c478bd9Sstevel@tonic-gate } 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate static const char *restropts[] = { 6037c478bd9Sstevel@tonic-gate RESTRICTED_MNTOPTS 6047c478bd9Sstevel@tonic-gate }; 6057c478bd9Sstevel@tonic-gate #define NROPTS (sizeof (restropts)/sizeof (restropts[0])) 6067c478bd9Sstevel@tonic-gate 6077c478bd9Sstevel@tonic-gate static int 6087c478bd9Sstevel@tonic-gate inherit_options(char *opts, char **mapentopts) 6097c478bd9Sstevel@tonic-gate { 6107c478bd9Sstevel@tonic-gate int i; 6117c478bd9Sstevel@tonic-gate char *new; 6127c478bd9Sstevel@tonic-gate struct mnttab mtmap; 6137c478bd9Sstevel@tonic-gate struct mnttab mtopt; 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate size_t len = strlen(*mapentopts); 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate for (i = 0; i < NROPTS; i++) 6187c478bd9Sstevel@tonic-gate len += strlen(restropts[i]); 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate /* "," for each new option plus the trailing NUL */ 6217c478bd9Sstevel@tonic-gate len += NROPTS + 1; 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate new = malloc(len); 6247c478bd9Sstevel@tonic-gate if (new == 0) 6257c478bd9Sstevel@tonic-gate return (-1); 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate (void) strcpy(new, *mapentopts); 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate mtmap.mnt_mntopts = *mapentopts; 6307c478bd9Sstevel@tonic-gate mtopt.mnt_mntopts = opts; 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate for (i = 0; i < NROPTS; i++) { 6337c478bd9Sstevel@tonic-gate if (hasmntopt(&mtopt, (char *)restropts[i]) != NULL && 6347c478bd9Sstevel@tonic-gate hasmntopt(&mtmap, (char *)restropts[i]) == NULL) { 6357c478bd9Sstevel@tonic-gate if (*new != '\0') 6367c478bd9Sstevel@tonic-gate (void) strcat(new, ","); 6377c478bd9Sstevel@tonic-gate (void) strcat(new, restropts[i]); 6387c478bd9Sstevel@tonic-gate } 6397c478bd9Sstevel@tonic-gate } 6407c478bd9Sstevel@tonic-gate free(*mapentopts); 6417c478bd9Sstevel@tonic-gate *mapentopts = new; 6427c478bd9Sstevel@tonic-gate return (0); 6437c478bd9Sstevel@tonic-gate } 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate bool_t 6467c478bd9Sstevel@tonic-gate hasrestrictopt(char *opts) 6477c478bd9Sstevel@tonic-gate { 6487c478bd9Sstevel@tonic-gate struct mnttab mt; 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate mt.mnt_mntopts = opts; 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate return (hasmntopt(&mt, MNTOPT_RESTRICT) != NULL); 6537c478bd9Sstevel@tonic-gate } 654*8548bf79Snr123932 655*8548bf79Snr123932 static int 656*8548bf79Snr123932 call_fork_exec(fstype, cmd, newargv, console) 657*8548bf79Snr123932 char *fstype; 658*8548bf79Snr123932 char *cmd; 659*8548bf79Snr123932 char **newargv; 660*8548bf79Snr123932 int console; 661*8548bf79Snr123932 { 662*8548bf79Snr123932 command_t command; 663*8548bf79Snr123932 door_arg_t darg; 664*8548bf79Snr123932 char path[MAXPATHLEN]; 665*8548bf79Snr123932 struct stat stbuf; 666*8548bf79Snr123932 int ret; 667*8548bf79Snr123932 int sz; 668*8548bf79Snr123932 int status; 669*8548bf79Snr123932 int i; 670*8548bf79Snr123932 671*8548bf79Snr123932 bzero(&command, sizeof (command)); 672*8548bf79Snr123932 /* build the full path name of the fstype dependent command */ 673*8548bf79Snr123932 (void) snprintf(path, MAXPATHLEN, "%s/%s/%s", VFS_PATH, fstype, cmd); 674*8548bf79Snr123932 675*8548bf79Snr123932 if (stat(path, &stbuf) != 0) { 676*8548bf79Snr123932 ret = errno; 677*8548bf79Snr123932 return (ret); 678*8548bf79Snr123932 } 679*8548bf79Snr123932 680*8548bf79Snr123932 strlcpy(command.file, path, MAXPATHLEN); 681*8548bf79Snr123932 strlcpy(command.argv[0], path, MAXOPTSLEN); 682*8548bf79Snr123932 for (i = 2; newargv[i]; i++) { 683*8548bf79Snr123932 strlcpy(command.argv[i-1], newargv[i], MAXOPTSLEN); 684*8548bf79Snr123932 } 685*8548bf79Snr123932 if (trace > 1) { 686*8548bf79Snr123932 trace_prt(1, " call_fork_exec: %s ", command.file); 687*8548bf79Snr123932 for (i = 0; *command.argv[i]; i++) 688*8548bf79Snr123932 trace_prt(0, "%s ", command.argv[i]); 689*8548bf79Snr123932 trace_prt(0, "\n"); 690*8548bf79Snr123932 } 691*8548bf79Snr123932 692*8548bf79Snr123932 command.console = console; 693*8548bf79Snr123932 694*8548bf79Snr123932 darg.data_ptr = (char *)&command; 695*8548bf79Snr123932 darg.data_size = sizeof (command); 696*8548bf79Snr123932 darg.desc_ptr = NULL; 697*8548bf79Snr123932 darg.desc_num = 0; 698*8548bf79Snr123932 darg.rbuf = (char *)&status; 699*8548bf79Snr123932 darg.rsize = sizeof (status); 700*8548bf79Snr123932 701*8548bf79Snr123932 ret = door_call(did_fork_exec, &darg); 702*8548bf79Snr123932 if (trace > 1) { 703*8548bf79Snr123932 trace_prt(1, " call_fork_exec: door_call failed %d\n", ret); 704*8548bf79Snr123932 } 705*8548bf79Snr123932 706*8548bf79Snr123932 return (status); 707*8548bf79Snr123932 } 708