1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * Portions of this source code were derived from Berkeley 4.3 BSD 31 * under license from the Regents of the University of California. 32 */ 33 34 #pragma ident "%Z%%M% %I% %E% SMI" 35 36 /* 37 * This module provides the user level support for the NFSv4 38 * callback program. It is modeled after nfsd. When a nfsv4 39 * mount occurs, the mount command forks and the child runs 40 * start_nfs4_callback. If this is the first mount, then the 41 * process will hang around listening for incoming connection 42 * requests from the nfsv4 server. 43 * 44 * For connection-less protocols, the krpc is started immediately. 45 * For connection oriented protocols, the kernel module is informed 46 * of netid and universal address that it can give this 47 * information to the server during setclientid. 48 */ 49 50 #include <sys/param.h> 51 #include <sys/types.h> 52 #include <syslog.h> 53 #include <tiuser.h> 54 #include <rpc/rpc.h> 55 #include <errno.h> 56 #include <thread.h> 57 #include <sys/resource.h> 58 #include <sys/file.h> 59 #include <nfs/nfs.h> 60 #include <nfs/nfssys.h> 61 #include <stdio.h> 62 #include <stdlib.h> 63 #include <netconfig.h> 64 #include <netdir.h> 65 #include <string.h> 66 #include <unistd.h> 67 #include <stropts.h> 68 #include <sys/tihdr.h> 69 #include <netinet/tcp.h> 70 #include "nfs_tbind.h" 71 #include "thrpool.h" 72 #include <rpcsvc/nfs4_prot.h> 73 #include <netdb.h> 74 #include <signal.h> 75 #include <strings.h> 76 #include <priv_utils.h> 77 #include <rpcsvc/daemon_utils.h> 78 79 static int nfs4svc(int, struct netbuf *, struct netconfig *, int, 80 struct netbuf *); 81 extern int _nfssys(int, void *); 82 83 static char *MyName; 84 85 /* 86 * The following are all globals used by routines in nfs_tbind.c. 87 */ 88 size_t end_listen_fds; /* used by conn_close_oldest() */ 89 size_t num_fds = 0; /* used by multiple routines */ 90 int listen_backlog = 32; /* used by bind_to_{provider,proto}() */ 91 int num_servers; /* used by cots_listen_event() */ 92 int (*Mysvc)(int, struct netbuf, struct netconfig *) = NULL; 93 /* used by cots_listen_event() */ 94 int max_conns_allowed = -1; /* used by cots_listen_event() */ 95 96 int 97 main(int argc, char *argv[]) 98 { 99 int pid; 100 int i; 101 struct protob *protobp; 102 struct flock f; 103 pid_t pi; 104 struct svcpool_args cb_svcpool; 105 106 MyName = "nfs4cbd"; 107 Mysvc4 = nfs4svc; 108 109 #ifndef DEBUG 110 /* 111 * Close existing file descriptors, open "/dev/null" as 112 * standard input, output, and error, and detach from 113 * controlling terminal. 114 */ 115 closefrom(0); 116 (void) open("/dev/null", O_RDONLY); 117 (void) open("/dev/null", O_WRONLY); 118 (void) dup(1); 119 (void) setsid(); 120 #endif 121 122 /* 123 * create a child to continue our work 124 * Parent's exit will tell mount command we're ready to go 125 */ 126 if ((pi = fork()) > 0) { 127 exit(0); 128 } 129 130 if (pi == -1) { 131 (void) syslog(LOG_ERR, 132 "Could not start NFS4_CALLBACK service"); 133 exit(1); 134 } 135 136 (void) _create_daemon_lock(NFS4CBD, DAEMON_UID, DAEMON_GID); 137 138 svcsetprio(); 139 140 if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, 141 DAEMON_UID, DAEMON_GID, PRIV_SYS_NFS, (char *)NULL) == -1) { 142 (void) fprintf(stderr, "%s must be run with sufficient" 143 " privileges\n", argv[0]); 144 exit(1); 145 } 146 /* Basic privileges we don't need, remove from E/P. */ 147 __fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_FORK, PRIV_FILE_LINK_ANY, 148 PRIV_PROC_SESSION, PRIV_PROC_INFO, (char *)NULL); 149 150 /* 151 * establish our lock on the lock file and write our pid to it. 152 * exit if some other process holds the lock, or if there's any 153 * error in writing/locking the file. 154 */ 155 pid = _enter_daemon_lock(NFS4CBD); 156 switch (pid) { 157 case 0: 158 break; 159 case -1: 160 syslog(LOG_ERR, "error locking for %s: %s", NFS4CBD, 161 strerror(errno)); 162 exit(2); 163 default: 164 /* daemon was already running */ 165 exit(0); 166 } 167 168 openlog(MyName, LOG_PID | LOG_NDELAY, LOG_DAEMON); 169 170 cb_svcpool.id = NFS_CB_SVCPOOL_ID; 171 cb_svcpool.maxthreads = 0; 172 cb_svcpool.redline = 0; 173 cb_svcpool.qsize = 0; 174 cb_svcpool.timeout = 0; 175 cb_svcpool.stksize = 0; 176 cb_svcpool.max_same_xprt = 0; 177 178 /* create a SVC_POOL for the nfsv4 callback deamon */ 179 if (_nfssys(SVCPOOL_CREATE, &cb_svcpool)) { 180 (void) syslog(LOG_ERR, "can't setup NFS_CB SVCPOOL: Exiting"); 181 exit(1); 182 } 183 184 /* 185 * Set up blocked thread to do LWP creation on behalf of the kernel. 186 */ 187 if (svcwait(NFS_CB_SVCPOOL_ID)) { 188 (void) syslog(LOG_ERR, 189 "Can't set up NFS_CB LWP creator: Exiting"); 190 exit(1); 191 } 192 193 194 /* 195 * Build a protocol block list for registration. 196 */ 197 protobp = (struct protob *)malloc(sizeof (struct protob)); 198 protobp->serv = "NFS4_CALLBACK"; 199 protobp->versmin = NFS_CB; 200 protobp->versmax = NFS_CB; 201 protobp->program = NFS4_CALLBACK; 202 protobp->next = NULL; 203 204 if (do_all(protobp, NULL, 0) == -1) { 205 exit(1); 206 } 207 208 free(protobp); 209 210 if (num_fds == 0) { 211 (void) syslog(LOG_ERR, 212 "Could not start NFS4_CALLBACK service for any protocol"); 213 exit(1); 214 } 215 216 end_listen_fds = num_fds; 217 /* 218 * Poll for non-data control events on the transport descriptors. 219 */ 220 poll_for_action(); 221 222 /* 223 * If we get here, something failed in poll_for_action(). 224 */ 225 return (1); 226 } 227 228 char * 229 get_uaddr(int fd, struct netconfig *nconf, struct netbuf *nb) 230 { 231 struct nfs_svc_args nsa; 232 char *ua, *ua2, *mua = NULL; 233 char me[MAXHOSTNAMELEN]; 234 struct nd_addrlist *nas; 235 struct nd_hostserv hs; 236 struct nd_mergearg ma; 237 238 ua = taddr2uaddr(nconf, nb); 239 240 if (ua == NULL) { 241 #ifdef DEBUG 242 fprintf(stderr, "taddr2uaddr failed for netid %s\n", 243 nconf->nc_netid); 244 #endif 245 return (NULL); 246 } 247 248 gethostname(me, MAXHOSTNAMELEN); 249 250 hs.h_host = me; 251 hs.h_serv = "nfs"; 252 if (netdir_getbyname(nconf, &hs, &nas)) { 253 #ifdef DEBUG 254 netdir_perror("netdir_getbyname"); 255 #endif 256 return (NULL); 257 } 258 259 ua2 = taddr2uaddr(nconf, nas->n_addrs); 260 261 if (ua2 == NULL) { 262 #ifdef DEBUG 263 fprintf(stderr, "taddr2uaddr failed for netid %s.\n", 264 nconf->nc_netid); 265 #endif 266 return (NULL); 267 } 268 269 ma.s_uaddr = ua; 270 ma.c_uaddr = ua2; 271 ma.m_uaddr = NULL; 272 273 if (netdir_options(nconf, ND_MERGEADDR, 0, (char *)&ma)) { 274 #ifdef DEBUG 275 netdir_perror("netdir_options"); 276 #endif 277 return (NULL); 278 } 279 280 mua = ma.m_uaddr; 281 return (mua); 282 } 283 284 /* 285 * Establish NFS4 callback service thread. 286 */ 287 static int 288 nfs4svc(int fd, struct netbuf *addrmask, struct netconfig *nconf, 289 int cmd, struct netbuf *addr) 290 { 291 struct nfs4_svc_args nsa; 292 char *ua; 293 int error; 294 295 ua = get_uaddr(fd, nconf, addr); 296 297 if (ua == NULL) { 298 syslog(LOG_NOTICE, "nfsv4 cannot determine local hostname " 299 "binding for transport %s - delegations will not be " 300 "available on this transport\n", nconf->nc_netid); 301 return (0); 302 } 303 304 #ifdef DEBUG 305 if (cmd & NFS4_KRPC_START) 306 fprintf(stderr, "nfs4cbd: starting callback rpc on %s %s\n", 307 nconf->nc_netid, ua); 308 else 309 fprintf(stderr, "nfs4cbd: listening on %s %s\n", 310 nconf->nc_netid, ua); 311 #endif 312 313 nsa.fd = fd; 314 nsa.cmd = cmd; 315 nsa.netid = nconf->nc_netid; 316 if (addrmask) 317 nsa.addrmask = *addrmask; 318 else 319 bzero(&nsa.addrmask, sizeof (struct netbuf)); 320 nsa.addr = ua; 321 nsa.protofmly = nconf->nc_protofmly; 322 nsa.proto = nconf->nc_proto; 323 if ((error = _nfssys(NFS4_SVC, &nsa)) != 0) 324 syslog(LOG_ERR, "nfssys NFS4_SVC failed\n"); 325 326 return (error); 327 } 328