chiark / gitweb /
ad8ad659d2db36c2e10fc88e355c3bc196da5217
[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 <sys/socket.h>
23 #include <poll.h>
24 #include <sys/types.h>
25 #include <assert.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <sys/un.h>
31 #include <sys/stat.h>
32 #include <sys/signalfd.h>
33 #include <getopt.h>
34 #include <termios.h>
35 #include <limits.h>
36 #include <stddef.h>
37
38 #include "log.h"
39 #include "macro.h"
40 #include "util.h"
41 #include "strv.h"
42 #include "ask-password-api.h"
43 #include "def.h"
44
45 static const char *arg_icon = NULL;
46 static const char *arg_id = NULL;
47 static const char *arg_message = NULL;
48 static bool arg_echo = false;
49 static bool arg_use_tty = true;
50 static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC;
51 static bool arg_accept_cached = false;
52 static bool arg_multiple = false;
53
54 static void help(void) {
55         printf("%s [OPTIONS...] MESSAGE\n\n"
56                "Query the user for a system passphrase, via the TTY or an UI agent.\n\n"
57                "  -h --help          Show this help\n"
58                "     --icon=NAME     Icon name\n"
59                "     --timeout=SEC   Timeout in sec\n"
60                "     --echo          Do not mask input (useful for usernames)\n"
61                "     --no-tty        Ask question via agent even on TTY\n"
62                "     --accept-cached Accept cached passwords\n"
63                "     --multiple      List multiple passwords if available\n"
64                "     --id=ID         Query identifier (e.g. cryptsetup:/dev/sda5)\n"
65                , program_invocation_short_name);
66 }
67
68 static int parse_argv(int argc, char *argv[]) {
69
70         enum {
71                 ARG_ICON = 0x100,
72                 ARG_TIMEOUT,
73                 ARG_ECHO,
74                 ARG_NO_TTY,
75                 ARG_ACCEPT_CACHED,
76                 ARG_MULTIPLE,
77                 ARG_ID
78         };
79
80         static const struct option options[] = {
81                 { "help",          no_argument,       NULL, 'h'               },
82                 { "icon",          required_argument, NULL, ARG_ICON          },
83                 { "timeout",       required_argument, NULL, ARG_TIMEOUT       },
84                 { "echo",          no_argument,       NULL, ARG_ECHO          },
85                 { "no-tty",        no_argument,       NULL, ARG_NO_TTY        },
86                 { "accept-cached", no_argument,       NULL, ARG_ACCEPT_CACHED },
87                 { "multiple",      no_argument,       NULL, ARG_MULTIPLE      },
88                 { "id",            required_argument, NULL, ARG_ID            },
89                 {}
90         };
91
92         int c;
93
94         assert(argc >= 0);
95         assert(argv);
96
97         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
98
99                 switch (c) {
100
101                 case 'h':
102                         help();
103                         return 0;
104
105                 case ARG_ICON:
106                         arg_icon = optarg;
107                         break;
108
109                 case ARG_TIMEOUT:
110                         if (parse_sec(optarg, &arg_timeout) < 0) {
111                                 log_error("Failed to parse --timeout parameter %s", optarg);
112                                 return -EINVAL;
113                         }
114                         break;
115
116                 case ARG_ECHO:
117                         arg_echo = true;
118                         break;
119
120                 case ARG_NO_TTY:
121                         arg_use_tty = false;
122                         break;
123
124                 case ARG_ACCEPT_CACHED:
125                         arg_accept_cached = true;
126                         break;
127
128                 case ARG_MULTIPLE:
129                         arg_multiple = true;
130                         break;
131
132                 case ARG_ID:
133                         arg_id = optarg;
134                         break;
135
136                 case '?':
137                         return -EINVAL;
138
139                 default:
140                         assert_not_reached("Unhandled option");
141                 }
142
143         if (optind != argc - 1) {
144                 log_error("%s: required argument missing.", program_invocation_short_name);
145                 return -EINVAL;
146         }
147
148         arg_message = argv[optind];
149         return 1;
150 }
151
152 int main(int argc, char *argv[]) {
153         int r;
154         usec_t timeout;
155
156         log_parse_environment();
157         log_open();
158
159         r = parse_argv(argc, argv);
160         if (r <= 0)
161                 goto finish;
162
163         if (arg_timeout > 0)
164                 timeout = now(CLOCK_MONOTONIC) + arg_timeout;
165         else
166                 timeout = 0;
167
168         if (arg_use_tty && isatty(STDIN_FILENO)) {
169                 char *password = NULL;
170
171                 if ((r = ask_password_tty(arg_message, timeout, arg_echo, NULL, &password)) >= 0) {
172                         puts(password);
173                         free(password);
174                 }
175
176         } else {
177                 char **l;
178
179                 if ((r = ask_password_agent(arg_message, arg_icon, arg_id, timeout, arg_echo, arg_accept_cached, &l)) >= 0) {
180                         char **p;
181
182                         STRV_FOREACH(p, l) {
183                                 puts(*p);
184
185                                 if (!arg_multiple)
186                                         break;
187                         }
188
189                         strv_free(l);
190                 }
191         }
192
193 finish:
194
195         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
196 }