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