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