xref: /onnv-gate/usr/src/cmd/fs.d/nfs/nfs4cbd/nfs4cbd.c (revision 12648:61bf50c7467b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52712Snn35248  * Common Development and Distribution License (the "License").
62712Snn35248  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*12648SSurya.Prakki@Sun.COM  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
260Sstevel@tonic-gate /*	  All Rights Reserved  	*/
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley 4.3 BSD
300Sstevel@tonic-gate  * under license from the Regents of the University of California.
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate 
330Sstevel@tonic-gate /*
340Sstevel@tonic-gate  * This module provides the user level support for the NFSv4
350Sstevel@tonic-gate  * callback program.  It is modeled after nfsd.  When a nfsv4
360Sstevel@tonic-gate  * mount occurs, the mount command forks and the child runs
370Sstevel@tonic-gate  * start_nfs4_callback.  If this is the first mount, then the
380Sstevel@tonic-gate  * process will hang around listening for incoming connection
390Sstevel@tonic-gate  * requests from the nfsv4 server.
400Sstevel@tonic-gate  *
410Sstevel@tonic-gate  * For connection-less protocols, the krpc is started immediately.
420Sstevel@tonic-gate  * For connection oriented protocols, the kernel module is informed
430Sstevel@tonic-gate  * of netid and universal address that it can give this
440Sstevel@tonic-gate  * information to the server during setclientid.
450Sstevel@tonic-gate  */
460Sstevel@tonic-gate 
470Sstevel@tonic-gate #include <sys/param.h>
480Sstevel@tonic-gate #include <sys/types.h>
490Sstevel@tonic-gate #include <syslog.h>
500Sstevel@tonic-gate #include <tiuser.h>
510Sstevel@tonic-gate #include <rpc/rpc.h>
520Sstevel@tonic-gate #include <errno.h>
530Sstevel@tonic-gate #include <thread.h>
540Sstevel@tonic-gate #include <sys/resource.h>
550Sstevel@tonic-gate #include <sys/file.h>
560Sstevel@tonic-gate #include <nfs/nfs.h>
570Sstevel@tonic-gate #include <nfs/nfssys.h>
580Sstevel@tonic-gate #include <stdio.h>
590Sstevel@tonic-gate #include <stdlib.h>
600Sstevel@tonic-gate #include <netconfig.h>
610Sstevel@tonic-gate #include <netdir.h>
620Sstevel@tonic-gate #include <string.h>
630Sstevel@tonic-gate #include <unistd.h>
640Sstevel@tonic-gate #include <stropts.h>
650Sstevel@tonic-gate #include <sys/tihdr.h>
660Sstevel@tonic-gate #include <netinet/tcp.h>
670Sstevel@tonic-gate #include "nfs_tbind.h"
680Sstevel@tonic-gate #include "thrpool.h"
690Sstevel@tonic-gate #include <rpcsvc/nfs4_prot.h>
700Sstevel@tonic-gate #include <netdb.h>
710Sstevel@tonic-gate #include <signal.h>
720Sstevel@tonic-gate #include <strings.h>
730Sstevel@tonic-gate #include <priv_utils.h>
740Sstevel@tonic-gate #include <rpcsvc/daemon_utils.h>
750Sstevel@tonic-gate 
760Sstevel@tonic-gate static	int	nfs4svc(int, struct netbuf *, struct netconfig *, int,
770Sstevel@tonic-gate 		struct netbuf *);
780Sstevel@tonic-gate extern	int	_nfssys(int, void *);
790Sstevel@tonic-gate 
800Sstevel@tonic-gate static	char	*MyName;
810Sstevel@tonic-gate 
820Sstevel@tonic-gate /*
830Sstevel@tonic-gate  * The following are all globals used by routines in nfs_tbind.c.
840Sstevel@tonic-gate  */
850Sstevel@tonic-gate size_t	end_listen_fds;		/* used by conn_close_oldest() */
860Sstevel@tonic-gate size_t	num_fds = 0;		/* used by multiple routines */
870Sstevel@tonic-gate int	listen_backlog = 32;	/* used by bind_to_{provider,proto}() */
880Sstevel@tonic-gate int	num_servers;		/* used by cots_listen_event() */
890Sstevel@tonic-gate int	(*Mysvc)(int, struct netbuf, struct netconfig *) = NULL;
900Sstevel@tonic-gate 				/* used by cots_listen_event() */
910Sstevel@tonic-gate int	max_conns_allowed = -1;	/* used by cots_listen_event() */
920Sstevel@tonic-gate 
93249Sjwahlig int
main(int argc,char * argv[])94249Sjwahlig main(int argc, char *argv[])
950Sstevel@tonic-gate {
960Sstevel@tonic-gate 	int pid;
970Sstevel@tonic-gate 	int i;
980Sstevel@tonic-gate 	struct protob *protobp;
990Sstevel@tonic-gate 	struct flock f;
1000Sstevel@tonic-gate 	pid_t pi;
1010Sstevel@tonic-gate 	struct svcpool_args cb_svcpool;
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 	MyName = "nfs4cbd";
1040Sstevel@tonic-gate 	Mysvc4 = nfs4svc;
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate #ifndef	DEBUG
1070Sstevel@tonic-gate 	/*
1080Sstevel@tonic-gate 	 * Close existing file descriptors, open "/dev/null" as
1090Sstevel@tonic-gate 	 * standard input, output, and error, and detach from
1100Sstevel@tonic-gate 	 * controlling terminal.
1110Sstevel@tonic-gate 	 */
1120Sstevel@tonic-gate 	closefrom(0);
1130Sstevel@tonic-gate 	(void) open("/dev/null", O_RDONLY);
1140Sstevel@tonic-gate 	(void) open("/dev/null", O_WRONLY);
1150Sstevel@tonic-gate 	(void) dup(1);
1160Sstevel@tonic-gate 	(void) setsid();
1170Sstevel@tonic-gate #endif
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 	/*
1200Sstevel@tonic-gate 	 * create a child to continue our work
1210Sstevel@tonic-gate 	 * Parent's exit will tell mount command we're ready to go
1220Sstevel@tonic-gate 	 */
1230Sstevel@tonic-gate 	if ((pi = fork()) > 0) {
1240Sstevel@tonic-gate 		exit(0);
1250Sstevel@tonic-gate 	}
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 	if (pi == -1) {
1280Sstevel@tonic-gate 		(void) syslog(LOG_ERR,
1290Sstevel@tonic-gate 			"Could not start NFS4_CALLBACK service");
1300Sstevel@tonic-gate 		exit(1);
1310Sstevel@tonic-gate 	}
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 	(void) _create_daemon_lock(NFS4CBD, DAEMON_UID, DAEMON_GID);
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 	svcsetprio();
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 	if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET,
1380Sstevel@tonic-gate 	    DAEMON_UID, DAEMON_GID, PRIV_SYS_NFS, (char *)NULL) == -1) {
1390Sstevel@tonic-gate 		(void) fprintf(stderr, "%s must be run with sufficient"
1400Sstevel@tonic-gate 			" privileges\n", argv[0]);
1410Sstevel@tonic-gate 		exit(1);
1420Sstevel@tonic-gate 	}
1430Sstevel@tonic-gate 	/* Basic privileges we don't need, remove from E/P. */
1440Sstevel@tonic-gate 	__fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_FORK, PRIV_FILE_LINK_ANY,
1450Sstevel@tonic-gate 	    PRIV_PROC_SESSION, PRIV_PROC_INFO, (char *)NULL);
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	/*
1480Sstevel@tonic-gate 	 * establish our lock on the lock file and write our pid to it.
1490Sstevel@tonic-gate 	 * exit if some other process holds the lock, or if there's any
1500Sstevel@tonic-gate 	 * error in writing/locking the file.
1510Sstevel@tonic-gate 	 */
1520Sstevel@tonic-gate 	pid = _enter_daemon_lock(NFS4CBD);
1530Sstevel@tonic-gate 	switch (pid) {
1540Sstevel@tonic-gate 	case 0:
1550Sstevel@tonic-gate 		break;
1560Sstevel@tonic-gate 	case -1:
1570Sstevel@tonic-gate 		syslog(LOG_ERR, "error locking for %s: %s", NFS4CBD,
1580Sstevel@tonic-gate 		    strerror(errno));
1590Sstevel@tonic-gate 		exit(2);
1600Sstevel@tonic-gate 	default:
1610Sstevel@tonic-gate 		/* daemon was already running */
1620Sstevel@tonic-gate 		exit(0);
1630Sstevel@tonic-gate 	}
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	openlog(MyName, LOG_PID | LOG_NDELAY, LOG_DAEMON);
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 	cb_svcpool.id = NFS_CB_SVCPOOL_ID;
1680Sstevel@tonic-gate 	cb_svcpool.maxthreads = 0;
1690Sstevel@tonic-gate 	cb_svcpool.redline = 0;
1700Sstevel@tonic-gate 	cb_svcpool.qsize = 0;
1710Sstevel@tonic-gate 	cb_svcpool.timeout = 0;
1720Sstevel@tonic-gate 	cb_svcpool.stksize = 0;
1730Sstevel@tonic-gate 	cb_svcpool.max_same_xprt = 0;
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	/* create a SVC_POOL for the nfsv4 callback deamon */
1760Sstevel@tonic-gate 	if (_nfssys(SVCPOOL_CREATE, &cb_svcpool)) {
1770Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "can't setup NFS_CB SVCPOOL: Exiting");
1780Sstevel@tonic-gate 		exit(1);
1790Sstevel@tonic-gate 	}
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	/*
1820Sstevel@tonic-gate 	 * Set up blocked thread to do LWP creation on behalf of the kernel.
1830Sstevel@tonic-gate 	 */
1840Sstevel@tonic-gate 	if (svcwait(NFS_CB_SVCPOOL_ID)) {
1850Sstevel@tonic-gate 		(void) syslog(LOG_ERR,
1860Sstevel@tonic-gate 		    "Can't set up NFS_CB LWP creator: Exiting");
1870Sstevel@tonic-gate 		exit(1);
1880Sstevel@tonic-gate 	}
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 	/*
1920Sstevel@tonic-gate 	 * Build a protocol block list for registration.
1930Sstevel@tonic-gate 	 */
1940Sstevel@tonic-gate 	protobp = (struct protob *)malloc(sizeof (struct protob));
1950Sstevel@tonic-gate 	protobp->serv = "NFS4_CALLBACK";
1960Sstevel@tonic-gate 	protobp->versmin = NFS_CB;
1970Sstevel@tonic-gate 	protobp->versmax = NFS_CB;
1980Sstevel@tonic-gate 	protobp->program = NFS4_CALLBACK;
1990Sstevel@tonic-gate 	protobp->next = NULL;
2000Sstevel@tonic-gate 
201*12648SSurya.Prakki@Sun.COM 	if (do_all(protobp, NULL) == -1) {
2020Sstevel@tonic-gate 		exit(1);
2030Sstevel@tonic-gate 	}
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	free(protobp);
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	if (num_fds == 0) {
2080Sstevel@tonic-gate 		(void) syslog(LOG_ERR,
2090Sstevel@tonic-gate 		"Could not start NFS4_CALLBACK service for any protocol");
2100Sstevel@tonic-gate 		exit(1);
2110Sstevel@tonic-gate 	}
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	end_listen_fds = num_fds;
2140Sstevel@tonic-gate 	/*
2150Sstevel@tonic-gate 	 * Poll for non-data control events on the transport descriptors.
2160Sstevel@tonic-gate 	 */
2170Sstevel@tonic-gate 	poll_for_action();
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	/*
2200Sstevel@tonic-gate 	 * If we get here, something failed in poll_for_action().
2210Sstevel@tonic-gate 	 */
2220Sstevel@tonic-gate 	return (1);
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate char *
get_uaddr(int fd,struct netconfig * nconf,struct netbuf * nb)2260Sstevel@tonic-gate get_uaddr(int fd, struct netconfig *nconf, struct netbuf *nb)
2270Sstevel@tonic-gate {
2280Sstevel@tonic-gate 	struct nfs_svc_args nsa;
2290Sstevel@tonic-gate 	char *ua, *ua2, *mua = NULL;
2300Sstevel@tonic-gate 	char me[MAXHOSTNAMELEN];
2310Sstevel@tonic-gate 	struct nd_addrlist *nas;
2320Sstevel@tonic-gate 	struct nd_hostserv hs;
2330Sstevel@tonic-gate 	struct nd_mergearg ma;
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	ua = taddr2uaddr(nconf, nb);
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	if (ua == NULL) {
2380Sstevel@tonic-gate #ifdef	DEBUG
2390Sstevel@tonic-gate 		fprintf(stderr, "taddr2uaddr failed for netid %s\n",
2400Sstevel@tonic-gate 			nconf->nc_netid);
2410Sstevel@tonic-gate #endif
2420Sstevel@tonic-gate 		return (NULL);
2430Sstevel@tonic-gate 	}
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	gethostname(me, MAXHOSTNAMELEN);
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 	hs.h_host = me;
2480Sstevel@tonic-gate 	hs.h_serv = "nfs";
2490Sstevel@tonic-gate 	if (netdir_getbyname(nconf, &hs, &nas)) {
2500Sstevel@tonic-gate #ifdef DEBUG
2510Sstevel@tonic-gate 		netdir_perror("netdir_getbyname");
2520Sstevel@tonic-gate #endif
2530Sstevel@tonic-gate 		return (NULL);
2540Sstevel@tonic-gate 	}
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 	ua2 = taddr2uaddr(nconf, nas->n_addrs);
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	if (ua2 == NULL) {
2590Sstevel@tonic-gate #ifdef	DEBUG
2600Sstevel@tonic-gate 		fprintf(stderr, "taddr2uaddr failed for netid %s.\n",
2610Sstevel@tonic-gate 			nconf->nc_netid);
2620Sstevel@tonic-gate #endif
2630Sstevel@tonic-gate 		return (NULL);
2640Sstevel@tonic-gate 	}
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	ma.s_uaddr = ua;
2670Sstevel@tonic-gate 	ma.c_uaddr = ua2;
2680Sstevel@tonic-gate 	ma.m_uaddr = NULL;
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 	if (netdir_options(nconf, ND_MERGEADDR, 0, (char *)&ma)) {
2710Sstevel@tonic-gate #ifdef DEBUG
2720Sstevel@tonic-gate 		netdir_perror("netdir_options");
2730Sstevel@tonic-gate #endif
2740Sstevel@tonic-gate 		return (NULL);
2750Sstevel@tonic-gate 	}
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	mua = ma.m_uaddr;
2780Sstevel@tonic-gate 	return (mua);
2790Sstevel@tonic-gate }
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate /*
2820Sstevel@tonic-gate  * Establish NFS4 callback service thread.
2830Sstevel@tonic-gate  */
2840Sstevel@tonic-gate static int
nfs4svc(int fd,struct netbuf * addrmask,struct netconfig * nconf,int cmd,struct netbuf * addr)2850Sstevel@tonic-gate nfs4svc(int fd, struct netbuf *addrmask, struct netconfig *nconf,
2860Sstevel@tonic-gate 	int cmd, struct netbuf *addr)
2870Sstevel@tonic-gate {
2880Sstevel@tonic-gate 	struct nfs4_svc_args nsa;
2890Sstevel@tonic-gate 	char *ua;
2900Sstevel@tonic-gate 	int error;
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	ua = get_uaddr(fd, nconf, addr);
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	if (ua == NULL) {
2950Sstevel@tonic-gate 		syslog(LOG_NOTICE, "nfsv4 cannot determine local hostname "
2960Sstevel@tonic-gate 			"binding for transport %s - delegations will not be "
2970Sstevel@tonic-gate 			"available on this transport\n", nconf->nc_netid);
2980Sstevel@tonic-gate 		return (0);
2990Sstevel@tonic-gate 	}
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate #ifdef	DEBUG
3020Sstevel@tonic-gate 	if (cmd & NFS4_KRPC_START)
3030Sstevel@tonic-gate 		fprintf(stderr, "nfs4cbd: starting callback rpc on %s %s\n",
3040Sstevel@tonic-gate 			nconf->nc_netid, ua);
3050Sstevel@tonic-gate 	else
3060Sstevel@tonic-gate 		fprintf(stderr, "nfs4cbd: listening on %s %s\n",
3070Sstevel@tonic-gate 			nconf->nc_netid, ua);
3080Sstevel@tonic-gate #endif
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	nsa.fd = fd;
3110Sstevel@tonic-gate 	nsa.cmd = cmd;
3120Sstevel@tonic-gate 	nsa.netid = nconf->nc_netid;
3130Sstevel@tonic-gate 	if (addrmask)
3140Sstevel@tonic-gate 		nsa.addrmask = *addrmask;
3150Sstevel@tonic-gate 	else
3160Sstevel@tonic-gate 		bzero(&nsa.addrmask, sizeof (struct netbuf));
3170Sstevel@tonic-gate 	nsa.addr = ua;
3180Sstevel@tonic-gate 	nsa.protofmly = nconf->nc_protofmly;
3190Sstevel@tonic-gate 	nsa.proto = nconf->nc_proto;
3200Sstevel@tonic-gate 	if ((error = _nfssys(NFS4_SVC, &nsa)) != 0)
3210Sstevel@tonic-gate 		syslog(LOG_ERR, "nfssys NFS4_SVC failed\n");
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 	return (error);
3240Sstevel@tonic-gate }
325