1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * files/getgrent.c -- "files" backend for nsswitch "group" database 26 */ 27 28 #include <grp.h> 29 #include <unistd.h> /* for GF_PATH */ 30 #include <stdlib.h> /* for GF_PATH */ 31 #include "files_common.h" 32 #include <strings.h> 33 34 static uint_t 35 hash_grname(nss_XbyY_args_t *argp, int keyhash, const char *line, 36 int linelen) 37 { 38 const char *name; 39 int namelen, i; 40 uint_t hash = 0; 41 42 if (keyhash) { 43 name = argp->key.name; 44 namelen = strlen(name); 45 } else { 46 name = line; 47 namelen = 0; 48 while (linelen-- && *line++ != ':') 49 namelen++; 50 } 51 52 for (i = 0; i < namelen; i++) 53 hash = hash * 15 + name[i]; 54 return (hash); 55 } 56 57 static uint_t 58 hash_grgid(nss_XbyY_args_t *argp, int keyhash, const char *line, 59 int linelen) 60 { 61 uint_t id; 62 const char *linep, *limit, *end; 63 64 linep = line; 65 limit = line + linelen; 66 67 if (keyhash) 68 return ((uint_t)argp->key.gid); 69 70 while (linep < limit && *linep++ != ':') /* skip groupname */ 71 continue; 72 while (linep < limit && *linep++ != ':') /* skip password */ 73 continue; 74 if (linep == limit) 75 return (GID_NOBODY); 76 77 /* gid */ 78 end = linep; 79 id = (uint_t)strtoul(linep, (char **)&end, 10); 80 /* empty gid */ 81 if (linep == end) 82 return (GID_NOBODY); 83 84 return (id); 85 } 86 87 static files_hash_func hash_gr[2] = { hash_grname, hash_grgid }; 88 89 static files_hash_t hashinfo = { 90 DEFAULTMUTEX, 91 sizeof (struct group), 92 NSS_BUFLEN_GROUP, 93 2, 94 hash_gr 95 }; 96 97 static int 98 check_grname(nss_XbyY_args_t *argp, const char *line, int linelen) 99 { 100 const char *linep, *limit; 101 const char *keyp = argp->key.name; 102 103 linep = line; 104 limit = line + linelen; 105 106 /* +/- entries valid for compat source only */ 107 if (linelen == 0 || *line == '+' || *line == '-') 108 return (0); 109 while (*keyp && linep < limit && *keyp == *linep) { 110 keyp++; 111 linep++; 112 } 113 return (linep < limit && *keyp == '\0' && *linep == ':'); 114 } 115 116 static nss_status_t 117 getbyname(be, a) 118 files_backend_ptr_t be; 119 void *a; 120 { 121 return (_nss_files_XY_hash(be, a, 0, &hashinfo, 0, check_grname)); 122 } 123 124 static int 125 check_grgid(nss_XbyY_args_t *argp, const char *line, int linelen) 126 { 127 const char *linep, *limit, *end; 128 ulong_t gr_gid; 129 130 linep = line; 131 limit = line + linelen; 132 133 /* +/- entries valid for compat source only */ 134 if (linelen == 0 || *line == '+' || *line == '-') 135 return (0); 136 137 while (linep < limit && *linep++ != ':') /* skip groupname */ 138 continue; 139 while (linep < limit && *linep++ != ':') /* skip password */ 140 continue; 141 if (linep == limit) 142 return (0); 143 144 /* gid */ 145 end = linep; 146 gr_gid = strtoul(linep, (char **)&end, 10); 147 148 /* check if gid is empty or overflows */ 149 if (linep == end || gr_gid > UINT32_MAX) 150 return (0); 151 152 return ((gid_t)gr_gid == argp->key.gid); 153 } 154 155 static nss_status_t 156 getbygid(be, a) 157 files_backend_ptr_t be; 158 void *a; 159 { 160 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 161 162 if (argp->key.gid > MAXUID) 163 return (NSS_NOTFOUND); 164 return (_nss_files_XY_hash(be, argp, 0, &hashinfo, 1, check_grgid)); 165 } 166 167 /* 168 * Validates group entry replacing gid > MAXUID by GID_NOBODY. 169 */ 170 int 171 validate_group_ids(char *line, int *linelenp, int buflen, int extra_chars, 172 files_XY_check_func check) 173 { 174 char *linep, *limit, *gidp; 175 ulong_t gid; 176 int oldgidlen, idlen; 177 int linelen = *linelenp, newlinelen; 178 179 /* 180 * getbygid() rejects searching by ephemeral gid therefore 181 * no need to validate because the matched entry won't have 182 * an ephemeral gid. 183 */ 184 if (check != NULL && check == check_grgid) 185 return (NSS_STR_PARSE_SUCCESS); 186 187 /* +/- entries valid for compat source only */ 188 if (linelen == 0 || *line == '+' || *line == '-') 189 return (NSS_STR_PARSE_SUCCESS); 190 191 linep = line; 192 limit = line + linelen; 193 194 while (linep < limit && *linep++ != ':') /* skip groupname */ 195 continue; 196 while (linep < limit && *linep++ != ':') /* skip password */ 197 continue; 198 if (linep == limit) 199 return (NSS_STR_PARSE_PARSE); 200 201 gidp = linep; 202 gid = strtoul(gidp, (char **)&linep, 10); /* grab gid */ 203 oldgidlen = linep - gidp; 204 if (linep >= limit || oldgidlen == 0) 205 return (NSS_STR_PARSE_PARSE); 206 207 if (gid <= MAXUID) 208 return (NSS_STR_PARSE_SUCCESS); 209 210 idlen = snprintf(NULL, 0, "%u", GID_NOBODY); 211 newlinelen = linelen + idlen - oldgidlen; 212 if (newlinelen + extra_chars > buflen) 213 return (NSS_STR_PARSE_ERANGE); 214 215 (void) bcopy(linep, gidp + idlen, limit - linep + extra_chars); 216 (void) snprintf(gidp, idlen + 1, "%u", GID_NOBODY); 217 *(gidp + idlen) = ':'; 218 *linelenp = newlinelen; 219 return (NSS_STR_PARSE_SUCCESS); 220 } 221 222 static nss_status_t 223 getbymember(be, a) 224 files_backend_ptr_t be; 225 void *a; 226 { 227 struct nss_groupsbymem *argp = (struct nss_groupsbymem *)a; 228 229 return (_nss_files_do_all(be, argp, argp->username, 230 (files_do_all_func_t)argp->process_cstr)); 231 } 232 233 static files_backend_op_t group_ops[] = { 234 _nss_files_destr, 235 _nss_files_endent, 236 _nss_files_setent, 237 _nss_files_getent_rigid, 238 getbyname, 239 getbygid, 240 getbymember 241 }; 242 243 /*ARGSUSED*/ 244 nss_backend_t * 245 _nss_files_group_constr(dummy1, dummy2, dummy3) 246 const char *dummy1, *dummy2, *dummy3; 247 { 248 return (_nss_files_constr(group_ops, 249 sizeof (group_ops) / sizeof (group_ops[0]), 250 GF_PATH, 251 NSS_LINELEN_GROUP, 252 &hashinfo)); 253 } 254