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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 28 /* 29 * This module contains the subroutines used by the server to manipulate 30 * objects and names. 31 */ 32 #include "mt.h" 33 #include <pwd.h> 34 #include <grp.h> 35 #include <syslog.h> 36 #include <stdio.h> 37 #include <string.h> 38 #include <ctype.h> 39 #include <stdlib.h> 40 #include <unistd.h> 41 #include <sys/time.h> 42 #include <sys/fcntl.h> 43 #include <netinet/in.h> 44 #include <rpc/rpc.h> /* Must be ahead of rpcb_clnt.h */ 45 #include <rpc/svc.h> 46 #include <tiuser.h> 47 #include <netconfig.h> 48 #include <netdir.h> 49 #include <rpc/rpcb_clnt.h> 50 #include <rpc/pmap_clnt.h> 51 #include <rpcsvc/nis.h> 52 #include <rpcsvc/nis_dhext.h> 53 #include "nis_clnt.h" 54 #include <sys/systeminfo.h> 55 #include <nsswitch.h> 56 57 #define MAXIPRINT (11) /* max length of printed integer */ 58 /* 59 * send and receive buffer size used for clnt_tli_create if not specified. 60 * This is only used for "UDP" connection. 61 * This limit can be changed from the application if this value is too 62 * small for the application. To use the maximum value for the transport, 63 * set this value to 0. 64 */ 65 int __nisipbufsize = 8192; 66 67 68 /* 69 * Static function prototypes. 70 */ 71 static struct local_names *__get_local_names(void); 72 static char *__map_addr(struct netconfig *, char *, rpcprog_t, rpcvers_t); 73 74 /* 75 * nis_dir_cmp() -- the results can be read as: 76 * "Name 'n1' is a $result than name 'n2'" 77 */ 78 name_pos 79 nis_dir_cmp( 80 nis_name n1, 81 nis_name n2) /* See if these are the same domain */ 82 { 83 size_t l1, l2; 84 name_pos result; 85 86 if ((n1 == NULL) || (n2 == NULL)) 87 return (BAD_NAME); 88 89 l1 = strlen(n1); 90 l2 = strlen(n2); 91 92 /* In this routine we're lenient and don't require a trailing '.' */ 93 /* so we need to ignore it if it does appear. */ 94 /* ==== That's what the previous version did so this one does */ 95 /* too, but why? Is this inconsistent with rest of system? */ 96 if (l1 != 0 && n1[l1 - 1] == '.') { 97 --l1; 98 } 99 if (l2 != 0 && n2[l2 - 1] == '.') { 100 --l2; 101 } 102 103 if (l1 > l2) { 104 result = LOWER_NAME; 105 } else if (l1 == l2) { 106 result = SAME_NAME; 107 } else /* (l1 < l2); swap l1/l2 and n1/n2 */ { 108 nis_name ntmp; 109 size_t ltmp; 110 ntmp = n1; n1 = n2; n2 = ntmp; 111 ltmp = l1; l1 = l2; l2 = ltmp; 112 113 result = HIGHER_NAME; 114 } 115 116 /* Now l1 >= l2 in all cases */ 117 if (l2 == 0) { 118 /* Special case for n2 == "." or "" */ 119 return (result); 120 } 121 if (l1 > l2) { 122 n1 += l1 - l2; 123 if (n1[-1] != '.') { 124 return (NOT_SEQUENTIAL); 125 } 126 } 127 if (strncasecmp(n1, n2, l2) == 0) { 128 return (result); 129 } 130 return (NOT_SEQUENTIAL); 131 } 132 133 #define LN_BUFSIZE (size_t)1024 134 135 struct principal_list { 136 uid_t uid; 137 char principal[LN_BUFSIZE]; 138 struct principal_list *next; 139 }; 140 141 142 struct local_names { 143 char domain[LN_BUFSIZE]; 144 char host[LN_BUFSIZE]; 145 char *rpcdomain; 146 struct principal_list *principal_map; 147 char group[LN_BUFSIZE]; 148 }; 149 150 static mutex_t ln_lock = DEFAULTMUTEX; /* lock level 2 */ 151 static struct local_names *ln = NULL; 152 static struct local_names *__get_local_names1(); 153 154 static struct local_names * 155 __get_local_names(void) 156 { 157 struct local_names *names; 158 159 sig_mutex_lock(&ln_lock); 160 names = __get_local_names1(); 161 sig_mutex_unlock(&ln_lock); 162 return (names); 163 } 164 165 166 static struct local_names * 167 __get_local_names1(void) 168 { 169 char *t; 170 171 if (ln != NULL) { 172 /* Second and subsequent calls go this way */ 173 return (ln); 174 } 175 /* First call goes this way */ 176 ln = calloc(1, sizeof (*ln)); 177 if (ln == NULL) { 178 syslog(LOG_ERR, "__get_local_names: Out of heap."); 179 return (NULL); 180 } 181 ln->principal_map = NULL; 182 183 if (sysinfo(SI_SRPC_DOMAIN, ln->domain, LN_BUFSIZE) < 0) 184 return (ln); 185 /* If no dot exists, add one. */ 186 if (ln->domain[strlen(ln->domain)-1] != '.') 187 (void) strcat(ln->domain, "."); 188 if (sysinfo(SI_HOSTNAME, ln->host, LN_BUFSIZE) < 0) 189 return (ln); 190 191 /* 192 * Check for fully qualified hostname. If it's a fully qualified 193 * hostname, strip off the domain part. We always use the local 194 * domainname for the host principal name. 195 */ 196 t = strchr(ln->host, '.'); 197 if (t) 198 *t = 0; 199 if (ln->domain[0] != '.') 200 (void) strcat(ln->host, "."); 201 ln->rpcdomain = strdup(ln->domain); 202 (void) strcat(ln->host, ln->domain); 203 204 t = getenv("NIS_GROUP"); 205 if (t == NULL) { 206 ln->group[0] = '\0'; 207 } else { 208 size_t maxlen = LN_BUFSIZE-1; /* max chars to copy */ 209 char *temp; /* temp marker */ 210 211 /* 212 * Copy <= maximum characters from NIS_GROUP; strncpy() 213 * doesn't terminate, so we do that manually. #1223323 214 * Also check to see if it's "". If it's the null string, 215 * we return because we don't want to add ".domain". 216 */ 217 (void) strncpy(ln->group, t, maxlen); 218 if (strcmp(ln->group, "") == 0) { 219 return (ln); 220 } 221 ln->group[maxlen] = '\0'; 222 223 /* Is the group name somewhat fully-qualified? */ 224 temp = strrchr(ln->group, '.'); 225 226 /* If not, we need to add ".domain" to the group */ 227 if ((temp == NULL) || (temp[1] != '\0')) { 228 229 /* truncate to make room for ".domain" */ 230 ln->group[maxlen - (strlen(ln->domain)+1)] = '\0'; 231 232 /* concat '.' if domain doesn't already have it */ 233 if (ln->domain[0] != '.') { 234 (void) strcat(ln->group, "."); 235 } 236 (void) strcat(ln->group, ln->domain); 237 } 238 } 239 return (ln); 240 } 241 242 /* 243 * nis_local_group() 244 * 245 * Return's the group name of the current user. 246 */ 247 nis_name 248 nis_local_group(void) 249 { 250 struct local_names *ln = __get_local_names(); 251 252 /* LOCK NOTE: Warning, after initialization, "ln" is expected */ 253 /* to stay constant, So no need to lock here. If this assumption */ 254 /* is changed, this code must be protected. */ 255 if (!ln) 256 return (NULL); 257 return (ln->group); 258 } 259 260 /* 261 * __nis_nextsep_of() 262 * 263 * This internal funtion will accept a pointer to a NIS name string and 264 * return a pointer to the next separator occurring in it (it will point 265 * just past the first label). It allows for labels to be "quoted" to 266 * prevent the the dot character within them to be interpreted as a 267 * separator, also the quote character itself can be quoted by using 268 * it twice. If the the name contains only one label and no trailing 269 * dot character, a pointer to the terminating NULL is returned. 270 */ 271 nis_name 272 __nis_nextsep_of(char *s) 273 { 274 char *d; 275 int in_quotes = FALSE, quote_quote = FALSE; 276 277 if (!s) 278 return (NULL); 279 280 for (d = s; (in_quotes && (*d != '\0')) || 281 (!in_quotes && (*d != '.') && (*d != '\0')); d++) { 282 if (quote_quote && in_quotes && (*d != '"')) { 283 quote_quote = FALSE; 284 in_quotes = FALSE; 285 if (*d == '.') 286 break; 287 } else if (quote_quote && in_quotes && (*d == '"')) { 288 quote_quote = FALSE; 289 } else if (quote_quote && (*d != '"')) { 290 quote_quote = FALSE; 291 in_quotes = TRUE; 292 } else if (quote_quote && (*d == '"')) { 293 quote_quote = FALSE; 294 } else if (in_quotes && (*d == '"')) { 295 quote_quote = TRUE; 296 } else if (!in_quotes && (*d == '"')) { 297 quote_quote = TRUE; 298 } 299 } 300 301 if (quote_quote || in_quotes) { 302 syslog(LOG_DEBUG, "__nis_nextsep_of: " 303 "Mismatched quotes in %s", s); 304 } 305 306 return (d); 307 } 308 309 /* 310 * nis_domain_of() 311 * 312 * This internal funtion will accept a pointer to a NIS name string and 313 * return a pointer to the "domain" part of it. 314 * 315 * ==== We don't need nis_domain_of_r(), but should we provide one for 316 * uniformity? 317 */ 318 nis_name 319 nis_domain_of(char *s) 320 { 321 char *d; 322 323 d = __nis_nextsep_of(s); 324 if (d == NULL) 325 return (NULL); 326 if (*d == '.') 327 d++; 328 if (*d == '\0') /* Don't return a zero length string */ 329 return ("."); /* return root domain instead */ 330 return (d); 331 } 332 333 334 /* 335 * nis_leaf_of() 336 * 337 * Returns the first label of a name. (other half of __domain_of) 338 */ 339 nis_name 340 nis_leaf_of_r( 341 const nis_name s, 342 char *buf, 343 size_t bufsize) 344 { 345 size_t nchars; 346 const char *d = __nis_nextsep_of((char *)s); 347 348 if (d == 0) { 349 return (0); 350 } 351 nchars = d - s; 352 if (bufsize < nchars + 1) { 353 return (0); 354 } 355 (void) strncpy(buf, s, nchars); 356 buf[nchars] = '\0'; 357 return (buf); 358 } 359 360 static pthread_key_t buf_key = PTHREAD_ONCE_KEY_NP; 361 static char buf_main[LN_BUFSIZE]; 362 363 nis_name 364 nis_leaf_of(char *s) 365 { 366 char *buf = thr_main()? buf_main : 367 thr_get_storage(&buf_key, LN_BUFSIZE, free); 368 369 if (buf == NULL) 370 return (NULL); 371 return (nis_leaf_of_r(s, buf, LN_BUFSIZE)); 372 } 373 374 /* 375 * nis_name_of() 376 * This internal function will remove from the NIS name, the domain 377 * name of the current server, this will leave the unique part in 378 * the name this becomes the "internal" version of the name. If this 379 * function returns NULL then the name we were given to resolve is 380 * bad somehow. 381 * NB: Uses static storage and this is a no-no with threads. XXX 382 */ 383 384 nis_name 385 nis_name_of_r( 386 char *s, /* string with the name in it. */ 387 char *buf, 388 size_t bufsize) 389 { 390 char *d; 391 struct local_names *ln = __get_local_names(); 392 size_t dl, sl; 393 name_pos p; 394 395 #ifdef lint 396 bufsize = bufsize; 397 #endif /* lint */ 398 if ((!s) || (!ln)) 399 return (NULL); /* No string, this can't continue */ 400 401 d = &(ln->domain[0]); 402 dl = strlen(ln->domain); /* _always dot terminated_ */ 403 404 sl = strlen(s); 405 if (sl >= bufsize || (s[sl-1] != '.' && sl >= bufsize-1)) 406 return (NULL); 407 (void) strcpy(buf, s); /* Make a private copy of 's' */ 408 if (buf[sl-1] != '.') { /* Add a dot if necessary. */ 409 (void) strcat(buf, "."); 410 sl++; 411 } 412 413 if (dl == 1) { /* We're the '.' directory */ 414 buf[sl-1] = '\0'; /* Lose the 'dot' */ 415 return (buf); 416 } 417 418 p = nis_dir_cmp(buf, d); 419 420 /* 's' is above 'd' in the tree */ 421 if ((p == HIGHER_NAME) || (p == NOT_SEQUENTIAL) || (p == SAME_NAME)) 422 return (NULL); 423 424 /* Insert a NUL where the domain name starts in the string */ 425 buf[(sl - dl) - 1] = '\0'; 426 427 /* Don't return a zero length name */ 428 if (buf[0] == '\0') 429 return (NULL); 430 431 return (buf); 432 } 433 434 nis_name 435 nis_name_of( 436 char *s) /* string with the name in it. */ 437 { 438 char *buf = thr_main()? buf_main : 439 thr_get_storage(&buf_key, LN_BUFSIZE, free); 440 441 if (!buf) 442 return (NULL); 443 return (nis_name_of_r(s, buf, LN_BUFSIZE)); 444 } 445 446 447 448 /* 449 * nis_local_directory() 450 * 451 * Return a pointer to a string with the local directory name in it. 452 */ 453 nis_name 454 nis_local_directory(void) 455 { 456 struct local_names *ln = __get_local_names(); 457 458 /* LOCK NOTE: Warning, after initialization, "ln" is expected */ 459 /* to stay constant, So no need to lock here. If this assumption */ 460 /* is changed, this code must be protected. */ 461 if (ln == NULL) 462 return (NULL); 463 return (ln->domain); 464 } 465 466 /* 467 * __nis_rpc_domain() 468 * 469 * Return a pointer to a string with the rpc domain name in it. 470 */ 471 nis_name 472 __nis_rpc_domain() 473 { 474 struct local_names *ln = __get_local_names(); 475 476 /* LOCK NOTE: Warning, after initialization, "ln" is expected */ 477 /* to stay constant, So no need to lock here. If this assumption */ 478 /* is changed, this code must be protected. */ 479 if (ln == NULL) 480 return (NULL); 481 return (ln->rpcdomain); 482 } 483 484 485 /* 486 * nis_local_host() 487 * Generate the principal name for this host, "hostname"+"domainname" 488 * unless the hostname already has "dots" in its name. 489 */ 490 nis_name 491 nis_local_host(void) 492 { 493 struct local_names *ln = __get_local_names(); 494 495 /* LOCK NOTE: Warning, after initialization, "ln" is expected */ 496 /* to stay constant, So no need to lock here. If this assumption */ 497 /* is changed, this code must be protected. */ 498 if (ln == NULL) 499 return (NULL); 500 501 return (ln->host); 502 } 503 504 /* 505 * nis_destroy_object() 506 * This function takes a pointer to a NIS object and deallocates it. This 507 * is the inverse of __clone_object below. It must be able to correctly 508 * deallocate partially allocated objects because __clone_object will call 509 * it if it runs out of memory and has to abort. Everything is freed, 510 * INCLUDING the pointer that is passed. 511 */ 512 void 513 nis_destroy_object(nis_object *obj) /* The object to clone */ 514 { 515 if (obj == 0) 516 return; 517 xdr_free(xdr_nis_object, (char *)obj); 518 free(obj); 519 } /* nis_destroy_object */ 520 521 static void 522 destroy_nis_sdata(void *p) 523 { 524 struct nis_sdata *ns = p; 525 526 if (ns->buf != 0) 527 free(ns->buf); 528 free(ns); 529 } 530 531 /* XXX Why are these static ? */ 532 /* static XDR in_xdrs, out_xdrs; */ 533 534 535 /* 536 * __clone_object_r() 537 * This function takes a pointer to a NIS object and clones it. This 538 * duplicate object is now available for use in the local context. 539 */ 540 nis_object * 541 nis_clone_object_r( 542 nis_object *obj, /* The object to clone */ 543 nis_object *dest, /* Use this pointer if non-null */ 544 struct nis_sdata *clone_buf_ptr) 545 { 546 nis_object *result; /* The clone itself */ 547 int status; /* a counter variable */ 548 XDR in_xdrs, out_xdrs; 549 550 if (!nis_get_static_storage(clone_buf_ptr, 1, 551 xdr_sizeof(xdr_nis_object, obj))) 552 return (NULL); 553 554 (void) memset(&in_xdrs, 0, sizeof (in_xdrs)); 555 (void) memset(&out_xdrs, 0, sizeof (out_xdrs)); 556 xdrmem_create(&in_xdrs, clone_buf_ptr->buf, clone_buf_ptr->size, 557 XDR_ENCODE); 558 xdrmem_create(&out_xdrs, clone_buf_ptr->buf, clone_buf_ptr->size, 559 XDR_DECODE); 560 561 /* Allocate a basic NIS object structure */ 562 if (dest) { 563 (void) memset(dest, 0, sizeof (nis_object)); 564 result = dest; 565 } else 566 result = calloc(1, sizeof (nis_object)); 567 568 if (result == NULL) 569 return (NULL); 570 571 /* Encode our object into the clone buffer */ 572 (void) xdr_setpos(&in_xdrs, 0); 573 status = xdr_nis_object(&in_xdrs, obj); 574 if (status == FALSE) 575 return (NULL); 576 577 /* Now decode the buffer into our result pointer ... */ 578 (void) xdr_setpos(&out_xdrs, 0); 579 status = xdr_nis_object(&out_xdrs, result); 580 if (status == FALSE) 581 return (NULL); 582 583 /* presto changeo, a new object */ 584 return (result); 585 } /* __clone_object_r */ 586 587 588 nis_object * 589 nis_clone_object( 590 nis_object *obj, /* The object to clone */ 591 nis_object *dest) /* Use this pointer if non-null */ 592 { 593 static pthread_key_t clone_buf_key = PTHREAD_ONCE_KEY_NP; 594 static struct nis_sdata clone_buf_main; 595 struct nis_sdata *clone_buf_ptr; 596 597 clone_buf_ptr = thr_main()? &clone_buf_main : 598 thr_get_storage(&clone_buf_key, sizeof (struct nis_sdata), 599 destroy_nis_sdata); 600 return (nis_clone_object_r(obj, dest, clone_buf_ptr)); 601 } /* __clone_object */ 602 603 /* Various subroutines used by the server code */ 604 nis_object * 605 nis_read_obj(char *f) /* name of the object to read */ 606 { 607 FILE *rootfile; 608 int status; /* Status of the XDR decoding */ 609 XDR xdrs; /* An xdr stream handle */ 610 nis_object *res; 611 612 res = calloc(1, sizeof (nis_object)); 613 if (!res) 614 return (NULL); 615 616 rootfile = fopen(f, "rF"); 617 if (rootfile == NULL) { 618 /* This is ok if we are the root of roots. */ 619 free(res); 620 return (NULL); 621 } 622 /* Now read in the object */ 623 xdrstdio_create(&xdrs, rootfile, XDR_DECODE); 624 status = xdr_nis_object(&xdrs, res); 625 xdr_destroy(&xdrs); 626 (void) fclose(rootfile); 627 if (!status) { 628 syslog(LOG_ERR, "Object file %s is corrupt!", f); 629 xdr_free(xdr_nis_object, (char *)res); 630 free(res); 631 return (NULL); 632 } 633 return (res); 634 } 635 636 int 637 nis_write_obj( 638 char *f, /* name of the object to read */ 639 nis_object *o) /* The object to write */ 640 { 641 FILE *rootfile; 642 int status; /* Status of the XDR decoding */ 643 XDR xdrs; /* An xdr stream handle */ 644 645 rootfile = fopen(f, "wF"); 646 if (rootfile == NULL) { 647 return (0); 648 } 649 /* Now encode the object */ 650 xdrstdio_create(&xdrs, rootfile, XDR_ENCODE); 651 status = xdr_nis_object(&xdrs, o); 652 xdr_destroy(&xdrs); 653 (void) fclose(rootfile); 654 return (status); 655 } 656 657 /* 658 * Transport INDEPENDENT RPC code. This code assumes you 659 * are using the new RPC/tli code and will build 660 * a ping handle on top of a datagram transport. 661 */ 662 663 /* 664 * __map_addr() 665 * 666 * This is our internal function that replaces rpcb_getaddr(). We 667 * build our own to prevent calling netdir_getbyname() which could 668 * recurse to the nameservice. 669 */ 670 static char * 671 __map_addr( 672 struct netconfig *nc, /* Our transport */ 673 char *uaddr, /* RPCBIND address */ 674 rpcprog_t prog, /* Name service Prog */ 675 rpcvers_t ver) 676 { 677 CLIENT *client; 678 RPCB parms; /* Parameters for RPC binder */ 679 enum clnt_stat clnt_st; /* Result from the rpc call */ 680 char *ua = NULL; /* Universal address of service */ 681 char *res = NULL; /* Our result to the parent */ 682 struct timeval tv; /* Timeout for our rpcb call */ 683 int ilen, olen; /* buffer length for clnt_tli_create */ 684 685 /* 686 * If using "udp", use __nisipbufsize if inbuf and outbuf are set to 0. 687 */ 688 if (strcmp(NC_UDP, nc->nc_proto) == 0) { 689 /* for udp only */ 690 ilen = olen = __nisipbufsize; 691 } else { 692 ilen = olen = 0; 693 } 694 client = __nis_clnt_create(RPC_ANYFD, nc, uaddr, 0, 0, 695 RPCBPROG, RPCBVERS, ilen, olen); 696 if (!client) 697 return (NULL); 698 699 (void) clnt_control(client, CLSET_FD_CLOSE, NULL); 700 701 /* 702 * Now make the call to get the NIS service address. 703 * We set the retry timeout to 3 seconds so that we 704 * will retry a few times. Retries should be rare 705 * because we are usually only called when we know 706 * a server is available. 707 */ 708 tv.tv_sec = 3; 709 tv.tv_usec = 0; 710 (void) clnt_control(client, CLSET_RETRY_TIMEOUT, (char *)&tv); 711 712 tv.tv_sec = 10; 713 tv.tv_usec = 0; 714 parms.r_prog = prog; 715 parms.r_vers = ver; 716 parms.r_netid = nc->nc_netid; /* not needed */ 717 parms.r_addr = ""; /* not needed; just for xdring */ 718 parms.r_owner = ""; /* not needed; just for xdring */ 719 clnt_st = clnt_call(client, RPCBPROC_GETADDR, xdr_rpcb, (char *)&parms, 720 xdr_wrapstring, (char *)&ua, tv); 721 722 if (clnt_st == RPC_SUCCESS) { 723 clnt_destroy(client); 724 if (*ua == '\0') { 725 free(ua); 726 return (NULL); 727 } 728 res = strdup(ua); 729 xdr_free(xdr_wrapstring, (char *)&ua); 730 return (res); 731 } else if (((clnt_st == RPC_PROGVERSMISMATCH) || 732 (clnt_st == RPC_PROGUNAVAIL)) && 733 (strcmp(nc->nc_protofmly, NC_INET) == 0)) { 734 /* 735 * version 3 not available. Try version 2 736 * The assumption here is that the netbuf 737 * is arranged in the sockaddr_in 738 * style for IP cases. 739 * 740 * Note: If the remote host doesn't support version 3, 741 * we assume it doesn't know IPv6 either. 742 */ 743 ushort_t port; 744 struct sockaddr_in *sa; 745 struct netbuf remote; 746 int protocol; 747 char buf[32]; 748 749 (void) clnt_control(client, CLGET_SVC_ADDR, (char *)&remote); 750 /* LINTED pointer cast */ 751 sa = (struct sockaddr_in *)(remote.buf); 752 protocol = strcmp(nc->nc_proto, NC_TCP) ? 753 IPPROTO_UDP : IPPROTO_TCP; 754 port = (ushort_t)pmap_getport(sa, prog, ver, protocol); 755 756 if (port != 0) { 757 port = htons(port); 758 (void) sprintf(buf, "%d.%d.%d.%d.%d.%d", 759 (sa->sin_addr.s_addr >> 24) & 0xff, 760 (sa->sin_addr.s_addr >> 16) & 0xff, 761 (sa->sin_addr.s_addr >> 8) & 0xff, 762 (sa->sin_addr.s_addr) & 0xff, 763 (port >> 8) & 0xff, 764 port & 0xff); 765 res = strdup(buf); 766 } else 767 res = NULL; 768 clnt_destroy(client); 769 return (res); 770 } 771 if (clnt_st == RPC_TIMEDOUT) 772 syslog(LOG_ERR, "NIS+ server not responding"); 773 else 774 syslog(LOG_ERR, "NIS+ server could not be contacted: %s", 775 clnt_sperrno(clnt_st)); 776 clnt_destroy(client); 777 return (NULL); 778 } 779 780 781 #define MAX_EP (20) 782 783 extern int __can_use_af(sa_family_t af); 784 785 CLIENT * 786 __nis_clnt_create(int fd, struct netconfig *nc, char *uaddr, 787 struct netbuf *addr, int domapaddr, 788 int prog, int ver, int inbuf, int outbuf) { 789 790 char *svc_addr; 791 CLIENT *clnt; 792 int freeaddr = 0; 793 794 /* Sanity check */ 795 if (nc == 0 || (addr == 0 && uaddr == 0)) { 796 return (0); 797 } 798 799 /* 800 * Check if we have a useable interface for this address family. 801 * This check properly belongs in RPC (or even further down), 802 * but until they provide it, we roll our own. 803 */ 804 if (__can_use_af((strcmp(nc->nc_protofmly, NC_INET6) == 0) ? 805 AF_INET6 : AF_INET) == 0) { 806 return (0); 807 } 808 809 if (domapaddr) { 810 svc_addr = __map_addr(nc, uaddr, prog, ver); 811 if (svc_addr == 0) 812 return (0); 813 addr = uaddr2taddr(nc, svc_addr); 814 freeaddr = 1; 815 free(svc_addr); 816 } else if (addr == 0) { 817 addr = uaddr2taddr(nc, uaddr); 818 freeaddr = 1; 819 } 820 821 if (addr == 0) { 822 return (0); 823 } 824 825 clnt = clnt_tli_create(fd, nc, addr, prog, ver, outbuf, inbuf); 826 827 if (clnt) { 828 if (clnt_control(clnt, CLGET_FD, (char *)&fd)) 829 /* make it "close on exec" */ 830 (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 831 (void) clnt_control(clnt, CLSET_FD_CLOSE, NULL); 832 } 833 834 if (freeaddr) 835 netdir_free(addr, ND_ADDR); 836 837 return (clnt); 838 } 839 840 static mutex_t __nis_ss_used_lock = DEFAULTMUTEX; /* lock level 3 */ 841 int __nis_ss_used = 0; 842 843 /* 844 * nis_get_static_storage() 845 * 846 * This function is used by various functions in their effort to minimize the 847 * hassles of memory management in an RPC daemon. Because the service doesn't 848 * implement any hard limits, this function allows people to get automatically 849 * growing buffers that meet their storage requirements. It returns the 850 * pointer in the nis_sdata structure. 851 * 852 */ 853 void * 854 nis_get_static_storage( 855 struct nis_sdata *bs, /* User buffer structure */ 856 uint_t el, /* Sizeof elements */ 857 uint_t nel) /* Number of elements */ 858 { 859 uint_t sz; 860 861 sz = nel * el; 862 if (!bs) 863 return (NULL); 864 865 if (!bs->buf) { 866 bs->buf = malloc(sz); 867 if (!bs->buf) 868 return (NULL); 869 bs->size = sz; 870 sig_mutex_lock(&__nis_ss_used_lock); 871 __nis_ss_used += sz; 872 sig_mutex_unlock(&__nis_ss_used_lock); 873 } else if (bs->size < sz) { 874 int size_delta; 875 876 free(bs->buf); 877 size_delta = - (bs->size); 878 bs->buf = malloc(sz); 879 880 /* check the result of malloc() first */ 881 /* then update the statistic. */ 882 if (!bs->buf) 883 return (NULL); 884 bs->size = sz; 885 size_delta += sz; 886 sig_mutex_lock(&__nis_ss_used_lock); 887 __nis_ss_used += size_delta; 888 sig_mutex_unlock(&__nis_ss_used_lock); 889 } 890 891 (void) memset(bs->buf, 0, sz); /* SYSV version of bzero() */ 892 return (bs->buf); 893 } 894