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) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * svc_generic.c, Server side for RPC.
32 *
33 */
34
35 #include "mt.h"
36 #include <stdlib.h>
37 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <netinet/tcp.h>
40 #include <netinet/udp.h>
41 #include <inttypes.h>
42 #include "rpc_mt.h"
43 #include <stdio.h>
44 #include <rpc/rpc.h>
70 extern bool_t __rpc_try_doors(const char *, bool_t *);
71
72 /*
73 * The highest level interface for server creation.
74 * It tries for all the nettokens in that particular class of token
75 * and returns the number of handles it can create and/or find.
76 *
77 * It creates a link list of all the handles it could create.
78 * If svc_create() is called multiple times, it uses the handle
79 * created earlier instead of creating a new handle every time.
80 */
81
82 /* VARIABLES PROTECTED BY xprtlist_lock: xprtlist */
83
84 SVCXPRT_LIST *_svc_xprtlist = NULL;
85 extern mutex_t xprtlist_lock;
86
87 static SVCXPRT * svc_tli_create_common(int, const struct netconfig *,
88 const struct t_bind *, uint_t, uint_t, boolean_t);
89
90 boolean_t
91 is_multilevel(rpcprog_t prognum)
92 {
93 /* This is a list of identified multilevel service provider */
94 if ((prognum == MOUNTPROG) || (prognum == NFS_PROGRAM) ||
95 (prognum == NFS_ACL_PROGRAM) || (prognum == NLM_PROG) ||
96 (prognum == NSM_ADDR_PROGRAM) || (prognum == RQUOTAPROG) ||
97 (prognum == SM_PROG))
98 return (B_TRUE);
99
100 return (B_FALSE);
101 }
102
103 void
104 __svc_free_xprtlist(void)
105 {
106 __svc_free_xlist(&_svc_xprtlist, &xprtlist_lock);
107 }
108
109 int
159 &xprtlist_lock)) {
160 (void) syslog(LOG_ERR,
161 "svc_create: no memory");
162 return (0);
163 }
164 num++;
165 }
166 }
167 }
168 __rpc_endconf(handle);
169 /*
170 * In case of num == 0; the error messages are generated by the
171 * underlying layers; and hence not needed here.
172 */
173 return (num);
174 }
175
176 /*
177 * The high level interface to svc_tli_create().
178 * It tries to create a server for "nconf" and registers the service
179 * with the rpcbind. It calls svc_tli_create();
180 */
181 SVCXPRT *
182 svc_tp_create(void (*dispatch)(), const rpcprog_t prognum,
183 const rpcvers_t versnum, const struct netconfig *nconf)
184 {
185 SVCXPRT *xprt;
186 boolean_t anon_mlp = B_FALSE;
187
188 if (nconf == NULL) {
189 (void) syslog(LOG_ERR, "svc_tp_create: invalid netconfig "
190 "structure for prog %d vers %d", prognum, versnum);
191 return (NULL);
192 }
193
194 /* Some programs need to allocate MLP for multilevel services */
195 if (is_system_labeled() && is_multilevel(prognum))
196 anon_mlp = B_TRUE;
197 xprt = svc_tli_create_common(RPC_ANYFD, nconf, NULL, 0, 0, anon_mlp);
198 if (xprt == NULL)
199 return (NULL);
200
201 (void) rpcb_unset(prognum, versnum, (struct netconfig *)nconf);
202 if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) {
203 (void) syslog(LOG_ERR,
204 "svc_tp_create: Could not register prog %d vers %d on %s",
205 prognum, versnum, nconf->nc_netid);
206 SVC_DESTROY(xprt);
207 return (NULL);
208 }
209 return (xprt);
210 }
211
212 SVCXPRT *
213 svc_tli_create(const int fd, const struct netconfig *nconf,
214 const struct t_bind *bindaddr, const uint_t sendsz, const uint_t recvsz)
215 {
216 return (svc_tli_create_common(fd, nconf, bindaddr, sendsz, recvsz, 0));
217 }
307 "svc_tli_create: "
308 "IP_RECVDSTADDR(1): %s", errorstr);
309 return (NULL);
310 }
311 }
312 }
313 }
314
315 /*
316 * If the fd is unbound, try to bind it.
317 * In any case, try to get its bound info in tres
318 */
319 /* LINTED pointer alignment */
320 tres = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
321 if (tres == NULL) {
322 (void) syslog(LOG_ERR, "svc_tli_create: No memory!");
323 goto freedata;
324 }
325
326 switch (state) {
327 bool_t tcp, exclbind;
328 case T_UNBND:
329 /* If this is a labeled system, then ask for an MLP */
330 if (is_system_labeled() &&
331 (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
332 strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
333 (void) __rpc_tli_set_options(fd, SOL_SOCKET,
334 SO_RECVUCRED, 1);
335 if (mlp_flag)
336 (void) __rpc_tli_set_options(fd, SOL_SOCKET,
337 SO_ANON_MLP, 1);
338 }
339
340 /*
341 * SO_EXCLBIND has the following properties
342 * - an fd bound to port P via IPv4 will prevent an IPv6
343 * bind to port P (and vice versa)
344 * - an fd bound to a wildcard IP address for port P will
345 * prevent a more specific IP address bind to port P
346 * (see {tcp,udp}.c for details)
347 *
348 * We use the latter property to prevent hijacking of RPC
349 * services that reside at non-privileged ports.
350 */
351 tcp = nconf ? (strcmp(nconf->nc_proto, NC_TCP) == 0) : 0;
352 if (nconf &&
353 (tcp || (strcmp(nconf->nc_proto, NC_UDP) == 0)) &&
354 rpc_control(__RPC_SVC_EXCLBIND_GET, &exclbind)) {
355 if (exclbind) {
356 if (__rpc_tli_set_options(fd, SOL_SOCKET,
357 SO_EXCLBIND, 1) < 0) {
358 syslog(LOG_ERR,
359 "svc_tli_create: can't set EXCLBIND [netid='%s']",
360 nconf->nc_netid);
361 goto freedata;
362 }
363 }
364 }
365 if (bindaddr) {
366 if (t_bind(fd, (struct t_bind *)bindaddr, tres) == -1) {
367 char errorstr[100];
368
369 __tli_sys_strerror(errorstr, sizeof (errorstr),
370 t_errno, errno);
371 (void) syslog(LOG_ERR,
372 "svc_tli_create: could not bind: %s",
373 errorstr);
374 goto freedata;
375 }
376 /*
377 * Should compare the addresses only if addr.len
378 * was non-zero
379 */
380 if (bindaddr->addr.len &&
381 (memcmp(bindaddr->addr.buf, tres->addr.buf,
382 (int)tres->addr.len) != 0)) {
383 (void) syslog(LOG_ERR, "svc_tli_create: could "
384 "not bind to requested address: address "
385 "mismatch");
386 goto freedata;
387 }
388 } else {
389 if (rpc_control(__RPC_SVC_LSTNBKLOG_GET, &tres->qlen)
390 == FALSE) {
391 syslog(LOG_ERR,
392 "svc_tli_create: can't get listen backlog");
393 goto freedata;
394 }
395 tres->addr.len = 0;
396 if (t_bind(fd, tres, tres) == -1) {
397 char errorstr[100];
398
399 __tli_sys_strerror(errorstr, sizeof (errorstr),
400 t_errno, errno);
401 (void) syslog(LOG_ERR,
402 "svc_tli_create: could not bind: %s",
403 errorstr);
404 goto freedata;
405 }
406 }
407
408 /* Enable options of returning the ip's for udp */
409 if (nconf) {
410 int ret = 0;
411 if (strcmp(nconf->nc_netid, "udp6") == 0) {
412 ret = __rpc_tli_set_options(fd, IPPROTO_IPV6,
413 IPV6_RECVPKTINFO, 1);
414 if (ret < 0) {
415 char errorstr[100];
416
417 __tli_sys_strerror(errorstr,
418 sizeof (errorstr), t_errno, errno);
419 (void) syslog(LOG_ERR,
420 "svc_tli_create: "
421 "IPV6_RECVPKTINFO(2): %s",
422 errorstr);
423 goto freedata;
424 }
425 } else if (strcmp(nconf->nc_netid, "udp") == 0) {
|
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 2016 Nexenta Systems, Inc. All rights reserved.
24 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
25 */
26
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * svc_generic.c, Server side for RPC.
32 *
33 */
34
35 #include "mt.h"
36 #include <stdlib.h>
37 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <netinet/tcp.h>
40 #include <netinet/udp.h>
41 #include <inttypes.h>
42 #include "rpc_mt.h"
43 #include <stdio.h>
44 #include <rpc/rpc.h>
70 extern bool_t __rpc_try_doors(const char *, bool_t *);
71
72 /*
73 * The highest level interface for server creation.
74 * It tries for all the nettokens in that particular class of token
75 * and returns the number of handles it can create and/or find.
76 *
77 * It creates a link list of all the handles it could create.
78 * If svc_create() is called multiple times, it uses the handle
79 * created earlier instead of creating a new handle every time.
80 */
81
82 /* VARIABLES PROTECTED BY xprtlist_lock: xprtlist */
83
84 SVCXPRT_LIST *_svc_xprtlist = NULL;
85 extern mutex_t xprtlist_lock;
86
87 static SVCXPRT * svc_tli_create_common(int, const struct netconfig *,
88 const struct t_bind *, uint_t, uint_t, boolean_t);
89
90 static SVCXPRT *svc_tp_create_bind(void (*dispatch)(),
91 const rpcprog_t, const rpcvers_t,
92 const struct netconfig *, const struct t_bind *);
93
94 boolean_t
95 is_multilevel(rpcprog_t prognum)
96 {
97 /* This is a list of identified multilevel service provider */
98 if ((prognum == MOUNTPROG) || (prognum == NFS_PROGRAM) ||
99 (prognum == NFS_ACL_PROGRAM) || (prognum == NLM_PROG) ||
100 (prognum == NSM_ADDR_PROGRAM) || (prognum == RQUOTAPROG) ||
101 (prognum == SM_PROG))
102 return (B_TRUE);
103
104 return (B_FALSE);
105 }
106
107 void
108 __svc_free_xprtlist(void)
109 {
110 __svc_free_xlist(&_svc_xprtlist, &xprtlist_lock);
111 }
112
113 int
163 &xprtlist_lock)) {
164 (void) syslog(LOG_ERR,
165 "svc_create: no memory");
166 return (0);
167 }
168 num++;
169 }
170 }
171 }
172 __rpc_endconf(handle);
173 /*
174 * In case of num == 0; the error messages are generated by the
175 * underlying layers; and hence not needed here.
176 */
177 return (num);
178 }
179
180 /*
181 * The high level interface to svc_tli_create().
182 * It tries to create a server for "nconf" and registers the service
183 * with the rpcbind.
184 */
185 SVCXPRT *
186 svc_tp_create(void (*dispatch)(), const rpcprog_t prognum,
187 const rpcvers_t versnum, const struct netconfig *nconf)
188 {
189 return (svc_tp_create_bind(dispatch, prognum, versnum, nconf, NULL));
190 }
191
192 /*
193 * svc_tp_create_addr()
194 * Variant of svc_tp_create() that allows specifying just the
195 * the binding address, for convenience.
196 */
197 SVCXPRT *
198 svc_tp_create_addr(void (*dispatch)(), const rpcprog_t prognum,
199 const rpcvers_t versnum, const struct netconfig *nconf,
200 const struct netbuf *addr)
201 {
202 struct t_bind bind;
203 struct t_bind *bindp = NULL;
204
205 if (addr != NULL) {
206
207 bind.addr = *addr;
208 if (!rpc_control(__RPC_SVC_LSTNBKLOG_GET, &bind.qlen)) {
209 syslog(LOG_ERR,
210 "svc_tp_create: can't get listen backlog");
211 return (NULL);
212 }
213 bindp = &bind;
214 }
215
216 /*
217 * When bindp == NULL, this is the same as svc_tp_create().
218 */
219 return (svc_tp_create_bind(dispatch, prognum, versnum,
220 nconf, bindp));
221 }
222
223 static SVCXPRT *
224 svc_tp_create_bind(void (*dispatch)(), const rpcprog_t prognum,
225 const rpcvers_t versnum, const struct netconfig *nconf,
226 const struct t_bind *bindaddr)
227 {
228 SVCXPRT *xprt;
229 boolean_t anon_mlp = B_FALSE;
230
231 if (nconf == NULL) {
232 (void) syslog(LOG_ERR, "svc_tp_create: invalid netconfig "
233 "structure for prog %d vers %d", prognum, versnum);
234 return (NULL);
235 }
236
237 /* Some programs need to allocate MLP for multilevel services */
238 if (is_system_labeled() && is_multilevel(prognum))
239 anon_mlp = B_TRUE;
240 xprt = svc_tli_create_common(RPC_ANYFD, nconf, bindaddr, 0, 0,
241 anon_mlp);
242 if (xprt == NULL)
243 return (NULL);
244
245 (void) rpcb_unset(prognum, versnum, (struct netconfig *)nconf);
246 if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) {
247 (void) syslog(LOG_ERR,
248 "svc_tp_create: Could not register prog %d vers %d on %s",
249 prognum, versnum, nconf->nc_netid);
250 SVC_DESTROY(xprt);
251 return (NULL);
252 }
253 return (xprt);
254 }
255
256 SVCXPRT *
257 svc_tli_create(const int fd, const struct netconfig *nconf,
258 const struct t_bind *bindaddr, const uint_t sendsz, const uint_t recvsz)
259 {
260 return (svc_tli_create_common(fd, nconf, bindaddr, sendsz, recvsz, 0));
261 }
351 "svc_tli_create: "
352 "IP_RECVDSTADDR(1): %s", errorstr);
353 return (NULL);
354 }
355 }
356 }
357 }
358
359 /*
360 * If the fd is unbound, try to bind it.
361 * In any case, try to get its bound info in tres
362 */
363 /* LINTED pointer alignment */
364 tres = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
365 if (tres == NULL) {
366 (void) syslog(LOG_ERR, "svc_tli_create: No memory!");
367 goto freedata;
368 }
369
370 switch (state) {
371 case T_UNBND:
372 /* If this is a labeled system, then ask for an MLP */
373 if (is_system_labeled() &&
374 (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
375 strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
376 (void) __rpc_tli_set_options(fd, SOL_SOCKET,
377 SO_RECVUCRED, 1);
378 if (mlp_flag)
379 (void) __rpc_tli_set_options(fd, SOL_SOCKET,
380 SO_ANON_MLP, 1);
381 }
382
383 if (bindaddr) {
384 /*
385 * Services that specify a bind address typically
386 * use a fixed service (IP port) so we need to set
387 * SO_REUSEADDR to prevent bind errors on restart.
388 */
389 if (bindaddr->addr.len != 0)
390 (void) __rpc_tli_set_options(fd, SOL_SOCKET,
391 SO_REUSEADDR, 1);
392 if (t_bind(fd, (struct t_bind *)bindaddr, tres) == -1) {
393 char errorstr[100];
394
395 __tli_sys_strerror(errorstr, sizeof (errorstr),
396 t_errno, errno);
397 (void) syslog(LOG_ERR,
398 "svc_tli_create: could not bind: %s",
399 errorstr);
400 goto freedata;
401 }
402 /*
403 * Should compare the addresses only if addr.len
404 * was non-zero
405 */
406 if (bindaddr->addr.len &&
407 (memcmp(bindaddr->addr.buf, tres->addr.buf,
408 (int)tres->addr.len) != 0)) {
409 (void) syslog(LOG_ERR, "svc_tli_create: could "
410 "not bind to requested address: address "
411 "mismatch");
412 goto freedata;
413 }
414 } else {
415 if (rpc_control(__RPC_SVC_LSTNBKLOG_GET, &tres->qlen)
416 == FALSE) {
417 syslog(LOG_ERR,
418 "svc_tli_create: can't get listen backlog");
419 goto freedata;
420 }
421 tres->addr.len = 0;
422 if (t_bind(fd, tres, tres) == -1) {
423 char errorstr[100];
424
425 __tli_sys_strerror(errorstr, sizeof (errorstr),
426 t_errno, errno);
427 (void) syslog(LOG_ERR,
428 "svc_tli_create: could not bind: %s",
429 errorstr);
430 goto freedata;
431 }
432 }
433
434 /*
435 * If requested, set SO_EXCLBIND on each binding.
436 *
437 * SO_EXCLBIND has the following properties
438 * - an fd bound to port P via IPv4 will prevent an IPv6
439 * bind to port P (and vice versa)
440 * - an fd bound to a wildcard IP address for port P will
441 * prevent a more specific IP address bind to port P
442 * (see {tcp,udp}.c for details)
443 *
444 * We use the latter property to prevent hijacking of RPC
445 * services that reside at non-privileged ports.
446 *
447 * When the bind address is not specified, each bind gets a
448 * new port number, and (for IP transports) we should set
449 * the exclusive flag after every IP bind. That's the
450 * strcmp nc_proto part of the expression below.
451 *
452 * When the bind address IS specified, we need to set the
453 * exclusive flag only after we've bound both IPv6+IPv4,
454 * or the IPv4 bind will fail. Setting the exclusive flag
455 * after the "tcp" or "udp" transport bind does that.
456 * That's the strcmp nc_netid part below.
457 */
458 if (nconf != NULL && ((bindaddr == NULL &&
459 (strcmp(nconf->nc_proto, NC_TCP) == 0 ||
460 strcmp(nconf->nc_proto, NC_UDP) == 0)) ||
461 (strcmp(nconf->nc_netid, "tcp") == 0 ||
462 strcmp(nconf->nc_netid, "udp") == 0))) {
463 bool_t exclbind = FALSE;
464 (void) rpc_control(__RPC_SVC_EXCLBIND_GET, &exclbind);
465 if (exclbind &&
466 __rpc_tli_set_options(fd, SOL_SOCKET,
467 SO_EXCLBIND, 1) < 0) {
468 syslog(LOG_ERR,
469 "svc_tli_create: can't set EXCLBIND [netid='%s']",
470 nconf->nc_netid);
471 goto freedata;
472 }
473 }
474
475 /* Enable options of returning the ip's for udp */
476 if (nconf) {
477 int ret = 0;
478 if (strcmp(nconf->nc_netid, "udp6") == 0) {
479 ret = __rpc_tli_set_options(fd, IPPROTO_IPV6,
480 IPV6_RECVPKTINFO, 1);
481 if (ret < 0) {
482 char errorstr[100];
483
484 __tli_sys_strerror(errorstr,
485 sizeof (errorstr), t_errno, errno);
486 (void) syslog(LOG_ERR,
487 "svc_tli_create: "
488 "IPV6_RECVPKTINFO(2): %s",
489 errorstr);
490 goto freedata;
491 }
492 } else if (strcmp(nconf->nc_netid, "udp") == 0) {
|