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