summaryrefslogtreecommitdiffstats
path: root/src/shared/user-record.h
blob: acf2cdc9d4d1bbaf225b32c7e8358163014f1e6b (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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once

#include <inttypes.h>
#include <sys/types.h>

#include "sd-id128.h"

#include "json.h"
#include "missing_resource.h"
#include "time-util.h"

/* But some limits on disk sizes: not less than 5M, not more than 5T */
#define USER_DISK_SIZE_MIN (UINT64_C(5)*1024*1024)
#define USER_DISK_SIZE_MAX (UINT64_C(5)*1024*1024*1024*1024)

/* The default disk size to use when nothing else is specified, relative to free disk space */
#define USER_DISK_SIZE_DEFAULT_PERCENT 85

bool uid_is_system(uid_t uid);
bool gid_is_system(gid_t gid);

static inline bool uid_is_dynamic(uid_t uid) {
        return DYNAMIC_UID_MIN <= uid && uid <= DYNAMIC_UID_MAX;
}

static inline bool gid_is_dynamic(gid_t gid) {
        return uid_is_dynamic((uid_t) gid);
}

static inline bool uid_is_container(uid_t uid) {
        return CONTAINER_UID_BASE_MIN <= uid && uid <= CONTAINER_UID_BASE_MAX;
}

static inline bool gid_is_container(gid_t gid) {
        return uid_is_container((uid_t) gid);
}

typedef struct UGIDAllocationRange {
        uid_t system_alloc_uid_min;
        uid_t system_uid_max;
        gid_t system_alloc_gid_min;
        gid_t system_gid_max;
} UGIDAllocationRange;

int read_login_defs(UGIDAllocationRange *ret_defs, const char *path, const char *root);
const UGIDAllocationRange *acquire_ugid_allocation_range(void);

typedef enum UserDisposition {
        USER_INTRINSIC,   /* root and nobody */
        USER_SYSTEM,      /* statically allocated users for system services */
        USER_DYNAMIC,     /* dynamically allocated users for system services */
        USER_REGULAR,     /* regular (typically human users) */
        USER_CONTAINER,   /* UID ranges allocated for container uses */
        USER_RESERVED,    /* Range above 2^31 */
        _USER_DISPOSITION_MAX,
        _USER_DISPOSITION_INVALID = -EINVAL,
} UserDisposition;

typedef enum UserHomeStorage {
        USER_CLASSIC,
        USER_LUKS,
        USER_DIRECTORY, /* A directory, and a .identity file in it, which USER_CLASSIC lacks */
        USER_SUBVOLUME,
        USER_FSCRYPT,
        USER_CIFS,
        _USER_STORAGE_MAX,
        _USER_STORAGE_INVALID = -EINVAL,
} UserStorage;

typedef enum UserRecordMask {
        /* The various sections an identity record may have, as bit mask */
        USER_RECORD_REGULAR     = 1U << 0,
        USER_RECORD_SECRET      = 1U << 1,
        USER_RECORD_PRIVILEGED  = 1U << 2,
        USER_RECORD_PER_MACHINE = 1U << 3,
        USER_RECORD_BINDING     = 1U << 4,
        USER_RECORD_STATUS      = 1U << 5,
        USER_RECORD_SIGNATURE   = 1U << 6,
        _USER_RECORD_MASK_MAX   = (1U << 7)-1
} UserRecordMask;

typedef enum UserRecordLoadFlags {
        /* A set of flags used while loading a user record from JSON data. We leave the lower 6 bits free,
         * just as a safety precaution so that we can detect borked conversions between UserRecordMask and
         * UserRecordLoadFlags. */

        /* What to require */
        USER_RECORD_REQUIRE_REGULAR     = USER_RECORD_REGULAR     << 7,
        USER_RECORD_REQUIRE_SECRET      = USER_RECORD_SECRET      << 7,
        USER_RECORD_REQUIRE_PRIVILEGED  = USER_RECORD_PRIVILEGED  << 7,
        USER_RECORD_REQUIRE_PER_MACHINE = USER_RECORD_PER_MACHINE << 7,
        USER_RECORD_REQUIRE_BINDING     = USER_RECORD_BINDING     << 7,
        USER_RECORD_REQUIRE_STATUS      = USER_RECORD_STATUS      << 7,
        USER_RECORD_REQUIRE_SIGNATURE   = USER_RECORD_SIGNATURE   << 7,

        /* What to allow */
        USER_RECORD_ALLOW_REGULAR       = USER_RECORD_REGULAR     << 14,
        USER_RECORD_ALLOW_SECRET        = USER_RECORD_SECRET      << 14,
        USER_RECORD_ALLOW_PRIVILEGED    = USER_RECORD_PRIVILEGED  << 14,
        USER_RECORD_ALLOW_PER_MACHINE   = USER_RECORD_PER_MACHINE << 14,
        USER_RECORD_ALLOW_BINDING       = USER_RECORD_BINDING     << 14,
        USER_RECORD_ALLOW_STATUS        = USER_RECORD_STATUS      << 14,
        USER_RECORD_ALLOW_SIGNATURE     = USER_RECORD_SIGNATURE   << 14,

        /* What to strip */
        USER_RECORD_STRIP_REGULAR       = USER_RECORD_REGULAR     << 21,
        USER_RECORD_STRIP_SECRET        = USER_RECORD_SECRET      << 21,
        USER_RECORD_STRIP_PRIVILEGED    = USER_RECORD_PRIVILEGED  << 21,
        USER_RECORD_STRIP_PER_MACHINE   = USER_RECORD_PER_MACHINE << 21,
        USER_RECORD_STRIP_BINDING       = USER_RECORD_BINDING     << 21,
        USER_RECORD_STRIP_STATUS        = USER_RECORD_STATUS      << 21,
        USER_RECORD_STRIP_SIGNATURE     = USER_RECORD_SIGNATURE   << 21,

        /* Some special combinations that deserve explicit names */
        USER_RECORD_LOAD_FULL           = USER_RECORD_REQUIRE_REGULAR |
                                          USER_RECORD_ALLOW_SECRET |
                                          USER_RECORD_ALLOW_PRIVILEGED |
                                          USER_RECORD_ALLOW_PER_MACHINE |
                                          USER_RECORD_ALLOW_BINDING |
                                          USER_RECORD_ALLOW_STATUS |
                                          USER_RECORD_ALLOW_SIGNATURE,

        USER_RECORD_LOAD_REFUSE_SECRET =  USER_RECORD_REQUIRE_REGULAR |
                                          USER_RECORD_ALLOW_PRIVILEGED |
                                          USER_RECORD_ALLOW_PER_MACHINE |
                                          USER_RECORD_ALLOW_BINDING |
                                          USER_RECORD_ALLOW_STATUS |
                                          USER_RECORD_ALLOW_SIGNATURE,

        USER_RECORD_LOAD_MASK_SECRET =    USER_RECORD_REQUIRE_REGULAR |
                                          USER_RECORD_ALLOW_PRIVILEGED |
                                          USER_RECORD_ALLOW_PER_MACHINE |
                                          USER_RECORD_ALLOW_BINDING |
                                          USER_RECORD_ALLOW_STATUS |
                                          USER_RECORD_ALLOW_SIGNATURE |
                                          USER_RECORD_STRIP_SECRET,

        USER_RECORD_EXTRACT_SECRET      = USER_RECORD_REQUIRE_SECRET |
                                          USER_RECORD_STRIP_REGULAR |
                                          USER_RECORD_STRIP_PRIVILEGED |
                                          USER_RECORD_STRIP_PER_MACHINE |
                                          USER_RECORD_STRIP_BINDING |
                                          USER_RECORD_STRIP_STATUS |
                                          USER_RECORD_STRIP_SIGNATURE,

        USER_RECORD_LOAD_SIGNABLE       = USER_RECORD_REQUIRE_REGULAR |
                                          USER_RECORD_ALLOW_PRIVILEGED |
                                          USER_RECORD_ALLOW_PER_MACHINE,

        USER_RECORD_EXTRACT_SIGNABLE    = USER_RECORD_LOAD_SIGNABLE |
                                          USER_RECORD_STRIP_SECRET |
                                          USER_RECORD_STRIP_BINDING |
                                          USER_RECORD_STRIP_STATUS |
                                          USER_RECORD_STRIP_SIGNATURE,

        USER_RECORD_LOAD_EMBEDDED       = USER_RECORD_REQUIRE_REGULAR |
                                          USER_RECORD_ALLOW_PRIVILEGED |
                                          USER_RECORD_ALLOW_PER_MACHINE |
                                          USER_RECORD_ALLOW_SIGNATURE,

        USER_RECORD_EXTRACT_EMBEDDED    = USER_RECORD_LOAD_EMBEDDED |
                                          USER_RECORD_STRIP_SECRET |
                                          USER_RECORD_STRIP_BINDING |
                                          USER_RECORD_STRIP_STATUS,

        /* Whether to log about loader errors beyond LOG_DEBUG */
        USER_RECORD_LOG                 = 1U << 28,

        /* Whether to ignore errors and load what we can */
        USER_RECORD_PERMISSIVE          = 1U << 29,

        /* Whether an empty record is OK */
        USER_RECORD_EMPTY_OK            = 1U << 30,
} UserRecordLoadFlags;

static inline UserRecordLoadFlags USER_RECORD_REQUIRE(UserRecordMask m) {
        assert((m & ~_USER_RECORD_MASK_MAX) == 0);
        return m << 7;
}

static inline UserRecordLoadFlags USER_RECORD_ALLOW(UserRecordMask m) {
        assert((m & ~_USER_RECORD_MASK_MAX) == 0);
        return m << 14;
}

static inline UserRecordLoadFlags USER_RECORD_STRIP(UserRecordMask m) {
        assert((m & ~_USER_RECORD_MASK_MAX) == 0);
        return m << 21;
}

static inline UserRecordMask USER_RECORD_REQUIRE_MASK(UserRecordLoadFlags f) {
        return (f >> 7) & _USER_RECORD_MASK_MAX;
}

static inline UserRecordMask USER_RECORD_ALLOW_MASK(UserRecordLoadFlags f) {
        return ((f >> 14) & _USER_RECORD_MASK_MAX) | USER_RECORD_REQUIRE_MASK(f);
}

static inline UserRecordMask USER_RECORD_STRIP_MASK(UserRecordLoadFlags f) {
        return (f >> 21) & _USER_RECORD_MASK_MAX;
}

static inline JsonDispatchFlags USER_RECORD_LOAD_FLAGS_TO_JSON_DISPATCH_FLAGS(UserRecordLoadFlags flags) {
        return (FLAGS_SET(flags, USER_RECORD_LOG) ? JSON_LOG : 0) |
                (FLAGS_SET(flags, USER_RECORD_PERMISSIVE) ? JSON_PERMISSIVE : 0);
}

typedef struct Pkcs11EncryptedKey {
        /* The encrypted passphrase, which can be decrypted with the private key indicated below */
        void *data;
        size_t size;

        /* Where to find the private key to decrypt the encrypted passphrase above */
        char *uri;

        /* What to test the decrypted passphrase against to allow access (classic UNIX password hash).  Note
         * that the decrypted passphrase is also used for unlocking LUKS and fscrypt, and if the account is
         * backed by LUKS or fscrypt the hashed password is only an additional layer of authentication, not
         * the only. */
        char *hashed_password;
} Pkcs11EncryptedKey;

typedef struct Fido2HmacCredential {
        void *id;
        size_t size;
} Fido2HmacCredential;

typedef struct Fido2HmacSalt {
        /* The FIDO2 Cridential ID to use */
        Fido2HmacCredential credential;

        /* The FIDO2 salt value */
        void *salt;
        size_t salt_size;

        /* What to test the hashed salt value against, usually UNIX password hash here. */
        char *hashed_password;

        /* Whether the 'up', 'uv', 'clientPin' features are enabled. */
        int uv, up, client_pin;
} Fido2HmacSalt;

typedef struct RecoveryKey {
        /* The type of recovery key, must be "modhex64" right now */
        char *type;

        /* A UNIX password hash of the normalized form of modhex64 */
        char *hashed_password;
} RecoveryKey;

typedef struct UserRecord {
        /* The following three fields are not part of the JSON record */
        unsigned n_ref;
        UserRecordMask mask;
        bool incomplete; /* incomplete due to security restrictions. */

        char *user_name;
        char *realm;
        char *user_name_and_realm_auto; /* the user_name field concatenated with '@' and the realm, if the latter is defined */
        char *real_name;
        char *email_address;
        char *password_hint;
        char *icon_name;
        char *location;

        UserDisposition disposition;
        uint64_t last_change_usec;
        uint64_t last_password_change_usec;

        char *shell;
        mode_t umask;
        char **environment;
        char *time_zone;
        char *preferred_language;
        int nice_level;
        struct rlimit *rlimits[_RLIMIT_MAX];

        int locked;               /* prohibit activation in general */
        uint64_t not_before_usec; /* prohibit activation before this unix time */
        uint64_t not_after_usec;  /* prohibit activation after this unix time */

        UserStorage storage;
        uint64_t disk_size;
        uint64_t disk_size_relative; /* Disk size, relative to the free bytes of the medium, normalized to UINT32_MAX = 100% */
        char *skeleton_directory;
        mode_t access_mode;

        uint64_t tasks_max;
        uint64_t memory_high;
        uint64_t memory_max;
        uint64_t cpu_weight;
        uint64_t io_weight;

        bool nosuid;
        bool nodev;
        bool noexec;

        char **hashed_password;
        char **ssh_authorized_keys;
        char **password;
        char **token_pin;

        char *cifs_domain;
        char *cifs_user_name;
        char *cifs_service;
        char *cifs_extra_mount_options;

        char *image_path;
        char *image_path_auto; /* when none is configured explicitly, this is where we place the implicit image */
        char *home_directory;
        char *home_directory_auto; /* when none is set explicitly, this is where we place the implicit home directory */

        uid_t uid;
        gid_t gid;

        char **member_of;

        char *file_system_type;
        sd_id128_t partition_uuid;
        sd_id128_t luks_uuid;
        sd_id128_t file_system_uuid;

        int luks_discard;
        int luks_offline_discard;
        char *luks_cipher;
        char *luks_cipher_mode;
        uint64_t luks_volume_key_size;
        char *luks_pbkdf_hash_algorithm;
        char *luks_pbkdf_type;
        uint64_t luks_pbkdf_time_cost_usec;
        uint64_t luks_pbkdf_memory_cost;
        uint64_t luks_pbkdf_parallel_threads;

        uint64_t disk_usage;
        uint64_t disk_free;
        uint64_t disk_ceiling;
        uint64_t disk_floor;

        char *state;
        char *service;
        int signed_locally;

        uint64_t good_authentication_counter;
        uint64_t bad_authentication_counter;
        uint64_t last_good_authentication_usec;
        uint64_t last_bad_authentication_usec;

        uint64_t ratelimit_begin_usec;
        uint64_t ratelimit_count;
        uint64_t ratelimit_interval_usec;
        uint64_t ratelimit_burst;

        int removable;
        int enforce_password_policy;
        int auto_login;
        int drop_caches;

        uint64_t stop_delay_usec;   /* How long to leave systemd --user around on log-out */
        int kill_processes;         /* Whether to kill user processes forcibly on log-out */

        /* The following exist mostly so that we can cover the full /etc/shadow set of fields */
        uint64_t password_change_min_usec;       /* maps to .sp_min */
        uint64_t password_change_max_usec;       /* maps to .sp_max */
        uint64_t password_change_warn_usec;      /* maps to .sp_warn */
        uint64_t password_change_inactive_usec;  /* maps to .sp_inact */
        int password_change_now;                 /* Require a password change immediately on next login (.sp_lstchg = 0) */

        char **pkcs11_token_uri;
        Pkcs11EncryptedKey *pkcs11_encrypted_key;
        size_t n_pkcs11_encrypted_key;
        int pkcs11_protected_authentication_path_permitted;

        Fido2HmacCredential *fido2_hmac_credential;
        size_t n_fido2_hmac_credential;
        Fido2HmacSalt *fido2_hmac_salt;
        size_t n_fido2_hmac_salt;
        int fido2_user_presence_permitted;
        int fido2_user_verification_permitted;

        char **recovery_key_type;
        RecoveryKey *recovery_key;
        size_t n_recovery_key;

        JsonVariant *json;
} UserRecord;

UserRecord* user_record_new(void);
UserRecord* user_record_ref(UserRecord *h);
UserRecord* user_record_unref(UserRecord *h);

DEFINE_TRIVIAL_CLEANUP_FUNC(UserRecord*, user_record_unref);

int user_record_load(UserRecord *h, JsonVariant *v, UserRecordLoadFlags flags);
int user_record_build(UserRecord **ret, ...);

const char *user_record_user_name_and_realm(UserRecord *h);
UserStorage user_record_storage(UserRecord *h);
const char *user_record_file_system_type(UserRecord *h);
const char *user_record_skeleton_directory(UserRecord *h);
mode_t user_record_access_mode(UserRecord *h);
const char *user_record_home_directory(UserRecord *h);
const char *user_record_image_path(UserRecord *h);
unsigned long user_record_mount_flags(UserRecord *h);
const char *user_record_cifs_user_name(UserRecord *h);
const char *user_record_shell(UserRecord *h);
const char *user_record_real_name(UserRecord *h);
bool user_record_luks_discard(UserRecord *h);
bool user_record_luks_offline_discard(UserRecord *h);
const char *user_record_luks_cipher(UserRecord *h);
const char *user_record_luks_cipher_mode(UserRecord *h);
uint64_t user_record_luks_volume_key_size(UserRecord *h);
const char* user_record_luks_pbkdf_type(UserRecord *h);
usec_t user_record_luks_pbkdf_time_cost_usec(UserRecord *h);
uint64_t user_record_luks_pbkdf_memory_cost(UserRecord *h);
uint64_t user_record_luks_pbkdf_parallel_threads(UserRecord *h);
const char *user_record_luks_pbkdf_hash_algorithm(UserRecord *h);
gid_t user_record_gid(UserRecord *h);
UserDisposition user_record_disposition(UserRecord *h);
int user_record_removable(UserRecord *h);
usec_t user_record_ratelimit_interval_usec(UserRecord *h);
uint64_t user_record_ratelimit_burst(UserRecord *h);
bool user_record_can_authenticate(UserRecord *h);
bool user_record_drop_caches(UserRecord *h);

int user_record_build_image_path(UserStorage storage, const char *user_name_and_realm, char **ret);

bool user_record_equal(UserRecord *a, UserRecord *b);
bool user_record_compatible(UserRecord *a, UserRecord *b);
int user_record_compare_last_change(UserRecord *a, UserRecord *b);

usec_t user_record_ratelimit_next_try(UserRecord *h);

int user_record_clone(UserRecord *h, UserRecordLoadFlags flags, UserRecord **ret);
int user_record_masked_equal(UserRecord *a, UserRecord *b, UserRecordMask mask);

int user_record_test_blocked(UserRecord *h);
int user_record_test_password_change_required(UserRecord *h);

/* The following six are user by group-record.c, that's why we export them here */
int json_dispatch_realm(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
int json_dispatch_gecos(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
int json_dispatch_user_group_list(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
int json_dispatch_user_disposition(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);

int per_machine_id_match(JsonVariant *ids, JsonDispatchFlags flags);
int per_machine_hostname_match(JsonVariant *hns, JsonDispatchFlags flags);
int user_group_record_mangle(JsonVariant *v, UserRecordLoadFlags load_flags, JsonVariant **ret_variant, UserRecordMask *ret_mask);

const char* user_storage_to_string(UserStorage t) _const_;
UserStorage user_storage_from_string(const char *s) _pure_;

const char* user_disposition_to_string(UserDisposition t) _const_;
UserDisposition user_disposition_from_string(const char *s) _pure_;