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 * 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 * 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 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 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