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