int krb5_verifypw( pam_handle_t *pamh, char *princ_str, char *old_password, boolean_t disp_flag, int debug) { kadm5_ret_t code; krb5_principal princ = 0; char admin_realm[1024]; char kprinc[2*MAXHOSTNAMELEN]; char *cpw_service; kadm5_principal_ent_rec principal_entry; kadm5_policy_ent_rec policy_entry; void *server_handle; krb5_context context; kadm5_config_params params; #define MSG_ROWS 5 char msgs[MSG_ROWS][PAM_MAX_MSG_SIZE]; (void) memset((char *)¶ms, 0, sizeof (params)); (void) memset(&principal_entry, 0, sizeof (principal_entry)); (void) memset(&policy_entry, 0, sizeof (policy_entry)); if (code = krb5_init_context(&context)) { return (6); } if ((code = get_kmd_kuser(context, (const char *)princ_str, kprinc, 2*MAXHOSTNAMELEN)) != 0) { return (code); } /* Need to get a krb5_principal struct */ code = krb5_parse_name(context, kprinc, &princ); if (code != 0) { return (MISC_EXIT_STATUS); } if (strlen(old_password) == 0) { krb5_free_principal(context, princ); return (5); } (void) strlcpy(admin_realm, krb5_princ_realm(context, princ)->data, sizeof (admin_realm)); params.mask |= KADM5_CONFIG_REALM; params.realm = admin_realm; if (kadm5_get_cpw_host_srv_name(context, admin_realm, &cpw_service)) { syslog(LOG_ERR, dgettext(TEXT_DOMAIN, "PAM-KRB5 (password): unable to get host based " "service name for realm %s\n"), admin_realm); return (3); } code = kadm5_init_with_password(kprinc, old_password, cpw_service, ¶ms, KADM5_STRUCT_VERSION, KADM5_API_VERSION_2, &server_handle); if (code != 0) { if (debug) syslog(LOG_DEBUG, "PAM-KRB5: krb5_verifypw: init_with_pw" " failed: (%s)", error_message(code)); krb5_free_principal(context, princ); return ((code == KADM5_BAD_PASSWORD) ? 2 : 3); } if (disp_flag && _kadm5_get_kpasswd_protocol(server_handle) == KRB5_CHGPWD_RPCSEC) { /* * Note: copy of this exists in login * (kverify.c/get_verified_in_tkt). */ code = kadm5_get_principal(server_handle, princ, &principal_entry, KADM5_PRINCIPAL_NORMAL_MASK); if (code != 0) { krb5_free_principal(context, princ); (void) kadm5_destroy(server_handle); return ((code == KADM5_UNK_PRINC) ? 1 : MISC_EXIT_STATUS); } if ((principal_entry.aux_attributes & KADM5_POLICY) != 0) { code = kadm5_get_policy(server_handle, principal_entry.policy, &policy_entry); if (code != 0) { /* * doesn't matter which error comes back, * there's no nice recovery or need to * differentiate to the user */ (void) kadm5_free_principal_ent(server_handle, &principal_entry); krb5_free_principal(context, princ); (void) kadm5_destroy(server_handle); return (MISC_EXIT_STATUS); } (void) snprintf(msgs[0], PAM_MAX_MSG_SIZE, dgettext(TEXT_DOMAIN, "POLICY_EXPLANATION:")); (void) snprintf(msgs[1], PAM_MAX_MSG_SIZE, dgettext(TEXT_DOMAIN, "Principal string is %s"), princ_str); (void) snprintf(msgs[2], PAM_MAX_MSG_SIZE, dgettext(TEXT_DOMAIN, "Policy Name is %s"), principal_entry.policy); (void) snprintf(msgs[3], PAM_MAX_MSG_SIZE, dgettext(TEXT_DOMAIN, "Minimum password length is %d"), policy_entry.pw_min_length); (void) snprintf(msgs[4], PAM_MAX_MSG_SIZE, dgettext(TEXT_DOMAIN, "Minimum password classes is %d"), policy_entry.pw_min_classes); display_msgs(pamh, PAM_TEXT_INFO, MSG_ROWS, msgs); if (code = kadm5_free_principal_ent(server_handle, &principal_entry)) { (void) kadm5_free_policy_ent(server_handle, &policy_entry); krb5_free_principal(context, princ); (void) kadm5_destroy(server_handle); return (MISC_EXIT_STATUS); } if (code = kadm5_free_policy_ent(server_handle, &policy_entry)) { krb5_free_principal(context, princ); (void) kadm5_destroy(server_handle); return (MISC_EXIT_STATUS); } } else { /* * kpasswd *COULD* output something here to encourage * the choice of good passwords, in the absence of * an enforced policy. */ if (code = kadm5_free_principal_ent(server_handle, &principal_entry)) { krb5_free_principal(context, princ); (void) kadm5_destroy(server_handle); return (MISC_EXIT_STATUS); } } } krb5_free_principal(context, princ); (void) kadm5_destroy(server_handle); return (0); }
kadm5_ret_t check_min_life(void *server_handle, krb5_principal principal, char *msg_ret, unsigned int msg_len) { krb5_int32 now; kadm5_ret_t ret; kadm5_policy_ent_rec pol; kadm5_principal_ent_rec princ; kadm5_server_handle_t handle = server_handle; if (msg_ret != NULL) *msg_ret = '\0'; ret = krb5_timeofday(handle->context, &now); if (ret) return ret; ret = kadm5_get_principal(handle->lhandle, principal, &princ, KADM5_PRINCIPAL_NORMAL_MASK); if(ret) return ret; if(princ.aux_attributes & KADM5_POLICY) { if((ret=kadm5_get_policy(handle->lhandle, princ.policy, &pol)) != KADM5_OK) { (void) kadm5_free_principal_ent(handle->lhandle, &princ); return ret; } if((now - princ.last_pwd_change) < pol.pw_min_life && !(princ.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { if (msg_ret != NULL) { time_t until; char *time_string, *ptr, *errstr; until = princ.last_pwd_change + pol.pw_min_life; time_string = ctime(&until); errstr = error_message(CHPASS_UTIL_PASSWORD_TOO_SOON); if (strlen(errstr) + strlen(time_string) >= msg_len) { *errstr = '\0'; } else { if (*(ptr = &time_string[strlen(time_string)-1]) == '\n') *ptr = '\0'; snprintf(msg_ret, msg_len, errstr, time_string); } } (void) kadm5_free_policy_ent(handle->lhandle, &pol); (void) kadm5_free_principal_ent(handle->lhandle, &princ); return KADM5_PASS_TOOSOON; } ret = kadm5_free_policy_ent(handle->lhandle, &pol); if (ret) { (void) kadm5_free_principal_ent(handle->lhandle, &princ); return ret; } } return kadm5_free_principal_ent(handle->lhandle, &princ); }