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