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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #pragma weak endpwent = _endpwent 30 #pragma weak setpwent = _setpwent 31 #pragma weak getpwnam_r = _getpwnam_r 32 #pragma weak getpwuid_r = _getpwuid_r 33 #pragma weak getpwent_r = _getpwent_r 34 #pragma weak fgetpwent_r = _fgetpwent_r 35 36 #include "synonyms.h" 37 #include <sys/types.h> 38 #include <pwd.h> 39 #include <nss_dbdefs.h> 40 #include <stdio.h> 41 #include <synch.h> 42 #include <sys/param.h> 43 #include <string.h> 44 #include <stdlib.h> 45 #include <sys/mman.h> 46 47 int str2passwd(const char *, int, void *, 48 char *, int); 49 50 static DEFINE_NSS_DB_ROOT(db_root); 51 static DEFINE_NSS_GETENT(context); 52 53 void 54 _nss_initf_passwd(nss_db_params_t *p) 55 { 56 p->name = NSS_DBNAM_PASSWD; 57 p->default_config = NSS_DEFCONF_PASSWD; 58 } 59 60 #include <getxby_door.h> 61 62 struct passwd * 63 _uncached_getpwuid_r(uid_t uid, struct passwd *result, char *buffer, 64 int buflen); 65 66 struct passwd * 67 _uncached_getpwnam_r(const char *name, struct passwd *result, char *buffer, 68 int buflen); 69 70 static struct passwd * 71 process_getpw(struct passwd *result, char *buffer, int buflen, 72 nsc_data_t *sptr, int ndata); 73 74 /* ARGSUSED4 */ 75 static struct passwd * 76 process_getpw(struct passwd *result, char *buffer, int buflen, 77 nsc_data_t *sptr, int ndata) 78 { 79 80 char *fixed; 81 #ifdef _LP64 82 struct passwd pass64; 83 #endif 84 85 #ifdef _LP64 86 fixed = (char *)(((uintptr_t)buffer + 7) & ~7); 87 #else 88 fixed = (char *)(((uintptr_t)buffer + 3) & ~3); 89 #endif 90 buflen -= fixed - buffer; 91 buffer = fixed; 92 93 if (sptr->nsc_ret.nsc_return_code != SUCCESS) 94 return (NULL); 95 96 #ifdef _LP64 97 if (sptr->nsc_ret.nsc_bufferbytesused - (int)sizeof (passwd32_t) 98 > buflen) { 99 #else 100 if (sptr->nsc_ret.nsc_bufferbytesused - (int)sizeof (struct passwd) 101 > buflen) { 102 #endif 103 errno = ERANGE; 104 return (NULL); 105 } 106 107 #ifdef _LP64 108 109 (void) memcpy(buffer, 110 (sptr->nsc_ret.nsc_u.buff + sizeof (passwd32_t)), 111 (sptr->nsc_ret.nsc_bufferbytesused - sizeof (passwd32_t))); 112 113 pass64.pw_name = (char *)(sptr->nsc_ret.nsc_u.pwd.pw_name + 114 (uintptr_t)buffer); 115 pass64.pw_passwd = (char *)(sptr->nsc_ret.nsc_u.pwd.pw_passwd + 116 (uintptr_t)buffer); 117 pass64.pw_uid = sptr->nsc_ret.nsc_u.pwd.pw_uid; 118 pass64.pw_gid = sptr->nsc_ret.nsc_u.pwd.pw_gid; 119 pass64.pw_age = (char *)(sptr->nsc_ret.nsc_u.pwd.pw_age + 120 (uintptr_t)buffer); 121 pass64.pw_comment = (char *)(sptr->nsc_ret.nsc_u.pwd.pw_comment + 122 (uintptr_t)buffer); 123 pass64.pw_gecos = (char *)(sptr->nsc_ret.nsc_u.pwd.pw_gecos + 124 (uintptr_t)buffer); 125 pass64.pw_dir = (char *)(sptr->nsc_ret.nsc_u.pwd.pw_dir + 126 (uintptr_t)buffer); 127 pass64.pw_shell = (char *)(sptr->nsc_ret.nsc_u.pwd.pw_shell + 128 (uintptr_t)buffer); 129 130 *result = pass64; 131 #else 132 sptr->nsc_ret.nsc_u.pwd.pw_name += (uintptr_t)buffer; 133 sptr->nsc_ret.nsc_u.pwd.pw_passwd += (uintptr_t)buffer; 134 sptr->nsc_ret.nsc_u.pwd.pw_age += (uintptr_t)buffer; 135 sptr->nsc_ret.nsc_u.pwd.pw_comment += (uintptr_t)buffer; 136 sptr->nsc_ret.nsc_u.pwd.pw_gecos += (uintptr_t)buffer; 137 sptr->nsc_ret.nsc_u.pwd.pw_dir += (uintptr_t)buffer; 138 sptr->nsc_ret.nsc_u.pwd.pw_shell += (uintptr_t)buffer; 139 140 *result = sptr->nsc_ret.nsc_u.pwd; 141 142 (void) memcpy(buffer, 143 (sptr->nsc_ret.nsc_u.buff + sizeof (struct passwd)), 144 (sptr->nsc_ret.nsc_bufferbytesused - sizeof (struct passwd))); 145 #endif 146 147 return (result); 148 } 149 150 /* 151 * POSIX.1c Draft-6 version of the function getpwnam_r. 152 * It was implemented by Solaris 2.3. 153 */ 154 struct passwd * 155 _getpwnam_r(const char *name, struct passwd *result, char *buffer, int buflen) 156 { 157 /* 158 * allocate data on the stack for passwd information 159 */ 160 union { 161 nsc_data_t s_d; 162 char s_b[1024]; 163 } space; 164 nsc_data_t *sptr; 165 int ndata; 166 int adata; 167 struct passwd *resptr = NULL; 168 169 if ((name == (const char *)NULL) || 170 (strlen(name) >= (sizeof (space) - sizeof (nsc_data_t)))) { 171 errno = ERANGE; 172 return ((struct passwd *)NULL); 173 } 174 ndata = sizeof (space); 175 adata = strlen(name) + sizeof (nsc_call_t) + 1; 176 space.s_d.nsc_call.nsc_callnumber = GETPWNAM; 177 (void) strcpy(space.s_d.nsc_call.nsc_u.name, name); 178 sptr = &space.s_d; 179 180 switch (_nsc_trydoorcall(&sptr, &ndata, &adata)) { 181 case SUCCESS: /* positive cache hit */ 182 break; 183 case NOTFOUND: /* negative cache hit */ 184 return (NULL); 185 default: 186 return ((struct passwd *)_uncached_getpwnam_r(name, result, 187 buffer, buflen)); 188 } 189 resptr = process_getpw(result, buffer, buflen, sptr, ndata); 190 191 /* 192 * check if doors reallocated the memory underneath us 193 * if they did munmap it or suffer a memory leak 194 */ 195 if (sptr != &space.s_d) 196 munmap((void *)sptr, ndata); 197 198 return (resptr); 199 } 200 201 /* 202 * POSIX.1c Draft-6 version of the function getpwuid_r. 203 * It was implemented by Solaris 2.3. 204 */ 205 struct passwd * 206 _getpwuid_r(uid_t uid, struct passwd *result, char *buffer, int buflen) 207 { 208 union { 209 nsc_data_t s_d; 210 char s_b[1024]; 211 } space; 212 nsc_data_t *sptr; 213 int ndata; 214 int adata; 215 struct passwd *resptr = NULL; 216 217 ndata = sizeof (space); 218 adata = sizeof (nsc_call_t) + 1; 219 space.s_d.nsc_call.nsc_callnumber = GETPWUID; 220 space.s_d.nsc_call.nsc_u.uid = uid; 221 sptr = &space.s_d; 222 223 switch (_nsc_trydoorcall(&sptr, &ndata, &adata)) { 224 case SUCCESS: /* positive cache hit */ 225 break; 226 case NOTFOUND: /* negative cache hit */ 227 return (NULL); 228 default: 229 return ((struct passwd *)_uncached_getpwuid_r(uid, result, 230 buffer, buflen)); 231 } 232 resptr = process_getpw(result, buffer, buflen, sptr, ndata); 233 234 /* 235 * check if doors reallocated the memory underneath us 236 * if they did munmap it or suffer a memory leak 237 */ 238 if (sptr != &space.s_d) 239 munmap((void *)sptr, ndata); 240 241 return (resptr); 242 } 243 244 245 struct passwd * 246 _uncached_getpwuid_r(uid_t uid, struct passwd *result, char *buffer, 247 int buflen) 248 { 249 nss_XbyY_args_t arg; 250 251 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2passwd); 252 arg.key.uid = uid; 253 (void) nss_search(&db_root, _nss_initf_passwd, NSS_DBOP_PASSWD_BYUID, 254 &arg); 255 return ((struct passwd *)NSS_XbyY_FINI(&arg)); 256 } 257 258 259 /* 260 * POSIX.1c standard version of the function getpwuid_r. 261 * User gets it via static getpwuid_r from the header file. 262 */ 263 int 264 __posix_getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, 265 size_t bufsize, struct passwd **result) 266 { 267 int nerrno = 0; 268 int oerrno = errno; 269 270 errno = 0; 271 if ((*result = _getpwuid_r(uid, pwd, buffer, (uintptr_t)bufsize)) 272 == NULL) { 273 nerrno = errno; 274 } 275 errno = oerrno; 276 return (nerrno); 277 } 278 279 struct passwd * 280 _uncached_getpwnam_r(const char *name, struct passwd *result, char *buffer, 281 int buflen) 282 { 283 nss_XbyY_args_t arg; 284 285 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2passwd); 286 arg.key.name = name; 287 (void) nss_search(&db_root, _nss_initf_passwd, NSS_DBOP_PASSWD_BYNAME, 288 &arg); 289 return ((struct passwd *)NSS_XbyY_FINI(&arg)); 290 } 291 292 /* 293 * POSIX.1c standard version of the function getpwnam_r. 294 * User gets it via static getpwnam_r from the header file. 295 */ 296 int 297 __posix_getpwnam_r(const char *name, struct passwd *pwd, char *buffer, 298 size_t bufsize, struct passwd **result) 299 { 300 int nerrno = 0; 301 int oerrno = errno; 302 303 errno = 0; 304 if ((*result = _getpwnam_r(name, pwd, buffer, (uintptr_t)bufsize)) 305 == NULL) { 306 nerrno = errno; 307 } 308 errno = oerrno; 309 return (nerrno); 310 } 311 312 void 313 setpwent(void) 314 { 315 nss_setent(&db_root, _nss_initf_passwd, &context); 316 } 317 318 void 319 endpwent(void) 320 { 321 nss_endent(&db_root, _nss_initf_passwd, &context); 322 nss_delete(&db_root); 323 } 324 325 struct passwd * 326 getpwent_r(struct passwd *result, char *buffer, int buflen) 327 { 328 nss_XbyY_args_t arg; 329 char *nam; 330 331 /* In getXXent_r(), protect the unsuspecting caller from +/- entries */ 332 333 do { 334 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2passwd); 335 /* No key to fill in */ 336 (void) nss_getent(&db_root, _nss_initf_passwd, &context, &arg); 337 } while (arg.returnval != 0 && 338 (nam = ((struct passwd *)arg.returnval)->pw_name) != 0 && 339 (*nam == '+' || *nam == '-')); 340 341 return ((struct passwd *)NSS_XbyY_FINI(&arg)); 342 } 343 344 struct passwd * 345 fgetpwent_r(FILE *f, struct passwd *result, char *buffer, int buflen) 346 { 347 extern void _nss_XbyY_fgets(FILE *, nss_XbyY_args_t *); 348 nss_XbyY_args_t arg; 349 350 /* ... but in fgetXXent_r, the caller deserves any +/- entry he gets */ 351 352 /* No key to fill in */ 353 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2passwd); 354 _nss_XbyY_fgets(f, &arg); 355 return ((struct passwd *)NSS_XbyY_FINI(&arg)); 356 } 357 358 static char * 359 gettok(char **nextpp) 360 { 361 char *p = *nextpp; 362 char *q = p; 363 char c; 364 365 if (p == 0) 366 return (0); 367 368 while ((c = *q) != '\0' && c != ':') 369 q++; 370 371 if (c == '\0') 372 *nextpp = 0; 373 else { 374 *q++ = '\0'; 375 *nextpp = q; 376 } 377 return (p); 378 } 379 380 /* 381 * Return values: 0 = success, 1 = parse error, 2 = erange ... 382 * The structure pointer passed in is a structure in the caller's space 383 * wherein the field pointers would be set to areas in the buffer if 384 * need be. instring and buffer should be separate areas. 385 */ 386 int 387 str2passwd(const char *instr, int lenstr, void *ent, char *buffer, int buflen) 388 { 389 struct passwd *passwd = (struct passwd *)ent; 390 char *p, *next; 391 int black_magic; /* "+" or "-" entry */ 392 393 if (lenstr + 1 > buflen) 394 return (NSS_STR_PARSE_ERANGE); 395 396 /* 397 * We copy the input string into the output buffer and 398 * operate on it in place. 399 */ 400 (void) memcpy(buffer, instr, lenstr); 401 buffer[lenstr] = '\0'; 402 403 next = buffer; 404 405 passwd->pw_name = p = gettok(&next); /* username */ 406 if (*p == '\0') { 407 /* Empty username; not allowed */ 408 return (NSS_STR_PARSE_PARSE); 409 } 410 black_magic = (*p == '+' || *p == '-'); 411 if (black_magic) { 412 passwd->pw_uid = UID_NOBODY; 413 passwd->pw_gid = GID_NOBODY; 414 /* 415 * pwconv tests pw_passwd and pw_age == NULL 416 */ 417 passwd->pw_passwd = ""; 418 passwd->pw_age = ""; 419 /* 420 * the rest of the passwd entry is "optional" 421 */ 422 passwd->pw_comment = ""; 423 passwd->pw_gecos = ""; 424 passwd->pw_dir = ""; 425 passwd->pw_shell = ""; 426 } 427 428 passwd->pw_passwd = p = gettok(&next); /* password */ 429 if (p == 0) { 430 if (black_magic) 431 return (NSS_STR_PARSE_SUCCESS); 432 else 433 return (NSS_STR_PARSE_PARSE); 434 } 435 for (; *p != '\0'; p++) { /* age */ 436 if (*p == ',') { 437 *p++ = '\0'; 438 break; 439 } 440 } 441 passwd->pw_age = p; 442 443 p = next; /* uid */ 444 if (p == 0 || *p == '\0') { 445 if (black_magic) 446 return (NSS_STR_PARSE_SUCCESS); 447 else 448 return (NSS_STR_PARSE_PARSE); 449 } 450 if (!black_magic) { 451 passwd->pw_uid = (uid_t)strtol(p, &next, 10); 452 if (next == p) { 453 /* uid field should be nonempty */ 454 return (NSS_STR_PARSE_PARSE); 455 } 456 /* 457 * The old code (in 2.0 through 2.5) would check 458 * for the uid being negative, or being greater 459 * than 60001 (the rfs limit). If it met either of 460 * these conditions, the uid was translated to 60001. 461 * 462 * Now we just check for negative uids; anything else 463 * is administrative policy 464 */ 465 if (passwd->pw_uid < 0) 466 passwd->pw_uid = UID_NOBODY; 467 } 468 if (*next++ != ':') { 469 if (black_magic) 470 (void) gettok(&next); 471 else 472 return (NSS_STR_PARSE_PARSE); 473 } 474 p = next; /* gid */ 475 if (p == 0 || *p == '\0') { 476 if (black_magic) 477 return (NSS_STR_PARSE_SUCCESS); 478 else 479 return (NSS_STR_PARSE_PARSE); 480 } 481 if (!black_magic) { 482 passwd->pw_gid = (gid_t)strtol(p, &next, 10); 483 if (next == p) { 484 /* gid field should be nonempty */ 485 return (NSS_STR_PARSE_PARSE); 486 } 487 /* 488 * gid should be non-negative; anything else 489 * is administrative policy. 490 */ 491 if (passwd->pw_gid < 0) 492 passwd->pw_gid = GID_NOBODY; 493 } 494 if (*next++ != ':') { 495 if (black_magic) 496 (void) gettok(&next); 497 else 498 return (NSS_STR_PARSE_PARSE); 499 } 500 501 passwd->pw_gecos = passwd->pw_comment = p = gettok(&next); 502 if (p == 0) { 503 if (black_magic) 504 return (NSS_STR_PARSE_SUCCESS); 505 else 506 return (NSS_STR_PARSE_PARSE); 507 } 508 509 passwd->pw_dir = p = gettok(&next); 510 if (p == 0) { 511 if (black_magic) 512 return (NSS_STR_PARSE_SUCCESS); 513 else 514 return (NSS_STR_PARSE_PARSE); 515 } 516 517 passwd->pw_shell = p = gettok(&next); 518 if (p == 0) { 519 if (black_magic) 520 return (NSS_STR_PARSE_SUCCESS); 521 else 522 return (NSS_STR_PARSE_PARSE); 523 } 524 525 /* Better not be any more fields... */ 526 if (next == 0) { 527 /* Successfully parsed and stored */ 528 return (NSS_STR_PARSE_SUCCESS); 529 } 530 return (NSS_STR_PARSE_PARSE); 531 } 532