1/* $NetBSD: security.c,v 1.14 2021/03/07 00:23:06 christos Exp $ */ 2/* $FreeBSD: head/usr.sbin/rpcbind/security.c 262860 2014-03-06 17:33:27Z mav $ */ 3 4#include <sys/types.h> 5#include <sys/time.h> 6#include <sys/socket.h> 7#include <netinet/in.h> 8#include <arpa/inet.h> 9#include <rpc/rpc.h> 10#include <rpc/rpcb_prot.h> 11#include <rpc/pmap_prot.h> 12#include <err.h> 13#include <stdio.h> 14#include <stdlib.h> 15#include <string.h> 16#include <unistd.h> 17#include <util.h> 18#include <syslog.h> 19#include <netdb.h> 20 21/* 22 * XXX for special case checks in check_callit. 23 */ 24#include <rpcsvc/mount.h> 25#include <rpcsvc/rquota.h> 26#include <rpcsvc/nfs_prot.h> 27 28#ifdef YP 29#include <rpcsvc/yp.h> 30#include <rpcsvc/ypclnt.h> 31#include <rpcsvc/yppasswd.h> 32#else 33/* Define enough to compile. */ 34#define YPBINDPROG ((unsigned long)100007) 35#define YPBINDPROC_SETDOM ((unsigned long)2) 36#define YPPROG ((unsigned long)100004) 37#define YPPROC_FIRST ((unsigned long)4) 38#define YPPROC_NEXT ((unsigned long)5) 39#define YPPROC_MATCH ((unsigned long)3) 40#define YPPROC_ALL ((unsigned long)8) 41#define YPPASSWDPROG ((unsigned long)100009) 42#endif 43 44#include "rpcbind.h" 45 46#ifdef LIBWRAP 47# include <tcpd.h> 48#ifndef LIBWRAP_ALLOW_FACILITY 49# define LIBWRAP_ALLOW_FACILITY LOG_AUTH 50#endif 51#ifndef LIBWRAP_ALLOW_SEVERITY 52# define LIBWRAP_ALLOW_SEVERITY LOG_INFO 53#endif 54#ifndef LIBWRAP_DENY_FACILITY 55# define LIBWRAP_DENY_FACILITY LOG_AUTH 56#endif 57#ifndef LIBWRAP_DENY_SEVERITY 58# define LIBWRAP_DENY_SEVERITY LOG_WARNING 59#endif 60int allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY; 61int deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY; 62#endif 63 64#ifndef PORTMAP_LOG_FACILITY 65# define PORTMAP_LOG_FACILITY LOG_AUTH 66#endif 67#ifndef PORTMAP_LOG_SEVERITY 68# define PORTMAP_LOG_SEVERITY LOG_INFO 69#endif 70int log_severity = PORTMAP_LOG_FACILITY|PORTMAP_LOG_SEVERITY; 71 72extern int verboselog; 73 74int 75check_access(SVCXPRT *xprt, rpcproc_t proc, void *args, unsigned int rpcbvers) 76{ 77 struct netbuf *caller = svc_getrpccaller(xprt); 78 struct sockaddr *addr = (struct sockaddr *)caller->buf; 79#ifdef LIBWRAP 80 struct request_info req; 81#endif 82 rpcprog_t prog = 0; 83 rpcb *rpcbp; 84 struct pmap *pmap; 85 86 /* 87 * The older PMAP_* equivalents have the same numbers, so 88 * they are accounted for here as well. 89 */ 90 switch (proc) { 91 case RPCBPROC_GETADDR: 92 case RPCBPROC_SET: 93 case RPCBPROC_UNSET: 94 if (rpcbvers > PMAPVERS) { 95 rpcbp = (rpcb *)args; 96 prog = rpcbp->r_prog; 97 } else { 98 pmap = (struct pmap *)args; 99 prog = pmap->pm_prog; 100 } 101 if (proc == RPCBPROC_GETADDR) 102 break; 103 if (!insecure && !is_loopback(caller)) { 104 if (verboselog) 105 logit(log_severity, addr, proc, prog, 106 " declined (non-loopback sender)"); 107 return 0; 108 } 109 break; 110 case RPCBPROC_CALLIT: 111 case RPCBPROC_INDIRECT: 112 case RPCBPROC_DUMP: 113 case RPCBPROC_GETTIME: 114 case RPCBPROC_UADDR2TADDR: 115 case RPCBPROC_TADDR2UADDR: 116 case RPCBPROC_GETVERSADDR: 117 case RPCBPROC_GETADDRLIST: 118 case RPCBPROC_GETSTAT: 119 default: 120 break; 121 } 122 123#ifdef LIBWRAP 124 if (libwrap && addr->sa_family != AF_LOCAL) { 125 request_init(&req, RQ_DAEMON, "rpcbind", RQ_CLIENT_SIN, addr, 126 RQ_FILE, xprt->xp_fd, NULL); 127 sock_methods(&req); 128 if(!hosts_access(&req)) { 129 logit(deny_severity, addr, proc, prog, 130 ": request from unauthorized host"); 131 return 0; 132 } 133 } 134#endif 135 if (verboselog) 136 logit(log_severity, addr, proc, prog, ""); 137 return 1; 138} 139 140int 141is_loopback(struct netbuf *nbuf) 142{ 143 struct sockaddr *addr = (struct sockaddr *)nbuf->buf; 144 struct sockaddr_in *sin; 145#ifdef INET6 146 struct sockaddr_in6 *sin6; 147#endif 148 149 switch (addr->sa_family) { 150 case AF_INET: 151 if (!oldstyle_local) 152 return 0; 153 sin = (struct sockaddr_in *)addr; 154 return ((sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) && 155 (ntohs(sin->sin_port) < IPPORT_RESERVED)); 156#ifdef INET6 157 case AF_INET6: 158 if (!oldstyle_local) 159 return 0; 160 sin6 = (struct sockaddr_in6 *)addr; 161 return (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) && 162 (ntohs(sin6->sin6_port) < IPV6PORT_RESERVED)); 163#endif 164 case AF_LOCAL: 165 return 1; 166 default: 167 break; 168 } 169 170 return 0; 171} 172 173 174/* logit - report events of interest via the syslog daemon */ 175void 176logit(int severity, struct sockaddr *addr, rpcproc_t procnum, rpcprog_t prognum, 177 const char *text) 178{ 179 const char *procname; 180 char procbuf[32]; 181 char *progname; 182 char progbuf[32]; 183 char fromname[NI_MAXHOST]; 184 struct rpcent *rpc; 185 static const char *procmap[] = { 186 /* RPCBPROC_NULL */ "null", 187 /* RPCBPROC_SET */ "set", 188 /* RPCBPROC_UNSET */ "unset", 189 /* RPCBPROC_GETADDR */ "getport/addr", 190 /* RPCBPROC_DUMP */ "dump", 191 /* RPCBPROC_CALLIT */ "callit", 192 /* RPCBPROC_GETTIME */ "gettime", 193 /* RPCBPROC_UADDR2TADDR */ "uaddr2taddr", 194 /* RPCBPROC_TADDR2UADDR */ "taddr2uaddr", 195 /* RPCBPROC_GETVERSADDR */ "getversaddr", 196 /* RPCBPROC_INDIRECT */ "indirect", 197 /* RPCBPROC_GETADDRLIST */ "getaddrlist", 198 /* RPCBPROC_GETSTAT */ "getstat" 199 }; 200 201 /* 202 * Fork off a process or the portmap daemon might hang while 203 * getrpcbynumber() or syslog() does its thing. 204 */ 205 206 if (fork() == 0) { 207 setproctitle("logit"); 208 209 /* Try to map program number to name. */ 210 211 if (prognum == 0) { 212 progname = __UNCONST(""); 213 } else if ((rpc = getrpcbynumber((int) prognum))) { 214 progname = rpc->r_name; 215 } else { 216 snprintf(progname = progbuf, sizeof(progbuf), "%u", 217 (unsigned)prognum); 218 } 219 220 /* Try to map procedure number to name. */ 221 222 if (procnum >= (sizeof procmap / sizeof (char *))) { 223 snprintf(procbuf, sizeof procbuf, "%u", 224 (unsigned)procnum); 225 procname = procbuf; 226 } else 227 procname = procmap[procnum]; 228 229 /* Write syslog record. */ 230 231 if (addr->sa_family == AF_LOCAL) 232 strlcpy(fromname, "local", sizeof(fromname)); 233 else 234 getnameinfo(addr, addr->sa_len, fromname, 235 sizeof fromname, NULL, 0, NI_NUMERICHOST); 236 237 syslog(severity, "connect from %s to %s(%s)%s", 238 fromname, procname, progname, text); 239 _exit(0); 240 } 241} 242 243int 244check_callit(SVCXPRT *xprt, struct r_rmtcall_args *args, int versnum __unused) 245{ 246 struct sockaddr *sa = (struct sockaddr *)svc_getrpccaller(xprt)->buf; 247 248 /* 249 * Always allow calling NULLPROC 250 */ 251 if (args->rmt_proc == 0) 252 return 1; 253 254 /* 255 * XXX - this special casing sucks. 256 */ 257 switch (args->rmt_prog) { 258 case RPCBPROG: 259 /* 260 * Allow indirect calls to ourselves in insecure mode. 261 * The is_loopback checks aren't useful then anyway. 262 */ 263 if (!insecure) 264 goto deny; 265 break; 266 case MOUNTPROG: 267 if (args->rmt_proc != MOUNTPROC_MNT && 268 args->rmt_proc != MOUNTPROC_UMNT) 269 break; 270 goto deny; 271 case YPBINDPROG: 272 if (args->rmt_proc != YPBINDPROC_SETDOM) 273 break; 274 /* FALLTHROUGH */ 275 case YPPASSWDPROG: 276 case NFS_PROGRAM: 277 case RQUOTAPROG: 278 goto deny; 279 case YPPROG: 280 switch (args->rmt_proc) { 281 case YPPROC_ALL: 282 case YPPROC_MATCH: 283 case YPPROC_FIRST: 284 case YPPROC_NEXT: 285 goto deny; 286 default: 287 break; 288 } 289 default: 290 break; 291 } 292 293 return 1; 294deny: 295#ifdef LIBWRAP 296 logit(deny_severity, sa, args->rmt_proc, args->rmt_prog, 297 ": indirect call not allowed"); 298#else 299 logit(0, sa, args->rmt_proc, args->rmt_prog, 300 ": indirect call not allowed"); 301#endif 302 return 0; 303} 304