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