Mercurial > projects > pwm
comparison pwm.c @ 18:1e39a251cbe9
Use libtecla for interactive input
author | Guido Berhoerster <guido+pwm@berhoerster.name> |
---|---|
date | Thu, 24 Aug 2017 13:10:56 +0200 |
parents | a07665727c19 |
children | 5c6155c8e9b6 |
comparison
equal
deleted
inserted
replaced
17:a08ef0674d8e | 18:1e39a251cbe9 |
---|---|
25 | 25 |
26 #ifdef HAVE_ERR_H | 26 #ifdef HAVE_ERR_H |
27 #include <err.h> | 27 #include <err.h> |
28 #endif /* HAVE_ERR_H */ | 28 #endif /* HAVE_ERR_H */ |
29 #include <errno.h> | 29 #include <errno.h> |
30 #include <fcntl.h> | |
30 #include <langinfo.h> | 31 #include <langinfo.h> |
31 #include <locale.h> | 32 #include <locale.h> |
32 #include <pwd.h> | 33 #include <pwd.h> |
33 #ifdef HAVE_READPASSPHRASE_H | |
34 #include <readpassphrase.h> | |
35 #endif /* READPASSPHRASE_H */ | |
36 #include <stdlib.h> | 34 #include <stdlib.h> |
37 #include <stdio.h> | 35 #include <stdio.h> |
38 #include <string.h> | 36 #include <string.h> |
39 #include <pwd.h> | 37 #include <pwd.h> |
40 #include <sys/stat.h> | 38 #include <sys/stat.h> |
45 #include "cmd.h" | 43 #include "cmd.h" |
46 #include "pwfile.h" | 44 #include "pwfile.h" |
47 #include "tok.h" | 45 #include "tok.h" |
48 #include "util.h" | 46 #include "util.h" |
49 | 47 |
50 #ifndef PWM_LINE_MAX | 48 #ifndef PWM_HISTORY_ENTRIES_MAX |
51 #define PWM_LINE_MAX 16384 | 49 #define PWM_HISTORY_ENTRIES_MAX 1024 |
52 #endif /* !PWM_LINE_MAX */ | 50 #endif /* !PWM_HISTORY_MAX */ |
51 | |
52 #ifndef PWM_HISTORY_LINES_MAX | |
53 #define PWM_HISTORY_LINES_MAX 256 | |
54 #endif /* !PWM_HISTORY_LINES_MAX */ | |
55 | |
56 #ifndef PWM_HISTORY_MAX | |
57 #define PWM_HISTORY_MAX (PWM_HISTORY_LINES_MAX * PWM_LINE_MAX) | |
58 #endif /* !PWM_HISTORY_MAX */ | |
53 | 59 |
54 static void | 60 static void |
55 usage(void) | 61 usage(void) |
56 { | 62 { |
57 fprintf(stderr, "usage: %s [-P file] [filename]\n", getprogname()); | 63 fprintf(stderr, "usage: %s [-P file] [filename]\n", getprogname()); |
74 ctx->errmsg = NULL; | 80 ctx->errmsg = NULL; |
75 } | 81 } |
76 } | 82 } |
77 | 83 |
78 static int | 84 static int |
85 complete_nothing(WordCompletion *cpl, void *data, const char *line, | |
86 int word_end) | |
87 { | |
88 return (0); | |
89 } | |
90 | |
91 static int | |
79 run_input_loop(struct pwm_ctx *ctx, int is_interactive) | 92 run_input_loop(struct pwm_ctx *ctx, int is_interactive) |
80 { | 93 { |
81 int retval = -1; | 94 int retval = -1; |
95 char prompt[8 + 2 + 1]; | |
96 GetLine *gl = NULL; | |
82 char buf[PWM_LINE_MAX]; | 97 char buf[PWM_LINE_MAX]; |
98 char *line = buf; | |
83 int c; | 99 int c; |
84 int argc = 0; | 100 int argc = 0; |
85 char **argv = NULL; | 101 char **argv = NULL; |
86 struct cmd *cmd; | 102 struct cmd *cmd; |
87 int i; | 103 int i; |
88 | 104 |
105 snprintf(prompt, sizeof (prompt), "%.*s> ", 8, getprogname()); | |
106 | |
107 /* initialize libtecla */ | |
108 gl = new_GetLine(PWM_LINE_MAX, PWM_HISTORY_MAX); | |
109 if (gl == NULL) { | |
110 err(1, "new_GetLine"); | |
111 } | |
112 gl_limit_history(gl, PWM_HISTORY_LINES_MAX); | |
113 /* disable default filename completion */ | |
114 gl_customize_completion(gl, NULL, complete_nothing); | |
115 | |
89 for (;;) { | 116 for (;;) { |
90 cmd = NULL; | 117 cmd = NULL; |
91 if (fgets(buf, (int)sizeof (buf), stdin) == NULL) { | 118 line = gl_get_line(gl, prompt, NULL, -1); |
92 if (ferror(stdin)) { | 119 if (line == NULL) { |
93 /* error */ | 120 switch (gl_return_status(gl)) { |
94 warn("failed to read command"); | 121 case GLR_EOF: |
95 goto out; | |
96 } else if (feof(stdin)) { | |
97 /* EOF */ | |
98 break; | 122 break; |
99 } | 123 case GLR_ERROR: |
100 } | 124 warnx("gl_get_line: %s", |
101 if ((buf[strlen(buf) - 1] != '\n') && !feof(stdin)) { | 125 gl_error_message(gl, NULL, 0)); |
102 /* line was truncated */ | 126 } |
103 fprintf(stderr, "line too long\n"); | 127 break; |
104 if (is_interactive) { | |
105 /* skip input to next newline */ | |
106 do { | |
107 errno = 0; | |
108 c = fgetc(stdin); | |
109 if ((c == EOF) && (errno != 0)) { | |
110 warn("failed to read command"); | |
111 goto out; | |
112 } | |
113 } while ((c != '\n') && (c != EOF)); | |
114 } else { | |
115 /* fatal error in non-interactive mode */ | |
116 goto out; | |
117 } | |
118 } | 128 } |
119 | 129 |
120 /* tokenize line */ | 130 /* tokenize line */ |
121 switch(tok_tokenize(buf, &argc, &argv)) { | 131 switch (tok_tokenize(line, &argc, &argv)) { |
122 case TOK_ERR_SYSTEM_ERROR: | 132 case TOK_ERR_SYSTEM_ERROR: |
123 err(1, "tok_tokenize"); | 133 err(1, "tok_tokenize"); |
124 case TOK_ERR_UNTERMINATED_QUOTE: | 134 case TOK_ERR_UNTERMINATED_QUOTE: |
125 fprintf(stderr, "unterminated quote\n"); | 135 fprintf(stderr, "unterminated quote\n"); |
126 if (!is_interactive) { | 136 if (!is_interactive) { |
181 out: | 191 out: |
182 for (i = 0; i < argc; i++) { | 192 for (i = 0; i < argc; i++) { |
183 free(argv[i]); | 193 free(argv[i]); |
184 } | 194 } |
185 free(argv); | 195 free(argv); |
196 del_GetLine(gl); | |
197 | |
198 return (retval); | |
199 } | |
200 | |
201 int | |
202 pwm_read_password(struct pwm_ctx *ctx, int is_new_password) | |
203 { | |
204 int retval = -1; | |
205 GetLine *gl = NULL; | |
206 char *line; | |
207 size_t len; | |
208 char password_buf[sizeof (ctx->password)] = { '\0' }; | |
209 | |
210 /* initialize libtecla */ | |
211 gl = new_GetLine(sizeof (password_buf) - 1, 0); | |
212 if (gl == NULL) { | |
213 err(1, "new_GetLine"); | |
214 } | |
215 /* disable default filename completion */ | |
216 gl_customize_completion(gl, NULL, complete_nothing); | |
217 gl_echo_mode(gl, 0); | |
218 | |
219 line = gl_get_line(gl, is_new_password ? "New password: " : | |
220 "Password: ", NULL, -1); | |
221 putchar('\n'); | |
222 if (line == NULL) { | |
223 if (gl_return_status(gl) == GLR_ERROR) { | |
224 errx(1, "gl_get_line: %s", gl_error_message(gl, NULL, | |
225 0)); | |
226 } | |
227 goto out; | |
228 } | |
229 len = strlen(line); | |
230 if ((len > 0) && (line[len - 1] == '\n')) { | |
231 line[--len] = '\0'; | |
232 } | |
233 if (len == 0) { | |
234 fprintf(stderr, "password must not be empty\n"); | |
235 goto out; | |
236 } | |
237 strcpy(password_buf, line); | |
238 | |
239 /* confirm the entered password entered */ | |
240 if (is_new_password) { | |
241 line = gl_get_line(gl, "Confirm password: ", NULL, -1); | |
242 putchar('\n'); | |
243 if (line == NULL) { | |
244 if (gl_return_status(gl) == GLR_ERROR) { | |
245 errx(1, "gl_get_line: %s", gl_error_message(gl, | |
246 NULL, 0)); | |
247 } | |
248 goto out; | |
249 } | |
250 len = strlen(line); | |
251 if ((len > 0) && (line[len - 1] == '\n')) { | |
252 line[--len] = '\0'; | |
253 } | |
254 if (strcmp(password_buf, line) != 0) { | |
255 fprintf(stderr, "passwords do not match\n"); | |
256 goto out; | |
257 } | |
258 } | |
259 | |
260 strcpy(ctx->password, password_buf); | |
261 retval = 0; | |
262 | |
263 out: | |
264 del_GetLine(gl); | |
186 | 265 |
187 return (retval); | 266 return (retval); |
188 } | 267 } |
189 | 268 |
190 static int | 269 static int |
251 const char *master_password_filename = NULL; | 330 const char *master_password_filename = NULL; |
252 struct pwm_ctx ctx = { 0 }; | 331 struct pwm_ctx ctx = { 0 }; |
253 struct passwd *passwd; | 332 struct passwd *passwd; |
254 char *pwm_dirname = NULL; | 333 char *pwm_dirname = NULL; |
255 FILE *fp = NULL; | 334 FILE *fp = NULL; |
256 char password_buf[PWS3_MAX_PASSWORD_LEN + 1]; | |
257 | 335 |
258 setprogname(argv[0]); | 336 setprogname(argv[0]); |
259 | 337 |
260 /* set up locale and check for UTF-8 codeset */ | 338 /* set up locale and check for UTF-8 codeset */ |
261 locale = setlocale(LC_ALL, ""); | 339 locale = setlocale(LC_ALL, ""); |
341 if (master_password_filename != NULL) { | 419 if (master_password_filename != NULL) { |
342 if (read_password_from_file(master_password_filename, | 420 if (read_password_from_file(master_password_filename, |
343 ctx.password, sizeof (ctx.password)) != 0) { | 421 ctx.password, sizeof (ctx.password)) != 0) { |
344 goto out; | 422 goto out; |
345 } | 423 } |
346 } else { | 424 } else if (pwm_read_password(&ctx, (fp == NULL)) != 0) { |
347 if (readpassphrase("Enter password: ", ctx.password, | 425 goto out; |
348 sizeof (ctx.password), RPP_ECHO_OFF | RPP_REQUIRE_TTY) == | |
349 NULL) { | |
350 err(1, "readpassphrase"); | |
351 } | |
352 if (ctx.password[0] == '\0') { | |
353 fprintf(stderr, "password must not be empty\n"); | |
354 goto out; | |
355 } | |
356 if (fp == NULL) { | |
357 if (readpassphrase("Confirm password: ", password_buf, | |
358 sizeof (password_buf), | |
359 RPP_ECHO_OFF | RPP_REQUIRE_TTY) == NULL) { | |
360 err(1, "readpassphrase"); | |
361 } | |
362 if (strcmp(ctx.password, password_buf) != 0) { | |
363 fprintf(stderr, "passwords do not match\n"); | |
364 goto out; | |
365 } | |
366 } | |
367 } | 426 } |
368 if (fp != NULL) { | 427 if (fp != NULL) { |
369 if (pwfile_read_file(&ctx, fp) != 0) { | 428 if (pwfile_read_file(&ctx, fp) != 0) { |
370 goto out; | 429 goto out; |
371 } | 430 } |