1 /* $NetBSD: yplib.c,v 1.39 2002/11/17 01:51:26 itojun Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@fsa.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Theo de Raadt. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 22 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 #if defined(LIBC_SCCS) && !defined(lint) 36 __RCSID("$NetBSD: yplib.c,v 1.39 2002/11/17 01:51:26 itojun Exp $"); 37 #endif 38 39 #include "namespace.h" 40 #include <sys/param.h> 41 #include <sys/socket.h> 42 #include <sys/file.h> 43 #include <sys/uio.h> 44 45 #include <arpa/nameser.h> 46 47 #include <assert.h> 48 #include <errno.h> 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <unistd.h> 53 54 #include <rpc/rpc.h> 55 #include <rpc/xdr.h> 56 #include <rpcsvc/yp_prot.h> 57 #include <rpcsvc/ypclnt.h> 58 #include "local.h" 59 60 #define BINDINGDIR "/var/yp/binding" 61 #define YPBINDLOCK "/var/run/ypbind.lock" 62 63 struct dom_binding *_ypbindlist; 64 char _yp_domain[MAXHOSTNAMELEN]; 65 66 #define YPLIB_TIMEOUT 10 67 #define YPLIB_RPC_RETRIES 4 68 69 struct timeval _yplib_timeout = { YPLIB_TIMEOUT, 0 }; 70 struct timeval _yplib_rpc_timeout = { YPLIB_TIMEOUT / YPLIB_RPC_RETRIES, 71 1000000 * (YPLIB_TIMEOUT % YPLIB_RPC_RETRIES) / YPLIB_RPC_RETRIES }; 72 int _yplib_nerrs = 5; 73 74 #ifdef __weak_alias 75 __weak_alias(yp_bind, _yp_bind) 76 __weak_alias(yp_unbind, _yp_unbind) 77 __weak_alias(yp_get_default_domain, _yp_get_default_domain) 78 #endif 79 80 int 81 _yp_dobind(dom, ypdb) 82 const char *dom; 83 struct dom_binding **ypdb; 84 { 85 static int pid = -1; 86 char path[MAXPATHLEN]; 87 struct dom_binding *ysd, *ysd2; 88 struct ypbind_resp ypbr; 89 struct sockaddr_in clnt_sin; 90 int clnt_sock, fd, gpid; 91 CLIENT *client; 92 int new = 0; 93 int nerrs = 0; 94 ssize_t r; 95 96 if (dom == NULL || *dom == '\0') 97 return YPERR_BADARGS; 98 99 /* 100 * test if YP is running or not 101 */ 102 if ((fd = open(YPBINDLOCK, O_RDONLY)) == -1) 103 return YPERR_YPBIND; 104 if (!(flock(fd, LOCK_EX | LOCK_NB) == -1 && errno == EWOULDBLOCK)) { 105 (void)close(fd); 106 return YPERR_YPBIND; 107 } 108 (void)close(fd); 109 110 gpid = getpid(); 111 if (!(pid == -1 || pid == gpid)) { 112 ysd = _ypbindlist; 113 while (ysd) { 114 if (ysd->dom_client) 115 clnt_destroy(ysd->dom_client); 116 ysd2 = ysd->dom_pnext; 117 free(ysd); 118 ysd = ysd2; 119 } 120 _ypbindlist = NULL; 121 } 122 pid = gpid; 123 124 if (ypdb != NULL) 125 *ypdb = NULL; 126 127 for (ysd = _ypbindlist; ysd; ysd = ysd->dom_pnext) 128 if (strcmp(dom, ysd->dom_domain) == 0) 129 break; 130 if (ysd == NULL) { 131 if ((ysd = malloc(sizeof *ysd)) == NULL) 132 return YPERR_YPERR; 133 (void)memset(ysd, 0, sizeof *ysd); 134 ysd->dom_socket = -1; 135 ysd->dom_vers = 0; 136 new = 1; 137 } 138 again: 139 if (ysd->dom_vers == 0) { 140 (void) snprintf(path, sizeof(path), "%s/%s.%d", 141 BINDINGDIR, dom, 2); 142 if ((fd = open(path, O_RDONLY)) == -1) { 143 /* 144 * no binding file, YP is dead, or not yet fully 145 * alive. 146 */ 147 goto trynet; 148 } 149 if (flock(fd, LOCK_EX | LOCK_NB) == -1 && 150 errno == EWOULDBLOCK) { 151 struct iovec iov[2]; 152 struct ypbind_resp ybr; 153 u_short ypb_port; 154 struct ypbind_binding *bn; 155 156 iov[0].iov_base = &ypb_port; 157 iov[0].iov_len = sizeof ypb_port; 158 iov[1].iov_base = &ybr; 159 iov[1].iov_len = sizeof ybr; 160 161 r = readv(fd, iov, 2); 162 if (r != (ssize_t)(iov[0].iov_len + iov[1].iov_len)) { 163 (void)close(fd); 164 ysd->dom_vers = -1; 165 goto again; 166 } 167 (void)memset(&ysd->dom_server_addr, 0, 168 sizeof ysd->dom_server_addr); 169 ysd->dom_server_addr.sin_len = 170 sizeof(struct sockaddr_in); 171 ysd->dom_server_addr.sin_family = AF_INET; 172 bn = &ybr.ypbind_respbody.ypbind_bindinfo; 173 ysd->dom_server_addr.sin_port = 174 bn->ypbind_binding_port; 175 176 ysd->dom_server_addr.sin_addr = 177 bn->ypbind_binding_addr; 178 179 ysd->dom_server_port = ysd->dom_server_addr.sin_port; 180 (void)close(fd); 181 goto gotit; 182 } else { 183 /* no lock on binding file, YP is dead. */ 184 (void)close(fd); 185 if (new) 186 free(ysd); 187 return YPERR_YPBIND; 188 } 189 } 190 trynet: 191 if (ysd->dom_vers == -1 || ysd->dom_vers == 0) { 192 struct ypbind_binding *bn; 193 (void)memset(&clnt_sin, 0, sizeof clnt_sin); 194 clnt_sin.sin_len = sizeof(struct sockaddr_in); 195 clnt_sin.sin_family = AF_INET; 196 clnt_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 197 198 clnt_sock = RPC_ANYSOCK; 199 client = clnttcp_create(&clnt_sin, YPBINDPROG, YPBINDVERS, 200 &clnt_sock, 0, 0); 201 if (client == NULL) { 202 clnt_pcreateerror("clnttcp_create"); 203 if (new) 204 free(ysd); 205 return YPERR_YPBIND; 206 } 207 r = clnt_call(client, (rpcproc_t)YPBINDPROC_DOMAIN, 208 (xdrproc_t)xdr_ypdomain_wrap_string, &dom, 209 (xdrproc_t)xdr_ypbind_resp, &ypbr, _yplib_timeout); 210 if (r != RPC_SUCCESS) { 211 if (new == 0 && ++nerrs == _yplib_nerrs) { 212 nerrs = 0; 213 fprintf(stderr, 214 "YP server for domain %s not responding, still trying\n", 215 dom); 216 } 217 clnt_destroy(client); 218 ysd->dom_vers = -1; 219 goto again; 220 } 221 clnt_destroy(client); 222 223 (void)memset(&ysd->dom_server_addr, 0, 224 sizeof ysd->dom_server_addr); 225 ysd->dom_server_addr.sin_len = sizeof(struct sockaddr_in); 226 ysd->dom_server_addr.sin_family = AF_INET; 227 bn = &ypbr.ypbind_respbody.ypbind_bindinfo; 228 ysd->dom_server_addr.sin_port = 229 bn->ypbind_binding_port; 230 ysd->dom_server_addr.sin_addr.s_addr = 231 bn->ypbind_binding_addr.s_addr; 232 ysd->dom_server_port = 233 bn->ypbind_binding_port; 234 gotit: 235 ysd->dom_vers = YPVERS; 236 (void)strlcpy(ysd->dom_domain, dom, sizeof(ysd->dom_domain)); 237 } 238 if (ysd->dom_client) 239 clnt_destroy(ysd->dom_client); 240 ysd->dom_socket = RPC_ANYSOCK; 241 ysd->dom_client = clntudp_create(&ysd->dom_server_addr, 242 YPPROG, YPVERS, _yplib_rpc_timeout, &ysd->dom_socket); 243 if (ysd->dom_client == NULL) { 244 clnt_pcreateerror("clntudp_create"); 245 ysd->dom_vers = -1; 246 goto again; 247 } 248 if (fcntl(ysd->dom_socket, F_SETFD, 1) == -1) 249 perror("fcntl: F_SETFD"); 250 251 if (new) { 252 ysd->dom_pnext = _ypbindlist; 253 _ypbindlist = ysd; 254 } 255 if (ypdb != NULL) 256 *ypdb = ysd; 257 return 0; 258 } 259 260 void 261 __yp_unbind(ypb) 262 struct dom_binding *ypb; 263 { 264 265 _DIAGASSERT(ypb != NULL); 266 267 clnt_destroy(ypb->dom_client); 268 ypb->dom_client = NULL; 269 ypb->dom_socket = -1; 270 } 271 272 int 273 yp_bind(dom) 274 const char *dom; 275 { 276 if (_yp_invalid_domain(dom)) 277 return YPERR_BADARGS; 278 279 return _yp_dobind(dom, NULL); 280 } 281 282 void 283 yp_unbind(dom) 284 const char *dom; 285 { 286 struct dom_binding *ypb, *ypbp; 287 288 if (_yp_invalid_domain(dom)) 289 return; 290 291 ypbp = NULL; 292 for (ypb = _ypbindlist; ypb; ypb = ypb->dom_pnext) { 293 if (strcmp(dom, ypb->dom_domain) == 0) { 294 clnt_destroy(ypb->dom_client); 295 if (ypbp) 296 ypbp->dom_pnext = ypb->dom_pnext; 297 else 298 _ypbindlist = ypb->dom_pnext; 299 free(ypb); 300 return; 301 } 302 ypbp = ypb; 303 } 304 return; 305 } 306 307 int 308 yp_get_default_domain(domp) 309 char **domp; 310 { 311 if (domp == NULL) 312 return YPERR_BADARGS; 313 *domp = NULL; 314 if (_yp_domain[0] == '\0') 315 if (getdomainname(_yp_domain, sizeof _yp_domain)) 316 return YPERR_NODOM; 317 *domp = _yp_domain; 318 return 0; 319 } 320 321 int 322 _yp_check(dom) 323 char **dom; 324 { 325 char *unused; 326 327 if (_yp_domain[0] == '\0') 328 if (yp_get_default_domain(&unused)) 329 return 0; 330 331 if (dom) 332 *dom = _yp_domain; 333 334 if (yp_bind(_yp_domain) == 0) 335 return 1; 336 return 0; 337 } 338 339 /* 340 * _yp_invalid_domain: check if given domainname isn't legal. 341 * returns non-zero if invalid 342 */ 343 int 344 _yp_invalid_domain(dom) 345 const char *dom; 346 { 347 if (dom == NULL || *dom == '\0') 348 return 1; 349 350 if (strlen(dom) > YPMAXDOMAIN) 351 return 1; 352 353 if (strchr(dom, '/') != NULL) 354 return 1; 355 356 return 0; 357 } 358