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 2004 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 /* 30 * rpcb_svc_4.c 31 * The server procedure for the version 4 rpcbind. 32 * 33 */ 34 35 #include <stdio.h> 36 #include <sys/types.h> 37 #include <sys/stat.h> 38 #include <unistd.h> 39 #include <rpc/rpc.h> 40 #include <netconfig.h> 41 #include <syslog.h> 42 #include <netdir.h> 43 #include <string.h> 44 #include <stdlib.h> 45 #include "rpcbind.h" 46 47 static void free_rpcb_entry_list(); 48 49 /* 50 * Called by svc_getreqset. There is a separate server handle for 51 * every transport that it waits on. 52 */ 53 void 54 rpcb_service_4(rqstp, transp) 55 register struct svc_req *rqstp; 56 register SVCXPRT *transp; 57 { 58 union { 59 rpcb rpcbproc_set_4_arg; 60 rpcb rpcbproc_unset_4_arg; 61 rpcb rpcbproc_getaddr_4_arg; 62 char *rpcbproc_uaddr2taddr_4_arg; 63 struct netbuf rpcbproc_taddr2uaddr_4_arg; 64 } argument; 65 char *result; 66 bool_t (*xdr_argument)(), (*xdr_result)(); 67 char *(*local)(); 68 69 rpcbs_procinfo(RPCBVERS_4_STAT, rqstp->rq_proc); 70 71 RPCB_CHECK(transp, rqstp->rq_proc); 72 73 switch (rqstp->rq_proc) { 74 case NULLPROC: 75 /* 76 * Null proc call 77 */ 78 #ifdef RPCBIND_DEBUG 79 fprintf(stderr, "RPCBPROC_NULL\n"); 80 #endif 81 (void) svc_sendreply(transp, (xdrproc_t)xdr_void, 82 (char *)NULL); 83 return; 84 85 case RPCBPROC_SET: 86 /* 87 * Check to see whether the message came from 88 * loopback transports (for security reasons) 89 */ 90 if (strcasecmp(transp->xp_netid, loopback_dg) && 91 strcasecmp(transp->xp_netid, loopback_vc) && 92 strcasecmp(transp->xp_netid, loopback_vc_ord)) { 93 syslog(LOG_ERR, "non-local attempt to set"); 94 svcerr_weakauth(transp); 95 return; 96 } 97 xdr_argument = xdr_rpcb; 98 xdr_result = xdr_bool; 99 local = (char *(*)()) rpcbproc_set_com; 100 break; 101 102 case RPCBPROC_UNSET: 103 /* 104 * Check to see whether the message came from 105 * loopback transports (for security reasons) 106 */ 107 if (strcasecmp(transp->xp_netid, loopback_dg) && 108 strcasecmp(transp->xp_netid, loopback_vc) && 109 strcasecmp(transp->xp_netid, loopback_vc_ord)) { 110 syslog(LOG_ERR, "non-local attempt to unset"); 111 svcerr_weakauth(transp); 112 return; 113 } 114 xdr_argument = xdr_rpcb; 115 xdr_result = xdr_bool; 116 local = (char *(*)()) rpcbproc_unset_com; 117 break; 118 119 case RPCBPROC_GETADDR: 120 xdr_argument = xdr_rpcb; 121 xdr_result = xdr_wrapstring; 122 local = (char *(*)()) rpcbproc_getaddr_4; 123 break; 124 125 case RPCBPROC_GETVERSADDR: 126 #ifdef RPCBIND_DEBUG 127 fprintf(stderr, "RPCBPROC_GETVERSADDR\n"); 128 #endif 129 xdr_argument = xdr_rpcb; 130 xdr_result = xdr_wrapstring; 131 local = (char *(*)()) rpcbproc_getversaddr_4; 132 break; 133 134 case RPCBPROC_DUMP: 135 #ifdef RPCBIND_DEBUG 136 fprintf(stderr, "RPCBPROC_DUMP\n"); 137 #endif 138 xdr_argument = xdr_void; 139 xdr_result = xdr_rpcblist_ptr; 140 local = (char *(*)()) rpcbproc_dump_4; 141 break; 142 143 case RPCBPROC_INDIRECT: 144 #ifdef RPCBIND_DEBUG 145 fprintf(stderr, "RPCBPROC_INDIRECT\n"); 146 #endif 147 rpcbproc_callit_com(rqstp, transp, rqstp->rq_proc, RPCBVERS4); 148 return; 149 150 /* case RPCBPROC_CALLIT: */ 151 case RPCBPROC_BCAST: 152 #ifdef RPCBIND_DEBUG 153 fprintf(stderr, "RPCBPROC_BCAST\n"); 154 #endif 155 rpcbproc_callit_com(rqstp, transp, rqstp->rq_proc, RPCBVERS4); 156 return; 157 158 case RPCBPROC_GETTIME: 159 #ifdef RPCBIND_DEBUG 160 fprintf(stderr, "RPCBPROC_GETTIME\n"); 161 #endif 162 xdr_argument = xdr_void; 163 xdr_result = xdr_u_long; 164 local = (char *(*)()) rpcbproc_gettime_com; 165 break; 166 167 case RPCBPROC_UADDR2TADDR: 168 #ifdef RPCBIND_DEBUG 169 fprintf(stderr, "RPCBPROC_UADDR2TADDR\n"); 170 #endif 171 xdr_argument = xdr_wrapstring; 172 xdr_result = xdr_netbuf; 173 local = (char *(*)()) rpcbproc_uaddr2taddr_com; 174 break; 175 176 case RPCBPROC_TADDR2UADDR: 177 #ifdef RPCBIND_DEBUG 178 fprintf(stderr, "RPCBPROC_TADDR2UADDR\n"); 179 #endif 180 xdr_argument = xdr_netbuf; 181 xdr_result = xdr_wrapstring; 182 local = (char *(*)()) rpcbproc_taddr2uaddr_com; 183 break; 184 185 case RPCBPROC_GETADDRLIST: 186 #ifdef RPCBIND_DEBUG 187 fprintf(stderr, "RPCBPROC_GETADDRLIST\n"); 188 #endif 189 xdr_argument = xdr_rpcb; 190 xdr_result = xdr_rpcb_entry_list_ptr; 191 local = (char *(*)()) rpcbproc_getaddrlist_4; 192 break; 193 194 case RPCBPROC_GETSTAT: 195 #ifdef RPCBIND_DEBUG 196 fprintf(stderr, "RPCBPROC_GETSTAT\n"); 197 #endif 198 xdr_argument = xdr_void; 199 xdr_result = xdr_rpcb_stat_byvers; 200 local = (char *(*)()) rpcbproc_getstat; 201 break; 202 203 default: 204 svcerr_noproc(transp); 205 return; 206 } 207 memset((char *)&argument, 0, sizeof (argument)); 208 if (!svc_getargs(transp, (xdrproc_t)xdr_argument, 209 (char *)&argument)) { 210 svcerr_decode(transp); 211 if (debugging) 212 (void) fprintf(stderr, "rpcbind: could not decode\n"); 213 return; 214 } 215 result = (*local)(&argument, rqstp, transp, RPCBVERS4); 216 if (result != NULL && !svc_sendreply(transp, (xdrproc_t)xdr_result, 217 result)) { 218 svcerr_systemerr(transp); 219 if (debugging) { 220 (void) fprintf(stderr, "rpcbind: svc_sendreply\n"); 221 if (doabort) { 222 rpcbind_abort(); 223 } 224 } 225 } 226 if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, 227 (char *)&argument)) { 228 if (debugging) { 229 (void) fprintf(stderr, "unable to free arguments\n"); 230 if (doabort) { 231 rpcbind_abort(); 232 } 233 } 234 } 235 } 236 237 /* 238 * Lookup the mapping for a program, version and return its 239 * address. Assuming that the caller wants the address of the 240 * server running on the transport on which the request came. 241 * Even if a service with a different version number is available, 242 * it will return that address. The client should check with an 243 * clnt_call to verify whether the service is the one that is desired. 244 * We also try to resolve the universal address in terms of 245 * address of the caller. 246 */ 247 /* ARGSUSED */ 248 static char ** 249 rpcbproc_getaddr_4(regp, rqstp, transp, rpcbversnum) 250 rpcb *regp; 251 struct svc_req *rqstp; /* Not used here */ 252 SVCXPRT *transp; 253 int rpcbversnum; /* unused here */ 254 { 255 #ifdef RPCBIND_DEBUG 256 char *uaddr; 257 258 uaddr = taddr2uaddr(rpcbind_get_conf(transp->xp_netid), 259 svc_getrpccaller(transp)); 260 fprintf(stderr, "RPCB_GETADDR request for (%lu, %lu, %s) from %s : ", 261 regp->r_prog, regp->r_vers, transp->xp_netid, uaddr); 262 free(uaddr); 263 #endif 264 return (rpcbproc_getaddr_com(regp, rqstp, transp, RPCBVERS4, 265 (ulong_t)RPCB_ALLVERS)); 266 } 267 268 /* 269 * Lookup the mapping for a program, version and return its 270 * address. Assuming that the caller wants the address of the 271 * server running on the transport on which the request came. 272 * 273 * We also try to resolve the universal address in terms of 274 * address of the caller. 275 */ 276 /* ARGSUSED */ 277 static char ** 278 rpcbproc_getversaddr_4(regp, rqstp, transp) 279 rpcb *regp; 280 struct svc_req *rqstp; /* Not used here */ 281 SVCXPRT *transp; 282 { 283 #ifdef RPCBIND_DEBUG 284 char *uaddr; 285 286 uaddr = taddr2uaddr(rpcbind_get_conf(transp->xp_netid), 287 svc_getrpccaller(transp)); 288 fprintf(stderr, "RPCB_GETVERSADDR rqst for (%lu, %lu, %s) from %s : ", 289 regp->r_prog, regp->r_vers, transp->xp_netid, uaddr); 290 free(uaddr); 291 #endif 292 return (rpcbproc_getaddr_com(regp, rqstp, transp, RPCBVERS4, 293 (ulong_t)RPCB_ONEVERS)); 294 } 295 296 /* 297 * Lookup the mapping for a program, version and return the 298 * addresses for all transports in the current transport family. 299 * We return a merged address. 300 */ 301 /* ARGSUSED */ 302 static rpcb_entry_list_ptr * 303 rpcbproc_getaddrlist_4(regp, rqstp, transp) 304 rpcb *regp; 305 struct svc_req *rqstp; /* Not used here */ 306 SVCXPRT *transp; 307 { 308 static rpcb_entry_list_ptr rlist; 309 register rpcblist_ptr rbl; 310 rpcb_entry_list_ptr rp, tail; 311 ulong_t prog, vers; 312 rpcb_entry *a; 313 struct netconfig *nconf; 314 struct netconfig *reg_nconf; 315 char *saddr, *maddr = NULL; 316 struct netconfig *trans_conf; /* transport netconfig */ 317 318 /* 319 * Deal with a possible window during which we could return an IPv6 320 * address when the caller wanted IPv4. See the comments in 321 * rpcbproc_getaddr_com() for more details. 322 */ 323 trans_conf = rpcbind_get_conf(transp->xp_netid); 324 if (strcmp(trans_conf->nc_protofmly, NC_INET6) == 0) { 325 struct sockaddr_in6 *rmtaddr; 326 327 rmtaddr = (struct sockaddr_in6 *)transp->xp_rtaddr.buf; 328 if (IN6_IS_ADDR_V4MAPPED(&rmtaddr->sin6_addr)) { 329 syslog(LOG_DEBUG, 330 "IPv4 GETADDRLIST request mapped " 331 "to IPv6: ignoring"); 332 return (NULL); 333 } 334 } 335 336 free_rpcb_entry_list(&rlist); 337 prog = regp->r_prog; 338 vers = regp->r_vers; 339 reg_nconf = rpcbind_get_conf(transp->xp_netid); 340 if (reg_nconf == NULL) 341 return (NULL); 342 if (*(regp->r_addr) != '\0') { 343 saddr = regp->r_addr; 344 } else { 345 saddr = NULL; 346 } 347 #ifdef RPCBIND_DEBUG 348 fprintf(stderr, "r_addr: %s r_netid: %s nc_protofmly: %s\n", 349 regp->r_addr, transp->xp_netid, reg_nconf->nc_protofmly); 350 #endif 351 for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) { 352 if ((rbl->rpcb_map.r_prog == prog) && 353 (rbl->rpcb_map.r_vers == vers)) { 354 nconf = rpcbind_get_conf(rbl->rpcb_map.r_netid); 355 if (nconf == NULL) 356 goto fail; 357 if (strcmp(nconf->nc_protofmly, reg_nconf->nc_protofmly) 358 != 0) { 359 continue; /* not same proto family */ 360 } 361 #ifdef RPCBIND_DEBUG 362 fprintf(stderr, "\tmerge with: %s", rbl->rpcb_map.r_addr); 363 #endif 364 if ((maddr = mergeaddr(transp, rbl->rpcb_map.r_netid, 365 rbl->rpcb_map.r_addr, saddr)) == NULL) { 366 #ifdef RPCBIND_DEBUG 367 fprintf(stderr, " FAILED\n"); 368 #endif 369 continue; 370 } else if (!maddr[0]) { 371 #ifdef RPCBIND_DEBUG 372 fprintf(stderr, " SUCCEEDED, but port died - maddr: nullstring\n"); 373 #endif 374 /* The server died. Unset this combination */ 375 delete_prog(regp->r_prog); 376 continue; 377 } 378 #ifdef RPCBIND_DEBUG 379 fprintf(stderr, " SUCCEEDED maddr: %s\n", maddr); 380 #endif 381 /* 382 * Add it to rlist. 383 */ 384 rp = (rpcb_entry_list_ptr) 385 malloc((uint_t)sizeof (rpcb_entry_list)); 386 if (rp == NULL) 387 goto fail; 388 a = &rp->rpcb_entry_map; 389 a->r_maddr = maddr; 390 a->r_nc_netid = nconf->nc_netid; 391 a->r_nc_semantics = nconf->nc_semantics; 392 a->r_nc_protofmly = nconf->nc_protofmly; 393 a->r_nc_proto = nconf->nc_proto; 394 rp->rpcb_entry_next = NULL; 395 if (rlist == NULL) { 396 rlist = rp; 397 tail = rp; 398 } else { 399 tail->rpcb_entry_next = rp; 400 tail = rp; 401 } 402 rp = NULL; 403 } 404 } 405 #ifdef RPCBIND_DEBUG 406 for (rp = rlist; rp; rp = rp->rpcb_entry_next) { 407 fprintf(stderr, "\t%s %s\n", rp->rpcb_entry_map.r_maddr, 408 rp->rpcb_entry_map.r_nc_proto); 409 } 410 #endif 411 /* 412 * XXX: getaddrlist info is also being stuffed into getaddr. 413 * Perhaps wrong, but better than it not getting counted at all. 414 */ 415 rpcbs_getaddr(RPCBVERS4 - 2, prog, vers, transp->xp_netid, maddr); 416 return (&rlist); 417 418 fail: free_rpcb_entry_list(&rlist); 419 return (NULL); 420 } 421 422 /* 423 * Free only the allocated structure, rest is all a pointer to some 424 * other data somewhere else. 425 */ 426 static void 427 free_rpcb_entry_list(rlistp) 428 rpcb_entry_list_ptr *rlistp; 429 { 430 register rpcb_entry_list_ptr rbl, tmp; 431 432 for (rbl = *rlistp; rbl != NULL; ) { 433 tmp = rbl; 434 rbl = rbl->rpcb_entry_next; 435 free((char *)tmp->rpcb_entry_map.r_maddr); 436 free((char *)tmp); 437 } 438 *rlistp = NULL; 439 } 440 441 /* VARARGS */ 442 static rpcblist_ptr * 443 rpcbproc_dump_4() 444 { 445 return ((rpcblist_ptr *)&list_rbl); 446 } 447