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