17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5cb5caa98Sdjl  * Common Development and Distribution License (the "License").
6cb5caa98Sdjl  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
210ec57554Sraf 
227c478bd9Sstevel@tonic-gate /*
23219f483bSandra  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
27*7257d1b4Sraf #include "lint.h"
287c478bd9Sstevel@tonic-gate #include <mtlib.h>
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
30cb5caa98Sdjl #include <errno.h>
317c478bd9Sstevel@tonic-gate #include <pwd.h>
327c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
337c478bd9Sstevel@tonic-gate #include <stdio.h>
34cb5caa98Sdjl #include <string.h>
357c478bd9Sstevel@tonic-gate #include <synch.h>
367c478bd9Sstevel@tonic-gate #include <sys/param.h>
377c478bd9Sstevel@tonic-gate #include <fcntl.h>
387c478bd9Sstevel@tonic-gate #include <unistd.h>
39cb5caa98Sdjl #include <stdlib.h>
407c478bd9Sstevel@tonic-gate #include <getxby_door.h>
417c478bd9Sstevel@tonic-gate #include <sys/door.h>
42cb5caa98Sdjl #include <procfs.h>
43cb5caa98Sdjl #include <door.h>
44606f6aa3Smichen #include <sys/mman.h>
457c478bd9Sstevel@tonic-gate #include "libc.h"
46cb5caa98Sdjl #include "tsd.h"
477c478bd9Sstevel@tonic-gate #include "base_conversion.h"
487c478bd9Sstevel@tonic-gate 
49cb5caa98Sdjl /* nss<->door hints */
50cb5caa98Sdjl static mutex_t	hints_lock = DEFAULTMUTEX;
51cb5caa98Sdjl static size_t	door_bsize = 0;
52cb5caa98Sdjl static size_t	door_nbsize = 0;
53cb5caa98Sdjl static int	proc_is_cache = -1;
54cb5caa98Sdjl 
55cb5caa98Sdjl /* library<->nscd door interaction apis */
56cb5caa98Sdjl 
577c478bd9Sstevel@tonic-gate /*
587c478bd9Sstevel@tonic-gate  *
597c478bd9Sstevel@tonic-gate  * Routine that actually performs the door call.
607c478bd9Sstevel@tonic-gate  * Note that we cache a file descriptor.  We do
617c478bd9Sstevel@tonic-gate  * the following to prevent disasters:
627c478bd9Sstevel@tonic-gate  *
637c478bd9Sstevel@tonic-gate  * 1) Never use 0,1 or 2; if we get this from the open
647c478bd9Sstevel@tonic-gate  *    we dup it upwards.
657c478bd9Sstevel@tonic-gate  *
667c478bd9Sstevel@tonic-gate  * 2) Set the close on exec flags so descriptor remains available
677c478bd9Sstevel@tonic-gate  *    to child processes.
687c478bd9Sstevel@tonic-gate  *
697c478bd9Sstevel@tonic-gate  * 3) Verify that the door is still the same one we had before
707c478bd9Sstevel@tonic-gate  *    by using door_info on the client side.
717c478bd9Sstevel@tonic-gate  *
727c478bd9Sstevel@tonic-gate  *	Note that we never close the file descriptor if it isn't one
737c478bd9Sstevel@tonic-gate  *	we allocated; we check this with door info.  The rather tricky
747c478bd9Sstevel@tonic-gate  *	logic is designed to be fast in the normal case (fd is already
757c478bd9Sstevel@tonic-gate  *	allocated and is ok) while handling the case where the application
767c478bd9Sstevel@tonic-gate  *	closed it underneath us or where the nscd dies or re-execs itself
777c478bd9Sstevel@tonic-gate  *	and we're a multi-threaded application.  Note that we cannot protect
787c478bd9Sstevel@tonic-gate  *	the application if it closes the fd and it is multi-threaded.
797c478bd9Sstevel@tonic-gate  *
80cb5caa98Sdjl  *  int _nsc_trydoorcall(void *dptr, size_t *bufsize, size_t *actualsize);
817c478bd9Sstevel@tonic-gate  *
827c478bd9Sstevel@tonic-gate  *      *dptr           IN: points to arg buffer OUT: points to results buffer
837c478bd9Sstevel@tonic-gate  *      *bufsize        IN: overall size of buffer OUT: overall size of buffer
847c478bd9Sstevel@tonic-gate  *      *actualsize     IN: size of call data OUT: size of return data
857c478bd9Sstevel@tonic-gate  *
867c478bd9Sstevel@tonic-gate  *  Note that *dptr may change if provided space as defined by *bufsize is
877c478bd9Sstevel@tonic-gate  *  inadequate.  In this case the door call mmaps more space and places
887c478bd9Sstevel@tonic-gate  *  the answer there and sets dptr to contain a pointer to the space, which
897c478bd9Sstevel@tonic-gate  *  should be freed with munmap.
907c478bd9Sstevel@tonic-gate  *
917c478bd9Sstevel@tonic-gate  *  Returns 0 if the door call reached the server, -1 if contact was not made.
927c478bd9Sstevel@tonic-gate  *
937c478bd9Sstevel@tonic-gate  */
947c478bd9Sstevel@tonic-gate 
95cb5caa98Sdjl /*
96cb5caa98Sdjl  * Max size for list of db names supported by the private nscd
97cb5caa98Sdjl  * No implied max here, any size will do, fixed size chosen to
98cb5caa98Sdjl  * reduce yet another malloc
99cb5caa98Sdjl  */
1007c478bd9Sstevel@tonic-gate 
101cb5caa98Sdjl #define	BD_BUFSIZE	1024
102cb5caa98Sdjl #define	BD_SEP		','
103cb5caa98Sdjl 
104cb5caa98Sdjl typedef struct _nsc_door_t {
105cb5caa98Sdjl 	int 		doorfd;
106cb5caa98Sdjl 	mutex_t		door_lock;
107cb5caa98Sdjl 	door_info_t 	doori;
108cb5caa98Sdjl } nsc_door_t;
109cb5caa98Sdjl 
110cb5caa98Sdjl static nsc_door_t	nsc_door[2] = {
111cb5caa98Sdjl 	{ -1, DEFAULTMUTEX, { 0 } },		/* front (fattached) door */
112cb5caa98Sdjl 	{ -1, DEFAULTMUTEX, { 0 } },		/* back (private) door */
113cb5caa98Sdjl };
114cb5caa98Sdjl 
115cb5caa98Sdjl /* assumed to be locked by using nsc_door[1] mutex */
116cb5caa98Sdjl static char	*nsc_db_buf = NULL;
117cb5caa98Sdjl static char	**nsc_db_list = NULL;
118cb5caa98Sdjl 
119cb5caa98Sdjl /*
120cb5caa98Sdjl  * Check for a valid and matching db in the list.
121cb5caa98Sdjl  * assume list is in the locked state.
122cb5caa98Sdjl  */
123cb5caa98Sdjl 
124cb5caa98Sdjl static int
_nsc_use_backdoor(char * db)125cb5caa98Sdjl _nsc_use_backdoor(char *db)
126cb5caa98Sdjl {
127cb5caa98Sdjl 	char 	**ndb;
128cb5caa98Sdjl 
129cb5caa98Sdjl 	if (db && nsc_db_buf != NULL && nsc_db_list != NULL) {
130cb5caa98Sdjl 		for (ndb = nsc_db_list; *ndb; ndb++) {
131cb5caa98Sdjl 			if (strcmp(db, *ndb) == 0)
132cb5caa98Sdjl 				return (1);
133cb5caa98Sdjl 		}
134cb5caa98Sdjl 	}
135cb5caa98Sdjl 	return (0);
136cb5caa98Sdjl }
137cb5caa98Sdjl 
138cb5caa98Sdjl /*
139cb5caa98Sdjl  * flush private db lists
140cb5caa98Sdjl  */
141cb5caa98Sdjl static void
_nsc_flush_private_db()142cb5caa98Sdjl _nsc_flush_private_db()
143cb5caa98Sdjl {
144cb5caa98Sdjl 	if (nsc_db_buf != NULL) {
145cb5caa98Sdjl 		libc_free((void *)nsc_db_buf);
146cb5caa98Sdjl 		nsc_db_buf = NULL;
147cb5caa98Sdjl 	}
148cb5caa98Sdjl 	if (nsc_db_list != NULL) {
149cb5caa98Sdjl 		libc_free((void *)nsc_db_list);
150cb5caa98Sdjl 		nsc_db_list = NULL;
151cb5caa98Sdjl 	}
152cb5caa98Sdjl }
153cb5caa98Sdjl 
154cb5caa98Sdjl /*
155cb5caa98Sdjl  * init/update nsc_db_buf given buff containing list of
156cb5caa98Sdjl  * db's to be processed by a private nscd.
157cb5caa98Sdjl  * This function assumes it has a well formed string from nscd.
158cb5caa98Sdjl  */
159cb5caa98Sdjl 
160cb5caa98Sdjl static int
_nsc_init_private_db(char * dblist)161cb5caa98Sdjl _nsc_init_private_db(char *dblist)
162cb5caa98Sdjl {
163cb5caa98Sdjl 	char	*cp, **lp;
164cb5caa98Sdjl 	int	buflen = 0;
165cb5caa98Sdjl 	int	arrlen = 0;
166cb5caa98Sdjl 
167cb5caa98Sdjl 	if (dblist == NULL)
168cb5caa98Sdjl 		return (0);
169cb5caa98Sdjl 
170cb5caa98Sdjl 	/* reset db list */
171cb5caa98Sdjl 	_nsc_flush_private_db();
172cb5caa98Sdjl 
173cb5caa98Sdjl 	/* rebuild fresh list */
174cb5caa98Sdjl 	buflen = strlen(dblist) + 1;
175cb5caa98Sdjl 	for (cp = dblist; *cp; cp++)
176cb5caa98Sdjl 		if (*cp == BD_SEP)
177cb5caa98Sdjl 			arrlen++;
178cb5caa98Sdjl 	if (cp == dblist)
179cb5caa98Sdjl 		return (0);
180cb5caa98Sdjl 	arrlen += 2;
181cb5caa98Sdjl 	nsc_db_buf = (char *)libc_malloc(buflen);
182cb5caa98Sdjl 	if (nsc_db_buf == (char *)NULL)
183cb5caa98Sdjl 		return (0);
184cb5caa98Sdjl 	nsc_db_list = (char **)libc_malloc(arrlen * sizeof (char *));
185cb5caa98Sdjl 	if (nsc_db_list == (char **)NULL) {
186cb5caa98Sdjl 		libc_free((void *)nsc_db_buf);
187cb5caa98Sdjl 		nsc_db_buf = NULL;
188cb5caa98Sdjl 		return (0);
189cb5caa98Sdjl 	}
190cb5caa98Sdjl 	(void) memcpy(nsc_db_buf, dblist, buflen);
191cb5caa98Sdjl 	lp = nsc_db_list;
192cb5caa98Sdjl 	*lp++ = nsc_db_buf;
193cb5caa98Sdjl 	for (cp = nsc_db_buf; *cp; ) {
194cb5caa98Sdjl 		if (*cp == BD_SEP) {
195cb5caa98Sdjl 			*cp++ = '\0';
196cb5caa98Sdjl 			*lp++ = cp;
197cb5caa98Sdjl 		} else
198cb5caa98Sdjl 			cp++;
199cb5caa98Sdjl 	}
200cb5caa98Sdjl 	*lp = NULL;
201cb5caa98Sdjl 	return (1);
202cb5caa98Sdjl }
203cb5caa98Sdjl 
204cb5caa98Sdjl /*
205cb5caa98Sdjl  * _nsc_initdoor_fp attempts to validate the given door and
206cb5caa98Sdjl  * confirm that it is still available for use.  The options are:
207cb5caa98Sdjl  *	Front door:
208cb5caa98Sdjl  *		If it's not open, attempt to open or error
209cb5caa98Sdjl  *		If it's open attempt to validate.
210cb5caa98Sdjl  *		If it's not validatable, reset fd and try again.
211cb5caa98Sdjl  *		Other wise it open and validated, return success
212cb5caa98Sdjl  *	Per user (back) door:
213cb5caa98Sdjl  *		This door is passed to the client through th front door
214cb5caa98Sdjl  *		attempt to validate it.  If it can't be validated, it
215cb5caa98Sdjl  *		must be reset. Then send a NSS_ALTRESET error, so nscd can
216cb5caa98Sdjl  *		forward another fd if desired.
217cb5caa98Sdjl  */
218cb5caa98Sdjl 
219cb5caa98Sdjl static nss_status_t
_nsc_initdoor_fp(nsc_door_t * dp)220cb5caa98Sdjl _nsc_initdoor_fp(nsc_door_t *dp)
2217c478bd9Sstevel@tonic-gate {
222cb5caa98Sdjl 
2237c478bd9Sstevel@tonic-gate 	door_info_t 		my_door;
224cb5caa98Sdjl 
225cb5caa98Sdjl 	if (dp == NULL) {
226cb5caa98Sdjl 		errno = ENOTCONN;
227cb5caa98Sdjl 		return (NSS_ERROR);
228cb5caa98Sdjl 	}
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	/*
231cb5caa98Sdjl 	 * the first time in we try and open and validate the front door.
232cb5caa98Sdjl 	 * A front door request may return an alternate private back door
233cb5caa98Sdjl 	 * that the client should use instead.
234cb5caa98Sdjl 	 *
235cb5caa98Sdjl 	 * To validate a door the door must have been created with
236cb5caa98Sdjl 	 * the name service door cookie. The front door is file
237cb5caa98Sdjl 	 * attached, owned by root and readonly by user, group and
238cb5caa98Sdjl 	 * other.  If any of these validations fail we refuse to use
239cb5caa98Sdjl 	 * the door.  A back door is delivered from the front door
240cb5caa98Sdjl 	 * via a door_desc_t, and have the same cooke notification.
2417c478bd9Sstevel@tonic-gate 	 */
2427c478bd9Sstevel@tonic-gate 
243cb5caa98Sdjl 	lmutex_lock(&dp->door_lock);
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate try_again:
2467c478bd9Sstevel@tonic-gate 
247cb5caa98Sdjl 	if (dp->doorfd == -1 && dp == &nsc_door[0]) {	/* open front door */
2487c478bd9Sstevel@tonic-gate 		int		tbc[3];
2497c478bd9Sstevel@tonic-gate 		int		i;
2500ec57554Sraf 
251cb5caa98Sdjl 		dp->doorfd = open64(NAME_SERVICE_DOOR, O_RDONLY, 0);
252cb5caa98Sdjl 		if (dp->doorfd == -1) {
253cb5caa98Sdjl 			lmutex_unlock(&dp->door_lock);
254cb5caa98Sdjl 			return (NSS_ERROR);
2557c478bd9Sstevel@tonic-gate 		}
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 		/*
2587c478bd9Sstevel@tonic-gate 		 * dup up the file descriptor if we have 0 - 2
2597c478bd9Sstevel@tonic-gate 		 * to avoid problems with shells stdin/out/err
2607c478bd9Sstevel@tonic-gate 		 */
2617c478bd9Sstevel@tonic-gate 		i = 0;
2627c478bd9Sstevel@tonic-gate 
263cb5caa98Sdjl 		while (dp->doorfd < 3) { /* we have a reserved fd */
264cb5caa98Sdjl 			tbc[i++] = dp->doorfd;
265cb5caa98Sdjl 			if ((dp->doorfd = dup(dp->doorfd)) < 0) {
2667c478bd9Sstevel@tonic-gate 				while (i--)
267219f483bSandra 					(void) close(tbc[i]);
268cb5caa98Sdjl 				dp->doorfd = -1;
269cb5caa98Sdjl 				lmutex_unlock(&dp->door_lock);
270cb5caa98Sdjl 				return (NSS_ERROR);
2717c478bd9Sstevel@tonic-gate 			}
2727c478bd9Sstevel@tonic-gate 		}
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 		while (i--)
275219f483bSandra 			(void) close(tbc[i]);
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 		/*
2787c478bd9Sstevel@tonic-gate 		 * mark this door descriptor as close on exec
2797c478bd9Sstevel@tonic-gate 		 */
280cb5caa98Sdjl 		(void) fcntl(dp->doorfd, F_SETFD, FD_CLOEXEC);
281cb5caa98Sdjl 		if (__door_info(dp->doorfd, &dp->doori) < 0 ||
282cb5caa98Sdjl 		    (dp->doori.di_attributes & DOOR_REVOKED) ||
283cb5caa98Sdjl 		    dp->doori.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE) {
2847c478bd9Sstevel@tonic-gate 			/*
2857c478bd9Sstevel@tonic-gate 			 * we should close doorfd because we just opened it
2867c478bd9Sstevel@tonic-gate 			 */
287cb5caa98Sdjl 			(void) close(dp->doorfd);
288cb5caa98Sdjl 			dp->doorfd = -1;
289cb5caa98Sdjl 			(void) memset((void *)&dp->doori,
290219f483bSandra 			    '\0', sizeof (door_info_t));
291cb5caa98Sdjl 			lmutex_unlock(&dp->door_lock);
292cb5caa98Sdjl 			errno = ECONNREFUSED;
293cb5caa98Sdjl 			return (NSS_ERROR);
2947c478bd9Sstevel@tonic-gate 		}
2950ec57554Sraf 	} else {
296cb5caa98Sdjl 		if (__door_info(dp->doorfd, &my_door) < 0 ||
2970ec57554Sraf 		    my_door.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE ||
298cb5caa98Sdjl 		    my_door.di_uniquifier != dp->doori.di_uniquifier) {
2990ec57554Sraf 			/*
3000ec57554Sraf 			 * don't close it -
3010ec57554Sraf 			 * someone else has clobbered fd
3020ec57554Sraf 			 */
303cb5caa98Sdjl 			dp->doorfd = -1;
304cb5caa98Sdjl 			(void) memset((void *)&dp->doori,
305219f483bSandra 			    '\0', sizeof (door_info_t));
306cb5caa98Sdjl 			if (dp == &nsc_door[1]) {	/* reset back door */
307cb5caa98Sdjl 				/* flush invalid db list */
308cb5caa98Sdjl 				_nsc_flush_private_db();
309cb5caa98Sdjl 				lmutex_unlock(&dp->door_lock);
310cb5caa98Sdjl 				return (NSS_ALTRESET);
311cb5caa98Sdjl 			}
3120ec57554Sraf 			goto try_again;
3137c478bd9Sstevel@tonic-gate 		}
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 		if (my_door.di_attributes & DOOR_REVOKED) {
316cb5caa98Sdjl 			(void) close(dp->doorfd);	/* nscd exited .... */
317cb5caa98Sdjl 			dp->doorfd = -1;	/* try and restart connection */
318cb5caa98Sdjl 			(void) memset((void *)&dp->doori,
319219f483bSandra 			    '\0', sizeof (door_info_t));
320cb5caa98Sdjl 			if (dp == &nsc_door[1]) {	/* back door reset */
321cb5caa98Sdjl 				/* flush invalid db list */
322cb5caa98Sdjl 				_nsc_flush_private_db();
323cb5caa98Sdjl 				lmutex_unlock(&dp->door_lock);
324cb5caa98Sdjl 				return (NSS_ALTRESET);
325cb5caa98Sdjl 			}
3267c478bd9Sstevel@tonic-gate 			goto try_again;
3277c478bd9Sstevel@tonic-gate 		}
3287c478bd9Sstevel@tonic-gate 	}
3297c478bd9Sstevel@tonic-gate 
330cb5caa98Sdjl 	lmutex_unlock(&dp->door_lock);
331cb5caa98Sdjl 	return (NSS_SUCCESS);
332cb5caa98Sdjl }
333cb5caa98Sdjl 
334cb5caa98Sdjl /*
335cb5caa98Sdjl  * Try the door request once only, to the specified connection.
336cb5caa98Sdjl  * return the results or error.
337cb5caa98Sdjl  */
338cb5caa98Sdjl 
339cb5caa98Sdjl static nss_status_t
_nsc_try1door(nsc_door_t * dp,void ** dptr,size_t * ndata,size_t * adata,int * pdesc)340cb5caa98Sdjl _nsc_try1door(nsc_door_t *dp, void **dptr, size_t *ndata,
341cb5caa98Sdjl 			size_t *adata, int *pdesc)
342cb5caa98Sdjl {
343cb5caa98Sdjl 	door_arg_t		param;
344cb5caa98Sdjl 	int			ret;
345cb5caa98Sdjl 	nss_pheader_t		*rp;
346cb5caa98Sdjl 
347cb5caa98Sdjl 	ret = _nsc_initdoor_fp(dp);
348cb5caa98Sdjl 	if (ret != NSS_SUCCESS)
349cb5caa98Sdjl 		return (ret);
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	param.rbuf = (char *)*dptr;
3527c478bd9Sstevel@tonic-gate 	param.rsize = *ndata;
3537c478bd9Sstevel@tonic-gate 	param.data_ptr = (char *)*dptr;
3547c478bd9Sstevel@tonic-gate 	param.data_size = *adata;
3557c478bd9Sstevel@tonic-gate 	param.desc_ptr = NULL;
3567c478bd9Sstevel@tonic-gate 	param.desc_num = 0;
357cb5caa98Sdjl 	ret = __door_call(dp->doorfd, &param);
358cb5caa98Sdjl 	if (ret < 0) {
359cb5caa98Sdjl 		return (NSS_ERROR);
360cb5caa98Sdjl 	}
361cb5caa98Sdjl 	*adata = param.data_size;
362cb5caa98Sdjl 	*ndata = param.rsize;
363cb5caa98Sdjl 	*dptr = (void *)param.data_ptr;
364cb5caa98Sdjl 	rp = (nss_pheader_t *)((void *)param.rbuf);
365cb5caa98Sdjl 	if (pdesc != NULL && rp && rp->p_status == NSS_ALTRETRY &&
366cb5caa98Sdjl 	    param.desc_ptr != NULL && param.desc_num > 0) {
367cb5caa98Sdjl 		if ((param.desc_ptr->d_attributes & DOOR_DESCRIPTOR) &&
368cb5caa98Sdjl 		    param.desc_ptr->d_data.d_desc.d_descriptor >= 0 &&
369cb5caa98Sdjl 		    param.desc_ptr->d_data.d_desc.d_id != 0) {
370cb5caa98Sdjl 			/* have an alt descriptor */
371cb5caa98Sdjl 			*pdesc = param.desc_ptr->d_data.d_desc.d_descriptor;
372cb5caa98Sdjl 			/* got a NSS_ALTRETRY command */
373cb5caa98Sdjl 			return (NSS_ALTRETRY);
374cb5caa98Sdjl 		}
375cb5caa98Sdjl 		errno = EINVAL;
376cb5caa98Sdjl 		return (NSS_ERROR);		/* other error? */
3777c478bd9Sstevel@tonic-gate 	}
3787c478bd9Sstevel@tonic-gate 	if (*adata == 0 || *dptr == NULL) {
379cb5caa98Sdjl 		errno = ENOTCONN;
380cb5caa98Sdjl 		return (NSS_ERROR);
3817c478bd9Sstevel@tonic-gate 	}
3827c478bd9Sstevel@tonic-gate 
383cb5caa98Sdjl 	if (rp->p_status == NSS_ALTRESET ||
384219f483bSandra 	    rp->p_status == NSS_ALTRETRY ||
385219f483bSandra 	    rp->p_status == NSS_TRYLOCAL)
386cb5caa98Sdjl 		return (rp->p_status);
387cb5caa98Sdjl 
388cb5caa98Sdjl 	return (NSS_SUCCESS);
389cb5caa98Sdjl }
390cb5caa98Sdjl 
391cb5caa98Sdjl /*
392cb5caa98Sdjl  * Backwards compatible API
393cb5caa98Sdjl  */
394cb5caa98Sdjl 
395cb5caa98Sdjl nss_status_t
_nsc_trydoorcall(void ** dptr,size_t * ndata,size_t * adata)396cb5caa98Sdjl _nsc_trydoorcall(void **dptr, size_t *ndata, size_t *adata)
397cb5caa98Sdjl {
398cb5caa98Sdjl 	return (_nsc_try1door(&nsc_door[0], dptr, ndata, adata, NULL));
399cb5caa98Sdjl }
400cb5caa98Sdjl 
401cb5caa98Sdjl /*
402cb5caa98Sdjl  * Send the request to the designated door, based on the supplied db
403cb5caa98Sdjl  * Retry on the alternate door fd if possible.
404cb5caa98Sdjl  */
405cb5caa98Sdjl 
406cb5caa98Sdjl nss_status_t
_nsc_trydoorcall_ext(void ** dptr,size_t * ndata,size_t * adata)407cb5caa98Sdjl _nsc_trydoorcall_ext(void **dptr, size_t *ndata, size_t *adata)
408cb5caa98Sdjl {
409cb5caa98Sdjl 	int		ret = NSS_ALTRETRY;
410cb5caa98Sdjl 	nsc_door_t	*frontd = &nsc_door[0];
411cb5caa98Sdjl 	nsc_door_t	*backd = &nsc_door[1];
412cb5caa98Sdjl 	int		fd;
413cb5caa98Sdjl 
414cb5caa98Sdjl 	nss_pheader_t	*ph, ph_save;
415cb5caa98Sdjl 	char		*dbl;
416cb5caa98Sdjl 	char		*db = NULL;
417cb5caa98Sdjl 	nss_dbd_t	*dbd;
418cb5caa98Sdjl 	int		fb2frontd = 0;
419cb5caa98Sdjl 	int		reset_frontd = 0;
420606f6aa3Smichen 	size_t		ndata_save = *ndata, adata_save = *adata;
421606f6aa3Smichen 	void		*dptr_save = *dptr;
422cb5caa98Sdjl 
423cb5caa98Sdjl 	ph = (nss_pheader_t *)*dptr;
424cb5caa98Sdjl 	dbd = (nss_dbd_t *)((void *)((char *)ph + ph->dbd_off));
425cb5caa98Sdjl 	if (dbd->o_name != 0)
426cb5caa98Sdjl 		db = (char *)dbd + dbd->o_name;
427606f6aa3Smichen 
428606f6aa3Smichen 	/*
429606f6aa3Smichen 	 * save away a copy of the header, in case the request needs
430606f6aa3Smichen 	 * to be sent to nscd more than once. In that case, this
431606f6aa3Smichen 	 * original header can be copied back to the door buffer
432606f6aa3Smichen 	 * to replace the possibly changed header
433606f6aa3Smichen 	 */
434cb5caa98Sdjl 	ph_save = *ph;
435cb5caa98Sdjl 
436cb5caa98Sdjl 	while (ret == NSS_ALTRETRY || ret == NSS_ALTRESET) {
437cb5caa98Sdjl 		/* try private (back) door first if it exists and applies */
438cb5caa98Sdjl 		if (db != NULL && backd->doorfd > 0 && fb2frontd == 0 &&
439219f483bSandra 		    _nsc_use_backdoor(db)) {
440cb5caa98Sdjl 			ret = _nsc_try1door(backd, dptr, ndata, adata, NULL);
441cb5caa98Sdjl 			if (ret == NSS_ALTRESET) {
442cb5caa98Sdjl 				/*
443cb5caa98Sdjl 				 * received NSS_ALTRESET command,
444cb5caa98Sdjl 				 * retry on front door
445cb5caa98Sdjl 				 */
446cb5caa98Sdjl 				lmutex_lock(&backd->door_lock);
447cb5caa98Sdjl 				backd->doorfd = -1;
448cb5caa98Sdjl 				(void) memset((void *)&backd->doori,
449219f483bSandra 				    '\0', sizeof (door_info_t));
450cb5caa98Sdjl 				/* flush now invalid db list */
451cb5caa98Sdjl 				_nsc_flush_private_db();
452cb5caa98Sdjl 				lmutex_unlock(&backd->door_lock);
453cb5caa98Sdjl 				continue;
454cb5caa98Sdjl 			} else if (ret == NSS_ALTRETRY) {
455cb5caa98Sdjl 				/*
456cb5caa98Sdjl 				 * received NSS_ALTRETRY command,
457cb5caa98Sdjl 				 * fall back and retry on front door
458cb5caa98Sdjl 				 */
459cb5caa98Sdjl 				fb2frontd = 1;
460606f6aa3Smichen 				if (*dptr != dptr_save)
461606f6aa3Smichen 					(void) munmap((void *)*dptr, *ndata);
462606f6aa3Smichen 
463606f6aa3Smichen 				/*
464606f6aa3Smichen 				 * restore the buffer size and header
465606f6aa3Smichen 				 * data so that the front door will
466606f6aa3Smichen 				 * see the original request
467606f6aa3Smichen 				 */
468606f6aa3Smichen 				*ndata = ndata_save;
469606f6aa3Smichen 				*adata = adata_save;
470606f6aa3Smichen 				*dptr = dptr_save;
471606f6aa3Smichen 				ph =  (nss_pheader_t *)*dptr;
472cb5caa98Sdjl 				*ph = ph_save;
473cb5caa98Sdjl 				/*
474cb5caa98Sdjl 				 * tell the front door server, this is
475cb5caa98Sdjl 				 * a fallback call
476cb5caa98Sdjl 				 */
477cb5caa98Sdjl 				ph->p_status = NSS_ALTRETRY;
478cb5caa98Sdjl 				continue;
479cb5caa98Sdjl 			}
480cb5caa98Sdjl 
481cb5caa98Sdjl 			/* return the result or error */
482cb5caa98Sdjl 			break;
483cb5caa98Sdjl 		}
484cb5caa98Sdjl 
485cb5caa98Sdjl 		/* try the front door */
486cb5caa98Sdjl 		fd = -1;
487cb5caa98Sdjl 		ret = _nsc_try1door(frontd, dptr, ndata, adata, &fd);
488cb5caa98Sdjl 
489cb5caa98Sdjl 		if (ret != NSS_ALTRETRY) {
490cb5caa98Sdjl 			/*
491cb5caa98Sdjl 			 * got a success or failure result.
492cb5caa98Sdjl 			 * but front door should never send NSS_ALTRESET
493cb5caa98Sdjl 			 */
494cb5caa98Sdjl 			if (ret == NSS_ALTRESET)
495cb5caa98Sdjl 				/* reset the front door */
496cb5caa98Sdjl 				reset_frontd = 1;
497cb5caa98Sdjl 			else
498cb5caa98Sdjl 				/*
499cb5caa98Sdjl 				 * not NSS_ALTRETRY and not NSS_ALTRESET
500cb5caa98Sdjl 				 * return the result or error
501cb5caa98Sdjl 				 */
502cb5caa98Sdjl 				break;
503cb5caa98Sdjl 		} else if (fb2frontd == 1) {
504cb5caa98Sdjl 			/*
505cb5caa98Sdjl 			 * front door should never send NSS_ALTRETRY
506cb5caa98Sdjl 			 * in a fallback call. Reset the front door.
507cb5caa98Sdjl 			 */
508cb5caa98Sdjl 			reset_frontd = 1;
509cb5caa98Sdjl 		}
510cb5caa98Sdjl 
511cb5caa98Sdjl 		if (reset_frontd == 1) {
512cb5caa98Sdjl 			lmutex_lock(&frontd->door_lock);
513cb5caa98Sdjl 			frontd->doorfd = -1;
514cb5caa98Sdjl 			(void) memset((void *)&frontd->doori,
515219f483bSandra 			    '\0', sizeof (door_info_t));
516cb5caa98Sdjl 			lmutex_unlock(&frontd->door_lock);
517cb5caa98Sdjl 			/* error out */
518cb5caa98Sdjl 			ret = NSS_ERROR;
519cb5caa98Sdjl 			break;
520cb5caa98Sdjl 		}
521cb5caa98Sdjl 
522cb5caa98Sdjl 		/* process NSS_ALTRETRY request from front door */
523cb5caa98Sdjl 		if (fd < 0)
524cb5caa98Sdjl 			continue;	/* no new door given, try again */
525cb5caa98Sdjl 
526cb5caa98Sdjl 		/* update and try alternate door */
527cb5caa98Sdjl 		lmutex_lock(&backd->door_lock);
528cb5caa98Sdjl 		if (backd->doorfd >= 0) {
529cb5caa98Sdjl 			/* unexpected open alt door - clean up, continue */
530cb5caa98Sdjl 			_nsc_flush_private_db();
531cb5caa98Sdjl 			(void) close(backd->doorfd);
532cb5caa98Sdjl 		}
533cb5caa98Sdjl 
534cb5caa98Sdjl 		/* set up back door fd */
535cb5caa98Sdjl 		backd->doorfd = fd;
536cb5caa98Sdjl 
537cb5caa98Sdjl 		/* set up back door db list */
538cb5caa98Sdjl 		ph =  (nss_pheader_t *)*dptr;
539cb5caa98Sdjl 		dbl = ((char *)ph) + ph->data_off;
540cb5caa98Sdjl 
541cb5caa98Sdjl 		if (_nsc_init_private_db(dbl) == 0) {
542cb5caa98Sdjl 			/* could not init db list, try again */
543cb5caa98Sdjl 			(void) close(backd->doorfd);
544cb5caa98Sdjl 			backd->doorfd = -1;
545cb5caa98Sdjl 			lmutex_unlock(&backd->door_lock);
546cb5caa98Sdjl 			continue;
547cb5caa98Sdjl 		}
548cb5caa98Sdjl 		if (door_info(backd->doorfd, &backd->doori) < 0 ||
549219f483bSandra 		    (backd->doori.di_attributes & DOOR_REVOKED) ||
550219f483bSandra 		    backd->doori.di_data !=
551219f483bSandra 		    (uintptr_t)NAME_SERVICE_DOOR_COOKIE) {
552cb5caa98Sdjl 			/* doorfd bad, or must not really be open */
553cb5caa98Sdjl 			(void) close(backd->doorfd);
554cb5caa98Sdjl 			backd->doorfd = -1;
555cb5caa98Sdjl 			(void) memset((void *)&backd->doori,
556219f483bSandra 			    '\0', sizeof (door_info_t));
557cb5caa98Sdjl 		}
558cb5caa98Sdjl 		(void) fcntl(backd->doorfd, F_SETFD, FD_CLOEXEC);
559cb5caa98Sdjl 		lmutex_unlock(&backd->door_lock);
560cb5caa98Sdjl 		/* NSS_ALTRETRY new back door */
561606f6aa3Smichen 		if (*dptr != dptr_save)
562606f6aa3Smichen 			(void) munmap((void *)*dptr, *ndata);
563606f6aa3Smichen 
564606f6aa3Smichen 		/*
565606f6aa3Smichen 		 * restore the buffer size and header
566606f6aa3Smichen 		 * data so that the back door will
567606f6aa3Smichen 		 * see the original request
568606f6aa3Smichen 		 */
569606f6aa3Smichen 		*ndata = ndata_save;
570606f6aa3Smichen 		*adata = adata_save;
571606f6aa3Smichen 		*dptr = dptr_save;
572606f6aa3Smichen 		ph =  (nss_pheader_t *)*dptr;
573cb5caa98Sdjl 		*ph = ph_save;
574cb5caa98Sdjl 	}
575cb5caa98Sdjl 	return (ret);
576cb5caa98Sdjl }
577cb5caa98Sdjl 
578cb5caa98Sdjl /*
579cb5caa98Sdjl  * Get the current (but growable) buffer size for a NSS2 packet.
580cb5caa98Sdjl  * Heuristic algorithm used:
581cb5caa98Sdjl  *	1) Make sure it's at least NSS_BUFLEN_DOOR in length (16k default)
582cb5caa98Sdjl  *	2) if an incoming user buffer is > larger than the current size
583cb5caa98Sdjl  *	   Make the buffer at least NSS_BUFLEN_DOOR/2+user buffer size
584cb5caa98Sdjl  *	   This should account for any reasonable nss_pheader, keys
585cb5caa98Sdjl  *	   extended area etc.
586cb5caa98Sdjl  *	3) keep the prototype/debugging (private)NSS_BUFLEN option
587cb5caa98Sdjl  *	   to change any preconfigured value if needed(?)
588cb5caa98Sdjl  */
589cb5caa98Sdjl 
590cb5caa98Sdjl static size_t
_nsc_getdoorbsize(size_t min_size)591cb5caa98Sdjl _nsc_getdoorbsize(size_t min_size)
592cb5caa98Sdjl {
593cb5caa98Sdjl 	if (!door_bsize) {
594cb5caa98Sdjl 		lmutex_lock(&hints_lock);
595cb5caa98Sdjl 		if (!door_bsize) {
596cb5caa98Sdjl 			/* future work - get nscd hint & use hint size */
597cb5caa98Sdjl 			door_bsize = ROUND_UP(door_bsize, NSS_BUFSIZ);
598cb5caa98Sdjl 			if (door_bsize < NSS_BUFLEN_DOOR) {
599cb5caa98Sdjl 				door_bsize = NSS_BUFLEN_DOOR;
600cb5caa98Sdjl 			}
601cb5caa98Sdjl 		}
602cb5caa98Sdjl 		lmutex_unlock(&hints_lock);
603cb5caa98Sdjl 	}
604cb5caa98Sdjl 	if (min_size && door_bsize < (min_size + NSS_BUFLEN_DOOR/2)) {
605cb5caa98Sdjl 		lmutex_lock(&hints_lock);
606cb5caa98Sdjl 		if (door_bsize < (min_size + NSS_BUFLEN_DOOR/2)) {
607cb5caa98Sdjl 			min_size += NSS_BUFLEN_DOOR;
608cb5caa98Sdjl 			door_bsize = ROUND_UP(min_size, NSS_BUFSIZ);
609cb5caa98Sdjl 		}
610cb5caa98Sdjl 		lmutex_unlock(&hints_lock);
611cb5caa98Sdjl 	}
612cb5caa98Sdjl 	return (door_bsize);
613cb5caa98Sdjl }
614cb5caa98Sdjl 
615cb5caa98Sdjl static void
_nsc_freedbuf(void * arg)616cb5caa98Sdjl _nsc_freedbuf(void *arg)
617cb5caa98Sdjl {
618cb5caa98Sdjl 	nss_XbyY_buf_t *tsdbuf = arg;
619cb5caa98Sdjl 
620cb5caa98Sdjl 	if (tsdbuf != NULL && tsdbuf->buffer != NULL) {
621cb5caa98Sdjl 		lfree(tsdbuf->buffer, (size_t)tsdbuf->buflen);
622cb5caa98Sdjl 		tsdbuf->result = NULL;
623cb5caa98Sdjl 		tsdbuf->buffer = NULL;
624cb5caa98Sdjl 		tsdbuf->buflen = 0;
625cb5caa98Sdjl 	}
626cb5caa98Sdjl }
627cb5caa98Sdjl 
628cb5caa98Sdjl /*
629cb5caa98Sdjl  * _nsc_getdoorbuf - return the client side per thread door buffer
630cb5caa98Sdjl  * Elsewhere, it is assumed that the header is 0'd upon return from here.
631cb5caa98Sdjl  */
632cb5caa98Sdjl 
633cb5caa98Sdjl int
_nsc_getdoorbuf(void ** doorptr,size_t * bufsize)634cb5caa98Sdjl _nsc_getdoorbuf(void **doorptr, size_t *bufsize)
635cb5caa98Sdjl {
636cb5caa98Sdjl 	nss_XbyY_buf_t *tsdbuf;
637cb5caa98Sdjl 	char *bp;
638cb5caa98Sdjl 	size_t dsize;
639cb5caa98Sdjl 
640cb5caa98Sdjl 	if (doorptr == NULL || bufsize == NULL)
641cb5caa98Sdjl 		return (-1);
642cb5caa98Sdjl 
643cb5caa98Sdjl 	/* Get thread specific pointer to door buffer */
644cb5caa98Sdjl 	tsdbuf = tsdalloc(_T_DOORBUF, sizeof (nss_XbyY_buf_t), _nsc_freedbuf);
645cb5caa98Sdjl 	if (tsdbuf == NULL)
646cb5caa98Sdjl 		return (-1);
647cb5caa98Sdjl 
648cb5caa98Sdjl 	/* if door buffer does not exist create it */
649cb5caa98Sdjl 	if (tsdbuf->buffer == NULL) {
650cb5caa98Sdjl 		dsize = _nsc_getdoorbsize(*bufsize);
651cb5caa98Sdjl 
652cb5caa98Sdjl 		/* setup a door buffer with a total length of dsize */
653cb5caa98Sdjl 		bp = lmalloc(dsize);
654cb5caa98Sdjl 		if (bp == NULL)
655cb5caa98Sdjl 			return (-1);
656cb5caa98Sdjl 		tsdbuf->buffer = bp;
657cb5caa98Sdjl 		tsdbuf->buflen = dsize;
658cb5caa98Sdjl 	} else {
659cb5caa98Sdjl 		/* check old buffer size and resize if needed */
660cb5caa98Sdjl 		if (*bufsize) {
661cb5caa98Sdjl 			dsize = _nsc_getdoorbsize(*bufsize);
662cb5caa98Sdjl 			if (tsdbuf->buflen < dsize) {
663cb5caa98Sdjl 				lfree(tsdbuf->buffer, (size_t)tsdbuf->buflen);
664cb5caa98Sdjl 				bp = lmalloc(dsize);
665cb5caa98Sdjl 				if (bp == NULL)
666cb5caa98Sdjl 					return (-1);
667cb5caa98Sdjl 				tsdbuf->buffer = bp;
668cb5caa98Sdjl 				tsdbuf->buflen = dsize;
669cb5caa98Sdjl 			}
670cb5caa98Sdjl 		}
671cb5caa98Sdjl 		/* freshly malloc'd door bufs are 0'd */
672cb5caa98Sdjl 		/* 0 header for now.  Zero entire buf(?) TDB */
673cb5caa98Sdjl 		(void) memset((void *)tsdbuf->buffer, 0,
674219f483bSandra 		    (size_t)sizeof (nss_pheader_t));
675cb5caa98Sdjl 
676cb5caa98Sdjl 	}
677cb5caa98Sdjl 	*doorptr = (void *)tsdbuf->buffer;
678cb5caa98Sdjl 	*bufsize = tsdbuf->buflen;
679cb5caa98Sdjl 	return (0);
680cb5caa98Sdjl }
681cb5caa98Sdjl 
682cb5caa98Sdjl void
_nsc_resizedoorbuf(size_t bsize)683cb5caa98Sdjl _nsc_resizedoorbuf(size_t bsize)
684cb5caa98Sdjl {
685cb5caa98Sdjl 	/* signal to update if new door size is desired */
686cb5caa98Sdjl 	lmutex_lock(&hints_lock);
687cb5caa98Sdjl 	if (bsize > door_bsize && door_nbsize < bsize)
688cb5caa98Sdjl 		door_nbsize = bsize;
689cb5caa98Sdjl 	lmutex_unlock(&hints_lock);
690cb5caa98Sdjl }
691cb5caa98Sdjl 
692cb5caa98Sdjl /*
693cb5caa98Sdjl  * Check uid and /proc/PID/psinfo to see if this process is nscd
694cb5caa98Sdjl  * If it is set the appropriate flags and allow policy reconfiguration.
695cb5caa98Sdjl  */
696cb5caa98Sdjl int
_nsc_proc_is_cache()697cb5caa98Sdjl _nsc_proc_is_cache()
698cb5caa98Sdjl {
699cb5caa98Sdjl 	psinfo_t	pinfo;
700cb5caa98Sdjl 	char		fname[128];
701cb5caa98Sdjl 	int		ret;
702cb5caa98Sdjl 	int		fd;
703cb5caa98Sdjl 
704cb5caa98Sdjl 	if (proc_is_cache >= 0)
705cb5caa98Sdjl 		return (proc_is_cache);
706cb5caa98Sdjl 	lmutex_lock(&hints_lock);
707cb5caa98Sdjl 	if (proc_is_cache >= 0) {
708cb5caa98Sdjl 		lmutex_unlock(&hints_lock);
709cb5caa98Sdjl 		return (proc_is_cache);
710cb5caa98Sdjl 	}
711cb5caa98Sdjl 	proc_is_cache = 0;
712cb5caa98Sdjl 	/* It can't be nscd if it's not running as root... */
713cb5caa98Sdjl 	if (getuid() != 0) {
714cb5caa98Sdjl 		lmutex_unlock(&hints_lock);
715cb5caa98Sdjl 		return (0);
716cb5caa98Sdjl 	}
717cb5caa98Sdjl 	ret = snprintf(fname, 128, "/proc/%d/psinfo", getpid());
718cb5caa98Sdjl 	if (ret > 0 && ret < 128) {
719219f483bSandra 		if ((fd = open(fname,  O_RDONLY)) >= 0) {
720cb5caa98Sdjl 			ret = read(fd, &pinfo, sizeof (psinfo_t));
721cb5caa98Sdjl 			(void) close(fd);
722cb5caa98Sdjl 			if (ret == sizeof (psinfo_t) &&
723cb5caa98Sdjl 			    (strcmp(pinfo.pr_fname, "nscd") == 0)) {
724cb5caa98Sdjl 				/* process runs as root and is named nscd */
725cb5caa98Sdjl 				/* that's good enough for now */
726cb5caa98Sdjl 				proc_is_cache = 1;
727cb5caa98Sdjl 			}
728cb5caa98Sdjl 		}
729cb5caa98Sdjl 	}
730cb5caa98Sdjl 	lmutex_unlock(&hints_lock);
731cb5caa98Sdjl 	return (proc_is_cache);
7327c478bd9Sstevel@tonic-gate }
733