]> mj.ucw.cz Git - subauth.git/commitdiff
Client mostly complete
authorMartin Mares <mj@ucw.cz>
Wed, 19 Jul 2017 21:41:54 +0000 (23:41 +0200)
committerMartin Mares <mj@ucw.cz>
Wed, 19 Jul 2017 21:41:54 +0000 (23:41 +0200)
client/subauth.c
server/auth.c
server/cmd.c
server/subauthd.h

index 30dd28cdd1a047b1ccd8f5317ab35cd2a4ea8eae..723ee4f3a055bc45bc93e6b0b3ae4733145fc103 100644 (file)
@@ -5,13 +5,16 @@
  */
 
 #include <ucw/lib.h>
+#include <ucw/log.h>
 #include <ucw/opt.h>
 #include <ucw-json/json.h>
 
 #include <errno.h>
 #include <fcntl.h>
+#include <pwd.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+#include <time.h>
 #include <unistd.h>
 
 #include "autoconf.h"
 
 static char *socket_path = INSTALL_RUN_DIR "/subauthd.socket";
 
-static char *arg_login;
+static char *arg_user;
 static char *arg_zone;
 static char *arg_ident;
+static char *arg_comment;
 static int debug;
 
 /*** Communication with the daemon ***/
@@ -33,7 +37,8 @@ static struct json_node *rp;
 
 static void set_string(struct json_node *n, const char *key, const char *val)
 {
-  json_object_set(n, key, json_new_string(js, val));
+  if (val)
+    json_object_set(n, key, json_new_string(js, val));
 }
 
 static struct json_node *get_child(struct json_node *obj, const char *key, uint type)
@@ -57,6 +62,8 @@ static void op_new(const char *op)
   js = json_new();
   rq = json_new_object(js);
   set_string(rq, "cmd", op);
+  if (arg_user)
+    set_string(rq, "login", arg_user);
 }
 
 static void op_debug(const char *msg, struct json_node *n)
@@ -97,7 +104,7 @@ static void op_run(void)
     die("Cannot send request: %m");
   bclose(rq_fb);
 
-  byte rp_buf[4096];           // FIXME
+  byte rp_buf[16384];
   int rp_len = recv(sk, rp_buf, sizeof(rp_buf), 0);
   if (rp_len < 0)
     die("Cannot receive reply: %m");
@@ -113,22 +120,145 @@ static void op_run(void)
     die("Malformed reply: Top-level node is not an object");
   struct json_node *err = need_child(rp, "error", JSON_STRING);
   if (strcmp(err->string, ""))
