]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
295c1a6e LP |
2 | |
3 | #include "format-util.h" | |
4 | #include "fs-util.h" | |
295c1a6e LP |
5 | #include "process-util.h" |
6 | #include "rlimit-util.h" | |
7 | #include "strv.h" | |
8 | #include "terminal-util.h" | |
9 | #include "user-record-show.h" | |
10 | #include "user-util.h" | |
11 | #include "userdb.h" | |
12 | ||
13 | const char *user_record_state_color(const char *state) { | |
14 | if (STR_IN_SET(state, "unfixated", "absent")) | |
15 | return ansi_grey(); | |
16 | else if (streq(state, "active")) | |
17 | return ansi_highlight_green(); | |
9be99f81 | 18 | else if (STR_IN_SET(state, "locked", "dirty")) |
295c1a6e LP |
19 | return ansi_highlight_yellow(); |
20 | ||
21 | return NULL; | |
22 | } | |
23 | ||
24 | void user_record_show(UserRecord *hr, bool show_full_group_info) { | |
25 | const char *hd, *ip, *shell; | |
26 | UserStorage storage; | |
27 | usec_t t; | |
28 | size_t k; | |
29 | int r, b; | |
30 | ||
31 | printf(" User name: %s\n", | |
32 | user_record_user_name_and_realm(hr)); | |
33 | ||
34 | if (hr->state) { | |
35 | const char *color; | |
36 | ||
37 | color = user_record_state_color(hr->state); | |
38 | ||
39 | printf(" State: %s%s%s\n", | |
40 | strempty(color), hr->state, color ? ansi_normal() : ""); | |
41 | } | |
42 | ||
43 | printf(" Disposition: %s\n", user_disposition_to_string(user_record_disposition(hr))); | |
44 | ||
45 | if (hr->last_change_usec != USEC_INFINITY) { | |
04f5c018 | 46 | printf(" Last Change: %s\n", FORMAT_TIMESTAMP(hr->last_change_usec)); |
51a95db6 LP |
47 | |
48 | if (hr->last_change_usec > now(CLOCK_REALTIME)) | |
49 | printf(" %sModification time lies in the future, system clock wrong?%s\n", | |
50 | ansi_highlight_yellow(), ansi_normal()); | |
295c1a6e LP |
51 | } |
52 | ||
53 | if (hr->last_password_change_usec != USEC_INFINITY && | |
04f5c018 ZJS |
54 | hr->last_password_change_usec != hr->last_change_usec) |
55 | printf(" Last Passw.: %s\n", FORMAT_TIMESTAMP(hr->last_password_change_usec)); | |
295c1a6e LP |
56 | |
57 | r = user_record_test_blocked(hr); | |
58 | switch (r) { | |
59 | ||
295c1a6e LP |
60 | case -ENOLCK: |
61 | printf(" Login OK: %sno%s (record is locked)\n", ansi_highlight_red(), ansi_normal()); | |
62 | break; | |
63 | ||
64 | case -EL2HLT: | |
65 | printf(" Login OK: %sno%s (record not valid yet))\n", ansi_highlight_red(), ansi_normal()); | |
66 | break; | |
67 | ||
68 | case -EL3HLT: | |
69 | printf(" Login OK: %sno%s (record not valid anymore))\n", ansi_highlight_red(), ansi_normal()); | |
70 | break; | |
71 | ||
51a95db6 | 72 | case -ESTALE: |
295c1a6e LP |
73 | default: { |
74 | usec_t y; | |
75 | ||
51a95db6 | 76 | if (r < 0 && r != -ESTALE) { |
295c1a6e LP |
77 | errno = -r; |
78 | printf(" Login OK: %sno%s (%m)\n", ansi_highlight_red(), ansi_normal()); | |
79 | break; | |
80 | } | |
81 | ||
82 | if (is_nologin_shell(user_record_shell(hr))) { | |
83 | printf(" Login OK: %sno%s (nologin shell)\n", ansi_highlight_red(), ansi_normal()); | |
84 | break; | |
85 | } | |
86 | ||
87 | y = user_record_ratelimit_next_try(hr); | |
88 | if (y != USEC_INFINITY && y > now(CLOCK_REALTIME)) { | |
89 | printf(" Login OK: %sno%s (ratelimit)\n", ansi_highlight_red(), ansi_normal()); | |
90 | break; | |
91 | } | |
92 | ||
93 | printf(" Login OK: %syes%s\n", ansi_highlight_green(), ansi_normal()); | |
94 | break; | |
95 | }} | |
96 | ||
97 | r = user_record_test_password_change_required(hr); | |
98 | switch (r) { | |
99 | ||
100 | case -EKEYREVOKED: | |
101 | printf(" Password OK: %schange now%s\n", ansi_highlight_yellow(), ansi_normal()); | |
102 | break; | |
103 | ||
104 | case -EOWNERDEAD: | |
105 | printf(" Password OK: %sexpired%s (change now!)\n", ansi_highlight_yellow(), ansi_normal()); | |
106 | break; | |
107 | ||
108 | case -EKEYREJECTED: | |
109 | printf(" Password OK: %sexpired%s (for good)\n", ansi_highlight_red(), ansi_normal()); | |
110 | break; | |
111 | ||
112 | case -EKEYEXPIRED: | |
113 | printf(" Password OK: %sexpires soon%s\n", ansi_highlight_yellow(), ansi_normal()); | |
114 | break; | |
115 | ||
116 | case -ENETDOWN: | |
117 | printf(" Password OK: %sno timestamp%s\n", ansi_highlight_red(), ansi_normal()); | |
118 | break; | |
119 | ||
120 | case -EROFS: | |
121 | printf(" Password OK: %schange not permitted%s\n", ansi_highlight_yellow(), ansi_normal()); | |
122 | break; | |
3e0b5486 LP |
123 | |
124 | case -ESTALE: | |
125 | printf(" Password OK: %slast password change in future%s\n", ansi_highlight_yellow(), ansi_normal()); | |
126 | break; | |
295c1a6e LP |
127 | |
128 | default: | |
129 | if (r < 0) { | |
130 | errno = -r; | |
131 | printf(" Password OK: %sno%s (%m)\n", ansi_highlight_yellow(), ansi_normal()); | |
132 | break; | |
133 | } | |
134 | ||
cd933f14 P |
135 | if (strv_isempty(hr->hashed_password)) { |
136 | if (hr->incomplete) /* Record might be incomplete, due to privs */ | |
137 | break; | |
138 | printf(" Password OK: %sno%s (none set)\n", ansi_highlight(), ansi_normal()); | |
139 | break; | |
140 | } | |
141 | if (strv_contains(hr->hashed_password, "")) { | |
142 | printf(" Password OK: %sno%s (empty set)\n", ansi_highlight_red(), ansi_normal()); | |
143 | break; | |
144 | } | |
145 | bool has_valid_passwords = false; | |
cd933f14 P |
146 | STRV_FOREACH(p, hr->hashed_password) |
147 | if (!hashed_password_is_locked_or_invalid(*p)) { | |
148 | has_valid_passwords = true; | |
149 | break; | |
150 | } | |
151 | if (has_valid_passwords) | |
152 | printf(" Password OK: %syes%s\n", ansi_highlight_green(), ansi_normal()); | |
153 | else | |
154 | printf(" Password OK: %sno%s (locked)\n", ansi_highlight(), ansi_normal()); | |
295c1a6e | 155 | } |
295c1a6e LP |
156 | if (uid_is_valid(hr->uid)) |
157 | printf(" UID: " UID_FMT "\n", hr->uid); | |
158 | if (gid_is_valid(hr->gid)) { | |
159 | if (show_full_group_info) { | |
160 | _cleanup_(group_record_unrefp) GroupRecord *gr = NULL; | |
161 | ||
162 | r = groupdb_by_gid(hr->gid, 0, &gr); | |
163 | if (r < 0) { | |
164 | errno = -r; | |
165 | printf(" GID: " GID_FMT " (unresolvable: %m)\n", hr->gid); | |
166 | } else | |
167 | printf(" GID: " GID_FMT " (%s)\n", hr->gid, gr->group_name); | |
168 | } else | |
169 | printf(" GID: " GID_FMT "\n", hr->gid); | |
170 | } else if (uid_is_valid(hr->uid)) /* Show UID as GID if not separately configured */ | |
171 | printf(" GID: " GID_FMT "\n", (gid_t) hr->uid); | |
172 | ||
173 | if (show_full_group_info) { | |
174 | _cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL; | |
175 | ||
176 | r = membershipdb_by_user(hr->user_name, 0, &iterator); | |
177 | if (r < 0) { | |
178 | errno = -r; | |
179 | printf(" Aux. Groups: (can't acquire: %m)\n"); | |
180 | } else { | |
181 | const char *prefix = " Aux. Groups:"; | |
182 | ||
183 | for (;;) { | |
184 | _cleanup_free_ char *group = NULL; | |
185 | ||
186 | r = membershipdb_iterator_get(iterator, NULL, &group); | |
187 | if (r == -ESRCH) | |
188 | break; | |
189 | if (r < 0) { | |
190 | errno = -r; | |
191 | printf("%s (can't iterate: %m)\n", prefix); | |
192 | break; | |
193 | } | |
194 | ||
195 | printf("%s %s\n", prefix, group); | |
196 | prefix = " "; | |
197 | } | |
198 | } | |
199 | } | |
200 | ||
201 | if (hr->real_name && !streq(hr->real_name, hr->user_name)) | |
202 | printf(" Real Name: %s\n", hr->real_name); | |
203 | ||
204 | hd = user_record_home_directory(hr); | |
205 | if (hd) | |
206 | printf(" Directory: %s\n", hd); | |
207 | ||
208 | storage = user_record_storage(hr); | |
209 | if (storage >= 0) /* Let's be political, and clarify which storage we like, and which we don't. About CIFS we don't complain. */ | |
210 | printf(" Storage: %s%s\n", user_storage_to_string(storage), | |
211 | storage == USER_LUKS ? " (strong encryption)" : | |
212 | storage == USER_FSCRYPT ? " (weak encryption)" : | |
213 | IN_SET(storage, USER_DIRECTORY, USER_SUBVOLUME) ? " (no encryption)" : ""); | |
214 | ||
215 | ip = user_record_image_path(hr); | |
216 | if (ip && !streq_ptr(ip, hd)) | |
217 | printf(" Image Path: %s\n", ip); | |
218 | ||
219 | b = user_record_removable(hr); | |
220 | if (b >= 0) | |
221 | printf(" Removable: %s\n", yes_no(b)); | |
222 | ||
223 | shell = user_record_shell(hr); | |
224 | if (shell) | |
225 | printf(" Shell: %s\n", shell); | |
226 | ||
227 | if (hr->email_address) | |
228 | printf(" Email: %s\n", hr->email_address); | |
229 | if (hr->location) | |
230 | printf(" Location: %s\n", hr->location); | |
231 | if (hr->password_hint) | |
232 | printf(" Passw. Hint: %s\n", hr->password_hint); | |
233 | if (hr->icon_name) | |
234 | printf(" Icon Name: %s\n", hr->icon_name); | |
235 | ||
236 | if (hr->time_zone) | |
237 | printf(" Time Zone: %s\n", hr->time_zone); | |
238 | ||
239 | if (hr->preferred_language) | |
240 | printf(" Language: %s\n", hr->preferred_language); | |
241 | ||
de010b0b | 242 | if (!strv_isempty(hr->environment)) |
295c1a6e LP |
243 | STRV_FOREACH(i, hr->environment) { |
244 | printf(i == hr->environment ? | |
245 | " Environment: %s\n" : | |
246 | " %s\n", *i); | |
247 | } | |
295c1a6e LP |
248 | |
249 | if (hr->locked >= 0) | |
250 | printf(" Locked: %s\n", yes_no(hr->locked)); | |
251 | ||
04f5c018 ZJS |
252 | if (hr->not_before_usec != UINT64_MAX) |
253 | printf(" Not Before: %s\n", FORMAT_TIMESTAMP(hr->not_before_usec)); | |
295c1a6e | 254 | |
04f5c018 ZJS |
255 | if (hr->not_after_usec != UINT64_MAX) |
256 | printf(" Not After: %s\n", FORMAT_TIMESTAMP(hr->not_after_usec)); | |
295c1a6e LP |
257 | |
258 | if (hr->umask != MODE_INVALID) | |
259 | printf(" UMask: 0%03o\n", hr->umask); | |
260 | ||
261 | if (nice_is_valid(hr->nice_level)) | |
262 | printf(" Nice: %i\n", hr->nice_level); | |
263 | ||
264 | for (int j = 0; j < _RLIMIT_MAX; j++) { | |
265 | if (hr->rlimits[j]) | |
266 | printf(" Limit: RLIMIT_%s=%" PRIu64 ":%" PRIu64 "\n", | |
267 | rlimit_to_string(j), (uint64_t) hr->rlimits[j]->rlim_cur, (uint64_t) hr->rlimits[j]->rlim_max); | |
268 | } | |
269 | ||
270 | if (hr->tasks_max != UINT64_MAX) | |
271 | printf(" Tasks Max: %" PRIu64 "\n", hr->tasks_max); | |
272 | ||
2b59bf51 ZJS |
273 | if (hr->memory_high != UINT64_MAX) |
274 | printf(" Memory High: %s\n", FORMAT_BYTES(hr->memory_high)); | |
295c1a6e | 275 | |
2b59bf51 ZJS |
276 | if (hr->memory_max != UINT64_MAX) |
277 | printf(" Memory Max: %s\n", FORMAT_BYTES(hr->memory_max)); | |
295c1a6e | 278 | |
c8340822 | 279 | if (hr->cpu_weight == CGROUP_WEIGHT_IDLE) |
280 | printf(" CPU Weight: %s\n", "idle"); | |
281 | else if (hr->cpu_weight != UINT64_MAX) | |
295c1a6e LP |
282 | printf(" CPU Weight: %" PRIu64 "\n", hr->cpu_weight); |
283 | ||
284 | if (hr->io_weight != UINT64_MAX) | |
285 | printf(" IO Weight: %" PRIu64 "\n", hr->io_weight); | |
286 | ||
287 | if (hr->access_mode != MODE_INVALID) | |
7cdd5c0d | 288 | printf(" Access Mode: 0%03o\n", user_record_access_mode(hr)); |
295c1a6e LP |
289 | |
290 | if (storage == USER_LUKS) { | |
5e86c82a | 291 | printf("LUKS Discard: online=%s offline=%s\n", yes_no(user_record_luks_discard(hr)), yes_no(user_record_luks_offline_discard(hr))); |
295c1a6e LP |
292 | |
293 | if (!sd_id128_is_null(hr->luks_uuid)) | |
30df3586 | 294 | printf(" LUKS UUID: " SD_ID128_UUID_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(hr->luks_uuid)); |
295c1a6e | 295 | if (!sd_id128_is_null(hr->partition_uuid)) |
30df3586 | 296 | printf(" Part UUID: " SD_ID128_UUID_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(hr->partition_uuid)); |
295c1a6e | 297 | if (!sd_id128_is_null(hr->file_system_uuid)) |
30df3586 | 298 | printf(" FS UUID: " SD_ID128_UUID_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(hr->file_system_uuid)); |
295c1a6e LP |
299 | |
300 | if (hr->file_system_type) | |
301 | printf(" File System: %s\n", user_record_file_system_type(hr)); | |
302 | ||
2e0001c2 LP |
303 | if (hr->luks_extra_mount_options) |
304 | printf("LUKS MntOpts: %s\n", hr->luks_extra_mount_options); | |
305 | ||
295c1a6e LP |
306 | if (hr->luks_cipher) |
307 | printf(" LUKS Cipher: %s\n", hr->luks_cipher); | |
308 | if (hr->luks_cipher_mode) | |
309 | printf(" Cipher Mode: %s\n", hr->luks_cipher_mode); | |
310 | if (hr->luks_volume_key_size != UINT64_MAX) | |
311 | printf(" Volume Key: %" PRIu64 "bit\n", hr->luks_volume_key_size * 8); | |
312 | ||
313 | if (hr->luks_pbkdf_type) | |
314 | printf(" PBKDF Type: %s\n", hr->luks_pbkdf_type); | |
315 | if (hr->luks_pbkdf_hash_algorithm) | |
316 | printf(" PBKDF Hash: %s\n", hr->luks_pbkdf_hash_algorithm); | |
b04ff66b AD |
317 | if (hr->luks_pbkdf_force_iterations != UINT64_MAX) |
318 | printf(" PBKDF Iters: %" PRIu64 "\n", hr->luks_pbkdf_force_iterations); | |
5291f26d ZJS |
319 | if (hr->luks_pbkdf_time_cost_usec != UINT64_MAX) |
320 | printf(" PBKDF Time: %s\n", FORMAT_TIMESPAN(hr->luks_pbkdf_time_cost_usec, 0)); | |
2b59bf51 ZJS |
321 | if (hr->luks_pbkdf_memory_cost != UINT64_MAX) |
322 | printf(" PBKDF Bytes: %s\n", FORMAT_BYTES(hr->luks_pbkdf_memory_cost)); | |
323 | ||
295c1a6e LP |
324 | if (hr->luks_pbkdf_parallel_threads != UINT64_MAX) |
325 | printf("PBKDF Thread: %" PRIu64 "\n", hr->luks_pbkdf_parallel_threads); | |
fd83c98e AD |
326 | if (hr->luks_sector_size != UINT64_MAX) |
327 | printf(" Sector Size: %" PRIu64 "\n", hr->luks_sector_size); | |
295c1a6e LP |
328 | |
329 | } else if (storage == USER_CIFS) { | |
330 | ||
331 | if (hr->cifs_service) | |
332 | printf("CIFS Service: %s\n", hr->cifs_service); | |
84f26185 LP |
333 | |
334 | if (hr->cifs_extra_mount_options) | |
335 | printf("CIFS MntOpts: %s\n", hr->cifs_extra_mount_options); | |
295c1a6e LP |
336 | } |
337 | ||
338 | if (hr->cifs_user_name) | |
339 | printf(" CIFS User: %s\n", user_record_cifs_user_name(hr)); | |
340 | if (hr->cifs_domain) | |
341 | printf(" CIFS Domain: %s\n", hr->cifs_domain); | |
342 | ||
343 | if (storage != USER_CLASSIC) | |
344 | printf(" Mount Flags: %s %s %s\n", | |
345 | hr->nosuid ? "nosuid" : "suid", | |
346 | hr->nodev ? "nodev" : "dev", | |
347 | hr->noexec ? "noexec" : "exec"); | |
348 | ||
349 | if (hr->skeleton_directory) | |
350 | printf(" Skel. Dir.: %s\n", user_record_skeleton_directory(hr)); | |
351 | ||
2b59bf51 ZJS |
352 | if (hr->disk_size != UINT64_MAX) |
353 | printf(" Disk Size: %s\n", FORMAT_BYTES(hr->disk_size)); | |
295c1a6e LP |
354 | |
355 | if (hr->disk_usage != UINT64_MAX) { | |
f5b7d681 LP |
356 | if (hr->disk_size != UINT64_MAX) { |
357 | unsigned permille; | |
358 | ||
359 | permille = (unsigned) DIV_ROUND_UP(hr->disk_usage * 1000U, hr->disk_size); /* Round up! */ | |
360 | printf(" Disk Usage: %s (= %u.%01u%%)\n", | |
2b59bf51 | 361 | FORMAT_BYTES(hr->disk_usage), |
f5b7d681 LP |
362 | permille / 10, permille % 10); |
363 | } else | |
2b59bf51 | 364 | printf(" Disk Usage: %s\n", FORMAT_BYTES(hr->disk_usage)); |
295c1a6e LP |
365 | } |
366 | ||
367 | if (hr->disk_free != UINT64_MAX) { | |
f5b7d681 | 368 | if (hr->disk_size != UINT64_MAX) { |
c01ef54f | 369 | const char *color_on, *color_off; |
f5b7d681 LP |
370 | unsigned permille; |
371 | ||
372 | permille = (unsigned) ((hr->disk_free * 1000U) / hr->disk_size); /* Round down! */ | |
c01ef54f LP |
373 | |
374 | /* Color the output red or yellow if we are below 10% resp. 25% free. Because 10% and | |
375 | * 25% can be a lot of space still, let's additionally make some absolute | |
376 | * restrictions: 1G and 2G */ | |
377 | if (permille <= 100U && | |
378 | hr->disk_free < 1024U*1024U*1024U /* 1G */) { | |
379 | color_on = ansi_highlight_red(); | |
380 | color_off = ansi_normal(); | |
381 | } else if (permille <= 250U && | |
382 | hr->disk_free < 2U*1024U*1024U*1024U /* 2G */) { | |
383 | color_on = ansi_highlight_yellow(); | |
384 | color_off = ansi_normal(); | |
385 | } else | |
386 | color_on = color_off = ""; | |
387 | ||
388 | printf(" Disk Free: %s%s (= %u.%01u%%)%s\n", | |
389 | color_on, | |
2b59bf51 | 390 | FORMAT_BYTES(hr->disk_free), |
c01ef54f LP |
391 | permille / 10, permille % 10, |
392 | color_off); | |
f5b7d681 | 393 | } else |
2b59bf51 | 394 | printf(" Disk Free: %s\n", FORMAT_BYTES(hr->disk_free)); |
295c1a6e LP |
395 | } |
396 | ||
2b59bf51 ZJS |
397 | if (hr->disk_floor != UINT64_MAX) |
398 | printf(" Disk Floor: %s\n", FORMAT_BYTES(hr->disk_floor)); | |
295c1a6e | 399 | |
2b59bf51 ZJS |
400 | if (hr->disk_ceiling != UINT64_MAX) |
401 | printf("Disk Ceiling: %s\n", FORMAT_BYTES(hr->disk_ceiling)); | |
295c1a6e LP |
402 | |
403 | if (hr->good_authentication_counter != UINT64_MAX) | |
404 | printf(" Good Auth.: %" PRIu64 "\n", hr->good_authentication_counter); | |
405 | ||
04f5c018 ZJS |
406 | if (hr->last_good_authentication_usec != UINT64_MAX) |
407 | printf(" Last Good: %s\n", FORMAT_TIMESTAMP(hr->last_good_authentication_usec)); | |
295c1a6e LP |
408 | |
409 | if (hr->bad_authentication_counter != UINT64_MAX) | |
410 | printf(" Bad Auth.: %" PRIu64 "\n", hr->bad_authentication_counter); | |
411 | ||
04f5c018 ZJS |
412 | if (hr->last_bad_authentication_usec != UINT64_MAX) |
413 | printf(" Last Bad: %s\n", FORMAT_TIMESTAMP(hr->last_bad_authentication_usec)); | |
295c1a6e LP |
414 | |
415 | t = user_record_ratelimit_next_try(hr); | |
416 | if (t != USEC_INFINITY) { | |
417 | usec_t n = now(CLOCK_REALTIME); | |
418 | ||
419 | if (t <= n) | |
420 | printf(" Next Try: anytime\n"); | |
5291f26d | 421 | else |
295c1a6e LP |
422 | printf(" Next Try: %sin %s%s\n", |
423 | ansi_highlight_red(), | |
5291f26d | 424 | FORMAT_TIMESPAN(t - n, USEC_PER_SEC), |
295c1a6e | 425 | ansi_normal()); |
295c1a6e LP |
426 | } |
427 | ||
5291f26d | 428 | if (storage != USER_CLASSIC) |
295c1a6e | 429 | printf(" Auth. Limit: %" PRIu64 " attempts per %s\n", user_record_ratelimit_burst(hr), |
5291f26d | 430 | FORMAT_TIMESPAN(user_record_ratelimit_interval_usec(hr), 0)); |
295c1a6e LP |
431 | |
432 | if (hr->enforce_password_policy >= 0) | |
433 | printf(" Passwd Pol.: %s\n", yes_no(hr->enforce_password_policy)); | |
434 | ||
435 | if (hr->password_change_min_usec != UINT64_MAX || | |
436 | hr->password_change_max_usec != UINT64_MAX || | |
437 | hr->password_change_warn_usec != UINT64_MAX || | |
438 | hr->password_change_inactive_usec != UINT64_MAX) { | |
439 | ||
295c1a6e LP |
440 | printf(" Passwd Chg.:"); |
441 | ||
442 | if (hr->password_change_min_usec != UINT64_MAX) { | |
5291f26d | 443 | printf(" min %s", FORMAT_TIMESPAN(hr->password_change_min_usec, 0)); |
295c1a6e LP |
444 | |
445 | if (hr->password_change_max_usec != UINT64_MAX) | |
446 | printf(" …"); | |
447 | } | |
448 | ||
449 | if (hr->password_change_max_usec != UINT64_MAX) | |
5291f26d | 450 | printf(" max %s", FORMAT_TIMESPAN(hr->password_change_max_usec, 0)); |
295c1a6e LP |
451 | |
452 | if (hr->password_change_warn_usec != UINT64_MAX) | |
5291f26d | 453 | printf("/warn %s", FORMAT_TIMESPAN(hr->password_change_warn_usec, 0)); |
295c1a6e LP |
454 | |
455 | if (hr->password_change_inactive_usec != UINT64_MAX) | |
5291f26d | 456 | printf("/inactive %s", FORMAT_TIMESPAN(hr->password_change_inactive_usec, 0)); |
295c1a6e LP |
457 | |
458 | printf("\n"); | |
459 | } | |
460 | ||
461 | if (hr->password_change_now >= 0) | |
462 | printf("Pas. Ch. Now: %s\n", yes_no(hr->password_change_now)); | |
463 | ||
86019efa LP |
464 | if (hr->drop_caches >= 0 || user_record_drop_caches(hr)) |
465 | printf(" Drop Caches: %s\n", yes_no(user_record_drop_caches(hr))); | |
466 | ||
8bec643c LP |
467 | if (hr->auto_resize_mode >= 0) |
468 | printf(" Auto Resize: %s\n", auto_resize_mode_to_string(user_record_auto_resize_mode(hr))); | |
469 | ||
9aa3e5eb LP |
470 | if (hr->rebalance_weight != REBALANCE_WEIGHT_UNSET) { |
471 | uint64_t rb; | |
472 | ||
473 | rb = user_record_rebalance_weight(hr); | |
474 | if (rb == REBALANCE_WEIGHT_OFF) | |
475 | printf(" Rebalance: off\n"); | |
476 | else | |
477 | printf(" Rebalance: weight %" PRIu64 "\n", rb); | |
478 | } | |
479 | ||
295c1a6e LP |
480 | if (!strv_isempty(hr->ssh_authorized_keys)) |
481 | printf("SSH Pub. Key: %zu\n", strv_length(hr->ssh_authorized_keys)); | |
482 | ||
de010b0b | 483 | if (!strv_isempty(hr->pkcs11_token_uri)) |
295c1a6e LP |
484 | STRV_FOREACH(i, hr->pkcs11_token_uri) |
485 | printf(i == hr->pkcs11_token_uri ? | |
5e4fa456 | 486 | "PKCS11 Token: %s\n" : |
295c1a6e | 487 | " %s\n", *i); |
295c1a6e | 488 | |
5e4fa456 LP |
489 | if (hr->n_fido2_hmac_credential > 0) |
490 | printf(" FIDO2 Token: %zu\n", hr->n_fido2_hmac_credential); | |
491 | ||
b3a97fd3 LP |
492 | if (!strv_isempty(hr->recovery_key_type)) |
493 | printf("Recovery Key: %zu\n", strv_length(hr->recovery_key_type)); | |
494 | ||
295c1a6e LP |
495 | k = strv_length(hr->hashed_password); |
496 | if (k == 0) | |
497 | printf(" Passwords: %snone%s\n", | |
498 | user_record_disposition(hr) == USER_REGULAR ? ansi_highlight_yellow() : ansi_normal(), ansi_normal()); | |
499 | else | |
500 | printf(" Passwords: %zu\n", k); | |
501 | ||
502 | if (hr->signed_locally >= 0) | |
503 | printf(" Local Sig.: %s\n", yes_no(hr->signed_locally)); | |
504 | ||
5291f26d ZJS |
505 | if (hr->stop_delay_usec != UINT64_MAX) |
506 | printf(" Stop Delay: %s\n", FORMAT_TIMESPAN(hr->stop_delay_usec, 0)); | |
295c1a6e LP |
507 | |
508 | if (hr->auto_login >= 0) | |
509 | printf("Autom. Login: %s\n", yes_no(hr->auto_login)); | |
510 | ||
511 | if (hr->kill_processes >= 0) | |
512 | printf(" Kill Proc.: %s\n", yes_no(hr->kill_processes)); | |
513 | ||
514 | if (hr->service) | |
515 | printf(" Service: %s\n", hr->service); | |
516 | } | |
52d3fbc8 ZJS |
517 | |
518 | void group_record_show(GroupRecord *gr, bool show_full_user_info) { | |
519 | int r; | |
520 | ||
521 | printf(" Group name: %s\n", | |
522 | group_record_group_name_and_realm(gr)); | |
523 | ||
524 | printf(" Disposition: %s\n", user_disposition_to_string(group_record_disposition(gr))); | |
525 | ||
04f5c018 ZJS |
526 | if (gr->last_change_usec != USEC_INFINITY) |
527 | printf(" Last Change: %s\n", FORMAT_TIMESTAMP(gr->last_change_usec)); | |
52d3fbc8 ZJS |
528 | |
529 | if (gid_is_valid(gr->gid)) | |
530 | printf(" GID: " GID_FMT "\n", gr->gid); | |
531 | ||
532 | if (show_full_user_info) { | |
533 | _cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL; | |
534 | ||
535 | r = membershipdb_by_group(gr->group_name, 0, &iterator); | |
536 | if (r < 0) { | |
537 | errno = -r; | |
538 | printf(" Members: (can't acquire: %m)"); | |
539 | } else { | |
540 | const char *prefix = " Members:"; | |
541 | ||
542 | for (;;) { | |
543 | _cleanup_free_ char *user = NULL; | |
544 | ||
545 | r = membershipdb_iterator_get(iterator, &user, NULL); | |
546 | if (r == -ESRCH) | |
547 | break; | |
548 | if (r < 0) { | |
549 | errno = -r; | |
550 | printf("%s (can't iterate: %m\n", prefix); | |
551 | break; | |
552 | } | |
553 | ||
554 | printf("%s %s\n", prefix, user); | |
555 | prefix = " "; | |
556 | } | |
557 | } | |
558 | } else { | |
559 | const char *prefix = " Members:"; | |
52d3fbc8 ZJS |
560 | |
561 | STRV_FOREACH(i, gr->members) { | |
562 | printf("%s %s\n", prefix, *i); | |
563 | prefix = " "; | |
564 | } | |
565 | } | |
566 | ||
567 | if (!strv_isempty(gr->administrators)) { | |
568 | const char *prefix = " Admins:"; | |
52d3fbc8 ZJS |
569 | |
570 | STRV_FOREACH(i, gr->administrators) { | |
571 | printf("%s %s\n", prefix, *i); | |
572 | prefix = " "; | |
573 | } | |
574 | } | |
575 | ||
576 | if (gr->description && !streq(gr->description, gr->group_name)) | |
577 | printf(" Description: %s\n", gr->description); | |
578 | ||
579 | if (!strv_isempty(gr->hashed_password)) | |
580 | printf(" Passwords: %zu\n", strv_length(gr->hashed_password)); | |
581 | ||
582 | if (gr->service) | |
583 | printf(" Service: %s\n", gr->service); | |
584 | } |