]> mj.ucw.cz Git - subauth.git/blobdiff - server/cmd.c
Real cryptography
[subauth.git] / server / cmd.c
index 8eba618a0b548f9100e4584d85c1fab5c6f4608c..3eb6bc02e79a3127850d1af1392e1b5c203a8f5a 100644 (file)
@@ -211,30 +211,150 @@ static void cmd_set_passwd(struct client *c)
   if (!aa->zone->allow_passwd)
     cmd_error(c, "This zone does not allow authentication by password");
 
+  if (strchr(passwd, '-'))
+    cmd_error(c, "The minus sign is forbidden in passwords");
+
   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_old = auth_find_token_passwd(aa);
+  if (at_old)
+    auth_delete_token(at_old);
 
   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)
+static void cmd_create_token(struct client *c)
 {
   struct auth_acct *aa = cmd_need_target_acct(c);
-  const char *passwd = cmd_need_string(c, "passwd");
 
-  // FIXME
+  if (!aa->zone->allow_tokens)
+    cmd_error(c, "This zone does not allow authentication by tokens");
+
+  if (clist_size(&aa->tokens) >= aa->zone->allow_tokens)
+    cmd_error(c, "Maximum number of tokens was reached");
+
+  struct auth_token *at = auth_create_token(aa);
+  char *tok = auth_set_token_generated(at, get_string(c->request, "comment"));
+  json_object_set(c->reply, "token", json_new_string(c->json, tok));
+  xfree(tok);
+
+  msg(L_INFO, "Created token: login=<%s> zone=<%s> id=<%s>", aa->user->login, aa->zone->name, at->ident);
+
+  db_write();
+  cmd_ok(c);
+}
+
+static void cmd_login_fake(struct client *c, const char *passwd)
+{
+  auth_check_token(auth_fake_token, passwd);
+  cmd_error(c, "Invalid password");
+}
+
+static void cmd_login(struct client *c)
+{
+  struct auth_zone *az = cmd_need_zone(c);
+  const char *given_passwd = cmd_need_string(c, "passwd");
+
+  // Split password string to token ident and the password proper
+  char passbuf[strlen(given_passwd) + 1];
+  strcpy(passbuf, given_passwd);
+  char *ident, *passwd;
+  char *sep = strchr(passbuf, '-');
+  if (sep)
+    {
+      *sep = 0;
+      ident = passbuf;
+      passwd = sep + 1;
+    }
+  else
+    {
+      ident = NULL;
+      passwd = passbuf;
+    }
+
+  const char *login = cmd_need_string(c, "login");
+  struct auth_user *au = auth_find_user(login, 0);
+  if (!au)
+    {
+      msg(L_INFO, "Login failed: No user=<%s>", login);
+      return cmd_login_fake(c, passwd);
+    }
+
+  struct auth_acct *aa = auth_find_acct(au, az, 0);
+  if (!aa)
+    {
+      msg(L_INFO, "Login failed: No account user=<%s> zone=<%s>", login, az->name);
+      return cmd_login_fake(c, passwd);
+    }
+
+  struct auth_token *at;
+  if (ident)
+    at = auth_find_token_generated(aa, ident);
+  else
+    at = auth_find_token_passwd(aa);
+  if (!at)
+    {
+      msg(L_INFO, "Login failed: No token user=<%s> zone=<%s> ident=<%s>", login, az->name, (ident ? : ""));
+      return cmd_login_fake(c, passwd);
+    }
+
+  if (!auth_check_token(at, passwd))
+    {
+      msg(L_INFO, "Login failed: Wrong password for user=<%s> zone=<%s> ident=<%s>", login, az->name, (ident ? : ""));
+      cmd_error(c, "Invalid password");
+    }
+
+  msg(L_INFO, "Login successful: user=<%s> zone=<%s> ident=<%s>", login, az->name, (ident ? : ""));
+  cmd_ok(c);
+}
+
+static void cmd_list(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;
+  json_object_set(c->reply, "login", json_new_string(js, au->login));
+  struct json_node *jas = json_new_array(js);
+  json_object_set(c->reply, "accounts", jas);
+
+  CLIST_FOR_EACH(struct auth_acct *, aa, au->accounts)
+    {
+      struct json_node *ja = json_new_object(js);
+      json_array_append(jas, ja);
+      json_object_set(ja, "zone", json_new_string(js, aa->zone->name));
+
+      struct json_node *jts = json_new_array(js);
+      json_object_set(ja, "tokens", jts);
+
+      CLIST_FOR_EACH(struct auth_token *, at, aa->tokens)
+       {
+         struct json_node *jt = json_new_object(js);
+         json_array_append(jts, jt);
+
+         const char *type;
+         switch (at->type)
+           {
+           case TOKEN_PASSWORD:        type = "passwd"; break;
+           case TOKEN_GENERATED:       type = "token"; break;
+           default:                    type = "unknown"; break;
+           }
+         json_object_set(jt, "type", json_new_string(js, type));
+
+         if (at->ident)
+           json_object_set(jt, "ident", json_new_string(js, at->ident));
+         if (at->comment)
+           json_object_set(jt, "comment", json_new_string(js, at->comment));
+         json_object_set(jt, "lastmod", json_new_number(js, at->last_modified));
+       }
+    }
 
   cmd_ok(c);
 }
@@ -248,8 +368,10 @@ static const struct command command_table[] = {
   { "nop",             cmd_nop },
   { "create-acct",     cmd_create_acct },
   { "delete-acct",     cmd_delete_acct },
+  { "create-token",    cmd_create_token },
   { "set-passwd",      cmd_set_passwd },
-  { "verify",          cmd_verify },
+  { "login",           cmd_login },
+  { "list",            cmd_list },
 };
 
 void cmd_dispatch(struct client *c)