1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <errno.h> 31 #include <stdlib.h> 32 #include <pwd.h> 33 #include <shadow.h> 34 #include <string.h> 35 #include <stdlib.h> 36 #include <unistd.h> 37 #include <nss_dbdefs.h> 38 39 #include "passwdutil.h" 40 41 /* from files_attr.c */ 42 struct passwd *private_getpwnam_r(const char *name, struct passwd *result, 43 char *buffer, int buflen); 44 45 int nss_getattr(char *name, attrlist *item, pwu_repository_t *rep); 46 int nss_getpwnam(char *name, attrlist *items, pwu_repository_t *rep, 47 void **buf); 48 49 /* 50 * nss function pointer table, used by passwdutil_init to initialize 51 * the global Repository-OPerations table "rops" 52 */ 53 struct repops nss_repops = { 54 NULL, /* checkhistory */ 55 nss_getattr, 56 nss_getpwnam, 57 NULL, /* update */ 58 NULL, /* putpwnam */ 59 NULL, /* user_to_authenticate */ 60 NULL, /* lock */ 61 NULL /* unlock */ 62 }; 63 64 /* 65 * this structure defines the buffer used to keep state between 66 * get/update/put calls 67 */ 68 struct pwbuf { 69 struct passwd *pwd; 70 char *pwd_scratch; 71 struct spwd *spwd; 72 char *spwd_scratch; 73 char *rep_name; 74 }; 75 76 /* 77 * We should use sysconf, but there is no sysconf name for SHADOW 78 * so we use these from nss_dbdefs 79 */ 80 #define PWD_SCRATCH_SIZE NSS_LINELEN_PASSWD 81 #define SPW_SCRATCH_SIZE NSS_LINELEN_SHADOW 82 83 84 /* 85 * nss_getpwnam(name, items, rep, buf) 86 * 87 */ 88 /*ARGSUSED*/ 89 int 90 nss_getpwnam(char *name, attrlist *items, pwu_repository_t *rep, void **buf) 91 { 92 attrlist *p; 93 struct pwbuf *pwbuf; 94 int repositories = REP_ERANGE; /* changed if ATTR_REP_NAME is set */ 95 int err = PWU_SUCCESS; 96 97 *buf = calloc(1, sizeof (struct pwbuf)); 98 pwbuf = (struct pwbuf *)*buf; 99 100 /* 101 * determine which password structure (/etc/passwd or /etc/shadow) 102 * we need for the items we need to update 103 */ 104 for (p = items; p != NULL; p = p->next) { 105 switch (p->type) { 106 case ATTR_NAME: 107 case ATTR_UID: 108 case ATTR_GID: 109 case ATTR_AGE: 110 case ATTR_COMMENT: 111 case ATTR_GECOS: 112 case ATTR_HOMEDIR: 113 case ATTR_SHELL: 114 if (pwbuf->pwd == NULL) 115 pwbuf->pwd = (struct passwd *) 116 malloc(sizeof (struct passwd)); 117 if (pwbuf->pwd == NULL) { 118 errno = ENOMEM; 119 if (pwbuf->spwd) 120 free(pwbuf->spwd); 121 return (PWU_NOMEM); 122 } 123 break; 124 case ATTR_PASSWD: 125 case ATTR_PASSWD_SERVER_POLICY: 126 case ATTR_LSTCHG: 127 case ATTR_MIN: 128 case ATTR_MAX: 129 case ATTR_WARN: 130 case ATTR_INACT: 131 case ATTR_EXPIRE: 132 case ATTR_FLAG: 133 case ATTR_LOCK_ACCOUNT: 134 case ATTR_EXPIRE_PASSWORD: 135 case ATTR_FAILED_LOGINS: 136 if (pwbuf->spwd == NULL) 137 pwbuf->spwd = (struct spwd *) 138 malloc(sizeof (struct spwd)); 139 if (pwbuf->spwd == NULL) { 140 errno = ENOMEM; 141 if (pwbuf->pwd) 142 free(pwbuf->pwd); 143 return (PWU_NOMEM); 144 } 145 break; 146 case ATTR_REP_NAME: 147 /* get the compat names (REP_COMPAT_*) */ 148 repositories = get_ns(rep, PWU_READ); 149 break; 150 default: 151 /* 152 * Some other repository might have different values 153 * so we ignore those. 154 */ 155 break; 156 } 157 } 158 159 if (pwbuf->pwd) { 160 if ((pwbuf->pwd_scratch = malloc(PWD_SCRATCH_SIZE)) == NULL) { 161 err = PWU_NOMEM; 162 goto error; 163 } 164 if (getpwnam_r(name, pwbuf->pwd, pwbuf->pwd_scratch, 165 PWD_SCRATCH_SIZE) == NULL) { 166 err = PWU_NOT_FOUND; 167 goto error; 168 } 169 } 170 171 if (pwbuf->spwd) { 172 if ((pwbuf->spwd_scratch = malloc(SPW_SCRATCH_SIZE)) == NULL) { 173 err = PWU_NOMEM; 174 goto error; 175 } 176 if (getspnam_r(name, pwbuf->spwd, pwbuf->spwd_scratch, 177 SPW_SCRATCH_SIZE) == NULL) { 178 err = PWU_NOT_FOUND; 179 goto error; 180 } 181 } 182 183 /* pwbuf->rep_name tells us where the user in fact comes from */ 184 if (repositories != REP_ERANGE) { 185 struct passwd pwd; 186 char pwd_scratch[PWD_SCRATCH_SIZE]; 187 188 /* can we find the user locally? */ 189 if (private_getpwnam_r(name, &pwd, pwd_scratch, 190 PWD_SCRATCH_SIZE) != NULL) 191 pwbuf->rep_name = "files"; 192 else if (repositories & REP_COMPAT_NISPLUS) 193 pwbuf->rep_name = "nisplus"; 194 else if (repositories & REP_COMPAT_LDAP) 195 pwbuf->rep_name = "ldap"; 196 else if (repositories & REP_COMPAT_NIS) 197 pwbuf->rep_name = "nis"; 198 else 199 pwbuf->rep_name = "nss"; 200 } else 201 pwbuf->rep_name = "nss"; 202 203 return (PWU_SUCCESS); 204 error: 205 if (pwbuf->pwd) free(pwbuf->pwd); 206 if (pwbuf->pwd_scratch) free(pwbuf->pwd_scratch); 207 if (pwbuf->spwd) free(pwbuf->spwd); 208 if (pwbuf->spwd_scratch) free(pwbuf->spwd_scratch); 209 free(pwbuf); 210 *buf = NULL; 211 212 return (err); 213 } 214 215 216 /* 217 * nss_getattr(name, items, rep) 218 * 219 * Get attributes specified in list 'items' 220 */ 221 int 222 nss_getattr(char *name, attrlist *items, pwu_repository_t *rep) 223 { 224 struct pwbuf *pwbuf; 225 struct passwd *pw; 226 struct spwd *spw; 227 attrlist *w; 228 int res = 0; 229 230 res = nss_getpwnam(name, items, rep, (void **)&pwbuf); 231 if (res != PWU_SUCCESS) 232 return (res); 233 234 pw = pwbuf->pwd; 235 spw = pwbuf->spwd; 236 237 for (w = items; res == PWU_SUCCESS && w != NULL; w = w->next) { 238 switch (w->type) { 239 case ATTR_NAME: 240 if ((w->data.val_s = strdup(pw->pw_name)) == NULL) 241 res = PWU_NOMEM; 242 break; 243 case ATTR_COMMENT: 244 if ((w->data.val_s = strdup(pw->pw_comment)) == NULL) 245 res = PWU_NOMEM; 246 break; 247 case ATTR_GECOS: 248 if ((w->data.val_s = strdup(pw->pw_gecos)) == NULL) 249 res = PWU_NOMEM; 250 break; 251 case ATTR_HOMEDIR: 252 if ((w->data.val_s = strdup(pw->pw_dir)) == NULL) 253 res = PWU_NOMEM; 254 break; 255 case ATTR_SHELL: 256 if ((w->data.val_s = strdup(pw->pw_shell)) == NULL) 257 res = PWU_NOMEM; 258 break; 259 /* 260 * Nothing special needs to be done for 261 * server policy 262 */ 263 case ATTR_PASSWD: 264 case ATTR_PASSWD_SERVER_POLICY: 265 if ((w->data.val_s = strdup(spw->sp_pwdp)) == NULL) 266 res = PWU_NOMEM; 267 break; 268 case ATTR_AGE: 269 if ((w->data.val_s = strdup(pw->pw_age)) == NULL) 270 res = PWU_NOMEM; 271 break; 272 case ATTR_REP_NAME: 273 if ((w->data.val_s = strdup(pwbuf->rep_name)) == NULL) 274 res = PWU_NOMEM; 275 break; 276 277 /* integer values */ 278 case ATTR_UID: 279 w->data.val_i = pw->pw_uid; 280 break; 281 case ATTR_GID: 282 w->data.val_i = pw->pw_gid; 283 break; 284 case ATTR_LSTCHG: 285 w->data.val_i = spw->sp_lstchg; 286 break; 287 case ATTR_MIN: 288 w->data.val_i = spw->sp_min; 289 break; 290 case ATTR_MAX: 291 w->data.val_i = spw->sp_max; 292 break; 293 case ATTR_WARN: 294 w->data.val_i = spw->sp_warn; 295 break; 296 case ATTR_INACT: 297 w->data.val_i = spw->sp_inact; 298 break; 299 case ATTR_EXPIRE: 300 w->data.val_i = spw->sp_expire; 301 break; 302 case ATTR_FLAG: 303 w->data.val_i = spw->sp_flag; 304 break; 305 case ATTR_FAILED_LOGINS: 306 w->data.val_i = spw->sp_flag & FAILCOUNT_MASK; 307 break; 308 default: 309 break; 310 } 311 } 312 313 if (pwbuf->pwd) free(pwbuf->pwd); 314 if (pwbuf->pwd_scratch) free(pwbuf->pwd_scratch); 315 if (pwbuf->spwd) free(pwbuf->spwd); 316 if (pwbuf->spwd_scratch) free(pwbuf->spwd_scratch); 317 free(pwbuf); 318 319 return (res); 320 } 321