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