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.
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.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <sys/types.h>
37 #include <nss_dbdefs.h>
41 #include <rpcsvc/nis.h>
43 #include "passwdutil.h"
48 * Translate the repository to a bitmask.
49 * if we don't recognise the repository name, we return REP_ERANGE
52 name_to_int(char *rep_name
)
54 int result
= REP_ERANGE
;
56 if (strcmp(rep_name
, "files") == 0)
58 else if (strcmp(rep_name
, "nis") == 0)
60 else if (strcmp(rep_name
, "ldap") == 0)
62 else if (strcmp(rep_name
, "compat") == 0) {
63 struct __nsw_switchconfig
*cfg
;
64 enum __nsw_parse_err pserr
;
66 cfg
= __nsw_getconfig("passwd_compat", &pserr
);
68 result
= REP_FILES
| REP_NIS
;
70 if (strcmp(cfg
->lookups
->service_name
, "ldap") == 0)
71 result
= REP_FILES
| REP_LDAP
;
74 (void) __nsw_freeconfig(cfg
);
82 * Figure out which repository we use in compat mode.
87 struct __nsw_switchconfig
*cfg
;
88 enum __nsw_parse_err pserr
;
89 int result
= REP_COMPAT_NIS
;
91 if ((cfg
= __nsw_getconfig("passwd_compat", &pserr
)) != NULL
) {
92 if (strcmp(cfg
->lookups
->service_name
, "ldap") == 0)
93 result
= REP_COMPAT_LDAP
;
95 (void) __nsw_freeconfig(cfg
);
101 * get_ns(rep, accesstype)
103 * returns a bitmask of repositories to use based on either
104 * 1. the repository that is given as argument
105 * 2. the nsswitch.conf file
106 * 3. the type of access requested
108 * "accesstype" indicates whether we are reading from or writing to the
109 * repository. We need to know this since "compat" will translate into
110 * REP_NSS (the nss-switch) for READ access but it translates into a bitmask on
113 * If we detect read-access in compat mode, we augment the result
114 * with one of REP_COMPAT_{NIS,LDAP}. We need this in order to
115 * implement ATTR_REP_NAME in nss_getpwnam.
117 * A return value of REP_NOREP indicates an error.
120 get_ns(pwu_repository_t
*rep
, int accesstype
)
122 struct __nsw_switchconfig
*conf
= NULL
;
123 enum __nsw_parse_err pserr
;
124 struct __nsw_lookup
*lkp
;
125 struct __nsw_lookup
*lkp2
;
126 struct __nsw_lookup
*lkp3
;
127 struct __nsw_lookup
*lkpn
;
128 int result
= REP_NOREP
;
130 if (rep
!= PWU_DEFAULT_REP
) {
131 result
= name_to_int(rep
->type
);
135 conf
= __nsw_getconfig("passwd", &pserr
);
138 * No config found. The user didn't supply a repository,
139 * so we try to change the password in the default
140 * repositories (files and nis) even though we cannot
141 * find the name service switch entry. (Backward compat)
143 syslog(LOG_ERR
, "passwdutil.so: nameservice switch entry for "
144 "passwd not found.");
145 result
= REP_FILES
| REP_NIS
;
152 * Supported nsswitch.conf can have a maximum of 3 repositories.
153 * If we encounter an unsupported nsswitch.conf, we return REP_NSS
154 * to fall back to the nsswitch backend.
156 * Note that specifying 'ad' in the configuration is acceptable
157 * though changing AD users' passwords through passwd(1) is not.
158 * Therefore "ad" will be silently ignored.
160 if (conf
->num_lookups
== 1) {
161 /* files or compat */
163 if (strcmp(lkp
->service_name
, "files") == 0) {
164 result
= name_to_int(lkp
->service_name
);
165 } else if (strcmp(lkp
->service_name
, "compat") == 0) {
166 if (accesstype
== PWU_READ
)
167 result
= REP_NSS
| get_compat_mode();
169 result
= name_to_int(lkp
->service_name
);
173 } else if (conf
->num_lookups
== 2) {
175 if (strcmp(lkp
->service_name
, "files") == 0) {
177 if (strcmp(lkp2
->service_name
, "ldap") == 0)
179 else if (strcmp(lkp2
->service_name
, "nis") == 0)
181 else if (strcmp(lkp2
->service_name
, "ad") != 0)
187 } else if (conf
->num_lookups
== 3) {
189 * Valid configurations with 3 repositories are:
190 * files ad [nis | ldap ] OR
191 * files [nis | ldap ] ad
195 if (strcmp(lkp2
->service_name
, "ad") == 0)
197 else if (strcmp(lkp3
->service_name
, "ad") == 0)
201 if (strcmp(lkp
->service_name
, "files") == 0 &&
204 if (strcmp(lkpn
->service_name
, "ldap") == 0)
206 else if (strcmp(lkpn
->service_name
, "nis") == 0)
217 (void) __nsw_freeconfig(conf
);
225 p
->name
= NSS_DBNAM_PASSWD
;
226 p
->flags
|= NSS_USE_DEFAULT_CONFIG
;
227 p
->default_config
= "ldap";
234 p
->name
= NSS_DBNAM_SHADOW
;
235 p
->config_name
= NSS_DBNAM_PASSWD
; /* Use config for "passwd" */
236 p
->flags
|= NSS_USE_DEFAULT_CONFIG
;
237 p
->default_config
= "ldap";
246 p
->name
= NSS_DBNAM_PASSWD
;
247 p
->flags
|= NSS_USE_DEFAULT_CONFIG
;
248 p
->default_config
= "nis";
255 p
->name
= NSS_DBNAM_SHADOW
;
256 p
->config_name
= NSS_DBNAM_PASSWD
; /* Use config for "passwd" */
257 p
->flags
|= NSS_USE_DEFAULT_CONFIG
;
258 p
->default_config
= "nis";
273 while ((c
= *q
) != '\0' && c
!= ':') {
286 * Return values: 0 = success, 1 = parse error, 2 = erange ...
287 * The structure pointer passed in is a structure in the caller's space
288 * wherein the field pointers would be set to areas in the buffer if
289 * need be. instring and buffer should be separate areas.
292 str2passwd(const char *instr
, int lenstr
, void *ent
, char *buffer
, int buflen
)
294 struct passwd
*passwd
= (struct passwd
*)ent
;
297 if (lenstr
+ 1 > buflen
) {
298 return (NSS_STR_PARSE_ERANGE
);
301 * We copy the input string into the output buffer and
302 * operate on it in place.
304 (void) memcpy(buffer
, instr
, lenstr
);
305 buffer
[lenstr
] = '\0';
309 passwd
->pw_name
= p
= gettok(&next
); /* username */
311 /* Empty username; not allowed */
312 return (NSS_STR_PARSE_PARSE
);
315 passwd
->pw_passwd
= p
= gettok(&next
); /* password */
317 return (NSS_STR_PARSE_PARSE
);
318 for (; *p
!= '\0'; p
++) { /* age */
327 if (p
== 0 || *p
== '\0')
328 return (NSS_STR_PARSE_PARSE
);
330 passwd
->pw_uid
= strtol(p
, &next
, 10);
332 /* uid field should be nonempty */
333 return (NSS_STR_PARSE_PARSE
);
336 * The old code (in 2.0 thru 2.5) would check
337 * for the uid being negative, or being greater
338 * than 60001 (the rfs limit). If it met either of
339 * these conditions, the uid was translated to 60001.
341 * Now we just check for ephemeral uids; anything else
342 * is administrative policy
344 if (passwd
->pw_uid
> MAXUID
)
345 passwd
->pw_uid
= UID_NOBODY
;
348 return (NSS_STR_PARSE_PARSE
);
350 if (p
== 0 || *p
== '\0')
351 return (NSS_STR_PARSE_PARSE
);
353 passwd
->pw_gid
= strtol(p
, &next
, 10);
355 /* gid field should be nonempty */
356 return (NSS_STR_PARSE_PARSE
);
359 * gid should be non-negative; anything else
360 * is administrative policy.
362 if (passwd
->pw_gid
> MAXUID
)
363 passwd
->pw_gid
= GID_NOBODY
;
365 return (NSS_STR_PARSE_PARSE
);
367 passwd
->pw_gecos
= passwd
->pw_comment
= p
= gettok(&next
);
369 return (NSS_STR_PARSE_PARSE
);
371 passwd
->pw_dir
= p
= gettok(&next
);
373 return (NSS_STR_PARSE_PARSE
);
375 passwd
->pw_shell
= p
= gettok(&next
);
377 return (NSS_STR_PARSE_PARSE
);
379 /* Better not be any more fields... */
381 /* Successfully parsed and stored */
382 return (NSS_STR_PARSE_SUCCESS
);
384 return (NSS_STR_PARSE_PARSE
);
387 typedef const char *constp
;
390 * Return value 1 means success and more input, 0 means error or no more
393 getfield(nextp
, limit
, uns
, valp
)
401 char numbuf
[12]; /* Holds -2^31 and trailing ':' */
406 if (p
== 0 || p
>= limit
) {
414 if ((len
= limit
- p
) > sizeof (numbuf
) - 1) {
415 len
= sizeof (numbuf
) - 1;
418 * We want to use strtol() and we have a readonly non-zero-terminated
419 * string, so first we copy and terminate the interesting bit.
420 * Ugh. (It's convenient to terminate with a colon rather than \0).
422 if ((endfield
= memccpy(numbuf
, p
, ':', len
)) == 0) {
423 if (len
!= limit
- p
) {
424 /* Error -- field is too big to be a legit number */
430 p
+= (endfield
- numbuf
);
433 ux
= strtoul(numbuf
, &endfield
, 10);
434 if (*endfield
!= ':') {
435 /* Error -- expected <integer><colon> */
438 *((unsigned int *)valp
) = (unsigned int)ux
;
440 x
= strtol(numbuf
, &endfield
, 10);
441 if (*endfield
!= ':') {
442 /* Error -- expected <integer><colon> */
445 *((int *)valp
) = (int)x
;
452 * str2spwd() -- convert a string to a shadow passwd entry. The parser is
453 * more liberal than the passwd or group parsers; since it's legitimate
454 * for almost all the fields here to be blank, the parser lets one omit
455 * any number of blank fields at the end of the entry.
456 * === Is this likely to do more harm than good?
458 * Return values: 0 = success, 1 = parse error, 2 = erange ...
459 * The structure pointer passed in is a structure in the caller's space
460 * wherein the field pointers would be set to areas in the buffer if
461 * need be. instring and buffer should be separate areas.
464 str2spwd(instr
, lenstr
, ent
, buffer
, buflen
)
467 void *ent
; /* really (struct spwd *) */
471 struct spwd
*shadow
= (struct spwd
*)ent
;
472 const char *p
= instr
, *limit
;
477 if ((p
= memchr(instr
, ':', lenstr
)) == 0 ||
479 (p
= memchr(p
, ':', limit
- p
)) == 0) {
486 if (lencopy
+ 1 > buflen
) {
487 return (NSS_STR_PARSE_ERANGE
);
489 (void) memcpy(buffer
, instr
, lencopy
);
492 shadow
->sp_namp
= bufp
= buffer
;
494 shadow
->sp_lstchg
= -1;
497 shadow
->sp_warn
= -1;
498 shadow
->sp_inact
= -1;
499 shadow
->sp_expire
= -1;
502 if ((bufp
= strchr(bufp
, ':')) == 0)
503 return (NSS_STR_PARSE_PARSE
);
506 shadow
->sp_pwdp
= bufp
;
508 if ((bufp
= strchr(bufp
, ':')) == 0)
509 return (NSS_STR_PARSE_PARSE
);
512 } /* else p was set when we copied name and passwd into the buffer */
514 if (!getfield(&p
, limit
, 0, &shadow
->sp_lstchg
))
515 return (NSS_STR_PARSE_SUCCESS
);
516 if (!getfield(&p
, limit
, 0, &shadow
->sp_min
))
517 return (NSS_STR_PARSE_SUCCESS
);
518 if (!getfield(&p
, limit
, 0, &shadow
->sp_max
))
519 return (NSS_STR_PARSE_SUCCESS
);
520 if (!getfield(&p
, limit
, 0, &shadow
->sp_warn
))
521 return (NSS_STR_PARSE_SUCCESS
);
522 if (!getfield(&p
, limit
, 0, &shadow
->sp_inact
))
523 return (NSS_STR_PARSE_SUCCESS
);
524 if (!getfield(&p
, limit
, 0, &shadow
->sp_expire
))
525 return (NSS_STR_PARSE_SUCCESS
);
526 if (!getfield(&p
, limit
, 1, &shadow
->sp_flag
))
527 return (NSS_STR_PARSE_SUCCESS
);
529 /* Syntax error -- garbage at end of line */
530 return (NSS_STR_PARSE_PARSE
);
532 return (NSS_STR_PARSE_SUCCESS
);
535 static nss_XbyY_buf_t
*buffer
;
536 static DEFINE_NSS_DB_ROOT(db_root
);
539 NSS_XbyY_ALLOC(&buffer, sizeof (struct passwd), NSS_BUFLEN_PASSWD)
541 #pragma fini(endutilpwent)
546 NSS_XbyY_FREE(&buffer
);
547 nss_delete(&db_root
);
552 getpwnam_from(const char *name
, pwu_repository_t
*rep
, int reptype
)
554 nss_XbyY_buf_t
*b
= GETBUF();
560 NSS_XbyY_INIT(&arg
, b
->result
, b
->buffer
, b
->buflen
, str2passwd
);
565 (void) nss_search(&db_root
, nss_ldap_passwd
,
566 NSS_DBOP_PASSWD_BYNAME
, &arg
);
570 (void) nss_search(&db_root
, nss_nis_passwd
,
571 NSS_DBOP_PASSWD_BYNAME
, &arg
);
578 return (struct passwd
*)NSS_XbyY_FINI(&arg
);
583 getpwuid_from(uid_t uid
, pwu_repository_t
*rep
, int reptype
)
585 nss_XbyY_buf_t
*b
= GETBUF();
591 NSS_XbyY_INIT(&arg
, b
->result
, b
->buffer
, b
->buflen
, str2passwd
);
596 (void) nss_search(&db_root
, nss_ldap_passwd
,
597 NSS_DBOP_PASSWD_BYUID
, &arg
);
601 (void) nss_search(&db_root
, nss_nis_passwd
,
602 NSS_DBOP_PASSWD_BYUID
, &arg
);
609 return (struct passwd
*)NSS_XbyY_FINI(&arg
);
612 static nss_XbyY_buf_t
*spbuf
;
613 static DEFINE_NSS_DB_ROOT(spdb_root
);
616 NSS_XbyY_ALLOC(&spbuf, sizeof (struct spwd), NSS_BUFLEN_SHADOW)
618 #pragma fini(endutilspent)
623 NSS_XbyY_FREE(&spbuf
);
624 nss_delete(&spdb_root
);
629 getspnam_from(const char *name
, pwu_repository_t
*rep
, int reptype
)
631 nss_XbyY_buf_t
*b
= GETSPBUF();
637 NSS_XbyY_INIT(&arg
, b
->result
, b
->buffer
, b
->buflen
, str2spwd
);
641 (void) nss_search(&spdb_root
, nss_ldap_shadow
,
642 NSS_DBOP_SHADOW_BYNAME
, &arg
);
646 (void) nss_search(&spdb_root
, nss_nis_shadow
,
647 NSS_DBOP_SHADOW_BYNAME
, &arg
);
653 return (struct spwd
*)NSS_XbyY_FINI(&arg
);