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
nis_dir_cmp(nis_name n1,nis_name n2)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 *
__get_local_names(void)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 *
__get_local_names1(void)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
nis_local_group(void)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
__nis_nextsep_of(char * s)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
nis_domain_of(char * s)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
nis_leaf_of_r(const nis_name s,char * buf,size_t bufsize)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
nis_leaf_of(char * s)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
nis_name_of_r(char * s,char * buf,size_t bufsize)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
nis_name_of(char * s)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
nis_local_directory(void)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
__nis_rpc_domain()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
nis_local_host(void)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
nis_destroy_object(nis_object * obj)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
destroy_nis_sdata(void * p)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 *
nis_clone_object_r(nis_object * obj,nis_object * dest,struct nis_sdata * clone_buf_ptr)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 *
nis_clone_object(nis_object * obj,nis_object * dest)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 *
nis_read_obj(char * f)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
nis_write_obj(char * f,nis_object * o)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 *
__map_addr(struct netconfig * nc,char * uaddr,rpcprog_t prog,rpcvers_t ver)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 *
__nis_clnt_create(int fd,struct netconfig * nc,char * uaddr,struct netbuf * addr,int domapaddr,int prog,int ver,int inbuf,int outbuf)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 *
nis_get_static_storage(struct nis_sdata * bs,uint_t el,uint_t nel)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