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