/*
- * 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.
*
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);
+ 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;
+ }
- 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;
+ /*
+ * 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);
}
- 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,
+ 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
krb5_keytab keytab,
krb5_ticket **ticket,
krb5_data *out_data,
+ u_int16_t *version,
int s,
struct sockaddr *sa,
int sa_size,
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;
krb5_data out_data;
krb5_ticket *ticket;
krb5_address other_addr;
+ u_int16_t version;
+
krb5_data_zero (&out_data);
}
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);