Home | History | Annotate | Download | only in gen
      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  */
     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 #include <errno.h>
     38 
     39 int str2passwd(const char *, int, void *,
     40 	char *, int);
     41 
     42 static DEFINE_NSS_DB_ROOT(db_root);
     43 static DEFINE_NSS_GETENT(context);
     44 
     45 void
     46 _nss_initf_passwd(nss_db_params_t *p)
     47 {
     48 	p->name	= NSS_DBNAM_PASSWD;
     49 	p->default_config = NSS_DEFCONF_PASSWD;
     50 }
     51 
     52 #include <getxby_door.h>
     53 
     54 struct passwd *
     55 _uncached_getpwuid_r(uid_t uid, struct passwd *result, char *buffer,
     56 	int buflen);
     57 
     58 struct passwd *
     59 _uncached_getpwnam_r(const char *name, struct passwd *result, char *buffer,
     60     int buflen);
     61 
     62 /*
     63  * POSIX.1c Draft-6 version of the function getpwnam_r.
     64  * It was implemented by Solaris 2.3.
     65  */
     66 struct passwd *
     67 getpwnam_r(const char *name, struct passwd *result, char *buffer, int buflen)
     68 {
     69 	nss_XbyY_args_t arg;
     70 
     71 	if (name == (const char *)NULL) {
     72 		errno = ERANGE;
     73 		return (NULL);
     74 	}
     75 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2passwd);
     76 	arg.key.name = name;
     77 	(void) nss_search(&db_root, _nss_initf_passwd, NSS_DBOP_PASSWD_BYNAME,
     78 	    &arg);
     79 	return ((struct passwd *)NSS_XbyY_FINI(&arg));
     80 }
     81 
     82 /*
     83  * POSIX.1c Draft-6 version of the function getpwuid_r.
     84  * It was implemented by Solaris 2.3.
     85  */
     86 struct passwd *
     87 getpwuid_r(uid_t uid, struct passwd *result, char *buffer, int buflen)
     88 {
     89 	nss_XbyY_args_t arg;
     90 
     91 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2passwd);
     92 	arg.key.uid = uid;
     93 	(void) nss_search(&db_root, _nss_initf_passwd, NSS_DBOP_PASSWD_BYUID,
     94 	    &arg);
     95 	return ((struct passwd *)NSS_XbyY_FINI(&arg));
     96 }
     97 
     98 
     99 struct passwd *
    100 _uncached_getpwuid_r(uid_t uid, struct passwd *result, char *buffer,
    101 	int buflen)
    102 {
    103 	nss_XbyY_args_t arg;
    104 
    105 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2passwd);
    106 	arg.key.uid = uid;
    107 	(void) nss_search(&db_root, _nss_initf_passwd, NSS_DBOP_PASSWD_BYUID,
    108 	    &arg);
    109 	return ((struct passwd *)NSS_XbyY_FINI(&arg));
    110 }
    111 
    112 
    113 /*
    114  * POSIX.1c standard version of the function getpwuid_r.
    115  * User gets it via static getpwuid_r from the header file.
    116  */
    117 int
    118 __posix_getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer,
    119     size_t bufsize, struct passwd **result)
    120 {
    121 	int nerrno = 0;
    122 	int oerrno = errno;
    123 
    124 	errno = 0;
    125 	if ((*result = getpwuid_r(uid, pwd, buffer, (uintptr_t)bufsize))
    126 	    == NULL) {
    127 			nerrno = errno;
    128 	}
    129 	errno = oerrno;
    130 	return (nerrno);
    131 }
    132 
    133 struct passwd *
    134 _uncached_getpwnam_r(const char *name, struct passwd *result, char *buffer,
    135 	int buflen)
    136 {
    137 	nss_XbyY_args_t arg;
    138 
    139 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2passwd);
    140 	arg.key.name = name;
    141 	(void) nss_search(&db_root, _nss_initf_passwd, NSS_DBOP_PASSWD_BYNAME,
    142 	    &arg);
    143 	return ((struct passwd *)NSS_XbyY_FINI(&arg));
    144 }
    145 
    146 /*
    147  * POSIX.1c standard version of the function getpwnam_r.
    148  * User gets it via static getpwnam_r from the header file.
    149  */
    150 int
    151 __posix_getpwnam_r(const char *name, struct passwd *pwd, char *buffer,
    152     size_t bufsize, struct passwd **result)
    153 {
    154 	int nerrno = 0;
    155 	int oerrno = errno;
    156 
    157 	errno = 0;
    158 	if ((*result = getpwnam_r(name, pwd, buffer, (uintptr_t)bufsize))
    159 	    == NULL) {
    160 			nerrno = errno;
    161 	}
    162 	errno = oerrno;
    163 	return (nerrno);
    164 }
    165 
    166 void
    167 setpwent(void)
    168 {
    169 	nss_setent(&db_root, _nss_initf_passwd, &context);
    170 }
    171 
    172 void
    173 endpwent(void)
    174 {
    175 	nss_endent(&db_root, _nss_initf_passwd, &context);
    176 	nss_delete(&db_root);
    177 }
    178 
    179 struct passwd *
    180 getpwent_r(struct passwd *result, char *buffer, int buflen)
    181 {
    182 	nss_XbyY_args_t arg;
    183 	char		*nam;
    184 
    185 	/* In getXXent_r(), protect the unsuspecting caller from +/- entries */
    186 
    187 	do {
    188 		NSS_XbyY_INIT(&arg, result, buffer, buflen, str2passwd);
    189 		/* No key to fill in */
    190 		(void) nss_getent(&db_root, _nss_initf_passwd, &context, &arg);
    191 	} while (arg.returnval != 0 &&
    192 	    (nam = ((struct passwd *)arg.returnval)->pw_name) != 0 &&
    193 	    (*nam == '+' || *nam == '-'));
    194 
    195 	return ((struct passwd *)NSS_XbyY_FINI(&arg));
    196 }
    197 
    198 struct passwd *
    199 fgetpwent_r(FILE *f, struct passwd *result, char *buffer, int buflen)
    200 {
    201 	extern void	_nss_XbyY_fgets(FILE *, nss_XbyY_args_t *);
    202 	nss_XbyY_args_t	arg;
    203 
    204 	/* ... but in fgetXXent_r, the caller deserves any +/- entry he gets */
    205 
    206 	/* No key to fill in */
    207 	NSS_XbyY_INIT(&arg, result, buffer, buflen, str2passwd);
    208 	_nss_XbyY_fgets(f, &arg);
    209 	return ((struct passwd *)NSS_XbyY_FINI(&arg));
    210 }
    211 
    212 static char *
    213 gettok(char **nextpp)
    214 {
    215 	char	*p = *nextpp;
    216 	char	*q = p;
    217 	char	c;
    218 
    219 	if (p == 0)
    220 		return (0);
    221 
    222 	while ((c = *q) != '\0' && c != ':')
    223 		q++;
    224 
    225 	if (c == '\0')
    226 		*nextpp = 0;
    227 	else {
    228 		*q++ = '\0';
    229 		*nextpp = q;
    230 	}
    231 	return (p);
    232 }
    233 
    234 /*
    235  * Return values: 0 = success, 1 = parse error, 2 = erange ...
    236  * The structure pointer passed in is a structure in the caller's space
    237  * wherein the field pointers would be set to areas in the buffer if
    238  * need be. instring and buffer should be separate areas.
    239  */
    240 int
    241 str2passwd(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
    242 {
    243 	struct passwd	*passwd	= (struct passwd *)ent;
    244 	char		*p, *next;
    245 	int		black_magic;	/* "+" or "-" entry */
    246 	ulong_t		tmp;
    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 		/*
    314 		 * strtoul returns unsigned long which is
    315 		 * 8 bytes on a 64-bit system. We don't want
    316 		 * to assign it directly to passwd->pw_uid
    317 		 * which is 4 bytes or else we will end up
    318 		 * truncating the value.
    319 		 */
    320 		errno = 0;
    321 		tmp = strtoul(p, &next, 10);
    322 		if (next == p || errno != 0) {
    323 			/* uid field should be nonempty */
    324 			/* also check errno from strtoul */
    325 			return (NSS_STR_PARSE_PARSE);
    326 		}
    327 		/*
    328 		 * The old code (in 2.0 through 2.5) would check
    329 		 * for the uid being negative, or being greater
    330 		 * than 60001 (the rfs limit).  If it met either of
    331 		 * these conditions, the uid was translated to 60001.
    332 		 *
    333 		 * Now we just check for -1 (UINT32_MAX); anything else
    334 		 * is administrative policy
    335 		 */
    336 		if (tmp >= UINT32_MAX)
    337 			passwd->pw_uid = UID_NOBODY;
    338 		else
    339 			passwd->pw_uid = (uid_t)tmp;
    340 	}
    341 	if (*next++ != ':') {
    342 		if (black_magic)
    343 			(void) gettok(&next);
    344 		else
    345 			return (NSS_STR_PARSE_PARSE);
    346 	}
    347 	p = next;					/* gid */
    348 	if (p == 0 || *p == '\0') {
    349 		if (black_magic)
    350 			return (NSS_STR_PARSE_SUCCESS);
    351 		else
    352 			return (NSS_STR_PARSE_PARSE);
    353 	}
    354 	if (!black_magic) {
    355 		errno = 0;
    356 		tmp = strtoul(p, &next, 10);
    357 		if (next == p || errno != 0) {
    358 			/* gid field should be nonempty */
    359 			/* also check errno from strtoul */
    360 			return (NSS_STR_PARSE_PARSE);
    361 		}
    362 		/*
    363 		 * gid should not be -1; anything else
    364 		 * is administrative policy.
    365 		 */
    366 		if (tmp >= UINT32_MAX)
    367 			passwd->pw_gid = GID_NOBODY;
    368 		else
    369 			passwd->pw_gid = (gid_t)tmp;
    370 	}
    371 	if (*next++ != ':') {
    372 		if (black_magic)
    373 			(void) gettok(&next);
    374 		else
    375 			return (NSS_STR_PARSE_PARSE);
    376 	}
    377 
    378 	passwd->pw_gecos = passwd->pw_comment = p = gettok(&next);
    379 	if (p == 0) {
    380 		if (black_magic)
    381 			return (NSS_STR_PARSE_SUCCESS);
    382 		else
    383 			return (NSS_STR_PARSE_PARSE);
    384 	}
    385 
    386 	passwd->pw_dir = p = gettok(&next);
    387 	if (p == 0) {
    388 		if (black_magic)
    389 			return (NSS_STR_PARSE_SUCCESS);
    390 		else
    391 			return (NSS_STR_PARSE_PARSE);
    392 	}
    393 
    394 	passwd->pw_shell = p = gettok(&next);
    395 	if (p == 0) {
    396 		if (black_magic)
    397 			return (NSS_STR_PARSE_SUCCESS);
    398 		else
    399 			return (NSS_STR_PARSE_PARSE);
    400 	}
    401 
    402 	/* Better not be any more fields... */
    403 	if (next == 0) {
    404 		/* Successfully parsed and stored */
    405 		return (NSS_STR_PARSE_SUCCESS);
    406 	}
    407 	return (NSS_STR_PARSE_PARSE);
    408 }
    409