diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index b60a0fd1f2..afe67d9e6c 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -260,7 +260,12 @@ finish: dns_query_free(q); } -static int validate_and_mangle_ifindex_and_flags(int ifindex, uint64_t *flags, uint64_t ok, sd_bus_error *error) { +static int validate_and_mangle_flags( + const char *name, + uint64_t *flags, + uint64_t ok, + sd_bus_error *error) { + assert(flags); /* Checks that the client supplied interface index and flags parameter actually are valid and make @@ -277,15 +282,16 @@ static int validate_and_mangle_ifindex_and_flags(int ifindex, uint64_t *flags, u * to mean "all supported protocols". */ - if (ifindex < 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index"); - if (*flags & ~(SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_CNAME|ok)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter"); if ((*flags & SD_RESOLVED_PROTOCOLS_ALL) == 0) /* If no protocol is enabled, enable all */ *flags |= SD_RESOLVED_PROTOCOLS_ALL; + /* Imply SD_RESOLVED_NO_SEARCH if permitted and name is dot suffixed. */ + if (name && FLAGS_SET(ok, SD_RESOLVED_NO_SEARCH) && dns_name_dot_suffixed(name) > 0) + *flags |= SD_RESOLVED_NO_SEARCH; + return 0; } @@ -371,10 +377,13 @@ static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata, if (r < 0) return r; + if (ifindex < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index"); + if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family); - r = validate_and_mangle_ifindex_and_flags(ifindex, &flags, SD_RESOLVED_NO_SEARCH, error); + r = validate_and_mangle_flags(hostname, &flags, SD_RESOLVED_NO_SEARCH, error); if (r < 0) return r; @@ -527,7 +536,10 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s if (r < 0) return r; - r = validate_and_mangle_ifindex_and_flags(ifindex, &flags, 0, error); + if (ifindex < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index"); + + r = validate_and_mangle_flags(NULL, &flags, 0, error); if (r < 0) return r; @@ -679,6 +691,9 @@ static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd if (r < 0) return r; + if (ifindex < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index"); + r = dns_name_is_valid(name); if (r < 0) return r; @@ -692,7 +707,7 @@ static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd if (dns_type_is_obsolete(type)) return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Specified DNS resource record type %" PRIu16 " is obsolete.", type); - r = validate_and_mangle_ifindex_and_flags(ifindex, &flags, 0, error); + r = validate_and_mangle_flags(name, &flags, 0, error); if (r < 0) return r; @@ -1205,6 +1220,9 @@ static int bus_method_resolve_service(sd_bus_message *message, void *userdata, s if (r < 0) return r; + if (ifindex < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index"); + if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family); @@ -1227,7 +1245,7 @@ static int bus_method_resolve_service(sd_bus_message *message, void *userdata, s if (name && !type) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Service name cannot be specified without service type."); - r = validate_and_mangle_ifindex_and_flags(ifindex, &flags, SD_RESOLVED_NO_TXT|SD_RESOLVED_NO_ADDRESS, error); + r = validate_and_mangle_flags(name, &flags, SD_RESOLVED_NO_TXT|SD_RESOLVED_NO_ADDRESS, error); if (r < 0) return r; diff --git a/src/resolve/resolved-varlink.c b/src/resolve/resolved-varlink.c index 2a65293c2a..2f11a78091 100644 --- a/src/resolve/resolved-varlink.c +++ b/src/resolve/resolved-varlink.c @@ -93,7 +93,11 @@ static void vl_on_disconnect(VarlinkServer *s, Varlink *link, void *userdata) { dns_query_complete(q, DNS_TRANSACTION_ABORTED); } -static bool validate_and_mangle_flags(uint64_t *flags, uint64_t ok) { +static bool validate_and_mangle_flags( + const char *name, + uint64_t *flags, + uint64_t ok) { + assert(flags); /* This checks that the specified client-provided flags parameter actually makes sense, and mangles @@ -116,6 +120,12 @@ static bool validate_and_mangle_flags(uint64_t *flags, uint64_t ok) { if ((*flags & SD_RESOLVED_PROTOCOLS_ALL) == 0) /* If no protocol is enabled, enable all */ *flags |= SD_RESOLVED_PROTOCOLS_ALL; + /* If the SD_RESOLVED_NO_SEARCH flag is acceptable, and the query name is dot-suffixed, turn off + * search domains. Note that DNS name normalization drops the dot suffix, hence we propagate this + * into the flags field as early as we can. */ + if (name && FLAGS_SET(ok, SD_RESOLVED_NO_SEARCH) && dns_name_dot_suffixed(name) > 0) + *flags |= SD_RESOLVED_NO_SEARCH; + return true; } @@ -285,7 +295,7 @@ static int vl_method_resolve_hostname(Varlink *link, JsonVariant *parameters, Va if (!IN_SET(p.family, AF_UNSPEC, AF_INET, AF_INET6)) return varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("family")); - if (!validate_and_mangle_flags(&p.flags, SD_RESOLVED_NO_SEARCH)) + if (!validate_and_mangle_flags(p.name, &p.flags, SD_RESOLVED_NO_SEARCH)) return varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("flags")); r = parse_as_address(link, &p); @@ -460,7 +470,7 @@ static int vl_method_resolve_address(Varlink *link, JsonVariant *parameters, Var if (FAMILY_ADDRESS_SIZE(p.family) != p.address_size) return varlink_error(link, "io.systemd.UserDatabase.BadAddressSize", NULL); - if (!validate_and_mangle_flags(&p.flags, 0)) + if (!validate_and_mangle_flags(NULL, &p.flags, 0)) return varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("flags")); r = dns_question_new_reverse(&question, p.family, &p.address);