-    {
-      fprintf(stderr, "Error: %s\n", err->string);
-      exit(1);
-    }
+    die("Error: %s", err->string);
 }
 
 /*** Commands ***/
 
 static void cmd_set_passwd(void)
 {
+  if (!arg_zone)
+    opt_failure("--zone must be given");
+
+  char *passwd = xstrdup(getpass("New password: "));
+  char *again = xstrdup(getpass("Confirm password: "));
+  if (strcmp(passwd, again))
+    die("Passwords do not match");
+
+  op_new("set-passwd");
+  set_string(rq, "zone", arg_zone);
+  set_string(rq, "passwd", passwd);
+
+  op_run();
+}
+
+static void cmd_delete_passwd(void)
+{
+  if (!arg_zone)
+    opt_failure("--zone must be given");
+
+  op_new("delete-passwd");
+  set_string(rq, "zone", arg_zone);
+
+  op_run();
+}
+
+static void cmd_create_token(void)
+{
+  if (!arg_zone)
+    opt_failure("--zone must be given");
+
+  op_new("create-token");
+  set_string(rq, "zone", arg_zone);
+  set_string(rq, "comment", arg_comment);
+
+  op_run();
+  struct json_node *jt = need_child(rp, "token", JSON_STRING);
+  printf("%s\n", jt->string);
+}
+
+static void cmd_delete_token(void)
+{
+  if (!arg_zone || !arg_ident)
+    opt_failure("--zone and --ident must be given");
+
+  op_new("delete-token");
+  set_string(rq, "zone", arg_zone);
+  set_string(rq, "ident", arg_ident);
+
+  op_run();
+}
+
+static void cmd_create_acct(void)
+{
+  if (!arg_zone || !arg_user)
+    opt_failure("--zone and --user must be given");
+
+  op_new("create-acct");
+  set_string(rq, "zone", arg_zone);
+  set_string(rq, "login", arg_user);
+
+  op_run();
+}
+
+static void cmd_delete_acct(void)
+{
+  if (!arg_zone || !arg_user)
+    opt_failure("--zone and --user must be given");
+
+  op_new("delete-acct");
+  set_string(rq, "zone", arg_zone);
+  set_string(rq, "login", arg_user);
+
+  op_run();
+}
+
+static void cmd_delete_user(void)
+{
+  if (!arg_user)
+    opt_failure("--user must be given");
+
+  op_new("delete-acct");
+  set_string(rq, "zone", "*");
+  set_string(rq, "login", arg_user);
+
+  op_run();
 }
 
 static void cmd_list(void)
 {
   op_new("list-accts");
   op_run();
+
+  struct json_node **jas = need_child(rp, "accounts", JSON_ARRAY)->elements;
+  if (!GARY_SIZE(jas))
+    {
+      puts("No accounts defined");
+      return;
+    }
+
+  printf("%-16s %-6s %-5s %-19s  %s\n",
+    "Zone", "Type", "Ident", "Last modified", "Comment");
+  for (uint i=0; i < GARY_SIZE(jas); i++)
+    {
+      struct json_node *ja = jas[i];
+      struct json_node *jz = need_child(ja, "zone", JSON_STRING);
+      struct json_node **jts = need_child(ja, "tokens", JSON_ARRAY)->elements;
+
+      if (!GARY_SIZE(jts))
+       {
+         printf("%-16s (no tokens defined)\n", jz->string);
+         continue;
+       }
+
+      for (uint j=0; j < GARY_SIZE(jts); j++)
+       {
+         struct json_node *lt = jts[j];
+         struct json_node *jtype = need_child(lt, "type", JSON_STRING);
+         struct json_node *jident = get_child(lt, "ident", JSON_STRING);
+         struct json_node *jcomment = get_child(lt, "comment", JSON_STRING);
+         struct json_node *jlastmod = need_child(lt, "lastmod", JSON_NUMBER);
+         time_t lm = jlastmod->number;
+         struct tm *tm = localtime(&lm);
+         printf("%-16s %-6s %-5s %04d-%02d-%02d %02d:%02d:%02d  %s\n",
+           jz->string,
+           jtype->string,
+           (jident ? jident->string : "-"),
+           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+           tm->tm_hour, tm->tm_min, tm->tm_sec,
+           (jcomment ? jcomment->string : ""));
+       }
+    }
 }
 
 static void cmd_zones(void)
@@ -153,6 +283,30 @@ static void cmd_zones(void)
     }
 }
 
