diff options
Diffstat (limited to 'usr/src/cmd/ypcmd/ypserv_proc.c')
| -rw-r--r-- | usr/src/cmd/ypcmd/ypserv_proc.c | 1521 |
1 files changed, 1521 insertions, 0 deletions
diff --git a/usr/src/cmd/ypcmd/ypserv_proc.c b/usr/src/cmd/ypcmd/ypserv_proc.c new file mode 100644 index 0000000000..c5e8bc7c16 --- /dev/null +++ b/usr/src/cmd/ypcmd/ypserv_proc.c @@ -0,0 +1,1521 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +/* + * Portions of this source code were derived from Berkeley 4.3 BSD + * under license from the Regents of the University of California. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * + * This contains YP server code which supplies the set of functions + * requested using rpc. The top level functions in this module + * are those which have symbols of the form YPPROC_xxxx defined in + * yp_prot.h, and symbols of the form YPOLDPROC_xxxx defined in ypsym.h. + * The latter exist to provide compatibility to the old version of the yp + * protocol/server, and may emulate the behavior of the previous software + * by invoking some other program. + * + * This module also contains functions which are used by (and only by) the + * top-level functions here. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <dirent.h> +#include <limits.h> +#include <sys/systeminfo.h> +#include <rpc/rpc.h> +#include <string.h> +#include <malloc.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include "ypsym.h" +#include "ypdefs.h" +#include <ctype.h> + +/* Use shim version of DBM calls */ +#include "shim.h" +#include "shim_hooks.h" + +USE_YP_PREFIX +USE_YP_SECURE +USE_YP_INTERDOMAIN + +#ifndef YPXFR_PROC +#define YPXFR_PROC "/usr/lib/netsvc/yp/ypxfr" +#endif +static char ypxfr_proc[] = YPXFR_PROC; +#ifndef YPPUSH_PROC +#define YPPUSH_PROC "/usr/lib/netsvc/yp/yppush" +#endif +static char yppush_proc[] = YPPUSH_PROC; +struct yppriv_sym { + char *sym; + unsigned len; +}; +static char err_fork[] = "ypserv: %s fork failure.\n"; +#define FORK_ERR logprintf(err_fork, fun) +static char err_execl[] = "ypserv: %s execl failure.\n"; +#define EXEC_ERR logprintf(err_execl, fun) +static char err_respond[] = "ypserv: %s can't respond to rpc request.\n"; +#define RESPOND_ERR logprintf(err_respond, fun) +static char err_free[] = "ypserv: %s can't free args.\n"; +#define FREE_ERR logprintf(err_free, fun) +static char err_map[] = "ypserv: %s no such map or access denied.\n"; +#define MAP_ERR logprintf(err_map, fun) +static char err_vers[] = "ypserv: %s version not supported.\n"; +#define VERS_ERR logprintf(err_vers, fun) + +static void ypfilter(DBM *fdb, datum *inkey, datum *outkey, datum *val, + uint_t *status, bool_t update); +static bool isypsym(datum *key); +static bool xdrypserv_ypall(XDR *xdrs, struct ypreq_nokey *req); +static int multihomed(struct ypreq_key req, struct ypresp_val *resp, + SVCXPRT *xprt, DBM *fdb); +static int omultihomed(struct yprequest req, struct ypresponse *resp, + SVCXPRT *xprt, DBM *fdb); + + +/* For DNS forwarding */ +extern bool dnsforward; +extern bool client_setup_failure; +extern int resolv_pid; +extern CLIENT *resolv_client; +extern char *resolv_tp; + +/* + * This determines whether or not a passed domain is served by this + * server, and returns a boolean. Used by both old and new protocol + * versions. + */ +void +ypdomain(SVCXPRT *transp, bool always_respond) +{ + char domain_name[YPMAXDOMAIN + 1]; + char *pdomain_name = domain_name; + bool isserved; + char *fun = "ypdomain"; + struct netbuf *nbuf; + sa_family_t af; + + memset(domain_name, 0, sizeof (domain_name)); + + if (!svc_getargs(transp, (xdrproc_t)xdr_ypdomain_wrap_string, + (caddr_t)&pdomain_name)) { + svcerr_decode(transp); + return; + } + + /* + * If the file /var/yp/securenets is present on the server, and if + * the hostname is present in the file, then let the client bind to + * the server. + */ + nbuf = svc_getrpccaller(transp); + af = ((struct sockaddr_storage *)nbuf->buf)->ss_family; + if (af != AF_INET && af != AF_INET6) { + logprintf("Protocol incorrect\n"); + return; + } + + if (!(check_secure_net_ti(nbuf, fun))) { + MAP_ERR; + return; + } + + isserved = ypcheck_domain(domain_name); + + if (isserved || always_respond) { + + if (!svc_sendreply(transp, xdr_bool, (char *)&isserved)) { + RESPOND_ERR; + } + if (!isserved) + logprintf("Domain %s not supported\n", + domain_name); + + } else { + /* + * This case is the one in which the domain is not + * supported, and in which we are not to respond in the + * unsupported case. We are going to make an error happen + * to allow the portmapper to end his wait without the + * normal timeout period. The assumption here is that + * the only process in the world which is using the function + * in its no-answer-if-nack form is the portmapper, which is + * doing the krock for pseudo-broadcast. If some poor fool + * calls this function as a single-cast message, the nack + * case will look like an incomprehensible error. Sigh... + * (The traditional Unix disclaimer) + */ + + svcerr_decode(transp); + logprintf("Domain %s not supported (broadcast)\n", + domain_name); + } +} + +/* + * This implements the yp "match" function. + */ +void +ypmatch(SVCXPRT *transp, struct svc_req *rqstp) +{ + struct ypreq_key req; + struct ypresp_val resp; + char *fun = "ypmatch"; + DBM *fdb; + + memset(&req, 0, sizeof (req)); + memset(&resp, 0, sizeof (resp)); + resp.status = (unsigned)YP_NOKEY; + + if (!svc_getargs(transp, (xdrproc_t)xdr_ypreq_key, (char *)&req)) { + svcerr_decode(transp); + return; + } + + /* + * sanity check the map name and to a DBM lookup + * also perform an access check... + */ + if ((fdb = ypset_current_map(req.map, req.domain, + &resp.status)) != NULL && + yp_map_access(transp, &resp.status, fdb)) { + + /* Check with the DBM database */ + resp.valdat = dbm_fetch(fdb, req.keydat); + if (resp.valdat.dptr != NULL) { + resp.status = YP_TRUE; + if (!silent) + printf("%s: dbm: %40.40s\n", + fun, resp.valdat.dptr); + goto send_reply; + } + + /* + * If we're being asked to match YP_SECURE or YP_INTERDOMAIN + * and we haven't found it in the dbm file, then we don't + * really want to waste any more time. Specifically, we don't + * want to ask DNS + */ + if (req.keydat.dsize == 0 || + req.keydat.dptr == NULL || + req.keydat.dptr[0] == '\0' || + strncmp(req.keydat.dptr, yp_secure, req.keydat.dsize) == 0 || + strncmp(req.keydat.dptr, yp_interdomain, req.keydat.dsize) == 0) { + goto send_reply; + } + + /* Let's try the YP_MULTI_ hack... */ +#ifdef MINUS_C_OPTION + if (multiflag == TRUE && multihomed(req, &resp, transp, fdb)) + goto send_reply; +#else + if (multihomed(req, &resp, transp, fdb)) + goto send_reply; +#endif + + /* + * Let's try DNS, but if client_setup_failure is set, + * we have tried DNS in the past and failed, there is + * no reason in forcing an infinite loop by turning + * off DNS in setup_resolv() only to turn it back on + * again here. + */ + if (!dnsforward && !client_setup_failure) { + datum idkey, idval; + idkey.dptr = yp_interdomain; + idkey.dsize = yp_interdomain_sz; + idval = dbm_fetch(fdb, idkey); + if (idval.dptr) + dnsforward = TRUE; + } + + if (dnsforward) { + if (!resolv_pid || !resolv_client) { + setup_resolv(&dnsforward, &resolv_pid, + &resolv_client, resolv_tp, 0); + if (resolv_client == NULL) + client_setup_failure = TRUE; + } + + if (resolv_req(&dnsforward, &resolv_client, + &resolv_pid, resolv_tp, + rqstp->rq_xprt, &req, + req.map) == TRUE) + goto free_args; + } + } + send_reply: + + if (!svc_sendreply(transp, (xdrproc_t)xdr_ypresp_val, + (caddr_t)&resp)) { + RESPOND_ERR; + } + + free_args: + + if (!svc_freeargs(transp, (xdrproc_t)xdr_ypreq_key, + (char *)&req)) { + FREE_ERR; + } +} + + +/* + * This implements the yp "get first" function. + */ +void +ypfirst(SVCXPRT *transp) +{ + struct ypreq_nokey req; + struct ypresp_key_val resp; + char *fun = "ypfirst"; + DBM *fdb; + + memset(&req, 0, sizeof (req)); + memset(&resp, 0, sizeof (resp)); + + if (!svc_getargs(transp, + (xdrproc_t)xdr_ypreq_nokey, + (char *)&req)) { + svcerr_decode(transp); + return; + } + + if ((fdb = ypset_current_map(req.map, req.domain, + &resp.status)) != NULL && + yp_map_access(transp, &resp.status, fdb)) { + ypfilter(fdb, NULL, + &resp.keydat, &resp.valdat, &resp.status, FALSE); + } + + if (!svc_sendreply(transp, + (xdrproc_t)xdr_ypresp_key_val, + (char *)&resp)) { + RESPOND_ERR; + } + + if (!svc_freeargs(transp, (xdrproc_t)xdr_ypreq_nokey, + (char *)&req)) { + FREE_ERR; + } +} + +/* + * This implements the yp "get next" function. + */ +void +ypnext(SVCXPRT *transp) +{ + struct ypreq_key req; + struct ypresp_key_val resp; + char *fun = "ypnext"; + DBM *fdb; + + memset(&req, 0, sizeof (req)); + memset(&resp, 0, sizeof (resp)); + + if (!svc_getargs(transp, (xdrproc_t)xdr_ypreq_key, (char *)&req)) { + svcerr_decode(transp); + return; + } + + if ((fdb = ypset_current_map(req.map, req.domain, + &resp.status)) != NULL && + yp_map_access(transp, &resp.status, fdb)) { + ypfilter(fdb, &req.keydat, + &resp.keydat, &resp.valdat, &resp.status, FALSE); + } + + if (!svc_sendreply(transp, + (xdrproc_t)xdr_ypresp_key_val, + (char *)&resp)) { + RESPOND_ERR; + } + + if (!svc_freeargs(transp, + (xdrproc_t)xdr_ypreq_key, + (char *)&req)) { + FREE_ERR; + } +} + +/* + * This implements the "transfer map" function. It takes the domain + * and map names and the callback information provided by the + * requester (yppush on some node), and execs a ypxfr process to do + * the actual transfer. + */ +void +ypxfr(SVCXPRT *transp, int prog) +{ + struct ypreq_newxfr newreq; + struct ypreq_xfr oldreq; + struct ypresp_val resp; /* not returned to the caller */ + char transid[32]; + char proto[32]; + char name[256]; + char *pdomain, *pmap; + pid_t pid = -1; + char *fun = "ypxfr"; + DBM *fdb; + + if (prog == YPPROC_NEWXFR) { + memset(&newreq, 0, sizeof (newreq)); + if (!svc_getargs(transp, (xdrproc_t)xdr_ypreq_newxfr, + (char *)&newreq)) { + svcerr_decode(transp); + return; + } + +#ifdef OPCOM_DEBUG + fprintf(stderr, "newreq:\n" + "\tmap_parms:\n" + "\t\tdomain: %s\n" + "\t\tmap: %s\n" + "\t\tordernum: %u\n" + "\t\towner: %s\n" + "\ttransid: %u\n" + "\tproto: %u\n" + "\tname: %s\n\n", + newreq.map_parms.domain, + newreq.map_parms.map, + newreq.map_parms.ordernum, + newreq.map_parms.owner, + newreq.transid, + newreq.proto, + newreq.name); +#endif + sprintf(transid, "%u", newreq.transid); + sprintf(proto, "%u", newreq.proto); + sprintf(name, "%s", newreq.ypxfr_owner); + pdomain = newreq.ypxfr_domain; + pmap = newreq.ypxfr_map; + } else if (prog == YPPROC_XFR) { + memset(&oldreq, 0, sizeof (oldreq)); + if (!svc_getargs(transp, + (xdrproc_t)xdr_ypreq_xfr, + (char *)&oldreq)) { + svcerr_decode(transp); + return; + } + +#ifdef OPCOM_DEBUG + fprintf(stderr, "oldreq:\n" + "\tmap_parms:\n" + "\t\tdomain: %s\n" + "\t\tmap: %s\n" + "\t\tordernum: %u\n" + "\t\towner: %s\n" + "\ttransid: %u\n" + "\tproto: %u\n" + "\tport: %u\n\n", + oldreq.map_parms.domain, + oldreq.map_parms.map, + oldreq.map_parms.ordernum, + oldreq.map_parms.owner, + oldreq.transid, + oldreq.proto, + oldreq.port); +#endif + + sprintf(transid, "%u", oldreq.transid); + sprintf(proto, "%u", oldreq.proto); + sprintf(name, "%s", oldreq.ypxfr_owner); + pdomain = oldreq.ypxfr_domain; + pmap = oldreq.ypxfr_map; + } else { + VERS_ERR; + } + + /* Check that the map exists and is accessible */ + if ((fdb = ypset_current_map(pmap, pdomain, &resp.status)) != NULL && + yp_map_access(transp, &resp.status, fdb)) { + + pid = vfork(); + if (pid == -1) { + FORK_ERR; + } else if (pid == 0) { + if (prog == YPPROC_NEWXFR || prog == YPPROC_XFR) { +#ifdef OPCOM_DEBUG + fprintf(stderr, + "EXECL: %s, -d, %s, -C, %s, %s, %s, %s\n", + ypxfr_proc, pdomain, + transid, proto, name, pmap); +#endif + if (execl(ypxfr_proc, "ypxfr", "-d", + pdomain, "-C", transid, proto, + name, pmap, NULL)) + EXEC_ERR; + } else { + VERS_ERR; + } + _exit(1); + } + + } else { + MAP_ERR; + } + if (!svc_sendreply(transp, xdr_void, 0)) { + RESPOND_ERR; + } + + if (prog == YPPROC_NEWXFR) { + if (!svc_freeargs(transp, + (xdrproc_t)xdr_ypreq_newxfr, + (char *)&newreq)) { + FREE_ERR; + } + } +} + +/* + * This implements the "get all" function. + */ +void +ypall(SVCXPRT *transp) +{ + struct ypreq_nokey req; + struct ypresp_val resp; /* not returned to the caller */ + pid_t pid; + char *fun = "ypall"; + DBM *fdb; + + req.domain = req.map = NULL; + + memset((char *)&req, 0, sizeof (req)); + + if (!svc_getargs(transp, + (xdrproc_t)xdr_ypreq_nokey, + (char *)&req)) { + svcerr_decode(transp); + return; + } + + pid = fork1(); + + if (pid) { + + if (pid == -1) { + FORK_ERR; + } + + if (!svc_freeargs(transp, + (xdrproc_t)xdr_ypreq_nokey, + (char *)&req)) { + FREE_ERR; + } + + return; + } + + /* + * access control hack: If denied then invalidate the map name. + */ + ypclr_current_map(); + if ((fdb = ypset_current_map(req.map, + req.domain, &resp.status)) != NULL && + !yp_map_access(transp, &resp.status, fdb)) { + + req.map[0] = '-'; + } + + /* + * This is the child process. The work gets done by xdrypserv_ypall/ + * we must clear the "current map" first so that we do not + * share a seek pointer with the parent server. + */ + + if (!svc_sendreply(transp, + (xdrproc_t)xdrypserv_ypall, + (char *)&req)) { + RESPOND_ERR; + } + + if (!svc_freeargs(transp, + (xdrproc_t)xdr_ypreq_nokey, + (char *)&req)) { + FREE_ERR; + } + + /* + * In yptol mode we may start a cache update thread within a child + * process. It is thus important that child processes do not exit, + * killing any such threads, before the thread has completed. + */ + if (yptol_mode) { + thr_join(0, NULL, NULL); + } + + exit(0); +} + +/* + * This implements the "get master name" function. + */ +void +ypmaster(SVCXPRT *transp) +{ + struct ypreq_nokey req; + struct ypresp_master resp; + char *nullstring = ""; + char *fun = "ypmaster"; + DBM *fdb; + + memset((char *)&req, 0, sizeof (req)); + resp.master = nullstring; + resp.status = YP_TRUE; + + if (!svc_getargs(transp, + (xdrproc_t)xdr_ypreq_nokey, + (char *)&req)) { + svcerr_decode(transp); + return; + } + + if ((fdb = ypset_current_map(req.map, + req.domain, &resp.status)) != NULL && + yp_map_access(transp, &resp.status, fdb)) { + + if (!ypget_map_master(&resp.master, fdb)) { + resp.status = (unsigned)YP_BADDB; + } + } + + if (!svc_sendreply(transp, + (xdrproc_t)xdr_ypresp_master, + (char *)&resp)) { + RESPOND_ERR; + } + + if (!svc_freeargs(transp, + (xdrproc_t)xdr_ypreq_nokey, + (char *)&req)) { + FREE_ERR; + } +} + +/* + * This implements the "get order number" function. + */ +void +yporder(SVCXPRT *transp) +{ + struct ypreq_nokey req; + struct ypresp_order resp; + char *fun = "yporder"; + DBM *fdb; + + req.domain = req.map = NULL; + resp.status = YP_TRUE; + resp.ordernum = 0; + + memset((char *)&req, 0, sizeof (req)); + + if (!svc_getargs(transp, + (xdrproc_t)xdr_ypreq_nokey, + (char *)&req)) { + svcerr_decode(transp); + return; + } + + resp.ordernum = 0; + + if ((fdb = ypset_current_map(req.map, + req.domain, + &resp.status)) != NULL && + yp_map_access(transp, &resp.status, fdb)) { + + if (!ypget_map_order(req.map, req.domain, &resp.ordernum)) { + resp.status = (unsigned)YP_BADDB; + } + } + + if (!svc_sendreply(transp, + (xdrproc_t)xdr_ypresp_order, + (char *)&resp)) { + RESPOND_ERR; + } + + if (!svc_freeargs(transp, + (xdrproc_t)xdr_ypreq_nokey, + (char *)&req)) { + FREE_ERR; + } +} + +void +ypmaplist(SVCXPRT *transp) +{ + char domain_name[YPMAXDOMAIN + 1]; + char *pdomain = domain_name; + char *fun = "ypmaplist"; + struct ypresp_maplist maplist; + struct ypmaplist *tmp; + + maplist.list = (struct ypmaplist *)NULL; + + memset(domain_name, 0, sizeof (domain_name)); + + if (!svc_getargs(transp, + (xdrproc_t)xdr_ypdomain_wrap_string, + (caddr_t)&pdomain)) { + svcerr_decode(transp); + return; + } + + maplist.status = yplist_maps(domain_name, &maplist.list); + + if (!svc_sendreply(transp, + (xdrproc_t)xdr_ypresp_maplist, + (char *)&maplist)) { + RESPOND_ERR; + } + + while (maplist.list) { + tmp = maplist.list->ypml_next; + free((char *)maplist.list); + maplist.list = tmp; + } +} + +/* + * Ancillary functions used by the top-level functions within this + * module + */ + +/* + * This returns TRUE if a given key is a yp-private symbol, otherwise + * FALSE + */ +static bool +isypsym(datum *key) +{ + if ((key->dptr == NULL) || + (key->dsize < yp_prefix_sz) || + memcmp(yp_prefix, key->dptr, yp_prefix_sz) || + (!memcmp(key->dptr, "YP_MULTI_", 9))) { + return (FALSE); + } + return (TRUE); +} + +/* + * This provides private-symbol filtration for the enumeration functions. + */ +static void +ypfilter(DBM *fdb, datum *inkey, datum *outkey, datum *val, uint_t *status, + bool_t update) +{ + datum k; + + if (inkey) { + + if (isypsym(inkey)) { + *status = (unsigned)YP_BADARGS; + return; + } + + k = dbm_do_nextkey(fdb, *inkey); + } else { + k = dbm_firstkey(fdb); + } + + while (k.dptr && isypsym(&k)) { + k = dbm_nextkey(fdb); + } + + if (k.dptr == NULL) { + *status = YP_NOMORE; + return; + } + + *outkey = k; + + /* + * In N2L mode we must call a version of dbm_fetch() that either does + * or does not check for entry updates. In non N2L mode both of these + * will end up doing a normal dbm_fetch(). + */ + if (update) + *val = shim_dbm_fetch(fdb, k); + else + *val = shim_dbm_fetch_noupdate(fdb, k); + + if (val->dptr != NULL) { + *status = YP_TRUE; + } else { + *status = (unsigned)YP_BADDB; + } +} + +/* + * Serializes a stream of struct ypresp_key_val's. This is used + * only by the ypserv side of the transaction. + */ +static bool +xdrypserv_ypall(XDR *xdrs, struct ypreq_nokey *req) +{ + bool_t more = TRUE; + struct ypresp_key_val resp; + DBM *fdb; + + resp.keydat.dptr = resp.valdat.dptr = (char *)NULL; + resp.keydat.dsize = resp.valdat.dsize = 0; + + if ((fdb = ypset_current_map(req->map, req->domain, + &resp.status)) != NULL) { + ypfilter(fdb, (datum *) NULL, &resp.keydat, &resp.valdat, + &resp.status, FALSE); + + while (resp.status == YP_TRUE) { + if (!xdr_bool(xdrs, &more)) { + return (FALSE); + } + + if (!xdr_ypresp_key_val(xdrs, &resp)) { + return (FALSE); + } + + ypfilter(fdb, &resp.keydat, &resp.keydat, &resp.valdat, + &resp.status, FALSE); + } + } + + if (!xdr_bool(xdrs, &more)) { + return (FALSE); + } + + if (!xdr_ypresp_key_val(xdrs, &resp)) { + return (FALSE); + } + + more = FALSE; + + if (!xdr_bool(xdrs, &more)) { + return (FALSE); + } + + return (TRUE); +} + +/* + * Additions for sparc cluster support + */ + +/* + * Check for special multihomed host cookie in the key. If there, + * collect the addresses from the comma separated list and return + * the one that's nearest the client. + */ +static int +multihomed(struct ypreq_key req, struct ypresp_val *resp, + SVCXPRT *xprt, DBM *fdb) +{ + char *cp, *bp; + ulong_t bestaddr, call_addr; + struct netbuf *nbuf; + char name[PATH_MAX]; + static char localbuf[_PBLKSIZ]; /* buffer for multihomed IPv6 addr */ + + if (strcmp(req.map, "hosts.byname") && + strcmp(req.map, "ipnodes.byname")) + /* default status is YP_NOKEY */ + return (0); + + if (strncmp(req.keydat.dptr, "YP_MULTI_", 9)) { + datum tmpname; + + strncpy(name, "YP_MULTI_", 9); + strncpy(name + 9, req.keydat.dptr, req.keydat.dsize); + tmpname.dsize = req.keydat.dsize + 9; + tmpname.dptr = name; + resp->valdat = dbm_fetch(fdb, tmpname); + } else { + /* + * Return whole line (for debugging) if YP_MULTI_hostnam + * is specified. + */ + resp->valdat = dbm_fetch(fdb, req.keydat); + if (resp->valdat.dptr != NULL) + return (1); + } + + if (resp->valdat.dptr == NULL) + return (0); + + strncpy(name, req.keydat.dptr, req.keydat.dsize); + name[req.keydat.dsize] = NULL; + + if (strcmp(req.map, "ipnodes.byname") == 0) { + /* + * This section handles multihomed IPv6 addresses. + * It returns all the IPv6 addresses one per line and only + * the requested hostname is returned. NO aliases will be + * returned. This is done exactly the same way DNS forwarding + * daemon handles multihomed hosts. + * New IPv6 enabled clients should be able to handle this + * information returned. The sorting is also the client's + * responsibility. + */ + + char *buf, *endbuf; + + if ((buf = strdup(resp->valdat.dptr)) == NULL) /* no memory */ + return (0); + if ((bp = strtok(buf, " \t")) == NULL) { /* no address field */ + free(buf); + return (0); + } + if ((cp = strtok(NULL, "")) == NULL) { /* no host field */ + free(buf); + return (0); + } + if ((cp = strtok(bp, ",")) != NULL) { /* multihomed host */ + int bsize; + + localbuf[0] = '\0'; + bsize = sizeof (localbuf); + endbuf = localbuf; + + while (cp) { + if ((strlen(cp) + strlen(name)) >= bsize) { + /* out of range */ + break; + } + sprintf(endbuf, "%s %s\n", cp, name); + cp = strtok(NULL, ","); + endbuf = &endbuf[strlen(endbuf)]; + bsize = &localbuf[sizeof (localbuf)] - endbuf; + } + resp->valdat.dptr = localbuf; + resp->valdat.dsize = strlen(localbuf); + } + + free(buf); + /* remove trailing newline */ + if (resp->valdat.dsize && + resp->valdat.dptr[resp->valdat.dsize-1] == '\n') { + resp->valdat.dptr[resp->valdat.dsize-1] = '\0'; + resp->valdat.dsize -= 1; + } + + resp->status = YP_TRUE; + return (1); + } + nbuf = svc_getrpccaller(xprt); + /* + * OK, now I have a netbuf structure which I'm supposed to + * treat as opaque... I hate transport independance! + * So, we're just gonna doit wrong... By wrong I mean that + * we assume that the buf part of the netbuf structure is going + * to be a sockaddr_in. We'll then check the assumed family + * member and hope that we find AF_INET in there... if not + * then we can't continue. + */ + if (((struct sockaddr_in *)(nbuf->buf))->sin_family != AF_INET) + return (0); + + call_addr = ((struct sockaddr_in *)(nbuf->buf))->sin_addr.s_addr; + + cp = resp->valdat.dptr; + if ((bp = strtok(cp, " \t")) == NULL) /* no address field */ + return (0); + if ((cp = strtok(NULL, "")) == NULL) /* no host field */ + return (0); + bp = strtok(bp, ","); + + bestaddr = inet_addr(bp); + while (cp = strtok(NULL, ",")) { + ulong_t taddr; + + taddr = inet_addr(cp); + if (ntohl(call_addr ^ taddr) < ntohl(call_addr ^ bestaddr)) + bestaddr = taddr; + } + cp = resp->valdat.dptr; + sprintf(cp, "%s %s", inet_ntoa(*(struct in_addr *)&bestaddr), name); + resp->valdat.dsize = strlen(cp); + + resp->status = YP_TRUE; + + return (1); +} + +/* V1 dispatch routines */ +void +ypoldmatch(SVCXPRT *transp, struct svc_req *rqstp) +{ + bool dbmop_ok = TRUE; + struct yprequest req; + struct ypreq_key nrq; + struct ypresponse resp; + char *fun = "ypoldmatch"; + DBM *fdb; + + memset((void *) &req, 0, sizeof (req)); + memset((void *) &resp, 0, sizeof (resp)); + + if (!svc_getargs(transp, + (xdrproc_t)_xdr_yprequest, + (caddr_t)&req)) { + svcerr_decode(transp); + return; + } + + if (req.yp_reqtype != YPMATCH_REQTYPE) { + resp.ypmatch_resp_status = (unsigned)YP_BADARGS; + dbmop_ok = FALSE; + } + + if (dbmop_ok && + (((fdb = ypset_current_map(req.ypmatch_req_map, + req.ypmatch_req_domain, + &resp.ypmatch_resp_status)) + != NULL) && + yp_map_access(transp, + &resp.ypmatch_resp_status, + fdb))) { + + /* Check with the DBM database */ + resp.ypmatch_resp_valdat = dbm_fetch(fdb, + req.ypmatch_req_keydat); + + if (resp.ypmatch_resp_valptr != NULL) { + resp.ypmatch_resp_status = YP_TRUE; + if (!silent) + printf("%s: dbm: %s\n", + fun, resp.ypmatch_resp_valptr); + goto send_oldreply; + } + + /* + * If we're being asked to match YP_SECURE or YP_INTERDOMAIN + * and we haven't found it in the dbm file, then we don't + * really want to waste any more time. Specifically, we don't + * want to ask DNS + */ + if (req.ypmatch_req_keysize == 0 || + req.ypmatch_req_keyptr == NULL || + req.ypmatch_req_keyptr[0] == '\0' || + strncmp(req.ypmatch_req_keyptr, "YP_SECURE", 9) == 0 || + strncmp(req.ypmatch_req_keyptr, "YP_INTERDOMAIN", 14) == 0) + + goto send_oldreply; + + /* Let's try the YP_MULTI_ hack... */ +#ifdef MINUS_C_OPTION + if (multiflag == TRUE && omultihomed(req, &resp, transp, fdb)) + goto send_oldreply; +#else + if (omultihomed(req, &resp, transp, fdb)) + goto send_oldreply; +#endif + + /* Let's try DNS */ + if (!dnsforward) { + USE_YP_INTERDOMAIN + datum idkey, idval; + idkey.dptr = yp_interdomain; + idkey.dsize = yp_interdomain_sz; + idval = dbm_fetch(fdb, idkey); + if (idval.dptr) + dnsforward = TRUE; + } + + if (dnsforward) { + if (!resolv_pid) + setup_resolv(&dnsforward, &resolv_pid, &resolv_client, + resolv_tp, 0); + + if (req.yp_reqtype == YPREQ_KEY) { + nrq = req.yp_reqbody.yp_req_keytype; + + resolv_req(&dnsforward, &resolv_client, &resolv_pid, + resolv_tp, rqstp->rq_xprt, + &nrq, nrq.map); + } + return; + } + } + + send_oldreply: + + if (!svc_sendreply(transp, + (xdrproc_t)_xdr_ypresponse, + (caddr_t)&resp)) { + RESPOND_ERR; + } + + if (!svc_freeargs(transp, + (xdrproc_t)_xdr_yprequest, + (char *)&req)) { + FREE_ERR; + } +} + +void +ypoldfirst(SVCXPRT *transp) +{ + bool dbmop_ok = TRUE; + struct yprequest req; + struct ypresponse resp; + char *fun = "ypoldfirst"; + DBM *fdb; + + memset((void *) &req, 0, sizeof (req)); + memset((void *) &resp, 0, sizeof (resp)); + + if (!svc_getargs(transp, + (xdrproc_t)_xdr_yprequest, + (caddr_t)&req)) { + svcerr_decode(transp); + return; + } + + if (req.yp_reqtype != YPFIRST_REQTYPE) { + resp.ypfirst_resp_status = (unsigned)YP_BADARGS; + dbmop_ok = FALSE; + } + + if (dbmop_ok && + ((fdb = ypset_current_map(req.ypfirst_req_map, + req.ypfirst_req_domain, + &resp.ypfirst_resp_status)) + != NULL) && + yp_map_access(transp, + &resp.ypfirst_resp_status, + fdb)) { + + resp.ypfirst_resp_keydat = dbm_firstkey(fdb); + + if (resp.ypfirst_resp_keyptr != NULL) { + resp.ypfirst_resp_valdat = + dbm_fetch(fdb, resp.ypfirst_resp_keydat); + + if (resp.ypfirst_resp_valptr != NULL) { + resp.ypfirst_resp_status = YP_TRUE; + } else { + resp.ypfirst_resp_status = (unsigned)YP_BADDB; + } + } else { + resp.ypfirst_resp_status = (unsigned)YP_NOKEY; + } + } + + resp.yp_resptype = YPFIRST_RESPTYPE; + + if (!svc_sendreply(transp, + (xdrproc_t)_xdr_ypresponse, + (caddr_t)&resp)) { + RESPOND_ERR; + } + + if (!svc_freeargs(transp, + (xdrproc_t)_xdr_yprequest, + (caddr_t)&req)) { + FREE_ERR; + } +} + +void +ypoldnext(SVCXPRT *transp) +{ + bool dbmop_ok = TRUE; + struct yprequest req; + struct ypresponse resp; + char *fun = "ypoldnext"; + DBM *fdb; + + memset((void *) &req, 0, sizeof (req)); + memset((void *) &resp, 0, sizeof (resp)); + + if (!svc_getargs(transp, + (xdrproc_t)_xdr_yprequest, + (caddr_t)&req)) { + svcerr_decode(transp); + return; + } + + if (req.yp_reqtype != YPNEXT_REQTYPE) { + resp.ypnext_resp_status = (unsigned)YP_BADARGS; + dbmop_ok = FALSE; + } + + if (dbmop_ok && + ((fdb = ypset_current_map(req.ypnext_req_map, + req.ypnext_req_domain, + &resp.ypnext_resp_status)) != NULL && + yp_map_access(transp, &resp.ypnext_resp_status, fdb))) { + + resp.ypnext_resp_keydat = dbm_nextkey(fdb); + + if (resp.ypnext_resp_keyptr != NULL) { + resp.ypnext_resp_valdat = + dbm_fetch(fdb, resp.ypnext_resp_keydat); + + if (resp.ypnext_resp_valptr != NULL) { + resp.ypnext_resp_status = YP_TRUE; + } else { + resp.ypnext_resp_status = (unsigned)YP_BADDB; + } + } else { + resp.ypnext_resp_status = (unsigned)YP_NOMORE; + } + } + + resp.yp_resptype = YPNEXT_RESPTYPE; + + if (!svc_sendreply(transp, + (xdrproc_t)_xdr_ypresponse, + (caddr_t)&resp)) { + RESPOND_ERR; + } + + if (!svc_freeargs(transp, + (xdrproc_t)_xdr_yprequest, + (caddr_t)&req)) { + FREE_ERR; + } +} + +/* + * This retrieves the order number and master peer name from the map. + * The conditions for the various message fields are: domain is filled + * in iff the domain exists. map is filled in iff the map exists. + * order number is filled in iff it's in the map. owner is filled in + * iff the master peer is in the map. + */ +void +ypoldpoll(SVCXPRT *transp) +{ + struct yprequest req; + struct ypresponse resp; + char *map = ""; + char *domain = ""; + char *owner = ""; + uint_t error; + char *fun = "ypoldpoll"; + DBM *fdb; + + memset((void *) &req, 0, sizeof (req)); + memset((void *) &resp, 0, sizeof (resp)); + + if (!svc_getargs(transp, + (xdrproc_t)_xdr_yprequest, + (caddr_t)&req)) { + svcerr_decode(transp); + return; + } + + if (req.yp_reqtype == YPPOLL_REQTYPE) { + if (strcmp(req.yppoll_req_domain, "yp_private") == 0 || + strcmp(req.yppoll_req_map, "ypdomains") == 0 || + strcmp(req.yppoll_req_map, "ypmaps") == 0) { + + /* + * Backward comatibility for 2.0 NIS servers + */ + domain = req.yppoll_req_domain; + map = req.yppoll_req_map; + } else if ((fdb = ypset_current_map(req.yppoll_req_map, + req.yppoll_req_domain, + &error)) != NULL) { + domain = req.yppoll_req_domain; + map = req.yppoll_req_map; + ypget_map_order(map, domain, + &resp.yppoll_resp_ordernum); + ypget_map_master(&owner, fdb); + } else { + switch ((int)error) { + case YP_BADDB: + map = req.yppoll_req_map; + /* Fall through to set the domain too. */ + + case YP_NOMAP: + domain = req.yppoll_req_domain; + break; + } + } + } + + resp.yp_resptype = YPPOLL_RESPTYPE; + resp.yppoll_resp_domain = domain; + resp.yppoll_resp_map = map; + resp.yppoll_resp_owner = owner; + + if (!svc_sendreply(transp, + (xdrproc_t)_xdr_ypresponse, + (caddr_t)&resp)) { + RESPOND_ERR; + } + + if (!svc_freeargs(transp, + (xdrproc_t)_xdr_yprequest, + (caddr_t)&req)) { + FREE_ERR; + } +} + +void +ypoldpush(SVCXPRT *transp) +{ + struct yprequest req; + struct ypresp_val resp; + pid_t pid = -1; + char *fun = "ypoldpush"; + DBM *fdb; + + memset((void *) &req, 0, sizeof (req)); + + if (!svc_getargs(transp, + (xdrproc_t)_xdr_yprequest, + (caddr_t)&req)) { + svcerr_decode(transp); + return; + } + + if (((fdb = ypset_current_map(req.yppush_req_map, + req.yppush_req_domain, + &resp.status)) != NULL) && + (yp_map_access(transp, &resp.status, fdb))) { + + pid = vfork(); + } + + if (pid == -1) { + FORK_ERR; + } else if (pid == 0) { + ypclr_current_map(); + + if (execl(yppush_proc, "yppush", "-d", req.yppush_req_domain, + req.yppush_req_map, NULL)) { + EXEC_ERR; + } + _exit(1); + } + + if (!svc_sendreply(transp, + (xdrproc_t)xdr_void, + (caddr_t)NULL)) { + RESPOND_ERR; + } + + if (!svc_freeargs(transp, + (xdrproc_t)_xdr_yprequest, + (caddr_t)&req)) { + FREE_ERR; + } +} + +void +ypoldpull(SVCXPRT *transp) +{ + struct yprequest req; + struct ypresp_val resp; + pid_t pid = -1; + char *fun = "ypoldpull"; + DBM *fdb; + + memset((void *) &req, 0, sizeof (req)); + + if (!svc_getargs(transp, + (xdrproc_t)_xdr_yprequest, + (caddr_t)&req)) { + svcerr_decode(transp); + return; + } + + if (req.yp_reqtype == YPPULL_REQTYPE) { + + if (((fdb = ypset_current_map(req.yppull_req_map, + req.yppull_req_domain, + &resp.status)) == NULL) || + (yp_map_access(transp, &resp.status, fdb))) { + pid = vfork(); + } + + if (pid == -1) { + FORK_ERR; + } else if (pid == 0) { + ypclr_current_map(); + + if (execl(ypxfr_proc, "ypxfr", "-d", + req.yppull_req_domain, + req.yppull_req_map, NULL)) { + EXEC_ERR; + } + _exit(1); + } + } + + if (!svc_freeargs(transp, + (xdrproc_t)_xdr_yprequest, + (caddr_t)&req)) { + FREE_ERR; + } +} + +void +ypoldget(SVCXPRT *transp) +{ + struct yprequest req; + struct ypresp_val resp; + pid_t pid = -1; + char *fun = "ypoldget"; + DBM *fdb; + + memset((void *) &req, 0, sizeof (req)); + + if (!svc_getargs(transp, + (xdrproc_t)_xdr_yprequest, + (caddr_t)&req)) { + svcerr_decode(transp); + return; + } + + if (!svc_sendreply(transp, xdr_void, 0)) { + RESPOND_ERR; + } + + if (req.yp_reqtype == YPGET_REQTYPE) { + + if (((fdb = ypset_current_map(req.ypget_req_map, + req.ypget_req_domain, + &resp.status)) == NULL) || + (yp_map_access(transp, &resp.status, fdb))) { + + pid = vfork(); + } + + if (pid == -1) { + FORK_ERR; + } else if (pid == 0) { + + ypclr_current_map(); + + if (execl(ypxfr_proc, "ypxfr", "-d", + req.ypget_req_domain, "-h", + req.ypget_req_owner, + req.ypget_req_map, NULL)) { + + EXEC_ERR; + } + _exit(1); + } + } + + if (!svc_freeargs(transp, + (xdrproc_t)_xdr_yprequest, + (caddr_t)&req)) { + RESPOND_ERR; + } +} + +static int +omultihomed(struct yprequest req, + struct ypresponse *resp, SVCXPRT *xprt, DBM *fdb) +{ + char *cp, *bp; + char name[PATH_MAX]; + struct netbuf *nbuf; + ulong_t bestaddr, call_addr; + + if (strcmp(req.ypmatch_req_map, "hosts.byname")) + return (0); + + if (strncmp(req.ypmatch_req_keyptr, "YP_MULTI_", 9)) { + datum tmpname; + + strncpy(name, "YP_MULTI_", 9); + strncpy(name + 9, req.ypmatch_req_keyptr, + req.ypmatch_req_keysize); + tmpname.dsize = req.ypmatch_req_keysize + 9; + tmpname.dptr = name; + resp->ypmatch_resp_valdat = dbm_fetch(fdb, tmpname); + } else { + resp->ypmatch_resp_valdat = + dbm_fetch(fdb, req.ypmatch_req_keydat); + if (resp->ypmatch_resp_valptr != NULL) + return (1); + } + + if (resp->ypmatch_resp_valptr == NULL) + return (0); + + strncpy(name, req.ypmatch_req_keyptr, req.ypmatch_req_keysize); + name[req.ypmatch_req_keysize] = NULL; + + nbuf = svc_getrpccaller(xprt); + + /* + * OK, now I have a netbuf structure which I'm supposed to treat + * as opaque... I hate transport independance! So, we're just + * gonna doit wrong... By wrong I mean that we assume that the + * buf part of the netbuf structure is going to be a sockaddr_in. + * We'll then check the assumed family member and hope that we + * find AF_INET in there... if not then we can't continue. + */ + if (((struct sockaddr_in *)(nbuf->buf))->sin_family != AF_INET) + return (0); + + call_addr = ((struct sockaddr_in *)(nbuf->buf))->sin_addr.s_addr; + + cp = resp->ypmatch_resp_valptr; + if ((bp = strtok(cp, "\t")) == NULL) /* No address field */ + return (0); + if ((cp = strtok(NULL, "")) == NULL) /* No host field */ + return (0); + bp = strtok(bp, ","); + + bestaddr = inet_addr(bp); + while (cp = strtok(NULL, ",")) { + ulong_t taddr; + + taddr = inet_addr(cp); + if (ntohl(call_addr ^ taddr) < ntohl(call_addr ^ bestaddr)) + bestaddr = taddr; + } + + cp = resp->ypmatch_resp_valptr; + sprintf(cp, "%s %s", inet_ntoa(*(struct in_addr *)&bestaddr), name); + resp->ypmatch_resp_valsize = strlen(cp); + + resp->ypmatch_resp_status = YP_TRUE; + + return (1); +} |
