Blame src/lib/kadm5/chpass_util.c

Packit Service 99d1c0
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
Packit Service 99d1c0
/*
Packit Service 99d1c0
 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
Packit Service 99d1c0
 */
Packit Service 99d1c0
Packit Service 99d1c0
Packit Service 99d1c0
#include "k5-int.h"
Packit Service 99d1c0
Packit Service 99d1c0
#include <kadm5/admin.h>
Packit Service 99d1c0
#include "admin_internal.h"
Packit Service 99d1c0
Packit Service 99d1c0
Packit Service 99d1c0
#define string_text error_message
Packit Service 99d1c0
Packit Service 99d1c0
/*
Packit Service 99d1c0
 * Function: kadm5_chpass_principal_util
Packit Service 99d1c0
 *
Packit Service 99d1c0
 * Purpose: Wrapper around chpass_principal. We can read new pw, change pw and return useful messages
Packit Service 99d1c0
 *
Packit Service 99d1c0
 * Arguments:
Packit Service 99d1c0
 *
Packit Service 99d1c0
 *      princ          (input) a krb5b_principal structure for the
Packit Service 99d1c0
 *                     principal whose password we should change.
Packit Service 99d1c0
 *
Packit Service 99d1c0
 *      new_password   (input) NULL or a null terminated string with the
Packit Service 99d1c0
 *                     the principal's desired new password.  If new_password
Packit Service 99d1c0
 *                     is NULL then this routine will read a new password.
Packit Service 99d1c0
 *
Packit Service 99d1c0
 *      pw_ret          (output) if non-NULL, points to a static buffer
Packit Service 99d1c0
 *                      containing the new password (if password is prompted
Packit Service 99d1c0
 *                      internally), or to the new_password argument (if
Packit Service 99d1c0
 *                      that is non-NULL).  If the former, then the buffer
Packit Service 99d1c0
 *                      is only valid until the next call to the function,
Packit Service 99d1c0
 *                      and the caller should be sure to zero it when
Packit Service 99d1c0
 *                      it is no longer needed.
Packit Service 99d1c0
 *
Packit Service 99d1c0
 *      msg_ret         (output) a useful message is copied here.
Packit Service 99d1c0
 *
Packit Service 99d1c0
 *      <return value>  exit status of 0 for success, else the com err code
Packit Service 99d1c0
 *                      for the last significant routine called.
Packit Service 99d1c0
 *
Packit Service 99d1c0
 * Requires:
Packit Service 99d1c0
 *
Packit Service 99d1c0
 *      A msg_ret should point to a buffer large enough for the messasge.
Packit Service 99d1c0
 *
Packit Service 99d1c0
 * Effects:
Packit Service 99d1c0
 *
Packit Service 99d1c0
 * Modifies:
Packit Service 99d1c0
 *
Packit Service 99d1c0
 *
Packit Service 99d1c0
 */
Packit Service 99d1c0
Packit Service 99d1c0
kadm5_ret_t _kadm5_chpass_principal_util(void *server_handle,
Packit Service 99d1c0
                                         void *lhandle,
Packit Service 99d1c0
                                         krb5_principal princ,
Packit Service 99d1c0
                                         char *new_pw,
Packit Service 99d1c0
                                         char **ret_pw,
Packit Service 99d1c0
                                         char *msg_ret,
Packit Service 99d1c0
                                         unsigned int msg_len)
