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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include "lint.h" 28 #include <sys/types.h> 29 #include <pwd.h> 30 #include <nss_dbdefs.h> 31 #include <stdio.h> 32 #include <synch.h> 33 #include <sys/param.h> 34 #include <string.h> 35 #include <stdlib.h> 36 #include <sys/mman.h> 37 38 int str2passwd(const char *, int, void *, 39 char *, int); 40 41 static DEFINE_NSS_DB_ROOT(db_root); 42 static DEFINE_NSS_GETENT(context); 43 44 void 45 _nss_initf_passwd(nss_db_params_t *p) 46 { 47 p->name = NSS_DBNAM_PASSWD; 48 p->default_config = NSS_DEFCONF_PASSWD; 49 } 50 51 #include <getxby_door.h> 52 53 struct passwd * 54 _uncached_getpwuid_r(uid_t uid, struct passwd *result, char *buffer, 55 int buflen); 56 57 struct passwd * 58 _uncached_getpwnam_r(const char *name, struct passwd *result, char *buffer, 59 int buflen); 60 61 /* 62 * POSIX.1c Draft-6 version of the function getpwnam_r. 63 * It was implemented by Solaris 2.3. 64 */ 65 struct passwd * 66 getpwnam_r(const char *name, struct passwd *result, char *buffer, int buflen) 67 { 68 nss_XbyY_args_t arg; 69 70 if (name == (const char *)NULL) { 71 errno = ERANGE; 72 return (NULL); 73 } 74 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2passwd); 75 arg.key.name = name; 76 (void) nss_search(&db_root, _nss_initf_passwd, NSS_DBOP_PASSWD_BYNAME, 77 &arg); 78 return ((struct passwd *)NSS_XbyY_FINI(&arg)); 79 } 80 81 /* 82 * POSIX.1c Draft-6 version of the function getpwuid_r. 83 * It was implemented by Solaris 2.3. 84 */ 85 struct passwd * 86 getpwuid_r(uid_t uid, struct passwd *result, char *buffer, int buflen) 87 { 88 nss_XbyY_args_t arg; 89 90 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2passwd); 91 arg.key.uid = uid; 92 (void) nss_search(&db_root, _nss_initf_passwd, NSS_DBOP_PASSWD_BYUID, 93 &arg); 94 return ((struct passwd *)NSS_XbyY_FINI(&arg)); 95 } 96 97 98 struct passwd * 99 _uncached_getpwuid_r(uid_t uid, struct passwd *result, char *buffer, 100 int buflen) 101 { 102 nss_XbyY_args_t arg; 103 104 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2passwd); 105 arg.key.uid = uid; 106 (void) nss_search(&db_root, _nss_initf_passwd, NSS_DBOP_PASSWD_BYUID, 107 &arg); 108 return ((struct passwd *)NSS_XbyY_FINI(&arg)); 109 } 110 111 112 /* 113 * POSIX.1c standard version of the function getpwuid_r. 114 * User gets it via static getpwuid_r from the header file. 115 */ 116 int 117 __posix_getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, 118 size_t bufsize, struct passwd **result) 119 { 120 int nerrno = 0; 121 int oerrno = errno; 122 123 errno = 0; 124 if ((*result = getpwuid_r(uid, pwd, buffer, (uintptr_t)bufsize)) 125 == NULL) { 126 nerrno = errno; 127 } 128 errno = oerrno; 129 return (nerrno); 130 } 131 132 struct passwd * 133 _uncached_getpwnam_r(const char *name, struct passwd *result, char *buffer, 134 int buflen) 135 { 136 nss_XbyY_args_t arg; 137 138 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2passwd); 139 arg.key.name = name; 140 (void) nss_search(&db_root, _nss_initf_passwd, NSS_DBOP_PASSWD_BYNAME, 141 &arg); 142 return ((struct passwd *)NSS_XbyY_FINI(&arg)); 143 } 144 145 /* 146 * POSIX.1c standard version of the function getpwnam_r. 147 * User gets it via static getpwnam_r from the header file. 148 */ 149 int 150 __posix_getpwnam_r(const char *name, struct passwd *pwd, char *buffer, 151 size_t bufsize, struct passwd **result) 152 { 153 int nerrno = 0; 154 int oerrno = errno; 155 156 errno = 0; 157 if ((*result = getpwnam_r(name, pwd, buffer, (uintptr_t)bufsize)) 158 == NULL) { 159 nerrno = errno; 160 } 161 errno = oerrno; 162 return (nerrno); 163 } 164 165 void 166 setpwent(void) 167 { 168 nss_setent(&db_root, _nss_initf_passwd, &context); 169 } 170 171 void 172 endpwent(void) 173 { 174 nss_endent(&db_root, _nss_initf_passwd, &context); 175 nss_delete(&db_root); 176 } 177 178 struct passwd * 179 getpwent_r(struct passwd *result, char *buffer, int buflen) 180 { 181 nss_XbyY_args_t arg; 182 char *nam; 183 184 /* In getXXent_r(), protect the unsuspecting caller from +/- entries */ 185 186 do { 187 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2passwd); 188 /* No key to fill in */ 189 (void) nss_getent(&db_root, _nss_initf_passwd, &context, &arg); 190 } while (arg.returnval != 0 && 191 (nam = ((struct passwd *)arg.returnval)->pw_name) != 0 && 192 (*nam == '+' || *nam == '-')); 193 194 return ((struct passwd *)NSS_XbyY_FINI(&arg)); 195 } 196 197 struct passwd * 198 fgetpwent_r(FILE *f, struct passwd *result, char *buffer, int buflen) 199 { 200 extern void _nss_XbyY_fgets(FILE *, nss_XbyY_args_t *); 201 nss_XbyY_args_t arg; 202 203 /* ... but in fgetXXent_r, the caller deserves any +/- entry he gets */ 204 205 /* No key to fill in */ 206 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2passwd); 207 _nss_XbyY_fgets(f, &arg); 208 return ((struct passwd *)NSS_XbyY_FINI(&arg)); 209 } 210 211 static char * 212 gettok(char **nextpp) 213 { 214 char *p = *nextpp; 215 char *q = p; 216 char c; 217 218 if (p == 0) 219 return (0); 220 221 while ((c = *q) != '\0' && c != ':') 222 q++; 223 224 if (c == '\0') 225 *nextpp = 0; 226 else { 227 *q++ = '\0'; 228 *nextpp = q; 229 } 230 return (p); 231 } 232 233 /* 234 * Return values: 0 = success, 1 = parse error, 2 = erange ... 235 * The structure pointer passed in is a structure in the caller's space 236 * wherein the field pointers would be set to areas in the buffer if 237 * need be. instring and buffer should be separate areas. 238 */ 239 int 240 str2passwd(const char *instr, int lenstr, void *ent, char *buffer, int buflen) 241 { 242 struct passwd *passwd = (struct passwd *)ent; 243 char *p, *next; 244 int black_magic; /* "+" or "-" entry */ 245 ulong_t tmp; 246 247 if (lenstr + 1 > buflen) 248 return (NSS_STR_PARSE_ERANGE); 249 250 /* 251 * We copy the input string into the output buffer and 252 * operate on it in place. 253 */ 254 if (instr != buffer) { 255 /* Overlapping buffer copies are OK */ 256 (void) memmove(buffer, instr, lenstr); 257 buffer[lenstr] = '\0'; 258 } 259 260 /* quick exit do not entry fill if not needed */ 261 if (ent == (void *)NULL) 262 return (NSS_STR_PARSE_SUCCESS); 263 264 next = buffer; 265 266 passwd->pw_name = p = gettok(&next); /* username */ 267 if (*p == '\0') { 268 /* Empty username; not allowed */ 269 return (NSS_STR_PARSE_PARSE); 270 } 271 black_magic = (*p == '+' || *p == '-'); 272 if (black_magic) { 273 passwd->pw_uid = UID_NOBODY; 274 passwd->pw_gid = GID_NOBODY; 275 /* 276 * pwconv tests pw_passwd and pw_age == NULL 277 */ 278 passwd->pw_passwd = ""; 279 passwd->pw_age = ""; 280 /* 281 * the rest of the passwd entry is "optional" 282 */ 283 passwd->pw_comment = ""; 284 passwd->pw_gecos = ""; 285 passwd->pw_dir = ""; 286 passwd->pw_shell = ""; 287 } 288 289 passwd->pw_passwd = p = gettok(&next); /* password */ 290 if (p == 0) { 291 if (black_magic) 292 return (NSS_STR_PARSE_SUCCESS); 293 else 294 return (NSS_STR_PARSE_PARSE); 295 } 296 for (; *p != '\0'; p++) { /* age */ 297 if (*p == ',') { 298 *p++ = '\0'; 299 break; 300 } 301 } 302 passwd->pw_age = p; 303 304 p = next; /* uid */ 305 if (p == 0 || *p == '\0') { 306 if (black_magic) 307 return (NSS_STR_PARSE_SUCCESS); 308 else 309 return (NSS_STR_PARSE_PARSE); 310 } 311 if (!black_magic) { 312 /* 313 * strtoul returns unsigned long which is 314 * 8 bytes on a 64-bit system. We don't want 315 * to assign it directly to passwd->pw_uid 316 * which is 4 bytes or else we will end up 317 * truncating the value. 318 */ 319 tmp = strtoul(p, &next, 10); 320 if (next == p) { 321 /* uid field should be nonempty */ 322 return (NSS_STR_PARSE_PARSE); 323 } 324 /* 325 * The old code (in 2.0 through 2.5) would check 326 * for the uid being negative, or being greater 327 * than 60001 (the rfs limit). If it met either of 328 * these conditions, the uid was translated to 60001. 329 * 330 * Now we just check for -1 (UINT32_MAX); anything else 331 * is administrative policy 332 */ 333 if (tmp >= UINT32_MAX) 334 passwd->pw_uid = UID_NOBODY; 335 else 336 passwd->pw_uid = (uid_t)tmp; 337 } 338 if (*next++ != ':') { 339 if (black_magic) 340 (void) gettok(&next); 341 else 342 return (NSS_STR_PARSE_PARSE); 343 } 344 p = next; /* gid */ 345 if (p == 0 || *p == '\0') { 346 if (black_magic) 347 return (NSS_STR_PARSE_SUCCESS); 348 else 349 return (NSS_STR_PARSE_PARSE); 350 } 351 if (!black_magic) { 352 tmp = strtoul(p, &next, 10); 353 if (next == p) { 354 /* gid field should be nonempty */ 355 return (NSS_STR_PARSE_PARSE); 356 } 357 /* 358 * gid should not be -1; anything else 359 * is administrative policy. 360 */ 361 if (passwd->pw_gid >= UINT32_MAX) 362 passwd->pw_gid = GID_NOBODY; 363 else 364 passwd->pw_gid = (gid_t)tmp; 365 } 366 if (*next++ != ':') { 367 if (black_magic) 368 (void) gettok(&next); 369 else 370 return (NSS_STR_PARSE_PARSE); 371 } 372 373 passwd->pw_gecos = passwd->pw_comment = p = gettok(&next); 374 if (p == 0) { 375 if (black_magic) 376 return (NSS_STR_PARSE_SUCCESS); 377 else 378 return (NSS_STR_PARSE_PARSE); 379 } 380 381 passwd->pw_dir = p = gettok(&next); 382 if (p == 0) { 383 if (black_magic) 384 return (NSS_STR_PARSE_SUCCESS); 385 else 386 return (NSS_STR_PARSE_PARSE); 387 } 388 389 passwd->pw_shell = p = gettok(&next); 390 if (p == 0) { 391 if (black_magic) 392 return (NSS_STR_PARSE_SUCCESS); 393 else 394 return (NSS_STR_PARSE_PARSE); 395 } 396 397 /* Better not be any more fields... */ 398 if (next == 0) { 399 /* Successfully parsed and stored */ 400 return (NSS_STR_PARSE_SUCCESS); 401 } 402 return (NSS_STR_PARSE_PARSE); 403 } 404