Example #1
0
static void test_valid_user_group_name(void) {
        log_info("/* %s */", __func__);

        assert_se(!valid_user_group_name(NULL));
        assert_se(!valid_user_group_name(""));
        assert_se(!valid_user_group_name("1"));
        assert_se(!valid_user_group_name("65535"));
        assert_se(!valid_user_group_name("-1"));
        assert_se(!valid_user_group_name("-kkk"));
        assert_se(!valid_user_group_name("rööt"));
        assert_se(!valid_user_group_name("."));
        assert_se(!valid_user_group_name("eff.eff"));
        assert_se(!valid_user_group_name("foo\nbar"));
        assert_se(!valid_user_group_name("0123456789012345678901234567890123456789"));
        assert_se(!valid_user_group_name_or_id("aaa:bbb"));

        assert_se(valid_user_group_name("root"));
        assert_se(valid_user_group_name("lennart"));
        assert_se(valid_user_group_name("LENNART"));
        assert_se(valid_user_group_name("_kkk"));
        assert_se(valid_user_group_name("kkk-"));
        assert_se(valid_user_group_name("kk-k"));

        assert_se(valid_user_group_name("some5"));
        assert_se(!valid_user_group_name("5some"));
        assert_se(valid_user_group_name("INNER5NUMBER"));
}
Example #2
0
static int dynamic_user_acquire(Manager *m, const char *name, DynamicUser** ret) {
        _cleanup_close_pair_ int storage_socket[2] = { -1, -1 };
        DynamicUser *d;
        int r;

        assert(m);
        assert(name);

        /* Return the DynamicUser structure for a specific user name. Note that this won't actually allocate a UID for
         * it, but just prepare the data structure for it. The UID is allocated only on demand, when it's really
         * needed, and in the child process we fork off, since allocation involves NSS checks which are not OK to do
         * from PID 1. To allow the children and PID 1 share information about allocated UIDs we use an anonymous
         * AF_UNIX/SOCK_DGRAM socket (called the "storage socket") that contains at most one datagram with the
         * allocated UID number, plus an fd referencing the lock file for the UID
         * (i.e. /run/systemd/dynamic-uid/$UID). Why involve the socket pair? So that PID 1 and all its children can
         * share the same storage for the UID and lock fd, simply by inheriting the storage socket fds. The socket pair
         * may exist in three different states:
         *
         * a) no datagram stored. This is the initial state. In this case the dynamic user was never realized.
         *
         * b) a datagram containing a UID stored, but no lock fd attached to it. In this case there was already a
         *    statically assigned UID by the same name, which we are reusing.
         *
         * c) a datagram containing a UID stored, and a lock fd is attached to it. In this case we allocated a dynamic
         *    UID and locked it in the file system, using the lock fd.
         *
         * As PID 1 and various children might access the socket pair simultaneously, and pop the datagram or push it
         * back in any time, we also maintain a lock on the socket pair. Note one peculiarity regarding locking here:
         * the UID lock on disk is protected via a BSD file lock (i.e. an fd-bound lock), so that the lock is kept in
         * place as long as there's a reference to the fd open. The lock on the storage socket pair however is a POSIX
         * file lock (i.e. a process-bound lock), as all users share the same fd of this (after all it is anonymous,
         * nobody else could get any access to it except via our own fd) and we want to synchronize access between all
         * processes that have access to it. */

        d = hashmap_get(m->dynamic_users, name);
        if (d) {
                if (ret) {
                        /* We already have a structure for the dynamic user, let's increase the ref count and reuse it */
                        d->n_ref++;
                        *ret = d;
                }
                return 0;
        }

        if (!valid_user_group_name_or_id(name))
                return -EINVAL;

        if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, storage_socket) < 0)
                return -errno;

        r = dynamic_user_add(m, name, storage_socket, &d);
        if (r < 0)
                return r;

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

        if (ret) {
                d->n_ref++;
                *ret = d;
        }

        return 1;
}