]> mj.ucw.cz Git - subauth.git/commitdiff
More commands
authorMartin Mares <mj@ucw.cz>
Wed, 19 Jul 2017 13:32:56 +0000 (15:32 +0200)
committerMartin Mares <mj@ucw.cz>
Wed, 19 Jul 2017 13:32:56 +0000 (15:32 +0200)
client/subauth.c
server/auth.c
server/cmd.c
server/subauthd.c
server/subauthd.h

index 42b900382a76191eee555d591a6aade6411a0f3d..91a1a1f5be0167a0aa34f569988d438ecb2a286e 100644 (file)
@@ -49,9 +49,17 @@ int main(int argc UNUSED, char **argv)
   struct fastbuf *out = bfdopen(1, 4096);
 
   struct json_context *js = json_new();
+
+#if 0
   struct json_node *rq = json_new_object(js);
 
-  json_object_set(rq, "cmd", json_new_string(js, "nop"));
+  json_object_set(rq, "cmd", json_new_string(js, "create-acct"));
+  json_object_set(rq, "login", json_new_string(js, "mj"));
+  json_object_set(rq, "zone", json_new_string(js, "mail"));
+#else
+  struct fastbuf *in = bfdopen(0, 4096);
+  struct json_node *rq = json_parse(js, in);
+#endif
 
   bprintf(out, ">>> Request:\n");
   json_write(js, out, rq);
index f34039baf5cf17e0efdeb0cbe5730fd683932fbe..040189820abcf2b21251893804d7af96bf115913 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <time.h>
 #include <unistd.h>
 
 #include "subauthd.h"
@@ -17,9 +18,9 @@
 #define HASH_NODE struct auth_user
 #define HASH_PREFIX(x) user_hash_##x
 #define HASH_KEY_ENDSTRING login
-//#define HASH_WANT_FIND
+#define HASH_WANT_FIND
 #define HASH_WANT_LOOKUP
-// #define HASH_WANT_REMOVE
+#define HASH_WANT_REMOVE
 #define HASH_GIVE_INIT_DATA
 
 static void user_hash_init_data(struct auth_user *au)
@@ -27,7 +28,9 @@ static void user_hash_init_data(struct auth_user *au)
   clist_init(&au->accounts);
 }
 
-static struct auth_zone *find_zone_by_name(const char *name)
+#include <ucw/hashtable.h>
+
+struct auth_zone *auth_find_zone(const char *name)
 {
   CLIST_FOR_EACH(struct auth_zone *, z, zone_list)
     if (!strcmp(z->name, name))
@@ -35,7 +38,71 @@ static struct auth_zone *find_zone_by_name(const char *name)
   return NULL;
 }
 
