diff --git a/include/rpcsvc/yp.x b/include/rpcsvc/yp.x --- a/include/rpcsvc/yp.x +++ b/include/rpcsvc/yp.x @@ -190,11 +190,31 @@ YPBIND_FAIL_VAL = 2 }; +struct ypbind_domain_3 { + char *ypbind_domainname; + unsigned int ypbind_vers; +}; + +struct ypbind_binding_3 { + struct netbuf *ypbind_svcaddr; + char *ypbind_servername; + unsigned int ypbind_hi_vers; + unsigned int ypbind_lo_vers; +}; + struct ypbind_binding { opaque ypbind_binding_addr[4]; /* In network order */ opaque ypbind_binding_port[2]; /* In network order */ }; +union ypbind_resp_3 switch (ypbind_resptype ypbind_status) +{ +case YPBIND_FAIL_VAL: + unsigned ypbind_error; +case YPBIND_SUCC_VAL: + ypbind_binding_3 ypbind_bindinfo; +}; + union ypbind_resp switch (ypbind_resptype ypbind_status) { case YPBIND_FAIL_VAL: unsigned ypbind_error; @@ -212,6 +232,12 @@ /* * Request data structure for ypbind "Set domain" procedure. */ +struct ypbind_setdom_3 { + char *ypsetdom_domain; + struct ypbind_binding_3 *ypsetdom_bindinfo; + unsigned ypsetdom_vers; +}; + struct ypbind_setdom { domainname ypsetdom_domain; ypbind_binding ypsetdom_binding; @@ -367,6 +393,17 @@ void YPBINDPROC_SETDOM(ypbind_setdom) = 2; } = 2; + + version YPBINDVERS_3 { + void + YPBINDPROC_NULL(void) = 0; + + ypbind_resp + YPBINDPROC_DOMAIN(ypbind_domain_3) = 1; + + void + YPBINDPROC_SETDOM(ypbind_setdom_3) = 2; + } = 3; } = 100007; #endif diff --git a/lib/libc/yp/Symbol.map b/lib/libc/yp/Symbol.map --- a/lib/libc/yp/Symbol.map +++ b/lib/libc/yp/Symbol.map @@ -49,5 +49,8 @@ xdr_ypresptype; xdr_ypstat; xdr_ypxfrstat; + xdr_ypbind_resp_3; + xdr_ypbind_domain_3; + xdr_ypbind_setdom_3; }; diff --git a/usr.sbin/ypbind/yp_ping.h b/usr.sbin/ypbind/yp_ping.h --- a/usr.sbin/ypbind/yp_ping.h +++ b/usr.sbin/ypbind/yp_ping.h @@ -1,4 +1,4 @@ /* */ -extern int __yp_ping(struct in_addr *, int, char *, short *); +extern int __yp_ping(struct sockaddr *, int, char *, short *); diff --git a/usr.sbin/ypbind/yp_ping.c b/usr.sbin/ypbind/yp_ping.c --- a/usr.sbin/ypbind/yp_ping.c +++ b/usr.sbin/ypbind/yp_ping.c @@ -103,18 +103,26 @@ * Returns 0 if no map exists. */ static u_short -__pmap_getport(struct sockaddr_in *address, u_long program, u_long version, +__pmap_getport(struct sockaddr *address, u_long program, u_long version, u_int protocol) { + struct netbuf nb; u_short port = 0; int sock = -1; register CLIENT *client; struct pmap parms; - address->sin_port = htons(PMAPPORT); + if (address->sa_family == AF_INET) { + ((struct sockaddr_in *)address)->sin_port = htons(PMAPPORT); + nb.len = nb.maxlen = sizeof(struct sockaddr_in); + } + else if (address->sa_family == AF_INET6) { + ((struct sockaddr_in6 *)address)->sin6_port = htons(PMAPPORT); + nb.len = nb.maxlen = sizeof(struct sockaddr_in6); + } + nb.buf = address; - client = clntudp_bufcreate(address, PMAPPROG, - PMAPVERS, timeout, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); + client = clnt_dg_create(sock, &nb, PMAPPROG, PMAPVERS, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); if (client != (CLIENT *)NULL) { parms.pm_prog = program; parms.pm_vers = version; @@ -131,9 +139,13 @@ } CLNT_DESTROY(client); } + clnt_control(client, CLSET_TIMEOUT, (char *)&timeout); if (sock != -1) (void)close(sock); - address->sin_port = 0; + if (address->sa_family == AF_INET) + ((struct sockaddr_in *)address)->sin_port = 0; + else if (address->sa_family == AF_INET6) + ((struct sockaddr_in6 *)address)->sin6_port = 0; return (port); } @@ -198,18 +210,20 @@ */ struct ping_req { - struct sockaddr_in sin; + struct sockaddr_storage ss; u_int32_t xid; }; int -__yp_ping(struct in_addr *restricted_addrs, int cnt, char *dom, short *port) +__yp_ping(struct sockaddr *restricted_addrs, int cnt, char *dom, short *port) { struct timeval tv = { 5, 0 }; struct ping_req **reqs; unsigned long i; int async; - struct sockaddr_in sin, *any = NULL; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + struct sockaddr *any = NULL; struct netbuf addr; int winner = -1; u_int32_t xid_seed, xid_lookup; @@ -217,23 +231,38 @@ CLIENT *clnt; char *foo = dom; int validsrvs = 0; + char host[NI_MAXHOST]; + int ret; /* Set up handles. */ reqs = calloc(cnt, sizeof(struct ping_req *)); xid_seed = time(NULL) ^ getpid(); for (i = 0; i < cnt; i++) { - bzero((char *)&sin, sizeof(sin)); - sin.sin_family = AF_INET; - bcopy((char *)&restricted_addrs[i], - (char *)&sin.sin_addr, sizeof(struct in_addr)); - sin.sin_port = htons(__pmap_getport(&sin, YPPROG, - YPVERS, IPPROTO_UDP)); - if (sin.sin_port == 0) - continue; - reqs[i] = calloc(1, sizeof(struct ping_req)); - bcopy((char *)&sin, (char *)&reqs[i]->sin, sizeof(sin)); - any = &reqs[i]->sin; + if (restricted_addrs[i].sa_family == AF_INET) { + bzero((char *)&sin, sizeof(sin)); + bcopy((char *)&restricted_addrs[i], + (char *)&sin.sin_addr, sizeof(struct in_addr)); + sin.sin_port = htons(__pmap_getport((struct sockaddr *)&sin, YPPROG, + YPVERS, IPPROTO_UDP)); + if (sin.sin_port == 0) + continue; + reqs[i] = calloc(1, sizeof(struct ping_req)); + bcopy((char *)&sin, (char *)&reqs[i]->ss, sizeof(sin)); + any = (struct sockaddr *)&reqs[i]->ss; + } + else if (restricted_addrs[i].sa_family == AF_INET6) { + bzero((char *)&sin6, sizeof(sin6)); + bcopy((char *)&restricted_addrs[i], + (char *)&sin6.sin6_addr, sizeof(struct in6_addr)); + sin6.sin6_port = htons(__pmap_getport((struct sockaddr *)&sin6, YPPROG, + YPVERS, IPPROTO_UDP)); + if (sin6.sin6_port == 0) + continue; + reqs[i] = calloc(1, sizeof(struct ping_req)); + bcopy((char *)&sin6, (char *)&reqs[i]->ss, sizeof(sin6)); + any = (struct sockaddr *)&reqs[i]->ss; + } reqs[i]->xid = xid_seed; xid_seed++; validsrvs++; @@ -246,8 +275,13 @@ } /* Create RPC handle */ - sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - clnt = clntudp_create(any, YPPROG, YPVERS, tv, &sock); + sock = socket(any->sa_family, SOCK_DGRAM, IPPROTO_UDP); + ret = getnameinfo(any, any->sa_len, host, sizeof(host), NULL, 0, + NI_NUMERICHOST | NI_NUMERICSERV); + if (ret != 0) + return(-1); + + clnt = clnt_create(host, YPPROG, YPVERS, "udp"); if (clnt == NULL) { close(sock); for (i = 0; i < cnt; i++) @@ -268,8 +302,8 @@ for (i = 0; i < cnt; i++) { if (reqs[i] != NULL) { clnt_control(clnt, CLSET_XID, (char *)&reqs[i]->xid); - addr.len = sizeof(reqs[i]->sin); - addr.buf = (char *) &reqs[i]->sin; + addr.len = sizeof(reqs[i]->ss); + addr.buf = (char *) &reqs[i]->ss; clnt_control(clnt, CLSET_SVC_ADDR, &addr); ypproc_domain_nonack_2_send(&foo, clnt); } @@ -283,7 +317,10 @@ for (i = 0; i < cnt; i++) { if (reqs[i] != NULL && reqs[i]->xid == xid_lookup) { winner = i; - *port = reqs[i]->sin.sin_port; + if (reqs[i]->ss.ss_family == AF_INET) + *port = ((struct sockaddr_in *)&reqs[i]->ss)->sin_port; + else if (reqs[i]->ss.ss_family == AF_INET6) + *port = ((struct sockaddr_in6 *)&reqs[i]->ss)->sin6_port; } } diff --git a/usr.sbin/ypbind/ypbind.c b/usr.sbin/ypbind/ypbind.c --- a/usr.sbin/ypbind/ypbind.c +++ b/usr.sbin/ypbind/ypbind.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -72,10 +73,13 @@ #define YPBINDLOCK "/var/run/ypbind.lock" #endif +typedef void *(svc_cb)(SVCXPRT *transp, void *arg, + struct svc_req *rqstp); + struct _dom_binding { struct _dom_binding *dom_pnext; char dom_domain[YPMAXDOMAIN + 1]; - struct sockaddr_in dom_server_addr; + struct ypbind_binding_3 *dom_binding; long int dom_vers; int dom_lockfd; int dom_alive; @@ -90,16 +94,20 @@ void checkwork(void); void *ypbindproc_null_2_yp(SVCXPRT *, void *, CLIENT *); +static struct ypbind_resp_3 *ypbindproc_domain_3_yp(SVCXPRT *transp, ypbind_domain_3 *argp, CLIENT *clnt); +static struct ypbind_resp_3 *ypbindproc_domain_2_yp(SVCXPRT *transp, domainname *argp, CLIENT *clnt); +void *ypbindproc_setdom_3_yp(SVCXPRT *, struct ypbind_setdom_3 *, CLIENT *); void *ypbindproc_setdom_2_yp(SVCXPRT *, struct ypbind_setdom *, CLIENT *); -void rpc_received(char *, struct sockaddr_in *, int); +void rpc_received(char *, struct netbuf *, int); void broadcast(struct _dom_binding *); int ping(struct _dom_binding *); -int tell_parent(char *, struct sockaddr_in *); +int tell_parent(char *, struct netbuf *); void handle_children(struct _dom_binding *); void reaper(int); void terminate(int); void yp_restricted_mode(char *); -int verify(struct in_addr); +int verify(struct netbuf *); +void copy_netbuf(struct netbuf *, struct netbuf *); static char *domain_name; static struct _dom_binding *ypbindlist; @@ -123,7 +131,7 @@ #define RESTRICTED_SERVERS 10 static int yp_restricted = 0; static int yp_manycast = 0; -static struct in_addr restricted_addrs[RESTRICTED_SERVERS]; +static struct sockaddr_storage restricted_addrs[RESTRICTED_SERVERS]; /* No more than MAX_CHILDREN child broadcasters at a time. */ #ifndef MAX_CHILDREN @@ -149,7 +157,7 @@ static int yplockfd; static fd_set fdsr; -static SVCXPRT *udptransp, *tcptransp; +static u_short xprt_port; void * ypbindproc_null_2_yp(SVCXPRT *transp, void *argp, CLIENT *clnt) @@ -160,53 +168,55 @@ return &res; } -static struct ypbind_resp * -ypbindproc_domain_2_yp(SVCXPRT *transp, domainname *argp, CLIENT *clnt) +static struct ypbind_resp_3 * +ypbindproc_domain_3_yp(SVCXPRT *transp, struct ypbind_domain_3 *argp, CLIENT *clnt) { - static struct ypbind_resp res; + static struct ypbind_resp_3 res; struct _dom_binding *ypdb; char path[MAXPATHLEN]; bzero(&res, sizeof res); res.ypbind_status = YPBIND_FAIL_VAL; - res.ypbind_resp_u.ypbind_error = YPBIND_ERR_NOSERV; + res.ypbind_resp_3_u.ypbind_error = YPBIND_ERR_NOSERV; - if (strchr(*argp, '/')) { + if (strchr(argp->ypbind_domainname, '/')) { syslog(LOG_WARNING, "Domain name '%s' has embedded slash -- \ -rejecting.", *argp); +rejecting.", argp->ypbind_domainname); return(&res); } for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext) { - if (strcmp(ypdb->dom_domain, *argp) == 0) + if (strcmp(ypdb->dom_domain, argp->ypbind_domainname) == 0) break; } if (ypdb == NULL) { if (yp_restricted) { - syslog(LOG_NOTICE, "Running in restricted mode -- request to bind domain \"%s\" rejected.\n", *argp); + syslog(LOG_NOTICE, "Running in restricted mode -- request to bind domain \"%s\" rejected.\n", + argp->ypbind_domainname); return (&res); } if (domains >= MAX_DOMAINS) { syslog(LOG_WARNING, "domain limit (%d) exceeded", MAX_DOMAINS); - res.ypbind_resp_u.ypbind_error = YPBIND_ERR_RESC; + res.ypbind_resp_3_u.ypbind_error = YPBIND_ERR_RESC; return (&res); } - if (strlen(*argp) > YPMAXDOMAIN) { - syslog(LOG_WARNING, "domain %s too long", *argp); - res.ypbind_resp_u.ypbind_error = YPBIND_ERR_RESC; + if (strlen(argp->ypbind_domainname) > YPMAXDOMAIN) { + syslog(LOG_WARNING, "domain %s too long", argp->ypbind_domainname); + res.ypbind_resp_3_u.ypbind_error = YPBIND_ERR_RESC; return (&res); } ypdb = malloc(sizeof *ypdb); if (ypdb == NULL) { syslog(LOG_WARNING, "malloc: %m"); - res.ypbind_resp_u.ypbind_error = YPBIND_ERR_RESC; + res.ypbind_resp_3_u.ypbind_error = YPBIND_ERR_RESC; return (&res); } + bzero(ypdb, sizeof *ypdb); - strlcpy(ypdb->dom_domain, *argp, sizeof ypdb->dom_domain); + strlcpy(ypdb->dom_domain, argp->ypbind_domainname, sizeof ypdb->dom_domain); ypdb->dom_vers = YPVERS; ypdb->dom_alive = 0; ypdb->dom_default = 0; @@ -224,33 +234,50 @@ } res.ypbind_status = YPBIND_SUCC_VAL; - res.ypbind_resp_u.ypbind_error = 0; /* Success */ - memcpy(&res.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr, - &ypdb->dom_server_addr.sin_addr.s_addr, sizeof(u_int32_t)); - memcpy(&res.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port, - &ypdb->dom_server_addr.sin_port, sizeof(u_short)); + res.ypbind_resp_3_u.ypbind_error = 0; /* Success */ + res.ypbind_resp_3_u.ypbind_bindinfo.ypbind_svcaddr = malloc(sizeof(struct netbuf)); + copy_netbuf(res.ypbind_resp_3_u.ypbind_bindinfo.ypbind_svcaddr, + ypdb->dom_binding->ypbind_svcaddr); /*printf("domain %s at %s/%d\n", ypdb->dom_domain, inet_ntoa(ypdb->dom_server_addr.sin_addr), ntohs(ypdb->dom_server_addr.sin_port));*/ return (&res); } +static struct ypbind_resp_3 * +ypbindproc_domain_2_yp(SVCXPRT *transp, domainname *argp, CLIENT *clnt) +{ + ypbind_domain_3 arg; + arg.ypbind_domainname = *argp; + return ypbindproc_domain_3_yp(transp, &arg, clnt); +} + void * -ypbindproc_setdom_2_yp(SVCXPRT *transp, ypbind_setdom *argp, CLIENT *clnt) +ypbindproc_setdom_3_yp(SVCXPRT *transp, ypbind_setdom_3 *argp, CLIENT *clnt) { - struct sockaddr_in *fromsin, bindsin; + struct netbuf *from, bind; + struct sockaddr *from_sin; static char *result = NULL; + char host[NI_MAXHOST]; + int ret; + u_short port = 0; if (strchr(argp->ypsetdom_domain, '/')) { syslog(LOG_WARNING, "Domain name '%s' has embedded slash -- \ rejecting.", argp->ypsetdom_domain); return(NULL); } - fromsin = svc_getcaller(transp); + from = svc_getrpccaller(transp); + from_sin = (struct sockaddr *)from->buf; + ret = getnameinfo(from_sin, from_sin->sa_len, host, sizeof(host), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV); + if (ret != 0) { + syslog(LOG_ERR, "getnameinfo: %s\n", gai_strerror(ret)); + return(NULL); + } switch (ypsetmode) { case YPSET_LOCAL: - if (fromsin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) { + if (strcmp(host, "127.0.0.1") == 0 || strcmp(host, "::1") == 0) { svcerr_noprog(transp); return(NULL); } @@ -263,27 +290,113 @@ return(NULL); } - if (ntohs(fromsin->sin_port) >= IPPORT_RESERVED) { + if (from_sin->sa_family == AF_INET) + port = ntohs(((struct sockaddr_in *)from_sin)->sin_port); + else if (from_sin->sa_family == AF_INET6) + port = ntohs(((struct sockaddr_in6 *)from_sin)->sin6_port); + + if (port >= IPPORT_RESERVED) { svcerr_noprog(transp); return(NULL); } - if (argp->ypsetdom_vers != YPVERS) { + if (argp->ypsetdom_bindinfo->ypbind_hi_vers <= YPVERS && + argp->ypsetdom_bindinfo->ypbind_lo_vers >= YPVERS) { svcerr_noprog(transp); return(NULL); } - bzero(&bindsin, sizeof bindsin); - bindsin.sin_family = AF_INET; - memcpy(&bindsin.sin_addr.s_addr, + bzero(&bind, sizeof bind); + copy_netbuf(&bind, argp->ypsetdom_bindinfo->ypbind_svcaddr); + rpc_received(argp->ypsetdom_domain, &bind, 1); + + return((void *) &result); +} + +void * +ypbindproc_setdom_2_yp(SVCXPRT *transp, ypbind_setdom *argp, CLIENT *clnt) +{ + struct netbuf nb; + struct sockaddr_in sin; + ypbind_setdom_3 argp_2; + + bzero(&sin, sizeof sin); + sin.sin_family = AF_INET; + memcpy(&sin.sin_addr.s_addr, &argp->ypsetdom_binding.ypbind_binding_addr, sizeof(u_int32_t)); - memcpy(&bindsin.sin_port, + memcpy(&sin.sin_port, &argp->ypsetdom_binding.ypbind_binding_port, sizeof(u_short)); - rpc_received(argp->ypsetdom_domain, &bindsin, 1); + nb.buf = &sin; + nb.len = nb.maxlen = sizeof(struct sockaddr_in); + strlcpy(argp_2.ypsetdom_domain, argp->ypsetdom_domain, sizeof(argp_2.ypsetdom_domain)); + argp_2.ypsetdom_bindinfo->ypbind_hi_vers = argp->ypsetdom_vers; + argp_2.ypsetdom_bindinfo->ypbind_lo_vers = argp->ypsetdom_vers; + argp_2.ypsetdom_bindinfo->ypbind_svcaddr = &nb; + + return (ypbindproc_setdom_3_yp(transp, &argp_2, clnt)); +} - return((void *) &result); +void +ypbindprog_3(struct svc_req *rqstp, register SVCXPRT *transp) +{ + union { + struct ypbind_domain_3 ypbindproc_domain_3_arg; + struct ypbind_setdom_3 ypbindproc_setdom_3_arg; + } argument; + struct authunix_parms *creds; + void *result; + xdrproc_t xdr_argument, xdr_result; + svc_cb *local; + + switch (rqstp->rq_proc) { + case YPBINDPROC_NULL: + xdr_argument = (xdrproc_t)xdr_void; + xdr_result = (xdrproc_t)xdr_void; + local = (svc_cb *)ypbindproc_null_2_yp; + break; + + case YPBINDPROC_DOMAIN: + xdr_argument = (xdrproc_t)xdr_ypbind_domain_3; + xdr_result = (xdrproc_t)xdr_ypbind_resp_3; + local = (svc_cb *)ypbindproc_domain_3_yp; + break; + + case YPBINDPROC_SETDOM: + switch (rqstp->rq_cred.oa_flavor) { + case AUTH_UNIX: + creds = (struct authunix_parms *)rqstp->rq_clntcred; + if (creds->aup_uid != 0) { + svcerr_auth(transp, AUTH_BADCRED); + return; + } + break; + default: + svcerr_auth(transp, AUTH_TOOWEAK); + return; + } + + xdr_argument = (xdrproc_t)xdr_ypbind_setdom_3; + xdr_result = (xdrproc_t)xdr_void; + local = (svc_cb *)ypbindproc_setdom_3_yp; + break; + + default: + svcerr_noproc(transp); + return; + } + bzero(&argument, sizeof(argument)); + if (!svc_getargs(transp, xdr_argument, &argument)) { + svcerr_decode(transp); + return; + } + result = (*local)(transp, &argument, rqstp); + if (result != NULL && + !svc_sendreply(transp, xdr_result, result)) { + svcerr_systemerr(transp); + } + return; } void @@ -296,8 +409,6 @@ struct authunix_parms *creds; void *result; xdrproc_t xdr_argument, xdr_result; - typedef void *(svc_cb)(SVCXPRT *transp, void *arg, - struct svc_req *rqstp); svc_cb *local; switch (rqstp->rq_proc) { @@ -362,8 +473,10 @@ void terminate(int sig) { + struct netconfig *nconf; struct _dom_binding *ypdb; char path[MAXPATHLEN]; + void *handle; if (ppid != getpid()) exit(0); @@ -378,18 +491,31 @@ } close(yplockfd); unlink(YPBINDLOCK); - pmap_unset(YPBINDPROG, YPBINDVERS); + if ((handle = setnetconfig()) == NULL) + errx(1, "setnetconfig failed"); + + while ((nconf = getnetconfig(handle)) != NULL) { + rpcb_unset(YPBINDPROG, YPBINDVERS_3, nconf); + if (strcmp(nconf->nc_protofmly, NC_INET) == 0 && + (nconf->nc_semantics == NC_TPI_CLTS || + nconf->nc_semantics == NC_TPI_COTS_ORD)) { + rpcb_unset(YPBINDPROG, YPBINDVERS, nconf); + } + } exit(0); } int main(int argc, char *argv[]) { + struct netconfig *nconf; struct timeval tv; int i; DIR *dird; struct dirent *dirp; struct _dom_binding *ypdb, *next; + SVCXPRT *xprt; + void *handle; /* Check that another ypbind isn't already running. */ if ((yplockfd = (open(YPBINDLOCK, O_RDONLY|O_CREAT, 0444))) == -1) @@ -439,22 +565,29 @@ err(1, "fork"); #endif - pmap_unset(YPBINDPROG, YPBINDVERS); - - udptransp = svcudp_create(RPC_ANYSOCK); - if (udptransp == NULL) - errx(1, "cannot create udp service"); - if (!svc_register(udptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, - IPPROTO_UDP)) - errx(1, "unable to register (YPBINDPROG, YPBINDVERS, udp)"); - - tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0); - if (tcptransp == NULL) - errx(1, "cannot create tcp service"); - - if (!svc_register(tcptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, - IPPROTO_TCP)) - errx(1, "unable to register (YPBINDPROG, YPBINDVERS, tcp)"); + if ((handle = setnetconfig()) == NULL) + errx(1, "setnetconfig failed"); + + while ((nconf = getnetconfig(handle)) != NULL) { + rpcb_unset(YPBINDPROG, YPBINDVERS_3, nconf); + /* Bind version 3 ypbind */ + if((xprt = svc_tp_create(ypbindprog_3, YPBINDPROG, YPBINDVERS_3, nconf)) == NULL) + errx(1, "terminating: cannot create rpcgind handle"); + + if (strcmp(nconf->nc_protofmly, NC_INET) == 0 && + nconf->nc_semantics == NC_TPI_CLTS) + xprt_port = xprt->xp_port; /* Store port as global variable */ + + /* Version 2 ypbind only support IPv4 on TCP and UDP */ + if (strcmp(nconf->nc_protofmly, NC_INET) == 0 && + (nconf->nc_semantics == NC_TPI_CLTS || + nconf->nc_semantics == NC_TPI_COTS_ORD)) { + rpcb_unset(YPBINDPROG, YPBINDVERS, nconf); + if (!svc_reg(xprt, YPBINDPROG, YPBINDVERS, ypbindprog_2, nconf)) + errx(1, "unable to register (YPBINDPROG, YPBINDVERS, tcp)"); + } + } + freenetconfigent(nconf); /* build initial domain binding, make it "unsuccessful" */ ypbindlist = malloc(sizeof *ypbindlist); @@ -537,8 +670,9 @@ void handle_children(struct _dom_binding *ypdb) { + struct netbuf nb; + struct sockaddr addr; char buf[YPMAXDOMAIN + 1]; - struct sockaddr_in addr; int d = 0, a = 0; struct _dom_binding *y, *prev = NULL; char path[MAXPATHLEN]; @@ -546,15 +680,17 @@ if ((d = read(READFD, &buf, sizeof(buf))) <= 0) syslog(LOG_WARNING, "could not read from child: %m"); - if ((a = read(READFD, &addr, sizeof(struct sockaddr_in))) < 0) + if ((a = read(READFD, &addr, sizeof(struct sockaddr))) < 0) syslog(LOG_WARNING, "could not read from child: %m"); close(READFD); FD_CLR(READFD, &fdsr); FD_CLR(READFD, &svc_fdset); READFD = WRITEFD = -1; + nb.len = nb.maxlen = sizeof(struct sockaddr); + nb.buf = &addr; if (d > 0 && a > 0) - rpc_received(buf, &addr, 0); + rpc_received(buf, &nb, 0); else { for (y = ypbindlist; y; y = y->dom_pnext) { if (y == ypdb) @@ -591,8 +727,9 @@ * Send our dying words back to our parent before we perish. */ int -tell_parent(char *dom, struct sockaddr_in *addr) +tell_parent(char *dom, struct netbuf *addr) { + struct sockaddr * sa; char buf[YPMAXDOMAIN + 1]; struct timeval timeout; fd_set fds; @@ -614,7 +751,8 @@ if (select(FD_SETSIZE, NULL, &fds, NULL, &timeout) == -1) return(1); if (FD_ISSET(BROADFD, &fds)) { - if (write(BROADFD, addr, sizeof(struct sockaddr_in)) < 0) + sa = (struct sockaddr *)addr->buf; + if (write(BROADFD, sa, sizeof(*sa)) < 0) return(1); } else { return(1); @@ -625,8 +763,11 @@ } static bool_t -broadcast_result(bool_t *out, struct sockaddr_in *addr) +broadcast_result(bool_t *out, struct netbuf *addr, struct netconfig *nconf) { + char host[NI_MAXHOST]; + int ret; + if (retries >= MAX_RETRIES) { bzero(addr, sizeof(struct sockaddr_in)); if (tell_parent(broad_domain->dom_domain, addr)) @@ -634,9 +775,13 @@ return (TRUE); } - if (yp_restricted && verify(addr->sin_addr)) { + if (yp_restricted && verify(addr)) { + ret = getnameinfo((struct sockaddr *)addr->buf, addr->len, host, sizeof(host), + NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV); + if (ret != 0) + syslog(LOG_ERR, "getnameinfo failed: %s", gai_strerror(ret)); retries++; - syslog(LOG_NOTICE, "NIS server at %s not in restricted mode access list -- rejecting.\n",inet_ntoa(addr->sin_addr)); + syslog(LOG_NOTICE, "NIS server at %s not in restricted mode access list -- rejecting.\n", host); return (FALSE); } else { if (tell_parent(broad_domain->dom_domain, addr)) @@ -658,8 +803,10 @@ void broadcast(struct _dom_binding *ypdb) { - bool_t out = FALSE; + struct sockaddr *sa; + char host[NI_MAXHOST]; enum clnt_stat stat; + int ret; if (children >= MAX_CHILDREN || ypdb->dom_broadcast_pid) return; @@ -669,11 +816,16 @@ return; } - if (ypdb->dom_vers == -1 && (long)ypdb->dom_server_addr.sin_addr.s_addr) { + if (ypdb->dom_vers == -1 && ypdb->dom_binding->ypbind_svcaddr) { if (not_responding_count++ >= NOT_RESPONDING_HYSTERESIS) { not_responding_count = NOT_RESPONDING_HYSTERESIS; + sa = (struct sockaddr *)ypdb->dom_binding->ypbind_svcaddr->buf; + ret = getnameinfo(sa, sa->sa_len, host, sizeof(host), NULL, 0, + NI_NUMERICHOST | NI_NUMERICSERV); + if (ret != 0) + syslog(LOG_ERR, "getnameinfo failed: %s", gai_strerror(ret)); syslog(LOG_WARNING, "NIS server [%s] for domain \"%s\" not responding", - inet_ntoa(ypdb->dom_server_addr.sin_addr), ypdb->dom_domain); + host, ypdb->dom_domain); } } @@ -716,23 +868,23 @@ if (yp_restricted && yp_manycast) { short port; int i; - struct sockaddr_in sin; + struct sockaddr_storage ss; + struct netbuf nb; - i = __yp_ping(restricted_addrs, yp_restricted, + i = __yp_ping((struct sockaddr *)restricted_addrs, yp_restricted, ypdb->dom_domain, &port); if (i == -1) { - bzero(&ypdb->dom_server_addr, - sizeof(struct sockaddr_in)); + bzero(ypdb->dom_binding->ypbind_svcaddr, + sizeof(struct netbuf)); if (tell_parent(ypdb->dom_domain, - &ypdb->dom_server_addr)) + ypdb->dom_binding->ypbind_svcaddr)) syslog(LOG_WARNING, "lost connection to parent"); } else { - bzero(&sin, sizeof(struct sockaddr_in)); - bcopy(&restricted_addrs[i], - &sin.sin_addr, sizeof(struct in_addr)); - sin.sin_family = AF_INET; - sin.sin_port = port; - if (tell_parent(broad_domain->dom_domain, &sin)) + bzero(&ss, sizeof(struct sockaddr_storage)); + bcopy(&restricted_addrs[i], &ss, sizeof(struct sockaddr_storage)); + nb.len = nb.maxlen = sizeof(struct sockaddr_storage); + nb.buf = &ss; + if (tell_parent(broad_domain->dom_domain, &nb)) syslog(LOG_WARNING, "lost connection to parent"); } @@ -745,16 +897,16 @@ char *ptr; ptr = ypdb->dom_domain; - stat = clnt_broadcast(YPPROG, YPVERS, YPPROC_DOMAIN_NONACK, - (xdrproc_t)xdr_domainname, &ptr, - (xdrproc_t)xdr_bool, &out, - (resultproc_t)broadcast_result); + stat = rpc_broadcast(YPPROG, YPVERS, YPPROC_DOMAIN_NONACK, + (xdrproc_t)xdr_domainname, ptr, + (xdrproc_t)xdr_bool, (char *)NULL, + (resultproc_t)broadcast_result, NULL); } if (stat != RPC_SUCCESS) { - bzero(&ypdb->dom_server_addr, - sizeof(struct sockaddr_in)); - if (tell_parent(ypdb->dom_domain, &ypdb->dom_server_addr)) + bzero(ypdb->dom_binding->ypbind_svcaddr, + sizeof(struct netbuf)); + if (tell_parent(ypdb->dom_domain, ypdb->dom_binding->ypbind_svcaddr)) syslog(LOG_WARNING, "lost connection to parent"); } @@ -789,16 +941,15 @@ if (ypdb->dom_broadcast_pid) return(1); - - if ((client_handle = clntudp_bufcreate(&ypdb->dom_server_addr, - YPPROG, YPVERS, interval, &rpcsock, RPCSMALLMSGSIZE, - RPCSMALLMSGSIZE)) == (CLIENT *)NULL) { + if ((client_handle = clnt_dg_create(rpcsock, ypdb->dom_binding->ypbind_svcaddr, YPPROG, YPVERS, + RPCSMALLMSGSIZE, RPCSMALLMSGSIZE)) == (CLIENT *)NULL) { /* Can't get a handle: we're dead. */ ypdb->dom_alive = 0; ypdb->dom_vers = -1; broadcast(ypdb); return(1); } + clnt_control(client_handle, CLSET_TIMEOUT, (char *)&timeout); { char *ptr; @@ -822,13 +973,15 @@ } void -rpc_received(char *dom, struct sockaddr_in *raddrp, int force) +rpc_received(char *dom, struct netbuf *raddrp, int force) { + struct sockaddr * sa; struct _dom_binding *ypdb, *prev = NULL; struct iovec iov[2]; - struct ypbind_resp ybr; - char path[MAXPATHLEN]; - int fd; + struct ypbind_resp_3 ybr; + char path[MAXPATHLEN], host[NI_MAXHOST]; + int fd, ret; + u_short port = 0; /*printf("returned from %s/%d about %s\n", inet_ntoa(raddrp->sin_addr), ntohs(raddrp->sin_port), dom);*/ @@ -852,10 +1005,21 @@ } } + sa = (struct sockaddr *)raddrp->buf; + ret = getnameinfo(sa, sa->sa_len, + host, sizeof(host), NULL, 0, + NI_NUMERICHOST | NI_NUMERICSERV); + if (ret != 0) + syslog(LOG_ERR, "getnameinfo failed: %s", gai_strerror(ret)); + + if (sa->sa_family == AF_INET) + port = ntohs(((struct sockaddr_in *)sa)->sin_port); + else if (sa->sa_family == AF_INET6) + port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port); /* if in secure mode, check originating port number */ - if ((ypsecuremode && (ntohs(raddrp->sin_port) >= IPPORT_RESERVED))) { + if ((ypsecuremode && port >= IPPORT_RESERVED)) { syslog(LOG_WARNING, "Rejected NIS server on [%s/%d] for domain %s.", - inet_ntoa(raddrp->sin_addr), ntohs(raddrp->sin_port), + host, port, dom); if (ypdb != NULL) { ypdb->dom_broadcast_pid = 0; @@ -864,7 +1028,7 @@ return; } - if (raddrp->sin_addr.s_addr == (long)0) { + if (strcmp(host, "0.0.0.0") == 0 || strcmp(host, "::") == 0) { switch (ypdb->dom_default) { case 0: if (prev == NULL) @@ -909,16 +1073,15 @@ } /* We've recovered from a crash: inform the world. */ - if (ypdb->dom_vers == -1 && ypdb->dom_server_addr.sin_addr.s_addr) { + if (ypdb->dom_vers == -1 && ypdb->dom_binding->ypbind_svcaddr) { if (not_responding_count >= NOT_RESPONDING_HYSTERESIS) { not_responding_count = 0; syslog(LOG_WARNING, "NIS server [%s] for domain \"%s\" OK", - inet_ntoa(raddrp->sin_addr), ypdb->dom_domain); + host, ypdb->dom_domain); } } - bcopy(raddrp, &ypdb->dom_server_addr, - sizeof ypdb->dom_server_addr); + copy_netbuf(ypdb->dom_binding->ypbind_svcaddr, raddrp); ypdb->dom_vers = YPVERS; ypdb->dom_alive = 1; @@ -950,17 +1113,16 @@ */ ypdb->dom_lockfd = fd; - iov[0].iov_base = (char *)&(udptransp->xp_port); - iov[0].iov_len = sizeof udptransp->xp_port; + iov[0].iov_base = (char *)&(xprt_port); + iov[0].iov_len = sizeof xprt_port; iov[1].iov_base = (char *)&ybr; iov[1].iov_len = sizeof ybr; + ybr.ypbind_resp_3_u.ypbind_bindinfo.ypbind_svcaddr = malloc(sizeof(struct netbuf)); + if (ybr.ypbind_resp_3_u.ypbind_bindinfo.ypbind_svcaddr == NULL) + errx(1, "malloc"); bzero(&ybr, sizeof ybr); - ybr.ypbind_status = YPBIND_SUCC_VAL; - memcpy(&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr, - &raddrp->sin_addr.s_addr, sizeof(u_int32_t)); - memcpy(&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port, - &raddrp->sin_port, sizeof(u_short)); + copy_netbuf(ybr.ypbind_resp_3_u.ypbind_bindinfo.ypbind_svcaddr, raddrp); if (writev(ypdb->dom_lockfd, iov, 2) != iov[0].iov_len + iov[1].iov_len) { syslog(LOG_WARNING, "write: %m"); @@ -975,13 +1137,32 @@ * 1 if not matched. */ int -verify(struct in_addr addr) +verify(struct netbuf *addr) { int i; - - for (i = 0; i < RESTRICTED_SERVERS; i++) - if (!bcmp(&addr, &restricted_addrs[i], sizeof(struct in_addr))) - return(0); + struct sockaddr *sa = (struct sockaddr *)addr->buf; + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + + if (sa->sa_family == AF_INET) { + sin = (struct sockaddr_in *)sa; + for (i = 0; i < RESTRICTED_SERVERS; i++) { + if (restricted_addrs[i].ss_family== AF_INET && + !memcmp(&sin->sin_addr, &((struct sockaddr_in *)&restricted_addrs[i])->sin_addr, + sizeof(struct in_addr))) { + return 0; + } + } + } else if (sa->sa_family == AF_INET6) { + sin6 = (struct sockaddr_in6 *)sa; + for (i = 0; i < RESTRICTED_SERVERS; i++) { + if (restricted_addrs[i].ss_family == AF_INET6 && + !memcmp(&sin6->sin6_addr, &((struct sockaddr_in6 *)&restricted_addrs[i])->sin6_addr, + sizeof(struct in6_addr))) { + return 0; + } + } + } return(1); } @@ -993,8 +1174,8 @@ void yp_restricted_mode(char *args) { - struct hostent *h; - int i = 0; + struct addrinfo hints, *res; + int i = 0, status; char *s; /* Find the restricted domain. */ @@ -1002,14 +1183,25 @@ return; domain_name = s; + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + /* Get the addresses of the servers. */ while ((s = strsep(&args, ",")) != NULL && i < RESTRICTED_SERVERS) { - if ((h = gethostbyname(s)) == NULL) + if ((status = getaddrinfo(s, NULL, &hints, &res)) != 0) return; - bcopy (h->h_addr_list[0], &restricted_addrs[i], - sizeof(struct in_addr)); + + if (res->ai_family == AF_INET) { + struct sockaddr_in *ipv4 = (struct sockaddr_in *)res->ai_addr; + memcpy(&restricted_addrs[i], ipv4, sizeof(struct sockaddr_in)); + } else if (res->ai_family == AF_INET6) { + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)res->ai_addr; + memcpy(&restricted_addrs[i], ipv6, sizeof(struct sockaddr_in6)); + } i++; } + freeaddrinfo(res); /* ypset and ypsetme not allowed with restricted mode */ ypsetmode = YPSET_NO; @@ -1017,3 +1209,19 @@ yp_restricted = i; return; } + +void +copy_netbuf(struct netbuf *dst, struct netbuf *src) +{ + if (src == NULL || dst == NULL) + errx(1, "Invalid input: src or dst is NULL"); + if (src->len > src->maxlen) + errx(1, "Invalid input: src len is greater than maxlen"); + dst->maxlen = src->maxlen; + dst->len = src->len; + dst->buf = (char *)malloc(src->maxlen); + if (dst->buf == NULL) + errx(1, "malloc"); + memcpy(dst->buf, src->buf, src->len); + return; +}