2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 1989, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
2N/A/* All Rights Reserved */
2N/A
2N/A/*
2N/A * Portions of this source code were derived from Berkeley
2N/A * under license from the Regents of the University of
2N/A * California.
2N/A */
2N/A
2N/A#include "mt.h"
2N/A#include <stdlib.h>
2N/A#include <unistd.h>
2N/A#include <rpc/rpc.h>
2N/A#include <syslog.h>
2N/A#include <rpcsvc/yp_b.h>
2N/A#include <rpcsvc/yp_prot.h>
2N/A#include <rpcsvc/ypclnt.h>
2N/A#include <netdir.h>
2N/A#include <string.h>
2N/A
2N/Aextern int __yp_dobind_cflookup(char *, struct dom_binding **, int);
2N/A
2N/Astatic struct timeval tp_timout = { 120, 0};
2N/Astatic char nullstring[] = "\000";
2N/A
2N/A/*
2N/A * __yp_all_cflookup() is a variant of the yp_all() code,
2N/A * which adds a 'hardlookup' parameter. This parameter is passed
2N/A * to __yp_dobind_cflookup(), and determines whether the server
2N/A * binding attempt is hard (try forever) of soft (retry a compiled-
2N/A * in number of times).
2N/A */
2N/Aint
2N/A__yp_all_cflookup(char *domain, char *map, struct ypall_callback *callback,
2N/A int hardlookup)
2N/A{
2N/A size_t domlen;
2N/A size_t maplen;
2N/A struct ypreq_nokey req;
2N/A int reason;
2N/A struct dom_binding *pdomb;
2N/A enum clnt_stat s;
2N/A CLIENT *allc;
2N/A char server_name[MAXHOSTNAMELEN];
2N/A char errbuf[BUFSIZ];
2N/A
2N/A if ((map == NULL) || (domain == NULL))
2N/A return (YPERR_BADARGS);
2N/A
2N/A domlen = strlen(domain);
2N/A maplen = strlen(map);
2N/A
2N/A if ((domlen == 0) || (domlen > YPMAXDOMAIN) ||
2N/A (maplen == 0) || (maplen > YPMAXMAP) ||
2N/A (callback == NULL))
2N/A return (YPERR_BADARGS);
2N/A
2N/A if (reason = __yp_dobind_cflookup(domain, &pdomb, hardlookup))
2N/A return (reason);
2N/A
2N/A if (pdomb->dom_binding->ypbind_hi_vers < YPVERS) {
2N/A __yp_rel_binding(pdomb);
2N/A return (YPERR_VERS);
2N/A }
2N/A (void) mutex_lock(&pdomb->server_name_lock);
2N/A if (!pdomb->dom_binding->ypbind_servername) {
2N/A (void) mutex_unlock(&pdomb->server_name_lock);
2N/A __yp_rel_binding(pdomb);
2N/A syslog(LOG_ERR, "yp_all: failed to get server's name\n");
2N/A return (YPERR_RPC);
2N/A }
2N/A (void) strlcpy(server_name, pdomb->dom_binding->ypbind_servername,
2N/A MAXHOSTNAMELEN);
2N/A (void) mutex_unlock(&pdomb->server_name_lock);
2N/A if (strcmp(server_name, nullstring) == 0) {
2N/A /*
2N/A * This is the case where ypbind is running in broadcast mode,
2N/A * we have to do the jugglery to get the
2N/A * ypserv's address on COTS transport based
2N/A * on the CLTS address ypbind gave us !
2N/A */
2N/A
2N/A struct nd_hostservlist *nhs;
2N/A
2N/A if (netdir_getbyaddr(pdomb->dom_binding->ypbind_nconf,
2N/A &nhs, pdomb->dom_binding->ypbind_svcaddr) != ND_OK) {
2N/A syslog(LOG_ERR,
2N/A "yp_all: failed to get server's name\n");
2N/A __yp_rel_binding(pdomb);
2N/A return (YPERR_RPC);
2N/A }
2N/A /* check server name again, some other thread may have set it */
2N/A (void) mutex_lock(&pdomb->server_name_lock);
2N/A if (strcmp(pdomb->dom_binding->ypbind_servername,
2N/A nullstring) == 0) {
2N/A pdomb->dom_binding->ypbind_servername =
2N/A (char *)strdup(nhs->h_hostservs->h_host);
2N/A }
2N/A (void) strlcpy(server_name,
2N/A pdomb->dom_binding->ypbind_servername, MAXHOSTNAMELEN);
2N/A (void) mutex_unlock(&pdomb->server_name_lock);
2N/A netdir_free((char *)nhs, ND_HOSTSERVLIST);
2N/A }
2N/A __yp_rel_binding(pdomb);
2N/A if ((allc = clnt_create(server_name, YPPROG,
2N/A YPVERS, "circuit_n")) == NULL) {
2N/A (void) snprintf(errbuf, BUFSIZ, "yp_all \
2N/A- transport level create failure for domain %s / map %s", domain, map);
2N/A syslog(LOG_ERR, "%s", clnt_spcreateerror(errbuf));
2N/A return (YPERR_RPC);
2N/A }
2N/A
2N/A req.domain = domain;
2N/A req.map = map;
2N/A
2N/A
2N/A s = clnt_call(allc, YPPROC_ALL,
2N/A (xdrproc_t)xdr_ypreq_nokey, (char *)&req,
2N/A (xdrproc_t)xdr_ypall, (char *)callback, tp_timout);
2N/A
2N/A if (s != RPC_SUCCESS && s != RPC_TIMEDOUT) {
2N/A syslog(LOG_ERR, "%s", clnt_sperror(allc,
2N/A "yp_all - RPC clnt_call (transport level) failure"));
2N/A }
2N/A
2N/A clnt_destroy(allc);
2N/A switch (s) {
2N/A case RPC_SUCCESS:
2N/A return (0);
2N/A case RPC_TIMEDOUT:
2N/A return (YPERR_YPSERV);
2N/A default:
2N/A return (YPERR_RPC);
2N/A }
2N/A}
2N/A
2N/A
2N/A/*
2N/A * This does the "glommed enumeration" stuff. callback->foreach is the name
2N/A * of a function which gets called per decoded key-value pair:
2N/A *
2N/A * (*callback->foreach)(status, key, keylen, val, vallen, callback->data);
2N/A *
2N/A * If the server we get back from __yp_dobind speaks the old protocol, this
2N/A * returns YPERR_VERS, and does not attempt to emulate the new functionality
2N/A * by using the old protocol.
2N/A */
2N/Aint
2N/Ayp_all(char *domain, char *map, struct ypall_callback *callback)
2N/A{
2N/A return (__yp_all_cflookup(domain, map, callback, 1));
2N/A}
2N/A
2N/A
2N/A/*
2N/A * This function is identical to 'yp_all' with the exception that it
2N/A * attempts to use reserve ports.
2N/A */
2N/Aint
2N/A__yp_all_rsvdport(char *domain, char *map, struct ypall_callback *callback)
2N/A{
2N/A size_t domlen;
2N/A size_t maplen;
2N/A struct ypreq_nokey req;
2N/A int reason;
2N/A struct dom_binding *pdomb;
2N/A enum clnt_stat s;
2N/A CLIENT *allc;
2N/A char server_name[MAXHOSTNAMELEN];
2N/A char errbuf[BUFSIZ];
2N/A
2N/A if ((map == NULL) || (domain == NULL))
2N/A return (YPERR_BADARGS);
2N/A
2N/A domlen = strlen(domain);
2N/A maplen = strlen(map);
2N/A
2N/A if ((domlen == 0) || (domlen > YPMAXDOMAIN) ||
2N/A (maplen == 0) || (maplen > YPMAXMAP) ||
2N/A (callback == NULL))
2N/A return (YPERR_BADARGS);
2N/A
2N/A if (reason = __yp_dobind_rsvdport(domain, &pdomb))
2N/A return (reason);
2N/A
2N/A if (pdomb->dom_binding->ypbind_hi_vers < YPVERS) {
2N/A /*
2N/A * Have to free the binding since the reserved
2N/A * port bindings are not cached.
2N/A */
2N/A __yp_rel_binding(pdomb);
2N/A free_dom_binding(pdomb);
2N/A return (YPERR_VERS);
2N/A }
2N/A (void) mutex_lock(&pdomb->server_name_lock);
2N/A if (!pdomb->dom_binding->ypbind_servername) {
2N/A (void) mutex_unlock(&pdomb->server_name_lock);
2N/A syslog(LOG_ERR, "yp_all: failed to get server's name\n");
2N/A __yp_rel_binding(pdomb);
2N/A free_dom_binding(pdomb);
2N/A return (YPERR_RPC);
2N/A }
2N/A (void) strlcpy(server_name,
2N/A pdomb->dom_binding->ypbind_servername, MAXHOSTNAMELEN);
2N/A (void) mutex_unlock(&pdomb->server_name_lock);
2N/A if (strcmp(server_name, nullstring) == 0) {
2N/A /*
2N/A * This is the case where ypbind is running in broadcast mode,
2N/A * we have to do the jugglery to get the
2N/A * ypserv's address on COTS transport based
2N/A * on the CLTS address ypbind gave us !
2N/A */
2N/A
2N/A struct nd_hostservlist *nhs;
2N/A
2N/A if (netdir_getbyaddr(pdomb->dom_binding->ypbind_nconf,
2N/A &nhs, pdomb->dom_binding->ypbind_svcaddr) != ND_OK) {
2N/A syslog(LOG_ERR,
2N/A "yp_all: failed to get server's name\n");
2N/A __yp_rel_binding(pdomb);
2N/A free_dom_binding(pdomb);
2N/A return (YPERR_RPC);
2N/A }
2N/A /* check server name again, some other thread may have set it */
2N/A (void) mutex_lock(&pdomb->server_name_lock);
2N/A if (strcmp(pdomb->dom_binding->ypbind_servername,
2N/A nullstring) == 0) {
2N/A pdomb->dom_binding->ypbind_servername =
2N/A (char *)strdup(nhs->h_hostservs->h_host);
2N/A }
2N/A (void) strlcpy(server_name,
2N/A pdomb->dom_binding->ypbind_servername, MAXHOSTNAMELEN);
2N/A (void) mutex_unlock(&pdomb->server_name_lock);
2N/A netdir_free((char *)nhs, ND_HOSTSERVLIST);
2N/A
2N/A }
2N/A __yp_rel_binding(pdomb);
2N/A if ((allc = __yp_clnt_create_rsvdport(server_name, YPPROG, YPVERS,
2N/A "tcp6", 0, 0)) == NULL &&
2N/A (allc = __yp_clnt_create_rsvdport(server_name, YPPROG, YPVERS,
2N/A "tcp", 0, 0)) == NULL) {
2N/A (void) snprintf(errbuf, BUFSIZ, "yp_all \
2N/A- transport level create failure for domain %s / map %s", domain, map);
2N/A syslog(LOG_ERR, "%s", clnt_spcreateerror(errbuf));
2N/A free_dom_binding(pdomb);
2N/A return (YPERR_RPC);
2N/A }
2N/A
2N/A req.domain = domain;
2N/A req.map = map;
2N/A
2N/A s = clnt_call(allc, YPPROC_ALL,
2N/A (xdrproc_t)xdr_ypreq_nokey, (char *)&req,
2N/A (xdrproc_t)xdr_ypall, (char *)callback, tp_timout);
2N/A
2N/A if (s != RPC_SUCCESS && s != RPC_TIMEDOUT) {
2N/A syslog(LOG_ERR, "%s", clnt_sperror(allc,
2N/A "yp_all - RPC clnt_call (transport level) failure"));
2N/A }
2N/A
2N/A clnt_destroy(allc);
2N/A free_dom_binding(pdomb);
2N/A switch (s) {
2N/A case RPC_SUCCESS:
2N/A return (0);
2N/A case RPC_TIMEDOUT:
2N/A return (YPERR_YPSERV);
2N/A default:
2N/A return (YPERR_RPC);
2N/A }
2N/A}