add support for Set password protocol as defined by RFC3244 --

Microsoft Windows 2000 Kerberos Change Password and Set Password Protocols


git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@12888 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
Love Hörnquist Åstrand
2003-09-20 00:08:06 +00:00
parent 37e7b7d87f
commit a87bc35edc

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997-2002 Kungliga Tekniska H<>gskolan
* Copyright (c) 1997-2003 Kungliga Tekniska H<>gskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -199,70 +199,188 @@ reply_priv (krb5_auth_context auth_context,
static void
change (krb5_auth_context auth_context,
krb5_principal principal,
krb5_principal admin_principal,
u_int16_t version,
int s,
struct sockaddr *sa,
int sa_size,
krb5_data *pwd_data)
krb5_data *in_data)
{
krb5_error_code ret;
char *client;
char *client = NULL, *admin = NULL;
const char *pwd_reason;
kadm5_config_params conf;
void *kadm5_handle;
void *kadm5_handle = NULL;
krb5_principal principal;
krb5_data *pwd_data = NULL;
char *tmp;
ChangePasswdDataMS chpw;
memset (&conf, 0, sizeof(conf));
memset(&chpw, 0, sizeof(chpw));
krb5_unparse_name (context, principal, &client);
if (version == KRB5_KPASSWD_VERS_CHANGEPW) {
ret = krb5_copy_data(context, &chpw.newpasswd, &pwd_data);
if (ret) {
krb5_warn (context, ret, "krb5_copy_data");
reply_priv (auth_context, s, sa, sa_size, KRB5_KPASSWD_MALFORMED,
"out out memory copying password");
return;
}
principal = admin_principal;
} else if (version == KRB5_KPASSWD_VERS_SETPW) {
size_t len;
ret = decode_ChangePasswdDataMS(in_data->data, in_data->length,
&chpw, &len);
if (ret) {
krb5_warn (context, ret, "decode_ChangePasswdDataMS");
reply_priv (auth_context, s, sa, sa_size, KRB5_KPASSWD_MALFORMED,
"malformed ChangePasswdData");
return;
}
ret = krb5_copy_data(context, &chpw.newpasswd, &pwd_data);
if (ret) {
krb5_warn (context, ret, "krb5_copy_data");
reply_priv (auth_context, s, sa, sa_size, KRB5_KPASSWD_MALFORMED,
"out out memory copying password");
goto out;
}
if (chpw.targname == NULL && chpw.targrealm != NULL) {
krb5_warn (context, ret, "kadm5_init_with_password_ctx");
reply_priv (auth_context, s, sa, sa_size,
KRB5_KPASSWD_MALFORMED,
"targrealm but not targname");
goto out;
}
if (chpw.targname) {
krb5_principal_data princ;
princ.name = *chpw.targname;
princ.realm = *chpw.targrealm;
if (princ.realm == NULL) {
ret = krb5_get_default_realm(context, &princ.realm);
if (ret) {
krb5_warnx (context,
"kadm5_init_with_password_ctx: "
"failed to allocate realm");
reply_priv (auth_context, s, sa, sa_size,
KRB5_KPASSWD_SOFTERROR,
"failed to allocate realm");
goto out;
}
}
ret = krb5_copy_principal(context, &princ, &principal);
if (ret)
abort();
if (*chpw.targrealm == NULL)
free(princ.realm);
} else
principal = admin_principal;
} else {
krb5_warnx (context, "kadm5_init_with_password_ctx: unknown proto");
reply_priv (auth_context, s, sa, sa_size,
KRB5_KPASSWD_HARDERROR,
"Unknown protocol used");
return;
}
ret = krb5_unparse_name (context, admin_principal, &admin);
if (ret) {
krb5_warn (context, ret, "unparse_name failed");
reply_priv (auth_context, s, sa, sa_size,
KRB5_KPASSWD_HARDERROR, "out of memory error");
goto out;
}
ret = kadm5_init_with_password_ctx(context,
client,
admin,
NULL,
KADM5_ADMIN_SERVICE,
&conf, 0, 0,
&kadm5_handle);
if (ret) {
free (client);
krb5_warn (context, ret, "kadm5_init_with_password_ctx");
reply_priv (auth_context, s, sa, sa_size, 2,
"Internal error");
return;
goto out;
}
krb5_warnx (context, "Changing password for %s", client);
free (client);
pwd_reason = kadm5_check_password_quality (context, principal, pwd_data);
if (pwd_reason != NULL ) {
krb5_warnx (context, "%s", pwd_reason);
reply_priv (auth_context, s, sa, sa_size, 4, pwd_reason);
kadm5_destroy (kadm5_handle);
return;
ret = krb5_unparse_name(context, principal, &client);
if (ret) {
krb5_warn (context, ret, "unparse_name failed");
reply_priv (auth_context, s, sa, sa_size,
KRB5_KPASSWD_HARDERROR, "out of memory error");
goto out;
}
tmp = malloc (pwd_data->length + 1);
if (tmp == NULL) {
krb5_warnx (context, "malloc: out of memory");
reply_priv (auth_context, s, sa, sa_size, 2,
/*
* Check password quality if not changing as administrator
*/
if (krb5_principal_compare(context, admin_principal, principal) == TRUE) {
pwd_reason = kadm5_check_password_quality (context, principal,
pwd_data);
if (pwd_reason != NULL ) {
krb5_warnx (context,
"%s didn't pass password quality check with error: %s",
client, pwd_reason);
reply_priv (auth_context, s, sa, sa_size,
KRB5_KPASSWD_SOFTERROR, pwd_reason);
goto out;
}
krb5_warnx (context, "Changing password for %s", client);
} else {
ret = _kadm5_acl_check_permission(kadm5_handle, KADM5_PRIV_CPW,
principal);
if (ret) {
krb5_warn (context, ret,
"Check ACL failed for %s for changing %s password",
admin, client);
reply_priv (auth_context, s, sa, sa_size,
KRB5_KPASSWD_HARDERROR, "permission denied");
goto out;
}
krb5_warnx (context, "%s is changing password for %s", admin, client);
}
ret = krb5_data_realloc(pwd_data, pwd_data->length + 1);
if (ret) {
krb5_warn (context, ret, "malloc: out of memory");
reply_priv (auth_context, s, sa, sa_size, KRB5_KPASSWD_HARDERROR,
"Internal error");
goto out;
}
memcpy (tmp, pwd_data->data, pwd_data->length);
tmp[pwd_data->length] = '\0';
tmp = pwd_data->data;
tmp[pwd_data->length - 1] = '\0';
ret = kadm5_s_chpass_principal_cond (kadm5_handle, principal, tmp);
memset (tmp, 0, pwd_data->length);
free (tmp);
krb5_free_data (context, pwd_data);
pwd_data = NULL;
if (ret) {
krb5_warn (context, ret, "kadm5_s_chpass_principal_cond");
reply_priv (auth_context, s, sa, sa_size, 2,
reply_priv (auth_context, s, sa, sa_size, KRB5_KPASSWD_HARDERROR,
"Internal error");
goto out;
}
reply_priv (auth_context, s, sa, sa_size, 0, "Password changed");
reply_priv (auth_context, s, sa, sa_size, KRB5_KPASSWD_SUCCESS,
"Password changed");
out:
kadm5_destroy (kadm5_handle);
free_ChangePasswdDataMS(&chpw);
if (admin)
free(admin);
if (client)
free(client);
if (pwd_data)
krb5_free_data(context, pwd_data);
if (kadm5_handle)
kadm5_destroy (kadm5_handle);
}
static int
@@ -271,6 +389,7 @@ verify (krb5_auth_context *auth_context,
krb5_keytab keytab,
krb5_ticket **ticket,
krb5_data *out_data,
u_int16_t *version,
int s,
struct sockaddr *sa,
int sa_size,
@@ -291,11 +410,13 @@ verify (krb5_auth_context *auth_context,
reply_error (server, s, sa, sa_size, 0, 1, "Bad request");
return 1;
}
if (pkt_ver != 0x0001) {
if (pkt_ver != KRB5_KPASSWD_VERS_CHANGEPW &&
pkt_ver != KRB5_KPASSWD_VERS_SETPW) {
krb5_warnx (context, "Bad version (%d)", pkt_ver);
reply_error (server, s, sa, sa_size, 0, 1, "Wrong program version");
return 1;
}
*version = pkt_ver;
ap_req_data.data = msg + 6;
ap_req_data.length = ap_req_len;
@@ -361,6 +482,8 @@ process (krb5_principal server,
krb5_data out_data;
krb5_ticket *ticket;
krb5_address other_addr;
u_int16_t version;
krb5_data_zero (&out_data);
@@ -390,9 +513,10 @@ process (krb5_principal server,
}
if (verify (&auth_context, server, keytab, &ticket, &out_data,
s, sa, sa_size, msg, len) == 0) {
&version, s, sa, sa_size, msg, len) == 0) {
change (auth_context,
ticket->client,
version,
s,
sa, sa_size,
&out_data);