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