Home | History | Annotate | Download | only in yp
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 
     23 /*
     24  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
     25  * Use is subject to license terms.
     26  */
     27 
     28 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
     29 /*	  All Rights Reserved   */
     30 
     31 /*
     32  * Portions of this source code were derived from Berkeley
     33  * under license from the Regents of the University of
     34  * California.
     35  */
     36 
     37 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     38 
     39 #include "mt.h"
     40 #include <stdlib.h>
     41 #include <unistd.h>
     42 #include <rpc/rpc.h>
     43 #include <syslog.h>
     44 #include "yp_b.h"
     45 #include <rpcsvc/yp_prot.h>
     46 #include <rpcsvc/ypclnt.h>
     47 #include <netdir.h>
     48 #include <string.h>
     49 
     50 extern int __yp_dobind_cflookup(char *, struct dom_binding **, int);
     51 
     52 static struct timeval tp_timout = { 120, 0};
     53 static char nullstring[] = "\000";
     54 
     55 /*
     56  * __yp_all_cflookup() is a variant of the yp_all() code,
     57  * which adds a 'hardlookup' parameter. This parameter is passed
     58  * to __yp_dobind_cflookup(), and determines whether the server
     59  * binding attempt is hard (try forever) of soft (retry a compiled-
     60  * in number of times).
     61  */
     62 int
     63 __yp_all_cflookup(char *domain, char *map, struct ypall_callback *callback,
     64 								int hardlookup)
     65 {
     66 	size_t domlen;
     67 	size_t maplen;
     68 	struct ypreq_nokey req;
     69 	int reason;
     70 	struct dom_binding *pdomb;
     71 	enum clnt_stat s;
     72 	CLIENT *allc;
     73 	char server_name[MAXHOSTNAMELEN];
     74 	char errbuf[BUFSIZ];
     75 
     76 	if ((map == NULL) || (domain == NULL))
     77 		return (YPERR_BADARGS);
     78 
     79 	domlen = strlen(domain);
     80 	maplen = strlen(map);
     81 
     82 	if ((domlen == 0) || (domlen > YPMAXDOMAIN) ||
     83 	    (maplen == 0) || (maplen > YPMAXMAP) ||
     84 	    (callback == NULL))
     85 		return (YPERR_BADARGS);
     86 
     87 	if (reason = __yp_dobind_cflookup(domain, &pdomb, hardlookup))
     88 		return (reason);
     89 
     90 	if (pdomb->dom_binding->ypbind_hi_vers < YPVERS) {
     91 		__yp_rel_binding(pdomb);
     92 		return (YPERR_VERS);
     93 	}
     94 	(void) mutex_lock(&pdomb->server_name_lock);
     95 	if (!pdomb->dom_binding->ypbind_servername) {
     96 		(void) mutex_unlock(&pdomb->server_name_lock);
     97 		__yp_rel_binding(pdomb);
     98 		syslog(LOG_ERR, "yp_all: failed to get server's name\n");
     99 		return (YPERR_RPC);
    100 	}
    101 	(void) strcpy(server_name, pdomb->dom_binding->ypbind_servername);
    102 	(void) mutex_unlock(&pdomb->server_name_lock);
    103 	if (strcmp(server_name, nullstring) == 0) {
    104 		/*
    105 		 * This is the case where ypbind is running in broadcast mode,
    106 		 * we have to do the jugglery to get the
    107 		 * ypserv's address on COTS transport based
    108 		 * on the CLTS address ypbind gave us !
    109 		 */
    110 
    111 		struct nd_hostservlist *nhs;
    112 
    113 		if (netdir_getbyaddr(pdomb->dom_binding->ypbind_nconf,
    114 			&nhs, pdomb->dom_binding->ypbind_svcaddr) != ND_OK) {
    115 			syslog(LOG_ERR,
    116 				"yp_all: failed to get server's name\n");
    117 			__yp_rel_binding(pdomb);
    118 			return (YPERR_RPC);
    119 		}
    120 		/* check server name again, some other thread may have set it */
    121 		(void) mutex_lock(&pdomb->server_name_lock);
    122 		if (strcmp(pdomb->dom_binding->ypbind_servername,
    123 					nullstring) == 0) {
    124 			pdomb->dom_binding->ypbind_servername =
    125 				(char *)strdup(nhs->h_hostservs->h_host);
    126 		}
    127 		(void) strcpy(server_name,
    128 		    pdomb->dom_binding->ypbind_servername);
    129 		(void) mutex_unlock(&pdomb->server_name_lock);
    130 		netdir_free((char *)nhs, ND_HOSTSERVLIST);
    131 	}
    132 	__yp_rel_binding(pdomb);
    133 	if ((allc = clnt_create(server_name, YPPROG,
    134 		YPVERS, "circuit_n")) == NULL) {
    135 			(void) snprintf(errbuf, BUFSIZ, "yp_all \
    136 - transport level create failure for domain %s / map %s", domain, map);
    137 			syslog(LOG_ERR, "%s", clnt_spcreateerror(errbuf));
    138 			return (YPERR_RPC);
    139 	}
    140 
    141 	req.domain = domain;
    142 	req.map = map;
    143 
    144 
    145 	s = clnt_call(allc, YPPROC_ALL,
    146 		(xdrproc_t)xdr_ypreq_nokey, (char *)&req,
    147 	    (xdrproc_t)xdr_ypall, (char *)callback, tp_timout);
    148 
    149 	if (s != RPC_SUCCESS && s != RPC_TIMEDOUT) {
    150 		syslog(LOG_ERR, "%s", clnt_sperror(allc,
    151 		    "yp_all - RPC clnt_call (transport level) failure"));
    152 	}
    153 
    154 	clnt_destroy(allc);
    155 	switch (s) {
    156 	case RPC_SUCCESS:
    157 		return (0);
    158 	case RPC_TIMEDOUT:
    159 		return (YPERR_YPSERV);
    160 	default:
    161 		return (YPERR_RPC);
    162 	}
    163 }
    164 
    165 
    166 /*
    167  * This does the "glommed enumeration" stuff.  callback->foreach is the name
    168  * of a function which gets called per decoded key-value pair:
    169  *
    170  * (*callback->foreach)(status, key, keylen, val, vallen, callback->data);
    171  *
    172  * If the server we get back from __yp_dobind speaks the old protocol, this
    173  * returns YPERR_VERS, and does not attempt to emulate the new functionality
    174  * by using the old protocol.
    175  */
    176 int
    177 yp_all(char *domain, char *map, struct ypall_callback *callback)
    178 {
    179 	return (__yp_all_cflookup(domain, map, callback, 1));
    180 }
    181 
    182 
    183 /*
    184  * This function is identical to 'yp_all' with the exception that it
    185  * attempts to use reserve ports.
    186  */
    187 int
    188 __yp_all_rsvdport(char *domain, char *map, struct ypall_callback *callback)
    189 {
    190 	size_t domlen;
    191 	size_t maplen;
    192 	struct ypreq_nokey req;
    193 	int reason;
    194 	struct dom_binding *pdomb;
    195 	enum clnt_stat s;
    196 	CLIENT *allc;
    197 	char server_name[MAXHOSTNAMELEN];
    198 	char errbuf[BUFSIZ];
    199 
    200 	if ((map == NULL) || (domain == NULL))
    201 		return (YPERR_BADARGS);
    202 
    203 	domlen =  strlen(domain);
    204 	maplen =  strlen(map);
    205 
    206 	if ((domlen == 0) || (domlen > YPMAXDOMAIN) ||
    207 	    (maplen == 0) || (maplen > YPMAXMAP) ||
    208 	    (callback == NULL))
    209 		return (YPERR_BADARGS);
    210 
    211 	if (reason = __yp_dobind_rsvdport(domain, &pdomb))
    212 		return (reason);
    213 
    214 	if (pdomb->dom_binding->ypbind_hi_vers < YPVERS) {
    215 		/*
    216 		 * Have to free the binding since the reserved
    217 		 * port bindings are not cached.
    218 		 */
    219 		__yp_rel_binding(pdomb);
    220 		free_dom_binding(pdomb);
    221 		return (YPERR_VERS);
    222 	}
    223 	(void) mutex_lock(&pdomb->server_name_lock);
    224 	if (!pdomb->dom_binding->ypbind_servername) {
    225 		(void) mutex_unlock(&pdomb->server_name_lock);
    226 		syslog(LOG_ERR, "yp_all: failed to get server's name\n");
    227 		__yp_rel_binding(pdomb);
    228 		free_dom_binding(pdomb);
    229 		return (YPERR_RPC);
    230 	}
    231 	(void) strcpy(server_name, pdomb->dom_binding->ypbind_servername);
    232 	(void) mutex_unlock(&pdomb->server_name_lock);
    233 	if (strcmp(server_name, nullstring) == 0) {
    234 		/*
    235 		 * This is the case where ypbind is running in broadcast mode,
    236 		 * we have to do the jugglery to get the
    237 		 * ypserv's address on COTS transport based
    238 		 * on the CLTS address ypbind gave us !
    239 		 */
    240 
    241 		struct nd_hostservlist *nhs;
    242 
    243 		if (netdir_getbyaddr(pdomb->dom_binding->ypbind_nconf,
    244 			&nhs, pdomb->dom_binding->ypbind_svcaddr) != ND_OK) {
    245 			syslog(LOG_ERR,
    246 				"yp_all: failed to get server's name\n");
    247 			__yp_rel_binding(pdomb);
    248 			free_dom_binding(pdomb);
    249 			return (YPERR_RPC);
    250 		}
    251 		/* check server name again, some other thread may have set it */
    252 		(void) mutex_lock(&pdomb->server_name_lock);
    253 		if (strcmp(pdomb->dom_binding->ypbind_servername,
    254 					nullstring) == 0) {
    255 			pdomb->dom_binding->ypbind_servername =
    256 			(char *)strdup(nhs->h_hostservs->h_host);
    257 		}
    258 		(void) strcpy(server_name,
    259 		    pdomb->dom_binding->ypbind_servername);
    260 		(void) mutex_unlock(&pdomb->server_name_lock);
    261 		netdir_free((char *)nhs, ND_HOSTSERVLIST);
    262 
    263 	}
    264 	__yp_rel_binding(pdomb);
    265 	if ((allc = __yp_clnt_create_rsvdport(server_name, YPPROG, YPVERS,
    266 	    "tcp6", 0, 0)) == NULL &&
    267 		(allc = __yp_clnt_create_rsvdport(server_name, YPPROG, YPVERS,
    268 	    "tcp", 0, 0)) == NULL) {
    269 		(void) snprintf(errbuf, BUFSIZ, "yp_all \
    270 - transport level create failure for domain %s / map %s", domain, map);
    271 		syslog(LOG_ERR, "%s", clnt_spcreateerror(errbuf));
    272 		free_dom_binding(pdomb);
    273 		return (YPERR_RPC);
    274 	}
    275 
    276 	req.domain = domain;
    277 	req.map = map;
    278 
    279 	s = clnt_call(allc, YPPROC_ALL,
    280 		(xdrproc_t)xdr_ypreq_nokey, (char *)&req,
    281 	    (xdrproc_t)xdr_ypall, (char *)callback, tp_timout);
    282 
    283 	if (s != RPC_SUCCESS && s != RPC_TIMEDOUT) {
    284 		syslog(LOG_ERR, "%s", clnt_sperror(allc,
    285 		    "yp_all - RPC clnt_call (transport level) failure"));
    286 	}
    287 
    288 	clnt_destroy(allc);
    289 	free_dom_binding(pdomb);
    290 	switch (s) {
    291 	case RPC_SUCCESS:
    292 		return (0);
    293 	case RPC_TIMEDOUT:
    294 		return (YPERR_YPSERV);
    295 	default:
    296 		return (YPERR_RPC);
    297 	}
    298 }
    299