1 /* $NetBSD: yplib.c,v 1.25 1996/12/24 15:08:39 christos 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 #if defined(LIBC_SCCS) && !defined(lint) 35 static char rcsid[] = "$NetBSD: yplib.c,v 1.25 1996/12/24 15:08:39 christos Exp $"; 36 #endif 37 38 #include <sys/param.h> 39 #include <sys/types.h> 40 #include <sys/socket.h> 41 #include <sys/file.h> 42 #include <sys/uio.h> 43 #include <errno.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 #include <rpc/rpc.h> 49 #include <rpc/xdr.h> 50 #include <rpcsvc/yp_prot.h> 51 #include <rpcsvc/ypclnt.h> 52 53 #define BINDINGDIR "/var/yp/binding" 54 #define YPBINDLOCK "/var/run/ypbind.lock" 55 56 struct dom_binding *_ypbindlist; 57 char _yp_domain[MAXHOSTNAMELEN]; 58 59 struct timeval _yplib_timeout = { 10, 0 }; 60 int _yplib_nerrs = 5; 61 62 void _yp_unbind __P((struct dom_binding *)); 63 64 int 65 _yp_dobind(dom, ypdb) 66 const char *dom; 67 struct dom_binding **ypdb; 68 { 69 static int pid = -1; 70 char path[MAXPATHLEN]; 71 struct dom_binding *ysd, *ysd2; 72 struct ypbind_resp ypbr; 73 struct sockaddr_in clnt_sin; 74 int clnt_sock, fd, gpid; 75 CLIENT *client; 76 int new = 0, r; 77 int nerrs = 0; 78 79 if (dom == NULL || *dom == 0) 80 return YPERR_BADARGS; 81 82 /* 83 * test if YP is running or not 84 */ 85 if ((fd = open(YPBINDLOCK, O_RDONLY)) == -1) 86 return YPERR_YPBIND; 87 if (!(flock(fd, LOCK_EX | LOCK_NB) == -1 && errno == EWOULDBLOCK)) { 88 (void)close(fd); 89 return YPERR_YPBIND; 90 } 91 (void)close(fd); 92 93 gpid = getpid(); 94 if (!(pid == -1 || pid == gpid)) { 95 ysd = _ypbindlist; 96 while (ysd) { 97 if (ysd->dom_client) 98 clnt_destroy(ysd->dom_client); 99 ysd2 = ysd->dom_pnext; 100 free(ysd); 101 ysd = ysd2; 102 } 103 _ypbindlist = NULL; 104 } 105 pid = gpid; 106 107 if (ypdb != NULL) 108 *ypdb = NULL; 109 110 for (ysd = _ypbindlist; ysd; ysd = ysd->dom_pnext) 111 if (strcmp(dom, ysd->dom_domain) == 0) 112 break; 113 if (ysd == NULL) { 114 if ((ysd = malloc(sizeof *ysd)) == NULL) 115 return YPERR_YPERR; 116 (void)memset(ysd, 0, sizeof *ysd); 117 ysd->dom_socket = -1; 118 ysd->dom_vers = 0; 119 new = 1; 120 } 121 again: 122 if (ysd->dom_vers == 0) { 123 (void) snprintf(path, sizeof(path), "%s/%s.%d", 124 BINDINGDIR, dom, 2); 125 if ((fd = open(path, O_RDONLY)) == -1) { 126 /* 127 * no binding file, YP is dead, or not yet fully 128 * alive. 129 */ 130 goto trynet; 131 } 132 if (flock(fd, LOCK_EX | LOCK_NB) == -1 && 133 errno == EWOULDBLOCK) { 134 struct iovec iov[2]; 135 struct ypbind_resp ybr; 136 u_short ypb_port; 137 struct ypbind_binding *bn; 138 139 iov[0].iov_base = (caddr_t) & ypb_port; 140 iov[0].iov_len = sizeof ypb_port; 141 iov[1].iov_base = (caddr_t) & ybr; 142 iov[1].iov_len = sizeof ybr; 143 144 r = readv(fd, iov, 2); 145 if (r != iov[0].iov_len + iov[1].iov_len) { 146 (void)close(fd); 147 ysd->dom_vers = -1; 148 goto again; 149 } 150 (void)memset(&ysd->dom_server_addr, 0, 151 sizeof ysd->dom_server_addr); 152 ysd->dom_server_addr.sin_len = 153 sizeof(struct sockaddr_in); 154 ysd->dom_server_addr.sin_family = AF_INET; 155 bn = &ybr.ypbind_respbody.ypbind_bindinfo; 156 ysd->dom_server_addr.sin_port = 157 bn->ypbind_binding_port; 158 159 ysd->dom_server_addr.sin_addr = 160 bn->ypbind_binding_addr; 161 162 ysd->dom_server_port = ysd->dom_server_addr.sin_port; 163 (void)close(fd); 164 goto gotit; 165 } else { 166 /* no lock on binding file, YP is dead. */ 167 (void)close(fd); 168 if (new) 169 free(ysd); 170 return YPERR_YPBIND; 171 } 172 } 173 trynet: 174 if (ysd->dom_vers == -1 || ysd->dom_vers == 0) { 175 struct ypbind_binding *bn; 176 (void)memset(&clnt_sin, 0, sizeof clnt_sin); 177 clnt_sin.sin_len = sizeof(struct sockaddr_in); 178 clnt_sin.sin_family = AF_INET; 179 clnt_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 180 181 clnt_sock = RPC_ANYSOCK; 182 client = clnttcp_create(&clnt_sin, YPBINDPROG, YPBINDVERS, 183 &clnt_sock, 0, 0); 184 if (client == NULL) { 185 clnt_pcreateerror("clnttcp_create"); 186 if (new) 187 free(ysd); 188 return YPERR_YPBIND; 189 } 190 r = clnt_call(client, YPBINDPROC_DOMAIN, 191 xdr_ypdomain_wrap_string, &dom, xdr_ypbind_resp, 192 &ypbr, _yplib_timeout); 193 if (r != RPC_SUCCESS) { 194 if (new == 0 && ++nerrs == _yplib_nerrs) { 195 nerrs = 0; 196 fprintf(stderr, 197 "YP server for domain %s not responding, still trying\n", 198 dom); 199 } 200 clnt_destroy(client); 201 ysd->dom_vers = -1; 202 goto again; 203 } 204 clnt_destroy(client); 205 206 (void)memset(&ysd->dom_server_addr, 0, 207 sizeof ysd->dom_server_addr); 208 ysd->dom_server_addr.sin_len = sizeof(struct sockaddr_in); 209 ysd->dom_server_addr.sin_family = AF_INET; 210 bn = &ypbr.ypbind_respbody.ypbind_bindinfo; 211 ysd->dom_server_addr.sin_port = 212 bn->ypbind_binding_port; 213 ysd->dom_server_addr.sin_addr.s_addr = 214 bn->ypbind_binding_addr.s_addr; 215 ysd->dom_server_port = 216 bn->ypbind_binding_port; 217 gotit: 218 ysd->dom_vers = YPVERS; 219 (void)strcpy(ysd->dom_domain, dom); 220 } 221 if (ysd->dom_client) 222 clnt_destroy(ysd->dom_client); 223 ysd->dom_socket = RPC_ANYSOCK; 224 ysd->dom_client = clntudp_create(&ysd->dom_server_addr, 225 YPPROG, YPVERS, _yplib_timeout, 226 &ysd->dom_socket); 227 if (ysd->dom_client == NULL) { 228 clnt_pcreateerror("clntudp_create"); 229 ysd->dom_vers = -1; 230 goto again; 231 } 232 if (fcntl(ysd->dom_socket, F_SETFD, 1) == -1) 233 perror("fcntl: F_SETFD"); 234 235 if (new) { 236 ysd->dom_pnext = _ypbindlist; 237 _ypbindlist = ysd; 238 } 239 if (ypdb != NULL) 240 *ypdb = ysd; 241 return 0; 242 } 243 244 void 245 _yp_unbind(ypb) 246 struct dom_binding *ypb; 247 { 248 clnt_destroy(ypb->dom_client); 249 ypb->dom_client = NULL; 250 ypb->dom_socket = -1; 251 } 252 253 int 254 yp_bind(dom) 255 const char *dom; 256 { 257 return _yp_dobind(dom, NULL); 258 } 259 260 void 261 yp_unbind(dom) 262 const char *dom; 263 { 264 struct dom_binding *ypb, *ypbp; 265 266 ypbp = NULL; 267 for (ypb = _ypbindlist; ypb; ypb = ypb->dom_pnext) { 268 if (strcmp(dom, ypb->dom_domain) == 0) { 269 clnt_destroy(ypb->dom_client); 270 if (ypbp) 271 ypbp->dom_pnext = ypb->dom_pnext; 272 else 273 _ypbindlist = ypb->dom_pnext; 274 free(ypb); 275 return; 276 } 277 ypbp = ypb; 278 } 279 return; 280 } 281 282 int 283 yp_get_default_domain(domp) 284 char **domp; 285 { 286 *domp = NULL; 287 if (_yp_domain[0] == '\0') 288 if (getdomainname(_yp_domain, sizeof _yp_domain)) 289 return YPERR_NODOM; 290 *domp = _yp_domain; 291 return 0; 292 } 293 294 int 295 _yp_check(dom) 296 char **dom; 297 { 298 char *unused; 299 300 if (_yp_domain[0] == '\0') 301 if (yp_get_default_domain(&unused)) 302 return 0; 303 304 if (dom) 305 *dom = _yp_domain; 306 307 if (yp_bind(_yp_domain) == 0) 308 return 1; 309 return 0; 310 } 311