xref: /titanic_41/usr/src/cmd/fs.d/nfs/lib/nfs_tbind.c (revision 9fe74b0bd10ffb93371dc533b2f32b6779992e16)
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 /*
23  * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright (c) 2012 by Delphix. All rights reserved.
25  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
26  * Copyright 2014 Gary Mills
27  */
28 
29 
30 /*
31  * nfs_tbind.c, common part for nfsd and lockd.
32  */
33 
34 #include <tiuser.h>
35 #include <fcntl.h>
36 #include <netconfig.h>
37 #include <stropts.h>
38 #include <errno.h>
39 #include <syslog.h>
40 #include <rpc/rpc.h>
41 #include <sys/time.h>
42 #include <sys/resource.h>
43 #include <signal.h>
44 #include <netdir.h>
45 #include <unistd.h>
46 #include <string.h>
47 #include <netinet/tcp.h>
48 #include <malloc.h>
49 #include <stdlib.h>
50 #include "nfs_tbind.h"
51 #include <nfs/nfs.h>
52 #include <nfs/nfs_acl.h>
53 #include <nfs/nfssys.h>
54 #include <nfs/nfs4.h>
55 #include <zone.h>
56 #include <sys/socket.h>
57 #include <tsol/label.h>
58 
59 /*
60  * Determine valid semantics for most applications.
61  */
62 #define	OK_TPI_TYPE(_nconf) \
63 	(_nconf->nc_semantics == NC_TPI_CLTS || \
64 	_nconf->nc_semantics == NC_TPI_COTS || \
65 	_nconf->nc_semantics == NC_TPI_COTS_ORD)
66 
67 #define	BE32_TO_U32(a) \
68 	((((ulong_t)((uchar_t *)a)[0] & 0xFF) << (ulong_t)24) | \
69 	(((ulong_t)((uchar_t *)a)[1] & 0xFF) << (ulong_t)16) | \
70 	(((ulong_t)((uchar_t *)a)[2] & 0xFF) << (ulong_t)8)  | \
71 	((ulong_t)((uchar_t *)a)[3] & 0xFF))
72 
73 /*
74  * Number of elements to add to the poll array on each allocation.
75  */
76 #define	POLL_ARRAY_INC_SIZE	64
77 
78 /*
79  * Number of file descriptors by which the process soft limit may be
80  * increased on each call to nofile_increase(0).
81  */
82 #define	NOFILE_INC_SIZE	64
83 
84 /*
85  * Default TCP send and receive buffer size of NFS server.
86  */
87 #define	NFSD_TCP_BUFSZ	(1024*1024)
88 
89 struct conn_ind {
90 	struct conn_ind *conn_next;
91 	struct conn_ind *conn_prev;
92 	struct t_call   *conn_call;
93 };
94 
95 struct conn_entry {
96 	bool_t			closing;
97 	struct netconfig	nc;
98 };
99 
100 /*
101  * this file contains transport routines common to nfsd and lockd
102  */
103 static	int	nofile_increase(int);
104 static	int	reuseaddr(int);
105 static	int	recvucred(int);
106 static  int	anonmlp(int);
107 static	void	add_to_poll_list(int, struct netconfig *);
108 static	char	*serv_name_to_port_name(char *);
109 static	int	bind_to_proto(char *, char *, struct netbuf **,
110 				struct netconfig **);
111 static	int	bind_to_provider(char *, char *, struct netbuf **,
112 					struct netconfig **);
113 static	void	conn_close_oldest(void);
114 static	boolean_t conn_get(int, struct netconfig *, struct conn_ind **);
115 static	void	cots_listen_event(int, int);
116 static	int	discon_get(int, struct netconfig *, struct conn_ind **);
117 static	int	do_poll_clts_action(int, int);
118 static	int	do_poll_cots_action(int, int);
119 static	void	remove_from_poll_list(int);
120 static	int	set_addrmask(int, struct netconfig *, struct netbuf *);
121 static	int	is_listen_fd_index(int);
122 
123 static	struct pollfd *poll_array;
124 static	struct conn_entry *conn_polled;
125 static	int	num_conns;		/* Current number of connections */
126 int		(*Mysvc4)(int, struct netbuf *, struct netconfig *, int,
127 		struct netbuf *);
128 static int	setopt(int fd, int level, int name, int value);
129 static int	get_opt(int fd, int level, int name);
130 static void	nfslib_set_sockbuf(int fd);
131 
132 /*
133  * Called to create and prepare a transport descriptor for in-kernel
134  * RPC service.
135  * Returns -1 on failure and a valid descriptor on success.
136  */
137 int
nfslib_transport_open(struct netconfig * nconf)138 nfslib_transport_open(struct netconfig *nconf)
139 {
140 	int fd;
141 	struct strioctl	strioc;
142 
143 	if ((nconf == (struct netconfig *)NULL) ||
144 	    (nconf->nc_device == (char *)NULL)) {
145 		syslog(LOG_ERR, "no netconfig device");
146 		return (-1);
147 	}
148 
149 	/*
150 	 * Open the transport device.
151 	 */
152 	fd = t_open(nconf->nc_device, O_RDWR, (struct t_info *)NULL);
153 	if (fd == -1) {
154 		if (t_errno == TSYSERR && errno == EMFILE &&
155 		    (nofile_increase(0) == 0)) {
156 			/* Try again with a higher NOFILE limit. */
157 			fd = t_open(nconf->nc_device, O_RDWR,
158 			    (struct t_info *)NULL);
159 		}
160 		if (fd == -1) {
161 			syslog(LOG_ERR, "t_open %s failed:  t_errno %d, %m",
162 			    nconf->nc_device, t_errno);
163 			return (-1);
164 		}
165 	}
166 
167 	/*
168 	 * Pop timod because the RPC module must be as close as possible
169 	 * to the transport.
170 	 */
171 	if (ioctl(fd, I_POP, 0) < 0) {
172 		syslog(LOG_ERR, "I_POP of timod failed: %m");
173 		(void) t_close(fd);
174 		return (-1);
175 	}
176 
177 	/*
178 	 * Common code for CLTS and COTS transports
179 	 */
180 	if (ioctl(fd, I_PUSH, "rpcmod") < 0) {
181 		syslog(LOG_ERR, "I_PUSH of rpcmod failed: %m");
182 		(void) t_close(fd);
183 		return (-1);
184 	}
185 
186 	strioc.ic_cmd = RPC_SERVER;
187 	strioc.ic_dp = (char *)0;
188 	strioc.ic_len = 0;
189 	strioc.ic_timout = -1;
190 
191 	/* Tell rpcmod to act like a server stream. */
192 	if (ioctl(fd, I_STR, &strioc) < 0) {
193 		syslog(LOG_ERR, "rpcmod set-up ioctl failed: %m");
194 		(void) t_close(fd);
195 		return (-1);
196 	}
197 
198 	/*
199 	 * Re-push timod so that we will still be doing TLI
200 	 * operations on the descriptor.
201 	 */
202 	if (ioctl(fd, I_PUSH, "timod") < 0) {
203 		syslog(LOG_ERR, "I_PUSH of timod failed: %m");
204 		(void) t_close(fd);
205 		return (-1);
206 	}
207 
208 	/*
209 	 * Enable options of returning the ip's for udp.
210 	 */
211 	if (strcmp(nconf->nc_netid, "udp6") == 0)
212 		__rpc_tli_set_options(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, 1);
213 	else if (strcmp(nconf->nc_netid, "udp") == 0)
214 		__rpc_tli_set_options(fd, IPPROTO_IP, IP_RECVDSTADDR, 1);
215 
216 	return (fd);
217 }
218 
219 static int
nofile_increase(int limit)220 nofile_increase(int limit)
221 {
222 	struct rlimit rl;
223 
224 	if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
225 		syslog(LOG_ERR, "getrlimit of NOFILE failed: %m");
226 		return (-1);
227 	}
228 
229 	if (limit > 0)
230 		rl.rlim_cur = limit;
231 	else
232 		rl.rlim_cur += NOFILE_INC_SIZE;
233 
234 	if (rl.rlim_cur > rl.rlim_max &&
235 	    rl.rlim_max != RLIM_INFINITY)
236 		rl.rlim_max = rl.rlim_cur;
237 
238 	if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
239 		syslog(LOG_ERR, "setrlimit of NOFILE to %d failed: %m",
240 		    rl.rlim_cur);
241 		return (-1);
242 	}
243 
244 	return (0);
245 }
246 
247 static void
nfslib_set_sockbuf(int fd)248 nfslib_set_sockbuf(int fd)
249 {
250 	int curval, val;
251 
252 	val = NFSD_TCP_BUFSZ;
253 
254 	curval = get_opt(fd, SOL_SOCKET, SO_SNDBUF);
255 	syslog(LOG_DEBUG, "Current SO_SNDBUF value is %d", curval);
256 	if ((curval != -1) && (curval < val)) {
257 		syslog(LOG_DEBUG, "Set SO_SNDBUF  option to %d", val);
258 		if (setopt(fd, SOL_SOCKET, SO_SNDBUF, val) < 0) {
259 			syslog(LOG_ERR,
260 			    "couldn't set SO_SNDBUF to %d - t_errno = %d",
261 			    val, t_errno);
262 			syslog(LOG_ERR,
263 			    "Check and increase system-wide tcp_max_buf");
264 		}
265 	}
266 
267 	curval = get_opt(fd, SOL_SOCKET, SO_RCVBUF);
268 	syslog(LOG_DEBUG, "Current SO_RCVBUF value is %d", curval);
269 	if ((curval != -1) && (curval < val)) {
270 		syslog(LOG_DEBUG, "Set SO_RCVBUF  option to %d", val);
271 		if (setopt(fd, SOL_SOCKET, SO_RCVBUF, val) < 0) {
272 			syslog(LOG_ERR,
273 			    "couldn't set SO_RCVBUF to %d - t_errno = %d",
274 			    val, t_errno);
275 			syslog(LOG_ERR,
276 			    "Check and increase system-wide tcp_max_buf");
277 		}
278 	}
279 }
280 
281 int
nfslib_bindit(struct netconfig * nconf,struct netbuf ** addr,struct nd_hostserv * hs,int backlog)282 nfslib_bindit(struct netconfig *nconf, struct netbuf **addr,
283 	struct nd_hostserv *hs, int backlog)
284 {
285 	int fd;
286 	struct t_bind  *ntb;
287 	struct t_bind tb;
288 	struct nd_addrlist *addrlist;
289 	struct t_optmgmt req, resp;
290 	struct opthdr *opt;
291 	char reqbuf[128];
292 	bool_t use_any = FALSE;
293 	bool_t gzone = TRUE;
294 
295 	if ((fd = nfslib_transport_open(nconf)) == -1) {
296 		syslog(LOG_ERR, "cannot establish transport service over %s",
297 		    nconf->nc_device);
298 		return (-1);
299 	}
300 
301 	addrlist = (struct nd_addrlist *)NULL;
302 
303 	/* nfs4_callback service does not used a fieed port number */
304 
305 	if (strcmp(hs->h_serv, "nfs4_callback") == 0) {
306 		tb.addr.maxlen = 0;
307 		tb.addr.len = 0;
308 		tb.addr.buf = 0;
309 		use_any = TRUE;
310 		gzone = (getzoneid() == GLOBAL_ZONEID);
311 	} else if (netdir_getbyname(nconf, hs, &addrlist) != 0) {
312 
313 		syslog(LOG_ERR,
314 		"Cannot get address for transport %s host %s service %s",
315 		    nconf->nc_netid, hs->h_host, hs->h_serv);
316 		(void) t_close(fd);
317 		return (-1);
318 	}
319 
320 	if (strcmp(nconf->nc_proto, "tcp") == 0) {
321 		/*
322 		 * If we're running over TCP, then set the
323 		 * SO_REUSEADDR option so that we can bind
324 		 * to our preferred address even if previously
325 		 * left connections exist in FIN_WAIT states.
326 		 * This is somewhat bogus, but otherwise you have
327 		 * to wait 2 minutes to restart after killing it.
328 		 */
329 		if (reuseaddr(fd) == -1) {
330 			syslog(LOG_WARNING,
331 			"couldn't set SO_REUSEADDR option on transport");
332 		}
333 	} else if (strcmp(nconf->nc_proto, "udp") == 0) {
334 		/*
335 		 * In order to run MLP on UDP, we need to handle creds.
336 		 */
337 		if (recvucred(fd) == -1) {
338 			syslog(LOG_WARNING,
339 			    "couldn't set SO_RECVUCRED option on transport");
340 		}
341 	}
342 
343 	/*
344 	 * Make non global zone nfs4_callback port MLP
345 	 */
346 	if (use_any && is_system_labeled() && !gzone) {
347 		if (anonmlp(fd) == -1) {
348 			/*
349 			 * failing to set this option means nfs4_callback
350 			 * could fail silently later. So fail it with
351 			 * with an error message now.
352 			 */
353 			syslog(LOG_ERR,
354 			    "couldn't set SO_ANON_MLP option on transport");
355 			(void) t_close(fd);
356 			return (-1);
357 		}
358 	}
359 
360 	if (nconf->nc_semantics == NC_TPI_CLTS)
361 		tb.qlen = 0;
362 	else
363 		tb.qlen = backlog;
364 
365 	/* LINTED pointer alignment */
366 	ntb = (struct t_bind *)t_alloc(fd, T_BIND, T_ALL);
367 	if (ntb == (struct t_bind *)NULL) {
368 		syslog(LOG_ERR, "t_alloc failed:  t_errno %d, %m", t_errno);
369 		(void) t_close(fd);
370 		netdir_free((void *)addrlist, ND_ADDRLIST);
371 		return (-1);
372 	}
373 
374 	/*
375 	 * XXX - what about the space tb->addr.buf points to? This should
376 	 * be either a memcpy() to/from the buf fields, or t_alloc(fd,T_BIND,)
377 	 * should't be called with T_ALL.
378 	 */
379 	if (addrlist)
380 		tb.addr = *(addrlist->n_addrs);		/* structure copy */
381 
382 	if (t_bind(fd, &tb, ntb) == -1) {
383 		syslog(LOG_ERR, "t_bind failed:  t_errno %d, %m", t_errno);
384 		(void) t_free((char *)ntb, T_BIND);
385 		netdir_free((void *)addrlist, ND_ADDRLIST);
386 		(void) t_close(fd);
387 		return (-1);
388 	}
389 
390 	/* make sure we bound to the right address */
391 	if (use_any == FALSE &&
392 	    (tb.addr.len != ntb->addr.len ||
393 	    memcmp(tb.addr.buf, ntb->addr.buf, tb.addr.len) != 0)) {
394 		syslog(LOG_ERR, "t_bind to wrong address");
395 		(void) t_free((char *)ntb, T_BIND);
396 		netdir_free((void *)addrlist, ND_ADDRLIST);
397 		(void) t_close(fd);
398 		return (-1);
399 	}
400 
401 	/*
402 	 * Call nfs4svc_setport so that the kernel can be
403 	 * informed what port number the daemon is listing
404 	 * for incoming connection requests.
405 	 */
406 
407 	if ((nconf->nc_semantics == NC_TPI_COTS ||
408 	    nconf->nc_semantics == NC_TPI_COTS_ORD) && Mysvc4 != NULL)
409 		(*Mysvc4)(fd, NULL, nconf, NFS4_SETPORT, &ntb->addr);
410 
411 	*addr = &ntb->addr;
412 	netdir_free((void *)addrlist, ND_ADDRLIST);
413 
414 	if (strcmp(nconf->nc_proto, "tcp") == 0) {
415 		/*
416 		 * Disable the Nagle algorithm on TCP connections.
417 		 * Connections accepted from this listener will
418 		 * inherit the listener options.
419 		 */
420 
421 		/* LINTED pointer alignment */
422 		opt = (struct opthdr *)reqbuf;
423 		opt->level = IPPROTO_TCP;
424 		opt->name = TCP_NODELAY;
425 		opt->len = sizeof (int);
426 
427 		/* LINTED pointer alignment */
428 		*(int *)((char *)opt + sizeof (*opt)) = 1;
429 
430 		req.flags = T_NEGOTIATE;
431 		req.opt.len = sizeof (*opt) + opt->len;
432 		req.opt.buf = (char *)opt;
433 		resp.flags = 0;
434 		resp.opt.buf = reqbuf;
435 		resp.opt.maxlen = sizeof (reqbuf);
436 
437 		if (t_optmgmt(fd, &req, &resp) < 0 ||
438 		    resp.flags != T_SUCCESS) {
439 			syslog(LOG_ERR,
440 	"couldn't set NODELAY option for proto %s: t_errno = %d, %m",
441 			    nconf->nc_proto, t_errno);
442 		}
443 
444 		nfslib_set_sockbuf(fd);
445 	}
446 
447 	return (fd);
448 }
449 
450 static int
get_opt(int fd,int level,int name)451 get_opt(int fd, int level, int name)
452 {
453 	struct t_optmgmt req, res;
454 	struct {
455 		struct opthdr opt;
456 		int value;
457 	} reqbuf;
458 
459 	reqbuf.opt.level = level;
460 	reqbuf.opt.name = name;
461 	reqbuf.opt.len = sizeof (int);
462 	reqbuf.value = 0;
463 
464 	req.flags = T_CURRENT;
465 	req.opt.len = sizeof (reqbuf);
466 	req.opt.buf = (char *)&reqbuf;
467 
468 	res.flags = 0;
469 	res.opt.buf = (char *)&reqbuf;
470 	res.opt.maxlen = sizeof (reqbuf);
471 
472 	if (t_optmgmt(fd, &req, &res) < 0 || res.flags != T_SUCCESS) {
473 		t_error("t_optmgmt");
474 		return (-1);
475 	}
476 	return (reqbuf.value);
477 }
478 
479 static int
setopt(int fd,int level,int name,int value)480 setopt(int fd, int level, int name, int value)
481 {
482 	struct t_optmgmt req, resp;
483 	struct {
484 		struct opthdr opt;
485 		int value;
486 	} reqbuf;
487 
488 	reqbuf.opt.level = level;
489 	reqbuf.opt.name = name;
490 	reqbuf.opt.len = sizeof (int);
491 
492 	reqbuf.value = value;
493 
494 	req.flags = T_NEGOTIATE;
495 	req.opt.len = sizeof (reqbuf);
496 	req.opt.buf = (char *)&reqbuf;
497 
498 	resp.flags = 0;
499 	resp.opt.buf = (char *)&reqbuf;
500 	resp.opt.maxlen = sizeof (reqbuf);
501 
502 	if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
503 		t_error("t_optmgmt");
504 		return (-1);
505 	}
506 	return (0);
507 }
508 
509 static int
reuseaddr(int fd)510 reuseaddr(int fd)
511 {
512 	return (setopt(fd, SOL_SOCKET, SO_REUSEADDR, 1));
513 }
514 
515 static int
recvucred(int fd)516 recvucred(int fd)
517 {
518 	return (setopt(fd, SOL_SOCKET, SO_RECVUCRED, 1));
519 }
520 
521 static int
anonmlp(int fd)522 anonmlp(int fd)
523 {
524 	return (setopt(fd, SOL_SOCKET, SO_ANON_MLP, 1));
525 }
526 
527 void
nfslib_log_tli_error(char * tli_name,int fd,struct netconfig * nconf)528 nfslib_log_tli_error(char *tli_name, int fd, struct netconfig *nconf)
529 {
530 	int error;
531 
532 	/*
533 	 * Save the error code across syslog(), just in case syslog()
534 	 * gets its own error and, therefore, overwrites errno.
535 	 */
536 	error = errno;
537 	if (t_errno == TSYSERR) {
538 		syslog(LOG_ERR, "%s(file descriptor %d/transport %s) %m",
539 		    tli_name, fd, nconf->nc_proto);
540 	} else {
541 		syslog(LOG_ERR,
542 		    "%s(file descriptor %d/transport %s) TLI error %d",
543 		    tli_name, fd, nconf->nc_proto, t_errno);
544 	}
545 	errno = error;
546 }
547 
548 /*
549  * Called to set up service over a particular transport.
550  */
551 void
do_one(char * provider,NETSELDECL (proto),struct protob * protobp0,int (* svc)(int,struct netbuf,struct netconfig *))552 do_one(char *provider, NETSELDECL(proto), struct protob *protobp0,
553 	int (*svc)(int, struct netbuf, struct netconfig *))
554 {
555 	register int sock;
556 	struct protob *protobp;
557 	struct netbuf *retaddr;
558 	struct netconfig *retnconf;
559 	struct netbuf addrmask;
560 	int vers;
561 	int err;
562 	int l;
563 
564 	if (provider)
565 		sock = bind_to_provider(provider, protobp0->serv, &retaddr,
566 		    &retnconf);
567 	else
568 		sock = bind_to_proto(proto, protobp0->serv, &retaddr,
569 		    &retnconf);
570 
571 	if (sock == -1) {
572 		(void) syslog(LOG_ERR,
573 	"Cannot establish %s service over %s: transport setup problem.",
574 		    protobp0->serv, provider ? provider : proto);
575 		return;
576 	}
577 
578 	if (set_addrmask(sock, retnconf, &addrmask) < 0) {
579 		(void) syslog(LOG_ERR,
580 		    "Cannot set address mask for %s", retnconf->nc_netid);
581 		return;
582 	}
583 
584 	/*
585 	 * Register all versions of the programs in the protocol block list.
586 	 */
587 	l = strlen(NC_UDP);
588 	for (protobp = protobp0; protobp; protobp = protobp->next) {
589 		for (vers = protobp->versmin; vers <= protobp->versmax;
590 		    vers++) {
591 			if ((protobp->program == NFS_PROGRAM ||
592 			    protobp->program == NFS_ACL_PROGRAM) &&
593 			    vers == NFS_V4 &&
594 			    strncasecmp(retnconf->nc_proto, NC_UDP, l) == 0)
595 				continue;
596 
597 			(void) rpcb_unset(protobp->program, vers, retnconf);
598 			(void) rpcb_set(protobp->program, vers, retnconf,
599 			    retaddr);
600 		}
601 	}
602 
603 	/*
604 	 * Register services with CLTS semantics right now.
605 	 * Note: services with COTS/COTS_ORD semantics will be
606 	 * registered later from cots_listen_event function.
607 	 */
608 	if (retnconf->nc_semantics == NC_TPI_CLTS) {
609 		/* Don't drop core if supporting module(s) aren't loaded. */
610 		(void) signal(SIGSYS, SIG_IGN);
611 
612 		/*
613 		 * svc() doesn't block, it returns success or failure.
614 		 */
615 
616 		if (svc == NULL && Mysvc4 != NULL)
617 			err = (*Mysvc4)(sock, &addrmask, retnconf,
618 			    NFS4_SETPORT|NFS4_KRPC_START, retaddr);
619 		else
620 			err = (*svc)(sock, addrmask, retnconf);
621 
622 		if (err < 0) {
623 			(void) syslog(LOG_ERR,
624 			    "Cannot establish %s service over <file desc."
625 			    " %d, protocol %s> : %m. Exiting",
626 			    protobp0->serv, sock, retnconf->nc_proto);
627 			exit(1);
628 		}
629 	}
630 	free(addrmask.buf);
631 
632 	/*
633 	 * We successfully set up the server over this transport.
634 	 * Add this descriptor to the one being polled on.
635 	 */
636 	add_to_poll_list(sock, retnconf);
637 }
638 
639 /*
640  * Set up the NFS service over all the available transports.
641  * Returns -1 for failure, 0 for success.
642  */
643 int
do_all(struct protob * protobp,int (* svc)(int,struct netbuf,struct netconfig *))644 do_all(struct protob *protobp,
645 	int (*svc)(int, struct netbuf, struct netconfig *))
646 {
647 	struct netconfig *nconf;
648 	NCONF_HANDLE *nc;
649 	int l;
650 
651 	if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
652 		syslog(LOG_ERR, "setnetconfig failed: %m");
653 		return (-1);
654 	}
655 	l = strlen(NC_UDP);
656 	while (nconf = getnetconfig(nc)) {
657 		if ((nconf->nc_flag & NC_VISIBLE) &&
658 		    strcmp(nconf->nc_protofmly, NC_LOOPBACK) != 0 &&
659 		    OK_TPI_TYPE(nconf) &&
660 		    (protobp->program != NFS4_CALLBACK ||
661 		    strncasecmp(nconf->nc_proto, NC_UDP, l) != 0))
662 			do_one(nconf->nc_device, nconf->nc_proto,
663 			    protobp, svc);
664 	}
665 	(void) endnetconfig(nc);
666 	return (0);
667 }
668 
669 /*
670  * poll on the open transport descriptors for events and errors.
671  */
672 void
poll_for_action(void)673 poll_for_action(void)
674 {
675 	int nfds;
676 	int i;
677 
678 	/*
679 	 * Keep polling until all transports have been closed. When this
680 	 * happens, we return.
681 	 */
682 	while ((int)num_fds > 0) {
683 		nfds = poll(poll_array, num_fds, INFTIM);
684 		switch (nfds) {
685 		case 0:
686 			continue;
687 
688 		case -1:
689 			/*
690 			 * Some errors from poll could be
691 			 * due to temporary conditions, and we try to
692 			 * be robust in the face of them. Other
693 			 * errors (should never happen in theory)
694 			 * are fatal (eg. EINVAL, EFAULT).
695 			 */
696 			switch (errno) {
697 			case EINTR:
698 				continue;
699 
700 			case EAGAIN:
701 			case ENOMEM:
702 				(void) sleep(10);
703 				continue;
704 
705 			default:
706 				(void) syslog(LOG_ERR,
707 				    "poll failed: %m. Exiting");
708 				exit(1);
709 			}
710 		default:
711 			break;
712 		}
713 
714 		/*
715 		 * Go through the poll list looking for events.
716 		 */
717 		for (i = 0; i < num_fds && nfds > 0; i++) {
718 			if (poll_array[i].revents) {
719 				nfds--;
720 				/*
721 				 * We have a message, so try to read it.
722 				 * Record the error return in errno,
723 				 * so that syslog(LOG_ERR, "...%m")
724 				 * dumps the corresponding error string.
725 				 */
726 				if (conn_polled[i].nc.nc_semantics ==
727 				    NC_TPI_CLTS) {
728 					errno = do_poll_clts_action(
729 					    poll_array[i].fd, i);
730 				} else {
731 					errno = do_poll_cots_action(
732 					    poll_array[i].fd, i);
733 				}
734 
735 				if (errno == 0)
736 					continue;
737 				/*
738 				 * Most returned error codes mean that there is
739 				 * fatal condition which we can only deal with
740 				 * by closing the transport.
741 				 */
742 				if (errno != EAGAIN && errno != ENOMEM) {
743 					(void) syslog(LOG_ERR,
744 		"Error (%m) reading descriptor %d/transport %s. Closing it.",
745 					    poll_array[i].fd,
746 					    conn_polled[i].nc.nc_proto);
747 					(void) t_close(poll_array[i].fd);
748 					remove_from_poll_list(poll_array[i].fd);
749 
750 				} else if (errno == ENOMEM)
751 					(void) sleep(5);
752 			}
753 		}
754 	}
755 
756 	(void) syslog(LOG_ERR,
757 	    "All transports have been closed with errors. Exiting.");
758 }
759 
760 /*
761  * Allocate poll/transport array entries for this descriptor.
762  */
763 static void
add_to_poll_list(int fd,struct netconfig * nconf)764 add_to_poll_list(int fd, struct netconfig *nconf)
765 {
766 	static int poll_array_size = 0;
767 
768 	/*
769 	 * If the arrays are full, allocate new ones.
770 	 */
771 	if (num_fds == poll_array_size) {
772 		struct pollfd *tpa;
773 		struct conn_entry *tnp;
774 
775 		if (poll_array_size != 0) {
776 			tpa = poll_array;
777 			tnp = conn_polled;
778 		} else
779 			tpa = (struct pollfd *)0;
780 
781 		poll_array_size += POLL_ARRAY_INC_SIZE;
782 		/*
783 		 * Allocate new arrays.
784 		 */
785 		poll_array = (struct pollfd *)
786 		    malloc(poll_array_size * sizeof (struct pollfd) + 256);
787 		conn_polled = (struct conn_entry *)
788 		    malloc(poll_array_size * sizeof (struct conn_entry) + 256);
789 		if (poll_array == (struct pollfd *)NULL ||
790 		    conn_polled == (struct conn_entry *)NULL) {
791 			syslog(LOG_ERR, "malloc failed for poll array");
792 			exit(1);
793 		}
794 
795 		/*
796 		 * Copy the data of the old ones into new arrays, and
797 		 * free the old ones.
798 		 */
799 		if (tpa) {
800 			(void) memcpy((void *)poll_array, (void *)tpa,
801 			    num_fds * sizeof (struct pollfd));
802 			(void) memcpy((void *)conn_polled, (void *)tnp,
803 			    num_fds * sizeof (struct conn_entry));
804 			free((void *)tpa);
805 			free((void *)tnp);
806 		}
807 	}
808 
809 	/*
810 	 * Set the descriptor and event list. All possible events are
811 	 * polled for.
812 	 */
813 	poll_array[num_fds].fd = fd;
814 	poll_array[num_fds].events = POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI;
815 
816 	/*
817 	 * Copy the transport data over too.
818 	 */
819 	conn_polled[num_fds].nc = *nconf;
820 	conn_polled[num_fds].closing = 0;
821 
822 	/*
823 	 * Set the descriptor to non-blocking. Avoids a race
824 	 * between data arriving on the stream and then having it
825 	 * flushed before we can read it.
826 	 */
827 	if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
828 		(void) syslog(LOG_ERR,
829 	"fcntl(file desc. %d/transport %s, F_SETFL, O_NONBLOCK): %m. Exiting",
830 		    num_fds, nconf->nc_proto);
831 		exit(1);
832 	}
833 
834 	/*
835 	 * Count this descriptor.
836 	 */
837 	++num_fds;
838 }
839 
840 static void
remove_from_poll_list(int fd)841 remove_from_poll_list(int fd)
842 {
843 	int i;
844 	int num_to_copy;
845 
846 	for (i = 0; i < num_fds; i++) {
847 		if (poll_array[i].fd == fd) {
848 			--num_fds;
849 			num_to_copy = num_fds - i;
850 			(void) memcpy((void *)&poll_array[i],
851 			    (void *)&poll_array[i+1],
852 			    num_to_copy * sizeof (struct pollfd));
853 			(void) memset((void *)&poll_array[num_fds], 0,
854 			    sizeof (struct pollfd));
855 			(void) memcpy((void *)&conn_polled[i],
856 			    (void *)&conn_polled[i+1],
857 			    num_to_copy * sizeof (struct conn_entry));
858 			(void) memset((void *)&conn_polled[num_fds], 0,
859 			    sizeof (struct conn_entry));
860 			return;
861 		}
862 	}
863 	syslog(LOG_ERR, "attempt to remove nonexistent fd from poll list");
864 
865 }
866 
867 /*
868  * Called to read and interpret the event on a connectionless descriptor.
869  * Returns 0 if successful, or a UNIX error code if failure.
870  */
871 static int
do_poll_clts_action(int fd,int conn_index)872 do_poll_clts_action(int fd, int conn_index)
873 {
874 	int error;
875 	int ret;
876 	int flags;
877 	struct netconfig *nconf = &conn_polled[conn_index].nc;
878 	static struct t_unitdata *unitdata = NULL;
879 	static struct t_uderr *uderr = NULL;
880 	static int oldfd = -1;
881 	struct nd_hostservlist *host = NULL;
882 	struct strbuf ctl[1], data[1];
883 	/*
884 	 * We just need to have some space to consume the
885 	 * message in the event we can't use the TLI interface to do the
886 	 * job.
887 	 *
888 	 * We flush the message using getmsg(). For the control part
889 	 * we allocate enough for any TPI header plus 32 bytes for address
890 	 * and options. For the data part, there is nothing magic about
891 	 * the size of the array, but 256 bytes is probably better than
892 	 * 1 byte, and we don't expect any data portion anyway.
893 	 *
894 	 * If the array sizes are too small, we handle this because getmsg()
895 	 * (called to consume the message) will return MOREDATA|MORECTL.
896 	 * Thus we just call getmsg() until it's read the message.
897 	 */
898 	char ctlbuf[sizeof (union T_primitives) + 32];
899 	char databuf[256];
900 
901 	/*
902 	 * If this is the same descriptor as the last time
903 	 * do_poll_clts_action was called, we can save some
904 	 * de-allocation and allocation.
905 	 */
906 	if (oldfd != fd) {
907 		oldfd = fd;
908 
909 		if (unitdata) {
910 			(void) t_free((char *)unitdata, T_UNITDATA);
911 			unitdata = NULL;
912 		}
913 		if (uderr) {
914 			(void) t_free((char *)uderr, T_UDERROR);
915 			uderr = NULL;
916 		}
917 	}
918 
919 	/*
920 	 * Allocate a unitdata structure for receiving the event.
921 	 */
922 	if (unitdata == NULL) {
923 		/* LINTED pointer alignment */
924 		unitdata = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ALL);
925 		if (unitdata == NULL) {
926 			if (t_errno == TSYSERR) {
927 				/*
928 				 * Save the error code across
929 				 * syslog(), just in case
930 				 * syslog() gets its own error
931 				 * and therefore overwrites errno.
932 				 */
933 				error = errno;
934 				(void) syslog(LOG_ERR,
935 	"t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed: %m",
936 				    fd, nconf->nc_proto);
937 				return (error);
938 			}
939 			(void) syslog(LOG_ERR,
940 "t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed TLI error %d",
941 			    fd, nconf->nc_proto, t_errno);
942 			goto flush_it;
943 		}
944 	}
945 
946 try_again:
947 	flags = 0;
948 
949 	/*
950 	 * The idea is we wait for T_UNITDATA_IND's. Of course,
951 	 * we don't get any, because rpcmod filters them out.
952 	 * However, we need to call t_rcvudata() to let TLI
953 	 * tell us we have a T_UDERROR_IND.
954 	 *
955 	 * algorithm is:
956 	 * 	t_rcvudata(), expecting TLOOK.
957 	 * 	t_look(), expecting T_UDERR.
958 	 * 	t_rcvuderr(), expecting success (0).
959 	 * 	expand destination address into ASCII,
960 	 *	and dump it.
961 	 */
962 
963 	ret = t_rcvudata(fd, unitdata, &flags);
964 	if (ret == 0 || t_errno == TBUFOVFLW) {
965 		(void) syslog(LOG_WARNING,
966 "t_rcvudata(file descriptor %d/transport %s) got unexpected data, %d bytes",
967 		    fd, nconf->nc_proto, unitdata->udata.len);
968 
969 		/*
970 		 * Even though we don't expect any data, in case we do,
971 		 * keep reading until there is no more.
972 		 */
973 		if (flags & T_MORE)
974 			goto try_again;
975 
976 		return (0);
977 	}
978 
979 	switch (t_errno) {
980 	case TNODATA:
981 		return (0);
982 	case TSYSERR:
983 		/*
984 		 * System errors are returned to caller.
985 		 * Save the error code across
986 		 * syslog(), just in case
987 		 * syslog() gets its own error
988 		 * and therefore overwrites errno.
989 		 */
990 		error = errno;
991 		(void) syslog(LOG_ERR,
992 		    "t_rcvudata(file descriptor %d/transport %s) %m",
993 		    fd, nconf->nc_proto);
994 		return (error);
995 	case TLOOK:
996 		break;
997 	default:
998 		(void) syslog(LOG_ERR,
999 		"t_rcvudata(file descriptor %d/transport %s) TLI error %d",
1000 		    fd, nconf->nc_proto, t_errno);
1001 		goto flush_it;
1002 	}
1003 
1004 	ret = t_look(fd);
1005 	switch (ret) {
1006 	case 0:
1007 		return (0);
1008 	case -1:
1009 		/*
1010 		 * System errors are returned to caller.
1011 		 */
1012 		if (t_errno == TSYSERR) {
1013 			/*
1014 			 * Save the error code across
1015 			 * syslog(), just in case
1016 			 * syslog() gets its own error
1017 			 * and therefore overwrites errno.
1018 			 */
1019 			error = errno;
1020 			(void) syslog(LOG_ERR,
1021 			    "t_look(file descriptor %d/transport %s) %m",
1022 			    fd, nconf->nc_proto);
1023 			return (error);
1024 		}
1025 		(void) syslog(LOG_ERR,
1026 		    "t_look(file descriptor %d/transport %s) TLI error %d",
1027 		    fd, nconf->nc_proto, t_errno);
1028 		goto flush_it;
1029 	case T_UDERR:
1030 		break;
1031 	default:
1032 		(void) syslog(LOG_WARNING,
1033 	"t_look(file descriptor %d/transport %s) returned %d not T_UDERR (%d)",
1034 		    fd, nconf->nc_proto, ret, T_UDERR);
1035 	}
1036 
1037 	if (uderr == NULL) {
1038 		/* LINTED pointer alignment */
1039 		uderr = (struct t_uderr *)t_alloc(fd, T_UDERROR, T_ALL);
1040 		if (uderr == NULL) {
1041 			if (t_errno == TSYSERR) {
1042 				/*
1043 				 * Save the error code across
1044 				 * syslog(), just in case
1045 				 * syslog() gets its own error
1046 				 * and therefore overwrites errno.
1047 				 */
1048 				error = errno;
1049 				(void) syslog(LOG_ERR,
1050 	"t_alloc(file descriptor %d/transport %s, T_UDERROR) failed: %m",
1051 				    fd, nconf->nc_proto);
1052 				return (error);
1053 			}
1054 			(void) syslog(LOG_ERR,
1055 "t_alloc(file descriptor %d/transport %s, T_UDERROR) failed TLI error: %d",
1056 			    fd, nconf->nc_proto, t_errno);
1057 			goto flush_it;
1058 		}
1059 	}
1060 
1061 	ret = t_rcvuderr(fd, uderr);
1062 	if (ret == 0) {
1063 
1064 		/*
1065 		 * Save the datagram error in errno, so that the
1066 		 * %m argument to syslog picks up the error string.
1067 		 */
1068 		errno = uderr->error;
1069 
1070 		/*
1071 		 * Log the datagram error, then log the host that
1072 		 * probably triggerred. Cannot log both in the
1073 		 * same transaction because of packet size limitations
1074 		 * in /dev/log.
1075 		 */
1076 		(void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
1077 "NFS response over <file descriptor %d/transport %s> generated error: %m",
1078 		    fd, nconf->nc_proto);
1079 
1080 		/*
1081 		 * Try to map the client's address back to a
1082 		 * name.
1083 		 */
1084 		ret = netdir_getbyaddr(nconf, &host, &uderr->addr);
1085 		if (ret != -1 && host && host->h_cnt > 0 &&
1086 		    host->h_hostservs) {
1087 		(void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
1088 "Bad NFS response was sent to client with host name: %s; service port: %s",
1089 		    host->h_hostservs->h_host,
1090 		    host->h_hostservs->h_serv);
1091 		} else {
1092 			int i, j;
1093 			char *buf;
1094 			char *hex = "0123456789abcdef";
1095 
1096 			/*
1097 			 * Mapping failed, print the whole thing
1098 			 * in ASCII hex.
1099 			 */
1100 			buf = (char *)malloc(uderr->addr.len * 2 + 1);
1101 			for (i = 0, j = 0; i < uderr->addr.len; i++, j += 2) {
1102 				buf[j] = hex[((uderr->addr.buf[i]) >> 4) & 0xf];
1103 				buf[j+1] = hex[uderr->addr.buf[i] & 0xf];
1104 			}
1105 			buf[j] = '\0';
1106 		(void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
1107 	"Bad NFS response was sent to client with transport address: 0x%s",
1108 		    buf);
1109 			free((void *)buf);
1110 		}
1111 
1112 		if (ret == 0 && host != NULL)
1113 			netdir_free((void *)host, ND_HOSTSERVLIST);
1114 		return (0);
1115 	}
1116 
1117 	switch (t_errno) {
1118 	case TNOUDERR:
1119 		goto flush_it;
1120 	case TSYSERR:
1121 		/*
1122 		 * System errors are returned to caller.
1123 		 * Save the error code across
1124 		 * syslog(), just in case
1125 		 * syslog() gets its own error
1126 		 * and therefore overwrites errno.
1127 		 */
1128 		error = errno;
1129 		(void) syslog(LOG_ERR,
1130 		    "t_rcvuderr(file descriptor %d/transport %s) %m",
1131 		    fd, nconf->nc_proto);
1132 		return (error);
1133 	default:
1134 		(void) syslog(LOG_ERR,
1135 		"t_rcvuderr(file descriptor %d/transport %s) TLI error %d",
1136 		    fd, nconf->nc_proto, t_errno);
1137 		goto flush_it;
1138 	}
1139 
1140 flush_it:
1141 	/*
1142 	 * If we get here, then we could not cope with whatever message
1143 	 * we attempted to read, so flush it. If we did read a message,
1144 	 * and one isn't present, that is all right, because fd is in
1145 	 * nonblocking mode.
1146 	 */
1147 	(void) syslog(LOG_ERR,
1148 	"Flushing one input message from <file descriptor %d/transport %s>",
1149 	    fd, nconf->nc_proto);
1150 
1151 	/*
1152 	 * Read and discard the message. Do this this until there is
1153 	 * no more control/data in the message or until we get an error.
1154 	 */
1155 	do {
1156 		ctl->maxlen = sizeof (ctlbuf);
1157 		ctl->buf = ctlbuf;
1158 		data->maxlen = sizeof (databuf);
1159 		data->buf = databuf;
1160 		flags = 0;
1161 		ret = getmsg(fd, ctl, data, &flags);
1162 		if (ret == -1)
1163 			return (errno);
1164 	} while (ret != 0);
1165 
1166 	return (0);
1167 }
1168 
1169 static void
conn_close_oldest(void)1170 conn_close_oldest(void)
1171 {
1172 	int fd;
1173 	int i1;
1174 
1175 	/*
1176 	 * Find the oldest connection that is not already in the
1177 	 * process of shutting down.
1178 	 */
1179 	for (i1 = end_listen_fds; /* no conditional expression */; i1++) {
1180 		if (i1 >= num_fds)
1181 			return;
1182 		if (conn_polled[i1].closing == 0)
1183 			break;
1184 	}
1185 #ifdef DEBUG
1186 	printf("too many connections (%d), releasing oldest (%d)\n",
1187 	    num_conns, poll_array[i1].fd);
1188 #else
1189 	syslog(LOG_WARNING, "too many connections (%d), releasing oldest (%d)",
1190 	    num_conns, poll_array[i1].fd);
1191 #endif
1192 	fd = poll_array[i1].fd;
1193 	if (conn_polled[i1].nc.nc_semantics == NC_TPI_COTS) {
1194 		/*
1195 		 * For politeness, send a T_DISCON_REQ to the transport
1196 		 * provider.  We close the stream anyway.
1197 		 */
1198 		(void) t_snddis(fd, (struct t_call *)0);
1199 		num_conns--;
1200 		remove_from_poll_list(fd);
1201 		(void) t_close(fd);
1202 	} else {
1203 		/*
1204 		 * For orderly release, we do not close the stream
1205 		 * until the T_ORDREL_IND arrives to complete
1206 		 * the handshake.
1207 		 */
1208 		if (t_sndrel(fd) == 0)
1209 			conn_polled[i1].closing = 1;
1210 	}
1211 }
1212 
1213 static boolean_t
conn_get(int fd,struct netconfig * nconf,struct conn_ind ** connp)1214 conn_get(int fd, struct netconfig *nconf, struct conn_ind **connp)
1215 {
1216 	struct conn_ind	*conn;
1217 	struct conn_ind	*next_conn;
1218 
1219 	conn = (struct conn_ind *)malloc(sizeof (*conn));
1220 	if (conn == NULL) {
1221 		syslog(LOG_ERR, "malloc for listen indication failed");
1222 		return (FALSE);
1223 	}
1224 
1225 	/* LINTED pointer alignment */
1226 	conn->conn_call = (struct t_call *)t_alloc(fd, T_CALL, T_ALL);
1227 	if (conn->conn_call == NULL) {
1228 		free((char *)conn);
1229 		nfslib_log_tli_error("t_alloc", fd, nconf);
1230 		return (FALSE);
1231 	}
1232 
1233 	if (t_listen(fd, conn->conn_call) == -1) {
1234 		nfslib_log_tli_error("t_listen", fd, nconf);
1235 		(void) t_free((char *)conn->conn_call, T_CALL);
1236 		free((char *)conn);
1237 		return (FALSE);
1238 	}
1239 
1240 	if (conn->conn_call->udata.len > 0) {
1241 		syslog(LOG_WARNING,
1242 	"rejecting inbound connection(%s) with %d bytes of connect data",
1243 		    nconf->nc_proto, conn->conn_call->udata.len);
1244 
1245 		conn->conn_call->udata.len = 0;
1246 		(void) t_snddis(fd, conn->conn_call);
1247 		(void) t_free((char *)conn->conn_call, T_CALL);
1248 		free((char *)conn);
1249 		return (FALSE);
1250 	}
1251 
1252 	if ((next_conn = *connp) != NULL) {
1253 		next_conn->conn_prev->conn_next = conn;
1254 		conn->conn_next = next_conn;
1255 		conn->conn_prev = next_conn->conn_prev;
1256 		next_conn->conn_prev = conn;
1257 	} else {
1258 		conn->conn_next = conn;
1259 		conn->conn_prev = conn;
1260 		*connp = conn;
1261 	}
1262 	return (TRUE);
1263 }
1264 
1265 static int
discon_get(int fd,struct netconfig * nconf,struct conn_ind ** connp)1266 discon_get(int fd, struct netconfig *nconf, struct conn_ind **connp)
1267 {
1268 	struct conn_ind	*conn;
1269 	struct t_discon	discon;
1270 
1271 	discon.udata.buf = (char *)0;
1272 	discon.udata.maxlen = 0;
1273 	if (t_rcvdis(fd, &discon) == -1) {
1274 		nfslib_log_tli_error("t_rcvdis", fd, nconf);
1275 		return (-1);
1276 	}
1277 
1278 	conn = *connp;
1279 	if (conn == NULL)
1280 		return (0);
1281 
1282 	do {
1283 		if (conn->conn_call->sequence == discon.sequence) {
1284 			if (conn->conn_next == conn)
1285 				*connp = (struct conn_ind *)0;
1286 			else {
1287 				if (conn == *connp) {
1288 					*connp = conn->conn_next;
1289 				}
1290 				conn->conn_next->conn_prev = conn->conn_prev;
1291 				conn->conn_prev->conn_next = conn->conn_next;
1292 			}
1293 			free((char *)conn);
1294 			break;
1295 		}
1296 		conn = conn->conn_next;
1297 	} while (conn != *connp);
1298 
1299 	return (0);
1300 }
1301 
1302 static void
cots_listen_event(int fd,int conn_index)1303 cots_listen_event(int fd, int conn_index)
1304 {
1305 	struct t_call *call;
1306 	struct conn_ind	*conn;
1307 	struct conn_ind	*conn_head;
1308 	int event;
1309 	struct netconfig *nconf = &conn_polled[conn_index].nc;
1310 	int new_fd;
1311 	struct netbuf addrmask;
1312 	int ret = 0;
1313 	char *clnt;
1314 	char *clnt_uaddr = NULL;
1315 	struct nd_hostservlist *clnt_serv = NULL;
1316 
1317 	conn_head = NULL;
1318 	(void) conn_get(fd, nconf, &conn_head);
1319 
1320 	while ((conn = conn_head) != NULL) {
1321 		conn_head = conn->conn_next;
1322 		if (conn_head == conn)
1323 			conn_head = NULL;
1324 		else {
1325 			conn_head->conn_prev = conn->conn_prev;
1326 			conn->conn_prev->conn_next = conn_head;
1327 		}
1328 		call = conn->conn_call;
1329 		free(conn);
1330 
1331 		/*
1332 		 * If we have already accepted the maximum number of
1333 		 * connections allowed on the command line, then drop
1334 		 * the oldest connection (for any protocol) before
1335 		 * accepting the new connection.  Unless explicitly
1336 		 * set on the command line, max_conns_allowed is -1.
1337 		 */
1338 		if (max_conns_allowed != -1 && num_conns >= max_conns_allowed)
1339 			conn_close_oldest();
1340 
1341 		/*
1342 		 * Create a new transport endpoint for the same proto as
1343 		 * the listener.
1344 		 */
1345 		new_fd = nfslib_transport_open(nconf);
1346 		if (new_fd == -1) {
1347 			call->udata.len = 0;
1348 			(void) t_snddis(fd, call);
1349 			(void) t_free((char *)call, T_CALL);
1350 			syslog(LOG_ERR, "Cannot establish transport over %s",
1351 			    nconf->nc_device);
1352 			continue;
1353 		}
1354 
1355 		/* Bind to a generic address/port for the accepting stream. */
1356 		if (t_bind(new_fd, NULL, NULL) == -1) {
1357 			nfslib_log_tli_error("t_bind", new_fd, nconf);
1358 			call->udata.len = 0;
1359 			(void) t_snddis(fd, call);
1360 			(void) t_free((char *)call, T_CALL);
1361 			(void) t_close(new_fd);
1362 			continue;
1363 		}
1364 
1365 		while (t_accept(fd, new_fd, call) == -1) {
1366 			if (t_errno != TLOOK) {
1367 #ifdef DEBUG
1368 				nfslib_log_tli_error("t_accept", fd, nconf);
1369 #endif
1370 				call->udata.len = 0;
1371 				(void) t_snddis(fd, call);
1372 				(void) t_free((char *)call, T_CALL);
1373 				(void) t_close(new_fd);
1374 				goto do_next_conn;
1375 			}
1376 			while (event = t_look(fd)) {
1377 				switch (event) {
1378 				case T_LISTEN:
1379 #ifdef DEBUG
1380 					printf(
1381 "cots_listen_event(%s): T_LISTEN during accept processing\n", nconf->nc_proto);
1382 #endif
1383 					(void) conn_get(fd, nconf, &conn_head);
1384 					continue;
1385 				case T_DISCONNECT:
1386 #ifdef DEBUG
1387 					printf(
1388 	"cots_listen_event(%s): T_DISCONNECT during accept processing\n",
1389 					    nconf->nc_proto);
1390 #endif
1391 					(void) discon_get(fd, nconf,
1392 					    &conn_head);
1393 					continue;
1394 				default:
1395 					syslog(LOG_ERR,
1396 			"unexpected event 0x%x during accept processing (%s)",
1397 					    event, nconf->nc_proto);
1398 					call->udata.len = 0;
1399 					(void) t_snddis(fd, call);
1400 					(void) t_free((char *)call, T_CALL);
1401 					(void) t_close(new_fd);
1402 					goto do_next_conn;
1403 				}
1404 			}
1405 		}
1406 
1407 		if (set_addrmask(new_fd, nconf, &addrmask) < 0) {
1408 			(void) syslog(LOG_ERR,
1409 			    "Cannot set address mask for %s",
1410 			    nconf->nc_netid);
1411 			(void) t_snddis(new_fd, NULL);
1412 			(void) t_free((char *)call, T_CALL);
1413 			(void) t_close(new_fd);
1414 			continue;
1415 		}
1416 
1417 		/* Tell kRPC about the new stream. */
1418 		if (Mysvc4 != NULL)
1419 			ret = (*Mysvc4)(new_fd, &addrmask, nconf,
1420 			    NFS4_KRPC_START, &call->addr);
1421 		else
1422 			ret = (*Mysvc)(new_fd, addrmask, nconf);
1423 
1424 		if (ret < 0) {
1425 			if (errno != ENOTCONN) {
1426 				syslog(LOG_ERR,
1427 				    "unable to register new connection: %m");
1428 			} else {
1429 				/*
1430 				 * This is the only error that could be
1431 				 * caused by the client, so who was it?
1432 				 */
1433 				if (netdir_getbyaddr(nconf, &clnt_serv,
1434 				    &(call->addr)) == ND_OK &&
1435 				    clnt_serv->h_cnt > 0)
1436 					clnt = clnt_serv->h_hostservs->h_host;
1437 				else
1438 					clnt = clnt_uaddr = taddr2uaddr(nconf,
1439 					    &(call->addr));
1440 				/*
1441 				 * If we don't know who the client was,
1442 				 * remain silent.
1443 				 */
1444 				if (clnt)
1445 					syslog(LOG_ERR,
1446 "unable to register new connection: client %s has dropped connection", clnt);
1447 				if (clnt_serv) {
1448 					netdir_free(clnt_serv, ND_HOSTSERVLIST);
1449 					clnt_serv = NULL;
1450 				}
1451 				if (clnt_uaddr) {
1452 					free(clnt_uaddr);
1453 					clnt_uaddr = NULL;
1454 				}
1455 			}
1456 			free(addrmask.buf);
1457 			(void) t_snddis(new_fd, NULL);
1458 			(void) t_free((char *)call, T_CALL);
1459 			(void) t_close(new_fd);
1460 			goto do_next_conn;
1461 		}
1462 
1463 		free(addrmask.buf);
1464 		(void) t_free((char *)call, T_CALL);
1465 
1466 		/*
1467 		 * Poll on the new descriptor so that we get disconnect
1468 		 * and orderly release indications.
1469 		 */
1470 		num_conns++;
1471 		add_to_poll_list(new_fd, nconf);
1472 
1473 		/* Reset nconf in case it has been moved. */
1474 		nconf = &conn_polled[conn_index].nc;
1475 do_next_conn:;
1476 	}
1477 }
1478 
1479 static int
do_poll_cots_action(int fd,int conn_index)1480 do_poll_cots_action(int fd, int conn_index)
1481 {
1482 	char buf[256];
1483 	int event;
1484 	int i1;
1485 	int flags;
1486 	struct conn_entry *connent = &conn_polled[conn_index];
1487 	struct netconfig *nconf = &(connent->nc);
1488 	const char *errorstr;
1489 
1490 	while (event = t_look(fd)) {
1491 		switch (event) {
1492 		case T_LISTEN:
1493 #ifdef DEBUG
1494 printf("do_poll_cots_action(%s,%d): T_LISTEN event\n", nconf->nc_proto, fd);
1495 #endif
1496 			cots_listen_event(fd, conn_index);
1497 			break;
1498 
1499 		case T_DATA:
1500 #ifdef DEBUG
1501 printf("do_poll_cots_action(%d,%s): T_DATA event\n", fd, nconf->nc_proto);
1502 #endif
1503 			/*
1504 			 * Receive a private notification from CONS rpcmod.
1505 			 */
1506 			i1 = t_rcv(fd, buf, sizeof (buf), &flags);
1507 			if (i1 == -1) {
1508 				syslog(LOG_ERR, "t_rcv failed");
1509 				break;
1510 			}
1511 			if (i1 < sizeof (int))
1512 				break;
1513 			i1 = BE32_TO_U32(buf);
1514 			if (i1 == 1 || i1 == 2) {
1515 				/*
1516 				 * This connection has been idle for too long,
1517 				 * so release it as politely as we can.  If we
1518 				 * have already initiated an orderly release
1519 				 * and we get notified that the stream is
1520 				 * still idle, pull the plug.  This prevents
1521 				 * hung connections from continuing to consume
1522 				 * resources.
1523 				 */
1524 #ifdef DEBUG
1525 printf("do_poll_cots_action(%s,%d): ", nconf->nc_proto, fd);
1526 printf("initiating orderly release of idle connection\n");
1527 #endif
1528 				if (nconf->nc_semantics == NC_TPI_COTS ||
1529 				    connent->closing != 0) {
1530 					(void) t_snddis(fd, (struct t_call *)0);
1531 					goto fdclose;
1532 				}
1533 				/*
1534 				 * For NC_TPI_COTS_ORD, the stream is closed
1535 				 * and removed from the poll list when the
1536 				 * T_ORDREL is received from the provider.  We
1537 				 * don't wait for it here because it may take
1538 				 * a while for the transport to shut down.
1539 				 */
1540 				if (t_sndrel(fd) == -1) {
1541 					syslog(LOG_ERR,
1542 					"unable to send orderly release %m");
1543 				}
1544 				connent->closing = 1;
1545 			} else
1546 				syslog(LOG_ERR,
1547 				"unexpected event from CONS rpcmod %d", i1);
1548 			break;
1549 
1550 		case T_ORDREL:
1551 #ifdef DEBUG
1552 printf("do_poll_cots_action(%s,%d): T_ORDREL event\n", nconf->nc_proto, fd);
1553 #endif
1554 			/* Perform an orderly release. */
1555 			if (t_rcvrel(fd) == 0) {
1556 				/* T_ORDREL on listen fd's should be ignored */
1557 				if (!is_listen_fd_index(conn_index)) {
1558 					(void) t_sndrel(fd);
1559 					goto fdclose;
1560 				}
1561 				break;
1562 
1563 			} else if (t_errno == TLOOK) {
1564 				break;
1565 			} else {
1566 				nfslib_log_tli_error("t_rcvrel", fd, nconf);
1567 
1568 				/*
1569 				 * check to make sure we do not close
1570 				 * listen fd
1571 				 */
1572 				if (is_listen_fd_index(conn_index))
1573 					break;
1574 				else
1575 					goto fdclose;
1576 			}
1577 
1578 		case T_DISCONNECT:
1579 #ifdef DEBUG
1580 printf("do_poll_cots_action(%s,%d): T_DISCONNECT event\n", nconf->nc_proto, fd);
1581 #endif
1582 			if (t_rcvdis(fd, (struct t_discon *)NULL) == -1)
1583 				nfslib_log_tli_error("t_rcvdis", fd, nconf);
1584 
1585 			/*
1586 			 * T_DISCONNECT on listen fd's should be ignored.
1587 			 */
1588 			if (is_listen_fd_index(conn_index))
1589 				break;
1590 			else
1591 				goto fdclose;
1592 
1593 		default:
1594 			if (t_errno == TSYSERR) {
1595 				if ((errorstr = strerror(errno)) == NULL) {
1596 					(void) sprintf(buf,
1597 					    "Unknown error num %d", errno);
1598 					errorstr = (const char *) buf;
1599 				}
1600 			} else if (event == -1)
1601 				errorstr = t_strerror(t_errno);
1602 			else
1603 				errorstr = "";
1604 			syslog(LOG_ERR,
1605 			    "unexpected TLI event (0x%x) on "
1606 			    "connection-oriented transport(%s,%d):%s",
1607 			    event, nconf->nc_proto, fd, errorstr);
1608 fdclose:
1609 			num_conns--;
1610 			remove_from_poll_list(fd);
1611 			(void) t_close(fd);
1612 			return (0);
1613 		}
1614 	}
1615 
1616 	return (0);
1617 }
1618 
1619 static char *
serv_name_to_port_name(char * name)1620 serv_name_to_port_name(char *name)
1621 {
1622 	/*
1623 	 * Map service names (used primarily in logging) to
1624 	 * RPC port names (used by netdir_*() routines).
1625 	 */
1626 	if (strcmp(name, "NFS") == 0) {
1627 		return ("nfs");
1628 	} else if (strcmp(name, "NLM") == 0) {
1629 		return ("lockd");
1630 	} else if (strcmp(name, "NFS4_CALLBACK") == 0) {
1631 		return ("nfs4_callback");
1632 	}
1633 
1634 	return ("unrecognized");
1635 }
1636 
1637 static int
bind_to_provider(char * provider,char * serv,struct netbuf ** addr,struct netconfig ** retnconf)1638 bind_to_provider(char *provider, char *serv, struct netbuf **addr,
1639 		struct netconfig **retnconf)
1640 {
1641 	struct netconfig *nconf;
1642 	NCONF_HANDLE *nc;
1643 	struct nd_hostserv hs;
1644 
1645 	hs.h_host = HOST_SELF;
1646 	hs.h_serv = serv_name_to_port_name(serv);
1647 
1648 	if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
1649 		syslog(LOG_ERR, "setnetconfig failed: %m");
1650 		return (-1);
1651 	}
1652 	while (nconf = getnetconfig(nc)) {
1653 		if (OK_TPI_TYPE(nconf) &&
1654 		    strcmp(nconf->nc_device, provider) == 0) {
1655 			*retnconf = nconf;
1656 			return (nfslib_bindit(nconf, addr, &hs,
1657 			    listen_backlog));
1658 		}
1659 	}
1660 	(void) endnetconfig(nc);
1661 
1662 	syslog(LOG_ERR, "couldn't find netconfig entry for provider %s",
1663 	    provider);
1664 	return (-1);
1665 }
1666 
1667 static int
bind_to_proto(NETSELDECL (proto),char * serv,struct netbuf ** addr,struct netconfig ** retnconf)1668 bind_to_proto(NETSELDECL(proto), char *serv, struct netbuf **addr,
1669 		struct netconfig **retnconf)
1670 {
1671 	struct netconfig *nconf;
1672 	NCONF_HANDLE *nc = NULL;
1673 	struct nd_hostserv hs;
1674 
1675 	hs.h_host = HOST_SELF;
1676 	hs.h_serv = serv_name_to_port_name(serv);
1677 
1678 	if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
1679 		syslog(LOG_ERR, "setnetconfig failed: %m");
1680 		return (-1);
1681 	}
1682 	while (nconf = getnetconfig(nc)) {
1683 		if (OK_TPI_TYPE(nconf) && NETSELEQ(nconf->nc_proto, proto)) {
1684 			*retnconf = nconf;
1685 			return (nfslib_bindit(nconf, addr, &hs,
1686 			    listen_backlog));
1687 		}
1688 	}
1689 	(void) endnetconfig(nc);
1690 
1691 	syslog(LOG_ERR, "couldn't find netconfig entry for protocol %s",
1692 	    proto);
1693 	return (-1);
1694 }
1695 
1696 #include <netinet/in.h>
1697 
1698 /*
1699  * Create an address mask appropriate for the transport.
1700  * The mask is used to obtain the host-specific part of
1701  * a network address when comparing addresses.
1702  * For an internet address the host-specific part is just
1703  * the 32 bit IP address and this part of the mask is set
1704  * to all-ones. The port number part of the mask is zeroes.
1705  */
1706 static int
set_addrmask(int fd,struct netconfig * nconf,struct netbuf * mask)1707 set_addrmask(int fd,
1708 	struct netconfig *nconf,
1709 	struct netbuf *mask)
1710 {
1711 	struct t_info info;
1712 
1713 	/*
1714 	 * Find the size of the address we need to mask.
1715 	 */
1716 	if (t_getinfo(fd, &info) < 0) {
1717 		t_error("t_getinfo");
1718 		return (-1);
1719 	}
1720 	mask->len = mask->maxlen = info.addr;
1721 	if (info.addr <= 0) {
1722 		/*
1723 		 * loopback devices have infinite addr size
1724 		 * (it is identified by -1 in addr field of t_info structure),
1725 		 * so don't build the netmask for them. It's a special case
1726 		 * that should be handled properly.
1727 		 */
1728 		if ((info.addr == -1) &&
1729 		    (0 == strcmp(nconf->nc_protofmly, NC_LOOPBACK))) {
1730 			memset(mask, 0, sizeof (*mask));
1731 			return (0);
1732 		}
1733 
1734 		syslog(LOG_ERR, "set_addrmask: address size: %ld", info.addr);
1735 		return (-1);
1736 	}
1737 
1738 	mask->buf = (char *)malloc(mask->len);
1739 	if (mask->buf == NULL) {
1740 		syslog(LOG_ERR, "set_addrmask: no memory");
1741 		return (-1);
1742 	}
1743 	(void) memset(mask->buf, 0, mask->len);	/* reset all mask bits */
1744 
1745 	if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
1746 		/*
1747 		 * Set the mask so that the port is ignored.
1748 		 */
1749 		/* LINTED pointer alignment */
1750 		((struct sockaddr_in *)mask->buf)->sin_addr.s_addr =
1751 		    (ulong_t)~0;
1752 		/* LINTED pointer alignment */
1753 		((struct sockaddr_in *)mask->buf)->sin_family =
1754 		    (ushort_t)~0;
1755 	} else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) {
1756 		/* LINTED pointer alignment */
1757 		(void) memset(&((struct sockaddr_in6 *)mask->buf)->sin6_addr,
1758 		    (uchar_t)~0, sizeof (struct in6_addr));
1759 		/* LINTED pointer alignment */
1760 		((struct sockaddr_in6 *)mask->buf)->sin6_family =
1761 		    (ushort_t)~0;
1762 	} else {
1763 
1764 		/*
1765 		 * Set all mask bits.
1766 		 */
1767 		(void) memset(mask->buf, 0xFF, mask->len);
1768 	}
1769 	return (0);
1770 }
1771 
1772 /*
1773  * For listen fd's index is always less than end_listen_fds.
1774  * end_listen_fds is defined externally in the daemon that uses this library.
1775  * It's value is equal to the number of open file descriptors after the
1776  * last listen end point was opened but before any connection was accepted.
1777  */
1778 static int
is_listen_fd_index(int index)1779 is_listen_fd_index(int index)
1780 {
1781 	return (index < end_listen_fds);
1782 }
1783