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