Packit Service 99d1c0
{
Packit Service 99d1c0
    int code, code2;
Packit Service 99d1c0
    unsigned int pwsize;
Packit Service 99d1c0
    static char buffer[255];
Packit Service 99d1c0
    char *new_password;
Packit Service 99d1c0
    kadm5_principal_ent_rec princ_ent;
Packit Service 99d1c0
    kadm5_policy_ent_rec policy_ent;
Packit Service 99d1c0
Packit Service 99d1c0
    _KADM5_CHECK_HANDLE(server_handle);
Packit Service 99d1c0
Packit Service 99d1c0
    if (ret_pw)
Packit Service 99d1c0
        *ret_pw = NULL;
Packit Service 99d1c0
Packit Service 99d1c0
    if (new_pw != NULL) {
Packit Service 99d1c0
        new_password = new_pw;
Packit Service 99d1c0
    } else { /* read the password */
Packit Service 99d1c0
        krb5_context context;
Packit Service 99d1c0
Packit Service 99d1c0
        if ((code = (int) kadm5_init_krb5_context(&context)) == 0) {
Packit Service 99d1c0
            pwsize = sizeof(buffer);
Packit Service 99d1c0
            code = krb5_read_password(context, KADM5_PW_FIRST_PROMPT,
Packit Service 99d1c0
                                      KADM5_PW_SECOND_PROMPT,
Packit Service 99d1c0
                                      buffer, &pwsize);
Packit Service 99d1c0
            krb5_free_context(context);
Packit Service 99d1c0
        }
Packit Service 99d1c0
Packit Service 99d1c0
        if (code == 0)
Packit Service 99d1c0
            new_password = buffer;
Packit Service 99d1c0
        else {
Packit Service 99d1c0
#ifdef ZEROPASSWD
Packit Service 99d1c0
            memset(buffer, 0, sizeof(buffer));
Packit Service 99d1c0
#endif
Packit Service 99d1c0
            if (code == KRB5_LIBOS_BADPWDMATCH) {
Packit Service 99d1c0
                strncpy(msg_ret, string_text(CHPASS_UTIL_NEW_PASSWORD_MISMATCH),
Packit Service 99d1c0
                        msg_len - 1);
Packit Service 99d1c0
                msg_ret[msg_len - 1] = '\0';
Packit Service 99d1c0
                return(code);
Packit Service 99d1c0
            } else {
Packit Service 99d1c0
                snprintf(msg_ret, msg_len, "%s %s\n\n%s",
Packit Service 99d1c0
                         error_message(code),
Packit Service 99d1c0
                         string_text(CHPASS_UTIL_WHILE_READING_PASSWORD),
Packit Service 99d1c0
                         string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED));
Packit Service 99d1c0
                msg_ret[msg_len - 1] = '\0';
Packit Service 99d1c0
                return(code);
Packit Service 99d1c0
            }
Packit Service 99d1c0
        }
Packit Service 99d1c0
        if (pwsize == 0) {
Packit Service 99d1c0
#ifdef ZEROPASSWD
Packit Service 99d1c0
            memset(buffer, 0, sizeof(buffer));
Packit Service 99d1c0
#endif
Packit Service 99d1c0
            strncpy(msg_ret, string_text(CHPASS_UTIL_NO_PASSWORD_READ), msg_len - 1);
Packit Service 99d1c0
            msg_ret[msg_len - 1] = '\0';
Packit Service 99d1c0
            return(KRB5_LIBOS_CANTREADPWD); /* could do better */
Packit Service 99d1c0
        }
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
    if (ret_pw)
Packit Service 99d1c0
        *ret_pw = new_password;
Packit Service 99d1c0
Packit Service 99d1c0
    code = kadm5_chpass_principal(server_handle, princ, new_password);
Packit Service 99d1c0
Packit Service 99d1c0
#ifdef ZEROPASSWD
Packit Service 99d1c0
    if (!ret_pw)
Packit Service 99d1c0
        memset(buffer, 0, sizeof(buffer)); /* in case we read a new password */
Packit Service 99d1c0
#endif
Packit Service 99d1c0
Packit Service 99d1c0
    if (code == KADM5_OK) {
Packit Service 99d1c0
        strncpy(msg_ret, string_text(CHPASS_UTIL_PASSWORD_CHANGED), msg_len - 1);
Packit Service 99d1c0
        msg_ret[msg_len - 1] = '\0';
Packit Service 99d1c0
        return(0);
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
    if ((code != KADM5_PASS_Q_TOOSHORT) &&
Packit Service 99d1c0
        (code != KADM5_PASS_REUSE) &&(code != KADM5_PASS_Q_CLASS) &&
Packit Service 99d1c0
        (code != KADM5_PASS_Q_DICT) && (code != KADM5_PASS_TOOSOON)) {
Packit Service 99d1c0
        /* Can't get more info for other errors */
Packit Service 99d1c0
        snprintf(msg_ret, msg_len, "%s\n%s %s\n",
Packit Service 99d1c0
                 string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED),
Packit Service 99d1c0
                 error_message(code),
Packit Service 99d1c0
                 string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE));
Packit Service 99d1c0
        return(code);
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
    /* Ok, we have a password quality error. Return a good message */
Packit Service 99d1c0
Packit Service 99d1c0
    if (code == KADM5_PASS_REUSE) {
Packit Service 99d1c0
        strncpy(msg_ret, string_text(CHPASS_UTIL_PASSWORD_REUSE), msg_len - 1);
Packit Service 99d1c0
        msg_ret[msg_len - 1] = '\0';
Packit Service 99d1c0
        return(code);
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
    if (code == KADM5_PASS_Q_DICT) {
Packit Service 99d1c0
        strncpy(msg_ret, string_text(CHPASS_UTIL_PASSWORD_IN_DICTIONARY),
Packit Service 99d1c0
                msg_len - 1);
Packit Service 99d1c0
        msg_ret[msg_len - 1] = '\0';
Packit Service 99d1c0
        return(code);
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
    /* Look up policy for the remaining messages */
Packit Service 99d1c0
Packit Service 99d1c0
    code2 = kadm5_get_principal (lhandle, princ, &princ_ent,
Packit Service 99d1c0
                                 KADM5_PRINCIPAL_NORMAL_MASK);
Packit Service 99d1c0
    if (code2 != 0) {
Packit Service 99d1c0
        snprintf(msg_ret, msg_len, "%s %s\n%s %s\n\n%s\n",
Packit Service 99d1c0
                 error_message(code2),
Packit Service 99d1c0
                 string_text(CHPASS_UTIL_GET_PRINC_INFO),
Packit Service 99d1c0
                 error_message(code),
Packit Service 99d1c0
                 string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE),
Packit Service 99d1c0
                 string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED));
Packit Service 99d1c0
        msg_ret[msg_len - 1] = '\0';
Packit Service 99d1c0
        return(code);
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
    if ((princ_ent.aux_attributes & KADM5_POLICY) == 0) {
Packit Service 99d1c0
        /* Some module implements its own password policy. */
Packit Service 99d1c0
        snprintf(msg_ret, msg_len, "%s\n\n%s",
Packit Service 99d1c0
                 error_message(code),
Packit Service 99d1c0
                 string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED));
Packit Service 99d1c0
        msg_ret[msg_len - 1] = '\0';
Packit Service 99d1c0
        (void) kadm5_free_principal_ent(lhandle, &princ_ent);
Packit Service 99d1c0
        return(code);
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
    code2 = kadm5_get_policy(lhandle, princ_ent.policy,
Packit Service 99d1c0
                             &policy_ent);
Packit Service 99d1c0
    if (code2 != 0) {
Packit Service 99d1c0
        snprintf(msg_ret, msg_len, "%s %s\n%s %s\n\n%s\n ", error_message(code2),
Packit Service 99d1c0
                 string_text(CHPASS_UTIL_GET_POLICY_INFO),
Packit Service 99d1c0
                 error_message(code),
Packit Service 99d1c0
                 string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE),
Packit Service 99d1c0
                 string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED));
Packit Service 99d1c0
        (void) kadm5_free_principal_ent(lhandle, &princ_ent);
Packit Service 99d1c0
        return(code);
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
    if (code == KADM5_PASS_Q_TOOSHORT) {
Packit Service 99d1c0
        snprintf(msg_ret, msg_len, string_text(CHPASS_UTIL_PASSWORD_TOO_SHORT),
Packit Service 99d1c0
                 policy_ent.pw_min_length);
Packit Service 99d1c0
        (void) kadm5_free_principal_ent(lhandle, &princ_ent);
Packit Service 99d1c0
        (void) kadm5_free_policy_ent(lhandle, &policy_ent);
Packit Service 99d1c0
        return(code);
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
/* Can't get more info for other errors */
Packit Service 99d1c0
Packit Service 99d1c0
    if (code == KADM5_PASS_Q_CLASS) {
Packit Service 99d1c0
        snprintf(msg_ret, msg_len, string_text(CHPASS_UTIL_TOO_FEW_CLASSES),
Packit Service 99d1c0
                 policy_ent.pw_min_classes);
Packit Service 99d1c0
        (void) kadm5_free_principal_ent(lhandle, &princ_ent);
Packit Service 99d1c0
        (void) kadm5_free_policy_ent(lhandle, &policy_ent);
Packit Service 99d1c0
        return(code);
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
    if (code == KADM5_PASS_TOOSOON) {
Packit Service 99d1c0
        time_t until;
Packit Service 99d1c0
        char *time_string, *ptr;
Packit Service 99d1c0
Packit Service 99d1c0
        until = ts_incr(princ_ent.last_pwd_change, policy_ent.pw_min_life);
Packit Service 99d1c0
Packit Service 99d1c0
        time_string = ctime(&until);
Packit Service 99d1c0
        if (time_string == NULL)
Packit Service 99d1c0
            time_string = "(error)";
Packit Service 99d1c0
        else if (*(ptr = &time_string[strlen(time_string)-1]) == '\n')
Packit Service 99d1c0
            *ptr = '\0';
Packit Service 99d1c0
Packit Service 99d1c0
        snprintf(msg_ret, msg_len, string_text(CHPASS_UTIL_PASSWORD_TOO_SOON),
Packit Service 99d1c0
                 time_string);
Packit Service 99d1c0
        (void) kadm5_free_principal_ent(lhandle, &princ_ent);
Packit Service 99d1c0
        (void) kadm5_free_policy_ent(lhandle, &policy_ent);
Packit Service 99d1c0
        return(code);
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
    /* We should never get here, but just in case ... */
Packit Service 99d1c0
    snprintf(msg_ret, msg_len, "%s\n%s %s\n",
Packit Service 99d1c0
             string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED),
Packit Service 99d1c0
             error_message(code),
Packit Service 99d1c0
             string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE));
Packit Service 99d1c0
    (void) kadm5_free_principal_ent(lhandle, &princ_ent);
Packit Service 99d1c0
    (void) kadm5_free_policy_ent(lhandle, &policy_ent);
Packit Service 99d1c0
    return(code);
Packit Service 99d1c0
}