summaryrefslogtreecommitdiffstats
path: root/src/home/homed-home.h
blob: b8b004642294628db7bd2c68ebcfe32a280ca79c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once

typedef struct Home Home;

#include "homed-manager.h"
#include "homed-operation.h"
#include "list.h"
#include "ordered-set.h"
#include "stat-util.h"
#include "user-record.h"

typedef enum HomeState {
        HOME_UNFIXATED,               /* home exists, but local record does not */
        HOME_ABSENT,                  /* local record exists, but home does not */
        HOME_INACTIVE,                /* record and home exist, but is not logged in */
        HOME_DIRTY,                   /* like HOME_INACTIVE, but the home directory wasn't cleanly deactivated */
        HOME_FIXATING,                /* generating local record from home */
        HOME_FIXATING_FOR_ACTIVATION, /* fixating in order to activate soon */
        HOME_FIXATING_FOR_ACQUIRE,    /* fixating because Acquire() was called */
        HOME_ACTIVATING,
        HOME_ACTIVATING_FOR_ACQUIRE,  /* activating because Acquire() was called */
        HOME_DEACTIVATING,
        HOME_ACTIVE,                  /* logged in right now */
        HOME_LINGERING,               /* not logged in anymore, but we didn't manage to deactivate (because some process keeps it busy?) but we'll keep trying */
        HOME_LOCKING,
        HOME_LOCKED,
        HOME_UNLOCKING,
        HOME_UNLOCKING_FOR_ACQUIRE,   /* unlocking because Acquire() was called */
        HOME_CREATING,
        HOME_REMOVING,
        HOME_UPDATING,
        HOME_UPDATING_WHILE_ACTIVE,
        HOME_RESIZING,
        HOME_RESIZING_WHILE_ACTIVE,
        HOME_PASSWD,
        HOME_PASSWD_WHILE_ACTIVE,
        HOME_AUTHENTICATING,
        HOME_AUTHENTICATING_WHILE_ACTIVE,
        HOME_AUTHENTICATING_FOR_ACQUIRE,  /* authenticating because Acquire() was called */
        _HOME_STATE_MAX,
        _HOME_STATE_INVALID = -EINVAL,
} HomeState;

static inline bool HOME_STATE_IS_ACTIVE(HomeState state) {
        return IN_SET(state,
                      HOME_ACTIVE,
                      HOME_LINGERING,
                      HOME_UPDATING_WHILE_ACTIVE,
                      HOME_RESIZING_WHILE_ACTIVE,
                      HOME_PASSWD_WHILE_ACTIVE,
                      HOME_AUTHENTICATING_WHILE_ACTIVE,
                      HOME_AUTHENTICATING_FOR_ACQUIRE);
}

static inline bool HOME_STATE_IS_EXECUTING_OPERATION(HomeState state) {
        return IN_SET(state,
                      HOME_FIXATING,
                      HOME_FIXATING_FOR_ACTIVATION,
                      HOME_FIXATING_FOR_ACQUIRE,
                      HOME_ACTIVATING,
                      HOME_ACTIVATING_FOR_ACQUIRE,
                      HOME_DEACTIVATING,
                      HOME_LOCKING,
                      HOME_UNLOCKING,
                      HOME_UNLOCKING_FOR_ACQUIRE,
                      HOME_CREATING,
                      HOME_REMOVING,
                      HOME_UPDATING,
                      HOME_UPDATING_WHILE_ACTIVE,
                      HOME_RESIZING,
                      HOME_RESIZING_WHILE_ACTIVE,
                      HOME_PASSWD,
                      HOME_PASSWD_WHILE_ACTIVE,
                      HOME_AUTHENTICATING,
                      HOME_AUTHENTICATING_WHILE_ACTIVE,
                      HOME_AUTHENTICATING_FOR_ACQUIRE);
}

static inline bool HOME_STATE_SHALL_PIN(HomeState state) {
        /* Like HOME_STATE_IS_ACTIVE() – but HOME_LINGERING is missing! */
        return IN_SET(state,
                      HOME_ACTIVE,
                      HOME_UPDATING_WHILE_ACTIVE,
                      HOME_RESIZING_WHILE_ACTIVE,
                      HOME_PASSWD_WHILE_ACTIVE,
                      HOME_AUTHENTICATING_WHILE_ACTIVE,
                      HOME_AUTHENTICATING_FOR_ACQUIRE);
}

#define HOME_STATE_SHALL_REBALANCE(state) HOME_STATE_SHALL_PIN(state)

static inline bool HOME_STATE_MAY_RETRY_DEACTIVATE(HomeState state) {
        /* Indicates when to leave the deactivate retry timer active */
        return IN_SET(state,
                      HOME_ACTIVE,
                      HOME_LINGERING,
                      HOME_DEACTIVATING,
                      HOME_LOCKING,
                      HOME_UNLOCKING,
                      HOME_UNLOCKING_FOR_ACQUIRE,
                      HOME_UPDATING_WHILE_ACTIVE,
                      HOME_RESIZING_WHILE_ACTIVE,
                      HOME_PASSWD_WHILE_ACTIVE,
                      HOME_AUTHENTICATING_WHILE_ACTIVE,
                      HOME_AUTHENTICATING_FOR_ACQUIRE);
}

struct Home {
        Manager *manager;
        char *user_name;
        uid_t uid;

        char *sysfs; /* When found via plugged in device, the sysfs path to it */

