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 400b5e8899SSean Farley static const char GroupLineFormat[] = "%s:%s:%ju:"; 410b5e8899SSean Farley 420b5e8899SSean Farley /* 430b5e8899SSean Farley * Compares two struct group's. 440b5e8899SSean Farley */ 450b5e8899SSean Farley int 460b5e8899SSean Farley gr_equal(const struct group *gr1, const struct group *gr2) 470b5e8899SSean Farley { 480b5e8899SSean Farley int gr1Ndx; 490b5e8899SSean Farley int gr2Ndx; 50a0671723SSean Farley bool equal; 51a0671723SSean Farley bool found; 520b5e8899SSean Farley 530b5e8899SSean Farley /* Check that the non-member information is the same. */ 540b5e8899SSean Farley equal = strcmp(gr1->gr_name, gr2->gr_name) == 0 && 550b5e8899SSean Farley strcmp(gr1->gr_passwd, gr2->gr_passwd) == 0 && 560b5e8899SSean Farley gr1->gr_gid == gr2->gr_gid; 570b5e8899SSean Farley 580b5e8899SSean Farley /* Check all members in both groups. */ 590b5e8899SSean Farley if (equal) { 600b5e8899SSean Farley for (found = false, gr1Ndx = 0; gr1->gr_mem[gr1Ndx] != NULL; 610b5e8899SSean Farley gr1Ndx++) { 620b5e8899SSean Farley for (gr2Ndx = 0; gr2->gr_mem[gr2Ndx] != NULL; gr2Ndx++) 630b5e8899SSean Farley if (strcmp(gr1->gr_mem[gr1Ndx], 640b5e8899SSean Farley gr2->gr_mem[gr2Ndx]) == 0) { 650b5e8899SSean Farley found = true; 660b5e8899SSean Farley break; 670b5e8899SSean Farley } 680b5e8899SSean Farley if (! found) { 690b5e8899SSean Farley equal = false; 700b5e8899SSean Farley break; 710b5e8899SSean Farley } 720b5e8899SSean Farley } 730b5e8899SSean Farley 740b5e8899SSean Farley /* Check that group2 does not have more members than group1. */ 750b5e8899SSean Farley if (gr2->gr_mem[gr1Ndx] != NULL) 760b5e8899SSean Farley equal = false; 770b5e8899SSean Farley } 780b5e8899SSean Farley 790b5e8899SSean Farley return (equal); 800b5e8899SSean Farley } 810b5e8899SSean Farley 820b5e8899SSean Farley /* 830b5e8899SSean Farley * Make a group line out of a struct group. 840b5e8899SSean Farley */ 850b5e8899SSean Farley char * 860b5e8899SSean Farley gr_make(const struct group *gr) 870b5e8899SSean Farley { 880b5e8899SSean Farley char *line; 890b5e8899SSean Farley size_t lineSize; 90a0671723SSean Farley int ndx; 910b5e8899SSean Farley 920b5e8899SSean Farley /* Calculate the length of the group line. */ 930b5e8899SSean Farley lineSize = snprintf(NULL, 0, GroupLineFormat, gr->gr_name, 940b5e8899SSean Farley gr->gr_passwd, (uintmax_t)gr->gr_gid) + 1; 950b5e8899SSean Farley for (ndx = 0; gr->gr_mem[ndx] != NULL; ndx++) 960b5e8899SSean Farley lineSize += strlen(gr->gr_mem[ndx]) + 1; 970b5e8899SSean Farley if (ndx > 0) 980b5e8899SSean Farley lineSize--; 990b5e8899SSean Farley 1000b5e8899SSean Farley /* Create the group line and fill it. */ 1010b5e8899SSean Farley if ((line = malloc(lineSize)) == NULL) 1020b5e8899SSean Farley return (NULL); 1030b5e8899SSean Farley lineSize = snprintf(line, lineSize, GroupLineFormat, gr->gr_name, 1040b5e8899SSean Farley gr->gr_passwd, (uintmax_t)gr->gr_gid); 1050b5e8899SSean Farley for (ndx = 0; gr->gr_mem[ndx] != NULL; ndx++) { 1060b5e8899SSean Farley strcat(line, gr->gr_mem[ndx]); 1070b5e8899SSean Farley if (gr->gr_mem[ndx + 1] != NULL) 1080b5e8899SSean Farley strcat(line, ","); 1090b5e8899SSean Farley } 1100b5e8899SSean Farley 1110b5e8899SSean Farley return (line); 1120b5e8899SSean Farley } 1130b5e8899SSean Farley 1140b5e8899SSean Farley /* 1150b5e8899SSean Farley * Duplicate a struct group. 1160b5e8899SSean Farley */ 1170b5e8899SSean Farley struct group * 1180b5e8899SSean Farley gr_dup(const struct group *gr) 1190b5e8899SSean Farley { 1200b5e8899SSean Farley size_t len; 1210b5e8899SSean Farley struct group *ngr; 122a0671723SSean Farley int ndx; 123a0671723SSean Farley int numMem; 1240b5e8899SSean Farley 1250b5e8899SSean Farley /* Calculate size of group. */ 1260b5e8899SSean Farley len = sizeof(*gr) + 1270b5e8899SSean Farley (gr->gr_name != NULL ? strlen(gr->gr_name) + 1 : 0) + 1280b5e8899SSean Farley (gr->gr_passwd != NULL ? strlen(gr->gr_passwd) + 1 : 0); 1290b5e8899SSean Farley numMem = 0; 1300b5e8899SSean Farley if (gr->gr_mem != NULL) { 1310b5e8899SSean Farley for (; gr->gr_mem[numMem] != NULL; numMem++) 1320b5e8899SSean Farley len += strlen(gr->gr_mem[numMem]) + 1; 133a0671723SSean Farley len += (numMem + 1) * sizeof(*gr->gr_mem); 1340b5e8899SSean Farley } 1350b5e8899SSean Farley 1360b5e8899SSean Farley /* Create new group and copy old group into it. */ 1370b5e8899SSean Farley if ((ngr = calloc(1, len)) == NULL) 1380b5e8899SSean Farley return (NULL); 1390b5e8899SSean Farley len = sizeof(*ngr); 1400b5e8899SSean Farley ngr->gr_gid = gr->gr_gid; 1410b5e8899SSean Farley if (gr->gr_name != NULL) { 1420b5e8899SSean Farley ngr->gr_name = (char *)ngr + len; 1430b5e8899SSean Farley len += sprintf(ngr->gr_name, "%s", gr->gr_name) + 1; 1440b5e8899SSean Farley } 1450b5e8899SSean Farley if (gr->gr_passwd != NULL) { 1460b5e8899SSean Farley ngr->gr_passwd = (char *)ngr + len; 1470b5e8899SSean Farley len += sprintf(ngr->gr_passwd, "%s", gr->gr_passwd) + 1; 1480b5e8899SSean Farley } 1490b5e8899SSean Farley if (gr->gr_mem != NULL) { 1500b5e8899SSean Farley ngr->gr_mem = (char **)((char *)ngr + len); 151a0671723SSean Farley len += (numMem + 1) * sizeof(*ngr->gr_mem); 1520b5e8899SSean Farley for (ndx = 0; gr->gr_mem[ndx] != NULL; ndx++) { 1530b5e8899SSean Farley ngr->gr_mem[ndx] = (char *)ngr + len; 1540b5e8899SSean Farley len += sprintf(ngr->gr_mem[ndx], "%s", 1550b5e8899SSean Farley gr->gr_mem[ndx]) + 1; 1560b5e8899SSean Farley } 1570b5e8899SSean Farley ngr->gr_mem[ndx] = NULL; 1580b5e8899SSean Farley } 1590b5e8899SSean Farley 1600b5e8899SSean Farley return (ngr); 1610b5e8899SSean Farley } 1620b5e8899SSean Farley 1630b5e8899SSean Farley /* 1640b5e8899SSean Farley * Scan a line and place it into a group structure. 1650b5e8899SSean Farley */ 1660b5e8899SSean Farley static bool 1670b5e8899SSean Farley __gr_scan(char *line, struct group *gr) 1680b5e8899SSean Farley { 1690b5e8899SSean Farley char *loc; 1700b5e8899SSean Farley int ndx; 1710b5e8899SSean Farley 1720b5e8899SSean Farley /* Assign non-member information to structure. */ 1730b5e8899SSean Farley gr->gr_name = line; 1740b5e8899SSean Farley if ((loc = strchr(line, ':')) == NULL) 1750b5e8899SSean Farley return (false); 1760b5e8899SSean Farley *loc = '\0'; 1770b5e8899SSean Farley gr->gr_passwd = loc + 1; 178a0671723SSean Farley if (*gr->gr_passwd == ':') 179a0671723SSean Farley *gr->gr_passwd = '\0'; 1800b5e8899SSean Farley else { 1810b5e8899SSean Farley if ((loc = strchr(loc + 1, ':')) == NULL) 1820b5e8899SSean Farley return (false); 1830b5e8899SSean Farley *loc = '\0'; 1840b5e8899SSean Farley } 185a0671723SSean Farley if (sscanf(loc + 1, "%u", &gr->gr_gid) != 1) 1860b5e8899SSean Farley return (false); 1870b5e8899SSean Farley 1880b5e8899SSean Farley /* Assign member information to structure. */ 1890b5e8899SSean Farley if ((loc = strchr(loc + 1, ':')) == NULL) 1900b5e8899SSean Farley return (false); 1910b5e8899SSean Farley line = loc + 1; 1920b5e8899SSean Farley gr->gr_mem = NULL; 1930b5e8899SSean Farley if (*line != '\0') { 1940b5e8899SSean Farley ndx = 0; 1950b5e8899SSean Farley do { 1960b5e8899SSean Farley if ((gr->gr_mem = reallocf(gr->gr_mem, 197a0671723SSean Farley sizeof(*gr->gr_mem) * (ndx + 1))) == NULL) 1980b5e8899SSean Farley return (false); 1990b5e8899SSean Farley gr->gr_mem[ndx] = strsep(&line, ","); 2000b5e8899SSean Farley } while (gr->gr_mem[ndx++] != NULL); 2010b5e8899SSean Farley } 2020b5e8899SSean Farley 2030b5e8899SSean Farley return (true); 2040b5e8899SSean Farley } 2050b5e8899SSean Farley 2060b5e8899SSean Farley /* 2070b5e8899SSean Farley * Create a struct group from a line. 2080b5e8899SSean Farley */ 2090b5e8899SSean Farley struct group * 2100b5e8899SSean Farley gr_scan(const char *line) 2110b5e8899SSean Farley { 212a0671723SSean Farley struct group gr; 2130b5e8899SSean Farley char *lineCopy; 2140b5e8899SSean Farley struct group *newGr; 2150b5e8899SSean Farley 2160b5e8899SSean Farley if ((lineCopy = strdup(line)) == NULL) 2170b5e8899SSean Farley return (NULL); 2180b5e8899SSean Farley if (!__gr_scan(lineCopy, &gr)) { 2190b5e8899SSean Farley free(lineCopy); 2200b5e8899SSean Farley return (NULL); 2210b5e8899SSean Farley } 2220b5e8899SSean Farley newGr = gr_dup(&gr); 2230b5e8899SSean Farley free(lineCopy); 2240b5e8899SSean Farley if (gr.gr_mem != NULL) 2250b5e8899SSean Farley free(gr.gr_mem); 2260b5e8899SSean Farley 2270b5e8899SSean Farley return (newGr); 2280b5e8899SSean Farley } 229