1/* 2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights 7 * Reserved. This file contains Original Code and/or Modifications of 8 * Original Code as defined in and that are subject to the Apple Public 9 * Source License Version 1.1 (the "License"). You may not use this file 10 * except in compliance with the License. Please obtain a copy of the 11 * License at http://www.apple.com/publicsource and read it before using 12 * this file. 13 * 14 * The Original Code and all software distributed under the License are 15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the 19 * License for the specific language governing rights and limitations 20 * under the License. 21 * 22 * @APPLE_LICENSE_HEADER_END@ 23 */ 24/* 25 * Copyright (c) 1996 Theo de Raadt <deraadt@theos.com> 26 * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@theos.com> 27 * All rights reserved. 28 * 29 * Redistribution and use in source and binary forms, with or without 30 * modification, are permitted provided that the following conditions 31 * are met: 32 * 1. Redistributions of source code must retain the above copyright 33 * notice, this list of conditions and the following disclaimer. 34 * 2. Redistributions in binary form must reproduce the above copyright 35 * notice, this list of conditions and the following disclaimer in the 36 * documentation and/or other materials provided with the distribution. 37 * 3. All advertising materials mentioning features or use of this software 38 * must display the following acknowledgement: 39 * This product includes software developed by Theo de Raadt. 40 * 4. The name of the author may not be used to endorse or promote products 41 * derived from this software without specific prior written permission. 42 * 43 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 44 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 45 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 46 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 47 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 53 * SUCH DAMAGE. 54 */ 55 56#if defined(LIBC_SCCS) && !defined(lint) 57static char *rcsid = "$OpenBSD: yp_bind.c,v 1.9 1997/04/29 21:25:20 deraadt Exp $"; 58#endif /* LIBC_SCCS and not lint */ 59 60#include <sys/param.h> 61#include <sys/types.h> 62#include <sys/socket.h> 63#include <sys/file.h> 64#include <sys/uio.h> 65#include <errno.h> 66#include <stdio.h> 67#include <stdlib.h> 68#include <string.h> 69#include <unistd.h> 70#include <rpc/rpc.h> 71#include <rpc/xdr.h> 72#include <rpcsvc/yp.h> 73#include <rpcsvc/ypclnt.h> 74#include <notify.h> 75#include <pthread.h> 76#include "ypinternal.h" 77 78extern int notify_register_plain(char *, int *); 79 80struct dom_binding *_ypbindlist = NULL; 81char _yp_domain[MAXHOSTNAMELEN] = { '\0' }; 82 83int _yplib_timeout = 10; 84 85int 86_yp_dobind(dom, ypdb) 87 const char *dom; 88 struct dom_binding **ypdb; 89{ 90 static int pid = -1; 91 struct dom_binding *ysd, *ysd2; 92 struct ypbind_resp ypbr; 93 struct timeval tv; 94 struct sockaddr_in clnt_sin; 95 struct ypbind_binding *bn; 96 int clnt_sock, fd, gpid; 97 CLIENT *client; 98 int new = 0, r, proto; 99 int count = 0; 100 u_short port; 101 int status, notify_token; 102 uint64_t abort; 103 char *notify_name; 104 105 /* 106 * test if YP is running or not 107 */ 108 if ((fd = open(YPBINDLOCK, O_RDONLY)) == -1) return YPERR_YPBIND; 109 110 if (!((flock(fd, LOCK_EX | LOCK_NB) == -1) && (errno == EWOULDBLOCK))) 111 { 112 close(fd); 113 return YPERR_YPBIND; 114 } 115 116 close(fd); 117 118 gpid = getpid(); 119 if (!((pid == -1) || (pid == gpid))) 120 { 121 ysd = _ypbindlist; 122 while (ysd) 123 { 124 if (ysd->dom_client) clnt_destroy(ysd->dom_client); 125 ysd2 = ysd->dom_pnext; 126 free(ysd); 127 ysd = ysd2; 128 } 129 130 _ypbindlist = NULL; 131 } 132 133 pid = gpid; 134 135 if (ypdb != NULL) *ypdb = NULL; 136 137 if ((dom == NULL) || (strlen(dom) == 0)) return YPERR_BADARGS; 138 139 for (ysd = _ypbindlist; ysd; ysd = ysd->dom_pnext) 140 { 141 if (strcmp(dom, ysd->dom_domain) == 0) break; 142 } 143 144 if (ysd == NULL) 145 { 146 ysd = calloc(1, sizeof(struct dom_binding)); 147 if (ysd == NULL) return YPERR_YPERR; 148 ysd->dom_socket = -1; 149 ysd->dom_vers = 0; 150 new = 1; 151 } 152 153 /* 154 * Get notification token 155 * we use a self-notification token to allow a caller 156 * to signal the thread doing this bind call to quit. 157 */ 158 notify_name = NULL; 159 notify_token = -1; 160 161 asprintf(¬ify_name, "self.thread.%lu", (unsigned long)pthread_self()); 162 if (notify_name != NULL) 163 { 164 status = notify_register_plain(notify_name, ¬ify_token); 165 free(notify_name); 166 } 167 168again: 169 if (notify_token != -1) 170 { 171 abort = 0; 172 status = notify_get_state(notify_token, &abort); 173 if (abort == ThreadStateExitRequested) 174 { 175 if (new) free(ysd); 176 notify_cancel(notify_token); 177 return YPERR_YPBIND; 178 } 179 } 180 181 proto = YP_BIND_UDP; 182 if (ysd->dom_vers == YP_BIND_TCP) proto = YP_BIND_TCP; 183 184 if ((ysd->dom_vers == 0) || (ysd->dom_vers == YP_BIND_UDP) || (ysd->dom_vers == YP_BIND_TCP)) 185 { 186 memset(&clnt_sin, 0, sizeof clnt_sin); 187 clnt_sin.sin_len = sizeof(struct sockaddr_in); 188 clnt_sin.sin_family = AF_INET; 189 clnt_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 190 191 clnt_sock = RPC_ANYSOCK; 192 client = clnttcp_create(&clnt_sin, YPBINDPROG, YPBINDVERS, &clnt_sock, 0, 0); 193 if (client == NULL) 194 { 195 clnt_pcreateerror("clnttcp_create"); 196 if (new) free(ysd); 197 if (notify_token != -1) notify_cancel(notify_token); 198 return YPERR_YPBIND; 199 } 200 201 if ((ntohs(clnt_sin.sin_port) >= IPPORT_RESERVED) || (ntohs(clnt_sin.sin_port) == 20)) 202 { 203 /* 204 * YP was not running, but someone has registered 205 * ypbind with portmap -- this simply means YP is 206 * not running. 207 */ 208 clnt_destroy(client); 209 if (new) free(ysd); 210 if (notify_token != -1) notify_cancel(notify_token); 211 return YPERR_YPBIND; 212 } 213 214 tv.tv_sec = _yplib_timeout; 215 tv.tv_usec = 0; 216 217 r = clnt_call(client, YPBINDPROC_DOMAIN, (xdrproc_t)xdr_domainname, &dom, (xdrproc_t)xdr_ypbind_resp, &ypbr, tv); 218 if (r != RPC_SUCCESS) 219 { 220 if (new == 0 || count) fprintf(stderr, "YP server for domain %s not responding, still trying\n", dom); 221 count++; 222 clnt_destroy(client); 223 ysd->dom_vers = proto; 224 goto again; 225 } 226 227 clnt_destroy(client); 228 229 bn = &ypbr.ypbind_resp_u.ypbind_bindinfo; 230 memcpy(&port, &bn->ypbind_binding_port, sizeof port); 231 if ((ntohs(port) >= IPPORT_RESERVED) || (ntohs(port) == 20)) 232 { 233 /* 234 * This is bogus -- the ypbind wants me to 235 * communicate to an insecure ypserv. We are 236 * within rights to syslog this as an attack, 237 * but for now we'll simply ignore it; real YP 238 * is obviously not running. 239 */ 240 if (new) free(ysd); 241 if (notify_token != -1) notify_cancel(notify_token); 242 return YPERR_YPBIND; 243 } 244 245 memset(&ysd->dom_server_addr, 0, sizeof ysd->dom_server_addr); 246 ysd->dom_server_addr.sin_len = sizeof(struct sockaddr_in); 247 ysd->dom_server_addr.sin_family = AF_INET; 248 memcpy(&ysd->dom_server_addr.sin_port, &bn->ypbind_binding_port, sizeof(ysd->dom_server_addr.sin_port)); 249 memcpy(&ysd->dom_server_addr.sin_addr.s_addr, &bn->ypbind_binding_addr, sizeof(ysd->dom_server_addr.sin_addr.s_addr)); 250 ysd->dom_server_port = ysd->dom_server_addr.sin_port; 251 ysd->dom_vers = YPVERS; 252 strncpy(ysd->dom_domain, dom, sizeof ysd->dom_domain-1); 253 ysd->dom_domain[sizeof ysd->dom_domain-1] = '\0'; 254 } 255 256 tv.tv_sec = _yplib_timeout / 2; 257 tv.tv_usec = 0; 258 259 if (ysd->dom_client) clnt_destroy(ysd->dom_client); 260 ysd->dom_socket = RPC_ANYSOCK; 261 262 if (proto == YP_BIND_UDP) ysd->dom_client = clntudp_create(&ysd->dom_server_addr, YPPROG, YPVERS, tv, &ysd->dom_socket); 263 else ysd->dom_client = clnttcp_create(&ysd->dom_server_addr, YPPROG, YPVERS, &ysd->dom_socket, 0, 0); 264 265 if (ysd->dom_client == NULL) 266 { 267 if (proto == YP_BIND_UDP) clnt_pcreateerror("clntudp_create"); 268 else clnt_pcreateerror("clnttcp_create"); 269 ysd->dom_vers = proto; 270 goto again; 271 } 272 273 if (notify_token != -1) notify_cancel(notify_token); 274 275 if (fcntl(ysd->dom_socket, F_SETFD, 1) == -1) 276 perror("fcntl: F_SETFD"); 277 278 if (new != 0) 279 { 280 ysd->dom_pnext = _ypbindlist; 281 _ypbindlist = ysd; 282 } 283 284 if (ypdb != NULL) *ypdb = ysd; 285 return 0; 286} 287 288void 289_yp_unbind(ypb) 290 struct dom_binding *ypb; 291{ 292 if (ypb->dom_client) clnt_destroy(ypb->dom_client); 293 ypb->dom_client = NULL; 294 ypb->dom_socket = -1; 295} 296 297int 298yp_bind(dom) 299 const char *dom; 300{ 301 return _yp_dobind(dom, NULL); 302} 303 304void 305yp_unbind(dom) 306 const char *dom; 307{ 308 struct dom_binding *ypb, *ypbp; 309 310 ypbp = NULL; 311 for (ypb = _ypbindlist; ypb; ypb = ypb->dom_pnext) { 312 if (strcmp(dom, ypb->dom_domain) == 0) { 313 if (ypb->dom_client) clnt_destroy(ypb->dom_client); 314 if (ypbp) 315 ypbp->dom_pnext = ypb->dom_pnext; 316 else 317 _ypbindlist = ypb->dom_pnext; 318 free(ypb); 319 return; 320 } 321 ypbp = ypb; 322 } 323} 324