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