import less(1)
[unleashed/tickless.git] / usr / src / lib / libc / port / nsl / nis_subr.c
blobe4dae21cbc9209d4770a8de7200d51f20f9260e8
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
29 * This module contains the subroutines used by the server to manipulate
30 * objects and names.
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>
57 #define MAXIPRINT (11) /* max length of printed integer */
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.
65 int __nisipbufsize = 8192;
69 * Static function prototypes.
71 static struct local_names *__get_local_names(void);
72 static char *__map_addr(struct netconfig *, char *, rpcprog_t, rpcvers_t);
75 * nis_dir_cmp() -- the results can be read as:
76 * "Name 'n1' is a $result than name 'n2'"
78 name_pos
79 nis_dir_cmp(
80 nis_name n1,
81 nis_name n2) /* See if these are the same domain */
83 size_t l1, l2;
84 name_pos result;
86 if ((n1 == NULL) || (n2 == NULL))
87 return (BAD_NAME);
89 l1 = strlen(n1);
90 l2 = strlen(n2);
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;
99 if (l2 != 0 && n2[l2 - 1] == '.') {
100 --l2;
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;
113 result = HIGHER_NAME;
116 /* Now l1 >= l2 in all cases */
117 if (l2 == 0) {
118 /* Special case for n2 == "." or "" */
119 return (result);
121 if (l1 > l2) {
122 n1 += l1 - l2;
123 if (n1[-1] != '.') {
124 return (NOT_SEQUENTIAL);
127 if (strncasecmp(n1, n2, l2) == 0) {
128 return (result);
130 return (NOT_SEQUENTIAL);
133 #define LN_BUFSIZE (size_t)1024
135 struct principal_list {
136 uid_t uid;
137 char principal[LN_BUFSIZE];
138 struct principal_list *next;
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];
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();
154 static struct local_names *
155 __get_local_names(void)
157 struct local_names *names;
159 sig_mutex_lock(&ln_lock);
160 names = __get_local_names1();
161 sig_mutex_unlock(&ln_lock);
162 return (names);
166 static struct local_names *
167 __get_local_names1(void)
169 char *t;
171 if (ln != NULL) {
172 /* Second and subsequent calls go this way */
173 return (ln);
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);
181 ln->principal_map = NULL;
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);
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.
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);
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 */
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".
217 (void) strncpy(ln->group, t, maxlen);
218 if (strcmp(ln->group, "") == 0) {
219 return (ln);
221 ln->group[maxlen] = '\0';
223 /* Is the group name somewhat fully-qualified? */
224 temp = strrchr(ln->group, '.');
226 /* If not, we need to add ".domain" to the group */
227 if ((temp == NULL) || (temp[1] != '\0')) {
229 /* truncate to make room for ".domain" */
230 ln->group[maxlen - (strlen(ln->domain)+1)] = '\0';
232 /* concat '.' if domain doesn't already have it */
233 if (ln->domain[0] != '.') {
234 (void) strcat(ln->group, ".");
236 (void) strcat(ln->group, ln->domain);
239 return (ln);
243 * nis_local_group()
245 * Return's the group name of the current user.
247 nis_name
248 nis_local_group(void)
250 struct local_names *ln = __get_local_names();
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);
261 * __nis_nextsep_of()
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.
271 nis_name
272 __nis_nextsep_of(char *s)
274 char *d;
275 int in_quotes = FALSE, quote_quote = FALSE;
277 if (!s)
278 return (NULL);
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;
301 if (quote_quote || in_quotes) {
302 syslog(LOG_DEBUG, "__nis_nextsep_of: "
303 "Mismatched quotes in %s", s);
306 return (d);
310 * nis_domain_of()
312 * This internal funtion will accept a pointer to a NIS name string and
313 * return a pointer to the "domain" part of it.
315 * ==== We don't need nis_domain_of_r(), but should we provide one for
316 * uniformity?
318 nis_name
319 nis_domain_of(char *s)
321 char *d;
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);
335 * nis_leaf_of()
337 * Returns the first label of a name. (other half of __domain_of)
339 nis_name
340 nis_leaf_of_r(
341 const nis_name s,
342 char *buf,
343 size_t bufsize)
345 size_t nchars;
346 const char *d = __nis_nextsep_of((char *)s);
348 if (d == 0) {
349 return (0);
351 nchars = d - s;
352 if (bufsize < nchars + 1) {
353 return (0);
355 (void) strncpy(buf, s, nchars);
356 buf[nchars] = '\0';
357 return (buf);
360 static pthread_key_t buf_key = PTHREAD_ONCE_KEY_NP;
361 static char buf_main[LN_BUFSIZE];
363 nis_name
364 nis_leaf_of(char *s)
366 char *buf = thr_main()? buf_main :
367 thr_get_storage(&buf_key, LN_BUFSIZE, free);
369 if (buf == NULL)
370 return (NULL);
371 return (nis_leaf_of_r(s, buf, LN_BUFSIZE));
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
384 nis_name
385 nis_name_of_r(
386 char *s, /* string with the name in it. */
387 char *buf,
388 size_t bufsize)
390 char *d;
391 struct local_names *ln = __get_local_names();
392 size_t dl, sl;
393 name_pos p;
395 if ((!s) || (!ln))
396 return (NULL); /* No string, this can't continue */
398 d = &(ln->domain[0]);
399 dl = strlen(ln->domain); /* _always dot terminated_ */
401 sl = strlen(s);
402 if (sl >= bufsize || (s[sl-1] != '.' && sl >= bufsize-1))
403 return (NULL);
404 (void) strcpy(buf, s); /* Make a private copy of 's' */
405 if (buf[sl-1] != '.') { /* Add a dot if necessary. */
406 (void) strcat(buf, ".");
407 sl++;
410 if (dl == 1) { /* We're the '.' directory */
411 buf[sl-1] = '\0'; /* Lose the 'dot' */
412 return (buf);
415 p = nis_dir_cmp(buf, d);
417 /* 's' is above 'd' in the tree */
418 if ((p == HIGHER_NAME) || (p == NOT_SEQUENTIAL) || (p == SAME_NAME))
419 return (NULL);
421 /* Insert a NUL where the domain name starts in the string */
422 buf[(sl - dl) - 1] = '\0';
424 /* Don't return a zero length name */
425 if (buf[0] == '\0')
426 return (NULL);
428 return (buf);
431 nis_name
432 nis_name_of(
433 char *s) /* string with the name in it. */
435 char *buf = thr_main()? buf_main :
436 thr_get_storage(&buf_key, LN_BUFSIZE, free);
438 if (!buf)
439 return (NULL);
440 return (nis_name_of_r(s, buf, LN_BUFSIZE));
446 * nis_local_directory()
448 * Return a pointer to a string with the local directory name in it.
450 nis_name
451 nis_local_directory(void)
453 struct local_names *ln = __get_local_names();
455 /* LOCK NOTE: Warning, after initialization, "ln" is expected */
456 /* to stay constant, So no need to lock here. If this assumption */
457 /* is changed, this code must be protected. */
458 if (ln == NULL)
459 return (NULL);
460 return (ln->domain);
464 * __nis_rpc_domain()
466 * Return a pointer to a string with the rpc domain name in it.
468 nis_name
469 __nis_rpc_domain()
471 struct local_names *ln = __get_local_names();
473 /* LOCK NOTE: Warning, after initialization, "ln" is expected */
474 /* to stay constant, So no need to lock here. If this assumption */
475 /* is changed, this code must be protected. */
476 if (ln == NULL)
477 return (NULL);
478 return (ln->rpcdomain);
483 * nis_local_host()
484 * Generate the principal name for this host, "hostname"+"domainname"
485 * unless the hostname already has "dots" in its name.
487 nis_name
488 nis_local_host(void)
490 struct local_names *ln = __get_local_names();
492 /* LOCK NOTE: Warning, after initialization, "ln" is expected */
493 /* to stay constant, So no need to lock here. If this assumption */
494 /* is changed, this code must be protected. */
495 if (ln == NULL)
496 return (NULL);
498 return (ln->host);
502 * nis_destroy_object()
503 * This function takes a pointer to a NIS object and deallocates it. This
504 * is the inverse of __clone_object below. It must be able to correctly
505 * deallocate partially allocated objects because __clone_object will call
506 * it if it runs out of memory and has to abort. Everything is freed,
507 * INCLUDING the pointer that is passed.
509 void
510 nis_destroy_object(nis_object *obj) /* The object to clone */
512 if (obj == 0)
513 return;
514 xdr_free(xdr_nis_object, (char *)obj);
515 free(obj);
516 } /* nis_destroy_object */
518 static void
519 destroy_nis_sdata(void *p)
521 struct nis_sdata *ns = p;
523 if (ns->buf != 0)
524 free(ns->buf);
525 free(ns);
528 /* XXX Why are these static ? */
529 /* static XDR in_xdrs, out_xdrs; */
533 * __clone_object_r()
534 * This function takes a pointer to a NIS object and clones it. This
535 * duplicate object is now available for use in the local context.
537 nis_object *
538 nis_clone_object_r(
539 nis_object *obj, /* The object to clone */
540 nis_object *dest, /* Use this pointer if non-null */
541 struct nis_sdata *clone_buf_ptr)
543 nis_object *result; /* The clone itself */
544 int status; /* a counter variable */
545 XDR in_xdrs, out_xdrs;
547 if (!nis_get_static_storage(clone_buf_ptr, 1,
548 xdr_sizeof(xdr_nis_object, obj)))
549 return (NULL);
551 (void) memset(&in_xdrs, 0, sizeof (in_xdrs));
552 (void) memset(&out_xdrs, 0, sizeof (out_xdrs));
553 xdrmem_create(&in_xdrs, clone_buf_ptr->buf, clone_buf_ptr->size,
554 XDR_ENCODE);
555 xdrmem_create(&out_xdrs, clone_buf_ptr->buf, clone_buf_ptr->size,
556 XDR_DECODE);
558 /* Allocate a basic NIS object structure */
559 if (dest) {
560 (void) memset(dest, 0, sizeof (nis_object));
561 result = dest;
562 } else
563 result = calloc(1, sizeof (nis_object));
565 if (result == NULL)
566 return (NULL);
568 /* Encode our object into the clone buffer */
569 (void) xdr_setpos(&in_xdrs, 0);
570 status = xdr_nis_object(&in_xdrs, obj);
571 if (status == FALSE)
572 return (NULL);
574 /* Now decode the buffer into our result pointer ... */
575 (void) xdr_setpos(&out_xdrs, 0);
576 status = xdr_nis_object(&out_xdrs, result);
577 if (status == FALSE)
578 return (NULL);
580 /* presto changeo, a new object */
581 return (result);
582 } /* __clone_object_r */
585 nis_object *
586 nis_clone_object(
587 nis_object *obj, /* The object to clone */
588 nis_object *dest) /* Use this pointer if non-null */
590 static pthread_key_t clone_buf_key = PTHREAD_ONCE_KEY_NP;
591 static struct nis_sdata clone_buf_main;
592 struct nis_sdata *clone_buf_ptr;
594 clone_buf_ptr = thr_main()? &clone_buf_main :
595 thr_get_storage(&clone_buf_key, sizeof (struct nis_sdata),
596 destroy_nis_sdata);
597 return (nis_clone_object_r(obj, dest, clone_buf_ptr));
598 } /* __clone_object */
600 /* Various subroutines used by the server code */
601 nis_object *
602 nis_read_obj(char *f) /* name of the object to read */
604 FILE *rootfile;
605 int status; /* Status of the XDR decoding */
606 XDR xdrs; /* An xdr stream handle */
607 nis_object *res;
609 res = calloc(1, sizeof (nis_object));
610 if (!res)
611 return (NULL);
613 rootfile = fopen(f, "rF");
614 if (rootfile == NULL) {
615 /* This is ok if we are the root of roots. */
616 free(res);
617 return (NULL);
619 /* Now read in the object */
620 xdrstdio_create(&xdrs, rootfile, XDR_DECODE);
621 status = xdr_nis_object(&xdrs, res);
622 xdr_destroy(&xdrs);
623 (void) fclose(rootfile);
624 if (!status) {
625 syslog(LOG_ERR, "Object file %s is corrupt!", f);
626 xdr_free(xdr_nis_object, (char *)res);
627 free(res);
628 return (NULL);
630 return (res);
634 nis_write_obj(
635 char *f, /* name of the object to read */
636 nis_object *o) /* The object to write */
638 FILE *rootfile;
639 int status; /* Status of the XDR decoding */
640 XDR xdrs; /* An xdr stream handle */
642 rootfile = fopen(f, "wF");
643 if (rootfile == NULL) {
644 return (0);
646 /* Now encode the object */
647 xdrstdio_create(&xdrs, rootfile, XDR_ENCODE);
648 status = xdr_nis_object(&xdrs, o);
649 xdr_destroy(&xdrs);
650 (void) fclose(rootfile);
651 return (status);
655 * Transport INDEPENDENT RPC code. This code assumes you
656 * are using the new RPC/tli code and will build
657 * a ping handle on top of a datagram transport.
661 * __map_addr()
663 * This is our internal function that replaces rpcb_getaddr(). We
664 * build our own to prevent calling netdir_getbyname() which could
665 * recurse to the nameservice.
667 static char *
668 __map_addr(
669 struct netconfig *nc, /* Our transport */
670 char *uaddr, /* RPCBIND address */
671 rpcprog_t prog, /* Name service Prog */
672 rpcvers_t ver)
674 CLIENT *client;
675 RPCB parms; /* Parameters for RPC binder */
676 enum clnt_stat clnt_st; /* Result from the rpc call */
677 char *ua = NULL; /* Universal address of service */
678 char *res = NULL; /* Our result to the parent */
679 struct timeval tv; /* Timeout for our rpcb call */
680 int ilen, olen; /* buffer length for clnt_tli_create */
683 * If using "udp", use __nisipbufsize if inbuf and outbuf are set to 0.
685 if (strcmp(NC_UDP, nc->nc_proto) == 0) {
686 /* for udp only */
687 ilen = olen = __nisipbufsize;
688 } else {
689 ilen = olen = 0;
691 client = __nis_clnt_create(RPC_ANYFD, nc, uaddr, 0, 0,
692 RPCBPROG, RPCBVERS, ilen, olen);
693 if (!client)
694 return (NULL);
696 (void) clnt_control(client, CLSET_FD_CLOSE, NULL);
699 * Now make the call to get the NIS service address.
700 * We set the retry timeout to 3 seconds so that we
701 * will retry a few times. Retries should be rare
702 * because we are usually only called when we know
703 * a server is available.
705 tv.tv_sec = 3;
706 tv.tv_usec = 0;
707 (void) clnt_control(client, CLSET_RETRY_TIMEOUT, (char *)&tv);
709 tv.tv_sec = 10;
710 tv.tv_usec = 0;
711 parms.r_prog = prog;
712 parms.r_vers = ver;
713 parms.r_netid = nc->nc_netid; /* not needed */
714 parms.r_addr = ""; /* not needed; just for xdring */
715 parms.r_owner = ""; /* not needed; just for xdring */
716 clnt_st = clnt_call(client, RPCBPROC_GETADDR, xdr_rpcb, (char *)&parms,
717 xdr_wrapstring, (char *)&ua, tv);
719 if (clnt_st == RPC_SUCCESS) {
720 clnt_destroy(client);
721 if (*ua == '\0') {
722 free(ua);
723 return (NULL);
725 res = strdup(ua);
726 xdr_free(xdr_wrapstring, (char *)&ua);
727 return (res);
728 } else if (((clnt_st == RPC_PROGVERSMISMATCH) ||
729 (clnt_st == RPC_PROGUNAVAIL)) &&
730 (strcmp(nc->nc_protofmly, NC_INET) == 0)) {
732 * version 3 not available. Try version 2
733 * The assumption here is that the netbuf
734 * is arranged in the sockaddr_in
735 * style for IP cases.
737 * Note: If the remote host doesn't support version 3,
738 * we assume it doesn't know IPv6 either.
740 ushort_t port;
741 struct sockaddr_in *sa;
742 struct netbuf remote;
743 int protocol;
744 char buf[32];
746 (void) clnt_control(client, CLGET_SVC_ADDR, (char *)&remote);
747 /* LINTED pointer cast */
748 sa = (struct sockaddr_in *)(remote.buf);
749 protocol = strcmp(nc->nc_proto, NC_TCP) ?
750 IPPROTO_UDP : IPPROTO_TCP;
751 port = (ushort_t)pmap_getport(sa, prog, ver, protocol);
753 if (port != 0) {
754 port = htons(port);
755 (void) sprintf(buf, "%d.%d.%d.%d.%d.%d",
756 (sa->sin_addr.s_addr >> 24) & 0xff,
757 (sa->sin_addr.s_addr >> 16) & 0xff,
758 (sa->sin_addr.s_addr >> 8) & 0xff,
759 (sa->sin_addr.s_addr) & 0xff,
760 (port >> 8) & 0xff,
761 port & 0xff);
762 res = strdup(buf);
763 } else
764 res = NULL;
765 clnt_destroy(client);
766 return (res);
768 if (clnt_st == RPC_TIMEDOUT)
769 syslog(LOG_ERR, "NIS+ server not responding");
770 else
771 syslog(LOG_ERR, "NIS+ server could not be contacted: %s",
772 clnt_sperrno(clnt_st));
773 clnt_destroy(client);
774 return (NULL);
778 #define MAX_EP (20)
780 extern int __can_use_af(sa_family_t af);
782 CLIENT *
783 __nis_clnt_create(int fd, struct netconfig *nc, char *uaddr,
784 struct netbuf *addr, int domapaddr,
785 int prog, int ver, int inbuf, int outbuf) {
787 char *svc_addr;
788 CLIENT *clnt;
789 int freeaddr = 0;
791 /* Sanity check */
792 if (nc == 0 || (addr == 0 && uaddr == 0)) {
793 return (0);
797 * Check if we have a useable interface for this address family.
798 * This check properly belongs in RPC (or even further down),
799 * but until they provide it, we roll our own.
801 if (__can_use_af((strcmp(nc->nc_protofmly, NC_INET6) == 0) ?
802 AF_INET6 : AF_INET) == 0) {
803 return (0);
806 if (domapaddr) {
807 svc_addr = __map_addr(nc, uaddr, prog, ver);
808 if (svc_addr == 0)
809 return (0);
810 addr = uaddr2taddr(nc, svc_addr);
811 freeaddr = 1;
812 free(svc_addr);
813 } else if (addr == 0) {
814 addr = uaddr2taddr(nc, uaddr);
815 freeaddr = 1;
818 if (addr == 0) {
819 return (0);
822 clnt = clnt_tli_create(fd, nc, addr, prog, ver, outbuf, inbuf);
824 if (clnt) {
825 if (clnt_control(clnt, CLGET_FD, (char *)&fd))
826 /* make it "close on exec" */
827 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
828 (void) clnt_control(clnt, CLSET_FD_CLOSE, NULL);
831 if (freeaddr)
832 netdir_free(addr, ND_ADDR);
834 return (clnt);
837 static mutex_t __nis_ss_used_lock = DEFAULTMUTEX; /* lock level 3 */
838 int __nis_ss_used = 0;
841 * nis_get_static_storage()
843 * This function is used by various functions in their effort to minimize the
844 * hassles of memory management in an RPC daemon. Because the service doesn't
845 * implement any hard limits, this function allows people to get automatically
846 * growing buffers that meet their storage requirements. It returns the
847 * pointer in the nis_sdata structure.
850 void *
851 nis_get_static_storage(
852 struct nis_sdata *bs, /* User buffer structure */
853 uint_t el, /* Sizeof elements */
854 uint_t nel) /* Number of elements */
856 uint_t sz;
858 sz = nel * el;
859 if (!bs)
860 return (NULL);
862 if (!bs->buf) {
863 bs->buf = malloc(sz);
864 if (!bs->buf)
865 return (NULL);
866 bs->size = sz;
867 sig_mutex_lock(&__nis_ss_used_lock);
868 __nis_ss_used += sz;
869 sig_mutex_unlock(&__nis_ss_used_lock);
870 } else if (bs->size < sz) {
871 int size_delta;
873 free(bs->buf);
874 size_delta = - (bs->size);
875 bs->buf = malloc(sz);
877 /* check the result of malloc() first */
878 /* then update the statistic. */
879 if (!bs->buf)
880 return (NULL);
881 bs->size = sz;
882 size_delta += sz;
883 sig_mutex_lock(&__nis_ss_used_lock);
884 __nis_ss_used += size_delta;
885 sig_mutex_unlock(&__nis_ss_used_lock);
888 (void) memset(bs->buf, 0, sz); /* SYSV version of bzero() */
889 return (bs->buf);