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