chiark / gitweb /
2cbed293ba65a9ff1dbc69e96f345b1550522ae6
[elogind.git] / src / ask-password / ask-password.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <unistd.h>
24 #include <getopt.h>
25 #include <stddef.h>
26
27 #include "log.h"
28 #include "macro.h"
29 #include "strv.h"
30 #include "ask-password-api.h"
31 #include "def.h"
32
33 static const char *arg_icon = NULL;
34 static const char *arg_id = NULL;
35 static const char *arg_message = NULL;
36 static bool arg_echo = false;
37 static bool arg_use_tty = true;
38 static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC;
39 static bool arg_accept_cached = false;
40 static bool arg_multiple = false;
41
42 static void help(void) {
43         printf("%s [OPTIONS...] MESSAGE\n\n"
44                "Query the user for a system passphrase, via the TTY or an UI agent.\n\n"
45                "  -h --help          Show this help\n"
46                "     --icon=NAME     Icon name\n"
47                "     --timeout=SEC   Timeout in sec\n"
48                "     --echo          Do not mask input (useful for usernames)\n"
49                "     --no-tty        Ask question via agent even on TTY\n"
50                "     --accept-cached Accept cached passwords\n"
51                "     --multiple      List multiple passwords if available\n"
52                "     --id=ID         Query identifier (e.g. cryptsetup:/dev/sda5)\n"
53                , program_invocation_short_name);
54 }
55
56 static int parse_argv(int argc, char *argv[]) {
57
58         enum {
59                 ARG_ICON = 0x100,
60                 ARG_TIMEOUT,
61                 ARG_ECHO,
62                 ARG_NO_TTY,
63                 ARG_ACCEPT_CACHED,
64                 ARG_MULTIPLE,
65                 ARG_ID
66         };
67
68         static const struct option options[] = {
69                 { "help",          no_argument,       NULL, 'h'               },
70                 { "icon",          required_argument, NULL, ARG_ICON          },
71                 { "timeout",       required_argument, NULL, ARG_TIMEOUT       },
72                 { "echo",          no_argument,       NULL, ARG_ECHO          },
73                 { "no-tty",        no_argument,       NULL, ARG_NO_TTY        },
74                 { "accept-cached", no_argument,       NULL, ARG_ACCEPT_CACHED },
75                 { "multiple",      no_argument,       NULL, ARG_MULTIPLE      },
76                 { "id",            required_argument, NULL, ARG_ID            },
77                 {}
78         };
79
80         int c;
81
82         assert(argc >= 0);
83         assert(argv);
84
85         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
86
87                 switch (c) {
88
89                 case 'h':
90                         help();
91                         return 0;
92
93                 case ARG_ICON:
94                         arg_icon = optarg;
95                         break;
96
97                 case ARG_TIMEOUT:
98                         if (parse_sec(optarg, &arg_timeout) < 0) {
99                                 log_error("Failed to parse --timeout parameter %s", optarg);
100                                 return -EINVAL;
101                         }
102                         break;
103
104                 case ARG_ECHO:
105                         arg_echo = true;
106                         break;
107
108                 case ARG_NO_TTY:
109                         arg_use_tty = false;
110                         break;
111
112                 case ARG_ACCEPT_CACHED:
113                         arg_accept_cached = true;
114                         break;
115
116                 case ARG_MULTIPLE:
117                         arg_multiple = true;
118                         break;
119
120                 case ARG_ID:
121                         arg_id = optarg;
122                         break;
123
124                 case '?':
125                         return -EINVAL;
126
127                 default:
128                         assert_not_reached("Unhandled option");
129                 }
130
131         if (optind != argc - 1) {
132                 log_error("%s: required argument missing.", program_invocation_short_name);
133                 return -EINVAL;
134         }
135
136         arg_message = argv[optind];
137         return 1;
138 }
139
140 int main(int argc, char *argv[]) {
141         int r;
142         usec_t timeout;
143
144         log_parse_environment();
145         log_open();
146
147         r = parse_argv(argc, argv);
148         if (r <= 0)
149                 goto finish;
150
151         if (arg_timeout > 0)
152                 timeout = now(CLOCK_MONOTONIC) + arg_timeout;
153         else
154                 timeout = 0;
155
156         if (arg_use_tty && isatty(STDIN_FILENO)) {
157                 char *password = NULL;
158
159                 if ((r = ask_password_tty(arg_message, timeout, arg_echo, NULL, &password)) >= 0) {
160                         puts(password);
161                         free(password);
162                 }
163
164         } else {
165                 char **l;
166
167                 if ((r = ask_password_agent(arg_message, arg_icon, arg_id, timeout, arg_echo, arg_accept_cached, &l)) >= 0) {
168                         char **p;
169
170                         STRV_FOREACH(p, l) {
171                                 puts(*p);
172
173                                 if (!arg_multiple)
174                                         break;
175                         }
176
177                         strv_free(l);
178                 }
179         }
180
181 finish:
182
183         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
184 }