2 * Copyright (c) 2003 Networks Associates Technology, Inc.
5 * This software was developed for the FreeBSD Project by
6 * Jacques A. Vidrine, Safeport Network Services, and Network
7 * Associates Laboratories, the Security Research Division of Network
8 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
9 * ("CBOSS"), as part of the DARPA CHATS research program.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * $FreeBSD: src/lib/libc/gen/getgrent.c,v 1.37 2007/12/12 10:08:02 bushman Exp $
35 #include "namespace.h"
36 #include <sys/param.h>
39 #include <rpcsvc/yp_prot.h>
40 #include <rpcsvc/ypclnt.h>
51 #include <pthread_np.h>
57 #include "un-namespace.h"
58 #include "libc_private.h"
65 GRP_STORAGE_INITIAL
= 1 << 10, /* 1 KByte */
66 GRP_STORAGE_MAX
= 1 << 20, /* 1 MByte */
69 HESIOD_NAME_MAX
= 256,
72 static const ns_src defaultsrc
[] = {
73 { NSSRC_COMPAT
, NS_SUCCESS
},
77 int __getgroupmembership(const char *, gid_t
, gid_t
*, int, int *);
78 int __gr_match_entry(const char *, size_t, enum nss_lookup_type
,
80 int __gr_parse_entry(char *, size_t, struct group
*, char *, size_t,
83 static int is_comment_line(const char *, size_t);
89 static struct group
*getgr(int (*)(union key
, struct group
*, char *, size_t,
90 struct group
**), union key
);
91 static int wrap_getgrnam_r(union key
, struct group
*, char *, size_t,
93 static int wrap_getgrgid_r(union key
, struct group
*, char *, size_t,
95 static int wrap_getgrent_r(union key
, struct group
*, char *, size_t,
102 static void files_endstate(void *);
103 NSS_TLS_HANDLING(files
);
104 static int files_setgrent(void *, void *, va_list);
105 static int files_group(void *, void *, va_list);
112 static void dns_endstate(void *);
113 NSS_TLS_HANDLING(dns
);
114 static int dns_setgrent(void *, void *, va_list);
115 static int dns_group(void *, void *, va_list);
121 char domain
[MAXHOSTNAMELEN
];
126 static void nis_endstate(void *);
127 NSS_TLS_HANDLING(nis
);
128 static int nis_setgrent(void *, void *, va_list);
129 static int nis_group(void *, void *, va_list);
132 struct compat_state
{
142 static void compat_endstate(void *);
143 NSS_TLS_HANDLING(compat
);
144 static int compat_setgrent(void *, void *, va_list);
145 static int compat_group(void *, void *, va_list);
147 static int gr_addgid(gid_t
, gid_t
*, int, int *);
148 static int getgroupmembership_fallback(void *, void *, va_list);
151 static int grp_id_func(char *, size_t *, va_list, void *);
152 static int grp_marshal_func(char *, size_t *, void *, va_list, void *);
153 static int grp_unmarshal_func(char *, size_t, void *, va_list, void *);
156 grp_id_func(char *buffer
, size_t *buffer_size
, va_list ap
, void *cache_mdata
)
161 size_t desired_size
, size
;
162 int res
= NS_UNAVAIL
;
163 enum nss_lookup_type lookup_type
;
166 lookup_type
= (enum nss_lookup_type
)cache_mdata
;
167 switch (lookup_type
) {
169 name
= va_arg(ap
, char *);
171 desired_size
= sizeof(enum nss_lookup_type
) + size
+ 1;
172 if (desired_size
> *buffer_size
) {
177 memcpy(buffer
, &lookup_type
, sizeof(enum nss_lookup_type
));
178 memcpy(buffer
+ sizeof(enum nss_lookup_type
), name
, size
+ 1);
183 gid
= va_arg(ap
, gid_t
);
184 desired_size
= sizeof(enum nss_lookup_type
) + sizeof(gid_t
);
185 if (desired_size
> *buffer_size
) {
190 memcpy(buffer
, &lookup_type
, sizeof(enum nss_lookup_type
));
191 memcpy(buffer
+ sizeof(enum nss_lookup_type
), &gid
,
197 /* should be unreachable */
202 *buffer_size
= desired_size
;
207 grp_marshal_func(char *buffer
, size_t *buffer_size
, void *retval __unused
,
208 va_list ap
, void *cache_mdata
)
213 char *orig_buf __unused
;
214 size_t orig_buf_size __unused
;
216 struct group new_grp
;
217 size_t desired_size
, size
, mem_size
;
220 switch ((enum nss_lookup_type
)cache_mdata
) {
222 name
= va_arg(ap
, char *);
225 gid
= va_arg(ap
, gid_t
);
230 /* should be unreachable */
234 grp
= va_arg(ap
, struct group
*);
235 orig_buf
= va_arg(ap
, char *);
236 orig_buf_size
= va_arg(ap
, size_t);
238 desired_size
= _ALIGNBYTES
+ sizeof(struct group
) + sizeof(char *);
240 if (grp
->gr_name
!= NULL
)
241 desired_size
+= strlen(grp
->gr_name
) + 1;
242 if (grp
->gr_passwd
!= NULL
)
243 desired_size
+= strlen(grp
->gr_passwd
) + 1;
245 if (grp
->gr_mem
!= NULL
) {
247 for (mem
= grp
->gr_mem
; *mem
; ++mem
) {
248 desired_size
+= strlen(*mem
) + 1;
252 desired_size
+= _ALIGNBYTES
+ (mem_size
+ 1) * sizeof(char *);
255 if (desired_size
> *buffer_size
) {
256 /* this assignment is here for future use */
257 *buffer_size
= desired_size
;
261 memcpy(&new_grp
, grp
, sizeof(struct group
));
262 memset(buffer
, 0, desired_size
);
264 *buffer_size
= desired_size
;
265 p
= buffer
+ sizeof(struct group
) + sizeof(char *);
266 memcpy(buffer
+ sizeof(struct group
), &p
, sizeof(char *));
267 p
= (char *)_ALIGN(p
);
269 if (new_grp
.gr_name
!= NULL
) {
270 size
= strlen(new_grp
.gr_name
);
271 memcpy(p
, new_grp
.gr_name
, size
);
276 if (new_grp
.gr_passwd
!= NULL
) {
277 size
= strlen(new_grp
.gr_passwd
);
278 memcpy(p
, new_grp
.gr_passwd
, size
);
279 new_grp
.gr_passwd
= p
;
283 if (new_grp
.gr_mem
!= NULL
) {
284 p
= (char *)_ALIGN(p
);
285 memcpy(p
, new_grp
.gr_mem
, sizeof(char *) * mem_size
);
286 new_grp
.gr_mem
= (char **)p
;
287 p
+= sizeof(char *) * (mem_size
+ 1);
289 for (mem
= new_grp
.gr_mem
; *mem
; ++mem
) {
291 memcpy(p
, *mem
, size
);
297 memcpy(buffer
, &new_grp
, sizeof(struct group
));
302 grp_unmarshal_func(char *buffer
, size_t buffer_size
, void *retval
, va_list ap
,
309 size_t orig_buf_size
;
315 switch ((enum nss_lookup_type
)cache_mdata
) {
317 name
= va_arg(ap
, char *);
320 gid
= va_arg(ap
, gid_t
);
325 /* should be unreachable */
329 grp
= va_arg(ap
, struct group
*);
330 orig_buf
= va_arg(ap
, char *);
331 orig_buf_size
= va_arg(ap
, size_t);
332 ret_errno
= va_arg(ap
, int *);
335 buffer_size
- sizeof(struct group
) - sizeof(char *)) {
340 memcpy(grp
, buffer
, sizeof(struct group
));
341 memcpy(&p
, buffer
+ sizeof(struct group
), sizeof(char *));
343 orig_buf
= (char *)_ALIGN(orig_buf
);
344 memcpy(orig_buf
, buffer
+ sizeof(struct group
) + sizeof(char *) +
345 _ALIGN(p
) - (size_t)p
,
346 buffer_size
- sizeof(struct group
) - sizeof(char *) -
347 _ALIGN(p
) + (size_t)p
);
348 p
= (char *)_ALIGN(p
);
350 NS_APPLY_OFFSET(grp
->gr_name
, orig_buf
, p
, char *);
351 NS_APPLY_OFFSET(grp
->gr_passwd
, orig_buf
, p
, char *);
352 if (grp
->gr_mem
!= NULL
) {
353 NS_APPLY_OFFSET(grp
->gr_mem
, orig_buf
, p
, char **);
355 for (mem
= grp
->gr_mem
; *mem
; ++mem
)
356 NS_APPLY_OFFSET(*mem
, orig_buf
, p
, char *);
360 *((struct group
**)retval
) = grp
;
365 NSS_MP_CACHE_HANDLING(group
);
366 #endif /* NS_CACHING */
369 static const nss_cache_info setgrent_cache_info
= NS_MP_CACHE_INFO_INITIALIZER(
370 group
, (void *)nss_lt_all
,
374 static const ns_dtab setgrent_dtab
[] = {
375 { NSSRC_FILES
, files_setgrent
, (void *)SETGRENT
},
377 { NSSRC_DNS
, dns_setgrent
, (void *)SETGRENT
},
380 { NSSRC_NIS
, nis_setgrent
, (void *)SETGRENT
},
382 { NSSRC_COMPAT
, compat_setgrent
, (void *)SETGRENT
},
384 NS_CACHE_CB(&setgrent_cache_info
)
390 static const nss_cache_info endgrent_cache_info
= NS_MP_CACHE_INFO_INITIALIZER(
391 group
, (void *)nss_lt_all
,
395 static const ns_dtab endgrent_dtab
[] = {
396 { NSSRC_FILES
, files_setgrent
, (void *)ENDGRENT
},
398 { NSSRC_DNS
, dns_setgrent
, (void *)ENDGRENT
},
401 { NSSRC_NIS
, nis_setgrent
, (void *)ENDGRENT
},
403 { NSSRC_COMPAT
, compat_setgrent
, (void *)ENDGRENT
},
405 NS_CACHE_CB(&endgrent_cache_info
)
411 static const nss_cache_info getgrent_r_cache_info
= NS_MP_CACHE_INFO_INITIALIZER(
412 group
, (void *)nss_lt_all
,
413 grp_marshal_func
, grp_unmarshal_func
);
416 static const ns_dtab getgrent_r_dtab
[] = {
417 { NSSRC_FILES
, files_group
, (void *)nss_lt_all
},
419 { NSSRC_DNS
, dns_group
, (void *)nss_lt_all
},
422 { NSSRC_NIS
, nis_group
, (void *)nss_lt_all
},
424 { NSSRC_COMPAT
, compat_group
, (void *)nss_lt_all
},
426 NS_CACHE_CB(&getgrent_r_cache_info
)
432 gr_addgid(gid_t gid
, gid_t
*groups
, int maxgrp
, int *grpcnt
)
436 for (dupc
= 0; dupc
< MIN(maxgrp
, *grpcnt
); dupc
++) {
437 if (groups
[dupc
] == gid
)
442 if (*grpcnt
< maxgrp
)
443 groups
[*grpcnt
] = gid
;
453 getgroupmembership_fallback(void *retval __unused
, void *mdata
, va_list ap
)
455 const ns_src src
[] = {
456 { mdata
, NS_SUCCESS
},
467 int i
, rv
, ret_errno
;
470 * As this is a fallback method, only provided src
471 * list will be respected during methods search.
473 assert(src
[0].name
!= NULL
);
475 uname
= va_arg(ap
, const char *);
476 agroup
= va_arg(ap
, gid_t
);
477 groups
= va_arg(ap
, gid_t
*);
478 maxgrp
= va_arg(ap
, int);
479 grpcnt
= va_arg(ap
, int *);
483 buf
= malloc(GRP_STORAGE_INITIAL
);
487 bufsize
= GRP_STORAGE_INITIAL
;
489 gr_addgid(agroup
, groups
, maxgrp
, grpcnt
);
491 _nsdispatch(NULL
, setgrent_dtab
, NSDB_GROUP
, "setgrent", src
, 0);
496 rv
= _nsdispatch(&grp_p
, getgrent_r_dtab
, NSDB_GROUP
,
497 "getgrent_r", src
, &grp
, buf
, bufsize
, &ret_errno
);
499 if (grp_p
== NULL
&& ret_errno
== ERANGE
) {
501 if ((bufsize
<< 1) > GRP_STORAGE_MAX
) {
508 buf
= malloc(bufsize
);
513 } while (grp_p
== NULL
&& ret_errno
== ERANGE
);
515 if (ret_errno
!= 0) {
523 for (i
= 0; grp
.gr_mem
[i
]; i
++) {
524 if (strcmp(grp
.gr_mem
[i
], uname
) == 0)
525 gr_addgid(grp
.gr_gid
, groups
, maxgrp
, grpcnt
);
529 _nsdispatch(NULL
, endgrent_dtab
, NSDB_GROUP
, "endgrent", src
);
538 _nsdispatch(NULL
, setgrent_dtab
, NSDB_GROUP
, "setgrent", defaultsrc
, 0);
543 setgroupent(int stayopen
)
545 _nsdispatch(NULL
, setgrent_dtab
, NSDB_GROUP
, "setgrent", defaultsrc
,
554 _nsdispatch(NULL
, endgrent_dtab
, NSDB_GROUP
, "endgrent", defaultsrc
);
559 getgrent_r(struct group
*grp
, char *buffer
, size_t bufsize
,
560 struct group
**result
)
566 rv
= _nsdispatch(result
, getgrent_r_dtab
, NSDB_GROUP
, "getgrent_r", defaultsrc
,
567 grp
, buffer
, bufsize
, &ret_errno
);
568 if (rv
== NS_SUCCESS
)
576 getgrnam_r(const char *name
, struct group
*grp
, char *buffer
, size_t bufsize
,
577 struct group
**result
)
580 static const nss_cache_info cache_info
=
581 NS_COMMON_CACHE_INFO_INITIALIZER(
582 group
, (void *)nss_lt_name
,
583 grp_id_func
, grp_marshal_func
, grp_unmarshal_func
);
586 static const ns_dtab dtab
[] = {
587 { NSSRC_FILES
, files_group
, (void *)nss_lt_name
},
589 { NSSRC_DNS
, dns_group
, (void *)nss_lt_name
},
592 { NSSRC_NIS
, nis_group
, (void *)nss_lt_name
},
594 { NSSRC_COMPAT
, compat_group
, (void *)nss_lt_name
},
596 NS_CACHE_CB(&cache_info
)
604 rv
= _nsdispatch(result
, dtab
, NSDB_GROUP
, "getgrnam_r", defaultsrc
,
605 name
, grp
, buffer
, bufsize
, &ret_errno
);
606 if (rv
== NS_SUCCESS
)
614 getgrgid_r(gid_t gid
, struct group
*grp
, char *buffer
, size_t bufsize
,
615 struct group
**result
)
618 static const nss_cache_info cache_info
=
619 NS_COMMON_CACHE_INFO_INITIALIZER(
620 group
, (void *)nss_lt_id
,
621 grp_id_func
, grp_marshal_func
, grp_unmarshal_func
);
624 static const ns_dtab dtab
[] = {
625 { NSSRC_FILES
, files_group
, (void *)nss_lt_id
},
627 { NSSRC_DNS
, dns_group
, (void *)nss_lt_id
},
630 { NSSRC_NIS
, nis_group
, (void *)nss_lt_id
},
632 { NSSRC_COMPAT
, compat_group
, (void *)nss_lt_id
},
634 NS_CACHE_CB(&cache_info
)
642 rv
= _nsdispatch(result
, dtab
, NSDB_GROUP
, "getgrgid_r", defaultsrc
,
643 gid
, grp
, buffer
, bufsize
, &ret_errno
);
644 if (rv
== NS_SUCCESS
)
653 __getgroupmembership(const char *uname
, gid_t agroup
, gid_t
*groups
,
654 int maxgrp
, int *grpcnt
)
656 static const ns_dtab dtab
[] = {
657 NS_FALLBACK_CB(getgroupmembership_fallback
)
662 assert(uname
!= NULL
);
663 /* groups may be NULL if just sizing when invoked with maxgrp = 0 */
664 assert(grpcnt
!= NULL
);
667 rv
= _nsdispatch(NULL
, dtab
, NSDB_GROUP
, "getgroupmembership",
668 defaultsrc
, uname
, agroup
, groups
, maxgrp
, grpcnt
);
670 /* too many groups found? */
671 return (*grpcnt
> maxgrp
? -1 : 0);
675 static struct group grp
;
676 static char *grp_storage
;
677 static size_t grp_storage_size
;
679 static struct group
*
680 getgr(int (*fn
)(union key
, struct group
*, char *, size_t, struct group
**),
686 if (grp_storage
== NULL
) {
687 grp_storage
= malloc(GRP_STORAGE_INITIAL
);
688 if (grp_storage
== NULL
)
690 grp_storage_size
= GRP_STORAGE_INITIAL
;
693 rv
= fn(key
, &grp
, grp_storage
, grp_storage_size
, &res
);
694 if (res
== NULL
&& rv
== ERANGE
) {
696 if ((grp_storage_size
<< 1) > GRP_STORAGE_MAX
) {
701 grp_storage_size
<<= 1;
702 grp_storage
= malloc(grp_storage_size
);
703 if (grp_storage
== NULL
)
706 } while (res
== NULL
&& rv
== ERANGE
);
714 wrap_getgrnam_r(union key key
, struct group
*grp
, char *buffer
, size_t bufsize
,
717 return (getgrnam_r(key
.name
, grp
, buffer
, bufsize
, res
));
722 wrap_getgrgid_r(union key key
, struct group
*grp
, char *buffer
, size_t bufsize
,
725 return (getgrgid_r(key
.gid
, grp
, buffer
, bufsize
, res
));
730 wrap_getgrent_r(union key key __unused
, struct group
*grp
, char *buffer
,
731 size_t bufsize
, struct group
**res
)
733 return (getgrent_r(grp
, buffer
, bufsize
, res
));
738 getgrnam(const char *name
)
743 return (getgr(wrap_getgrnam_r
, key
));
753 return (getgr(wrap_getgrgid_r
, key
));
762 key
.gid
= 0; /* not used */
763 return (getgr(wrap_getgrent_r
, key
));
768 is_comment_line(const char *s
, size_t n
)
775 if (*s
== '#' || !isspace((unsigned char)*s
))
777 return (*s
== '#' || s
== eom
);
785 files_endstate(void *p
)
790 if (((struct files_state
*)p
)->fp
!= NULL
)
791 fclose(((struct files_state
*)p
)->fp
);
797 files_setgrent(void *retval __unused
, void *mdata
, va_list ap
)
799 struct files_state
*st
;
802 rv
= files_getstate(&st
);
805 switch ((enum constants
)mdata
) {
807 stayopen
= va_arg(ap
, int);
811 st
->fp
= fopen(_PATH_GROUP
, "r");
814 if (st
->fp
!= NULL
) {
827 files_group(void *retval
, void *mdata
, va_list ap
)
829 struct files_state
*st
;
830 enum nss_lookup_type how
;
831 const char *name
, *line
;
835 size_t bufsize
, linesize
;
837 int rv
, stayopen
, *errnop
;
841 how
= (enum nss_lookup_type
)mdata
;
844 name
= va_arg(ap
, const char *);
847 gid
= va_arg(ap
, gid_t
);
852 return (NS_NOTFOUND
);
854 grp
= va_arg(ap
, struct group
*);
855 buffer
= va_arg(ap
, char *);
856 bufsize
= va_arg(ap
, size_t);
857 errnop
= va_arg(ap
, int *);
858 *errnop
= files_getstate(&st
);
861 if (st
->fp
== NULL
&&
862 ((st
->fp
= fopen(_PATH_GROUP
, "r")) == NULL
)) {
866 if (how
== nss_lt_all
)
870 stayopen
= st
->stayopen
;
873 pos
= ftello(st
->fp
);
874 while ((line
= fgetln(st
->fp
, &linesize
)) != NULL
) {
875 if (line
[linesize
-1] == '\n')
877 rv
= __gr_match_entry(line
, linesize
, how
, name
, gid
);
878 if (rv
!= NS_SUCCESS
)
880 /* We need room at least for the line, a string NUL
881 * terminator, alignment padding, and one (char *)
882 * pointer for the member list terminator.
884 if (bufsize
<= linesize
+ _ALIGNBYTES
+ sizeof(char *)) {
889 memcpy(buffer
, line
, linesize
);
890 buffer
[linesize
] = '\0';
891 rv
= __gr_parse_entry(buffer
, linesize
, grp
,
892 &buffer
[linesize
+ 1], bufsize
- linesize
- 1, errnop
);
893 if (rv
& NS_TERMINATE
)
895 pos
= ftello(st
->fp
);
897 if (!stayopen
&& st
->fp
!= NULL
) {
901 if (rv
== NS_SUCCESS
&& retval
!= NULL
)
902 *(struct group
**)retval
= grp
;
903 else if (rv
== NS_RETURN
&& *errnop
== ERANGE
&& st
->fp
!= NULL
)
904 fseeko(st
->fp
, pos
, SEEK_SET
);
914 dns_endstate(void *p
)
922 dns_setgrent(void *retval __unused
, void *cb_data __unused
, va_list ap __unused
)
924 struct dns_state
*st
;
927 rv
= dns_getstate(&st
);
936 dns_group(void *retval
, void *mdata
, va_list ap
)
938 char buf
[HESIOD_NAME_MAX
];
939 struct dns_state
*st
;
941 const char *name
, *label
;
944 size_t bufsize
, adjsize
, linesize
;
946 enum nss_lookup_type how
;
953 how
= (enum nss_lookup_type
)mdata
;
956 name
= va_arg(ap
, const char *);
959 gid
= va_arg(ap
, gid_t
);
964 grp
= va_arg(ap
, struct group
*);
965 buffer
= va_arg(ap
, char *);
966 bufsize
= va_arg(ap
, size_t);
967 errnop
= va_arg(ap
, int *);
968 *errnop
= dns_getstate(&st
);
971 if (hesiod_init(&ctx
) != 0) {
983 if (snprintf(buf
, sizeof(buf
), "%lu",
984 (unsigned long)gid
) >= sizeof(buf
))
991 if (snprintf(buf
, sizeof(buf
), "group-%ld",
992 st
->counter
++) >= sizeof(buf
))
997 hes
= hesiod_resolve(ctx
, label
,
998 how
== nss_lt_id
? "gid" : "group");
999 if ((how
== nss_lt_id
&& hes
== NULL
&&
1000 (hes
= hesiod_resolve(ctx
, buf
, "group")) == NULL
) ||
1002 if (how
== nss_lt_all
)
1004 if (errno
!= ENOENT
)
1008 rv
= __gr_match_entry(hes
[0], strlen(hes
[0]), how
, name
, gid
);
1009 if (rv
!= NS_SUCCESS
) {
1010 hesiod_free_list(ctx
, hes
);
1014 /* We need room at least for the line, a string NUL
1015 * terminator, alignment padding, and one (char *)
1016 * pointer for the member list terminator.
1018 adjsize
= bufsize
- _ALIGNBYTES
- sizeof(char *);
1019 linesize
= strlcpy(buffer
, hes
[0], adjsize
);
1020 if (linesize
>= adjsize
) {
1025 hesiod_free_list(ctx
, hes
);
1027 rv
= __gr_parse_entry(buffer
, linesize
, grp
,
1028 &buffer
[linesize
+ 1], bufsize
- linesize
- 1, errnop
);
1029 } while (how
== nss_lt_all
&& !(rv
& NS_TERMINATE
));
1032 hesiod_free_list(ctx
, hes
);
1035 if (rv
== NS_SUCCESS
&& retval
!= NULL
)
1036 *(struct group
**)retval
= grp
;
1047 nis_endstate(void *p
)
1052 free(((struct nis_state
*)p
)->key
);
1058 nis_setgrent(void *retval __unused
, void *cb_data __unused
, va_list ap __unused
)
1060 struct nis_state
*st
;
1063 rv
= nis_getstate(&st
);
1065 return (NS_UNAVAIL
);
1069 return (NS_UNAVAIL
);
1074 nis_group(void *retval
, void *mdata
, va_list ap
)
1077 struct nis_state
*st
;
1080 char *buffer
, *key
, *result
;
1083 enum nss_lookup_type how
;
1084 int *errnop
, keylen
, resultlen
, rv
;
1088 how
= (enum nss_lookup_type
)mdata
;
1091 name
= va_arg(ap
, const char *);
1092 map
= "group.byname";
1095 gid
= va_arg(ap
, gid_t
);
1096 map
= "group.bygid";
1099 map
= "group.byname";
1102 grp
= va_arg(ap
, struct group
*);
1103 buffer
= va_arg(ap
, char *);
1104 bufsize
= va_arg(ap
, size_t);
1105 errnop
= va_arg(ap
, int *);
1106 *errnop
= nis_getstate(&st
);
1108 return (NS_UNAVAIL
);
1109 if (st
->domain
[0] == '\0') {
1110 if (getdomainname(st
->domain
, sizeof(st
->domain
)) != 0) {
1112 return (NS_UNAVAIL
);
1120 if (strlcpy(buffer
, name
, bufsize
) >= bufsize
)
1124 if (snprintf(buffer
, bufsize
, "%lu",
1125 (unsigned long)gid
) >= bufsize
)
1134 if (how
== nss_lt_all
) {
1135 if (st
->key
== NULL
)
1136 rv
= yp_first(st
->domain
, map
, &st
->key
,
1137 &st
->keylen
, &result
, &resultlen
);
1140 keylen
= st
->keylen
;
1142 rv
= yp_next(st
->domain
, map
, key
, keylen
,
1143 &st
->key
, &st
->keylen
, &result
,
1151 if (rv
== YPERR_NOMORE
) {
1159 rv
= yp_match(st
->domain
, map
, buffer
, strlen(buffer
),
1160 &result
, &resultlen
);
1161 if (rv
== YPERR_KEY
) {
1164 } else if (rv
!= 0) {
1170 /* We need room at least for the line, a string NUL
1171 * terminator, alignment padding, and one (char *)
1172 * pointer for the member list terminator.
1174 if (resultlen
>= bufsize
- _ALIGNBYTES
- sizeof(char *))
1176 memcpy(buffer
, result
, resultlen
);
1177 buffer
[resultlen
] = '\0';
1179 rv
= __gr_match_entry(buffer
, resultlen
, how
, name
, gid
);
1180 if (rv
== NS_SUCCESS
)
1181 rv
= __gr_parse_entry(buffer
, resultlen
, grp
,
1182 &buffer
[resultlen
+1], bufsize
- resultlen
- 1,
1184 } while (how
== nss_lt_all
&& !(rv
& NS_TERMINATE
));
1186 if (rv
== NS_SUCCESS
&& retval
!= NULL
)
1187 *(struct group
**)retval
= grp
;
1201 compat_endstate(void *p
)
1203 struct compat_state
*st
;
1207 st
= (struct compat_state
*)p
;
1216 compat_setgrent(void *retval __unused
, void *mdata
, va_list ap
)
1218 static const ns_src compatsrc
[] = {
1220 { NSSRC_NIS
, NS_SUCCESS
},
1226 { NSSRC_DNS
, dns_setgrent
, NULL
},
1229 { NSSRC_NIS
, nis_setgrent
, NULL
},
1231 { NULL
, NULL
, NULL
}
1233 struct compat_state
*st
;
1236 #define set_setent(x, y) do { \
1239 for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++) \
1240 x[i].mdata = (void *)y; \
1243 rv
= compat_getstate(&st
);
1245 return (NS_UNAVAIL
);
1246 switch ((enum constants
)mdata
) {
1248 stayopen
= va_arg(ap
, int);
1252 st
->fp
= fopen(_PATH_GROUP
, "r");
1253 set_setent(dtab
, mdata
);
1254 _nsdispatch(NULL
, dtab
, NSDB_GROUP_COMPAT
, "setgrent",
1258 if (st
->fp
!= NULL
) {
1262 set_setent(dtab
, mdata
);
1263 _nsdispatch(NULL
, dtab
, NSDB_GROUP_COMPAT
, "endgrent",
1269 st
->compat
= COMPAT_MODE_OFF
;
1272 return (NS_UNAVAIL
);
1278 compat_group(void *retval
, void *mdata
, va_list ap
)
1280 static const ns_src compatsrc
[] = {
1282 { NSSRC_NIS
, NS_SUCCESS
},
1288 { NSSRC_NIS
, nis_group
, NULL
},
1291 { NSSRC_DNS
, dns_group
, NULL
},
1293 { NULL
, NULL
, NULL
}
1295 struct compat_state
*st
;
1296 enum nss_lookup_type how
;
1297 const char *name
, *line
;
1302 size_t bufsize
, linesize
;
1304 int rv
, stayopen
, *errnop
;
1306 #define set_lookup_type(x, y) do { \
1309 for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++) \
1310 x[i].mdata = (void *)y; \
1315 how
= (enum nss_lookup_type
)mdata
;
1318 name
= va_arg(ap
, const char *);
1321 gid
= va_arg(ap
, gid_t
);
1326 return (NS_NOTFOUND
);
1328 grp
= va_arg(ap
, struct group
*);
1329 buffer
= va_arg(ap
, char *);
1330 bufsize
= va_arg(ap
, size_t);
1331 errnop
= va_arg(ap
, int *);
1332 *errnop
= compat_getstate(&st
);
1334 return (NS_UNAVAIL
);
1335 if (st
->fp
== NULL
&&
1336 ((st
->fp
= fopen(_PATH_GROUP
, "r")) == NULL
)) {
1341 if (how
== nss_lt_all
)
1345 stayopen
= st
->stayopen
;
1348 switch (st
->compat
) {
1349 case COMPAT_MODE_ALL
:
1350 set_lookup_type(dtab
, how
);
1353 rv
= _nsdispatch(&discard
, dtab
, NSDB_GROUP_COMPAT
,
1354 "getgrent_r", compatsrc
, grp
, buffer
, bufsize
,
1358 rv
= _nsdispatch(&discard
, dtab
, NSDB_GROUP_COMPAT
,
1359 "getgrgid_r", compatsrc
, gid
, grp
, buffer
, bufsize
,
1363 rv
= _nsdispatch(&discard
, dtab
, NSDB_GROUP_COMPAT
,
1364 "getgrnam_r", compatsrc
, name
, grp
, buffer
,
1368 if (rv
& NS_TERMINATE
)
1370 st
->compat
= COMPAT_MODE_OFF
;
1372 case COMPAT_MODE_NAME
:
1373 set_lookup_type(dtab
, nss_lt_name
);
1374 rv
= _nsdispatch(&discard
, dtab
, NSDB_GROUP_COMPAT
,
1375 "getgrnam_r", compatsrc
, st
->name
, grp
, buffer
, bufsize
,
1381 if (strcmp(name
, grp
->gr_name
) != 0)
1385 if (gid
!= grp
->gr_gid
)
1399 st
->compat
= COMPAT_MODE_OFF
;
1400 if (rv
== NS_SUCCESS
)
1407 pos
= ftello(st
->fp
);
1408 while ((line
= fgetln(st
->fp
, &linesize
)) != NULL
) {
1409 if (line
[linesize
-1] == '\n')
1411 if (linesize
> 2 && line
[0] == '+') {
1412 p
= memchr(&line
[1], ':', linesize
);
1413 if (p
== NULL
|| p
== &line
[1])
1414 st
->compat
= COMPAT_MODE_ALL
;
1416 st
->name
= malloc(p
- line
);
1417 if (st
->name
== NULL
) {
1419 "getgrent memory allocation failure");
1424 memcpy(st
->name
, &line
[1], p
- line
- 1);
1425 st
->name
[p
- line
- 1] = '\0';
1426 st
->compat
= COMPAT_MODE_NAME
;
1430 rv
= __gr_match_entry(line
, linesize
, how
, name
, gid
);
1431 if (rv
!= NS_SUCCESS
)
1433 /* We need room at least for the line, a string NUL
1434 * terminator, alignment padding, and one (char *)
1435 * pointer for the member list terminator.
1437 if (bufsize
<= linesize
+ _ALIGNBYTES
+ sizeof(char *)) {
1442 memcpy(buffer
, line
, linesize
);
1443 buffer
[linesize
] = '\0';
1444 rv
= __gr_parse_entry(buffer
, linesize
, grp
,
1445 &buffer
[linesize
+ 1], bufsize
- linesize
- 1, errnop
);
1446 if (rv
& NS_TERMINATE
)
1448 pos
= ftello(st
->fp
);
1451 if (!stayopen
&& st
->fp
!= NULL
) {
1455 if (rv
== NS_SUCCESS
&& retval
!= NULL
)
1456 *(struct group
**)retval
= grp
;
1457 else if (rv
== NS_RETURN
&& *errnop
== ERANGE
&& st
->fp
!= NULL
)
1458 fseeko(st
->fp
, pos
, SEEK_SET
);
1460 #undef set_lookup_type
1465 * common group line matching and parsing
1468 __gr_match_entry(const char *line
, size_t linesize
, enum nss_lookup_type how
,
1469 const char *name
, gid_t gid
)
1472 const char *p
, *eol
;
1477 if (linesize
== 0 || is_comment_line(line
, linesize
))
1478 return (NS_NOTFOUND
);
1480 case nss_lt_name
: needed
= 1; break;
1481 case nss_lt_id
: needed
= 2; break;
1482 default: needed
= 2; break;
1484 eol
= &line
[linesize
];
1485 for (p
= line
, i
= 0; i
< needed
&& p
< eol
; p
++)
1489 return (NS_NOTFOUND
);
1492 namesize
= strlen(name
);
1493 if (namesize
+ 1 == (size_t)(p
- line
) &&
1494 memcmp(line
, name
, namesize
) == 0)
1495 return (NS_SUCCESS
);
1498 n
= strtoul(p
, &q
, 10);
1499 if (q
< eol
&& *q
== ':' && gid
== (gid_t
)n
)
1500 return (NS_SUCCESS
);
1503 return (NS_SUCCESS
);
1507 return (NS_NOTFOUND
);
1512 __gr_parse_entry(char *line
, size_t linesize __unused
, struct group
*grp
,
1513 char *membuf
, size_t membufsize
, int *errnop
)
1515 char *s_gid
, *s_mem
, *p
, **members
;
1519 memset(grp
, 0, sizeof(*grp
));
1520 members
= (char **)_ALIGN(membuf
);
1521 membufsize
-= (char *)members
- membuf
;
1522 maxmembers
= membufsize
/ sizeof(*members
);
1523 if (maxmembers
<= 0 ||
1524 (grp
->gr_name
= strsep(&line
, ":")) == NULL
||
1525 grp
->gr_name
[0] == '\0' ||
1526 (grp
->gr_passwd
= strsep(&line
, ":")) == NULL
||
1527 (s_gid
= strsep(&line
, ":")) == NULL
||
1529 return (NS_NOTFOUND
);
1531 n
= strtoul(s_gid
, &s_gid
, 10);
1532 if (s_gid
[0] != '\0')
1533 return (NS_NOTFOUND
);
1534 grp
->gr_gid
= (gid_t
)n
;
1535 grp
->gr_mem
= members
;
1536 while (maxmembers
> 1 && s_mem
!= NULL
) {
1537 p
= strsep(&s_mem
, ",");
1538 if (p
!= NULL
&& *p
!= '\0') {
1545 return (NS_SUCCESS
);