kadmind: Send error code back... on error!

Seeing "End of file" errors from kadm5 client calls which were the
result of not sending back errors in many error paths in
kadmin/server.c:kadmind_dispatch().
This commit is contained in:
Nicolas Williams
2022-03-19 18:10:44 -05:00
parent 7556a114e1
commit 14ce7bbaca

View File

@@ -81,18 +81,39 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
client, sizeof(client)); client, sizeof(client));
if (ret == 0) if (ret == 0)
ret = krb5_ret_int32(sp, &cmd); ret = krb5_ret_int32(sp, &cmd);
if (ret) if (ret) {
ret_sp = krb5_store_int32(rsp, KADM5_FAILURE);
goto fail; goto fail;
}
switch(cmd){ switch(cmd){
case kadm_nop:{
/*
* In the future we could use this for versioning.
*
* We used to respond to NOPs with KADM5_FAILURE. Now we respond with
* zero. In the future we could send back a protocol version number
* and use NOPs for protocol version negotiation.
*
* In the meantime, this gets called only if a client wants to
* interrupt a long-running LIST operation.
*/
op = "NOP";
ret_sp = krb5_store_int32(rsp, ret = 0);
break;
}
case kadm_get:{ case kadm_get:{
op = "GET"; op = "GET";
ret = krb5_ret_principal(sp, &princ); ret = krb5_ret_principal(sp, &princ);
if(ret) if (ret) {
ret_sp = krb5_store_int32(rsp, KADM5_UNK_PRINC);
goto fail; goto fail;
}
ret = krb5_ret_int32(sp, &mask); ret = krb5_ret_int32(sp, &mask);
if (ret) if (ret) {
ret_sp = krb5_store_int32(rsp, KADM5_FAILURE);
goto fail; goto fail;
}
mask |= KADM5_PRINCIPAL; mask |= KADM5_PRINCIPAL;
krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name));
@@ -100,8 +121,10 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
/* If the caller doesn't have KADM5_PRIV_GET, we're done. */ /* If the caller doesn't have KADM5_PRIV_GET, we're done. */
ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_GET, princ); ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_GET, princ);
if (ret) if (ret) {
ret_sp = krb5_store_int32(rsp, ret);
goto fail; goto fail;
}
/* Then check to see if it is ok to return keys */ /* Then check to see if it is ok to return keys */
if ((mask & KADM5_KEY_DATA) != 0) { if ((mask & KADM5_KEY_DATA) != 0) {
@@ -129,6 +152,7 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
* modes request other things too, so in all likelihood this * modes request other things too, so in all likelihood this
* heuristic will not hurt any kadmin get uses. * heuristic will not hurt any kadmin get uses.
*/ */
ret_sp = krb5_store_int32(rsp, ret);
goto fail; goto fail;
} }
} }
@@ -147,7 +171,7 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
case kadm_delete:{ case kadm_delete:{
op = "DELETE"; op = "DELETE";
if (readonly) { if (readonly) {
ret = KADM5_READ_ONLY; ret_sp = krb5_store_int32(rsp, ret = KADM5_READ_ONLY);
goto fail; goto fail;
} }
ret = krb5_ret_principal(sp, &princ); ret = krb5_ret_principal(sp, &princ);
@@ -171,19 +195,23 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
case kadm_create:{ case kadm_create:{
op = "CREATE"; op = "CREATE";
if (readonly) { if (readonly) {
ret = KADM5_READ_ONLY; ret_sp = krb5_store_int32(rsp, ret = KADM5_READ_ONLY);
goto fail; goto fail;
} }
ret = kadm5_ret_principal_ent(sp, &ent); ret = kadm5_ret_principal_ent(sp, &ent);
if(ret) if(ret) {
ret_sp = krb5_store_int32(rsp, ret);
goto fail; goto fail;
}
ret = krb5_ret_int32(sp, &mask); ret = krb5_ret_int32(sp, &mask);
if(ret){ if(ret){
ret_sp = krb5_store_int32(rsp, KADM5_FAILURE);
kadm5_free_principal_ent(kadm_handlep, &ent); kadm5_free_principal_ent(kadm_handlep, &ent);
goto fail; goto fail;
} }
ret = krb5_ret_string(sp, &password); ret = krb5_ret_string(sp, &password);
if(ret){ if(ret){
ret_sp = krb5_store_int32(rsp, KADM5_FAILURE);
kadm5_free_principal_ent(kadm_handlep, &ent); kadm5_free_principal_ent(kadm_handlep, &ent);
goto fail; goto fail;
} }
@@ -193,6 +221,7 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_ADD, ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_ADD,
ent.principal); ent.principal);
if(ret){ if(ret){
ret_sp = krb5_store_int32(rsp, ret);
kadm5_free_principal_ent(kadm_handlep, &ent); kadm5_free_principal_ent(kadm_handlep, &ent);
goto fail; goto fail;
} }
@@ -203,6 +232,7 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
*/ */
ret = check_aliases(contextp, &ent, NULL); ret = check_aliases(contextp, &ent, NULL);
if (ret) { if (ret) {
ret_sp = krb5_store_int32(rsp, KADM5_BAD_PRINCIPAL);
kadm5_free_principal_ent(kadm_handlep, &ent); kadm5_free_principal_ent(kadm_handlep, &ent);
goto fail; goto fail;
} }
@@ -216,14 +246,17 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
case kadm_modify:{ case kadm_modify:{
op = "MODIFY"; op = "MODIFY";
if (readonly) { if (readonly) {
ret = KADM5_READ_ONLY; ret_sp = krb5_store_int32(rsp, ret = KADM5_READ_ONLY);
goto fail; goto fail;
} }
ret = kadm5_ret_principal_ent(sp, &ent); ret = kadm5_ret_principal_ent(sp, &ent);
if(ret) if(ret) {
ret_sp = krb5_store_int32(rsp, KADM5_FAILURE);
goto fail; goto fail;
}
ret = krb5_ret_int32(sp, &mask); ret = krb5_ret_int32(sp, &mask);
if(ret){ if(ret){
ret_sp = krb5_store_int32(rsp, KADM5_FAILURE);
kadm5_free_principal_ent(contextp, &ent); kadm5_free_principal_ent(contextp, &ent);
goto fail; goto fail;
} }
@@ -233,6 +266,7 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_MODIFY, ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_MODIFY,
ent.principal); ent.principal);
if(ret){ if(ret){
ret_sp = krb5_store_int32(rsp, ret);
kadm5_free_principal_ent(contextp, &ent); kadm5_free_principal_ent(contextp, &ent);
goto fail; goto fail;
} }
@@ -245,12 +279,14 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
*/ */
ret = kadm5_get_principal(kadm_handlep, ent.principal, &ent_prev, mask); ret = kadm5_get_principal(kadm_handlep, ent.principal, &ent_prev, mask);
if (ret) { if (ret) {
ret_sp = krb5_store_int32(rsp, ret);
kadm5_free_principal_ent(contextp, &ent); kadm5_free_principal_ent(contextp, &ent);
goto fail; goto fail;
} }
ret = check_aliases(contextp, &ent, &ent_prev); ret = check_aliases(contextp, &ent, &ent_prev);
kadm5_free_principal_ent(contextp, &ent_prev); kadm5_free_principal_ent(contextp, &ent_prev);
if (ret) { if (ret) {
ret_sp = krb5_store_int32(rsp, KADM5_BAD_PRINCIPAL);
kadm5_free_principal_ent(contextp, &ent); kadm5_free_principal_ent(contextp, &ent);
goto fail; goto fail;
} }
@@ -263,23 +299,25 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
case kadm_prune:{ case kadm_prune:{
op = "PRUNE"; op = "PRUNE";
if (readonly) { if (readonly) {
ret = KADM5_READ_ONLY; ret_sp = krb5_store_int32(rsp, ret = KADM5_READ_ONLY);
goto fail; goto fail;
} }
ret = krb5_ret_principal(sp, &princ); ret = krb5_ret_principal(sp, &princ);
if (ret) if (ret == 0)
goto fail;
ret = krb5_ret_int32(sp, &kvno); ret = krb5_ret_int32(sp, &kvno);
if (ret == HEIM_ERR_EOF) { if (ret == HEIM_ERR_EOF) {
kvno = 0; kvno = 0;
} else if (ret) { } else if (ret) {
ret_sp = krb5_store_int32(rsp, KADM5_FAILURE);
goto fail; goto fail;
} }
krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name));
krb5_warnx(contextp->context, "%s: %s %s", client, op, name); krb5_warnx(contextp->context, "%s: %s %s", client, op, name);
ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ); ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ);
if (ret) if (ret) {
ret_sp = krb5_store_int32(rsp, ret);
goto fail; goto fail;
}
ret = kadm5_prune_principal(kadm_handlep, princ, kvno); ret = kadm5_prune_principal(kadm_handlep, princ, kvno);
ret_sp = krb5_store_int32(rsp, ret); ret_sp = krb5_store_int32(rsp, ret);
@@ -288,15 +326,16 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
case kadm_rename:{ case kadm_rename:{
op = "RENAME"; op = "RENAME";
if (readonly) { if (readonly) {
ret = KADM5_READ_ONLY; ret_sp = krb5_store_int32(rsp, ret = KADM5_READ_ONLY);
goto fail; goto fail;
} }
ret = krb5_ret_principal(sp, &princ); ret = krb5_ret_principal(sp, &princ);
if(ret) if (ret == 0)
goto fail;
ret = krb5_ret_principal(sp, &princ2); ret = krb5_ret_principal(sp, &princ2);
if (ret) if (ret) {
ret_sp = krb5_store_int32(rsp, KADM5_FAILURE);
goto fail; goto fail;
}
krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name));
krb5_unparse_name_fixed(contextp->context, princ2, krb5_unparse_name_fixed(contextp->context, princ2,
@@ -321,8 +360,10 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
princ); princ);
} }
} }
if (ret) if (ret) {
ret_sp = krb5_store_int32(rsp, ret);
goto fail; goto fail;
}
ret = kadm5_rename_principal(kadm_handlep, princ, princ2); ret = kadm5_rename_principal(kadm_handlep, princ, princ2);
ret_sp = krb5_store_int32(rsp, ret); ret_sp = krb5_store_int32(rsp, ret);
@@ -333,7 +374,7 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
op = "CHPASS"; op = "CHPASS";
if (readonly) { if (readonly) {
ret = KADM5_READ_ONLY; ret_sp = krb5_store_int32(rsp, ret = KADM5_READ_ONLY);
goto fail; goto fail;
} }
ret = krb5_ret_principal(sp, &princ); ret = krb5_ret_principal(sp, &princ);
@@ -348,8 +389,10 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
if (ret == 0) if (ret == 0)
krb5_warnx(contextp->context, "%s: %s %s", client, op, name); krb5_warnx(contextp->context, "%s: %s %s", client, op, name);
} }
if (ret) if (ret) {
ret_sp = krb5_store_int32(rsp, KADM5_FAILURE);
goto fail; goto fail;
}
/* /*
* Change password requests are subject to ACLs unless the principal is * Change password requests are subject to ACLs unless the principal is
@@ -363,9 +406,11 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
"kadmin", "allow_self_change_password", NULL); "kadmin", "allow_self_change_password", NULL);
if (!(is_self_cpw && initial && allow_self_cpw)) { if (!(is_self_cpw && initial && allow_self_cpw)) {
ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ); ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ);
if (ret) if (ret) {
ret_sp = krb5_store_int32(rsp, ret);
goto fail; goto fail;
} }
}
ret = kadm5_chpass_principal_3(kadm_handlep, princ, keepold, 0, NULL, ret = kadm5_chpass_principal_3(kadm_handlep, princ, keepold, 0, NULL,
password); password);
@@ -379,7 +424,7 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
op = "CHPASS_WITH_KEY"; op = "CHPASS_WITH_KEY";
if (readonly) { if (readonly) {
ret = KADM5_READ_ONLY; ret_sp = krb5_store_int32(rsp, ret = KADM5_READ_ONLY);
goto fail; goto fail;
} }
ret = krb5_ret_principal(sp, &princ); ret = krb5_ret_principal(sp, &princ);
@@ -390,18 +435,22 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
if (ret == HEIM_ERR_EOF) if (ret == HEIM_ERR_EOF)
ret = 0; ret = 0;
} }
if (ret) if (ret) {
ret_sp = krb5_store_int32(rsp, KADM5_FAILURE);
goto fail; goto fail;
}
/* n_key_data will be squeezed into an int16_t below. */ /* n_key_data will be squeezed into an int16_t below. */
if (n_key_data < 0 || n_key_data >= 1 << 16 || if (n_key_data < 0 || n_key_data >= 1 << 16 ||
(size_t)n_key_data > UINT_MAX/sizeof(*key_data)) { (size_t)n_key_data > UINT_MAX/sizeof(*key_data)) {
ret_sp = krb5_store_int32(rsp, KADM5_FAILURE);
ret = ERANGE; ret = ERANGE;
goto fail; goto fail;
} }
key_data = malloc (n_key_data * sizeof(*key_data)); key_data = malloc (n_key_data * sizeof(*key_data));
if (key_data == NULL && n_key_data != 0) { if (key_data == NULL && n_key_data != 0) {
ret_sp = krb5_store_int32(rsp, KADM5_FAILURE);
ret = krb5_enomem(contextp->context); ret = krb5_enomem(contextp->context);
goto fail; goto fail;
} }
@@ -413,6 +462,7 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
kadm5_free_key_data (contextp, &dummy, key_data); kadm5_free_key_data (contextp, &dummy, key_data);
free (key_data); free (key_data);
ret_sp = krb5_store_int32(rsp, KADM5_FAILURE);
goto fail; goto fail;
} }
} }
@@ -432,6 +482,7 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
kadm5_free_key_data (contextp, &dummy, key_data); kadm5_free_key_data (contextp, &dummy, key_data);
free (key_data); free (key_data);
ret_sp = krb5_store_int32(rsp, KADM5_FAILURE);
goto fail; goto fail;
} }
ret = kadm5_chpass_principal_with_key_3(kadm_handlep, princ, keepold, ret = kadm5_chpass_principal_with_key_3(kadm_handlep, princ, keepold,
@@ -449,12 +500,14 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
op = "RANDKEY"; op = "RANDKEY";
if (readonly) { if (readonly) {
ret = KADM5_READ_ONLY; ret_sp = krb5_store_int32(rsp, ret = KADM5_READ_ONLY);
goto fail; goto fail;
} }
ret = krb5_ret_principal(sp, &princ); ret = krb5_ret_principal(sp, &princ);
if (ret) if (ret) {
ret_sp = krb5_store_int32(rsp, KADM5_FAILURE);
goto fail; goto fail;
}
krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name)); krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name));
krb5_warnx(contextp->context, "%s: %s %s", client, op, name); krb5_warnx(contextp->context, "%s: %s %s", client, op, name);
/* /*
@@ -470,16 +523,20 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
else else
ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ); ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ);
if (ret) if (ret) {
ret_sp = krb5_store_int32(rsp, ret);
goto fail; goto fail;
}
/* /*
* See comments in kadm5_c_randkey_principal() regarding the * See comments in kadm5_c_randkey_principal() regarding the
* protocol. * protocol.
*/ */
ret = krb5_ret_int32(sp, &keepold); ret = krb5_ret_int32(sp, &keepold);
if (ret != 0 && ret != HEIM_ERR_EOF) if (ret != 0 && ret != HEIM_ERR_EOF) {
ret_sp = krb5_store_int32(rsp, KADM5_FAILURE);
goto fail; goto fail;
}
ret = krb5_ret_int32(sp, &n_ks_tuple); ret = krb5_ret_int32(sp, &n_ks_tuple);
if (ret == HEIM_ERR_EOF) { if (ret == HEIM_ERR_EOF) {
@@ -497,15 +554,19 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
&n, &ks_tuple); &n, &ks_tuple);
n_ks_tuple = n; n_ks_tuple = n;
} }
if (ret != 0) if (ret != 0) {
ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); /* XXX */
goto fail; goto fail;
}
if (n_ks_tuple < 0) { if (n_ks_tuple < 0) {
ret_sp = krb5_store_int32(rsp, KADM5_FAILURE); /* XXX */
ret = EOVERFLOW; ret = EOVERFLOW;
goto fail; goto fail;
} }
free(ks_tuple); free(ks_tuple);
if ((ks_tuple = calloc(n_ks_tuple, sizeof (*ks_tuple))) == NULL) { if ((ks_tuple = calloc(n_ks_tuple, sizeof (*ks_tuple))) == NULL) {
ret_sp = krb5_store_int32(rsp, KADM5_FAILURE);
ret = errno; ret = errno;
goto fail; goto fail;
} }
@@ -513,11 +574,13 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
for (i = 0; i < n_ks_tuple; i++) { for (i = 0; i < n_ks_tuple; i++) {
ret = krb5_ret_int32(sp, &ks_tuple[i].ks_enctype); ret = krb5_ret_int32(sp, &ks_tuple[i].ks_enctype);
if (ret != 0) { if (ret != 0) {
ret_sp = krb5_store_int32(rsp, KADM5_FAILURE);
free(ks_tuple); free(ks_tuple);
goto fail; goto fail;
} }
ret = krb5_ret_int32(sp, &ks_tuple[i].ks_salttype); ret = krb5_ret_int32(sp, &ks_tuple[i].ks_salttype);
if (ret != 0) { if (ret != 0) {
ret_sp = krb5_store_int32(rsp, KADM5_FAILURE);
free(ks_tuple); free(ks_tuple);
goto fail; goto fail;
} }