]> mj.ucw.cz Git - subauth.git/blob - server/cmd.c
More commands
[subauth.git] / server / cmd.c
1 /*
2  *      Sub-authentication Daemon: Commands
3  *
4  *      (c) 2017 Martin Mares <mj@ucw.cz>
5  */
6
7 #include <ucw/lib.h>
8 #include <ucw/trans.h>
9
10 #include <pwd.h>
11 #include <stdarg.h>
12 #include <stdio.h>
13
14 #include "subauthd.h"
15
16 static void NONRET cmd_error(struct client *c, const char *err, ...)
17 {
18   va_list args;
19   char msg[1024];
20   va_start(args, err);
21   vsnprintf(msg, sizeof(msg), err, args);
22   json_object_set(c->reply, "error", json_new_string(c->json, msg));
23   trans_throw("adhoc", NULL, "Error caught");
24   va_end(args);
25 }
26
27 static void cmd_ok(struct client *c)
28 {
29   json_object_set(c->reply, "error", json_new_string_ref(c->json, ""));
30 }
31
32 const char *get_string(struct json_node *n, const char *key)
33 {
34   struct json_node *s = json_object_get(n, key);
35   if (s && s->type == JSON_STRING)
36     return s->string;
37   else
38     return NULL;
39 }
40
41 bool get_uint(struct json_node *n, const char *key, uint *dest)
42 {
43   struct json_node *s = json_object_get(n, key);
44   if (s && s->type == JSON_NUMBER)
45     {
46       uint u = (uint) s->number;
47       if ((double) u == s->number)
48         {
49           *dest = u;
50           return 1;
51         }
52     }
53   *dest = 0;
54   return 0;
55 }
56
57 struct json_node **get_array(struct json_node *n, const char *key)
58 {
59   struct json_node *s = json_object_get(n, key);
60   if (s && s->type == JSON_ARRAY)
61     return s->elements;
62   else
63     return NULL;
64 }
65
66 struct json_node *get_object(struct json_node *n, const char *key)
67 {
68   struct json_node *s = json_object_get(n, key);
69   if (s && s->type == JSON_OBJECT)
70     return s;
71   else
72     return NULL;
73 }
74
75 static const char *cmd_need_string(struct client *c, const char *key)
76 {
77   const char *val = get_string(c->request, key);
78   if (!val)
79     cmd_error(c, "Missing %s", key);
80   return val;
81 }
82
83 static struct auth_zone *cmd_need_zone(struct client *c)
84 {
85   const char *name = cmd_need_string(c, "zone");
86   struct auth_zone *az = auth_find_zone(name);
87   if (!az)
88     cmd_error(c, "No such zone");
89   return az;
90 }
91
92 static bool cmd_is_admin(struct client *c)
93 {
94   // FIXME
95   (void) c;
96   return 1;
97 }
98
99 static void cmd_require_admin(struct client *c)
100 {
101   if (!cmd_is_admin(c))
102     cmd_error(c, "Permission denied");
103 }
104
105 static const char *cmd_need_target_login(struct client *c)
106 {
107   const char *l = get_string(c->request, "login");
108   if (l)
109     {
110       cmd_require_admin(c);
111       return l;
112     }
113   else
114     {
115       struct passwd *pw = getpwuid(c->uid);
116       if (!pw)
117         cmd_error(c, "You do not exist");
118       return json_strdup(c->json, pw->pw_name);
119     }
120 }
121
122 static struct auth_acct *cmd_need_target_acct(struct client *c)
123 {
124   const char *login = cmd_need_target_login(c);
125   struct auth_zone *az = cmd_need_zone(c);
126
127   struct auth_user *au = auth_find_user(login, 0);
128   struct auth_acct *aa = au ? auth_find_acct(au, az, 0) : NULL;
129   if (aa)
130     return aa;
131
132   if (!az->auto_create_acct)
133     cmd_error(c, "No such account");
134
135   if (!au)
136     {
137       msg(L_INFO, "Automatically creating user: login=<%s>", login);
138       au = auth_find_user(login, 1);
139     }
140   msg(L_INFO, "Automatically creating account: login=<%s> zone=<%s>", login, az->name);
141   return auth_find_acct(au, az, 1);
142 }
143
144 static void cmd_nop(struct client *c)
145 {
146   cmd_ok(c);
147 }
148
149 static void cmd_create_acct(struct client *c)
150 {
151   cmd_require_admin(c);
152
153   const char *login = get_string(c->request, "login");
154   if (!login)
155     cmd_error(c, "Login required");
156
157   struct auth_zone *az = cmd_need_zone(c);
158   struct auth_user *au = auth_find_user(login, 1);
159   if (!auth_find_acct(au, az, 0))
160     {
161       msg(L_INFO, "Creating account: login=<%s> zone=<%s>", login, az->name);
162       auth_find_acct(au, az, 1);
163       db_write();
164     }
165
166   cmd_ok(c);
167 }
168
169 static void cmd_delete_acct(struct client *c)
170 {
171   cmd_require_admin(c);
172
173   const char *login = get_string(c->request, "login");
174   if (!login)
175     cmd_error(c, "Login required");
176   const char *zone_name = get_string(c->request, "zone");
177
178   struct auth_user *au = auth_find_user(login, 0);
179   if (!au)
180     return cmd_ok(c);
181
182   if (zone_name && !strcmp(zone_name, "*"))
183     {
184       msg(L_INFO, "Deleting user: login=<%s>", login);
185       auth_delete_user(au);
186     }
187   else
188     {
189       struct auth_zone *az = cmd_need_zone(c);
190       struct auth_acct *aa = auth_find_acct(au, az, 0);
191       if (!aa)
192         return cmd_ok(c);
193       msg(L_INFO, "Deleting account: login=<%s> zone=<%s>", login, az->name);
194       auth_delete_acct(aa);
195       if (!clist_head(&au->accounts))
196         {
197           msg(L_INFO, "Deleting user with no accounts: login=<%s>", login);
198           auth_delete_user(au);
199         }
200     }
201
202   db_write();
203   cmd_ok(c);
204 }
205
206 static void cmd_set_passwd(struct client *c)
207 {
208   struct auth_acct *aa = cmd_need_target_acct(c);
209   const char *passwd = cmd_need_string(c, "passwd");
210
211   if (!aa->zone->allow_passwd)
212     cmd_error(c, "This zone does not allow authentication by password");
213
214   msg(L_INFO, "Set password: login=<%s> zone=<%s>", aa->user->login, aa->zone->name);
215
216   CLIST_FOR_EACH(struct auth_token *, at, aa->tokens)
217     if (at->type == TOKEN_PASSWORD)
218       {
219         auth_delete_token(at);
220         break;
221       }
222
223   struct auth_token *at = auth_create_token(aa);
224   auth_set_token_passwd(at, passwd);
225
226   // FIXME
227
228   db_write();
229   cmd_ok(c);
230 }
231
232 static void cmd_verify(struct client *c)
233 {
234   struct auth_acct *aa = cmd_need_target_acct(c);
235   const char *passwd = cmd_need_string(c, "passwd");
236
237   // FIXME
238
239   cmd_ok(c);
240 }
241
242 struct command {
243   const char *cmd;
244   void (*handler)(struct client *c);
245 };
246
247 static const struct command command_table[] = {
248   { "nop",              cmd_nop },
249   { "create-acct",      cmd_create_acct },
250   { "delete-acct",      cmd_delete_acct },
251   { "set-passwd",       cmd_set_passwd },
252   { "verify",           cmd_verify },
253 };
254
255 void cmd_dispatch(struct client *c)
256 {
257   struct json_node *rq = c->request;
258   const char *cmd;
259
260   if (rq->type != JSON_OBJECT || !(cmd = get_string(rq, "cmd")))
261     {
262       json_object_set(c->reply, "error", json_new_string_ref(c->json, "Malformed request"));
263       return;
264     }
265
266   const struct command *command = NULL;
267   for (uint i=0; i < ARRAY_SIZE(command_table); i++)
268     if (!strcmp(cmd, command_table[i].cmd))
269       {
270         command = &command_table[i];
271         break;
272       }
273   if (!command)
274     {
275       json_object_set(c->reply, "error", json_new_string_ref(c->json, "No such command"));
276       return;
277     }
278
279   TRANS_TRY
280     {
281       if (command)
282         command->handler(c);
283     }
284   TRANS_CATCH(x)
285     {
286     }
287   TRANS_END;
288 }