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 2005 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/varargs.h> 30 #include <string.h> 31 #include <stdlib.h> 32 #include <syslog.h> 33 34 #include <security/pam_appl.h> 35 #include <security/pam_modules.h> 36 #include <security/pam_impl.h> 37 38 #include <sys/note.h> 39 40 #include <libintl.h> 41 42 #include <passwdutil.h> 43 44 /*PRINTFLIKE2*/ 45 void 46 error(pam_handle_t *pamh, char *fmt, ...) 47 { 48 va_list ap; 49 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE]; 50 51 va_start(ap, fmt); 52 (void) vsnprintf(messages[0], sizeof (messages[0]), fmt, ap); 53 (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, messages, NULL); 54 va_end(ap); 55 } 56 57 int 58 read_authtok(pam_handle_t *pamh, int debug) 59 { 60 int res; 61 char *authtok; 62 char *pwd; 63 64 /* 65 * We are about to read the new AUTHTOK. Store the AUTHTOK that 66 * the user used to authenticate in OLDAUTHTOK, so it is available 67 * to future modules. If OLDAUTHTOK is already set, we leave it alone 68 */ 69 70 res = pam_get_item(pamh, PAM_OLDAUTHTOK, (void **)&authtok); 71 if (res != PAM_SUCCESS) 72 return (res); 73 74 if (authtok == NULL) { 75 res = pam_get_item(pamh, PAM_AUTHTOK, (void **)&authtok); 76 if (res != PAM_SUCCESS) 77 return (res); 78 if (authtok != NULL) { 79 res = pam_set_item(pamh, PAM_OLDAUTHTOK, 80 (void *)authtok); 81 if (res == PAM_SUCCESS) 82 res = pam_set_item(pamh, PAM_AUTHTOK, NULL); 83 84 if (debug) 85 syslog(LOG_DEBUG, "read_authtok: Copied " 86 "AUTHTOK to OLDAUTHTOK"); 87 88 if (res != PAM_SUCCESS) 89 goto out; 90 } 91 } else { 92 /* 93 * OLDAUTHTOK was filled in. If AUTHTOK is also filled 94 * in, we either succeed a module that has done our 95 * work, or we're here because one of the modules 96 * that are stacked beyond us has returned PAM_TRY_AGAIN. 97 * In either case, we should *not* prompt for another 98 * password. 99 */ 100 res = pam_get_item(pamh, PAM_AUTHTOK, (void **)&pwd); 101 if (res != PAM_SUCCESS) 102 goto out; 103 if (pwd != NULL) { 104 goto out; 105 } 106 } 107 108 /* 109 * Make sure PAM_AUTHTOK is empty, or the framework will not 110 * put the value read by __pam_get_authtok into it 111 */ 112 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL); 113 114 res = __pam_get_authtok(pamh, PAM_PROMPT, PAM_AUTHTOK, 115 dgettext(TEXT_DOMAIN, "New Password: "), &pwd); 116 117 if (res != PAM_SUCCESS) 118 goto out; 119 120 if (pwd == NULL) { 121 char *service; 122 if ((pam_get_item(pamh, PAM_SERVICE, (void **)&service) == 123 PAM_SUCCESS) && service != NULL) { 124 error(pamh, dgettext(TEXT_DOMAIN, "%s: Sorry."), 125 service); 126 } 127 res = PAM_PERM_DENIED; 128 } else { 129 (void) memset(pwd, 0, strlen(pwd)); 130 free(pwd); 131 } 132 out: 133 if (res != PAM_SUCCESS) { 134 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL); 135 (void) pam_set_item(pamh, PAM_OLDAUTHTOK, NULL); 136 } else { 137 /* 138 * Since we don't actually check the password, we should 139 * not return PAM_SUCCESS if everything went OK. 140 * We should return PAM_IGNORE instead. 141 */ 142 res = PAM_IGNORE; 143 } 144 145 return (res); 146 } 147 148 int 149 verify_authtok(pam_handle_t *pamh, int debug) 150 { 151 int res; 152 char *authtok; 153 char *pwd; 154 155 if (debug) 156 syslog(LOG_DEBUG, "pam_authtok_get: verifying authtok"); 157 158 /* 159 * All we need to do, is make sure that the user re-enters 160 * the password correctly. 161 */ 162 163 res = pam_get_item(pamh, PAM_AUTHTOK, (void **)&authtok); 164 if (res != PAM_SUCCESS || authtok == NULL) 165 return (PAM_AUTHTOK_ERR); 166 167 res = __pam_get_authtok(pamh, PAM_PROMPT, 0, dgettext(TEXT_DOMAIN, 168 "Re-enter new Password: "), &pwd); 169 170 if (res != PAM_SUCCESS) 171 return (res); 172 173 if (strcmp(authtok, pwd) != 0) { 174 char *service; 175 176 if ((pam_get_item(pamh, PAM_SERVICE, (void **)&service) == 177 PAM_SUCCESS) && service != NULL) { 178 error(pamh, dgettext(TEXT_DOMAIN, 179 "%s: They don't match."), service); 180 } 181 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL); 182 (void) memset(pwd, 0, strlen(pwd)); 183 free(pwd); 184 return (PAM_AUTHTOK_ERR); 185 } 186 187 if (debug) 188 syslog(LOG_DEBUG, "pam_authtok_get: new password verified"); 189 190 (void) memset(pwd, 0, strlen(pwd)); 191 free(pwd); 192 return (PAM_IGNORE); 193 } 194 195 int 196 pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) 197 { 198 int i; 199 int debug = 0; 200 int res; 201 202 for (i = 0; i < argc; i++) 203 if (strcmp(argv[i], "debug") == 0) 204 debug = 1; 205 206 if ((flags & PAM_PRELIM_CHECK) == PAM_PRELIM_CHECK) 207 res = read_authtok(pamh, debug); 208 else 209 res = verify_authtok(pamh, debug); 210 211 return (res); 212 } 213 214 /* 215 * int pam_sm_authenticate(pamh, flags, argc, argv) 216 * 217 * Read authentication token from user. 218 */ 219 int 220 pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) 221 { 222 223 char *user; 224 char *password; 225 int i; 226 int debug = 0; 227 int res; 228 int fail = 0; 229 230 attrlist al[1]; 231 pam_repository_t *auth_rep = NULL; 232 pwu_repository_t *pwu_rep = NULL; 233 234 for (i = 0; i < argc; i++) 235 if (strcmp(argv[i], "debug") == 0) 236 debug = 1; 237 238 if (debug) 239 syslog(LOG_DEBUG, "pam_authtok_get:pam_sm_authenticate: " 240 "flags = %d", flags); 241 242 if ((res = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) { 243 if (debug) 244 syslog(LOG_DEBUG, 245 "pam_authtok_get: get user failed: %s", 246 pam_strerror(pamh, res)); 247 return (res); 248 } 249 250 if (user == NULL || *user == '\0') { 251 syslog(LOG_ERR, "pam_authtok_get: pam_sm_authenticate: " 252 "PAM_USER NULL or empty"); 253 return (PAM_SYSTEM_ERR); 254 } 255 256 res = pam_get_item(pamh, PAM_AUTHTOK, (void **)&password); 257 if (res != PAM_SUCCESS) 258 return (res); 259 260 if (password != NULL) 261 return (PAM_IGNORE); 262 263 /* 264 * No password has been entered yet. Check to see if we need 265 * to obtain a password 266 */ 267 268 res = pam_get_item(pamh, PAM_REPOSITORY, (void **)&auth_rep); 269 if (res != PAM_SUCCESS) { 270 syslog(LOG_ERR, "pam_authtok_get: error getting repository"); 271 return (PAM_SYSTEM_ERR); 272 } 273 274 if (auth_rep == NULL) { 275 pwu_rep = PWU_DEFAULT_REP; 276 } else { 277 if ((pwu_rep = calloc(1, sizeof (*pwu_rep))) == NULL) 278 return (PAM_BUF_ERR); 279 pwu_rep->type = auth_rep->type; 280 pwu_rep->scope = auth_rep->scope; 281 pwu_rep->scope_len = auth_rep->scope_len; 282 } 283 284 (void) memset(&al, 0, sizeof (al)); 285 al[0].type = ATTR_PASSWD; 286 al[0].next = NULL; 287 288 res = __get_authtoken_attr(user, pwu_rep, al); 289 290 if (pwu_rep != PWU_DEFAULT_REP) 291 free(pwu_rep); 292 293 if (res == PWU_SUCCESS && 294 (al[0].data.val_s == NULL || al[0].data.val_s[0] == '\0')) { 295 /* 296 * if PAM_DIASALLOW_NULL_AUTHTOK has not been set, we 297 * simply return IGNORE 298 */ 299 if ((flags & PAM_DISALLOW_NULL_AUTHTOK) == 0) 300 return (PAM_IGNORE); 301 302 /* 303 * NULL authtoks are not allowed, so we need to 304 * fail. We will ask for a password to mask the 305 * failure however. 306 */ 307 308 fail = 1; 309 } 310 if (al[0].data.val_s != NULL) { 311 (void) memset(al[0].data.val_s, 0, strlen(al[0].data.val_s)); 312 free(al[0].data.val_s); 313 } 314 315 res = __pam_get_authtok(pamh, PAM_PROMPT, PAM_AUTHTOK, 316 dgettext(TEXT_DOMAIN, "Password: "), &password); 317 if (res != PAM_SUCCESS) 318 return (res); 319 320 if (password != NULL) { 321 (void) pam_set_item(pamh, PAM_AUTHTOK, (void *)password); 322 (void) memset(password, 0, strlen(password)); 323 free(password); 324 } else if (debug) { 325 syslog(LOG_DEBUG, "pam_authtok_get: pam_sm_authenticate: " 326 "got NULL password from get_authtok()"); 327 } 328 329 if (fail) { 330 syslog(LOG_DEBUG, "pam_authtok_get:pam_sm_authenticate: " 331 "failing because NULL authtok not allowed"); 332 return (PAM_AUTH_ERR); 333 } else 334 return (PAM_IGNORE); 335 } 336 337 /*ARGSUSED*/ 338 int 339 pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) 340 { 341 return (PAM_IGNORE); 342 } 343