xref: /illumos-gate/usr/src/lib/libc/port/gen/getxby_door.c (revision 1da57d551424de5a9d469760be7c4b4d4f10a755)
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 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include "lint.h"
28 #include <mtlib.h>
29 #include <sys/types.h>
30 #include <errno.h>
31 #include <pwd.h>
32 #include <nss_dbdefs.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <synch.h>
36 #include <sys/param.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <stdlib.h>
40 #include <getxby_door.h>
41 #include <sys/door.h>
42 #include <procfs.h>
43 #include <door.h>
44 #include <sys/mman.h>
45 #include "libc.h"
46 #include "tsd.h"
47 #include "base_conversion.h"
48 
49 /* nss<->door hints */
50 static mutex_t	hints_lock = DEFAULTMUTEX;
51 static size_t	door_bsize = 0;
52 static size_t	door_nbsize = 0;
53 static int	proc_is_cache = -1;
54 
55 /* library<->nscd door interaction apis */
56 
57 /*
58  *
59  * Routine that actually performs the door call.
60  * Note that we cache a file descriptor.  We do
61  * the following to prevent disasters:
62  *
63  * 1) Never use 0,1 or 2; if we get this from the open
64  *    we dup it upwards.
65  *
66  * 2) Set the close on exec flags so descriptor remains available
67  *    to child processes.
68  *
69  * 3) Verify that the door is still the same one we had before
70  *    by using door_info on the client side.
71  *
72  *	Note that we never close the file descriptor if it isn't one
73  *	we allocated; we check this with door info.  The rather tricky
74  *	logic is designed to be fast in the normal case (fd is already
75  *	allocated and is ok) while handling the case where the application
76  *	closed it underneath us or where the nscd dies or re-execs itself
77  *	and we're a multi-threaded application.  Note that we cannot protect
78  *	the application if it closes the fd and it is multi-threaded.
79  *
80  *  int _nsc_trydoorcall(void *dptr, size_t *bufsize, size_t *actualsize);
81  *
82  *      *dptr           IN: points to arg buffer OUT: points to results buffer
83  *      *bufsize        IN: overall size of buffer OUT: overall size of buffer
84  *      *actualsize     IN: size of call data OUT: size of return data
85  *
86  *  Note that *dptr may change if provided space as defined by *bufsize is
87  *  inadequate.  In this case the door call mmaps more space and places
88  *  the answer there and sets dptr to contain a pointer to the space, which
89  *  should be freed with munmap.
90  *
91  *  Returns 0 if the door call reached the server, -1 if contact was not made.
92  *
93  */
94 
95 /*
96  * Max size for list of db names supported by the private nscd
97  * No implied max here, any size will do, fixed size chosen to
98  * reduce yet another malloc
99  */
100 
101 #define	BD_BUFSIZE	1024
102 #define	BD_SEP		','
103 
104 typedef struct _nsc_door_t {
105 	int 		doorfd;
106 	mutex_t		door_lock;
107 	door_info_t 	doori;
108 } nsc_door_t;
109 
110 static nsc_door_t	nsc_door[2] = {
111 	{ -1, DEFAULTMUTEX, { 0 } },		/* front (fattached) door */
112 	{ -1, DEFAULTMUTEX, { 0 } },		/* back (private) door */
113 };
114 
115 /* assumed to be locked by using nsc_door[1] mutex */
116 static char	*nsc_db_buf = NULL;
117 static char	**nsc_db_list = NULL;
118 
119 /*
120  * Check for a valid and matching db in the list.
121  * assume list is in the locked state.
122  */
123 
124 static int
_nsc_use_backdoor(char * db)125 _nsc_use_backdoor(char *db)
126 {
127 	char 	**ndb;
128 
129 	if (db && nsc_db_buf != NULL && nsc_db_list != NULL) {
130 		for (ndb = nsc_db_list; *ndb; ndb++) {
131 			if (strcmp(db, *ndb) == 0)
132 				return (1);
133 		}
134 	}
135 	return (0);
136 }
137 
138 /*
139  * flush private db lists
140  */
141 static void
_nsc_flush_private_db()142 _nsc_flush_private_db()
143 {
144 	if (nsc_db_buf != NULL) {
145 		libc_free((void *)nsc_db_buf);
146 		nsc_db_buf = NULL;
147 	}
148 	if (nsc_db_list != NULL) {
149 		libc_free((void *)nsc_db_list);
150 		nsc_db_list = NULL;
151 	}
152 }
153 
154 /*
155  * init/update nsc_db_buf given buff containing list of
156  * db's to be processed by a private nscd.
157  * This function assumes it has a well formed string from nscd.
158  */
159 
160 static int
_nsc_init_private_db(char * dblist)161 _nsc_init_private_db(char *dblist)
162 {
163 	char	*cp, **lp;
164 	int	buflen = 0;
165 	int	arrlen = 0;
166 
167 	if (dblist == NULL)
168 		return (0);
169 
170 	/* reset db list */
171 	_nsc_flush_private_db();
172 
173 	/* rebuild fresh list */
174 	buflen = strlen(dblist) + 1;
175 	for (cp = dblist; *cp; cp++)
176 		if (*cp == BD_SEP)
177 			arrlen++;
178 	if (cp == dblist)
179 		return (0);
180 	arrlen += 2;
181 	nsc_db_buf = (char *)libc_malloc(buflen);
182 	if (nsc_db_buf == (char *)NULL)
183 		return (0);
184 	nsc_db_list = (char **)libc_malloc(arrlen * sizeof (char *));
185 	if (nsc_db_list == (char **)NULL) {
186 		libc_free((void *)nsc_db_buf);
187 		nsc_db_buf = NULL;
188 		return (0);
189 	}
190 	(void) memcpy(nsc_db_buf, dblist, buflen);
191 	lp = nsc_db_list;
192 	*lp++ = nsc_db_buf;
193 	for (cp = nsc_db_buf; *cp; ) {
194 		if (*cp == BD_SEP) {
195 			*cp++ = '\0';
196 			*lp++ = cp;
197 		} else
198 			cp++;
199 	}
200 	*lp = NULL;
201 	return (1);
202 }
203 
204 /*
205  * _nsc_initdoor_fp attempts to validate the given door and
206  * confirm that it is still available for use.  The options are:
207  *	Front door:
208  *		If it's not open, attempt to open or error
209  *		If it's open attempt to validate.
210  *		If it's not validatable, reset fd and try again.
211  *		Other wise it open and validated, return success
212  *	Per user (back) door:
213  *		This door is passed to the client through th front door
214  *		attempt to validate it.  If it can't be validated, it
215  *		must be reset. Then send a NSS_ALTRESET error, so nscd can
216  *		forward another fd if desired.
217  */
218 
219 static nss_status_t
_nsc_initdoor_fp(nsc_door_t * dp)220 _nsc_initdoor_fp(nsc_door_t *dp)
221 {
222 
223 	door_info_t 		my_door;
224 
225 	if (dp == NULL) {
226 		errno = ENOTCONN;
227 		return (NSS_ERROR);
228 	}
229 
230 	/*
231 	 * the first time in we try and open and validate the front door.
232 	 * A front door request may return an alternate private back door
233 	 * that the client should use instead.
234 	 *
235 	 * To validate a door the door must have been created with
236 	 * the name service door cookie. The front door is file
237 	 * attached, owned by root and readonly by user, group and
238 	 * other.  If any of these validations fail we refuse to use
239 	 * the door.  A back door is delivered from the front door
240 	 * via a door_desc_t, and have the same cooke notification.
241 	 */
242 
243 	lmutex_lock(&dp->door_lock);
244 
245 try_again:
246 
247 	if (dp->doorfd == -1 && dp == &nsc_door[0]) {	/* open front door */
248 		int		tbc[3];
249 		int		i;
250 
251 		dp->doorfd = open64(NAME_SERVICE_DOOR, O_RDONLY, 0);
252 		if (dp->doorfd == -1) {
253 			lmutex_unlock(&dp->door_lock);
254 			return (NSS_ERROR);
255 		}
256 
257 		/*
258 		 * dup up the file descriptor if we have 0 - 2
259 		 * to avoid problems with shells stdin/out/err
260 		 */
261 		i = 0;
262 
263 		while (dp->doorfd < 3) { /* we have a reserved fd */
264 			tbc[i++] = dp->doorfd;
265 			if ((dp->doorfd = dup(dp->doorfd)) < 0) {
266 				while (i--)
267 					(void) close(tbc[i]);
268 				dp->doorfd = -1;
269 				lmutex_unlock(&dp->door_lock);
270 				return (NSS_ERROR);
271 			}
272 		}
273 
274 		while (i--)
275 			(void) close(tbc[i]);
276 
277 		/*
278 		 * mark this door descriptor as close on exec
279 		 */
280 		(void) fcntl(dp->doorfd, F_SETFD, FD_CLOEXEC);
281 		if (__door_info(dp->doorfd, &dp->doori) < 0 ||
282 		    (dp->doori.di_attributes & DOOR_REVOKED) ||
283 		    dp->doori.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE) {
284 			/*
285 			 * we should close doorfd because we just opened it
286 			 */
287 			(void) close(dp->doorfd);
288 			dp->doorfd = -1;
289 			(void) memset((void *)&dp->doori,
290 			    '\0', sizeof (door_info_t));
291 			lmutex_unlock(&dp->door_lock);
292 			errno = ECONNREFUSED;
293 			return (NSS_ERROR);
294 		}
295 	} else {
296 		if (__door_info(dp->doorfd, &my_door) < 0 ||
297 		    my_door.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE ||
298 		    my_door.di_uniquifier != dp->doori.di_uniquifier) {
299 			/*
300 			 * don't close it -
301 			 * someone else has clobbered fd
302 			 */
303 			dp->doorfd = -1;
304 			(void) memset((void *)&dp->doori,
305 			    '\0', sizeof (door_info_t));
306 			if (dp == &nsc_door[1]) {	/* reset back door */
307 				/* flush invalid db list */
308 				_nsc_flush_private_db();
309 				lmutex_unlock(&dp->door_lock);
310 				return (NSS_ALTRESET);
311 			}
312 			goto try_again;
313 		}
314 
315 		if (my_door.di_attributes & DOOR_REVOKED) {
316 			(void) close(dp->doorfd);	/* nscd exited .... */
317 			dp->doorfd = -1;	/* try and restart connection */
318 			(void) memset((void *)&dp->doori,
319 			    '\0', sizeof (door_info_t));
320 			if (dp == &nsc_door[1]) {	/* back door reset */
321 				/* flush invalid db list */
322 				_nsc_flush_private_db();
323 				lmutex_unlock(&dp->door_lock);
324 				return (NSS_ALTRESET);
325 			}
326 			goto try_again;
327 		}
328 	}
329 
330 	lmutex_unlock(&dp->door_lock);
331 	return (NSS_SUCCESS);
332 }
333 
334 /*
335  * Try the door request once only, to the specified connection.
336  * return the results or error.
337  */
338 
339 static nss_status_t
_nsc_try1door(nsc_door_t * dp,void ** dptr,size_t * ndata,size_t * adata,int * pdesc)340 _nsc_try1door(nsc_door_t *dp, void **dptr, size_t *ndata,
341 			size_t *adata, int *pdesc)
342 {
343 	door_arg_t		param;
344 	int			ret;
345 	nss_pheader_t		*rp;
346 
347 	ret = _nsc_initdoor_fp(dp);
348 	if (ret != NSS_SUCCESS)
349 		return (ret);
350 
351 	param.rbuf = (char *)*dptr;
352 	param.rsize = *ndata;
353 	param.data_ptr = (char *)*dptr;
354 	param.data_size = *adata;
355 	param.desc_ptr = NULL;
356 	param.desc_num = 0;
357 	ret = __door_call(dp->doorfd, &param);
358 	if (ret < 0) {
359 		return (NSS_ERROR);
360 	}
361 	*adata = param.data_size;
362 	*ndata = param.rsize;
363 	*dptr = (void *)param.data_ptr;
364 	rp = (nss_pheader_t *)((void *)param.rbuf);
365 	if (pdesc != NULL && rp && rp->p_status == NSS_ALTRETRY &&
366 	    param.desc_ptr != NULL && param.desc_num > 0) {
367 		if ((param.desc_ptr->d_attributes & DOOR_DESCRIPTOR) &&
368 		    param.desc_ptr->d_data.d_desc.d_descriptor >= 0 &&
369 		    param.desc_ptr->d_data.d_desc.d_id != 0) {
370 			/* have an alt descriptor */
371 			*pdesc = param.desc_ptr->d_data.d_desc.d_descriptor;
372 			/* got a NSS_ALTRETRY command */
373 			return (NSS_ALTRETRY);
374 		}
375 		errno = EINVAL;
376 		return (NSS_ERROR);		/* other error? */
377 	}
378 	if (*adata == 0 || *dptr == NULL) {
379 		errno = ENOTCONN;
380 		return (NSS_ERROR);
381 	}
382 
383 	if (rp->p_status == NSS_ALTRESET ||
384 	    rp->p_status == NSS_ALTRETRY ||
385 	    rp->p_status == NSS_TRYLOCAL)
386 		return (rp->p_status);
387 
388 	return (NSS_SUCCESS);
389 }
390 
391 /*
392  * Backwards compatible API
393  */
394 
395 nss_status_t
_nsc_trydoorcall(void ** dptr,size_t * ndata,size_t * adata)396 _nsc_trydoorcall(void **dptr, size_t *ndata, size_t *adata)
397 {
398 	return (_nsc_try1door(&nsc_door[0], dptr, ndata, adata, NULL));
399 }
400 
401 /*
402  * Send the request to the designated door, based on the supplied db
403  * Retry on the alternate door fd if possible.
404  */
405 
406 nss_status_t
_nsc_trydoorcall_ext(void ** dptr,size_t * ndata,size_t * adata)407 _nsc_trydoorcall_ext(void **dptr, size_t *ndata, size_t *adata)
408 {
409 	int		ret = NSS_ALTRETRY;
410 	nsc_door_t	*frontd = &nsc_door[0];
411 	nsc_door_t	*backd = &nsc_door[1];
412 	int		fd;
413 
414 	nss_pheader_t	*ph, ph_save;
415 	char		*dbl;
416 	char		*db = NULL;
417 	nss_dbd_t	*dbd;
418 	int		fb2frontd = 0;
419 	int		reset_frontd = 0;
420 	size_t		ndata_save = *ndata, adata_save = *adata;
421 	void		*dptr_save = *dptr;
422 
423 	ph = (nss_pheader_t *)*dptr;
424 	dbd = (nss_dbd_t *)((void *)((char *)ph + ph->dbd_off));
425 	if (dbd->o_name != 0)
426 		db = (char *)dbd + dbd->o_name;
427 
428 	/*
429 	 * save away a copy of the header, in case the request needs
430 	 * to be sent to nscd more than once. In that case, this
431 	 * original header can be copied back to the door buffer
432 	 * to replace the possibly changed header
433 	 */
434 	ph_save = *ph;
435 
436 	while (ret == NSS_ALTRETRY || ret == NSS_ALTRESET) {
437 		/* try private (back) door first if it exists and applies */
438 		if (db != NULL && backd->doorfd > 0 && fb2frontd == 0 &&
439 		    _nsc_use_backdoor(db)) {
440 			ret = _nsc_try1door(backd, dptr, ndata, adata, NULL);
441 			if (ret == NSS_ALTRESET) {
442 				/*
443 				 * received NSS_ALTRESET command,
444 				 * retry on front door
445 				 */
446 				lmutex_lock(&backd->door_lock);
447 				backd->doorfd = -1;
448 				(void) memset((void *)&backd->doori,
449 				    '\0', sizeof (door_info_t));
450 				/* flush now invalid db list */
451 				_nsc_flush_private_db();
452 				lmutex_unlock(&backd->door_lock);
453 				continue;
454 			} else if (ret == NSS_ALTRETRY) {
455 				/*
456 				 * received NSS_ALTRETRY command,
457 				 * fall back and retry on front door
458 				 */
459 				fb2frontd = 1;
460 				if (*dptr != dptr_save)
461 					(void) munmap((void *)*dptr, *ndata);
462 
463 				/*
464 				 * restore the buffer size and header
465 				 * data so that the front door will
466 				 * see the original request
467 				 */
468 				*ndata = ndata_save;
469 				*adata = adata_save;
470 				*dptr = dptr_save;
471 				ph =  (nss_pheader_t *)*dptr;
472 				*ph = ph_save;
473 				/*
474 				 * tell the front door server, this is
475 				 * a fallback call
476 				 */
477 				ph->p_status = NSS_ALTRETRY;
478 				continue;
479 			}
480 
481 			/* return the result or error */
482 			break;
483 		}
484 
485 		/* try the front door */
486 		fd = -1;
487 		ret = _nsc_try1door(frontd, dptr, ndata, adata, &fd);
488 
489 		if (ret != NSS_ALTRETRY) {
490 			/*
491 			 * got a success or failure result.
492 			 * but front door should never send NSS_ALTRESET
493 			 */
494 			if (ret == NSS_ALTRESET)
495 				/* reset the front door */
496 				reset_frontd = 1;
497 			else
498 				/*
499 				 * not NSS_ALTRETRY and not NSS_ALTRESET
500 				 * return the result or error
501 				 */
502 				break;
503 		} else if (fb2frontd == 1) {
504 			/*
505 			 * front door should never send NSS_ALTRETRY
506 			 * in a fallback call. Reset the front door.
507 			 */
508 			reset_frontd = 1;
509 		}
510 
511 		if (reset_frontd == 1) {
512 			lmutex_lock(&frontd->door_lock);
513 			frontd->doorfd = -1;
514 			(void) memset((void *)&frontd->doori,
515 			    '\0', sizeof (door_info_t));
516 			lmutex_unlock(&frontd->door_lock);
517 			/* error out */
518 			ret = NSS_ERROR;
519 			break;
520 		}
521 
522 		/* process NSS_ALTRETRY request from front door */
523 		if (fd < 0)
524 			continue;	/* no new door given, try again */
525 
526 		/* update and try alternate door */
527 		lmutex_lock(&backd->door_lock);
528 		if (backd->doorfd >= 0) {
529 			/* unexpected open alt door - clean up, continue */
530 			_nsc_flush_private_db();
531 			(void) close(backd->doorfd);
532 		}
533 
534 		/* set up back door fd */
535 		backd->doorfd = fd;
536 
537 		/* set up back door db list */
538 		ph =  (nss_pheader_t *)*dptr;
539 		dbl = ((char *)ph) + ph->data_off;
540 
541 		if (_nsc_init_private_db(dbl) == 0) {
542 			/* could not init db list, try again */
543 			(void) close(backd->doorfd);
544 			backd->doorfd = -1;
545 			lmutex_unlock(&backd->door_lock);
546 			continue;
547 		}
548 		if (door_info(backd->doorfd, &backd->doori) < 0 ||
549 		    (backd->doori.di_attributes & DOOR_REVOKED) ||
550 		    backd->doori.di_data !=
551 		    (uintptr_t)NAME_SERVICE_DOOR_COOKIE) {
552 			/* doorfd bad, or must not really be open */
553 			(void) close(backd->doorfd);
554 			backd->doorfd = -1;
555 			(void) memset((void *)&backd->doori,
556 			    '\0', sizeof (door_info_t));
557 		}
558 		(void) fcntl(backd->doorfd, F_SETFD, FD_CLOEXEC);
559 		lmutex_unlock(&backd->door_lock);
560 		/* NSS_ALTRETRY new back door */
561 		if (*dptr != dptr_save)
562 			(void) munmap((void *)*dptr, *ndata);
563 
564 		/*
565 		 * restore the buffer size and header
566 		 * data so that the back door will
567 		 * see the original request
568 		 */
569 		*ndata = ndata_save;
570 		*adata = adata_save;
571 		*dptr = dptr_save;
572 		ph =  (nss_pheader_t *)*dptr;
573 		*ph = ph_save;
574 	}
575 	return (ret);
576 }
577 
578 /*
579  * Get the current (but growable) buffer size for a NSS2 packet.
580  * Heuristic algorithm used:
581  *	1) Make sure it's at least NSS_BUFLEN_DOOR in length (16k default)
582  *	2) if an incoming user buffer is > larger than the current size
583  *	   Make the buffer at least NSS_BUFLEN_DOOR/2+user buffer size
584  *	   This should account for any reasonable nss_pheader, keys
585  *	   extended area etc.
586  *	3) keep the prototype/debugging (private)NSS_BUFLEN option
587  *	   to change any preconfigured value if needed(?)
588  */
589 
590 static size_t
_nsc_getdoorbsize(size_t min_size)591 _nsc_getdoorbsize(size_t min_size)
592 {
593 	if (!door_bsize) {
594 		lmutex_lock(&hints_lock);
595 		if (!door_bsize) {
596 			/* future work - get nscd hint & use hint size */
597 			door_bsize = ROUND_UP(door_bsize, NSS_BUFSIZ);
598 			if (door_bsize < NSS_BUFLEN_DOOR) {
599 				door_bsize = NSS_BUFLEN_DOOR;
600 			}
601 		}
602 		lmutex_unlock(&hints_lock);
603 	}
604 	if (min_size && door_bsize < (min_size + NSS_BUFLEN_DOOR/2)) {
605 		lmutex_lock(&hints_lock);
606 		if (door_bsize < (min_size + NSS_BUFLEN_DOOR/2)) {
607 			min_size += NSS_BUFLEN_DOOR;
608 			door_bsize = ROUND_UP(min_size, NSS_BUFSIZ);
609 		}
610 		lmutex_unlock(&hints_lock);
611 	}
612 	return (door_bsize);
613 }
614 
615 static void
_nsc_freedbuf(void * arg)616 _nsc_freedbuf(void *arg)
617 {
618 	nss_XbyY_buf_t *tsdbuf = arg;
619 
620 	if (tsdbuf != NULL && tsdbuf->buffer != NULL) {
621 		lfree(tsdbuf->buffer, (size_t)tsdbuf->buflen);
622 		tsdbuf->result = NULL;
623 		tsdbuf->buffer = NULL;
624 		tsdbuf->buflen = 0;
625 	}
626 }
627 
628 /*
629  * _nsc_getdoorbuf - return the client side per thread door buffer
630  * Elsewhere, it is assumed that the header is 0'd upon return from here.
631  */
632 
633 int
_nsc_getdoorbuf(void ** doorptr,size_t * bufsize)634 _nsc_getdoorbuf(void **doorptr, size_t *bufsize)
635 {
636 	nss_XbyY_buf_t *tsdbuf;
637 	char *bp;
638 	size_t dsize;
639 
640 	if (doorptr == NULL || bufsize == NULL)
641 		return (-1);
642 
643 	/* Get thread specific pointer to door buffer */
644 	tsdbuf = tsdalloc(_T_DOORBUF, sizeof (nss_XbyY_buf_t), _nsc_freedbuf);
645 	if (tsdbuf == NULL)
646 		return (-1);
647 
648 	/* if door buffer does not exist create it */
649 	if (tsdbuf->buffer == NULL) {
650 		dsize = _nsc_getdoorbsize(*bufsize);
651 
652 		/* setup a door buffer with a total length of dsize */
653 		bp = lmalloc(dsize);
654 		if (bp == NULL)
655 			return (-1);
656 		tsdbuf->buffer = bp;
657 		tsdbuf->buflen = dsize;
658 	} else {
659 		/* check old buffer size and resize if needed */
660 		if (*bufsize) {
661 			dsize = _nsc_getdoorbsize(*bufsize);
662 			if (tsdbuf->buflen < dsize) {
663 				lfree(tsdbuf->buffer, (size_t)tsdbuf->buflen);
664 				bp = lmalloc(dsize);
665 				if (bp == NULL)
666 					return (-1);
667 				tsdbuf->buffer = bp;
668 				tsdbuf->buflen = dsize;
669 			}
670 		}
671 		/* freshly malloc'd door bufs are 0'd */
672 		/* 0 header for now.  Zero entire buf(?) TDB */
673 		(void) memset((void *)tsdbuf->buffer, 0,
674 		    (size_t)sizeof (nss_pheader_t));
675 
676 	}
677 	*doorptr = (void *)tsdbuf->buffer;
678 	*bufsize = tsdbuf->buflen;
679 	return (0);
680 }
681 
682 void
_nsc_resizedoorbuf(size_t bsize)683 _nsc_resizedoorbuf(size_t bsize)
684 {
685 	/* signal to update if new door size is desired */
686 	lmutex_lock(&hints_lock);
687 	if (bsize > door_bsize && door_nbsize < bsize)
688 		door_nbsize = bsize;
689 	lmutex_unlock(&hints_lock);
690 }
691 
692 /*
693  * Check uid and /proc/PID/psinfo to see if this process is nscd
694  * If it is set the appropriate flags and allow policy reconfiguration.
695  */
696 int
_nsc_proc_is_cache()697 _nsc_proc_is_cache()
698 {
699 	psinfo_t	pinfo;
700 	char		fname[128];
701 	int		ret;
702 	int		fd;
703 
704 	if (proc_is_cache >= 0)
705 		return (proc_is_cache);
706 	lmutex_lock(&hints_lock);
707 	if (proc_is_cache >= 0) {
708 		lmutex_unlock(&hints_lock);
709 		return (proc_is_cache);
710 	}
711 	proc_is_cache = 0;
712 	/* It can't be nscd if it's not running as root... */
713 	if (getuid() != 0) {
714 		lmutex_unlock(&hints_lock);
715 		return (0);
716 	}
717 	ret = snprintf(fname, 128, "/proc/%d/psinfo", getpid());
718 	if (ret > 0 && ret < 128) {
719 		if ((fd = open(fname,  O_RDONLY)) >= 0) {
720 			ret = read(fd, &pinfo, sizeof (psinfo_t));
721 			(void) close(fd);
722 			if (ret == sizeof (psinfo_t) &&
723 			    (strcmp(pinfo.pr_fname, "nscd") == 0)) {
724 				/* process runs as root and is named nscd */
725 				/* that's good enough for now */
726 				proc_is_cache = 1;
727 			}
728 		}
729 	}
730 	lmutex_unlock(&hints_lock);
731 	return (proc_is_cache);
732 }
733