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