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 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include "lint.h" 30 #include <sys/types.h> 31 #include <pwd.h> 32 #include <nss_dbdefs.h> 33 #include <stdio.h> 34 #include <synch.h> 35 #include <sys/param.h> 36 #include <string.h> 37 #include <stdlib.h> 38 #include <sys/mman.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 he 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 248 if (lenstr + 1 > buflen) 249 return (NSS_STR_PARSE_ERANGE); 250 251 /* 252 * We copy the input string into the output buffer and 253 * operate on it in place. 254 */ 255 if (instr != buffer) { 256 /* Overlapping buffer copies are OK */ 257 (void) memmove(buffer, instr, lenstr); 258 buffer[lenstr] = '\0'; 259 } 260 261 /* quick exit do not entry fill if not needed */ 262 if (ent == (void *)NULL) 263 return (NSS_STR_PARSE_SUCCESS); 264 265 next = buffer; 266 267 passwd->pw_name = p = gettok(&next); /* username */ 268 if (*p == '\0') { 269 /* Empty username; not allowed */ 270 return (NSS_STR_PARSE_PARSE); 271 } 272 black_magic = (*p == '+' || *p == '-'); 273 if (black_magic) { 274 passwd->pw_uid = UID_NOBODY; 275 passwd->pw_gid = GID_NOBODY; 276 /* 277 * pwconv tests pw_passwd and pw_age == NULL 278 */ 279 passwd->pw_passwd = ""; 280 passwd->pw_age = ""; 281 /* 282 * the rest of the passwd entry is "optional" 283 */ 284 passwd->pw_comment = ""; 285 passwd->pw_gecos = ""; 286 passwd->pw_dir = ""; 287 passwd->pw_shell = ""; 288 } 289 290 passwd->pw_passwd = p = gettok(&next); /* password */ 291 if (p == 0) { 292 if (black_magic) 293 return (NSS_STR_PARSE_SUCCESS); 294 else 295 return (NSS_STR_PARSE_PARSE); 296 } 297 for (; *p != '\0'; p++) { /* age */ 298 if (*p == ',') { 299 *p++ = '\0'; 300 break; 301 } 302 } 303 passwd->pw_age = p; 304 305 p = next; /* uid */ 306 if (p == 0 || *p == '\0') { 307 if (black_magic) 308 return (NSS_STR_PARSE_SUCCESS); 309 else 310 return (NSS_STR_PARSE_PARSE); 311 } 312 if (!black_magic) { 313 passwd->pw_uid = (uid_t)strtol(p, &next, 10); 314 if (next == p) { 315 /* uid field should be nonempty */ 316 return (NSS_STR_PARSE_PARSE); 317 } 318 /* 319 * The old code (in 2.0 through 2.5) would check 320 * for the uid being negative, or being greater 321 * than 60001 (the rfs limit). If it met either of 322 * these conditions, the uid was translated to 60001. 323 * 324 * Now we just check for negative uids; anything else 325 * is administrative policy 326 */ 327 if (passwd->pw_uid > MAXUID) 328 passwd->pw_uid = UID_NOBODY; 329 } 330 if (*next++ != ':') { 331 if (black_magic) 332 (void) gettok(&next); 333 else 334 return (NSS_STR_PARSE_PARSE); 335 } 336 p = next; /* gid */ 337 if (p == 0 || *p == '\0') { 338 if (black_magic) 339 return (NSS_STR_PARSE_SUCCESS); 340 else 341 return (NSS_STR_PARSE_PARSE); 342 } 343 if (!black_magic) { 344 passwd->pw_gid = (gid_t)strtol(p, &next, 10); 345 if (next == p) { 346 /* gid field should be nonempty */ 347 return (NSS_STR_PARSE_PARSE); 348 } 349 /* 350 * gid should be non-negative; anything else 351 * is administrative policy. 352 */ 353 if (passwd->pw_gid > MAXUID) 354 passwd->pw_gid = GID_NOBODY; 355 } 356 if (*next++ != ':') { 357 if (black_magic) 358 (void) gettok(&next); 359 else 360 return (NSS_STR_PARSE_PARSE); 361 } 362 363 passwd->pw_gecos = passwd->pw_comment = p = gettok(&next); 364 if (p == 0) { 365 if (black_magic) 366 return (NSS_STR_PARSE_SUCCESS); 367 else 368 return (NSS_STR_PARSE_PARSE); 369 } 370 371 passwd->pw_dir = p = gettok(&next); 372 if (p == 0) { 373 if (black_magic) 374 return (NSS_STR_PARSE_SUCCESS); 375 else 376 return (NSS_STR_PARSE_PARSE); 377 } 378 379 passwd->pw_shell = 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 /* Better not be any more fields... */ 388 if (next == 0) { 389 /* Successfully parsed and stored */ 390 return (NSS_STR_PARSE_SUCCESS); 391 } 392 return (NSS_STR_PARSE_PARSE); 393 } 394