1 /* $NetBSD: getpwent.c,v 1.75.8.2 2008/12/28 01:18:11 christos Exp $ */
4 * Copyright (c) 1997-2000, 2004-2005 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Copyright (c) 1988, 1993
34 * The Regents of the University of California. All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * Portions Copyright (c) 1994, 1995, Jason Downs. All rights reserved.
64 * Redistribution and use in source and binary forms, with or without
65 * modification, are permitted provided that the following conditions
67 * 1. Redistributions of source code must retain the above copyright
68 * notice, this list of conditions and the following disclaimer.
69 * 2. Redistributions in binary form must reproduce the above copyright
70 * notice, this list of conditions and the following disclaimer in the
71 * documentation and/or other materials provided with the distribution.
73 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
74 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
75 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
76 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
77 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
78 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
79 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
80 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
81 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
82 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
86 #include <sys/cdefs.h>
87 #if defined(LIBC_SCCS) && !defined(lint)
89 static char sccsid
[] = "@(#)getpwent.c 8.2 (Berkeley) 4/27/95";
91 __RCSID("$NetBSD: getpwent.c,v 1.75.8.2 2008/12/28 01:18:11 christos Exp $");
93 #endif /* LIBC_SCCS and not lint */
95 #include "namespace.h"
96 #include "reentrant.h"
98 #include <sys/param.h>
105 #include <netgroup.h>
106 #include <nsswitch.h>
120 #include <machine/param.h>
122 #include <rpcsvc/yp_prot.h>
123 #include <rpcsvc/ypclnt.h>
126 #include "pw_private.h"
128 #define _PASSWD_COMPAT /* "passwd" defaults to compat, so always provide it */
131 __weak_alias(endpwent
,_endpwent
)
132 __weak_alias(getpwent
,_getpwent
)
133 __weak_alias(getpwent_r
,_getpwent_r
)
134 __weak_alias(getpwnam
,_getpwnam
)
135 __weak_alias(getpwnam_r
,_getpwnam_r
)
136 __weak_alias(getpwuid
,_getpwuid
)
137 __weak_alias(getpwuid_r
,_getpwuid_r
)
138 __weak_alias(setpassent
,_setpassent
)
139 __weak_alias(setpwent
,_setpwent
)
143 static mutex_t _pwmutex
= MUTEX_INITIALIZER
;
146 const char __yp_token
[] = "__YP!"; /* Let pwd_mkdb pull this in. */
150 * The pwd.db lookup techniques and data extraction code here must be kept
151 * in sync with that in `pwd_mkdb'.
154 #if defined(YP) || defined(HESIOD)
157 * Parses entry using pw_scan(3) (without the trailing \n)
158 * after copying to buf, and fills in pw with corresponding values.
159 * If old is non-zero, entry is in _PASSWORD_OLDFMT.
160 * Returns 1 if parsed successfully, 0 on parse failure.
163 _pw_parse(const char *entry
, struct passwd
*pw
, char *buf
, size_t buflen
,
168 _DIAGASSERT(entry
!= NULL
);
169 _DIAGASSERT(pw
!= NULL
);
170 _DIAGASSERT(buf
!= NULL
);
172 if (strlcpy(buf
, entry
, buflen
) >= buflen
)
174 flags
= _PASSWORD_NOWARN
;
176 flags
|= _PASSWORD_OLDFMT
;
177 return __pw_scan(buf
, pw
, &flags
);
179 #endif /* YP || HESIOD */
183 * if *db is NULL, dbopen(3) /etc/spwd.db or /etc/pwd.db (depending
184 * upon permissions, etc)
187 _pw_opendb(DB
**db
, int *version
)
193 const char *dbfile
= NULL
;
195 _DIAGASSERT(db
!= NULL
);
196 _DIAGASSERT(version
!= NULL
);
197 if (*db
!= NULL
) /* open *db */
200 if (geteuid() == 0) {
201 dbfile
= _PATH_SMP_DB
;
202 *db
= dbopen(dbfile
, O_RDONLY
, 0, DB_HASH
, NULL
);
205 dbfile
= _PATH_MP_DB
;
206 *db
= dbopen(dbfile
, O_RDONLY
, 0, DB_HASH
, NULL
);
211 syslog(LOG_ERR
, "%s: %m", dbfile
);
217 key
.data
= __UNCONST("VERSION");
218 key
.size
= strlen((char *)key
.data
) + 1;
219 switch ((*(*db
)->get
)(*db
, &key
, &value
, 0)) {
221 if (sizeof(*version
) != value
.size
)
223 (void)memcpy(version
, value
.data
, value
.size
);
226 *version
= 0; /* not found */
229 return NS_UNAVAIL
; /* error in db routines */
238 * Lookup key in *db, filling in pw
239 * with the result, allocating memory from buffer (size buflen).
240 * (The caller may point key.data to buffer on entry; the contents
241 * of key.data will be invalid on exit.)
244 _pw_getkey(DB
*db
, DBT
*key
,
245 struct passwd
*pw
, char *buffer
, size_t buflen
, int *pwflags
,
251 _DIAGASSERT(db
!= NULL
);
252 _DIAGASSERT(key
!= NULL
);
253 _DIAGASSERT(pw
!= NULL
);
254 _DIAGASSERT(buffer
!= NULL
);
255 /* pwflags may be NULL (if we don't care about them */
257 if (db
== NULL
) /* this shouldn't happen */
260 switch ((db
->get
)(db
, key
, &data
, 0)) {
264 return NS_NOTFOUND
; /* not found */
266 return NS_UNAVAIL
; /* error in db routines */
271 p
= (char *)data
.data
;
272 if (data
.size
> buflen
) {
278 * THE DECODING BELOW MUST MATCH THAT IN pwd_mkdb.
281 #define MACRO(a) do { a } while (/*CONSTCOND*/0)
282 #define EXPAND(e) MACRO(e = t; while ((*t++ = *p++));)
283 #define SCALAR(v) MACRO(memmove(&(v), p, sizeof v); p += sizeof v;)
285 EXPAND(pw
->pw_passwd
);
293 SCALAR(pw
->pw_change
);
294 EXPAND(pw
->pw_class
);
295 EXPAND(pw
->pw_gecos
);
297 EXPAND(pw
->pw_shell
);
303 SCALAR(pw
->pw_expire
);
305 /* See if there's any data left. If so, read in flags. */
306 if (data
.size
> (size_t) (p
- (char *)data
.data
)) {
308 } else { /* default */
309 *pwflags
= _PASSWORD_NOUID
|_PASSWORD_NOGID
;
318 * Obtain want bytes from buffer (of size buflen) and return a pointer
319 * to the available memory after adjusting buffer/buflen.
320 * Returns NULL if there is insufficient space.
323 _pw_memfrombuf(size_t want
, char **buffer
, size_t *buflen
)
327 if (want
> *buflen
) {
339 * Copy the contents of frompw to pw; memory for strings
340 * and arrays will be allocated from buf (of size buflen).
341 * If proto != NULL, use various fields in proto in preference to frompw.
342 * Returns 1 if copied successfully, 0 on copy failure.
343 * NOTE: frompw must not use buf for its own pointers.
346 _pw_copy(const struct passwd
*frompw
, struct passwd
*pw
,
347 char *buf
, size_t buflen
, const struct passwd
*protopw
, int protoflags
)
352 _DIAGASSERT(frompw
!= NULL
);
353 _DIAGASSERT(pw
!= NULL
);
354 _DIAGASSERT(buf
!= NULL
);
355 /* protopw may be NULL */
357 useproto
= protopw
&& protopw
->pw_name
;
359 #define COPYSTR(to, from) \
361 count = strlen((from)); \
362 (to) = _pw_memfrombuf(count+1, &buf, &buflen); \
365 memmove((to), (from), count); \
367 } while (0) /* LINTED */
369 #define COPYFIELD(field) COPYSTR(pw->field, frompw->field)
371 #define COPYPROTOFIELD(field) COPYSTR(pw->field, \
372 (useproto && *protopw->field ? protopw->field : frompw->field))
376 #ifdef PW_OVERRIDE_PASSWD
377 COPYPROTOFIELD(pw_passwd
);
379 COPYFIELD(pw_passwd
);
382 if (useproto
&& !(protoflags
& _PASSWORD_NOUID
))
383 pw
->pw_uid
= protopw
->pw_uid
;
385 pw
->pw_uid
= frompw
->pw_uid
;
387 if (useproto
&& !(protoflags
& _PASSWORD_NOGID
))
388 pw
->pw_gid
= protopw
->pw_gid
;
390 pw
->pw_gid
= frompw
->pw_gid
;
392 pw
->pw_change
= frompw
->pw_change
;
394 COPYPROTOFIELD(pw_gecos
);
395 COPYPROTOFIELD(pw_dir
);
396 COPYPROTOFIELD(pw_shell
);
400 #undef COPYPROTOFIELD
410 /* state shared between files methods */
412 int stayopen
; /* see getpassent(3) */
413 DB
*db
; /* passwd file handle */
414 int keynum
; /* key counter, -1 if no more */
418 static struct files_state _files_state
;
419 /* storage for non _r functions */
420 static struct passwd _files_passwd
;
421 static char _files_passwdbuf
[_GETPW_R_SIZE_MAX
];
424 _files_start(struct files_state
*state
)
428 _DIAGASSERT(state
!= NULL
);
431 rv
= _pw_opendb(&state
->db
, &state
->version
);
432 if (rv
!= NS_SUCCESS
)
438 _files_end(struct files_state
*state
)
441 _DIAGASSERT(state
!= NULL
);
445 (void)(state
->db
->close
)(state
->db
);
453 * Search state->db for the next desired entry.
454 * If search is _PW_KEYBYNUM, look for state->keynum.
455 * If search is _PW_KEYBYNAME, look for name.
456 * If search is _PW_KEYBYUID, look for uid.
457 * Sets *retval to the errno if the result is not NS_SUCCESS
461 _files_pwscan(int *retval
, struct passwd
*pw
, char *buffer
, size_t buflen
,
462 struct files_state
*state
, int search
, const char *name
, uid_t uid
)
469 _DIAGASSERT(retval
!= NULL
);
470 _DIAGASSERT(pw
!= NULL
);
471 _DIAGASSERT(buffer
!= NULL
);
472 _DIAGASSERT(state
!= NULL
);
473 /* name is NULL to indicate searching for uid */
477 if (state
->db
== NULL
) { /* only start if file not open yet */
478 rv
= _files_start(state
);
479 if (rv
!= NS_SUCCESS
)
480 goto filespwscan_out
;
483 for (;;) { /* search for a match */
486 if (state
->keynum
== -1)
487 return NS_NOTFOUND
; /* no more records */
489 from
= &state
->keynum
;
490 fromlen
= sizeof(state
->keynum
);
494 fromlen
= strlen(name
);
498 fromlen
= sizeof(uid
);
504 if (buflen
<= fromlen
) { /* buffer too small */
508 buffer
[0] = search
; /* setup key */
509 memmove(buffer
+ 1, from
, fromlen
);
510 key
.size
= fromlen
+ 1;
511 key
.data
= (u_char
*)buffer
;
514 rv
= _pw_getkey(state
->db
, &key
, pw
, buffer
, buflen
, NULL
,
516 if (rv
!= NS_SUCCESS
) /* no match */
518 if (pw
->pw_name
[0] == '+' || pw
->pw_name
[0] == '-') {
519 /* if a compat line */
520 if (search
== _PW_KEYBYNUM
)
521 continue; /* read next if pwent */
522 rv
= NS_NOTFOUND
; /* don't match if pw{nam,uid} */
528 if (rv
== NS_NOTFOUND
&& search
== _PW_KEYBYNUM
)
529 state
->keynum
= -1; /* flag `no more records' */
531 if (rv
== NS_SUCCESS
) {
532 if ((search
== _PW_KEYBYUID
&& pw
->pw_uid
!= uid
) ||
533 (search
== _PW_KEYBYNAME
&& strcmp(pw
->pw_name
, name
) != 0))
538 if (rv
!= NS_SUCCESS
&& rv
!= NS_NOTFOUND
)
545 _files_setpwent(void *nsrv
, void *nscb
, va_list ap
)
548 _files_state
.stayopen
= 0;
549 return _files_start(&_files_state
);
554 _files_setpassent(void *nsrv
, void *nscb
, va_list ap
)
556 int *retval
= va_arg(ap
, int *);
557 int stayopen
= va_arg(ap
, int);
561 _files_state
.stayopen
= stayopen
;
562 rv
= _files_start(&_files_state
);
563 *retval
= (rv
== NS_SUCCESS
);
569 _files_endpwent(void *nsrv
, void *nscb
, va_list ap
)
572 _files_state
.stayopen
= 0;
573 return _files_end(&_files_state
);
578 _files_getpwent(void *nsrv
, void *nscb
, va_list ap
)
580 struct passwd
**retval
= va_arg(ap
, struct passwd
**);
584 _DIAGASSERT(retval
!= NULL
);
587 rv
= _files_pwscan(&rerror
, &_files_passwd
,
588 _files_passwdbuf
, sizeof(_files_passwdbuf
),
589 &_files_state
, _PW_KEYBYNUM
, NULL
, 0);
590 if (rv
== NS_SUCCESS
)
591 *retval
= &_files_passwd
;
597 _files_getpwent_r(void *nsrv
, void *nscb
, va_list ap
)
599 int *retval
= va_arg(ap
, int *);
600 struct passwd
*pw
= va_arg(ap
, struct passwd
*);
601 char *buffer
= va_arg(ap
, char *);
602 size_t buflen
= va_arg(ap
, size_t);
603 struct passwd
**result
= va_arg(ap
, struct passwd
**);
607 _DIAGASSERT(retval
!= NULL
);
608 _DIAGASSERT(pw
!= NULL
);
609 _DIAGASSERT(buffer
!= NULL
);
610 _DIAGASSERT(result
!= NULL
);
612 rv
= _files_pwscan(retval
, pw
, buffer
, buflen
, &_files_state
,
613 _PW_KEYBYNUM
, NULL
, 0);
614 if (rv
== NS_SUCCESS
)
623 _files_getpwnam(void *nsrv
, void *nscb
, va_list ap
)
625 struct passwd
**retval
= va_arg(ap
, struct passwd
**);
626 const char *name
= va_arg(ap
, const char *);
630 _DIAGASSERT(retval
!= NULL
);
633 rv
= _files_start(&_files_state
);
634 if (rv
!= NS_SUCCESS
)
636 rv
= _files_pwscan(&rerror
, &_files_passwd
,
637 _files_passwdbuf
, sizeof(_files_passwdbuf
),
638 &_files_state
, _PW_KEYBYNAME
, name
, 0);
639 if (!_files_state
.stayopen
)
640 _files_end(&_files_state
);
641 if (rv
== NS_SUCCESS
)
642 *retval
= &_files_passwd
;
648 _files_getpwnam_r(void *nsrv
, void *nscb
, va_list ap
)
650 int *retval
= va_arg(ap
, int *);
651 const char *name
= va_arg(ap
, const char *);
652 struct passwd
*pw
= va_arg(ap
, struct passwd
*);
653 char *buffer
= va_arg(ap
, char *);
654 size_t buflen
= va_arg(ap
, size_t);
655 struct passwd
**result
= va_arg(ap
, struct passwd
**);
657 struct files_state state
;
660 _DIAGASSERT(retval
!= NULL
);
661 _DIAGASSERT(pw
!= NULL
);
662 _DIAGASSERT(buffer
!= NULL
);
663 _DIAGASSERT(result
!= NULL
);
666 memset(&state
, 0, sizeof(state
));
667 rv
= _files_pwscan(retval
, pw
, buffer
, buflen
, &state
,
668 _PW_KEYBYNAME
, name
, 0);
670 if (rv
== NS_SUCCESS
)
677 _files_getpwuid(void *nsrv
, void *nscb
, va_list ap
)
679 struct passwd
**retval
= va_arg(ap
, struct passwd
**);
680 uid_t uid
= va_arg(ap
, uid_t
);
684 _DIAGASSERT(retval
!= NULL
);
687 rv
= _files_start(&_files_state
);
688 if (rv
!= NS_SUCCESS
)
690 rv
= _files_pwscan(&rerror
, &_files_passwd
,
691 _files_passwdbuf
, sizeof(_files_passwdbuf
),
692 &_files_state
, _PW_KEYBYUID
, NULL
, uid
);
693 if (!_files_state
.stayopen
)
694 _files_end(&_files_state
);
695 if (rv
== NS_SUCCESS
)
696 *retval
= &_files_passwd
;
702 _files_getpwuid_r(void *nsrv
, void *nscb
, va_list ap
)
704 int *retval
= va_arg(ap
, int *);
705 uid_t uid
= va_arg(ap
, uid_t
);
706 struct passwd
*pw
= va_arg(ap
, struct passwd
*);
707 char *buffer
= va_arg(ap
, char *);
708 size_t buflen
= va_arg(ap
, size_t);
709 struct passwd
**result
= va_arg(ap
, struct passwd
**);
711 struct files_state state
;
714 _DIAGASSERT(retval
!= NULL
);
715 _DIAGASSERT(pw
!= NULL
);
716 _DIAGASSERT(buffer
!= NULL
);
717 _DIAGASSERT(result
!= NULL
);
720 memset(&state
, 0, sizeof(state
));
721 rv
= _files_pwscan(retval
, pw
, buffer
, buflen
, &state
,
722 _PW_KEYBYUID
, NULL
, uid
);
724 if (rv
== NS_SUCCESS
)
735 /* state shared between dns methods */
737 int stayopen
; /* see getpassent(3) */
738 void *context
; /* Hesiod context */
739 int num
; /* passwd index, -1 if no more */
742 static struct dns_state _dns_state
;
743 /* storage for non _r functions */
744 static struct passwd _dns_passwd
;
745 static char _dns_passwdbuf
[_GETPW_R_SIZE_MAX
];
748 _dns_start(struct dns_state
*state
)
751 _DIAGASSERT(state
!= NULL
);
754 if (state
->context
== NULL
) { /* setup Hesiod */
755 if (hesiod_init(&state
->context
) == -1)
763 _dns_end(struct dns_state
*state
)
766 _DIAGASSERT(state
!= NULL
);
769 if (state
->context
) {
770 hesiod_end(state
->context
);
771 state
->context
= NULL
;
778 * Look for the Hesiod name provided in buffer in the NULL-terminated
780 * and decode into pw/buffer/buflen.
783 _dns_pwscan(int *retval
, struct passwd
*pw
, char *buffer
, size_t buflen
,
784 struct dns_state
*state
, const char **zones
)
786 const char **curzone
;
790 _DIAGASSERT(retval
!= NULL
);
791 _DIAGASSERT(pw
!= NULL
);
792 _DIAGASSERT(buffer
!= NULL
);
793 _DIAGASSERT(state
!= NULL
);
794 _DIAGASSERT(zones
!= NULL
);
798 if (state
->context
== NULL
) { /* only start if Hesiod not setup */
799 rv
= _dns_start(state
);
800 if (rv
!= NS_SUCCESS
)
807 for (curzone
= zones
; *curzone
; curzone
++) { /* search zones */
808 hp
= hesiod_resolve(state
->context
, buffer
, *curzone
);
811 if (errno
!= ENOENT
) {
816 if (*curzone
== NULL
)
819 if ((ep
= strchr(hp
[0], '\n')) != NULL
)
820 *ep
= '\0'; /* clear trailing \n */
821 if (_pw_parse(hp
[0], pw
, buffer
, buflen
, 1)) /* validate line */
827 if (rv
!= NS_SUCCESS
&& rv
!= NS_NOTFOUND
)
830 hesiod_free_list(state
->context
, hp
);
836 _dns_setpwent(void *nsrv
, void *nscb
, va_list ap
)
839 _dns_state
.stayopen
= 0;
840 return _dns_start(&_dns_state
);
845 _dns_setpassent(void *nsrv
, void *nscb
, va_list ap
)
847 int *retval
= va_arg(ap
, int *);
848 int stayopen
= va_arg(ap
, int);
852 _dns_state
.stayopen
= stayopen
;
853 rv
= _dns_start(&_dns_state
);
854 *retval
= (rv
== NS_SUCCESS
);
860 _dns_endpwent(void *nsrv
, void *nscb
, va_list ap
)
863 _dns_state
.stayopen
= 0;
864 return _dns_end(&_dns_state
);
869 _dns_getpwent(void *nsrv
, void *nscb
, va_list ap
)
871 struct passwd
**retval
= va_arg(ap
, struct passwd
**);
876 _DIAGASSERT(retval
!= NULL
);
880 if (_dns_state
.num
== -1) /* exhausted search */
883 if (_dns_state
.context
== NULL
) {
884 /* only start if Hesiod not setup */
885 rv
= _dns_start(&_dns_state
);
886 if (rv
!= NS_SUCCESS
)
894 /* find passwd-NNN */
895 snprintf(_dns_passwdbuf
, sizeof(_dns_passwdbuf
),
896 "passwd-%u", _dns_state
.num
);
899 hp
= hesiod_resolve(_dns_state
.context
, _dns_passwdbuf
, "passwd");
906 if ((ep
= strchr(hp
[0], '\n')) != NULL
)
907 *ep
= '\0'; /* clear trailing \n */
909 if (_pw_parse(hp
[0], &_dns_passwd
,
910 _dns_passwdbuf
, sizeof(_dns_passwdbuf
), 1))
912 else { /* dodgy entry, try again */
913 hesiod_free_list(_dns_state
.context
, hp
);
919 hesiod_free_list(_dns_state
.context
, hp
);
920 if (rv
== NS_SUCCESS
)
921 *retval
= &_dns_passwd
;
927 _dns_getpwent_r(void *nsrv
, void *nscb
, va_list ap
)
929 int *retval
= va_arg(ap
, int *);
930 struct passwd
*pw
= va_arg(ap
, struct passwd
*);
931 char *buffer
= va_arg(ap
, char *);
932 size_t buflen
= va_arg(ap
, size_t);
933 struct passwd
**result
= va_arg(ap
, struct passwd
**);
938 _DIAGASSERT(retval
!= NULL
);
939 _DIAGASSERT(pw
!= NULL
);
940 _DIAGASSERT(buffer
!= NULL
);
941 _DIAGASSERT(result
!= NULL
);
945 if (_dns_state
.num
== -1) /* exhausted search */
948 if (_dns_state
.context
== NULL
) {
949 /* only start if Hesiod not setup */
950 rv
= _dns_start(&_dns_state
);
951 if (rv
!= NS_SUCCESS
)
959 /* find passwd-NNN */
960 snprintf(buffer
, buflen
, "passwd-%u", _dns_state
.num
);
963 hp
= hesiod_resolve(_dns_state
.context
, buffer
, "passwd");
970 if ((ep
= strchr(hp
[0], '\n')) != NULL
)
971 *ep
= '\0'; /* clear trailing \n */
973 if (_pw_parse(hp
[0], pw
, buffer
, buflen
, 1))
975 else { /* dodgy entry, try again */
976 hesiod_free_list(_dns_state
.context
, hp
);
982 hesiod_free_list(_dns_state
.context
, hp
);
983 if (rv
== NS_SUCCESS
)
990 static const char *_dns_uid_zones
[] = {
998 _dns_getpwuid(void *nsrv
, void *nscb
, va_list ap
)
1000 struct passwd
**retval
= va_arg(ap
, struct passwd
**);
1001 uid_t uid
= va_arg(ap
, uid_t
);
1005 _DIAGASSERT(retval
!= NULL
);
1008 rv
= _dns_start(&_dns_state
);
1009 if (rv
!= NS_SUCCESS
)
1011 snprintf(_dns_passwdbuf
, sizeof(_dns_passwdbuf
),
1012 "%u", (unsigned int)uid
);
1013 rv
= _dns_pwscan(&rerror
, &_dns_passwd
,
1014 _dns_passwdbuf
, sizeof(_dns_passwdbuf
),
1015 &_dns_state
, _dns_uid_zones
);
1016 if (!_dns_state
.stayopen
)
1017 _dns_end(&_dns_state
);
1018 if (rv
== NS_SUCCESS
&& uid
== _dns_passwd
.pw_uid
)
1019 *retval
= &_dns_passwd
;
1025 _dns_getpwuid_r(void *nsrv
, void *nscb
, va_list ap
)
1027 int *retval
= va_arg(ap
, int *);
1028 uid_t uid
= va_arg(ap
, uid_t
);
1029 struct passwd
*pw
= va_arg(ap
, struct passwd
*);
1030 char *buffer
= va_arg(ap
, char *);
1031 size_t buflen
= va_arg(ap
, size_t);
1032 struct passwd
**result
= va_arg(ap
, struct passwd
**);
1034 struct dns_state state
;
1037 _DIAGASSERT(retval
!= NULL
);
1038 _DIAGASSERT(pw
!= NULL
);
1039 _DIAGASSERT(buffer
!= NULL
);
1040 _DIAGASSERT(result
!= NULL
);
1043 memset(&state
, 0, sizeof(state
));
1044 snprintf(buffer
, buflen
, "%u", (unsigned int)uid
);
1045 rv
= _dns_pwscan(retval
, pw
, buffer
, buflen
, &state
, _dns_uid_zones
);
1047 if (rv
!= NS_SUCCESS
)
1049 if (uid
== pw
->pw_uid
) {
1056 static const char *_dns_nam_zones
[] = {
1063 _dns_getpwnam(void *nsrv
, void *nscb
, va_list ap
)
1065 struct passwd
**retval
= va_arg(ap
, struct passwd
**);
1066 const char *name
= va_arg(ap
, const char *);
1070 _DIAGASSERT(retval
!= NULL
);
1073 rv
= _dns_start(&_dns_state
);
1074 if (rv
!= NS_SUCCESS
)
1076 snprintf(_dns_passwdbuf
, sizeof(_dns_passwdbuf
), "%s", name
);
1077 rv
= _dns_pwscan(&rerror
, &_dns_passwd
,
1078 _dns_passwdbuf
, sizeof(_dns_passwdbuf
),
1079 &_dns_state
, _dns_nam_zones
);
1080 if (!_dns_state
.stayopen
)
1081 _dns_end(&_dns_state
);
1082 if (rv
== NS_SUCCESS
&& strcmp(name
, _dns_passwd
.pw_name
) == 0)
1083 *retval
= &_dns_passwd
;
1089 _dns_getpwnam_r(void *nsrv
, void *nscb
, va_list ap
)
1091 int *retval
= va_arg(ap
, int *);
1092 const char *name
= va_arg(ap
, const char *);
1093 struct passwd
*pw
= va_arg(ap
, struct passwd
*);
1094 char *buffer
= va_arg(ap
, char *);
1095 size_t buflen
= va_arg(ap
, size_t);
1096 struct passwd
**result
= va_arg(ap
, struct passwd
**);
1098 struct dns_state state
;
1101 _DIAGASSERT(retval
!= NULL
);
1102 _DIAGASSERT(pw
!= NULL
);
1103 _DIAGASSERT(buffer
!= NULL
);
1104 _DIAGASSERT(result
!= NULL
);
1107 memset(&state
, 0, sizeof(state
));
1108 snprintf(buffer
, buflen
, "%s", name
);
1109 rv
= _dns_pwscan(retval
, pw
, buffer
, buflen
, &state
, _dns_nam_zones
);
1111 if (rv
!= NS_SUCCESS
)
1113 if (strcmp(name
, pw
->pw_name
) == 0) {
1127 /* state shared between nis methods */
1129 int stayopen
; /* see getpassent(3) */
1130 char *domain
; /* NIS domain */
1131 int done
; /* non-zero if search exhausted */
1132 char *current
; /* current first/next match */
1133 int currentlen
; /* length of _nis_current */
1134 enum { /* shadow map type */
1135 NISMAP_UNKNOWN
, /* unknown ... */
1136 NISMAP_NONE
, /* none: use "passwd.by*" */
1137 NISMAP_ADJUNCT
, /* pw_passwd from "passwd.adjunct.*" */
1138 NISMAP_MASTER
/* all from "master.passwd.by*" */
1142 static struct nis_state _nis_state
;
1143 /* storage for non _r functions */
1144 static struct passwd _nis_passwd
;
1145 static char _nis_passwdbuf
[_GETPW_R_SIZE_MAX
];
1147 /* macros for deciding which NIS maps to use. */
1148 #define PASSWD_BYNAME(x) ((x)->maptype == NISMAP_MASTER \
1149 ? "master.passwd.byname" : "passwd.byname")
1150 #define PASSWD_BYUID(x) ((x)->maptype == NISMAP_MASTER \
1151 ? "master.passwd.byuid" : "passwd.byuid")
1154 _nis_start(struct nis_state
*state
)
1157 _DIAGASSERT(state
!= NULL
);
1160 if (state
->current
) {
1161 free(state
->current
);
1162 state
->current
= NULL
;
1164 if (state
->domain
== NULL
) { /* setup NIS */
1165 switch (yp_get_default_domain(&state
->domain
)) {
1175 /* determine where to get pw_passwd from */
1176 if (state
->maptype
== NISMAP_UNKNOWN
) {
1179 state
->maptype
= NISMAP_NONE
; /* default to no adjunct */
1180 if (geteuid() != 0) /* non-root can't use adjunct */
1183 /* look for "master.passwd.*" */
1184 r
= yp_order(state
->domain
, "master.passwd.byname", &order
);
1186 state
->maptype
= NISMAP_MASTER
;
1190 /* master.passwd doesn't exist, try passwd.adjunct */
1191 if (r
== YPERR_MAP
) {
1192 r
= yp_order(state
->domain
, "passwd.adjunct.byname",
1195 state
->maptype
= NISMAP_ADJUNCT
;
1202 _nis_end(struct nis_state
*state
)
1205 _DIAGASSERT(state
!= NULL
);
1208 state
->domain
= NULL
;
1211 free(state
->current
);
1212 state
->current
= NULL
;
1213 state
->maptype
= NISMAP_UNKNOWN
;
1219 * wrapper to _pw_parse that obtains the real password from the
1220 * "passwd.adjunct.byname" NIS map if the maptype is NISMAP_ADJUNCT.
1223 _nis_parse(const char *entry
, struct passwd
*pw
, char *buf
, size_t buflen
,
1224 struct nis_state
*state
)
1228 _DIAGASSERT(entry
!= NULL
);
1229 _DIAGASSERT(pw
!= NULL
);
1230 _DIAGASSERT(buf
!= NULL
);
1231 _DIAGASSERT(state
!= NULL
);
1233 elen
= strlen(entry
);
1236 if (! _pw_parse(entry
, pw
, buf
, buflen
,
1237 !(state
->maptype
== NISMAP_MASTER
)))
1240 if ((state
->maptype
== NISMAP_ADJUNCT
) &&
1241 (strstr(pw
->pw_passwd
, "##") != NULL
)) {
1245 if (yp_match(state
->domain
, "passwd.adjunct.byname",
1246 pw
->pw_name
, (int)strlen(pw
->pw_name
),
1247 &data
, &datalen
) == 0) {
1249 /* skip name to get password */
1251 if ((bp
= strsep(&ep
, ":")) != NULL
&&
1252 (bp
= strsep(&ep
, ":")) != NULL
) {
1253 /* store new pw_passwd after entry */
1254 strlcpy(buf
+ elen
, bp
, buflen
- elen
);
1255 pw
->pw_passwd
= &buf
[elen
];
1267 * Look for the yp key provided in buffer from map,
1268 * and decode into pw/buffer/buflen.
1271 _nis_pwscan(int *retval
, struct passwd
*pw
, char *buffer
, size_t buflen
,
1272 struct nis_state
*state
, const char *map
)
1275 int nisr
, rv
, datalen
;
1277 _DIAGASSERT(retval
!= NULL
);
1278 _DIAGASSERT(pw
!= NULL
);
1279 _DIAGASSERT(buffer
!= NULL
);
1280 _DIAGASSERT(state
!= NULL
);
1281 _DIAGASSERT(map
!= NULL
);
1285 if (state
->domain
== NULL
) { /* only start if NIS not setup */
1286 rv
= _nis_start(state
);
1287 if (rv
!= NS_SUCCESS
)
1295 nisr
= yp_match(state
->domain
, map
, buffer
, (int)strlen(buffer
),
1299 data
[datalen
] = '\0'; /* clear trailing \n */
1300 if (_nis_parse(data
, pw
, buffer
, buflen
, state
))
1301 rv
= NS_SUCCESS
; /* validate line */
1312 if (rv
!= NS_SUCCESS
&& rv
!= NS_NOTFOUND
)
1321 _nis_setpwent(void *nsrv
, void *nscb
, va_list ap
)
1324 _nis_state
.stayopen
= 0;
1325 return _nis_start(&_nis_state
);
1330 _nis_setpassent(void *nsrv
, void *nscb
, va_list ap
)
1332 int *retval
= va_arg(ap
, int *);
1333 int stayopen
= va_arg(ap
, int);
1337 _nis_state
.stayopen
= stayopen
;
1338 rv
= _nis_start(&_nis_state
);
1339 *retval
= (rv
== NS_SUCCESS
);
1345 _nis_endpwent(void *nsrv
, void *nscb
, va_list ap
)
1348 return _nis_end(&_nis_state
);
1354 _nis_getpwent(void *nsrv
, void *nscb
, va_list ap
)
1356 struct passwd
**retval
= va_arg(ap
, struct passwd
**);
1359 int keylen
, datalen
, rv
, nisr
;
1361 _DIAGASSERT(retval
!= NULL
);
1365 if (_nis_state
.done
) /* exhausted search */
1367 if (_nis_state
.domain
== NULL
) {
1368 /* only start if NIS not setup */
1369 rv
= _nis_start(&_nis_state
);
1370 if (rv
!= NS_SUCCESS
)
1379 if (_nis_state
.current
) { /* already searching */
1380 nisr
= yp_next(_nis_state
.domain
, PASSWD_BYNAME(&_nis_state
),
1381 _nis_state
.current
, _nis_state
.currentlen
,
1382 &key
, &keylen
, &data
, &datalen
);
1383 free(_nis_state
.current
);
1384 _nis_state
.current
= NULL
;
1387 _nis_state
.current
= key
;
1388 _nis_state
.currentlen
= keylen
;
1392 _nis_state
.done
= 1;
1398 } else { /* new search */
1399 if (yp_first(_nis_state
.domain
, PASSWD_BYNAME(&_nis_state
),
1400 &_nis_state
.current
, &_nis_state
.currentlen
,
1407 data
[datalen
] = '\0'; /* clear trailing \n */
1409 if (_nis_parse(data
, &_nis_passwd
,
1410 _nis_passwdbuf
, sizeof(_nis_passwdbuf
), &_nis_state
))
1412 else { /* dodgy entry, try again */
1414 goto next_nis_entry
;
1422 if (rv
== NS_SUCCESS
)
1423 *retval
= &_nis_passwd
;
1429 _nis_getpwent_r(void *nsrv
, void *nscb
, va_list ap
)
1431 int *retval
= va_arg(ap
, int *);
1432 struct passwd
*pw
= va_arg(ap
, struct passwd
*);
1433 char *buffer
= va_arg(ap
, char *);
1434 size_t buflen
= va_arg(ap
, size_t);
1435 struct passwd
**result
= va_arg(ap
, struct passwd
**);
1438 int keylen
, datalen
, rv
, nisr
;
1440 _DIAGASSERT(retval
!= NULL
);
1441 _DIAGASSERT(pw
!= NULL
);
1442 _DIAGASSERT(buffer
!= NULL
);
1443 _DIAGASSERT(result
!= NULL
);
1447 if (_nis_state
.done
) /* exhausted search */
1449 if (_nis_state
.domain
== NULL
) {
1450 /* only start if NIS not setup */
1451 rv
= _nis_start(&_nis_state
);
1452 if (rv
!= NS_SUCCESS
)
1461 if (_nis_state
.current
) { /* already searching */
1462 nisr
= yp_next(_nis_state
.domain
, PASSWD_BYNAME(&_nis_state
),
1463 _nis_state
.current
, _nis_state
.currentlen
,
1464 &key
, &keylen
, &data
, &datalen
);
1465 free(_nis_state
.current
);
1466 _nis_state
.current
= NULL
;
1469 _nis_state
.current
= key
;
1470 _nis_state
.currentlen
= keylen
;
1474 _nis_state
.done
= 1;
1480 } else { /* new search */
1481 if (yp_first(_nis_state
.domain
, PASSWD_BYNAME(&_nis_state
),
1482 &_nis_state
.current
, &_nis_state
.currentlen
,
1489 data
[datalen
] = '\0'; /* clear trailing \n */
1491 if (_nis_parse(data
, pw
, buffer
, buflen
, &_nis_state
))
1493 else { /* dodgy entry, try again */
1497 goto next_nis_entry
;
1505 if (rv
== NS_SUCCESS
)
1514 _nis_getpwuid(void *nsrv
, void *nscb
, va_list ap
)
1516 struct passwd
**retval
= va_arg(ap
, struct passwd
**);
1517 uid_t uid
= va_arg(ap
, uid_t
);
1521 _DIAGASSERT(retval
!= NULL
);
1524 rv
= _nis_start(&_nis_state
);
1525 if (rv
!= NS_SUCCESS
)
1527 snprintf(_nis_passwdbuf
, sizeof(_nis_passwdbuf
), "%u", (unsigned int)uid
);
1528 rv
= _nis_pwscan(&rerror
, &_nis_passwd
,
1529 _nis_passwdbuf
, sizeof(_nis_passwdbuf
),
1530 &_nis_state
, PASSWD_BYUID(&_nis_state
));
1531 if (!_nis_state
.stayopen
)
1532 _nis_end(&_nis_state
);
1533 if (rv
== NS_SUCCESS
&& uid
== _nis_passwd
.pw_uid
)
1534 *retval
= &_nis_passwd
;
1540 _nis_getpwuid_r(void *nsrv
, void *nscb
, va_list ap
)
1542 int *retval
= va_arg(ap
, int *);
1543 uid_t uid
= va_arg(ap
, uid_t
);
1544 struct passwd
*pw
= va_arg(ap
, struct passwd
*);
1545 char *buffer
= va_arg(ap
, char *);
1546 size_t buflen
= va_arg(ap
, size_t);
1547 struct passwd
**result
= va_arg(ap
, struct passwd
**);
1549 struct nis_state state
;
1552 _DIAGASSERT(retval
!= NULL
);
1553 _DIAGASSERT(pw
!= NULL
);
1554 _DIAGASSERT(buffer
!= NULL
);
1555 _DIAGASSERT(result
!= NULL
);
1558 memset(&state
, 0, sizeof(state
));
1559 rv
= _nis_start(&state
);
1560 if (rv
!= NS_SUCCESS
)
1562 snprintf(buffer
, buflen
, "%u", (unsigned int)uid
);
1563 rv
= _nis_pwscan(retval
, pw
, buffer
, buflen
,
1564 &state
, PASSWD_BYUID(&state
));
1566 if (rv
!= NS_SUCCESS
)
1568 if (uid
== pw
->pw_uid
) {
1577 _nis_getpwnam(void *nsrv
, void *nscb
, va_list ap
)
1579 struct passwd
**retval
= va_arg(ap
, struct passwd
**);
1580 const char *name
= va_arg(ap
, const char *);
1584 _DIAGASSERT(retval
!= NULL
);
1587 rv
= _nis_start(&_nis_state
);
1588 if (rv
!= NS_SUCCESS
)
1590 snprintf(_nis_passwdbuf
, sizeof(_nis_passwdbuf
), "%s", name
);
1591 rv
= _nis_pwscan(&rerror
, &_nis_passwd
,
1592 _nis_passwdbuf
, sizeof(_nis_passwdbuf
),
1593 &_nis_state
, PASSWD_BYNAME(&_nis_state
));
1594 if (!_nis_state
.stayopen
)
1595 _nis_end(&_nis_state
);
1596 if (rv
== NS_SUCCESS
&& strcmp(name
, _nis_passwd
.pw_name
) == 0)
1597 *retval
= &_nis_passwd
;
1603 _nis_getpwnam_r(void *nsrv
, void *nscb
, va_list ap
)
1605 int *retval
= va_arg(ap
, int *);
1606 const char *name
= va_arg(ap
, const char *);
1607 struct passwd
*pw
= va_arg(ap
, struct passwd
*);
1608 char *buffer
= va_arg(ap
, char *);
1609 size_t buflen
= va_arg(ap
, size_t);
1610 struct passwd
**result
= va_arg(ap
, struct passwd
**);
1612 struct nis_state state
;
1615 _DIAGASSERT(retval
!= NULL
);
1616 _DIAGASSERT(pw
!= NULL
);
1617 _DIAGASSERT(buffer
!= NULL
);
1618 _DIAGASSERT(result
!= NULL
);
1621 snprintf(buffer
, buflen
, "%s", name
);
1622 memset(&state
, 0, sizeof(state
));
1623 rv
= _nis_start(&state
);
1624 if (rv
!= NS_SUCCESS
)
1626 rv
= _nis_pwscan(retval
, pw
, buffer
, buflen
,
1627 &state
, PASSWD_BYNAME(&state
));
1629 if (rv
!= NS_SUCCESS
)
1631 if (strcmp(name
, pw
->pw_name
) == 0) {
1641 #ifdef _PASSWD_COMPAT
1646 /* state shared between compat methods */
1648 struct compat_state
{
1649 int stayopen
; /* see getpassent(3) */
1650 DB
*db
; /* passwd DB */
1651 int keynum
; /* key counter, -1 if no more */
1652 enum { /* current compat mode */
1653 COMPAT_NOTOKEN
= 0, /* no compat token present */
1654 COMPAT_NONE
, /* parsing normal pwd.db line */
1655 COMPAT_FULL
, /* parsing `+' entries */
1656 COMPAT_USER
, /* parsing `+name' entries */
1657 COMPAT_NETGROUP
/* parsing `+@netgroup' entries */
1659 char *user
; /* COMPAT_USER "+name" */
1660 DB
*exclude
; /* compat exclude DB */
1661 struct passwd proto
; /* proto passwd entry */
1662 char protobuf
[_GETPW_R_SIZE_MAX
];
1663 /* buffer for proto ptrs */
1664 int protoflags
; /* proto passwd flags */
1668 static struct compat_state _compat_state
;
1669 /* storage for non _r functions */
1670 static struct passwd _compat_passwd
;
1671 static char _compat_passwdbuf
[_GETPW_R_SIZE_MAX
];
1674 _compat_start(struct compat_state
*state
)
1678 _DIAGASSERT(state
!= NULL
);
1681 if (state
->db
== NULL
) { /* not open yet */
1684 char bf
[MAXLOGNAME
];
1686 rv
= _pw_opendb(&state
->db
, &state
->version
);
1687 if (rv
!= NS_SUCCESS
)
1690 state
->mode
= COMPAT_NOTOKEN
;
1693 * Determine if the "compat" token is present in pwd.db;
1694 * either "__YP!" or PW_KEYBYNAME+"+".
1695 * Only works if pwd_mkdb installs the token.
1697 key
.data
= (u_char
*)__UNCONST(__yp_token
);
1698 key
.size
= strlen(__yp_token
);
1700 bf
[0] = _PW_KEYBYNAME
; /* Pre-token database support. */
1702 pkey
.data
= (u_char
*)bf
;
1705 if ((state
->db
->get
)(state
->db
, &key
, &data
, 0) == 0
1706 || (state
->db
->get
)(state
->db
, &pkey
, &pdata
, 0) == 0)
1707 state
->mode
= COMPAT_NONE
;
1713 _compat_end(struct compat_state
*state
)
1716 _DIAGASSERT(state
!= NULL
);
1720 (void)(state
->db
->close
)(state
->db
);
1723 state
->mode
= COMPAT_NOTOKEN
;
1727 if (state
->exclude
!= NULL
)
1728 (void)(state
->exclude
->close
)(state
->exclude
);
1729 state
->exclude
= NULL
;
1730 state
->proto
.pw_name
= NULL
;
1731 state
->protoflags
= 0;
1736 * _compat_add_exclude
1737 * add the name to the exclude list in state->exclude.
1740 _compat_add_exclude(struct compat_state
*state
, const char *name
)
1744 _DIAGASSERT(state
!= NULL
);
1745 _DIAGASSERT(name
!= NULL
);
1747 /* initialize the exclusion table if needed */
1748 if (state
->exclude
== NULL
) {
1749 state
->exclude
= dbopen(NULL
, O_RDWR
, 600, DB_HASH
, NULL
);
1750 if (state
->exclude
== NULL
)
1754 key
.size
= strlen(name
); /* set up the key */
1755 key
.data
= (u_char
*)__UNCONST(name
);
1757 data
.data
= NULL
; /* data is nothing */
1761 if ((state
->exclude
->put
)(state
->exclude
, &key
, &data
, 0) == -1)
1768 * _compat_is_excluded
1769 * test if a name is on the compat mode exclude list
1772 _compat_is_excluded(struct compat_state
*state
, const char *name
)
1776 _DIAGASSERT(state
!= NULL
);
1777 _DIAGASSERT(name
!= NULL
);
1779 if (state
->exclude
== NULL
)
1780 return 0; /* nothing excluded */
1782 key
.size
= strlen(name
); /* set up the key */
1783 key
.data
= (u_char
*)__UNCONST(name
);
1785 if ((state
->exclude
->get
)(state
->exclude
, &key
, &data
, 0) == 0)
1786 return 1; /* is excluded */
1794 * log an error if "files" or "compat" is specified in
1795 * passwd_compat database
1799 _passwdcompat_bad(void *nsrv
, void *nscb
, va_list ap
)
1803 _DIAGASSERT(nsrv
!= NULL
);
1804 _DIAGASSERT(nscb
!= NULL
);
1808 "nsswitch.conf passwd_compat database can't use '%s'",
1816 * _passwdcompat_setpassent
1817 * Call setpassent for all passwd_compat sources.
1820 _passwdcompat_setpassent(int stayopen
)
1822 static const ns_dtab dtab
[] = {
1823 NS_FILES_CB(_passwdcompat_bad
, "files")
1824 NS_DNS_CB(_dns_setpassent
, NULL
)
1825 NS_NIS_CB(_nis_setpassent
, NULL
)
1826 NS_COMPAT_CB(_passwdcompat_bad
, "compat")
1832 rv
= nsdispatch(NULL
, dtab
, NSDB_PASSWD_COMPAT
, "setpassent",
1833 __nsdefaultnis_forceall
, &result
, stayopen
);
1838 * _passwdcompat_endpwent
1839 * Call endpwent for all passwd_compat sources.
1842 _passwdcompat_endpwent(void)
1844 static const ns_dtab dtab
[] = {
1845 NS_FILES_CB(_passwdcompat_bad
, "files")
1846 NS_DNS_CB(_dns_endpwent
, NULL
)
1847 NS_NIS_CB(_nis_endpwent
, NULL
)
1848 NS_COMPAT_CB(_passwdcompat_bad
, "compat")
1852 return nsdispatch(NULL
, dtab
, NSDB_PASSWD_COMPAT
, "endpwent",
1853 __nsdefaultnis_forceall
);
1857 * _passwdcompat_pwscan
1858 * When a name lookup in compat mode is required (e.g., `+name', or a
1859 * name in `+@netgroup'), look it up in the 'passwd_compat' nsswitch
1861 * Fail if passwd_compat contains files or compat.
1864 _passwdcompat_pwscan(struct passwd
*pw
, char *buffer
, size_t buflen
,
1865 int search
, const char *name
, uid_t uid
)
1867 static const ns_dtab compatentdtab
[] = {
1868 NS_FILES_CB(_passwdcompat_bad
, "files")
1869 NS_DNS_CB(_dns_getpwent_r
, NULL
)
1870 NS_NIS_CB(_nis_getpwent_r
, NULL
)
1871 NS_COMPAT_CB(_passwdcompat_bad
, "compat")
1874 static const ns_dtab compatuiddtab
[] = {
1875 NS_FILES_CB(_passwdcompat_bad
, "files")
1876 NS_DNS_CB(_dns_getpwuid_r
, NULL
)
1877 NS_NIS_CB(_nis_getpwuid_r
, NULL
)
1878 NS_COMPAT_CB(_passwdcompat_bad
, "compat")
1881 static const ns_dtab compatnamdtab
[] = {
1882 NS_FILES_CB(_passwdcompat_bad
, "files")
1883 NS_DNS_CB(_dns_getpwnam_r
, NULL
)
1884 NS_NIS_CB(_nis_getpwnam_r
, NULL
)
1885 NS_COMPAT_CB(_passwdcompat_bad
, "compat")
1894 rv
= nsdispatch(NULL
, compatentdtab
,
1895 NSDB_PASSWD_COMPAT
, "getpwent_r", __nsdefaultnis
,
1896 &crv
, pw
, buffer
, buflen
, &cpw
);
1899 _DIAGASSERT(name
!= NULL
);
1900 rv
= nsdispatch(NULL
, compatnamdtab
,
1901 NSDB_PASSWD_COMPAT
, "getpwnam_r", __nsdefaultnis
,
1902 &crv
, name
, pw
, buffer
, buflen
, &cpw
);
1905 rv
= nsdispatch(NULL
, compatuiddtab
,
1906 NSDB_PASSWD_COMPAT
, "getpwuid_r", __nsdefaultnis
,
1907 &crv
, uid
, pw
, buffer
, buflen
, &cpw
);
1918 * Search state->db for the next desired entry.
1919 * If search is _PW_KEYBYNUM, look for state->keynum.
1920 * If search is _PW_KEYBYNAME, look for name.
1921 * If search is _PW_KEYBYUID, look for uid.
1922 * Sets *retval to the errno if the result is not NS_SUCCESS
1926 _compat_pwscan(int *retval
, struct passwd
*pw
, char *buffer
, size_t buflen
,
1927 struct compat_state
*state
, int search
, const char *name
, uid_t uid
)
1931 const char *user
, *host
, *dom
;
1935 _DIAGASSERT(retval
!= NULL
);
1936 _DIAGASSERT(pw
!= NULL
);
1937 _DIAGASSERT(buffer
!= NULL
);
1938 _DIAGASSERT(state
!= NULL
);
1939 /* name may be NULL */
1943 if (state
->db
== NULL
) {
1944 rv
= _compat_start(state
);
1945 if (rv
!= NS_SUCCESS
)
1948 if (buflen
<= 1) { /* buffer too small */
1953 for (;;) { /* loop over pwd.db */
1955 if (state
->mode
!= COMPAT_NOTOKEN
&&
1956 state
->mode
!= COMPAT_NONE
) {
1957 /* doing a compat lookup */
1959 char cbuf
[_GETPW_R_SIZE_MAX
];
1961 switch (state
->mode
) {
1964 /* get next user or lookup by key */
1965 rv
= _passwdcompat_pwscan(&cpw
,
1966 cbuf
, sizeof(cbuf
), search
, name
, uid
);
1967 if (rv
!= NS_SUCCESS
)
1968 state
->mode
= COMPAT_NONE
;
1971 case COMPAT_NETGROUP
:
1972 /* XXXREENTRANT: getnetgrent is not thread safe */
1973 /* get next user from netgroup */
1974 r
= getnetgrent(&host
, &user
, &dom
);
1975 if (r
== 0) { /* end of group */
1977 state
->mode
= COMPAT_NONE
;
1980 if (!user
|| !*user
)
1982 rv
= _passwdcompat_pwscan(&cpw
,
1984 _PW_KEYBYNAME
, user
, 0);
1988 /* get specific user */
1989 if (state
->user
== NULL
) {
1990 state
->mode
= COMPAT_NONE
;
1993 rv
= _passwdcompat_pwscan(&cpw
,
1995 _PW_KEYBYNAME
, state
->user
, 0);
1998 state
->mode
= COMPAT_NONE
;
2001 case COMPAT_NOTOKEN
:
2006 if (rv
!= NS_SUCCESS
) /* if not matched, next loop */
2009 /* copy cpw to pw, applying prototype */
2010 if (! _pw_copy(&cpw
, pw
, buffer
, buflen
,
2011 &state
->proto
, state
->protoflags
)) {
2016 if (_compat_is_excluded(state
, pw
->pw_name
))
2017 continue; /* excluded; next loop */
2019 if ((search
== _PW_KEYBYNAME
2020 && strcmp(pw
->pw_name
, name
) != 0)
2021 || (search
== _PW_KEYBYUID
&& pw
->pw_uid
!= uid
)) {
2022 continue; /* not specific; next loop */
2025 break; /* exit loop if found */
2026 } else { /* not a compat line */
2027 state
->proto
.pw_name
= NULL
;
2028 /* clear prototype */
2031 if (state
->mode
== COMPAT_NOTOKEN
) {
2032 /* no compat token; do direct lookup */
2035 if (state
->keynum
== -1) /* no more records */
2038 from
= &state
->keynum
;
2039 fromlen
= sizeof(state
->keynum
);
2043 fromlen
= strlen(name
);
2047 fromlen
= sizeof(uid
);
2054 /* compat token; do line by line */
2055 if (state
->keynum
== -1) /* no more records */
2058 from
= &state
->keynum
;
2059 fromlen
= sizeof(state
->keynum
);
2060 buffer
[0] = _PW_KEYBYNUM
;
2063 if (buflen
<= fromlen
) { /* buffer too small */
2067 memmove(buffer
+ 1, from
, fromlen
); /* setup key */
2068 key
.size
= fromlen
+ 1;
2069 key
.data
= (u_char
*)buffer
;
2071 rv
= _pw_getkey(state
->db
, &key
, pw
, buffer
, buflen
, &pwflags
,
2073 if (rv
!= NS_SUCCESS
) /* stop on error */
2076 if (state
->mode
== COMPAT_NOTOKEN
)
2077 break; /* stop if no compat token */
2079 if (pw
->pw_name
[0] == '+') {
2080 /* compat inclusion */
2081 switch(pw
->pw_name
[1]) {
2082 case '\0': /* `+' */
2083 state
->mode
= COMPAT_FULL
;
2084 /* reset passwd_compat search */
2085 /* XXXREENTRANT: setpassent is not thread safe ? */
2086 (void) _passwdcompat_setpassent(0);
2088 case '@': /* `+@netgroup' */
2089 state
->mode
= COMPAT_NETGROUP
;
2090 /* reset netgroup search */
2091 /* XXXREENTRANT: setnetgrent is not thread safe */
2092 setnetgrent(pw
->pw_name
+ 2);
2094 default: /* `+name' */
2095 state
->mode
= COMPAT_USER
;
2098 state
->user
= strdup(pw
->pw_name
+ 1);
2101 /* save the prototype */
2102 state
->protoflags
= pwflags
;
2103 if (! _pw_copy(pw
, &state
->proto
, state
->protobuf
,
2104 sizeof(state
->protobuf
), NULL
, 0)) {
2108 continue; /* loop again after inclusion */
2109 } else if (pw
->pw_name
[0] == '-') {
2110 /* compat exclusion */
2112 switch(pw
->pw_name
[1]) {
2113 case '\0': /* `-' */
2115 case '@': /* `-@netgroup' */
2116 /* XXXREENTRANT: {set,get,end}netgrent is not thread safe */
2117 setnetgrent(pw
->pw_name
+ 2);
2118 while (getnetgrent(&host
, &user
, &dom
)) {
2119 if (!user
|| !*user
)
2121 if (! _compat_add_exclude(state
,user
)) {
2128 default: /* `-name' */
2129 if (! _compat_add_exclude(state
,
2135 if (rv
!= NS_SUCCESS
) /* exclusion failure */
2137 continue; /* loop again after exclusion */
2139 if (search
== _PW_KEYBYNUM
||
2140 (search
== _PW_KEYBYUID
&& pw
->pw_uid
== uid
) ||
2141 (search
== _PW_KEYBYNAME
&& strcmp(pw
->pw_name
, name
) == 0))
2142 break; /* token mode match found */
2145 if (rv
== NS_NOTFOUND
&&
2146 (search
== _PW_KEYBYNUM
|| state
->mode
!= COMPAT_NOTOKEN
))
2147 state
->keynum
= -1; /* flag `no more records' */
2149 if (rv
== NS_SUCCESS
) {
2150 if ((search
== _PW_KEYBYNAME
&& strcmp(pw
->pw_name
, name
) != 0)
2151 || (search
== _PW_KEYBYUID
&& pw
->pw_uid
!= uid
))
2155 if (rv
!= NS_SUCCESS
&& rv
!= NS_NOTFOUND
)
2162 _compat_setpwent(void *nsrv
, void *nscb
, va_list ap
)
2165 /* force passwd_compat setpwent() */
2166 (void) _passwdcompat_setpassent(0);
2168 /* reset state, keep db open */
2169 _compat_state
.stayopen
= 0;
2170 return _compat_start(&_compat_state
);
2175 _compat_setpassent(void *nsrv
, void *nscb
, va_list ap
)
2177 int *retval
= va_arg(ap
, int *);
2178 int stayopen
= va_arg(ap
, int);
2182 /* force passwd_compat setpassent() */
2183 (void) _passwdcompat_setpassent(stayopen
);
2185 _compat_state
.stayopen
= stayopen
;
2186 rv
= _compat_start(&_compat_state
);
2187 *retval
= (rv
== NS_SUCCESS
);
2193 _compat_endpwent(void *nsrv
, void *nscb
, va_list ap
)
2196 /* force passwd_compat endpwent() */
2197 (void) _passwdcompat_endpwent();
2199 /* reset state, close db */
2200 _compat_state
.stayopen
= 0;
2201 return _compat_end(&_compat_state
);
2207 _compat_getpwent(void *nsrv
, void *nscb
, va_list ap
)
2209 struct passwd
**retval
= va_arg(ap
, struct passwd
**);
2213 _DIAGASSERT(retval
!= NULL
);
2216 rv
= _compat_pwscan(&rerror
, &_compat_passwd
,
2217 _compat_passwdbuf
, sizeof(_compat_passwdbuf
),
2218 &_compat_state
, _PW_KEYBYNUM
, NULL
, 0);
2219 if (rv
== NS_SUCCESS
)
2220 *retval
= &_compat_passwd
;
2226 _compat_getpwent_r(void *nsrv
, void *nscb
, va_list ap
)
2228 int *retval
= va_arg(ap
, int *);
2229 struct passwd
*pw
= va_arg(ap
, struct passwd
*);
2230 char *buffer
= va_arg(ap
, char *);
2231 size_t buflen
= va_arg(ap
, size_t);
2232 struct passwd
**result
= va_arg(ap
, struct passwd
**);
2236 _DIAGASSERT(retval
!= NULL
);
2237 _DIAGASSERT(pw
!= NULL
);
2238 _DIAGASSERT(buffer
!= NULL
);
2239 _DIAGASSERT(result
!= NULL
);
2241 rv
= _compat_pwscan(retval
, pw
, buffer
, buflen
, &_compat_state
,
2242 _PW_KEYBYNUM
, NULL
, 0);
2243 if (rv
== NS_SUCCESS
)
2253 _compat_getpwnam(void *nsrv
, void *nscb
, va_list ap
)
2255 struct passwd
**retval
= va_arg(ap
, struct passwd
**);
2256 const char *name
= va_arg(ap
, const char *);
2260 _DIAGASSERT(retval
!= NULL
);
2263 rv
= _compat_start(&_compat_state
);
2264 if (rv
!= NS_SUCCESS
)
2266 rv
= _compat_pwscan(&rerror
, &_compat_passwd
,
2267 _compat_passwdbuf
, sizeof(_compat_passwdbuf
),
2268 &_compat_state
, _PW_KEYBYNAME
, name
, 0);
2269 if (!_compat_state
.stayopen
)
2270 _compat_end(&_compat_state
);
2271 if (rv
== NS_SUCCESS
)
2272 *retval
= &_compat_passwd
;
2278 _compat_getpwnam_r(void *nsrv
, void *nscb
, va_list ap
)
2280 int *retval
= va_arg(ap
, int *);
2281 const char *name
= va_arg(ap
, const char *);
2282 struct passwd
*pw
= va_arg(ap
, struct passwd
*);
2283 char *buffer
= va_arg(ap
, char *);
2284 size_t buflen
= va_arg(ap
, size_t);
2285 struct passwd
**result
= va_arg(ap
, struct passwd
**);
2287 struct compat_state state
;
2290 _DIAGASSERT(retval
!= NULL
);
2291 _DIAGASSERT(pw
!= NULL
);
2292 _DIAGASSERT(buffer
!= NULL
);
2293 _DIAGASSERT(result
!= NULL
);
2296 memset(&state
, 0, sizeof(state
));
2297 rv
= _compat_pwscan(retval
, pw
, buffer
, buflen
, &state
,
2298 _PW_KEYBYNAME
, name
, 0);
2299 _compat_end(&state
);
2300 if (rv
== NS_SUCCESS
)
2307 _compat_getpwuid(void *nsrv
, void *nscb
, va_list ap
)
2309 struct passwd
**retval
= va_arg(ap
, struct passwd
**);
2310 uid_t uid
= va_arg(ap
, uid_t
);
2314 _DIAGASSERT(retval
!= NULL
);
2317 rv
= _compat_start(&_compat_state
);
2318 if (rv
!= NS_SUCCESS
)
2320 rv
= _compat_pwscan(&rerror
, &_compat_passwd
,
2321 _compat_passwdbuf
, sizeof(_compat_passwdbuf
),
2322 &_compat_state
, _PW_KEYBYUID
, NULL
, uid
);
2323 if (!_compat_state
.stayopen
)
2324 _compat_end(&_compat_state
);
2325 if (rv
== NS_SUCCESS
)
2326 *retval
= &_compat_passwd
;
2332 _compat_getpwuid_r(void *nsrv
, void *nscb
, va_list ap
)
2334 int *retval
= va_arg(ap
, int *);
2335 uid_t uid
= va_arg(ap
, uid_t
);
2336 struct passwd
*pw
= va_arg(ap
, struct passwd
*);
2337 char *buffer
= va_arg(ap
, char *);
2338 size_t buflen
= va_arg(ap
, size_t);
2339 struct passwd
**result
= va_arg(ap
, struct passwd
**);
2341 struct compat_state state
;
2344 _DIAGASSERT(retval
!= NULL
);
2345 _DIAGASSERT(pw
!= NULL
);
2346 _DIAGASSERT(buffer
!= NULL
);
2347 _DIAGASSERT(result
!= NULL
);
2350 memset(&state
, 0, sizeof(state
));
2351 rv
= _compat_pwscan(retval
, pw
, buffer
, buflen
, &state
,
2352 _PW_KEYBYUID
, NULL
, uid
);
2353 _compat_end(&state
);
2354 if (rv
== NS_SUCCESS
)
2359 #endif /* _PASSWD_COMPAT */
2370 struct passwd
*retval
;
2372 static const ns_dtab dtab
[] = {
2373 NS_FILES_CB(_files_getpwent
, NULL
)
2374 NS_DNS_CB(_dns_getpwent
, NULL
)
2375 NS_NIS_CB(_nis_getpwent
, NULL
)
2376 NS_COMPAT_CB(_compat_getpwent
, NULL
)
2380 mutex_lock(&_pwmutex
);
2381 r
= nsdispatch(NULL
, dtab
, NSDB_PASSWD
, "getpwent", __nsdefaultcompat
,
2383 mutex_unlock(&_pwmutex
);
2384 return (r
== NS_SUCCESS
) ? retval
: NULL
;
2388 getpwent_r(struct passwd
*pwd
, char *buffer
, size_t buflen
,
2389 struct passwd
**result
)
2393 static const ns_dtab dtab
[] = {
2394 NS_FILES_CB(_files_getpwent_r
, NULL
)
2395 NS_DNS_CB(_dns_getpwent_r
, NULL
)
2396 NS_NIS_CB(_nis_getpwent_r
, NULL
)
2397 NS_COMPAT_CB(_compat_getpwent_r
, NULL
)
2401 _DIAGASSERT(pwd
!= NULL
);
2402 _DIAGASSERT(buffer
!= NULL
);
2403 _DIAGASSERT(result
!= NULL
);
2407 mutex_lock(&_pwmutex
);
2408 r
= nsdispatch(NULL
, dtab
, NSDB_PASSWD
, "getpwent_r", __nsdefaultcompat
,
2409 &retval
, pwd
, buffer
, buflen
, result
);
2410 mutex_unlock(&_pwmutex
);
2422 getpwnam(const char *name
)
2425 struct passwd
*retval
;
2427 static const ns_dtab dtab
[] = {
2428 NS_FILES_CB(_files_getpwnam
, NULL
)
2429 NS_DNS_CB(_dns_getpwnam
, NULL
)
2430 NS_NIS_CB(_nis_getpwnam
, NULL
)
2431 NS_COMPAT_CB(_compat_getpwnam
, NULL
)
2435 mutex_lock(&_pwmutex
);
2436 rv
= nsdispatch(NULL
, dtab
, NSDB_PASSWD
, "getpwnam", __nsdefaultcompat
,
2438 mutex_unlock(&_pwmutex
);
2439 return (rv
== NS_SUCCESS
) ? retval
: NULL
;
2443 getpwnam_r(const char *name
, struct passwd
*pwd
, char *buffer
, size_t buflen
,
2444 struct passwd
**result
)
2448 static const ns_dtab dtab
[] = {
2449 NS_FILES_CB(_files_getpwnam_r
, NULL
)
2450 NS_DNS_CB(_dns_getpwnam_r
, NULL
)
2451 NS_NIS_CB(_nis_getpwnam_r
, NULL
)
2452 NS_COMPAT_CB(_compat_getpwnam_r
, NULL
)
2456 _DIAGASSERT(name
!= NULL
);
2457 _DIAGASSERT(pwd
!= NULL
);
2458 _DIAGASSERT(buffer
!= NULL
);
2459 _DIAGASSERT(result
!= NULL
);
2463 mutex_lock(&_pwmutex
);
2464 r
= nsdispatch(NULL
, dtab
, NSDB_PASSWD
, "getpwnam_r", __nsdefaultcompat
,
2465 &retval
, name
, pwd
, buffer
, buflen
, result
);
2466 mutex_unlock(&_pwmutex
);
2480 struct passwd
*retval
;
2482 static const ns_dtab dtab
[] = {
2483 NS_FILES_CB(_files_getpwuid
, NULL
)
2484 NS_DNS_CB(_dns_getpwuid
, NULL
)
2485 NS_NIS_CB(_nis_getpwuid
, NULL
)
2486 NS_COMPAT_CB(_compat_getpwuid
, NULL
)
2490 mutex_lock(&_pwmutex
);
2491 rv
= nsdispatch(NULL
, dtab
, NSDB_PASSWD
, "getpwuid", __nsdefaultcompat
,
2493 mutex_unlock(&_pwmutex
);
2494 return (rv
== NS_SUCCESS
) ? retval
: NULL
;
2498 getpwuid_r(uid_t uid
, struct passwd
*pwd
, char *buffer
, size_t buflen
,
2499 struct passwd
**result
)
2503 static const ns_dtab dtab
[] = {
2504 NS_FILES_CB(_files_getpwuid_r
, NULL
)
2505 NS_DNS_CB(_dns_getpwuid_r
, NULL
)
2506 NS_NIS_CB(_nis_getpwuid_r
, NULL
)
2507 NS_COMPAT_CB(_compat_getpwuid_r
, NULL
)
2511 _DIAGASSERT(pwd
!= NULL
);
2512 _DIAGASSERT(buffer
!= NULL
);
2513 _DIAGASSERT(result
!= NULL
);
2517 mutex_lock(&_pwmutex
);
2518 r
= nsdispatch(NULL
, dtab
, NSDB_PASSWD
, "getpwuid_r", __nsdefaultcompat
,
2519 &retval
, uid
, pwd
, buffer
, buflen
, result
);
2520 mutex_unlock(&_pwmutex
);
2533 static const ns_dtab dtab
[] = {
2534 NS_FILES_CB(_files_endpwent
, NULL
)
2535 NS_DNS_CB(_dns_endpwent
, NULL
)
2536 NS_NIS_CB(_nis_endpwent
, NULL
)
2537 NS_COMPAT_CB(_compat_endpwent
, NULL
)
2541 mutex_lock(&_pwmutex
);
2542 /* force all endpwent() methods */
2543 (void) nsdispatch(NULL
, dtab
, NSDB_PASSWD
, "endpwent",
2544 __nsdefaultcompat_forceall
);
2545 mutex_unlock(&_pwmutex
);
2550 setpassent(int stayopen
)
2552 static const ns_dtab dtab
[] = {
2553 NS_FILES_CB(_files_setpassent
, NULL
)
2554 NS_DNS_CB(_dns_setpassent
, NULL
)
2555 NS_NIS_CB(_nis_setpassent
, NULL
)
2556 NS_COMPAT_CB(_compat_setpassent
, NULL
)
2561 mutex_lock(&_pwmutex
);
2562 /* force all setpassent() methods */
2563 rv
= nsdispatch(NULL
, dtab
, NSDB_PASSWD
, "setpassent",
2564 __nsdefaultcompat_forceall
, &retval
, stayopen
);
2565 mutex_unlock(&_pwmutex
);
2566 return (rv
== NS_SUCCESS
) ? retval
: 0;
2572 static const ns_dtab dtab
[] = {
2573 NS_FILES_CB(_files_setpwent
, NULL
)
2574 NS_DNS_CB(_dns_setpwent
, NULL
)
2575 NS_NIS_CB(_nis_setpwent
, NULL
)
2576 NS_COMPAT_CB(_compat_setpwent
, NULL
)
2580 mutex_lock(&_pwmutex
);
2581 /* force all setpwent() methods */
2582 (void) nsdispatch(NULL
, dtab
, NSDB_PASSWD
, "setpwent",
2583 __nsdefaultcompat_forceall
);
2584 mutex_unlock(&_pwmutex
);