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 * 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 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