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 __gr_match_entry(const char *, size_t, enum nss_lookup_type
,
79 int __gr_parse_entry(char *, size_t, struct group
*, char *, size_t,
82 static int is_comment_line(const char *, size_t);
88 static struct group
*getgr(int (*)(union key
, struct group
*, char *, size_t,
89 struct group
**), union key
);
90 static int wrap_getgrnam_r(union key
, struct group
*, char *, size_t,
92 static int wrap_getgrgid_r(union key
, struct group
*, char *, size_t,
94 static int wrap_getgrent_r(union key
, struct group
*, char *, size_t,
101 static void files_endstate(void *);
102 NSS_TLS_HANDLING(files
);
103 static int files_setgrent(void *, void *, va_list);
104 static int files_group(void *, void *, va_list);
111 static void dns_endstate(void *);
112 NSS_TLS_HANDLING(dns
);
113 static int dns_setgrent(void *, void *, va_list);
114 static int dns_group(void *, void *, va_list);
120 char domain
[MAXHOSTNAMELEN
];
125 static void nis_endstate(void *);
126 NSS_TLS_HANDLING(nis
);
127 static int nis_setgrent(void *, void *, va_list);
128 static int nis_group(void *, void *, va_list);
131 struct compat_state
{
141 static void compat_endstate(void *);
142 NSS_TLS_HANDLING(compat
);
143 static int compat_setgrent(void *, void *, va_list);
144 static int compat_group(void *, void *, va_list);
146 static int gr_addgid(gid_t
, gid_t
*, int, int *);
147 static int getgroupmembership_fallback(void *, void *, va_list);
150 static int grp_id_func(char *, size_t *, va_list, void *);
151 static int grp_marshal_func(char *, size_t *, void *, va_list, void *);
152 static int grp_unmarshal_func(char *, size_t, void *, va_list, void *);
155 grp_id_func(char *buffer
, size_t *buffer_size
, va_list ap
, void *cache_mdata
)
160 size_t desired_size
, size
;
161 int res
= NS_UNAVAIL
;
162 enum nss_lookup_type lookup_type
;
165 lookup_type
= (enum nss_lookup_type
)cache_mdata
;
166 switch (lookup_type
) {
168 name
= va_arg(ap
, char *);
170 desired_size
= sizeof(enum nss_lookup_type
) + size
+ 1;
171 if (desired_size
> *buffer_size
) {
176 memcpy(buffer
, &lookup_type
, sizeof(enum nss_lookup_type
));
177 memcpy(buffer
+ sizeof(enum nss_lookup_type
), name
, size
+ 1);
182 gid
= va_arg(ap
, gid_t
);
183 desired_size
= sizeof(enum nss_lookup_type
) + sizeof(gid_t
);
184 if (desired_size
> *buffer_size
) {
189 memcpy(buffer
, &lookup_type
, sizeof(enum nss_lookup_type
));
190 memcpy(buffer
+ sizeof(enum nss_lookup_type
), &gid
,
196 /* should be unreachable */
201 *buffer_size
= desired_size
;
206 grp_marshal_func(char *buffer
, size_t *buffer_size
, void *retval __unused
,
207 va_list ap
, void *cache_mdata
)
212 char *orig_buf __unused
;
213 size_t orig_buf_size __unused
;
215 struct group new_grp
;
216 size_t desired_size
, size
, mem_size
;
219 switch ((enum nss_lookup_type
)cache_mdata
) {
221 name
= va_arg(ap
, char *);
224 gid
= va_arg(ap
, gid_t
);
229 /* should be unreachable */
233 grp
= va_arg(ap
, struct group
*);
234 orig_buf
= va_arg(ap
, char *);
235 orig_buf_size
= va_arg(ap
, size_t);
237 desired_size
= _ALIGNBYTES
+ sizeof(struct group
) + sizeof(char *);
239 if (grp
->gr_name
!= NULL
)
240 desired_size
+= strlen(grp
->gr_name
) + 1;
241 if (grp
->gr_passwd
!= NULL
)
242 desired_size
+= strlen(grp
->gr_passwd
) + 1;
244 if (grp
->gr_mem
!= NULL
) {
246 for (mem
= grp
->gr_mem
; *mem
; ++mem
) {
247 desired_size
+= strlen(*mem
) + 1;
251 desired_size
+= _ALIGNBYTES
+ (mem_size
+ 1) * sizeof(char *);
254 if (desired_size
> *buffer_size
) {
255 /* this assignment is here for future use */
256 *buffer_size
= desired_size
;
260 memcpy(&new_grp
, grp
, sizeof(struct group
));
261 memset(buffer
, 0, desired_size
);
263 *buffer_size
= desired_size
;
264 p
= buffer
+ sizeof(struct group
) + sizeof(char *);
265 memcpy(buffer
+ sizeof(struct group
), &p
, sizeof(char *));
266 p
= (char *)_ALIGN(p
);
268 if (new_grp
.gr_name
!= NULL
) {
269 size
= strlen(new_grp
.gr_name
);
270 memcpy(p
, new_grp
.gr_name
, size
);
275 if (new_grp
.gr_passwd
!= NULL
) {
276 size
= strlen(new_grp
.gr_passwd
);
277 memcpy(p
, new_grp
.gr_passwd
, size
);
278 new_grp
.gr_passwd
= p
;
282 if (new_grp
.gr_mem
!= NULL
) {
283 p
= (char *)_ALIGN(p
);
284 memcpy(p
, new_grp
.gr_mem
, sizeof(char *) * mem_size
);
285 new_grp
.gr_mem
= (char **)p
;
286 p
+= sizeof(char *) * (mem_size
+ 1);
288 for (mem
= new_grp
.gr_mem
; *mem
; ++mem
) {
290 memcpy(p
, *mem
, size
);
296 memcpy(buffer
, &new_grp
, sizeof(struct group
));
301 grp_unmarshal_func(char *buffer
, size_t buffer_size
, void *retval
, va_list ap
,
308 size_t orig_buf_size
;
314 switch ((enum nss_lookup_type
)cache_mdata
) {
316 name
= va_arg(ap
, char *);
319 gid
= va_arg(ap
, gid_t
);
324 /* should be unreachable */
328 grp
= va_arg(ap
, struct group
*);
329 orig_buf
= va_arg(ap
, char *);
330 orig_buf_size
= va_arg(ap
, size_t);
331 ret_errno
= va_arg(ap
, int *);
334 buffer_size
- sizeof(struct group
) - sizeof(char *)) {
339 memcpy(grp
, buffer
, sizeof(struct group
));
340 memcpy(&p
, buffer
+ sizeof(struct group
), sizeof(char *));
342 orig_buf
= (char *)_ALIGN(orig_buf
);
343 memcpy(orig_buf
, buffer
+ sizeof(struct group
) + sizeof(char *) +
344 _ALIGN(p
) - (size_t)p
,
345 buffer_size
- sizeof(struct group
) - sizeof(char *) -
346 _ALIGN(p
) + (size_t)p
);
347 p
= (char *)_ALIGN(p
);
349 NS_APPLY_OFFSET(grp
->gr_name
, orig_buf
, p
, char *);
350 NS_APPLY_OFFSET(grp
->gr_passwd
, orig_buf
, p
, char *);
351 if (grp
->gr_mem
!= NULL
) {
352 NS_APPLY_OFFSET(grp
->gr_mem
, orig_buf
, p
, char **);
354 for (mem
= grp
->gr_mem
; *mem
; ++mem
)
355 NS_APPLY_OFFSET(*mem
, orig_buf
, p
, char *);
359 *((struct group
**)retval
) = grp
;
364 NSS_MP_CACHE_HANDLING(group
);
365 #endif /* NS_CACHING */
368 static const nss_cache_info setgrent_cache_info
= NS_MP_CACHE_INFO_INITIALIZER(
369 group
, (void *)nss_lt_all
,
373 static const ns_dtab setgrent_dtab
[] = {
374 { NSSRC_FILES
, files_setgrent
, (void *)SETGRENT
},
376 { NSSRC_DNS
, dns_setgrent
, (void *)SETGRENT
},
379 { NSSRC_NIS
, nis_setgrent
, (void *)SETGRENT
},
381 { NSSRC_COMPAT
, compat_setgrent
, (void *)SETGRENT
},
383 NS_CACHE_CB(&setgrent_cache_info
)
389 static const nss_cache_info endgrent_cache_info
= NS_MP_CACHE_INFO_INITIALIZER(
390 group
, (void *)nss_lt_all
,
394 static const ns_dtab endgrent_dtab
[] = {
395 { NSSRC_FILES
, files_setgrent
, (void *)ENDGRENT
},
397 { NSSRC_DNS
, dns_setgrent
, (void *)ENDGRENT
},
400 { NSSRC_NIS
, nis_setgrent
, (void *)ENDGRENT
},
402 { NSSRC_COMPAT
, compat_setgrent
, (void *)ENDGRENT
},
404 NS_CACHE_CB(&endgrent_cache_info
)
410 static const nss_cache_info getgrent_r_cache_info
= NS_MP_CACHE_INFO_INITIALIZER(
411 group
, (void *)nss_lt_all
,
412 grp_marshal_func
, grp_unmarshal_func
);
415 static const ns_dtab getgrent_r_dtab
[] = {
416 { NSSRC_FILES
, files_group
, (void *)nss_lt_all
},
418 { NSSRC_DNS
, dns_group
, (void *)nss_lt_all
},
421 { NSSRC_NIS
, nis_group
, (void *)nss_lt_all
},
423 { NSSRC_COMPAT
, compat_group
, (void *)nss_lt_all
},
425 NS_CACHE_CB(&getgrent_r_cache_info
)
431 gr_addgid(gid_t gid
, gid_t
*groups
, int maxgrp
, int *grpcnt
)
435 for (dupc
= 0; dupc
< MIN(maxgrp
, *grpcnt
); dupc
++) {
436 if (groups
[dupc
] == gid
)
441 if (*grpcnt
< maxgrp
)
442 groups
[*grpcnt
] = gid
;
452 getgroupmembership_fallback(void *retval __unused
, void *mdata
, va_list ap
)
454 const ns_src src
[] = {
455 { mdata
, NS_SUCCESS
},
466 int i
, rv
, ret_errno
;
469 * As this is a fallback method, only provided src
470 * list will be respected during methods search.
472 assert(src
[0].name
!= NULL
);
474 uname
= va_arg(ap
, const char *);
475 agroup
= va_arg(ap
, gid_t
);
476 groups
= va_arg(ap
, gid_t
*);
477 maxgrp
= va_arg(ap
, int);
478 grpcnt
= va_arg(ap
, int *);
482 buf
= malloc(GRP_STORAGE_INITIAL
);
486 bufsize
= GRP_STORAGE_INITIAL
;
488 gr_addgid(agroup
, groups
, maxgrp
, grpcnt
);
490 _nsdispatch(NULL
, setgrent_dtab
, NSDB_GROUP
, "setgrent", src
, 0);
495 rv
= _nsdispatch(&grp_p
, getgrent_r_dtab
, NSDB_GROUP
,
496 "getgrent_r", src
, &grp
, buf
, bufsize
, &ret_errno
);
498 if (grp_p
== NULL
&& ret_errno
== ERANGE
) {
500 if ((bufsize
<< 1) > GRP_STORAGE_MAX
) {
507 buf
= malloc(bufsize
);
512 } while (grp_p
== NULL
&& ret_errno
== ERANGE
);
514 if (ret_errno
!= 0) {
522 for (i
= 0; grp
.gr_mem
[i
]; i
++) {
523 if (strcmp(grp
.gr_mem
[i
], uname
) == 0)
524 gr_addgid(grp
.gr_gid
, groups
, maxgrp
, grpcnt
);
528 _nsdispatch(NULL
, endgrent_dtab
, NSDB_GROUP
, "endgrent", src
);
537 _nsdispatch(NULL
, setgrent_dtab
, NSDB_GROUP
, "setgrent", defaultsrc
, 0);
542 setgroupent(int stayopen
)
544 _nsdispatch(NULL
, setgrent_dtab
, NSDB_GROUP
, "setgrent", defaultsrc
,
553 _nsdispatch(NULL
, endgrent_dtab
, NSDB_GROUP
, "endgrent", defaultsrc
);
558 getgrent_r(struct group
*grp
, char *buffer
, size_t bufsize
,
559 struct group
**result
)
565 rv
= _nsdispatch(result
, getgrent_r_dtab
, NSDB_GROUP
, "getgrent_r", defaultsrc
,
566 grp
, buffer
, bufsize
, &ret_errno
);
567 if (rv
== NS_SUCCESS
)
575 getgrnam_r(const char *name
, struct group
*grp
, char *buffer
, size_t bufsize
,
576 struct group
**result
)
579 static const nss_cache_info cache_info
=
580 NS_COMMON_CACHE_INFO_INITIALIZER(
581 group
, (void *)nss_lt_name
,
582 grp_id_func
, grp_marshal_func
, grp_unmarshal_func
);
585 static const ns_dtab dtab
[] = {
586 { NSSRC_FILES
, files_group
, (void *)nss_lt_name
},
588 { NSSRC_DNS
, dns_group
, (void *)nss_lt_name
},
591 { NSSRC_NIS
, nis_group
, (void *)nss_lt_name
},
593 { NSSRC_COMPAT
, compat_group
, (void *)nss_lt_name
},
595 NS_CACHE_CB(&cache_info
)
603 rv
= _nsdispatch(result
, dtab
, NSDB_GROUP
, "getgrnam_r", defaultsrc
,
604 name
, grp
, buffer
, bufsize
, &ret_errno
);
605 if (rv
== NS_SUCCESS
)
613 getgrgid_r(gid_t gid
, struct group
*grp
, char *buffer
, size_t bufsize
,
614 struct group
**result
)
617 static const nss_cache_info cache_info
=
618 NS_COMMON_CACHE_INFO_INITIALIZER(
619 group
, (void *)nss_lt_id
,
620 grp_id_func
, grp_marshal_func
, grp_unmarshal_func
);
623 static const ns_dtab dtab
[] = {
624 { NSSRC_FILES
, files_group
, (void *)nss_lt_id
},
626 { NSSRC_DNS
, dns_group
, (void *)nss_lt_id
},
629 { NSSRC_NIS
, nis_group
, (void *)nss_lt_id
},
631 { NSSRC_COMPAT
, compat_group
, (void *)nss_lt_id
},
633 NS_CACHE_CB(&cache_info
)
641 rv
= _nsdispatch(result
, dtab
, NSDB_GROUP
, "getgrgid_r", defaultsrc
,
642 gid
, grp
, buffer
, bufsize
, &ret_errno
);
643 if (rv
== NS_SUCCESS
)
652 __getgroupmembership(const char *uname
, gid_t agroup
, gid_t
*groups
,
653 int maxgrp
, int *grpcnt
)
655 static const ns_dtab dtab
[] = {
656 NS_FALLBACK_CB(getgroupmembership_fallback
)
661 assert(uname
!= NULL
);
662 /* groups may be NULL if just sizing when invoked with maxgrp = 0 */
663 assert(grpcnt
!= NULL
);
666 rv
= _nsdispatch(NULL
, dtab
, NSDB_GROUP
, "getgroupmembership",
667 defaultsrc
, uname
, agroup
, groups
, maxgrp
, grpcnt
);
669 /* too many groups found? */
670 return (*grpcnt
> maxgrp
? -1 : 0);
674 static struct group grp
;
675 static char *grp_storage
;
676 static size_t grp_storage_size
;
678 static struct group
*
679 getgr(int (*fn
)(union key
, struct group
*, char *, size_t, struct group
**),
685 if (grp_storage
== NULL
) {
686 grp_storage
= malloc(GRP_STORAGE_INITIAL
);
687 if (grp_storage
== NULL
)
689 grp_storage_size
= GRP_STORAGE_INITIAL
;
692 rv
= fn(key
, &grp
, grp_storage
, grp_storage_size
, &res
);
693 if (res
== NULL
&& rv
== ERANGE
) {
695 if ((grp_storage_size
<< 1) > GRP_STORAGE_MAX
) {
700 grp_storage_size
<<= 1;
701 grp_storage
= malloc(grp_storage_size
);
702 if (grp_storage
== NULL
)
705 } while (res
== NULL
&& rv
== ERANGE
);
713 wrap_getgrnam_r(union key key
, struct group
*grp
, char *buffer
, size_t bufsize
,
716 return (getgrnam_r(key
.name
, grp
, buffer
, bufsize
, res
));
721 wrap_getgrgid_r(union key key
, struct group
*grp
, char *buffer
, size_t bufsize
,
724 return (getgrgid_r(key
.gid
, grp
, buffer
, bufsize
, res
));
729 wrap_getgrent_r(union key key __unused
, struct group
*grp
, char *buffer
,
730 size_t bufsize
, struct group
**res
)
732 return (getgrent_r(grp
, buffer
, bufsize
, res
));
737 getgrnam(const char *name
)
742 return (getgr(wrap_getgrnam_r
, key
));
752 return (getgr(wrap_getgrgid_r
, key
));
761 key
.gid
= 0; /* not used */
762 return (getgr(wrap_getgrent_r
, key
));
767 is_comment_line(const char *s
, size_t n
)
774 if (*s
== '#' || !isspace((unsigned char)*s
))
776 return (*s
== '#' || s
== eom
);
784 files_endstate(void *p
)
789 if (((struct files_state
*)p
)->fp
!= NULL
)
790 fclose(((struct files_state
*)p
)->fp
);
796 files_setgrent(void *retval __unused
, void *mdata
, va_list ap
)
798 struct files_state
*st
;
801 rv
= files_getstate(&st
);
804 switch ((enum constants
)mdata
) {
806 stayopen
= va_arg(ap
, int);
810 st
->fp
= fopen(_PATH_GROUP
, "r");
813 if (st
->fp
!= NULL
) {
826 files_group(void *retval
, void *mdata
, va_list ap
)
828 struct files_state
*st
;
829 enum nss_lookup_type how
;
830 const char *name
, *line
;
834 size_t bufsize
, linesize
;
836 int rv
, stayopen
, *errnop
;
840 how
= (enum nss_lookup_type
)mdata
;
843 name
= va_arg(ap
, const char *);
846 gid
= va_arg(ap
, gid_t
);
851 return (NS_NOTFOUND
);
853 grp
= va_arg(ap
, struct group
*);
854 buffer
= va_arg(ap
, char *);
855 bufsize
= va_arg(ap
, size_t);
856 errnop
= va_arg(ap
, int *);
857 *errnop
= files_getstate(&st
);
860 if (st
->fp
== NULL
&&
861 ((st
->fp
= fopen(_PATH_GROUP
, "r")) == NULL
)) {
865 if (how
== nss_lt_all
)
869 stayopen
= st
->stayopen
;
872 pos
= ftello(st
->fp
);
873 while ((line
= fgetln(st
->fp
, &linesize
)) != NULL
) {
874 if (line
[linesize
-1] == '\n')
876 rv
= __gr_match_entry(line
, linesize
, how
, name
, gid
);
877 if (rv
!= NS_SUCCESS
)
879 /* We need room at least for the line, a string NUL
880 * terminator, alignment padding, and one (char *)
881 * pointer for the member list terminator.
883 if (bufsize
<= linesize
+ _ALIGNBYTES
+ sizeof(char *)) {
888 memcpy(buffer
, line
, linesize
);
889 buffer
[linesize
] = '\0';
890 rv
= __gr_parse_entry(buffer
, linesize
, grp
,
891 &buffer
[linesize
+ 1], bufsize
- linesize
- 1, errnop
);
892 if (rv
& NS_TERMINATE
)
894 pos
= ftello(st
->fp
);
896 if (!stayopen
&& st
->fp
!= NULL
) {
900 if (rv
== NS_SUCCESS
&& retval
!= NULL
)
901 *(struct group
**)retval
= grp
;
902 else if (rv
== NS_RETURN
&& *errnop
== ERANGE
&& st
->fp
!= NULL
)
903 fseeko(st
->fp
, pos
, SEEK_SET
);
913 dns_endstate(void *p
)
921 dns_setgrent(void *retval
, void *cb_data
, va_list ap
)
923 struct dns_state
*st
;
926 rv
= dns_getstate(&st
);
935 dns_group(void *retval
, void *mdata
, va_list ap
)
937 char buf
[HESIOD_NAME_MAX
];
938 struct dns_state
*st
;
940 const char *name
, *label
;
943 size_t bufsize
, adjsize
, linesize
;
945 enum nss_lookup_type how
;
952 how
= (enum nss_lookup_type
)mdata
;
955 name
= va_arg(ap
, const char *);
958 gid
= va_arg(ap
, gid_t
);
963 grp
= va_arg(ap
, struct group
*);
964 buffer
= va_arg(ap
, char *);
965 bufsize
= va_arg(ap
, size_t);
966 errnop
= va_arg(ap
, int *);
967 *errnop
= dns_getstate(&st
);
970 if (hesiod_init(&ctx
) != 0) {
982 if (snprintf(buf
, sizeof(buf
), "%lu",
983 (unsigned long)gid
) >= sizeof(buf
))
990 if (snprintf(buf
, sizeof(buf
), "group-%ld",
991 st
->counter
++) >= sizeof(buf
))
996 hes
= hesiod_resolve(ctx
, label
,
997 how
== nss_lt_id
? "gid" : "group");
998 if ((how
== nss_lt_id
&& hes
== NULL
&&
999 (hes
= hesiod_resolve(ctx
, buf
, "group")) == NULL
) ||
1001 if (how
== nss_lt_all
)
1003 if (errno
!= ENOENT
)
1007 rv
= __gr_match_entry(hes
[0], strlen(hes
[0]), how
, name
, gid
);
1008 if (rv
!= NS_SUCCESS
) {
1009 hesiod_free_list(ctx
, hes
);
1013 /* We need room at least for the line, a string NUL
1014 * terminator, alignment padding, and one (char *)
1015 * pointer for the member list terminator.
1017 adjsize
= bufsize
- _ALIGNBYTES
- sizeof(char *);
1018 linesize
= strlcpy(buffer
, hes
[0], adjsize
);
1019 if (linesize
>= adjsize
) {
1024 hesiod_free_list(ctx
, hes
);
1026 rv
= __gr_parse_entry(buffer
, linesize
, grp
,
1027 &buffer
[linesize
+ 1], bufsize
- linesize
- 1, errnop
);
1028 } while (how
== nss_lt_all
&& !(rv
& NS_TERMINATE
));
1031 hesiod_free_list(ctx
, hes
);
1034 if (rv
== NS_SUCCESS
&& retval
!= NULL
)
1035 *(struct group
**)retval
= grp
;
1046 nis_endstate(void *p
)
1051 free(((struct nis_state
*)p
)->key
);
1057 nis_setgrent(void *retval __unused
, void *cb_data __unused
, va_list ap __unused
)
1059 struct nis_state
*st
;
1062 rv
= nis_getstate(&st
);
1064 return (NS_UNAVAIL
);
1068 return (NS_UNAVAIL
);
1073 nis_group(void *retval
, void *mdata
, va_list ap
)
1076 struct nis_state
*st
;
1079 char *buffer
, *key
, *result
;
1082 enum nss_lookup_type how
;
1083 int *errnop
, keylen
, resultlen
, rv
;
1087 how
= (enum nss_lookup_type
)mdata
;
1090 name
= va_arg(ap
, const char *);
1091 map
= "group.byname";
1094 gid
= va_arg(ap
, gid_t
);
1095 map
= "group.bygid";
1098 map
= "group.byname";
1101 grp
= va_arg(ap
, struct group
*);
1102 buffer
= va_arg(ap
, char *);
1103 bufsize
= va_arg(ap
, size_t);
1104 errnop
= va_arg(ap
, int *);
1105 *errnop
= nis_getstate(&st
);
1107 return (NS_UNAVAIL
);
1108 if (st
->domain
[0] == '\0') {
1109 if (getdomainname(st
->domain
, sizeof(st
->domain
)) != 0) {
1111 return (NS_UNAVAIL
);
1119 if (strlcpy(buffer
, name
, bufsize
) >= bufsize
)
1123 if (snprintf(buffer
, bufsize
, "%lu",
1124 (unsigned long)gid
) >= bufsize
)
1133 if (how
== nss_lt_all
) {
1134 if (st
->key
== NULL
)
1135 rv
= yp_first(st
->domain
, map
, &st
->key
,
1136 &st
->keylen
, &result
, &resultlen
);
1139 keylen
= st
->keylen
;
1141 rv
= yp_next(st
->domain
, map
, key
, keylen
,
1142 &st
->key
, &st
->keylen
, &result
,
1150 if (rv
== YPERR_NOMORE
) {
1158 rv
= yp_match(st
->domain
, map
, buffer
, strlen(buffer
),
1159 &result
, &resultlen
);
1160 if (rv
== YPERR_KEY
) {
1163 } else if (rv
!= 0) {
1169 /* We need room at least for the line, a string NUL
1170 * terminator, alignment padding, and one (char *)
1171 * pointer for the member list terminator.
1173 if (resultlen
>= bufsize
- _ALIGNBYTES
- sizeof(char *))
1175 memcpy(buffer
, result
, resultlen
);
1176 buffer
[resultlen
] = '\0';
1178 rv
= __gr_match_entry(buffer
, resultlen
, how
, name
, gid
);
1179 if (rv
== NS_SUCCESS
)
1180 rv
= __gr_parse_entry(buffer
, resultlen
, grp
,
1181 &buffer
[resultlen
+1], bufsize
- resultlen
- 1,
1183 } while (how
== nss_lt_all
&& !(rv
& NS_TERMINATE
));
1185 if (rv
== NS_SUCCESS
&& retval
!= NULL
)
1186 *(struct group
**)retval
= grp
;
1200 compat_endstate(void *p
)
1202 struct compat_state
*st
;
1206 st
= (struct compat_state
*)p
;
1215 compat_setgrent(void *retval __unused
, void *mdata
, va_list ap
)
1217 static const ns_src compatsrc
[] = {
1219 { NSSRC_NIS
, NS_SUCCESS
},
1225 { NSSRC_DNS
, dns_setgrent
, NULL
},
1228 { NSSRC_NIS
, nis_setgrent
, NULL
},
1230 { NULL
, NULL
, NULL
}
1232 struct compat_state
*st
;
1235 #define set_setent(x, y) do { \
1238 for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++) \
1239 x[i].mdata = (void *)y; \
1242 rv
= compat_getstate(&st
);
1244 return (NS_UNAVAIL
);
1245 switch ((enum constants
)mdata
) {
1247 stayopen
= va_arg(ap
, int);
1251 st
->fp
= fopen(_PATH_GROUP
, "r");
1252 set_setent(dtab
, mdata
);
1253 _nsdispatch(NULL
, dtab
, NSDB_GROUP_COMPAT
, "setgrent",
1257 if (st
->fp
!= NULL
) {
1261 set_setent(dtab
, mdata
);
1262 _nsdispatch(NULL
, dtab
, NSDB_GROUP_COMPAT
, "endgrent",
1268 st
->compat
= COMPAT_MODE_OFF
;
1271 return (NS_UNAVAIL
);
1277 compat_group(void *retval
, void *mdata
, va_list ap
)
1279 static const ns_src compatsrc
[] = {
1281 { NSSRC_NIS
, NS_SUCCESS
},
1287 { NSSRC_NIS
, nis_group
, NULL
},
1290 { NSSRC_DNS
, dns_group
, NULL
},
1292 { NULL
, NULL
, NULL
}
1294 struct compat_state
*st
;
1295 enum nss_lookup_type how
;
1296 const char *name
, *line
;
1301 size_t bufsize
, linesize
;
1303 int rv
, stayopen
, *errnop
;
1305 #define set_lookup_type(x, y) do { \
1308 for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++) \
1309 x[i].mdata = (void *)y; \
1314 how
= (enum nss_lookup_type
)mdata
;
1317 name
= va_arg(ap
, const char *);
1320 gid
= va_arg(ap
, gid_t
);
1325 return (NS_NOTFOUND
);
1327 grp
= va_arg(ap
, struct group
*);
1328 buffer
= va_arg(ap
, char *);
1329 bufsize
= va_arg(ap
, size_t);
1330 errnop
= va_arg(ap
, int *);
1331 *errnop
= compat_getstate(&st
);
1333 return (NS_UNAVAIL
);
1334 if (st
->fp
== NULL
&&
1335 ((st
->fp
= fopen(_PATH_GROUP
, "r")) == NULL
)) {
1340 if (how
== nss_lt_all
)
1344 stayopen
= st
->stayopen
;
1347 switch (st
->compat
) {
1348 case COMPAT_MODE_ALL
:
1349 set_lookup_type(dtab
, how
);
1352 rv
= _nsdispatch(&discard
, dtab
, NSDB_GROUP_COMPAT
,
1353 "getgrent_r", compatsrc
, grp
, buffer
, bufsize
,
1357 rv
= _nsdispatch(&discard
, dtab
, NSDB_GROUP_COMPAT
,
1358 "getgrgid_r", compatsrc
, gid
, grp
, buffer
, bufsize
,
1362 rv
= _nsdispatch(&discard
, dtab
, NSDB_GROUP_COMPAT
,
1363 "getgrnam_r", compatsrc
, name
, grp
, buffer
,
1367 if (rv
& NS_TERMINATE
)
1369 st
->compat
= COMPAT_MODE_OFF
;
1371 case COMPAT_MODE_NAME
:
1372 set_lookup_type(dtab
, nss_lt_name
);
1373 rv
= _nsdispatch(&discard
, dtab
, NSDB_GROUP_COMPAT
,
1374 "getgrnam_r", compatsrc
, st
->name
, grp
, buffer
, bufsize
,
1380 if (strcmp(name
, grp
->gr_name
) != 0)
1384 if (gid
!= grp
->gr_gid
)
1398 st
->compat
= COMPAT_MODE_OFF
;
1399 if (rv
== NS_SUCCESS
)
1406 pos
= ftello(st
->fp
);
1407 while ((line
= fgetln(st
->fp
, &linesize
)) != NULL
) {
1408 if (line
[linesize
-1] == '\n')
1410 if (linesize
> 2 && line
[0] == '+') {
1411 p
= memchr(&line
[1], ':', linesize
);
1412 if (p
== NULL
|| p
== &line
[1])
1413 st
->compat
= COMPAT_MODE_ALL
;
1415 st
->name
= malloc(p
- line
);
1416 if (st
->name
== NULL
) {
1418 "getgrent memory allocation failure");
1423 memcpy(st
->name
, &line
[1], p
- line
- 1);
1424 st
->name
[p
- line
- 1] = '\0';
1425 st
->compat
= COMPAT_MODE_NAME
;
1429 rv
= __gr_match_entry(line
, linesize
, how
, name
, gid
);
1430 if (rv
!= NS_SUCCESS
)
1432 /* We need room at least for the line, a string NUL
1433 * terminator, alignment padding, and one (char *)
1434 * pointer for the member list terminator.
1436 if (bufsize
<= linesize
+ _ALIGNBYTES
+ sizeof(char *)) {
1441 memcpy(buffer
, line
, linesize
);
1442 buffer
[linesize
] = '\0';
1443 rv
= __gr_parse_entry(buffer
, linesize
, grp
,
1444 &buffer
[linesize
+ 1], bufsize
- linesize
- 1, errnop
);
1445 if (rv
& NS_TERMINATE
)
1447 pos
= ftello(st
->fp
);
1450 if (!stayopen
&& st
->fp
!= NULL
) {
1454 if (rv
== NS_SUCCESS
&& retval
!= NULL
)
1455 *(struct group
**)retval
= grp
;
1456 else if (rv
== NS_RETURN
&& *errnop
== ERANGE
&& st
->fp
!= NULL
)
1457 fseeko(st
->fp
, pos
, SEEK_SET
);
1459 #undef set_lookup_type
1464 * common group line matching and parsing
1467 __gr_match_entry(const char *line
, size_t linesize
, enum nss_lookup_type how
,
1468 const char *name
, gid_t gid
)
1471 const char *p
, *eol
;
1476 if (linesize
== 0 || is_comment_line(line
, linesize
))
1477 return (NS_NOTFOUND
);
1479 case nss_lt_name
: needed
= 1; break;
1480 case nss_lt_id
: needed
= 2; break;
1481 default: needed
= 2; break;
1483 eol
= &line
[linesize
];
1484 for (p
= line
, i
= 0; i
< needed
&& p
< eol
; p
++)
1488 return (NS_NOTFOUND
);
1491 namesize
= strlen(name
);
1492 if (namesize
+ 1 == (size_t)(p
- line
) &&
1493 memcmp(line
, name
, namesize
) == 0)
1494 return (NS_SUCCESS
);
1497 n
= strtoul(p
, &q
, 10);
1498 if (q
< eol
&& *q
== ':' && gid
== (gid_t
)n
)
1499 return (NS_SUCCESS
);
1502 return (NS_SUCCESS
);
1506 return (NS_NOTFOUND
);
1511 __gr_parse_entry(char *line
, size_t linesize __unused
, struct group
*grp
,
1512 char *membuf
, size_t membufsize
, int *errnop
)
1514 char *s_gid
, *s_mem
, *p
, **members
;
1518 memset(grp
, 0, sizeof(*grp
));
1519 members
= (char **)_ALIGN(membuf
);
1520 membufsize
-= (char *)members
- membuf
;
1521 maxmembers
= membufsize
/ sizeof(*members
);
1522 if (maxmembers
<= 0 ||
1523 (grp
->gr_name
= strsep(&line
, ":")) == NULL
||
1524 grp
->gr_name
[0] == '\0' ||
1525 (grp
->gr_passwd
= strsep(&line
, ":")) == NULL
||
1526 (s_gid
= strsep(&line
, ":")) == NULL
||
1528 return (NS_NOTFOUND
);
1530 n
= strtoul(s_gid
, &s_gid
, 10);
1531 if (s_gid
[0] != '\0')
1532 return (NS_NOTFOUND
);
1533 grp
->gr_gid
= (gid_t
)n
;
1534 grp
->gr_mem
= members
;
1535 while (maxmembers
> 1 && s_mem
!= NULL
) {
1536 p
= strsep(&s_mem
, ",");
1537 if (p
!= NULL
&& *p
!= '\0') {
1544 return (NS_SUCCESS
);