1 #include "config.h"
2 #include <sys/types.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <errno.h>
7 #include <libgen.h>
8 #include <limits.h>
9 #include <grp.h>
10
11 #define TEST_GROUP "test/test.group"
12 static char grfile[PATH_MAX];
13 static void setup_grfile() __attribute__((constructor));
14
15 static void setup_grfile() {
16 snprintf(grfile, sizeof(grfile), "%s/%s", BASEDIR, TEST_GROUP);
17 }
18
19 #define ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
20 #define ALIGN(x, a) ALIGN_MASK(x, (typeof(x))(a) - 1)
21
22 static int test_getgrent_r(FILE *file, struct group *grp, char *buf,
23 size_t buflen, struct group **result)
24 {
25 char *line, *str, *remain;
26 int count, index = 0;
27 int gr_mem_cnt = 0;
28
29 *result = NULL;
30
31 line = fgets(buf, buflen, file);
32 if (!line)
33 return 0;
34
35 /* We'll stuff the gr_mem array in the remaining space in the buffer */
36 remain = buf + ALIGN(line + strlen(line) - buf, sizeof(char *));
37 grp->gr_mem = (char **)remain;
38 count = (buf + buflen - remain) / sizeof (char *);
39 if (!count) {
40 errno = ERANGE;
41 return -1;
42 }
43
44 grp->gr_mem[--count] = NULL;
45
46 while ((str = strtok(line, ":"))) {
47 char *ptr;
48 switch (index++) {
49 case 0:
50 grp->gr_name = str;
51 break;
52 case 1:
53 grp->gr_passwd = str;
54 break;
55 case 2:
56 errno = 0;
57 grp->gr_gid = strtol(str, NULL, 10);
58 if (errno)
59 return -1;
60 break;
61 case 3:
62 while ((str = strtok_r(str, ",", &ptr))) {
63 if (count-- <= 0) {
64 errno = ERANGE;
65 return -1;
66 }
67 grp->gr_mem[gr_mem_cnt++] = str;
68 str = NULL;
69 }
70 }
71 line = NULL;
72 }
73
74 *result = grp;
75
76 return 0;
77 }
78
79 static int test_getgr_match(struct group *grp, char *buf, size_t buflen,
80 struct group **result,
81 int (*match)(const struct group *, const void *),
82 const void *data)
83 {
84 FILE *file;
85 struct group *_result;
86
87 *result = NULL;
88
89 file = fopen(grfile, "r");
90 if (!file) {
91 errno = EBADF;
92 return -1;
93 }
94
95 errno = 0;
96 while (!test_getgrent_r(file, grp, buf, buflen, &_result)) {
97 if (!_result)
98 break;
99 else if (match(grp, data)) {
100 *result = grp;
101 break;
102 }
103 }
104
105 fclose(file);
106 if (!errno && !*result)
107 errno = ENOENT;
108 if (errno)
109 return -1;
110 return 0;
111 }
112
113 static int match_name(const struct group *grp, const void *data)
114 {
115 const char *name = data;
116 return !strcmp(grp->gr_name, name);
117 }
118
119 EXPORT
120 int getgrnam_r(const char *name, struct group *grp, char *buf, size_t buflen,
121 struct group **result)
122 {
123 return test_getgr_match(grp, buf, buflen, result, match_name, name);
124 }
125
126 EXPORT
127 struct group *getgrnam(const char *name)
128 {
129 static char buf[16384];
130 static struct group grp;
131 struct group *result;
132
133 (void) getgrnam_r(name, &grp, buf, sizeof(buf), &result);
134 return result;
135 }
136
137 static int match_gid(const struct group *grp, const void *data)
138 {
139 gid_t gid = *(gid_t *)data;
140 return grp->gr_gid == gid;
141 }
142
143 EXPORT
144 int getgrgid_r(gid_t gid, struct group *grp, char *buf, size_t buflen,
145 struct group **result)
146 {
147 return test_getgr_match(grp, buf, buflen, result, match_gid, &gid);
148 }
149
150 EXPORT
151 struct group *getgrgid(gid_t gid)
152 {
153 static char buf[16384];
154 static struct group grp;
155 struct group *result;
156
157 (void) getgrgid_r(gid, &grp, buf, sizeof(buf), &result);
158 return result;
159 }