varlink,json: introduce new varlink_dispatch() helper

varlink_dispatch() is a simple wrapper around json_dispatch() that
returns clean, standards-compliant InvalidParameter error back to
clients, if the specified JSON cannot be parsed properly.

For this json_dispatch() is extended to return the offending field's
name. Because it already has quite a few parameters, I then renamed
json_dispatch() to json_dispatch_full() and made json_dispatch() a
wrapper around it that passes the new argument as NULL. While doing so I
figured we should also get rid of the bad= argument in the short
wrapper, since it's only used in the OCI code.

To simplify the OCI code this adds a second wrapper oci_dispatch()
around json_dispatch_full(), that fills in bad= the way we want.

Net result: instead of one json_dispatch() call there are now:

1. json_dispatch_full() for the fully feature mother of all dispathers.
2. json_dispatch() for the simpler version that you want to use most of
   the time.
3. varlink_dispatch() that generates nice Varlink errors
4. oci_dispatch() that does the OCI specific error handling

And that's all there is.
This commit is contained in:
Lennart Poettering
2023-11-02 01:19:21 +00:00
committed by Luca Boccassi
parent d0404391e5
commit f1b622a00c
24 changed files with 171 additions and 116 deletions
+5 -5
View File
@@ -50,7 +50,7 @@ static int dispatch_privileged(const char *name, JsonVariant *variant, JsonDispa
{},
};
return json_dispatch(variant, privileged_dispatch_table, NULL, flags, userdata);
return json_dispatch(variant, privileged_dispatch_table, flags, userdata);
}
static int dispatch_binding(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
@@ -78,7 +78,7 @@ static int dispatch_binding(const char *name, JsonVariant *variant, JsonDispatch
if (!m)
return 0;
return json_dispatch(m, binding_dispatch_table, NULL, flags, userdata);
return json_dispatch(m, binding_dispatch_table, flags, userdata);
}
static int dispatch_per_machine(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
@@ -131,7 +131,7 @@ static int dispatch_per_machine(const char *name, JsonVariant *variant, JsonDisp
if (!matching)
continue;
r = json_dispatch(e, per_machine_dispatch_table, NULL, flags, userdata);
r = json_dispatch(e, per_machine_dispatch_table, flags, userdata);
if (r < 0)
return r;
}
@@ -164,7 +164,7 @@ static int dispatch_status(const char *name, JsonVariant *variant, JsonDispatchF
if (!m)
return 0;
return json_dispatch(m, status_dispatch_table, NULL, flags, userdata);
return json_dispatch(m, status_dispatch_table, flags, userdata);
}
static int group_record_augment(GroupRecord *h, JsonDispatchFlags json_flags) {
@@ -230,7 +230,7 @@ int group_record_load(
if (r < 0)
return r;
r = json_dispatch(h->json, group_dispatch_table, NULL, json_flags, h);
r = json_dispatch(h->json, group_dispatch_table, json_flags, h);
if (r < 0)
return r;
+30 -3
View File
@@ -4484,7 +4484,13 @@ static void *dispatch_userdata(const JsonDispatch *p, void *userdata) {
return SIZE_TO_PTR(p->offset);
}
int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallback bad, JsonDispatchFlags flags, void *userdata) {
int json_dispatch_full(
JsonVariant *v,
const JsonDispatch table[],
JsonDispatchCallback bad,
JsonDispatchFlags flags,
void *userdata,
const char **reterr_bad_field) {
size_t m;
int r, done = 0;
bool *found;
@@ -4495,6 +4501,9 @@ int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallba
if (flags & JSON_PERMISSIVE)
return 0;
if (reterr_bad_field)
*reterr_bad_field = NULL;
return -EINVAL;
}
@@ -4517,7 +4526,7 @@ int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallba
streq_ptr(json_variant_string(key), p->name))
break;
if (p->name) { /* Found a matching entry! :-) */
if (p->name) { /* Found a matching entry! 🙂 */
JsonDispatchFlags merged_flags;
merged_flags = flags | p->flags;
@@ -4532,6 +4541,9 @@ int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallba
if (merged_flags & JSON_PERMISSIVE)
continue;
if (reterr_bad_field)
*reterr_bad_field = p->name;
return -EINVAL;
}
@@ -4541,6 +4553,9 @@ int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallba
if (merged_flags & JSON_PERMISSIVE)
continue;
if (reterr_bad_field)
*reterr_bad_field = p->name;
return -ENOTUNIQ;
}
@@ -4552,13 +4567,16 @@ int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallba
if (merged_flags & JSON_PERMISSIVE)
continue;
if (reterr_bad_field)
*reterr_bad_field = json_variant_string(key);
return r;
}
}
done ++;
} else { /* Didn't find a matching entry! :-( */
} else { /* Didn't find a matching entry! ☹️ */
if (bad) {
r = bad(json_variant_string(key), value, flags, userdata);
@@ -4566,6 +4584,9 @@ int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallba
if (flags & JSON_PERMISSIVE)
continue;
if (reterr_bad_field)
*reterr_bad_field = json_variant_string(key);
return r;
} else
done ++;
@@ -4576,6 +4597,9 @@ int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallba
if (flags & JSON_PERMISSIVE)
continue;
if (reterr_bad_field)
*reterr_bad_field = json_variant_string(key);
return -EADDRNOTAVAIL;
}
}
@@ -4590,6 +4614,9 @@ int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallba
if ((merged_flags & JSON_PERMISSIVE))
continue;
if (reterr_bad_field)
*reterr_bad_field = p->name;
return -ENXIO;
}
}
+5 -1
View File
@@ -396,7 +396,11 @@ typedef struct JsonDispatch {
JsonDispatchFlags flags;
} JsonDispatch;
int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallback bad, JsonDispatchFlags flags, void *userdata);
int json_dispatch_full(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallback bad, JsonDispatchFlags flags, void *userdata, const char **reterr_bad_field);
static inline int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchFlags flags, void *userdata) {
return json_dispatch_full(v, table, NULL, flags, userdata, NULL);
}
int json_dispatch_string(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
int json_dispatch_const_string(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
+9 -9
View File
@@ -657,7 +657,7 @@ static int dispatch_secret(const char *name, JsonVariant *variant, JsonDispatchF
{},
};
return json_dispatch(variant, secret_dispatch_table, NULL, flags, userdata);
return json_dispatch(variant, secret_dispatch_table, flags, userdata);
}
static int dispatch_pkcs11_uri(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
@@ -786,7 +786,7 @@ static int dispatch_pkcs11_key(const char *name, JsonVariant *variant, JsonDispa
k = h->pkcs11_encrypted_key + h->n_pkcs11_encrypted_key;
*k = (Pkcs11EncryptedKey) {};
r = json_dispatch(e, pkcs11_key_dispatch_table, NULL, flags, k);
r = json_dispatch(e, pkcs11_key_dispatch_table, flags, k);
if (r < 0) {
pkcs11_encrypted_key_done(k);
return r;
@@ -920,7 +920,7 @@ static int dispatch_fido2_hmac_salt(const char *name, JsonVariant *variant, Json
.client_pin = -1,
};
r = json_dispatch(e, fido2_hmac_salt_dispatch_table, NULL, flags, k);
r = json_dispatch(e, fido2_hmac_salt_dispatch_table, flags, k);
if (r < 0) {
fido2_hmac_salt_done(k);
return r;
@@ -960,7 +960,7 @@ static int dispatch_recovery_key(const char *name, JsonVariant *variant, JsonDis
k = h->recovery_key + h->n_recovery_key;
*k = (RecoveryKey) {};
r = json_dispatch(e, recovery_key_dispatch_table, NULL, flags, k);
r = json_dispatch(e, recovery_key_dispatch_table, flags, k);
if (r < 0) {
recovery_key_done(k);
return r;
@@ -1042,7 +1042,7 @@ static int dispatch_privileged(const char *name, JsonVariant *variant, JsonDispa
{},
};
return json_dispatch(variant, privileged_dispatch_table, NULL, flags, userdata);
return json_dispatch(variant, privileged_dispatch_table, flags, userdata);
}
static int dispatch_binding(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
@@ -1081,7 +1081,7 @@ static int dispatch_binding(const char *name, JsonVariant *variant, JsonDispatch
if (!m)
return 0;
return json_dispatch(m, binding_dispatch_table, NULL, flags, userdata);
return json_dispatch(m, binding_dispatch_table, flags, userdata);
}
int per_machine_id_match(JsonVariant *ids, JsonDispatchFlags flags) {
@@ -1283,7 +1283,7 @@ static int dispatch_per_machine(const char *name, JsonVariant *variant, JsonDisp
if (!matching)
continue;
r = json_dispatch(e, per_machine_dispatch_table, NULL, flags, userdata);
r = json_dispatch(e, per_machine_dispatch_table, flags, userdata);
if (r < 0)
return r;
}
@@ -1332,7 +1332,7 @@ static int dispatch_status(const char *name, JsonVariant *variant, JsonDispatchF
if (!m)
return 0;
return json_dispatch(m, status_dispatch_table, NULL, flags, userdata);
return json_dispatch(m, status_dispatch_table, flags, userdata);
}
int user_record_build_image_path(UserStorage storage, const char *user_name_and_realm, char **ret) {
@@ -1625,7 +1625,7 @@ int user_record_load(UserRecord *h, JsonVariant *v, UserRecordLoadFlags load_fla
if (r < 0)
return r;
r = json_dispatch(h->json, user_dispatch_table, NULL, json_flags, h);
r = json_dispatch(h->json, user_dispatch_table, json_flags, h);
if (r < 0)
return r;
+3 -3
View File
@@ -199,7 +199,7 @@ static int userdb_on_query_reply(
assert_se(!iterator->found_user);
r = json_dispatch(parameters, dispatch_table, NULL, 0, &user_data);
r = json_dispatch(parameters, dispatch_table, 0, &user_data);
if (r < 0)
goto finish;
@@ -256,7 +256,7 @@ static int userdb_on_query_reply(
assert_se(!iterator->found_group);
r = json_dispatch(parameters, dispatch_table, NULL, 0, &group_data);
r = json_dispatch(parameters, dispatch_table, 0, &group_data);
if (r < 0)
goto finish;
@@ -309,7 +309,7 @@ static int userdb_on_query_reply(
assert(!iterator->found_user_name);
assert(!iterator->found_group_name);
r = json_dispatch(parameters, dispatch_table, NULL, 0, &membership_data);
r = json_dispatch(parameters, dispatch_table, 0, &membership_data);
if (r < 0)
goto finish;
+2 -2
View File
@@ -48,8 +48,8 @@ int varlink_method_set_log_level(Varlink *link, JsonVariant *parameters, Varlink
if (json_variant_elements(parameters) != 2)
return varlink_error_invalid_parameter(link, parameters);
r = json_dispatch(parameters, dispatch_table, NULL, 0, &level);
if (r < 0)
r = varlink_dispatch(link, parameters, dispatch_table, &level);
if (r != 0)
return r;
if (LOG_PRI(level) != level)
+21 -1
View File
@@ -1205,7 +1205,7 @@ static int generic_method_get_interface_description(
assert(link);
r = json_dispatch(parameters, dispatch_table, NULL, 0, &name);
r = json_dispatch(parameters, dispatch_table, 0, &name);
if (r < 0)
return r;
@@ -2479,6 +2479,26 @@ int varlink_notifyb(Varlink *v, ...) {
return varlink_notify(v, parameters);
}
int varlink_dispatch(Varlink *v, JsonVariant *parameters, const JsonDispatch table[], void *userdata) {
const char *bad_field = NULL;
int r;
assert_return(v, -EINVAL);
assert_return(table, -EINVAL);
/* A wrapper around json_dispatch_full() that returns a nice InvalidParameter error if we hit a problem with some field. */
r = json_dispatch_full(parameters, table, /* bad= */ NULL, /* flags= */ 0, userdata, &bad_field);
if (r < 0) {
if (bad_field)
return varlink_errorb(v, VARLINK_ERROR_INVALID_PARAMETER,
JSON_BUILD_OBJECT(JSON_BUILD_PAIR("parameter", JSON_BUILD_STRING(bad_field))));
return r;
}
return 0;
}
int varlink_bind_reply(Varlink *v, VarlinkReply callback) {
assert_return(v, -EINVAL);
+3
View File
@@ -115,6 +115,9 @@ int varlink_error_errno(Varlink *v, int error);
int varlink_notify(Varlink *v, JsonVariant *parameters);
int varlink_notifyb(Varlink *v, ...);
/* Parsing incoming data via json_dispatch() and generate a nice error on parse errors */
int varlink_dispatch(Varlink *v, JsonVariant *parameters, const JsonDispatch table[], void *userdata);
/* Write outgoing fds into the socket (to be associated with the next enqueued message) */
int varlink_push_fd(Varlink *v, int fd);
int varlink_dup_fd(Varlink *v, int fd);