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