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