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