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, ¶m);
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