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:
@@ -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);
|
||||
|
Reference in New Issue
Block a user