usr/src/lib/libc/port/gen/getxby_door.c
changeset 2830 5228d1267a01
parent 1016 a2290e972fca
child 4142 0d7fa83a8b00
--- a/usr/src/lib/libc/port/gen/getxby_door.c	Fri Sep 29 05:15:47 2006 -0700
+++ b/usr/src/lib/libc/port/gen/getxby_door.c	Fri Sep 29 06:00:17 2006 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -21,7 +20,7 @@
  */
 
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -30,18 +29,32 @@
 #include "synonyms.h"
 #include <mtlib.h>
 #include <sys/types.h>
+#include <errno.h>
 #include <pwd.h>
 #include <nss_dbdefs.h>
 #include <stdio.h>
+#include <string.h>
 #include <synch.h>
 #include <sys/param.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <stdlib.h>
 #include <getxby_door.h>
 #include <sys/door.h>
+#include <procfs.h>
+#include <door.h>
 #include "libc.h"
+#include "tsd.h"
 #include "base_conversion.h"
 
+/* nss<->door hints */
+static mutex_t	hints_lock = DEFAULTMUTEX;
+static size_t	door_bsize = 0;
+static size_t	door_nbsize = 0;
+static int	proc_is_cache = -1;
+
+/* library<->nscd door interaction apis */
+
 /*
  *
  * Routine that actually performs the door call.
@@ -65,7 +78,7 @@
  *	and we're a multi-threaded application.  Note that we cannot protect
  *	the application if it closes the fd and it is multi-threaded.
  *
- *  int _nsc_trydoorcall(void *dptr, int *bufsize, int *actualsize);
+ *  int _nsc_trydoorcall(void *dptr, size_t *bufsize, size_t *actualsize);
  *
  *      *dptr           IN: points to arg buffer OUT: points to results buffer
  *      *bufsize        IN: overall size of buffer OUT: overall size of buffer
@@ -80,36 +93,166 @@
  *
  */
 
-static mutex_t	_door_lock = DEFAULTMUTEX;
+/*
+ * Max size for list of db names supported by the private nscd
+ * No implied max here, any size will do, fixed size chosen to
+ * reduce yet another malloc
+ */
+
+#define	BD_BUFSIZE	1024
+#define	BD_SEP		','
+
+typedef struct _nsc_door_t {
+	int 		doorfd;
+	mutex_t		door_lock;
+	door_info_t 	doori;
+} nsc_door_t;
+
+static nsc_door_t	nsc_door[2] = {
+	{ -1, DEFAULTMUTEX, { 0 } },		/* front (fattached) door */
+	{ -1, DEFAULTMUTEX, { 0 } },		/* back (private) door */
+};
+
+/* assumed to be locked by using nsc_door[1] mutex */
+static char	*nsc_db_buf = NULL;
+static char	**nsc_db_list = NULL;
 
