linkctl.c (2325B)
1 #define _GNU_SOURCE 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <string.h> 5 #include <strings.h> 6 #include <termios.h> 7 #include <unistd.h> 8 9 #include "cli/client.h" 10 #include "registry.h" 11 #include "util/auth.h" 12 13 static void usage(const char *prog) { 14 fprintf(stderr, "usage: %s <command> [args...]\n", prog); 15 fprintf(stderr, " %s COMMAND list what the daemon accepts\n", prog); 16 fprintf(stderr, " %s hash [user] generate a password-file entry\n", prog); 17 } 18 19 static char *read_password(const char *prompt) { 20 struct termios old, quiet; 21 int tty = isatty(STDIN_FILENO); 22 char *line = NULL; 23 size_t cap = 0; 24 25 if (tty) { 26 fprintf(stderr, "%s", prompt); 27 fflush(stderr); 28 if (tcgetattr(STDIN_FILENO, &old) == 0) { 29 quiet = old; 30 quiet.c_lflag &= (tcflag_t)~ECHO; 31 tcsetattr(STDIN_FILENO, TCSAFLUSH, &quiet); 32 } else { 33 tty = 0; 34 } 35 } 36 37 ssize_t n = getline(&line, &cap, stdin); 38 39 if (tty) { 40 tcsetattr(STDIN_FILENO, TCSAFLUSH, &old); 41 fprintf(stderr, "\n"); 42 } 43 44 if (n <= 0) { free(line); return NULL; } 45 char *nl = strpbrk(line, "\r\n"); 46 if (nl) *nl = '\0'; 47 return line; 48 } 49 50 static int cmd_hash(int argc, char *argv[]) { 51 const char *user = argc > 1 ? argv[1] : NULL; 52 53 char *pass = read_password("Password: "); 54 if (!pass || !*pass) { 55 fprintf(stderr, "linkctl: empty password\n"); 56 free(pass); 57 return 1; 58 } 59 if (isatty(STDIN_FILENO)) { 60 char *again = read_password("Again: "); 61 if (!again || strcmp(pass, again) != 0) { 62 fprintf(stderr, "linkctl: passwords do not match\n"); 63 free(pass); 64 free(again); 65 return 1; 66 } 67 free(again); 68 } 69 70 char *hash = auth_make_hash(pass, AUTH_DEFAULT_ITERATIONS); 71 memset(pass, 0, strlen(pass)); 72 free(pass); 73 74 if (!hash) { 75 fprintf(stderr, "linkctl: could not generate hash\n"); 76 return 1; 77 } 78 79 if (user) printf("%s:%s:readonly\n", user, hash); 80 else printf("%s\n", hash); 81 free(hash); 82 return 0; 83 } 84 85 int main_linkctl(int argc, char *argv[]) { 86 if (argc < 2) { 87 usage(argv[0]); 88 return 1; 89 } 90 if (!strcasecmp(argv[1], "hash")) return cmd_hash(argc - 1, argv + 1); 91 92 return linkd_call(argc - 1, (const char **)argv + 1); 93 } 94 95 __attribute__((constructor)) 96 static void register_linkctl(void) { 97 cli_register("linkctl", main_linkctl); 98 }