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