1 /* $NetBSD: security.c,v 1.5 2000/06/08 09:01:05 fvdl 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 45 int allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY; 46 int 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 55 int log_severity = PORTMAP_LOG_FACILITY|PORTMAP_LOG_SEVERITY; 56 57 extern int verboselog; 58 59 int 60 check_access(SVCXPRT *xprt, rpcproc_t proc, void *args, int 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 } 106 107 #ifdef LIBWRAP 108 if (addr->sa_family == AF_LOCAL) 109 return 1; 110 request_init(&req, RQ_DAEMON, "rpcbind", RQ_CLIENT_SIN, addr, 0); 111 sock_methods(&req); 112 if(!hosts_access(&req)) { 113 logit(deny_severity, addr, proc, prog, ": request from unauthorized host"); 114 return 0; 115 } 116 #endif 117 if (verboselog) 118 logit(log_severity, addr, proc, prog, ""); 119 return 1; 120 } 121 122 int 123 is_loopback(struct netbuf *nbuf) 124 { 125 struct sockaddr *addr = (struct sockaddr *)nbuf->buf; 126 struct sockaddr_in *sin; 127 #ifdef INET6 128 struct sockaddr_in6 *sin6; 129 #endif 130 131 switch (addr->sa_family) { 132 case AF_INET: 133 if (!oldstyle_local) 134 return 0; 135 sin = (struct sockaddr_in *)addr; 136 return ((sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) && 137 (ntohs(sin->sin_port) < IPPORT_RESERVED)); 138 #ifdef INET6 139 case AF_INET6: 140 if (!oldstyle_local) 141 return 0; 142 sin6 = (struct sockaddr_in6 *)addr; 143 return (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) && 144 (ntohs(sin6->sin6_port) < IPV6PORT_RESERVED)); 145 #endif 146 case AF_LOCAL: 147 return 1; 148 default: 149 } 150 151 return 0; 152 } 153 154 155 /* logit - report events of interest via the syslog daemon */ 156 void 157 logit(int severity, struct sockaddr *addr, rpcproc_t procnum, rpcprog_t prognum, 158 const char *text) 159 { 160 const char *procname; 161 char procbuf[32]; 162 char *progname; 163 char progbuf[32]; 164 char fromname[NI_MAXHOST]; 165 struct rpcent *rpc; 166 static const char *procmap[] = { 167 /* RPCBPROC_NULL */ "null", 168 /* RPCBPROC_SET */ "set", 169 /* RPCBPROC_UNSET */ "unset", 170 /* RPCBPROC_GETADDR */ "getport/addr", 171 /* RPCBPROC_DUMP */ "dump", 172 /* RPCBPROC_CALLIT */ "callit", 173 /* RPCBPROC_GETTIME */ "gettime", 174 /* RPCBPROC_UADDR2TADDR */ "uaddr2taddr", 175 /* RPCBPROC_TADDR2UADDR */ "taddr2uaddr", 176 /* RPCBPROC_GETVERSADDR */ "getversaddr", 177 /* RPCBPROC_INDIRECT */ "indirect", 178 /* RPCBPROC_GETADDRLIST */ "getaddrlist", 179 /* RPCBPROC_GETSTAT */ "getstat" 180 }; 181 182 /* 183 * Fork off a process or the portmap daemon might hang while 184 * getrpcbynumber() or syslog() does its thing. 185 */ 186 187 if (fork() == 0) { 188 setproctitle("logit"); 189 190 /* Try to map program number to name. */ 191 192 if (prognum == 0) { 193 progname = ""; 194 } else if ((rpc = getrpcbynumber((int) prognum))) { 195 progname = rpc->r_name; 196 } else { 197 snprintf(progname = progbuf, sizeof(progbuf), "%u", 198 (unsigned)prognum); 199 } 200 201 /* Try to map procedure number to name. */ 202 203 if (procnum > (sizeof procmap / sizeof (char *))) { 204 snprintf(procbuf, sizeof procbuf, "%u", 205 (unsigned)procnum); 206 procname = procbuf; 207 } else 208 procname = procmap[procnum]; 209 210 /* Write syslog record. */ 211 212 if (addr->sa_family == AF_LOCAL) 213 strcpy(fromname, "local"); 214 else 215 getnameinfo(addr, addr->sa_len, fromname, 216 sizeof fromname, NULL, 0, NI_NUMERICHOST); 217 218 syslog(severity, "connect from %s to %s(%s)%s", 219 fromname, procname, progname, text); 220 _exit(0); 221 } 222 } 223 224 int 225 check_callit(SVCXPRT *xprt, struct r_rmtcall_args *args, int versnum) 226 { 227 struct sockaddr *sa = (struct sockaddr *)svc_getrpccaller(xprt)->buf; 228 229 /* 230 * Always allow calling NULLPROC 231 */ 232 if (args->rmt_proc == 0) 233 return 1; 234 235 /* 236 * XXX - this special casing sucks. 237 */ 238 switch (args->rmt_prog) { 239 case RPCBPROG: 240 /* 241 * Allow indirect calls to ourselves in insecure mode. 242 * The is_loopback checks aren't useful then anyway. 243 */ 244 if (!insecure) 245 goto deny; 246 break; 247 case MOUNTPROG: 248 if (args->rmt_proc != MOUNTPROC_MNT && 249 args->rmt_proc != MOUNTPROC_UMNT) 250 break; 251 goto deny; 252 case YPBINDPROG: 253 if (args->rmt_proc != YPBINDPROC_SETDOM) 254 break; 255 /* FALLTHROUGH */ 256 case YPPASSWDPROG: 257 case NFS_PROGRAM: 258 case RQUOTAPROG: 259 goto deny; 260 case YPPROG: 261 switch (args->rmt_proc) { 262 case YPPROC_ALL: 263 case YPPROC_MATCH: 264 case YPPROC_FIRST: 265 case YPPROC_NEXT: 266 goto deny; 267 default: 268 } 269 default: 270 } 271 272 return 1; 273 deny: 274 logit(deny_severity, sa, args->rmt_proc, args->rmt_prog, 275 ": indirect call not allowed"); 276 277 return 0; 278 } 279