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