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/getpwnam.c -- "files" backend for nsswitch "passwd" database 26 */ 27 28 #include <pwd.h> 29 #include <shadow.h> 30 #include <unistd.h> /* for PF_PATH */ 31 #include "files_common.h" 32 #include <strings.h> 33 #include <stdlib.h> 34 35 static uint_t 36 hash_pwname(nss_XbyY_args_t *argp, int keyhash, const char *line, 37 int linelen) 38 { 39 const char *name; 40 int namelen, i; 41 uint_t hash = 0; 42 43 if (keyhash) { 44 name = argp->key.name; 45 namelen = strlen(name); 46 } else { 47 name = line; 48 namelen = 0; 49 while (linelen-- && *line++ != ':') 50 namelen++; 51 } 52 53 for (i = 0; i < namelen; i++) 54 hash = hash * 15 + name[i]; 55 return (hash); 56 } 57 58 static uint_t 59 hash_pwuid(nss_XbyY_args_t *argp, int keyhash, const char *line, 60 int linelen) 61 { 62 uint_t id; 63 const char *linep, *limit, *end; 64 65 linep = line; 66 limit = line + linelen; 67 68 if (keyhash) 69 return ((uint_t)argp->key.uid); 70 71 while (linep < limit && *linep++ != ':') /* skip username */ 72 continue; 73 while (linep < limit && *linep++ != ':') /* skip password */ 74 continue; 75 if (linep == limit) 76 return (UID_NOBODY); 77 78 /* uid */ 79 end = linep; 80 id = (uint_t)strtoul(linep, (char **)&end, 10); 81 82 /* empty uid */ 83 if (linep == end) 84 return (UID_NOBODY); 85 86 return (id); 87 } 88 89 static files_hash_func hash_pw[2] = { hash_pwname, hash_pwuid }; 90 91 static files_hash_t hashinfo = { 92 DEFAULTMUTEX, 93 sizeof (struct passwd), 94 NSS_BUFLEN_PASSWD, 95 2, 96 hash_pw 97 }; 98 99 static int 100 check_pwname(nss_XbyY_args_t *argp, const char *line, int linelen) 101 { 102 const char *linep, *limit; 103 const char *keyp = argp->key.name; 104 105 linep = line; 106 limit = line + linelen; 107 108 /* +/- entries valid for compat source only */ 109 if (linelen == 0 || *line == '+' || *line == '-') 110 return (0); 111 while (*keyp && linep < limit && *keyp == *linep) { 112 keyp++; 113 linep++; 114 } 115 return (linep < limit && *keyp == '\0' && *linep == ':'); 116 } 117 118 static nss_status_t 119 getbyname(be, a) 120 files_backend_ptr_t be; 121 void *a; 122 { 123 return (_nss_files_XY_hash(be, a, 0, &hashinfo, 0, check_pwname)); 124 } 125 126 static int 127 check_pwuid(nss_XbyY_args_t *argp, const char *line, int linelen) 128 { 129 const char *linep, *limit, *end; 130 ulong_t pw_uid; 131 132 linep = line; 133 limit = line + linelen; 134 135 /* +/- entries valid for compat source only */ 136 if (linelen == 0 || *line == '+' || *line == '-') 137 return (0); 138 139 while (linep < limit && *linep++ != ':') /* skip username */ 140 continue; 141 while (linep < limit && *linep++ != ':') /* skip password */ 142 continue; 143 if (linep == limit) 144 return (0); 145 146 /* uid */ 147 end = linep; 148 pw_uid = strtoul(linep, (char **)&end, 10); 149 150 /* check if the uid is empty or overflows */ 151 if (linep == end || pw_uid > UINT32_MAX) 152 return (0); 153 154 return ((uid_t)pw_uid == argp->key.uid); 155 } 156 157 static nss_status_t 158 getbyuid(be, a) 159 files_backend_ptr_t be; 160 void *a; 161 { 162 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 163 164 if (argp->key.uid > MAXUID) 165 return (NSS_NOTFOUND); 166 return (_nss_files_XY_hash(be, argp, 0, &hashinfo, 1, check_pwuid)); 167 } 168 169 /* 170 * Validates passwd entry replacing uid/gid > MAXUID by ID_NOBODY. 171 */ 172 int 173 validate_passwd_ids(char *line, int *linelenp, int buflen, int extra_chars) 174 { 175 char *linep, *limit, *uidp, *gidp; 176 uid_t uid; 177 gid_t gid; 178 ulong_t uidl, gidl; 179 int olduidlen, oldgidlen, idlen; 180 int linelen = *linelenp, newlinelen; 181 182 /* 183 * +name entries in passwd(4) do not override uid and gid 184 * values. Therefore no need to validate the ids in these 185 * entries. 186 */ 187 if (linelen == 0 || *line == '+' || *line == '-') 188 return (NSS_STR_PARSE_SUCCESS); 189 190 linep = line; 191 limit = line + linelen; 192 193 while (linep < limit && *linep++ != ':') /* skip username */ 194 continue; 195 while (linep < limit && *linep++ != ':') /* skip password */ 196 continue; 197 if (linep == limit) 198 return (NSS_STR_PARSE_PARSE); 199 200 uidp = linep; 201 uidl = strtoul(uidp, (char **)&linep, 10); /* grab uid */ 202 olduidlen = linep - uidp; 203 if (++linep >= limit || olduidlen == 0) 204 return (NSS_STR_PARSE_PARSE); 205 206 gidp = linep; 207 gidl = strtoul(gidp, (char **)&linep, 10); /* grab gid */ 208 oldgidlen = linep - gidp; 209 if (linep >= limit || oldgidlen == 0) 210 return (NSS_STR_PARSE_PARSE); 211 212 if (uidl <= MAXUID && gidl <= MAXUID) 213 return (NSS_STR_PARSE_SUCCESS); 214 uid = (uidl > MAXUID) ? UID_NOBODY : (uid_t)uidl; 215 gid = (gidl > MAXUID) ? GID_NOBODY : (gid_t)gidl; 216 217 /* Check if we have enough space in the buffer */ 218 idlen = snprintf(NULL, 0, "%u:%u", uid, gid); 219 newlinelen = linelen + idlen - olduidlen - oldgidlen - 1; 220 if (newlinelen + extra_chars > buflen) 221 return (NSS_STR_PARSE_ERANGE); 222 223 /* Replace ephemeral ids by ID_NOBODY */ 224 (void) bcopy(linep, uidp + idlen, limit - linep + extra_chars); 225 (void) snprintf(uidp, idlen + 1, "%u:%u", uid, gid); 226 *(uidp + idlen) = ':'; /* restore : that was overwritten by snprintf */ 227 *linelenp = newlinelen; 228 return (NSS_STR_PARSE_SUCCESS); 229 } 230 231 static files_backend_op_t passwd_ops[] = { 232 _nss_files_destr, 233 _nss_files_endent, 234 _nss_files_setent, 235 _nss_files_getent_rigid, 236 getbyname, 237 getbyuid 238 }; 239 240 /*ARGSUSED*/ 241 nss_backend_t * 242 _nss_files_passwd_constr(dummy1, dummy2, dummy3) 243 const char *dummy1, *dummy2, *dummy3; 244 { 245 return (_nss_files_constr(passwd_ops, 246 sizeof (passwd_ops) / sizeof (passwd_ops[0]), 247 PF_PATH, 248 NSS_LINELEN_PASSWD, 249 &hashinfo)); 250 } 251