2 * Sub-authentication Client
4 * (c) 2017 Martin Mares <mj@ucw.cz>
9 #include <ucw-json/json.h>
13 #include <sys/socket.h>
21 static char *socket_path = INSTALL_RUN_DIR "/subauthd.socket";
23 static char *arg_login;
24 static char *arg_zone;
25 static char *arg_ident;
28 /*** Communication with the daemon ***/
30 static struct json_context *js;
31 static struct json_node *rq;
32 static struct json_node *rp;
34 static void set_string(struct json_node *n, const char *key, const char *val)
36 json_object_set(n, key, json_new_string(js, val));
39 static struct json_node *get_child(struct json_node *obj, const char *key, bool mandatory, uint type)
41 struct json_node *n = json_object_get(obj, key);
45 die("Malformed reply: missing %s", key);
47 else if (n->type != type)
48 die("Malformed reply: %s has wrong type", key);
52 static void op_new(const char *op)
55 rq = json_new_object(js);
56 set_string(rq, "cmd", op);
59 static void op_debug(const char *msg, struct json_node *n)
64 struct fastbuf *out = bfdopen_shared(1, 4096);
65 bprintf(out, ">>> %s\n", msg);
66 js->format_options = JSON_FORMAT_INDENT;
67 json_write(js, out, n);
68 js->format_options = 0;
72 static void op_run(void)
74 int sk = socket(PF_UNIX, SOCK_SEQPACKET, 0);
76 die("socket(PF_UNIX, SOCK_SEQPACKET): %m");
78 struct sockaddr_un sun;
79 sun.sun_family = AF_UNIX;
80 if (strlen(socket_path) >= sizeof(sun.sun_path))
81 die("Socket path too long");
82 strcpy(sun.sun_path, socket_path);
84 if (connect(sk, (struct sockaddr *) &sun, sizeof(sun)) < 0)
85 die("Cannot connect to %s: %m", socket_path);
87 op_debug("Request", rq);
89 struct fastbuf *rq_fb = fbgrow_create(4096);
90 json_write(js, rq_fb, rq);
92 uint rq_len = fbgrow_get_buf(rq_fb, &rq_buf);
93 if (send(sk, rq_buf, rq_len, 0) < 0)
94 die("Cannot send request: %m");
97 byte rp_buf[4096]; // FIXME
98 int rp_len = recv(sk, rp_buf, sizeof(rp_buf), 0);
100 die("Cannot receive reply: %m");
102 struct fastbuf rp_fb;
103 fbbuf_init_read(&rp_fb, rp_buf, rp_len, 0);
104 rp = json_parse(js, &rp_fb);
105 op_debug("Reply", rp);
109 if (rp->type != JSON_OBJECT)
110 die("Malformed reply: Top-level node is not an object");
111 struct json_node *err = get_child(rp, "error", 1, JSON_STRING);
112 if (strcmp(err->string, ""))
114 fprintf(stderr, "Error: %s\n", err->string);
121 static void cmd_set_passwd(void)
125 static void cmd_list(void)
131 static void cmd_raw(void)
135 struct fastbuf *in = bfdopen_shared(0, 4096);
136 rq = json_parse(js, in);
149 void (* const command_handlers[CMD_MAX])(void) = {
150 [CMD_SET_PASSWD] = cmd_set_passwd,
151 [CMD_LIST] = cmd_list,
155 static int command = -1;
159 static const struct opt_section options = {
161 OPT_HELP("A client to the sub-authentication daemon."),
162 OPT_HELP("Usage: subauth [general options] <command> [options]"),
164 OPT_HELP("General options:"),
165 OPT_STRING('s', "socket", socket_path, OPT_REQUIRED_VALUE, "path\tPath to daemon control socket"),
166 OPT_BOOL(0, "debug", debug, 0, "\tDump raw communication with the daemon"),
169 OPT_HELP("Commands:"),
170 OPT_SWITCH(0, "passwd", command, CMD_SET_PASSWD, OPT_SINGLE, "\tSet password"),
171 OPT_SWITCH(0, "list", command, CMD_LIST, OPT_SINGLE, "\tList tokens for all zones"),
172 OPT_SWITCH(0, "raw", command, CMD_RAW, OPT_SINGLE, "\tSend raw JSON command to the daemon"),
174 OPT_HELP("Command options:"),
175 OPT_STRING('u', "user", arg_login, OPT_REQUIRED_VALUE, "login\tUser to act on (default: whoever calls it)"),
176 OPT_STRING('z', "zone", arg_zone, OPT_REQUIRED_VALUE, "zone\tAuthentication zone"),
177 OPT_STRING('i', "ident", arg_ident, OPT_REQUIRED_VALUE, "id\tToken ID"),
182 int main(int argc UNUSED, char **argv)
184 opt_parse(&options, argv+1);
187 opt_failure("No command given");
188 if (!command_handlers[command])
189 opt_failure("Command not implemented");
190 command_handlers[command]();