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