-#include <ucw/hashtable.h>
+struct auth_user *auth_find_user(const char *login, bool create)
+{
+  if (create)
+    return user_hash_lookup((char *) login);
+  else
+    return user_hash_find((char *) login);
+}
+
+struct auth_acct *auth_find_acct(struct auth_user *au, struct auth_zone *az, bool create)
+{
+  CLIST_FOR_EACH(struct auth_acct *, aa, au->accounts)
+    if (aa->zone == az)
+      return aa;
+
+  if (!create)
+    return NULL;
+
+  struct auth_acct *aa = xmalloc_zero(sizeof(*aa));
+  clist_add_tail(&au->accounts, &aa->n);
+  aa->user = au;
+  aa->zone = az;
+  clist_init(&aa->tokens);
+  return aa;
+}
+
+void auth_delete_user(struct auth_user *au)
+{
+  struct auth_acct *aa;
+  while (aa = clist_head(&au->accounts))
+    auth_delete_acct(aa);
+
+  user_hash_remove(au);
+}
+
+void auth_delete_acct(struct auth_acct *ac)
+{
+  struct auth_token *at;
+  while (at = clist_head(&ac->tokens))
+    auth_delete_token(at);
+  clist_remove(&ac->n);
+}
+
+void auth_delete_token(struct auth_token *at)
+{
+  clist_remove(&at->n);
+  xfree(at->salt);
+  xfree(at->hash);
+  xfree(at->comment);
+}
+
+struct auth_token *auth_create_token(struct auth_acct *aa)
+{
+  struct auth_token *at = xmalloc_zero(sizeof(*at));
+  clist_add_tail(&aa->tokens, &at->n);
+  at->acct = aa;
+  at->last_modified = time(NULL);
+  return at;
+}
+
+void auth_set_token_passwd(struct auth_token *at, const char *passwd)
+{
+  at->type = TOKEN_PASSWORD;
+  at->salt = xstrdup("???");
+  at->hash = xstrdup("???");
+}
 
 static void NONRET db_corrupted(const char *reason)
 {
@@ -55,7 +122,7 @@ static void db_parse_user(struct json_node *ju)
   if (!jas)
     db_corrupted("User has no accounts");
 
-  struct auth_user *au = user_hash_lookup((char *) login);
+  struct auth_user *au = auth_find_user(login, 1);
   if (clist_head(&au->accounts))
     db_corrupted("Multiple users with the same login");
 
@@ -69,7 +136,8 @@ static void db_parse_user(struct json_node *ju)
 
       struct auth_acct *aa = xmalloc_zero(sizeof(*aa));
       clist_add_tail(&au->accounts, &aa->n);
-      aa->zone = find_zone_by_name(zone_name);
+      aa->user = au;
+      aa->zone = auth_find_zone(zone_name);
       if (!aa->zone)
        die("Database defines accounts in zone %s, which is not configured", zone_name);
       clist_init(&aa->tokens);
@@ -97,8 +165,7 @@ static void db_parse_user(struct json_node *ju)
              if (!get_uint(jt, "m", &lastmod))
                db_corrupted("Token has invalid last modified time");
 
-             struct auth_token *at = xmalloc(sizeof(*at));
-             clist_add_tail(&aa->tokens, &at->n);
+             struct auth_token *at = auth_create_token(aa);
              at->type = type;
              at->salt = xstrdup(salt);
              at->hash = xstrdup(hash);
index 125422a93614ded3623c43991bb1dbd35f5479f5..8eba618a0b548f9100e4584d85c1fab5c6f4608c 100644 (file)
@@ -5,17 +5,28 @@
  */
 
 #include <ucw/lib.h>
+#include <ucw/trans.h>
+
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdio.h>
 
 #include "subauthd.h"
 
-void cmd_error(struct client *c, const char *err)
+static void NONRET cmd_error(struct client *c, const char *err, ...)
 {
-  json_object_set(c->reply, "error", json_new_string(c->json, err));
+  va_list args;
+  char msg[1024];
+  va_start(args, err);
+  vsnprintf(msg, sizeof(msg), err, args);
+  json_object_set(c->reply, "error", json_new_string(c->json, msg));
+  trans_throw("adhoc", NULL, "Error caught");
+  va_end(args);
 }
 
 static void cmd_ok(struct client *c)
 {
-  cmd_error(c, "");
+  json_object_set(c->reply, "error", json_new_string_ref(c->json, ""));
 }
 
 const char *get_string(struct json_node *n, const char *key)
@@ -61,11 +72,173 @@ struct json_node *get_object(struct json_node *n, const char *key)
     return NULL;
 }
 
