]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/ask-password/ask-password.c
creds: Add ImportCredential=
[thirdparty/systemd.git] / src / ask-password / ask-password.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
490aed58 2
490aed58 3#include <errno.h>
490aed58 4#include <getopt.h>
0e098b15 5#include <stddef.h>
00843602 6#include <unistd.h>
490aed58 7
00843602 8#include "ask-password-api.h"
d6b4d1c7 9#include "build.h"
28db6fbf 10#include "constants.h"
490aed58
LP
11#include "log.h"
12#include "macro.h"
c7d7adf5 13#include "main-func.h"
e390c34d 14#include "parse-argument.h"
294bf0c3 15#include "pretty-print.h"
21bc923a 16#include "strv.h"
8806bb4b 17#include "terminal-util.h"
490aed58
LP
18
19static const char *arg_icon = NULL;
8806bb4b
LP
20static const char *arg_id = NULL; /* identifier for 'ask-password' protocol */
21static const char *arg_key_name = NULL; /* name in kernel keyring */
22static const char *arg_credential_name = NULL; /* name in $CREDENTIALS_DIRECTORY directory */
e287086b 23static char *arg_message = NULL;
7f434cf4 24static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC;
21bc923a 25static bool arg_multiple = false;
a5a4e365 26static bool arg_no_output = false;
e287086b 27static AskPasswordFlags arg_flags = ASK_PASSWORD_PUSH_CACHE;
b80ef40c 28static bool arg_newline = true;
490aed58 29
c7d7adf5
YW
30STATIC_DESTRUCTOR_REGISTER(arg_message, freep);
31
37ec0fdd
LP
32static 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
8806bb4b
LP
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"
e287086b
LP
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"
8806bb4b 46 " --credential=NAME\n"
bbfb25f4
DDM
47 " Credential name for ImportCredential=, LoadCredential= or\n"
48 " SetCredential= credentials\n"
e287086b 49 " --timeout=SEC Timeout in seconds\n"
49365d1c
LP
50 " --echo=yes|no|masked\n"
51 " Control whether to show password while typing (echo)\n"
52 " -e --echo Equivalent to --echo=yes\n"
e390c34d
CH
53 " --emoji=yes|no|auto\n"
54 " Show a lock and key emoji\n"
e287086b
LP
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"
a5a4e365 58 " --no-output Do not print password to standard output\n"
b80ef40c
LP
59 " -n Do not suffix password written to standard output with\n"
60 " newline\n"
8806bb4b 61 "\nSee the %2$s for details.\n",
bc556335 62 program_invocation_short_name,
8806bb4b
LP
63 link,
64 ansi_highlight(),
65 ansi_normal());
37ec0fdd
LP
66
67 return 0;
490aed58
LP
68}
69
70static int parse_argv(int argc, char *argv[]) {
71
72 enum {
73 ARG_ICON = 0x100,
1b39d4b9 74 ARG_TIMEOUT,
e390c34d 75 ARG_EMOJI,
21bc923a
LP
76 ARG_NO_TTY,
77 ARG_ACCEPT_CACHED,
9fa1de96 78 ARG_MULTIPLE,
e287086b
LP
79 ARG_ID,
80 ARG_KEYNAME,
a5a4e365 81 ARG_NO_OUTPUT,
37ec0fdd 82 ARG_VERSION,
8806bb4b 83 ARG_CREDENTIAL,
490aed58
LP
84 };
85
86 static const struct option options[] = {
21bc923a 87 { "help", no_argument, NULL, 'h' },
37ec0fdd 88 { "version", no_argument, NULL, ARG_VERSION },
21bc923a
LP
89 { "icon", required_argument, NULL, ARG_ICON },
90 { "timeout", required_argument, NULL, ARG_TIMEOUT },
49365d1c 91 { "echo", optional_argument, NULL, 'e' },
e390c34d 92 { "emoji", required_argument, NULL, ARG_EMOJI },
21bc923a
LP
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 },
9fa1de96 96 { "id", required_argument, NULL, ARG_ID },
e287086b 97 { "keyname", required_argument, NULL, ARG_KEYNAME },
a5a4e365 98 { "no-output", no_argument, NULL, ARG_NO_OUTPUT },
8806bb4b 99 { "credential", required_argument, NULL, ARG_CREDENTIAL },
eb9da376 100 {}
490aed58
LP
101 };
102
e390c34d 103 const char *emoji = NULL;
49365d1c 104 int c, r;
490aed58
LP
105
106 assert(argc >= 0);
107 assert(argv);
108
49365d1c
LP
109 /* Note the asymmetry: the long option --echo= allows an optional argument, the short option does
110 * not. */
ef9c12b1
YW
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;
b80ef40c 115 while ((c = getopt_long(argc, argv, "+hen", options, NULL)) >= 0)
490aed58
LP
116
117 switch (c) {
118
119 case 'h':
37ec0fdd
LP
120 return help();
121
122 case ARG_VERSION:
123 return version();
490aed58
LP
124
125 case ARG_ICON:
126 arg_icon = optarg;
127 break;
128
129 case ARG_TIMEOUT:
49365d1c
LP
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
490aed58
LP
134 break;
135
49365d1c
LP
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 {
51214cf4 145 r = parse_boolean_argument("--echo=", optarg, NULL);
49365d1c
LP
146 if (r < 0)
147 return r;
148
51214cf4
ZJS
149 SET_FLAG(arg_flags, ASK_PASSWORD_ECHO, r);
150 SET_FLAG(arg_flags, ASK_PASSWORD_SILENT, !r);
49365d1c 151 }
64845bdc
DS
152 break;
153
e390c34d
CH
154 case ARG_EMOJI:
155 emoji = optarg;
156 break;
157
1b39d4b9 158 case ARG_NO_TTY:
e287086b 159 arg_flags |= ASK_PASSWORD_NO_TTY;
1b39d4b9
LP
160 break;
161
21bc923a 162 case ARG_ACCEPT_CACHED:
e287086b 163 arg_flags |= ASK_PASSWORD_ACCEPT_CACHED;
21bc923a
LP
164 break;
165
166 case ARG_MULTIPLE:
167 arg_multiple = true;
168 break;
169
9fa1de96
DH
170 case ARG_ID:
171 arg_id = optarg;
172 break;
173
e287086b 174 case ARG_KEYNAME:
8806bb4b 175 arg_key_name = optarg;
e287086b
LP
176 break;
177
a5a4e365
CH
178 case ARG_NO_OUTPUT:
179 arg_no_output = true;
180 break;
181
8806bb4b
LP
182 case ARG_CREDENTIAL:
183 arg_credential_name = optarg;
184 break;
185
b80ef40c
LP
186 case 'n':
187 arg_newline = false;
188 break;
189
490aed58
LP
190 case '?':
191 return -EINVAL;
192
193 default:
04499a70 194 assert_not_reached();
490aed58 195 }
490aed58 196
e390c34d
CH
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 {
51214cf4 200 r = parse_boolean_argument("--emoji=", emoji, NULL);
e390c34d
CH
201 if (r < 0)
202 return r;
49365d1c 203
51214cf4 204 SET_FLAG(arg_flags, ASK_PASSWORD_HIDE_EMOJI, !r);
e390c34d
CH
205 }
206
e287086b
LP
207 if (argc > optind) {
208 arg_message = strv_join(argv + optind, " ");
a5116848
LP
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:");
e287086b
LP
217 if (!arg_message)
218 return log_oom();
490aed58
LP
219 }
220
1b39d4b9 221 return 1;
490aed58
LP
222}
223
c7d7adf5 224static int run(int argc, char *argv[]) {
ab84f5b9 225 _cleanup_strv_free_erase_ char **l = NULL;
7dcda352 226 usec_t timeout;
e287086b 227 int r;
1b39d4b9 228
1a043959 229 log_show_color(true);
1b39d4b9
LP
230 log_parse_environment();
231 log_open();
232
601185b4
ZJS
233 r = parse_argv(argc, argv);
234 if (r <= 0)
c7d7adf5 235 return r;
1b39d4b9 236
7dcda352 237 if (arg_timeout > 0)
496db330 238 timeout = usec_add(now(CLOCK_MONOTONIC), arg_timeout);
7dcda352
LP
239 else
240 timeout = 0;
241
8806bb4b 242 r = ask_password_auto(arg_message, arg_icon, arg_id, arg_key_name, arg_credential_name ?: "password", timeout, arg_flags, &l);
c7d7adf5
YW
243 if (r < 0)
244 return log_error_errno(r, "Failed to query password: %m");
21bc923a 245
e287086b 246 STRV_FOREACH(p, l) {
b80ef40c
LP
247 if (!arg_no_output) {
248 if (arg_newline)
249 puts(*p);
250 else
251 fputs(*p, stdout);
252 }
253
254 fflush(stdout);
ec863ba6 255
e287086b
LP
256 if (!arg_multiple)
257 break;
7f4e0805 258 }
1b39d4b9 259
c7d7adf5 260 return 0;
1b39d4b9 261}
c7d7adf5
YW
262
263DEFINE_MAIN_FUNCTION(run);