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