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 * Copyright 2023 OmniOS Community Edition (OmniOSce) Association. 26 */ 27 28 #include <sys/varargs.h> 29 #include <string.h> 30 #include <stdlib.h> 31 #include <syslog.h> 32 33 #include <security/pam_appl.h> 34 #include <security/pam_modules.h> 35 #include <security/pam_impl.h> 36 37 #include <sys/note.h> 38 39 #include <libintl.h> 40 41 #include <passwdutil.h> 42 43 /*PRINTFLIKE2*/ 44 void 45 error(pam_handle_t *pamh, char *fmt, ...) 46 { 47 va_list ap; 48 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE]; 49 50 va_start(ap, fmt); 51 (void) vsnprintf(messages[0], sizeof (messages[0]), fmt, ap); 52 (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, messages, NULL); 53 va_end(ap); 54 } 55 56 int 57 read_authtok(pam_handle_t *pamh, int debug) 58 { 59 int res; 60 const char *authtok; 61 char *pwd; 62 63 /* 64 * We are about to read the new AUTHTOK. Store the AUTHTOK that 65 * the user used to authenticate in OLDAUTHTOK, so it is available 66 * to future modules. If OLDAUTHTOK is already set, we leave it alone 67 */ 68 69 res = pam_get_item(pamh, PAM_OLDAUTHTOK, (const void **)&authtok); 70 if (res != PAM_SUCCESS) 71 return (res); 72 73 if (authtok == NULL) { 74 res = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&authtok); 75 if (res != PAM_SUCCESS) 76 return (res); 77 if (authtok != NULL) { 78 res = pam_set_item(pamh, PAM_OLDAUTHTOK, 79 (void *)authtok); 80 if (res == PAM_SUCCESS) 81 res = pam_set_item(pamh, PAM_AUTHTOK, NULL); 82 83 if (debug) 84 __pam_log(LOG_AUTH | LOG_DEBUG, 85 "read_authtok: Copied AUTHTOK to " 86 "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, (const 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 const char *service; 122 if ((pam_get_item(pamh, PAM_SERVICE, (const 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 const char *authtok; 153 char *pwd; 154 155 if (debug) 156 __pam_log(LOG_AUTH | LOG_DEBUG, 157 "pam_authtok_get: verifying authtok"); 158 159 /* 160 * All we need to do, is make sure that the user re-enters 161 * the password correctly. 162 */ 163 164 res = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&authtok); 165 if (res != PAM_SUCCESS || authtok == NULL) 166 return (PAM_AUTHTOK_ERR); 167 168 res = __pam_get_authtok(pamh, PAM_PROMPT, 0, dgettext(TEXT_DOMAIN, 169 "Re-enter new Password: "), &pwd); 170 171 if (res != PAM_SUCCESS) 172 return (res); 173 174 if (strcmp(authtok, pwd) != 0) { 175 const char *service; 176 177 if ((pam_get_item(pamh, PAM_SERVICE, (const void **)&service) == 178 PAM_SUCCESS) && service != NULL) { 179 error(pamh, dgettext(TEXT_DOMAIN, 180 "%s: They don't match."), service); 181 } 182 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL); 183 (void) memset(pwd, 0, strlen(pwd)); 184 free(pwd); 185 return (PAM_AUTHTOK_ERR); 186 } 187 188 if (debug) 189 __pam_log(LOG_AUTH | LOG_DEBUG, 190 "pam_authtok_get: new password verified"); 191 192 (void) memset(pwd, 0, strlen(pwd)); 193 free(pwd); 194 return (PAM_IGNORE); 195 } 196 197 int 198 pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) 199 { 200 int i; 201 int debug = 0; 202 int res; 203 204 for (i = 0; i < argc; i++) 205 if (strcmp(argv[i], "debug") == 0) 206 debug = 1; 207 208 if ((flags & PAM_PRELIM_CHECK) == PAM_PRELIM_CHECK) 209 res = read_authtok(pamh, debug); 210 else 211 res = verify_authtok(pamh, debug); 212 213 return (res); 214 } 215 216 /* 217 * int pam_sm_authenticate(pamh, flags, argc, argv) 218 * 219 * Read authentication token from user. 220 */ 221 int 222 pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) 223 { 224 const char *user; 225 char *password; 226 int i; 227 int debug = 0; 228 int res; 229 int fail = 0; 230 231 attrlist al[1]; 232 const pam_repository_t *auth_rep = NULL; 233 pwu_repository_t *pwu_rep = NULL; 234 235 for (i = 0; i < argc; i++) 236 if (strcmp(argv[i], "debug") == 0) 237 debug = 1; 238 239 if (debug) 240 __pam_log(LOG_AUTH | LOG_DEBUG, 241 "pam_authtok_get:pam_sm_authenticate: flags = %d", flags); 242 243 if ((res = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) { 244 if (debug) 245 __pam_log(LOG_AUTH | LOG_DEBUG, 246 "pam_authtok_get: get user failed: %s", 247 pam_strerror(pamh, res)); 248 return (res); 249 } 250 251 if (user == NULL || *user == '\0') { 252 __pam_log(LOG_AUTH | LOG_ERR, 253 "pam_authtok_get: pam_sm_authenticate: PAM_USER NULL or " 254 "empty"); 255 return (PAM_SYSTEM_ERR); 256 } 257 258 res = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&password); 259 if (res != PAM_SUCCESS) 260 return (res); 261 262 if (password != NULL) 263 return (PAM_IGNORE); 264 265 /* 266 * No password has been entered yet. Check to see if we need 267 * to obtain a password 268 */ 269 270 res = pam_get_item(pamh, PAM_REPOSITORY, (const void **)&auth_rep); 271 if (res != PAM_SUCCESS) { 272 __pam_log(LOG_AUTH | LOG_ERR, 273 "pam_authtok_get: error getting repository"); 274 return (PAM_SYSTEM_ERR); 275 } 276 277 if (auth_rep == NULL) { 278 pwu_rep = PWU_DEFAULT_REP; 279 } else { 280 if ((pwu_rep = calloc(1, sizeof (*pwu_rep))) == NULL) 281 return (PAM_BUF_ERR); 282 pwu_rep->type = auth_rep->type; 283 pwu_rep->scope = auth_rep->scope; 284 pwu_rep->scope_len = auth_rep->scope_len; 285 } 286 287 (void) memset(&al, 0, sizeof (al)); 288 al[0].type = ATTR_PASSWD; 289 al[0].next = NULL; 290 291 res = __get_authtoken_attr(user, pwu_rep, al); 292 293 if (pwu_rep != PWU_DEFAULT_REP) 294 free(pwu_rep); 295 296 if (res == PWU_SUCCESS && 297 (al[0].data.val_s == NULL || al[0].data.val_s[0] == '\0')) { 298 const char *service = NULL; 299 const char *rhost = NULL; 300 301 /* 302 * if PAM_DIASALLOW_NULL_AUTHTOK has not been set, we 303 * simply return IGNORE 304 */ 305 if ((flags & PAM_DISALLOW_NULL_AUTHTOK) == 0) 306 return (PAM_IGNORE); 307 308 /* 309 * NULL authtoks are not allowed, so we need to fail. 310 * We will ask for a password to mask the failure however. 311 */ 312 (void) pam_get_item(pamh, PAM_RHOST, (const void **)&rhost); 313 (void) pam_get_item(pamh, PAM_SERVICE, (const void **)&service); 314 if (service == NULL) 315 service = "unknown"; 316 if (rhost == NULL || *rhost == '\0') 317 rhost = "localhost"; 318 __pam_log(LOG_AUTH | LOG_NOTICE, 319 "pam_authtok_get: %s: empty password not allowed for " 320 "%s from %s.", service, user, rhost); 321 fail = 1; 322 } 323 if (al[0].data.val_s != NULL) { 324 (void) memset(al[0].data.val_s, 0, strlen(al[0].data.val_s)); 325 free(al[0].data.val_s); 326 } 327 328 res = __pam_get_authtok(pamh, PAM_PROMPT, PAM_AUTHTOK, 329 dgettext(TEXT_DOMAIN, "Password: "), &password); 330 if (res != PAM_SUCCESS) 331 return (res); 332 333 if (password != NULL) { 334 (void) pam_set_item(pamh, PAM_AUTHTOK, (const void *)password); 335 (void) memset(password, 0, strlen(password)); 336 free(password); 337 } else if (debug) { 338 __pam_log(LOG_AUTH | LOG_DEBUG, 339 "pam_authtok_get: pam_sm_authenticate: " 340 "got NULL password from get_authtok()"); 341 } 342 343 if (fail) { 344 __pam_log(LOG_AUTH | LOG_DEBUG, 345 "pam_authtok_get:pam_sm_authenticate: " 346 "failing because NULL authtok not allowed"); 347 return (PAM_AUTH_ERR); 348 } else 349 return (PAM_IGNORE); 350 } 351 352 /*ARGSUSED*/ 353 int 354 pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) 355 { 356 return (PAM_IGNORE); 357 } 358