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