Libinfo-173.tar.gz
[apple/libinfo.git] / nis.subproj / yp_bind.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * Copyright (c) 1996 Theo de Raadt <deraadt@theos.com>
27 * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@theos.com>
28 * All rights reserved.
29 *
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 * must display the following acknowledgement:
40 * This product includes software developed by Theo de Raadt.
41 * 4. The name of the author may not be used to endorse or promote products
42 * derived from this software without specific prior written permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
45 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
46 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
48 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
55 */
56
57 #if defined(LIBC_SCCS) && !defined(lint)
58 static char *rcsid = "$OpenBSD: yp_bind.c,v 1.9 1997/04/29 21:25:20 deraadt Exp $";
59 #endif /* LIBC_SCCS and not lint */
60
61 #include <sys/param.h>
62 #include <sys/types.h>
63 #include <sys/socket.h>
64 #include <sys/file.h>
65 #include <sys/uio.h>
66 #include <errno.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <unistd.h>
71 #include <rpc/rpc.h>
72 #include <rpc/xdr.h>
73 #include <rpcsvc/yp.h>
74 #include <rpcsvc/ypclnt.h>
75 #include "ypinternal.h"
76
77 struct dom_binding *_ypbindlist = NULL;
78 char _yp_domain[MAXHOSTNAMELEN] = { '\0' };
79
80 int _yplib_timeout = 10;
81
82 int
83 _yp_dobind(dom, ypdb)
84 const char *dom;
85 struct dom_binding **ypdb;
86 {
87 static int pid = -1;
88 char path[MAXPATHLEN];
89 struct dom_binding *ysd, *ysd2;
90 struct ypbind_resp ypbr;
91 struct timeval tv;
92 struct sockaddr_in clnt_sin;
93 struct ypbind_binding *bn;
94 int clnt_sock, fd, gpid;
95 CLIENT *client;
96 int new = 0, r;
97 int count = 0;
98 u_short port;
99
100 /*
101 * test if YP is running or not
102 */
103 if ((fd = open(YPBINDLOCK, O_RDONLY)) == -1)
104 return YPERR_YPBIND;
105 if (!(flock(fd, LOCK_EX | LOCK_NB) == -1 && errno == EWOULDBLOCK)) {
106 (void)close(fd);
107 return YPERR_YPBIND;
108 }
109 (void)close(fd);
110
111 gpid = getpid();
112 if (!(pid == -1 || pid == gpid)) {
113 ysd = _ypbindlist;
114 while (ysd) {
115 if (ysd->dom_client)
116 clnt_destroy(ysd->dom_client);
117 ysd2 = ysd->dom_pnext;
118 free(ysd);
119 ysd = ysd2;
120 }
121 _ypbindlist = NULL;
122 }
123 pid = gpid;
124
125 if (ypdb != NULL)
126 *ypdb = NULL;
127
128 if (dom == NULL || strlen(dom) == 0)
129 return YPERR_BADARGS;
130
131 for (ysd = _ypbindlist; ysd; ysd = ysd->dom_pnext)
132 if (strcmp(dom, ysd->dom_domain) == 0)
133 break;
134 if (ysd == NULL) {
135 if ((ysd = malloc(sizeof *ysd)) == NULL)
136 return YPERR_YPERR;
137 (void)memset(ysd, 0, sizeof *ysd);
138 ysd->dom_socket = -1;
139 ysd->dom_vers = 0;
140 new = 1;
141 }
142 again:
143 if (ysd->dom_vers == 0) {
144 (void) snprintf(path, sizeof(path), "%s/%s.%d",
145 BINDINGDIR, dom, 2);
146 if ((fd = open(path, O_RDONLY)) == -1) {
147 /*
148 * no binding file, YP is dead, or not yet fully
149 * alive.
150 */
151 goto trynet;
152 }
153 if (flock(fd, LOCK_EX | LOCK_NB) == -1 &&
154 errno == EWOULDBLOCK) {
155 struct iovec iov[2];
156 u_short ypb_port;
157
158 /*
159 * we fetch the ypbind port number, but do
160 * nothing with it.
161 */
162 iov[0].iov_base = (caddr_t) &ypb_port;
163 iov[0].iov_len = sizeof ypb_port;
164 iov[1].iov_base = (caddr_t) &ypbr;
165 iov[1].iov_len = sizeof ypbr;
166
167 r = readv(fd, iov, 2);
168 if (r != iov[0].iov_len + iov[1].iov_len) {
169 (void)close(fd);
170 ysd->dom_vers = -1;
171 goto again;
172 }
173 (void)close(fd);
174 goto gotdata;
175 } else {
176 /* no lock on binding file, YP is dead. */
177 (void)close(fd);
178 if (new)
179 free(ysd);
180 return YPERR_YPBIND;
181 }
182 }
183 trynet:
184 if (ysd->dom_vers == -1 || ysd->dom_vers == 0) {
185 (void)memset(&clnt_sin, 0, sizeof clnt_sin);
186 clnt_sin.sin_len = sizeof(struct sockaddr_in);
187 clnt_sin.sin_family = AF_INET;
188 clnt_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
189
190 clnt_sock = RPC_ANYSOCK;
191 client = clnttcp_create(&clnt_sin, YPBINDPROG, YPBINDVERS,
192 &clnt_sock, 0, 0);
193 if (client == NULL) {
194 clnt_pcreateerror("clnttcp_create");
195 if (new)
196 free(ysd);
197 return YPERR_YPBIND;
198 }
199 if (ntohs(clnt_sin.sin_port) >= IPPORT_RESERVED ||
200 ntohs(clnt_sin.sin_port) == 20) {
201 /*
202 * YP was not running, but someone has registered
203 * ypbind with portmap -- this simply means YP is
204 * not running.
205 */
206 clnt_destroy(client);
207 if (new)
208 free(ysd);
209 return YPERR_YPBIND;
210 }
211 tv.tv_sec = _yplib_timeout;
212 tv.tv_usec = 0;
213 r = clnt_call(client, YPBINDPROC_DOMAIN, xdr_domainname,
214 &dom, xdr_ypbind_resp, &ypbr, tv);
215 if (r != RPC_SUCCESS) {
216 if (new == 0 || count)
217 fprintf(stderr,
218 "YP server for domain %s not responding, still trying\n",
219 dom);
220 count++;
221 clnt_destroy(client);
222 ysd->dom_vers = -1;
223 goto again;
224 }
225 clnt_destroy(client);
226 gotdata:
227 bn = &ypbr.ypbind_resp_u.ypbind_bindinfo;
228 memcpy(&port, &bn->ypbind_binding_port, sizeof port);
229 if (ntohs(port) >= IPPORT_RESERVED ||
230 ntohs(port) == 20) {
231 /*
232 * This is bogus -- the ypbind wants me to
233 * communicate to an insecure ypserv. We are
234 * within rights to syslog this as an attack,
235 * but for now we'll simply ignore it; real YP
236 * is obviously not running.
237 */
238 if (new)
239 free(ysd);
240 return YPERR_YPBIND;
241 }
242 (void)memset(&ysd->dom_server_addr, 0,
243 sizeof ysd->dom_server_addr);
244 ysd->dom_server_addr.sin_len = sizeof(struct sockaddr_in);
245 ysd->dom_server_addr.sin_family = AF_INET;
246 memcpy(&ysd->dom_server_addr.sin_port,
247 &bn->ypbind_binding_port,
248 sizeof(ysd->dom_server_addr.sin_port));
249 memcpy(&ysd->dom_server_addr.sin_addr.s_addr,
250 &bn->ypbind_binding_addr,
251 sizeof(ysd->dom_server_addr.sin_addr.s_addr));
252 ysd->dom_server_port = ysd->dom_server_addr.sin_port;
253 ysd->dom_vers = YPVERS;
254 (void)strncpy(ysd->dom_domain, dom, sizeof ysd->dom_domain-1);
255 ysd->dom_domain[sizeof ysd->dom_domain-1] = '\0';
256 }
257 tv.tv_sec = _yplib_timeout / 2;
258 tv.tv_usec = 0;
259 if (ysd->dom_client)
260 clnt_destroy(ysd->dom_client);
261 ysd->dom_socket = RPC_ANYSOCK;
262 ysd->dom_client = clntudp_create(&ysd->dom_server_addr,
263 YPPROG, YPVERS, tv, &ysd->dom_socket);
264 if (ysd->dom_client == NULL) {
265 clnt_pcreateerror("clntudp_create");
266 ysd->dom_vers = -1;
267 goto again;
268 }
269 if (fcntl(ysd->dom_socket, F_SETFD, 1) == -1)
270 perror("fcntl: F_SETFD");
271
272 if (new) {
273 ysd->dom_pnext = _ypbindlist;
274 _ypbindlist = ysd;
275 }
276 if (ypdb != NULL)
277 *ypdb = ysd;
278 return 0;
279 }
280
281 void
282 _yp_unbind(ypb)
283 struct dom_binding *ypb;
284 {
285 if (ypb->dom_client) clnt_destroy(ypb->dom_client);
286 ypb->dom_client = NULL;
287 ypb->dom_socket = -1;
288 }
289
290 int
291 yp_bind(dom)
292 const char *dom;
293 {
294 return _yp_dobind(dom, NULL);
295 }
296
297 void
298 yp_unbind(dom)
299 const char *dom;
300 {
301 struct dom_binding *ypb, *ypbp;
302
303 ypbp = NULL;
304 for (ypb = _ypbindlist; ypb; ypb = ypb->dom_pnext) {
305 if (strcmp(dom, ypb->dom_domain) == 0) {
306 if (ypb->dom_client) clnt_destroy(ypb->dom_client);
307 if (ypbp)
308 ypbp->dom_pnext = ypb->dom_pnext;
309 else
310 _ypbindlist = ypb->dom_pnext;
311 free(ypb);
312 return;
313 }
314 ypbp = ypb;
315 }
316 }