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