1 /* $OpenBSD: group.c,v 1.6 2005/10/30 23:59:43 fgsch Exp $ */
2
3 /* David Leonard <d@openbsd.org>, 2001. Public Domain. */
4
5 /*
6 * Test getgrgid_r() across multiple threads to see if the members list changes.
7 */
8
9 #include <sys/types.h>
10 #include <grp.h>
11 #include <pthread.h>
12 #include <unistd.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include "test.h"
16
17 int getgrgid_r(gid_t, struct group *, char *, size_t, struct group **);
18
19 char fail[] = "fail";
20
21 pthread_cond_t done;
22 volatile int done_count;
23
24 pthread_mutex_t display;
25 pthread_mutex_t display2;
26
27 static void *
test(void * arg)28 test(void *arg)
29 {
30 gid_t gid = *(gid_t *)arg;
31 gid_t ogid;
32 struct group grpbuf;
33 struct group *grp;
34 char **p;
35 char buffer[5000];
36 char buf[2048];
37 char *cpy[128];
38 int i;
39 int count1, count2;
40 char *s;
41 char *oname;
42 char *opasswd;
43 size_t len;
44
45 /* Acquire lock for running first part. */
46 CHECKr(pthread_mutex_lock(&display));
47
48 /* Store magic name to test for non-alteration */
49 grpbuf.gr_name = fail;
50
51 /* Call getgrgid_r() */
52 printf("gid %d\n", gid);
53 CHECKr(getgrgid_r(gid, &grpbuf, buffer, sizeof(buffer), &grp));
54
55 /* Test for non-alteration of group structure */
56 ASSERT(grp->gr_name != fail);
57
58 /* We must get the right group */
59 ASSERT(grp->gr_gid == gid);
60
61 s = buf; /* Keep our private buffer on the stack */
62 len = sizeof(buf);
63
64 /* copy gr_name */
65 strlcpy(oname = s, grp->gr_name, len);
66 len -= 1 + strlen(s);
67 s += 1 + strlen(s);
68
69 /* copy gr_passwd */
70 strlcpy(opasswd = s, grp->gr_passwd, len);
71 len -= 1 + strlen(s);
72 s += 1 + strlen(s);
73
74 /* copy gr_gid */
75 ogid = grp->gr_gid;
76
77 /* copy gr_mem */
78 for (i = 0, p = grp->gr_mem; *p; p++) {
79 strlcpy(cpy[i] = s, *p, len);
80 i++;
81 len -= 1 + strlen(s);
82 s += 1 + strlen(s);
83 }
84 cpy[i] = NULL;
85
86 #if 0
87 printf("now: %s:%s:%d:", grp->gr_name, grp->gr_passwd, grp->gr_gid);
88 for (p = grp->gr_mem; *p; p++)
89 printf("%s%s", *p, *(p+1) == NULL ? "": ",");
90 printf("\n");
91 #endif
92
93 #ifdef DEBUG /* debugging this program */
94 printf("buf = \"");
95 for (i = 0; i < s - buf; i++)
96 if (buf[i] == '\0') printf("\\0");
97 else printf("%c", buf[i]);
98 printf("\"\n");
99 #endif
100
101 /* Inform main that we have finished */
102 done_count++;
103 CHECKr(pthread_cond_signal(&done));
104
105 /* Allow other threads to run first part */
106 CHECKr(pthread_mutex_unlock(&display));
107
108 /* Acquire lock for the second part */
109 CHECKr(pthread_mutex_lock(&display2));
110
111 count1 = 0;
112 printf("before: %s:%s:%d:", oname, opasswd, ogid);
113 for (p = cpy; *p; p++) {
114 count1++;
115 printf("%s%s", *p, *(p+1) == NULL ? "": ",");
116 }
117 printf("\n");
118
119 count2 = 0;
120 printf("after: %s:%s:%d:", grp->gr_name, grp->gr_passwd, grp->gr_gid);
121 for (p = grp->gr_mem; *p; p++) {
122 count2++;
123 printf("%s%s", *p, *(p+1) == NULL ? "": ",");
124 }
125 printf("\n");
126
127 CHECKr(pthread_mutex_unlock(&display2));
128
129 if (count1 != count2)
130 return "gr_mem length changed";
131 for (i = 0; i < count1; i++)
132 if (strcmp(cpy[i], grp->gr_mem[i]) != 0)
133 return "gr_mem list changed";
134 if (strcmp(grp->gr_name, oname) != 0)
135 return "gr_name changed";
136 if (strcmp(grp->gr_passwd, opasswd) != 0)
137 return "gr_passwd changed";
138 if (grp->gr_gid != ogid)
139 return "gr_gid changed";
140 return NULL;
141 }
142
143
144 #define NGRPS 5
145 int
main(int argc,char * argv[])146 main(int argc, char *argv[])
147 {
148 pthread_t thread[NGRPS];
149 int gid;
150 int failed;
151 void *result;
152
153 CHECKr(pthread_mutex_init(&display, NULL));
154 CHECKr(pthread_mutex_init(&display2, NULL));
155
156 CHECKr(pthread_cond_init(&done, NULL));
157 done_count = 0;
158
159 pthread_mutex_lock(&display);
160 pthread_mutex_lock(&display2);
161
162 /* Get separate threads to do a group open separately */
163 for (gid = 0; gid < NGRPS; gid++) {
164 int *n = (int *)malloc(sizeof(int));
165 *n = gid;
166
167 CHECKr(pthread_create(&thread[gid], NULL, test, (void *)n));
168 }
169
170 /* Allow all threads to run their first part */
171 while (done_count < NGRPS)
172 pthread_cond_wait(&done, &display);
173
174 /* Allow each thread to run the 2nd part of its test */
175 CHECKr(pthread_mutex_unlock(&display2));
176
177 /* Wait for each thread to terminate, collecting results. */
178 failed = 0;
179 for (gid = 0; gid < NGRPS; gid++) {
180 CHECKr(pthread_join(thread[gid], &result));
181 if (result != NULL) {
182 fprintf(stderr, "gid %d: %s\n", gid, (char *)result);
183 failed++;
184 }
185 }
186
187 if (!failed) {
188 SUCCEED;
189 } else {
190 exit(1);
191 }
192 }
193