int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key) {
        _cleanup_(dns_transaction_freep) DnsTransaction *t = NULL;
        int r;

        assert(ret);
        assert(s);
        assert(key);

        r = hashmap_ensure_allocated(&s->manager->dns_transactions, NULL);
        if (r < 0)
                return r;

        r = hashmap_ensure_allocated(&s->transactions, &dns_resource_key_hash_ops);
        if (r < 0)
                return r;

        t = new0(DnsTransaction, 1);
        if (!t)
                return -ENOMEM;

        t->dns_udp_fd = -1;
        t->key = dns_resource_key_ref(key);

        /* Find a fresh, unused transaction id */
        do
                random_bytes(&t->id, sizeof(t->id));
        while (t->id == 0 ||
               hashmap_get(s->manager->dns_transactions, UINT_TO_PTR(t->id)));

        r = hashmap_put(s->manager->dns_transactions, UINT_TO_PTR(t->id), t);
        if (r < 0) {
                t->id = 0;
                return r;
        }

        r = hashmap_put(s->transactions, t->key, t);
        if (r < 0) {
                hashmap_remove(s->manager->dns_transactions, UINT_TO_PTR(t->id));
                return r;
        }

        t->scope = s;

        if (ret)
                *ret = t;

        t = NULL;

        return 0;
}
Exemple #2
0
static int device_set_sysfs(Device *d, const char *sysfs) {
        Device *first;
        char *copy;
        int r;

        assert(d);

        if (streq_ptr(d->sysfs, sysfs))
                return 0;

        r = hashmap_ensure_allocated(&UNIT(d)->manager->devices_by_sysfs, &string_hash_ops);
        if (r < 0)
                return r;

        copy = strdup(sysfs);
        if (!copy)
                return -ENOMEM;

        device_unset_sysfs(d);

        first = hashmap_get(UNIT(d)->manager->devices_by_sysfs, sysfs);
        LIST_PREPEND(same_sysfs, first, d);

        r = hashmap_replace(UNIT(d)->manager->devices_by_sysfs, copy, first);
        if (r < 0) {
                LIST_REMOVE(same_sysfs, first, d);
                free(copy);
                return r;
        }

        d->sysfs = copy;

        return 0;
}
Exemple #3
0
int link_new(Manager *m, Link **ret, int ifindex) {
        _cleanup_(link_freep) Link *l = NULL;
        int r;

        assert(m);
        assert(ifindex > 0);

        r = hashmap_ensure_allocated(&m->links, NULL);
        if (r < 0)
                return r;

        l = new0(Link, 1);
        if (!l)
                return -ENOMEM;

        l->ifindex = ifindex;
        l->llmnr_support = RESOLVE_SUPPORT_YES;
        l->mdns_support = RESOLVE_SUPPORT_NO;
        l->dnssec_mode = _DNSSEC_MODE_INVALID;

        r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
        if (r < 0)
                return r;

        l->manager = m;

        if (ret)
                *ret = l;
        l = NULL;

        return 0;
}
Exemple #4
0
static int dynamic_user_add(Manager *m, const char *name, int storage_socket[2], DynamicUser **ret) {
        DynamicUser *d;
        int r;

        assert(m);
        assert(name);
        assert(storage_socket);

        r = hashmap_ensure_allocated(&m->dynamic_users, &string_hash_ops);
        if (r < 0)
                return r;

        d = malloc0(offsetof(DynamicUser, name) + strlen(name) + 1);
        if (!d)
                return -ENOMEM;

        strcpy(d->name, name);

        d->storage_socket[0] = storage_socket[0];
        d->storage_socket[1] = storage_socket[1];

        r = hashmap_put(m->dynamic_users, d->name, d);
        if (r < 0) {
                free(d);
                return r;
        }

        d->manager = m;

        if (ret)
                *ret = d;

        return 0;
}
Exemple #5
0
static int client_acquire(Context *context, uint64_t id, Client **_c) {
        char *watch = NULL;
        Client *c;
        int r;

        assert(context);
        assert(_c);

        c = hashmap_get(context->clients, &id);
        if (c) {
                *_c = c;
                return 0;
        }

        if (hashmap_size(context->clients) >= CLIENTS_MAX)
                return -ENOBUFS;

        r = hashmap_ensure_allocated(&context->clients, uint64_hash_func, uint64_compare_func);
        if (r < 0)
                return r;

        c = new0(Client, 1);
        if (!c)
                return -ENOMEM;

        c->id = id;

        r = hashmap_put(context->clients, &c->id, c);
        if (r < 0)
                goto fail;

        c->context = context;

        if (asprintf(&watch,
                     "type='signal',"
                     "sender='org.freedesktop.DBus',"
                     "path='/org/freedesktop/DBus',"
                     "interface='org.freedesktop.DBus',"
                     "member='NameOwnerChanged',"
                     "arg0=':1.%llu'", (unsigned long long) id) < 0) {
                r = -ENOMEM;
                goto fail;
        }

        r = sd_bus_add_match(context->bus, watch, on_name_owner_changed, c);
        if (r < 0) {
                free(watch);
                goto fail;
        }

        c->watch = watch;

        *_c = c;
        return 0;

fail:
        client_free(c);
        return r;
}
Exemple #6
0
int image_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
        _cleanup_free_ char *e = NULL;
        Manager *m = userdata;
        Image *image = NULL;
        const char *p;
        int r;

        assert(bus);
        assert(path);
        assert(interface);
        assert(found);

        p = startswith(path, "/org/freedesktop/machine1/image/");
        if (!p)
                return 0;

        e = bus_label_unescape(p);
        if (!e)
                return -ENOMEM;

        image = hashmap_get(m->image_cache, e);
        if (image) {
                *found = image;
                return 1;
        }

        r = hashmap_ensure_allocated(&m->image_cache, &string_hash_ops);
        if (r < 0)
                return r;

        if (!m->image_cache_defer_event) {
                r = sd_event_add_defer(m->event, &m->image_cache_defer_event, image_flush_cache, m);
                if (r < 0)
                        return r;

                r = sd_event_source_set_priority(m->image_cache_defer_event, SD_EVENT_PRIORITY_IDLE);
                if (r < 0)
                        return r;
        }

        r = sd_event_source_set_enabled(m->image_cache_defer_event, SD_EVENT_ONESHOT);
        if (r < 0)
                return r;

        r = image_find(e, &image);
        if (r <= 0)
                return r;

        image->userdata = m;

        r = hashmap_put(m->image_cache, image->name, image);
        if (r < 0) {
                image_unref(image);
                return r;
        }

        *found = image;
        return 1;
}
int link_new(Manager *m, Link **ret, int ifindex, const char *ifname) {
        _cleanup_(link_freep) Link *l = NULL;
        int r;

        assert(m);
        assert(ifindex > 0);

        r = hashmap_ensure_allocated(&m->links, NULL);
        if (r < 0)
                return r;

        r = hashmap_ensure_allocated(&m->links_by_name, &string_hash_ops);
        if (r < 0)
                return r;

        l = new0(Link, 1);
        if (!l)
                return -ENOMEM;

        l->manager = m;

        l->ifname = strdup(ifname);
        if (!l->ifname)
                return -ENOMEM;

        r = hashmap_put(m->links_by_name, l->ifname, l);
        if (r < 0)
                return r;

        l->ifindex = ifindex;

        r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
        if (r < 0)
                return r;

        if (ret)
                *ret = l;
        l = NULL;

        return 0;
}
static void test_hashmap_ensure_allocated(void) {
        Hashmap *m;
        int valid_hashmap;

        m = hashmap_new(&string_hash_ops);

        valid_hashmap = hashmap_ensure_allocated(&m, &string_hash_ops);
        assert_se(valid_hashmap == 0);

        assert_se(m);
        hashmap_free(m);
}
Exemple #9
0
static int prefix_new_static(Network *network, const char *filename,
                             unsigned section_line, Prefix **ret) {
        _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
        _cleanup_(prefix_freep) Prefix *prefix = NULL;
        int r;

        assert(network);
        assert(ret);
        assert(!!filename == (section_line > 0));

        if (filename) {
                r = network_config_section_new(filename, section_line, &n);
                if (r < 0)
                        return r;

                if (section_line) {
                        prefix = hashmap_get(network->prefixes_by_section, n);
                        if (prefix) {
                                *ret = TAKE_PTR(prefix);

                                return 0;
                        }
                }
        }

        r = prefix_new(&prefix);
        if (r < 0)
                return r;

        prefix->network = network;
        LIST_APPEND(prefixes, network->static_prefixes, prefix);
        network->n_static_prefixes++;

        if (filename) {
                prefix->section = TAKE_PTR(n);

                r = hashmap_ensure_allocated(&network->prefixes_by_section, &network_config_hash_ops);
                if (r < 0)
                        return r;

                r = hashmap_put(network->prefixes_by_section, prefix->section, prefix);
                if (r < 0)
                        return r;
        }

        *ret = TAKE_PTR(prefix);

        return 0;
}
static void test_hashmap_put(void) {
        Hashmap *m = NULL;
        int valid_hashmap_put;
        void *val1 = (void*) "val 1";

        assert_se(hashmap_ensure_allocated(&m, &string_hash_ops) >= 0);
        assert_se(m);

        valid_hashmap_put = hashmap_put(m, "key 1", val1);
        assert_se(valid_hashmap_put == 1);
        assert_se(hashmap_put(m, "key 1", val1) == 0);
        assert_se(hashmap_put(m, "key 1", (void *)"val 2") == -EEXIST);

        hashmap_free(m);
}
Exemple #11
0
_public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
        _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL;
        _cleanup_free_ char *n = NULL;
        const char *match;
        int r;

        assert_return(track, -EINVAL);
        assert_return(service_name_is_valid(name), -EINVAL);

        r = hashmap_ensure_allocated(&track->names, &string_hash_ops);
        if (r < 0)
                return r;

        n = strdup(name);
        if (!n)
                return -ENOMEM;

        /* First, subscribe to this name */
        match = MATCH_FOR_NAME(n);
        r = sd_bus_add_match(track->bus, &slot, match, on_name_owner_changed, track);
        if (r < 0)
                return r;

        r = hashmap_put(track->names, n, slot);
        if (r == -EEXIST)
                return 0;
        if (r < 0)
                return r;

        /* Second, check if it is currently existing, or maybe
         * doesn't, or maybe disappeared already. */
        r = sd_bus_get_name_creds(track->bus, n, 0, NULL);
        if (r < 0) {
                hashmap_remove(track->names, n);
                return r;
        }

        n = NULL;
        slot = NULL;

        bus_track_remove_from_queue(track);
        track->modified = true;

        return 1;
}
Exemple #12
0
static int client_context_new(Server *s, pid_t pid, ClientContext **ret) {
        ClientContext *c;
        int r;

        assert(s);
        assert(pid_is_valid(pid));
        assert(ret);

        r = hashmap_ensure_allocated(&s->client_contexts, NULL);
        if (r < 0)
                return r;

        r = prioq_ensure_allocated(&s->client_contexts_lru, client_context_compare);
        if (r < 0)
                return r;

        c = new0(ClientContext, 1);
        if (!c)
                return -ENOMEM;

        c->pid = pid;

        c->uid = UID_INVALID;
        c->gid = GID_INVALID;
        c->auditid = AUDIT_SESSION_INVALID;
        c->loginuid = UID_INVALID;
        c->owner_uid = UID_INVALID;
        c->lru_index = PRIOQ_IDX_NULL;
        c->timestamp = USEC_INFINITY;
        c->extra_fields_mtime = NSEC_INFINITY;
        c->log_level_max = -1;
        c->log_rate_limit_interval = s->rate_limit_interval;
        c->log_rate_limit_burst = s->rate_limit_burst;

        r = hashmap_put(s->client_contexts, PID_TO_PTR(pid), c);
        if (r < 0) {
                free(c);
                return r;
        }

        *ret = c;
        return 0;
}
Exemple #13
0
static int match_new(Client *c, struct bus_match_component *components, unsigned n_components, Match **_m) {
        Match *m, *first;
        int r;

        assert(c);
        assert(_m);

        r = hashmap_ensure_allocated(&c->matches, string_hash_func, string_compare_func);
        if (r < 0)
                return r;

        m = new0(Match, 1);
        if (!m)
                return -ENOMEM;

        m->match = bus_match_to_string(components, n_components);
        if (!m->match) {
                r = -ENOMEM;
                goto fail;
        }

        m->cookie = ++c->next_cookie;

        first = hashmap_get(c->matches, m->match);
        LIST_PREPEND(matches, first, m);
        r = hashmap_replace(c->matches, m->match, first);
        if (r < 0) {
                LIST_REMOVE(matches, first, m);
                goto fail;
        }

        m->client = c;
        c->n_matches++;

        *_m = m;
        m = NULL;

        return 0;

fail:
        match_free(m);
        return r;
}
int dns_trust_anchor_load(DnsTrustAnchor *d) {
        _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
        _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
        int r;

        assert(d);

        r = hashmap_ensure_allocated(&d->by_key, &dns_resource_key_hash_ops);
        if (r < 0)
                return r;

        if (hashmap_get(d->by_key, &DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_DS, ".")))
                return 0;

        /* Add the RR from https://data.iana.org/root-anchors/root-anchors.xml */
        rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "");
        if (!rr)
                return -ENOMEM;

        rr->ds.key_tag = 19036;
        rr->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256;
        rr->ds.digest_type = DNSSEC_DIGEST_SHA256;
        rr->ds.digest_size = sizeof(root_digest);
        rr->ds.digest = memdup(root_digest, rr->ds.digest_size);
        if (!rr->ds.digest)
                return  -ENOMEM;

        answer = dns_answer_new(1);
        if (!answer)
                return -ENOMEM;

        r = dns_answer_add(answer, rr, 0);
        if (r < 0)
                return r;

        r = hashmap_put(d->by_key, rr->key, answer);
        if (r < 0)
                return r;

        answer = NULL;
        return 0;
}
static void test_hashmap_put(void) {
        Hashmap *m = NULL;
        int valid_hashmap_put;
        void *val1 = (void*) "val 1";
        void *val2 = (void*) "val 2";
        _cleanup_free_ char* key1 = NULL;

        assert_se(hashmap_ensure_allocated(&m, &string_hash_ops) >= 0);
        assert_se(m);

        valid_hashmap_put = hashmap_put(m, "key 1", val1);
        assert_se(valid_hashmap_put == 1);
        assert_se(hashmap_put(m, "key 1", val1) == 0);
        assert_se(hashmap_put(m, "key 1", val2) == -EEXIST);
        key1 = strdup("key 1");
        assert_se(hashmap_put(m, key1, val1) == 0);
        assert_se(hashmap_put(m, key1, val2) == -EEXIST);

        hashmap_free(m);
}
int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsQuestion *q) {
        _cleanup_(dns_transaction_freep) DnsTransaction *t = NULL;
        int r;

        assert(ret);
        assert(s);
        assert(q);

        r = hashmap_ensure_allocated(&s->manager->dns_transactions, NULL);
        if (r < 0)
                return r;

        t = new0(DnsTransaction, 1);
        if (!t)
                return -ENOMEM;

        t->dns_fd = -1;

        t->question = dns_question_ref(q);

        do
                random_bytes(&t->id, sizeof(t->id));
        while (t->id == 0 ||
               hashmap_get(s->manager->dns_transactions, UINT_TO_PTR(t->id)));

        r = hashmap_put(s->manager->dns_transactions, UINT_TO_PTR(t->id), t);
        if (r < 0) {
                t->id = 0;
                return r;
        }

        LIST_PREPEND(transactions_by_scope, s->transactions, t);
        t->scope = s;

        if (ret)
                *ret = t;

        t = NULL;

        return 0;
}
Exemple #17
0
int link_new(Manager *m, Link **ret, int ifindex) {
        _cleanup_(link_freep) Link *l = NULL;
        int r;

        assert(m);
        assert(ifindex > 0);

        r = hashmap_ensure_allocated(&m->links, NULL);
        if (r < 0)
                return r;

        l = new0(Link, 1);
        if (!l)
                return -ENOMEM;

        l->ifindex = ifindex;
        l->llmnr_support = RESOLVE_SUPPORT_YES;
        l->mdns_support = RESOLVE_SUPPORT_NO;
        l->dnssec_mode = _DNSSEC_MODE_INVALID;
        l->operstate = IF_OPER_UNKNOWN;

        if (asprintf(&l->state_file, "/run/systemd/resolve/netif/%i", ifindex) < 0)
                return -ENOMEM;

        r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
        if (r < 0)
                return r;

        l->manager = m;

        if (ret)
                *ret = l;
        l = NULL;

        return 0;
}
Exemple #18
0
int set_ensure_allocated(Set **s, hash_func_t hash_func, compare_func_t compare_func) {
        return hashmap_ensure_allocated((Hashmap**) s, hash_func, compare_func);
}
Exemple #19
0
int bus_verify_polkit_async(
                sd_bus *bus,
                Hashmap **registry,
                sd_bus_message *m,
                const char *action,
                bool interactive,
                sd_bus_error *error,
                sd_bus_message_handler_t callback,
                void *userdata) {

#ifdef ENABLE_POLKIT
        _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
        AsyncPolkitQuery *q;
#endif
        const char *sender;
        uid_t uid;
        int r;

        assert(bus);
        assert(registry);
        assert(m);
        assert(action);

#ifdef ENABLE_POLKIT
        q = hashmap_remove(*registry, m);
        if (q) {
                unsigned authorized, challenge;

                /* This is the second invocation of this function, and
                 * there's already a response from polkit, let's
                 * process it */
                assert(q->reply);

                if (sd_bus_message_is_method_error(q->reply, NULL)) {
                        const sd_bus_error *e;

                        /* Treat no PK available as access denied */
                        if (sd_bus_message_is_method_error(q->reply, SD_BUS_ERROR_SERVICE_UNKNOWN)) {
                                async_polkit_query_free(bus, q);
                                return -EACCES;
                        }

                        e = sd_bus_message_get_error(q->reply);
                        sd_bus_error_copy(error, e);
                        r = sd_bus_error_get_errno(e);

                        async_polkit_query_free(bus, q);
                        return r;
                }

                r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
                if (r >= 0)
                        r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);

                async_polkit_query_free(bus, q);

                if (r < 0)
                        return r;

                if (authorized)
                        return 1;

                return -EACCES;
        }
