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