linkd

Control plane daemon for unos
git clone git://git.finwo.net/app/linkd
Log | Files | Refs | README

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 }