#endif

        sender = sd_bus_message_get_sender(m);
        if (!sender)
                return -EBADMSG;

        r = sd_bus_get_owner_uid(bus, sender, &uid);
        if (r < 0)
                return r;

        if (uid == 0)
                return 1;
#ifdef ENABLE_POLKIT

        r = hashmap_ensure_allocated(registry, trivial_hash_func, trivial_compare_func);
        if (r < 0)
                return r;

        r = sd_bus_message_new_method_call(
                        bus,
                        "org.freedesktop.PolicyKit1",
                        "/org/freedesktop/PolicyKit1/Authority",
                        "org.freedesktop.PolicyKit1.Authority",
                        "CheckAuthorization",
                        &pk);
        if (r < 0)
                return r;

        r = sd_bus_message_append(
                        pk,
                        "(sa{sv})sa{ss}us",
                        "system-bus-name", 1, "name", "s", sender,
                        action,
                        0,
                        interactive ? 1 : 0,
                        "");
        if (r < 0)
                return r;

        q = new0(AsyncPolkitQuery, 1);
        if (!q)
                return -ENOMEM;

        q->request = sd_bus_message_ref(m);
        q->callback = callback;
        q->userdata = userdata;

        r = hashmap_put(*registry, m, q);
        if (r < 0) {
                async_polkit_query_free(bus, q);
                return r;
        }

        r = sd_bus_send_with_reply(bus, pk, async_polkit_callback, q, 0, &q->serial);
        if (r < 0)
                return r;

        return 0;
