1 /* $OpenBSD: group.c,v 1.5 2003/07/31 21:48:04 deraadt 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 44 /* Acquire lock for running first part. */ 45 CHECKr(pthread_mutex_lock(&display)); 46 47 /* Store magic name to test for non-alteration */ 48 grpbuf.gr_name = fail; 49 50 /* Call getgrgid_r() */ 51 printf("gid %d\n", gid); 52 CHECKr(getgrgid_r(gid, &grpbuf, buffer, sizeof(buffer), &grp)); 53 54 /* Test for non-alteration of group structure */ 55 ASSERT(grp->gr_name != fail); 56 57 /* We must get the right group */ 58 ASSERT(grp->gr_gid == gid); 59 60 s = buf; /* Keep our private buffer on the stack */ 61 62 /* copy gr_name */ 63 strcpy(oname = s, grp->gr_name); 64 s += 1 + strlen(s); 65 66 /* copy gr_passwd */ 67 strcpy(opasswd = s, grp->gr_passwd); 68 s += 1 + strlen(s); 69 70 /* copy gr_gid */ 71 ogid = grp->gr_gid; 72 73 /* copy gr_mem */ 74 for (i = 0, p = grp->gr_mem; *p; p++) { 75 strcpy(cpy[i] = s, *p); i++; 76 s += 1 + strlen(s); 77 } 78 cpy[i] = NULL; 79 80 #if 0 81 printf("now: %s:%s:%d:", grp->gr_name, grp->gr_passwd, grp->gr_gid); 82 for (p = grp->gr_mem; *p; p++) 83 printf("%s%s", *p, *(p+1) == NULL ? "": ","); 84 printf("\n"); 85 #endif 86 87 #ifdef DEBUG /* debugging this program */ 88 printf("buf = \""); 89 for (i = 0; i < s - buf; i++) 90 if (buf[i] == '\0') printf("\\0"); 91 else printf("%c", buf[i]); 92 printf("\"\n"); 93 #endif 94 95 /* Inform main that we have finished */ 96 done_count++; 97 CHECKr(pthread_cond_signal(&done)); 98 99 /* Allow other threads to run first part */ 100 CHECKr(pthread_mutex_unlock(&display)); 101 102 /* Acquire lock for the second part */ 103 CHECKr(pthread_mutex_lock(&display2)); 104 105 count1 = 0; 106 printf("before: %s:%s:%d:", oname, opasswd, ogid); 107 for (p = cpy; *p; p++) { 108 count1++; 109 printf("%s%s", *p, *(p+1) == NULL ? "": ","); 110 } 111 printf("\n"); 112 113 count2 = 0; 114 printf("after: %s:%s:%d:", grp->gr_name, grp->gr_passwd, grp->gr_gid); 115 for (p = grp->gr_mem; *p; p++) { 116 count2++; 117 printf("%s%s", *p, *(p+1) == NULL ? "": ","); 118 } 119 printf("\n"); 120 121 CHECKr(pthread_mutex_unlock(&display2)); 122 123 if (count1 != count2) 124 return "gr_mem length changed"; 125 for (i = 0; i < count1; i++) 126 if (strcmp(cpy[i], grp->gr_mem[i]) != 0) 127 return "gr_mem list changed"; 128 if (strcmp(grp->gr_name, oname) != 0) 129 return "gr_name changed"; 130 if (strcmp(grp->gr_passwd, opasswd) != 0) 131 return "gr_passwd changed"; 132 if (grp->gr_gid != ogid) 133 return "gr_gid changed"; 134 return NULL; 135 } 136 137 138 #define NGRPS 5 139 int 140 main(int argc, char *argv[]) 141 { 142 pthread_t thread[NGRPS]; 143 int gid; 144 int failed; 145 void *result; 146 147 CHECKr(pthread_mutex_init(&display, NULL)); 148 CHECKr(pthread_mutex_init(&display2, NULL)); 149 150 CHECKr(pthread_cond_init(&done, NULL)); 151 done_count = 0; 152 153 pthread_mutex_lock(&display); 154 pthread_mutex_lock(&display2); 155 156 /* Get separate threads to do a group open separately */ 157 for (gid = 0; gid < NGRPS; gid++) { 158 int *n = (int *)malloc(sizeof(int)); 159 *n = gid; 160 161 CHECKr(pthread_create(&thread[gid], NULL, test, (void *)n)); 162 } 163 164 /* Allow all threads to run their first part */ 165 while (done_count < NGRPS) 166 pthread_cond_wait(&done, &display); 167 168 /* Allow each thread to run the 2nd part of its test */ 169 CHECKr(pthread_mutex_unlock(&display2)); 170 171 /* Wait for each thread to terminate, collecting results. */ 172 failed = 0; 173 for (gid = 0; gid < NGRPS; gid++) { 174 CHECKr(pthread_join(thread[gid], &result)); 175 if (result != NULL) { 176 fprintf(stderr, "gid %d: %s\n", gid, (char *)result); 177 failed++; 178 } 179 } 180 181 if (!failed) { 182 SUCCEED; 183 } else { 184 exit(1); 185 } 186 } 187