xref: /illumos-gate/usr/src/cmd/rpcbind/rpcb_check.c (revision 8f6d9dae)
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  * Auxiliary routines to shield off random internet hosts and to report
23  * service requests (verbose mode only) or violations (always).
24  *
25  * This code was extensively modifed from a version authored by:
26  *
27  * Wietse Venema, Eindhoven University of Technology, The Netherlands
28  * and distributed as "rpcbind 2.1".
29  *
30  * Sun was granted permission to use, modify, including make
31  * derivatives of, copy, reproduce and distribute this code.c in both
32  * binary and source forms, directly and indirectly.
33  *
34  * Modified for bundling with Solaris and IPv6.
35  *
36  * Solaris specific modifcations made are:
37  *
38  *	Double fork() logging replaced with qsyslog();
39  *	Connection refusals are flagged with svcerr_auth(); this
40  *	aids in quicker diagnosability of misconfigurations and quicker
41  *	failures for /net automounts;
42  *	Single function for pmap* and rpcb*;
43  *	Local transport checks made using localxprt().
44  *
45  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
46  * Use is subject to license terms.
47  */
48 /*
49  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
50  */
51 
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <unistd.h>
55 #include <string.h>
56 #include <syslog.h>
57 #include <errno.h>
58 #include <netconfig.h>
59 #include <netdb.h>
60 #include <netdir.h>
61 #include <arpa/inet.h>
62 #include <netinet/in.h>
63 #include <rpc/rpc.h>
64 #include <rpc/pmap_prot.h>
65 #include <rpc/rpcb_prot.h>
66 #include <thread.h>
67 #include <synch.h>
68 #include <tcpd.h>
69 
70 #include "rpcbind.h"
71 
72 /*
73  * These are globally visible so that they can be modified by the wrapper's
74  * language extension routines.
75  */
76 int allow_severity = LOG_INFO;
77 int deny_severity = LOG_WARNING;
78 
79 static mutex_t hosts_ctl_lock = DEFAULTMUTEX;
80 
81 /*
82  * "inet_ntoa/inet_pton" for struct sockaddr_gen
83  */
84 static const char *
sgen_toa(struct sockaddr_gen * addr,char * buf,size_t bufsize)85 sgen_toa(struct sockaddr_gen *addr, char *buf, size_t bufsize)
86 {
87 	return (inet_ntop(SGFAM(addr), SGADDRP(addr), buf, bufsize));
88 }
89 
90 struct proc_map {
91 	rpcproc_t code;
92 	const char *proc;
93 };
94 
95 static const struct proc_map pmapmap[] = {
96 	PMAPPROC_CALLIT,	"callit",
97 	PMAPPROC_DUMP,		"dump",
98 	PMAPPROC_GETPORT,	"getport",
99 	PMAPPROC_SET,		"set",
100 	PMAPPROC_UNSET,		"unset",
101 	NULLPROC,		"null",
102 };
103 
104 static const struct proc_map rpcbmap[] = {
105 	RPCBPROC_SET,		"set",
106 	RPCBPROC_UNSET,		"unset",
107 	RPCBPROC_GETADDR,	"getaddr",
108 	RPCBPROC_DUMP,		"dump",
109 	RPCBPROC_CALLIT,	"callit",
110 	RPCBPROC_GETTIME,	"gettime",
111 	RPCBPROC_UADDR2TADDR,	"uaddr2taddr",
112 	RPCBPROC_TADDR2UADDR,	"taddr2uaddr",
113 	RPCBPROC_GETVERSADDR,	"getversaddr",
114 	RPCBPROC_INDIRECT,	"indirect",
115 	RPCBPROC_GETADDRLIST,	"getaddrlist",
116 	RPCBPROC_GETSTAT,	"getstat",
117 	NULLPROC,		"null",
118 };
119 
120 /*
121  * find_procname - map rpcb/pmap procedure number to name
122  */
123 static const char *
find_procname(rpcproc_t procnum,boolean_t pm)124 find_procname(rpcproc_t procnum, boolean_t pm)
125 {
126 	int nitems, i;
127 	const struct proc_map *procp;
128 
129 	if (pm) {
130 		procp = pmapmap;
131 		nitems = sizeof (pmapmap)/sizeof (struct proc_map);
132 	} else {
133 		procp = rpcbmap;
134 		nitems = sizeof (rpcbmap)/sizeof (struct proc_map);
135 	}
136 
137 	for (i = 0; i < nitems; i++) {
138 		if (procp[i].code == procnum)
139 			return (procp[i].proc);
140 	}
141 	return (NULL);
142 }
143 
144 /*
145  * rpcb_log - log request for service
146  */
147 void
rpcb_log(boolean_t verdict,SVCXPRT * transp,rpcproc_t proc,rpcprog_t prog,boolean_t pm)148 rpcb_log(boolean_t verdict, SVCXPRT *transp, rpcproc_t proc, rpcprog_t prog,
149     boolean_t pm)
150 {
151 	struct netconfig *conf;
152 	const char *client = "unknown";
153 	char *uaddr;
154 	char buf[BUFSIZ];
155 	char toabuf[INET6_ADDRSTRLEN];
156 	const char *procname;
157 
158 	/*
159 	 * Transform the transport address into something printable.
160 	 */
161 	if ((conf = rpcbind_get_conf(transp->xp_netid)) == 0) {
162 		syslog(LOG_WARNING,
163 		    "unknown transport (rpcbind_get_conf failed)");
164 	} else if (strcmp(conf->nc_protofmly, "inet") == 0 ||
165 	    strcmp(conf->nc_protofmly, "inet6") == 0) {
166 		client = sgen_toa(svc_getgencaller(transp), toabuf,
167 		    sizeof (toabuf));
168 	} else if ((uaddr = taddr2uaddr(conf, &(transp->xp_rtaddr))) == NULL) {
169 		syslog(LOG_WARNING, "unknown address (taddr2uaddr failed)");
170 	} else {
171 		(void) snprintf(buf, sizeof (buf), "%s(%s)",
172 		    conf->nc_protofmly, uaddr);
173 		free(uaddr);
174 		client = buf;
175 	}
176 
177 	if ((procname = find_procname(proc, pm)) == NULL) {
178 		qsyslog(verdict ? allow_severity : deny_severity,
179 		    "%sconnect from %s to %s-%lu(%lu)",
180 		    verdict ? "" : "refused ", client, pm ? "pmap" : "rpcb",
181 		    (ulong_t)proc, (ulong_t)prog);
182 	} else {
183 		qsyslog(verdict ? allow_severity : deny_severity,
184 		    "%sconnect from %s to %s(%lu)", verdict ? "" : "refused ",
185 		    client, procname, (ulong_t)prog);
186 	}
187 }
188 
189 /*
190  * rpcb_check; the rpcbind/portmap access check function.
191  */
192 boolean_t
rpcb_check(SVCXPRT * transp,rpcproc_t procnum,boolean_t ispmap)193 rpcb_check(SVCXPRT *transp, rpcproc_t procnum, boolean_t ispmap)
194 {
195 	struct netconfig *conf;
196 	boolean_t res = B_TRUE;
197 
198 	if ((conf = rpcbind_get_conf(transp->xp_netid)) == 0) {
199 		syslog(LOG_ERR,
200 		    "rpcbind_get_conf failed: no client address checks");
201 		return (B_TRUE);
202 	}
203 
204 	/*
205 	 * Require IPv4 for pmap calls; they're not defined for anything else.
206 	 */
207 	if (ispmap && strcmp(conf->nc_protofmly, "inet") != 0) {
208 		res = B_FALSE;
209 	} else if (strcmp(conf->nc_protofmly, "inet") == 0 ||
210 	    strcmp(conf->nc_protofmly, "inet6") == 0) {
211 		if (!localxprt(transp, ispmap)) {
212 			if (local_only) {
213 				res = B_FALSE;
214 			} else {
215 				char buf[INET6_ADDRSTRLEN];
216 				const char *addr_string =
217 				    sgen_toa(svc_getgencaller(transp), buf,
218 				    sizeof (buf));
219 
220 				(void) mutex_lock(&hosts_ctl_lock);
221 				if (hosts_ctl("rpcbind", addr_string,
222 				    addr_string, "") == 0)
223 					res = B_FALSE;
224 				(void) mutex_unlock(&hosts_ctl_lock);
225 			}
226 		}
227 	}
228 
229 	if (!res)
230 		svcerr_auth(transp, AUTH_FAILED);
231 
232 	if (verboselog || !res)
233 		rpcb_log(res, transp, procnum, 0, ispmap);
234 
235 	return (res);
236 }
237