+static void cmd_login(void)
+{
+  if (!arg_zone)
+    opt_failure("--zone must be given");
+
+  if (!arg_user)
+    {
+      uid_t uid = getuid();
+      struct passwd *pw = getpwuid(uid);
+      if (!pw)
+       die("You do not exist");
+      arg_user = xstrdup(pw->pw_name);
+    }
+
+  char *passwd = xstrdup(getpass("Password: "));
+
+  op_new("login");
+  set_string(rq, "zone", arg_zone);
+  set_string(rq, "passwd", passwd);
+
+  op_run();
+  printf("OK\n");
+}
+
 static void cmd_raw(void)
 {
   op_new("");
@@ -166,16 +320,30 @@ static void cmd_raw(void)
 
 enum command {
   CMD_SET_PASSWD,
+  CMD_DELETE_PASSWD,
+  CMD_CREATE_TOKEN,
+  CMD_DELETE_TOKEN,
+  CMD_CREATE_ACCT,
+  CMD_DELETE_ACCT,
+  CMD_DELETE_USER,
   CMD_LIST,
   CMD_ZONES,
+  CMD_LOGIN,
   CMD_RAW,
   CMD_MAX
 };
 
 void (* const command_handlers[CMD_MAX])(void) = {
   [CMD_SET_PASSWD] = cmd_set_passwd,
+  [CMD_DELETE_PASSWD] = cmd_delete_passwd,
+  [CMD_CREATE_TOKEN] = cmd_create_token,
+  [CMD_DELETE_TOKEN] = cmd_delete_token,
+  [CMD_CREATE_ACCT] = cmd_create_acct,
+  [CMD_DELETE_ACCT] = cmd_delete_acct,
+  [CMD_DELETE_USER] = cmd_delete_user,
   [CMD_LIST] = cmd_list,
   [CMD_ZONES] = cmd_zones,
+  [CMD_LOGIN] = cmd_login,
   [CMD_RAW] = cmd_raw,
 };
 
@@ -193,22 +361,33 @@ static const struct opt_section options = {
     OPT_BOOL(0, "debug", debug, 0, "\tDump raw communication with the daemon"),
     OPT_HELP_OPTION,
     OPT_HELP(""),
-    OPT_HELP("Commands:"),
-    OPT_SWITCH(0, "passwd", command, CMD_SET_PASSWD, OPT_SINGLE, "\tSet password"),
-    OPT_SWITCH(0, "list", command, CMD_LIST, OPT_SINGLE, "\tList tokens for all zones"),
-    OPT_SWITCH(0, "zones", command, CMD_ZONES, OPT_SINGLE, "\tList all known zones"),
-    OPT_SWITCH(0, "raw", command, CMD_RAW, OPT_SINGLE, "\tSend raw JSON command to the daemon"),
+    OPT_HELP("User commands:"),
+    OPT_SWITCH('l', "list",            command, CMD_LIST,              OPT_SINGLE, "\tList tokens for all zones"),
+    OPT_SWITCH(0,   "zones",           command, CMD_ZONES,             OPT_SINGLE, "\tList all known zones"),
+    OPT_SWITCH(0,   "passwd",          command, CMD_SET_PASSWD,        OPT_SINGLE, "\tSet password"),
+    OPT_SWITCH(0,   "delete-passwd",   command, CMD_DELETE_PASSWD,     OPT_SINGLE, "\tRemove password"),
+    OPT_SWITCH(0,   "create-token",    command, CMD_CREATE_TOKEN,      OPT_SINGLE, "\tCreate a new token"),
+    OPT_SWITCH(0,   "delete-token",    command, CMD_DELETE_TOKEN,      OPT_SINGLE, "\tRemove an existing token"),
+    OPT_SWITCH(0,   "login",           command, CMD_LOGIN,             OPT_SINGLE, "\tTry to log in"),
+    OPT_HELP(""),
+    OPT_HELP("Administrative commands:"),
+    OPT_SWITCH(0,   "create-acct",     command, CMD_CREATE_ACCT,       OPT_SINGLE, "\tCreate an account"),
+    OPT_SWITCH(0,   "delete-acct",     command, CMD_DELETE_ACCT,       OPT_SINGLE, "\tDelete an account"),
+    OPT_SWITCH(0,   "delete-user",     command, CMD_DELETE_USER,       OPT_SINGLE, "\tDelete a user with all his accounts"),
+    OPT_SWITCH(0,   "raw",             command, CMD_RAW,               OPT_SINGLE, "\tSend raw JSON command to the daemon"),
     OPT_HELP(""),
     OPT_HELP("Command options:"),
-    OPT_STRING('u', "user", arg_login, OPT_REQUIRED_VALUE, "login\tUser to act on (default: whoever calls it)"),
+    OPT_STRING('u', "user", arg_user, OPT_REQUIRED_VALUE, "login\tUser to act on (default: whoever calls it)"),
     OPT_STRING('z', "zone", arg_zone, OPT_REQUIRED_VALUE, "zone\tAuthentication zone"),
-    OPT_STRING('i', "ident", arg_ident, OPT_REQUIRED_VALUE, "id\tToken ID"),
+    OPT_STRING('i', "ident", arg_ident, OPT_REQUIRED_VALUE, "id\tToken ID ('*' for all tokens in zone)"),
+    OPT_STRING('c', "comment", arg_comment, OPT_REQUIRED_VALUE, "string\tHuman-readable description of token"),
     OPT_END
   }
 };
 
 int main(int argc UNUSED, char **argv)
 {
+  log_set_format(log_default_stream(), 0, 0);
   opt_parse(&options, argv+1);
 
   if (command < 0)
index bafcd525a5626869d22ebb29bb7e17107aa1b6ca..e92d5ad887c6ebdb961caadc2bb9365951fb40c5 100644 (file)
@@ -77,7 +77,7 @@ struct auth_token *auth_find_token_passwd(struct auth_acct *aa)
   return NULL;
 }
 