-int
-_nsc_trydoorcall(nsc_data_t **dptr, int *ndata, int *adata)
+/*
+ * Check for a valid and matching db in the list.
+ * assume list is in the locked state.
+ */
+
+static int
+_nsc_use_backdoor(char *db)
+{
+	char 	**ndb;
+
+	if (db && nsc_db_buf != NULL && nsc_db_list != NULL) {
+		for (ndb = nsc_db_list; *ndb; ndb++) {
+			if (strcmp(db, *ndb) == 0)
+				return (1);
+		}
+	}
+	return (0);
+}
+
+/*
+ * flush private db lists
+ */
+static void
+_nsc_flush_private_db()
 {
-	static	int 		doorfd = -1;
-	static	door_info_t 	real_door;
+	if (nsc_db_buf != NULL) {
+		libc_free((void *)nsc_db_buf);
+		nsc_db_buf = NULL;
+	}
+	if (nsc_db_list != NULL) {
+		libc_free((void *)nsc_db_list);
+		nsc_db_list = NULL;
+	}
+}
+
+/*
+ * init/update nsc_db_buf given buff containing list of
+ * db's to be processed by a private nscd.
+ * This function assumes it has a well formed string from nscd.
+ */
+
+static int
+_nsc_init_private_db(char *dblist)
+{
+	char	*cp, **lp;
+	int	buflen = 0;
+	int	arrlen = 0;
+
+	if (dblist == NULL)
+		return (0);
+
+	/* reset db list */
+	_nsc_flush_private_db();
+
+	/* rebuild fresh list */
+	buflen = strlen(dblist) + 1;
+	for (cp = dblist; *cp; cp++)
+		if (*cp == BD_SEP)
+			arrlen++;
+	if (cp == dblist)
+		return (0);
+	arrlen += 2;
+	nsc_db_buf = (char *)libc_malloc(buflen);
+	if (nsc_db_buf == (char *)NULL)
+		return (0);
+	nsc_db_list = (char **)libc_malloc(arrlen * sizeof (char *));
+	if (nsc_db_list == (char **)NULL) {
+		libc_free((void *)nsc_db_buf);
+		nsc_db_buf = NULL;
+		return (0);
+	}
+	(void) memcpy(nsc_db_buf, dblist, buflen);
+	lp = nsc_db_list;
+	*lp++ = nsc_db_buf;
+	for (cp = nsc_db_buf; *cp; ) {
+		if (*cp == BD_SEP) {
+			*cp++ = '\0';
+			*lp++ = cp;
+		} else
+			cp++;
+	}
+	*lp = NULL;
+	return (1);
+}
+
+/*
+ * _nsc_initdoor_fp attempts to validate the given door and
+ * confirm that it is still available for use.  The options are:
+ *	Front door:
+ *		If it's not open, attempt to open or error
+ *		If it's open attempt to validate.
+ *		If it's not validatable, reset fd and try again.
+ *		Other wise it open and validated, return success
+ *	Per user (back) door:
+ *		This door is passed to the client through th front door
+ *		attempt to validate it.  If it can't be validated, it
+ *		must be reset. Then send a NSS_ALTRESET error, so nscd can
+ *		forward another fd if desired.
+ */
+
+static nss_status_t
+_nsc_initdoor_fp(nsc_door_t *dp)
+{
+
 	door_info_t 		my_door;
-	door_arg_t		param;
+
+	if (dp == NULL) {
+		errno = ENOTCONN;
+		return (NSS_ERROR);
+	}
 
 	/*
-	 * the first time in we try and open and validate the door.
-	 * the validations are that the door must have been
-	 * created with the name service door cookie and
-	 * that the file attached to the door is owned by root
-	 * and readonly by user, group and other.  If any of these
-	 * validations fail we refuse to use the door.
+	 * the first time in we try and open and validate the front door.
+	 * A front door request may return an alternate private back door
+	 * that the client should use instead.
+	 *
+	 * To validate a door the door must have been created with
+	 * the name service door cookie. The front door is file
+	 * attached, owned by root and readonly by user, group and
+	 * other.  If any of these validations fail we refuse to use
+	 * the door.  A back door is delivered from the front door
+	 * via a door_desc_t, and have the same cooke notification.
 	 */
 
-	lmutex_lock(&_door_lock);
+	lmutex_lock(&dp->door_lock);
 
 try_again:
 
-	if (doorfd == -1) {
+	if (dp->doorfd == -1 && dp == &nsc_door[0]) {	/* open front door */
 		int		tbc[3];
 		int		i;
 
-		if ((doorfd = open64(NAME_SERVICE_DOOR, O_RDONLY, 0)) == -1) {
-			lmutex_unlock(&_door_lock);
-			return (NOSERVER);
+		dp->doorfd = open64(NAME_SERVICE_DOOR, O_RDONLY, 0);
+		if (dp->doorfd == -1) {
+			lmutex_unlock(&dp->door_lock);
+			return (NSS_ERROR);
 		}
 
 		/*
@@ -118,14 +261,14 @@
 		 */
 		i = 0;
 
-		while (doorfd < 3) { /* we have a reserved fd */
-			tbc[i++] = doorfd;
-			if ((doorfd = dup(doorfd)) < 0) {
+		while (dp->doorfd < 3) { /* we have a reserved fd */
+			tbc[i++] = dp->doorfd;
+			if ((dp->doorfd = dup(dp->doorfd)) < 0) {
 				while (i--)
 				    (void) close(tbc[i]);
-				doorfd = -1;
-				lmutex_unlock(&_door_lock);
-				return (NOSERVER);
+				dp->doorfd = -1;
+				lmutex_unlock(&dp->door_lock);
+				return (NSS_ERROR);
 			}
 		}
 
@@ -135,38 +278,76 @@
 		/*
 		 * mark this door descriptor as close on exec
 		 */
-		(void) fcntl(doorfd, F_SETFD, FD_CLOEXEC);
-		if (__door_info(doorfd, &real_door) == -1 ||
-		    (real_door.di_attributes & DOOR_REVOKED) ||
-		    real_door.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE) {
+		(void) fcntl(dp->doorfd, F_SETFD, FD_CLOEXEC);
+		if (__door_info(dp->doorfd, &dp->doori) < 0 ||
+		    (dp->doori.di_attributes & DOOR_REVOKED) ||
+		    dp->doori.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE) {
 			/*
 			 * we should close doorfd because we just opened it
 			 */
-			(void) close(doorfd);
-			doorfd = -1;
-			lmutex_unlock(&_door_lock);
-			return (NOSERVER);
+			(void) close(dp->doorfd);
+			dp->doorfd = -1;
+			(void) memset((void *)&dp->doori,
+					'\0', sizeof (door_info_t));
+			lmutex_unlock(&dp->door_lock);
+			errno = ECONNREFUSED;
+			return (NSS_ERROR);
 		}
 	} else {
-		if (__door_info(doorfd, &my_door) == -1 ||
+		if (__door_info(dp->doorfd, &my_door) < 0 ||
 		    my_door.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE ||
-		    my_door.di_uniquifier != real_door.di_uniquifier) {
+		    my_door.di_uniquifier != dp->doori.di_uniquifier) {
 			/*
 			 * don't close it -
 			 * someone else has clobbered fd
 			 */
-			doorfd = -1;
+			dp->doorfd = -1;
+			(void) memset((void *)&dp->doori,
+					'\0', sizeof (door_info_t));
+			if (dp == &nsc_door[1]) {	/* reset back door */
+				/* flush invalid db list */
+				_nsc_flush_private_db();
+				lmutex_unlock(&dp->door_lock);
+				return (NSS_ALTRESET);
+			}
 			goto try_again;
 		}
 
 		if (my_door.di_attributes & DOOR_REVOKED) {
-			(void) close(doorfd);	/* nscd exited .... */
-			doorfd = -1;	/* try and restart connection */
+			(void) close(dp->doorfd);	/* nscd exited .... */
+			dp->doorfd = -1;	/* try and restart connection */
+			(void) memset((void *)&dp->doori,
+					'\0', sizeof (door_info_t));
+			if (dp == &nsc_door[1]) {	/* back door reset */
+				/* flush invalid db list */
+				_nsc_flush_private_db();
+				lmutex_unlock(&dp->door_lock);
+				return (NSS_ALTRESET);
+			}
 			goto try_again;
 		}
 	}
 
-	lmutex_unlock(&_door_lock);
+	lmutex_unlock(&dp->door_lock);
+	return (NSS_SUCCESS);
+}
+
+/*
+ * Try the door request once only, to the specified connection.
+ * return the results or error.
+ */
+
+static nss_status_t
+_nsc_try1door(nsc_door_t *dp, void **dptr, size_t *ndata,
+			size_t *adata, int *pdesc)
+{
+	door_arg_t		param;
+	int			ret;
+	nss_pheader_t		*rp;
+
+	ret = _nsc_initdoor_fp(dp);
+	if (ret != NSS_SUCCESS)
+		return (ret);
 
 	param.rbuf = (char *)*dptr;
 	param.rsize = *ndata;
@@ -174,15 +355,346 @@
 	param.data_size = *adata;
 	param.desc_ptr = NULL;
 	param.desc_num = 0;
-	if (__door_call(doorfd, &param) == -1) {
-		return (NOSERVER);
+	ret = __door_call(dp->doorfd, &param);
+	if (ret < 0) {
+		return (NSS_ERROR);
 	}
-	*adata = (int)param.data_size;
-	*ndata = (int)param.rsize;
-	*dptr = (nsc_data_t *)(uintptr_t)param.data_ptr;
+	*adata = param.data_size;
+	*ndata = param.rsize;
+	*dptr = (void *)param.data_ptr;
+	rp = (nss_pheader_t *)((void *)param.rbuf);
+	if (pdesc != NULL && rp && rp->p_status == NSS_ALTRETRY &&
+	    param.desc_ptr != NULL && param.desc_num > 0) {
+		if ((param.desc_ptr->d_attributes & DOOR_DESCRIPTOR) &&
+		    param.desc_ptr->d_data.d_desc.d_descriptor >= 0 &&
+		    param.desc_ptr->d_data.d_desc.d_id != 0) {
+			/* have an alt descriptor */
+			*pdesc = param.desc_ptr->d_data.d_desc.d_descriptor;
+			/* got a NSS_ALTRETRY command */
+			return (NSS_ALTRETRY);
+		}
+		errno = EINVAL;
+		return (NSS_ERROR);		/* other error? */
+	}
 	if (*adata == 0 || *dptr == NULL) {
-		return (NOSERVER);
+		errno = ENOTCONN;
+		return (NSS_ERROR);
 	}
 
-	return ((*dptr)->nsc_ret.nsc_return_code);
+	if (rp->p_status == NSS_ALTRESET ||
+		rp->p_status == NSS_ALTRETRY ||
+		rp->p_status == NSS_TRYLOCAL)
+		return (rp->p_status);
+
+	return (NSS_SUCCESS);
+}
+
+/*
+ * Backwards compatible API
+ */
+
+nss_status_t
+_nsc_trydoorcall(void **dptr, size_t *ndata, size_t *adata)
+{
+	return (_nsc_try1door(&nsc_door[0], dptr, ndata, adata, NULL));
 }
+
+/*
+ * Send the request to the designated door, based on the supplied db
+ * Retry on the alternate door fd if possible.
+ */
+
+nss_status_t
+_nsc_trydoorcall_ext(void **dptr, size_t *ndata, size_t *adata)
+{
+	int		ret = NSS_ALTRETRY;
+	nsc_door_t	*frontd = &nsc_door[0];
+	nsc_door_t	*backd = &nsc_door[1];
+	int		fd;
+
+	nss_pheader_t	*ph, ph_save;
+	char		*dbl;
+	char		*db = NULL;
+	nss_dbd_t	*dbd;
+	int		fb2frontd = 0;
+	int		reset_frontd = 0;
+
+	ph = (nss_pheader_t *)*dptr;
+	dbd = (nss_dbd_t *)((void *)((char *)ph + ph->dbd_off));
+	if (dbd->o_name != 0)
+		db = (char *)dbd + dbd->o_name;
+	ph_save = *ph;
+
+	while (ret == NSS_ALTRETRY || ret == NSS_ALTRESET) {
+		/* try private (back) door first if it exists and applies */
+		if (db != NULL && backd->doorfd > 0 && fb2frontd == 0 &&
+				_nsc_use_backdoor(db)) {
+			ret = _nsc_try1door(backd, dptr, ndata, adata, NULL);
+			if (ret == NSS_ALTRESET) {
+				/*
+				 * received NSS_ALTRESET command,
+				 * retry on front door
+				 */
+				lmutex_lock(&backd->door_lock);
+				backd->doorfd = -1;
+				(void) memset((void *)&backd->doori,
+					'\0', sizeof (door_info_t));
+				/* flush now invalid db list */
+				_nsc_flush_private_db();
+				lmutex_unlock(&backd->door_lock);
+				continue;
+			} else if (ret == NSS_ALTRETRY) {
+				/*
+				 * received NSS_ALTRETRY command,
+				 * fall back and retry on front door
+				 */
+				fb2frontd = 1;
+				*ph = ph_save;
+				/*
+				 * tell the front door server, this is
+				 * a fallback call
+				 */
+				ph->p_status = NSS_ALTRETRY;
+				continue;
+			}
+
+			/* return the result or error */
+			break;
+		}
+
+		/* try the front door */
+		fd = -1;
+		ret = _nsc_try1door(frontd, dptr, ndata, adata, &fd);
+
+		if (ret != NSS_ALTRETRY) {
+			/*
+			 * got a success or failure result.
+			 * but front door should never send NSS_ALTRESET
+			 */
+			if (ret == NSS_ALTRESET)
+				/* reset the front door */
+				reset_frontd = 1;
+			else
+				/*
+				 * not NSS_ALTRETRY and not NSS_ALTRESET
+				 * return the result or error
+				 */
+				break;
+		} else if (fb2frontd == 1) {
+			/*
+			 * front door should never send NSS_ALTRETRY
+			 * in a fallback call. Reset the front door.
+			 */
+			reset_frontd = 1;
+		}
+
+		if (reset_frontd == 1) {
+			lmutex_lock(&frontd->door_lock);
+			frontd->doorfd = -1;
+			(void) memset((void *)&frontd->doori,
+				'\0', sizeof (door_info_t));
+			lmutex_unlock(&frontd->door_lock);
+			/* error out */
+			ret = NSS_ERROR;
+			break;
+		}
+
+		/* process NSS_ALTRETRY request from front door */
+		if (fd < 0)
+			continue;	/* no new door given, try again */
+
+		/* update and try alternate door */
+		lmutex_lock(&backd->door_lock);
+		if (backd->doorfd >= 0) {
+			/* unexpected open alt door - clean up, continue */
+			_nsc_flush_private_db();
+			(void) close(backd->doorfd);
+		}
+
+		/* set up back door fd */
+		backd->doorfd = fd;
+
+		/* set up back door db list */
+		ph =  (nss_pheader_t *)*dptr;
+		dbl = ((char *)ph) + ph->data_off;
+
+		if (_nsc_init_private_db(dbl) == 0) {
+			/* could not init db list, try again */
+			(void) close(backd->doorfd);
+			backd->doorfd = -1;
+			lmutex_unlock(&backd->door_lock);
+			continue;
+		}
+		if (door_info(backd->doorfd, &backd->doori) < 0 ||
+				(backd->doori.di_attributes & DOOR_REVOKED) ||
+				backd->doori.di_data !=
+				(uintptr_t)NAME_SERVICE_DOOR_COOKIE) {
+			/* doorfd bad, or must not really be open */
+			(void) close(backd->doorfd);
+			backd->doorfd = -1;
+			(void) memset((void *)&backd->doori,
+				'\0', sizeof (door_info_t));
+		}
+		(void) fcntl(backd->doorfd, F_SETFD, FD_CLOEXEC);
+		lmutex_unlock(&backd->door_lock);
+		/* NSS_ALTRETRY new back door */
+		*ph = ph_save;
+	}
+	return (ret);
+}
+
+/*
+ * Get the current (but growable) buffer size for a NSS2 packet.
+ * Heuristic algorithm used:
+ *	1) Make sure it's at least NSS_BUFLEN_DOOR in length (16k default)
+ *	2) if an incoming user buffer is > larger than the current size
+ *	   Make the buffer at least NSS_BUFLEN_DOOR/2+user buffer size
+ *	   This should account for any reasonable nss_pheader, keys
+ *	   extended area etc.
+ *	3) keep the prototype/debugging (private)NSS_BUFLEN option
+ *	   to change any preconfigured value if needed(?)
+ */
+
+static size_t
+_nsc_getdoorbsize(size_t min_size)
+{
+	if (!door_bsize) {
+		lmutex_lock(&hints_lock);
+		if (!door_bsize) {
+			/* future work - get nscd hint & use hint size */
+			door_bsize = ROUND_UP(door_bsize, NSS_BUFSIZ);
+			if (door_bsize < NSS_BUFLEN_DOOR) {
+				door_bsize = NSS_BUFLEN_DOOR;
+			}
+		}
+		lmutex_unlock(&hints_lock);
+	}
+	if (min_size && door_bsize < (min_size + NSS_BUFLEN_DOOR/2)) {
+		lmutex_lock(&hints_lock);
+		if (door_bsize < (min_size + NSS_BUFLEN_DOOR/2)) {
+			min_size += NSS_BUFLEN_DOOR;
+			door_bsize = ROUND_UP(min_size, NSS_BUFSIZ);
+		}
+		lmutex_unlock(&hints_lock);
+	}
+	return (door_bsize);
+}
+
+static void
+_nsc_freedbuf(void *arg)
+{
+	nss_XbyY_buf_t *tsdbuf = arg;
+
+	if (tsdbuf != NULL && tsdbuf->buffer != NULL) {
+		lfree(tsdbuf->buffer, (size_t)tsdbuf->buflen);
+		tsdbuf->result = NULL;
+		tsdbuf->buffer = NULL;
+		tsdbuf->buflen = 0;
+	}
+}
+
+/*
+ * _nsc_getdoorbuf - return the client side per thread door buffer
+ * Elsewhere, it is assumed that the header is 0'd upon return from here.
+ */
+
+int
+_nsc_getdoorbuf(void **doorptr, size_t *bufsize)
+{
+	nss_XbyY_buf_t *tsdbuf;
+	char *bp;
+	size_t dsize;
+
+	if (doorptr == NULL || bufsize == NULL)
+		return (-1);
+
+	/* Get thread specific pointer to door buffer */
+	tsdbuf = tsdalloc(_T_DOORBUF, sizeof (nss_XbyY_buf_t), _nsc_freedbuf);
+	if (tsdbuf == NULL)
+		return (-1);
+
+	/* if door buffer does not exist create it */
+	if (tsdbuf->buffer == NULL) {
+		dsize = _nsc_getdoorbsize(*bufsize);
+
+		/* setup a door buffer with a total length of dsize */
+		bp = lmalloc(dsize);
+		if (bp == NULL)
+			return (-1);
+		tsdbuf->buffer = bp;
+		tsdbuf->buflen = dsize;
+	} else {
+		/* check old buffer size and resize if needed */
+		if (*bufsize) {
+			dsize = _nsc_getdoorbsize(*bufsize);
+			if (tsdbuf->buflen < dsize) {
+				lfree(tsdbuf->buffer, (size_t)tsdbuf->buflen);
+				bp = lmalloc(dsize);
+				if (bp == NULL)
+					return (-1);
+				tsdbuf->buffer = bp;
+				tsdbuf->buflen = dsize;
+			}
+		}
+		/* freshly malloc'd door bufs are 0'd */
+		/* 0 header for now.  Zero entire buf(?) TDB */
+		(void) memset((void *)tsdbuf->buffer, 0,
+				(size_t)sizeof (nss_pheader_t));
+
+	}
+	*doorptr = (void *)tsdbuf->buffer;
+	*bufsize = tsdbuf->buflen;
+	return (0);
+}
+
+void
+_nsc_resizedoorbuf(size_t bsize)
+{
+	/* signal to update if new door size is desired */
+	lmutex_lock(&hints_lock);
+	if (bsize > door_bsize && door_nbsize < bsize)
+		door_nbsize = bsize;
+	lmutex_unlock(&hints_lock);
+}
+
+/*
+ * Check uid and /proc/PID/psinfo to see if this process is nscd
+ * If it is set the appropriate flags and allow policy reconfiguration.
+ */
+int
+_nsc_proc_is_cache()
+{
+	psinfo_t	pinfo;
+	char		fname[128];
+	int		ret;
+	int		fd;
+
+	if (proc_is_cache >= 0)
+		return (proc_is_cache);
+	lmutex_lock(&hints_lock);
+	if (proc_is_cache >= 0) {
+		lmutex_unlock(&hints_lock);
+		return (proc_is_cache);
+	}
+	proc_is_cache = 0;
+	/* It can't be nscd if it's not running as root... */
+	if (getuid() != 0) {
+		lmutex_unlock(&hints_lock);
+		return (0);
+	}
+	ret = snprintf(fname, 128, "/proc/%d/psinfo", getpid());
+	if (ret > 0 && ret < 128) {
+		if ((fd = open(fname,  O_RDONLY)) > 0) {
+			ret = read(fd, &pinfo, sizeof (psinfo_t));
+			(void) close(fd);
+			if (ret == sizeof (psinfo_t) &&
+			    (strcmp(pinfo.pr_fname, "nscd") == 0)) {
+				/* process runs as root and is named nscd */
+				/* that's good enough for now */
+				proc_is_cache = 1;
+			}
+		}
+	}
+	lmutex_unlock(&hints_lock);
+	return (proc_is_cache);
+}