1 /*- 2 * Copyright (c) 2008 Sean C. Farley <scf@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * without modification, immediately at the beginning of the file. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 32 #include <grp.h> 33 #include <inttypes.h> 34 #include <libutil.h> 35 #include <stdbool.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 40 struct group_storage { 41 struct group gr; 42 char *members[]; 43 }; 44 45 static const char group_line_format[] = "%s:%s:%ju:"; 46 47 /* 48 * Compares two struct group's. 49 */ 50 int 51 gr_equal(const struct group *gr1, const struct group *gr2) 52 { 53 int gr1_ndx; 54 int gr2_ndx; 55 bool found; 56 57 /* Check that the non-member information is the same. */ 58 if (gr1->gr_name == NULL || gr2->gr_name == NULL) { 59 if (gr1->gr_name != gr2->gr_name) 60 return (false); 61 } else if (strcmp(gr1->gr_name, gr2->gr_name) != 0) 62 return (false); 63 if (gr1->gr_passwd == NULL || gr2->gr_passwd == NULL) { 64 if (gr1->gr_passwd != gr2->gr_passwd) 65 return (false); 66 } else if (strcmp(gr1->gr_passwd, gr2->gr_passwd) != 0) 67 return (false); 68 if (gr1->gr_gid != gr2->gr_gid) 69 return (false); 70 71 /* Check all members in both groups. */ 72 if (gr1->gr_mem == NULL || gr2->gr_mem == NULL) { 73 if (gr1->gr_mem != gr2->gr_mem) 74 return (false); 75 } else { 76 for (found = false, gr1_ndx = 0; gr1->gr_mem[gr1_ndx] != NULL; 77 gr1_ndx++) { 78 for (gr2_ndx = 0; gr2->gr_mem[gr2_ndx] != NULL; 79 gr2_ndx++) 80 if (strcmp(gr1->gr_mem[gr1_ndx], 81 gr2->gr_mem[gr2_ndx]) == 0) { 82 found = true; 83 break; 84 } 85 if (!found) 86 return (false); 87 } 88 89 /* Check that group2 does not have more members than group1. */ 90 if (gr2->gr_mem[gr1_ndx] != NULL) 91 return (false); 92 } 93 94 return (true); 95 } 96 97 /* 98 * Make a group line out of a struct group. 99 */ 100 char * 101 gr_make(const struct group *gr) 102 { 103 char *line; 104 size_t line_size; 105 int ndx; 106 107 /* Calculate the length of the group line. */ 108 line_size = snprintf(NULL, 0, group_line_format, gr->gr_name, 109 gr->gr_passwd, (uintmax_t)gr->gr_gid) + 1; 110 if (gr->gr_mem != NULL) { 111 for (ndx = 0; gr->gr_mem[ndx] != NULL; ndx++) 112 line_size += strlen(gr->gr_mem[ndx]) + 1; 113 if (ndx > 0) 114 line_size--; 115 } 116 117 /* Create the group line and fill it. */ 118 if ((line = malloc(line_size)) == NULL) 119 return (NULL); 120 snprintf(line, line_size, group_line_format, gr->gr_name, gr->gr_passwd, 121 (uintmax_t)gr->gr_gid); 122 if (gr->gr_mem != NULL) 123 for (ndx = 0; gr->gr_mem[ndx] != NULL; ndx++) { 124 strcat(line, gr->gr_mem[ndx]); 125 if (gr->gr_mem[ndx + 1] != NULL) 126 strcat(line, ","); 127 } 128 129 return (line); 130 } 131 132 /* 133 * Duplicate a struct group. 134 */ 135 struct group * 136 gr_dup(const struct group *gr) 137 { 138 char *dst; 139 size_t len; 140 struct group_storage *gs; 141 int ndx; 142 int num_mem; 143 144 /* Calculate size of the group. */ 145 len = sizeof(*gs); 146 if (gr->gr_name != NULL) 147 len += strlen(gr->gr_name) + 1; 148 if (gr->gr_passwd != NULL) 149 len += strlen(gr->gr_passwd) + 1; 150 if (gr->gr_mem != NULL) { 151 for (num_mem = 0; gr->gr_mem[num_mem] != NULL; num_mem++) 152 len += strlen(gr->gr_mem[num_mem]) + 1; 153 len += (num_mem + 1) * sizeof(*gr->gr_mem); 154 } else 155 num_mem = -1; 156 157 /* Create new group and copy old group into it. */ 158 if ((gs = calloc(1, len)) == NULL) 159 return (NULL); 160 dst = (char *)&gs->members[num_mem + 1]; 161 if (gr->gr_name != NULL) { 162 gs->gr.gr_name = dst; 163 dst = stpcpy(gs->gr.gr_name, gr->gr_name) + 1; 164 } 165 if (gr->gr_passwd != NULL) { 166 gs->gr.gr_passwd = dst; 167 dst = stpcpy(gs->gr.gr_passwd, gr->gr_passwd) + 1; 168 } 169 gs->gr.gr_gid = gr->gr_gid; 170 if (gr->gr_mem != NULL) { 171 gs->gr.gr_mem = gs->members; 172 for (ndx = 0; ndx < num_mem; ndx++) { 173 gs->gr.gr_mem[ndx] = dst; 174 dst = stpcpy(gs->gr.gr_mem[ndx], gr->gr_mem[ndx]) + 1; 175 } 176 gs->gr.gr_mem[ndx] = NULL; 177 } 178 179 return (&gs->gr); 180 } 181 182 /* 183 * Scan a line and place it into a group structure. 184 */ 185 static bool 186 __gr_scan(char *line, struct group *gr) 187 { 188 char *loc; 189 int ndx; 190 191 /* Assign non-member information to structure. */ 192 gr->gr_name = line; 193 if ((loc = strchr(line, ':')) == NULL) 194 return (false); 195 *loc = '\0'; 196 gr->gr_passwd = loc + 1; 197 if (*gr->gr_passwd == ':') 198 *gr->gr_passwd = '\0'; 199 else { 200 if ((loc = strchr(loc + 1, ':')) == NULL) 201 return (false); 202 *loc = '\0'; 203 } 204 if (sscanf(loc + 1, "%u", &gr->gr_gid) != 1) 205 return (false); 206 207 /* Assign member information to structure. */ 208 if ((loc = strchr(loc + 1, ':')) == NULL) 209 return (false); 210 line = loc + 1; 211 gr->gr_mem = NULL; 212 ndx = 0; 213 do { 214 gr->gr_mem = reallocf(gr->gr_mem, sizeof(*gr->gr_mem) * 215 (ndx + 1)); 216 if (gr->gr_mem == NULL) 217 return (false); 218 219 /* Skip locations without members (i.e., empty string). */ 220 do { 221 gr->gr_mem[ndx] = strsep(&line, ","); 222 } while (gr->gr_mem[ndx] != NULL && *gr->gr_mem[ndx] == '\0'); 223 } while (gr->gr_mem[ndx++] != NULL); 224 225 return (true); 226 } 227 228 /* 229 * Create a struct group from a line. 230 */ 231 struct group * 232 gr_scan(const char *line) 233 { 234 struct group gr; 235 char *line_copy; 236 struct group *new_gr; 237 238 if ((line_copy = strdup(line)) == NULL) 239 return (NULL); 240 if (!__gr_scan(line_copy, &gr)) { 241 free(line_copy); 242 return (NULL); 243 } 244 new_gr = gr_dup(&gr); 245 free(line_copy); 246 if (gr.gr_mem != NULL) 247 free(gr.gr_mem); 248 249 return (new_gr); 250 } 251