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 * Copyright 2024 OmniOS Community Edition (OmniOSce) Association. 25 */ 26 27 #include <sys/types.h> 28 #include <errno.h> 29 #include <stdlib.h> 30 #include <pwd.h> 31 #include <shadow.h> 32 #include <string.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <nss_dbdefs.h> 36 37 #include "passwdutil.h" 38 39 /* from files_attr.c */ 40 struct passwd *private_getpwnam_r(const char *name, struct passwd *result, 41 char *buffer, int buflen); 42 43 int nss_getattr(const char *name, attrlist *item, pwu_repository_t *rep); 44 int nss_getpwnam(const char *name, attrlist *items, pwu_repository_t *rep, 45 void **buf); 46 47 /* 48 * nss function pointer table, used by passwdutil_init to initialize 49 * the global Repository-OPerations table "rops" 50 */ 51 struct repops nss_repops = { 52 NULL, /* checkhistory */ 53 nss_getattr, 54 nss_getpwnam, 55 NULL, /* update */ 56 NULL, /* putpwnam */ 57 NULL, /* user_to_authenticate */ 58 NULL, /* lock */ 59 NULL /* unlock */ 60 }; 61 62 /* 63 * this structure defines the buffer used to keep state between 64 * get/update/put calls 65 */ 66 struct pwbuf { 67 struct passwd *pwd; 68 char *pwd_scratch; 69 struct spwd *spwd; 70 char *spwd_scratch; 71 char *rep_name; 72 }; 73 74 /* 75 * We should use sysconf, but there is no sysconf name for SHADOW 76 * so we use these from nss_dbdefs 77 */ 78 #define PWD_SCRATCH_SIZE NSS_LINELEN_PASSWD 79 #define SPW_SCRATCH_SIZE NSS_LINELEN_SHADOW 80 81 82 /* 83 * nss_getpwnam(name, items, rep, buf) 84 * 85 */ 86 /*ARGSUSED*/ 87 int 88 nss_getpwnam(const char *name, attrlist *items, pwu_repository_t *rep, 89 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_LDAP) 194 pwbuf->rep_name = "ldap"; 195 else if (repositories & REP_COMPAT_NIS) 196 pwbuf->rep_name = "nis"; 197 else 198 pwbuf->rep_name = "nss"; 199 } else 200 pwbuf->rep_name = "nss"; 201 202 return (PWU_SUCCESS); 203 error: 204 if (pwbuf->pwd) free(pwbuf->pwd); 205 if (pwbuf->pwd_scratch) free(pwbuf->pwd_scratch); 206 if (pwbuf->spwd) free(pwbuf->spwd); 207 if (pwbuf->spwd_scratch) free(pwbuf->spwd_scratch); 208 free(pwbuf); 209 *buf = NULL; 210 211 return (err); 212 } 213 214 215 /* 216 * nss_getattr(name, items, rep) 217 * 218 * Get attributes specified in list 'items' 219 */ 220 int 221 nss_getattr(const char *name, attrlist *items, pwu_repository_t *rep) 222 { 223 struct pwbuf *pwbuf; 224 struct passwd *pw; 225 struct spwd *spw; 226 attrlist *w; 227 int res = 0; 228 229 res = nss_getpwnam(name, items, rep, (void **)&pwbuf); 230 if (res != PWU_SUCCESS) 231 return (res); 232 233 pw = pwbuf->pwd; 234 spw = pwbuf->spwd; 235 236 for (w = items; res == PWU_SUCCESS && w != NULL; w = w->next) { 237 switch (w->type) { 238 case ATTR_NAME: 239 if ((w->data.val_s = strdup(pw->pw_name)) == NULL) 240 res = PWU_NOMEM; 241 break; 242 case ATTR_COMMENT: 243 if ((w->data.val_s = strdup(pw->pw_comment)) == NULL) 244 res = PWU_NOMEM; 245 break; 246 case ATTR_GECOS: 247 if ((w->data.val_s = strdup(pw->pw_gecos)) == NULL) 248 res = PWU_NOMEM; 249 break; 250 case ATTR_HOMEDIR: 251 if ((w->data.val_s = strdup(pw->pw_dir)) == NULL) 252 res = PWU_NOMEM; 253 break; 254 case ATTR_SHELL: 255 if ((w->data.val_s = strdup(pw->pw_shell)) == NULL) 256 res = PWU_NOMEM; 257 break; 258 /* 259 * Nothing special needs to be done for 260 * server policy 261 */ 262 case ATTR_PASSWD: 263 case ATTR_PASSWD_SERVER_POLICY: 264 if ((w->data.val_s = strdup(spw->sp_pwdp)) == NULL) 265 res = PWU_NOMEM; 266 break; 267 case ATTR_AGE: 268 if ((w->data.val_s = strdup(pw->pw_age)) == NULL) 269 res = PWU_NOMEM; 270 break; 271 case ATTR_REP_NAME: 272 if ((w->data.val_s = strdup(pwbuf->rep_name)) == NULL) 273 res = PWU_NOMEM; 274 break; 275 276 /* integer values */ 277 case ATTR_UID: 278 w->data.val_i = pw->pw_uid; 279 break; 280 case ATTR_GID: 281 w->data.val_i = pw->pw_gid; 282 break; 283 case ATTR_LSTCHG: 284 w->data.val_i = spw->sp_lstchg; 285 break; 286 case ATTR_MIN: 287 w->data.val_i = spw->sp_min; 288 break; 289 case ATTR_MAX: 290 w->data.val_i = spw->sp_max; 291 break; 292 case ATTR_WARN: 293 w->data.val_i = spw->sp_warn; 294 break; 295 case ATTR_INACT: 296 w->data.val_i = spw->sp_inact; 297 break; 298 case ATTR_EXPIRE: 299 w->data.val_i = spw->sp_expire; 300 break; 301 case ATTR_FLAG: 302 w->data.val_i = spw->sp_flag; 303 break; 304 case ATTR_FAILED_LOGINS: 305 w->data.val_i = spw->sp_flag & FAILCOUNT_MASK; 306 break; 307 default: 308 break; 309 } 310 } 311 312 if (pwbuf->pwd) free(pwbuf->pwd); 313 if (pwbuf->pwd_scratch) free(pwbuf->pwd_scratch); 314 if (pwbuf->spwd) free(pwbuf->spwd); 315 if (pwbuf->spwd_scratch) free(pwbuf->spwd_scratch); 316 free(pwbuf); 317 318 return (res); 319 } 320