]> mj.ucw.cz Git - subauth.git/commitdiff
Parts of the client
authorMartin Mares <mj@ucw.cz>
Wed, 19 Jul 2017 17:01:27 +0000 (19:01 +0200)
committerMartin Mares <mj@ucw.cz>
Wed, 19 Jul 2017 17:01:27 +0000 (19:01 +0200)
client/subauth.c

index 91a1a1f5be0167a0aa34f569988d438ecb2a286e..dc28cd0b015e7614f8ca37e9e800ee690f17c63e 100644 (file)
 
 #include "autoconf.h"
 
+/*** Arguments ***/
+
 static char *socket_path = INSTALL_RUN_DIR "/subauthd.socket";
 
-static const struct opt_section options = {
-  OPT_ITEMS {
-    OPT_HELP("A client to the sub-authentication daemon."),
-    OPT_HELP("Usage: subauth [options]"),
-    OPT_HELP(""),
-    OPT_HELP("Options:"),
-    OPT_HELP_OPTION,
-    OPT_END
-  }
-};
+static char *arg_login;
+static char *arg_zone;
+static char *arg_ident;
+static int debug;
 
-int main(int argc UNUSED, char **argv)
+/*** Communication with the daemon ***/
+
+static struct json_context *js;
+static struct json_node *rq;
+static struct json_node *rp;
+
+static void set_string(struct json_node *n, const char *key, const char *val)
 {
-  opt_parse(&options, argv+1);
+  json_object_set(n, key, json_new_string(js, val));
+}
+
+static struct json_node *get_child(struct json_node *obj, const char *key, bool mandatory, uint type)
+{
+  struct json_node *n = json_object_get(obj, key);
+  if (!n)
+    {
+      if (mandatory)
+       die("Malformed reply: missing %s", key);
+    }
+  else if (n->type != type)
+    die("Malformed reply: %s has wrong type", key);
+  return n;
+}
+
+static void op_new(const char *op)
+{
+  js = json_new();
+  rq = json_new_object(js);
+  set_string(rq, "cmd", op);
+}
 
+static void op_debug(const char *msg, struct json_node *n)
+{
+  if (!debug)
+    return;
+
+  struct fastbuf *out = bfdopen_shared(1, 4096);
+  bprintf(out, ">>> %s\n", msg);
+  js->format_options = JSON_FORMAT_INDENT;
+  json_write(js, out, n);
+  js->format_options = 0;
+  bclose(out);
+}
+
+static void op_run(void)
+{
   int sk = socket(PF_UNIX, SOCK_SEQPACKET, 0);
   if (sk < 0)
     die("socket(PF_UNIX, SOCK_SEQPACKET): %m");
@@ -46,24 +84,7 @@ int main(int argc UNUSED, char **argv)
   if (connect(sk, (struct sockaddr *) &sun, sizeof(sun)) < 0)
     die("Cannot connect to %s: %m", socket_path);
 
-  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, "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);
-  bflush(out);
+  op_debug("Request", rq);
 
   struct fastbuf *rq_fb = fbgrow_create(4096);
   json_write(js, rq_fb, rq);
@@ -78,13 +99,95 @@ int main(int argc UNUSED, char **argv)
   if (rp_len < 0)
     die("Cannot receive reply: %m");
 
-  puts("Parsing reply");
   struct fastbuf rp_fb;
   fbbuf_init_read(&rp_fb, rp_buf, rp_len, 0);
-  struct json_node *rp = json_parse(js, &rp_fb);
-  bprintf(out, "<<< Reply:\n");
-  json_write(js, out, rp);
-  bflush(out);
+  rp = json_parse(js, &rp_fb);
+  op_debug("Reply", rp);
+
+  close(sk);
+
+  if (rp->type != JSON_OBJECT)
+    die("Malformed reply: Top-level node is not an object");
+  struct json_node *err = get_child(rp, "error", 1, JSON_STRING);
+  if (strcmp(err->string, ""))
+    {
+      fprintf(stderr, "Error: %s\n", err->string);
+      exit(1);
+    }
+}
+
+/*** Commands ***/
+
+static void cmd_set_passwd(void)
+{
+}
+
+static void cmd_list(void)
+{
+  op_new("list");
+  op_run();
+}
+
+static void cmd_raw(void)
+{
+  op_new("");
+
+  struct fastbuf *in = bfdopen_shared(0, 4096);
+  rq = json_parse(js, in);
+  bclose(in);
+
+  op_run();
+}
+
+enum command {
+  CMD_SET_PASSWD,
+  CMD_LIST,
+  CMD_RAW,
+  CMD_MAX
+};
+
+void (* const command_handlers[CMD_MAX])(void) = {
+  [CMD_SET_PASSWD] = cmd_set_passwd,
+  [CMD_LIST] = cmd_list,
+  [CMD_RAW] = cmd_raw,
+};
+
+static int command = -1;
+
+/*** Main ***/
+
+static const struct opt_section options = {
+  OPT_ITEMS {
+    OPT_HELP("A client to the sub-authentication daemon."),
+    OPT_HELP("Usage: subauth [general options] <command> [options]"),
+    OPT_HELP(""),
+    OPT_HELP("General options:"),
+    OPT_STRING('s', "socket", socket_path, OPT_REQUIRED_VALUE, "path\tPath to daemon control socket"),
+    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, "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('z', "zone", arg_zone, OPT_REQUIRED_VALUE, "zone\tAuthentication zone"),
+    OPT_STRING('i', "ident", arg_ident, OPT_REQUIRED_VALUE, "id\tToken ID"),
+    OPT_END
+  }
+};
+
+int main(int argc UNUSED, char **argv)
+{
+  opt_parse(&options, argv+1);
+
+  if (command < 0)
+    opt_failure("No command given");
+  if (!command_handlers[command])
+    opt_failure("Command not implemented");
+  command_handlers[command]();
 
   return 0;
 }