]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/ask-password/ask-password.c
creds: Add ImportCredential=
[thirdparty/systemd.git] / src / ask-password / ask-password.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <getopt.h>
5 #include <stddef.h>
6 #include <unistd.h>
7
8 #include "ask-password-api.h"
9 #include "build.h"
10 #include "constants.h"
11 #include "log.h"
12 #include "macro.h"
13 #include "main-func.h"
14 #include "parse-argument.h"
15 #include "pretty-print.h"
16 #include "strv.h"
17 #include "terminal-util.h"
18
19 static const char *arg_icon = NULL;
20 static const char *arg_id = NULL; /* identifier for 'ask-password' protocol */
21 static const char *arg_key_name = NULL; /* name in kernel keyring */
22 static const char *arg_credential_name = NULL; /* name in $CREDENTIALS_DIRECTORY directory */
23 static char *arg_message = NULL;
24 static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC;
25 static bool arg_multiple = false;
26 static bool arg_no_output = false;
27 static AskPasswordFlags arg_flags = ASK_PASSWORD_PUSH_CACHE;
28 static bool arg_newline = true;
29
30 STATIC_DESTRUCTOR_REGISTER(arg_message, freep);
31
32 static int help(void) {
33 _cleanup_free_ char *link = NULL;
34 int r;
35
36 r = terminal_urlify_man("systemd-ask-password", "1", &link);
37 if (r < 0)
38 return log_oom();
39
40 printf("%1$s [OPTIONS...] MESSAGE\n\n"
41 "%3$sQuery the user for a system passphrase, via the TTY or an UI agent.%4$s\n\n"
42 " -h --help Show this help\n"
43 " --icon=NAME Icon name\n"
44 " --id=ID Query identifier (e.g. \"cryptsetup:/dev/sda5\")\n"
45 " --keyname=NAME Kernel key name for caching passwords (e.g. \"cryptsetup\")\n"
46 " --credential=NAME\n"
47 " Credential name for ImportCredential=, LoadCredential= or\n"
48 " SetCredential= credentials\n"
49 " --timeout=SEC Timeout in seconds\n"
50 " --echo=yes|no|masked\n"
51 " Control whether to show password while typing (echo)\n"
52 " -e --echo Equivalent to --echo=yes\n"
53 " --emoji=yes|no|auto\n"
54 " Show a lock and key emoji\n"
55 " --no-tty Ask question via agent even on TTY\n"
56 " --accept-cached Accept cached passwords\n"
57 " --multiple List multiple passwords if available\n"
58 " --no-output Do not print password to standard output\n"
59 " -n Do not suffix password written to standard output with\n"
60 " newline\n"
61 "\nSee the %2$s for details.\n",
62 program_invocation_short_name,
63 link,
64 ansi_highlight(),
65 ansi_normal());
66
67 return 0;
68 }
69
70 static int parse_argv(int argc, char *argv[]) {
71
72 enum {
73 ARG_ICON = 0x100,
74 ARG_TIMEOUT,
75 ARG_EMOJI,
76 ARG_NO_TTY,
77 ARG_ACCEPT_CACHED,
78 ARG_MULTIPLE,
79 ARG_ID,
80 ARG_KEYNAME,
81 ARG_NO_OUTPUT,
82 ARG_VERSION,
83 ARG_CREDENTIAL,
84 };
85
86 static const struct option options[] = {
87 { "help", no_argument, NULL, 'h' },
88 { "version", no_argument, NULL, ARG_VERSION },
89 { "icon", required_argument, NULL, ARG_ICON },
90 { "timeout", required_argument, NULL, ARG_TIMEOUT },
91 { "echo", optional_argument, NULL, 'e' },
92 { "emoji", required_argument, NULL, ARG_EMOJI },
93 { "no-tty", no_argument, NULL, ARG_NO_TTY },
94 { "accept-cached", no_argument, NULL, ARG_ACCEPT_CACHED },
95 { "multiple", no_argument, NULL, ARG_MULTIPLE },
96 { "id", required_argument, NULL, ARG_ID },
97 { "keyname", required_argument, NULL, ARG_KEYNAME },
98 { "no-output", no_argument, NULL, ARG_NO_OUTPUT },
99 { "credential", required_argument, NULL, ARG_CREDENTIAL },
100 {}
101 };
102
103 const char *emoji = NULL;
104 int c, r;
105
106 assert(argc >= 0);
107 assert(argv);
108
109 /* Note the asymmetry: the long option --echo= allows an optional argument, the short option does
110 * not. */
111
112 /* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
113 * that checks for GNU extensions in optstring ('-' or '+' at the beginning). */
114 optind = 0;
115 while ((c = getopt_long(argc, argv, "+hen", options, NULL)) >= 0)
116
117 switch (c) {
118
119 case 'h':
120 return help();
121
122 case ARG_VERSION:
123 return version();
124
125 case ARG_ICON:
126 arg_icon = optarg;
127 break;
128
129 case ARG_TIMEOUT:
130 r = parse_sec(optarg, &arg_timeout);
131 if (r < 0)
132 return log_error_errno(r, "Failed to parse --timeout= parameter: %s", optarg);
133
134 break;
135
136 case 'e':
137 if (!optarg) {
138 /* Short option -e is used, or no argument to long option --echo= */
139 arg_flags |= ASK_PASSWORD_ECHO;
140 arg_flags &= ~ASK_PASSWORD_SILENT;
141 } else if (isempty(optarg) || streq(optarg, "masked"))
142 /* Empty argument or explicit string "masked" for default behaviour. */
143 arg_flags &= ~(ASK_PASSWORD_ECHO|ASK_PASSWORD_SILENT);
144 else {
145 r = parse_boolean_argument("--echo=", optarg, NULL);
146 if (r < 0)
147 return r;
148
149 SET_FLAG(arg_flags, ASK_PASSWORD_ECHO, r);
150 SET_FLAG(arg_flags, ASK_PASSWORD_SILENT, !r);
151 }
152 break;
153
154 case ARG_EMOJI:
155 emoji = optarg;
156 break;
157
158 case ARG_NO_TTY:
159 arg_flags |= ASK_PASSWORD_NO_TTY;
160 break;
161
162 case ARG_ACCEPT_CACHED:
163 arg_flags |= ASK_PASSWORD_ACCEPT_CACHED;
164 break;
165
166 case ARG_MULTIPLE:
167 arg_multiple = true;
168 break;
169
170 case ARG_ID:
171 arg_id = optarg;
172 break;
173
174 case ARG_KEYNAME:
175 arg_key_name = optarg;
176 break;
177
178 case ARG_NO_OUTPUT:
179 arg_no_output = true;
180 break;
181
182 case ARG_CREDENTIAL:
183 arg_credential_name = optarg;
184 break;
185
186 case 'n':
187 arg_newline = false;
188 break;
189
190 case '?':
191 return -EINVAL;
192
193 default:
194 assert_not_reached();
195 }
196
197 if (isempty(emoji) || streq(emoji, "auto"))
198 SET_FLAG(arg_flags, ASK_PASSWORD_HIDE_EMOJI, FLAGS_SET(arg_flags, ASK_PASSWORD_ECHO));
199 else {
200 r = parse_boolean_argument("--emoji=", emoji, NULL);
201 if (r < 0)
202 return r;
203
204 SET_FLAG(arg_flags, ASK_PASSWORD_HIDE_EMOJI, !r);
205 }
206
207 if (argc > optind) {
208 arg_message = strv_join(argv + optind, " ");
209 if (!arg_message)
210 return log_oom();
211 } else if (FLAGS_SET(arg_flags, ASK_PASSWORD_ECHO)) {
212 /* By default ask_password_auto() will query with the string "Password: ", which is not right
213 * when full echo is on, since then it's unlikely a password. Let's hence default to a less
214 * confusing string in that case. */
215
216 arg_message = strdup("Input:");
217 if (!arg_message)
218 return log_oom();
219 }
220
221 return 1;
222 }
223
224 static int run(int argc, char *argv[]) {
225 _cleanup_strv_free_erase_ char **l = NULL;
226 usec_t timeout;
227 int r;
228
229 log_show_color(true);
230 log_parse_environment();
231 log_open();
232
233 r = parse_argv(argc, argv);
234 if (r <= 0)
235 return r;
236
237 if (arg_timeout > 0)
238 timeout = usec_add(now(CLOCK_MONOTONIC), arg_timeout);
239 else
240 timeout = 0;
241
242 r = ask_password_auto(arg_message, arg_icon, arg_id, arg_key_name, arg_credential_name ?: "password", timeout, arg_flags, &l);
243 if (r < 0)
244 return log_error_errno(r, "Failed to query password: %m");
245
246 STRV_FOREACH(p, l) {
247 if (!arg_no_output) {
248 if (arg_newline)
249 puts(*p);
250 else
251 fputs(*p, stdout);
252 }
253
254 fflush(stdout);
255
256 if (!arg_multiple)
257 break;
258 }
259
260 return 0;
261 }
262
263 DEFINE_MAIN_FUNCTION(run);