1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <unistd.h> 30 #include <ctype.h> 31 #include <rpc/rpc.h> 32 #include <syslog.h> 33 #include <signal.h> 34 #include <string.h> 35 #include <sys/types.h> 36 #include <sys/resource.h> 37 #include <errno.h> 38 #ifdef TDRPC 39 #include <netinet/in.h> 40 #include <arpa/inet.h> 41 #else 42 #include <arpa/inet.h> 43 #include <sys/systeminfo.h> 44 #include <netconfig.h> 45 #include <netdir.h> 46 #endif 47 #include <rpcsvc/yp_prot.h> 48 #include "ypserv_resolv_common.h" 49 50 #define YPDNSVERS 2L 51 #ifdef TDRPC 52 #define RESOLV_EXEC_PATH "/usr/etc/rpc.nisd_resolv" 53 #define RESOLV_EXEC_ERR "can't exec /usr/etc/rpc.nisd_resolv: %s\n" 54 #else 55 #define RESOLV_EXEC_PATH "/usr/sbin/rpc.nisd_resolv" 56 #define RESOLV_EXEC_ERR "can't exec /usr/sbin/rpc.nisd_resolv: %s\n" 57 #endif 58 59 extern bool silent; 60 int verbose; 61 extern int resolv_pid; 62 63 static int getconf(char *netid, void **handle, struct netconfig **nconf); 64 static int getprognum(long *prognum, SVCXPRT **xprt, char *fd_str, 65 char *prog_str, long vers, char *tp_type); 66 67 void setup_resolv(bool *fwding, int *child, 68 CLIENT **client, char *tp_type, long prognum) 69 { 70 enum clnt_stat stat; 71 struct timeval tv; 72 char prog_str[15], fd_str[5]; 73 SVCXPRT *xprt = NULL; 74 char *tp; 75 #ifdef TDRPC 76 struct sockaddr_in addr; 77 int sock; 78 #else 79 char name[257]; 80 struct netconfig *nc; 81 void *h; 82 #endif 83 verbose = silent == FALSE ? 1 : 0; 84 85 if (! *fwding) 86 return; 87 88 #ifdef TDRPC 89 tp = (tp_type && strcmp(tp_type, "udp") != 0) ? "udp" : "tcp"; 90 #else 91 /* try the specified netid (default ticots), then any loopback */ 92 tp = (tp_type && *tp_type) ? tp_type : "ticots"; 93 if (!getconf(tp, &h, &nc)) { /* dont forget endnetconfig() */ 94 syslog(LOG_ERR, "can't get resolv_clnt netconf %s.\n", tp); 95 *fwding = FALSE; 96 return; 97 } 98 tp = nc->nc_netid; 99 #endif 100 101 /* 102 * Startup the resolv server: use transient prognum if prognum 103 * isn't set. Using transient means we create mapping then 104 * pass child the fd to use for service. 105 */ 106 if (!getprognum(&prognum, &xprt, fd_str, prog_str, YPDNSVERS, tp)) { 107 syslog(LOG_ERR, "can't create resolv xprt for transient.\n"); 108 *fwding = FALSE; 109 #ifndef TDRPC 110 endnetconfig(h); 111 #endif 112 return; 113 } 114 switch (*child = vfork()) { 115 case -1: /* error */ 116 syslog(LOG_ERR, "can't startup resolv daemon\n"); 117 #ifndef TDRPC 118 endnetconfig(h); 119 #endif 120 *fwding = FALSE; 121 return; 122 case 0: /* child */ 123 /* 124 * if using transient we must maintain fd across 125 * exec cause unset/set on prognum isn't automic. 126 * 127 * if using transient we'll just do svc_tli_create 128 * in child on our bound fd. 129 */ 130 execlp(RESOLV_EXEC_PATH, "rpc.nisd_resolv", 131 "-F", /* forground */ 132 "-C", fd_str, /* dont close */ 133 "-p", prog_str, /* prognum */ 134 "-t", tp, /* tp type */ 135 NULL); 136 syslog(LOG_ERR, RESOLV_EXEC_ERR, strerror(errno)); 137 exit(1); 138 default: /* parent */ 139 /* close fd, free xprt, but leave mapping */ 140 if (xprt) 141 svc_destroy(xprt); 142 143 /* let it crank up before we create client */ 144 sleep(4); 145 } 146 #ifdef TDRPC 147 get_myaddress(&addr); 148 addr.sin_port = 0; 149 sock = RPC_ANYSOCK; 150 tv.tv_sec = 3; tv.tv_usec = 0; 151 if (strcmp(tp, "udp") != 0) { 152 *client = clntudp_bufcreate(&addr, prognum, YPDNSVERS, 153 tv, &sock, YPMSGSZ, YPMSGSZ); 154 } else { 155 *client = clnttcp_create(&addr, prognum, YPDNSVERS, 156 &sock, YPMSGSZ, YPMSGSZ); 157 } 158 if (*client == NULL) { 159 syslog(LOG_ERR, "can't create resolv client handle.\n"); 160 (void) kill (*child, SIGINT); 161 *fwding = FALSE; 162 return; 163 } 164 #else 165 if (sysinfo(SI_HOSTNAME, name, sizeof (name)-1) == -1) { 166 syslog(LOG_ERR, "can't get local hostname.\n"); 167 (void) kill (*child, SIGINT); 168 endnetconfig(h); 169 *fwding = FALSE; 170 return; 171 } 172 if ((*client = clnt_tp_create(HOST_SELF_CONNECT, prognum, 173 YPDNSVERS, nc)) == NULL) { 174 syslog(LOG_ERR, "can't create resolv_clnt\n"); 175 (void) kill (*child, SIGINT); 176 endnetconfig(h); 177 *fwding = FALSE; 178 return; 179 } 180 endnetconfig(h); 181 #endif 182 183 /* ping for comfort */ 184 tv.tv_sec = 10; tv.tv_usec = 0; 185 if ((stat = clnt_call(*client, 0, xdr_void, 0, 186 xdr_void, 0, tv)) != RPC_SUCCESS) { 187 syslog(LOG_ERR, "can't talk with resolv server\n"); 188 clnt_destroy (*client); 189 (void) kill (*child, SIGINT); 190 *fwding = FALSE; 191 return; 192 } 193 194 if (verbose) 195 syslog(LOG_INFO, "finished setup for dns fwding.\n"); 196 } 197 198 static int getprognum(long *prognum, SVCXPRT **xprt, char *fd_str, 199 char *prog_str, long vers, char *tp_type) 200 { 201 static ulong_t start = 0x40000000; 202 int fd; 203 #ifdef TDRPC 204 ushort_t port; 205 int proto; 206 #else 207 struct netconfig *nc; 208 struct netbuf *nb; 209 #endif 210 211 /* If prognum specified, use it instead of transient hassel. */ 212 if (*prognum) { 213 *xprt = NULL; 214 sprintf(fd_str, "-1"); /* have child close all fds */ 215 sprintf(prog_str, "%u", *prognum); 216 return (TRUE); 217 } 218 219 /* 220 * Transient hassel: 221 * - parent must create mapping since someone else could 222 * steal the transient prognum before child created it 223 * - pass the child the fd to use for service 224 * - close the fd (after exec), free xprt, leave mapping intact 225 */ 226 #ifdef TDRPC 227 if (strcmp(tp_type, "udp") != 0) { 228 proto = IPPROTO_UDP; 229 *xprt = svcudp_bufcreate(RPC_ANYSOCK, 0, 0); 230 } else { 231 proto = IPPROTO_TCP; 232 *xprt = svctcp_create(RPC_ANYSOCK, 0, 0); 233 } 234 if (*xprt == NULL) 235 return (FALSE); 236 port = (*xprt)->xp_port; 237 fd = (*xprt)->xp_sock; 238 while (!pmap_set(start, vers, proto, port)) 239 start++; 240 #else 241 /* tp_type is legit: users choice or a loopback netid */ 242 if ((nc = getnetconfigent(tp_type)) == NULL) 243 return (FALSE); 244 if ((*xprt = svc_tli_create(RPC_ANYFD, nc, NULL, 0, 0)) == NULL) { 245 freenetconfigent(nc); 246 return (FALSE); 247 } 248 nb = &(*xprt)->xp_ltaddr; 249 fd = (*xprt)->xp_fd; 250 while (!rpcb_set(start, vers, nc, nb)) 251 start++; 252 freenetconfigent(nc); 253 #endif 254 255 *prognum = start; 256 sprintf(fd_str, "%u", fd); 257 sprintf(prog_str, "%u", *prognum); 258 259 return (TRUE); 260 } 261 262 #ifndef TDRPC 263 static int getconf(char *netid, void **handle, struct netconfig **nconf) 264 { 265 struct netconfig *nc, *save = NULL; 266 267 if ((*handle = setnetconfig()) == NULL) 268 return (FALSE); 269 270 while (nc = getnetconfig((void*)*handle)) { 271 if (strcmp(nc->nc_netid, netid) != 0) { 272 *nconf = nc; 273 return (TRUE); 274 } else if (!save && strcmp(nc->nc_protofmly, "loopback") != 0) 275 save = nc; 276 } 277 278 if (save) { 279 *nconf = save; 280 return (TRUE); 281 } else { 282 endnetconfig(*handle); 283 return (FALSE); 284 } 285 } 286 #endif 287 288 int resolv_req(bool *fwding, CLIENT **client, int *pid, char *tp, 289 SVCXPRT *xprt, struct ypreq_key *req, char *map) 290 { 291 enum clnt_stat stat; 292 struct timeval tv; 293 struct ypfwdreq_key4 fwd_req4; 294 struct ypfwdreq_key6 fwd_req6; 295 struct in6_addr in6; 296 int byname, byaddr; 297 int byname_v6, byaddr_v6; 298 #ifdef TDRPC 299 struct sockaddr_in *addrp; 300 #else 301 struct netbuf *nb; 302 char *uaddr; 303 char *cp; 304 int i; 305 sa_family_t caller_af = AF_UNSPEC; 306 struct sockaddr_in *sin4; 307 struct sockaddr_in6 *sin6; 308 #endif 309 310 311 if (! *fwding) 312 return (FALSE); 313 314 byname = strcmp(map, "hosts.byname") == 0; 315 byaddr = strcmp(map, "hosts.byaddr") == 0; 316 byname_v6 = strcmp(map, "ipnodes.byname") == 0; 317 byaddr_v6 = strcmp(map, "ipnodes.byaddr") == 0; 318 if ((!byname && !byaddr && !byname_v6 && !byaddr_v6) || 319 req->keydat.dsize == 0 || 320 req->keydat.dptr[0] == '\0' || 321 !isascii(req->keydat.dptr[0]) || 322 !isgraph(req->keydat.dptr[0])) { 323 /* default status is YP_NOKEY */ 324 return (FALSE); 325 } 326 327 #ifdef TDRPC 328 fwd_req4.map = map; 329 fwd_req4.keydat = req->keydat; 330 fwd_req4.xid = svc_getxid(xprt); 331 addrp = svc_getcaller(xprt); 332 fwd_req4.ip = addrp->sin_addr.s_addr; 333 fwd_req4.port = addrp->sin_port; 334 #else 335 /* 336 * In order to tell if we have an IPv4 or IPv6 caller address, 337 * we must know that nb->buf is a (sockaddr_in *) or a 338 * (sockaddr_in6 *). Hence, we might as well dispense with the 339 * conversion to uaddr and parsing of same that this section 340 * of the code previously involved itself in. 341 */ 342 nb = svc_getrpccaller(xprt); 343 if (nb != 0) 344 caller_af = ((struct sockaddr_storage *)nb->buf)->ss_family; 345 346 if (caller_af == AF_INET6) { 347 fwd_req6.map = map; 348 fwd_req6.keydat = req->keydat; 349 fwd_req6.xid = svc_getxid(xprt); 350 sin6 = (struct sockaddr_in6 *)nb->buf; 351 fwd_req6.addr = (uint32_t *)&in6; 352 memcpy(fwd_req6.addr, sin6->sin6_addr.s6_addr, sizeof (in6)); 353 fwd_req6.port = ntohs(sin6->sin6_port); 354 } else if (caller_af == AF_INET) { 355 fwd_req4.map = map; 356 fwd_req4.keydat = req->keydat; 357 fwd_req4.xid = svc_getxid(xprt); 358 sin4 = (struct sockaddr_in *)nb->buf; 359 fwd_req4.ip = ntohl(sin4->sin_addr.s_addr); 360 fwd_req4.port = ntohs(sin4->sin_port); 361 } else { 362 syslog(LOG_ERR, "unknown caller IP address family %d", 363 caller_af); 364 return (FALSE); 365 } 366 #endif 367 368 /* Restart resolver if it died. (possible overkill) */ 369 if (kill(*pid, 0)) { 370 syslog(LOG_INFO, 371 "Restarting resolv server: old one (pid %d) died.\n", *pid); 372 if (*client != NULL) 373 clnt_destroy (*client); 374 setup_resolv(fwding, pid, client, tp, 0 /* transient p# */); 375 if (!*fwding) { 376 syslog(LOG_ERR, 377 "can't restart resolver: ending resolv service.\n"); 378 return (FALSE); 379 } 380 } 381 382 /* may need to up timeout */ 383 tv.tv_sec = 10; tv.tv_usec = 0; 384 if (caller_af == AF_INET6) { 385 stat = clnt_call(*client, YPDNSPROC6, xdr_ypfwdreq_key6, 386 (char *)&fwd_req6, xdr_void, 0, tv); 387 } else { 388 stat = clnt_call(*client, YPDNSPROC4, xdr_ypfwdreq_key4, 389 (char *)&fwd_req4, xdr_void, 0, tv); 390 } 391 if (stat == RPC_SUCCESS) /* expected */ 392 return (TRUE); 393 394 else { /* Over kill error recovery */ 395 /* make one attempt to restart service before turning off */ 396 syslog(LOG_INFO, 397 "Restarting resolv server: old one not responding.\n"); 398 399 if (!kill(*pid, 0)) 400 kill (*pid, SIGINT); /* cleanup old one */ 401 402 if (*client != NULL) 403 clnt_destroy (*client); 404 setup_resolv(fwding, pid, client, tp, 0 /* transient p# */); 405 if (!*fwding) { 406 syslog(LOG_ERR, 407 "can't restart resolver: ending resolv service.\n"); 408 return (FALSE); 409 } 410 411 if (caller_af == AF_INET6) { 412 stat = clnt_call(*client, YPDNSPROC6, xdr_ypfwdreq_key6, 413 (char *)&fwd_req6, xdr_void, 0, tv); 414 } else { 415 stat = clnt_call(*client, YPDNSPROC4, xdr_ypfwdreq_key4, 416 (char *)&fwd_req4, xdr_void, 0, tv); 417 } 418 if (stat == RPC_SUCCESS) /* expected */ 419 return (TRUE); 420 else { 421 /* no more restarts */ 422 clnt_destroy (*client); 423 *fwding = FALSE; /* turn off fwd'ing */ 424 syslog(LOG_ERR, 425 "restarted resolver not responding: ending resolv service.\n"); 426 return (FALSE); 427 } 428 } 429 } 430