        /* Note that the 'state' field is only set to a state while we are doing something (i.e. activating,
         * deactivating, creating, removing, and such), or when the home is an "unfixated" one. When we are
         * done with an operation we invalidate the state. This is hint for home_get_state() to check the
         * state on request as needed from the mount table and similar. */
        HomeState state;
        int signed_locally; /* signed only by us */

        UserRecord *record;

        pid_t worker_pid;
        int worker_stdout_fd;
        sd_event_source *worker_event_source;
        int worker_error_code;

        /* The message we are currently processing, and thus need to reply to on completion */
        Operation *current_operation;

        /* Stores the raw, plaintext passwords, but only for short periods of time */
        UserRecord *secret;

        /* When we create a home area and that fails, we should possibly unregister the record altogether
         * again, which is remembered in this boolean. */
        bool unregister_on_failure;

        /* The reading side of a FIFO stored in /run/systemd/home/, the writing side being used for reference
         * counting. The references dropped to zero as soon as we see EOF. This concept exists thrice: once
         * for clients that are fine if we lock the home directory on system suspend, once for clients
         * that are not ok with that, and once for clients that are usually ok with it but temporarily
         * want to opt-out so that they can implement more advanced behavior on their own. This allows
         * us to determine for each home whether there are any clients that don't support suspend at this
         * moment. */
        sd_event_source *ref_event_source_please_suspend;
        sd_event_source *ref_event_source_dont_suspend;
        /* This is distinct from ref_event_source_dont_suspend because it can be obtained from unprivileged
         * code, and thus we don't count it as a reference on the home area. */
        sd_event_source *inhibit_suspend_event_source;

        /* Any pending operations we still need to execute. These are for operations we want to queue if we
         * can't execute them right-away. */
        OrderedSet *pending_operations;

        /* A defer event source that processes pending acquire/release/eof events. We have a common
         * dispatcher that processes all three kinds of events. */
        sd_event_source *pending_event_source;

        /* Did we send out a D-Bus notification about this entry? */
        bool announced;

        /* Used to coalesce bus PropertiesChanged events */
        sd_event_source *deferred_change_event_source;

        /* An fd to the top-level home directory we keep while logged in, to keep the dir busy */
        int pin_fd;

        /* A time event used to repeatedly try to unmount home dir after use if it didn't work on first try */
        sd_event_source *retry_deactivate_event_source;

        /* An fd that locks the backing file of LUKS home dirs with a BSD lock. */
        int luks_lock_fd;

        /* Space metrics during rebalancing */
        uint64_t rebalance_size, rebalance_usage, rebalance_free, rebalance_min, rebalance_weight, rebalance_goal;

        /* Whether a rebalance operation is pending */
        bool rebalance_pending;
};

int home_new(Manager *m, UserRecord *hr, const char *sysfs, Home **ret);
Home *home_free(Home *h);

DEFINE_TRIVIAL_CLEANUP_FUNC(Home*, home_free);

int home_set_record(Home *h, UserRecord *hr);
int home_save_record(Home *h);
int home_unlink_record(Home *h);

int home_fixate(Home *h, UserRecord *secret, sd_bus_error *error);
int home_activate(Home *h, UserRecord *secret, sd_bus_error *error);
int home_authenticate(Home *h, UserRecord *secret, sd_bus_error *error);
int home_deactivate(Home *h, bool force, sd_bus_error *error);
int home_create(Home *h, UserRecord *secret, sd_bus_error *error);
int home_remove(Home *h, sd_bus_error *error);
int home_update(Home *h, UserRecord *new_record, sd_bus_error *error);
int home_resize(Home *h, uint64_t disk_size, UserRecord *secret, bool automatic, sd_bus_error *error);
int home_passwd(Home *h, UserRecord *new_secret, UserRecord *old_secret, sd_bus_error *error);
int home_unregister(Home *h, sd_bus_error *error);
int home_lock(Home *h, sd_bus_error *error);
int home_unlock(Home *h, UserRecord *secret, sd_bus_error *error);

bool home_is_referenced(Home *h);
bool home_shall_suspend(Home *h);
HomeState home_get_state(Home *h);

int home_get_disk_status(Home *h, uint64_t *ret_disk_size,uint64_t *ret_disk_usage, uint64_t *ret_disk_free, uint64_t *ret_disk_ceiling, uint64_t *ret_disk_floor, statfs_f_type_t *ret_fstype, mode_t *ret_access_mode);

void home_process_notify(Home *h, char **l, int fd);

int home_killall(Home *h);

int home_augment_status(Home *h, UserRecordLoadFlags flags, UserRecord **ret);

typedef enum {
        HOME_FIFO_PLEASE_SUSPEND,
        HOME_FIFO_DONT_SUSPEND,
        HOME_FIFO_INHIBIT_SUSPEND,
        _HOME_FIFO_TYPE_MAX,
        _HOME_FIFO_TYPE_INVALID = -EINVAL,
} HomeFifoType;
int home_create_fifo(Home *h, HomeFifoType mode);

int home_schedule_operation(Home *h, Operation *o, sd_bus_error *error);

int home_auto_login(Home *h, char ***ret_seats);

int home_set_current_message(Home *h, sd_bus_message *m);

int home_wait_for_worker(Home *h);

bool home_shall_rebalance(Home *h);

bool home_is_busy(Home *h);

const char *home_state_to_string(HomeState state);
HomeState home_state_from_string(const char *s);