+static const char *cmd_need_string(struct client *c, const char *key)
+{
+  const char *val = get_string(c->request, key);
+  if (!val)
+    cmd_error(c, "Missing %s", key);
+  return val;
+}
+
+static struct auth_zone *cmd_need_zone(struct client *c)
+{
+  const char *name = cmd_need_string(c, "zone");
+  struct auth_zone *az = auth_find_zone(name);
+  if (!az)
+    cmd_error(c, "No such zone");
+  return az;
+}
+
+static bool cmd_is_admin(struct client *c)
+{
+  // FIXME
+  (void) c;
+  return 1;
+}
+
+static void cmd_require_admin(struct client *c)
+{
+  if (!cmd_is_admin(c))
+    cmd_error(c, "Permission denied");
+}
+
+static const char *cmd_need_target_login(struct client *c)
+{
+  const char *l = get_string(c->request, "login");
+  if (l)
+    {
+      cmd_require_admin(c);
+      return l;
+    }
+  else
+    {
+      struct passwd *pw = getpwuid(c->uid);
+      if (!pw)
+       cmd_error(c, "You do not exist");
+      return json_strdup(c->json, pw->pw_name);
+    }
+}
+
+static struct auth_acct *cmd_need_target_acct(struct client *c)
+{
+  const char *login = cmd_need_target_login(c);
+  struct auth_zone *az = cmd_need_zone(c);
+
+  struct auth_user *au = auth_find_user(login, 0);
+  struct auth_acct *aa = au ? auth_find_acct(au, az, 0) : NULL;
+  if (aa)
+    return aa;
+
+  if (!az->auto_create_acct)
+    cmd_error(c, "No such account");
+
+  if (!au)
+    {
+      msg(L_INFO, "Automatically creating user: login=<%s>", login);
+      au = auth_find_user(login, 1);
+    }
+  msg(L_INFO, "Automatically creating account: login=<%s> zone=<%s>", login, az->name);
+  return auth_find_acct(au, az, 1);
+}
+
 static void cmd_nop(struct client *c)
 {
   cmd_ok(c);
 }
 
