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 527242a7cSthurlow * Common Development and Distribution License (the "License"). 627242a7cSthurlow * 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 2089621fe1SMarcel Telka */ 2189621fe1SMarcel Telka 2289621fe1SMarcel Telka /* 2354d34259SMarcel Telka * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 2489621fe1SMarcel Telka * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 287c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate /* 317c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD 327c478bd9Sstevel@tonic-gate * under license from the Regents of the University of California. 337c478bd9Sstevel@tonic-gate */ 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate #include <stdio.h> 3697adda44SMarcel Telka #include <stdio_ext.h> 377c478bd9Sstevel@tonic-gate #include <stdlib.h> 387c478bd9Sstevel@tonic-gate #include <ctype.h> 397c478bd9Sstevel@tonic-gate #include <sys/types.h> 407c478bd9Sstevel@tonic-gate #include <string.h> 417c478bd9Sstevel@tonic-gate #include <syslog.h> 427c478bd9Sstevel@tonic-gate #include <sys/param.h> 437c478bd9Sstevel@tonic-gate #include <rpc/rpc.h> 447c478bd9Sstevel@tonic-gate #include <sys/stat.h> 457c478bd9Sstevel@tonic-gate #include <netconfig.h> 467c478bd9Sstevel@tonic-gate #include <netdir.h> 477c478bd9Sstevel@tonic-gate #include <sys/file.h> 487c478bd9Sstevel@tonic-gate #include <sys/time.h> 497c478bd9Sstevel@tonic-gate #include <sys/errno.h> 507c478bd9Sstevel@tonic-gate #include <rpcsvc/mount.h> 517c478bd9Sstevel@tonic-gate #include <sys/pathconf.h> 527c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h> 537c478bd9Sstevel@tonic-gate #include <sys/utsname.h> 54250a0733Sth199096 #include <sys/wait.h> 5597adda44SMarcel Telka #include <sys/resource.h> 567c478bd9Sstevel@tonic-gate #include <signal.h> 577c478bd9Sstevel@tonic-gate #include <locale.h> 587c478bd9Sstevel@tonic-gate #include <unistd.h> 597c478bd9Sstevel@tonic-gate #include <errno.h> 607c478bd9Sstevel@tonic-gate #include <sys/socket.h> 617c478bd9Sstevel@tonic-gate #include <netinet/in.h> 627c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 637c478bd9Sstevel@tonic-gate #include <netdb.h> 647c478bd9Sstevel@tonic-gate #include <thread.h> 657c478bd9Sstevel@tonic-gate #include <assert.h> 667c478bd9Sstevel@tonic-gate #include <priv_utils.h> 671cc55349Srmesta #include <nfs/auth.h> 681cc55349Srmesta #include <nfs/nfssys.h> 697c478bd9Sstevel@tonic-gate #include <nfs/nfs.h> 707c478bd9Sstevel@tonic-gate #include <nfs/nfs_sec.h> 717c478bd9Sstevel@tonic-gate #include <rpcsvc/daemon_utils.h> 727c478bd9Sstevel@tonic-gate #include <deflt.h> 737c478bd9Sstevel@tonic-gate #include "../../fslib.h" 74a237e38eSth199096 #include <sharefs/share.h> 75a237e38eSth199096 #include <sharefs/sharetab.h> 767c478bd9Sstevel@tonic-gate #include "../lib/sharetab.h" 777c478bd9Sstevel@tonic-gate #include "mountd.h" 7803986916Sjarrett #include <tsol/label.h> 7903986916Sjarrett #include <sys/tsol/label_macro.h> 8003986916Sjarrett #include <libtsnet.h> 814a508a79SThomas Haynes #include <sys/sdt.h> 82dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include <libscf.h> 83dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include <limits.h> 846b086bafSSam Falkner #include <sys/nvpair.h> 856b086bafSSam Falkner #include <attr.h> 86dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include "smfcfg.h" 875cb0d679SMarcel Telka #include <pwd.h> 885cb0d679SMarcel Telka #include <grp.h> 8989621fe1SMarcel Telka #include <alloca.h> 907c478bd9Sstevel@tonic-gate 91250a0733Sth199096 extern int daemonize_init(void); 9254d34259SMarcel Telka extern void daemonize_fini(int); 9354d34259SMarcel Telka 9454d34259SMarcel Telka extern int _nfssys(int, void *); 95250a0733Sth199096 967c478bd9Sstevel@tonic-gate struct sh_list *share_list; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate rwlock_t sharetab_lock; /* lock to protect the cached sharetab */ 997c478bd9Sstevel@tonic-gate static mutex_t mnttab_lock; /* prevent concurrent mnttab readers */ 1007c478bd9Sstevel@tonic-gate 1014a508a79SThomas Haynes static mutex_t logging_queue_lock; 1024a508a79SThomas Haynes static cond_t logging_queue_cv; 1034a508a79SThomas Haynes 1044a508a79SThomas Haynes static share_t *find_lofsentry(char *, int *); 105*a9685eaaSMarcel Telka static int getclientsflavors_old(share_t *, struct cln *, int *); 106*a9685eaaSMarcel Telka static int getclientsflavors_new(share_t *, struct cln *, int *); 107*a9685eaaSMarcel Telka static int check_client_old(share_t *, struct cln *, int, uid_t, gid_t, uint_t, 108*a9685eaaSMarcel Telka gid_t *, uid_t *, gid_t *, uint_t *, gid_t **); 109*a9685eaaSMarcel Telka static int check_client_new(share_t *, struct cln *, int, uid_t, gid_t, uint_t, 110*a9685eaaSMarcel Telka gid_t *, uid_t *, gid_t *i, uint_t *, gid_t **); 1117c478bd9Sstevel@tonic-gate static void mnt(struct svc_req *, SVCXPRT *); 1127c478bd9Sstevel@tonic-gate static void mnt_pathconf(struct svc_req *); 1134a508a79SThomas Haynes static int mount(struct svc_req *r); 1147c478bd9Sstevel@tonic-gate static void sh_free(struct sh_list *); 1157c478bd9Sstevel@tonic-gate static void umount(struct svc_req *); 1167c478bd9Sstevel@tonic-gate static void umountall(struct svc_req *); 1177c478bd9Sstevel@tonic-gate static int newopts(char *); 11803986916Sjarrett static tsol_tpent_t *get_client_template(struct sockaddr *); 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate static int verbose; 1217c478bd9Sstevel@tonic-gate static int rejecting; 1227c478bd9Sstevel@tonic-gate static int mount_vers_min = MOUNTVERS; 1237c478bd9Sstevel@tonic-gate static int mount_vers_max = MOUNTVERS3; 1247c478bd9Sstevel@tonic-gate 125b89a8333Snatalie li - Sun Microsystems - Irvine United States extern void nfscmd_func(void *, char *, size_t, door_desc_t *, uint_t); 126b89a8333Snatalie li - Sun Microsystems - Irvine United States 1271cc55349Srmesta thread_t nfsauth_thread; 128b89a8333Snatalie li - Sun Microsystems - Irvine United States thread_t cmd_thread; 1294a508a79SThomas Haynes thread_t logging_thread; 1304a508a79SThomas Haynes 1314a508a79SThomas Haynes typedef struct logging_data { 1324a508a79SThomas Haynes char *ld_host; 1334a508a79SThomas Haynes char *ld_path; 1344a508a79SThomas Haynes char *ld_rpath; 1354a508a79SThomas Haynes int ld_status; 1364a508a79SThomas Haynes char *ld_netid; 1374a508a79SThomas Haynes struct netbuf *ld_nb; 1384a508a79SThomas Haynes struct logging_data *ld_next; 1394a508a79SThomas Haynes } logging_data; 1404a508a79SThomas Haynes 1414a508a79SThomas Haynes static logging_data *logging_head = NULL; 1424a508a79SThomas Haynes static logging_data *logging_tail = NULL; 1431cc55349Srmesta 14489621fe1SMarcel Telka /* 14589621fe1SMarcel Telka * Our copy of some system variables obtained using sysconf(3c) 14689621fe1SMarcel Telka */ 14789621fe1SMarcel Telka static long ngroups_max; /* _SC_NGROUPS_MAX */ 14889621fe1SMarcel Telka static long pw_size; /* _SC_GETPW_R_SIZE_MAX */ 14989621fe1SMarcel Telka 1501cc55349Srmesta /* ARGSUSED */ 1511cc55349Srmesta static void * 1521cc55349Srmesta nfsauth_svc(void *arg) 1531cc55349Srmesta { 1541cc55349Srmesta int doorfd = -1; 1551cc55349Srmesta uint_t darg; 1561cc55349Srmesta #ifdef DEBUG 1571cc55349Srmesta int dfd; 1581cc55349Srmesta #endif 1591cc55349Srmesta 1601cc55349Srmesta if ((doorfd = door_create(nfsauth_func, NULL, 1611cc55349Srmesta DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) { 1621cc55349Srmesta syslog(LOG_ERR, "Unable to create door: %m\n"); 1631cc55349Srmesta exit(10); 1641cc55349Srmesta } 1651cc55349Srmesta 1661cc55349Srmesta #ifdef DEBUG 1671cc55349Srmesta /* 1681cc55349Srmesta * Create a file system path for the door 1691cc55349Srmesta */ 1701cc55349Srmesta if ((dfd = open(MOUNTD_DOOR, O_RDWR|O_CREAT|O_TRUNC, 1711cc55349Srmesta S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) { 1721cc55349Srmesta syslog(LOG_ERR, "Unable to open %s: %m\n", MOUNTD_DOOR); 1731cc55349Srmesta (void) close(doorfd); 1741cc55349Srmesta exit(11); 1751cc55349Srmesta } 1761cc55349Srmesta 1771cc55349Srmesta /* 1781cc55349Srmesta * Clean up any stale namespace associations 1791cc55349Srmesta */ 1801cc55349Srmesta (void) fdetach(MOUNTD_DOOR); 1811cc55349Srmesta 1821cc55349Srmesta /* 1831cc55349Srmesta * Register in namespace to pass to the kernel to door_ki_open 1841cc55349Srmesta */ 1851cc55349Srmesta if (fattach(doorfd, MOUNTD_DOOR) == -1) { 1861cc55349Srmesta syslog(LOG_ERR, "Unable to fattach door: %m\n"); 1871cc55349Srmesta (void) close(dfd); 1881cc55349Srmesta (void) close(doorfd); 1891cc55349Srmesta exit(12); 1901cc55349Srmesta } 1911cc55349Srmesta (void) close(dfd); 1921cc55349Srmesta #endif 1931cc55349Srmesta 1941cc55349Srmesta /* 1951cc55349Srmesta * Must pass the doorfd down to the kernel. 1961cc55349Srmesta */ 1971cc55349Srmesta darg = doorfd; 1981cc55349Srmesta (void) _nfssys(MOUNTD_ARGS, &darg); 1991cc55349Srmesta 2001cc55349Srmesta /* 2011cc55349Srmesta * Wait for incoming calls 2021cc55349Srmesta */ 2031cc55349Srmesta /*CONSTCOND*/ 2041cc55349Srmesta for (;;) 2051cc55349Srmesta (void) pause(); 2061cc55349Srmesta 2071cc55349Srmesta /*NOTREACHED*/ 2081cc55349Srmesta syslog(LOG_ERR, gettext("Door server exited")); 2091cc55349Srmesta return (NULL); 2101cc55349Srmesta } 2111cc55349Srmesta 212b89a8333Snatalie li - Sun Microsystems - Irvine United States /* 213b89a8333Snatalie li - Sun Microsystems - Irvine United States * NFS command service thread code for setup and handling of the 214b89a8333Snatalie li - Sun Microsystems - Irvine United States * nfs_cmd requests for character set conversion and other future 215b89a8333Snatalie li - Sun Microsystems - Irvine United States * events. 216b89a8333Snatalie li - Sun Microsystems - Irvine United States */ 217b89a8333Snatalie li - Sun Microsystems - Irvine United States 218b89a8333Snatalie li - Sun Microsystems - Irvine United States static void * 219b89a8333Snatalie li - Sun Microsystems - Irvine United States cmd_svc(void *arg) 220b89a8333Snatalie li - Sun Microsystems - Irvine United States { 221b89a8333Snatalie li - Sun Microsystems - Irvine United States int doorfd = -1; 222b89a8333Snatalie li - Sun Microsystems - Irvine United States uint_t darg; 223b89a8333Snatalie li - Sun Microsystems - Irvine United States 224b89a8333Snatalie li - Sun Microsystems - Irvine United States if ((doorfd = door_create(nfscmd_func, NULL, 225b89a8333Snatalie li - Sun Microsystems - Irvine United States DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) { 226b89a8333Snatalie li - Sun Microsystems - Irvine United States syslog(LOG_ERR, "Unable to create cmd door: %m\n"); 227b89a8333Snatalie li - Sun Microsystems - Irvine United States exit(10); 228b89a8333Snatalie li - Sun Microsystems - Irvine United States } 229b89a8333Snatalie li - Sun Microsystems - Irvine United States 230b89a8333Snatalie li - Sun Microsystems - Irvine United States /* 231b89a8333Snatalie li - Sun Microsystems - Irvine United States * Must pass the doorfd down to the kernel. 232b89a8333Snatalie li - Sun Microsystems - Irvine United States */ 233b89a8333Snatalie li - Sun Microsystems - Irvine United States darg = doorfd; 234b89a8333Snatalie li - Sun Microsystems - Irvine United States (void) _nfssys(NFSCMD_ARGS, &darg); 235b89a8333Snatalie li - Sun Microsystems - Irvine United States 236b89a8333Snatalie li - Sun Microsystems - Irvine United States /* 237b89a8333Snatalie li - Sun Microsystems - Irvine United States * Wait for incoming calls 238b89a8333Snatalie li - Sun Microsystems - Irvine United States */ 239b89a8333Snatalie li - Sun Microsystems - Irvine United States /*CONSTCOND*/ 240b89a8333Snatalie li - Sun Microsystems - Irvine United States for (;;) 241b89a8333Snatalie li - Sun Microsystems - Irvine United States (void) pause(); 242b89a8333Snatalie li - Sun Microsystems - Irvine United States 243b89a8333Snatalie li - Sun Microsystems - Irvine United States /*NOTREACHED*/ 244b89a8333Snatalie li - Sun Microsystems - Irvine United States syslog(LOG_ERR, gettext("Cmd door server exited")); 245b89a8333Snatalie li - Sun Microsystems - Irvine United States return (NULL); 246b89a8333Snatalie li - Sun Microsystems - Irvine United States } 247250a0733Sth199096 2484a508a79SThomas Haynes static void 2494a508a79SThomas Haynes free_logging_data(logging_data *lq) 2504a508a79SThomas Haynes { 2514a508a79SThomas Haynes if (lq != NULL) { 2524a508a79SThomas Haynes free(lq->ld_host); 2534a508a79SThomas Haynes free(lq->ld_netid); 2544a508a79SThomas Haynes 2554a508a79SThomas Haynes if (lq->ld_nb != NULL) { 2564a508a79SThomas Haynes free(lq->ld_nb->buf); 2574a508a79SThomas Haynes free(lq->ld_nb); 2584a508a79SThomas Haynes } 2594a508a79SThomas Haynes 2604a508a79SThomas Haynes free(lq->ld_path); 2614a508a79SThomas Haynes free(lq->ld_rpath); 2624a508a79SThomas Haynes 2634a508a79SThomas Haynes free(lq); 2644a508a79SThomas Haynes } 2654a508a79SThomas Haynes } 2664a508a79SThomas Haynes 2674a508a79SThomas Haynes static logging_data * 2684a508a79SThomas Haynes remove_head_of_queue(void) 2694a508a79SThomas Haynes { 2704a508a79SThomas Haynes logging_data *lq; 2714a508a79SThomas Haynes 2724a508a79SThomas Haynes /* 2734a508a79SThomas Haynes * Pull it off the queue. 2744a508a79SThomas Haynes */ 2754a508a79SThomas Haynes lq = logging_head; 2764a508a79SThomas Haynes if (lq) { 2774a508a79SThomas Haynes logging_head = lq->ld_next; 2784a508a79SThomas Haynes 2794a508a79SThomas Haynes /* 2804a508a79SThomas Haynes * Drained it. 2814a508a79SThomas Haynes */ 2824a508a79SThomas Haynes if (logging_head == NULL) { 2834a508a79SThomas Haynes logging_tail = NULL; 2844a508a79SThomas Haynes } 2854a508a79SThomas Haynes } 2864a508a79SThomas Haynes 2874a508a79SThomas Haynes return (lq); 2884a508a79SThomas Haynes } 2894a508a79SThomas Haynes 2904a508a79SThomas Haynes static void 2914a508a79SThomas Haynes do_logging_queue(logging_data *lq) 2924a508a79SThomas Haynes { 2934a508a79SThomas Haynes int cleared = 0; 2944a508a79SThomas Haynes char *host; 2954a508a79SThomas Haynes 2964a508a79SThomas Haynes while (lq) { 297*a9685eaaSMarcel Telka struct cln cln; 298*a9685eaaSMarcel Telka 2994a508a79SThomas Haynes if (lq->ld_host == NULL) { 3004a508a79SThomas Haynes DTRACE_PROBE(mountd, name_by_lazy); 301*a9685eaaSMarcel Telka cln_init_lazy(&cln, lq->ld_netid, lq->ld_nb); 302*a9685eaaSMarcel Telka host = cln_gethost(&cln); 3034a508a79SThomas Haynes } else 3044a508a79SThomas Haynes host = lq->ld_host; 3054a508a79SThomas Haynes 3064a508a79SThomas Haynes audit_mountd_mount(host, lq->ld_path, lq->ld_status); /* BSM */ 3074a508a79SThomas Haynes 3084a508a79SThomas Haynes /* add entry to mount list */ 3094a508a79SThomas Haynes if (lq->ld_rpath) 3104a508a79SThomas Haynes mntlist_new(host, lq->ld_rpath); 3114a508a79SThomas Haynes 312*a9685eaaSMarcel Telka if (lq->ld_host == NULL) 313*a9685eaaSMarcel Telka cln_fini(&cln); 314d383eb7aSMarcel Telka 315c596e866SMarcel Telka free_logging_data(lq); 316c596e866SMarcel Telka cleared++; 3174a508a79SThomas Haynes 3184a508a79SThomas Haynes (void) mutex_lock(&logging_queue_lock); 3194a508a79SThomas Haynes lq = remove_head_of_queue(); 3204a508a79SThomas Haynes (void) mutex_unlock(&logging_queue_lock); 3214a508a79SThomas Haynes } 3224a508a79SThomas Haynes 3234a508a79SThomas Haynes DTRACE_PROBE1(mountd, logging_cleared, cleared); 3244a508a79SThomas Haynes } 3254a508a79SThomas Haynes 3264a508a79SThomas Haynes static void * 3274a508a79SThomas Haynes logging_svc(void *arg) 3284a508a79SThomas Haynes { 3294a508a79SThomas Haynes logging_data *lq; 3304a508a79SThomas Haynes 3314a508a79SThomas Haynes for (;;) { 3324a508a79SThomas Haynes (void) mutex_lock(&logging_queue_lock); 3334a508a79SThomas Haynes while (logging_head == NULL) { 3344a508a79SThomas Haynes (void) cond_wait(&logging_queue_cv, 3354a508a79SThomas Haynes &logging_queue_lock); 3364a508a79SThomas Haynes } 3374a508a79SThomas Haynes 3384a508a79SThomas Haynes lq = remove_head_of_queue(); 3394a508a79SThomas Haynes (void) mutex_unlock(&logging_queue_lock); 3404a508a79SThomas Haynes 3414a508a79SThomas Haynes do_logging_queue(lq); 3424a508a79SThomas Haynes } 3434a508a79SThomas Haynes 3444a508a79SThomas Haynes /*NOTREACHED*/ 3454a508a79SThomas Haynes syslog(LOG_ERR, gettext("Logging server exited")); 3464a508a79SThomas Haynes return (NULL); 3474a508a79SThomas Haynes } 3484a508a79SThomas Haynes 349361f55a5SMarcel Telka static int 350361f55a5SMarcel Telka convert_int(int *val, char *str) 351361f55a5SMarcel Telka { 352361f55a5SMarcel Telka long lval; 353361f55a5SMarcel Telka 354361f55a5SMarcel Telka if (str == NULL || !isdigit(*str)) 355361f55a5SMarcel Telka return (-1); 356361f55a5SMarcel Telka 357361f55a5SMarcel Telka lval = strtol(str, &str, 10); 358361f55a5SMarcel Telka if (*str != '\0' || lval > INT_MAX) 359361f55a5SMarcel Telka return (-2); 360361f55a5SMarcel Telka 361361f55a5SMarcel Telka *val = (int)lval; 362361f55a5SMarcel Telka return (0); 363361f55a5SMarcel Telka } 364361f55a5SMarcel Telka 36511606941Sjwahlig int 36611606941Sjwahlig main(int argc, char *argv[]) 3677c478bd9Sstevel@tonic-gate { 3687c478bd9Sstevel@tonic-gate int pid; 3697c478bd9Sstevel@tonic-gate int c; 3702f416683SMarcel Telka int rpc_svc_fdunlim = 1; 3717c478bd9Sstevel@tonic-gate int rpc_svc_mode = RPC_SVC_MT_AUTO; 3727c478bd9Sstevel@tonic-gate int maxrecsz = RPC_MAXDATASIZE; 3737c478bd9Sstevel@tonic-gate bool_t exclbind = TRUE; 37445916cd2Sjpk bool_t can_do_mlp; 3751cc55349Srmesta long thr_flags = (THR_NEW_LWP|THR_DAEMON); 376dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States char defval[4]; 377dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States int defvers, ret, bufsz; 37897adda44SMarcel Telka struct rlimit rl; 379361f55a5SMarcel Telka int listen_backlog = 0; 380361f55a5SMarcel Telka int max_threads = 0; 381361f55a5SMarcel Telka int tmp; 3827c478bd9Sstevel@tonic-gate 383250a0733Sth199096 int pipe_fd = -1; 384250a0733Sth199096 3857c478bd9Sstevel@tonic-gate /* 3867c478bd9Sstevel@tonic-gate * Mountd requires uid 0 for: 3877c478bd9Sstevel@tonic-gate * /etc/rmtab updates (we could chown it to daemon) 3887c478bd9Sstevel@tonic-gate * /etc/dfs/dfstab reading (it wants to lock out share which 3897c478bd9Sstevel@tonic-gate * doesn't do any locking before first truncate; 3907c478bd9Sstevel@tonic-gate * NFS share does; should use fcntl locking instead) 3917c478bd9Sstevel@tonic-gate * Needed privileges: 3927c478bd9Sstevel@tonic-gate * auditing 3937c478bd9Sstevel@tonic-gate * nfs syscall 3947c478bd9Sstevel@tonic-gate * file dac search (so it can stat all files) 39545916cd2Sjpk * Optional privileges: 39645916cd2Sjpk * MLP 3977c478bd9Sstevel@tonic-gate */ 39845916cd2Sjpk can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP); 3997c478bd9Sstevel@tonic-gate if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, -1, -1, 4007c478bd9Sstevel@tonic-gate PRIV_SYS_NFS, PRIV_PROC_AUDIT, PRIV_FILE_DAC_SEARCH, 40145916cd2Sjpk can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) { 4027c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 403250a0733Sth199096 "%s: must be run with sufficient privileges\n", 4047c478bd9Sstevel@tonic-gate argv[0]); 4057c478bd9Sstevel@tonic-gate exit(1); 4067c478bd9Sstevel@tonic-gate } 4077c478bd9Sstevel@tonic-gate 40897adda44SMarcel Telka if (getrlimit(RLIMIT_NOFILE, &rl) != 0) { 40997adda44SMarcel Telka syslog(LOG_ERR, "getrlimit failed"); 41097adda44SMarcel Telka } else { 41197adda44SMarcel Telka rl.rlim_cur = rl.rlim_max; 41297adda44SMarcel Telka if (setrlimit(RLIMIT_NOFILE, &rl) != 0) 41397adda44SMarcel Telka syslog(LOG_ERR, "setrlimit failed"); 41497adda44SMarcel Telka } 41597adda44SMarcel Telka 41697adda44SMarcel Telka (void) enable_extended_FILE_stdio(-1, -1); 41797adda44SMarcel Telka 418361f55a5SMarcel Telka ret = nfs_smf_get_iprop("mountd_max_threads", &max_threads, 419361f55a5SMarcel Telka DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD); 420361f55a5SMarcel Telka if (ret != SA_OK) { 421361f55a5SMarcel Telka syslog(LOG_ERR, "Reading of mountd_max_threads from SMF " 422361f55a5SMarcel Telka "failed, using default value"); 423361f55a5SMarcel Telka } 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "vrm:")) != EOF) { 4267c478bd9Sstevel@tonic-gate switch (c) { 4277c478bd9Sstevel@tonic-gate case 'v': 4287c478bd9Sstevel@tonic-gate verbose++; 4297c478bd9Sstevel@tonic-gate break; 4307c478bd9Sstevel@tonic-gate case 'r': 4317c478bd9Sstevel@tonic-gate rejecting = 1; 4327c478bd9Sstevel@tonic-gate break; 4337c478bd9Sstevel@tonic-gate case 'm': 434361f55a5SMarcel Telka if (convert_int(&tmp, optarg) != 0 || tmp < 1) { 435361f55a5SMarcel Telka (void) fprintf(stderr, "%s: invalid " 436361f55a5SMarcel Telka "max_threads option, using defaults\n", 4377c478bd9Sstevel@tonic-gate argv[0]); 4387c478bd9Sstevel@tonic-gate break; 4397c478bd9Sstevel@tonic-gate } 440361f55a5SMarcel Telka max_threads = tmp; 441361f55a5SMarcel Telka break; 442361f55a5SMarcel Telka default: 443361f55a5SMarcel Telka fprintf(stderr, "usage: mountd [-v] [-r]\n"); 444361f55a5SMarcel Telka exit(1); 445361f55a5SMarcel Telka } 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate /* 4497c478bd9Sstevel@tonic-gate * Read in the NFS version values from config file. 4507c478bd9Sstevel@tonic-gate */ 451dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States bufsz = 4; 452dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States ret = nfs_smf_get_prop("server_versmin", defval, DEFAULT_INSTANCE, 453dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States SCF_TYPE_INTEGER, NFSD, &bufsz); 454dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States if (ret == SA_OK) { 4557c478bd9Sstevel@tonic-gate errno = 0; 4567c478bd9Sstevel@tonic-gate defvers = strtol(defval, (char **)NULL, 10); 4577c478bd9Sstevel@tonic-gate if (errno == 0) { 4587c478bd9Sstevel@tonic-gate mount_vers_min = defvers; 4597c478bd9Sstevel@tonic-gate /* 4607c478bd9Sstevel@tonic-gate * special because NFSv2 is 4617c478bd9Sstevel@tonic-gate * supported by mount v1 & v2 4627c478bd9Sstevel@tonic-gate */ 4637c478bd9Sstevel@tonic-gate if (defvers == NFS_VERSION) 4647c478bd9Sstevel@tonic-gate mount_vers_min = MOUNTVERS; 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate } 467dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 468dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States bufsz = 4; 469dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States ret = nfs_smf_get_prop("server_versmax", defval, DEFAULT_INSTANCE, 470dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States SCF_TYPE_INTEGER, NFSD, &bufsz); 471dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States if (ret == SA_OK) { 4727c478bd9Sstevel@tonic-gate errno = 0; 4737c478bd9Sstevel@tonic-gate defvers = strtol(defval, (char **)NULL, 10); 4747c478bd9Sstevel@tonic-gate if (errno == 0) { 4757c478bd9Sstevel@tonic-gate mount_vers_max = defvers; 4767c478bd9Sstevel@tonic-gate } 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate 479361f55a5SMarcel Telka ret = nfs_smf_get_iprop("mountd_listen_backlog", &listen_backlog, 480361f55a5SMarcel Telka DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD); 481361f55a5SMarcel Telka if (ret != SA_OK) { 482361f55a5SMarcel Telka syslog(LOG_ERR, "Reading of mountd_listen_backlog from SMF " 483361f55a5SMarcel Telka "failed, using default value"); 484361f55a5SMarcel Telka } 485361f55a5SMarcel Telka 4867c478bd9Sstevel@tonic-gate /* 4877c478bd9Sstevel@tonic-gate * Sanity check versions, 4887c478bd9Sstevel@tonic-gate * even though we may get versions > MOUNTVERS3, we still need 4897c478bd9Sstevel@tonic-gate * to start nfsauth service, so continue on regardless of values. 4907c478bd9Sstevel@tonic-gate */ 4917c478bd9Sstevel@tonic-gate if (mount_vers_min > mount_vers_max) { 492361f55a5SMarcel Telka fprintf(stderr, "server_versmin > server_versmax\n"); 4937c478bd9Sstevel@tonic-gate mount_vers_max = mount_vers_min; 4947c478bd9Sstevel@tonic-gate } 4957c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 4967c478bd9Sstevel@tonic-gate (void) rwlock_init(&sharetab_lock, USYNC_THREAD, NULL); 4977c478bd9Sstevel@tonic-gate (void) mutex_init(&mnttab_lock, USYNC_THREAD, NULL); 4984a508a79SThomas Haynes (void) mutex_init(&logging_queue_lock, USYNC_THREAD, NULL); 4994a508a79SThomas Haynes (void) cond_init(&logging_queue_cv, USYNC_THREAD, NULL); 5004a508a79SThomas Haynes 5017c478bd9Sstevel@tonic-gate netgroup_init(); 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 5047c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 5057c478bd9Sstevel@tonic-gate #endif 5067c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate /* Don't drop core if the NFS module isn't loaded. */ 5097c478bd9Sstevel@tonic-gate (void) signal(SIGSYS, SIG_IGN); 5107c478bd9Sstevel@tonic-gate 511250a0733Sth199096 pipe_fd = daemonize_init(); 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate /* 5147c478bd9Sstevel@tonic-gate * If we coredump it'll be in /core 5157c478bd9Sstevel@tonic-gate */ 5167c478bd9Sstevel@tonic-gate if (chdir("/") < 0) 517361f55a5SMarcel Telka fprintf(stderr, "chdir /: %s\n", strerror(errno)); 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate openlog("mountd", LOG_PID, LOG_DAEMON); 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate /* 5227c478bd9Sstevel@tonic-gate * establish our lock on the lock file and write our pid to it. 5237c478bd9Sstevel@tonic-gate * exit if some other process holds the lock, or if there's any 5247c478bd9Sstevel@tonic-gate * error in writing/locking the file. 5257c478bd9Sstevel@tonic-gate */ 5267c478bd9Sstevel@tonic-gate pid = _enter_daemon_lock(MOUNTD); 5277c478bd9Sstevel@tonic-gate switch (pid) { 5287c478bd9Sstevel@tonic-gate case 0: 5297c478bd9Sstevel@tonic-gate break; 5307c478bd9Sstevel@tonic-gate case -1: 531361f55a5SMarcel Telka fprintf(stderr, "error locking for %s: %s\n", MOUNTD, 5327c478bd9Sstevel@tonic-gate strerror(errno)); 5337c478bd9Sstevel@tonic-gate exit(2); 5347c478bd9Sstevel@tonic-gate default: 5357c478bd9Sstevel@tonic-gate /* daemon was already running */ 5367c478bd9Sstevel@tonic-gate exit(0); 5377c478bd9Sstevel@tonic-gate } 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate audit_mountd_setup(); /* BSM */ 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate /* 54289621fe1SMarcel Telka * Get required system variables 54389621fe1SMarcel Telka */ 54489621fe1SMarcel Telka if ((ngroups_max = sysconf(_SC_NGROUPS_MAX)) == -1) { 54589621fe1SMarcel Telka syslog(LOG_ERR, "Unable to get _SC_NGROUPS_MAX"); 54689621fe1SMarcel Telka exit(1); 54789621fe1SMarcel Telka } 54889621fe1SMarcel Telka if ((pw_size = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) { 54989621fe1SMarcel Telka syslog(LOG_ERR, "Unable to get _SC_GETPW_R_SIZE_MAX"); 55089621fe1SMarcel Telka exit(1); 55189621fe1SMarcel Telka } 55289621fe1SMarcel Telka 55389621fe1SMarcel Telka /* 5542f416683SMarcel Telka * Set number of file descriptors to unlimited 5552f416683SMarcel Telka */ 5562f416683SMarcel Telka if (!rpc_control(RPC_SVC_USE_POLLFD, &rpc_svc_fdunlim)) { 5572f416683SMarcel Telka syslog(LOG_INFO, "unable to set number of FDs to unlimited"); 5582f416683SMarcel Telka } 5592f416683SMarcel Telka 5602f416683SMarcel Telka /* 5617c478bd9Sstevel@tonic-gate * Tell RPC that we want automatic thread mode. 5627c478bd9Sstevel@tonic-gate * A new thread will be spawned for each request. 5637c478bd9Sstevel@tonic-gate */ 5647c478bd9Sstevel@tonic-gate if (!rpc_control(RPC_SVC_MTMODE_SET, &rpc_svc_mode)) { 565361f55a5SMarcel Telka fprintf(stderr, "unable to set automatic MT mode\n"); 5667c478bd9Sstevel@tonic-gate exit(1); 5677c478bd9Sstevel@tonic-gate } 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate /* 5707c478bd9Sstevel@tonic-gate * Enable non-blocking mode and maximum record size checks for 5717c478bd9Sstevel@tonic-gate * connection oriented transports. 5727c478bd9Sstevel@tonic-gate */ 5737c478bd9Sstevel@tonic-gate if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) { 574361f55a5SMarcel Telka fprintf(stderr, "unable to set RPC max record size\n"); 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate /* 5787c478bd9Sstevel@tonic-gate * Prevent our non-priv udp and tcp ports bound w/wildcard addr 5797c478bd9Sstevel@tonic-gate * from being hijacked by a bind to a more specific addr. 5807c478bd9Sstevel@tonic-gate */ 5817c478bd9Sstevel@tonic-gate if (!rpc_control(__RPC_SVC_EXCLBIND_SET, &exclbind)) { 582361f55a5SMarcel Telka fprintf(stderr, "warning: unable to set udp/tcp EXCLBIND\n"); 5837c478bd9Sstevel@tonic-gate } 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate /* 586361f55a5SMarcel Telka * Set the maximum number of outstanding connection 587361f55a5SMarcel Telka * indications (listen backlog) to the value specified. 588361f55a5SMarcel Telka */ 589361f55a5SMarcel Telka if (listen_backlog > 0 && !rpc_control(__RPC_SVC_LSTNBKLOG_SET, 590361f55a5SMarcel Telka &listen_backlog)) { 591361f55a5SMarcel Telka fprintf(stderr, "unable to set listen backlog\n"); 592361f55a5SMarcel Telka exit(1); 593361f55a5SMarcel Telka } 594361f55a5SMarcel Telka 595361f55a5SMarcel Telka /* 596361f55a5SMarcel Telka * If max_threads was specified, then set the 5977c478bd9Sstevel@tonic-gate * maximum number of threads to the value specified. 5987c478bd9Sstevel@tonic-gate */ 599361f55a5SMarcel Telka if (max_threads > 0 && !rpc_control(RPC_SVC_THRMAX_SET, &max_threads)) { 600361f55a5SMarcel Telka fprintf(stderr, "unable to set max_threads\n"); 6017c478bd9Sstevel@tonic-gate exit(1); 6027c478bd9Sstevel@tonic-gate } 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate /* 6057c478bd9Sstevel@tonic-gate * Make sure to unregister any previous versions in case the 6067c478bd9Sstevel@tonic-gate * user is reconfiguring the server in interesting ways. 6077c478bd9Sstevel@tonic-gate */ 6087c478bd9Sstevel@tonic-gate svc_unreg(MOUNTPROG, MOUNTVERS); 6097c478bd9Sstevel@tonic-gate svc_unreg(MOUNTPROG, MOUNTVERS_POSIX); 6107c478bd9Sstevel@tonic-gate svc_unreg(MOUNTPROG, MOUNTVERS3); 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate /* 6131cc55349Srmesta * Create the nfsauth thread with same signal disposition 6141cc55349Srmesta * as the main thread. We need to create a separate thread 6151cc55349Srmesta * since mountd() will be both an RPC server (for remote 6161cc55349Srmesta * traffic) _and_ a doors server (for kernel upcalls). 6177c478bd9Sstevel@tonic-gate */ 6181cc55349Srmesta if (thr_create(NULL, 0, nfsauth_svc, 0, thr_flags, &nfsauth_thread)) { 619361f55a5SMarcel Telka fprintf(stderr, 620361f55a5SMarcel Telka gettext("Failed to create NFSAUTH svc thread\n")); 6211cc55349Srmesta exit(2); 6227c478bd9Sstevel@tonic-gate } 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate /* 625b89a8333Snatalie li - Sun Microsystems - Irvine United States * Create the cmd service thread with same signal disposition 626b89a8333Snatalie li - Sun Microsystems - Irvine United States * as the main thread. We need to create a separate thread 627b89a8333Snatalie li - Sun Microsystems - Irvine United States * since mountd() will be both an RPC server (for remote 628b89a8333Snatalie li - Sun Microsystems - Irvine United States * traffic) _and_ a doors server (for kernel upcalls). 629b89a8333Snatalie li - Sun Microsystems - Irvine United States */ 630b89a8333Snatalie li - Sun Microsystems - Irvine United States if (thr_create(NULL, 0, cmd_svc, 0, thr_flags, &cmd_thread)) { 631b89a8333Snatalie li - Sun Microsystems - Irvine United States syslog(LOG_ERR, gettext("Failed to create CMD svc thread")); 632b89a8333Snatalie li - Sun Microsystems - Irvine United States exit(2); 633b89a8333Snatalie li - Sun Microsystems - Irvine United States } 634b89a8333Snatalie li - Sun Microsystems - Irvine United States 635b89a8333Snatalie li - Sun Microsystems - Irvine United States /* 6364a508a79SThomas Haynes * Create an additional thread to service the rmtab and 6374a508a79SThomas Haynes * audit_mountd_mount logging for mount requests. Use the same 6384a508a79SThomas Haynes * signal disposition as the main thread. We create 6394a508a79SThomas Haynes * a separate thread to allow the mount request threads to 6404a508a79SThomas Haynes * clear as soon as possible. 6414a508a79SThomas Haynes */ 6424a508a79SThomas Haynes if (thr_create(NULL, 0, logging_svc, 0, thr_flags, &logging_thread)) { 6434a508a79SThomas Haynes syslog(LOG_ERR, gettext("Failed to create LOGGING svc thread")); 6444a508a79SThomas Haynes exit(2); 6454a508a79SThomas Haynes } 6464a508a79SThomas Haynes 6474a508a79SThomas Haynes /* 6487c478bd9Sstevel@tonic-gate * Create datagram and connection oriented services 6497c478bd9Sstevel@tonic-gate */ 6507c478bd9Sstevel@tonic-gate if (mount_vers_max >= MOUNTVERS) { 6517c478bd9Sstevel@tonic-gate if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "datagram_v") == 0) { 652250a0733Sth199096 fprintf(stderr, 653361f55a5SMarcel Telka "couldn't register datagram_v MOUNTVERS\n"); 6547c478bd9Sstevel@tonic-gate exit(1); 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "circuit_v") == 0) { 657250a0733Sth199096 fprintf(stderr, 658361f55a5SMarcel Telka "couldn't register circuit_v MOUNTVERS\n"); 6597c478bd9Sstevel@tonic-gate exit(1); 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate } 6624a508a79SThomas Haynes 6637c478bd9Sstevel@tonic-gate if (mount_vers_max >= MOUNTVERS_POSIX) { 6647c478bd9Sstevel@tonic-gate if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX, 6657c478bd9Sstevel@tonic-gate "datagram_v") == 0) { 666250a0733Sth199096 fprintf(stderr, 667361f55a5SMarcel Telka "couldn't register datagram_v MOUNTVERS_POSIX\n"); 6687c478bd9Sstevel@tonic-gate exit(1); 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX, 6717c478bd9Sstevel@tonic-gate "circuit_v") == 0) { 672250a0733Sth199096 fprintf(stderr, 673361f55a5SMarcel Telka "couldn't register circuit_v MOUNTVERS_POSIX\n"); 6747c478bd9Sstevel@tonic-gate exit(1); 6757c478bd9Sstevel@tonic-gate } 6767c478bd9Sstevel@tonic-gate } 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate if (mount_vers_max >= MOUNTVERS3) { 6797c478bd9Sstevel@tonic-gate if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "datagram_v") == 0) { 680250a0733Sth199096 fprintf(stderr, 681361f55a5SMarcel Telka "couldn't register datagram_v MOUNTVERS3\n"); 6827c478bd9Sstevel@tonic-gate exit(1); 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "circuit_v") == 0) { 685250a0733Sth199096 fprintf(stderr, 686361f55a5SMarcel Telka "couldn't register circuit_v MOUNTVERS3\n"); 6877c478bd9Sstevel@tonic-gate exit(1); 6887c478bd9Sstevel@tonic-gate } 6897c478bd9Sstevel@tonic-gate } 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate /* 6927c478bd9Sstevel@tonic-gate * Start serving 6937c478bd9Sstevel@tonic-gate */ 6947c478bd9Sstevel@tonic-gate rmtab_load(); 695250a0733Sth199096 696250a0733Sth199096 daemonize_fini(pipe_fd); 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate /* Get rid of the most dangerous basic privileges. */ 6997c478bd9Sstevel@tonic-gate __fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_INFO, PRIV_PROC_SESSION, 7007c478bd9Sstevel@tonic-gate (char *)NULL); 7017c478bd9Sstevel@tonic-gate 7027c478bd9Sstevel@tonic-gate svc_run(); 7037c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Error: svc_run shouldn't have returned"); 7047c478bd9Sstevel@tonic-gate abort(); 705250a0733Sth199096 7067c478bd9Sstevel@tonic-gate /* NOTREACHED */ 70711606941Sjwahlig return (0); 7087c478bd9Sstevel@tonic-gate } 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate /* 7117c478bd9Sstevel@tonic-gate * Server procedure switch routine 7127c478bd9Sstevel@tonic-gate */ 7137c478bd9Sstevel@tonic-gate void 7147c478bd9Sstevel@tonic-gate mnt(struct svc_req *rqstp, SVCXPRT *transp) 7157c478bd9Sstevel@tonic-gate { 7167c478bd9Sstevel@tonic-gate switch (rqstp->rq_proc) { 7177c478bd9Sstevel@tonic-gate case NULLPROC: 7187c478bd9Sstevel@tonic-gate errno = 0; 7197c478bd9Sstevel@tonic-gate if (!svc_sendreply(transp, xdr_void, (char *)0)) 7207c478bd9Sstevel@tonic-gate log_cant_reply(transp); 7217c478bd9Sstevel@tonic-gate return; 7227c478bd9Sstevel@tonic-gate 7237c478bd9Sstevel@tonic-gate case MOUNTPROC_MNT: 7244a508a79SThomas Haynes (void) mount(rqstp); 7257c478bd9Sstevel@tonic-gate return; 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate case MOUNTPROC_DUMP: 7287c478bd9Sstevel@tonic-gate mntlist_send(transp); 7297c478bd9Sstevel@tonic-gate return; 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate case MOUNTPROC_UMNT: 7327c478bd9Sstevel@tonic-gate umount(rqstp); 7337c478bd9Sstevel@tonic-gate return; 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate case MOUNTPROC_UMNTALL: 7367c478bd9Sstevel@tonic-gate umountall(rqstp); 7377c478bd9Sstevel@tonic-gate return; 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate case MOUNTPROC_EXPORT: 7407c478bd9Sstevel@tonic-gate case MOUNTPROC_EXPORTALL: 7417c478bd9Sstevel@tonic-gate export(rqstp); 7427c478bd9Sstevel@tonic-gate return; 7437c478bd9Sstevel@tonic-gate 7447c478bd9Sstevel@tonic-gate case MOUNTPROC_PATHCONF: 7457c478bd9Sstevel@tonic-gate if (rqstp->rq_vers == MOUNTVERS_POSIX) 7467c478bd9Sstevel@tonic-gate mnt_pathconf(rqstp); 7477c478bd9Sstevel@tonic-gate else 7487c478bd9Sstevel@tonic-gate svcerr_noproc(transp); 7497c478bd9Sstevel@tonic-gate return; 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate default: 7527c478bd9Sstevel@tonic-gate svcerr_noproc(transp); 7537c478bd9Sstevel@tonic-gate return; 7547c478bd9Sstevel@tonic-gate } 7557c478bd9Sstevel@tonic-gate } 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate void 758*a9685eaaSMarcel Telka log_cant_reply_cln(struct cln *cln) 7597c478bd9Sstevel@tonic-gate { 7607c478bd9Sstevel@tonic-gate int saverrno; 76154d34259SMarcel Telka char *host; 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate saverrno = errno; /* save error code */ 764*a9685eaaSMarcel Telka 765*a9685eaaSMarcel Telka host = cln_gethost(cln); 766*a9685eaaSMarcel Telka if (host == NULL) 7677c478bd9Sstevel@tonic-gate return; 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate errno = saverrno; 7707c478bd9Sstevel@tonic-gate if (errno == 0) 7717c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "couldn't send reply to %s", host); 7727c478bd9Sstevel@tonic-gate else 7737c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "couldn't send reply to %s: %m", host); 774*a9685eaaSMarcel Telka } 7757c478bd9Sstevel@tonic-gate 776*a9685eaaSMarcel Telka void 777*a9685eaaSMarcel Telka log_cant_reply(SVCXPRT *transp) 778*a9685eaaSMarcel Telka { 779*a9685eaaSMarcel Telka int saverrno; 780*a9685eaaSMarcel Telka struct cln cln; 781*a9685eaaSMarcel Telka 782*a9685eaaSMarcel Telka saverrno = errno; /* save error code */ 783*a9685eaaSMarcel Telka cln_init(&cln, transp); 784*a9685eaaSMarcel Telka errno = saverrno; 785*a9685eaaSMarcel Telka 786*a9685eaaSMarcel Telka log_cant_reply_cln(&cln); 787*a9685eaaSMarcel Telka 788*a9685eaaSMarcel Telka cln_fini(&cln); 7897c478bd9Sstevel@tonic-gate } 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate /* 7927c478bd9Sstevel@tonic-gate * Answer pathconf questions for the mount point fs 7937c478bd9Sstevel@tonic-gate */ 7947c478bd9Sstevel@tonic-gate static void 7957c478bd9Sstevel@tonic-gate mnt_pathconf(struct svc_req *rqstp) 7967c478bd9Sstevel@tonic-gate { 7977c478bd9Sstevel@tonic-gate SVCXPRT *transp; 7987c478bd9Sstevel@tonic-gate struct pathcnf p; 7997c478bd9Sstevel@tonic-gate char *path, rpath[MAXPATHLEN]; 8007c478bd9Sstevel@tonic-gate struct stat st; 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate transp = rqstp->rq_xprt; 8037c478bd9Sstevel@tonic-gate path = NULL; 8047c478bd9Sstevel@tonic-gate (void) memset((caddr_t)&p, 0, sizeof (p)); 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) { 8077c478bd9Sstevel@tonic-gate svcerr_decode(transp); 8087c478bd9Sstevel@tonic-gate return; 8097c478bd9Sstevel@tonic-gate } 8107c478bd9Sstevel@tonic-gate if (lstat(path, &st) < 0) { 8117c478bd9Sstevel@tonic-gate _PC_SET(_PC_ERROR, p.pc_mask); 8127c478bd9Sstevel@tonic-gate goto done; 8137c478bd9Sstevel@tonic-gate } 8147c478bd9Sstevel@tonic-gate /* 8157c478bd9Sstevel@tonic-gate * Get a path without symbolic links. 8167c478bd9Sstevel@tonic-gate */ 8177c478bd9Sstevel@tonic-gate if (realpath(path, rpath) == NULL) { 8187c478bd9Sstevel@tonic-gate syslog(LOG_DEBUG, 8197c478bd9Sstevel@tonic-gate "mount request: realpath failed on %s: %m", 8207c478bd9Sstevel@tonic-gate path); 8217c478bd9Sstevel@tonic-gate _PC_SET(_PC_ERROR, p.pc_mask); 8227c478bd9Sstevel@tonic-gate goto done; 8237c478bd9Sstevel@tonic-gate } 8247c478bd9Sstevel@tonic-gate (void) memset((caddr_t)&p, 0, sizeof (p)); 8257c478bd9Sstevel@tonic-gate /* 8267c478bd9Sstevel@tonic-gate * can't ask about devices over NFS 8277c478bd9Sstevel@tonic-gate */ 8287c478bd9Sstevel@tonic-gate _PC_SET(_PC_MAX_CANON, p.pc_mask); 8297c478bd9Sstevel@tonic-gate _PC_SET(_PC_MAX_INPUT, p.pc_mask); 8307c478bd9Sstevel@tonic-gate _PC_SET(_PC_PIPE_BUF, p.pc_mask); 8317c478bd9Sstevel@tonic-gate _PC_SET(_PC_VDISABLE, p.pc_mask); 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate errno = 0; 8347c478bd9Sstevel@tonic-gate p.pc_link_max = pathconf(rpath, _PC_LINK_MAX); 8357c478bd9Sstevel@tonic-gate if (errno) 8367c478bd9Sstevel@tonic-gate _PC_SET(_PC_LINK_MAX, p.pc_mask); 8377c478bd9Sstevel@tonic-gate p.pc_name_max = pathconf(rpath, _PC_NAME_MAX); 8387c478bd9Sstevel@tonic-gate if (errno) 8397c478bd9Sstevel@tonic-gate _PC_SET(_PC_NAME_MAX, p.pc_mask); 8407c478bd9Sstevel@tonic-gate p.pc_path_max = pathconf(rpath, _PC_PATH_MAX); 8417c478bd9Sstevel@tonic-gate if (errno) 8427c478bd9Sstevel@tonic-gate _PC_SET(_PC_PATH_MAX, p.pc_mask); 8437c478bd9Sstevel@tonic-gate if (pathconf(rpath, _PC_NO_TRUNC) == 1) 8447c478bd9Sstevel@tonic-gate _PC_SET(_PC_NO_TRUNC, p.pc_mask); 8457c478bd9Sstevel@tonic-gate if (pathconf(rpath, _PC_CHOWN_RESTRICTED) == 1) 8467c478bd9Sstevel@tonic-gate _PC_SET(_PC_CHOWN_RESTRICTED, p.pc_mask); 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate done: 8497c478bd9Sstevel@tonic-gate errno = 0; 8507c478bd9Sstevel@tonic-gate if (!svc_sendreply(transp, xdr_ppathcnf, (char *)&p)) 8517c478bd9Sstevel@tonic-gate log_cant_reply(transp); 8527c478bd9Sstevel@tonic-gate if (path != NULL) 8537c478bd9Sstevel@tonic-gate svc_freeargs(transp, xdr_dirpath, (caddr_t)&path); 8547c478bd9Sstevel@tonic-gate } 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate /* 8577c478bd9Sstevel@tonic-gate * If the rootmount (export) option is specified, the all mount requests for 8587c478bd9Sstevel@tonic-gate * subdirectories return EACCES. 8597c478bd9Sstevel@tonic-gate */ 8607c478bd9Sstevel@tonic-gate static int 8614a508a79SThomas Haynes checkrootmount(share_t *sh, char *rpath) 8627c478bd9Sstevel@tonic-gate { 8637c478bd9Sstevel@tonic-gate char *val; 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate if ((val = getshareopt(sh->sh_opts, SHOPT_NOSUB)) != NULL) { 8667c478bd9Sstevel@tonic-gate free(val); 8677c478bd9Sstevel@tonic-gate if (strcmp(sh->sh_path, rpath) != 0) 8687c478bd9Sstevel@tonic-gate return (0); 8697c478bd9Sstevel@tonic-gate else 8707c478bd9Sstevel@tonic-gate return (1); 8717c478bd9Sstevel@tonic-gate } else 8727c478bd9Sstevel@tonic-gate return (1); 8737c478bd9Sstevel@tonic-gate } 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate #define MAX_FLAVORS 128 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate /* 8787c478bd9Sstevel@tonic-gate * Return only EACCES if client does not have access 8797c478bd9Sstevel@tonic-gate * to this directory. 8807c478bd9Sstevel@tonic-gate * "If the server exports only /a/b, an attempt to 8817c478bd9Sstevel@tonic-gate * mount a/b/c will fail with ENOENT if the directory 8827c478bd9Sstevel@tonic-gate * does not exist"... However, if the client 8837c478bd9Sstevel@tonic-gate * does not have access to /a/b, an attacker can 8847c478bd9Sstevel@tonic-gate * determine whether the directory exists. 8857c478bd9Sstevel@tonic-gate * This routine checks either existence of the file or 8867c478bd9Sstevel@tonic-gate * existence of the file name entry in the mount table. 8877c478bd9Sstevel@tonic-gate * If the file exists and there is no file name entry, 8887c478bd9Sstevel@tonic-gate * the error returned should be EACCES. 8897c478bd9Sstevel@tonic-gate * If the file does not exist, it must be determined 8907c478bd9Sstevel@tonic-gate * whether the client has access to a parent 8917c478bd9Sstevel@tonic-gate * directory. If the client has access to a parent 8927c478bd9Sstevel@tonic-gate * directory, the error returned should be ENOENT, 8937c478bd9Sstevel@tonic-gate * otherwise EACCES. 8947c478bd9Sstevel@tonic-gate */ 8957c478bd9Sstevel@tonic-gate static int 896*a9685eaaSMarcel Telka mount_enoent_error(struct cln *cln, char *path, char *rpath, int *flavor_list) 8977c478bd9Sstevel@tonic-gate { 8987c478bd9Sstevel@tonic-gate char *checkpath, *dp; 8994a508a79SThomas Haynes share_t *sh = NULL; 9007c478bd9Sstevel@tonic-gate int realpath_error = ENOENT, reply_error = EACCES, lofs_tried = 0; 9017c478bd9Sstevel@tonic-gate int flavor_count; 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate checkpath = strdup(path); 9047c478bd9Sstevel@tonic-gate if (checkpath == NULL) { 9057c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "mount_enoent: no memory"); 9067c478bd9Sstevel@tonic-gate return (EACCES); 9077c478bd9Sstevel@tonic-gate } 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate /* CONSTCOND */ 9107c478bd9Sstevel@tonic-gate while (1) { 9117c478bd9Sstevel@tonic-gate if (sh) { 9127c478bd9Sstevel@tonic-gate sharefree(sh); 9137c478bd9Sstevel@tonic-gate sh = NULL; 9147c478bd9Sstevel@tonic-gate } 9154a508a79SThomas Haynes 9167c478bd9Sstevel@tonic-gate if ((sh = findentry(rpath)) == NULL && 9177c478bd9Sstevel@tonic-gate (sh = find_lofsentry(rpath, &lofs_tried)) == NULL) { 9187c478bd9Sstevel@tonic-gate /* 9197c478bd9Sstevel@tonic-gate * There is no file name entry. 9207c478bd9Sstevel@tonic-gate * If the file (with symbolic links resolved) exists, 9217c478bd9Sstevel@tonic-gate * the error returned should be EACCES. 9227c478bd9Sstevel@tonic-gate */ 9237c478bd9Sstevel@tonic-gate if (realpath_error == 0) 9247c478bd9Sstevel@tonic-gate break; 9257c478bd9Sstevel@tonic-gate } else if (checkrootmount(sh, rpath) == 0) { 9267c478bd9Sstevel@tonic-gate /* 9277c478bd9Sstevel@tonic-gate * This is a "nosub" only export, in which case, 9287c478bd9Sstevel@tonic-gate * mounting subdirectories isn't allowed. 9297c478bd9Sstevel@tonic-gate * If the file (with symbolic links resolved) exists, 9307c478bd9Sstevel@tonic-gate * the error returned should be EACCES. 9317c478bd9Sstevel@tonic-gate */ 9327c478bd9Sstevel@tonic-gate if (realpath_error == 0) 9337c478bd9Sstevel@tonic-gate break; 9347c478bd9Sstevel@tonic-gate } else { 9357c478bd9Sstevel@tonic-gate /* 9367c478bd9Sstevel@tonic-gate * Check permissions in mount table. 9377c478bd9Sstevel@tonic-gate */ 9387c478bd9Sstevel@tonic-gate if (newopts(sh->sh_opts)) 939*a9685eaaSMarcel Telka flavor_count = getclientsflavors_new(sh, cln, 940*a9685eaaSMarcel Telka flavor_list); 9417c478bd9Sstevel@tonic-gate else 942*a9685eaaSMarcel Telka flavor_count = getclientsflavors_old(sh, cln, 943*a9685eaaSMarcel Telka flavor_list); 9447c478bd9Sstevel@tonic-gate if (flavor_count != 0) { 9457c478bd9Sstevel@tonic-gate /* 9467c478bd9Sstevel@tonic-gate * Found entry in table and 9477c478bd9Sstevel@tonic-gate * client has correct permissions. 9487c478bd9Sstevel@tonic-gate */ 9497c478bd9Sstevel@tonic-gate reply_error = ENOENT; 9507c478bd9Sstevel@tonic-gate break; 9517c478bd9Sstevel@tonic-gate } 9527c478bd9Sstevel@tonic-gate } 9534a508a79SThomas Haynes 9547c478bd9Sstevel@tonic-gate /* 9557c478bd9Sstevel@tonic-gate * Check all parent directories. 9567c478bd9Sstevel@tonic-gate */ 9577c478bd9Sstevel@tonic-gate dp = strrchr(checkpath, '/'); 9587c478bd9Sstevel@tonic-gate if (dp == NULL) 9597c478bd9Sstevel@tonic-gate break; 9607c478bd9Sstevel@tonic-gate *dp = '\0'; 9617c478bd9Sstevel@tonic-gate if (strlen(checkpath) == 0) 9627c478bd9Sstevel@tonic-gate break; 9637c478bd9Sstevel@tonic-gate /* 9647c478bd9Sstevel@tonic-gate * Get the real path (no symbolic links in it) 9657c478bd9Sstevel@tonic-gate */ 9667c478bd9Sstevel@tonic-gate if (realpath(checkpath, rpath) == NULL) { 9677c478bd9Sstevel@tonic-gate if (errno != ENOENT) 9687c478bd9Sstevel@tonic-gate break; 9697c478bd9Sstevel@tonic-gate } else { 9707c478bd9Sstevel@tonic-gate realpath_error = 0; 9717c478bd9Sstevel@tonic-gate } 9727c478bd9Sstevel@tonic-gate } 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate if (sh) 9757c478bd9Sstevel@tonic-gate sharefree(sh); 9767c478bd9Sstevel@tonic-gate free(checkpath); 9777c478bd9Sstevel@tonic-gate return (reply_error); 9787c478bd9Sstevel@tonic-gate } 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate /* 9814a508a79SThomas Haynes * We need to inform the caller whether or not we were 9824a508a79SThomas Haynes * able to add a node to the queue. If we are not, then 9834a508a79SThomas Haynes * it is up to the caller to go ahead and log the data. 9844a508a79SThomas Haynes */ 9854a508a79SThomas Haynes static int 9864a508a79SThomas Haynes enqueue_logging_data(char *host, SVCXPRT *transp, char *path, 9874a508a79SThomas Haynes char *rpath, int status, int error) 9884a508a79SThomas Haynes { 9894a508a79SThomas Haynes logging_data *lq; 9904a508a79SThomas Haynes struct netbuf *nb; 9914a508a79SThomas Haynes 9924a508a79SThomas Haynes lq = (logging_data *)calloc(1, sizeof (logging_data)); 9934a508a79SThomas Haynes if (lq == NULL) 9944a508a79SThomas Haynes goto cleanup; 9954a508a79SThomas Haynes 9964a508a79SThomas Haynes /* 9974a508a79SThomas Haynes * We might not yet have the host... 9984a508a79SThomas Haynes */ 9994a508a79SThomas Haynes if (host) { 10004a508a79SThomas Haynes DTRACE_PROBE1(mountd, log_host, host); 10014a508a79SThomas Haynes lq->ld_host = strdup(host); 10024a508a79SThomas Haynes if (lq->ld_host == NULL) 10034a508a79SThomas Haynes goto cleanup; 10044a508a79SThomas Haynes } else { 10054a508a79SThomas Haynes DTRACE_PROBE(mountd, log_no_host); 10064a508a79SThomas Haynes 10074a508a79SThomas Haynes lq->ld_netid = strdup(transp->xp_netid); 10084a508a79SThomas Haynes if (lq->ld_netid == NULL) 10094a508a79SThomas Haynes goto cleanup; 10104a508a79SThomas Haynes 10114a508a79SThomas Haynes lq->ld_nb = calloc(1, sizeof (struct netbuf)); 10124a508a79SThomas Haynes if (lq->ld_nb == NULL) 10134a508a79SThomas Haynes goto cleanup; 10144a508a79SThomas Haynes 10154a508a79SThomas Haynes nb = svc_getrpccaller(transp); 10164a508a79SThomas Haynes if (nb == NULL) { 10174a508a79SThomas Haynes DTRACE_PROBE(mountd, e__nb__enqueue); 10184a508a79SThomas Haynes goto cleanup; 10194a508a79SThomas Haynes } 10204a508a79SThomas Haynes 10214a508a79SThomas Haynes DTRACE_PROBE(mountd, nb_set_enqueue); 10224a508a79SThomas Haynes 10234a508a79SThomas Haynes lq->ld_nb->maxlen = nb->maxlen; 10244a508a79SThomas Haynes lq->ld_nb->len = nb->len; 10254a508a79SThomas Haynes 10264a508a79SThomas Haynes lq->ld_nb->buf = malloc(lq->ld_nb->len); 10274a508a79SThomas Haynes if (lq->ld_nb->buf == NULL) 10284a508a79SThomas Haynes goto cleanup; 10294a508a79SThomas Haynes 10304a508a79SThomas Haynes bcopy(nb->buf, lq->ld_nb->buf, lq->ld_nb->len); 10314a508a79SThomas Haynes } 10324a508a79SThomas Haynes 10334a508a79SThomas Haynes lq->ld_path = strdup(path); 10344a508a79SThomas Haynes if (lq->ld_path == NULL) 10354a508a79SThomas Haynes goto cleanup; 10364a508a79SThomas Haynes 10374a508a79SThomas Haynes if (!error) { 10384a508a79SThomas Haynes lq->ld_rpath = strdup(rpath); 10394a508a79SThomas Haynes if (lq->ld_rpath == NULL) 10404a508a79SThomas Haynes goto cleanup; 10414a508a79SThomas Haynes } 10424a508a79SThomas Haynes 10434a508a79SThomas Haynes lq->ld_status = status; 10444a508a79SThomas Haynes 10454a508a79SThomas Haynes /* 10464a508a79SThomas Haynes * Add to the tail of the logging queue. 10474a508a79SThomas Haynes */ 10484a508a79SThomas Haynes (void) mutex_lock(&logging_queue_lock); 10494a508a79SThomas Haynes if (logging_tail == NULL) { 10504a508a79SThomas Haynes logging_tail = logging_head = lq; 10514a508a79SThomas Haynes } else { 10524a508a79SThomas Haynes logging_tail->ld_next = lq; 10534a508a79SThomas Haynes logging_tail = lq; 10544a508a79SThomas Haynes } 10554a508a79SThomas Haynes (void) cond_signal(&logging_queue_cv); 10564a508a79SThomas Haynes (void) mutex_unlock(&logging_queue_lock); 10574a508a79SThomas Haynes 10584a508a79SThomas Haynes return (TRUE); 10594a508a79SThomas Haynes 10604a508a79SThomas Haynes cleanup: 10614a508a79SThomas Haynes 10624a508a79SThomas Haynes free_logging_data(lq); 10634a508a79SThomas Haynes 10644a508a79SThomas Haynes return (FALSE); 10654a508a79SThomas Haynes } 10664a508a79SThomas Haynes 1067*a9685eaaSMarcel Telka 1068*a9685eaaSMarcel Telka #define CLN_CLNAMES (1 << 0) 1069*a9685eaaSMarcel Telka #define CLN_HOST (1 << 1) 1070*a9685eaaSMarcel Telka 1071*a9685eaaSMarcel Telka static void 1072*a9685eaaSMarcel Telka cln_init_common(struct cln *cln, SVCXPRT *transp, char *netid, 1073*a9685eaaSMarcel Telka struct netbuf *nbuf) 1074*a9685eaaSMarcel Telka { 1075*a9685eaaSMarcel Telka if ((cln->transp = transp) != NULL) { 1076*a9685eaaSMarcel Telka assert(netid == NULL && nbuf == NULL); 1077*a9685eaaSMarcel Telka cln->netid = transp->xp_netid; 1078*a9685eaaSMarcel Telka cln->nbuf = svc_getrpccaller(transp); 1079*a9685eaaSMarcel Telka } else { 1080*a9685eaaSMarcel Telka cln->netid = netid; 1081*a9685eaaSMarcel Telka cln->nbuf = nbuf; 1082*a9685eaaSMarcel Telka } 1083*a9685eaaSMarcel Telka 1084*a9685eaaSMarcel Telka cln->nconf = NULL; 1085*a9685eaaSMarcel Telka cln->clnames = NULL; 1086*a9685eaaSMarcel Telka cln->host = NULL; 1087*a9685eaaSMarcel Telka 1088*a9685eaaSMarcel Telka cln->flags = 0; 1089*a9685eaaSMarcel Telka } 1090*a9685eaaSMarcel Telka 1091*a9685eaaSMarcel Telka void 1092*a9685eaaSMarcel Telka cln_init(struct cln *cln, SVCXPRT *transp) 1093*a9685eaaSMarcel Telka { 1094*a9685eaaSMarcel Telka cln_init_common(cln, transp, NULL, NULL); 1095*a9685eaaSMarcel Telka } 1096*a9685eaaSMarcel Telka 1097*a9685eaaSMarcel Telka void 1098*a9685eaaSMarcel Telka cln_init_lazy(struct cln *cln, char *netid, struct netbuf *nbuf) 1099*a9685eaaSMarcel Telka { 1100*a9685eaaSMarcel Telka cln_init_common(cln, NULL, netid, nbuf); 1101*a9685eaaSMarcel Telka } 1102*a9685eaaSMarcel Telka 1103*a9685eaaSMarcel Telka void 1104*a9685eaaSMarcel Telka cln_fini(struct cln *cln) 1105*a9685eaaSMarcel Telka { 1106*a9685eaaSMarcel Telka if (cln->nconf != NULL) 1107*a9685eaaSMarcel Telka freenetconfigent(cln->nconf); 1108*a9685eaaSMarcel Telka 1109*a9685eaaSMarcel Telka if (cln->clnames != NULL) 1110*a9685eaaSMarcel Telka netdir_free(cln->clnames, ND_HOSTSERVLIST); 1111*a9685eaaSMarcel Telka 1112*a9685eaaSMarcel Telka free(cln->host); 1113*a9685eaaSMarcel Telka } 1114*a9685eaaSMarcel Telka 1115*a9685eaaSMarcel Telka struct netbuf * 1116*a9685eaaSMarcel Telka cln_getnbuf(struct cln *cln) 1117*a9685eaaSMarcel Telka { 1118*a9685eaaSMarcel Telka return (cln->nbuf); 1119*a9685eaaSMarcel Telka } 1120*a9685eaaSMarcel Telka 1121*a9685eaaSMarcel Telka struct nd_hostservlist * 1122*a9685eaaSMarcel Telka cln_getclientsnames(struct cln *cln) 1123*a9685eaaSMarcel Telka { 1124*a9685eaaSMarcel Telka if ((cln->flags & CLN_CLNAMES) == 0) { 1125*a9685eaaSMarcel Telka /* 1126*a9685eaaSMarcel Telka * nconf is not needed if we do not have nbuf (see 1127*a9685eaaSMarcel Telka * cln_gethost() too), so we check for nbuf and in a case it is 1128*a9685eaaSMarcel Telka * NULL we do not try to get nconf. 1129*a9685eaaSMarcel Telka */ 1130*a9685eaaSMarcel Telka if (cln->netid != NULL && cln->nbuf != NULL) { 1131*a9685eaaSMarcel Telka cln->nconf = getnetconfigent(cln->netid); 1132*a9685eaaSMarcel Telka if (cln->nconf == NULL) 1133*a9685eaaSMarcel Telka syslog(LOG_ERR, "%s: getnetconfigent failed", 1134*a9685eaaSMarcel Telka cln->netid); 1135*a9685eaaSMarcel Telka } 1136*a9685eaaSMarcel Telka 1137*a9685eaaSMarcel Telka if (cln->nconf != NULL && cln->nbuf != NULL) 1138*a9685eaaSMarcel Telka (void) __netdir_getbyaddr_nosrv(cln->nconf, 1139*a9685eaaSMarcel Telka &cln->clnames, cln->nbuf); 1140*a9685eaaSMarcel Telka 1141*a9685eaaSMarcel Telka cln->flags |= CLN_CLNAMES; 1142*a9685eaaSMarcel Telka } 1143*a9685eaaSMarcel Telka 1144*a9685eaaSMarcel Telka return (cln->clnames); 1145*a9685eaaSMarcel Telka } 1146*a9685eaaSMarcel Telka 1147*a9685eaaSMarcel Telka /* 1148*a9685eaaSMarcel Telka * Return B_TRUE if the host is already available at no cost 1149*a9685eaaSMarcel Telka */ 1150*a9685eaaSMarcel Telka boolean_t 1151*a9685eaaSMarcel Telka cln_havehost(struct cln *cln) 1152*a9685eaaSMarcel Telka { 1153*a9685eaaSMarcel Telka return ((cln->flags & (CLN_CLNAMES | CLN_HOST)) != 0); 1154*a9685eaaSMarcel Telka } 1155*a9685eaaSMarcel Telka 1156*a9685eaaSMarcel Telka char * 1157*a9685eaaSMarcel Telka cln_gethost(struct cln *cln) 1158*a9685eaaSMarcel Telka { 1159*a9685eaaSMarcel Telka if (cln_getclientsnames(cln) != NULL) 1160*a9685eaaSMarcel Telka return (cln->clnames->h_hostservs[0].h_host); 1161*a9685eaaSMarcel Telka 1162*a9685eaaSMarcel Telka if ((cln->flags & CLN_HOST) == 0) { 1163*a9685eaaSMarcel Telka if (cln->nconf == NULL || cln->nbuf == NULL) { 1164*a9685eaaSMarcel Telka cln->host = strdup("(anon)"); 1165*a9685eaaSMarcel Telka } else { 1166*a9685eaaSMarcel Telka char host[MAXIPADDRLEN]; 1167*a9685eaaSMarcel Telka 1168*a9685eaaSMarcel Telka if (strcmp(cln->nconf->nc_protofmly, NC_INET) == 0) { 1169*a9685eaaSMarcel Telka struct sockaddr_in *sa; 1170*a9685eaaSMarcel Telka 1171*a9685eaaSMarcel Telka /* LINTED pointer alignment */ 1172*a9685eaaSMarcel Telka sa = (struct sockaddr_in *)(cln->nbuf->buf); 1173*a9685eaaSMarcel Telka (void) inet_ntoa_r(sa->sin_addr, host); 1174*a9685eaaSMarcel Telka 1175*a9685eaaSMarcel Telka cln->host = strdup(host); 1176*a9685eaaSMarcel Telka } else if (strcmp(cln->nconf->nc_protofmly, 1177*a9685eaaSMarcel Telka NC_INET6) == 0) { 1178*a9685eaaSMarcel Telka struct sockaddr_in6 *sa; 1179*a9685eaaSMarcel Telka 1180*a9685eaaSMarcel Telka /* LINTED pointer alignment */ 1181*a9685eaaSMarcel Telka sa = (struct sockaddr_in6 *)(cln->nbuf->buf); 1182*a9685eaaSMarcel Telka (void) inet_ntop(AF_INET6, 1183*a9685eaaSMarcel Telka sa->sin6_addr.s6_addr, 1184*a9685eaaSMarcel Telka host, INET6_ADDRSTRLEN); 1185*a9685eaaSMarcel Telka 1186*a9685eaaSMarcel Telka cln->host = strdup(host); 1187*a9685eaaSMarcel Telka } else { 1188*a9685eaaSMarcel Telka syslog(LOG_ERR, gettext("Client's address is " 1189*a9685eaaSMarcel Telka "neither IPv4 nor IPv6")); 1190*a9685eaaSMarcel Telka 1191*a9685eaaSMarcel Telka cln->host = strdup("(anon)"); 1192*a9685eaaSMarcel Telka } 1193*a9685eaaSMarcel Telka } 1194*a9685eaaSMarcel Telka 1195*a9685eaaSMarcel Telka cln->flags |= CLN_HOST; 1196*a9685eaaSMarcel Telka } 1197*a9685eaaSMarcel Telka 1198*a9685eaaSMarcel Telka return (cln->host); 1199*a9685eaaSMarcel Telka } 1200*a9685eaaSMarcel Telka 12014a508a79SThomas Haynes /* 12027c478bd9Sstevel@tonic-gate * Check mount requests, add to mounted list if ok 12037c478bd9Sstevel@tonic-gate */ 12044a508a79SThomas Haynes static int 12057c478bd9Sstevel@tonic-gate mount(struct svc_req *rqstp) 12067c478bd9Sstevel@tonic-gate { 12077c478bd9Sstevel@tonic-gate SVCXPRT *transp; 120827242a7cSthurlow int version, vers; 12097c478bd9Sstevel@tonic-gate struct fhstatus fhs; 12107c478bd9Sstevel@tonic-gate struct mountres3 mountres3; 121127242a7cSthurlow char fh[FHSIZE3]; 121227242a7cSthurlow int len = FHSIZE3; 12137c478bd9Sstevel@tonic-gate char *path, rpath[MAXPATHLEN]; 12144a508a79SThomas Haynes share_t *sh = NULL; 1215*a9685eaaSMarcel Telka struct cln cln; 12167c478bd9Sstevel@tonic-gate char *host = NULL; 12174a508a79SThomas Haynes int error = 0, lofs_tried = 0, enqueued; 12187c478bd9Sstevel@tonic-gate int flavor_list[MAX_FLAVORS]; 12197c478bd9Sstevel@tonic-gate int flavor_count; 122003986916Sjarrett ucred_t *uc = NULL; 12217c478bd9Sstevel@tonic-gate 12224a508a79SThomas Haynes int audit_status; 12234a508a79SThomas Haynes 12247c478bd9Sstevel@tonic-gate transp = rqstp->rq_xprt; 12257c478bd9Sstevel@tonic-gate version = rqstp->rq_vers; 12267c478bd9Sstevel@tonic-gate path = NULL; 12277c478bd9Sstevel@tonic-gate 12287c478bd9Sstevel@tonic-gate if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) { 12297c478bd9Sstevel@tonic-gate svcerr_decode(transp); 12304a508a79SThomas Haynes return (EACCES); 12317c478bd9Sstevel@tonic-gate } 12327c478bd9Sstevel@tonic-gate 1233*a9685eaaSMarcel Telka cln_init(&cln, transp); 1234*a9685eaaSMarcel Telka 12354a508a79SThomas Haynes /* 12364a508a79SThomas Haynes * Put off getting the name for the client until we 12374a508a79SThomas Haynes * need it. This is a performance gain. If we are logging, 12384a508a79SThomas Haynes * then we don't care about performance and might as well 12394a508a79SThomas Haynes * get the host name now in case we need to spit out an 12404a508a79SThomas Haynes * error message. 12414a508a79SThomas Haynes */ 12424a508a79SThomas Haynes if (verbose) { 12434a508a79SThomas Haynes DTRACE_PROBE(mountd, name_by_verbose); 1244*a9685eaaSMarcel Telka if ((host = cln_gethost(&cln)) == NULL) { 12457c478bd9Sstevel@tonic-gate /* 12464a508a79SThomas Haynes * We failed to get a name for the client, even 12474a508a79SThomas Haynes * 'anon', probably because we ran out of memory. 12484a508a79SThomas Haynes * In this situation it doesn't make sense to 12494a508a79SThomas Haynes * allow the mount to succeed. 12507c478bd9Sstevel@tonic-gate */ 12517c478bd9Sstevel@tonic-gate error = EACCES; 12527c478bd9Sstevel@tonic-gate goto reply; 12537c478bd9Sstevel@tonic-gate } 12544a508a79SThomas Haynes } 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate /* 12577c478bd9Sstevel@tonic-gate * If the version being used is less than the minimum version, 12587c478bd9Sstevel@tonic-gate * the filehandle translation should not be provided to the 12597c478bd9Sstevel@tonic-gate * client. 12607c478bd9Sstevel@tonic-gate */ 12617c478bd9Sstevel@tonic-gate if (rejecting || version < mount_vers_min) { 12627c478bd9Sstevel@tonic-gate if (verbose) 12637c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE, "Rejected mount: %s for %s", 12647c478bd9Sstevel@tonic-gate host, path); 12657c478bd9Sstevel@tonic-gate error = EACCES; 12667c478bd9Sstevel@tonic-gate goto reply; 12677c478bd9Sstevel@tonic-gate } 12687c478bd9Sstevel@tonic-gate 12697c478bd9Sstevel@tonic-gate /* 127003986916Sjarrett * Trusted Extension doesn't support nfsv2. nfsv2 client 127103986916Sjarrett * uses MOUNT protocol v1 and v2. To prevent circumventing 127203986916Sjarrett * TX label policy via using nfsv2 client, reject a mount 127303986916Sjarrett * request with version less than 3 and log an error. 127445916cd2Sjpk */ 127545916cd2Sjpk if (is_system_labeled()) { 127603986916Sjarrett if (version < 3) { 127703986916Sjarrett if (verbose) 127845916cd2Sjpk syslog(LOG_ERR, 127903986916Sjarrett "Rejected mount: TX doesn't support NFSv2"); 128045916cd2Sjpk error = EACCES; 128145916cd2Sjpk goto reply; 128245916cd2Sjpk } 128303986916Sjarrett } 128445916cd2Sjpk 128545916cd2Sjpk /* 12867c478bd9Sstevel@tonic-gate * Get the real path (no symbolic links in it) 12877c478bd9Sstevel@tonic-gate */ 12887c478bd9Sstevel@tonic-gate if (realpath(path, rpath) == NULL) { 12897c478bd9Sstevel@tonic-gate error = errno; 12907c478bd9Sstevel@tonic-gate if (verbose) 12917c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 12927c478bd9Sstevel@tonic-gate "mount request: realpath: %s: %m", path); 12937c478bd9Sstevel@tonic-gate if (error == ENOENT) 1294*a9685eaaSMarcel Telka error = mount_enoent_error(&cln, path, rpath, 1295*a9685eaaSMarcel Telka flavor_list); 12967c478bd9Sstevel@tonic-gate goto reply; 12977c478bd9Sstevel@tonic-gate } 12987c478bd9Sstevel@tonic-gate 12997c478bd9Sstevel@tonic-gate if ((sh = findentry(rpath)) == NULL && 13007c478bd9Sstevel@tonic-gate (sh = find_lofsentry(rpath, &lofs_tried)) == NULL) { 13017c478bd9Sstevel@tonic-gate error = EACCES; 13027c478bd9Sstevel@tonic-gate goto reply; 13037c478bd9Sstevel@tonic-gate } 13047c478bd9Sstevel@tonic-gate 13057c478bd9Sstevel@tonic-gate /* 13067c478bd9Sstevel@tonic-gate * Check if this is a "nosub" only export, in which case, mounting 13077c478bd9Sstevel@tonic-gate * subdirectories isn't allowed. Bug 1184573. 13087c478bd9Sstevel@tonic-gate */ 13097c478bd9Sstevel@tonic-gate if (checkrootmount(sh, rpath) == 0) { 13107c478bd9Sstevel@tonic-gate error = EACCES; 13117c478bd9Sstevel@tonic-gate goto reply; 13127c478bd9Sstevel@tonic-gate } 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate if (newopts(sh->sh_opts)) 1315*a9685eaaSMarcel Telka flavor_count = getclientsflavors_new(sh, &cln, flavor_list); 13167c478bd9Sstevel@tonic-gate else 1317*a9685eaaSMarcel Telka flavor_count = getclientsflavors_old(sh, &cln, flavor_list); 13184a508a79SThomas Haynes 13197c478bd9Sstevel@tonic-gate if (flavor_count == 0) { 13207c478bd9Sstevel@tonic-gate error = EACCES; 13217c478bd9Sstevel@tonic-gate goto reply; 13227c478bd9Sstevel@tonic-gate } 13237c478bd9Sstevel@tonic-gate 13247c478bd9Sstevel@tonic-gate /* 132503986916Sjarrett * Check MAC policy here. The server side policy should be 132603986916Sjarrett * consistent with client side mount policy, i.e. 132703986916Sjarrett * - we disallow an admin_low unlabeled client to mount 132803986916Sjarrett * - we disallow mount from a lower labeled client. 132903986916Sjarrett */ 133003986916Sjarrett if (is_system_labeled()) { 133103986916Sjarrett m_label_t *clabel = NULL; 133203986916Sjarrett m_label_t *slabel = NULL; 133303986916Sjarrett m_label_t admin_low; 133403986916Sjarrett 133503986916Sjarrett if (svc_getcallerucred(rqstp->rq_xprt, &uc) != 0) { 133603986916Sjarrett syslog(LOG_ERR, 133703986916Sjarrett "mount request: Failed to get caller's ucred : %m"); 133803986916Sjarrett error = EACCES; 133903986916Sjarrett goto reply; 134003986916Sjarrett } 134103986916Sjarrett if ((clabel = ucred_getlabel(uc)) == NULL) { 134203986916Sjarrett syslog(LOG_ERR, 134303986916Sjarrett "mount request: can't get client label from ucred"); 134403986916Sjarrett error = EACCES; 134503986916Sjarrett goto reply; 134603986916Sjarrett } 134703986916Sjarrett 134803986916Sjarrett bsllow(&admin_low); 134903986916Sjarrett if (blequal(&admin_low, clabel)) { 135003986916Sjarrett struct sockaddr *ca; 135103986916Sjarrett tsol_tpent_t *tp; 135203986916Sjarrett 135303986916Sjarrett ca = (struct sockaddr *)(void *)svc_getrpccaller( 135403986916Sjarrett rqstp->rq_xprt)->buf; 135503986916Sjarrett if (ca == NULL) { 135603986916Sjarrett error = EACCES; 135703986916Sjarrett goto reply; 135803986916Sjarrett } 135903986916Sjarrett /* 136003986916Sjarrett * get trusted network template associated 136103986916Sjarrett * with the client. 136203986916Sjarrett */ 136303986916Sjarrett tp = get_client_template(ca); 136403986916Sjarrett if (tp == NULL || tp->host_type != SUN_CIPSO) { 136503986916Sjarrett if (tp != NULL) 136603986916Sjarrett tsol_freetpent(tp); 136703986916Sjarrett error = EACCES; 136803986916Sjarrett goto reply; 136903986916Sjarrett } 137003986916Sjarrett tsol_freetpent(tp); 137103986916Sjarrett } else { 137203986916Sjarrett if ((slabel = m_label_alloc(MAC_LABEL)) == NULL) { 137303986916Sjarrett error = EACCES; 137403986916Sjarrett goto reply; 137503986916Sjarrett } 137603986916Sjarrett 137703986916Sjarrett if (getlabel(rpath, slabel) != 0) { 137803986916Sjarrett m_label_free(slabel); 137903986916Sjarrett error = EACCES; 138003986916Sjarrett goto reply; 138103986916Sjarrett } 138203986916Sjarrett 138303986916Sjarrett if (!bldominates(clabel, slabel)) { 138403986916Sjarrett m_label_free(slabel); 138503986916Sjarrett error = EACCES; 138603986916Sjarrett goto reply; 138703986916Sjarrett } 138803986916Sjarrett m_label_free(slabel); 138903986916Sjarrett } 139003986916Sjarrett } 139103986916Sjarrett 139203986916Sjarrett /* 13937c478bd9Sstevel@tonic-gate * Now get the filehandle. 13947c478bd9Sstevel@tonic-gate * 139527242a7cSthurlow * NFS V2 clients get a 32 byte filehandle. 139627242a7cSthurlow * NFS V3 clients get a 32 or 64 byte filehandle, depending on 139727242a7cSthurlow * the embedded FIDs. 13987c478bd9Sstevel@tonic-gate */ 139927242a7cSthurlow vers = (version == MOUNTVERS3) ? NFS_V3 : NFS_VERSION; 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 140227242a7cSthurlow while (nfs_getfh(rpath, vers, &len, fh) < 0) { 14037c478bd9Sstevel@tonic-gate if (errno == EINVAL && 14047c478bd9Sstevel@tonic-gate (sh = find_lofsentry(rpath, &lofs_tried)) != NULL) { 14057c478bd9Sstevel@tonic-gate errno = 0; 14067c478bd9Sstevel@tonic-gate continue; 14077c478bd9Sstevel@tonic-gate } 14087c478bd9Sstevel@tonic-gate error = errno == EINVAL ? EACCES : errno; 14097c478bd9Sstevel@tonic-gate syslog(LOG_DEBUG, "mount request: getfh failed on %s: %m", 14107c478bd9Sstevel@tonic-gate path); 14117c478bd9Sstevel@tonic-gate break; 14127c478bd9Sstevel@tonic-gate } 14137c478bd9Sstevel@tonic-gate 141427242a7cSthurlow if (version == MOUNTVERS3) { 141527242a7cSthurlow mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len = len; 141627242a7cSthurlow mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val = fh; 141727242a7cSthurlow } else { 141827242a7cSthurlow bcopy(fh, &fhs.fhstatus_u.fhs_fhandle, NFS_FHSIZE); 141927242a7cSthurlow } 142027242a7cSthurlow 14217c478bd9Sstevel@tonic-gate reply: 142203986916Sjarrett if (uc != NULL) 142303986916Sjarrett ucred_free(uc); 14244a508a79SThomas Haynes 14257c478bd9Sstevel@tonic-gate switch (version) { 14267c478bd9Sstevel@tonic-gate case MOUNTVERS: 14277c478bd9Sstevel@tonic-gate case MOUNTVERS_POSIX: 14287c478bd9Sstevel@tonic-gate if (error == EINVAL) 14297c478bd9Sstevel@tonic-gate fhs.fhs_status = NFSERR_ACCES; 14307c478bd9Sstevel@tonic-gate else if (error == EREMOTE) 14317c478bd9Sstevel@tonic-gate fhs.fhs_status = NFSERR_REMOTE; 14327c478bd9Sstevel@tonic-gate else 14337c478bd9Sstevel@tonic-gate fhs.fhs_status = error; 14344a508a79SThomas Haynes 14357c478bd9Sstevel@tonic-gate if (!svc_sendreply(transp, xdr_fhstatus, (char *)&fhs)) 1436*a9685eaaSMarcel Telka log_cant_reply_cln(&cln); 14374a508a79SThomas Haynes 14384a508a79SThomas Haynes audit_status = fhs.fhs_status; 14397c478bd9Sstevel@tonic-gate break; 14407c478bd9Sstevel@tonic-gate 14417c478bd9Sstevel@tonic-gate case MOUNTVERS3: 14427c478bd9Sstevel@tonic-gate if (!error) { 14437c478bd9Sstevel@tonic-gate mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val = 14447c478bd9Sstevel@tonic-gate flavor_list; 14457c478bd9Sstevel@tonic-gate mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len = 14467c478bd9Sstevel@tonic-gate flavor_count; 14477c478bd9Sstevel@tonic-gate 14487c478bd9Sstevel@tonic-gate } else if (error == ENAMETOOLONG) 14497c478bd9Sstevel@tonic-gate error = MNT3ERR_NAMETOOLONG; 14507c478bd9Sstevel@tonic-gate 14517c478bd9Sstevel@tonic-gate mountres3.fhs_status = error; 14527c478bd9Sstevel@tonic-gate if (!svc_sendreply(transp, xdr_mountres3, (char *)&mountres3)) 1453*a9685eaaSMarcel Telka log_cant_reply_cln(&cln); 14547c478bd9Sstevel@tonic-gate 14554a508a79SThomas Haynes audit_status = mountres3.fhs_status; 14567c478bd9Sstevel@tonic-gate break; 14577c478bd9Sstevel@tonic-gate } 14587c478bd9Sstevel@tonic-gate 1459*a9685eaaSMarcel Telka if (cln_havehost(&cln)) 1460*a9685eaaSMarcel Telka host = cln_gethost(&cln); 1461*a9685eaaSMarcel Telka 14627c478bd9Sstevel@tonic-gate if (verbose) 14637c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE, "MOUNT: %s %s %s", 14647c478bd9Sstevel@tonic-gate (host == NULL) ? "unknown host" : host, 14657c478bd9Sstevel@tonic-gate error ? "denied" : "mounted", path); 14667c478bd9Sstevel@tonic-gate 14674a508a79SThomas Haynes /* 14684a508a79SThomas Haynes * If we can not create a queue entry, go ahead and do it 14694a508a79SThomas Haynes * in the context of this thread. 14704a508a79SThomas Haynes */ 14714a508a79SThomas Haynes enqueued = enqueue_logging_data(host, transp, path, rpath, 14724a508a79SThomas Haynes audit_status, error); 14734a508a79SThomas Haynes if (enqueued == FALSE) { 14744a508a79SThomas Haynes if (host == NULL) { 14754a508a79SThomas Haynes DTRACE_PROBE(mountd, name_by_in_thread); 1476*a9685eaaSMarcel Telka host = cln_gethost(&cln); 14774a508a79SThomas Haynes } 14784a508a79SThomas Haynes 14794a508a79SThomas Haynes DTRACE_PROBE(mountd, logged_in_thread); 14804a508a79SThomas Haynes audit_mountd_mount(host, path, audit_status); /* BSM */ 14814a508a79SThomas Haynes if (!error) 14824a508a79SThomas Haynes mntlist_new(host, rpath); /* add entry to mount list */ 14834a508a79SThomas Haynes } 14844a508a79SThomas Haynes 14857c478bd9Sstevel@tonic-gate if (path != NULL) 14867c478bd9Sstevel@tonic-gate svc_freeargs(transp, xdr_dirpath, (caddr_t)&path); 14877c478bd9Sstevel@tonic-gate 14887c478bd9Sstevel@tonic-gate if (sh) 14897c478bd9Sstevel@tonic-gate sharefree(sh); 1490*a9685eaaSMarcel Telka 1491*a9685eaaSMarcel Telka cln_fini(&cln); 14924a508a79SThomas Haynes 14934a508a79SThomas Haynes return (error); 14947c478bd9Sstevel@tonic-gate } 14957c478bd9Sstevel@tonic-gate 14966b086bafSSam Falkner /* 14976b086bafSSam Falkner * Determine whether two paths are within the same file system. 14986b086bafSSam Falkner * Returns nonzero (true) if paths are the same, zero (false) if 14996b086bafSSam Falkner * they are different. If an error occurs, return false. 15006b086bafSSam Falkner * 15016b086bafSSam Falkner * Use the actual FSID if it's available (via getattrat()); otherwise, 15026b086bafSSam Falkner * fall back on st_dev. 15036b086bafSSam Falkner * 15046b086bafSSam Falkner * With ZFS snapshots, st_dev differs from the regular file system 15056b086bafSSam Falkner * versus the snapshot. But the fsid is the same throughout. Thus 15066b086bafSSam Falkner * the fsid is a better test. 15076b086bafSSam Falkner */ 15086b086bafSSam Falkner static int 15096b086bafSSam Falkner same_file_system(const char *path1, const char *path2) 15106b086bafSSam Falkner { 15116b086bafSSam Falkner uint64_t fsid1, fsid2; 15126b086bafSSam Falkner struct stat64 st1, st2; 15136b086bafSSam Falkner nvlist_t *nvl1 = NULL; 15146b086bafSSam Falkner nvlist_t *nvl2 = NULL; 15156b086bafSSam Falkner 15166b086bafSSam Falkner if ((getattrat(AT_FDCWD, XATTR_VIEW_READONLY, path1, &nvl1) == 0) && 15176b086bafSSam Falkner (getattrat(AT_FDCWD, XATTR_VIEW_READONLY, path2, &nvl2) == 0) && 15186b086bafSSam Falkner (nvlist_lookup_uint64(nvl1, A_FSID, &fsid1) == 0) && 15196b086bafSSam Falkner (nvlist_lookup_uint64(nvl2, A_FSID, &fsid2) == 0)) { 15206b086bafSSam Falkner nvlist_free(nvl1); 15216b086bafSSam Falkner nvlist_free(nvl2); 15226b086bafSSam Falkner /* 15236b086bafSSam Falkner * We have found fsid's for both paths. 15246b086bafSSam Falkner */ 15256b086bafSSam Falkner 15266b086bafSSam Falkner if (fsid1 == fsid2) 15276b086bafSSam Falkner return (B_TRUE); 15286b086bafSSam Falkner 15296b086bafSSam Falkner return (B_FALSE); 15306b086bafSSam Falkner } 15316b086bafSSam Falkner 15326b086bafSSam Falkner nvlist_free(nvl1); 15336b086bafSSam Falkner nvlist_free(nvl2); 15346b086bafSSam Falkner 15356b086bafSSam Falkner /* 15366b086bafSSam Falkner * We were unable to find fsid's for at least one of the paths. 15376b086bafSSam Falkner * fall back on st_dev. 15386b086bafSSam Falkner */ 15396b086bafSSam Falkner 15406b086bafSSam Falkner if (stat64(path1, &st1) < 0) { 15416b086bafSSam Falkner syslog(LOG_NOTICE, "%s: %m", path1); 15426b086bafSSam Falkner return (B_FALSE); 15436b086bafSSam Falkner } 15446b086bafSSam Falkner if (stat64(path2, &st2) < 0) { 15456b086bafSSam Falkner syslog(LOG_NOTICE, "%s: %m", path2); 15466b086bafSSam Falkner return (B_FALSE); 15476b086bafSSam Falkner } 15486b086bafSSam Falkner 15496b086bafSSam Falkner if (st1.st_dev == st2.st_dev) 15506b086bafSSam Falkner return (B_TRUE); 15516b086bafSSam Falkner 15526b086bafSSam Falkner return (B_FALSE); 15536b086bafSSam Falkner } 15546b086bafSSam Falkner 15554a508a79SThomas Haynes share_t * 15567c478bd9Sstevel@tonic-gate findentry(char *path) 15577c478bd9Sstevel@tonic-gate { 15584a508a79SThomas Haynes share_t *sh = NULL; 15597c478bd9Sstevel@tonic-gate struct sh_list *shp; 156054d34259SMarcel Telka char *p1, *p2; 15617c478bd9Sstevel@tonic-gate 15627c478bd9Sstevel@tonic-gate check_sharetab(); 15637c478bd9Sstevel@tonic-gate 15647c478bd9Sstevel@tonic-gate (void) rw_rdlock(&sharetab_lock); 15657c478bd9Sstevel@tonic-gate 15667c478bd9Sstevel@tonic-gate for (shp = share_list; shp; shp = shp->shl_next) { 15677c478bd9Sstevel@tonic-gate sh = shp->shl_sh; 15687c478bd9Sstevel@tonic-gate for (p1 = sh->sh_path, p2 = path; *p1 == *p2; p1++, p2++) 15697c478bd9Sstevel@tonic-gate if (*p1 == '\0') 15707c478bd9Sstevel@tonic-gate goto done; /* exact match */ 15717c478bd9Sstevel@tonic-gate 15727c478bd9Sstevel@tonic-gate /* 15737c478bd9Sstevel@tonic-gate * Now compare the pathnames for three cases: 15747c478bd9Sstevel@tonic-gate * 15757c478bd9Sstevel@tonic-gate * Parent: /export/foo (no trailing slash on parent) 15767c478bd9Sstevel@tonic-gate * Child: /export/foo/bar 15777c478bd9Sstevel@tonic-gate * 15787c478bd9Sstevel@tonic-gate * Parent: /export/foo/ (trailing slash on parent) 15797c478bd9Sstevel@tonic-gate * Child: /export/foo/bar 15807c478bd9Sstevel@tonic-gate * 15817c478bd9Sstevel@tonic-gate * Parent: /export/foo/ (no trailing slash on child) 15827c478bd9Sstevel@tonic-gate * Child: /export/foo 15837c478bd9Sstevel@tonic-gate */ 15847c478bd9Sstevel@tonic-gate if ((*p1 == '\0' && *p2 == '/') || 15857c478bd9Sstevel@tonic-gate (*p1 == '\0' && *(p1-1) == '/') || 15867c478bd9Sstevel@tonic-gate (*p2 == '\0' && *p1 == '/' && *(p1+1) == '\0')) { 15877c478bd9Sstevel@tonic-gate /* 15886b086bafSSam Falkner * We have a subdirectory. Test whether the 15896b086bafSSam Falkner * subdirectory is in the same file system. 15907c478bd9Sstevel@tonic-gate */ 15916b086bafSSam Falkner if (same_file_system(path, sh->sh_path)) 15927c478bd9Sstevel@tonic-gate goto done; 15937c478bd9Sstevel@tonic-gate } 15947c478bd9Sstevel@tonic-gate } 15957c478bd9Sstevel@tonic-gate done: 15967c478bd9Sstevel@tonic-gate sh = shp ? sharedup(sh) : NULL; 15977c478bd9Sstevel@tonic-gate 15987c478bd9Sstevel@tonic-gate (void) rw_unlock(&sharetab_lock); 15997c478bd9Sstevel@tonic-gate 16007c478bd9Sstevel@tonic-gate return (sh); 16017c478bd9Sstevel@tonic-gate } 16027c478bd9Sstevel@tonic-gate 16037c478bd9Sstevel@tonic-gate 16047c478bd9Sstevel@tonic-gate static int 16057c478bd9Sstevel@tonic-gate is_substring(char **mntp, char **path) 16067c478bd9Sstevel@tonic-gate { 16077c478bd9Sstevel@tonic-gate char *p1 = *mntp, *p2 = *path; 16087c478bd9Sstevel@tonic-gate 16097c478bd9Sstevel@tonic-gate if (*p1 == '\0' && *p2 == '\0') /* exact match */ 16107c478bd9Sstevel@tonic-gate return (1); 16117c478bd9Sstevel@tonic-gate else if (*p1 == '\0' && *p2 == '/') 16127c478bd9Sstevel@tonic-gate return (1); 16137c478bd9Sstevel@tonic-gate else if (*p1 == '\0' && *(p1-1) == '/') { 16147c478bd9Sstevel@tonic-gate *path = --p2; /* we need the slash in p2 */ 16157c478bd9Sstevel@tonic-gate return (1); 16167c478bd9Sstevel@tonic-gate } else if (*p2 == '\0') { 16177c478bd9Sstevel@tonic-gate while (*p1 == '/') 16187c478bd9Sstevel@tonic-gate p1++; 16197c478bd9Sstevel@tonic-gate if (*p1 == '\0') /* exact match */ 16207c478bd9Sstevel@tonic-gate return (1); 16217c478bd9Sstevel@tonic-gate } 16227c478bd9Sstevel@tonic-gate return (0); 16237c478bd9Sstevel@tonic-gate } 16247c478bd9Sstevel@tonic-gate 16257c478bd9Sstevel@tonic-gate /* 16267c478bd9Sstevel@tonic-gate * find_lofsentry() searches for the real path which this requested LOFS path 16277c478bd9Sstevel@tonic-gate * (rpath) shadows. If found, it will return the sharetab entry of 16287c478bd9Sstevel@tonic-gate * the real path that corresponds to the LOFS path. 16297c478bd9Sstevel@tonic-gate * We first search mnttab to see if the requested path is an automounted 16307c478bd9Sstevel@tonic-gate * path. If it is an automounted path, it will trigger the mount by stat()ing 16317c478bd9Sstevel@tonic-gate * the requested path. Note that it is important to check that this path is 16327c478bd9Sstevel@tonic-gate * actually an automounted path, otherwise we would stat() a path which may 16337c478bd9Sstevel@tonic-gate * turn out to be NFS and block indefinitely on a dead server. The automounter 16347c478bd9Sstevel@tonic-gate * times-out if the server is dead, so there's no risk of hanging this 16357c478bd9Sstevel@tonic-gate * thread waiting for stat(). 16367c478bd9Sstevel@tonic-gate * After the mount has been triggered (if necessary), we look for a 16377c478bd9Sstevel@tonic-gate * mountpoint of type LOFS (by searching /etc/mnttab again) which 16387c478bd9Sstevel@tonic-gate * is a substring of the rpath. If found, we construct a new path by 16397c478bd9Sstevel@tonic-gate * concatenating the mnt_special and the remaining of rpath, call findentry() 16407c478bd9Sstevel@tonic-gate * to make sure the 'real path' is shared. 16417c478bd9Sstevel@tonic-gate */ 16424a508a79SThomas Haynes static share_t * 16437c478bd9Sstevel@tonic-gate find_lofsentry(char *rpath, int *done_flag) 16447c478bd9Sstevel@tonic-gate { 16457c478bd9Sstevel@tonic-gate struct stat r_stbuf; 16467c478bd9Sstevel@tonic-gate mntlist_t *ml, *mntl, *mntpnt = NULL; 16474a508a79SThomas Haynes share_t *retcode = NULL; 16487c478bd9Sstevel@tonic-gate char tmp_path[MAXPATHLEN]; 16497c478bd9Sstevel@tonic-gate int mntpnt_len = 0, tmp; 16507c478bd9Sstevel@tonic-gate char *p1, *p2; 16517c478bd9Sstevel@tonic-gate 16527c478bd9Sstevel@tonic-gate if ((*done_flag)++) 16537c478bd9Sstevel@tonic-gate return (retcode); 16547c478bd9Sstevel@tonic-gate 16557c478bd9Sstevel@tonic-gate /* 16567c478bd9Sstevel@tonic-gate * While fsgetmntlist() uses lockf() to 16577c478bd9Sstevel@tonic-gate * lock the mnttab before reading it in, 16587c478bd9Sstevel@tonic-gate * the lock ignores threads in the same process. 16597c478bd9Sstevel@tonic-gate * Read in the mnttab with the protection of a mutex. 16607c478bd9Sstevel@tonic-gate */ 16617c478bd9Sstevel@tonic-gate (void) mutex_lock(&mnttab_lock); 16627c478bd9Sstevel@tonic-gate mntl = fsgetmntlist(); 16637c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mnttab_lock); 16647c478bd9Sstevel@tonic-gate 16657c478bd9Sstevel@tonic-gate /* 16667c478bd9Sstevel@tonic-gate * Obtain the mountpoint for the requested path. 16677c478bd9Sstevel@tonic-gate */ 16687c478bd9Sstevel@tonic-gate for (ml = mntl; ml; ml = ml->mntl_next) { 16697c478bd9Sstevel@tonic-gate for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath; 1670250a0733Sth199096 *p1 == *p2 && *p1; p1++, p2++) 1671250a0733Sth199096 ; 16727c478bd9Sstevel@tonic-gate if (is_substring(&p1, &p2) && 16737c478bd9Sstevel@tonic-gate (tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len) { 16747c478bd9Sstevel@tonic-gate mntpnt = ml; 16757c478bd9Sstevel@tonic-gate mntpnt_len = tmp; 16767c478bd9Sstevel@tonic-gate } 16777c478bd9Sstevel@tonic-gate } 16787c478bd9Sstevel@tonic-gate 16797c478bd9Sstevel@tonic-gate /* 16807c478bd9Sstevel@tonic-gate * If the path needs to be autoFS mounted, trigger the mount by 16817c478bd9Sstevel@tonic-gate * stat()ing it. This is determined by checking whether the 16827c478bd9Sstevel@tonic-gate * mountpoint we just found is of type autofs. 16837c478bd9Sstevel@tonic-gate */ 16847c478bd9Sstevel@tonic-gate if (mntpnt != NULL && 16857c478bd9Sstevel@tonic-gate strcmp(mntpnt->mntl_mnt->mnt_fstype, "autofs") == 0) { 16867c478bd9Sstevel@tonic-gate /* 16877c478bd9Sstevel@tonic-gate * The requested path is a substring of an autoFS filesystem. 16887c478bd9Sstevel@tonic-gate * Trigger the mount. 16897c478bd9Sstevel@tonic-gate */ 16907c478bd9Sstevel@tonic-gate if (stat(rpath, &r_stbuf) < 0) { 16917c478bd9Sstevel@tonic-gate if (verbose) 16927c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE, "%s: %m", rpath); 16937c478bd9Sstevel@tonic-gate goto done; 16947c478bd9Sstevel@tonic-gate } 16957c478bd9Sstevel@tonic-gate if ((r_stbuf.st_mode & S_IFMT) == S_IFDIR) { 16967c478bd9Sstevel@tonic-gate /* 16977c478bd9Sstevel@tonic-gate * The requested path is a directory, stat(2) it 16987c478bd9Sstevel@tonic-gate * again with a trailing '.' to force the autoFS 16997c478bd9Sstevel@tonic-gate * module to trigger the mount of indirect 17007c478bd9Sstevel@tonic-gate * automount entries, such as /net/jurassic/. 17017c478bd9Sstevel@tonic-gate */ 17027c478bd9Sstevel@tonic-gate if (strlen(rpath) + 2 > MAXPATHLEN) { 17037c478bd9Sstevel@tonic-gate if (verbose) { 17047c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE, 17057c478bd9Sstevel@tonic-gate "%s/.: exceeds MAXPATHLEN %d", 17067c478bd9Sstevel@tonic-gate rpath, MAXPATHLEN); 17077c478bd9Sstevel@tonic-gate } 17087c478bd9Sstevel@tonic-gate goto done; 17097c478bd9Sstevel@tonic-gate } 17107c478bd9Sstevel@tonic-gate (void) strcpy(tmp_path, rpath); 17117c478bd9Sstevel@tonic-gate (void) strcat(tmp_path, "/."); 17127c478bd9Sstevel@tonic-gate 17137c478bd9Sstevel@tonic-gate if (stat(tmp_path, &r_stbuf) < 0) { 17147c478bd9Sstevel@tonic-gate if (verbose) 17157c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE, "%s: %m", tmp_path); 17167c478bd9Sstevel@tonic-gate goto done; 17177c478bd9Sstevel@tonic-gate } 17187c478bd9Sstevel@tonic-gate } 17194a508a79SThomas Haynes 17207c478bd9Sstevel@tonic-gate /* 17217c478bd9Sstevel@tonic-gate * The mount has been triggered, re-read mnttab to pick up 17227c478bd9Sstevel@tonic-gate * the changes made by autoFS. 17237c478bd9Sstevel@tonic-gate */ 17247c478bd9Sstevel@tonic-gate fsfreemntlist(mntl); 17257c478bd9Sstevel@tonic-gate (void) mutex_lock(&mnttab_lock); 17267c478bd9Sstevel@tonic-gate mntl = fsgetmntlist(); 17277c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mnttab_lock); 17287c478bd9Sstevel@tonic-gate } 17297c478bd9Sstevel@tonic-gate 17307c478bd9Sstevel@tonic-gate /* 17317c478bd9Sstevel@tonic-gate * The autoFS mountpoint has been triggered if necessary, 17327c478bd9Sstevel@tonic-gate * now search mnttab again to determine if the requested path 17337c478bd9Sstevel@tonic-gate * is an LOFS mount of a shared path. 17347c478bd9Sstevel@tonic-gate */ 17357c478bd9Sstevel@tonic-gate mntpnt_len = 0; 17367c478bd9Sstevel@tonic-gate for (ml = mntl; ml; ml = ml->mntl_next) { 17377c478bd9Sstevel@tonic-gate if (strcmp(ml->mntl_mnt->mnt_fstype, "lofs")) 17387c478bd9Sstevel@tonic-gate continue; 17397c478bd9Sstevel@tonic-gate 17407c478bd9Sstevel@tonic-gate for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath; 1741250a0733Sth199096 *p1 == *p2 && *p1; p1++, p2++) 1742250a0733Sth199096 ; 17437c478bd9Sstevel@tonic-gate 17447c478bd9Sstevel@tonic-gate if (is_substring(&p1, &p2) && 17457c478bd9Sstevel@tonic-gate ((tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len)) { 17467c478bd9Sstevel@tonic-gate mntpnt_len = tmp; 17477c478bd9Sstevel@tonic-gate 17487c478bd9Sstevel@tonic-gate if ((strlen(ml->mntl_mnt->mnt_special) + strlen(p2)) > 17497c478bd9Sstevel@tonic-gate MAXPATHLEN) { 17507c478bd9Sstevel@tonic-gate if (verbose) { 17517c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE, "%s%s: exceeds %d", 17527c478bd9Sstevel@tonic-gate ml->mntl_mnt->mnt_special, p2, 17537c478bd9Sstevel@tonic-gate MAXPATHLEN); 17547c478bd9Sstevel@tonic-gate } 17557c478bd9Sstevel@tonic-gate if (retcode) 17567c478bd9Sstevel@tonic-gate sharefree(retcode); 17577c478bd9Sstevel@tonic-gate retcode = NULL; 17587c478bd9Sstevel@tonic-gate goto done; 17597c478bd9Sstevel@tonic-gate } 17607c478bd9Sstevel@tonic-gate 17617c478bd9Sstevel@tonic-gate (void) strcpy(tmp_path, ml->mntl_mnt->mnt_special); 17627c478bd9Sstevel@tonic-gate (void) strcat(tmp_path, p2); 17637c478bd9Sstevel@tonic-gate if (retcode) 17647c478bd9Sstevel@tonic-gate sharefree(retcode); 17657c478bd9Sstevel@tonic-gate retcode = findentry(tmp_path); 17667c478bd9Sstevel@tonic-gate } 17677c478bd9Sstevel@tonic-gate } 17687c478bd9Sstevel@tonic-gate 17697c478bd9Sstevel@tonic-gate if (retcode) { 17707c478bd9Sstevel@tonic-gate assert(strlen(tmp_path) > 0); 17717c478bd9Sstevel@tonic-gate (void) strcpy(rpath, tmp_path); 17727c478bd9Sstevel@tonic-gate } 17737c478bd9Sstevel@tonic-gate 17747c478bd9Sstevel@tonic-gate done: 17757c478bd9Sstevel@tonic-gate fsfreemntlist(mntl); 17767c478bd9Sstevel@tonic-gate return (retcode); 17777c478bd9Sstevel@tonic-gate } 17787c478bd9Sstevel@tonic-gate 17797c478bd9Sstevel@tonic-gate /* 17807c478bd9Sstevel@tonic-gate * Determine whether an access list grants rights to a particular host. 17817c478bd9Sstevel@tonic-gate * We match on aliases of the hostname as well as on the canonical name. 17827c478bd9Sstevel@tonic-gate * Names in the access list may be either hosts or netgroups; they're 17837c478bd9Sstevel@tonic-gate * not distinguished syntactically. We check for hosts first because 17849b241b4eSYuri Pankov * it's cheaper, then try netgroups. 1785d34083bdSJan Kryl * 1786*a9685eaaSMarcel Telka * Return values: 1787*a9685eaaSMarcel Telka * 1 - access is granted 1788*a9685eaaSMarcel Telka * 0 - access is denied 1789*a9685eaaSMarcel Telka * -1 - an error occured 17907c478bd9Sstevel@tonic-gate */ 179111606941Sjwahlig int 1792*a9685eaaSMarcel Telka in_access_list(struct cln *cln, 17937c478bd9Sstevel@tonic-gate char *access_list) /* N.B. we clobber this "input" parameter */ 17947c478bd9Sstevel@tonic-gate { 17959b241b4eSYuri Pankov char addr[INET_ADDRSTRLEN]; 17969b241b4eSYuri Pankov char buff[256]; 17979b241b4eSYuri Pankov int nentries = 0; 17989b241b4eSYuri Pankov char *cstr = access_list; 17999b241b4eSYuri Pankov char *gr = access_list; 18007c478bd9Sstevel@tonic-gate int i; 18017c478bd9Sstevel@tonic-gate int response; 1802*a9685eaaSMarcel Telka struct netbuf *pnb; 1803*a9685eaaSMarcel Telka struct nd_hostservlist *clnames = NULL; 18044a508a79SThomas Haynes 18059b241b4eSYuri Pankov /* If no access list - then it's unrestricted */ 18067c478bd9Sstevel@tonic-gate if (access_list == NULL || *access_list == '\0') 18077c478bd9Sstevel@tonic-gate return (1); 18087c478bd9Sstevel@tonic-gate 1809*a9685eaaSMarcel Telka if ((pnb = cln_getnbuf(cln)) == NULL) 1810*a9685eaaSMarcel Telka return (-1); 18119b241b4eSYuri Pankov 18129b241b4eSYuri Pankov for (;;) { 1813*a9685eaaSMarcel Telka if ((cstr = strpbrk(cstr, "[:")) != NULL) { 1814*a9685eaaSMarcel Telka if (*cstr == ':') { 18159b241b4eSYuri Pankov *cstr = '\0'; 1816*a9685eaaSMarcel Telka } else { 1817*a9685eaaSMarcel Telka assert(*cstr == '['); 1818*a9685eaaSMarcel Telka cstr = strchr(cstr + 1, ']'); 1819*a9685eaaSMarcel Telka if (cstr == NULL) 1820*a9685eaaSMarcel Telka return (-1); 1821*a9685eaaSMarcel Telka cstr++; 1822*a9685eaaSMarcel Telka continue; 18239b241b4eSYuri Pankov } 18249b241b4eSYuri Pankov } 18257c478bd9Sstevel@tonic-gate 18267c478bd9Sstevel@tonic-gate /* 18279b241b4eSYuri Pankov * If the list name has a '-' prepended then a match of 18289b241b4eSYuri Pankov * the following name implies failure instead of success. 18297c478bd9Sstevel@tonic-gate */ 18307c478bd9Sstevel@tonic-gate if (*gr == '-') { 18317c478bd9Sstevel@tonic-gate response = 0; 18327c478bd9Sstevel@tonic-gate gr++; 18339b241b4eSYuri Pankov } else { 18347c478bd9Sstevel@tonic-gate response = 1; 1835d34083bdSJan Kryl } 1836d34083bdSJan Kryl 18379b241b4eSYuri Pankov /* 18389b241b4eSYuri Pankov * First check if we have '@' entry, as it doesn't 18399b241b4eSYuri Pankov * require client hostname. 18409b241b4eSYuri Pankov */ 18419b241b4eSYuri Pankov if (*gr == '@') { 18429b241b4eSYuri Pankov gr++; 18439b241b4eSYuri Pankov 18449b241b4eSYuri Pankov /* Netname support */ 18459b241b4eSYuri Pankov if (!isdigit(*gr) && *gr != '[') { 1846*a9685eaaSMarcel Telka struct netent n, *np; 1847*a9685eaaSMarcel Telka 18489b241b4eSYuri Pankov if ((np = getnetbyname_r(gr, &n, buff, 18499b241b4eSYuri Pankov sizeof (buff))) != NULL && 18509b241b4eSYuri Pankov np->n_net != 0) { 18519b241b4eSYuri Pankov while ((np->n_net & 0xFF000000u) == 0) 18529b241b4eSYuri Pankov np->n_net <<= 8; 18539b241b4eSYuri Pankov np->n_net = htonl(np->n_net); 18549b241b4eSYuri Pankov if (inet_ntop(AF_INET, &np->n_net, addr, 18559b241b4eSYuri Pankov INET_ADDRSTRLEN) == NULL) 18569b241b4eSYuri Pankov break; 1857*a9685eaaSMarcel Telka if (inet_matchaddr(pnb->buf, addr)) 18584a508a79SThomas Haynes return (response); 18599b241b4eSYuri Pankov } 18609b241b4eSYuri Pankov } else { 1861*a9685eaaSMarcel Telka if (inet_matchaddr(pnb->buf, gr)) 18629b241b4eSYuri Pankov return (response); 18639b241b4eSYuri Pankov } 18649b241b4eSYuri Pankov 1865*a9685eaaSMarcel Telka goto next; 18664a508a79SThomas Haynes } 18674a508a79SThomas Haynes 18684a508a79SThomas Haynes /* 18699b241b4eSYuri Pankov * No other checks can be performed if client address 18709b241b4eSYuri Pankov * can't be resolved. 18714a508a79SThomas Haynes */ 1872*a9685eaaSMarcel Telka if ((clnames = cln_getclientsnames(cln)) == NULL) 1873*a9685eaaSMarcel Telka goto next; 18744a508a79SThomas Haynes 18759b241b4eSYuri Pankov /* Otherwise loop through all client hostname aliases */ 18767c478bd9Sstevel@tonic-gate for (i = 0; i < clnames->h_cnt; i++) { 1877*a9685eaaSMarcel Telka char *host = clnames->h_hostservs[i].h_host; 18787c478bd9Sstevel@tonic-gate 18797c478bd9Sstevel@tonic-gate /* 18807c478bd9Sstevel@tonic-gate * If the list name begins with a dot then 18817c478bd9Sstevel@tonic-gate * do a domain name suffix comparison. 18827c478bd9Sstevel@tonic-gate * A single dot matches any name with no 18837c478bd9Sstevel@tonic-gate * suffix. 18847c478bd9Sstevel@tonic-gate */ 18857c478bd9Sstevel@tonic-gate if (*gr == '.') { 18867c478bd9Sstevel@tonic-gate if (*(gr + 1) == '\0') { /* single dot */ 18877c478bd9Sstevel@tonic-gate if (strchr(host, '.') == NULL) 18887c478bd9Sstevel@tonic-gate return (response); 18897c478bd9Sstevel@tonic-gate } else { 1890*a9685eaaSMarcel Telka int off = strlen(host) - strlen(gr); 18917c478bd9Sstevel@tonic-gate if (off > 0 && 18927c478bd9Sstevel@tonic-gate strcasecmp(host + off, gr) == 0) { 18937c478bd9Sstevel@tonic-gate return (response); 18947c478bd9Sstevel@tonic-gate } 18957c478bd9Sstevel@tonic-gate } 18969b241b4eSYuri Pankov } else { 18979b241b4eSYuri Pankov /* Just do a hostname match */ 18989b241b4eSYuri Pankov if (strcasecmp(gr, host) == 0) 18999b241b4eSYuri Pankov return (response); 19007c478bd9Sstevel@tonic-gate } 19017c478bd9Sstevel@tonic-gate } 19027c478bd9Sstevel@tonic-gate 19037c478bd9Sstevel@tonic-gate nentries++; 19047c478bd9Sstevel@tonic-gate 1905*a9685eaaSMarcel Telka next: 19069b241b4eSYuri Pankov if (cstr == NULL) 19077c478bd9Sstevel@tonic-gate break; 19089b241b4eSYuri Pankov 19099b241b4eSYuri Pankov gr = ++cstr; 19107c478bd9Sstevel@tonic-gate } 19119b241b4eSYuri Pankov 19129b241b4eSYuri Pankov if (clnames == NULL) 19137c478bd9Sstevel@tonic-gate return (0); 19147c478bd9Sstevel@tonic-gate 19159b241b4eSYuri Pankov return (netgroup_check(clnames, access_list, nentries)); 19167c478bd9Sstevel@tonic-gate } 19177c478bd9Sstevel@tonic-gate 19187c478bd9Sstevel@tonic-gate 19197c478bd9Sstevel@tonic-gate static char *optlist[] = { 19207c478bd9Sstevel@tonic-gate #define OPT_RO 0 19217c478bd9Sstevel@tonic-gate SHOPT_RO, 19227c478bd9Sstevel@tonic-gate #define OPT_RW 1 19237c478bd9Sstevel@tonic-gate SHOPT_RW, 19247c478bd9Sstevel@tonic-gate #define OPT_ROOT 2 19257c478bd9Sstevel@tonic-gate SHOPT_ROOT, 19267c478bd9Sstevel@tonic-gate #define OPT_SECURE 3 19277c478bd9Sstevel@tonic-gate SHOPT_SECURE, 19287c478bd9Sstevel@tonic-gate #define OPT_ANON 4 19297c478bd9Sstevel@tonic-gate SHOPT_ANON, 19307c478bd9Sstevel@tonic-gate #define OPT_WINDOW 5 19317c478bd9Sstevel@tonic-gate SHOPT_WINDOW, 19327c478bd9Sstevel@tonic-gate #define OPT_NOSUID 6 19337c478bd9Sstevel@tonic-gate SHOPT_NOSUID, 19347c478bd9Sstevel@tonic-gate #define OPT_ACLOK 7 19357c478bd9Sstevel@tonic-gate SHOPT_ACLOK, 19367c478bd9Sstevel@tonic-gate #define OPT_SEC 8 19377c478bd9Sstevel@tonic-gate SHOPT_SEC, 1938b89a8333Snatalie li - Sun Microsystems - Irvine United States #define OPT_NONE 9 1939b89a8333Snatalie li - Sun Microsystems - Irvine United States SHOPT_NONE, 19405cb0d679SMarcel Telka #define OPT_UIDMAP 10 19415cb0d679SMarcel Telka SHOPT_UIDMAP, 19425cb0d679SMarcel Telka #define OPT_GIDMAP 11 19435cb0d679SMarcel Telka SHOPT_GIDMAP, 19447c478bd9Sstevel@tonic-gate NULL 19457c478bd9Sstevel@tonic-gate }; 19467c478bd9Sstevel@tonic-gate 19477c478bd9Sstevel@tonic-gate static int 19487c478bd9Sstevel@tonic-gate map_flavor(char *str) 19497c478bd9Sstevel@tonic-gate { 19507c478bd9Sstevel@tonic-gate seconfig_t sec; 19517c478bd9Sstevel@tonic-gate 19527c478bd9Sstevel@tonic-gate if (nfs_getseconfig_byname(str, &sec)) 19537c478bd9Sstevel@tonic-gate return (-1); 19547c478bd9Sstevel@tonic-gate 19557c478bd9Sstevel@tonic-gate return (sec.sc_nfsnum); 19567c478bd9Sstevel@tonic-gate } 19577c478bd9Sstevel@tonic-gate 19587c478bd9Sstevel@tonic-gate /* 19597c478bd9Sstevel@tonic-gate * If the option string contains a "sec=" 19607c478bd9Sstevel@tonic-gate * option, then use new option syntax. 19617c478bd9Sstevel@tonic-gate */ 19627c478bd9Sstevel@tonic-gate static int 19637c478bd9Sstevel@tonic-gate newopts(char *opts) 19647c478bd9Sstevel@tonic-gate { 19657c478bd9Sstevel@tonic-gate char *head, *p, *val; 19667c478bd9Sstevel@tonic-gate 19677c478bd9Sstevel@tonic-gate if (!opts || *opts == '\0') 19687c478bd9Sstevel@tonic-gate return (0); 19697c478bd9Sstevel@tonic-gate 19707c478bd9Sstevel@tonic-gate head = strdup(opts); 19717c478bd9Sstevel@tonic-gate if (head == NULL) { 19727c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "opts: no memory"); 19737c478bd9Sstevel@tonic-gate return (0); 19747c478bd9Sstevel@tonic-gate } 19757c478bd9Sstevel@tonic-gate 19767c478bd9Sstevel@tonic-gate p = head; 19777c478bd9Sstevel@tonic-gate while (*p) { 19787c478bd9Sstevel@tonic-gate if (getsubopt(&p, optlist, &val) == OPT_SEC) { 19797c478bd9Sstevel@tonic-gate free(head); 19807c478bd9Sstevel@tonic-gate return (1); 19817c478bd9Sstevel@tonic-gate } 19827c478bd9Sstevel@tonic-gate } 19837c478bd9Sstevel@tonic-gate 19847c478bd9Sstevel@tonic-gate free(head); 19857c478bd9Sstevel@tonic-gate return (0); 19867c478bd9Sstevel@tonic-gate } 19877c478bd9Sstevel@tonic-gate 19887c478bd9Sstevel@tonic-gate /* 19897c478bd9Sstevel@tonic-gate * Given an export and the clients hostname(s) 19907c478bd9Sstevel@tonic-gate * determine the security flavors that this 19917c478bd9Sstevel@tonic-gate * client is permitted to use. 19927c478bd9Sstevel@tonic-gate * 19937c478bd9Sstevel@tonic-gate * This routine is called only for "old" syntax, i.e. 19947c478bd9Sstevel@tonic-gate * only one security flavor is allowed. So we need 19957c478bd9Sstevel@tonic-gate * to determine two things: the particular flavor, 19967c478bd9Sstevel@tonic-gate * and whether the client is allowed to use this 19977c478bd9Sstevel@tonic-gate * flavor, i.e. is in the access list. 19987c478bd9Sstevel@tonic-gate * 19997c478bd9Sstevel@tonic-gate * Note that if there is no access list, then the 20007c478bd9Sstevel@tonic-gate * default is that access is granted. 20017c478bd9Sstevel@tonic-gate */ 20027c478bd9Sstevel@tonic-gate static int 2003*a9685eaaSMarcel Telka getclientsflavors_old(share_t *sh, struct cln *cln, int *flavors) 20047c478bd9Sstevel@tonic-gate { 20057c478bd9Sstevel@tonic-gate char *opts, *p, *val; 2006b89a8333Snatalie li - Sun Microsystems - Irvine United States boolean_t ok = B_FALSE; 20077c478bd9Sstevel@tonic-gate int defaultaccess = 1; 2008b89a8333Snatalie li - Sun Microsystems - Irvine United States boolean_t reject = B_FALSE; 20097c478bd9Sstevel@tonic-gate 20107c478bd9Sstevel@tonic-gate opts = strdup(sh->sh_opts); 20117c478bd9Sstevel@tonic-gate if (opts == NULL) { 20127c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "getclientsflavors: no memory"); 20137c478bd9Sstevel@tonic-gate return (0); 20147c478bd9Sstevel@tonic-gate } 20157c478bd9Sstevel@tonic-gate 20167c478bd9Sstevel@tonic-gate flavors[0] = AUTH_SYS; 20177c478bd9Sstevel@tonic-gate p = opts; 20187c478bd9Sstevel@tonic-gate 20197c478bd9Sstevel@tonic-gate while (*p) { 20207c478bd9Sstevel@tonic-gate 20217c478bd9Sstevel@tonic-gate switch (getsubopt(&p, optlist, &val)) { 20227c478bd9Sstevel@tonic-gate case OPT_SECURE: 20237c478bd9Sstevel@tonic-gate flavors[0] = AUTH_DES; 20247c478bd9Sstevel@tonic-gate break; 20257c478bd9Sstevel@tonic-gate 20267c478bd9Sstevel@tonic-gate case OPT_RO: 20277c478bd9Sstevel@tonic-gate case OPT_RW: 20287c478bd9Sstevel@tonic-gate defaultaccess = 0; 2029*a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0) 2030*a9685eaaSMarcel Telka ok = B_TRUE; 20317c478bd9Sstevel@tonic-gate break; 2032b89a8333Snatalie li - Sun Microsystems - Irvine United States 2033b89a8333Snatalie li - Sun Microsystems - Irvine United States case OPT_NONE: 2034b89a8333Snatalie li - Sun Microsystems - Irvine United States defaultaccess = 0; 2035*a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0) 2036b89a8333Snatalie li - Sun Microsystems - Irvine United States reject = B_TRUE; 20377c478bd9Sstevel@tonic-gate } 20387c478bd9Sstevel@tonic-gate } 20397c478bd9Sstevel@tonic-gate 20407c478bd9Sstevel@tonic-gate free(opts); 20417c478bd9Sstevel@tonic-gate 2042b89a8333Snatalie li - Sun Microsystems - Irvine United States /* none takes precedence over everything else */ 2043b89a8333Snatalie li - Sun Microsystems - Irvine United States if (reject) 2044*a9685eaaSMarcel Telka ok = B_FALSE; 2045b89a8333Snatalie li - Sun Microsystems - Irvine United States 20467c478bd9Sstevel@tonic-gate return (defaultaccess || ok); 20477c478bd9Sstevel@tonic-gate } 20487c478bd9Sstevel@tonic-gate 20497c478bd9Sstevel@tonic-gate /* 20507c478bd9Sstevel@tonic-gate * Given an export and the clients hostname(s) 20517c478bd9Sstevel@tonic-gate * determine the security flavors that this 20527c478bd9Sstevel@tonic-gate * client is permitted to use. 20537c478bd9Sstevel@tonic-gate * 20547c478bd9Sstevel@tonic-gate * This is somewhat more complicated than the "old" 20557c478bd9Sstevel@tonic-gate * routine because the options may contain multiple 20567c478bd9Sstevel@tonic-gate * security flavors (sec=) each with its own access 20577c478bd9Sstevel@tonic-gate * lists. So a client could be granted access based 20587c478bd9Sstevel@tonic-gate * on a number of security flavors. Note that the 20597c478bd9Sstevel@tonic-gate * type of access might not always be the same, the 20607c478bd9Sstevel@tonic-gate * client may get readonly access with one flavor 20617c478bd9Sstevel@tonic-gate * and readwrite with another, however the client 20627c478bd9Sstevel@tonic-gate * is not told this detail, it gets only the list 20637c478bd9Sstevel@tonic-gate * of flavors, and only if the client is using 20647c478bd9Sstevel@tonic-gate * version 3 of the mount protocol. 20657c478bd9Sstevel@tonic-gate */ 20667c478bd9Sstevel@tonic-gate static int 2067*a9685eaaSMarcel Telka getclientsflavors_new(share_t *sh, struct cln *cln, int *flavors) 20687c478bd9Sstevel@tonic-gate { 20697c478bd9Sstevel@tonic-gate char *opts, *p, *val; 20707c478bd9Sstevel@tonic-gate char *lasts; 20717c478bd9Sstevel@tonic-gate char *f; 2072*a9685eaaSMarcel Telka boolean_t defaultaccess = B_TRUE; /* default access is rw */ 2073*a9685eaaSMarcel Telka boolean_t access_ok = B_FALSE; 2074cf7e209dSIgor Kozhukhov int count, c; 2075b89a8333Snatalie li - Sun Microsystems - Irvine United States boolean_t reject = B_FALSE; 20767c478bd9Sstevel@tonic-gate 20777c478bd9Sstevel@tonic-gate opts = strdup(sh->sh_opts); 20787c478bd9Sstevel@tonic-gate if (opts == NULL) { 20797c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "getclientsflavors: no memory"); 20807c478bd9Sstevel@tonic-gate return (0); 20817c478bd9Sstevel@tonic-gate } 20827c478bd9Sstevel@tonic-gate 20837c478bd9Sstevel@tonic-gate p = opts; 2084cf7e209dSIgor Kozhukhov count = c = 0; 20857c478bd9Sstevel@tonic-gate 20867c478bd9Sstevel@tonic-gate while (*p) { 20877c478bd9Sstevel@tonic-gate switch (getsubopt(&p, optlist, &val)) { 20887c478bd9Sstevel@tonic-gate case OPT_SEC: 2089*a9685eaaSMarcel Telka if (reject) 2090*a9685eaaSMarcel Telka access_ok = B_FALSE; 2091*a9685eaaSMarcel Telka 20927c478bd9Sstevel@tonic-gate /* 20937c478bd9Sstevel@tonic-gate * Before a new sec=xxx option, check if we need 20947c478bd9Sstevel@tonic-gate * to move the c index back to the previous count. 20957c478bd9Sstevel@tonic-gate */ 2096*a9685eaaSMarcel Telka if (!defaultaccess && !access_ok) { 20977c478bd9Sstevel@tonic-gate c = count; 20987c478bd9Sstevel@tonic-gate } 20997c478bd9Sstevel@tonic-gate 21007c478bd9Sstevel@tonic-gate /* get all the sec=f1[:f2] flavors */ 2101*a9685eaaSMarcel Telka while ((f = strtok_r(val, ":", &lasts)) != NULL) { 21027c478bd9Sstevel@tonic-gate flavors[c++] = map_flavor(f); 21037c478bd9Sstevel@tonic-gate val = NULL; 21047c478bd9Sstevel@tonic-gate } 21054a508a79SThomas Haynes 21067c478bd9Sstevel@tonic-gate /* for a new sec=xxx option, default is rw access */ 2107*a9685eaaSMarcel Telka defaultaccess = B_TRUE; 2108*a9685eaaSMarcel Telka access_ok = B_FALSE; 2109*a9685eaaSMarcel Telka reject = B_FALSE; 21107c478bd9Sstevel@tonic-gate break; 21117c478bd9Sstevel@tonic-gate 21127c478bd9Sstevel@tonic-gate case OPT_RO: 21137c478bd9Sstevel@tonic-gate case OPT_RW: 2114*a9685eaaSMarcel Telka defaultaccess = B_FALSE; 2115*a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0) 2116b89a8333Snatalie li - Sun Microsystems - Irvine United States access_ok = B_TRUE; 21177c478bd9Sstevel@tonic-gate break; 2118b89a8333Snatalie li - Sun Microsystems - Irvine United States 2119b89a8333Snatalie li - Sun Microsystems - Irvine United States case OPT_NONE: 2120*a9685eaaSMarcel Telka defaultaccess = B_FALSE; 2121*a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0) 2122b89a8333Snatalie li - Sun Microsystems - Irvine United States reject = B_TRUE; /* none overides rw/ro */ 2123b89a8333Snatalie li - Sun Microsystems - Irvine United States break; 21247c478bd9Sstevel@tonic-gate } 21257c478bd9Sstevel@tonic-gate } 21267c478bd9Sstevel@tonic-gate 2127b89a8333Snatalie li - Sun Microsystems - Irvine United States if (reject) 2128b89a8333Snatalie li - Sun Microsystems - Irvine United States access_ok = B_FALSE; 2129b89a8333Snatalie li - Sun Microsystems - Irvine United States 2130*a9685eaaSMarcel Telka if (!defaultaccess && !access_ok) 21317c478bd9Sstevel@tonic-gate c = count; 2132b89a8333Snatalie li - Sun Microsystems - Irvine United States 21337c478bd9Sstevel@tonic-gate free(opts); 21347c478bd9Sstevel@tonic-gate 21357c478bd9Sstevel@tonic-gate return (c); 21367c478bd9Sstevel@tonic-gate } 21377c478bd9Sstevel@tonic-gate 21387c478bd9Sstevel@tonic-gate /* 21397c478bd9Sstevel@tonic-gate * This is a tricky piece of code that parses the 21407c478bd9Sstevel@tonic-gate * share options looking for a match on the auth 21417c478bd9Sstevel@tonic-gate * flavor that the client is using. If it finds 21427c478bd9Sstevel@tonic-gate * a match, then the client is given ro, rw, or 21437c478bd9Sstevel@tonic-gate * no access depending whether it is in the access 21447c478bd9Sstevel@tonic-gate * list. There is a special case for "secure" 21457c478bd9Sstevel@tonic-gate * flavor. Other flavors are values of the new "sec=" option. 21467c478bd9Sstevel@tonic-gate */ 21477c478bd9Sstevel@tonic-gate int 2148*a9685eaaSMarcel Telka check_client(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid, 2149*a9685eaaSMarcel Telka gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid, 2150*a9685eaaSMarcel Telka gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids) 21517c478bd9Sstevel@tonic-gate { 21527c478bd9Sstevel@tonic-gate if (newopts(sh->sh_opts)) 2153*a9685eaaSMarcel Telka return (check_client_new(sh, cln, flavor, clnt_uid, clnt_gid, 2154*a9685eaaSMarcel Telka clnt_ngids, clnt_gids, srv_uid, srv_gid, srv_ngids, 2155*a9685eaaSMarcel Telka srv_gids)); 21567c478bd9Sstevel@tonic-gate else 2157*a9685eaaSMarcel Telka return (check_client_old(sh, cln, flavor, clnt_uid, clnt_gid, 2158*a9685eaaSMarcel Telka clnt_ngids, clnt_gids, srv_uid, srv_gid, srv_ngids, 2159*a9685eaaSMarcel Telka srv_gids)); 216089621fe1SMarcel Telka } 216189621fe1SMarcel Telka 216289621fe1SMarcel Telka extern int _getgroupsbymember(const char *, gid_t[], int, int); 216389621fe1SMarcel Telka 216489621fe1SMarcel Telka /* 216589621fe1SMarcel Telka * Get supplemental groups for uid 216689621fe1SMarcel Telka */ 216789621fe1SMarcel Telka static int 216889621fe1SMarcel Telka getusergroups(uid_t uid, uint_t *ngrps, gid_t **grps) 216989621fe1SMarcel Telka { 217089621fe1SMarcel Telka struct passwd pwd; 217189621fe1SMarcel Telka char *pwbuf = alloca(pw_size); 217289621fe1SMarcel Telka gid_t *tmpgrps = alloca(ngroups_max * sizeof (gid_t)); 217389621fe1SMarcel Telka int tmpngrps; 217489621fe1SMarcel Telka 217589621fe1SMarcel Telka if (getpwuid_r(uid, &pwd, pwbuf, pw_size) == NULL) 217689621fe1SMarcel Telka return (-1); 217789621fe1SMarcel Telka 217889621fe1SMarcel Telka tmpgrps[0] = pwd.pw_gid; 217989621fe1SMarcel Telka 218089621fe1SMarcel Telka tmpngrps = _getgroupsbymember(pwd.pw_name, tmpgrps, ngroups_max, 1); 218189621fe1SMarcel Telka if (tmpngrps <= 0) { 218289621fe1SMarcel Telka syslog(LOG_WARNING, 218389621fe1SMarcel Telka "getusergroups(): Unable to get groups for user %s", 218489621fe1SMarcel Telka pwd.pw_name); 218589621fe1SMarcel Telka 218689621fe1SMarcel Telka return (-1); 218789621fe1SMarcel Telka } 218889621fe1SMarcel Telka 218989621fe1SMarcel Telka *grps = malloc(tmpngrps * sizeof (gid_t)); 219089621fe1SMarcel Telka if (*grps == NULL) { 219189621fe1SMarcel Telka syslog(LOG_ERR, 219289621fe1SMarcel Telka "getusergroups(): Memory allocation failed: %m"); 219389621fe1SMarcel Telka 219489621fe1SMarcel Telka return (-1); 219589621fe1SMarcel Telka } 219689621fe1SMarcel Telka 219789621fe1SMarcel Telka *ngrps = tmpngrps; 219889621fe1SMarcel Telka (void) memcpy(*grps, tmpgrps, tmpngrps * sizeof (gid_t)); 219989621fe1SMarcel Telka 220089621fe1SMarcel Telka return (0); 22015cb0d679SMarcel Telka } 22025cb0d679SMarcel Telka 22035cb0d679SMarcel Telka /* 22045cb0d679SMarcel Telka * is_a_number(number) 22055cb0d679SMarcel Telka * 22065cb0d679SMarcel Telka * is the string a number in one of the forms we want to use? 22075cb0d679SMarcel Telka */ 22085cb0d679SMarcel Telka 22095cb0d679SMarcel Telka static int 22105cb0d679SMarcel Telka is_a_number(char *number) 22115cb0d679SMarcel Telka { 22125cb0d679SMarcel Telka int ret = 1; 22135cb0d679SMarcel Telka int hex = 0; 22145cb0d679SMarcel Telka 22155cb0d679SMarcel Telka if (strncmp(number, "0x", 2) == 0) { 22165cb0d679SMarcel Telka number += 2; 22175cb0d679SMarcel Telka hex = 1; 22185cb0d679SMarcel Telka } else if (*number == '-') { 22195cb0d679SMarcel Telka number++; /* skip the minus */ 22205cb0d679SMarcel Telka } 22215cb0d679SMarcel Telka while (ret == 1 && *number != '\0') { 22225cb0d679SMarcel Telka if (hex) { 22235cb0d679SMarcel Telka ret = isxdigit(*number++); 22245cb0d679SMarcel Telka } else { 22255cb0d679SMarcel Telka ret = isdigit(*number++); 22265cb0d679SMarcel Telka } 22275cb0d679SMarcel Telka } 22285cb0d679SMarcel Telka return (ret); 22295cb0d679SMarcel Telka } 22305cb0d679SMarcel Telka 22315cb0d679SMarcel Telka static boolean_t 22325cb0d679SMarcel Telka get_uid(char *value, uid_t *uid) 22335cb0d679SMarcel Telka { 22345cb0d679SMarcel Telka if (!is_a_number(value)) { 22355cb0d679SMarcel Telka struct passwd *pw; 22365cb0d679SMarcel Telka /* 22375cb0d679SMarcel Telka * in this case it would have to be a 22385cb0d679SMarcel Telka * user name 22395cb0d679SMarcel Telka */ 22405cb0d679SMarcel Telka pw = getpwnam(value); 22415cb0d679SMarcel Telka if (pw == NULL) 22425cb0d679SMarcel Telka return (B_FALSE); 22435cb0d679SMarcel Telka *uid = pw->pw_uid; 22445cb0d679SMarcel Telka endpwent(); 22455cb0d679SMarcel Telka } else { 22465cb0d679SMarcel Telka uint64_t intval; 22475cb0d679SMarcel Telka intval = strtoull(value, NULL, 0); 22485cb0d679SMarcel Telka if (intval > UID_MAX && intval != -1) 22495cb0d679SMarcel Telka return (B_FALSE); 22505cb0d679SMarcel Telka *uid = (uid_t)intval; 22515cb0d679SMarcel Telka } 22525cb0d679SMarcel Telka 22535cb0d679SMarcel Telka return (B_TRUE); 22545cb0d679SMarcel Telka } 22555cb0d679SMarcel Telka 22565cb0d679SMarcel Telka static boolean_t 22575cb0d679SMarcel Telka get_gid(char *value, gid_t *gid) 22585cb0d679SMarcel Telka { 22595cb0d679SMarcel Telka if (!is_a_number(value)) { 22605cb0d679SMarcel Telka struct group *gr; 22615cb0d679SMarcel Telka /* 22625cb0d679SMarcel Telka * in this case it would have to be a 22635cb0d679SMarcel Telka * group name 22645cb0d679SMarcel Telka */ 22655cb0d679SMarcel Telka gr = getgrnam(value); 22665cb0d679SMarcel Telka if (gr == NULL) 22675cb0d679SMarcel Telka return (B_FALSE); 22685cb0d679SMarcel Telka *gid = gr->gr_gid; 22695cb0d679SMarcel Telka endgrent(); 22705cb0d679SMarcel Telka } else { 22715cb0d679SMarcel Telka uint64_t intval; 22725cb0d679SMarcel Telka intval = strtoull(value, NULL, 0); 22735cb0d679SMarcel Telka if (intval > UID_MAX && intval != -1) 22745cb0d679SMarcel Telka return (B_FALSE); 22755cb0d679SMarcel Telka *gid = (gid_t)intval; 22765cb0d679SMarcel Telka } 22775cb0d679SMarcel Telka 22785cb0d679SMarcel Telka return (B_TRUE); 22797c478bd9Sstevel@tonic-gate } 22807c478bd9Sstevel@tonic-gate 22817c478bd9Sstevel@tonic-gate static int 2282*a9685eaaSMarcel Telka check_client_old(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid, 228389621fe1SMarcel Telka gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid, 228489621fe1SMarcel Telka gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids) 22857c478bd9Sstevel@tonic-gate { 22867c478bd9Sstevel@tonic-gate char *opts, *p, *val; 22877c478bd9Sstevel@tonic-gate int match; /* Set when a flavor is matched */ 22887c478bd9Sstevel@tonic-gate int perm = 0; /* Set when "ro", "rw" or "root" is matched */ 22897c478bd9Sstevel@tonic-gate int list = 0; /* Set when "ro", "rw" is found */ 22907c478bd9Sstevel@tonic-gate int ro_val = 0; /* Set if ro option is 'ro=' */ 22917c478bd9Sstevel@tonic-gate int rw_val = 0; /* Set if rw option is 'rw=' */ 22925cb0d679SMarcel Telka 22935cb0d679SMarcel Telka boolean_t map_deny = B_FALSE; 22947c478bd9Sstevel@tonic-gate 22957c478bd9Sstevel@tonic-gate opts = strdup(sh->sh_opts); 22967c478bd9Sstevel@tonic-gate if (opts == NULL) { 22977c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "check_client: no memory"); 22987c478bd9Sstevel@tonic-gate return (0); 22997c478bd9Sstevel@tonic-gate } 23007c478bd9Sstevel@tonic-gate 230189621fe1SMarcel Telka /* 230289621fe1SMarcel Telka * If client provided 16 supplemental groups with AUTH_SYS, lookup 230389621fe1SMarcel Telka * locally for all of them 230489621fe1SMarcel Telka */ 230589621fe1SMarcel Telka if (flavor == AUTH_SYS && clnt_ngids == NGRPS && ngroups_max > NGRPS) 230689621fe1SMarcel Telka if (getusergroups(clnt_uid, srv_ngids, srv_gids) == 0) 230789621fe1SMarcel Telka perm |= NFSAUTH_GROUPS; 230889621fe1SMarcel Telka 23097c478bd9Sstevel@tonic-gate p = opts; 23107c478bd9Sstevel@tonic-gate match = AUTH_UNIX; 23117c478bd9Sstevel@tonic-gate 23127c478bd9Sstevel@tonic-gate while (*p) { 23137c478bd9Sstevel@tonic-gate switch (getsubopt(&p, optlist, &val)) { 23147c478bd9Sstevel@tonic-gate 23157c478bd9Sstevel@tonic-gate case OPT_SECURE: 23167c478bd9Sstevel@tonic-gate match = AUTH_DES; 231789621fe1SMarcel Telka 231889621fe1SMarcel Telka if (perm & NFSAUTH_GROUPS) { 231989621fe1SMarcel Telka free(*srv_gids); 232089621fe1SMarcel Telka *srv_ngids = 0; 232189621fe1SMarcel Telka *srv_gids = NULL; 232289621fe1SMarcel Telka perm &= ~NFSAUTH_GROUPS; 232389621fe1SMarcel Telka } 232489621fe1SMarcel Telka 23257c478bd9Sstevel@tonic-gate break; 23267c478bd9Sstevel@tonic-gate 23277c478bd9Sstevel@tonic-gate case OPT_RO: 23287c478bd9Sstevel@tonic-gate list++; 23295cb0d679SMarcel Telka if (val != NULL) 23305cb0d679SMarcel Telka ro_val++; 2331*a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0) 23327c478bd9Sstevel@tonic-gate perm |= NFSAUTH_RO; 23337c478bd9Sstevel@tonic-gate break; 23347c478bd9Sstevel@tonic-gate 23357c478bd9Sstevel@tonic-gate case OPT_RW: 23367c478bd9Sstevel@tonic-gate list++; 23375cb0d679SMarcel Telka if (val != NULL) 23385cb0d679SMarcel Telka rw_val++; 2339*a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0) 23407c478bd9Sstevel@tonic-gate perm |= NFSAUTH_RW; 23417c478bd9Sstevel@tonic-gate break; 23427c478bd9Sstevel@tonic-gate 23437c478bd9Sstevel@tonic-gate case OPT_ROOT: 23447c478bd9Sstevel@tonic-gate /* 23457c478bd9Sstevel@tonic-gate * Check if the client is in 23467c478bd9Sstevel@tonic-gate * the root list. Only valid 23477c478bd9Sstevel@tonic-gate * for AUTH_SYS. 23487c478bd9Sstevel@tonic-gate */ 23497c478bd9Sstevel@tonic-gate if (flavor != AUTH_SYS) 23507c478bd9Sstevel@tonic-gate break; 23517c478bd9Sstevel@tonic-gate 23527c478bd9Sstevel@tonic-gate if (val == NULL || *val == '\0') 23537c478bd9Sstevel@tonic-gate break; 23547c478bd9Sstevel@tonic-gate 23555cb0d679SMarcel Telka if (clnt_uid != 0) 23565cb0d679SMarcel Telka break; 23575cb0d679SMarcel Telka 2358*a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0) { 23597c478bd9Sstevel@tonic-gate perm |= NFSAUTH_ROOT; 23605cb0d679SMarcel Telka perm |= NFSAUTH_UIDMAP | NFSAUTH_GIDMAP; 23615cb0d679SMarcel Telka map_deny = B_FALSE; 236289621fe1SMarcel Telka 236389621fe1SMarcel Telka if (perm & NFSAUTH_GROUPS) { 236489621fe1SMarcel Telka free(*srv_gids); 236589621fe1SMarcel Telka *srv_ngids = 0; 236689621fe1SMarcel Telka *srv_gids = NULL; 236789621fe1SMarcel Telka perm &= ~NFSAUTH_GROUPS; 236889621fe1SMarcel Telka } 23695cb0d679SMarcel Telka } 23707c478bd9Sstevel@tonic-gate break; 2371b89a8333Snatalie li - Sun Microsystems - Irvine United States 2372b89a8333Snatalie li - Sun Microsystems - Irvine United States case OPT_NONE: 2373b89a8333Snatalie li - Sun Microsystems - Irvine United States /* 2374b89a8333Snatalie li - Sun Microsystems - Irvine United States * Check if the client should have no access 2375b89a8333Snatalie li - Sun Microsystems - Irvine United States * to this share at all. This option behaves 2376b89a8333Snatalie li - Sun Microsystems - Irvine United States * more like "root" than either "rw" or "ro". 2377b89a8333Snatalie li - Sun Microsystems - Irvine United States */ 2378*a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0) 23795cb0d679SMarcel Telka perm |= NFSAUTH_DENIED; 23805cb0d679SMarcel Telka break; 23815cb0d679SMarcel Telka 23825cb0d679SMarcel Telka case OPT_UIDMAP: { 23835cb0d679SMarcel Telka char *c; 23845cb0d679SMarcel Telka char *n; 23855cb0d679SMarcel Telka 23865cb0d679SMarcel Telka /* 23875cb0d679SMarcel Telka * The uidmap is supported for AUTH_SYS only. 23885cb0d679SMarcel Telka */ 23895cb0d679SMarcel Telka if (flavor != AUTH_SYS) 23905cb0d679SMarcel Telka break; 23915cb0d679SMarcel Telka 23925cb0d679SMarcel Telka if (perm & NFSAUTH_UIDMAP || map_deny) 23935cb0d679SMarcel Telka break; 23945cb0d679SMarcel Telka 23955cb0d679SMarcel Telka for (c = val; c != NULL; c = n) { 23965cb0d679SMarcel Telka char *s; 23975cb0d679SMarcel Telka char *al; 23985cb0d679SMarcel Telka uid_t srv; 23995cb0d679SMarcel Telka 24005cb0d679SMarcel Telka n = strchr(c, '~'); 24015cb0d679SMarcel Telka if (n != NULL) 24025cb0d679SMarcel Telka *n++ = '\0'; 24035cb0d679SMarcel Telka 24045cb0d679SMarcel Telka s = strchr(c, ':'); 24055cb0d679SMarcel Telka if (s != NULL) { 24065cb0d679SMarcel Telka *s++ = '\0'; 24075cb0d679SMarcel Telka al = strchr(s, ':'); 24085cb0d679SMarcel Telka if (al != NULL) 24095cb0d679SMarcel Telka *al++ = '\0'; 24105cb0d679SMarcel Telka } 24115cb0d679SMarcel Telka 24125cb0d679SMarcel Telka if (s == NULL || al == NULL) 24135cb0d679SMarcel Telka continue; 24145cb0d679SMarcel Telka 24155cb0d679SMarcel Telka if (*c == '\0') { 24165cb0d679SMarcel Telka if (clnt_uid != (uid_t)-1) 24175cb0d679SMarcel Telka continue; 24185cb0d679SMarcel Telka } else if (strcmp(c, "*") != 0) { 24195cb0d679SMarcel Telka uid_t clnt; 24205cb0d679SMarcel Telka 24215cb0d679SMarcel Telka if (!get_uid(c, &clnt)) 24225cb0d679SMarcel Telka continue; 24235cb0d679SMarcel Telka 24245cb0d679SMarcel Telka if (clnt_uid != clnt) 24255cb0d679SMarcel Telka continue; 24265cb0d679SMarcel Telka } 24275cb0d679SMarcel Telka 24285cb0d679SMarcel Telka if (*s == '\0') 24295cb0d679SMarcel Telka srv = UID_NOBODY; 24305cb0d679SMarcel Telka else if (!get_uid(s, &srv)) 24315cb0d679SMarcel Telka continue; 24325cb0d679SMarcel Telka else if (srv == (uid_t)-1) { 24335cb0d679SMarcel Telka map_deny = B_TRUE; 24345cb0d679SMarcel Telka break; 24355cb0d679SMarcel Telka } 24365cb0d679SMarcel Telka 2437*a9685eaaSMarcel Telka if (in_access_list(cln, al) > 0) { 24385cb0d679SMarcel Telka *srv_uid = srv; 24395cb0d679SMarcel Telka perm |= NFSAUTH_UIDMAP; 244089621fe1SMarcel Telka 244189621fe1SMarcel Telka if (perm & NFSAUTH_GROUPS) { 244289621fe1SMarcel Telka free(*srv_gids); 244389621fe1SMarcel Telka *srv_ngids = 0; 244489621fe1SMarcel Telka *srv_gids = NULL; 244589621fe1SMarcel Telka perm &= ~NFSAUTH_GROUPS; 244689621fe1SMarcel Telka } 244789621fe1SMarcel Telka 24485cb0d679SMarcel Telka break; 24495cb0d679SMarcel Telka } 24505cb0d679SMarcel Telka } 24515cb0d679SMarcel Telka 24525cb0d679SMarcel Telka break; 24535cb0d679SMarcel Telka } 24545cb0d679SMarcel Telka 24555cb0d679SMarcel Telka case OPT_GIDMAP: { 24565cb0d679SMarcel Telka char *c; 24575cb0d679SMarcel Telka char *n; 24585cb0d679SMarcel Telka 24595cb0d679SMarcel Telka /* 24605cb0d679SMarcel Telka * The gidmap is supported for AUTH_SYS only. 24615cb0d679SMarcel Telka */ 24625cb0d679SMarcel Telka if (flavor != AUTH_SYS) 24635cb0d679SMarcel Telka break; 24645cb0d679SMarcel Telka 24655cb0d679SMarcel Telka if (perm & NFSAUTH_GIDMAP || map_deny) 24665cb0d679SMarcel Telka break; 24675cb0d679SMarcel Telka 24685cb0d679SMarcel Telka for (c = val; c != NULL; c = n) { 24695cb0d679SMarcel Telka char *s; 24705cb0d679SMarcel Telka char *al; 24715cb0d679SMarcel Telka gid_t srv; 24725cb0d679SMarcel Telka 24735cb0d679SMarcel Telka n = strchr(c, '~'); 24745cb0d679SMarcel Telka if (n != NULL) 24755cb0d679SMarcel Telka *n++ = '\0'; 24765cb0d679SMarcel Telka 24775cb0d679SMarcel Telka s = strchr(c, ':'); 24785cb0d679SMarcel Telka if (s != NULL) { 24795cb0d679SMarcel Telka *s++ = '\0'; 24805cb0d679SMarcel Telka al = strchr(s, ':'); 24815cb0d679SMarcel Telka if (al != NULL) 24825cb0d679SMarcel Telka *al++ = '\0'; 24835cb0d679SMarcel Telka } 24845cb0d679SMarcel Telka 24855cb0d679SMarcel Telka if (s == NULL || al == NULL) 24865cb0d679SMarcel Telka break; 24875cb0d679SMarcel Telka 24885cb0d679SMarcel Telka if (*c == '\0') { 24895cb0d679SMarcel Telka if (clnt_gid != (gid_t)-1) 24905cb0d679SMarcel Telka continue; 24915cb0d679SMarcel Telka } else if (strcmp(c, "*") != 0) { 24925cb0d679SMarcel Telka gid_t clnt; 24935cb0d679SMarcel Telka 24945cb0d679SMarcel Telka if (!get_gid(c, &clnt)) 24955cb0d679SMarcel Telka continue; 24965cb0d679SMarcel Telka 24975cb0d679SMarcel Telka if (clnt_gid != clnt) 24985cb0d679SMarcel Telka continue; 24995cb0d679SMarcel Telka } 25005cb0d679SMarcel Telka 25015cb0d679SMarcel Telka if (*s == '\0') 25025cb0d679SMarcel Telka srv = UID_NOBODY; 25035cb0d679SMarcel Telka else if (!get_gid(s, &srv)) 25045cb0d679SMarcel Telka continue; 25055cb0d679SMarcel Telka else if (srv == (gid_t)-1) { 25065cb0d679SMarcel Telka map_deny = B_TRUE; 25075cb0d679SMarcel Telka break; 25085cb0d679SMarcel Telka } 25095cb0d679SMarcel Telka 2510*a9685eaaSMarcel Telka if (in_access_list(cln, al) > 0) { 25115cb0d679SMarcel Telka *srv_gid = srv; 25125cb0d679SMarcel Telka perm |= NFSAUTH_GIDMAP; 251389621fe1SMarcel Telka 251489621fe1SMarcel Telka if (perm & NFSAUTH_GROUPS) { 251589621fe1SMarcel Telka free(*srv_gids); 251689621fe1SMarcel Telka *srv_ngids = 0; 251789621fe1SMarcel Telka *srv_gids = NULL; 251889621fe1SMarcel Telka perm &= ~NFSAUTH_GROUPS; 251989621fe1SMarcel Telka } 252089621fe1SMarcel Telka 25215cb0d679SMarcel Telka break; 25225cb0d679SMarcel Telka } 25235cb0d679SMarcel Telka } 25245cb0d679SMarcel Telka 25255cb0d679SMarcel Telka break; 25265cb0d679SMarcel Telka } 25275cb0d679SMarcel Telka 25285cb0d679SMarcel Telka default: 2529b89a8333Snatalie li - Sun Microsystems - Irvine United States break; 25307c478bd9Sstevel@tonic-gate } 25317c478bd9Sstevel@tonic-gate } 25327c478bd9Sstevel@tonic-gate 25337c478bd9Sstevel@tonic-gate free(opts); 25347c478bd9Sstevel@tonic-gate 25355cb0d679SMarcel Telka if (perm & NFSAUTH_ROOT) { 25365cb0d679SMarcel Telka *srv_uid = 0; 25375cb0d679SMarcel Telka *srv_gid = 0; 25385cb0d679SMarcel Telka } 25395cb0d679SMarcel Telka 25405cb0d679SMarcel Telka if (map_deny) 25415cb0d679SMarcel Telka perm |= NFSAUTH_DENIED; 25425cb0d679SMarcel Telka 25435cb0d679SMarcel Telka if (!(perm & NFSAUTH_UIDMAP)) 25445cb0d679SMarcel Telka *srv_uid = clnt_uid; 25455cb0d679SMarcel Telka if (!(perm & NFSAUTH_GIDMAP)) 25465cb0d679SMarcel Telka *srv_gid = clnt_gid; 25475cb0d679SMarcel Telka 25485cb0d679SMarcel Telka if (flavor != match || perm & NFSAUTH_DENIED) 25497c478bd9Sstevel@tonic-gate return (NFSAUTH_DENIED); 25507c478bd9Sstevel@tonic-gate 25517c478bd9Sstevel@tonic-gate if (list) { 25527c478bd9Sstevel@tonic-gate /* 25537c478bd9Sstevel@tonic-gate * If the client doesn't match an "ro" or "rw" 25547c478bd9Sstevel@tonic-gate * list then set no access. 25557c478bd9Sstevel@tonic-gate */ 25567c478bd9Sstevel@tonic-gate if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0) 25577c478bd9Sstevel@tonic-gate perm |= NFSAUTH_DENIED; 25587c478bd9Sstevel@tonic-gate } else { 25597c478bd9Sstevel@tonic-gate /* 25607c478bd9Sstevel@tonic-gate * The client matched a flavor entry that 25617c478bd9Sstevel@tonic-gate * has no explicit "rw" or "ro" determination. 25627c478bd9Sstevel@tonic-gate * Default it to "rw". 25637c478bd9Sstevel@tonic-gate */ 25647c478bd9Sstevel@tonic-gate perm |= NFSAUTH_RW; 25657c478bd9Sstevel@tonic-gate } 25667c478bd9Sstevel@tonic-gate 25677c478bd9Sstevel@tonic-gate /* 25687c478bd9Sstevel@tonic-gate * The client may show up in both ro= and rw= 25697c478bd9Sstevel@tonic-gate * lists. If so, then turn off the RO access 25707c478bd9Sstevel@tonic-gate * bit leaving RW access. 25717c478bd9Sstevel@tonic-gate */ 25727c478bd9Sstevel@tonic-gate if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) { 25737c478bd9Sstevel@tonic-gate /* 25747c478bd9Sstevel@tonic-gate * Logically cover all permutations of rw=,ro=. 25757c478bd9Sstevel@tonic-gate * In the case where, rw,ro=<host> we would like 25767c478bd9Sstevel@tonic-gate * to remove RW access for the host. In all other cases 25777c478bd9Sstevel@tonic-gate * RW wins the precedence battle. 25787c478bd9Sstevel@tonic-gate */ 25797c478bd9Sstevel@tonic-gate if (!rw_val && ro_val) { 25807c478bd9Sstevel@tonic-gate perm &= ~(NFSAUTH_RW); 25817c478bd9Sstevel@tonic-gate } else { 25827c478bd9Sstevel@tonic-gate perm &= ~(NFSAUTH_RO); 25837c478bd9Sstevel@tonic-gate } 25847c478bd9Sstevel@tonic-gate } 25857c478bd9Sstevel@tonic-gate 25867c478bd9Sstevel@tonic-gate return (perm); 25877c478bd9Sstevel@tonic-gate } 25887c478bd9Sstevel@tonic-gate 25897c478bd9Sstevel@tonic-gate /* 25907c478bd9Sstevel@tonic-gate * Check if the client has access by using a flavor different from 25917c478bd9Sstevel@tonic-gate * the given "flavor". If "flavor" is not in the flavor list, 25927c478bd9Sstevel@tonic-gate * return TRUE to indicate that this "flavor" is a wrong sec. 25937c478bd9Sstevel@tonic-gate */ 25947c478bd9Sstevel@tonic-gate static bool_t 2595*a9685eaaSMarcel Telka is_wrongsec(share_t *sh, struct cln *cln, int flavor) 25967c478bd9Sstevel@tonic-gate { 25977c478bd9Sstevel@tonic-gate int flavor_list[MAX_FLAVORS]; 25987c478bd9Sstevel@tonic-gate int flavor_count, i; 25997c478bd9Sstevel@tonic-gate 26007c478bd9Sstevel@tonic-gate /* get the flavor list that the client has access with */ 2601*a9685eaaSMarcel Telka flavor_count = getclientsflavors_new(sh, cln, flavor_list); 26027c478bd9Sstevel@tonic-gate 26037c478bd9Sstevel@tonic-gate if (flavor_count == 0) 26047c478bd9Sstevel@tonic-gate return (FALSE); 26057c478bd9Sstevel@tonic-gate 26067c478bd9Sstevel@tonic-gate /* 26077c478bd9Sstevel@tonic-gate * Check if the given "flavor" is in the flavor_list. 26087c478bd9Sstevel@tonic-gate */ 26097c478bd9Sstevel@tonic-gate for (i = 0; i < flavor_count; i++) { 26107c478bd9Sstevel@tonic-gate if (flavor == flavor_list[i]) 26117c478bd9Sstevel@tonic-gate return (FALSE); 26127c478bd9Sstevel@tonic-gate } 26137c478bd9Sstevel@tonic-gate 26147c478bd9Sstevel@tonic-gate /* 26157c478bd9Sstevel@tonic-gate * If "flavor" is not in the flavor_list, return TRUE to indicate 26167c478bd9Sstevel@tonic-gate * that the client should have access by using a security flavor 26177c478bd9Sstevel@tonic-gate * different from this "flavor". 26187c478bd9Sstevel@tonic-gate */ 26197c478bd9Sstevel@tonic-gate return (TRUE); 26207c478bd9Sstevel@tonic-gate } 26217c478bd9Sstevel@tonic-gate 26227c478bd9Sstevel@tonic-gate /* 26237c478bd9Sstevel@tonic-gate * Given an export and the client's hostname, we 26247c478bd9Sstevel@tonic-gate * check the security options to see whether the 26257c478bd9Sstevel@tonic-gate * client is allowed to use the given security flavor. 26267c478bd9Sstevel@tonic-gate * 26277c478bd9Sstevel@tonic-gate * The strategy is to proceed through the options looking 26287c478bd9Sstevel@tonic-gate * for a flavor match, then pay attention to the ro, rw, 26297c478bd9Sstevel@tonic-gate * and root options. 26307c478bd9Sstevel@tonic-gate * 26317c478bd9Sstevel@tonic-gate * Note that an entry may list several flavors in a 26327c478bd9Sstevel@tonic-gate * single entry, e.g. 26337c478bd9Sstevel@tonic-gate * 26347c478bd9Sstevel@tonic-gate * sec=krb5,rw=clnt1:clnt2,ro,sec=sys,ro 26357c478bd9Sstevel@tonic-gate * 26367c478bd9Sstevel@tonic-gate */ 26377c478bd9Sstevel@tonic-gate 26387c478bd9Sstevel@tonic-gate static int 2639*a9685eaaSMarcel Telka check_client_new(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid, 264089621fe1SMarcel Telka gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid, 264189621fe1SMarcel Telka gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids) 26427c478bd9Sstevel@tonic-gate { 26437c478bd9Sstevel@tonic-gate char *opts, *p, *val; 26447c478bd9Sstevel@tonic-gate char *lasts; 26457c478bd9Sstevel@tonic-gate char *f; 26467c478bd9Sstevel@tonic-gate int match = 0; /* Set when a flavor is matched */ 26477c478bd9Sstevel@tonic-gate int perm = 0; /* Set when "ro", "rw" or "root" is matched */ 26487c478bd9Sstevel@tonic-gate int list = 0; /* Set when "ro", "rw" is found */ 26497c478bd9Sstevel@tonic-gate int ro_val = 0; /* Set if ro option is 'ro=' */ 26507c478bd9Sstevel@tonic-gate int rw_val = 0; /* Set if rw option is 'rw=' */ 26515cb0d679SMarcel Telka 26525cb0d679SMarcel Telka boolean_t map_deny = B_FALSE; 26537c478bd9Sstevel@tonic-gate 26547c478bd9Sstevel@tonic-gate opts = strdup(sh->sh_opts); 26557c478bd9Sstevel@tonic-gate if (opts == NULL) { 26567c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "check_client: no memory"); 26577c478bd9Sstevel@tonic-gate return (0); 26587c478bd9Sstevel@tonic-gate } 26597c478bd9Sstevel@tonic-gate 266089621fe1SMarcel Telka /* 266189621fe1SMarcel Telka * If client provided 16 supplemental groups with AUTH_SYS, lookup 266289621fe1SMarcel Telka * locally for all of them 266389621fe1SMarcel Telka */ 266489621fe1SMarcel Telka if (flavor == AUTH_SYS && clnt_ngids == NGRPS && ngroups_max > NGRPS) 266589621fe1SMarcel Telka if (getusergroups(clnt_uid, srv_ngids, srv_gids) == 0) 266689621fe1SMarcel Telka perm |= NFSAUTH_GROUPS; 266789621fe1SMarcel Telka 26687c478bd9Sstevel@tonic-gate p = opts; 26697c478bd9Sstevel@tonic-gate 26707c478bd9Sstevel@tonic-gate while (*p) { 26717c478bd9Sstevel@tonic-gate switch (getsubopt(&p, optlist, &val)) { 26727c478bd9Sstevel@tonic-gate 26737c478bd9Sstevel@tonic-gate case OPT_SEC: 26747c478bd9Sstevel@tonic-gate if (match) 26757c478bd9Sstevel@tonic-gate goto done; 26767c478bd9Sstevel@tonic-gate 26777c478bd9Sstevel@tonic-gate while ((f = strtok_r(val, ":", &lasts)) 26787c478bd9Sstevel@tonic-gate != NULL) { 26797c478bd9Sstevel@tonic-gate if (flavor == map_flavor(f)) { 26807c478bd9Sstevel@tonic-gate match = 1; 26817c478bd9Sstevel@tonic-gate break; 26827c478bd9Sstevel@tonic-gate } 26837c478bd9Sstevel@tonic-gate val = NULL; 26847c478bd9Sstevel@tonic-gate } 26857c478bd9Sstevel@tonic-gate break; 26867c478bd9Sstevel@tonic-gate 26877c478bd9Sstevel@tonic-gate case OPT_RO: 26887c478bd9Sstevel@tonic-gate if (!match) 26897c478bd9Sstevel@tonic-gate break; 26907c478bd9Sstevel@tonic-gate 26917c478bd9Sstevel@tonic-gate list++; 26925cb0d679SMarcel Telka if (val != NULL) 26935cb0d679SMarcel Telka ro_val++; 2694*a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0) 26957c478bd9Sstevel@tonic-gate perm |= NFSAUTH_RO; 26967c478bd9Sstevel@tonic-gate break; 26977c478bd9Sstevel@tonic-gate 26987c478bd9Sstevel@tonic-gate case OPT_RW: 26997c478bd9Sstevel@tonic-gate if (!match) 27007c478bd9Sstevel@tonic-gate break; 27017c478bd9Sstevel@tonic-gate 27027c478bd9Sstevel@tonic-gate list++; 27035cb0d679SMarcel Telka if (val != NULL) 27045cb0d679SMarcel Telka rw_val++; 2705*a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0) 27067c478bd9Sstevel@tonic-gate perm |= NFSAUTH_RW; 27077c478bd9Sstevel@tonic-gate break; 27087c478bd9Sstevel@tonic-gate 27097c478bd9Sstevel@tonic-gate case OPT_ROOT: 27107c478bd9Sstevel@tonic-gate /* 27117c478bd9Sstevel@tonic-gate * Check if the client is in 27127c478bd9Sstevel@tonic-gate * the root list. Only valid 27137c478bd9Sstevel@tonic-gate * for AUTH_SYS. 27147c478bd9Sstevel@tonic-gate */ 27157c478bd9Sstevel@tonic-gate if (flavor != AUTH_SYS) 27167c478bd9Sstevel@tonic-gate break; 27177c478bd9Sstevel@tonic-gate 27187c478bd9Sstevel@tonic-gate if (!match) 27197c478bd9Sstevel@tonic-gate break; 27207c478bd9Sstevel@tonic-gate 27217c478bd9Sstevel@tonic-gate if (val == NULL || *val == '\0') 27227c478bd9Sstevel@tonic-gate break; 27237c478bd9Sstevel@tonic-gate 27245cb0d679SMarcel Telka if (clnt_uid != 0) 27255cb0d679SMarcel Telka break; 27265cb0d679SMarcel Telka 2727*a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0) { 27287c478bd9Sstevel@tonic-gate perm |= NFSAUTH_ROOT; 27295cb0d679SMarcel Telka perm |= NFSAUTH_UIDMAP | NFSAUTH_GIDMAP; 27305cb0d679SMarcel Telka map_deny = B_FALSE; 273189621fe1SMarcel Telka 273289621fe1SMarcel Telka if (perm & NFSAUTH_GROUPS) { 273389621fe1SMarcel Telka free(*srv_gids); 273489621fe1SMarcel Telka *srv_gids = NULL; 273589621fe1SMarcel Telka *srv_ngids = 0; 273689621fe1SMarcel Telka perm &= ~NFSAUTH_GROUPS; 273789621fe1SMarcel Telka } 27385cb0d679SMarcel Telka } 27397c478bd9Sstevel@tonic-gate break; 2740b89a8333Snatalie li - Sun Microsystems - Irvine United States 2741b89a8333Snatalie li - Sun Microsystems - Irvine United States case OPT_NONE: 2742b89a8333Snatalie li - Sun Microsystems - Irvine United States /* 2743b89a8333Snatalie li - Sun Microsystems - Irvine United States * Check if the client should have no access 2744b89a8333Snatalie li - Sun Microsystems - Irvine United States * to this share at all. This option behaves 2745b89a8333Snatalie li - Sun Microsystems - Irvine United States * more like "root" than either "rw" or "ro". 2746b89a8333Snatalie li - Sun Microsystems - Irvine United States */ 2747*a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0) 2748b89a8333Snatalie li - Sun Microsystems - Irvine United States perm |= NFSAUTH_DENIED; 2749b89a8333Snatalie li - Sun Microsystems - Irvine United States break; 27505cb0d679SMarcel Telka 27515cb0d679SMarcel Telka case OPT_UIDMAP: { 27525cb0d679SMarcel Telka char *c; 27535cb0d679SMarcel Telka char *n; 27545cb0d679SMarcel Telka 27555cb0d679SMarcel Telka /* 27565cb0d679SMarcel Telka * The uidmap is supported for AUTH_SYS only. 27575cb0d679SMarcel Telka */ 27585cb0d679SMarcel Telka if (flavor != AUTH_SYS) 27595cb0d679SMarcel Telka break; 27605cb0d679SMarcel Telka 27615cb0d679SMarcel Telka if (!match || perm & NFSAUTH_UIDMAP || map_deny) 27625cb0d679SMarcel Telka break; 27635cb0d679SMarcel Telka 27645cb0d679SMarcel Telka for (c = val; c != NULL; c = n) { 27655cb0d679SMarcel Telka char *s; 27665cb0d679SMarcel Telka char *al; 27675cb0d679SMarcel Telka uid_t srv; 27685cb0d679SMarcel Telka 27695cb0d679SMarcel Telka n = strchr(c, '~'); 27705cb0d679SMarcel Telka if (n != NULL) 27715cb0d679SMarcel Telka *n++ = '\0'; 27725cb0d679SMarcel Telka 27735cb0d679SMarcel Telka s = strchr(c, ':'); 27745cb0d679SMarcel Telka if (s != NULL) { 27755cb0d679SMarcel Telka *s++ = '\0'; 27765cb0d679SMarcel Telka al = strchr(s, ':'); 27775cb0d679SMarcel Telka if (al != NULL) 27785cb0d679SMarcel Telka *al++ = '\0'; 27795cb0d679SMarcel Telka } 27805cb0d679SMarcel Telka 27815cb0d679SMarcel Telka if (s == NULL || al == NULL) 27825cb0d679SMarcel Telka continue; 27835cb0d679SMarcel Telka 27845cb0d679SMarcel Telka if (*c == '\0') { 27855cb0d679SMarcel Telka if (clnt_uid != (uid_t)-1) 27865cb0d679SMarcel Telka continue; 27875cb0d679SMarcel Telka } else if (strcmp(c, "*") != 0) { 27885cb0d679SMarcel Telka uid_t clnt; 27895cb0d679SMarcel Telka 27905cb0d679SMarcel Telka if (!get_uid(c, &clnt)) 27915cb0d679SMarcel Telka continue; 27925cb0d679SMarcel Telka 27935cb0d679SMarcel Telka if (clnt_uid != clnt) 27945cb0d679SMarcel Telka continue; 27955cb0d679SMarcel Telka } 27965cb0d679SMarcel Telka 27975cb0d679SMarcel Telka if (*s == '\0') 27985cb0d679SMarcel Telka srv = UID_NOBODY; 27995cb0d679SMarcel Telka else if (!get_uid(s, &srv)) 28005cb0d679SMarcel Telka continue; 28015cb0d679SMarcel Telka else if (srv == (uid_t)-1) { 28025cb0d679SMarcel Telka map_deny = B_TRUE; 28035cb0d679SMarcel Telka break; 28045cb0d679SMarcel Telka } 28055cb0d679SMarcel Telka 2806*a9685eaaSMarcel Telka if (in_access_list(cln, al) > 0) { 28075cb0d679SMarcel Telka *srv_uid = srv; 28085cb0d679SMarcel Telka perm |= NFSAUTH_UIDMAP; 280989621fe1SMarcel Telka 281089621fe1SMarcel Telka if (perm & NFSAUTH_GROUPS) { 281189621fe1SMarcel Telka free(*srv_gids); 281289621fe1SMarcel Telka *srv_gids = NULL; 281389621fe1SMarcel Telka *srv_ngids = 0; 281489621fe1SMarcel Telka perm &= ~NFSAUTH_GROUPS; 281589621fe1SMarcel Telka } 281689621fe1SMarcel Telka 28175cb0d679SMarcel Telka break; 28185cb0d679SMarcel Telka } 28195cb0d679SMarcel Telka } 28205cb0d679SMarcel Telka 28215cb0d679SMarcel Telka break; 28225cb0d679SMarcel Telka } 28235cb0d679SMarcel Telka 28245cb0d679SMarcel Telka case OPT_GIDMAP: { 28255cb0d679SMarcel Telka char *c; 28265cb0d679SMarcel Telka char *n; 28275cb0d679SMarcel Telka 28285cb0d679SMarcel Telka /* 28295cb0d679SMarcel Telka * The gidmap is supported for AUTH_SYS only. 28305cb0d679SMarcel Telka */ 28315cb0d679SMarcel Telka if (flavor != AUTH_SYS) 28325cb0d679SMarcel Telka break; 28335cb0d679SMarcel Telka 28345cb0d679SMarcel Telka if (!match || perm & NFSAUTH_GIDMAP || map_deny) 28355cb0d679SMarcel Telka break; 28365cb0d679SMarcel Telka 28375cb0d679SMarcel Telka for (c = val; c != NULL; c = n) { 28385cb0d679SMarcel Telka char *s; 28395cb0d679SMarcel Telka char *al; 28405cb0d679SMarcel Telka gid_t srv; 28415cb0d679SMarcel Telka 28425cb0d679SMarcel Telka n = strchr(c, '~'); 28435cb0d679SMarcel Telka if (n != NULL) 28445cb0d679SMarcel Telka *n++ = '\0'; 28455cb0d679SMarcel Telka 28465cb0d679SMarcel Telka s = strchr(c, ':'); 28475cb0d679SMarcel Telka if (s != NULL) { 28485cb0d679SMarcel Telka *s++ = '\0'; 28495cb0d679SMarcel Telka al = strchr(s, ':'); 28505cb0d679SMarcel Telka if (al != NULL) 28515cb0d679SMarcel Telka *al++ = '\0'; 28525cb0d679SMarcel Telka } 28535cb0d679SMarcel Telka 28545cb0d679SMarcel Telka if (s == NULL || al == NULL) 28555cb0d679SMarcel Telka break; 28565cb0d679SMarcel Telka 28575cb0d679SMarcel Telka if (*c == '\0') { 28585cb0d679SMarcel Telka if (clnt_gid != (gid_t)-1) 28595cb0d679SMarcel Telka continue; 28605cb0d679SMarcel Telka } else if (strcmp(c, "*") != 0) { 28615cb0d679SMarcel Telka gid_t clnt; 28625cb0d679SMarcel Telka 28635cb0d679SMarcel Telka if (!get_gid(c, &clnt)) 28645cb0d679SMarcel Telka continue; 28655cb0d679SMarcel Telka 28665cb0d679SMarcel Telka if (clnt_gid != clnt) 28675cb0d679SMarcel Telka continue; 28685cb0d679SMarcel Telka } 28695cb0d679SMarcel Telka 28705cb0d679SMarcel Telka if (*s == '\0') 28715cb0d679SMarcel Telka srv = UID_NOBODY; 28725cb0d679SMarcel Telka else if (!get_gid(s, &srv)) 28735cb0d679SMarcel Telka continue; 28745cb0d679SMarcel Telka else if (srv == (gid_t)-1) { 28755cb0d679SMarcel Telka map_deny = B_TRUE; 28765cb0d679SMarcel Telka break; 28775cb0d679SMarcel Telka } 28785cb0d679SMarcel Telka 2879*a9685eaaSMarcel Telka if (in_access_list(cln, al) > 0) { 28805cb0d679SMarcel Telka *srv_gid = srv; 28815cb0d679SMarcel Telka perm |= NFSAUTH_GIDMAP; 288289621fe1SMarcel Telka 288389621fe1SMarcel Telka if (perm & NFSAUTH_GROUPS) { 288489621fe1SMarcel Telka free(*srv_gids); 288589621fe1SMarcel Telka *srv_gids = NULL; 288689621fe1SMarcel Telka *srv_ngids = 0; 288789621fe1SMarcel Telka perm &= ~NFSAUTH_GROUPS; 288889621fe1SMarcel Telka } 288989621fe1SMarcel Telka 28905cb0d679SMarcel Telka break; 28915cb0d679SMarcel Telka } 28925cb0d679SMarcel Telka } 28935cb0d679SMarcel Telka 28945cb0d679SMarcel Telka break; 28955cb0d679SMarcel Telka } 28965cb0d679SMarcel Telka 28975cb0d679SMarcel Telka default: 28985cb0d679SMarcel Telka break; 28997c478bd9Sstevel@tonic-gate } 29007c478bd9Sstevel@tonic-gate } 29017c478bd9Sstevel@tonic-gate 29027c478bd9Sstevel@tonic-gate done: 29035cb0d679SMarcel Telka if (perm & NFSAUTH_ROOT) { 29045cb0d679SMarcel Telka *srv_uid = 0; 29055cb0d679SMarcel Telka *srv_gid = 0; 29065cb0d679SMarcel Telka } 29075cb0d679SMarcel Telka 29085cb0d679SMarcel Telka if (map_deny) 29095cb0d679SMarcel Telka perm |= NFSAUTH_DENIED; 29105cb0d679SMarcel Telka 29115cb0d679SMarcel Telka if (!(perm & NFSAUTH_UIDMAP)) 29125cb0d679SMarcel Telka *srv_uid = clnt_uid; 29135cb0d679SMarcel Telka if (!(perm & NFSAUTH_GIDMAP)) 29145cb0d679SMarcel Telka *srv_gid = clnt_gid; 29155cb0d679SMarcel Telka 29167c478bd9Sstevel@tonic-gate /* 29177c478bd9Sstevel@tonic-gate * If no match then set the perm accordingly 29187c478bd9Sstevel@tonic-gate */ 29195cb0d679SMarcel Telka if (!match || perm & NFSAUTH_DENIED) { 29205cb0d679SMarcel Telka free(opts); 29217c478bd9Sstevel@tonic-gate return (NFSAUTH_DENIED); 29225cb0d679SMarcel Telka } 29237c478bd9Sstevel@tonic-gate 29247c478bd9Sstevel@tonic-gate if (list) { 29257c478bd9Sstevel@tonic-gate /* 29267c478bd9Sstevel@tonic-gate * If the client doesn't match an "ro" or "rw" list then 29277c478bd9Sstevel@tonic-gate * check if it may have access by using a different flavor. 29287c478bd9Sstevel@tonic-gate * If so, return NFSAUTH_WRONGSEC. 29297c478bd9Sstevel@tonic-gate * If not, return NFSAUTH_DENIED. 29307c478bd9Sstevel@tonic-gate */ 29317c478bd9Sstevel@tonic-gate if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0) { 2932*a9685eaaSMarcel Telka if (is_wrongsec(sh, cln, flavor)) 29337c478bd9Sstevel@tonic-gate perm |= NFSAUTH_WRONGSEC; 29347c478bd9Sstevel@tonic-gate else 29357c478bd9Sstevel@tonic-gate perm |= NFSAUTH_DENIED; 29367c478bd9Sstevel@tonic-gate } 29377c478bd9Sstevel@tonic-gate } else { 29387c478bd9Sstevel@tonic-gate /* 29397c478bd9Sstevel@tonic-gate * The client matched a flavor entry that 29407c478bd9Sstevel@tonic-gate * has no explicit "rw" or "ro" determination. 29417c478bd9Sstevel@tonic-gate * Make sure it defaults to "rw". 29427c478bd9Sstevel@tonic-gate */ 29437c478bd9Sstevel@tonic-gate perm |= NFSAUTH_RW; 29447c478bd9Sstevel@tonic-gate } 29457c478bd9Sstevel@tonic-gate 29467c478bd9Sstevel@tonic-gate /* 29477c478bd9Sstevel@tonic-gate * The client may show up in both ro= and rw= 29487c478bd9Sstevel@tonic-gate * lists. If so, then turn off the RO access 29497c478bd9Sstevel@tonic-gate * bit leaving RW access. 29507c478bd9Sstevel@tonic-gate */ 29517c478bd9Sstevel@tonic-gate if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) { 29527c478bd9Sstevel@tonic-gate /* 29537c478bd9Sstevel@tonic-gate * Logically cover all permutations of rw=,ro=. 29547c478bd9Sstevel@tonic-gate * In the case where, rw,ro=<host> we would like 29557c478bd9Sstevel@tonic-gate * to remove RW access for the host. In all other cases 29567c478bd9Sstevel@tonic-gate * RW wins the precedence battle. 29577c478bd9Sstevel@tonic-gate */ 29587c478bd9Sstevel@tonic-gate if (!rw_val && ro_val) { 29597c478bd9Sstevel@tonic-gate perm &= ~(NFSAUTH_RW); 29607c478bd9Sstevel@tonic-gate } else { 29617c478bd9Sstevel@tonic-gate perm &= ~(NFSAUTH_RO); 29627c478bd9Sstevel@tonic-gate } 29637c478bd9Sstevel@tonic-gate } 29647c478bd9Sstevel@tonic-gate 29657c478bd9Sstevel@tonic-gate free(opts); 29667c478bd9Sstevel@tonic-gate 29677c478bd9Sstevel@tonic-gate return (perm); 29687c478bd9Sstevel@tonic-gate } 29697c478bd9Sstevel@tonic-gate 29707c478bd9Sstevel@tonic-gate void 29717c478bd9Sstevel@tonic-gate check_sharetab() 29727c478bd9Sstevel@tonic-gate { 29737c478bd9Sstevel@tonic-gate FILE *f; 29747c478bd9Sstevel@tonic-gate struct stat st; 29757c478bd9Sstevel@tonic-gate static timestruc_t last_sharetab_time; 29767c478bd9Sstevel@tonic-gate timestruc_t prev_sharetab_time; 29774a508a79SThomas Haynes share_t *sh; 29787c478bd9Sstevel@tonic-gate struct sh_list *shp, *shp_prev; 29797c478bd9Sstevel@tonic-gate int res, c = 0; 29807c478bd9Sstevel@tonic-gate 29817c478bd9Sstevel@tonic-gate /* 29827c478bd9Sstevel@tonic-gate * read in /etc/dfs/sharetab if it has changed 29837c478bd9Sstevel@tonic-gate */ 29847c478bd9Sstevel@tonic-gate if (stat(SHARETAB, &st) != 0) { 29857c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB); 29867c478bd9Sstevel@tonic-gate return; 29877c478bd9Sstevel@tonic-gate } 29887c478bd9Sstevel@tonic-gate 29897c478bd9Sstevel@tonic-gate if (st.st_mtim.tv_sec == last_sharetab_time.tv_sec && 29907c478bd9Sstevel@tonic-gate st.st_mtim.tv_nsec == last_sharetab_time.tv_nsec) { 29917c478bd9Sstevel@tonic-gate /* 29927c478bd9Sstevel@tonic-gate * No change. 29937c478bd9Sstevel@tonic-gate */ 29947c478bd9Sstevel@tonic-gate return; 29957c478bd9Sstevel@tonic-gate } 29967c478bd9Sstevel@tonic-gate 29977c478bd9Sstevel@tonic-gate /* 29987c478bd9Sstevel@tonic-gate * Remember the mod time, then after getting the 29997c478bd9Sstevel@tonic-gate * write lock check again. If another thread 30007c478bd9Sstevel@tonic-gate * already did the update, then there's no 30017c478bd9Sstevel@tonic-gate * work to do. 30027c478bd9Sstevel@tonic-gate */ 30037c478bd9Sstevel@tonic-gate prev_sharetab_time = last_sharetab_time; 30047c478bd9Sstevel@tonic-gate 30057c478bd9Sstevel@tonic-gate (void) rw_wrlock(&sharetab_lock); 30067c478bd9Sstevel@tonic-gate 30077c478bd9Sstevel@tonic-gate if (prev_sharetab_time.tv_sec != last_sharetab_time.tv_sec || 30087c478bd9Sstevel@tonic-gate prev_sharetab_time.tv_nsec != last_sharetab_time.tv_nsec) { 30097c478bd9Sstevel@tonic-gate (void) rw_unlock(&sharetab_lock); 30107c478bd9Sstevel@tonic-gate return; 30117c478bd9Sstevel@tonic-gate } 30127c478bd9Sstevel@tonic-gate 3013a237e38eSth199096 /* 3014a237e38eSth199096 * Note that since the sharetab is now in memory 3015a237e38eSth199096 * and a snapshot is taken, we no longer have to 3016a237e38eSth199096 * lock the file. 3017a237e38eSth199096 */ 3018a237e38eSth199096 f = fopen(SHARETAB, "r"); 30197c478bd9Sstevel@tonic-gate if (f == NULL) { 30207c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Cannot open %s: %m", SHARETAB); 30217c478bd9Sstevel@tonic-gate (void) rw_unlock(&sharetab_lock); 30227c478bd9Sstevel@tonic-gate return; 30237c478bd9Sstevel@tonic-gate } 30247c478bd9Sstevel@tonic-gate 30257c478bd9Sstevel@tonic-gate /* 30267c478bd9Sstevel@tonic-gate * Once we are sure /etc/dfs/sharetab has been 30277c478bd9Sstevel@tonic-gate * modified, flush netgroup cache entries. 30287c478bd9Sstevel@tonic-gate */ 30297c478bd9Sstevel@tonic-gate netgrp_cache_flush(); 30307c478bd9Sstevel@tonic-gate 30317c478bd9Sstevel@tonic-gate sh_free(share_list); /* free old list */ 30327c478bd9Sstevel@tonic-gate share_list = NULL; 30337c478bd9Sstevel@tonic-gate 30347c478bd9Sstevel@tonic-gate while ((res = getshare(f, &sh)) > 0) { 30357c478bd9Sstevel@tonic-gate c++; 30367c478bd9Sstevel@tonic-gate if (strcmp(sh->sh_fstype, "nfs") != 0) 30377c478bd9Sstevel@tonic-gate continue; 30387c478bd9Sstevel@tonic-gate 30397c478bd9Sstevel@tonic-gate shp = malloc(sizeof (*shp)); 30407c478bd9Sstevel@tonic-gate if (shp == NULL) 30417c478bd9Sstevel@tonic-gate goto alloc_failed; 30427c478bd9Sstevel@tonic-gate if (share_list == NULL) 30437c478bd9Sstevel@tonic-gate share_list = shp; 30447c478bd9Sstevel@tonic-gate else 30457c478bd9Sstevel@tonic-gate /* LINTED not used before set */ 30467c478bd9Sstevel@tonic-gate shp_prev->shl_next = shp; 30477c478bd9Sstevel@tonic-gate shp_prev = shp; 30487c478bd9Sstevel@tonic-gate shp->shl_next = NULL; 30497c478bd9Sstevel@tonic-gate shp->shl_sh = sharedup(sh); 30507c478bd9Sstevel@tonic-gate if (shp->shl_sh == NULL) 30517c478bd9Sstevel@tonic-gate goto alloc_failed; 30527c478bd9Sstevel@tonic-gate } 30534a508a79SThomas Haynes 30547c478bd9Sstevel@tonic-gate if (res < 0) 30557c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s: invalid at line %d\n", 30567c478bd9Sstevel@tonic-gate SHARETAB, c + 1); 30577c478bd9Sstevel@tonic-gate 30587c478bd9Sstevel@tonic-gate if (stat(SHARETAB, &st) != 0) { 30597c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB); 306062a1b812Sth199096 (void) fclose(f); 30617c478bd9Sstevel@tonic-gate (void) rw_unlock(&sharetab_lock); 30627c478bd9Sstevel@tonic-gate return; 30637c478bd9Sstevel@tonic-gate } 30644a508a79SThomas Haynes 30657c478bd9Sstevel@tonic-gate last_sharetab_time = st.st_mtim; 30667c478bd9Sstevel@tonic-gate (void) fclose(f); 30677c478bd9Sstevel@tonic-gate (void) rw_unlock(&sharetab_lock); 30684a508a79SThomas Haynes 30697c478bd9Sstevel@tonic-gate return; 30707c478bd9Sstevel@tonic-gate 30717c478bd9Sstevel@tonic-gate alloc_failed: 30724a508a79SThomas Haynes 30737c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "check_sharetab: no memory"); 30747c478bd9Sstevel@tonic-gate sh_free(share_list); 30757c478bd9Sstevel@tonic-gate share_list = NULL; 30767c478bd9Sstevel@tonic-gate (void) fclose(f); 30777c478bd9Sstevel@tonic-gate (void) rw_unlock(&sharetab_lock); 30787c478bd9Sstevel@tonic-gate } 30797c478bd9Sstevel@tonic-gate 30807c478bd9Sstevel@tonic-gate static void 30817c478bd9Sstevel@tonic-gate sh_free(struct sh_list *shp) 30827c478bd9Sstevel@tonic-gate { 308354d34259SMarcel Telka struct sh_list *next; 30847c478bd9Sstevel@tonic-gate 30857c478bd9Sstevel@tonic-gate while (shp) { 30867c478bd9Sstevel@tonic-gate sharefree(shp->shl_sh); 30877c478bd9Sstevel@tonic-gate next = shp->shl_next; 30887c478bd9Sstevel@tonic-gate free(shp); 30897c478bd9Sstevel@tonic-gate shp = next; 30907c478bd9Sstevel@tonic-gate } 30917c478bd9Sstevel@tonic-gate } 30927c478bd9Sstevel@tonic-gate 30937c478bd9Sstevel@tonic-gate 30947c478bd9Sstevel@tonic-gate /* 30957c478bd9Sstevel@tonic-gate * Remove an entry from mounted list 30967c478bd9Sstevel@tonic-gate */ 30977c478bd9Sstevel@tonic-gate static void 30987c478bd9Sstevel@tonic-gate umount(struct svc_req *rqstp) 30997c478bd9Sstevel@tonic-gate { 31007c478bd9Sstevel@tonic-gate char *host, *path, *remove_path; 31017c478bd9Sstevel@tonic-gate char rpath[MAXPATHLEN]; 31027c478bd9Sstevel@tonic-gate SVCXPRT *transp; 3103*a9685eaaSMarcel Telka struct cln cln; 31047c478bd9Sstevel@tonic-gate 31057c478bd9Sstevel@tonic-gate transp = rqstp->rq_xprt; 31067c478bd9Sstevel@tonic-gate path = NULL; 31077c478bd9Sstevel@tonic-gate if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) { 31087c478bd9Sstevel@tonic-gate svcerr_decode(transp); 31097c478bd9Sstevel@tonic-gate return; 31107c478bd9Sstevel@tonic-gate } 3111*a9685eaaSMarcel Telka 3112*a9685eaaSMarcel Telka cln_init(&cln, transp); 3113*a9685eaaSMarcel Telka 31147c478bd9Sstevel@tonic-gate errno = 0; 31157c478bd9Sstevel@tonic-gate if (!svc_sendreply(transp, xdr_void, (char *)NULL)) 3116*a9685eaaSMarcel Telka log_cant_reply_cln(&cln); 31177c478bd9Sstevel@tonic-gate 3118*a9685eaaSMarcel Telka host = cln_gethost(&cln); 3119*a9685eaaSMarcel Telka if (host == NULL) { 31207c478bd9Sstevel@tonic-gate /* 31217c478bd9Sstevel@tonic-gate * Without the hostname we can't do audit or delete 31227c478bd9Sstevel@tonic-gate * this host from the mount entries. 31237c478bd9Sstevel@tonic-gate */ 31247c478bd9Sstevel@tonic-gate svc_freeargs(transp, xdr_dirpath, (caddr_t)&path); 31257c478bd9Sstevel@tonic-gate return; 31267c478bd9Sstevel@tonic-gate } 31277c478bd9Sstevel@tonic-gate 31287c478bd9Sstevel@tonic-gate if (verbose) 31297c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE, "UNMOUNT: %s unmounted %s", host, path); 31307c478bd9Sstevel@tonic-gate 31317c478bd9Sstevel@tonic-gate audit_mountd_umount(host, path); 31327c478bd9Sstevel@tonic-gate 31337c478bd9Sstevel@tonic-gate remove_path = rpath; /* assume we will use the cannonical path */ 31347c478bd9Sstevel@tonic-gate if (realpath(path, rpath) == NULL) { 31357c478bd9Sstevel@tonic-gate if (verbose) 31367c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, "UNMOUNT: realpath: %s: %m ", path); 31377c478bd9Sstevel@tonic-gate remove_path = path; /* use path provided instead */ 31387c478bd9Sstevel@tonic-gate } 31397c478bd9Sstevel@tonic-gate 31407c478bd9Sstevel@tonic-gate mntlist_delete(host, remove_path); /* remove from mount list */ 31417c478bd9Sstevel@tonic-gate 3142*a9685eaaSMarcel Telka cln_fini(&cln); 3143*a9685eaaSMarcel Telka 31447c478bd9Sstevel@tonic-gate svc_freeargs(transp, xdr_dirpath, (caddr_t)&path); 31457c478bd9Sstevel@tonic-gate } 31467c478bd9Sstevel@tonic-gate 31477c478bd9Sstevel@tonic-gate /* 31487c478bd9Sstevel@tonic-gate * Remove all entries for one machine from mounted list 31497c478bd9Sstevel@tonic-gate */ 31507c478bd9Sstevel@tonic-gate static void 31517c478bd9Sstevel@tonic-gate umountall(struct svc_req *rqstp) 31527c478bd9Sstevel@tonic-gate { 31537c478bd9Sstevel@tonic-gate SVCXPRT *transp; 31547c478bd9Sstevel@tonic-gate char *host; 3155*a9685eaaSMarcel Telka struct cln cln; 31567c478bd9Sstevel@tonic-gate 31577c478bd9Sstevel@tonic-gate transp = rqstp->rq_xprt; 31587c478bd9Sstevel@tonic-gate if (!svc_getargs(transp, xdr_void, NULL)) { 31597c478bd9Sstevel@tonic-gate svcerr_decode(transp); 31607c478bd9Sstevel@tonic-gate return; 31617c478bd9Sstevel@tonic-gate } 31627c478bd9Sstevel@tonic-gate /* 31637c478bd9Sstevel@tonic-gate * We assume that this call is asynchronous and made via rpcbind 31647c478bd9Sstevel@tonic-gate * callit routine. Therefore return control immediately. The error 31657c478bd9Sstevel@tonic-gate * causes rpcbind to remain silent, as opposed to every machine 31667c478bd9Sstevel@tonic-gate * on the net blasting the requester with a response. 31677c478bd9Sstevel@tonic-gate */ 31687c478bd9Sstevel@tonic-gate svcerr_systemerr(transp); 3169*a9685eaaSMarcel Telka 3170*a9685eaaSMarcel Telka cln_init(&cln, transp); 3171*a9685eaaSMarcel Telka 3172*a9685eaaSMarcel Telka host = cln_gethost(&cln); 3173*a9685eaaSMarcel Telka if (host == NULL) { 31747c478bd9Sstevel@tonic-gate /* Can't do anything without the name of the client */ 31757c478bd9Sstevel@tonic-gate return; 31767c478bd9Sstevel@tonic-gate } 31777c478bd9Sstevel@tonic-gate 31787c478bd9Sstevel@tonic-gate /* 31797c478bd9Sstevel@tonic-gate * Remove all hosts entries from mount list 31807c478bd9Sstevel@tonic-gate */ 31817c478bd9Sstevel@tonic-gate mntlist_delete_all(host); 31827c478bd9Sstevel@tonic-gate 31837c478bd9Sstevel@tonic-gate if (verbose) 31847c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE, "UNMOUNTALL: from %s", host); 31857c478bd9Sstevel@tonic-gate 3186*a9685eaaSMarcel Telka cln_fini(&cln); 31877c478bd9Sstevel@tonic-gate } 31887c478bd9Sstevel@tonic-gate 31897c478bd9Sstevel@tonic-gate void * 31907c478bd9Sstevel@tonic-gate exmalloc(size_t size) 31917c478bd9Sstevel@tonic-gate { 31927c478bd9Sstevel@tonic-gate void *ret; 31937c478bd9Sstevel@tonic-gate 31947c478bd9Sstevel@tonic-gate if ((ret = malloc(size)) == NULL) { 31957c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Out of memory"); 31967c478bd9Sstevel@tonic-gate exit(1); 31977c478bd9Sstevel@tonic-gate } 31987c478bd9Sstevel@tonic-gate return (ret); 31997c478bd9Sstevel@tonic-gate } 32007c478bd9Sstevel@tonic-gate 320103986916Sjarrett static tsol_tpent_t * 320203986916Sjarrett get_client_template(struct sockaddr *sock) 320303986916Sjarrett { 320403986916Sjarrett in_addr_t v4client; 320503986916Sjarrett in6_addr_t v6client; 320603986916Sjarrett char v4_addr[INET_ADDRSTRLEN]; 320703986916Sjarrett char v6_addr[INET6_ADDRSTRLEN]; 320803986916Sjarrett tsol_rhent_t *rh; 320903986916Sjarrett tsol_tpent_t *tp; 321003986916Sjarrett 321103986916Sjarrett switch (sock->sa_family) { 321203986916Sjarrett case AF_INET: 321303986916Sjarrett v4client = ((struct sockaddr_in *)(void *)sock)-> 321403986916Sjarrett sin_addr.s_addr; 321503986916Sjarrett if (inet_ntop(AF_INET, &v4client, v4_addr, INET_ADDRSTRLEN) == 321603986916Sjarrett NULL) 321703986916Sjarrett return (NULL); 321803986916Sjarrett rh = tsol_getrhbyaddr(v4_addr, sizeof (v4_addr), AF_INET); 321903986916Sjarrett if (rh == NULL) 322003986916Sjarrett return (NULL); 322103986916Sjarrett tp = tsol_gettpbyname(rh->rh_template); 322203986916Sjarrett tsol_freerhent(rh); 322303986916Sjarrett return (tp); 322403986916Sjarrett break; 322503986916Sjarrett case AF_INET6: 322603986916Sjarrett v6client = ((struct sockaddr_in6 *)(void *)sock)->sin6_addr; 322703986916Sjarrett if (inet_ntop(AF_INET6, &v6client, v6_addr, INET6_ADDRSTRLEN) == 322803986916Sjarrett NULL) 322903986916Sjarrett return (NULL); 323003986916Sjarrett rh = tsol_getrhbyaddr(v6_addr, sizeof (v6_addr), AF_INET6); 323103986916Sjarrett if (rh == NULL) 323203986916Sjarrett return (NULL); 323303986916Sjarrett tp = tsol_gettpbyname(rh->rh_template); 323403986916Sjarrett tsol_freerhent(rh); 323503986916Sjarrett return (tp); 323603986916Sjarrett break; 323703986916Sjarrett default: 323803986916Sjarrett return (NULL); 323903986916Sjarrett } 324003986916Sjarrett } 3241