krb5_data *in, krb5_data *out)
{
kadm5_ret_t ret;
- int32_t cmd, mask, tmp;
+ int32_t cmd, mask, kvno, tmp;
kadm5_server_context *contextp = kadm_handlep;
char client[128], name[128], name2[128];
const char *op = "";
- krb5_principal princ, princ2;
+ krb5_principal princ = NULL, princ2 = NULL;
kadm5_principal_ent_rec ent, ent_prev;
- char *password, *expression;
+ char *password = NULL, *expression;
krb5_keyblock *new_keys;
krb5_key_salt_tuple *ks_tuple = NULL;
- krb5_boolean keepold = FALSE;
+ int keepold = FALSE;
int n_ks_tuple = 0;
int n_keys;
char **princs;
int n_princs;
int keys_ok = 0;
krb5_storage *sp;
+ int len;
krb5_unparse_name_fixed(contextp->context, contextp->caller,
client, sizeof(client));
sp = krb5_storage_from_data(in);
- if (sp == NULL)
- krb5_errx(contextp->context, 1, "out of memory");
+ if (sp == NULL) {
+ ret = krb5_enomem(contextp->context);
+ goto fail;
+ }
krb5_ret_int32(sp, &cmd);
switch(cmd){
if(ret)
goto fail;
ret = krb5_ret_int32(sp, &mask);
- if(ret){
- krb5_free_principal(contextp->context, princ);
+ if (ret)
goto fail;
- }
+
mask |= KADM5_PRINCIPAL;
krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name));
krb5_warnx(contextp->context, "%s: %s %s", client, op, name);
/* If the caller doesn't have KADM5_PRIV_GET, we're done. */
ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_GET, princ);
- if (ret) {
- krb5_free_principal(contextp->context, princ);
+ if (ret)
goto fail;
- }
/* Then check to see if it is ok to return keys */
if ((mask & KADM5_KEY_DATA) != 0) {
* modes request other things too, so in all likelihood this
* heuristic will not hurt any kadmin get uses.
*/
- krb5_free_principal(contextp->context, princ);
goto fail;
}
}
ret = kadm5_get_principal(kadm_handlep, princ, &ent, mask);
krb5_storage_free(sp);
sp = krb5_storage_emem();
+ if (sp == NULL) {
+ ret = krb5_enomem(contextp->context);
+ goto fail;
+ }
krb5_store_int32(sp, ret);
if (ret == 0){
if (keys_ok)
kadm5_store_principal_ent_nokeys(sp, &ent);
kadm5_free_principal_ent(kadm_handlep, &ent);
}
- krb5_free_principal(contextp->context, princ);
break;
}
case kadm_delete:{
krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name));
krb5_warnx(contextp->context, "%s: %s %s", client, op, name);
ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_DELETE, princ);
- if(ret){
- krb5_free_principal(contextp->context, princ);
+ if (ret)
goto fail;
- }
/*
* There's no need to check that the caller has permission to
*/
ret = kadm5_delete_principal(kadm_handlep, princ);
- krb5_free_principal(contextp->context, princ);
krb5_storage_free(sp);
sp = krb5_storage_emem();
+ if (sp == NULL) {
+ ret = krb5_enomem(contextp->context);
+ goto fail;
+ }
krb5_store_int32(sp, ret);
break;
}
ent.principal);
if(ret){
kadm5_free_principal_ent(kadm_handlep, &ent);
- memset(password, 0, strlen(password));
- free(password);
goto fail;
}
if ((mask & KADM5_TL_DATA)) {
ret = check_aliases(contextp, &ent, NULL);
if (ret) {
kadm5_free_principal_ent(kadm_handlep, &ent);
- memset(password, 0, strlen(password));
- free(password);
goto fail;
}
}
ret = kadm5_create_principal(kadm_handlep, &ent,
mask, password);
kadm5_free_principal_ent(kadm_handlep, &ent);
- memset(password, 0, strlen(password));
- free(password);
krb5_storage_free(sp);
sp = krb5_storage_emem();
+ if (sp == NULL) {
+ ret = krb5_enomem(contextp->context);
+ goto fail;
+ }
krb5_store_int32(sp, ret);
break;
}
kadm5_free_principal_ent(kadm_handlep, &ent);
krb5_storage_free(sp);
sp = krb5_storage_emem();
+ if (sp == NULL) {
+ ret = krb5_enomem(contextp->context);
+ goto fail;
+ }
krb5_store_int32(sp, ret);
break;
}
+ case kadm_prune:{
+ op = "PRUNE";
+ ret = krb5_ret_principal(sp, &princ);
+ if (ret)
+ goto fail;
+ ret = krb5_ret_int32(sp, &kvno);
+ if (ret == HEIM_ERR_EOF) {
+ kvno = 0;
+ } else if (ret) {
+ goto fail;
+ }
+ krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name));
+ krb5_warnx(contextp->context, "%s: %s %s", client, op, name);
+ ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ);
+ if (ret)
+ goto fail;
+
+ ret = kadm5_prune_principal(kadm_handlep, princ, kvno);
+ krb5_storage_free(sp);
+ sp = krb5_storage_emem();
+ if (sp == NULL) {
+ ret = krb5_enomem(contextp->context);
+ goto fail;
+ }
+ krb5_store_int32(sp, ret);
+ break;
+ }
case kadm_rename:{
op = "RENAME";
ret = krb5_ret_principal(sp, &princ);
if(ret)
goto fail;
ret = krb5_ret_principal(sp, &princ2);
- if(ret){
- krb5_free_principal(contextp->context, princ);
+ if (ret)
goto fail;
- }
+
krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name));
krb5_unparse_name_fixed(contextp->context, princ2,
name2, sizeof(name2));
princ);
}
}
- if(ret){
- krb5_free_principal(contextp->context, princ);
- krb5_free_principal(contextp->context, princ2);
+ if (ret)
goto fail;
- }
+
ret = kadm5_rename_principal(kadm_handlep, princ, princ2);
- krb5_free_principal(contextp->context, princ);
- krb5_free_principal(contextp->context, princ2);
krb5_storage_free(sp);
sp = krb5_storage_emem();
+ if (sp == NULL) {
+ ret = krb5_enomem(contextp->context);
+ goto fail;
+ }
krb5_store_int32(sp, ret);
break;
}
case kadm_chpass:{
+ krb5_boolean is_self_cpw, allow_self_cpw;
+
op = "CHPASS";
ret = krb5_ret_principal(sp, &princ);
if (ret)
goto fail;
ret = krb5_ret_string(sp, &password);
- if (ret) {
- krb5_free_principal(contextp->context, princ);
+ if (ret)
goto fail;
- }
+
ret = krb5_ret_int32(sp, &keepold);
- if (ret && ret != HEIM_ERR_EOF) {
- krb5_free_principal(contextp->context, princ);
+ if (ret && ret != HEIM_ERR_EOF)
goto fail;
- }
+
krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name));
krb5_warnx(contextp->context, "%s: %s %s", client, op, name);
/*
- * The change is allowed if at least one of:
- *
- * a) allowed by sysadmin
- * b) it's for the principal him/herself and this was an
- * initial ticket, but then, check with the password quality
- * function.
- * c) the user is on the CPW ACL.
+ * Change password requests are subject to ACLs unless the principal is
+ * changing their own password and the initial ticket flag is set, and
+ * the allow_self_change_password configuration option is TRUE.
*/
-
- if (krb5_config_get_bool_default(contextp->context, NULL, TRUE,
- "kadmin", "allow_self_change_password", NULL)
- && initial
- && krb5_principal_compare (contextp->context, contextp->caller,
- princ))
- {
- krb5_data pwd_data;
- const char *pwd_reason;
-
- pwd_data.data = password;
- pwd_data.length = strlen(password);
-
- pwd_reason = kadm5_check_password_quality (contextp->context,
- princ, &pwd_data);
- if (pwd_reason != NULL)
- ret = KADM5_PASS_Q_DICT;
- else
- ret = 0;
- } else
+ is_self_cpw =
+ krb5_principal_compare(contextp->context, contextp->caller, princ);
+ allow_self_cpw =
+ krb5_config_get_bool_default(contextp->context, NULL, TRUE,
+ "kadmin", "allow_self_change_password", NULL);
+ if (!(is_self_cpw && initial && allow_self_cpw)) {
ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ);
-
- if(ret) {
- krb5_free_principal(contextp->context, princ);
- memset(password, 0, strlen(password));
- free(password);
- goto fail;
+ if (ret)
+ goto fail;
}
+
ret = kadm5_chpass_principal_3(kadm_handlep, princ, keepold, 0, NULL,
password);
- krb5_free_principal(contextp->context, princ);
- memset(password, 0, strlen(password));
- free(password);
krb5_storage_free(sp);
sp = krb5_storage_emem();
+ if (sp == NULL) {
+ ret = krb5_enomem(contextp->context);
+ goto fail;
+ }
krb5_store_int32(sp, ret);
break;
}
if(ret)
goto fail;
ret = krb5_ret_int32(sp, &n_key_data);
- if (ret) {
- krb5_free_principal(contextp->context, princ);
+ if (ret)
goto fail;
- }
+
ret = krb5_ret_int32(sp, &keepold);
- if (ret && ret != HEIM_ERR_EOF) {
- krb5_free_principal(contextp->context, princ);
+ if (ret && ret != HEIM_ERR_EOF)
goto fail;
- }
+
/* n_key_data will be squeezed into an int16_t below. */
if (n_key_data < 0 || n_key_data >= 1 << 16 ||
(size_t)n_key_data > UINT_MAX/sizeof(*key_data)) {
ret = ERANGE;
- krb5_free_principal(contextp->context, princ);
goto fail;
}
key_data = malloc (n_key_data * sizeof(*key_data));
if (key_data == NULL && n_key_data != 0) {
- ret = ENOMEM;
- krb5_free_principal(contextp->context, princ);
+ ret = krb5_enomem(contextp->context);
goto fail;
}
kadm5_free_key_data (contextp, &dummy, key_data);
free (key_data);
- krb5_free_principal(contextp->context, princ);
goto fail;
}
}
kadm5_free_key_data (contextp, &dummy, key_data);
free (key_data);
- krb5_free_principal(contextp->context, princ);
goto fail;
}
ret = kadm5_chpass_principal_with_key_3(kadm_handlep, princ, keepold,
kadm5_free_key_data (contextp, &dummy, key_data);
}
free (key_data);
- krb5_free_principal(contextp->context, princ);
krb5_storage_free(sp);
sp = krb5_storage_emem();
+ if (sp == NULL) {
+ ret = krb5_enomem(contextp->context);
+ goto fail;
+ }
krb5_store_int32(sp, ret);
break;
}
case kadm_randkey:{
+ size_t i;
+
op = "RANDKEY";
ret = krb5_ret_principal(sp, &princ);
- if(ret)
+ if (ret)
goto fail;
krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name));
krb5_warnx(contextp->context, "%s: %s %s", client, op, name);
else
ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ);
- if(ret) {
- krb5_free_principal(contextp->context, princ);
+ if (ret)
goto fail;
- }
/*
* See comments in kadm5_c_randkey_principal() regarding the
* protocol.
*/
ret = krb5_ret_int32(sp, &keepold);
- if (ret != 0 && ret != HEIM_ERR_EOF) {
- krb5_free_principal(contextp->context, princ);
+ if (ret != 0 && ret != HEIM_ERR_EOF)
goto fail;
- }
ret = krb5_ret_int32(sp, &n_ks_tuple);
- if (ret != 0 && ret != HEIM_ERR_EOF) {
- krb5_free_principal(contextp->context, princ);
+ if (ret == HEIM_ERR_EOF) {
+ const char *enctypes;
+ size_t n;
+
+ enctypes = krb5_config_get_string(contextp->context, NULL,
+ "realms",
+ krb5_principal_get_realm(contextp->context,
+ princ),
+ "supported_enctypes", NULL);
+ if (enctypes == NULL || enctypes[0] == '\0')
+ enctypes = "aes128-cts-hmac-sha1-96";
+ ret = krb5_string_to_keysalts2(contextp->context, enctypes,
+ &n, &ks_tuple);
+ n_ks_tuple = n;
+ }
+ if (ret != 0)
goto fail;
- } else if (ret == 0) {
- size_t i;
- if (n_ks_tuple < 0) {
- ret = EOVERFLOW;
- krb5_free_principal(contextp->context, princ);
- goto fail;
- }
+ if (n_ks_tuple < 0) {
+ ret = EOVERFLOW;
+ goto fail;
+ }
- if ((ks_tuple = calloc(n_ks_tuple, sizeof (*ks_tuple))) == NULL) {
- ret = errno;
- krb5_free_principal(contextp->context, princ);
- goto fail;
- }
+ if ((ks_tuple = calloc(n_ks_tuple, sizeof (*ks_tuple))) == NULL) {
+ ret = errno;
+ goto fail;
+ }
- for (i = 0; i < n_ks_tuple; i++) {
- ret = krb5_ret_int32(sp, &ks_tuple[i].ks_enctype);
- if (ret != 0) {
- krb5_free_principal(contextp->context, princ);
- goto fail;
- }
- ret = krb5_ret_int32(sp, &ks_tuple[i].ks_salttype);
- if (ret != 0) {
- krb5_free_principal(contextp->context, princ);
- goto fail;
- }
- }
- }
+ for (i = 0; i < n_ks_tuple; i++) {
+ ret = krb5_ret_int32(sp, &ks_tuple[i].ks_enctype);
+ if (ret != 0) {
+ free(ks_tuple);
+ goto fail;
+ }
+ ret = krb5_ret_int32(sp, &ks_tuple[i].ks_salttype);
+ if (ret != 0) {
+ free(ks_tuple);
+ goto fail;
+ }
+ }
ret = kadm5_randkey_principal_3(kadm_handlep, princ, keepold,
n_ks_tuple, ks_tuple, &new_keys,
&n_keys);
- krb5_free_principal(contextp->context, princ);
+ free(ks_tuple);
krb5_storage_free(sp);
sp = krb5_storage_emem();
+ if (sp == NULL) {
+ ret = krb5_enomem(contextp->context);
+ goto fail;
+ }
krb5_store_int32(sp, ret);
- if(ret == 0){
- int i;
+ if (ret == 0){
krb5_store_int32(sp, n_keys);
- for(i = 0; i < n_keys; i++){
- krb5_store_keyblock(sp, new_keys[i]);
+ for (i = 0; i < n_keys; i++){
+ if (ret == 0)
+ ret = krb5_store_keyblock(sp, new_keys[i]);
krb5_free_keyblock_contents(contextp->context, &new_keys[i]);
}
free(new_keys);
ret = kadm5_get_privs(kadm_handlep, &privs);
krb5_storage_free(sp);
sp = krb5_storage_emem();
+ if (sp == NULL) {
+ ret = krb5_enomem(contextp->context);
+ goto fail;
+ }
krb5_store_int32(sp, ret);
if(ret == 0)
krb5_store_uint32(sp, privs);
free(expression);
krb5_storage_free(sp);
sp = krb5_storage_emem();
+ if (sp == NULL) {
+ ret = krb5_enomem(contextp->context);
+ goto fail;
+ }
krb5_store_int32(sp, ret);
if(ret == 0){
int i;
krb5_warnx(contextp->context, "%s: UNKNOWN OP %d", client, cmd);
krb5_storage_free(sp);
sp = krb5_storage_emem();
+ if (sp == NULL) {
+ ret = krb5_enomem(contextp->context);
+ goto fail;
+ }
krb5_store_int32(sp, KADM5_FAILURE);
break;
}
+ if (password != NULL) {
+ len = strlen(password);
+ memset_s(password, len, 0, len);
+ free(password);
+ }
krb5_storage_to_data(sp, out);
krb5_storage_free(sp);
+ if (princ != NULL)
+ krb5_free_principal(contextp->context, princ);
+ if (princ2 != NULL)
+ krb5_free_principal(contextp->context, princ2);
return 0;
fail:
+ if (password != NULL) {
+ len = strlen(password);
+ memset_s(password, len, 0, len);
+ free(password);
+ }
krb5_warn(contextp->context, ret, "%s", op);
- krb5_storage_seek(sp, 0, SEEK_SET);
- krb5_store_int32(sp, ret);
- krb5_storage_to_data(sp, out);
- krb5_storage_free(sp);
+ if (sp != NULL) {
+ krb5_storage_seek(sp, 0, SEEK_SET);
+ krb5_store_int32(sp, ret);
+ krb5_storage_to_data(sp, out);
+ krb5_storage_free(sp);
+ }
+ if (princ != NULL)
+ krb5_free_principal(contextp->context, princ);
+ if (princ2 != NULL)
+ krb5_free_principal(contextp->context, princ2);
return 0;
}
if(ret)
krb5_err(contextp, 1, ret, "krb5_read_priv_message");
doing_useful_work = 1;
- kadmind_dispatch(kadm_handlep, initial, &in, &out);
+ ret = kadmind_dispatch(kadm_handlep, initial, &in, &out);
+ if (ret)
+ krb5_err(contextp, 1, ret, "kadmind_dispatch");
krb5_data_free(&in);
ret = krb5_write_priv_message(contextp, ac, &fd, &out);
+ krb5_data_free(&out);
if(ret)
krb5_err(contextp, 1, ret, "krb5_write_priv_message");
}
krb5_boolean initial;
krb5_auth_context ac = NULL;
- unsigned kadm_version;
+ unsigned kadm_version = 1;
kadm5_config_params realm_params;
ret = krb5_recvauth_match_version(contextp, &ac, &fd,
return 0;
}
+