1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 30*7c478bd9Sstevel@tonic-gate #include <nsswitch.h> 31*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 32*7c478bd9Sstevel@tonic-gate #include <stdio.h> 33*7c478bd9Sstevel@tonic-gate #include <string.h> 34*7c478bd9Sstevel@tonic-gate #include <syslog.h> 35*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 36*7c478bd9Sstevel@tonic-gate #include <unistd.h> 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate #include "ns_sldap.h" 39*7c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h> 40*7c478bd9Sstevel@tonic-gate #include <nsswitch.h> 41*7c478bd9Sstevel@tonic-gate #include <pwd.h> 42*7c478bd9Sstevel@tonic-gate #include <shadow.h> 43*7c478bd9Sstevel@tonic-gate #include <rpcsvc/nis.h> 44*7c478bd9Sstevel@tonic-gate 45*7c478bd9Sstevel@tonic-gate #include "passwdutil.h" 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate static struct passwd *nisplus_getpw_from_master(const char *, char *); 48*7c478bd9Sstevel@tonic-gate static struct spwd *nisplus_getsp_from_master(const char *, char *); 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate /* 51*7c478bd9Sstevel@tonic-gate * name_to_int(rep) 52*7c478bd9Sstevel@tonic-gate * 53*7c478bd9Sstevel@tonic-gate * Translate the repository to a bitmask. 54*7c478bd9Sstevel@tonic-gate * if we don't recognise the repository name, we return REP_ERANGE 55*7c478bd9Sstevel@tonic-gate */ 56*7c478bd9Sstevel@tonic-gate int 57*7c478bd9Sstevel@tonic-gate name_to_int(char *rep_name) 58*7c478bd9Sstevel@tonic-gate { 59*7c478bd9Sstevel@tonic-gate int result = REP_ERANGE; 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate if (strcmp(rep_name, "files") == 0) 62*7c478bd9Sstevel@tonic-gate result = REP_FILES; 63*7c478bd9Sstevel@tonic-gate else if (strcmp(rep_name, "nis") == 0) 64*7c478bd9Sstevel@tonic-gate result = REP_NIS; 65*7c478bd9Sstevel@tonic-gate else if (strcmp(rep_name, "nisplus") == 0) 66*7c478bd9Sstevel@tonic-gate result = REP_NISPLUS; 67*7c478bd9Sstevel@tonic-gate else if (strcmp(rep_name, "ldap") == 0) 68*7c478bd9Sstevel@tonic-gate result = REP_LDAP; 69*7c478bd9Sstevel@tonic-gate else if (strcmp(rep_name, "compat") == 0) { 70*7c478bd9Sstevel@tonic-gate struct __nsw_switchconfig *cfg; 71*7c478bd9Sstevel@tonic-gate enum __nsw_parse_err pserr; 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate cfg = __nsw_getconfig("passwd_compat", &pserr); 74*7c478bd9Sstevel@tonic-gate if (cfg == NULL) { 75*7c478bd9Sstevel@tonic-gate result = REP_FILES | REP_NIS; 76*7c478bd9Sstevel@tonic-gate } else { 77*7c478bd9Sstevel@tonic-gate if (strcmp(cfg->lookups->service_name, "nisplus") == 0) 78*7c478bd9Sstevel@tonic-gate result = REP_FILES | REP_NISPLUS; 79*7c478bd9Sstevel@tonic-gate else if (strcmp(cfg->lookups->service_name, "ldap") == 80*7c478bd9Sstevel@tonic-gate 0) 81*7c478bd9Sstevel@tonic-gate result = REP_FILES | REP_LDAP; 82*7c478bd9Sstevel@tonic-gate else 83*7c478bd9Sstevel@tonic-gate result = REP_ERANGE; 84*7c478bd9Sstevel@tonic-gate __nsw_freeconfig(cfg); 85*7c478bd9Sstevel@tonic-gate } 86*7c478bd9Sstevel@tonic-gate } 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate return (result); 89*7c478bd9Sstevel@tonic-gate } 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate /* 92*7c478bd9Sstevel@tonic-gate * Figure out which repository we use in compat mode. 93*7c478bd9Sstevel@tonic-gate */ 94*7c478bd9Sstevel@tonic-gate int 95*7c478bd9Sstevel@tonic-gate get_compat_mode(void) 96*7c478bd9Sstevel@tonic-gate { 97*7c478bd9Sstevel@tonic-gate struct __nsw_switchconfig *cfg; 98*7c478bd9Sstevel@tonic-gate enum __nsw_parse_err pserr; 99*7c478bd9Sstevel@tonic-gate int result = REP_COMPAT_NIS; 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate if ((cfg = __nsw_getconfig("passwd_compat", &pserr)) != NULL) { 102*7c478bd9Sstevel@tonic-gate if (strcmp(cfg->lookups->service_name, "nisplus") == 0) 103*7c478bd9Sstevel@tonic-gate result = REP_COMPAT_NISPLUS; 104*7c478bd9Sstevel@tonic-gate else if (strcmp(cfg->lookups->service_name, "ldap") == 0) 105*7c478bd9Sstevel@tonic-gate result = REP_COMPAT_LDAP; 106*7c478bd9Sstevel@tonic-gate } 107*7c478bd9Sstevel@tonic-gate __nsw_freeconfig(cfg); 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate return (result); 110*7c478bd9Sstevel@tonic-gate } 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate /* 113*7c478bd9Sstevel@tonic-gate * get_ns(rep, accesstype) 114*7c478bd9Sstevel@tonic-gate * 115*7c478bd9Sstevel@tonic-gate * returns a bitmask of repositories to use based on either 116*7c478bd9Sstevel@tonic-gate * 1. the repository that is given as argument 117*7c478bd9Sstevel@tonic-gate * 2. the nsswitch.conf file 118*7c478bd9Sstevel@tonic-gate * 3. the type of access requested 119*7c478bd9Sstevel@tonic-gate * 120*7c478bd9Sstevel@tonic-gate * "accesstype" indicates whether we are reading from or writing to the 121*7c478bd9Sstevel@tonic-gate * repository. We need to know this since "compat" will translate into 122*7c478bd9Sstevel@tonic-gate * REP_NSS (the nss-switch) for READ access (needed to decode 123*7c478bd9Sstevel@tonic-gate * the black-magic '+' entries) but it translates into a bitmask 124*7c478bd9Sstevel@tonic-gate * on WRITE access. 125*7c478bd9Sstevel@tonic-gate * 126*7c478bd9Sstevel@tonic-gate * If we detect read-access in compat mode, we augment the result 127*7c478bd9Sstevel@tonic-gate * with one of REP_COMPAT_{NIS,NISPLUS,LDAP}. We need this in order to 128*7c478bd9Sstevel@tonic-gate * implement ATTR_REP_NAME in nss_getpwnam. 129*7c478bd9Sstevel@tonic-gate * 130*7c478bd9Sstevel@tonic-gate * A return value of REP_NOREP indicates an error. 131*7c478bd9Sstevel@tonic-gate */ 132*7c478bd9Sstevel@tonic-gate int 133*7c478bd9Sstevel@tonic-gate get_ns(pwu_repository_t *rep, int accesstype) 134*7c478bd9Sstevel@tonic-gate { 135*7c478bd9Sstevel@tonic-gate struct __nsw_switchconfig *conf = NULL; 136*7c478bd9Sstevel@tonic-gate enum __nsw_parse_err pserr; 137*7c478bd9Sstevel@tonic-gate struct __nsw_lookup *lkp; 138*7c478bd9Sstevel@tonic-gate struct __nsw_lookup *lkp2; 139*7c478bd9Sstevel@tonic-gate int result = REP_NOREP; 140*7c478bd9Sstevel@tonic-gate 141*7c478bd9Sstevel@tonic-gate if (rep != PWU_DEFAULT_REP) { 142*7c478bd9Sstevel@tonic-gate result = name_to_int(rep->type); 143*7c478bd9Sstevel@tonic-gate return (result); 144*7c478bd9Sstevel@tonic-gate } 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate conf = __nsw_getconfig("passwd", &pserr); 147*7c478bd9Sstevel@tonic-gate if (conf == NULL) { 148*7c478bd9Sstevel@tonic-gate /* 149*7c478bd9Sstevel@tonic-gate * No config found. The user didn't supply a repository, 150*7c478bd9Sstevel@tonic-gate * so we try to change the password in the default 151*7c478bd9Sstevel@tonic-gate * repositories (files and nis) even though we cannot 152*7c478bd9Sstevel@tonic-gate * find the name service switch entry. (Backward compat) 153*7c478bd9Sstevel@tonic-gate */ 154*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "passwdutil.so: nameservice switch entry for " 155*7c478bd9Sstevel@tonic-gate "passwd not found."); 156*7c478bd9Sstevel@tonic-gate result = REP_FILES | REP_NIS; 157*7c478bd9Sstevel@tonic-gate return (result); 158*7c478bd9Sstevel@tonic-gate } 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate lkp = conf->lookups; 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate /* 163*7c478bd9Sstevel@tonic-gate * Supported nsswitch.conf can have a maximum of 2 repositories. 164*7c478bd9Sstevel@tonic-gate * If we encounter an unsupported nsswitch.conf, we return REP_NSS 165*7c478bd9Sstevel@tonic-gate * to fall back to the nsswitch backend. 166*7c478bd9Sstevel@tonic-gate */ 167*7c478bd9Sstevel@tonic-gate if (conf->num_lookups == 1) { 168*7c478bd9Sstevel@tonic-gate /* files or compat */ 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate if (strcmp(lkp->service_name, "files") == 0) { 171*7c478bd9Sstevel@tonic-gate result = name_to_int(lkp->service_name); 172*7c478bd9Sstevel@tonic-gate } else if (strcmp(lkp->service_name, "compat") == 0) { 173*7c478bd9Sstevel@tonic-gate if (accesstype == PWU_READ) 174*7c478bd9Sstevel@tonic-gate result = REP_NSS | get_compat_mode(); 175*7c478bd9Sstevel@tonic-gate else 176*7c478bd9Sstevel@tonic-gate result = name_to_int(lkp->service_name); 177*7c478bd9Sstevel@tonic-gate } else 178*7c478bd9Sstevel@tonic-gate result = REP_NSS; 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate } else if (conf->num_lookups == 2) { 181*7c478bd9Sstevel@tonic-gate lkp2 = lkp->next; 182*7c478bd9Sstevel@tonic-gate if (strcmp(lkp->service_name, "files") == 0) { 183*7c478bd9Sstevel@tonic-gate result = REP_FILES; 184*7c478bd9Sstevel@tonic-gate if (strcmp(lkp2->service_name, "ldap") == 0) 185*7c478bd9Sstevel@tonic-gate result |= REP_LDAP; 186*7c478bd9Sstevel@tonic-gate else if (strcmp(lkp2->service_name, "nis") == 0) 187*7c478bd9Sstevel@tonic-gate result |= REP_NIS; 188*7c478bd9Sstevel@tonic-gate else if (strcmp(lkp2->service_name, "nisplus") == 0) 189*7c478bd9Sstevel@tonic-gate result |= REP_NISPLUS; 190*7c478bd9Sstevel@tonic-gate else 191*7c478bd9Sstevel@tonic-gate result = REP_NSS; 192*7c478bd9Sstevel@tonic-gate } else { 193*7c478bd9Sstevel@tonic-gate result = REP_NSS; 194*7c478bd9Sstevel@tonic-gate } 195*7c478bd9Sstevel@tonic-gate } else { 196*7c478bd9Sstevel@tonic-gate result = REP_NSS; 197*7c478bd9Sstevel@tonic-gate } 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate __nsw_freeconfig(conf); 200*7c478bd9Sstevel@tonic-gate return (result); 201*7c478bd9Sstevel@tonic-gate } 202*7c478bd9Sstevel@tonic-gate 203*7c478bd9Sstevel@tonic-gate static void 204*7c478bd9Sstevel@tonic-gate nss_ldap_passwd(p) 205*7c478bd9Sstevel@tonic-gate nss_db_params_t *p; 206*7c478bd9Sstevel@tonic-gate { 207*7c478bd9Sstevel@tonic-gate p->name = NSS_DBNAM_PASSWD; 208*7c478bd9Sstevel@tonic-gate p->flags |= NSS_USE_DEFAULT_CONFIG; 209*7c478bd9Sstevel@tonic-gate p->default_config = "ldap"; 210*7c478bd9Sstevel@tonic-gate } 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate static void 213*7c478bd9Sstevel@tonic-gate nss_ldap_shadow(p) 214*7c478bd9Sstevel@tonic-gate nss_db_params_t *p; 215*7c478bd9Sstevel@tonic-gate { 216*7c478bd9Sstevel@tonic-gate p->name = NSS_DBNAM_SHADOW; 217*7c478bd9Sstevel@tonic-gate p->config_name = NSS_DBNAM_PASSWD; /* Use config for "passwd" */ 218*7c478bd9Sstevel@tonic-gate p->flags |= NSS_USE_DEFAULT_CONFIG; 219*7c478bd9Sstevel@tonic-gate p->default_config = "ldap"; 220*7c478bd9Sstevel@tonic-gate } 221*7c478bd9Sstevel@tonic-gate 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate #ifdef PAM_NIS 224*7c478bd9Sstevel@tonic-gate static void 225*7c478bd9Sstevel@tonic-gate nss_nis_passwd(p) 226*7c478bd9Sstevel@tonic-gate nss_db_params_t *p; 227*7c478bd9Sstevel@tonic-gate { 228*7c478bd9Sstevel@tonic-gate p->name = NSS_DBNAM_PASSWD; 229*7c478bd9Sstevel@tonic-gate p->flags |= NSS_USE_DEFAULT_CONFIG; 230*7c478bd9Sstevel@tonic-gate p->default_config = "nis"; 231*7c478bd9Sstevel@tonic-gate } 232*7c478bd9Sstevel@tonic-gate 233*7c478bd9Sstevel@tonic-gate static void 234*7c478bd9Sstevel@tonic-gate nss_nis_shadow(p) 235*7c478bd9Sstevel@tonic-gate nss_db_params_t *p; 236*7c478bd9Sstevel@tonic-gate { 237*7c478bd9Sstevel@tonic-gate p->name = NSS_DBNAM_SHADOW; 238*7c478bd9Sstevel@tonic-gate p->config_name = NSS_DBNAM_PASSWD; /* Use config for "passwd" */ 239*7c478bd9Sstevel@tonic-gate p->flags |= NSS_USE_DEFAULT_CONFIG; 240*7c478bd9Sstevel@tonic-gate p->default_config = "nis"; 241*7c478bd9Sstevel@tonic-gate } 242*7c478bd9Sstevel@tonic-gate #endif /* PAM_NIS */ 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate static void 246*7c478bd9Sstevel@tonic-gate nss_nisplus_passwd(p) 247*7c478bd9Sstevel@tonic-gate nss_db_params_t *p; 248*7c478bd9Sstevel@tonic-gate { 249*7c478bd9Sstevel@tonic-gate p->name = NSS_DBNAM_PASSWD; 250*7c478bd9Sstevel@tonic-gate p->flags |= NSS_USE_DEFAULT_CONFIG; 251*7c478bd9Sstevel@tonic-gate p->default_config = "nisplus"; 252*7c478bd9Sstevel@tonic-gate } 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate static void 255*7c478bd9Sstevel@tonic-gate nss_nisplus_shadow(p) 256*7c478bd9Sstevel@tonic-gate nss_db_params_t *p; 257*7c478bd9Sstevel@tonic-gate { 258*7c478bd9Sstevel@tonic-gate p->name = NSS_DBNAM_SHADOW; 259*7c478bd9Sstevel@tonic-gate p->config_name = NSS_DBNAM_PASSWD; /* Use config for "passwd" */ 260*7c478bd9Sstevel@tonic-gate p->flags |= NSS_USE_DEFAULT_CONFIG; 261*7c478bd9Sstevel@tonic-gate p->default_config = "nisplus"; 262*7c478bd9Sstevel@tonic-gate } 263*7c478bd9Sstevel@tonic-gate 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate static char * 266*7c478bd9Sstevel@tonic-gate gettok(nextpp) 267*7c478bd9Sstevel@tonic-gate char **nextpp; 268*7c478bd9Sstevel@tonic-gate { 269*7c478bd9Sstevel@tonic-gate char *p = *nextpp; 270*7c478bd9Sstevel@tonic-gate char *q = p; 271*7c478bd9Sstevel@tonic-gate char c; 272*7c478bd9Sstevel@tonic-gate 273*7c478bd9Sstevel@tonic-gate if (p == 0) { 274*7c478bd9Sstevel@tonic-gate return (0); 275*7c478bd9Sstevel@tonic-gate } 276*7c478bd9Sstevel@tonic-gate while ((c = *q) != '\0' && c != ':') { 277*7c478bd9Sstevel@tonic-gate q++; 278*7c478bd9Sstevel@tonic-gate } 279*7c478bd9Sstevel@tonic-gate if (c == '\0') { 280*7c478bd9Sstevel@tonic-gate *nextpp = 0; 281*7c478bd9Sstevel@tonic-gate } else { 282*7c478bd9Sstevel@tonic-gate *q++ = '\0'; 283*7c478bd9Sstevel@tonic-gate *nextpp = q; 284*7c478bd9Sstevel@tonic-gate } 285*7c478bd9Sstevel@tonic-gate return (p); 286*7c478bd9Sstevel@tonic-gate } 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate /* 289*7c478bd9Sstevel@tonic-gate * Return values: 0 = success, 1 = parse error, 2 = erange ... 290*7c478bd9Sstevel@tonic-gate * The structure pointer passed in is a structure in the caller's space 291*7c478bd9Sstevel@tonic-gate * wherein the field pointers would be set to areas in the buffer if 292*7c478bd9Sstevel@tonic-gate * need be. instring and buffer should be separate areas. 293*7c478bd9Sstevel@tonic-gate */ 294*7c478bd9Sstevel@tonic-gate static int 295*7c478bd9Sstevel@tonic-gate str2passwd(const char *instr, int lenstr, void *ent, char *buffer, int buflen) 296*7c478bd9Sstevel@tonic-gate { 297*7c478bd9Sstevel@tonic-gate struct passwd *passwd = (struct passwd *)ent; 298*7c478bd9Sstevel@tonic-gate char *p, *next; 299*7c478bd9Sstevel@tonic-gate int black_magic; /* "+" or "-" entry */ 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate if (lenstr + 1 > buflen) { 302*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_ERANGE); 303*7c478bd9Sstevel@tonic-gate } 304*7c478bd9Sstevel@tonic-gate /* 305*7c478bd9Sstevel@tonic-gate * We copy the input string into the output buffer and 306*7c478bd9Sstevel@tonic-gate * operate on it in place. 307*7c478bd9Sstevel@tonic-gate */ 308*7c478bd9Sstevel@tonic-gate (void) memcpy(buffer, instr, lenstr); 309*7c478bd9Sstevel@tonic-gate buffer[lenstr] = '\0'; 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate next = buffer; 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate passwd->pw_name = p = gettok(&next); /* username */ 314*7c478bd9Sstevel@tonic-gate if (*p == '\0') { 315*7c478bd9Sstevel@tonic-gate /* Empty username; not allowed */ 316*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 317*7c478bd9Sstevel@tonic-gate } 318*7c478bd9Sstevel@tonic-gate black_magic = (*p == '+' || *p == '-'); 319*7c478bd9Sstevel@tonic-gate if (black_magic) { 320*7c478bd9Sstevel@tonic-gate passwd->pw_uid = UID_NOBODY; 321*7c478bd9Sstevel@tonic-gate passwd->pw_gid = GID_NOBODY; 322*7c478bd9Sstevel@tonic-gate /* 323*7c478bd9Sstevel@tonic-gate * pwconv tests pw_passwd and pw_age == NULL 324*7c478bd9Sstevel@tonic-gate */ 325*7c478bd9Sstevel@tonic-gate passwd->pw_passwd = ""; 326*7c478bd9Sstevel@tonic-gate passwd->pw_age = ""; 327*7c478bd9Sstevel@tonic-gate /* 328*7c478bd9Sstevel@tonic-gate * the rest of the passwd entry is "optional" 329*7c478bd9Sstevel@tonic-gate */ 330*7c478bd9Sstevel@tonic-gate passwd->pw_comment = ""; 331*7c478bd9Sstevel@tonic-gate passwd->pw_gecos = ""; 332*7c478bd9Sstevel@tonic-gate passwd->pw_dir = ""; 333*7c478bd9Sstevel@tonic-gate passwd->pw_shell = ""; 334*7c478bd9Sstevel@tonic-gate } 335*7c478bd9Sstevel@tonic-gate 336*7c478bd9Sstevel@tonic-gate passwd->pw_passwd = p = gettok(&next); /* password */ 337*7c478bd9Sstevel@tonic-gate if (p == 0) { 338*7c478bd9Sstevel@tonic-gate if (black_magic) 339*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 340*7c478bd9Sstevel@tonic-gate else 341*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 342*7c478bd9Sstevel@tonic-gate } 343*7c478bd9Sstevel@tonic-gate for (; *p != '\0'; p++) { /* age */ 344*7c478bd9Sstevel@tonic-gate if (*p == ',') { 345*7c478bd9Sstevel@tonic-gate *p++ = '\0'; 346*7c478bd9Sstevel@tonic-gate break; 347*7c478bd9Sstevel@tonic-gate } 348*7c478bd9Sstevel@tonic-gate } 349*7c478bd9Sstevel@tonic-gate passwd->pw_age = p; 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate p = next; /* uid */ 352*7c478bd9Sstevel@tonic-gate if (p == 0 || *p == '\0') { 353*7c478bd9Sstevel@tonic-gate if (black_magic) 354*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 355*7c478bd9Sstevel@tonic-gate else 356*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 357*7c478bd9Sstevel@tonic-gate } 358*7c478bd9Sstevel@tonic-gate if (!black_magic) { 359*7c478bd9Sstevel@tonic-gate passwd->pw_uid = strtol(p, &next, 10); 360*7c478bd9Sstevel@tonic-gate if (next == p) { 361*7c478bd9Sstevel@tonic-gate /* uid field should be nonempty */ 362*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 363*7c478bd9Sstevel@tonic-gate } 364*7c478bd9Sstevel@tonic-gate /* 365*7c478bd9Sstevel@tonic-gate * The old code (in 2.0 thru 2.5) would check 366*7c478bd9Sstevel@tonic-gate * for the uid being negative, or being greater 367*7c478bd9Sstevel@tonic-gate * than 60001 (the rfs limit). If it met either of 368*7c478bd9Sstevel@tonic-gate * these conditions, the uid was translated to 60001. 369*7c478bd9Sstevel@tonic-gate * 370*7c478bd9Sstevel@tonic-gate * Now we just check for negative uids; anything else 371*7c478bd9Sstevel@tonic-gate * is administrative policy 372*7c478bd9Sstevel@tonic-gate */ 373*7c478bd9Sstevel@tonic-gate if (passwd->pw_uid < 0) 374*7c478bd9Sstevel@tonic-gate passwd->pw_uid = UID_NOBODY; 375*7c478bd9Sstevel@tonic-gate } 376*7c478bd9Sstevel@tonic-gate if (*next++ != ':') { 377*7c478bd9Sstevel@tonic-gate if (black_magic) 378*7c478bd9Sstevel@tonic-gate p = gettok(&next); 379*7c478bd9Sstevel@tonic-gate else 380*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 381*7c478bd9Sstevel@tonic-gate } 382*7c478bd9Sstevel@tonic-gate p = next; /* gid */ 383*7c478bd9Sstevel@tonic-gate if (p == 0 || *p == '\0') { 384*7c478bd9Sstevel@tonic-gate if (black_magic) 385*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 386*7c478bd9Sstevel@tonic-gate else 387*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 388*7c478bd9Sstevel@tonic-gate } 389*7c478bd9Sstevel@tonic-gate if (!black_magic) { 390*7c478bd9Sstevel@tonic-gate passwd->pw_gid = strtol(p, &next, 10); 391*7c478bd9Sstevel@tonic-gate if (next == p) { 392*7c478bd9Sstevel@tonic-gate /* gid field should be nonempty */ 393*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 394*7c478bd9Sstevel@tonic-gate } 395*7c478bd9Sstevel@tonic-gate /* 396*7c478bd9Sstevel@tonic-gate * gid should be non-negative; anything else 397*7c478bd9Sstevel@tonic-gate * is administrative policy. 398*7c478bd9Sstevel@tonic-gate */ 399*7c478bd9Sstevel@tonic-gate if (passwd->pw_gid < 0) 400*7c478bd9Sstevel@tonic-gate passwd->pw_gid = GID_NOBODY; 401*7c478bd9Sstevel@tonic-gate } 402*7c478bd9Sstevel@tonic-gate if (*next++ != ':') { 403*7c478bd9Sstevel@tonic-gate if (black_magic) 404*7c478bd9Sstevel@tonic-gate p = gettok(&next); 405*7c478bd9Sstevel@tonic-gate else 406*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 407*7c478bd9Sstevel@tonic-gate } 408*7c478bd9Sstevel@tonic-gate 409*7c478bd9Sstevel@tonic-gate passwd->pw_gecos = passwd->pw_comment = p = gettok(&next); 410*7c478bd9Sstevel@tonic-gate if (p == 0) { 411*7c478bd9Sstevel@tonic-gate if (black_magic) 412*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 413*7c478bd9Sstevel@tonic-gate else 414*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 415*7c478bd9Sstevel@tonic-gate } 416*7c478bd9Sstevel@tonic-gate 417*7c478bd9Sstevel@tonic-gate passwd->pw_dir = p = gettok(&next); 418*7c478bd9Sstevel@tonic-gate if (p == 0) { 419*7c478bd9Sstevel@tonic-gate if (black_magic) 420*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 421*7c478bd9Sstevel@tonic-gate else 422*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 423*7c478bd9Sstevel@tonic-gate } 424*7c478bd9Sstevel@tonic-gate 425*7c478bd9Sstevel@tonic-gate passwd->pw_shell = p = gettok(&next); 426*7c478bd9Sstevel@tonic-gate if (p == 0) { 427*7c478bd9Sstevel@tonic-gate if (black_magic) 428*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 429*7c478bd9Sstevel@tonic-gate else 430*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 431*7c478bd9Sstevel@tonic-gate } 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate /* Better not be any more fields... */ 434*7c478bd9Sstevel@tonic-gate if (next == 0) { 435*7c478bd9Sstevel@tonic-gate /* Successfully parsed and stored */ 436*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 437*7c478bd9Sstevel@tonic-gate } 438*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 439*7c478bd9Sstevel@tonic-gate } 440*7c478bd9Sstevel@tonic-gate 441*7c478bd9Sstevel@tonic-gate typedef const char *constp; 442*7c478bd9Sstevel@tonic-gate 443*7c478bd9Sstevel@tonic-gate /* 444*7c478bd9Sstevel@tonic-gate * Return value 1 means success and more input, 0 means error or no more 445*7c478bd9Sstevel@tonic-gate */ 446*7c478bd9Sstevel@tonic-gate static int 447*7c478bd9Sstevel@tonic-gate getfield(nextp, limit, uns, valp) 448*7c478bd9Sstevel@tonic-gate constp *nextp; 449*7c478bd9Sstevel@tonic-gate constp limit; 450*7c478bd9Sstevel@tonic-gate int uns; 451*7c478bd9Sstevel@tonic-gate void *valp; 452*7c478bd9Sstevel@tonic-gate { 453*7c478bd9Sstevel@tonic-gate constp p = *nextp; 454*7c478bd9Sstevel@tonic-gate char *endfield; 455*7c478bd9Sstevel@tonic-gate char numbuf[12]; /* Holds -2^31 and trailing ':' */ 456*7c478bd9Sstevel@tonic-gate int len; 457*7c478bd9Sstevel@tonic-gate long x; 458*7c478bd9Sstevel@tonic-gate unsigned long ux; 459*7c478bd9Sstevel@tonic-gate 460*7c478bd9Sstevel@tonic-gate if (p == 0 || p >= limit) { 461*7c478bd9Sstevel@tonic-gate return (0); 462*7c478bd9Sstevel@tonic-gate } 463*7c478bd9Sstevel@tonic-gate if (*p == ':') { 464*7c478bd9Sstevel@tonic-gate p++; 465*7c478bd9Sstevel@tonic-gate *nextp = p; 466*7c478bd9Sstevel@tonic-gate return (p < limit); 467*7c478bd9Sstevel@tonic-gate } 468*7c478bd9Sstevel@tonic-gate if ((len = limit - p) > sizeof (numbuf) - 1) { 469*7c478bd9Sstevel@tonic-gate len = sizeof (numbuf) - 1; 470*7c478bd9Sstevel@tonic-gate } 471*7c478bd9Sstevel@tonic-gate /* 472*7c478bd9Sstevel@tonic-gate * We want to use strtol() and we have a readonly non-zero-terminated 473*7c478bd9Sstevel@tonic-gate * string, so first we copy and terminate the interesting bit. 474*7c478bd9Sstevel@tonic-gate * Ugh. (It's convenient to terminate with a colon rather than \0). 475*7c478bd9Sstevel@tonic-gate */ 476*7c478bd9Sstevel@tonic-gate if ((endfield = memccpy(numbuf, p, ':', len)) == 0) { 477*7c478bd9Sstevel@tonic-gate if (len != limit - p) { 478*7c478bd9Sstevel@tonic-gate /* Error -- field is too big to be a legit number */ 479*7c478bd9Sstevel@tonic-gate return (0); 480*7c478bd9Sstevel@tonic-gate } 481*7c478bd9Sstevel@tonic-gate numbuf[len] = ':'; 482*7c478bd9Sstevel@tonic-gate p = limit; 483*7c478bd9Sstevel@tonic-gate } else { 484*7c478bd9Sstevel@tonic-gate p += (endfield - numbuf); 485*7c478bd9Sstevel@tonic-gate } 486*7c478bd9Sstevel@tonic-gate if (uns) { 487*7c478bd9Sstevel@tonic-gate ux = strtoul(numbuf, &endfield, 10); 488*7c478bd9Sstevel@tonic-gate if (*endfield != ':') { 489*7c478bd9Sstevel@tonic-gate /* Error -- expected <integer><colon> */ 490*7c478bd9Sstevel@tonic-gate return (0); 491*7c478bd9Sstevel@tonic-gate } 492*7c478bd9Sstevel@tonic-gate *((unsigned int *)valp) = (unsigned int)ux; 493*7c478bd9Sstevel@tonic-gate } else { 494*7c478bd9Sstevel@tonic-gate x = strtol(numbuf, &endfield, 10); 495*7c478bd9Sstevel@tonic-gate if (*endfield != ':') { 496*7c478bd9Sstevel@tonic-gate /* Error -- expected <integer><colon> */ 497*7c478bd9Sstevel@tonic-gate return (0); 498*7c478bd9Sstevel@tonic-gate } 499*7c478bd9Sstevel@tonic-gate *((int *)valp) = (int)x; 500*7c478bd9Sstevel@tonic-gate } 501*7c478bd9Sstevel@tonic-gate *nextp = p; 502*7c478bd9Sstevel@tonic-gate return (p < limit); 503*7c478bd9Sstevel@tonic-gate } 504*7c478bd9Sstevel@tonic-gate 505*7c478bd9Sstevel@tonic-gate /* 506*7c478bd9Sstevel@tonic-gate * str2spwd() -- convert a string to a shadow passwd entry. The parser is 507*7c478bd9Sstevel@tonic-gate * more liberal than the passwd or group parsers; since it's legitimate 508*7c478bd9Sstevel@tonic-gate * for almost all the fields here to be blank, the parser lets one omit 509*7c478bd9Sstevel@tonic-gate * any number of blank fields at the end of the entry. The acceptable 510*7c478bd9Sstevel@tonic-gate * forms for '+' and '-' entries are the same as those for normal entries. 511*7c478bd9Sstevel@tonic-gate * === Is this likely to do more harm than good? 512*7c478bd9Sstevel@tonic-gate * 513*7c478bd9Sstevel@tonic-gate * Return values: 0 = success, 1 = parse error, 2 = erange ... 514*7c478bd9Sstevel@tonic-gate * The structure pointer passed in is a structure in the caller's space 515*7c478bd9Sstevel@tonic-gate * wherein the field pointers would be set to areas in the buffer if 516*7c478bd9Sstevel@tonic-gate * need be. instring and buffer should be separate areas. 517*7c478bd9Sstevel@tonic-gate */ 518*7c478bd9Sstevel@tonic-gate int 519*7c478bd9Sstevel@tonic-gate str2spwd(instr, lenstr, ent, buffer, buflen) 520*7c478bd9Sstevel@tonic-gate const char *instr; 521*7c478bd9Sstevel@tonic-gate int lenstr; 522*7c478bd9Sstevel@tonic-gate void *ent; /* really (struct spwd *) */ 523*7c478bd9Sstevel@tonic-gate char *buffer; 524*7c478bd9Sstevel@tonic-gate int buflen; 525*7c478bd9Sstevel@tonic-gate { 526*7c478bd9Sstevel@tonic-gate struct spwd *shadow = (struct spwd *)ent; 527*7c478bd9Sstevel@tonic-gate const char *p = instr, *limit; 528*7c478bd9Sstevel@tonic-gate char *bufp; 529*7c478bd9Sstevel@tonic-gate int lencopy, black_magic; 530*7c478bd9Sstevel@tonic-gate 531*7c478bd9Sstevel@tonic-gate limit = p + lenstr; 532*7c478bd9Sstevel@tonic-gate if ((p = memchr(instr, ':', lenstr)) == 0 || 533*7c478bd9Sstevel@tonic-gate ++p >= limit || 534*7c478bd9Sstevel@tonic-gate (p = memchr(p, ':', limit - p)) == 0) { 535*7c478bd9Sstevel@tonic-gate lencopy = lenstr; 536*7c478bd9Sstevel@tonic-gate p = 0; 537*7c478bd9Sstevel@tonic-gate } else { 538*7c478bd9Sstevel@tonic-gate lencopy = p - instr; 539*7c478bd9Sstevel@tonic-gate p++; 540*7c478bd9Sstevel@tonic-gate } 541*7c478bd9Sstevel@tonic-gate if (lencopy + 1 > buflen) { 542*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_ERANGE); 543*7c478bd9Sstevel@tonic-gate } 544*7c478bd9Sstevel@tonic-gate (void) memcpy(buffer, instr, lencopy); 545*7c478bd9Sstevel@tonic-gate buffer[lencopy] = 0; 546*7c478bd9Sstevel@tonic-gate 547*7c478bd9Sstevel@tonic-gate black_magic = (*instr == '+' || *instr == '-'); 548*7c478bd9Sstevel@tonic-gate shadow->sp_namp = bufp = buffer; 549*7c478bd9Sstevel@tonic-gate shadow->sp_pwdp = 0; 550*7c478bd9Sstevel@tonic-gate shadow->sp_lstchg = -1; 551*7c478bd9Sstevel@tonic-gate shadow->sp_min = -1; 552*7c478bd9Sstevel@tonic-gate shadow->sp_max = -1; 553*7c478bd9Sstevel@tonic-gate shadow->sp_warn = -1; 554*7c478bd9Sstevel@tonic-gate shadow->sp_inact = -1; 555*7c478bd9Sstevel@tonic-gate shadow->sp_expire = -1; 556*7c478bd9Sstevel@tonic-gate shadow->sp_flag = 0; 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate if ((bufp = strchr(bufp, ':')) == 0) { 559*7c478bd9Sstevel@tonic-gate if (black_magic) 560*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 561*7c478bd9Sstevel@tonic-gate else 562*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 563*7c478bd9Sstevel@tonic-gate } 564*7c478bd9Sstevel@tonic-gate *bufp++ = '\0'; 565*7c478bd9Sstevel@tonic-gate 566*7c478bd9Sstevel@tonic-gate shadow->sp_pwdp = bufp; 567*7c478bd9Sstevel@tonic-gate if (instr == 0) { 568*7c478bd9Sstevel@tonic-gate if ((bufp = strchr(bufp, ':')) == 0) { 569*7c478bd9Sstevel@tonic-gate if (black_magic) 570*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 571*7c478bd9Sstevel@tonic-gate else 572*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 573*7c478bd9Sstevel@tonic-gate } 574*7c478bd9Sstevel@tonic-gate *bufp++ = '\0'; 575*7c478bd9Sstevel@tonic-gate p = bufp; 576*7c478bd9Sstevel@tonic-gate } /* else p was set when we copied name and passwd into the buffer */ 577*7c478bd9Sstevel@tonic-gate 578*7c478bd9Sstevel@tonic-gate if (!getfield(&p, limit, 0, &shadow->sp_lstchg)) 579*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 580*7c478bd9Sstevel@tonic-gate if (!getfield(&p, limit, 0, &shadow->sp_min)) 581*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 582*7c478bd9Sstevel@tonic-gate if (!getfield(&p, limit, 0, &shadow->sp_max)) 583*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 584*7c478bd9Sstevel@tonic-gate if (!getfield(&p, limit, 0, &shadow->sp_warn)) 585*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 586*7c478bd9Sstevel@tonic-gate if (!getfield(&p, limit, 0, &shadow->sp_inact)) 587*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 588*7c478bd9Sstevel@tonic-gate if (!getfield(&p, limit, 0, &shadow->sp_expire)) 589*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 590*7c478bd9Sstevel@tonic-gate if (!getfield(&p, limit, 1, &shadow->sp_flag)) 591*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 592*7c478bd9Sstevel@tonic-gate if (p != limit) { 593*7c478bd9Sstevel@tonic-gate /* Syntax error -- garbage at end of line */ 594*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE); 595*7c478bd9Sstevel@tonic-gate } 596*7c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS); 597*7c478bd9Sstevel@tonic-gate } 598*7c478bd9Sstevel@tonic-gate 599*7c478bd9Sstevel@tonic-gate static nss_XbyY_buf_t *buffer; 600*7c478bd9Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root); 601*7c478bd9Sstevel@tonic-gate 602*7c478bd9Sstevel@tonic-gate #define GETBUF() \ 603*7c478bd9Sstevel@tonic-gate NSS_XbyY_ALLOC(&buffer, sizeof (struct passwd), NSS_BUFLEN_PASSWD) 604*7c478bd9Sstevel@tonic-gate 605*7c478bd9Sstevel@tonic-gate #pragma fini(endutilpwent) 606*7c478bd9Sstevel@tonic-gate 607*7c478bd9Sstevel@tonic-gate static void 608*7c478bd9Sstevel@tonic-gate endutilpwent(void) 609*7c478bd9Sstevel@tonic-gate { 610*7c478bd9Sstevel@tonic-gate NSS_XbyY_FREE(&buffer); 611*7c478bd9Sstevel@tonic-gate nss_delete(&db_root); 612*7c478bd9Sstevel@tonic-gate } 613*7c478bd9Sstevel@tonic-gate 614*7c478bd9Sstevel@tonic-gate struct passwd * 615*7c478bd9Sstevel@tonic-gate getpwnam_from(const char *name, pwu_repository_t *rep, int reptype) 616*7c478bd9Sstevel@tonic-gate { 617*7c478bd9Sstevel@tonic-gate nss_XbyY_buf_t *b = GETBUF(); 618*7c478bd9Sstevel@tonic-gate nss_XbyY_args_t arg; 619*7c478bd9Sstevel@tonic-gate 620*7c478bd9Sstevel@tonic-gate if (b == 0) 621*7c478bd9Sstevel@tonic-gate return (0); 622*7c478bd9Sstevel@tonic-gate 623*7c478bd9Sstevel@tonic-gate NSS_XbyY_INIT(&arg, b->result, b->buffer, b->buflen, str2passwd); 624*7c478bd9Sstevel@tonic-gate arg.key.name = name; 625*7c478bd9Sstevel@tonic-gate 626*7c478bd9Sstevel@tonic-gate switch (reptype) { 627*7c478bd9Sstevel@tonic-gate case REP_LDAP: 628*7c478bd9Sstevel@tonic-gate (void) nss_search(&db_root, nss_ldap_passwd, 629*7c478bd9Sstevel@tonic-gate NSS_DBOP_PASSWD_BYNAME, &arg); 630*7c478bd9Sstevel@tonic-gate break; 631*7c478bd9Sstevel@tonic-gate case REP_NISPLUS: 632*7c478bd9Sstevel@tonic-gate if (rep && rep->scope) 633*7c478bd9Sstevel@tonic-gate return (nisplus_getpw_from_master(name, rep->scope)); 634*7c478bd9Sstevel@tonic-gate 635*7c478bd9Sstevel@tonic-gate (void) nss_search(&db_root, nss_nisplus_passwd, 636*7c478bd9Sstevel@tonic-gate NSS_DBOP_PASSWD_BYNAME, &arg); 637*7c478bd9Sstevel@tonic-gate break; 638*7c478bd9Sstevel@tonic-gate #ifdef PAM_NIS 639*7c478bd9Sstevel@tonic-gate case REP_NIS: 640*7c478bd9Sstevel@tonic-gate (void) nss_search(&db_root, nss_nis_passwd, 641*7c478bd9Sstevel@tonic-gate NSS_DBOP_PASSWD_BYNAME, &arg); 642*7c478bd9Sstevel@tonic-gate break; 643*7c478bd9Sstevel@tonic-gate #endif 644*7c478bd9Sstevel@tonic-gate default: 645*7c478bd9Sstevel@tonic-gate return (NULL); 646*7c478bd9Sstevel@tonic-gate } 647*7c478bd9Sstevel@tonic-gate 648*7c478bd9Sstevel@tonic-gate return (struct passwd *)NSS_XbyY_FINI(&arg); 649*7c478bd9Sstevel@tonic-gate } 650*7c478bd9Sstevel@tonic-gate 651*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 652*7c478bd9Sstevel@tonic-gate struct passwd * 653*7c478bd9Sstevel@tonic-gate getpwuid_from(uid_t uid, pwu_repository_t *rep, int reptype) 654*7c478bd9Sstevel@tonic-gate { 655*7c478bd9Sstevel@tonic-gate nss_XbyY_buf_t *b = GETBUF(); 656*7c478bd9Sstevel@tonic-gate nss_XbyY_args_t arg; 657*7c478bd9Sstevel@tonic-gate 658*7c478bd9Sstevel@tonic-gate if (b == 0) 659*7c478bd9Sstevel@tonic-gate return (0); 660*7c478bd9Sstevel@tonic-gate 661*7c478bd9Sstevel@tonic-gate NSS_XbyY_INIT(&arg, b->result, b->buffer, b->buflen, str2passwd); 662*7c478bd9Sstevel@tonic-gate arg.key.uid = uid; 663*7c478bd9Sstevel@tonic-gate 664*7c478bd9Sstevel@tonic-gate switch (reptype) { 665*7c478bd9Sstevel@tonic-gate case REP_LDAP: 666*7c478bd9Sstevel@tonic-gate (void) nss_search(&db_root, nss_ldap_passwd, 667*7c478bd9Sstevel@tonic-gate NSS_DBOP_PASSWD_BYUID, &arg); 668*7c478bd9Sstevel@tonic-gate break; 669*7c478bd9Sstevel@tonic-gate case REP_NISPLUS: 670*7c478bd9Sstevel@tonic-gate (void) nss_search(&db_root, nss_nisplus_passwd, 671*7c478bd9Sstevel@tonic-gate NSS_DBOP_PASSWD_BYUID, &arg); 672*7c478bd9Sstevel@tonic-gate break; 673*7c478bd9Sstevel@tonic-gate #ifdef PAM_NIS 674*7c478bd9Sstevel@tonic-gate case REP_NIS: 675*7c478bd9Sstevel@tonic-gate (void) nss_search(&db_root, nss_nis_passwd, 676*7c478bd9Sstevel@tonic-gate NSS_DBOP_PASSWD_BYUID, &arg); 677*7c478bd9Sstevel@tonic-gate break; 678*7c478bd9Sstevel@tonic-gate #endif 679*7c478bd9Sstevel@tonic-gate default: 680*7c478bd9Sstevel@tonic-gate return (NULL); 681*7c478bd9Sstevel@tonic-gate } 682*7c478bd9Sstevel@tonic-gate 683*7c478bd9Sstevel@tonic-gate return (struct passwd *)NSS_XbyY_FINI(&arg); 684*7c478bd9Sstevel@tonic-gate } 685*7c478bd9Sstevel@tonic-gate 686*7c478bd9Sstevel@tonic-gate static nss_XbyY_buf_t *spbuf; 687*7c478bd9Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(spdb_root); 688*7c478bd9Sstevel@tonic-gate 689*7c478bd9Sstevel@tonic-gate #define GETSPBUF() \ 690*7c478bd9Sstevel@tonic-gate NSS_XbyY_ALLOC(&spbuf, sizeof (struct spwd), NSS_BUFLEN_SHADOW) 691*7c478bd9Sstevel@tonic-gate 692*7c478bd9Sstevel@tonic-gate #pragma fini(endutilspent) 693*7c478bd9Sstevel@tonic-gate 694*7c478bd9Sstevel@tonic-gate static void 695*7c478bd9Sstevel@tonic-gate endutilspent(void) 696*7c478bd9Sstevel@tonic-gate { 697*7c478bd9Sstevel@tonic-gate NSS_XbyY_FREE(&spbuf); 698*7c478bd9Sstevel@tonic-gate nss_delete(&spdb_root); 699*7c478bd9Sstevel@tonic-gate } 700*7c478bd9Sstevel@tonic-gate 701*7c478bd9Sstevel@tonic-gate struct spwd * 702*7c478bd9Sstevel@tonic-gate getspnam_from(const char *name, pwu_repository_t *rep, int reptype) 703*7c478bd9Sstevel@tonic-gate { 704*7c478bd9Sstevel@tonic-gate nss_XbyY_buf_t *b = GETSPBUF(); 705*7c478bd9Sstevel@tonic-gate nss_XbyY_args_t arg; 706*7c478bd9Sstevel@tonic-gate 707*7c478bd9Sstevel@tonic-gate if (b == 0) 708*7c478bd9Sstevel@tonic-gate return (0); 709*7c478bd9Sstevel@tonic-gate 710*7c478bd9Sstevel@tonic-gate NSS_XbyY_INIT(&arg, b->result, b->buffer, b->buflen, str2spwd); 711*7c478bd9Sstevel@tonic-gate arg.key.name = name; 712*7c478bd9Sstevel@tonic-gate switch (reptype) { 713*7c478bd9Sstevel@tonic-gate case REP_LDAP: 714*7c478bd9Sstevel@tonic-gate (void) nss_search(&spdb_root, nss_ldap_shadow, 715*7c478bd9Sstevel@tonic-gate NSS_DBOP_SHADOW_BYNAME, &arg); 716*7c478bd9Sstevel@tonic-gate break; 717*7c478bd9Sstevel@tonic-gate case REP_NISPLUS: 718*7c478bd9Sstevel@tonic-gate if (rep && rep->scope) 719*7c478bd9Sstevel@tonic-gate return (nisplus_getsp_from_master(name, rep->scope)); 720*7c478bd9Sstevel@tonic-gate 721*7c478bd9Sstevel@tonic-gate (void) nss_search(&spdb_root, nss_nisplus_shadow, 722*7c478bd9Sstevel@tonic-gate NSS_DBOP_SHADOW_BYNAME, &arg); 723*7c478bd9Sstevel@tonic-gate break; 724*7c478bd9Sstevel@tonic-gate #ifdef PAM_NIS 725*7c478bd9Sstevel@tonic-gate case REP_NIS: 726*7c478bd9Sstevel@tonic-gate (void) nss_search(&spdb_root, nss_nis_shadow, 727*7c478bd9Sstevel@tonic-gate NSS_DBOP_SHADOW_BYNAME, &arg); 728*7c478bd9Sstevel@tonic-gate break; 729*7c478bd9Sstevel@tonic-gate #endif 730*7c478bd9Sstevel@tonic-gate default: 731*7c478bd9Sstevel@tonic-gate return (NULL); 732*7c478bd9Sstevel@tonic-gate } 733*7c478bd9Sstevel@tonic-gate return (struct spwd *)NSS_XbyY_FINI(&arg); 734*7c478bd9Sstevel@tonic-gate } 735*7c478bd9Sstevel@tonic-gate 736*7c478bd9Sstevel@tonic-gate 737*7c478bd9Sstevel@tonic-gate static nis_result * 738*7c478bd9Sstevel@tonic-gate nisplus_match(const char *name, char *domain, char *buf, int len) 739*7c478bd9Sstevel@tonic-gate { 740*7c478bd9Sstevel@tonic-gate int n; 741*7c478bd9Sstevel@tonic-gate int flags; 742*7c478bd9Sstevel@tonic-gate nis_result *res; 743*7c478bd9Sstevel@tonic-gate nis_object *object; 744*7c478bd9Sstevel@tonic-gate 745*7c478bd9Sstevel@tonic-gate n = snprintf(buf, len, "[name=%s],passwd.org_dir.%s", name, domain); 746*7c478bd9Sstevel@tonic-gate if (n >= len) { 747*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "nisplus_match: name too long"); 748*7c478bd9Sstevel@tonic-gate return (NULL); 749*7c478bd9Sstevel@tonic-gate } 750*7c478bd9Sstevel@tonic-gate if (buf[n-1] != '.') { 751*7c478bd9Sstevel@tonic-gate if (n == len-1) { 752*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "nisplus_match: name too long"); 753*7c478bd9Sstevel@tonic-gate return (NULL); 754*7c478bd9Sstevel@tonic-gate } 755*7c478bd9Sstevel@tonic-gate buf[n++] = '.'; 756*7c478bd9Sstevel@tonic-gate buf[n] = '\0'; 757*7c478bd9Sstevel@tonic-gate } 758*7c478bd9Sstevel@tonic-gate 759*7c478bd9Sstevel@tonic-gate flags = USE_DGRAM | FOLLOW_LINKS | FOLLOW_PATH | MASTER_ONLY; 760*7c478bd9Sstevel@tonic-gate 761*7c478bd9Sstevel@tonic-gate res = nis_list(buf, flags, NULL, NULL); 762*7c478bd9Sstevel@tonic-gate 763*7c478bd9Sstevel@tonic-gate if (res == NULL) { 764*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "nisplus_match: nis_list returned NULL"); 765*7c478bd9Sstevel@tonic-gate return (NULL); 766*7c478bd9Sstevel@tonic-gate } 767*7c478bd9Sstevel@tonic-gate 768*7c478bd9Sstevel@tonic-gate if (NIS_RES_STATUS(res) != NIS_SUCCESS || NIS_RES_NUMOBJ(res) != 1) { 769*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "nisplus_match: match failed: %s", 770*7c478bd9Sstevel@tonic-gate nis_sperrno(NIS_RES_STATUS(res))); 771*7c478bd9Sstevel@tonic-gate nis_freeresult(res); 772*7c478bd9Sstevel@tonic-gate return (NULL); 773*7c478bd9Sstevel@tonic-gate } 774*7c478bd9Sstevel@tonic-gate 775*7c478bd9Sstevel@tonic-gate object = NIS_RES_OBJECT(res); 776*7c478bd9Sstevel@tonic-gate 777*7c478bd9Sstevel@tonic-gate if (object->EN_data.en_cols.en_cols_len < 8) { 778*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "nisplus_match: " 779*7c478bd9Sstevel@tonic-gate "not a valid passwd table entry for user %s", name); 780*7c478bd9Sstevel@tonic-gate nis_freeresult(res); 781*7c478bd9Sstevel@tonic-gate return (NULL); 782*7c478bd9Sstevel@tonic-gate } 783*7c478bd9Sstevel@tonic-gate 784*7c478bd9Sstevel@tonic-gate return (res); 785*7c478bd9Sstevel@tonic-gate } 786*7c478bd9Sstevel@tonic-gate 787*7c478bd9Sstevel@tonic-gate #define SAFE_STRDUP(dst, idx) \ 788*7c478bd9Sstevel@tonic-gate if ((idx) <= 3 && ENTRY_VAL(nret, (idx)) == NULL) { \ 789*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, \ 790*7c478bd9Sstevel@tonic-gate "passwdutil: missing field from password entry"); \ 791*7c478bd9Sstevel@tonic-gate goto error; \ 792*7c478bd9Sstevel@tonic-gate } \ 793*7c478bd9Sstevel@tonic-gate len = ENTRY_LEN(nret, (idx)); \ 794*7c478bd9Sstevel@tonic-gate (dst) = malloc(len+1); \ 795*7c478bd9Sstevel@tonic-gate if ((dst) == NULL) { \ 796*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "passwdutil: out of memory"); \ 797*7c478bd9Sstevel@tonic-gate goto error; \ 798*7c478bd9Sstevel@tonic-gate } \ 799*7c478bd9Sstevel@tonic-gate (dst)[len] = '\0'; \ 800*7c478bd9Sstevel@tonic-gate (void) strncpy((dst), \ 801*7c478bd9Sstevel@tonic-gate ENTRY_VAL(nret, (idx)) ? ENTRY_VAL(nret, (idx)) : "", \ 802*7c478bd9Sstevel@tonic-gate len); 803*7c478bd9Sstevel@tonic-gate 804*7c478bd9Sstevel@tonic-gate 805*7c478bd9Sstevel@tonic-gate 806*7c478bd9Sstevel@tonic-gate static struct passwd * 807*7c478bd9Sstevel@tonic-gate nisplus_getpw_from_master(const char *name, char *domain) 808*7c478bd9Sstevel@tonic-gate { 809*7c478bd9Sstevel@tonic-gate char lookup[NIS_MAXNAMELEN+1]; 810*7c478bd9Sstevel@tonic-gate nis_result *res; 811*7c478bd9Sstevel@tonic-gate nis_object *nret; 812*7c478bd9Sstevel@tonic-gate int len; 813*7c478bd9Sstevel@tonic-gate char *p; 814*7c478bd9Sstevel@tonic-gate struct passwd *pw; 815*7c478bd9Sstevel@tonic-gate 816*7c478bd9Sstevel@tonic-gate if ((pw = calloc(1, sizeof (*pw))) == NULL) 817*7c478bd9Sstevel@tonic-gate return (NULL); 818*7c478bd9Sstevel@tonic-gate 819*7c478bd9Sstevel@tonic-gate res = nisplus_match(name, domain, lookup, sizeof (lookup)); 820*7c478bd9Sstevel@tonic-gate 821*7c478bd9Sstevel@tonic-gate if (res == NULL) 822*7c478bd9Sstevel@tonic-gate return (NULL); 823*7c478bd9Sstevel@tonic-gate 824*7c478bd9Sstevel@tonic-gate nret = NIS_RES_OBJECT(res); 825*7c478bd9Sstevel@tonic-gate 826*7c478bd9Sstevel@tonic-gate SAFE_STRDUP(pw->pw_name, 0); 827*7c478bd9Sstevel@tonic-gate 828*7c478bd9Sstevel@tonic-gate if ((pw->pw_passwd = strdup("x")) == NULL) { 829*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "passwdutil: out of memory"); 830*7c478bd9Sstevel@tonic-gate goto error; 831*7c478bd9Sstevel@tonic-gate } 832*7c478bd9Sstevel@tonic-gate 833*7c478bd9Sstevel@tonic-gate SAFE_STRDUP(p, 2); 834*7c478bd9Sstevel@tonic-gate pw->pw_uid = atoi(p); 835*7c478bd9Sstevel@tonic-gate free(p); 836*7c478bd9Sstevel@tonic-gate 837*7c478bd9Sstevel@tonic-gate SAFE_STRDUP(p, 3); 838*7c478bd9Sstevel@tonic-gate pw->pw_gid = atoi(p); 839*7c478bd9Sstevel@tonic-gate free(p); 840*7c478bd9Sstevel@tonic-gate 841*7c478bd9Sstevel@tonic-gate pw->pw_age = NULL; 842*7c478bd9Sstevel@tonic-gate pw->pw_comment = NULL; 843*7c478bd9Sstevel@tonic-gate 844*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ 845*7c478bd9Sstevel@tonic-gate SAFE_STRDUP(pw->pw_gecos, 4); 846*7c478bd9Sstevel@tonic-gate 847*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ 848*7c478bd9Sstevel@tonic-gate SAFE_STRDUP(pw->pw_dir, 5); 849*7c478bd9Sstevel@tonic-gate 850*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ 851*7c478bd9Sstevel@tonic-gate SAFE_STRDUP(pw->pw_shell, 6); 852*7c478bd9Sstevel@tonic-gate 853*7c478bd9Sstevel@tonic-gate nis_freeresult(res); 854*7c478bd9Sstevel@tonic-gate 855*7c478bd9Sstevel@tonic-gate return (pw); 856*7c478bd9Sstevel@tonic-gate 857*7c478bd9Sstevel@tonic-gate error: 858*7c478bd9Sstevel@tonic-gate nis_freeresult(res); 859*7c478bd9Sstevel@tonic-gate if (pw->pw_name) 860*7c478bd9Sstevel@tonic-gate free(pw->pw_name); 861*7c478bd9Sstevel@tonic-gate if (pw->pw_passwd) 862*7c478bd9Sstevel@tonic-gate free(pw->pw_passwd); 863*7c478bd9Sstevel@tonic-gate if (pw->pw_gecos) 864*7c478bd9Sstevel@tonic-gate free(pw->pw_gecos); 865*7c478bd9Sstevel@tonic-gate if (pw->pw_dir) 866*7c478bd9Sstevel@tonic-gate free(pw->pw_dir); 867*7c478bd9Sstevel@tonic-gate if (pw->pw_shell) 868*7c478bd9Sstevel@tonic-gate free(pw->pw_shell); 869*7c478bd9Sstevel@tonic-gate free(pw); 870*7c478bd9Sstevel@tonic-gate 871*7c478bd9Sstevel@tonic-gate return (NULL); 872*7c478bd9Sstevel@tonic-gate } 873*7c478bd9Sstevel@tonic-gate 874*7c478bd9Sstevel@tonic-gate /* 875*7c478bd9Sstevel@tonic-gate * struct spwd * nisplus_getsp_from_master() 876*7c478bd9Sstevel@tonic-gate * 877*7c478bd9Sstevel@tonic-gate * Get the shadow structure from a NIS+ master. 878*7c478bd9Sstevel@tonic-gate * This routine normally runs with EUID==0. This can cause trouble 879*7c478bd9Sstevel@tonic-gate * if the NIS+ tables are locked down so that only the owner can 880*7c478bd9Sstevel@tonic-gate * access the encrypted password. If we detect that scenario, we switch 881*7c478bd9Sstevel@tonic-gate * EUID to the owner of the record and refetch it. 882*7c478bd9Sstevel@tonic-gate */ 883*7c478bd9Sstevel@tonic-gate static struct spwd * 884*7c478bd9Sstevel@tonic-gate nisplus_getsp_from_master(const char *name, char *domain) 885*7c478bd9Sstevel@tonic-gate { 886*7c478bd9Sstevel@tonic-gate char lookup[NIS_MAXNAMELEN+1]; 887*7c478bd9Sstevel@tonic-gate nis_result *res = NULL; 888*7c478bd9Sstevel@tonic-gate nis_object *nret = NULL; 889*7c478bd9Sstevel@tonic-gate int len; 890*7c478bd9Sstevel@tonic-gate struct spwd *spw; 891*7c478bd9Sstevel@tonic-gate char *shadow = NULL; 892*7c478bd9Sstevel@tonic-gate const char *p = NULL; 893*7c478bd9Sstevel@tonic-gate const char *limit; 894*7c478bd9Sstevel@tonic-gate 895*7c478bd9Sstevel@tonic-gate res = nisplus_match(name, domain, lookup, sizeof (lookup)); 896*7c478bd9Sstevel@tonic-gate if (res == NULL) 897*7c478bd9Sstevel@tonic-gate return (NULL); 898*7c478bd9Sstevel@tonic-gate 899*7c478bd9Sstevel@tonic-gate nret = NIS_RES_OBJECT(res); 900*7c478bd9Sstevel@tonic-gate 901*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ 902*7c478bd9Sstevel@tonic-gate SAFE_STRDUP(shadow, 7); 903*7c478bd9Sstevel@tonic-gate 904*7c478bd9Sstevel@tonic-gate /* 905*7c478bd9Sstevel@tonic-gate * If we got "*NP*" as password, try again with EUID set to 906*7c478bd9Sstevel@tonic-gate * the UID of the record-owner. 907*7c478bd9Sstevel@tonic-gate */ 908*7c478bd9Sstevel@tonic-gate if (strncmp(shadow, "*NP*", 4) == 0) { 909*7c478bd9Sstevel@tonic-gate char *p; 910*7c478bd9Sstevel@tonic-gate uid_t owner_uid; 911*7c478bd9Sstevel@tonic-gate uid_t euid = geteuid(); 912*7c478bd9Sstevel@tonic-gate 913*7c478bd9Sstevel@tonic-gate SAFE_STRDUP(p, 2); /* record-owner field */ 914*7c478bd9Sstevel@tonic-gate owner_uid = atoi(p); 915*7c478bd9Sstevel@tonic-gate free(p); 916*7c478bd9Sstevel@tonic-gate 917*7c478bd9Sstevel@tonic-gate if (owner_uid != euid) { 918*7c478bd9Sstevel@tonic-gate /* re-obtain entry using owners EUID */ 919*7c478bd9Sstevel@tonic-gate free(shadow); 920*7c478bd9Sstevel@tonic-gate nis_freeresult(res); 921*7c478bd9Sstevel@tonic-gate 922*7c478bd9Sstevel@tonic-gate (void) seteuid(owner_uid); 923*7c478bd9Sstevel@tonic-gate res = nisplus_match(name, domain, lookup, 924*7c478bd9Sstevel@tonic-gate sizeof (lookup)); 925*7c478bd9Sstevel@tonic-gate (void) seteuid(euid); 926*7c478bd9Sstevel@tonic-gate 927*7c478bd9Sstevel@tonic-gate if (res == NULL) 928*7c478bd9Sstevel@tonic-gate return (NULL); 929*7c478bd9Sstevel@tonic-gate nret = NIS_RES_OBJECT(res); 930*7c478bd9Sstevel@tonic-gate 931*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ 932*7c478bd9Sstevel@tonic-gate SAFE_STRDUP(shadow, 7); 933*7c478bd9Sstevel@tonic-gate } 934*7c478bd9Sstevel@tonic-gate } 935*7c478bd9Sstevel@tonic-gate 936*7c478bd9Sstevel@tonic-gate if ((spw = calloc(1, sizeof (*spw))) == NULL) { 937*7c478bd9Sstevel@tonic-gate nis_freeresult(res); 938*7c478bd9Sstevel@tonic-gate return (NULL); 939*7c478bd9Sstevel@tonic-gate } 940*7c478bd9Sstevel@tonic-gate 941*7c478bd9Sstevel@tonic-gate SAFE_STRDUP(spw->sp_namp, 0); 942*7c478bd9Sstevel@tonic-gate SAFE_STRDUP(spw->sp_pwdp, 1); 943*7c478bd9Sstevel@tonic-gate 944*7c478bd9Sstevel@tonic-gate nis_freeresult(res); 945*7c478bd9Sstevel@tonic-gate 946*7c478bd9Sstevel@tonic-gate limit = shadow + strlen(shadow) + 1; 947*7c478bd9Sstevel@tonic-gate p = shadow; 948*7c478bd9Sstevel@tonic-gate 949*7c478bd9Sstevel@tonic-gate spw->sp_lstchg = -1; 950*7c478bd9Sstevel@tonic-gate spw->sp_min = -1; 951*7c478bd9Sstevel@tonic-gate spw->sp_max = -1; 952*7c478bd9Sstevel@tonic-gate spw->sp_warn = -1; 953*7c478bd9Sstevel@tonic-gate spw->sp_inact = -1; 954*7c478bd9Sstevel@tonic-gate spw->sp_expire = -1; 955*7c478bd9Sstevel@tonic-gate spw->sp_flag = 0; 956*7c478bd9Sstevel@tonic-gate 957*7c478bd9Sstevel@tonic-gate if (!getfield(&p, limit, 0, &spw->sp_lstchg)) 958*7c478bd9Sstevel@tonic-gate goto out; 959*7c478bd9Sstevel@tonic-gate 960*7c478bd9Sstevel@tonic-gate if (!getfield(&p, limit, 0, &spw->sp_min)) 961*7c478bd9Sstevel@tonic-gate goto out; 962*7c478bd9Sstevel@tonic-gate 963*7c478bd9Sstevel@tonic-gate if (!getfield(&p, limit, 0, &spw->sp_max)) 964*7c478bd9Sstevel@tonic-gate goto out; 965*7c478bd9Sstevel@tonic-gate 966*7c478bd9Sstevel@tonic-gate if (!getfield(&p, limit, 0, &spw->sp_warn)) 967*7c478bd9Sstevel@tonic-gate goto out; 968*7c478bd9Sstevel@tonic-gate 969*7c478bd9Sstevel@tonic-gate if (!getfield(&p, limit, 0, &spw->sp_inact)) 970*7c478bd9Sstevel@tonic-gate goto out; 971*7c478bd9Sstevel@tonic-gate 972*7c478bd9Sstevel@tonic-gate if (!getfield(&p, limit, 0, &spw->sp_expire)) 973*7c478bd9Sstevel@tonic-gate goto out; 974*7c478bd9Sstevel@tonic-gate 975*7c478bd9Sstevel@tonic-gate if (!getfield(&p, limit, 1, &spw->sp_flag)) 976*7c478bd9Sstevel@tonic-gate goto out; 977*7c478bd9Sstevel@tonic-gate 978*7c478bd9Sstevel@tonic-gate if (p != limit) { 979*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "passwdutil: garbage at end of record"); 980*7c478bd9Sstevel@tonic-gate goto error; 981*7c478bd9Sstevel@tonic-gate } 982*7c478bd9Sstevel@tonic-gate 983*7c478bd9Sstevel@tonic-gate out: 984*7c478bd9Sstevel@tonic-gate free(shadow); 985*7c478bd9Sstevel@tonic-gate return (spw); 986*7c478bd9Sstevel@tonic-gate 987*7c478bd9Sstevel@tonic-gate error: 988*7c478bd9Sstevel@tonic-gate if (spw->sp_namp) 989*7c478bd9Sstevel@tonic-gate free(spw->sp_namp); 990*7c478bd9Sstevel@tonic-gate if (spw->sp_pwdp) 991*7c478bd9Sstevel@tonic-gate free(spw->sp_pwdp); 992*7c478bd9Sstevel@tonic-gate free(spw); 993*7c478bd9Sstevel@tonic-gate if (shadow) 994*7c478bd9Sstevel@tonic-gate free(shadow); 995*7c478bd9Sstevel@tonic-gate return (NULL); 996*7c478bd9Sstevel@tonic-gate } 997