10b5e8899SSean Farley /*- 20b5e8899SSean Farley * Copyright (c) 2008 Sean C. Farley <scf@FreeBSD.org> 30b5e8899SSean Farley * All rights reserved. 40b5e8899SSean Farley * 50b5e8899SSean Farley * Redistribution and use in source and binary forms, with or without 60b5e8899SSean Farley * modification, are permitted provided that the following conditions 70b5e8899SSean Farley * are met: 80b5e8899SSean Farley * 1. Redistributions of source code must retain the above copyright 90b5e8899SSean Farley * notice, this list of conditions and the following disclaimer, 100b5e8899SSean Farley * without modification, immediately at the beginning of the file. 110b5e8899SSean Farley * 2. Redistributions in binary form must reproduce the above copyright 120b5e8899SSean Farley * notice, this list of conditions and the following disclaimer in the 130b5e8899SSean Farley * documentation and/or other materials provided with the distribution. 140b5e8899SSean Farley * 150b5e8899SSean Farley * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 160b5e8899SSean Farley * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 170b5e8899SSean Farley * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 180b5e8899SSean Farley * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 190b5e8899SSean Farley * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 200b5e8899SSean Farley * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 210b5e8899SSean Farley * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 220b5e8899SSean Farley * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 230b5e8899SSean Farley * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 240b5e8899SSean Farley * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 250b5e8899SSean Farley */ 260b5e8899SSean Farley 270b5e8899SSean Farley #include <sys/cdefs.h> 280b5e8899SSean Farley __FBSDID("$FreeBSD$"); 290b5e8899SSean Farley 300b5e8899SSean Farley #include <sys/param.h> 31a0671723SSean Farley 320b5e8899SSean Farley #include <grp.h> 330b5e8899SSean Farley #include <inttypes.h> 34a0671723SSean Farley #include <libutil.h> 350b5e8899SSean Farley #include <stdbool.h> 360b5e8899SSean Farley #include <stdio.h> 370b5e8899SSean Farley #include <stdlib.h> 380b5e8899SSean Farley #include <string.h> 390b5e8899SSean Farley 40805da51aSSean Farley struct group_storage { 41805da51aSSean Farley struct group gr; 42805da51aSSean Farley char *members[]; 43805da51aSSean Farley }; 44805da51aSSean Farley 45805da51aSSean Farley static const char group_line_format[] = "%s:%s:%ju:"; 460b5e8899SSean Farley 470b5e8899SSean Farley /* 480b5e8899SSean Farley * Compares two struct group's. 490b5e8899SSean Farley */ 500b5e8899SSean Farley int 510b5e8899SSean Farley gr_equal(const struct group *gr1, const struct group *gr2) 520b5e8899SSean Farley { 53805da51aSSean Farley int gr1_ndx; 54805da51aSSean Farley int gr2_ndx; 55a0671723SSean Farley bool found; 560b5e8899SSean Farley 570b5e8899SSean Farley /* Check that the non-member information is the same. */ 58805da51aSSean Farley if (gr1->gr_name == NULL || gr2->gr_name == NULL) { 59805da51aSSean Farley if (gr1->gr_name != gr2->gr_name) 60805da51aSSean Farley return (false); 61805da51aSSean Farley } else if (strcmp(gr1->gr_name, gr2->gr_name) != 0) 62805da51aSSean Farley return (false); 63805da51aSSean Farley if (gr1->gr_passwd == NULL || gr2->gr_passwd == NULL) { 64805da51aSSean Farley if (gr1->gr_passwd != gr2->gr_passwd) 65805da51aSSean Farley return (false); 66805da51aSSean Farley } else if (strcmp(gr1->gr_passwd, gr2->gr_passwd) != 0) 67805da51aSSean Farley return (false); 68805da51aSSean Farley if (gr1->gr_gid != gr2->gr_gid) 69805da51aSSean Farley return (false); 700b5e8899SSean Farley 710b5e8899SSean Farley /* Check all members in both groups. */ 72805da51aSSean Farley if (gr1->gr_mem == NULL || gr2->gr_mem == NULL) { 73805da51aSSean Farley if (gr1->gr_mem != gr2->gr_mem) 74805da51aSSean Farley return (false); 75805da51aSSean Farley } else { 76805da51aSSean Farley for (found = false, gr1_ndx = 0; gr1->gr_mem[gr1_ndx] != NULL; 77805da51aSSean Farley gr1_ndx++) { 78805da51aSSean Farley for (gr2_ndx = 0; gr2->gr_mem[gr2_ndx] != NULL; 79805da51aSSean Farley gr2_ndx++) 80805da51aSSean Farley if (strcmp(gr1->gr_mem[gr1_ndx], 81805da51aSSean Farley gr2->gr_mem[gr2_ndx]) == 0) { 820b5e8899SSean Farley found = true; 830b5e8899SSean Farley break; 840b5e8899SSean Farley } 85805da51aSSean Farley if (!found) 86805da51aSSean Farley return (false); 870b5e8899SSean Farley } 880b5e8899SSean Farley 890b5e8899SSean Farley /* Check that group2 does not have more members than group1. */ 90805da51aSSean Farley if (gr2->gr_mem[gr1_ndx] != NULL) 91805da51aSSean Farley return (false); 920b5e8899SSean Farley } 930b5e8899SSean Farley 94805da51aSSean Farley return (true); 950b5e8899SSean Farley } 960b5e8899SSean Farley 970b5e8899SSean Farley /* 980b5e8899SSean Farley * Make a group line out of a struct group. 990b5e8899SSean Farley */ 1000b5e8899SSean Farley char * 1010b5e8899SSean Farley gr_make(const struct group *gr) 1020b5e8899SSean Farley { 1030b5e8899SSean Farley char *line; 104805da51aSSean Farley size_t line_size; 105a0671723SSean Farley int ndx; 1060b5e8899SSean Farley 1070b5e8899SSean Farley /* Calculate the length of the group line. */ 108805da51aSSean Farley line_size = snprintf(NULL, 0, group_line_format, gr->gr_name, 1090b5e8899SSean Farley gr->gr_passwd, (uintmax_t)gr->gr_gid) + 1; 110805da51aSSean Farley if (gr->gr_mem != NULL) { 1110b5e8899SSean Farley for (ndx = 0; gr->gr_mem[ndx] != NULL; ndx++) 112805da51aSSean Farley line_size += strlen(gr->gr_mem[ndx]) + 1; 1130b5e8899SSean Farley if (ndx > 0) 114805da51aSSean Farley line_size--; 115805da51aSSean Farley } 1160b5e8899SSean Farley 1170b5e8899SSean Farley /* Create the group line and fill it. */ 118805da51aSSean Farley if ((line = malloc(line_size)) == NULL) 1190b5e8899SSean Farley return (NULL); 120805da51aSSean Farley line_size = snprintf(line, line_size, group_line_format, gr->gr_name, 1210b5e8899SSean Farley gr->gr_passwd, (uintmax_t)gr->gr_gid); 122805da51aSSean Farley if (gr->gr_mem != NULL) 1230b5e8899SSean Farley for (ndx = 0; gr->gr_mem[ndx] != NULL; ndx++) { 1240b5e8899SSean Farley strcat(line, gr->gr_mem[ndx]); 1250b5e8899SSean Farley if (gr->gr_mem[ndx + 1] != NULL) 1260b5e8899SSean Farley strcat(line, ","); 1270b5e8899SSean Farley } 1280b5e8899SSean Farley 1290b5e8899SSean Farley return (line); 1300b5e8899SSean Farley } 1310b5e8899SSean Farley 1320b5e8899SSean Farley /* 1330b5e8899SSean Farley * Duplicate a struct group. 1340b5e8899SSean Farley */ 1350b5e8899SSean Farley struct group * 1360b5e8899SSean Farley gr_dup(const struct group *gr) 1370b5e8899SSean Farley { 138805da51aSSean Farley char *dst; 1390b5e8899SSean Farley size_t len; 140805da51aSSean Farley struct group_storage *gs; 141a0671723SSean Farley int ndx; 142805da51aSSean Farley int num_mem; 1430b5e8899SSean Farley 144805da51aSSean Farley /* Calculate size of the group. */ 145805da51aSSean Farley len = sizeof(*gs); 146805da51aSSean Farley if (gr->gr_name != NULL) 147805da51aSSean Farley len += strlen(gr->gr_name) + 1; 148805da51aSSean Farley if (gr->gr_passwd != NULL) 149805da51aSSean Farley len += strlen(gr->gr_passwd) + 1; 1500b5e8899SSean Farley if (gr->gr_mem != NULL) { 151805da51aSSean Farley for (num_mem = 0; gr->gr_mem[num_mem] != NULL; num_mem++) 152805da51aSSean Farley len += strlen(gr->gr_mem[num_mem]) + 1; 153805da51aSSean Farley len += (num_mem + 1) * sizeof(*gr->gr_mem); 154805da51aSSean Farley } else 155805da51aSSean Farley num_mem = -1; 1560b5e8899SSean Farley 1570b5e8899SSean Farley /* Create new group and copy old group into it. */ 158805da51aSSean Farley if ((gs = calloc(1, len)) == NULL) 1590b5e8899SSean Farley return (NULL); 160805da51aSSean Farley dst = (char *)&gs->members[num_mem + 1]; 1610b5e8899SSean Farley if (gr->gr_name != NULL) { 162805da51aSSean Farley gs->gr.gr_name = dst; 163805da51aSSean Farley dst = stpcpy(gs->gr.gr_name, gr->gr_name) + 1; 1640b5e8899SSean Farley } 1650b5e8899SSean Farley if (gr->gr_passwd != NULL) { 166805da51aSSean Farley gs->gr.gr_passwd = dst; 167805da51aSSean Farley dst = stpcpy(gs->gr.gr_passwd, gr->gr_passwd) + 1; 1680b5e8899SSean Farley } 169805da51aSSean Farley gs->gr.gr_gid = gr->gr_gid; 1700b5e8899SSean Farley if (gr->gr_mem != NULL) { 171805da51aSSean Farley gs->gr.gr_mem = gs->members; 172805da51aSSean Farley for (ndx = 0; ndx < num_mem; ndx++) { 173805da51aSSean Farley gs->gr.gr_mem[ndx] = dst; 174805da51aSSean Farley dst = stpcpy(gs->gr.gr_mem[ndx], gr->gr_mem[ndx]) + 1; 1750b5e8899SSean Farley } 176805da51aSSean Farley gs->gr.gr_mem[ndx] = NULL; 1770b5e8899SSean Farley } 1780b5e8899SSean Farley 179805da51aSSean Farley return (&gs->gr); 1800b5e8899SSean Farley } 1810b5e8899SSean Farley 1820b5e8899SSean Farley /* 1830b5e8899SSean Farley * Scan a line and place it into a group structure. 1840b5e8899SSean Farley */ 1850b5e8899SSean Farley static bool 1860b5e8899SSean Farley __gr_scan(char *line, struct group *gr) 1870b5e8899SSean Farley { 1880b5e8899SSean Farley char *loc; 1890b5e8899SSean Farley int ndx; 1900b5e8899SSean Farley 1910b5e8899SSean Farley /* Assign non-member information to structure. */ 1920b5e8899SSean Farley gr->gr_name = line; 1930b5e8899SSean Farley if ((loc = strchr(line, ':')) == NULL) 1940b5e8899SSean Farley return (false); 1950b5e8899SSean Farley *loc = '\0'; 1960b5e8899SSean Farley gr->gr_passwd = loc + 1; 197a0671723SSean Farley if (*gr->gr_passwd == ':') 198a0671723SSean Farley *gr->gr_passwd = '\0'; 1990b5e8899SSean Farley else { 2000b5e8899SSean Farley if ((loc = strchr(loc + 1, ':')) == NULL) 2010b5e8899SSean Farley return (false); 2020b5e8899SSean Farley *loc = '\0'; 2030b5e8899SSean Farley } 204a0671723SSean Farley if (sscanf(loc + 1, "%u", &gr->gr_gid) != 1) 2050b5e8899SSean Farley return (false); 2060b5e8899SSean Farley 2070b5e8899SSean Farley /* Assign member information to structure. */ 2080b5e8899SSean Farley if ((loc = strchr(loc + 1, ':')) == NULL) 2090b5e8899SSean Farley return (false); 2100b5e8899SSean Farley line = loc + 1; 2110b5e8899SSean Farley gr->gr_mem = NULL; 2120b5e8899SSean Farley ndx = 0; 2130b5e8899SSean Farley do { 214805da51aSSean Farley gr->gr_mem = reallocf(gr->gr_mem, sizeof(*gr->gr_mem) * 215805da51aSSean Farley (ndx + 1)); 216805da51aSSean Farley if (gr->gr_mem == NULL) 2170b5e8899SSean Farley return (false); 218805da51aSSean Farley 219805da51aSSean Farley /* Skip locations without members (i.e., empty string). */ 220805da51aSSean Farley do { 2210b5e8899SSean Farley gr->gr_mem[ndx] = strsep(&line, ","); 222805da51aSSean Farley } while (gr->gr_mem[ndx] != NULL && *gr->gr_mem[ndx] == '\0'); 2230b5e8899SSean Farley } while (gr->gr_mem[ndx++] != NULL); 2240b5e8899SSean Farley 2250b5e8899SSean Farley return (true); 2260b5e8899SSean Farley } 2270b5e8899SSean Farley 2280b5e8899SSean Farley /* 2290b5e8899SSean Farley * Create a struct group from a line. 2300b5e8899SSean Farley */ 2310b5e8899SSean Farley struct group * 2320b5e8899SSean Farley gr_scan(const char *line) 2330b5e8899SSean Farley { 234a0671723SSean Farley struct group gr; 235805da51aSSean Farley char *line_copy; 236805da51aSSean Farley struct group *new_gr; 2370b5e8899SSean Farley 238805da51aSSean Farley if ((line_copy = strdup(line)) == NULL) 2390b5e8899SSean Farley return (NULL); 240805da51aSSean Farley if (!__gr_scan(line_copy, &gr)) { 241805da51aSSean Farley free(line_copy); 2420b5e8899SSean Farley return (NULL); 2430b5e8899SSean Farley } 244805da51aSSean Farley new_gr = gr_dup(&gr); 245805da51aSSean Farley free(line_copy); 2460b5e8899SSean Farley if (gr.gr_mem != NULL) 2470b5e8899SSean Farley free(gr.gr_mem); 2480b5e8899SSean Farley 249805da51aSSean Farley return (new_gr); 2500b5e8899SSean Farley } 251