From 5fee60d1bbf8baf7e43709ef979efde8d31eb5ae Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Wed, 19 Jul 2017 19:01:27 +0200 Subject: [PATCH] Parts of the client --- client/subauth.c | 173 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 138 insertions(+), 35 deletions(-) diff --git a/client/subauth.c b/client/subauth.c index 91a1a1f..dc28cd0 100644 --- a/client/subauth.c +++ b/client/subauth.c @@ -16,23 +16,61 @@ #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] [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; } -- 2.39.5