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