1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include "format-util.h"
5 #include "group-record.h"
6 #include "process-util.h"
7 #include "rlimit-util.h"
9 #include "terminal-util.h"
10 #include "user-record-show.h"
11 #include "user-util.h"
14 const char *user_record_state_color(const char *state
) {
15 if (STR_IN_SET(state
, "unfixated", "absent"))
17 else if (streq(state
, "active"))
18 return ansi_highlight_green();
19 else if (streq(state
, "locked"))
20 return ansi_highlight_yellow();
25 void user_record_show(UserRecord
*hr
, bool show_full_group_info
) {
26 const char *hd
, *ip
, *shell
;
32 printf(" User name: %s\n",
33 user_record_user_name_and_realm(hr
));
38 color
= user_record_state_color(hr
->state
);
40 printf(" State: %s%s%s\n",
41 strempty(color
), hr
->state
, color
? ansi_normal() : "");
44 printf(" Disposition: %s\n", user_disposition_to_string(user_record_disposition(hr
)));
46 if (hr
->last_change_usec
!= USEC_INFINITY
) {
47 char buf
[FORMAT_TIMESTAMP_MAX
];
48 printf(" Last Change: %s\n", format_timestamp(buf
, sizeof(buf
), hr
->last_change_usec
));
51 if (hr
->last_password_change_usec
!= USEC_INFINITY
&&
52 hr
->last_password_change_usec
!= hr
->last_change_usec
) {
53 char buf
[FORMAT_TIMESTAMP_MAX
];
54 printf(" Last Passw.: %s\n", format_timestamp(buf
, sizeof(buf
), hr
->last_password_change_usec
));
57 r
= user_record_test_blocked(hr
);
61 printf(" Login OK: %sno%s (last change time is in the future)\n", ansi_highlight_red(), ansi_normal());
65 printf(" Login OK: %sno%s (record is locked)\n", ansi_highlight_red(), ansi_normal());
69 printf(" Login OK: %sno%s (record not valid yet))\n", ansi_highlight_red(), ansi_normal());
73 printf(" Login OK: %sno%s (record not valid anymore))\n", ansi_highlight_red(), ansi_normal());
81 printf(" Login OK: %sno%s (%m)\n", ansi_highlight_red(), ansi_normal());
85 if (is_nologin_shell(user_record_shell(hr
))) {
86 printf(" Login OK: %sno%s (nologin shell)\n", ansi_highlight_red(), ansi_normal());
90 y
= user_record_ratelimit_next_try(hr
);
91 if (y
!= USEC_INFINITY
&& y
> now(CLOCK_REALTIME
)) {
92 printf(" Login OK: %sno%s (ratelimit)\n", ansi_highlight_red(), ansi_normal());
96 printf(" Login OK: %syes%s\n", ansi_highlight_green(), ansi_normal());
100 r
= user_record_test_password_change_required(hr
);
104 printf(" Password OK: %schange now%s\n", ansi_highlight_yellow(), ansi_normal());
108 printf(" Password OK: %sexpired%s (change now!)\n", ansi_highlight_yellow(), ansi_normal());
112 printf(" Password OK: %sexpired%s (for good)\n", ansi_highlight_red(), ansi_normal());
116 printf(" Password OK: %sexpires soon%s\n", ansi_highlight_yellow(), ansi_normal());
120 printf(" Password OK: %sno timestamp%s\n", ansi_highlight_red(), ansi_normal());
124 printf(" Password OK: %schange not permitted%s\n", ansi_highlight_yellow(), ansi_normal());
130 printf(" Password OK: %sno%s (%m)\n", ansi_highlight_yellow(), ansi_normal());
134 printf(" Password OK: %syes%s\n", ansi_highlight_green(), ansi_normal());
138 if (uid_is_valid(hr
->uid
))
139 printf(" UID: " UID_FMT
"\n", hr
->uid
);
140 if (gid_is_valid(hr
->gid
)) {
141 if (show_full_group_info
) {
142 _cleanup_(group_record_unrefp
) GroupRecord
*gr
= NULL
;
144 r
= groupdb_by_gid(hr
->gid
, 0, &gr
);
147 printf(" GID: " GID_FMT
" (unresolvable: %m)\n", hr
->gid
);
149 printf(" GID: " GID_FMT
" (%s)\n", hr
->gid
, gr
->group_name
);
151 printf(" GID: " GID_FMT
"\n", hr
->gid
);
152 } else if (uid_is_valid(hr
->uid
)) /* Show UID as GID if not separately configured */
153 printf(" GID: " GID_FMT
"\n", (gid_t
) hr
->uid
);
155 if (show_full_group_info
) {
156 _cleanup_(userdb_iterator_freep
) UserDBIterator
*iterator
= NULL
;
158 r
= membershipdb_by_user(hr
->user_name
, 0, &iterator
);
161 printf(" Aux. Groups: (can't acquire: %m)\n");
163 const char *prefix
= " Aux. Groups:";
166 _cleanup_free_
char *group
= NULL
;
168 r
= membershipdb_iterator_get(iterator
, NULL
, &group
);
173 printf("%s (can't iterate: %m)\n", prefix
);
177 printf("%s %s\n", prefix
, group
);
183 if (hr
->real_name
&& !streq(hr
->real_name
, hr
->user_name
))
184 printf(" Real Name: %s\n", hr
->real_name
);
186 hd
= user_record_home_directory(hr
);
188 printf(" Directory: %s\n", hd
);
190 storage
= user_record_storage(hr
);
191 if (storage
>= 0) /* Let's be political, and clarify which storage we like, and which we don't. About CIFS we don't complain. */
192 printf(" Storage: %s%s\n", user_storage_to_string(storage
),
193 storage
== USER_LUKS
? " (strong encryption)" :
194 storage
== USER_FSCRYPT
? " (weak encryption)" :
195 IN_SET(storage
, USER_DIRECTORY
, USER_SUBVOLUME
) ? " (no encryption)" : "");
197 ip
= user_record_image_path(hr
);
198 if (ip
&& !streq_ptr(ip
, hd
))
199 printf(" Image Path: %s\n", ip
);
201 b
= user_record_removable(hr
);
203 printf(" Removable: %s\n", yes_no(b
));
205 shell
= user_record_shell(hr
);
207 printf(" Shell: %s\n", shell
);
209 if (hr
->email_address
)
210 printf(" Email: %s\n", hr
->email_address
);
212 printf(" Location: %s\n", hr
->location
);
213 if (hr
->password_hint
)
214 printf(" Passw. Hint: %s\n", hr
->password_hint
);
216 printf(" Icon Name: %s\n", hr
->icon_name
);
219 printf(" Time Zone: %s\n", hr
->time_zone
);
221 if (hr
->preferred_language
)
222 printf(" Language: %s\n", hr
->preferred_language
);
224 if (!strv_isempty(hr
->environment
)) {
227 STRV_FOREACH(i
, hr
->environment
) {
228 printf(i
== hr
->environment
?
229 " Environment: %s\n" :
235 printf(" Locked: %s\n", yes_no(hr
->locked
));
237 if (hr
->not_before_usec
!= UINT64_MAX
) {
238 char buf
[FORMAT_TIMESTAMP_MAX
];
239 printf(" Not Before: %s\n", format_timestamp(buf
, sizeof(buf
), hr
->not_before_usec
));
242 if (hr
->not_after_usec
!= UINT64_MAX
) {
243 char buf
[FORMAT_TIMESTAMP_MAX
];
244 printf(" Not After: %s\n", format_timestamp(buf
, sizeof(buf
), hr
->not_after_usec
));
247 if (hr
->umask
!= MODE_INVALID
)
248 printf(" UMask: 0%03o\n", hr
->umask
);
250 if (nice_is_valid(hr
->nice_level
))
251 printf(" Nice: %i\n", hr
->nice_level
);
253 for (int j
= 0; j
< _RLIMIT_MAX
; j
++) {
255 printf(" Limit: RLIMIT_%s=%" PRIu64
":%" PRIu64
"\n",
256 rlimit_to_string(j
), (uint64_t) hr
->rlimits
[j
]->rlim_cur
, (uint64_t) hr
->rlimits
[j
]->rlim_max
);
259 if (hr
->tasks_max
!= UINT64_MAX
)
260 printf(" Tasks Max: %" PRIu64
"\n", hr
->tasks_max
);
262 if (hr
->memory_high
!= UINT64_MAX
) {
263 char buf
[FORMAT_BYTES_MAX
];
264 printf(" Memory High: %s\n", format_bytes(buf
, sizeof(buf
), hr
->memory_high
));
267 if (hr
->memory_max
!= UINT64_MAX
) {
268 char buf
[FORMAT_BYTES_MAX
];
269 printf(" Memory Max: %s\n", format_bytes(buf
, sizeof(buf
), hr
->memory_max
));
272 if (hr
->cpu_weight
!= UINT64_MAX
)
273 printf(" CPU Weight: %" PRIu64
"\n", hr
->cpu_weight
);
275 if (hr
->io_weight
!= UINT64_MAX
)
276 printf(" IO Weight: %" PRIu64
"\n", hr
->io_weight
);
278 if (hr
->access_mode
!= MODE_INVALID
)
279 printf(" Access Mode: 0%03oo\n", user_record_access_mode(hr
));
281 if (storage
== USER_LUKS
) {
282 printf("LUKS Discard: %s\n", yes_no(user_record_luks_discard(hr
)));
284 if (!sd_id128_is_null(hr
->luks_uuid
))
285 printf(" LUKS UUID: " SD_ID128_FORMAT_STR
"\n", SD_ID128_FORMAT_VAL(hr
->luks_uuid
));
286 if (!sd_id128_is_null(hr
->partition_uuid
))
287 printf(" Part UUID: " SD_ID128_FORMAT_STR
"\n", SD_ID128_FORMAT_VAL(hr
->partition_uuid
));
288 if (!sd_id128_is_null(hr
->file_system_uuid
))
289 printf(" FS UUID: " SD_ID128_FORMAT_STR
"\n", SD_ID128_FORMAT_VAL(hr
->file_system_uuid
));
291 if (hr
->file_system_type
)
292 printf(" File System: %s\n", user_record_file_system_type(hr
));
295 printf(" LUKS Cipher: %s\n", hr
->luks_cipher
);
296 if (hr
->luks_cipher_mode
)
297 printf(" Cipher Mode: %s\n", hr
->luks_cipher_mode
);
298 if (hr
->luks_volume_key_size
!= UINT64_MAX
)
299 printf(" Volume Key: %" PRIu64
"bit\n", hr
->luks_volume_key_size
* 8);
301 if (hr
->luks_pbkdf_type
)
302 printf(" PBKDF Type: %s\n", hr
->luks_pbkdf_type
);
303 if (hr
->luks_pbkdf_hash_algorithm
)
304 printf(" PBKDF Hash: %s\n", hr
->luks_pbkdf_hash_algorithm
);
305 if (hr
->luks_pbkdf_time_cost_usec
!= UINT64_MAX
) {
306 char buf
[FORMAT_TIMESPAN_MAX
];
307 printf(" PBKDF Time: %s\n", format_timespan(buf
, sizeof(buf
), hr
->luks_pbkdf_time_cost_usec
, 0));
309 if (hr
->luks_pbkdf_memory_cost
!= UINT64_MAX
) {
310 char buf
[FORMAT_BYTES_MAX
];
311 printf(" PBKDF Bytes: %s\n", format_bytes(buf
, sizeof(buf
), hr
->luks_pbkdf_memory_cost
));
313 if (hr
->luks_pbkdf_parallel_threads
!= UINT64_MAX
)
314 printf("PBKDF Thread: %" PRIu64
"\n", hr
->luks_pbkdf_parallel_threads
);
316 } else if (storage
== USER_CIFS
) {
318 if (hr
->cifs_service
)
319 printf("CIFS Service: %s\n", hr
->cifs_service
);
322 if (hr
->cifs_user_name
)
323 printf(" CIFS User: %s\n", user_record_cifs_user_name(hr
));
325 printf(" CIFS Domain: %s\n", hr
->cifs_domain
);
327 if (storage
!= USER_CLASSIC
)
328 printf(" Mount Flags: %s %s %s\n",
329 hr
->nosuid
? "nosuid" : "suid",
330 hr
->nodev
? "nodev" : "dev",
331 hr
->noexec
? "noexec" : "exec");
333 if (hr
->skeleton_directory
)
334 printf(" Skel. Dir.: %s\n", user_record_skeleton_directory(hr
));
336 if (hr
->disk_size
!= UINT64_MAX
) {
337 char buf
[FORMAT_BYTES_MAX
];
338 printf(" Disk Size: %s\n", format_bytes(buf
, sizeof(buf
), hr
->disk_size
));
341 if (hr
->disk_usage
!= UINT64_MAX
) {
342 char buf
[FORMAT_BYTES_MAX
];
344 if (hr
->disk_size
!= UINT64_MAX
) {
347 permille
= (unsigned) DIV_ROUND_UP(hr
->disk_usage
* 1000U, hr
->disk_size
); /* Round up! */
348 printf(" Disk Usage: %s (= %u.%01u%%)\n",
349 format_bytes(buf
, sizeof(buf
), hr
->disk_usage
),
350 permille
/ 10, permille
% 10);
352 printf(" Disk Usage: %s\n", format_bytes(buf
, sizeof(buf
), hr
->disk_usage
));
355 if (hr
->disk_free
!= UINT64_MAX
) {
356 char buf
[FORMAT_BYTES_MAX
];
358 if (hr
->disk_size
!= UINT64_MAX
) {
361 permille
= (unsigned) ((hr
->disk_free
* 1000U) / hr
->disk_size
); /* Round down! */
362 printf(" Disk Free: %s (= %u.%01u%%)\n",
363 format_bytes(buf
, sizeof(buf
), hr
->disk_free
),
364 permille
/ 10, permille
% 10);
366 printf(" Disk Free: %s\n", format_bytes(buf
, sizeof(buf
), hr
->disk_free
));
369 if (hr
->disk_floor
!= UINT64_MAX
) {
370 char buf
[FORMAT_BYTES_MAX
];
371 printf(" Disk Floor: %s\n", format_bytes(buf
, sizeof(buf
), hr
->disk_floor
));
374 if (hr
->disk_ceiling
!= UINT64_MAX
) {
375 char buf
[FORMAT_BYTES_MAX
];
376 printf("Disk Ceiling: %s\n", format_bytes(buf
, sizeof(buf
), hr
->disk_ceiling
));
379 if (hr
->good_authentication_counter
!= UINT64_MAX
)
380 printf(" Good Auth.: %" PRIu64
"\n", hr
->good_authentication_counter
);
382 if (hr
->last_good_authentication_usec
!= UINT64_MAX
) {
383 char buf
[FORMAT_TIMESTAMP_MAX
];
384 printf(" Last Good: %s\n", format_timestamp(buf
, sizeof(buf
), hr
->last_good_authentication_usec
));
387 if (hr
->bad_authentication_counter
!= UINT64_MAX
)
388 printf(" Bad Auth.: %" PRIu64
"\n", hr
->bad_authentication_counter
);
390 if (hr
->last_bad_authentication_usec
!= UINT64_MAX
) {
391 char buf
[FORMAT_TIMESTAMP_MAX
];
392 printf(" Last Bad: %s\n", format_timestamp(buf
, sizeof(buf
), hr
->last_bad_authentication_usec
));
395 t
= user_record_ratelimit_next_try(hr
);
396 if (t
!= USEC_INFINITY
) {
397 usec_t n
= now(CLOCK_REALTIME
);
400 printf(" Next Try: anytime\n");
402 char buf
[FORMAT_TIMESPAN_MAX
];
403 printf(" Next Try: %sin %s%s\n",
404 ansi_highlight_red(),
405 format_timespan(buf
, sizeof(buf
), t
- n
, USEC_PER_SEC
),
410 if (storage
!= USER_CLASSIC
) {
411 char buf
[FORMAT_TIMESPAN_MAX
];
412 printf(" Auth. Limit: %" PRIu64
" attempts per %s\n", user_record_ratelimit_burst(hr
),
413 format_timespan(buf
, sizeof(buf
), user_record_ratelimit_interval_usec(hr
), 0));
416 if (hr
->enforce_password_policy
>= 0)
417 printf(" Passwd Pol.: %s\n", yes_no(hr
->enforce_password_policy
));
419 if (hr
->password_change_min_usec
!= UINT64_MAX
||
420 hr
->password_change_max_usec
!= UINT64_MAX
||
421 hr
->password_change_warn_usec
!= UINT64_MAX
||
422 hr
->password_change_inactive_usec
!= UINT64_MAX
) {
424 char buf
[FORMAT_TIMESPAN_MAX
];
425 printf(" Passwd Chg.:");
427 if (hr
->password_change_min_usec
!= UINT64_MAX
) {
428 printf(" min %s", format_timespan(buf
, sizeof(buf
), hr
->password_change_min_usec
, 0));
430 if (hr
->password_change_max_usec
!= UINT64_MAX
)
434 if (hr
->password_change_max_usec
!= UINT64_MAX
)
435 printf(" max %s", format_timespan(buf
, sizeof(buf
), hr
->password_change_max_usec
, 0));
437 if (hr
->password_change_warn_usec
!= UINT64_MAX
)
438 printf("/warn %s", format_timespan(buf
, sizeof(buf
), hr
->password_change_warn_usec
, 0));
440 if (hr
->password_change_inactive_usec
!= UINT64_MAX
)
441 printf("/inactive %s", format_timespan(buf
, sizeof(buf
), hr
->password_change_inactive_usec
, 0));
446 if (hr
->password_change_now
>= 0)
447 printf("Pas. Ch. Now: %s\n", yes_no(hr
->password_change_now
));
449 if (!strv_isempty(hr
->ssh_authorized_keys
))
450 printf("SSH Pub. Key: %zu\n", strv_length(hr
->ssh_authorized_keys
));
452 if (!strv_isempty(hr
->pkcs11_token_uri
)) {
455 STRV_FOREACH(i
, hr
->pkcs11_token_uri
)
456 printf(i
== hr
->pkcs11_token_uri
?
457 " Sec. Token: %s\n" :
461 k
= strv_length(hr
->hashed_password
);
463 printf(" Passwords: %snone%s\n",
464 user_record_disposition(hr
) == USER_REGULAR
? ansi_highlight_yellow() : ansi_normal(), ansi_normal());
466 printf(" Passwords: %zu\n", k
);
468 if (hr
->signed_locally
>= 0)
469 printf(" Local Sig.: %s\n", yes_no(hr
->signed_locally
));
471 if (hr
->stop_delay_usec
!= UINT64_MAX
) {
472 char buf
[FORMAT_TIMESPAN_MAX
];
473 printf(" Stop Delay: %s\n", format_timespan(buf
, sizeof(buf
), hr
->stop_delay_usec
, 0));
476 if (hr
->auto_login
>= 0)
477 printf("Autom. Login: %s\n", yes_no(hr
->auto_login
));
479 if (hr
->kill_processes
>= 0)
480 printf(" Kill Proc.: %s\n", yes_no(hr
->kill_processes
));
483 printf(" Service: %s\n", hr
->service
);