#endif

        return -EACCES;
}
Exemple #20
0
        if (d->manager)
                (void) hashmap_remove(d->manager->dynamic_users, d->name);

        safe_close_pair(d->storage_socket);
        return mfree(d);
}

static int dynamic_user_add(Manager *m, const char *name, int storage_socket[static 2], DynamicUser **ret) {
        DynamicUser *d;
        int r;

        assert(m);
        assert(name);
        assert(storage_socket);

        r = hashmap_ensure_allocated(&m->dynamic_users, &string_hash_ops);
        if (r < 0)
                return r;

        d = malloc0(offsetof(DynamicUser, name) + strlen(name) + 1);
        if (!d)
                return -ENOMEM;

        strcpy(d->name, name);

        d->storage_socket[0] = storage_socket[0];
        d->storage_socket[1] = storage_socket[1];

        r = hashmap_put(m->dynamic_users, d->name, d);
        if (r < 0) {
                free(d);
Exemple #21
0
static int curl_glue_socket_callback(CURLM *curl, curl_socket_t s, int action, void *userdata, void *socketp) {
        sd_event_source *io;
        CurlGlue *g = userdata;
        uint32_t events = 0;
        int r;

        assert(curl);
        assert(g);

        io = hashmap_get(g->ios, FD_TO_PTR(s));

        if (action == CURL_POLL_REMOVE) {
                if (io) {
                        int fd;

                        fd = sd_event_source_get_io_fd(io);
                        assert(fd >= 0);

                        sd_event_source_set_enabled(io, SD_EVENT_OFF);
                        sd_event_source_unref(io);

                        hashmap_remove(g->ios, FD_TO_PTR(s));
                        hashmap_remove(g->translate_fds, FD_TO_PTR(fd));

                        safe_close(fd);
                }

                return 0;
        }

        r = hashmap_ensure_allocated(&g->ios, &trivial_hash_ops);
        if (r < 0) {
                log_oom();
                return -1;
        }

        r = hashmap_ensure_allocated(&g->translate_fds, &trivial_hash_ops);
        if (r < 0) {
                log_oom();
                return -1;
        }

        if (action == CURL_POLL_IN)
                events = EPOLLIN;
        else if (action == CURL_POLL_OUT)
                events = EPOLLOUT;
        else if (action == CURL_POLL_INOUT)
                events = EPOLLIN|EPOLLOUT;

        if (io) {
                if (sd_event_source_set_io_events(io, events) < 0)
                        return -1;

                if (sd_event_source_set_enabled(io, SD_EVENT_ON) < 0)
                        return -1;
        } else {
                _cleanup_close_ int fd = -1;

                /* When curl needs to remove an fd from us it closes
                 * the fd first, and only then calls into us. This is
                 * nasty, since we cannot pass the fd on to epoll()
                 * anymore. Hence, duplicate the fds here, and keep a
                 * copy for epoll which we control after use. */

                fd = fcntl(s, F_DUPFD_CLOEXEC, 3);
                if (fd < 0)
                        return -1;

                if (sd_event_add_io(g->event, &io, fd, events, curl_glue_on_io, g) < 0)
                        return -1;

                (void) sd_event_source_set_description(io, "curl-io");

                r = hashmap_put(g->ios, FD_TO_PTR(s), io);
                if (r < 0) {
                        log_oom();
                        sd_event_source_unref(io);
                        return -1;
                }

                r = hashmap_put(g->translate_fds, FD_TO_PTR(fd), FD_TO_PTR(s));
                if (r < 0) {
                        log_oom();
                        hashmap_remove(g->ios, FD_TO_PTR(s));
                        sd_event_source_unref(io);
                        return -1;
                }

                fd = -1;
        }

        return 0;
}
Exemple #22
0
int set_ensure_allocated(Set **s, const struct hash_ops *hash_ops) {
        return hashmap_ensure_allocated((Hashmap**) s, hash_ops);
}
Exemple #23
0
int bus_verify_polkit_async(
                sd_bus_message *call,
                int capability,
                const char *action,
                bool interactive,
                Hashmap **registry,
                sd_bus_error *error) {

#ifdef ENABLE_POLKIT
        _cleanup_bus_message_unref_ sd_bus_message *pk = NULL;
        AsyncPolkitQuery *q;
        const char *sender;
        sd_bus_message_handler_t callback;
        void *userdata;
#endif
        int r;

        assert(call);
        assert(action);
        assert(registry);

#ifdef ENABLE_POLKIT
        q = hashmap_get(*registry, call);
        if (q) {
                int authorized, challenge;

                /* This is the second invocation of this function, and
                 * there's already a response from polkit, let's
                 * process it */
                assert(q->reply);

                if (sd_bus_message_is_method_error(q->reply, NULL)) {
                        const sd_bus_error *e;

                        /* Copy error from polkit reply */
                        e = sd_bus_message_get_error(q->reply);
                        sd_bus_error_copy(error, e);

                        /* Treat no PK available as access denied */
                        if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
                                return -EACCES;

                        return -sd_bus_error_get_errno(e);
                }

                r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}");
                if (r >= 0)
                        r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge);

                if (r < 0)
                        return r;

                if (authorized)
                        return 1;

                return -EACCES;
        }
#endif

        r = sd_bus_query_sender_privilege(call, capability);
        if (r < 0)
                return r;
        else if (r > 0)
                return 1;

#ifdef ENABLE_POLKIT
        if (sd_bus_get_current_message(call->bus) != call)
                return -EINVAL;

        callback = sd_bus_get_current_handler(call->bus);
        if (!callback)
                return -EINVAL;

        userdata = sd_bus_get_current_userdata(call->bus);

        sender = sd_bus_message_get_sender(call);
        if (!sender)
                return -EBADMSG;

        r = hashmap_ensure_allocated(registry, trivial_hash_func, trivial_compare_func);
        if (r < 0)
                return r;

        r = sd_bus_message_new_method_call(
                        call->bus,
                        &pk,
                        "org.freedesktop.PolicyKit1",
                        "/org/freedesktop/PolicyKit1/Authority",
                        "org.freedesktop.PolicyKit1.Authority",
                        "CheckAuthorization");
        if (r < 0)
                return r;

        r = sd_bus_message_append(
                        pk,
                        "(sa{sv})sa{ss}us",
                        "system-bus-name", 1, "name", "s", sender,
                        action,
                        0,
                        interactive ? 1 : 0,
                        NULL);
        if (r < 0)
                return r;

        q = new0(AsyncPolkitQuery, 1);
        if (!q)
                return -ENOMEM;

        q->request = sd_bus_message_ref(call);
        q->callback = callback;
        q->userdata = userdata;

        r = hashmap_put(*registry, call, q);
        if (r < 0) {
                async_polkit_query_free(q);
                return r;
        }

        q->registry = *registry;

        r = sd_bus_call_async(call->bus, &q->slot, pk, async_polkit_callback, q, 0);
        if (r < 0) {
                async_polkit_query_free(q);
                return r;
        }

        return 0;
#endif

        return -EACCES;
}
Exemple #24
0
int coredump_vacuum(int exclude_fd, uint64_t keep_free, uint64_t max_use) {
        _cleanup_closedir_ DIR *d = NULL;
        struct stat exclude_st;
        int r;

        if (keep_free == 0 && max_use == 0)
                return 0;

        if (exclude_fd >= 0) {
                if (fstat(exclude_fd, &exclude_st) < 0)
                        return log_error_errno(errno, "Failed to fstat(): %m");
        }

        /* This algorithm will keep deleting the oldest file of the
         * user with the most coredumps until we are back in the size
         * limits. Note that vacuuming for journal files is different,
         * because we rely on rate-limiting of the messages there,
         * to avoid being flooded. */

        d = opendir("/var/lib/systemd/coredump");
        if (!d) {
                if (errno == ENOENT)
                        return 0;

                log_error_errno(errno, "Can't open coredump directory: %m");
                return -errno;
        }

        for (;;) {
                _cleanup_(vacuum_candidate_hasmap_freep) Hashmap *h = NULL;
                struct vacuum_candidate *worst = NULL;
                struct dirent *de;
                uint64_t sum = 0;

                rewinddir(d);

                FOREACH_DIRENT(de, d, goto fail) {
                        struct vacuum_candidate *c;
                        struct stat st;
                        uid_t uid;
                        usec_t t;

                        r = uid_from_file_name(de->d_name, &uid);
                        if (r < 0)
                                continue;

                        if (fstatat(dirfd(d), de->d_name, &st, AT_NO_AUTOMOUNT|AT_SYMLINK_NOFOLLOW) < 0) {
                                if (errno == ENOENT)
                                        continue;

                                log_warning("Failed to stat /var/lib/systemd/coredump/%s", de->d_name);
                                continue;
                        }

                        if (!S_ISREG(st.st_mode))
                                continue;

                        if (exclude_fd >= 0 &&
                            exclude_st.st_dev == st.st_dev &&
                            exclude_st.st_ino == st.st_ino)
                                continue;

                        r = hashmap_ensure_allocated(&h, NULL);
                        if (r < 0)
                                return log_oom();

                        t = timespec_load(&st.st_mtim);

                        c = hashmap_get(h, UINT32_TO_PTR(uid));
                        if (c) {

                                if (t < c->oldest_mtime) {
                                        char *n;

                                        n = strdup(de->d_name);
                                        if (!n)
                                                return log_oom();

                                        free(c->oldest_file);
                                        c->oldest_file = n;
                                        c->oldest_mtime = t;
                                }

                        } else {
                                _cleanup_(vacuum_candidate_freep) struct vacuum_candidate *n = NULL;

                                n = new0(struct vacuum_candidate, 1);
                                if (!n)
                                        return log_oom();

                                n->oldest_file = strdup(de->d_name);
                                if (!n->oldest_file)
                                        return log_oom();

                                n->oldest_mtime = t;

                                r = hashmap_put(h, UINT32_TO_PTR(uid), n);
                                if (r < 0)
                                        return log_oom();

                                c = n;
                                n = NULL;
                        }

                        c->n_files++;

                        if (!worst ||
                            worst->n_files < c->n_files ||
                            (worst->n_files == c->n_files && c->oldest_mtime < worst->oldest_mtime))
                                worst = c;

                        sum += st.st_blocks * 512;
                }

                if (!worst)
                        break;

                r = vacuum_necessary(dirfd(d), sum, keep_free, max_use);
                if (r <= 0)
                        return r;

                if (unlinkat(dirfd(d), worst->oldest_file, 0) < 0) {

                        if (errno == ENOENT)
                                continue;

                        log_error_errno(errno, "Failed to remove file %s: %m", worst->oldest_file);
                        return -errno;
                } else
                        log_info("Removed old coredump %s.", worst->oldest_file);
        }

        return 0;

fail:
        log_error_errno(errno, "Failed to read directory: %m");
        return -errno;
}