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 #include <grp.h> 32 #include <inttypes.h> 33 #include <stdbool.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 38 #include <libutil.h> 39 40 41 static const char GroupLineFormat[] = "%s:%s:%ju:"; 42 43 44 /* 45 * Compares two struct group's. 46 */ 47 int 48 gr_equal(const struct group *gr1, const struct group *gr2) 49 { 50 bool found; 51 bool equal; 52 int gr1Ndx; 53 int gr2Ndx; 54 55 /* Check that the non-member information is the same. */ 56 equal = strcmp(gr1->gr_name, gr2->gr_name) == 0 && 57 strcmp(gr1->gr_passwd, gr2->gr_passwd) == 0 && 58 gr1->gr_gid == gr2->gr_gid; 59 60 /* Check all members in both groups. */ 61 if (equal) { 62 for (found = false, gr1Ndx = 0; gr1->gr_mem[gr1Ndx] != NULL; 63 gr1Ndx++) { 64 for (gr2Ndx = 0; gr2->gr_mem[gr2Ndx] != NULL; gr2Ndx++) 65 if (strcmp(gr1->gr_mem[gr1Ndx], 66 gr2->gr_mem[gr2Ndx]) == 0) { 67 found = true; 68 break; 69 } 70 if (! found) { 71 equal = false; 72 break; 73 } 74 } 75 76 /* Check that group2 does not have more members than group1. */ 77 if (gr2->gr_mem[gr1Ndx] != NULL) 78 equal = false; 79 } 80 81 return (equal); 82 } 83 84 85 /* 86 * Make a group line out of a struct group. 87 */ 88 char * 89 gr_make(const struct group *gr) 90 { 91 char *line; 92 int ndx; 93 size_t lineSize; 94 95 /* Calculate the length of the group line. */ 96 lineSize = snprintf(NULL, 0, GroupLineFormat, gr->gr_name, 97 gr->gr_passwd, (uintmax_t)gr->gr_gid) + 1; 98 for (ndx = 0; gr->gr_mem[ndx] != NULL; ndx++) 99 lineSize += strlen(gr->gr_mem[ndx]) + 1; 100 if (ndx > 0) 101 lineSize--; 102 103 /* Create the group line and fill it. */ 104 if ((line = malloc(lineSize)) == NULL) 105 return (NULL); 106 lineSize = snprintf(line, lineSize, GroupLineFormat, gr->gr_name, 107 gr->gr_passwd, (uintmax_t)gr->gr_gid); 108 for (ndx = 0; gr->gr_mem[ndx] != NULL; ndx++) { 109 strcat(line, gr->gr_mem[ndx]); 110 if (gr->gr_mem[ndx + 1] != NULL) 111 strcat(line, ","); 112 } 113 114 return (line); 115 } 116 117 118 /* 119 * Duplicate a struct group. 120 */ 121 struct group * 122 gr_dup(const struct group *gr) 123 { 124 int ndx; 125 int numMem; 126 size_t len; 127 struct group *ngr; 128 129 /* Calculate size of group. */ 130 len = sizeof(*gr) + 131 (gr->gr_name != NULL ? strlen(gr->gr_name) + 1 : 0) + 132 (gr->gr_passwd != NULL ? strlen(gr->gr_passwd) + 1 : 0); 133 numMem = 0; 134 if (gr->gr_mem != NULL) { 135 for (; gr->gr_mem[numMem] != NULL; numMem++) 136 len += strlen(gr->gr_mem[numMem]) + 1; 137 len += (numMem + 1) * sizeof(*(gr->gr_mem)); 138 } 139 140 /* Create new group and copy old group into it. */ 141 if ((ngr = calloc(1, len)) == NULL) 142 return (NULL); 143 len = sizeof(*ngr); 144 ngr->gr_gid = gr->gr_gid; 145 if (gr->gr_name != NULL) { 146 ngr->gr_name = (char *)ngr + len; 147 len += sprintf(ngr->gr_name, "%s", gr->gr_name) + 1; 148 } 149 if (gr->gr_passwd != NULL) { 150 ngr->gr_passwd = (char *)ngr + len; 151 len += sprintf(ngr->gr_passwd, "%s", gr->gr_passwd) + 1; 152 } 153 if (gr->gr_mem != NULL) { 154 ngr->gr_mem = (char **)((char *)ngr + len); 155 len += (numMem + 1) * sizeof(*(ngr->gr_mem)); 156 for (ndx = 0; gr->gr_mem[ndx] != NULL; ndx++) { 157 ngr->gr_mem[ndx] = (char *)ngr + len; 158 len += sprintf(ngr->gr_mem[ndx], "%s", 159 gr->gr_mem[ndx]) + 1; 160 } 161 ngr->gr_mem[ndx] = NULL; 162 } 163 164 return (ngr); 165 } 166 167 168 /* 169 * Scan a line and place it into a group structure. 170 */ 171 static bool 172 __gr_scan(char *line, struct group *gr) 173 { 174 char *loc; 175 int ndx; 176 177 /* Assign non-member information to structure. */ 178 gr->gr_name = line; 179 if ((loc = strchr(line, ':')) == NULL) 180 return (false); 181 *loc = '\0'; 182 gr->gr_passwd = loc + 1; 183 if (*(gr->gr_passwd) == ':') 184 *(gr->gr_passwd) = '\0'; 185 else { 186 if ((loc = strchr(loc + 1, ':')) == NULL) 187 return (false); 188 *loc = '\0'; 189 } 190 if (sscanf(loc + 1, "%u", &(gr->gr_gid)) != 1) 191 return (false); 192 193 /* Assign member information to structure. */ 194 if ((loc = strchr(loc + 1, ':')) == NULL) 195 return (false); 196 line = loc + 1; 197 gr->gr_mem = NULL; 198 if (*line != '\0') { 199 ndx = 0; 200 do { 201 if ((gr->gr_mem = reallocf(gr->gr_mem, 202 sizeof(*(gr->gr_mem)) * (ndx + 1))) == NULL) 203 return (false); 204 gr->gr_mem[ndx] = strsep(&line, ","); 205 } while (gr->gr_mem[ndx++] != NULL); 206 } 207 208 return (true); 209 } 210 211 212 /* 213 * Create a struct group from a line. 214 */ 215 struct group * 216 gr_scan(const char *line) 217 { 218 char *lineCopy; 219 struct group *newGr; 220 struct group gr; 221 222 if ((lineCopy = strdup(line)) == NULL) 223 return (NULL); 224 if (!__gr_scan(lineCopy, &gr)) { 225 free(lineCopy); 226 return (NULL); 227 } 228 newGr = gr_dup(&gr); 229 free(lineCopy); 230 if (gr.gr_mem != NULL) 231 free(gr.gr_mem); 232 233 return (newGr); 234 } 235