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