-struct auth_token *auth_find_token_generated(struct auth_acct *aa, char *ident)
+struct auth_token *auth_find_token_generated(struct auth_acct *aa, const char *ident)
 {
   CLIST_FOR_EACH(struct auth_token *, at, aa->tokens)
     if (at->type == TOKEN_GENERATED && !strcmp(at->ident, ident))
index 4b10368cc8efad80649e27ffbfa32f19a7d6a280..5533ddc92e677bad4572d39c2e18a19644d88afb 100644 (file)
@@ -236,6 +236,20 @@ static void cmd_set_passwd(struct client *c)
   cmd_ok(c);
 }
 
+static void cmd_delete_passwd(struct client *c)
+{
+  struct auth_acct *aa = cmd_need_target_acct(c);
+  struct auth_token *at = auth_find_token_passwd(aa);
+  if (!at)
+    cmd_error(c, "No password set");
+
+  msg(L_INFO, "Deleted password: login=<%s> zone=<%s>", aa->user->login, aa->zone->name);
+  auth_delete_token(at);
+
+  db_write();
+  cmd_ok(c);
+}
+
 static void cmd_create_token(struct client *c)
 {
   struct auth_acct *aa = cmd_need_target_acct(c);
@@ -257,6 +271,29 @@ static void cmd_create_token(struct client *c)
   cmd_ok(c);
 }
 
+static void cmd_delete_token(struct client *c)
+{
+  struct auth_acct *aa = cmd_need_target_acct(c);
+  const char *ident = cmd_need_string(c, "ident");
+  bool all = !strcmp(ident, "*");
+  bool matched = 0;
+
+  struct auth_token *tmp;
+  CLIST_FOR_EACH_DELSAFE(struct auth_token *, at, aa->tokens, tmp)
+    if (at->type == TOKEN_GENERATED && (all || !strcmp(at->ident, ident)))
+      {
+       matched = 1;
+       msg(L_INFO, "Deleted token: login=<%s> zone=<%s> id=<%s>", aa->user->login, aa->zone->name, at->ident);
+       auth_delete_token(at);
+      }
+
+  if (!all && !matched)
+    cmd_error(c, "No such token");
+
+  db_write();
+  cmd_ok(c);
+}
+
 static void cmd_login_fake(struct client *c, const char *passwd)
 {
   auth_check_token(auth_fake_token, passwd);
@@ -325,15 +362,18 @@ static void cmd_list_accts(struct client *c)
 {
   const char *login = cmd_need_target_login(c);
 
-  struct auth_user *au = auth_find_user(login, 0);
-  if (!au)
-    cmd_error(c, "No such user");
-
   struct json_context *js = c->json;
-  set_string(c, c->reply, "login", au->login);
+  set_string(c, c->reply, "login", login);
   struct json_node *jas = json_new_array(js);
   json_object_set(c->reply, "accounts", jas);
 
+  struct auth_user *au = auth_find_user(login, 0);
+  if (!au)
+    {
+      cmd_ok(c);
+      return;
+    }
+
   CLIST_FOR_EACH(struct auth_acct *, aa, au->accounts)
     {
       struct json_node *ja = json_new_object(js);
@@ -396,7 +436,9 @@ static const struct command command_table[] = {
   { "create-acct",     cmd_create_acct },
   { "delete-acct",     cmd_delete_acct },
   { "create-token",    cmd_create_token },
+  { "delete-token",    cmd_delete_token },
   { "set-passwd",      cmd_set_passwd },
+  { "delete-passwd",   cmd_delete_passwd },
   { "login",           cmd_login },
   { "list-accts",      cmd_list_accts },
   { "list-zones",      cmd_list_zones },
index 7148bfd145bbf4a7d0a43e5f07a2e951f58f385c..4fb665039c5beea8e195a057fa0fba3677a7acbe 100644 (file)
@@ -92,7 +92,7 @@ struct auth_zone *auth_find_zone(const char *name);
 struct auth_user *auth_find_user(const char *login, bool create);
 struct auth_acct *auth_find_acct(struct auth_user *au, struct auth_zone *az, bool create);
 struct auth_token *auth_find_token_passwd(struct auth_acct *aa);
-struct auth_token *auth_find_token_generated(struct auth_acct *aa, char *ident);
+struct auth_token *auth_find_token_generated(struct auth_acct *aa, const char *ident);
 void auth_delete_user(struct auth_user *au);
 void auth_delete_acct(struct auth_acct *aa);
 void auth_delete_token(struct auth_token *at);