1 /* 2 * Copyright (c) 1996 Theo de Raadt <deraadt@theos.com> 3 * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@theos.com> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Theo de Raadt. 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 21 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #if defined(LIBC_SCCS) && !defined(lint) 34 static char *rcsid = "$OpenBSD: yp_bind.c,v 1.10 1999/08/17 09:13:13 millert Exp $"; 35 #endif /* LIBC_SCCS and not lint */ 36 37 #include <sys/param.h> 38 #include <sys/types.h> 39 #include <sys/socket.h> 40 #include <sys/uio.h> 41 #include <errno.h> 42 #include <fcntl.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <unistd.h> 47 #include <rpc/rpc.h> 48 #include <rpc/xdr.h> 49 #include <rpcsvc/yp.h> 50 #include <rpcsvc/ypclnt.h> 51 #include "ypinternal.h" 52 53 struct dom_binding *_ypbindlist; 54 char _yp_domain[MAXHOSTNAMELEN]; 55 int _yplib_timeout = 10; 56 57 int 58 _yp_dobind(dom, ypdb) 59 const char *dom; 60 struct dom_binding **ypdb; 61 { 62 static int pid = -1; 63 char path[MAXPATHLEN]; 64 struct dom_binding *ysd, *ysd2; 65 struct ypbind_resp ypbr; 66 struct timeval tv; 67 struct sockaddr_in clnt_sin; 68 struct ypbind_binding *bn; 69 int clnt_sock, fd, gpid; 70 CLIENT *client; 71 int new = 0, r; 72 int count = 0; 73 u_short port; 74 75 /* 76 * test if YP is running or not 77 */ 78 if ((fd = open(YPBINDLOCK, O_RDONLY)) == -1) 79 return YPERR_YPBIND; 80 if (!(flock(fd, LOCK_EX | LOCK_NB) == -1 && errno == EWOULDBLOCK)) { 81 (void)close(fd); 82 return YPERR_YPBIND; 83 } 84 (void)close(fd); 85 86 gpid = getpid(); 87 if (!(pid == -1 || pid == gpid)) { 88 ysd = _ypbindlist; 89 while (ysd) { 90 if (ysd->dom_client) 91 clnt_destroy(ysd->dom_client); 92 ysd2 = ysd->dom_pnext; 93 free(ysd); 94 ysd = ysd2; 95 } 96 _ypbindlist = NULL; 97 } 98 pid = gpid; 99 100 if (ypdb != NULL) 101 *ypdb = NULL; 102 103 if (dom == NULL || strlen(dom) == 0) 104 return YPERR_BADARGS; 105 106 for (ysd = _ypbindlist; ysd; ysd = ysd->dom_pnext) 107 if (strcmp(dom, ysd->dom_domain) == 0) 108 break; 109 if (ysd == NULL) { 110 if ((ysd = malloc(sizeof *ysd)) == NULL) 111 return YPERR_YPERR; 112 (void)memset(ysd, 0, sizeof *ysd); 113 ysd->dom_socket = -1; 114 ysd->dom_vers = 0; 115 new = 1; 116 } 117 again: 118 if (ysd->dom_vers == 0) { 119 (void) snprintf(path, sizeof(path), "%s/%s.%d", 120 BINDINGDIR, dom, 2); 121 if ((fd = open(path, O_RDONLY)) == -1) { 122 /* 123 * no binding file, YP is dead, or not yet fully 124 * alive. 125 */ 126 goto trynet; 127 } 128 if (flock(fd, LOCK_EX | LOCK_NB) == -1 && 129 errno == EWOULDBLOCK) { 130 struct iovec iov[2]; 131 u_short ypb_port; 132 133 /* 134 * we fetch the ypbind port number, but do 135 * nothing with it. 136 */ 137 iov[0].iov_base = (caddr_t) &ypb_port; 138 iov[0].iov_len = sizeof ypb_port; 139 iov[1].iov_base = (caddr_t) &ypbr; 140 iov[1].iov_len = sizeof ypbr; 141 142 r = readv(fd, iov, 2); 143 if (r != iov[0].iov_len + iov[1].iov_len) { 144 (void)close(fd); 145 ysd->dom_vers = -1; 146 goto again; 147 } 148 (void)close(fd); 149 goto gotdata; 150 } else { 151 /* no lock on binding file, YP is dead. */ 152 (void)close(fd); 153 if (new) 154 free(ysd); 155 return YPERR_YPBIND; 156 } 157 } 158 trynet: 159 if (ysd->dom_vers == -1 || ysd->dom_vers == 0) { 160 (void)memset(&clnt_sin, 0, sizeof clnt_sin); 161 clnt_sin.sin_len = sizeof(struct sockaddr_in); 162 clnt_sin.sin_family = AF_INET; 163 clnt_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 164 165 clnt_sock = RPC_ANYSOCK; 166 client = clnttcp_create(&clnt_sin, YPBINDPROG, YPBINDVERS, 167 &clnt_sock, 0, 0); 168 if (client == NULL) { 169 clnt_pcreateerror("clnttcp_create"); 170 if (new) 171 free(ysd); 172 return YPERR_YPBIND; 173 } 174 if (ntohs(clnt_sin.sin_port) >= IPPORT_RESERVED || 175 ntohs(clnt_sin.sin_port) == 20) { 176 /* 177 * YP was not running, but someone has registered 178 * ypbind with portmap -- this simply means YP is 179 * not running. 180 */ 181 clnt_destroy(client); 182 if (new) 183 free(ysd); 184 return YPERR_YPBIND; 185 } 186 tv.tv_sec = _yplib_timeout; 187 tv.tv_usec = 0; 188 r = clnt_call(client, YPBINDPROC_DOMAIN, xdr_domainname, 189 &dom, xdr_ypbind_resp, &ypbr, tv); 190 if (r != RPC_SUCCESS) { 191 if (new == 0 || count) 192 fprintf(stderr, 193 "YP server for domain %s not responding, still trying\n", 194 dom); 195 count++; 196 clnt_destroy(client); 197 ysd->dom_vers = -1; 198 goto again; 199 } 200 clnt_destroy(client); 201 gotdata: 202 bn = &ypbr.ypbind_resp_u.ypbind_bindinfo; 203 memcpy(&port, &bn->ypbind_binding_port, sizeof port); 204 if (ntohs(port) >= IPPORT_RESERVED || 205 ntohs(port) == 20) { 206 /* 207 * This is bullshit -- the ypbind wants me to 208 * communicate to an insecure ypserv. We are 209 * within rights to syslog this as an attack, 210 * but for now we'll simply ignore it; real YP 211 * is obviously not running. 212 */ 213 if (new) 214 free(ysd); 215 return YPERR_YPBIND; 216 } 217 (void)memset(&ysd->dom_server_addr, 0, 218 sizeof ysd->dom_server_addr); 219 ysd->dom_server_addr.sin_len = sizeof(struct sockaddr_in); 220 ysd->dom_server_addr.sin_family = AF_INET; 221 memcpy(&ysd->dom_server_addr.sin_port, 222 &bn->ypbind_binding_port, 223 sizeof(ysd->dom_server_addr.sin_port)); 224 memcpy(&ysd->dom_server_addr.sin_addr.s_addr, 225 &bn->ypbind_binding_addr, 226 sizeof(ysd->dom_server_addr.sin_addr.s_addr)); 227 ysd->dom_server_port = ysd->dom_server_addr.sin_port; 228 ysd->dom_vers = YPVERS; 229 (void)strncpy(ysd->dom_domain, dom, sizeof ysd->dom_domain-1); 230 ysd->dom_domain[sizeof ysd->dom_domain-1] = '\0'; 231 } 232 tv.tv_sec = _yplib_timeout / 2; 233 tv.tv_usec = 0; 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, tv, &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 return _yp_dobind(dom, NULL); 270 } 271 272 void 273 yp_unbind(dom) 274 const char *dom; 275 { 276 struct dom_binding *ypb, *ypbp; 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 } 292