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 /*
2389621fe1SMarcel Telka * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
242c3ccf74SGordon Ross * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
252c3ccf74SGordon Ross * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
2635a075c3SToomas Soome * Copyright 2022 RackTop Systems.
277c478bd9Sstevel@tonic-gate */
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
30544783caSToomas Soome /* All Rights Reserved */
317c478bd9Sstevel@tonic-gate
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD
347c478bd9Sstevel@tonic-gate * under license from the Regents of the University of California.
357c478bd9Sstevel@tonic-gate */
367c478bd9Sstevel@tonic-gate
377c478bd9Sstevel@tonic-gate #include <stdio.h>
3897adda44SMarcel Telka #include <stdio_ext.h>
397c478bd9Sstevel@tonic-gate #include <stdlib.h>
407c478bd9Sstevel@tonic-gate #include <ctype.h>
417c478bd9Sstevel@tonic-gate #include <sys/types.h>
427c478bd9Sstevel@tonic-gate #include <string.h>
437c478bd9Sstevel@tonic-gate #include <syslog.h>
447c478bd9Sstevel@tonic-gate #include <sys/param.h>
457c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
467c478bd9Sstevel@tonic-gate #include <sys/stat.h>
477c478bd9Sstevel@tonic-gate #include <netconfig.h>
487c478bd9Sstevel@tonic-gate #include <netdir.h>
497c478bd9Sstevel@tonic-gate #include <sys/file.h>
507c478bd9Sstevel@tonic-gate #include <sys/time.h>
517c478bd9Sstevel@tonic-gate #include <sys/errno.h>
527c478bd9Sstevel@tonic-gate #include <rpcsvc/mount.h>
537c478bd9Sstevel@tonic-gate #include <sys/pathconf.h>
547c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
557c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
56250a0733Sth #include <sys/wait.h>
5797adda44SMarcel Telka #include <sys/resource.h>
587c478bd9Sstevel@tonic-gate #include <signal.h>
597c478bd9Sstevel@tonic-gate #include <locale.h>
607c478bd9Sstevel@tonic-gate #include <unistd.h>
617c478bd9Sstevel@tonic-gate #include <errno.h>
627c478bd9Sstevel@tonic-gate #include <sys/socket.h>
637c478bd9Sstevel@tonic-gate #include <netinet/in.h>
647c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
657c478bd9Sstevel@tonic-gate #include <netdb.h>
667c478bd9Sstevel@tonic-gate #include <thread.h>
677c478bd9Sstevel@tonic-gate #include <assert.h>
687c478bd9Sstevel@tonic-gate #include <priv_utils.h>
691cc55349Srmesta #include <nfs/auth.h>
701cc55349Srmesta #include <nfs/nfssys.h>
717c478bd9Sstevel@tonic-gate #include <nfs/nfs.h>
727c478bd9Sstevel@tonic-gate #include <nfs/nfs_sec.h>
737c478bd9Sstevel@tonic-gate #include <rpcsvc/daemon_utils.h>
747c478bd9Sstevel@tonic-gate #include <deflt.h>
757c478bd9Sstevel@tonic-gate #include "../../fslib.h"
76a237e38eSth #include <sharefs/share.h>
77a237e38eSth #include <sharefs/sharetab.h>
787c478bd9Sstevel@tonic-gate #include "../lib/sharetab.h"
797c478bd9Sstevel@tonic-gate #include "mountd.h"
8003986916Sjarrett #include <tsol/label.h>
8103986916Sjarrett #include <sys/tsol/label_macro.h>
8203986916Sjarrett #include <libtsnet.h>
834a508a79SThomas Haynes #include <sys/sdt.h>
84dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include <libscf.h>
85dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include <limits.h>
866b086bafSSam Falkner #include <sys/nvpair.h>
876b086bafSSam Falkner #include <attr.h>
88dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include "smfcfg.h"
895cb0d679SMarcel Telka #include <pwd.h>
905cb0d679SMarcel Telka #include <grp.h>
9189621fe1SMarcel Telka #include <alloca.h>
9235a075c3SToomas Soome #include <libinetutil.h>
9335a075c3SToomas Soome #include <libsocket_priv.h>
947c478bd9Sstevel@tonic-gate
95250a0733Sth extern int daemonize_init(void);
9654d34259SMarcel Telka extern void daemonize_fini(int);
9754d34259SMarcel Telka
9854d34259SMarcel Telka extern int _nfssys(int, void *);
99250a0733Sth
1007c478bd9Sstevel@tonic-gate struct sh_list *share_list;
1017c478bd9Sstevel@tonic-gate
1027c478bd9Sstevel@tonic-gate rwlock_t sharetab_lock; /* lock to protect the cached sharetab */
1037c478bd9Sstevel@tonic-gate static mutex_t mnttab_lock; /* prevent concurrent mnttab readers */
1047c478bd9Sstevel@tonic-gate
1054a508a79SThomas Haynes static mutex_t logging_queue_lock;
1064a508a79SThomas Haynes static cond_t logging_queue_cv;
1074a508a79SThomas Haynes
1084a508a79SThomas Haynes static share_t *find_lofsentry(char *, int *);
109a9685eaaSMarcel Telka static int getclientsflavors_old(share_t *, struct cln *, int *);
110a9685eaaSMarcel Telka static int getclientsflavors_new(share_t *, struct cln *, int *);
111a9685eaaSMarcel Telka static int check_client_old(share_t *, struct cln *, int, uid_t, gid_t, uint_t,
112a9685eaaSMarcel Telka gid_t *, uid_t *, gid_t *, uint_t *, gid_t **);
113a9685eaaSMarcel Telka static int check_client_new(share_t *, struct cln *, int, uid_t, gid_t, uint_t,
114a9685eaaSMarcel Telka gid_t *, uid_t *, gid_t *i, uint_t *, gid_t **);
1157c478bd9Sstevel@tonic-gate static void mnt(struct svc_req *, SVCXPRT *);
1167c478bd9Sstevel@tonic-gate static void mnt_pathconf(struct svc_req *);
1174a508a79SThomas Haynes static int mount(struct svc_req *r);
1187c478bd9Sstevel@tonic-gate static void sh_free(struct sh_list *);
1197c478bd9Sstevel@tonic-gate static void umount(struct svc_req *);
1207c478bd9Sstevel@tonic-gate static void umountall(struct svc_req *);
1217c478bd9Sstevel@tonic-gate static int newopts(char *);
12203986916Sjarrett static tsol_tpent_t *get_client_template(struct sockaddr *);
1237c478bd9Sstevel@tonic-gate
1242c3ccf74SGordon Ross static int debug;
1257c478bd9Sstevel@tonic-gate static int verbose;
1267c478bd9Sstevel@tonic-gate static int rejecting;
1277c478bd9Sstevel@tonic-gate static int mount_vers_min = MOUNTVERS;
1287c478bd9Sstevel@tonic-gate static int mount_vers_max = MOUNTVERS3;
1292c3ccf74SGordon Ross static int mountd_port = 0;
13035a075c3SToomas Soome static boolean_t mountd_remote_dump = B_FALSE;
1317c478bd9Sstevel@tonic-gate
132b89a8333Snatalie li - Sun Microsystems - Irvine United States extern void nfscmd_func(void *, char *, size_t, door_desc_t *, uint_t);
133b89a8333Snatalie li - Sun Microsystems - Irvine United States
1341cc55349Srmesta thread_t nfsauth_thread;
135b89a8333Snatalie li - Sun Microsystems - Irvine United States thread_t cmd_thread;
1364a508a79SThomas Haynes thread_t logging_thread;
1374a508a79SThomas Haynes
1384a508a79SThomas Haynes typedef struct logging_data {
1394a508a79SThomas Haynes char *ld_host;
1404a508a79SThomas Haynes char *ld_path;
1414a508a79SThomas Haynes char *ld_rpath;
1424a508a79SThomas Haynes int ld_status;
1434a508a79SThomas Haynes char *ld_netid;
1444a508a79SThomas Haynes struct netbuf *ld_nb;
1454a508a79SThomas Haynes struct logging_data *ld_next;
1464a508a79SThomas Haynes } logging_data;
1474a508a79SThomas Haynes
1484a508a79SThomas Haynes static logging_data *logging_head = NULL;
1494a508a79SThomas Haynes static logging_data *logging_tail = NULL;
1501cc55349Srmesta
15189621fe1SMarcel Telka /*
15289621fe1SMarcel Telka * Our copy of some system variables obtained using sysconf(3c)
15389621fe1SMarcel Telka */
15489621fe1SMarcel Telka static long ngroups_max; /* _SC_NGROUPS_MAX */
15589621fe1SMarcel Telka static long pw_size; /* _SC_GETPW_R_SIZE_MAX */
15689621fe1SMarcel Telka
15735a075c3SToomas Soome /* Cached address info for this host. */
15835a075c3SToomas Soome static struct addrinfo *host_ai = NULL;
15935a075c3SToomas Soome
1601cc55349Srmesta static void *
nfsauth_svc(void * arg __unused)161544783caSToomas Soome nfsauth_svc(void *arg __unused)
1621cc55349Srmesta {
1631cc55349Srmesta int doorfd = -1;
1641cc55349Srmesta uint_t darg;
1651cc55349Srmesta #ifdef DEBUG
1661cc55349Srmesta int dfd;
1671cc55349Srmesta #endif
1681cc55349Srmesta
1691cc55349Srmesta if ((doorfd = door_create(nfsauth_func, NULL,
1701cc55349Srmesta DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
1711cc55349Srmesta syslog(LOG_ERR, "Unable to create door: %m\n");
1721cc55349Srmesta exit(10);
1731cc55349Srmesta }
1741cc55349Srmesta
1751cc55349Srmesta #ifdef DEBUG
1761cc55349Srmesta /*
1771cc55349Srmesta * Create a file system path for the door
1781cc55349Srmesta */
1791cc55349Srmesta if ((dfd = open(MOUNTD_DOOR, O_RDWR|O_CREAT|O_TRUNC,
1801cc55349Srmesta S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) {
1811cc55349Srmesta syslog(LOG_ERR, "Unable to open %s: %m\n", MOUNTD_DOOR);
1821cc55349Srmesta (void) close(doorfd);
1831cc55349Srmesta exit(11);
1841cc55349Srmesta }
1851cc55349Srmesta
1861cc55349Srmesta /*
1871cc55349Srmesta * Clean up any stale namespace associations
1881cc55349Srmesta */
1891cc55349Srmesta (void) fdetach(MOUNTD_DOOR);
1901cc55349Srmesta
1911cc55349Srmesta /*
1921cc55349Srmesta * Register in namespace to pass to the kernel to door_ki_open
1931cc55349Srmesta */
1941cc55349Srmesta if (fattach(doorfd, MOUNTD_DOOR) == -1) {
1951cc55349Srmesta syslog(LOG_ERR, "Unable to fattach door: %m\n");
1961cc55349Srmesta (void) close(dfd);
1971cc55349Srmesta (void) close(doorfd);
1981cc55349Srmesta exit(12);
1991cc55349Srmesta }
2001cc55349Srmesta (void) close(dfd);
2011cc55349Srmesta #endif
2021cc55349Srmesta
2031cc55349Srmesta /*
2041cc55349Srmesta * Must pass the doorfd down to the kernel.
2051cc55349Srmesta */
2061cc55349Srmesta darg = doorfd;
2071cc55349Srmesta (void) _nfssys(MOUNTD_ARGS, &darg);
2081cc55349Srmesta
2091cc55349Srmesta /*
2101cc55349Srmesta * Wait for incoming calls
2111cc55349Srmesta */
2121cc55349Srmesta /*CONSTCOND*/
2131cc55349Srmesta for (;;)
2141cc55349Srmesta (void) pause();
2151cc55349Srmesta
2161cc55349Srmesta /*NOTREACHED*/
2171cc55349Srmesta syslog(LOG_ERR, gettext("Door server exited"));
2181cc55349Srmesta return (NULL);
2191cc55349Srmesta }
2201cc55349Srmesta
221b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
222b89a8333Snatalie li - Sun Microsystems - Irvine United States * NFS command service thread code for setup and handling of the
223b89a8333Snatalie li - Sun Microsystems - Irvine United States * nfs_cmd requests for character set conversion and other future
224b89a8333Snatalie li - Sun Microsystems - Irvine United States * events.
225b89a8333Snatalie li - Sun Microsystems - Irvine United States */
226b89a8333Snatalie li - Sun Microsystems - Irvine United States
227b89a8333Snatalie li - Sun Microsystems - Irvine United States static void *
cmd_svc(void * arg)228b89a8333Snatalie li - Sun Microsystems - Irvine United States cmd_svc(void *arg)
229b89a8333Snatalie li - Sun Microsystems - Irvine United States {
230b89a8333Snatalie li - Sun Microsystems - Irvine United States int doorfd = -1;
231b89a8333Snatalie li - Sun Microsystems - Irvine United States uint_t darg;
232b89a8333Snatalie li - Sun Microsystems - Irvine United States
233b89a8333Snatalie li - Sun Microsystems - Irvine United States if ((doorfd = door_create(nfscmd_func, NULL,
234b89a8333Snatalie li - Sun Microsystems - Irvine United States DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
235b89a8333Snatalie li - Sun Microsystems - Irvine United States syslog(LOG_ERR, "Unable to create cmd door: %m\n");
236b89a8333Snatalie li - Sun Microsystems - Irvine United States exit(10);
237b89a8333Snatalie li - Sun Microsystems - Irvine United States }
238b89a8333Snatalie li - Sun Microsystems - Irvine United States
239b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
240b89a8333Snatalie li - Sun Microsystems - Irvine United States * Must pass the doorfd down to the kernel.
241b89a8333Snatalie li - Sun Microsystems - Irvine United States */
242b89a8333Snatalie li - Sun Microsystems - Irvine United States darg = doorfd;
243b89a8333Snatalie li - Sun Microsystems - Irvine United States (void) _nfssys(NFSCMD_ARGS, &darg);
244b89a8333Snatalie li - Sun Microsystems - Irvine United States
245b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
246b89a8333Snatalie li - Sun Microsystems - Irvine United States * Wait for incoming calls
247b89a8333Snatalie li - Sun Microsystems - Irvine United States */
248b89a8333Snatalie li - Sun Microsystems - Irvine United States /*CONSTCOND*/
249b89a8333Snatalie li - Sun Microsystems - Irvine United States for (;;)
250b89a8333Snatalie li - Sun Microsystems - Irvine United States (void) pause();
251b89a8333Snatalie li - Sun Microsystems - Irvine United States
252b89a8333Snatalie li - Sun Microsystems - Irvine United States /*NOTREACHED*/
253b89a8333Snatalie li - Sun Microsystems - Irvine United States syslog(LOG_ERR, gettext("Cmd door server exited"));
254b89a8333Snatalie li - Sun Microsystems - Irvine United States return (NULL);
255b89a8333Snatalie li - Sun Microsystems - Irvine United States }
256250a0733Sth
2574a508a79SThomas Haynes static void
free_logging_data(logging_data * lq)2584a508a79SThomas Haynes free_logging_data(logging_data *lq)
2594a508a79SThomas Haynes {
2604a508a79SThomas Haynes if (lq != NULL) {
2614a508a79SThomas Haynes free(lq->ld_host);
2624a508a79SThomas Haynes free(lq->ld_netid);
2634a508a79SThomas Haynes
2644a508a79SThomas Haynes if (lq->ld_nb != NULL) {
2654a508a79SThomas Haynes free(lq->ld_nb->buf);
2664a508a79SThomas Haynes free(lq->ld_nb);
2674a508a79SThomas Haynes }
2684a508a79SThomas Haynes
2694a508a79SThomas Haynes free(lq->ld_path);
2704a508a79SThomas Haynes free(lq->ld_rpath);
2714a508a79SThomas Haynes
2724a508a79SThomas Haynes free(lq);
2734a508a79SThomas Haynes }
2744a508a79SThomas Haynes }
2754a508a79SThomas Haynes
2764a508a79SThomas Haynes static logging_data *
remove_head_of_queue(void)2774a508a79SThomas Haynes remove_head_of_queue(void)
2784a508a79SThomas Haynes {
2794a508a79SThomas Haynes logging_data *lq;
2804a508a79SThomas Haynes
2814a508a79SThomas Haynes /*
2824a508a79SThomas Haynes * Pull it off the queue.
2834a508a79SThomas Haynes */
2844a508a79SThomas Haynes lq = logging_head;
2854a508a79SThomas Haynes if (lq) {
2864a508a79SThomas Haynes logging_head = lq->ld_next;
2874a508a79SThomas Haynes
2884a508a79SThomas Haynes /*
2894a508a79SThomas Haynes * Drained it.
2904a508a79SThomas Haynes */
2914a508a79SThomas Haynes if (logging_head == NULL) {
2924a508a79SThomas Haynes logging_tail = NULL;
2934a508a79SThomas Haynes }
2944a508a79SThomas Haynes }
2954a508a79SThomas Haynes
2964a508a79SThomas Haynes return (lq);
2974a508a79SThomas Haynes }
2984a508a79SThomas Haynes
2994a508a79SThomas Haynes static void
do_logging_queue(logging_data * lq)3004a508a79SThomas Haynes do_logging_queue(logging_data *lq)
3014a508a79SThomas Haynes {
3024a508a79SThomas Haynes int cleared = 0;
3034a508a79SThomas Haynes char *host;
3044a508a79SThomas Haynes
3054a508a79SThomas Haynes while (lq) {
306a9685eaaSMarcel Telka struct cln cln;
307a9685eaaSMarcel Telka
3084a508a79SThomas Haynes if (lq->ld_host == NULL) {
3094a508a79SThomas Haynes DTRACE_PROBE(mountd, name_by_lazy);
310a9685eaaSMarcel Telka cln_init_lazy(&cln, lq->ld_netid, lq->ld_nb);
311a9685eaaSMarcel Telka host = cln_gethost(&cln);
3124a508a79SThomas Haynes } else
3134a508a79SThomas Haynes host = lq->ld_host;
3144a508a79SThomas Haynes
3154a508a79SThomas Haynes audit_mountd_mount(host, lq->ld_path, lq->ld_status); /* BSM */
3164a508a79SThomas Haynes
3174a508a79SThomas Haynes /* add entry to mount list */
3184a508a79SThomas Haynes if (lq->ld_rpath)
3194a508a79SThomas Haynes mntlist_new(host, lq->ld_rpath);
3204a508a79SThomas Haynes
321a9685eaaSMarcel Telka if (lq->ld_host == NULL)
322a9685eaaSMarcel Telka cln_fini(&cln);
323d383eb7aSMarcel Telka
324c596e866SMarcel Telka free_logging_data(lq);
325c596e866SMarcel Telka cleared++;
3264a508a79SThomas Haynes
3274a508a79SThomas Haynes (void) mutex_lock(&logging_queue_lock);
3284a508a79SThomas Haynes lq = remove_head_of_queue();
3294a508a79SThomas Haynes (void) mutex_unlock(&logging_queue_lock);
3304a508a79SThomas Haynes }
3314a508a79SThomas Haynes
3324a508a79SThomas Haynes DTRACE_PROBE1(mountd, logging_cleared, cleared);
3334a508a79SThomas Haynes }
3344a508a79SThomas Haynes
3354a508a79SThomas Haynes static void *
logging_svc(void * arg __unused)336544783caSToomas Soome logging_svc(void *arg __unused)
3374a508a79SThomas Haynes {
3384a508a79SThomas Haynes logging_data *lq;
3394a508a79SThomas Haynes
3404a508a79SThomas Haynes for (;;) {
3414a508a79SThomas Haynes (void) mutex_lock(&logging_queue_lock);
3424a508a79SThomas Haynes while (logging_head == NULL) {
3434a508a79SThomas Haynes (void) cond_wait(&logging_queue_cv,
3444a508a79SThomas Haynes &logging_queue_lock);
3454a508a79SThomas Haynes }
3464a508a79SThomas Haynes
3474a508a79SThomas Haynes lq = remove_head_of_queue();
3484a508a79SThomas Haynes (void) mutex_unlock(&logging_queue_lock);
3494a508a79SThomas Haynes
3504a508a79SThomas Haynes do_logging_queue(lq);
3514a508a79SThomas Haynes }
3524a508a79SThomas Haynes
3534a508a79SThomas Haynes /*NOTREACHED*/
3544a508a79SThomas Haynes syslog(LOG_ERR, gettext("Logging server exited"));
3554a508a79SThomas Haynes return (NULL);
3564a508a79SThomas Haynes }
3574a508a79SThomas Haynes
3582c3ccf74SGordon Ross /*
3592c3ccf74SGordon Ross * This function is called for each configured network type to
3602c3ccf74SGordon Ross * bind and register our RPC service programs.
3612c3ccf74SGordon Ross *
3622c3ccf74SGordon Ross * On TCP or UDP, we may want to bind MOUNTPROG on a specific port
3632c3ccf74SGordon Ross * (when mountd_port is specified) in which case we'll use the
3642c3ccf74SGordon Ross * variant of svc_tp_create() that lets us pass a bind address.
3652c3ccf74SGordon Ross */
3662c3ccf74SGordon Ross static void
md_svc_tp_create(struct netconfig * nconf)3672c3ccf74SGordon Ross md_svc_tp_create(struct netconfig *nconf)
3682c3ccf74SGordon Ross {
3692c3ccf74SGordon Ross char port_str[8];
3702c3ccf74SGordon Ross struct nd_hostserv hs;
3712c3ccf74SGordon Ross struct nd_addrlist *al = NULL;
3722c3ccf74SGordon Ross SVCXPRT *xprt = NULL;
3732c3ccf74SGordon Ross rpcvers_t vers;
3742c3ccf74SGordon Ross
3752c3ccf74SGordon Ross vers = mount_vers_max;
3762c3ccf74SGordon Ross
3772c3ccf74SGordon Ross /*
3782c3ccf74SGordon Ross * If mountd_port is set and this is an inet transport,
3792c3ccf74SGordon Ross * bind this service on the specified port. The TLI way
3802c3ccf74SGordon Ross * to create such a bind address is netdir_getbyname()
3812c3ccf74SGordon Ross * with the special "host" HOST_SELF_BIND. This builds
3822c3ccf74SGordon Ross * an all-zeros IP address with the specified port.
3832c3ccf74SGordon Ross */
3842c3ccf74SGordon Ross if (mountd_port != 0 &&
3852c3ccf74SGordon Ross (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
3862c3ccf74SGordon Ross strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
3872c3ccf74SGordon Ross int err;
3882c3ccf74SGordon Ross
389544783caSToomas Soome (void) snprintf(port_str, sizeof (port_str), "%u",
3902c3ccf74SGordon Ross (unsigned short)mountd_port);
3912c3ccf74SGordon Ross
3922c3ccf74SGordon Ross hs.h_host = HOST_SELF_BIND;
3932c3ccf74SGordon Ross hs.h_serv = port_str;
3942c3ccf74SGordon Ross err = netdir_getbyname((struct netconfig *)nconf, &hs, &al);
3952c3ccf74SGordon Ross if (err == 0 && al != NULL) {
3962c3ccf74SGordon Ross xprt = svc_tp_create_addr(mnt, MOUNTPROG, vers,
3972c3ccf74SGordon Ross nconf, al->n_addrs);
3982c3ccf74SGordon Ross netdir_free(al, ND_ADDRLIST);
3992c3ccf74SGordon Ross }
4002c3ccf74SGordon Ross if (xprt == NULL) {
4012c3ccf74SGordon Ross syslog(LOG_ERR, "mountd: unable to create "
4022c3ccf74SGordon Ross "(MOUNTD,%d) on transport %s (port %d)",
4032c3ccf74SGordon Ross vers, nconf->nc_netid, mountd_port);
4042c3ccf74SGordon Ross }
4052c3ccf74SGordon Ross /* fall-back to default bind */
4062c3ccf74SGordon Ross }
4072c3ccf74SGordon Ross if (xprt == NULL) {
4082c3ccf74SGordon Ross /*
4092c3ccf74SGordon Ross * Had mountd_port=0, or non-inet transport,
4102c3ccf74SGordon Ross * or the bind to a specific port failed.
4112c3ccf74SGordon Ross * Do a default bind.
4122c3ccf74SGordon Ross */
4132c3ccf74SGordon Ross xprt = svc_tp_create(mnt, MOUNTPROG, vers, nconf);
4142c3ccf74SGordon Ross }
4152c3ccf74SGordon Ross if (xprt == NULL) {
4162c3ccf74SGordon Ross syslog(LOG_ERR, "mountd: unable to create "
4172c3ccf74SGordon Ross "(MOUNTD,%d) on transport %s",
4182c3ccf74SGordon Ross vers, nconf->nc_netid);
4192c3ccf74SGordon Ross return;
4202c3ccf74SGordon Ross }
4212c3ccf74SGordon Ross
4222c3ccf74SGordon Ross /*
4232c3ccf74SGordon Ross * Register additional versions on this transport.
4242c3ccf74SGordon Ross */
4252c3ccf74SGordon Ross while (--vers >= mount_vers_min) {
4262c3ccf74SGordon Ross if (!svc_reg(xprt, MOUNTPROG, vers, mnt, nconf)) {
4272c3ccf74SGordon Ross (void) syslog(LOG_ERR, "mountd: "
4282c3ccf74SGordon Ross "failed to register vers %d on %s",
4292c3ccf74SGordon Ross vers, nconf->nc_netid);
4302c3ccf74SGordon Ross }
4312c3ccf74SGordon Ross }
4322c3ccf74SGordon Ross }
4332c3ccf74SGordon Ross
43411606941Sjwahlig int
main(int argc,char * argv[])43511606941Sjwahlig main(int argc, char *argv[])
4367c478bd9Sstevel@tonic-gate {
4371cc55349Srmesta int pid;
4381cc55349Srmesta int c;
4392f416683SMarcel Telka int rpc_svc_fdunlim = 1;
4401cc55349Srmesta int rpc_svc_mode = RPC_SVC_MT_AUTO;
4411cc55349Srmesta int maxrecsz = RPC_MAXDATASIZE;
4421cc55349Srmesta bool_t exclbind = TRUE;
4431cc55349Srmesta bool_t can_do_mlp;
4441cc55349Srmesta long thr_flags = (THR_NEW_LWP|THR_DAEMON);
44535a075c3SToomas Soome char defval[5];
4463ed679c0SGordon Ross int ret, bufsz;
44797adda44SMarcel Telka struct rlimit rl;
448361f55a5SMarcel Telka int listen_backlog = 0;
449361f55a5SMarcel Telka int max_threads = 0;
450361f55a5SMarcel Telka int tmp;
4512c3ccf74SGordon Ross struct netconfig *nconf;
4522c3ccf74SGordon Ross NCONF_HANDLE *nc;
453544783caSToomas Soome const char *errstr;
454250a0733Sth int pipe_fd = -1;
45535a075c3SToomas Soome char hostbuf[256];
456250a0733Sth
4577c478bd9Sstevel@tonic-gate /*
4587c478bd9Sstevel@tonic-gate * Mountd requires uid 0 for:
4597c478bd9Sstevel@tonic-gate * /etc/rmtab updates (we could chown it to daemon)
4607c478bd9Sstevel@tonic-gate * /etc/dfs/dfstab reading (it wants to lock out share which
4617c478bd9Sstevel@tonic-gate * doesn't do any locking before first truncate;
4627c478bd9Sstevel@tonic-gate * NFS share does; should use fcntl locking instead)
4637c478bd9Sstevel@tonic-gate * Needed privileges:
4647c478bd9Sstevel@tonic-gate * auditing
4657c478bd9Sstevel@tonic-gate * nfs syscall
4667c478bd9Sstevel@tonic-gate * file dac search (so it can stat all files)
46745916cd2Sjpk * Optional privileges:
46845916cd2Sjpk * MLP
4697c478bd9Sstevel@tonic-gate */
47045916cd2Sjpk can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
4717c478bd9Sstevel@tonic-gate if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, -1, -1,
47245916cd2Sjpk PRIV_SYS_NFS, PRIV_PROC_AUDIT, PRIV_FILE_DAC_SEARCH,
4732c3ccf74SGordon Ross PRIV_NET_PRIVADDR,
47445916cd2Sjpk can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) {
4757c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
476250a0733Sth "%s: must be run with sufficient privileges\n",
477250a0733Sth argv[0]);
4787c478bd9Sstevel@tonic-gate exit(1);
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate
48197adda44SMarcel Telka if (getrlimit(RLIMIT_NOFILE, &rl) != 0) {
48297adda44SMarcel Telka syslog(LOG_ERR, "getrlimit failed");
48397adda44SMarcel Telka } else {
48497adda44SMarcel Telka rl.rlim_cur = rl.rlim_max;
48597adda44SMarcel Telka if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
48697adda44SMarcel Telka syslog(LOG_ERR, "setrlimit failed");
48797adda44SMarcel Telka }
48897adda44SMarcel Telka
48997adda44SMarcel Telka (void) enable_extended_FILE_stdio(-1, -1);
49097adda44SMarcel Telka
491*86147f89SToomas Soome /* Upgrade SMF settings, if necessary. */
492*86147f89SToomas Soome nfs_config_upgrade(NFSD);
493*86147f89SToomas Soome
494361f55a5SMarcel Telka ret = nfs_smf_get_iprop("mountd_max_threads", &max_threads,
495361f55a5SMarcel Telka DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
496361f55a5SMarcel Telka if (ret != SA_OK) {
497361f55a5SMarcel Telka syslog(LOG_ERR, "Reading of mountd_max_threads from SMF "
498361f55a5SMarcel Telka "failed, using default value");
499361f55a5SMarcel Telka }
5007c478bd9Sstevel@tonic-gate
5012c3ccf74SGordon Ross ret = nfs_smf_get_iprop("mountd_port", &mountd_port,
5022c3ccf74SGordon Ross DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
5032c3ccf74SGordon Ross if (ret != SA_OK) {
5042c3ccf74SGordon Ross syslog(LOG_ERR, "Reading of mountd_port from SMF "
5052c3ccf74SGordon Ross "failed, using default value");
5062c3ccf74SGordon Ross }
5072c3ccf74SGordon Ross
5082c3ccf74SGordon Ross while ((c = getopt(argc, argv, "dvrm:p:")) != EOF) {
5097c478bd9Sstevel@tonic-gate switch (c) {
5102c3ccf74SGordon Ross case 'd':
5112c3ccf74SGordon Ross debug++;
5122c3ccf74SGordon Ross break;
5137c478bd9Sstevel@tonic-gate case 'v':
5147c478bd9Sstevel@tonic-gate verbose++;
5157c478bd9Sstevel@tonic-gate break;
5167c478bd9Sstevel@tonic-gate case 'r':
5177c478bd9Sstevel@tonic-gate rejecting = 1;
5187c478bd9Sstevel@tonic-gate break;
5197c478bd9Sstevel@tonic-gate case 'm':
520544783caSToomas Soome tmp = strtonum(optarg, 1, INT_MAX, &errstr);
521544783caSToomas Soome if (errstr != NULL) {
522361f55a5SMarcel Telka (void) fprintf(stderr, "%s: invalid "
523544783caSToomas Soome "max_threads option: %s, using defaults\n",
524544783caSToomas Soome argv[0], errstr);
525361f55a5SMarcel Telka break;
5267c478bd9Sstevel@tonic-gate }
527361f55a5SMarcel Telka max_threads = tmp;
5287c478bd9Sstevel@tonic-gate break;
5292c3ccf74SGordon Ross case 'p':
530544783caSToomas Soome tmp = strtonum(optarg, 1, UINT16_MAX, &errstr);
531544783caSToomas Soome if (errstr != NULL) {
5322c3ccf74SGordon Ross (void) fprintf(stderr, "%s: invalid port "
533544783caSToomas Soome "number: %s\n", argv[0], errstr);
5342c3ccf74SGordon Ross break;
5352c3ccf74SGordon Ross }
5362c3ccf74SGordon Ross mountd_port = tmp;
5372c3ccf74SGordon Ross break;
538361f55a5SMarcel Telka default:
539361f55a5SMarcel Telka fprintf(stderr, "usage: mountd [-v] [-r]\n");
540361f55a5SMarcel Telka exit(1);
5417c478bd9Sstevel@tonic-gate }
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate
5447c478bd9Sstevel@tonic-gate /*
5453ed679c0SGordon Ross * One might be tempted to use the NFS configuration values
5463ed679c0SGordon Ross * server_versmin, server_versmax to constrain the range of
5473ed679c0SGordon Ross * mountd versions supported here. However, older clients
5483ed679c0SGordon Ross * use mountd V1 for showmount, so just leave all mountd
5493ed679c0SGordon Ross * versions enabled here. (mount_vers_min, mount_vers_max)
5507c478bd9Sstevel@tonic-gate */
5517c478bd9Sstevel@tonic-gate
552361f55a5SMarcel Telka ret = nfs_smf_get_iprop("mountd_listen_backlog", &listen_backlog,
553361f55a5SMarcel Telka DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
554361f55a5SMarcel Telka if (ret != SA_OK) {
555361f55a5SMarcel Telka syslog(LOG_ERR, "Reading of mountd_listen_backlog from SMF "
556361f55a5SMarcel Telka "failed, using default value");
557361f55a5SMarcel Telka }
558361f55a5SMarcel Telka
55935a075c3SToomas Soome bufsz = sizeof (defval);
56035a075c3SToomas Soome ret = nfs_smf_get_prop("mountd_remote_dump", defval, DEFAULT_INSTANCE,
56135a075c3SToomas Soome SCF_TYPE_BOOLEAN, NFSD, &bufsz);
56235a075c3SToomas Soome if (ret == SA_OK) {
56335a075c3SToomas Soome mountd_remote_dump = string_to_boolean(defval);
56435a075c3SToomas Soome }
56535a075c3SToomas Soome if (!mountd_remote_dump) {
56635a075c3SToomas Soome /* Cache host address list */
56735a075c3SToomas Soome if (gethostname(hostbuf, sizeof (hostbuf)) < 0) {
56835a075c3SToomas Soome syslog(LOG_ERR, "gethostname() failed");
56935a075c3SToomas Soome exit(1);
57035a075c3SToomas Soome }
57135a075c3SToomas Soome if (getaddrinfo(hostbuf, NULL, NULL, &host_ai) != 0) {
57235a075c3SToomas Soome syslog(LOG_ERR, "getaddrinfo() failed");
57335a075c3SToomas Soome exit(1);
57435a075c3SToomas Soome }
57535a075c3SToomas Soome }
57635a075c3SToomas Soome
5777c478bd9Sstevel@tonic-gate /*
5787c478bd9Sstevel@tonic-gate * Sanity check versions,
5797c478bd9Sstevel@tonic-gate * even though we may get versions > MOUNTVERS3, we still need
5807c478bd9Sstevel@tonic-gate * to start nfsauth service, so continue on regardless of values.
5817c478bd9Sstevel@tonic-gate */
5822c3ccf74SGordon Ross if (mount_vers_max > MOUNTVERS3)
5832c3ccf74SGordon Ross mount_vers_max = MOUNTVERS3;
5847c478bd9Sstevel@tonic-gate if (mount_vers_min > mount_vers_max) {
585361f55a5SMarcel Telka fprintf(stderr, "server_versmin > server_versmax\n");
5867c478bd9Sstevel@tonic-gate mount_vers_max = mount_vers_min;
5877c478bd9Sstevel@tonic-gate }
5887c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
5897c478bd9Sstevel@tonic-gate (void) rwlock_init(&sharetab_lock, USYNC_THREAD, NULL);
5907c478bd9Sstevel@tonic-gate (void) mutex_init(&mnttab_lock, USYNC_THREAD, NULL);
5914a508a79SThomas Haynes (void) mutex_init(&logging_queue_lock, USYNC_THREAD, NULL);
5924a508a79SThomas Haynes (void) cond_init(&logging_queue_cv, USYNC_THREAD, NULL);
5934a508a79SThomas Haynes
5947c478bd9Sstevel@tonic-gate netgroup_init();
5957c478bd9Sstevel@tonic-gate
5967c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
5977c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST"
5987c478bd9Sstevel@tonic-gate #endif
5997c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN);
6007c478bd9Sstevel@tonic-gate
6017c478bd9Sstevel@tonic-gate /* Don't drop core if the NFS module isn't loaded. */
6027c478bd9Sstevel@tonic-gate (void) signal(SIGSYS, SIG_IGN);
6037c478bd9Sstevel@tonic-gate
6042c3ccf74SGordon Ross if (!debug)
6052c3ccf74SGordon Ross pipe_fd = daemonize_init();
6067c478bd9Sstevel@tonic-gate
6077c478bd9Sstevel@tonic-gate /*
6087c478bd9Sstevel@tonic-gate * If we coredump it'll be in /core
6097c478bd9Sstevel@tonic-gate */
6107c478bd9Sstevel@tonic-gate if (chdir("/") < 0)
611361f55a5SMarcel Telka fprintf(stderr, "chdir /: %s\n", strerror(errno));
6127c478bd9Sstevel@tonic-gate
6132c3ccf74SGordon Ross if (!debug)
6142c3ccf74SGordon Ross openlog("mountd", LOG_PID, LOG_DAEMON);
6157c478bd9Sstevel@tonic-gate
6167c478bd9Sstevel@tonic-gate /*
6177c478bd9Sstevel@tonic-gate * establish our lock on the lock file and write our pid to it.
6187c478bd9Sstevel@tonic-gate * exit if some other process holds the lock, or if there's any
6197c478bd9Sstevel@tonic-gate * error in writing/locking the file.
6207c478bd9Sstevel@tonic-gate */
6217c478bd9Sstevel@tonic-gate pid = _enter_daemon_lock(MOUNTD);
6227c478bd9Sstevel@tonic-gate switch (pid) {
6237c478bd9Sstevel@tonic-gate case 0:
6247c478bd9Sstevel@tonic-gate break;
6257c478bd9Sstevel@tonic-gate case -1:
626361f55a5SMarcel Telka fprintf(stderr, "error locking for %s: %s\n", MOUNTD,
6277c478bd9Sstevel@tonic-gate strerror(errno));
6287c478bd9Sstevel@tonic-gate exit(2);
6297c478bd9Sstevel@tonic-gate default:
6307c478bd9Sstevel@tonic-gate /* daemon was already running */
6317c478bd9Sstevel@tonic-gate exit(0);
6327c478bd9Sstevel@tonic-gate }
6337c478bd9Sstevel@tonic-gate
6347c478bd9Sstevel@tonic-gate audit_mountd_setup(); /* BSM */
6357c478bd9Sstevel@tonic-gate
63689621fe1SMarcel Telka /*
63789621fe1SMarcel Telka * Get required system variables
63889621fe1SMarcel Telka */
63989621fe1SMarcel Telka if ((ngroups_max = sysconf(_SC_NGROUPS_MAX)) == -1) {
64089621fe1SMarcel Telka syslog(LOG_ERR, "Unable to get _SC_NGROUPS_MAX");
64189621fe1SMarcel Telka exit(1);
64289621fe1SMarcel Telka }
64389621fe1SMarcel Telka if ((pw_size = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) {
64489621fe1SMarcel Telka syslog(LOG_ERR, "Unable to get _SC_GETPW_R_SIZE_MAX");
64589621fe1SMarcel Telka exit(1);
64689621fe1SMarcel Telka }
64789621fe1SMarcel Telka
6482f416683SMarcel Telka /*
6492f416683SMarcel Telka * Set number of file descriptors to unlimited
6502f416683SMarcel Telka */
6512f416683SMarcel Telka if (!rpc_control(RPC_SVC_USE_POLLFD, &rpc_svc_fdunlim)) {
6522f416683SMarcel Telka syslog(LOG_INFO, "unable to set number of FDs to unlimited");
6532f416683SMarcel Telka }
6542f416683SMarcel Telka
6557c478bd9Sstevel@tonic-gate /*
6567c478bd9Sstevel@tonic-gate * Tell RPC that we want automatic thread mode.
6577c478bd9Sstevel@tonic-gate * A new thread will be spawned for each request.
6587c478bd9Sstevel@tonic-gate */
6597c478bd9Sstevel@tonic-gate if (!rpc_control(RPC_SVC_MTMODE_SET, &rpc_svc_mode)) {
660361f55a5SMarcel Telka fprintf(stderr, "unable to set automatic MT mode\n");
6617c478bd9Sstevel@tonic-gate exit(1);
6627c478bd9Sstevel@tonic-gate }
6637c478bd9Sstevel@tonic-gate
6647c478bd9Sstevel@tonic-gate /*
6657c478bd9Sstevel@tonic-gate * Enable non-blocking mode and maximum record size checks for
6667c478bd9Sstevel@tonic-gate * connection oriented transports.
6677c478bd9Sstevel@tonic-gate */
6687c478bd9Sstevel@tonic-gate if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) {
669361f55a5SMarcel Telka fprintf(stderr, "unable to set RPC max record size\n");
6707c478bd9Sstevel@tonic-gate }
6717c478bd9Sstevel@tonic-gate
6727c478bd9Sstevel@tonic-gate /*
6737c478bd9Sstevel@tonic-gate * Prevent our non-priv udp and tcp ports bound w/wildcard addr
6747c478bd9Sstevel@tonic-gate * from being hijacked by a bind to a more specific addr.
6757c478bd9Sstevel@tonic-gate */
6767c478bd9Sstevel@tonic-gate if (!rpc_control(__RPC_SVC_EXCLBIND_SET, &exclbind)) {
677361f55a5SMarcel Telka fprintf(stderr, "warning: unable to set udp/tcp EXCLBIND\n");
678361f55a5SMarcel Telka }
679361f55a5SMarcel Telka
680361f55a5SMarcel Telka /*
681361f55a5SMarcel Telka * Set the maximum number of outstanding connection
682361f55a5SMarcel Telka * indications (listen backlog) to the value specified.
683361f55a5SMarcel Telka */
684361f55a5SMarcel Telka if (listen_backlog > 0 && !rpc_control(__RPC_SVC_LSTNBKLOG_SET,
685361f55a5SMarcel Telka &listen_backlog)) {
686361f55a5SMarcel Telka fprintf(stderr, "unable to set listen backlog\n");
687361f55a5SMarcel Telka exit(1);
6887c478bd9Sstevel@tonic-gate }
6897c478bd9Sstevel@tonic-gate
6907c478bd9Sstevel@tonic-gate /*
691361f55a5SMarcel Telka * If max_threads was specified, then set the
6927c478bd9Sstevel@tonic-gate * maximum number of threads to the value specified.
6937c478bd9Sstevel@tonic-gate */
694361f55a5SMarcel Telka if (max_threads > 0 && !rpc_control(RPC_SVC_THRMAX_SET, &max_threads)) {
695361f55a5SMarcel Telka fprintf(stderr, "unable to set max_threads\n");
6967c478bd9Sstevel@tonic-gate exit(1);
6977c478bd9Sstevel@tonic-gate }
6987c478bd9Sstevel@tonic-gate
6992c3ccf74SGordon Ross if (mountd_port < 0 || mountd_port > UINT16_MAX) {
7002c3ccf74SGordon Ross fprintf(stderr, "unable to use specified port\n");
7012c3ccf74SGordon Ross exit(1);
7022c3ccf74SGordon Ross }
7032c3ccf74SGordon Ross
7047c478bd9Sstevel@tonic-gate /*
7057c478bd9Sstevel@tonic-gate * Make sure to unregister any previous versions in case the
7067c478bd9Sstevel@tonic-gate * user is reconfiguring the server in interesting ways.
7077c478bd9Sstevel@tonic-gate */
7087c478bd9Sstevel@tonic-gate svc_unreg(MOUNTPROG, MOUNTVERS);
7097c478bd9Sstevel@tonic-gate svc_unreg(MOUNTPROG, MOUNTVERS_POSIX);
7107c478bd9Sstevel@tonic-gate svc_unreg(MOUNTPROG, MOUNTVERS3);
7117c478bd9Sstevel@tonic-gate
7127c478bd9Sstevel@tonic-gate /*
7131cc55349Srmesta * Create the nfsauth thread with same signal disposition
7141cc55349Srmesta * as the main thread. We need to create a separate thread
7151cc55349Srmesta * since mountd() will be both an RPC server (for remote
7161cc55349Srmesta * traffic) _and_ a doors server (for kernel upcalls).
7177c478bd9Sstevel@tonic-gate */
7181cc55349Srmesta if (thr_create(NULL, 0, nfsauth_svc, 0, thr_flags, &nfsauth_thread)) {
719361f55a5SMarcel Telka fprintf(stderr,
720361f55a5SMarcel Telka gettext("Failed to create NFSAUTH svc thread\n"));
7211cc55349Srmesta exit(2);
7227c478bd9Sstevel@tonic-gate }
7237c478bd9Sstevel@tonic-gate
724b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
725b89a8333Snatalie li - Sun Microsystems - Irvine United States * Create the cmd service thread with same signal disposition
726b89a8333Snatalie li - Sun Microsystems - Irvine United States * as the main thread. We need to create a separate thread
727b89a8333Snatalie li - Sun Microsystems - Irvine United States * since mountd() will be both an RPC server (for remote
728b89a8333Snatalie li - Sun Microsystems - Irvine United States * traffic) _and_ a doors server (for kernel upcalls).
729b89a8333Snatalie li - Sun Microsystems - Irvine United States */
730b89a8333Snatalie li - Sun Microsystems - Irvine United States if (thr_create(NULL, 0, cmd_svc, 0, thr_flags, &cmd_thread)) {
731b89a8333Snatalie li - Sun Microsystems - Irvine United States syslog(LOG_ERR, gettext("Failed to create CMD svc thread"));
732b89a8333Snatalie li - Sun Microsystems - Irvine United States exit(2);
733b89a8333Snatalie li - Sun Microsystems - Irvine United States }
734b89a8333Snatalie li - Sun Microsystems - Irvine United States
7354a508a79SThomas Haynes /*
7364a508a79SThomas Haynes * Create an additional thread to service the rmtab and
7374a508a79SThomas Haynes * audit_mountd_mount logging for mount requests. Use the same
7384a508a79SThomas Haynes * signal disposition as the main thread. We create
7394a508a79SThomas Haynes * a separate thread to allow the mount request threads to
7404a508a79SThomas Haynes * clear as soon as possible.
7414a508a79SThomas Haynes */
7424a508a79SThomas Haynes if (thr_create(NULL, 0, logging_svc, 0, thr_flags, &logging_thread)) {
7434a508a79SThomas Haynes syslog(LOG_ERR, gettext("Failed to create LOGGING svc thread"));
7444a508a79SThomas Haynes exit(2);
7454a508a79SThomas Haynes }
7464a508a79SThomas Haynes
7477c478bd9Sstevel@tonic-gate /*
7482c3ccf74SGordon Ross * Enumerate network transports and create service listeners
7492c3ccf74SGordon Ross * as appropriate for each.
7507c478bd9Sstevel@tonic-gate */
7512c3ccf74SGordon Ross if ((nc = setnetconfig()) == NULL) {
7522c3ccf74SGordon Ross syslog(LOG_ERR, "setnetconfig failed: %m");
7532c3ccf74SGordon Ross return (-1);
7547c478bd9Sstevel@tonic-gate }
7552c3ccf74SGordon Ross while ((nconf = getnetconfig(nc)) != NULL) {
7562c3ccf74SGordon Ross /*
7572c3ccf74SGordon Ross * Skip things like tpi_raw, invisible...
7582c3ccf74SGordon Ross */
7592c3ccf74SGordon Ross if ((nconf->nc_flag & NC_VISIBLE) == 0)
7602c3ccf74SGordon Ross continue;
7612c3ccf74SGordon Ross if (nconf->nc_semantics != NC_TPI_CLTS &&
7622c3ccf74SGordon Ross nconf->nc_semantics != NC_TPI_COTS &&
7632c3ccf74SGordon Ross nconf->nc_semantics != NC_TPI_COTS_ORD)
7642c3ccf74SGordon Ross continue;
7652c3ccf74SGordon Ross
7662c3ccf74SGordon Ross md_svc_tp_create(nconf);
7677c478bd9Sstevel@tonic-gate }
7682c3ccf74SGordon Ross (void) endnetconfig(nc);
7697c478bd9Sstevel@tonic-gate
7707c478bd9Sstevel@tonic-gate /*
7717c478bd9Sstevel@tonic-gate * Start serving
7727c478bd9Sstevel@tonic-gate */
7737c478bd9Sstevel@tonic-gate rmtab_load();
774250a0733Sth
775250a0733Sth daemonize_fini(pipe_fd);
7767c478bd9Sstevel@tonic-gate
7777c478bd9Sstevel@tonic-gate /* Get rid of the most dangerous basic privileges. */
7787c478bd9Sstevel@tonic-gate __fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_INFO, PRIV_PROC_SESSION,
7797c478bd9Sstevel@tonic-gate (char *)NULL);
7807c478bd9Sstevel@tonic-gate
7817c478bd9Sstevel@tonic-gate svc_run();
7827c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Error: svc_run shouldn't have returned");
7837c478bd9Sstevel@tonic-gate abort();
784250a0733Sth
7857c478bd9Sstevel@tonic-gate /* NOTREACHED */
78611606941Sjwahlig return (0);
7877c478bd9Sstevel@tonic-gate }
7887c478bd9Sstevel@tonic-gate
78935a075c3SToomas Soome /*
79035a075c3SToomas Soome * copied from usr/src/uts/common/klm/nlm_impl.c
79135a075c3SToomas Soome */
79235a075c3SToomas Soome static bool_t
caller_is_local(SVCXPRT * transp)79335a075c3SToomas Soome caller_is_local(SVCXPRT *transp)
79435a075c3SToomas Soome {
79535a075c3SToomas Soome struct addrinfo *a;
79635a075c3SToomas Soome char *netid;
79735a075c3SToomas Soome struct netbuf *rtaddr;
79835a075c3SToomas Soome struct sockaddr_storage addr;
79935a075c3SToomas Soome bool_t rv = FALSE;
80035a075c3SToomas Soome
80135a075c3SToomas Soome netid = transp->xp_netid;
80235a075c3SToomas Soome rtaddr = svc_getrpccaller(transp);
80335a075c3SToomas Soome
80435a075c3SToomas Soome if (netid == NULL)
80535a075c3SToomas Soome return (FALSE);
80635a075c3SToomas Soome
80735a075c3SToomas Soome if (strcmp(netid, "ticlts") == 0 ||
80835a075c3SToomas Soome strcmp(netid, "ticotsord") == 0)
80935a075c3SToomas Soome return (TRUE);
81035a075c3SToomas Soome
81135a075c3SToomas Soome if (strcmp(netid, "tcp") == 0 || strcmp(netid, "udp") == 0) {
81235a075c3SToomas Soome struct sockaddr_in *sin = (void *)rtaddr->buf;
81335a075c3SToomas Soome
81435a075c3SToomas Soome if (sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK))
81535a075c3SToomas Soome return (TRUE);
81635a075c3SToomas Soome
81735a075c3SToomas Soome memmove(&addr, sin, sizeof (*sin));
81835a075c3SToomas Soome }
81935a075c3SToomas Soome if (strcmp(netid, "tcp6") == 0 || strcmp(netid, "udp6") == 0) {
82035a075c3SToomas Soome struct sockaddr_in6 *sin6 = (void *)rtaddr->buf;
82135a075c3SToomas Soome
82235a075c3SToomas Soome if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
82335a075c3SToomas Soome return (TRUE);
82435a075c3SToomas Soome
82535a075c3SToomas Soome memmove(&addr, sin6, sizeof (*sin6));
82635a075c3SToomas Soome }
82735a075c3SToomas Soome
82835a075c3SToomas Soome for (a = host_ai; a != NULL; a = a->ai_next) {
82935a075c3SToomas Soome if (sockaddrcmp(&addr,
83035a075c3SToomas Soome (struct sockaddr_storage *)a->ai_addr)) {
83135a075c3SToomas Soome rv = TRUE;
83235a075c3SToomas Soome break;
83335a075c3SToomas Soome }
83435a075c3SToomas Soome }
83535a075c3SToomas Soome return (rv);
83635a075c3SToomas Soome }
83735a075c3SToomas Soome
8387c478bd9Sstevel@tonic-gate /*
8397c478bd9Sstevel@tonic-gate * Server procedure switch routine
8407c478bd9Sstevel@tonic-gate */
8417c478bd9Sstevel@tonic-gate void
mnt(struct svc_req * rqstp,SVCXPRT * transp)8427c478bd9Sstevel@tonic-gate mnt(struct svc_req *rqstp, SVCXPRT *transp)
8437c478bd9Sstevel@tonic-gate {
8447c478bd9Sstevel@tonic-gate switch (rqstp->rq_proc) {
8457c478bd9Sstevel@tonic-gate case NULLPROC:
8467c478bd9Sstevel@tonic-gate errno = 0;
8477c478bd9Sstevel@tonic-gate if (!svc_sendreply(transp, xdr_void, (char *)0))
8487c478bd9Sstevel@tonic-gate log_cant_reply(transp);
8497c478bd9Sstevel@tonic-gate return;
8507c478bd9Sstevel@tonic-gate
8517c478bd9Sstevel@tonic-gate case MOUNTPROC_MNT:
8524a508a79SThomas Haynes (void) mount(rqstp);
8537c478bd9Sstevel@tonic-gate return;
8547c478bd9Sstevel@tonic-gate
8557c478bd9Sstevel@tonic-gate case MOUNTPROC_DUMP:
85635a075c3SToomas Soome if (mountd_remote_dump || caller_is_local(transp))
85735a075c3SToomas Soome mntlist_send(transp);
85835a075c3SToomas Soome else
85935a075c3SToomas Soome svcerr_noproc(transp);
8607c478bd9Sstevel@tonic-gate return;
8617c478bd9Sstevel@tonic-gate
8627c478bd9Sstevel@tonic-gate case MOUNTPROC_UMNT:
8637c478bd9Sstevel@tonic-gate umount(rqstp);
8647c478bd9Sstevel@tonic-gate return;
8657c478bd9Sstevel@tonic-gate
8667c478bd9Sstevel@tonic-gate case MOUNTPROC_UMNTALL:
8677c478bd9Sstevel@tonic-gate umountall(rqstp);
8687c478bd9Sstevel@tonic-gate return;
8697c478bd9Sstevel@tonic-gate
8707c478bd9Sstevel@tonic-gate case MOUNTPROC_EXPORT:
8717c478bd9Sstevel@tonic-gate case MOUNTPROC_EXPORTALL:
8727c478bd9Sstevel@tonic-gate export(rqstp);
8737c478bd9Sstevel@tonic-gate return;
8747c478bd9Sstevel@tonic-gate
8757c478bd9Sstevel@tonic-gate case MOUNTPROC_PATHCONF:
8767c478bd9Sstevel@tonic-gate if (rqstp->rq_vers == MOUNTVERS_POSIX)
8777c478bd9Sstevel@tonic-gate mnt_pathconf(rqstp);
8787c478bd9Sstevel@tonic-gate else
8797c478bd9Sstevel@tonic-gate svcerr_noproc(transp);
8807c478bd9Sstevel@tonic-gate return;
8817c478bd9Sstevel@tonic-gate
8827c478bd9Sstevel@tonic-gate default:
8837c478bd9Sstevel@tonic-gate svcerr_noproc(transp);
8847c478bd9Sstevel@tonic-gate return;
8857c478bd9Sstevel@tonic-gate }
8867c478bd9Sstevel@tonic-gate }
8877c478bd9Sstevel@tonic-gate
888a9685eaaSMarcel Telka void
log_cant_reply_cln(struct cln * cln)889a9685eaaSMarcel Telka log_cant_reply_cln(struct cln *cln)
8907c478bd9Sstevel@tonic-gate {
891a9685eaaSMarcel Telka int saverrno;
892a9685eaaSMarcel Telka char *host;
8937c478bd9Sstevel@tonic-gate
894a9685eaaSMarcel Telka saverrno = errno; /* save error code */
8957c478bd9Sstevel@tonic-gate
896a9685eaaSMarcel Telka host = cln_gethost(cln);
8977c478bd9Sstevel@tonic-gate if (host == NULL)
898a9685eaaSMarcel Telka return;
8994a508a79SThomas Haynes
900a9685eaaSMarcel Telka errno = saverrno;
901a9685eaaSMarcel Telka if (errno == 0)
902a9685eaaSMarcel Telka syslog(LOG_ERR, "couldn't send reply to %s", host);
903a9685eaaSMarcel Telka else
904a9685eaaSMarcel Telka syslog(LOG_ERR, "couldn't send reply to %s: %m", host);
9057c478bd9Sstevel@tonic-gate }
9067c478bd9Sstevel@tonic-gate
9077c478bd9Sstevel@tonic-gate void
log_cant_reply(SVCXPRT * transp)9087c478bd9Sstevel@tonic-gate log_cant_reply(SVCXPRT *transp)
9097c478bd9Sstevel@tonic-gate {
9107c478bd9Sstevel@tonic-gate int saverrno;
911a9685eaaSMarcel Telka struct cln cln;
9127c478bd9Sstevel@tonic-gate
9137c478bd9Sstevel@tonic-gate saverrno = errno; /* save error code */
914a9685eaaSMarcel Telka cln_init(&cln, transp);
9157c478bd9Sstevel@tonic-gate errno = saverrno;
9167c478bd9Sstevel@tonic-gate
917a9685eaaSMarcel Telka log_cant_reply_cln(&cln);
918a9685eaaSMarcel Telka
919a9685eaaSMarcel Telka cln_fini(&cln);
9207c478bd9Sstevel@tonic-gate }
9217c478bd9Sstevel@tonic-gate
9227c478bd9Sstevel@tonic-gate /*
9237c478bd9Sstevel@tonic-gate * Answer pathconf questions for the mount point fs
9247c478bd9Sstevel@tonic-gate */
9257c478bd9Sstevel@tonic-gate static void
mnt_pathconf(struct svc_req * rqstp)9267c478bd9Sstevel@tonic-gate mnt_pathconf(struct svc_req *rqstp)
9277c478bd9Sstevel@tonic-gate {
9287c478bd9Sstevel@tonic-gate SVCXPRT *transp;
9297c478bd9Sstevel@tonic-gate struct pathcnf p;
9307c478bd9Sstevel@tonic-gate char *path, rpath[MAXPATHLEN];
9317c478bd9Sstevel@tonic-gate struct stat st;
9327c478bd9Sstevel@tonic-gate
9337c478bd9Sstevel@tonic-gate transp = rqstp->rq_xprt;
9347c478bd9Sstevel@tonic-gate path = NULL;
9357c478bd9Sstevel@tonic-gate (void) memset((caddr_t)&p, 0, sizeof (p));
9367c478bd9Sstevel@tonic-gate
9377c478bd9Sstevel@tonic-gate if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
9387c478bd9Sstevel@tonic-gate svcerr_decode(transp);
9397c478bd9Sstevel@tonic-gate return;
9407c478bd9Sstevel@tonic-gate }
9417c478bd9Sstevel@tonic-gate if (lstat(path, &st) < 0) {
9427c478bd9Sstevel@tonic-gate _PC_SET(_PC_ERROR, p.pc_mask);
9437c478bd9Sstevel@tonic-gate goto done;
9447c478bd9Sstevel@tonic-gate }
9457c478bd9Sstevel@tonic-gate /*
9467c478bd9Sstevel@tonic-gate * Get a path without symbolic links.
9477c478bd9Sstevel@tonic-gate */
9487c478bd9Sstevel@tonic-gate if (realpath(path, rpath) == NULL) {
9497c478bd9Sstevel@tonic-gate syslog(LOG_DEBUG,
950250a0733Sth "mount request: realpath failed on %s: %m",
951250a0733Sth path);
9527c478bd9Sstevel@tonic-gate _PC_SET(_PC_ERROR, p.pc_mask);
9537c478bd9Sstevel@tonic-gate goto done;
9547c478bd9Sstevel@tonic-gate }
9557c478bd9Sstevel@tonic-gate (void) memset((caddr_t)&p, 0, sizeof (p));
9567c478bd9Sstevel@tonic-gate /*
9577c478bd9Sstevel@tonic-gate * can't ask about devices over NFS
9587c478bd9Sstevel@tonic-gate */
9597c478bd9Sstevel@tonic-gate _PC_SET(_PC_MAX_CANON, p.pc_mask);
9607c478bd9Sstevel@tonic-gate _PC_SET(_PC_MAX_INPUT, p.pc_mask);
9617c478bd9Sstevel@tonic-gate _PC_SET(_PC_PIPE_BUF, p.pc_mask);
9627c478bd9Sstevel@tonic-gate _PC_SET(_PC_VDISABLE, p.pc_mask);
9637c478bd9Sstevel@tonic-gate
9647c478bd9Sstevel@tonic-gate errno = 0;
9657c478bd9Sstevel@tonic-gate p.pc_link_max = pathconf(rpath, _PC_LINK_MAX);
9667c478bd9Sstevel@tonic-gate if (errno)
9677c478bd9Sstevel@tonic-gate _PC_SET(_PC_LINK_MAX, p.pc_mask);
9687c478bd9Sstevel@tonic-gate p.pc_name_max = pathconf(rpath, _PC_NAME_MAX);
9697c478bd9Sstevel@tonic-gate if (errno)
9707c478bd9Sstevel@tonic-gate _PC_SET(_PC_NAME_MAX, p.pc_mask);
9717c478bd9Sstevel@tonic-gate p.pc_path_max = pathconf(rpath, _PC_PATH_MAX);
9727c478bd9Sstevel@tonic-gate if (errno)
9737c478bd9Sstevel@tonic-gate _PC_SET(_PC_PATH_MAX, p.pc_mask);
9747c478bd9Sstevel@tonic-gate if (pathconf(rpath, _PC_NO_TRUNC) == 1)
9757c478bd9Sstevel@tonic-gate _PC_SET(_PC_NO_TRUNC, p.pc_mask);
9767c478bd9Sstevel@tonic-gate if (pathconf(rpath, _PC_CHOWN_RESTRICTED) == 1)
9777c478bd9Sstevel@tonic-gate _PC_SET(_PC_CHOWN_RESTRICTED, p.pc_mask);
9787c478bd9Sstevel@tonic-gate
9797c478bd9Sstevel@tonic-gate done:
9807c478bd9Sstevel@tonic-gate errno = 0;
9817c478bd9Sstevel@tonic-gate if (!svc_sendreply(transp, xdr_ppathcnf, (char *)&p))
9827c478bd9Sstevel@tonic-gate log_cant_reply(transp);
9837c478bd9Sstevel@tonic-gate if (path != NULL)
984544783caSToomas Soome (void) svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
9857c478bd9Sstevel@tonic-gate }
9867c478bd9Sstevel@tonic-gate
9877c478bd9Sstevel@tonic-gate /*
9887c478bd9Sstevel@tonic-gate * If the rootmount (export) option is specified, the all mount requests for
9897c478bd9Sstevel@tonic-gate * subdirectories return EACCES.
9907c478bd9Sstevel@tonic-gate */
9917c478bd9Sstevel@tonic-gate static int
checkrootmount(share_t * sh,char * rpath)9924a508a79SThomas Haynes checkrootmount(share_t *sh, char *rpath)
9937c478bd9Sstevel@tonic-gate {
9947c478bd9Sstevel@tonic-gate char *val;
9957c478bd9Sstevel@tonic-gate
9967c478bd9Sstevel@tonic-gate if ((val = getshareopt(sh->sh_opts, SHOPT_NOSUB)) != NULL) {
9977c478bd9Sstevel@tonic-gate free(val);
9987c478bd9Sstevel@tonic-gate if (strcmp(sh->sh_path, rpath) != 0)
9997c478bd9Sstevel@tonic-gate return (0);
10007c478bd9Sstevel@tonic-gate else
10017c478bd9Sstevel@tonic-gate return (1);
10027c478bd9Sstevel@tonic-gate } else
10037c478bd9Sstevel@tonic-gate return (1);
10047c478bd9Sstevel@tonic-gate }
10057c478bd9Sstevel@tonic-gate
10067c478bd9Sstevel@tonic-gate #define MAX_FLAVORS 128
10077c478bd9Sstevel@tonic-gate
10087c478bd9Sstevel@tonic-gate /*
10097c478bd9Sstevel@tonic-gate * Return only EACCES if client does not have access
10107c478bd9Sstevel@tonic-gate * to this directory.
10117c478bd9Sstevel@tonic-gate * "If the server exports only /a/b, an attempt to
10127c478bd9Sstevel@tonic-gate * mount a/b/c will fail with ENOENT if the directory
10137c478bd9Sstevel@tonic-gate * does not exist"... However, if the client
10147c478bd9Sstevel@tonic-gate * does not have access to /a/b, an attacker can
10157c478bd9Sstevel@tonic-gate * determine whether the directory exists.
10167c478bd9Sstevel@tonic-gate * This routine checks either existence of the file or
10177c478bd9Sstevel@tonic-gate * existence of the file name entry in the mount table.
10187c478bd9Sstevel@tonic-gate * If the file exists and there is no file name entry,
10197c478bd9Sstevel@tonic-gate * the error returned should be EACCES.
10207c478bd9Sstevel@tonic-gate * If the file does not exist, it must be determined
10217c478bd9Sstevel@tonic-gate * whether the client has access to a parent
10227c478bd9Sstevel@tonic-gate * directory. If the client has access to a parent
10237c478bd9Sstevel@tonic-gate * directory, the error returned should be ENOENT,
10247c478bd9Sstevel@tonic-gate * otherwise EACCES.
10257c478bd9Sstevel@tonic-gate */
10267c478bd9Sstevel@tonic-gate static int
mount_enoent_error(struct cln * cln,char * path,char * rpath,int * flavor_list)1027a9685eaaSMarcel Telka mount_enoent_error(struct cln *cln, char *path, char *rpath, int *flavor_list)
10287c478bd9Sstevel@tonic-gate {
10297c478bd9Sstevel@tonic-gate char *checkpath, *dp;
10304a508a79SThomas Haynes share_t *sh = NULL;
10317c478bd9Sstevel@tonic-gate int realpath_error = ENOENT, reply_error = EACCES, lofs_tried = 0;
10327c478bd9Sstevel@tonic-gate int flavor_count;
10337c478bd9Sstevel@tonic-gate
10347c478bd9Sstevel@tonic-gate checkpath = strdup(path);
10357c478bd9Sstevel@tonic-gate if (checkpath == NULL) {
10367c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "mount_enoent: no memory");
10377c478bd9Sstevel@tonic-gate return (EACCES);
10387c478bd9Sstevel@tonic-gate }
10397c478bd9Sstevel@tonic-gate
10407c478bd9Sstevel@tonic-gate /* CONSTCOND */
10417c478bd9Sstevel@tonic-gate while (1) {
10427c478bd9Sstevel@tonic-gate if (sh) {
10437c478bd9Sstevel@tonic-gate sharefree(sh);
10447c478bd9Sstevel@tonic-gate sh = NULL;
10457c478bd9Sstevel@tonic-gate }
10464a508a79SThomas Haynes
10477c478bd9Sstevel@tonic-gate if ((sh = findentry(rpath)) == NULL &&
1048250a0733Sth (sh = find_lofsentry(rpath, &lofs_tried)) == NULL) {
10497c478bd9Sstevel@tonic-gate /*
10507c478bd9Sstevel@tonic-gate * There is no file name entry.
10517c478bd9Sstevel@tonic-gate * If the file (with symbolic links resolved) exists,
10527c478bd9Sstevel@tonic-gate * the error returned should be EACCES.
10537c478bd9Sstevel@tonic-gate */
10547c478bd9Sstevel@tonic-gate if (realpath_error == 0)
10557c478bd9Sstevel@tonic-gate break;
10567c478bd9Sstevel@tonic-gate } else if (checkrootmount(sh, rpath) == 0) {
10577c478bd9Sstevel@tonic-gate /*
10587c478bd9Sstevel@tonic-gate * This is a "nosub" only export, in which case,
10597c478bd9Sstevel@tonic-gate * mounting subdirectories isn't allowed.
10607c478bd9Sstevel@tonic-gate * If the file (with symbolic links resolved) exists,
10617c478bd9Sstevel@tonic-gate * the error returned should be EACCES.
10627c478bd9Sstevel@tonic-gate */
10637c478bd9Sstevel@tonic-gate if (realpath_error == 0)
10647c478bd9Sstevel@tonic-gate break;
10657c478bd9Sstevel@tonic-gate } else {
10667c478bd9Sstevel@tonic-gate /*
10677c478bd9Sstevel@tonic-gate * Check permissions in mount table.
10687c478bd9Sstevel@tonic-gate */
10697c478bd9Sstevel@tonic-gate if (newopts(sh->sh_opts))
1070a9685eaaSMarcel Telka flavor_count = getclientsflavors_new(sh, cln,
1071a9685eaaSMarcel Telka flavor_list);
10727c478bd9Sstevel@tonic-gate else
1073a9685eaaSMarcel Telka flavor_count = getclientsflavors_old(sh, cln,
1074a9685eaaSMarcel Telka flavor_list);
10757c478bd9Sstevel@tonic-gate if (flavor_count != 0) {
10767c478bd9Sstevel@tonic-gate /*
10777c478bd9Sstevel@tonic-gate * Found entry in table and
10787c478bd9Sstevel@tonic-gate * client has correct permissions.
10797c478bd9Sstevel@tonic-gate */
10807c478bd9Sstevel@tonic-gate reply_error = ENOENT;
10817c478bd9Sstevel@tonic-gate break;
10827c478bd9Sstevel@tonic-gate }
10837c478bd9Sstevel@tonic-gate }
10844a508a79SThomas Haynes
10857c478bd9Sstevel@tonic-gate /*
10867c478bd9Sstevel@tonic-gate * Check all parent directories.
10877c478bd9Sstevel@tonic-gate */
10887c478bd9Sstevel@tonic-gate dp = strrchr(checkpath, '/');
10897c478bd9Sstevel@tonic-gate if (dp == NULL)
10907c478bd9Sstevel@tonic-gate break;
10917c478bd9Sstevel@tonic-gate *dp = '\0';
10927c478bd9Sstevel@tonic-gate if (strlen(checkpath) == 0)
10937c478bd9Sstevel@tonic-gate break;
10947c478bd9Sstevel@tonic-gate /*
10957c478bd9Sstevel@tonic-gate * Get the real path (no symbolic links in it)
10967c478bd9Sstevel@tonic-gate */
10977c478bd9Sstevel@tonic-gate if (realpath(checkpath, rpath) == NULL) {
10987c478bd9Sstevel@tonic-gate if (errno != ENOENT)
10997c478bd9Sstevel@tonic-gate break;
11007c478bd9Sstevel@tonic-gate } else {
11017c478bd9Sstevel@tonic-gate realpath_error = 0;
11027c478bd9Sstevel@tonic-gate }
11037c478bd9Sstevel@tonic-gate }
11047c478bd9Sstevel@tonic-gate
11057c478bd9Sstevel@tonic-gate if (sh)
11067c478bd9Sstevel@tonic-gate sharefree(sh);
11077c478bd9Sstevel@tonic-gate free(checkpath);
11087c478bd9Sstevel@tonic-gate return (reply_error);
11097c478bd9Sstevel@tonic-gate }
11107c478bd9Sstevel@tonic-gate
11114a508a79SThomas Haynes /*
11124a508a79SThomas Haynes * We need to inform the caller whether or not we were
11134a508a79SThomas Haynes * able to add a node to the queue. If we are not, then
11144a508a79SThomas Haynes * it is up to the caller to go ahead and log the data.
11154a508a79SThomas Haynes */
11164a508a79SThomas Haynes static int
enqueue_logging_data(char * host,SVCXPRT * transp,char * path,char * rpath,int status,int error)11174a508a79SThomas Haynes enqueue_logging_data(char *host, SVCXPRT *transp, char *path,
11184a508a79SThomas Haynes char *rpath, int status, int error)
11194a508a79SThomas Haynes {
11204a508a79SThomas Haynes logging_data *lq;
11214a508a79SThomas Haynes struct netbuf *nb;
11224a508a79SThomas Haynes
11234a508a79SThomas Haynes lq = (logging_data *)calloc(1, sizeof (logging_data));
11244a508a79SThomas Haynes if (lq == NULL)
11254a508a79SThomas Haynes goto cleanup;
11264a508a79SThomas Haynes
11274a508a79SThomas Haynes /*
11284a508a79SThomas Haynes * We might not yet have the host...
11294a508a79SThomas Haynes */
11304a508a79SThomas Haynes if (host) {
11314a508a79SThomas Haynes DTRACE_PROBE1(mountd, log_host, host);
11324a508a79SThomas Haynes lq->ld_host = strdup(host);
11334a508a79SThomas Haynes if (lq->ld_host == NULL)
11344a508a79SThomas Haynes goto cleanup;
11354a508a79SThomas Haynes } else {
11364a508a79SThomas Haynes DTRACE_PROBE(mountd, log_no_host);
11374a508a79SThomas Haynes
11384a508a79SThomas Haynes lq->ld_netid = strdup(transp->xp_netid);
11394a508a79SThomas Haynes if (lq->ld_netid == NULL)
11404a508a79SThomas Haynes goto cleanup;
11414a508a79SThomas Haynes
11424a508a79SThomas Haynes lq->ld_nb = calloc(1, sizeof (struct netbuf));
11434a508a79SThomas Haynes if (lq->ld_nb == NULL)
11444a508a79SThomas Haynes goto cleanup;
11454a508a79SThomas Haynes
11464a508a79SThomas Haynes nb = svc_getrpccaller(transp);
11474a508a79SThomas Haynes if (nb == NULL) {
11484a508a79SThomas Haynes DTRACE_PROBE(mountd, e__nb__enqueue);
11494a508a79SThomas Haynes goto cleanup;
11504a508a79SThomas Haynes }
11514a508a79SThomas Haynes
11524a508a79SThomas Haynes DTRACE_PROBE(mountd, nb_set_enqueue);
11534a508a79SThomas Haynes
11544a508a79SThomas Haynes lq->ld_nb->maxlen = nb->maxlen;
11554a508a79SThomas Haynes lq->ld_nb->len = nb->len;
11564a508a79SThomas Haynes
11574a508a79SThomas Haynes lq->ld_nb->buf = malloc(lq->ld_nb->len);
11584a508a79SThomas Haynes if (lq->ld_nb->buf == NULL)
11594a508a79SThomas Haynes goto cleanup;
11604a508a79SThomas Haynes
11614a508a79SThomas Haynes bcopy(nb->buf, lq->ld_nb->buf, lq->ld_nb->len);
11624a508a79SThomas Haynes }
11634a508a79SThomas Haynes
11644a508a79SThomas Haynes lq->ld_path = strdup(path);
11654a508a79SThomas Haynes if (lq->ld_path == NULL)
11664a508a79SThomas Haynes goto cleanup;
11674a508a79SThomas Haynes
11684a508a79SThomas Haynes if (!error) {
11694a508a79SThomas Haynes lq->ld_rpath = strdup(rpath);
11704a508a79SThomas Haynes if (lq->ld_rpath == NULL)
11714a508a79SThomas Haynes goto cleanup;
11724a508a79SThomas Haynes }
11734a508a79SThomas Haynes
11744a508a79SThomas Haynes lq->ld_status = status;
11754a508a79SThomas Haynes
11764a508a79SThomas Haynes /*
11774a508a79SThomas Haynes * Add to the tail of the logging queue.
11784a508a79SThomas Haynes */
11794a508a79SThomas Haynes (void) mutex_lock(&logging_queue_lock);
11804a508a79SThomas Haynes if (logging_tail == NULL) {
11814a508a79SThomas Haynes logging_tail = logging_head = lq;
11824a508a79SThomas Haynes } else {
11834a508a79SThomas Haynes logging_tail->ld_next = lq;
11844a508a79SThomas Haynes logging_tail = lq;
11854a508a79SThomas Haynes }
11864a508a79SThomas Haynes (void) cond_signal(&logging_queue_cv);
11874a508a79SThomas Haynes (void) mutex_unlock(&logging_queue_lock);
11884a508a79SThomas Haynes
11894a508a79SThomas Haynes return (TRUE);
11904a508a79SThomas Haynes
11914a508a79SThomas Haynes cleanup:
11924a508a79SThomas Haynes
11934a508a79SThomas Haynes free_logging_data(lq);
11944a508a79SThomas Haynes
11954a508a79SThomas Haynes return (FALSE);
11964a508a79SThomas Haynes }
11974a508a79SThomas Haynes
1198a9685eaaSMarcel Telka
1199a9685eaaSMarcel Telka #define CLN_CLNAMES (1 << 0)
1200a9685eaaSMarcel Telka #define CLN_HOST (1 << 1)
1201a9685eaaSMarcel Telka
1202a9685eaaSMarcel Telka static void
cln_init_common(struct cln * cln,SVCXPRT * transp,char * netid,struct netbuf * nbuf)1203a9685eaaSMarcel Telka cln_init_common(struct cln *cln, SVCXPRT *transp, char *netid,
1204a9685eaaSMarcel Telka struct netbuf *nbuf)
1205a9685eaaSMarcel Telka {
1206a9685eaaSMarcel Telka if ((cln->transp = transp) != NULL) {
1207a9685eaaSMarcel Telka assert(netid == NULL && nbuf == NULL);
1208a9685eaaSMarcel Telka cln->netid = transp->xp_netid;
1209a9685eaaSMarcel Telka cln->nbuf = svc_getrpccaller(transp);
1210a9685eaaSMarcel Telka } else {
1211a9685eaaSMarcel Telka cln->netid = netid;
1212a9685eaaSMarcel Telka cln->nbuf = nbuf;
1213a9685eaaSMarcel Telka }
1214a9685eaaSMarcel Telka
1215a9685eaaSMarcel Telka cln->nconf = NULL;
1216a9685eaaSMarcel Telka cln->clnames = NULL;
1217a9685eaaSMarcel Telka cln->host = NULL;
1218a9685eaaSMarcel Telka
1219a9685eaaSMarcel Telka cln->flags = 0;
1220a9685eaaSMarcel Telka }
1221a9685eaaSMarcel Telka
1222a9685eaaSMarcel Telka void
cln_init(struct cln * cln,SVCXPRT * transp)1223a9685eaaSMarcel Telka cln_init(struct cln *cln, SVCXPRT *transp)
1224a9685eaaSMarcel Telka {
1225a9685eaaSMarcel Telka cln_init_common(cln, transp, NULL, NULL);
1226a9685eaaSMarcel Telka }
1227a9685eaaSMarcel Telka
1228a9685eaaSMarcel Telka void
cln_init_lazy(struct cln * cln,char * netid,struct netbuf * nbuf)1229a9685eaaSMarcel Telka cln_init_lazy(struct cln *cln, char *netid, struct netbuf *nbuf)
1230a9685eaaSMarcel Telka {
1231a9685eaaSMarcel Telka cln_init_common(cln, NULL, netid, nbuf);
1232a9685eaaSMarcel Telka }
1233a9685eaaSMarcel Telka
1234a9685eaaSMarcel Telka void
cln_fini(struct cln * cln)1235a9685eaaSMarcel Telka cln_fini(struct cln *cln)
1236a9685eaaSMarcel Telka {
1237a9685eaaSMarcel Telka if (cln->nconf != NULL)
1238a9685eaaSMarcel Telka freenetconfigent(cln->nconf);
1239a9685eaaSMarcel Telka
1240a9685eaaSMarcel Telka if (cln->clnames != NULL)
1241a9685eaaSMarcel Telka netdir_free(cln->clnames, ND_HOSTSERVLIST);
1242a9685eaaSMarcel Telka
1243a9685eaaSMarcel Telka free(cln->host);
1244a9685eaaSMarcel Telka }
1245a9685eaaSMarcel Telka
1246a9685eaaSMarcel Telka struct netbuf *
cln_getnbuf(struct cln * cln)1247a9685eaaSMarcel Telka cln_getnbuf(struct cln *cln)
1248a9685eaaSMarcel Telka {
1249a9685eaaSMarcel Telka return (cln->nbuf);
1250a9685eaaSMarcel Telka }
1251a9685eaaSMarcel Telka
1252a9685eaaSMarcel Telka struct nd_hostservlist *
cln_getclientsnames(struct cln * cln)1253a9685eaaSMarcel Telka cln_getclientsnames(struct cln *cln)
1254a9685eaaSMarcel Telka {
1255a9685eaaSMarcel Telka if ((cln->flags & CLN_CLNAMES) == 0) {
1256a9685eaaSMarcel Telka /*
1257a9685eaaSMarcel Telka * nconf is not needed if we do not have nbuf (see
1258a9685eaaSMarcel Telka * cln_gethost() too), so we check for nbuf and in a case it is
1259a9685eaaSMarcel Telka * NULL we do not try to get nconf.
1260a9685eaaSMarcel Telka */
1261a9685eaaSMarcel Telka if (cln->netid != NULL && cln->nbuf != NULL) {
1262a9685eaaSMarcel Telka cln->nconf = getnetconfigent(cln->netid);
1263a9685eaaSMarcel Telka if (cln->nconf == NULL)
1264a9685eaaSMarcel Telka syslog(LOG_ERR, "%s: getnetconfigent failed",
1265a9685eaaSMarcel Telka cln->netid);
1266a9685eaaSMarcel Telka }
1267a9685eaaSMarcel Telka
1268a9685eaaSMarcel Telka if (cln->nconf != NULL && cln->nbuf != NULL)
1269a9685eaaSMarcel Telka (void) __netdir_getbyaddr_nosrv(cln->nconf,
1270a9685eaaSMarcel Telka &cln->clnames, cln->nbuf);
1271a9685eaaSMarcel Telka
1272a9685eaaSMarcel Telka cln->flags |= CLN_CLNAMES;
1273a9685eaaSMarcel Telka }
1274a9685eaaSMarcel Telka
1275a9685eaaSMarcel Telka return (cln->clnames);
1276a9685eaaSMarcel Telka }
1277a9685eaaSMarcel Telka
1278a9685eaaSMarcel Telka /*
1279a9685eaaSMarcel Telka * Return B_TRUE if the host is already available at no cost
1280a9685eaaSMarcel Telka */
1281a9685eaaSMarcel Telka boolean_t
cln_havehost(struct cln * cln)1282a9685eaaSMarcel Telka cln_havehost(struct cln *cln)
1283a9685eaaSMarcel Telka {
1284a9685eaaSMarcel Telka return ((cln->flags & (CLN_CLNAMES | CLN_HOST)) != 0);
1285a9685eaaSMarcel Telka }
1286a9685eaaSMarcel Telka
1287a9685eaaSMarcel Telka char *
cln_gethost(struct cln * cln)1288a9685eaaSMarcel Telka cln_gethost(struct cln *cln)
1289a9685eaaSMarcel Telka {
1290a9685eaaSMarcel Telka if (cln_getclientsnames(cln) != NULL)
1291a9685eaaSMarcel Telka return (cln->clnames->h_hostservs[0].h_host);
1292a9685eaaSMarcel Telka
1293a9685eaaSMarcel Telka if ((cln->flags & CLN_HOST) == 0) {
1294a9685eaaSMarcel Telka if (cln->nconf == NULL || cln->nbuf == NULL) {
1295a9685eaaSMarcel Telka cln->host = strdup("(anon)");
1296a9685eaaSMarcel Telka } else {
1297a9685eaaSMarcel Telka char host[MAXIPADDRLEN];
1298a9685eaaSMarcel Telka
1299a9685eaaSMarcel Telka if (strcmp(cln->nconf->nc_protofmly, NC_INET) == 0) {
1300a9685eaaSMarcel Telka struct sockaddr_in *sa;
1301a9685eaaSMarcel Telka
1302a9685eaaSMarcel Telka /* LINTED pointer alignment */
1303a9685eaaSMarcel Telka sa = (struct sockaddr_in *)(cln->nbuf->buf);
1304a9685eaaSMarcel Telka (void) inet_ntoa_r(sa->sin_addr, host);
1305a9685eaaSMarcel Telka
1306a9685eaaSMarcel Telka cln->host = strdup(host);
1307a9685eaaSMarcel Telka } else if (strcmp(cln->nconf->nc_protofmly,
1308a9685eaaSMarcel Telka NC_INET6) == 0) {
1309a9685eaaSMarcel Telka struct sockaddr_in6 *sa;
1310a9685eaaSMarcel Telka
1311a9685eaaSMarcel Telka /* LINTED pointer alignment */
1312a9685eaaSMarcel Telka sa = (struct sockaddr_in6 *)(cln->nbuf->buf);
1313a9685eaaSMarcel Telka (void) inet_ntop(AF_INET6,
1314a9685eaaSMarcel Telka sa->sin6_addr.s6_addr,
1315a9685eaaSMarcel Telka host, INET6_ADDRSTRLEN);
1316a9685eaaSMarcel Telka
1317a9685eaaSMarcel Telka cln->host = strdup(host);
1318a9685eaaSMarcel Telka } else {
1319a9685eaaSMarcel Telka syslog(LOG_ERR, gettext("Client's address is "
1320a9685eaaSMarcel Telka "neither IPv4 nor IPv6"));
1321a9685eaaSMarcel Telka
1322a9685eaaSMarcel Telka cln->host = strdup("(anon)");
1323a9685eaaSMarcel Telka }
1324a9685eaaSMarcel Telka }
1325a9685eaaSMarcel Telka
1326a9685eaaSMarcel Telka cln->flags |= CLN_HOST;
1327a9685eaaSMarcel Telka }
1328a9685eaaSMarcel Telka
1329a9685eaaSMarcel Telka return (cln->host);
1330a9685eaaSMarcel Telka }
1331a9685eaaSMarcel Telka
13327c478bd9Sstevel@tonic-gate /*
13337c478bd9Sstevel@tonic-gate * Check mount requests, add to mounted list if ok
13347c478bd9Sstevel@tonic-gate */
13354a508a79SThomas Haynes static int
mount(struct svc_req * rqstp)13367c478bd9Sstevel@tonic-gate mount(struct svc_req *rqstp)
13377c478bd9Sstevel@tonic-gate {
13387c478bd9Sstevel@tonic-gate SVCXPRT *transp;
133927242a7cSthurlow int version, vers;
13407c478bd9Sstevel@tonic-gate struct fhstatus fhs;
13417c478bd9Sstevel@tonic-gate struct mountres3 mountres3;
134227242a7cSthurlow char fh[FHSIZE3];
134327242a7cSthurlow int len = FHSIZE3;
13447c478bd9Sstevel@tonic-gate char *path, rpath[MAXPATHLEN];
13454a508a79SThomas Haynes share_t *sh = NULL;
1346a9685eaaSMarcel Telka struct cln cln;
13477c478bd9Sstevel@tonic-gate char *host = NULL;
13484a508a79SThomas Haynes int error = 0, lofs_tried = 0, enqueued;
13497c478bd9Sstevel@tonic-gate int flavor_list[MAX_FLAVORS];
13507c478bd9Sstevel@tonic-gate int flavor_count;
135103986916Sjarrett ucred_t *uc = NULL;
13527c478bd9Sstevel@tonic-gate
13534a508a79SThomas Haynes int audit_status;
13544a508a79SThomas Haynes
13557c478bd9Sstevel@tonic-gate transp = rqstp->rq_xprt;
13567c478bd9Sstevel@tonic-gate version = rqstp->rq_vers;
13577c478bd9Sstevel@tonic-gate path = NULL;
13587c478bd9Sstevel@tonic-gate
13597c478bd9Sstevel@tonic-gate if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
13607c478bd9Sstevel@tonic-gate svcerr_decode(transp);
13614a508a79SThomas Haynes return (EACCES);
13627c478bd9Sstevel@tonic-gate }
13637c478bd9Sstevel@tonic-gate
1364a9685eaaSMarcel Telka cln_init(&cln, transp);
1365a9685eaaSMarcel Telka
13664a508a79SThomas Haynes /*
13674a508a79SThomas Haynes * Put off getting the name for the client until we
13684a508a79SThomas Haynes * need it. This is a performance gain. If we are logging,
13694a508a79SThomas Haynes * then we don't care about performance and might as well
13704a508a79SThomas Haynes * get the host name now in case we need to spit out an
13714a508a79SThomas Haynes * error message.
13724a508a79SThomas Haynes */
13734a508a79SThomas Haynes if (verbose) {
13744a508a79SThomas Haynes DTRACE_PROBE(mountd, name_by_verbose);
1375a9685eaaSMarcel Telka if ((host = cln_gethost(&cln)) == NULL) {
13764a508a79SThomas Haynes /*
13774a508a79SThomas Haynes * We failed to get a name for the client, even
13784a508a79SThomas Haynes * 'anon', probably because we ran out of memory.
13794a508a79SThomas Haynes * In this situation it doesn't make sense to
13804a508a79SThomas Haynes * allow the mount to succeed.
13814a508a79SThomas Haynes */
13824a508a79SThomas Haynes error = EACCES;
13834a508a79SThomas Haynes goto reply;
13844a508a79SThomas Haynes }
13857c478bd9Sstevel@tonic-gate }
13867c478bd9Sstevel@tonic-gate
13877c478bd9Sstevel@tonic-gate /*
13887c478bd9Sstevel@tonic-gate * If the version being used is less than the minimum version,
13897c478bd9Sstevel@tonic-gate * the filehandle translation should not be provided to the
13907c478bd9Sstevel@tonic-gate * client.
13917c478bd9Sstevel@tonic-gate */
13927c478bd9Sstevel@tonic-gate if (rejecting || version < mount_vers_min) {
13937c478bd9Sstevel@tonic-gate if (verbose)
13947c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE, "Rejected mount: %s for %s",
1395250a0733Sth host, path);
13967c478bd9Sstevel@tonic-gate error = EACCES;
13977c478bd9Sstevel@tonic-gate goto reply;
13987c478bd9Sstevel@tonic-gate }
13997c478bd9Sstevel@tonic-gate
140045916cd2Sjpk /*
140103986916Sjarrett * Trusted Extension doesn't support nfsv2. nfsv2 client
140203986916Sjarrett * uses MOUNT protocol v1 and v2. To prevent circumventing
140303986916Sjarrett * TX label policy via using nfsv2 client, reject a mount
140403986916Sjarrett * request with version less than 3 and log an error.
140545916cd2Sjpk */
140645916cd2Sjpk if (is_system_labeled()) {
140703986916Sjarrett if (version < 3) {
140803986916Sjarrett if (verbose)
140903986916Sjarrett syslog(LOG_ERR,
141003986916Sjarrett "Rejected mount: TX doesn't support NFSv2");
141103986916Sjarrett error = EACCES;
141203986916Sjarrett goto reply;
141303986916Sjarrett }
141445916cd2Sjpk }
141545916cd2Sjpk
14167c478bd9Sstevel@tonic-gate /*
14177c478bd9Sstevel@tonic-gate * Get the real path (no symbolic links in it)
14187c478bd9Sstevel@tonic-gate */
14197c478bd9Sstevel@tonic-gate if (realpath(path, rpath) == NULL) {
14207c478bd9Sstevel@tonic-gate error = errno;
14217c478bd9Sstevel@tonic-gate if (verbose)
14227c478bd9Sstevel@tonic-gate syslog(LOG_ERR,
1423250a0733Sth "mount request: realpath: %s: %m", path);
14247c478bd9Sstevel@tonic-gate if (error == ENOENT)
1425a9685eaaSMarcel Telka error = mount_enoent_error(&cln, path, rpath,
1426a9685eaaSMarcel Telka flavor_list);
14277c478bd9Sstevel@tonic-gate goto reply;
14287c478bd9Sstevel@tonic-gate }
14297c478bd9Sstevel@tonic-gate
14307c478bd9Sstevel@tonic-gate if ((sh = findentry(rpath)) == NULL &&
1431250a0733Sth (sh = find_lofsentry(rpath, &lofs_tried)) == NULL) {
14327c478bd9Sstevel@tonic-gate error = EACCES;
14337c478bd9Sstevel@tonic-gate goto reply;
14347c478bd9Sstevel@tonic-gate }
14357c478bd9Sstevel@tonic-gate
14367c478bd9Sstevel@tonic-gate /*
14377c478bd9Sstevel@tonic-gate * Check if this is a "nosub" only export, in which case, mounting
14387c478bd9Sstevel@tonic-gate * subdirectories isn't allowed. Bug 1184573.
14397c478bd9Sstevel@tonic-gate */
14407c478bd9Sstevel@tonic-gate if (checkrootmount(sh, rpath) == 0) {
14417c478bd9Sstevel@tonic-gate error = EACCES;
14427c478bd9Sstevel@tonic-gate goto reply;
14437c478bd9Sstevel@tonic-gate }
14447c478bd9Sstevel@tonic-gate
14457c478bd9Sstevel@tonic-gate if (newopts(sh->sh_opts))
1446a9685eaaSMarcel Telka flavor_count = getclientsflavors_new(sh, &cln, flavor_list);
14477c478bd9Sstevel@tonic-gate else
1448a9685eaaSMarcel Telka flavor_count = getclientsflavors_old(sh, &cln, flavor_list);
14494a508a79SThomas Haynes
14507c478bd9Sstevel@tonic-gate if (flavor_count == 0) {
14517c478bd9Sstevel@tonic-gate error = EACCES;
14527c478bd9Sstevel@tonic-gate goto reply;
14537c478bd9Sstevel@tonic-gate }
14547c478bd9Sstevel@tonic-gate
145503986916Sjarrett /*
145603986916Sjarrett * Check MAC policy here. The server side policy should be
145703986916Sjarrett * consistent with client side mount policy, i.e.
145803986916Sjarrett * - we disallow an admin_low unlabeled client to mount
145903986916Sjarrett * - we disallow mount from a lower labeled client.
146003986916Sjarrett */
146103986916Sjarrett if (is_system_labeled()) {
146203986916Sjarrett m_label_t *clabel = NULL;
146303986916Sjarrett m_label_t *slabel = NULL;
146403986916Sjarrett m_label_t admin_low;
146503986916Sjarrett
146603986916Sjarrett if (svc_getcallerucred(rqstp->rq_xprt, &uc) != 0) {
146703986916Sjarrett syslog(LOG_ERR,
146803986916Sjarrett "mount request: Failed to get caller's ucred : %m");
146903986916Sjarrett error = EACCES;
147003986916Sjarrett goto reply;
147103986916Sjarrett }
147203986916Sjarrett if ((clabel = ucred_getlabel(uc)) == NULL) {
147303986916Sjarrett syslog(LOG_ERR,
147403986916Sjarrett "mount request: can't get client label from ucred");
147503986916Sjarrett error = EACCES;
147603986916Sjarrett goto reply;
147703986916Sjarrett }
147803986916Sjarrett
147903986916Sjarrett bsllow(&admin_low);
148003986916Sjarrett if (blequal(&admin_low, clabel)) {
148103986916Sjarrett struct sockaddr *ca;
148203986916Sjarrett tsol_tpent_t *tp;
148303986916Sjarrett
148403986916Sjarrett ca = (struct sockaddr *)(void *)svc_getrpccaller(
148503986916Sjarrett rqstp->rq_xprt)->buf;
148603986916Sjarrett if (ca == NULL) {
148703986916Sjarrett error = EACCES;
148803986916Sjarrett goto reply;
148903986916Sjarrett }
149003986916Sjarrett /*
149103986916Sjarrett * get trusted network template associated
149203986916Sjarrett * with the client.
149303986916Sjarrett */
149403986916Sjarrett tp = get_client_template(ca);
149503986916Sjarrett if (tp == NULL || tp->host_type != SUN_CIPSO) {
149603986916Sjarrett if (tp != NULL)
149703986916Sjarrett tsol_freetpent(tp);
149803986916Sjarrett error = EACCES;
149903986916Sjarrett goto reply;
150003986916Sjarrett }
150103986916Sjarrett tsol_freetpent(tp);
150203986916Sjarrett } else {
150303986916Sjarrett if ((slabel = m_label_alloc(MAC_LABEL)) == NULL) {
150403986916Sjarrett error = EACCES;
150503986916Sjarrett goto reply;
150603986916Sjarrett }
150703986916Sjarrett
150803986916Sjarrett if (getlabel(rpath, slabel) != 0) {
150903986916Sjarrett m_label_free(slabel);
151003986916Sjarrett error = EACCES;
151103986916Sjarrett goto reply;
151203986916Sjarrett }
151303986916Sjarrett
151403986916Sjarrett if (!bldominates(clabel, slabel)) {
151503986916Sjarrett m_label_free(slabel);
151603986916Sjarrett error = EACCES;
151703986916Sjarrett goto reply;
151803986916Sjarrett }
151903986916Sjarrett m_label_free(slabel);
152003986916Sjarrett }
152103986916Sjarrett }
152203986916Sjarrett
15237c478bd9Sstevel@tonic-gate /*
15247c478bd9Sstevel@tonic-gate * Now get the filehandle.
15257c478bd9Sstevel@tonic-gate *
152627242a7cSthurlow * NFS V2 clients get a 32 byte filehandle.
152727242a7cSthurlow * NFS V3 clients get a 32 or 64 byte filehandle, depending on
152827242a7cSthurlow * the embedded FIDs.
15297c478bd9Sstevel@tonic-gate */
153027242a7cSthurlow vers = (version == MOUNTVERS3) ? NFS_V3 : NFS_VERSION;
15317c478bd9Sstevel@tonic-gate
15327c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
153327242a7cSthurlow while (nfs_getfh(rpath, vers, &len, fh) < 0) {
15347c478bd9Sstevel@tonic-gate if (errno == EINVAL &&
1535250a0733Sth (sh = find_lofsentry(rpath, &lofs_tried)) != NULL) {
15367c478bd9Sstevel@tonic-gate errno = 0;
15377c478bd9Sstevel@tonic-gate continue;
15387c478bd9Sstevel@tonic-gate }
15397c478bd9Sstevel@tonic-gate error = errno == EINVAL ? EACCES : errno;
15407c478bd9Sstevel@tonic-gate syslog(LOG_DEBUG, "mount request: getfh failed on %s: %m",
1541250a0733Sth path);
15427c478bd9Sstevel@tonic-gate break;
15437c478bd9Sstevel@tonic-gate }
15447c478bd9Sstevel@tonic-gate
154527242a7cSthurlow if (version == MOUNTVERS3) {
154627242a7cSthurlow mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len = len;
154727242a7cSthurlow mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val = fh;
154827242a7cSthurlow } else {
154927242a7cSthurlow bcopy(fh, &fhs.fhstatus_u.fhs_fhandle, NFS_FHSIZE);
155027242a7cSthurlow }
155127242a7cSthurlow
15527c478bd9Sstevel@tonic-gate reply:
155303986916Sjarrett if (uc != NULL)
155403986916Sjarrett ucred_free(uc);
15554a508a79SThomas Haynes
15567c478bd9Sstevel@tonic-gate switch (version) {
15577c478bd9Sstevel@tonic-gate case MOUNTVERS:
15587c478bd9Sstevel@tonic-gate case MOUNTVERS_POSIX:
15597c478bd9Sstevel@tonic-gate if (error == EINVAL)
15607c478bd9Sstevel@tonic-gate fhs.fhs_status = NFSERR_ACCES;
15617c478bd9Sstevel@tonic-gate else if (error == EREMOTE)
15627c478bd9Sstevel@tonic-gate fhs.fhs_status = NFSERR_REMOTE;
15637c478bd9Sstevel@tonic-gate else
15647c478bd9Sstevel@tonic-gate fhs.fhs_status = error;
15654a508a79SThomas Haynes
15667c478bd9Sstevel@tonic-gate if (!svc_sendreply(transp, xdr_fhstatus, (char *)&fhs))
1567a9685eaaSMarcel Telka log_cant_reply_cln(&cln);
15684a508a79SThomas Haynes
15694a508a79SThomas Haynes audit_status = fhs.fhs_status;
15707c478bd9Sstevel@tonic-gate break;
15717c478bd9Sstevel@tonic-gate
15727c478bd9Sstevel@tonic-gate case MOUNTVERS3:
15737c478bd9Sstevel@tonic-gate if (!error) {
15747c478bd9Sstevel@tonic-gate mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val =
1575250a0733Sth flavor_list;
15767c478bd9Sstevel@tonic-gate mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len =
1577250a0733Sth flavor_count;
15787c478bd9Sstevel@tonic-gate
15797c478bd9Sstevel@tonic-gate } else if (error == ENAMETOOLONG)
15807c478bd9Sstevel@tonic-gate error = MNT3ERR_NAMETOOLONG;
15817c478bd9Sstevel@tonic-gate
15827c478bd9Sstevel@tonic-gate mountres3.fhs_status = error;
15837c478bd9Sstevel@tonic-gate if (!svc_sendreply(transp, xdr_mountres3, (char *)&mountres3))
1584a9685eaaSMarcel Telka log_cant_reply_cln(&cln);
15857c478bd9Sstevel@tonic-gate
15864a508a79SThomas Haynes audit_status = mountres3.fhs_status;
15877c478bd9Sstevel@tonic-gate break;
15887c478bd9Sstevel@tonic-gate }
15897c478bd9Sstevel@tonic-gate
1590a9685eaaSMarcel Telka if (cln_havehost(&cln))
1591a9685eaaSMarcel Telka host = cln_gethost(&cln);
1592a9685eaaSMarcel Telka
15937c478bd9Sstevel@tonic-gate if (verbose)
15947c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE, "MOUNT: %s %s %s",
1595250a0733Sth (host == NULL) ? "unknown host" : host,
1596250a0733Sth error ? "denied" : "mounted", path);
15977c478bd9Sstevel@tonic-gate
15984a508a79SThomas Haynes /*
15994a508a79SThomas Haynes * If we can not create a queue entry, go ahead and do it
16004a508a79SThomas Haynes * in the context of this thread.
16014a508a79SThomas Haynes */
16024a508a79SThomas Haynes enqueued = enqueue_logging_data(host, transp, path, rpath,
16034a508a79SThomas Haynes audit_status, error);
16044a508a79SThomas Haynes if (enqueued == FALSE) {
16054a508a79SThomas Haynes if (host == NULL) {
16064a508a79SThomas Haynes DTRACE_PROBE(mountd, name_by_in_thread);
1607a9685eaaSMarcel Telka host = cln_gethost(&cln);
16084a508a79SThomas Haynes }
16094a508a79SThomas Haynes
16104a508a79SThomas Haynes DTRACE_PROBE(mountd, logged_in_thread);
16114a508a79SThomas Haynes audit_mountd_mount(host, path, audit_status); /* BSM */
16124a508a79SThomas Haynes if (!error)
16134a508a79SThomas Haynes mntlist_new(host, rpath); /* add entry to mount list */
16144a508a79SThomas Haynes }
16154a508a79SThomas Haynes
16167c478bd9Sstevel@tonic-gate if (path != NULL)
1617544783caSToomas Soome (void) svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
16187c478bd9Sstevel@tonic-gate
16197c478bd9Sstevel@tonic-gate if (sh)
16207c478bd9Sstevel@tonic-gate sharefree(sh);
1621a9685eaaSMarcel Telka
1622a9685eaaSMarcel Telka cln_fini(&cln);
16234a508a79SThomas Haynes
16244a508a79SThomas Haynes return (error);
16257c478bd9Sstevel@tonic-gate }
16267c478bd9Sstevel@tonic-gate
16276b086bafSSam Falkner /*
16286b086bafSSam Falkner * Determine whether two paths are within the same file system.
16296b086bafSSam Falkner * Returns nonzero (true) if paths are the same, zero (false) if
16306b086bafSSam Falkner * they are different. If an error occurs, return false.
16316b086bafSSam Falkner *
16326b086bafSSam Falkner * Use the actual FSID if it's available (via getattrat()); otherwise,
16336b086bafSSam Falkner * fall back on st_dev.
16346b086bafSSam Falkner *
16356b086bafSSam Falkner * With ZFS snapshots, st_dev differs from the regular file system
16366b086bafSSam Falkner * versus the snapshot. But the fsid is the same throughout. Thus
16376b086bafSSam Falkner * the fsid is a better test.
16386b086bafSSam Falkner */
16396b086bafSSam Falkner static int
same_file_system(const char * path1,const char * path2)16406b086bafSSam Falkner same_file_system(const char *path1, const char *path2)
16416b086bafSSam Falkner {
16426b086bafSSam Falkner uint64_t fsid1, fsid2;
16436b086bafSSam Falkner struct stat64 st1, st2;
16446b086bafSSam Falkner nvlist_t *nvl1 = NULL;
16456b086bafSSam Falkner nvlist_t *nvl2 = NULL;
16466b086bafSSam Falkner
16476b086bafSSam Falkner if ((getattrat(AT_FDCWD, XATTR_VIEW_READONLY, path1, &nvl1) == 0) &&
16486b086bafSSam Falkner (getattrat(AT_FDCWD, XATTR_VIEW_READONLY, path2, &nvl2) == 0) &&
16496b086bafSSam Falkner (nvlist_lookup_uint64(nvl1, A_FSID, &fsid1) == 0) &&
16506b086bafSSam Falkner (nvlist_lookup_uint64(nvl2, A_FSID, &fsid2) == 0)) {
16516b086bafSSam Falkner nvlist_free(nvl1);
16526b086bafSSam Falkner nvlist_free(nvl2);
16536b086bafSSam Falkner /*
16546b086bafSSam Falkner * We have found fsid's for both paths.
16556b086bafSSam Falkner */
16566b086bafSSam Falkner
16576b086bafSSam Falkner if (fsid1 == fsid2)
16586b086bafSSam Falkner return (B_TRUE);
16596b086bafSSam Falkner
16606b086bafSSam Falkner return (B_FALSE);
16616b086bafSSam Falkner }
16626b086bafSSam Falkner
1663aab83bb8SJosef 'Jeff' Sipek nvlist_free(nvl1);
1664aab83bb8SJosef 'Jeff' Sipek nvlist_free(nvl2);
16656b086bafSSam Falkner
16666b086bafSSam Falkner /*
16676b086bafSSam Falkner * We were unable to find fsid's for at least one of the paths.
16686b086bafSSam Falkner * fall back on st_dev.
16696b086bafSSam Falkner */
16706b086bafSSam Falkner
16716b086bafSSam Falkner if (stat64(path1, &st1) < 0) {
16726b086bafSSam Falkner syslog(LOG_NOTICE, "%s: %m", path1);
16736b086bafSSam Falkner return (B_FALSE);
16746b086bafSSam Falkner }
16756b086bafSSam Falkner if (stat64(path2, &st2) < 0) {
16766b086bafSSam Falkner syslog(LOG_NOTICE, "%s: %m", path2);
16776b086bafSSam Falkner return (B_FALSE);
16786b086bafSSam Falkner }
16796b086bafSSam Falkner
16806b086bafSSam Falkner if (st1.st_dev == st2.st_dev)
16816b086bafSSam Falkner return (B_TRUE);
16826b086bafSSam Falkner
16836b086bafSSam Falkner return (B_FALSE);
16846b086bafSSam Falkner }
16856b086bafSSam Falkner
16864a508a79SThomas Haynes share_t *
findentry(char * path)16877c478bd9Sstevel@tonic-gate findentry(char *path)
16887c478bd9Sstevel@tonic-gate {
16894a508a79SThomas Haynes share_t *sh = NULL;
16907c478bd9Sstevel@tonic-gate struct sh_list *shp;
169154d34259SMarcel Telka char *p1, *p2;
16927c478bd9Sstevel@tonic-gate
16937c478bd9Sstevel@tonic-gate check_sharetab();
16947c478bd9Sstevel@tonic-gate
16957c478bd9Sstevel@tonic-gate (void) rw_rdlock(&sharetab_lock);
16967c478bd9Sstevel@tonic-gate
16977c478bd9Sstevel@tonic-gate for (shp = share_list; shp; shp = shp->shl_next) {
16987c478bd9Sstevel@tonic-gate sh = shp->shl_sh;
16997c478bd9Sstevel@tonic-gate for (p1 = sh->sh_path, p2 = path; *p1 == *p2; p1++, p2++)
17007c478bd9Sstevel@tonic-gate if (*p1 == '\0')
17017c478bd9Sstevel@tonic-gate goto done; /* exact match */
17027c478bd9Sstevel@tonic-gate
17037c478bd9Sstevel@tonic-gate /*
17047c478bd9Sstevel@tonic-gate * Now compare the pathnames for three cases:
17057c478bd9Sstevel@tonic-gate *
17067c478bd9Sstevel@tonic-gate * Parent: /export/foo (no trailing slash on parent)
17077c478bd9Sstevel@tonic-gate * Child: /export/foo/bar
17087c478bd9Sstevel@tonic-gate *
17097c478bd9Sstevel@tonic-gate * Parent: /export/foo/ (trailing slash on parent)
17107c478bd9Sstevel@tonic-gate * Child: /export/foo/bar
17117c478bd9Sstevel@tonic-gate *
17127c478bd9Sstevel@tonic-gate * Parent: /export/foo/ (no trailing slash on child)
17137c478bd9Sstevel@tonic-gate * Child: /export/foo
17147c478bd9Sstevel@tonic-gate */
17157c478bd9Sstevel@tonic-gate if ((*p1 == '\0' && *p2 == '/') ||
17167c478bd9Sstevel@tonic-gate (*p1 == '\0' && *(p1-1) == '/') ||
17177c478bd9Sstevel@tonic-gate (*p2 == '\0' && *p1 == '/' && *(p1+1) == '\0')) {
17187c478bd9Sstevel@tonic-gate /*
17196b086bafSSam Falkner * We have a subdirectory. Test whether the
17206b086bafSSam Falkner * subdirectory is in the same file system.
17217c478bd9Sstevel@tonic-gate */
17226b086bafSSam Falkner if (same_file_system(path, sh->sh_path))
17237c478bd9Sstevel@tonic-gate goto done;
17247c478bd9Sstevel@tonic-gate }
17257c478bd9Sstevel@tonic-gate }
17267c478bd9Sstevel@tonic-gate done:
17277c478bd9Sstevel@tonic-gate sh = shp ? sharedup(sh) : NULL;
17287c478bd9Sstevel@tonic-gate
17297c478bd9Sstevel@tonic-gate (void) rw_unlock(&sharetab_lock);
17307c478bd9Sstevel@tonic-gate
17317c478bd9Sstevel@tonic-gate return (sh);
17327c478bd9Sstevel@tonic-gate }
17337c478bd9Sstevel@tonic-gate
17347c478bd9Sstevel@tonic-gate
17357c478bd9Sstevel@tonic-gate static int
is_substring(char ** mntp,char ** path)17367c478bd9Sstevel@tonic-gate is_substring(char **mntp, char **path)
17377c478bd9Sstevel@tonic-gate {
17387c478bd9Sstevel@tonic-gate char *p1 = *mntp, *p2 = *path;
17397c478bd9Sstevel@tonic-gate
17407c478bd9Sstevel@tonic-gate if (*p1 == '\0' && *p2 == '\0') /* exact match */
17417c478bd9Sstevel@tonic-gate return (1);
17427c478bd9Sstevel@tonic-gate else if (*p1 == '\0' && *p2 == '/')
17437c478bd9Sstevel@tonic-gate return (1);
17447c478bd9Sstevel@tonic-gate else if (*p1 == '\0' && *(p1-1) == '/') {
17457c478bd9Sstevel@tonic-gate *path = --p2; /* we need the slash in p2 */
17467c478bd9Sstevel@tonic-gate return (1);
17477c478bd9Sstevel@tonic-gate } else if (*p2 == '\0') {
17487c478bd9Sstevel@tonic-gate while (*p1 == '/')
17497c478bd9Sstevel@tonic-gate p1++;
17507c478bd9Sstevel@tonic-gate if (*p1 == '\0') /* exact match */
17517c478bd9Sstevel@tonic-gate return (1);
17527c478bd9Sstevel@tonic-gate }
17537c478bd9Sstevel@tonic-gate return (0);
17547c478bd9Sstevel@tonic-gate }
17557c478bd9Sstevel@tonic-gate
17567c478bd9Sstevel@tonic-gate /*
17577c478bd9Sstevel@tonic-gate * find_lofsentry() searches for the real path which this requested LOFS path
17587c478bd9Sstevel@tonic-gate * (rpath) shadows. If found, it will return the sharetab entry of
17597c478bd9Sstevel@tonic-gate * the real path that corresponds to the LOFS path.
17607c478bd9Sstevel@tonic-gate * We first search mnttab to see if the requested path is an automounted
17617c478bd9Sstevel@tonic-gate * path. If it is an automounted path, it will trigger the mount by stat()ing
17627c478bd9Sstevel@tonic-gate * the requested path. Note that it is important to check that this path is
17637c478bd9Sstevel@tonic-gate * actually an automounted path, otherwise we would stat() a path which may
17647c478bd9Sstevel@tonic-gate * turn out to be NFS and block indefinitely on a dead server. The automounter
17657c478bd9Sstevel@tonic-gate * times-out if the server is dead, so there's no risk of hanging this
17667c478bd9Sstevel@tonic-gate * thread waiting for stat().
17677c478bd9Sstevel@tonic-gate * After the mount has been triggered (if necessary), we look for a
17687c478bd9Sstevel@tonic-gate * mountpoint of type LOFS (by searching /etc/mnttab again) which
17697c478bd9Sstevel@tonic-gate * is a substring of the rpath. If found, we construct a new path by
17707c478bd9Sstevel@tonic-gate * concatenating the mnt_special and the remaining of rpath, call findentry()
17717c478bd9Sstevel@tonic-gate * to make sure the 'real path' is shared.
17727c478bd9Sstevel@tonic-gate */
17734a508a79SThomas Haynes static share_t *
find_lofsentry(char * rpath,int * done_flag)17747c478bd9Sstevel@tonic-gate find_lofsentry(char *rpath, int *done_flag)
17757c478bd9Sstevel@tonic-gate {
17767c478bd9Sstevel@tonic-gate struct stat r_stbuf;
17777c478bd9Sstevel@tonic-gate mntlist_t *ml, *mntl, *mntpnt = NULL;
17784a508a79SThomas Haynes share_t *retcode = NULL;
17797c478bd9Sstevel@tonic-gate char tmp_path[MAXPATHLEN];
17807c478bd9Sstevel@tonic-gate int mntpnt_len = 0, tmp;
17817c478bd9Sstevel@tonic-gate char *p1, *p2;
17827c478bd9Sstevel@tonic-gate
17837c478bd9Sstevel@tonic-gate if ((*done_flag)++)
17847c478bd9Sstevel@tonic-gate return (retcode);
17857c478bd9Sstevel@tonic-gate
17867c478bd9Sstevel@tonic-gate /*
17877c478bd9Sstevel@tonic-gate * While fsgetmntlist() uses lockf() to
17887c478bd9Sstevel@tonic-gate * lock the mnttab before reading it in,
17897c478bd9Sstevel@tonic-gate * the lock ignores threads in the same process.
17907c478bd9Sstevel@tonic-gate * Read in the mnttab with the protection of a mutex.
17917c478bd9Sstevel@tonic-gate */
17927c478bd9Sstevel@tonic-gate (void) mutex_lock(&mnttab_lock);
17937c478bd9Sstevel@tonic-gate mntl = fsgetmntlist();
17947c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mnttab_lock);
17957c478bd9Sstevel@tonic-gate
17967c478bd9Sstevel@tonic-gate /*
17977c478bd9Sstevel@tonic-gate * Obtain the mountpoint for the requested path.
17987c478bd9Sstevel@tonic-gate */
17997c478bd9Sstevel@tonic-gate for (ml = mntl; ml; ml = ml->mntl_next) {
18007c478bd9Sstevel@tonic-gate for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath;
1801250a0733Sth *p1 == *p2 && *p1; p1++, p2++)
1802250a0733Sth ;
18037c478bd9Sstevel@tonic-gate if (is_substring(&p1, &p2) &&
18047c478bd9Sstevel@tonic-gate (tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len) {
18057c478bd9Sstevel@tonic-gate mntpnt = ml;
18067c478bd9Sstevel@tonic-gate mntpnt_len = tmp;
18077c478bd9Sstevel@tonic-gate }
18087c478bd9Sstevel@tonic-gate }
18097c478bd9Sstevel@tonic-gate
18107c478bd9Sstevel@tonic-gate /*
18117c478bd9Sstevel@tonic-gate * If the path needs to be autoFS mounted, trigger the mount by
18127c478bd9Sstevel@tonic-gate * stat()ing it. This is determined by checking whether the
18137c478bd9Sstevel@tonic-gate * mountpoint we just found is of type autofs.
18147c478bd9Sstevel@tonic-gate */
18157c478bd9Sstevel@tonic-gate if (mntpnt != NULL &&
18167c478bd9Sstevel@tonic-gate strcmp(mntpnt->mntl_mnt->mnt_fstype, "autofs") == 0) {
18177c478bd9Sstevel@tonic-gate /*
18187c478bd9Sstevel@tonic-gate * The requested path is a substring of an autoFS filesystem.
18197c478bd9Sstevel@tonic-gate * Trigger the mount.
18207c478bd9Sstevel@tonic-gate */
18217c478bd9Sstevel@tonic-gate if (stat(rpath, &r_stbuf) < 0) {
18227c478bd9Sstevel@tonic-gate if (verbose)
18237c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE, "%s: %m", rpath);
18247c478bd9Sstevel@tonic-gate goto done;
18257c478bd9Sstevel@tonic-gate }
18267c478bd9Sstevel@tonic-gate if ((r_stbuf.st_mode & S_IFMT) == S_IFDIR) {
18277c478bd9Sstevel@tonic-gate /*
18287c478bd9Sstevel@tonic-gate * The requested path is a directory, stat(2) it
18297c478bd9Sstevel@tonic-gate * again with a trailing '.' to force the autoFS
18307c478bd9Sstevel@tonic-gate * module to trigger the mount of indirect
18317c478bd9Sstevel@tonic-gate * automount entries, such as /net/jurassic/.
18327c478bd9Sstevel@tonic-gate */
18337c478bd9Sstevel@tonic-gate if (strlen(rpath) + 2 > MAXPATHLEN) {
18347c478bd9Sstevel@tonic-gate if (verbose) {
18357c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE,
1836250a0733Sth "%s/.: exceeds MAXPATHLEN %d",
1837250a0733Sth rpath, MAXPATHLEN);
18387c478bd9Sstevel@tonic-gate }
18397c478bd9Sstevel@tonic-gate goto done;
18407c478bd9Sstevel@tonic-gate }
18417c478bd9Sstevel@tonic-gate (void) strcpy(tmp_path, rpath);
18427c478bd9Sstevel@tonic-gate (void) strcat(tmp_path, "/.");
18437c478bd9Sstevel@tonic-gate
18447c478bd9Sstevel@tonic-gate if (stat(tmp_path, &r_stbuf) < 0) {
18457c478bd9Sstevel@tonic-gate if (verbose)
18467c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE, "%s: %m", tmp_path);
18477c478bd9Sstevel@tonic-gate goto done;
18487c478bd9Sstevel@tonic-gate }
18497c478bd9Sstevel@tonic-gate }
18504a508a79SThomas Haynes
18517c478bd9Sstevel@tonic-gate /*
18527c478bd9Sstevel@tonic-gate * The mount has been triggered, re-read mnttab to pick up
18537c478bd9Sstevel@tonic-gate * the changes made by autoFS.
18547c478bd9Sstevel@tonic-gate */
18557c478bd9Sstevel@tonic-gate fsfreemntlist(mntl);
18567c478bd9Sstevel@tonic-gate (void) mutex_lock(&mnttab_lock);
18577c478bd9Sstevel@tonic-gate mntl = fsgetmntlist();
18587c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mnttab_lock);
18597c478bd9Sstevel@tonic-gate }
18607c478bd9Sstevel@tonic-gate
18617c478bd9Sstevel@tonic-gate /*
18627c478bd9Sstevel@tonic-gate * The autoFS mountpoint has been triggered if necessary,
18637c478bd9Sstevel@tonic-gate * now search mnttab again to determine if the requested path
18647c478bd9Sstevel@tonic-gate * is an LOFS mount of a shared path.
18657c478bd9Sstevel@tonic-gate */
18667c478bd9Sstevel@tonic-gate mntpnt_len = 0;
18677c478bd9Sstevel@tonic-gate for (ml = mntl; ml; ml = ml->mntl_next) {
18687c478bd9Sstevel@tonic-gate if (strcmp(ml->mntl_mnt->mnt_fstype, "lofs"))
18697c478bd9Sstevel@tonic-gate continue;
18707c478bd9Sstevel@tonic-gate
18717c478bd9Sstevel@tonic-gate for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath;
1872250a0733Sth *p1 == *p2 && *p1; p1++, p2++)
1873250a0733Sth ;
18747c478bd9Sstevel@tonic-gate
18757c478bd9Sstevel@tonic-gate if (is_substring(&p1, &p2) &&
18767c478bd9Sstevel@tonic-gate ((tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len)) {
18777c478bd9Sstevel@tonic-gate mntpnt_len = tmp;
18787c478bd9Sstevel@tonic-gate
18797c478bd9Sstevel@tonic-gate if ((strlen(ml->mntl_mnt->mnt_special) + strlen(p2)) >
18807c478bd9Sstevel@tonic-gate MAXPATHLEN) {
18817c478bd9Sstevel@tonic-gate if (verbose) {
18827c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE, "%s%s: exceeds %d",
1883250a0733Sth ml->mntl_mnt->mnt_special, p2,
1884250a0733Sth MAXPATHLEN);
18857c478bd9Sstevel@tonic-gate }
18867c478bd9Sstevel@tonic-gate if (retcode)
18877c478bd9Sstevel@tonic-gate sharefree(retcode);
18887c478bd9Sstevel@tonic-gate retcode = NULL;
18897c478bd9Sstevel@tonic-gate goto done;
18907c478bd9Sstevel@tonic-gate }
18917c478bd9Sstevel@tonic-gate
18927c478bd9Sstevel@tonic-gate (void) strcpy(tmp_path, ml->mntl_mnt->mnt_special);
18937c478bd9Sstevel@tonic-gate (void) strcat(tmp_path, p2);
18947c478bd9Sstevel@tonic-gate if (retcode)
18957c478bd9Sstevel@tonic-gate sharefree(retcode);
18967c478bd9Sstevel@tonic-gate retcode = findentry(tmp_path);
18977c478bd9Sstevel@tonic-gate }
18987c478bd9Sstevel@tonic-gate }
18997c478bd9Sstevel@tonic-gate
19007c478bd9Sstevel@tonic-gate if (retcode) {
19017c478bd9Sstevel@tonic-gate assert(strlen(tmp_path) > 0);
19027c478bd9Sstevel@tonic-gate (void) strcpy(rpath, tmp_path);
19037c478bd9Sstevel@tonic-gate }
19047c478bd9Sstevel@tonic-gate
19057c478bd9Sstevel@tonic-gate done:
19067c478bd9Sstevel@tonic-gate fsfreemntlist(mntl);
19077c478bd9Sstevel@tonic-gate return (retcode);
19087c478bd9Sstevel@tonic-gate }
19097c478bd9Sstevel@tonic-gate
19107c478bd9Sstevel@tonic-gate /*
19117c478bd9Sstevel@tonic-gate * Determine whether an access list grants rights to a particular host.
19127c478bd9Sstevel@tonic-gate * We match on aliases of the hostname as well as on the canonical name.
19137c478bd9Sstevel@tonic-gate * Names in the access list may be either hosts or netgroups; they're
19147c478bd9Sstevel@tonic-gate * not distinguished syntactically. We check for hosts first because
19159b241b4eSYuri Pankov * it's cheaper, then try netgroups.
1916d34083bdSJan Kryl *
1917a9685eaaSMarcel Telka * Return values:
1918a9685eaaSMarcel Telka * 1 - access is granted
1919a9685eaaSMarcel Telka * 0 - access is denied
1920a9685eaaSMarcel Telka * -1 - an error occured
19217c478bd9Sstevel@tonic-gate */
192211606941Sjwahlig int
in_access_list(struct cln * cln,char * access_list)1923a9685eaaSMarcel Telka in_access_list(struct cln *cln,
19247c478bd9Sstevel@tonic-gate char *access_list) /* N.B. we clobber this "input" parameter */
19257c478bd9Sstevel@tonic-gate {
19269b241b4eSYuri Pankov char addr[INET_ADDRSTRLEN];
19279b241b4eSYuri Pankov char buff[256];
19289b241b4eSYuri Pankov int nentries = 0;
19299b241b4eSYuri Pankov char *cstr = access_list;
19309b241b4eSYuri Pankov char *gr = access_list;
19317c478bd9Sstevel@tonic-gate int i;
19327c478bd9Sstevel@tonic-gate int response;
193303b59f78SYuri Pankov int ret;
1934a9685eaaSMarcel Telka struct netbuf *pnb;
1935a9685eaaSMarcel Telka struct nd_hostservlist *clnames = NULL;
19364a508a79SThomas Haynes
19379b241b4eSYuri Pankov /* If no access list - then it's unrestricted */
19387c478bd9Sstevel@tonic-gate if (access_list == NULL || *access_list == '\0')
19397c478bd9Sstevel@tonic-gate return (1);
19407c478bd9Sstevel@tonic-gate
1941a9685eaaSMarcel Telka if ((pnb = cln_getnbuf(cln)) == NULL)
1942a9685eaaSMarcel Telka return (-1);
19437c478bd9Sstevel@tonic-gate
19449b241b4eSYuri Pankov for (;;) {
1945a9685eaaSMarcel Telka if ((cstr = strpbrk(cstr, "[:")) != NULL) {
1946a9685eaaSMarcel Telka if (*cstr == ':') {
1947a9685eaaSMarcel Telka *cstr = '\0';
1948a9685eaaSMarcel Telka } else {
1949a9685eaaSMarcel Telka assert(*cstr == '[');
1950a9685eaaSMarcel Telka cstr = strchr(cstr + 1, ']');
1951a9685eaaSMarcel Telka if (cstr == NULL)
1952a9685eaaSMarcel Telka return (-1);
19539b241b4eSYuri Pankov cstr++;
19549b241b4eSYuri Pankov continue;
19559b241b4eSYuri Pankov }
19569b241b4eSYuri Pankov }
19577c478bd9Sstevel@tonic-gate
19587c478bd9Sstevel@tonic-gate /*
19599b241b4eSYuri Pankov * If the list name has a '-' prepended then a match of
19609b241b4eSYuri Pankov * the following name implies failure instead of success.
19617c478bd9Sstevel@tonic-gate */
19627c478bd9Sstevel@tonic-gate if (*gr == '-') {
19637c478bd9Sstevel@tonic-gate response = 0;
19647c478bd9Sstevel@tonic-gate gr++;
19659b241b4eSYuri Pankov } else {
19667c478bd9Sstevel@tonic-gate response = 1;
19679b241b4eSYuri Pankov }
19687c478bd9Sstevel@tonic-gate
19694a508a79SThomas Haynes /*
19709b241b4eSYuri Pankov * First check if we have '@' entry, as it doesn't
19719b241b4eSYuri Pankov * require client hostname.
19724a508a79SThomas Haynes */
19734a508a79SThomas Haynes if (*gr == '@') {
19749b241b4eSYuri Pankov gr++;
19759b241b4eSYuri Pankov
19769b241b4eSYuri Pankov /* Netname support */
19779b241b4eSYuri Pankov if (!isdigit(*gr) && *gr != '[') {
1978a9685eaaSMarcel Telka struct netent n, *np;
1979a9685eaaSMarcel Telka
19809b241b4eSYuri Pankov if ((np = getnetbyname_r(gr, &n, buff,
19819b241b4eSYuri Pankov sizeof (buff))) != NULL &&
19829b241b4eSYuri Pankov np->n_net != 0) {
19839b241b4eSYuri Pankov while ((np->n_net & 0xFF000000u) == 0)
19849b241b4eSYuri Pankov np->n_net <<= 8;
19859b241b4eSYuri Pankov np->n_net = htonl(np->n_net);
19869b241b4eSYuri Pankov if (inet_ntop(AF_INET, &np->n_net, addr,
19879b241b4eSYuri Pankov INET_ADDRSTRLEN) == NULL)
19889b241b4eSYuri Pankov break;
198903b59f78SYuri Pankov ret = inet_matchaddr(pnb->buf, addr);
199003b59f78SYuri Pankov if (ret == -1) {
199103b59f78SYuri Pankov if (errno == EINVAL) {
199203b59f78SYuri Pankov syslog(LOG_WARNING,
199303b59f78SYuri Pankov "invalid access "
199403b59f78SYuri Pankov "list entry: %s",
199503b59f78SYuri Pankov addr);
199603b59f78SYuri Pankov }
199703b59f78SYuri Pankov return (-1);
199803b59f78SYuri Pankov } else if (ret == 1) {
19999b241b4eSYuri Pankov return (response);
200003b59f78SYuri Pankov }
20019b241b4eSYuri Pankov }
20029b241b4eSYuri Pankov } else {
200303b59f78SYuri Pankov ret = inet_matchaddr(pnb->buf, gr);
200403b59f78SYuri Pankov if (ret == -1) {
200503b59f78SYuri Pankov if (errno == EINVAL) {
200603b59f78SYuri Pankov syslog(LOG_WARNING,
200703b59f78SYuri Pankov "invalid access list "
200803b59f78SYuri Pankov "entry: %s", gr);
200903b59f78SYuri Pankov }
201003b59f78SYuri Pankov return (-1);
201103b59f78SYuri Pankov } else if (ret == 1) {
20129b241b4eSYuri Pankov return (response);
201303b59f78SYuri Pankov }
2014d34083bdSJan Kryl }
2015d34083bdSJan Kryl
2016a9685eaaSMarcel Telka goto next;
20174a508a79SThomas Haynes }
20184a508a79SThomas Haynes
20194a508a79SThomas Haynes /*
20209b241b4eSYuri Pankov * No other checks can be performed if client address
20219b241b4eSYuri Pankov * can't be resolved.
20224a508a79SThomas Haynes */
2023a9685eaaSMarcel Telka if ((clnames = cln_getclientsnames(cln)) == NULL)
2024a9685eaaSMarcel Telka goto next;
20259b241b4eSYuri Pankov
20269b241b4eSYuri Pankov /* Otherwise loop through all client hostname aliases */
20277c478bd9Sstevel@tonic-gate for (i = 0; i < clnames->h_cnt; i++) {
2028a9685eaaSMarcel Telka char *host = clnames->h_hostservs[i].h_host;
20297c478bd9Sstevel@tonic-gate
20307c478bd9Sstevel@tonic-gate /*
20317c478bd9Sstevel@tonic-gate * If the list name begins with a dot then
20327c478bd9Sstevel@tonic-gate * do a domain name suffix comparison.
20337c478bd9Sstevel@tonic-gate * A single dot matches any name with no
20347c478bd9Sstevel@tonic-gate * suffix.
20357c478bd9Sstevel@tonic-gate */
20367c478bd9Sstevel@tonic-gate if (*gr == '.') {
20377c478bd9Sstevel@tonic-gate if (*(gr + 1) == '\0') { /* single dot */
20387c478bd9Sstevel@tonic-gate if (strchr(host, '.') == NULL)
20397c478bd9Sstevel@tonic-gate return (response);
20407c478bd9Sstevel@tonic-gate } else {
2041a9685eaaSMarcel Telka int off = strlen(host) - strlen(gr);
20427c478bd9Sstevel@tonic-gate if (off > 0 &&
20437c478bd9Sstevel@tonic-gate strcasecmp(host + off, gr) == 0) {
20447c478bd9Sstevel@tonic-gate return (response);
20457c478bd9Sstevel@tonic-gate }
20467c478bd9Sstevel@tonic-gate }
20479b241b4eSYuri Pankov } else {
20489b241b4eSYuri Pankov /* Just do a hostname match */
20499b241b4eSYuri Pankov if (strcasecmp(gr, host) == 0)
20509b241b4eSYuri Pankov return (response);
20517c478bd9Sstevel@tonic-gate }
20527c478bd9Sstevel@tonic-gate }
20537c478bd9Sstevel@tonic-gate
20547c478bd9Sstevel@tonic-gate nentries++;
20557c478bd9Sstevel@tonic-gate
2056a9685eaaSMarcel Telka next:
20579b241b4eSYuri Pankov if (cstr == NULL)
20589b241b4eSYuri Pankov break;
20597c478bd9Sstevel@tonic-gate
20609b241b4eSYuri Pankov gr = ++cstr;
20617c478bd9Sstevel@tonic-gate }
20627c478bd9Sstevel@tonic-gate
20639b241b4eSYuri Pankov if (clnames == NULL)
20649b241b4eSYuri Pankov return (0);
20657c478bd9Sstevel@tonic-gate
20669b241b4eSYuri Pankov return (netgroup_check(clnames, access_list, nentries));
20677c478bd9Sstevel@tonic-gate }
20687c478bd9Sstevel@tonic-gate
20697c478bd9Sstevel@tonic-gate
20707c478bd9Sstevel@tonic-gate static char *optlist[] = {
20717c478bd9Sstevel@tonic-gate #define OPT_RO 0
20727c478bd9Sstevel@tonic-gate SHOPT_RO,
20737c478bd9Sstevel@tonic-gate #define OPT_RW 1
20747c478bd9Sstevel@tonic-gate SHOPT_RW,
20757c478bd9Sstevel@tonic-gate #define OPT_ROOT 2
20767c478bd9Sstevel@tonic-gate SHOPT_ROOT,
20777c478bd9Sstevel@tonic-gate #define OPT_SECURE 3
20787c478bd9Sstevel@tonic-gate SHOPT_SECURE,
20797c478bd9Sstevel@tonic-gate #define OPT_ANON 4
20807c478bd9Sstevel@tonic-gate SHOPT_ANON,
20817c478bd9Sstevel@tonic-gate #define OPT_WINDOW 5
20827c478bd9Sstevel@tonic-gate SHOPT_WINDOW,
20837c478bd9Sstevel@tonic-gate #define OPT_NOSUID 6
20847c478bd9Sstevel@tonic-gate SHOPT_NOSUID,
20857c478bd9Sstevel@tonic-gate #define OPT_ACLOK 7
20867c478bd9Sstevel@tonic-gate SHOPT_ACLOK,
20877c478bd9Sstevel@tonic-gate #define OPT_SEC 8
20887c478bd9Sstevel@tonic-gate SHOPT_SEC,
2089b89a8333Snatalie li - Sun Microsystems - Irvine United States #define OPT_NONE 9
2090b89a8333Snatalie li - Sun Microsystems - Irvine United States SHOPT_NONE,
20915cb0d679SMarcel Telka #define OPT_UIDMAP 10
20925cb0d679SMarcel Telka SHOPT_UIDMAP,
20935cb0d679SMarcel Telka #define OPT_GIDMAP 11
20945cb0d679SMarcel Telka SHOPT_GIDMAP,
20957c478bd9Sstevel@tonic-gate NULL
20967c478bd9Sstevel@tonic-gate };
20977c478bd9Sstevel@tonic-gate
20987c478bd9Sstevel@tonic-gate static int
map_flavor(char * str)20997c478bd9Sstevel@tonic-gate map_flavor(char *str)
21007c478bd9Sstevel@tonic-gate {
21017c478bd9Sstevel@tonic-gate seconfig_t sec;
21027c478bd9Sstevel@tonic-gate
21037c478bd9Sstevel@tonic-gate if (nfs_getseconfig_byname(str, &sec))
21047c478bd9Sstevel@tonic-gate return (-1);
21057c478bd9Sstevel@tonic-gate
21067c478bd9Sstevel@tonic-gate return (sec.sc_nfsnum);
21077c478bd9Sstevel@tonic-gate }
21087c478bd9Sstevel@tonic-gate
21097c478bd9Sstevel@tonic-gate /*
21107c478bd9Sstevel@tonic-gate * If the option string contains a "sec="
21117c478bd9Sstevel@tonic-gate * option, then use new option syntax.
21127c478bd9Sstevel@tonic-gate */
21137c478bd9Sstevel@tonic-gate static int
newopts(char * opts)21147c478bd9Sstevel@tonic-gate newopts(char *opts)
21157c478bd9Sstevel@tonic-gate {
21167c478bd9Sstevel@tonic-gate char *head, *p, *val;
21177c478bd9Sstevel@tonic-gate
21187c478bd9Sstevel@tonic-gate if (!opts || *opts == '\0')
21197c478bd9Sstevel@tonic-gate return (0);
21207c478bd9Sstevel@tonic-gate
21217c478bd9Sstevel@tonic-gate head = strdup(opts);
21227c478bd9Sstevel@tonic-gate if (head == NULL) {
21237c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "opts: no memory");
21247c478bd9Sstevel@tonic-gate return (0);
21257c478bd9Sstevel@tonic-gate }
21267c478bd9Sstevel@tonic-gate
21277c478bd9Sstevel@tonic-gate p = head;
21287c478bd9Sstevel@tonic-gate while (*p) {
21297c478bd9Sstevel@tonic-gate if (getsubopt(&p, optlist, &val) == OPT_SEC) {
21307c478bd9Sstevel@tonic-gate free(head);
21317c478bd9Sstevel@tonic-gate return (1);
21327c478bd9Sstevel@tonic-gate }
21337c478bd9Sstevel@tonic-gate }
21347c478bd9Sstevel@tonic-gate
21357c478bd9Sstevel@tonic-gate free(head);
21367c478bd9Sstevel@tonic-gate return (0);
21377c478bd9Sstevel@tonic-gate }
21387c478bd9Sstevel@tonic-gate
21397c478bd9Sstevel@tonic-gate /*
21407c478bd9Sstevel@tonic-gate * Given an export and the clients hostname(s)
21417c478bd9Sstevel@tonic-gate * determine the security flavors that this
21427c478bd9Sstevel@tonic-gate * client is permitted to use.
21437c478bd9Sstevel@tonic-gate *
21447c478bd9Sstevel@tonic-gate * This routine is called only for "old" syntax, i.e.
21457c478bd9Sstevel@tonic-gate * only one security flavor is allowed. So we need
21467c478bd9Sstevel@tonic-gate * to determine two things: the particular flavor,
21477c478bd9Sstevel@tonic-gate * and whether the client is allowed to use this
21487c478bd9Sstevel@tonic-gate * flavor, i.e. is in the access list.
21497c478bd9Sstevel@tonic-gate *
21507c478bd9Sstevel@tonic-gate * Note that if there is no access list, then the
21517c478bd9Sstevel@tonic-gate * default is that access is granted.
21527c478bd9Sstevel@tonic-gate */
21537c478bd9Sstevel@tonic-gate static int
getclientsflavors_old(share_t * sh,struct cln * cln,int * flavors)2154a9685eaaSMarcel Telka getclientsflavors_old(share_t *sh, struct cln *cln, int *flavors)
21557c478bd9Sstevel@tonic-gate {
21567c478bd9Sstevel@tonic-gate char *opts, *p, *val;
2157b89a8333Snatalie li - Sun Microsystems - Irvine United States boolean_t ok = B_FALSE;
21587c478bd9Sstevel@tonic-gate int defaultaccess = 1;
2159b89a8333Snatalie li - Sun Microsystems - Irvine United States boolean_t reject = B_FALSE;
21607c478bd9Sstevel@tonic-gate
21617c478bd9Sstevel@tonic-gate opts = strdup(sh->sh_opts);
21627c478bd9Sstevel@tonic-gate if (opts == NULL) {
21637c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "getclientsflavors: no memory");
21647c478bd9Sstevel@tonic-gate return (0);
21657c478bd9Sstevel@tonic-gate }
21667c478bd9Sstevel@tonic-gate
21677c478bd9Sstevel@tonic-gate flavors[0] = AUTH_SYS;
21687c478bd9Sstevel@tonic-gate p = opts;
21697c478bd9Sstevel@tonic-gate
21707c478bd9Sstevel@tonic-gate while (*p) {
21717c478bd9Sstevel@tonic-gate
21727c478bd9Sstevel@tonic-gate switch (getsubopt(&p, optlist, &val)) {
21737c478bd9Sstevel@tonic-gate case OPT_SECURE:
21747c478bd9Sstevel@tonic-gate flavors[0] = AUTH_DES;
21757c478bd9Sstevel@tonic-gate break;
21767c478bd9Sstevel@tonic-gate
21777c478bd9Sstevel@tonic-gate case OPT_RO:
21787c478bd9Sstevel@tonic-gate case OPT_RW:
21797c478bd9Sstevel@tonic-gate defaultaccess = 0;
2180a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0)
2181a9685eaaSMarcel Telka ok = B_TRUE;
21827c478bd9Sstevel@tonic-gate break;
2183b89a8333Snatalie li - Sun Microsystems - Irvine United States
2184b89a8333Snatalie li - Sun Microsystems - Irvine United States case OPT_NONE:
2185b89a8333Snatalie li - Sun Microsystems - Irvine United States defaultaccess = 0;
2186a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0)
2187b89a8333Snatalie li - Sun Microsystems - Irvine United States reject = B_TRUE;
21887c478bd9Sstevel@tonic-gate }
21897c478bd9Sstevel@tonic-gate }
21907c478bd9Sstevel@tonic-gate
21917c478bd9Sstevel@tonic-gate free(opts);
21927c478bd9Sstevel@tonic-gate
2193b89a8333Snatalie li - Sun Microsystems - Irvine United States /* none takes precedence over everything else */
2194b89a8333Snatalie li - Sun Microsystems - Irvine United States if (reject)
2195a9685eaaSMarcel Telka ok = B_FALSE;
2196b89a8333Snatalie li - Sun Microsystems - Irvine United States
21977c478bd9Sstevel@tonic-gate return (defaultaccess || ok);
21987c478bd9Sstevel@tonic-gate }
21997c478bd9Sstevel@tonic-gate
22007c478bd9Sstevel@tonic-gate /*
22017c478bd9Sstevel@tonic-gate * Given an export and the clients hostname(s)
22027c478bd9Sstevel@tonic-gate * determine the security flavors that this
22037c478bd9Sstevel@tonic-gate * client is permitted to use.
22047c478bd9Sstevel@tonic-gate *
22057c478bd9Sstevel@tonic-gate * This is somewhat more complicated than the "old"
22067c478bd9Sstevel@tonic-gate * routine because the options may contain multiple
22077c478bd9Sstevel@tonic-gate * security flavors (sec=) each with its own access
22087c478bd9Sstevel@tonic-gate * lists. So a client could be granted access based
22097c478bd9Sstevel@tonic-gate * on a number of security flavors. Note that the
22107c478bd9Sstevel@tonic-gate * type of access might not always be the same, the
22117c478bd9Sstevel@tonic-gate * client may get readonly access with one flavor
22127c478bd9Sstevel@tonic-gate * and readwrite with another, however the client
22137c478bd9Sstevel@tonic-gate * is not told this detail, it gets only the list
22147c478bd9Sstevel@tonic-gate * of flavors, and only if the client is using
22157c478bd9Sstevel@tonic-gate * version 3 of the mount protocol.
22167c478bd9Sstevel@tonic-gate */
22177c478bd9Sstevel@tonic-gate static int
getclientsflavors_new(share_t * sh,struct cln * cln,int * flavors)2218a9685eaaSMarcel Telka getclientsflavors_new(share_t *sh, struct cln *cln, int *flavors)
22197c478bd9Sstevel@tonic-gate {
22207c478bd9Sstevel@tonic-gate char *opts, *p, *val;
22217c478bd9Sstevel@tonic-gate char *lasts;
22227c478bd9Sstevel@tonic-gate char *f;
2223a9685eaaSMarcel Telka boolean_t defaultaccess = B_TRUE; /* default access is rw */
2224a9685eaaSMarcel Telka boolean_t access_ok = B_FALSE;
2225cf7e209dSIgor Kozhukhov int count, c;
2226b89a8333Snatalie li - Sun Microsystems - Irvine United States boolean_t reject = B_FALSE;
22277c478bd9Sstevel@tonic-gate
22287c478bd9Sstevel@tonic-gate opts = strdup(sh->sh_opts);
22297c478bd9Sstevel@tonic-gate if (opts == NULL) {
22307c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "getclientsflavors: no memory");
22317c478bd9Sstevel@tonic-gate return (0);
22327c478bd9Sstevel@tonic-gate }
22337c478bd9Sstevel@tonic-gate
22347c478bd9Sstevel@tonic-gate p = opts;
2235cf7e209dSIgor Kozhukhov count = c = 0;
22367c478bd9Sstevel@tonic-gate
22377c478bd9Sstevel@tonic-gate while (*p) {
22387c478bd9Sstevel@tonic-gate switch (getsubopt(&p, optlist, &val)) {
22397c478bd9Sstevel@tonic-gate case OPT_SEC:
2240a9685eaaSMarcel Telka if (reject)
2241a9685eaaSMarcel Telka access_ok = B_FALSE;
2242a9685eaaSMarcel Telka
22437c478bd9Sstevel@tonic-gate /*
22447c478bd9Sstevel@tonic-gate * Before a new sec=xxx option, check if we need
22457c478bd9Sstevel@tonic-gate * to move the c index back to the previous count.
22467c478bd9Sstevel@tonic-gate */
2247a9685eaaSMarcel Telka if (!defaultaccess && !access_ok) {
22487c478bd9Sstevel@tonic-gate c = count;
22497c478bd9Sstevel@tonic-gate }
22507c478bd9Sstevel@tonic-gate
22517c478bd9Sstevel@tonic-gate /* get all the sec=f1[:f2] flavors */
2252a9685eaaSMarcel Telka while ((f = strtok_r(val, ":", &lasts)) != NULL) {
22537c478bd9Sstevel@tonic-gate flavors[c++] = map_flavor(f);
22547c478bd9Sstevel@tonic-gate val = NULL;
22557c478bd9Sstevel@tonic-gate }
22564a508a79SThomas Haynes
22577c478bd9Sstevel@tonic-gate /* for a new sec=xxx option, default is rw access */
2258a9685eaaSMarcel Telka defaultaccess = B_TRUE;
2259a9685eaaSMarcel Telka access_ok = B_FALSE;
2260a9685eaaSMarcel Telka reject = B_FALSE;
22617c478bd9Sstevel@tonic-gate break;
22627c478bd9Sstevel@tonic-gate
22637c478bd9Sstevel@tonic-gate case OPT_RO:
22647c478bd9Sstevel@tonic-gate case OPT_RW:
2265a9685eaaSMarcel Telka defaultaccess = B_FALSE;
2266a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0)
2267b89a8333Snatalie li - Sun Microsystems - Irvine United States access_ok = B_TRUE;
22687c478bd9Sstevel@tonic-gate break;
2269b89a8333Snatalie li - Sun Microsystems - Irvine United States
2270b89a8333Snatalie li - Sun Microsystems - Irvine United States case OPT_NONE:
2271a9685eaaSMarcel Telka defaultaccess = B_FALSE;
2272a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0)
2273b89a8333Snatalie li - Sun Microsystems - Irvine United States reject = B_TRUE; /* none overides rw/ro */
2274b89a8333Snatalie li - Sun Microsystems - Irvine United States break;
22757c478bd9Sstevel@tonic-gate }
22767c478bd9Sstevel@tonic-gate }
22777c478bd9Sstevel@tonic-gate
2278b89a8333Snatalie li - Sun Microsystems - Irvine United States if (reject)
2279b89a8333Snatalie li - Sun Microsystems - Irvine United States access_ok = B_FALSE;
2280b89a8333Snatalie li - Sun Microsystems - Irvine United States
2281a9685eaaSMarcel Telka if (!defaultaccess && !access_ok)
22827c478bd9Sstevel@tonic-gate c = count;
2283b89a8333Snatalie li - Sun Microsystems - Irvine United States
22847c478bd9Sstevel@tonic-gate free(opts);
22857c478bd9Sstevel@tonic-gate
22867c478bd9Sstevel@tonic-gate return (c);
22877c478bd9Sstevel@tonic-gate }
22887c478bd9Sstevel@tonic-gate
22897c478bd9Sstevel@tonic-gate /*
22907c478bd9Sstevel@tonic-gate * This is a tricky piece of code that parses the
22917c478bd9Sstevel@tonic-gate * share options looking for a match on the auth
22927c478bd9Sstevel@tonic-gate * flavor that the client is using. If it finds
22937c478bd9Sstevel@tonic-gate * a match, then the client is given ro, rw, or
22947c478bd9Sstevel@tonic-gate * no access depending whether it is in the access
22957c478bd9Sstevel@tonic-gate * list. There is a special case for "secure"
22967c478bd9Sstevel@tonic-gate * flavor. Other flavors are values of the new "sec=" option.
22977c478bd9Sstevel@tonic-gate */
22987c478bd9Sstevel@tonic-gate int
check_client(share_t * sh,struct cln * cln,int flavor,uid_t clnt_uid,gid_t clnt_gid,uint_t clnt_ngids,gid_t * clnt_gids,uid_t * srv_uid,gid_t * srv_gid,uint_t * srv_ngids,gid_t ** srv_gids)2299a9685eaaSMarcel Telka check_client(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid,
2300a9685eaaSMarcel Telka gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid,
2301a9685eaaSMarcel Telka gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids)
23027c478bd9Sstevel@tonic-gate {
23037c478bd9Sstevel@tonic-gate if (newopts(sh->sh_opts))
2304a9685eaaSMarcel Telka return (check_client_new(sh, cln, flavor, clnt_uid, clnt_gid,
2305a9685eaaSMarcel Telka clnt_ngids, clnt_gids, srv_uid, srv_gid, srv_ngids,
2306a9685eaaSMarcel Telka srv_gids));
23077c478bd9Sstevel@tonic-gate else
2308a9685eaaSMarcel Telka return (check_client_old(sh, cln, flavor, clnt_uid, clnt_gid,
2309a9685eaaSMarcel Telka clnt_ngids, clnt_gids, srv_uid, srv_gid, srv_ngids,
2310a9685eaaSMarcel Telka srv_gids));
231189621fe1SMarcel Telka }
231289621fe1SMarcel Telka
231389621fe1SMarcel Telka extern int _getgroupsbymember(const char *, gid_t[], int, int);
231489621fe1SMarcel Telka
231589621fe1SMarcel Telka /*
231689621fe1SMarcel Telka * Get supplemental groups for uid
231789621fe1SMarcel Telka */
231889621fe1SMarcel Telka static int
getusergroups(uid_t uid,uint_t * ngrps,gid_t ** grps)231989621fe1SMarcel Telka getusergroups(uid_t uid, uint_t *ngrps, gid_t **grps)
232089621fe1SMarcel Telka {
232189621fe1SMarcel Telka struct passwd pwd;
232289621fe1SMarcel Telka char *pwbuf = alloca(pw_size);
232389621fe1SMarcel Telka gid_t *tmpgrps = alloca(ngroups_max * sizeof (gid_t));
232489621fe1SMarcel Telka int tmpngrps;
232589621fe1SMarcel Telka
232689621fe1SMarcel Telka if (getpwuid_r(uid, &pwd, pwbuf, pw_size) == NULL)
232789621fe1SMarcel Telka return (-1);
232889621fe1SMarcel Telka
232989621fe1SMarcel Telka tmpgrps[0] = pwd.pw_gid;
233089621fe1SMarcel Telka
233189621fe1SMarcel Telka tmpngrps = _getgroupsbymember(pwd.pw_name, tmpgrps, ngroups_max, 1);
233289621fe1SMarcel Telka if (tmpngrps <= 0) {
233389621fe1SMarcel Telka syslog(LOG_WARNING,
233489621fe1SMarcel Telka "getusergroups(): Unable to get groups for user %s",
233589621fe1SMarcel Telka pwd.pw_name);
233689621fe1SMarcel Telka
233789621fe1SMarcel Telka return (-1);
233889621fe1SMarcel Telka }
233989621fe1SMarcel Telka
234089621fe1SMarcel Telka *grps = malloc(tmpngrps * sizeof (gid_t));
234189621fe1SMarcel Telka if (*grps == NULL) {
234289621fe1SMarcel Telka syslog(LOG_ERR,
234389621fe1SMarcel Telka "getusergroups(): Memory allocation failed: %m");
234489621fe1SMarcel Telka
234589621fe1SMarcel Telka return (-1);
234689621fe1SMarcel Telka }
234789621fe1SMarcel Telka
234889621fe1SMarcel Telka *ngrps = tmpngrps;
234989621fe1SMarcel Telka (void) memcpy(*grps, tmpgrps, tmpngrps * sizeof (gid_t));
235089621fe1SMarcel Telka
235189621fe1SMarcel Telka return (0);
23525cb0d679SMarcel Telka }
23535cb0d679SMarcel Telka
23545cb0d679SMarcel Telka /*
23555cb0d679SMarcel Telka * is_a_number(number)
23565cb0d679SMarcel Telka *
23575cb0d679SMarcel Telka * is the string a number in one of the forms we want to use?
23585cb0d679SMarcel Telka */
23595cb0d679SMarcel Telka
23605cb0d679SMarcel Telka static int
is_a_number(char * number)23615cb0d679SMarcel Telka is_a_number(char *number)
23625cb0d679SMarcel Telka {
23635cb0d679SMarcel Telka int ret = 1;
23645cb0d679SMarcel Telka int hex = 0;
23655cb0d679SMarcel Telka
23665cb0d679SMarcel Telka if (strncmp(number, "0x", 2) == 0) {
23675cb0d679SMarcel Telka number += 2;
23685cb0d679SMarcel Telka hex = 1;
23695cb0d679SMarcel Telka } else if (*number == '-') {
23705cb0d679SMarcel Telka number++; /* skip the minus */
23715cb0d679SMarcel Telka }
23725cb0d679SMarcel Telka while (ret == 1 && *number != '\0') {
23735cb0d679SMarcel Telka if (hex) {
23745cb0d679SMarcel Telka ret = isxdigit(*number++);
23755cb0d679SMarcel Telka } else {
23765cb0d679SMarcel Telka ret = isdigit(*number++);
23775cb0d679SMarcel Telka }
23785cb0d679SMarcel Telka }
23795cb0d679SMarcel Telka return (ret);
23805cb0d679SMarcel Telka }
23815cb0d679SMarcel Telka
23825cb0d679SMarcel Telka static boolean_t
get_uid(char * value,uid_t * uid)23835cb0d679SMarcel Telka get_uid(char *value, uid_t *uid)
23845cb0d679SMarcel Telka {
23855cb0d679SMarcel Telka if (!is_a_number(value)) {
23865cb0d679SMarcel Telka struct passwd *pw;
23875cb0d679SMarcel Telka /*
23885cb0d679SMarcel Telka * in this case it would have to be a
23895cb0d679SMarcel Telka * user name
23905cb0d679SMarcel Telka */
23915cb0d679SMarcel Telka pw = getpwnam(value);
23925cb0d679SMarcel Telka if (pw == NULL)
23935cb0d679SMarcel Telka return (B_FALSE);
23945cb0d679SMarcel Telka *uid = pw->pw_uid;
23955cb0d679SMarcel Telka endpwent();
23965cb0d679SMarcel Telka } else {
23975cb0d679SMarcel Telka uint64_t intval;
23985cb0d679SMarcel Telka intval = strtoull(value, NULL, 0);
23995cb0d679SMarcel Telka if (intval > UID_MAX && intval != -1)
24005cb0d679SMarcel Telka return (B_FALSE);
24015cb0d679SMarcel Telka *uid = (uid_t)intval;
24025cb0d679SMarcel Telka }
24035cb0d679SMarcel Telka
24045cb0d679SMarcel Telka return (B_TRUE);
24055cb0d679SMarcel Telka }
24065cb0d679SMarcel Telka
24075cb0d679SMarcel Telka static boolean_t
get_gid(char * value,gid_t * gid)24085cb0d679SMarcel Telka get_gid(char *value, gid_t *gid)
24095cb0d679SMarcel Telka {
24105cb0d679SMarcel Telka if (!is_a_number(value)) {
24115cb0d679SMarcel Telka struct group *gr;
24125cb0d679SMarcel Telka /*
24135cb0d679SMarcel Telka * in this case it would have to be a
24145cb0d679SMarcel Telka * group name
24155cb0d679SMarcel Telka */
24165cb0d679SMarcel Telka gr = getgrnam(value);
24175cb0d679SMarcel Telka if (gr == NULL)
24185cb0d679SMarcel Telka return (B_FALSE);
24195cb0d679SMarcel Telka *gid = gr->gr_gid;
24205cb0d679SMarcel Telka endgrent();
24215cb0d679SMarcel Telka } else {
24225cb0d679SMarcel Telka uint64_t intval;
24235cb0d679SMarcel Telka intval = strtoull(value, NULL, 0);
24245cb0d679SMarcel Telka if (intval > UID_MAX && intval != -1)
24255cb0d679SMarcel Telka return (B_FALSE);
24265cb0d679SMarcel Telka *gid = (gid_t)intval;
24275cb0d679SMarcel Telka }
24285cb0d679SMarcel Telka
24295cb0d679SMarcel Telka return (B_TRUE);
24307c478bd9Sstevel@tonic-gate }
24317c478bd9Sstevel@tonic-gate
24327c478bd9Sstevel@tonic-gate static int
check_client_old(share_t * sh,struct cln * cln,int flavor,uid_t clnt_uid,gid_t clnt_gid,uint_t clnt_ngids,gid_t * clnt_gids,uid_t * srv_uid,gid_t * srv_gid,uint_t * srv_ngids,gid_t ** srv_gids)2433a9685eaaSMarcel Telka check_client_old(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid,
243489621fe1SMarcel Telka gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid,
243589621fe1SMarcel Telka gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids)
24367c478bd9Sstevel@tonic-gate {
24377c478bd9Sstevel@tonic-gate char *opts, *p, *val;
24387c478bd9Sstevel@tonic-gate int match; /* Set when a flavor is matched */
24397c478bd9Sstevel@tonic-gate int perm = 0; /* Set when "ro", "rw" or "root" is matched */
24407c478bd9Sstevel@tonic-gate int list = 0; /* Set when "ro", "rw" is found */
24417c478bd9Sstevel@tonic-gate int ro_val = 0; /* Set if ro option is 'ro=' */
24427c478bd9Sstevel@tonic-gate int rw_val = 0; /* Set if rw option is 'rw=' */
24435cb0d679SMarcel Telka
24445cb0d679SMarcel Telka boolean_t map_deny = B_FALSE;
24457c478bd9Sstevel@tonic-gate
24467c478bd9Sstevel@tonic-gate opts = strdup(sh->sh_opts);
24477c478bd9Sstevel@tonic-gate if (opts == NULL) {
24487c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "check_client: no memory");
24497c478bd9Sstevel@tonic-gate return (0);
24507c478bd9Sstevel@tonic-gate }
24517c478bd9Sstevel@tonic-gate
245289621fe1SMarcel Telka /*
245389621fe1SMarcel Telka * If client provided 16 supplemental groups with AUTH_SYS, lookup
245489621fe1SMarcel Telka * locally for all of them
245589621fe1SMarcel Telka */
245689621fe1SMarcel Telka if (flavor == AUTH_SYS && clnt_ngids == NGRPS && ngroups_max > NGRPS)
245789621fe1SMarcel Telka if (getusergroups(clnt_uid, srv_ngids, srv_gids) == 0)
245889621fe1SMarcel Telka perm |= NFSAUTH_GROUPS;
245989621fe1SMarcel Telka
24607c478bd9Sstevel@tonic-gate p = opts;
24617c478bd9Sstevel@tonic-gate match = AUTH_UNIX;
24627c478bd9Sstevel@tonic-gate
24637c478bd9Sstevel@tonic-gate while (*p) {
24647c478bd9Sstevel@tonic-gate switch (getsubopt(&p, optlist, &val)) {
24657c478bd9Sstevel@tonic-gate
24667c478bd9Sstevel@tonic-gate case OPT_SECURE:
24677c478bd9Sstevel@tonic-gate match = AUTH_DES;
246889621fe1SMarcel Telka
246989621fe1SMarcel Telka if (perm & NFSAUTH_GROUPS) {
247089621fe1SMarcel Telka free(*srv_gids);
247189621fe1SMarcel Telka *srv_ngids = 0;
247289621fe1SMarcel Telka *srv_gids = NULL;
247389621fe1SMarcel Telka perm &= ~NFSAUTH_GROUPS;
247489621fe1SMarcel Telka }
247589621fe1SMarcel Telka
24767c478bd9Sstevel@tonic-gate break;
24777c478bd9Sstevel@tonic-gate
24787c478bd9Sstevel@tonic-gate case OPT_RO:
24797c478bd9Sstevel@tonic-gate list++;
24805cb0d679SMarcel Telka if (val != NULL)
24815cb0d679SMarcel Telka ro_val++;
2482a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0)
24837c478bd9Sstevel@tonic-gate perm |= NFSAUTH_RO;
24847c478bd9Sstevel@tonic-gate break;
24857c478bd9Sstevel@tonic-gate
24867c478bd9Sstevel@tonic-gate case OPT_RW:
24877c478bd9Sstevel@tonic-gate list++;
24885cb0d679SMarcel Telka if (val != NULL)
24895cb0d679SMarcel Telka rw_val++;
2490a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0)
24917c478bd9Sstevel@tonic-gate perm |= NFSAUTH_RW;
24927c478bd9Sstevel@tonic-gate break;
24937c478bd9Sstevel@tonic-gate
24947c478bd9Sstevel@tonic-gate case OPT_ROOT:
24957c478bd9Sstevel@tonic-gate /*
24967c478bd9Sstevel@tonic-gate * Check if the client is in
24977c478bd9Sstevel@tonic-gate * the root list. Only valid
24987c478bd9Sstevel@tonic-gate * for AUTH_SYS.
24997c478bd9Sstevel@tonic-gate */
25007c478bd9Sstevel@tonic-gate if (flavor != AUTH_SYS)
25017c478bd9Sstevel@tonic-gate break;
25027c478bd9Sstevel@tonic-gate
25037c478bd9Sstevel@tonic-gate if (val == NULL || *val == '\0')
25047c478bd9Sstevel@tonic-gate break;
25057c478bd9Sstevel@tonic-gate
25065cb0d679SMarcel Telka if (clnt_uid != 0)
25075cb0d679SMarcel Telka break;
25085cb0d679SMarcel Telka
2509a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0) {
25107c478bd9Sstevel@tonic-gate perm |= NFSAUTH_ROOT;
25115cb0d679SMarcel Telka perm |= NFSAUTH_UIDMAP | NFSAUTH_GIDMAP;
25125cb0d679SMarcel Telka map_deny = B_FALSE;
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 }
25205cb0d679SMarcel Telka }
25217c478bd9Sstevel@tonic-gate break;
2522b89a8333Snatalie li - Sun Microsystems - Irvine United States
2523b89a8333Snatalie li - Sun Microsystems - Irvine United States case OPT_NONE:
2524b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
252554d34259SMarcel Telka * Check if the client should have no access
2526b89a8333Snatalie li - Sun Microsystems - Irvine United States * to this share at all. This option behaves
2527b89a8333Snatalie li - Sun Microsystems - Irvine United States * more like "root" than either "rw" or "ro".
2528b89a8333Snatalie li - Sun Microsystems - Irvine United States */
2529a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0)
25305cb0d679SMarcel Telka perm |= NFSAUTH_DENIED;
25315cb0d679SMarcel Telka break;
25325cb0d679SMarcel Telka
25335cb0d679SMarcel Telka case OPT_UIDMAP: {
25345cb0d679SMarcel Telka char *c;
25355cb0d679SMarcel Telka char *n;
25365cb0d679SMarcel Telka
25375cb0d679SMarcel Telka /*
25385cb0d679SMarcel Telka * The uidmap is supported for AUTH_SYS only.
25395cb0d679SMarcel Telka */
25405cb0d679SMarcel Telka if (flavor != AUTH_SYS)
25415cb0d679SMarcel Telka break;
25425cb0d679SMarcel Telka
25435cb0d679SMarcel Telka if (perm & NFSAUTH_UIDMAP || map_deny)
25445cb0d679SMarcel Telka break;
25455cb0d679SMarcel Telka
25465cb0d679SMarcel Telka for (c = val; c != NULL; c = n) {
25475cb0d679SMarcel Telka char *s;
25485cb0d679SMarcel Telka char *al;
25495cb0d679SMarcel Telka uid_t srv;
25505cb0d679SMarcel Telka
25515cb0d679SMarcel Telka n = strchr(c, '~');
25525cb0d679SMarcel Telka if (n != NULL)
25535cb0d679SMarcel Telka *n++ = '\0';
25545cb0d679SMarcel Telka
25555cb0d679SMarcel Telka s = strchr(c, ':');
25565cb0d679SMarcel Telka if (s != NULL) {
25575cb0d679SMarcel Telka *s++ = '\0';
25585cb0d679SMarcel Telka al = strchr(s, ':');
25595cb0d679SMarcel Telka if (al != NULL)
25605cb0d679SMarcel Telka *al++ = '\0';
25615cb0d679SMarcel Telka }
25625cb0d679SMarcel Telka
25635cb0d679SMarcel Telka if (s == NULL || al == NULL)
25645cb0d679SMarcel Telka continue;
25655cb0d679SMarcel Telka
25665cb0d679SMarcel Telka if (*c == '\0') {
25675cb0d679SMarcel Telka if (clnt_uid != (uid_t)-1)
25685cb0d679SMarcel Telka continue;
25695cb0d679SMarcel Telka } else if (strcmp(c, "*") != 0) {
25705cb0d679SMarcel Telka uid_t clnt;
25715cb0d679SMarcel Telka
25725cb0d679SMarcel Telka if (!get_uid(c, &clnt))
25735cb0d679SMarcel Telka continue;
25745cb0d679SMarcel Telka
25755cb0d679SMarcel Telka if (clnt_uid != clnt)
25765cb0d679SMarcel Telka continue;
25775cb0d679SMarcel Telka }
25785cb0d679SMarcel Telka
25795cb0d679SMarcel Telka if (*s == '\0')
25805cb0d679SMarcel Telka srv = UID_NOBODY;
25815cb0d679SMarcel Telka else if (!get_uid(s, &srv))
25825cb0d679SMarcel Telka continue;
25835cb0d679SMarcel Telka else if (srv == (uid_t)-1) {
25845cb0d679SMarcel Telka map_deny = B_TRUE;
25855cb0d679SMarcel Telka break;
25865cb0d679SMarcel Telka }
25875cb0d679SMarcel Telka
2588a9685eaaSMarcel Telka if (in_access_list(cln, al) > 0) {
25895cb0d679SMarcel Telka *srv_uid = srv;
25905cb0d679SMarcel Telka perm |= NFSAUTH_UIDMAP;
259189621fe1SMarcel Telka
259289621fe1SMarcel Telka if (perm & NFSAUTH_GROUPS) {
259389621fe1SMarcel Telka free(*srv_gids);
259489621fe1SMarcel Telka *srv_ngids = 0;
259589621fe1SMarcel Telka *srv_gids = NULL;
259689621fe1SMarcel Telka perm &= ~NFSAUTH_GROUPS;
259789621fe1SMarcel Telka }
259889621fe1SMarcel Telka
25995cb0d679SMarcel Telka break;
26005cb0d679SMarcel Telka }
26015cb0d679SMarcel Telka }
26025cb0d679SMarcel Telka
26035cb0d679SMarcel Telka break;
26045cb0d679SMarcel Telka }
26055cb0d679SMarcel Telka
26065cb0d679SMarcel Telka case OPT_GIDMAP: {
26075cb0d679SMarcel Telka char *c;
26085cb0d679SMarcel Telka char *n;
26095cb0d679SMarcel Telka
26105cb0d679SMarcel Telka /*
26115cb0d679SMarcel Telka * The gidmap is supported for AUTH_SYS only.
26125cb0d679SMarcel Telka */
26135cb0d679SMarcel Telka if (flavor != AUTH_SYS)
26145cb0d679SMarcel Telka break;
26155cb0d679SMarcel Telka
26165cb0d679SMarcel Telka if (perm & NFSAUTH_GIDMAP || map_deny)
26175cb0d679SMarcel Telka break;
26185cb0d679SMarcel Telka
26195cb0d679SMarcel Telka for (c = val; c != NULL; c = n) {
26205cb0d679SMarcel Telka char *s;
26215cb0d679SMarcel Telka char *al;
26225cb0d679SMarcel Telka gid_t srv;
26235cb0d679SMarcel Telka
26245cb0d679SMarcel Telka n = strchr(c, '~');
26255cb0d679SMarcel Telka if (n != NULL)
26265cb0d679SMarcel Telka *n++ = '\0';
26275cb0d679SMarcel Telka
26285cb0d679SMarcel Telka s = strchr(c, ':');
26295cb0d679SMarcel Telka if (s != NULL) {
26305cb0d679SMarcel Telka *s++ = '\0';
26315cb0d679SMarcel Telka al = strchr(s, ':');
26325cb0d679SMarcel Telka if (al != NULL)
26335cb0d679SMarcel Telka *al++ = '\0';
26345cb0d679SMarcel Telka }
26355cb0d679SMarcel Telka
26365cb0d679SMarcel Telka if (s == NULL || al == NULL)
26375cb0d679SMarcel Telka break;
26385cb0d679SMarcel Telka
26395cb0d679SMarcel Telka if (*c == '\0') {
26405cb0d679SMarcel Telka if (clnt_gid != (gid_t)-1)
26415cb0d679SMarcel Telka continue;
26425cb0d679SMarcel Telka } else if (strcmp(c, "*") != 0) {
26435cb0d679SMarcel Telka gid_t clnt;
26445cb0d679SMarcel Telka
26455cb0d679SMarcel Telka if (!get_gid(c, &clnt))
26465cb0d679SMarcel Telka continue;
26475cb0d679SMarcel Telka
26485cb0d679SMarcel Telka if (clnt_gid != clnt)
26495cb0d679SMarcel Telka continue;
26505cb0d679SMarcel Telka }
26515cb0d679SMarcel Telka
26525cb0d679SMarcel Telka if (*s == '\0')
26535cb0d679SMarcel Telka srv = UID_NOBODY;
26545cb0d679SMarcel Telka else if (!get_gid(s, &srv))
26555cb0d679SMarcel Telka continue;
26565cb0d679SMarcel Telka else if (srv == (gid_t)-1) {
26575cb0d679SMarcel Telka map_deny = B_TRUE;
26585cb0d679SMarcel Telka break;
26595cb0d679SMarcel Telka }
26605cb0d679SMarcel Telka
2661a9685eaaSMarcel Telka if (in_access_list(cln, al) > 0) {
26625cb0d679SMarcel Telka *srv_gid = srv;
26635cb0d679SMarcel Telka perm |= NFSAUTH_GIDMAP;
266489621fe1SMarcel Telka
266589621fe1SMarcel Telka if (perm & NFSAUTH_GROUPS) {
266689621fe1SMarcel Telka free(*srv_gids);
266789621fe1SMarcel Telka *srv_ngids = 0;
266889621fe1SMarcel Telka *srv_gids = NULL;
266989621fe1SMarcel Telka perm &= ~NFSAUTH_GROUPS;
267089621fe1SMarcel Telka }
267189621fe1SMarcel Telka
26725cb0d679SMarcel Telka break;
26735cb0d679SMarcel Telka }
26745cb0d679SMarcel Telka }
26755cb0d679SMarcel Telka
26765cb0d679SMarcel Telka break;
26775cb0d679SMarcel Telka }
26785cb0d679SMarcel Telka
26795cb0d679SMarcel Telka default:
2680b89a8333Snatalie li - Sun Microsystems - Irvine United States break;
26817c478bd9Sstevel@tonic-gate }
26827c478bd9Sstevel@tonic-gate }
26837c478bd9Sstevel@tonic-gate
26847c478bd9Sstevel@tonic-gate free(opts);
26857c478bd9Sstevel@tonic-gate
26865cb0d679SMarcel Telka if (perm & NFSAUTH_ROOT) {
26875cb0d679SMarcel Telka *srv_uid = 0;
26885cb0d679SMarcel Telka *srv_gid = 0;
26895cb0d679SMarcel Telka }
26905cb0d679SMarcel Telka
26915cb0d679SMarcel Telka if (map_deny)
26925cb0d679SMarcel Telka perm |= NFSAUTH_DENIED;
26935cb0d679SMarcel Telka
26945cb0d679SMarcel Telka if (!(perm & NFSAUTH_UIDMAP))
26955cb0d679SMarcel Telka *srv_uid = clnt_uid;
26965cb0d679SMarcel Telka if (!(perm & NFSAUTH_GIDMAP))
26975cb0d679SMarcel Telka *srv_gid = clnt_gid;
26985cb0d679SMarcel Telka
26995cb0d679SMarcel Telka if (flavor != match || perm & NFSAUTH_DENIED)
27007c478bd9Sstevel@tonic-gate return (NFSAUTH_DENIED);
27017c478bd9Sstevel@tonic-gate
27027c478bd9Sstevel@tonic-gate if (list) {
27037c478bd9Sstevel@tonic-gate /*
27047c478bd9Sstevel@tonic-gate * If the client doesn't match an "ro" or "rw"
27057c478bd9Sstevel@tonic-gate * list then set no access.
27067c478bd9Sstevel@tonic-gate */
27077c478bd9Sstevel@tonic-gate if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0)
27087c478bd9Sstevel@tonic-gate perm |= NFSAUTH_DENIED;
27097c478bd9Sstevel@tonic-gate } else {
27107c478bd9Sstevel@tonic-gate /*
27117c478bd9Sstevel@tonic-gate * The client matched a flavor entry that
27127c478bd9Sstevel@tonic-gate * has no explicit "rw" or "ro" determination.
27137c478bd9Sstevel@tonic-gate * Default it to "rw".
27147c478bd9Sstevel@tonic-gate */
27157c478bd9Sstevel@tonic-gate perm |= NFSAUTH_RW;
27167c478bd9Sstevel@tonic-gate }
27177c478bd9Sstevel@tonic-gate
27187c478bd9Sstevel@tonic-gate /*
27197c478bd9Sstevel@tonic-gate * The client may show up in both ro= and rw=
27207c478bd9Sstevel@tonic-gate * lists. If so, then turn off the RO access
27217c478bd9Sstevel@tonic-gate * bit leaving RW access.
27227c478bd9Sstevel@tonic-gate */
27237c478bd9Sstevel@tonic-gate if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) {
27247c478bd9Sstevel@tonic-gate /*
27257c478bd9Sstevel@tonic-gate * Logically cover all permutations of rw=,ro=.
27267c478bd9Sstevel@tonic-gate * In the case where, rw,ro=<host> we would like
27277c478bd9Sstevel@tonic-gate * to remove RW access for the host. In all other cases
27287c478bd9Sstevel@tonic-gate * RW wins the precedence battle.
27297c478bd9Sstevel@tonic-gate */
27307c478bd9Sstevel@tonic-gate if (!rw_val && ro_val) {
27317c478bd9Sstevel@tonic-gate perm &= ~(NFSAUTH_RW);
27327c478bd9Sstevel@tonic-gate } else {
27337c478bd9Sstevel@tonic-gate perm &= ~(NFSAUTH_RO);
27347c478bd9Sstevel@tonic-gate }
27357c478bd9Sstevel@tonic-gate }
27367c478bd9Sstevel@tonic-gate
27377c478bd9Sstevel@tonic-gate return (perm);
27387c478bd9Sstevel@tonic-gate }
27397c478bd9Sstevel@tonic-gate
27407c478bd9Sstevel@tonic-gate /*
27417c478bd9Sstevel@tonic-gate * Check if the client has access by using a flavor different from
27427c478bd9Sstevel@tonic-gate * the given "flavor". If "flavor" is not in the flavor list,
27437c478bd9Sstevel@tonic-gate * return TRUE to indicate that this "flavor" is a wrong sec.
27447c478bd9Sstevel@tonic-gate */
27457c478bd9Sstevel@tonic-gate static bool_t
is_wrongsec(share_t * sh,struct cln * cln,int flavor)2746a9685eaaSMarcel Telka is_wrongsec(share_t *sh, struct cln *cln, int flavor)
27477c478bd9Sstevel@tonic-gate {
27487c478bd9Sstevel@tonic-gate int flavor_list[MAX_FLAVORS];
27497c478bd9Sstevel@tonic-gate int flavor_count, i;
27507c478bd9Sstevel@tonic-gate
27517c478bd9Sstevel@tonic-gate /* get the flavor list that the client has access with */
2752a9685eaaSMarcel Telka flavor_count = getclientsflavors_new(sh, cln, flavor_list);
27537c478bd9Sstevel@tonic-gate
27547c478bd9Sstevel@tonic-gate if (flavor_count == 0)
27557c478bd9Sstevel@tonic-gate return (FALSE);
27567c478bd9Sstevel@tonic-gate
27577c478bd9Sstevel@tonic-gate /*
27587c478bd9Sstevel@tonic-gate * Check if the given "flavor" is in the flavor_list.
27597c478bd9Sstevel@tonic-gate */
27607c478bd9Sstevel@tonic-gate for (i = 0; i < flavor_count; i++) {
27617c478bd9Sstevel@tonic-gate if (flavor == flavor_list[i])
27627c478bd9Sstevel@tonic-gate return (FALSE);
27637c478bd9Sstevel@tonic-gate }
27647c478bd9Sstevel@tonic-gate
27657c478bd9Sstevel@tonic-gate /*
27667c478bd9Sstevel@tonic-gate * If "flavor" is not in the flavor_list, return TRUE to indicate
27677c478bd9Sstevel@tonic-gate * that the client should have access by using a security flavor
27687c478bd9Sstevel@tonic-gate * different from this "flavor".
27697c478bd9Sstevel@tonic-gate */
27707c478bd9Sstevel@tonic-gate return (TRUE);
27717c478bd9Sstevel@tonic-gate }
27727c478bd9Sstevel@tonic-gate
27737c478bd9Sstevel@tonic-gate /*
27747c478bd9Sstevel@tonic-gate * Given an export and the client's hostname, we
27757c478bd9Sstevel@tonic-gate * check the security options to see whether the
27767c478bd9Sstevel@tonic-gate * client is allowed to use the given security flavor.
27777c478bd9Sstevel@tonic-gate *
27787c478bd9Sstevel@tonic-gate * The strategy is to proceed through the options looking
27797c478bd9Sstevel@tonic-gate * for a flavor match, then pay attention to the ro, rw,
27807c478bd9Sstevel@tonic-gate * and root options.
27817c478bd9Sstevel@tonic-gate *
27827c478bd9Sstevel@tonic-gate * Note that an entry may list several flavors in a
27837c478bd9Sstevel@tonic-gate * single entry, e.g.
27847c478bd9Sstevel@tonic-gate *
27857c478bd9Sstevel@tonic-gate * sec=krb5,rw=clnt1:clnt2,ro,sec=sys,ro
27867c478bd9Sstevel@tonic-gate *
27877c478bd9Sstevel@tonic-gate */
27887c478bd9Sstevel@tonic-gate
27897c478bd9Sstevel@tonic-gate static int
check_client_new(share_t * sh,struct cln * cln,int flavor,uid_t clnt_uid,gid_t clnt_gid,uint_t clnt_ngids,gid_t * clnt_gids,uid_t * srv_uid,gid_t * srv_gid,uint_t * srv_ngids,gid_t ** srv_gids)2790a9685eaaSMarcel Telka check_client_new(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid,
279189621fe1SMarcel Telka gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid,
279289621fe1SMarcel Telka gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids)
27937c478bd9Sstevel@tonic-gate {
27947c478bd9Sstevel@tonic-gate char *opts, *p, *val;
27957c478bd9Sstevel@tonic-gate char *lasts;
27967c478bd9Sstevel@tonic-gate char *f;
27977c478bd9Sstevel@tonic-gate int match = 0; /* Set when a flavor is matched */
27987c478bd9Sstevel@tonic-gate int perm = 0; /* Set when "ro", "rw" or "root" is matched */
27997c478bd9Sstevel@tonic-gate int list = 0; /* Set when "ro", "rw" is found */
28007c478bd9Sstevel@tonic-gate int ro_val = 0; /* Set if ro option is 'ro=' */
28017c478bd9Sstevel@tonic-gate int rw_val = 0; /* Set if rw option is 'rw=' */
28025cb0d679SMarcel Telka
28035cb0d679SMarcel Telka boolean_t map_deny = B_FALSE;
28047c478bd9Sstevel@tonic-gate
28057c478bd9Sstevel@tonic-gate opts = strdup(sh->sh_opts);
28067c478bd9Sstevel@tonic-gate if (opts == NULL) {
28077c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "check_client: no memory");
28087c478bd9Sstevel@tonic-gate return (0);
28097c478bd9Sstevel@tonic-gate }
28107c478bd9Sstevel@tonic-gate
281189621fe1SMarcel Telka /*
281289621fe1SMarcel Telka * If client provided 16 supplemental groups with AUTH_SYS, lookup
281389621fe1SMarcel Telka * locally for all of them
281489621fe1SMarcel Telka */
281589621fe1SMarcel Telka if (flavor == AUTH_SYS && clnt_ngids == NGRPS && ngroups_max > NGRPS)
281689621fe1SMarcel Telka if (getusergroups(clnt_uid, srv_ngids, srv_gids) == 0)
281789621fe1SMarcel Telka perm |= NFSAUTH_GROUPS;
281889621fe1SMarcel Telka
28197c478bd9Sstevel@tonic-gate p = opts;
28207c478bd9Sstevel@tonic-gate
28217c478bd9Sstevel@tonic-gate while (*p) {
28227c478bd9Sstevel@tonic-gate switch (getsubopt(&p, optlist, &val)) {
28237c478bd9Sstevel@tonic-gate
28247c478bd9Sstevel@tonic-gate case OPT_SEC:
28257c478bd9Sstevel@tonic-gate if (match)
28267c478bd9Sstevel@tonic-gate goto done;
28277c478bd9Sstevel@tonic-gate
28287c478bd9Sstevel@tonic-gate while ((f = strtok_r(val, ":", &lasts))
2829250a0733Sth != NULL) {
28307c478bd9Sstevel@tonic-gate if (flavor == map_flavor(f)) {
28317c478bd9Sstevel@tonic-gate match = 1;
28327c478bd9Sstevel@tonic-gate break;
28337c478bd9Sstevel@tonic-gate }
28347c478bd9Sstevel@tonic-gate val = NULL;
28357c478bd9Sstevel@tonic-gate }
28367c478bd9Sstevel@tonic-gate break;
28377c478bd9Sstevel@tonic-gate
28387c478bd9Sstevel@tonic-gate case OPT_RO:
28397c478bd9Sstevel@tonic-gate if (!match)
28407c478bd9Sstevel@tonic-gate break;
28417c478bd9Sstevel@tonic-gate
28427c478bd9Sstevel@tonic-gate list++;
28435cb0d679SMarcel Telka if (val != NULL)
28445cb0d679SMarcel Telka ro_val++;
2845a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0)
28467c478bd9Sstevel@tonic-gate perm |= NFSAUTH_RO;
28477c478bd9Sstevel@tonic-gate break;
28487c478bd9Sstevel@tonic-gate
28497c478bd9Sstevel@tonic-gate case OPT_RW:
28507c478bd9Sstevel@tonic-gate if (!match)
28517c478bd9Sstevel@tonic-gate break;
28527c478bd9Sstevel@tonic-gate
28537c478bd9Sstevel@tonic-gate list++;
28545cb0d679SMarcel Telka if (val != NULL)
28555cb0d679SMarcel Telka rw_val++;
2856a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0)
28577c478bd9Sstevel@tonic-gate perm |= NFSAUTH_RW;
28587c478bd9Sstevel@tonic-gate break;
28597c478bd9Sstevel@tonic-gate
28607c478bd9Sstevel@tonic-gate case OPT_ROOT:
28617c478bd9Sstevel@tonic-gate /*
28627c478bd9Sstevel@tonic-gate * Check if the client is in
28637c478bd9Sstevel@tonic-gate * the root list. Only valid
28647c478bd9Sstevel@tonic-gate * for AUTH_SYS.
28657c478bd9Sstevel@tonic-gate */
28667c478bd9Sstevel@tonic-gate if (flavor != AUTH_SYS)
28677c478bd9Sstevel@tonic-gate break;
28687c478bd9Sstevel@tonic-gate
28697c478bd9Sstevel@tonic-gate if (!match)
28707c478bd9Sstevel@tonic-gate break;
28717c478bd9Sstevel@tonic-gate
28727c478bd9Sstevel@tonic-gate if (val == NULL || *val == '\0')
28737c478bd9Sstevel@tonic-gate break;
28747c478bd9Sstevel@tonic-gate
28755cb0d679SMarcel Telka if (clnt_uid != 0)
28765cb0d679SMarcel Telka break;
28775cb0d679SMarcel Telka
2878a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0) {
28797c478bd9Sstevel@tonic-gate perm |= NFSAUTH_ROOT;
28805cb0d679SMarcel Telka perm |= NFSAUTH_UIDMAP | NFSAUTH_GIDMAP;
28815cb0d679SMarcel Telka map_deny = B_FALSE;
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 }
28895cb0d679SMarcel Telka }
28907c478bd9Sstevel@tonic-gate break;
2891b89a8333Snatalie li - Sun Microsystems - Irvine United States
2892b89a8333Snatalie li - Sun Microsystems - Irvine United States case OPT_NONE:
2893b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
289454d34259SMarcel Telka * Check if the client should have no access
2895b89a8333Snatalie li - Sun Microsystems - Irvine United States * to this share at all. This option behaves
2896b89a8333Snatalie li - Sun Microsystems - Irvine United States * more like "root" than either "rw" or "ro".
2897b89a8333Snatalie li - Sun Microsystems - Irvine United States */
2898a9685eaaSMarcel Telka if (in_access_list(cln, val) > 0)
2899b89a8333Snatalie li - Sun Microsystems - Irvine United States perm |= NFSAUTH_DENIED;
2900b89a8333Snatalie li - Sun Microsystems - Irvine United States break;
29015cb0d679SMarcel Telka
29025cb0d679SMarcel Telka case OPT_UIDMAP: {
29035cb0d679SMarcel Telka char *c;
29045cb0d679SMarcel Telka char *n;
29055cb0d679SMarcel Telka
29065cb0d679SMarcel Telka /*
29075cb0d679SMarcel Telka * The uidmap is supported for AUTH_SYS only.
29085cb0d679SMarcel Telka */
29095cb0d679SMarcel Telka if (flavor != AUTH_SYS)
29105cb0d679SMarcel Telka break;
29115cb0d679SMarcel Telka
29125cb0d679SMarcel Telka if (!match || perm & NFSAUTH_UIDMAP || map_deny)
29135cb0d679SMarcel Telka break;
29145cb0d679SMarcel Telka
29155cb0d679SMarcel Telka for (c = val; c != NULL; c = n) {
29165cb0d679SMarcel Telka char *s;
29175cb0d679SMarcel Telka char *al;
29185cb0d679SMarcel Telka uid_t srv;
29195cb0d679SMarcel Telka
29205cb0d679SMarcel Telka n = strchr(c, '~');
29215cb0d679SMarcel Telka if (n != NULL)
29225cb0d679SMarcel Telka *n++ = '\0';
29235cb0d679SMarcel Telka
29245cb0d679SMarcel Telka s = strchr(c, ':');
29255cb0d679SMarcel Telka if (s != NULL) {
29265cb0d679SMarcel Telka *s++ = '\0';
29275cb0d679SMarcel Telka al = strchr(s, ':');
29285cb0d679SMarcel Telka if (al != NULL)
29295cb0d679SMarcel Telka *al++ = '\0';
29305cb0d679SMarcel Telka }
29315cb0d679SMarcel Telka
29325cb0d679SMarcel Telka if (s == NULL || al == NULL)
29335cb0d679SMarcel Telka continue;
29345cb0d679SMarcel Telka
29355cb0d679SMarcel Telka if (*c == '\0') {
29365cb0d679SMarcel Telka if (clnt_uid != (uid_t)-1)
29375cb0d679SMarcel Telka continue;
29385cb0d679SMarcel Telka } else if (strcmp(c, "*") != 0) {
29395cb0d679SMarcel Telka uid_t clnt;
29405cb0d679SMarcel Telka
29415cb0d679SMarcel Telka if (!get_uid(c, &clnt))
29425cb0d679SMarcel Telka continue;
29435cb0d679SMarcel Telka
29445cb0d679SMarcel Telka if (clnt_uid != clnt)
29455cb0d679SMarcel Telka continue;
29465cb0d679SMarcel Telka }
29475cb0d679SMarcel Telka
29485cb0d679SMarcel Telka if (*s == '\0')
29495cb0d679SMarcel Telka srv = UID_NOBODY;
29505cb0d679SMarcel Telka else if (!get_uid(s, &srv))
29515cb0d679SMarcel Telka continue;
29525cb0d679SMarcel Telka else if (srv == (uid_t)-1) {
29535cb0d679SMarcel Telka map_deny = B_TRUE;
29545cb0d679SMarcel Telka break;
29555cb0d679SMarcel Telka }
29565cb0d679SMarcel Telka
2957a9685eaaSMarcel Telka if (in_access_list(cln, al) > 0) {
29585cb0d679SMarcel Telka *srv_uid = srv;
29595cb0d679SMarcel Telka perm |= NFSAUTH_UIDMAP;
296089621fe1SMarcel Telka
296189621fe1SMarcel Telka if (perm & NFSAUTH_GROUPS) {
296289621fe1SMarcel Telka free(*srv_gids);
296389621fe1SMarcel Telka *srv_gids = NULL;
296489621fe1SMarcel Telka *srv_ngids = 0;
296589621fe1SMarcel Telka perm &= ~NFSAUTH_GROUPS;
296689621fe1SMarcel Telka }
296789621fe1SMarcel Telka
29685cb0d679SMarcel Telka break;
29695cb0d679SMarcel Telka }
29705cb0d679SMarcel Telka }
29715cb0d679SMarcel Telka
29725cb0d679SMarcel Telka break;
29735cb0d679SMarcel Telka }
29745cb0d679SMarcel Telka
29755cb0d679SMarcel Telka case OPT_GIDMAP: {
29765cb0d679SMarcel Telka char *c;
29775cb0d679SMarcel Telka char *n;
29785cb0d679SMarcel Telka
29795cb0d679SMarcel Telka /*
29805cb0d679SMarcel Telka * The gidmap is supported for AUTH_SYS only.
29815cb0d679SMarcel Telka */
29825cb0d679SMarcel Telka if (flavor != AUTH_SYS)
29835cb0d679SMarcel Telka break;
29845cb0d679SMarcel Telka
29855cb0d679SMarcel Telka if (!match || perm & NFSAUTH_GIDMAP || map_deny)
29865cb0d679SMarcel Telka break;
29875cb0d679SMarcel Telka
29885cb0d679SMarcel Telka for (c = val; c != NULL; c = n) {
29895cb0d679SMarcel Telka char *s;
29905cb0d679SMarcel Telka char *al;
29915cb0d679SMarcel Telka gid_t srv;
29925cb0d679SMarcel Telka
29935cb0d679SMarcel Telka n = strchr(c, '~');
29945cb0d679SMarcel Telka if (n != NULL)
29955cb0d679SMarcel Telka *n++ = '\0';
29965cb0d679SMarcel Telka
29975cb0d679SMarcel Telka s = strchr(c, ':');
29985cb0d679SMarcel Telka if (s != NULL) {
29995cb0d679SMarcel Telka *s++ = '\0';
30005cb0d679SMarcel Telka al = strchr(s, ':');
30015cb0d679SMarcel Telka if (al != NULL)
30025cb0d679SMarcel Telka *al++ = '\0';
30035cb0d679SMarcel Telka }
30045cb0d679SMarcel Telka
30055cb0d679SMarcel Telka if (s == NULL || al == NULL)
30065cb0d679SMarcel Telka break;
30075cb0d679SMarcel Telka
30085cb0d679SMarcel Telka if (*c == '\0') {
30095cb0d679SMarcel Telka if (clnt_gid != (gid_t)-1)
30105cb0d679SMarcel Telka continue;
30115cb0d679SMarcel Telka } else if (strcmp(c, "*") != 0) {
30125cb0d679SMarcel Telka gid_t clnt;
30135cb0d679SMarcel Telka
30145cb0d679SMarcel Telka if (!get_gid(c, &clnt))
30155cb0d679SMarcel Telka continue;
30165cb0d679SMarcel Telka
30175cb0d679SMarcel Telka if (clnt_gid != clnt)
30185cb0d679SMarcel Telka continue;
30195cb0d679SMarcel Telka }
30205cb0d679SMarcel Telka
30215cb0d679SMarcel Telka if (*s == '\0')
30225cb0d679SMarcel Telka srv = UID_NOBODY;
30235cb0d679SMarcel Telka else if (!get_gid(s, &srv))
30245cb0d679SMarcel Telka continue;
30255cb0d679SMarcel Telka else if (srv == (gid_t)-1) {
30265cb0d679SMarcel Telka map_deny = B_TRUE;
30275cb0d679SMarcel Telka break;
30285cb0d679SMarcel Telka }
30295cb0d679SMarcel Telka
3030a9685eaaSMarcel Telka if (in_access_list(cln, al) > 0) {
30315cb0d679SMarcel Telka *srv_gid = srv;
30325cb0d679SMarcel Telka perm |= NFSAUTH_GIDMAP;
303389621fe1SMarcel Telka
303489621fe1SMarcel Telka if (perm & NFSAUTH_GROUPS) {
303589621fe1SMarcel Telka free(*srv_gids);
303689621fe1SMarcel Telka *srv_gids = NULL;
303789621fe1SMarcel Telka *srv_ngids = 0;
303889621fe1SMarcel Telka perm &= ~NFSAUTH_GROUPS;
303989621fe1SMarcel Telka }
304089621fe1SMarcel Telka
30415cb0d679SMarcel Telka break;
30425cb0d679SMarcel Telka }
30435cb0d679SMarcel Telka }
30445cb0d679SMarcel Telka
30455cb0d679SMarcel Telka break;
30465cb0d679SMarcel Telka }
30475cb0d679SMarcel Telka
30485cb0d679SMarcel Telka default:
30495cb0d679SMarcel Telka break;
30507c478bd9Sstevel@tonic-gate }
30517c478bd9Sstevel@tonic-gate }
30527c478bd9Sstevel@tonic-gate
30537c478bd9Sstevel@tonic-gate done:
30545cb0d679SMarcel Telka if (perm & NFSAUTH_ROOT) {
30555cb0d679SMarcel Telka *srv_uid = 0;
30565cb0d679SMarcel Telka *srv_gid = 0;
30575cb0d679SMarcel Telka }
30585cb0d679SMarcel Telka
30595cb0d679SMarcel Telka if (map_deny)
30605cb0d679SMarcel Telka perm |= NFSAUTH_DENIED;
30615cb0d679SMarcel Telka
30625cb0d679SMarcel Telka if (!(perm & NFSAUTH_UIDMAP))
30635cb0d679SMarcel Telka *srv_uid = clnt_uid;
30645cb0d679SMarcel Telka if (!(perm & NFSAUTH_GIDMAP))
30655cb0d679SMarcel Telka *srv_gid = clnt_gid;
30665cb0d679SMarcel Telka
30677c478bd9Sstevel@tonic-gate /*
30687c478bd9Sstevel@tonic-gate * If no match then set the perm accordingly
30697c478bd9Sstevel@tonic-gate */
30705cb0d679SMarcel Telka if (!match || perm & NFSAUTH_DENIED) {
30715cb0d679SMarcel Telka free(opts);
30727c478bd9Sstevel@tonic-gate return (NFSAUTH_DENIED);
30735cb0d679SMarcel Telka }
30747c478bd9Sstevel@tonic-gate
30757c478bd9Sstevel@tonic-gate if (list) {
30767c478bd9Sstevel@tonic-gate /*
30777c478bd9Sstevel@tonic-gate * If the client doesn't match an "ro" or "rw" list then
30787c478bd9Sstevel@tonic-gate * check if it may have access by using a different flavor.
30797c478bd9Sstevel@tonic-gate * If so, return NFSAUTH_WRONGSEC.
30807c478bd9Sstevel@tonic-gate * If not, return NFSAUTH_DENIED.
30817c478bd9Sstevel@tonic-gate */
30827c478bd9Sstevel@tonic-gate if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0) {
3083a9685eaaSMarcel Telka if (is_wrongsec(sh, cln, flavor))
30847c478bd9Sstevel@tonic-gate perm |= NFSAUTH_WRONGSEC;
30857c478bd9Sstevel@tonic-gate else
30867c478bd9Sstevel@tonic-gate perm |= NFSAUTH_DENIED;
30877c478bd9Sstevel@tonic-gate }
30887c478bd9Sstevel@tonic-gate } else {
30897c478bd9Sstevel@tonic-gate /*
30907c478bd9Sstevel@tonic-gate * The client matched a flavor entry that
30917c478bd9Sstevel@tonic-gate * has no explicit "rw" or "ro" determination.
30927c478bd9Sstevel@tonic-gate * Make sure it defaults to "rw".
30937c478bd9Sstevel@tonic-gate */
30947c478bd9Sstevel@tonic-gate perm |= NFSAUTH_RW;
30957c478bd9Sstevel@tonic-gate }
30967c478bd9Sstevel@tonic-gate
30977c478bd9Sstevel@tonic-gate /*
30987c478bd9Sstevel@tonic-gate * The client may show up in both ro= and rw=
30997c478bd9Sstevel@tonic-gate * lists. If so, then turn off the RO access
31007c478bd9Sstevel@tonic-gate * bit leaving RW access.
31017c478bd9Sstevel@tonic-gate */
31027c478bd9Sstevel@tonic-gate if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) {
31037c478bd9Sstevel@tonic-gate /*
31047c478bd9Sstevel@tonic-gate * Logically cover all permutations of rw=,ro=.
31057c478bd9Sstevel@tonic-gate * In the case where, rw,ro=<host> we would like
31067c478bd9Sstevel@tonic-gate * to remove RW access for the host. In all other cases
31077c478bd9Sstevel@tonic-gate * RW wins the precedence battle.
31087c478bd9Sstevel@tonic-gate */
31097c478bd9Sstevel@tonic-gate if (!rw_val && ro_val) {
31107c478bd9Sstevel@tonic-gate perm &= ~(NFSAUTH_RW);
31117c478bd9Sstevel@tonic-gate } else {
31127c478bd9Sstevel@tonic-gate perm &= ~(NFSAUTH_RO);
31137c478bd9Sstevel@tonic-gate }
31147c478bd9Sstevel@tonic-gate }
31157c478bd9Sstevel@tonic-gate
31167c478bd9Sstevel@tonic-gate free(opts);
31177c478bd9Sstevel@tonic-gate
31187c478bd9Sstevel@tonic-gate return (perm);
31197c478bd9Sstevel@tonic-gate }
31207c478bd9Sstevel@tonic-gate
31217c478bd9Sstevel@tonic-gate void
check_sharetab()31227c478bd9Sstevel@tonic-gate check_sharetab()
31237c478bd9Sstevel@tonic-gate {
31247c478bd9Sstevel@tonic-gate FILE *f;
31257c478bd9Sstevel@tonic-gate struct stat st;
31267c478bd9Sstevel@tonic-gate static timestruc_t last_sharetab_time;
31277c478bd9Sstevel@tonic-gate timestruc_t prev_sharetab_time;
31284a508a79SThomas Haynes share_t *sh;
31297c478bd9Sstevel@tonic-gate struct sh_list *shp, *shp_prev;
31307c478bd9Sstevel@tonic-gate int res, c = 0;
31317c478bd9Sstevel@tonic-gate
31327c478bd9Sstevel@tonic-gate /*
31337c478bd9Sstevel@tonic-gate * read in /etc/dfs/sharetab if it has changed
31347c478bd9Sstevel@tonic-gate */
31357c478bd9Sstevel@tonic-gate if (stat(SHARETAB, &st) != 0) {
31367c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB);
31377c478bd9Sstevel@tonic-gate return;
31387c478bd9Sstevel@tonic-gate }
31397c478bd9Sstevel@tonic-gate
31407c478bd9Sstevel@tonic-gate if (st.st_mtim.tv_sec == last_sharetab_time.tv_sec &&
31417c478bd9Sstevel@tonic-gate st.st_mtim.tv_nsec == last_sharetab_time.tv_nsec) {
31427c478bd9Sstevel@tonic-gate /*
31437c478bd9Sstevel@tonic-gate * No change.
31447c478bd9Sstevel@tonic-gate */
31457c478bd9Sstevel@tonic-gate return;
31467c478bd9Sstevel@tonic-gate }
31477c478bd9Sstevel@tonic-gate
31487c478bd9Sstevel@tonic-gate /*
31497c478bd9Sstevel@tonic-gate * Remember the mod time, then after getting the
31507c478bd9Sstevel@tonic-gate * write lock check again. If another thread
31517c478bd9Sstevel@tonic-gate * already did the update, then there's no
31527c478bd9Sstevel@tonic-gate * work to do.
31537c478bd9Sstevel@tonic-gate */
31547c478bd9Sstevel@tonic-gate prev_sharetab_time = last_sharetab_time;
31557c478bd9Sstevel@tonic-gate
31567c478bd9Sstevel@tonic-gate (void) rw_wrlock(&sharetab_lock);
31577c478bd9Sstevel@tonic-gate
31587c478bd9Sstevel@tonic-gate if (prev_sharetab_time.tv_sec != last_sharetab_time.tv_sec ||
31597c478bd9Sstevel@tonic-gate prev_sharetab_time.tv_nsec != last_sharetab_time.tv_nsec) {
31607c478bd9Sstevel@tonic-gate (void) rw_unlock(&sharetab_lock);
31617c478bd9Sstevel@tonic-gate return;
31627c478bd9Sstevel@tonic-gate }
31637c478bd9Sstevel@tonic-gate
31647c478bd9Sstevel@tonic-gate /*
3165a237e38eSth * Note that since the sharetab is now in memory
3166a237e38eSth * and a snapshot is taken, we no longer have to
3167a237e38eSth * lock the file.
31687c478bd9Sstevel@tonic-gate */
3169a237e38eSth f = fopen(SHARETAB, "r");
3170a237e38eSth if (f == NULL) {
3171a237e38eSth syslog(LOG_ERR, "Cannot open %s: %m", SHARETAB);
31727c478bd9Sstevel@tonic-gate (void) rw_unlock(&sharetab_lock);
31737c478bd9Sstevel@tonic-gate return;
31747c478bd9Sstevel@tonic-gate }
31757c478bd9Sstevel@tonic-gate
31767c478bd9Sstevel@tonic-gate /*
31777c478bd9Sstevel@tonic-gate * Once we are sure /etc/dfs/sharetab has been
31787c478bd9Sstevel@tonic-gate * modified, flush netgroup cache entries.
31797c478bd9Sstevel@tonic-gate */
31807c478bd9Sstevel@tonic-gate netgrp_cache_flush();
31817c478bd9Sstevel@tonic-gate
31827c478bd9Sstevel@tonic-gate sh_free(share_list); /* free old list */
31837c478bd9Sstevel@tonic-gate share_list = NULL;
31847c478bd9Sstevel@tonic-gate
31857c478bd9Sstevel@tonic-gate while ((res = getshare(f, &sh)) > 0) {
31867c478bd9Sstevel@tonic-gate c++;
31877c478bd9Sstevel@tonic-gate if (strcmp(sh->sh_fstype, "nfs") != 0)
31887c478bd9Sstevel@tonic-gate continue;
31897c478bd9Sstevel@tonic-gate
31907c478bd9Sstevel@tonic-gate shp = malloc(sizeof (*shp));
31917c478bd9Sstevel@tonic-gate if (shp == NULL)
31927c478bd9Sstevel@tonic-gate goto alloc_failed;
31937c478bd9Sstevel@tonic-gate if (share_list == NULL)
31947c478bd9Sstevel@tonic-gate share_list = shp;
31957c478bd9Sstevel@tonic-gate else
31967c478bd9Sstevel@tonic-gate /* LINTED not used before set */
31977c478bd9Sstevel@tonic-gate shp_prev->shl_next = shp;
31987c478bd9Sstevel@tonic-gate shp_prev = shp;
31997c478bd9Sstevel@tonic-gate shp->shl_next = NULL;
32007c478bd9Sstevel@tonic-gate shp->shl_sh = sharedup(sh);
32017c478bd9Sstevel@tonic-gate if (shp->shl_sh == NULL)
32027c478bd9Sstevel@tonic-gate goto alloc_failed;
32037c478bd9Sstevel@tonic-gate }
32044a508a79SThomas Haynes
32057c478bd9Sstevel@tonic-gate if (res < 0)
32067c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s: invalid at line %d\n",
3207250a0733Sth SHARETAB, c + 1);
32087c478bd9Sstevel@tonic-gate
32097c478bd9Sstevel@tonic-gate if (stat(SHARETAB, &st) != 0) {
32107c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB);
321162a1b812Sth (void) fclose(f);
32127c478bd9Sstevel@tonic-gate (void) rw_unlock(&sharetab_lock);
32137c478bd9Sstevel@tonic-gate return;
32147c478bd9Sstevel@tonic-gate }
32154a508a79SThomas Haynes
32167c478bd9Sstevel@tonic-gate last_sharetab_time = st.st_mtim;
32177c478bd9Sstevel@tonic-gate (void) fclose(f);
32187c478bd9Sstevel@tonic-gate (void) rw_unlock(&sharetab_lock);
32194a508a79SThomas Haynes
32207c478bd9Sstevel@tonic-gate return;
32217c478bd9Sstevel@tonic-gate
32227c478bd9Sstevel@tonic-gate alloc_failed:
32234a508a79SThomas Haynes
32247c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "check_sharetab: no memory");
32257c478bd9Sstevel@tonic-gate sh_free(share_list);
32267c478bd9Sstevel@tonic-gate share_list = NULL;
32277c478bd9Sstevel@tonic-gate (void) fclose(f);
32287c478bd9Sstevel@tonic-gate (void) rw_unlock(&sharetab_lock);
32297c478bd9Sstevel@tonic-gate }
32307c478bd9Sstevel@tonic-gate
32317c478bd9Sstevel@tonic-gate static void
sh_free(struct sh_list * shp)32327c478bd9Sstevel@tonic-gate sh_free(struct sh_list *shp)
32337c478bd9Sstevel@tonic-gate {
323454d34259SMarcel Telka struct sh_list *next;
32357c478bd9Sstevel@tonic-gate
32367c478bd9Sstevel@tonic-gate while (shp) {
32377c478bd9Sstevel@tonic-gate sharefree(shp->shl_sh);
32387c478bd9Sstevel@tonic-gate next = shp->shl_next;
32397c478bd9Sstevel@tonic-gate free(shp);
32407c478bd9Sstevel@tonic-gate shp = next;
32417c478bd9Sstevel@tonic-gate }
32427c478bd9Sstevel@tonic-gate }
32437c478bd9Sstevel@tonic-gate
32447c478bd9Sstevel@tonic-gate
32457c478bd9Sstevel@tonic-gate /*
32467c478bd9Sstevel@tonic-gate * Remove an entry from mounted list
32477c478bd9Sstevel@tonic-gate */
32487c478bd9Sstevel@tonic-gate static void
umount(struct svc_req * rqstp)32497c478bd9Sstevel@tonic-gate umount(struct svc_req *rqstp)
32507c478bd9Sstevel@tonic-gate {
32517c478bd9Sstevel@tonic-gate char *host, *path, *remove_path;
32527c478bd9Sstevel@tonic-gate char rpath[MAXPATHLEN];
32537c478bd9Sstevel@tonic-gate SVCXPRT *transp;
3254a9685eaaSMarcel Telka struct cln cln;
32557c478bd9Sstevel@tonic-gate
32567c478bd9Sstevel@tonic-gate transp = rqstp->rq_xprt;
32577c478bd9Sstevel@tonic-gate path = NULL;
32587c478bd9Sstevel@tonic-gate if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
32597c478bd9Sstevel@tonic-gate svcerr_decode(transp);
32607c478bd9Sstevel@tonic-gate return;
32617c478bd9Sstevel@tonic-gate }
3262a9685eaaSMarcel Telka
3263a9685eaaSMarcel Telka cln_init(&cln, transp);
3264a9685eaaSMarcel Telka
32657c478bd9Sstevel@tonic-gate errno = 0;
32667c478bd9Sstevel@tonic-gate if (!svc_sendreply(transp, xdr_void, (char *)NULL))
3267a9685eaaSMarcel Telka log_cant_reply_cln(&cln);
32687c478bd9Sstevel@tonic-gate
3269a9685eaaSMarcel Telka host = cln_gethost(&cln);
3270a9685eaaSMarcel Telka if (host == NULL) {
32717c478bd9Sstevel@tonic-gate /*
32727c478bd9Sstevel@tonic-gate * Without the hostname we can't do audit or delete
32737c478bd9Sstevel@tonic-gate * this host from the mount entries.
32747c478bd9Sstevel@tonic-gate */
3275544783caSToomas Soome (void) svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
32767c478bd9Sstevel@tonic-gate return;
32777c478bd9Sstevel@tonic-gate }
32787c478bd9Sstevel@tonic-gate
32797c478bd9Sstevel@tonic-gate if (verbose)
32807c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE, "UNMOUNT: %s unmounted %s", host, path);
32817c478bd9Sstevel@tonic-gate
32827c478bd9Sstevel@tonic-gate audit_mountd_umount(host, path);
32837c478bd9Sstevel@tonic-gate
32847c478bd9Sstevel@tonic-gate remove_path = rpath; /* assume we will use the cannonical path */
32857c478bd9Sstevel@tonic-gate if (realpath(path, rpath) == NULL) {
32867c478bd9Sstevel@tonic-gate if (verbose)
32877c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, "UNMOUNT: realpath: %s: %m ", path);
32887c478bd9Sstevel@tonic-gate remove_path = path; /* use path provided instead */
32897c478bd9Sstevel@tonic-gate }
32907c478bd9Sstevel@tonic-gate
32917c478bd9Sstevel@tonic-gate mntlist_delete(host, remove_path); /* remove from mount list */
32927c478bd9Sstevel@tonic-gate
3293a9685eaaSMarcel Telka cln_fini(&cln);
3294a9685eaaSMarcel Telka
3295544783caSToomas Soome (void) svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
32967c478bd9Sstevel@tonic-gate }
32977c478bd9Sstevel@tonic-gate
32987c478bd9Sstevel@tonic-gate /*
32997c478bd9Sstevel@tonic-gate * Remove all entries for one machine from mounted list
33007c478bd9Sstevel@tonic-gate */
33017c478bd9Sstevel@tonic-gate static void
umountall(struct svc_req * rqstp)33027c478bd9Sstevel@tonic-gate umountall(struct svc_req *rqstp)
33037c478bd9Sstevel@tonic-gate {
33047c478bd9Sstevel@tonic-gate SVCXPRT *transp;
33057c478bd9Sstevel@tonic-gate char *host;
3306a9685eaaSMarcel Telka struct cln cln;
33077c478bd9Sstevel@tonic-gate
33087c478bd9Sstevel@tonic-gate transp = rqstp->rq_xprt;
33097c478bd9Sstevel@tonic-gate if (!svc_getargs(transp, xdr_void, NULL)) {
33107c478bd9Sstevel@tonic-gate svcerr_decode(transp);
33117c478bd9Sstevel@tonic-gate return;
33127c478bd9Sstevel@tonic-gate }
33137c478bd9Sstevel@tonic-gate /*
33147c478bd9Sstevel@tonic-gate * We assume that this call is asynchronous and made via rpcbind
33157c478bd9Sstevel@tonic-gate * callit routine. Therefore return control immediately. The error
33167c478bd9Sstevel@tonic-gate * causes rpcbind to remain silent, as opposed to every machine
33177c478bd9Sstevel@tonic-gate * on the net blasting the requester with a response.
33187c478bd9Sstevel@tonic-gate */
33197c478bd9Sstevel@tonic-gate svcerr_systemerr(transp);
3320a9685eaaSMarcel Telka
3321a9685eaaSMarcel Telka cln_init(&cln, transp);
3322a9685eaaSMarcel Telka
3323a9685eaaSMarcel Telka host = cln_gethost(&cln);
3324a9685eaaSMarcel Telka if (host == NULL) {
33257c478bd9Sstevel@tonic-gate /* Can't do anything without the name of the client */
33267c478bd9Sstevel@tonic-gate return;
33277c478bd9Sstevel@tonic-gate }
33287c478bd9Sstevel@tonic-gate
33297c478bd9Sstevel@tonic-gate /*
33307c478bd9Sstevel@tonic-gate * Remove all hosts entries from mount list
33317c478bd9Sstevel@tonic-gate */
33327c478bd9Sstevel@tonic-gate mntlist_delete_all(host);
33337c478bd9Sstevel@tonic-gate
33347c478bd9Sstevel@tonic-gate if (verbose)
33357c478bd9Sstevel@tonic-gate syslog(LOG_NOTICE, "UNMOUNTALL: from %s", host);
33367c478bd9Sstevel@tonic-gate
3337a9685eaaSMarcel Telka cln_fini(&cln);
33387c478bd9Sstevel@tonic-gate }
33397c478bd9Sstevel@tonic-gate
33407c478bd9Sstevel@tonic-gate void *
exmalloc(size_t size)33417c478bd9Sstevel@tonic-gate exmalloc(size_t size)
33427c478bd9Sstevel@tonic-gate {
33437c478bd9Sstevel@tonic-gate void *ret;
33447c478bd9Sstevel@tonic-gate
33457c478bd9Sstevel@tonic-gate if ((ret = malloc(size)) == NULL) {
33467c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "Out of memory");
33477c478bd9Sstevel@tonic-gate exit(1);
33487c478bd9Sstevel@tonic-gate }
33497c478bd9Sstevel@tonic-gate return (ret);
33507c478bd9Sstevel@tonic-gate }
33517c478bd9Sstevel@tonic-gate
335203986916Sjarrett static tsol_tpent_t *
get_client_template(struct sockaddr * sock)335303986916Sjarrett get_client_template(struct sockaddr *sock)
335403986916Sjarrett {
335503986916Sjarrett in_addr_t v4client;
335603986916Sjarrett in6_addr_t v6client;
335703986916Sjarrett char v4_addr[INET_ADDRSTRLEN];
335803986916Sjarrett char v6_addr[INET6_ADDRSTRLEN];
335903986916Sjarrett tsol_rhent_t *rh;
336003986916Sjarrett tsol_tpent_t *tp;
336103986916Sjarrett
336203986916Sjarrett switch (sock->sa_family) {
336303986916Sjarrett case AF_INET:
336403986916Sjarrett v4client = ((struct sockaddr_in *)(void *)sock)->
336503986916Sjarrett sin_addr.s_addr;
336603986916Sjarrett if (inet_ntop(AF_INET, &v4client, v4_addr, INET_ADDRSTRLEN) ==
336703986916Sjarrett NULL)
336803986916Sjarrett return (NULL);
336903986916Sjarrett rh = tsol_getrhbyaddr(v4_addr, sizeof (v4_addr), AF_INET);
337003986916Sjarrett if (rh == NULL)
337103986916Sjarrett return (NULL);
337203986916Sjarrett tp = tsol_gettpbyname(rh->rh_template);
337303986916Sjarrett tsol_freerhent(rh);
337403986916Sjarrett return (tp);
337503986916Sjarrett break;
337603986916Sjarrett case AF_INET6:
337703986916Sjarrett v6client = ((struct sockaddr_in6 *)(void *)sock)->sin6_addr;
337803986916Sjarrett if (inet_ntop(AF_INET6, &v6client, v6_addr, INET6_ADDRSTRLEN) ==
337903986916Sjarrett NULL)
338003986916Sjarrett return (NULL);
338103986916Sjarrett rh = tsol_getrhbyaddr(v6_addr, sizeof (v6_addr), AF_INET6);
338203986916Sjarrett if (rh == NULL)
338303986916Sjarrett return (NULL);
338403986916Sjarrett tp = tsol_gettpbyname(rh->rh_template);
338503986916Sjarrett tsol_freerhent(rh);
338603986916Sjarrett return (tp);
338703986916Sjarrett break;
338803986916Sjarrett default:
338903986916Sjarrett return (NULL);
339003986916Sjarrett }
339103986916Sjarrett }
3392