+static void cmd_create_acct(struct client *c)
+{
+  cmd_require_admin(c);
+
+  const char *login = get_string(c->request, "login");
+  if (!login)
+    cmd_error(c, "Login required");
+
+  struct auth_zone *az = cmd_need_zone(c);
+  struct auth_user *au = auth_find_user(login, 1);
+  if (!auth_find_acct(au, az, 0))
+    {
+      msg(L_INFO, "Creating account: login=<%s> zone=<%s>", login, az->name);
+      auth_find_acct(au, az, 1);
+      db_write();
+    }
+
+  cmd_ok(c);
+}
+
+static void cmd_delete_acct(struct client *c)
+{
+  cmd_require_admin(c);
+
+  const char *login = get_string(c->request, "login");
+  if (!login)
+    cmd_error(c, "Login required");
+  const char *zone_name = get_string(c->request, "zone");
+
+  struct auth_user *au = auth_find_user(login, 0);
+  if (!au)
+    return cmd_ok(c);
+
+  if (zone_name && !strcmp(zone_name, "*"))
+    {
+      msg(L_INFO, "Deleting user: login=<%s>", login);
+      auth_delete_user(au);
+    }
+  else
+    {
+      struct auth_zone *az = cmd_need_zone(c);
+      struct auth_acct *aa = auth_find_acct(au, az, 0);
+      if (!aa)
+       return cmd_ok(c);
+      msg(L_INFO, "Deleting account: login=<%s> zone=<%s>", login, az->name);
+      auth_delete_acct(aa);
+      if (!clist_head(&au->accounts))
+       {
+         msg(L_INFO, "Deleting user with no accounts: login=<%s>", login);
+         auth_delete_user(au);
+       }
+    }
+
+  db_write();
+  cmd_ok(c);
+}
+
+static void cmd_set_passwd(struct client *c)
+{
+  struct auth_acct *aa = cmd_need_target_acct(c);
+  const char *passwd = cmd_need_string(c, "passwd");
+
+  if (!aa->zone->allow_passwd)
+    cmd_error(c, "This zone does not allow authentication by password");
+
+  msg(L_INFO, "Set password: login=<%s> zone=<%s>", aa->user->login, aa->zone->name);
+
+  CLIST_FOR_EACH(struct auth_token *, at, aa->tokens)
+    if (at->type == TOKEN_PASSWORD)
+      {
+       auth_delete_token(at);
+       break;
+      }
+
+  struct auth_token *at = auth_create_token(aa);
+  auth_set_token_passwd(at, passwd);
+
+  // FIXME
+
+  db_write();
+  cmd_ok(c);
+}
+
+static void cmd_verify(struct client *c)
+{
+  struct auth_acct *aa = cmd_need_target_acct(c);
+  const char *passwd = cmd_need_string(c, "passwd");
+
+  // FIXME
+
+  cmd_ok(c);
+}
+
 struct command {
   const char *cmd;
   void (*handler)(struct client *c);
@@ -73,6 +246,10 @@ struct command {
 
 static const struct command command_table[] = {
   { "nop",             cmd_nop },
+  { "create-acct",     cmd_create_acct },
+  { "delete-acct",     cmd_delete_acct },
+  { "set-passwd",      cmd_set_passwd },
+  { "verify",          cmd_verify },
 };
 
 void cmd_dispatch(struct client *c)
@@ -82,16 +259,30 @@ void cmd_dispatch(struct client *c)
 
   if (rq->type != JSON_OBJECT || !(cmd = get_string(rq, "cmd")))
     {
-      cmd_error(c, "Malformed request");
+      json_object_set(c->reply, "error", json_new_string_ref(c->json, "Malformed request"));
       return;
     }
 
+  const struct command *command = NULL;
   for (uint i=0; i < ARRAY_SIZE(command_table); i++)
     if (!strcmp(cmd, command_table[i].cmd))
       {
-       command_table[i].handler(c);
-       return;
+       command = &command_table[i];
+       break;
       }
+  if (!command)
+    {
+      json_object_set(c->reply, "error", json_new_string_ref(c->json, "No such command"));
+      return;
+    }
 
-  cmd_error(c, "No such command");
+  TRANS_TRY
+    {
+      if (command)
+       command->handler(c);
+    }
+  TRANS_CATCH(x)
+    {
+    }
+  TRANS_END;
 }
index d9892b4e15f6dac63c8567d9ea5b2e3cfcfda475..30c25a27848fcafc89b434312463d9c04517b3ce 100644 (file)
@@ -112,7 +112,7 @@ static void received_packet(struct client *c, byte *pkt, int len)
     }
   TRANS_CATCH(x)
     {
-      cmd_error(c, "Parse error");
+      json_object_set(c->reply, "error", json_new_string_ref(c->json, "Parse error"));
       send_reply(c);
       return;
     }
index e807ef326d3b1a011a795cd72e88629de69417fc..d1a1cf7409e5c16514a4a4403ff6e0bbba6fb089 100644 (file)
@@ -30,7 +30,6 @@ extern char *database_name;
 
 /* cmd.c */
 
-void cmd_error(struct client *c, const char *err);
 void cmd_dispatch(struct client *c);
 
 const char *get_string(struct json_node *n, const char *key);
@@ -55,6 +54,7 @@ struct auth_user {
 
 struct auth_acct {
   cnode n;
+  struct auth_user *user;
   struct auth_zone *zone;
   clist tokens;                                // of struct auth_token
 };
@@ -67,6 +67,7 @@ enum token_type {
 
 struct auth_token {
   cnode n;
+  struct auth_acct *acct;
   enum token_type type;
   char *salt;
   char *hash;
@@ -76,3 +77,11 @@ struct auth_token {
 
 void auth_init(void);
 void db_write(void);
+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);
+void auth_delete_user(struct auth_user *au);
+void auth_delete_acct(struct auth_acct *aa);
+void auth_delete_token(struct auth_token *at);
+struct auth_token *auth_create_token(struct auth_acct *aa);
+void auth_set_token_passwd(struct auth_token *at, const char *passwd);