/* * Function: krb5_changepw * * Purpose: Initialize and call lower level routines to change a password * * Arguments: * * princ_str principal name to use, optional * old_password old password * new_password new password * * Returns: * exit status of PAM_SUCCESS for success * 1 principal unknown * 2 old password wrong * 3 cannot initialize admin server session * 4 new passwd mismatch or error trying to change pw * 5 password not typed * 6 misc error * 7 incorrect usage * * Requires: * Passwords cannot be more than 255 characters long. * * Modifies: * * Changes the principal's password. * */ static int krb5_changepw( pam_handle_t *pamh, char *princ_str, char *old_password, char *new_password, int debug) { kadm5_ret_t code; krb5_principal princ = 0; char msg_ret[1024], 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; (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) snprintf(admin_realm, sizeof (admin_realm), "%s", krb5_princ_realm(context, princ)->data); 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); free(cpw_service); if (code != 0) { if (debug) syslog(LOG_DEBUG, "PAM-KRB5 (password): changepw: " "init_with_pw failed: (%s)", error_message(code)); krb5_free_principal(context, princ); return ((code == KADM5_BAD_PASSWORD) ? 2 : 3); } code = kadm5_chpass_principal_util(server_handle, princ, new_password, NULL /* don't need pw back */, msg_ret, sizeof (msg_ret)); if (code) { char msgs[2][PAM_MAX_MSG_SIZE]; (void) snprintf(msgs[0], PAM_MAX_MSG_SIZE, "%s", dgettext(TEXT_DOMAIN, "Kerberos password not changed: ")); (void) snprintf(msgs[1], PAM_MAX_MSG_SIZE, "%s", msg_ret); display_msgs(pamh, PAM_ERROR_MSG, 2, msgs); } krb5_free_principal(context, princ); (void) kadm5_destroy(server_handle); if (debug) syslog(LOG_DEBUG, "PAM-KRB5 (password): changepw: end %d", code); if (code == KRB5_LIBOS_CANTREADPWD) return (5); else if (code) return (4); else return (PAM_SUCCESS); }
static int fetch_princ_entry( krb5_module_data_t *kmd, char *princ_str, kadm5_principal_ent_rec *prent, /* out */ int debug) { kadm5_ret_t code; krb5_principal princ = 0; char admin_realm[1024]; char kprinc[2*MAXHOSTNAMELEN]; char *cpw_service, *password; void *server_handle; krb5_context context; kadm5_config_params params; password = kmd->password; context = kmd->kcontext; if ((code = get_kmd_kuser(context, (const char *)princ_str, kprinc, 2*MAXHOSTNAMELEN)) != 0) { return (code); } code = krb5_parse_name(context, kprinc, &princ); if (code != 0) { return (PAM_SYSTEM_ERR); } if (strlen(password) == 0) { krb5_free_principal(context, princ); if (debug) __pam_log(LOG_AUTH | LOG_DEBUG, "PAM-KRB5 (acct): fetch_princ_entry: pwlen=0"); return (PAM_AUTH_ERR); } (void) strlcpy(admin_realm, krb5_princ_realm(context, princ)->data, sizeof (admin_realm)); (void) memset((char *)¶ms, 0, sizeof (params)); params.mask |= KADM5_CONFIG_REALM; params.realm = admin_realm; if (kadm5_get_cpw_host_srv_name(context, admin_realm, &cpw_service)) { __pam_log(LOG_AUTH | LOG_ERR, "PAM-KRB5 (acct): unable to get host based " "service name for realm '%s'", admin_realm); krb5_free_principal(context, princ); return (PAM_SYSTEM_ERR); } code = kadm5_init_with_password(kprinc, password, cpw_service, ¶ms, KADM5_STRUCT_VERSION, KADM5_API_VERSION_2, NULL, &server_handle); if (code != 0) { if (debug) __pam_log(LOG_AUTH | LOG_DEBUG, "PAM-KRB5 (acct): fetch_princ_entry: " "init_with_pw failed: code = %d", code); krb5_free_principal(context, princ); return ((code == KADM5_BAD_PASSWORD) ? PAM_AUTH_ERR : PAM_SYSTEM_ERR); } if (_kadm5_get_kpasswd_protocol(server_handle) != KRB5_CHGPWD_RPCSEC) { if (debug) __pam_log(LOG_AUTH | LOG_DEBUG, "PAM-KRB5 (acct): fetch_princ_entry: " "non-RPCSEC_GSS chpw server, can't get " "princ entry"); (void) kadm5_destroy(server_handle); krb5_free_principal(context, princ); return (PAM_SYSTEM_ERR); } code = kadm5_get_principal(server_handle, princ, prent, KADM5_PRINCIPAL_NORMAL_MASK); if (code != 0) { (void) kadm5_destroy(server_handle); krb5_free_principal(context, princ); return ((code == KADM5_UNK_PRINC) ? PAM_USER_UNKNOWN : PAM_SYSTEM_ERR); } (void) kadm5_destroy(server_handle); krb5_free_principal(context, princ); return (PAM_SUCCESS); }
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); }