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