afs-supervisor: Enforce session check (for token)
[src/app-framework-binder.git] / src / afs-supervisor.c
1 /*
2  * Copyright (C) 2016, 2017 "IoT.bzh"
3  * Author José Bollo <jose.bollo@iot.bzh>
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #define _GNU_SOURCE
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <signal.h>
24 #include <unistd.h>
25 #include <pthread.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <sys/un.h>
29
30 #include <json-c/json.h>
31 #include <afb/afb-binding-v2.h>
32
33 #include "afb-cred.h"
34 #include "afb-stub-ws.h"
35 #include "afb-api.h"
36 #include "afb-xreq.h"
37 #include "afb-api-so-v2.h"
38 #include "afb-apiset.h"
39 #include "afb-fdev.h"
40
41 #include "fdev.h"
42 #include "verbose.h"
43 #include "wrap-json.h"
44
45 #include "afs-supervision.h"
46 #include "afs-supervisor.h"
47 #include "afs-discover.h"
48
49 /* supervised items */
50 struct supervised
51 {
52         /* link to the next supervised */
53         struct supervised *next;
54
55         /* credentials of the supervised */
56         struct afb_cred *cred;
57
58         /* connection with the supervised */
59         struct afb_stub_ws *stub;
60 };
61
62 /* api and apiset name */
63 static const char supervision_apiname[] = AFS_SURPERVISION_APINAME;
64 static const char supervisor_apiname[] = AFS_SURPERVISOR_APINAME;
65
66 /* the empty apiset */
67 static struct afb_apiset *empty_apiset;
68
69 /* supervision socket path */
70 static const char supervision_socket_path[] = AFS_SURPERVISION_SOCKET;
71 static struct fdev *supervision_fdev;
72
73 /* global mutex */
74 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
75
76 /* list of supervised daemons */
77 static struct supervised *superviseds;
78
79 /*************************************************************************************/
80
81
82 /*************************************************************************************/
83
84 /**
85  * Creates the supervisor socket for 'path' and return it
86  * return -1 in case of failure
87  */
88 static int create_supervision_socket(const char *path)
89 {
90         int fd, rc;
91         struct sockaddr_un addr;
92         size_t length;
93
94         /* check the path's length */
95         length = strlen(path);
96         if (length >= 108) {
97                 ERROR("Path name of supervision socket too long: %d", (int)length);
98                 errno = ENAMETOOLONG;
99                 return -1;
100         }
101
102         /* create a socket */
103         fd = socket(AF_UNIX, SOCK_STREAM, 0);
104         if (fd < 0) {
105                 ERROR("Can't create socket: %m");
106                 return fd;
107         }
108
109         /* setup the bind to a path */
110         memset(&addr, 0, sizeof addr);
111         addr.sun_family = AF_UNIX;
112         strcpy(addr.sun_path, path);
113         if (addr.sun_path[0] == '@')
114                 addr.sun_path[0] = 0; /* abstract sockets */
115         else
116                 unlink(path);
117
118         /* binds the socket to the path */
119         rc = bind(fd, (struct sockaddr *) &addr, (socklen_t)(sizeof addr));
120         if (rc < 0) {
121                 ERROR("can't bind socket to %s", path);
122                 close(fd);
123                 return rc;
124         }
125         return fd;
126 }
127
128 /**
129  * send on 'fd' an initiator with 'command'
130  * return 0 on success or -1 on failure
131  */
132 static int send_initiator(int fd, const char *command)
133 {
134         int rc;
135         ssize_t swr;
136         struct afs_supervision_initiator asi;
137
138         /* set  */
139         memset(&asi, 0, sizeof asi);
140         strcpy(asi.interface, AFS_SURPERVISION_INTERFACE_1);
141         if (command)
142                 strncpy(asi.extra, command, sizeof asi.extra - 1);
143
144         /* send the initiator */
145         swr = write(fd, &asi, sizeof asi);
146         if (swr < 0) {
147                 ERROR("Can't send initiator: %m");
148                 rc = -1;
149         } else if (swr < sizeof asi) {
150                 ERROR("Sending incomplete initiator: %m");
151                 rc = -1;
152         } else
153                 rc = 0;
154         return rc;
155 }
156
157 /*
158  * checks whether the incomming supervised represented by its creds
159  * is to be accepted or not.
160  * return 1 if yes or 0 otherwise.
161  */
162 static int should_accept(struct afb_cred *cred)
163 {
164         return cred && cred->pid != getpid(); /* not me! */
165 }
166
167 static void on_supervised_hangup(struct afb_stub_ws *stub)
168 {
169         struct supervised *s, **ps;
170         pthread_mutex_lock(&mutex);
171         ps = &superviseds;
172         while ((s = *ps) && s->stub != stub)
173                 ps = &s->next;
174         if (s) {
175                 *ps = s->next;
176                 afb_stub_ws_unref(stub);
177         }
178         pthread_mutex_unlock(&mutex);
179 }
180
181 /*
182  * create a supervised for socket 'fd' and 'cred'
183  * return 0 in case of success or -1 in case of error
184  */
185 static int make_supervised(int fd, struct afb_cred *cred)
186 {
187         struct supervised *s;
188         struct fdev *fdev;
189
190         s = malloc(sizeof *s);
191         if (!s)
192                 return -1;
193
194         fdev = afb_fdev_create(fd);
195         if (!fdev) {
196                 free(s);
197                 return -1;
198         }
199
200         s->cred = cred;
201         s->stub = afb_stub_ws_create_client(fdev, supervision_apiname, empty_apiset);
202         if (!s->stub) {
203                 free(s);
204                 return -1;
205         }
206         pthread_mutex_lock(&mutex);
207         s->next = superviseds;
208         superviseds = s;
209         pthread_mutex_unlock(&mutex);
210         afb_stub_ws_on_hangup(s->stub, on_supervised_hangup);
211         return 0;
212 }
213
214 /**
215  * Search the supervised of 'pid', return it or NULL.
216  */
217 static struct supervised *supervised_of_pid(pid_t pid)
218 {
219         struct supervised *s;
220
221         pthread_mutex_lock(&mutex);
222         s = superviseds;
223         while (s && pid != s->cred->pid)
224                 s = s->next;
225         pthread_mutex_unlock(&mutex);
226
227         return s;
228 }
229
230 /*
231  * handles incoming connection on 'sock'
232  */
233 static void accept_supervision_link(int sock)
234 {
235         int rc, fd;
236         struct sockaddr addr;
237         socklen_t lenaddr;
238         struct afb_cred *cred;
239
240         lenaddr = (socklen_t)sizeof addr;
241         fd = accept(sock, &addr, &lenaddr);
242         if (fd >= 0) {
243                 cred = afb_cred_create_for_socket(fd);
244                 rc = should_accept(cred);
245                 if (rc) {
246                         rc = send_initiator(fd, NULL);
247                         if (!rc) {
248                                 rc = make_supervised(fd, cred);
249                                 if (!rc)
250                                         return;
251                         }
252                 }
253                 afb_cred_unref(cred);
254                 close(fd);
255         }
256 }
257
258 /*
259  * handle even on server socket
260  */
261 static void listening(void *closure, uint32_t revents, struct fdev *fdev)
262 {
263         if ((revents & EPOLLIN) != 0)
264                 accept_supervision_link((int)(intptr_t)closure);
265         if ((revents & EPOLLHUP) != 0) {
266                 ERROR("supervision socket closed");
267                 exit(1);
268         }
269 }
270
271 /*
272  */
273 static void discovered_cb(void *closure, pid_t pid)
274 {
275         struct supervised *s;
276
277         s = supervised_of_pid(pid);
278         if (!s) {
279                 (*(int*)closure)++;
280                 kill(pid, SIGHUP);
281         }
282 }
283
284 int afs_supervisor_discover()
285 {
286         int n = 0;
287         afs_discover("afb-daemon", discovered_cb, &n);
288         return n;
289 }
290
291 /*************************************************************************************/
292
293 static struct afb_binding_data_v2 datav2;
294
295 static void f_list(struct afb_req req)
296 {
297         char pid[50];
298         struct json_object *resu, *item;
299         struct supervised *s;
300
301         resu = json_object_new_object();
302         s = superviseds;
303         while (s) {
304                 sprintf(pid, "%d", (int)s->cred->pid);
305                 item = NULL;
306                 wrap_json_pack(&item, "{si si si ss ss ss}",
307                                 "pid", (int)s->cred->pid,
308                                 "uid", (int)s->cred->uid,
309                                 "gid", (int)s->cred->gid,
310                                 "id", s->cred->id,
311                                 "label", s->cred->label,
312                                 "user", s->cred->user
313                                 );
314                 json_object_object_add(resu, pid, item);
315                 s = s->next;
316         }
317         afb_req_success(req, resu, NULL);
318 }
319
320 static void f_discover(struct afb_req req)
321 {
322         afs_supervisor_discover();
323         afb_req_success(req, NULL, NULL);
324 }
325
326 static void propagate(struct afb_req req, const char *verb)
327 {
328         struct afb_xreq *xreq;
329         struct json_object *args, *item;
330         struct supervised *s;
331         struct afb_api api;
332         int p;
333
334         xreq = xreq_from_request(req.closure);
335         args = afb_xreq_json(xreq);
336         if (!json_object_object_get_ex(args, "pid", &item)) {
337                 afb_xreq_fail(xreq, "no-pid", NULL);
338                 return;
339         }
340         errno = 0;
341         p = json_object_get_int(item);
342         if (!p && errno) {
343                 afb_xreq_fail(xreq, "bad-pid", NULL);
344                 return;
345         }
346         s = supervised_of_pid((pid_t)p);
347         if (!s) {
348                 afb_req_fail(req, "unknown-pid", NULL);
349                 return;
350         }
351         json_object_object_del(args, "pid");
352         if (verb)
353                 xreq->request.verb = verb;
354         api = afb_stub_ws_client_api(s->stub);
355         api.itf->call(api.closure, xreq);
356 }
357
358 static void f_do(struct afb_req req)
359 {
360         propagate(req, NULL);
361 }
362
363 static void f_config(struct afb_req req)
364 {
365         propagate(req, NULL);
366 }
367
368 static void f_trace(struct afb_req req)
369 {
370         propagate(req, NULL);
371 }
372
373 static void f_sessions(struct afb_req req)
374 {
375         propagate(req, "slist");
376 }
377
378 static void f_session_close(struct afb_req req)
379 {
380         propagate(req, "sclose");
381 }
382
383 static void f_exit(struct afb_req req)
384 {
385         propagate(req, NULL);
386         afb_req_success(req, NULL, NULL);
387 }
388
389 static void f_debug_wait(struct afb_req req)
390 {
391         propagate(req, "wait");
392         afb_req_success(req, NULL, NULL);
393 }
394
395 static void f_debug_break(struct afb_req req)
396 {
397         propagate(req, "break");
398         afb_req_success(req, NULL, NULL);
399 }
400
401 /*************************************************************************************/
402
403 /**
404  * initalize the supervisor
405  */
406 static int init_supervisor()
407 {
408         int rc, fd;
409
410         /* create an empty set for superviseds */
411         empty_apiset = afb_apiset_create(supervision_apiname, 0);
412         if (!empty_apiset) {
413                 ERROR("Can't create supervision apiset");
414                 return -1;
415         }
416
417         /* create the supervision socket */
418         fd = create_supervision_socket(supervision_socket_path);
419         if (fd < 0)
420                 return fd;
421
422         /* listen the socket */
423         rc = listen(fd, 5);
424         if (rc < 0) {
425                 ERROR("refused to listen on socket");
426                 return rc;
427         }
428
429         /* integrate the socket to the loop */
430         supervision_fdev = afb_fdev_create(fd);
431         if (rc < 0) {
432                 ERROR("handling socket event isn't possible");
433                 return rc;
434         }
435         fdev_set_events(supervision_fdev, EPOLLIN);
436         fdev_set_callback(supervision_fdev, listening, (void*)(intptr_t)fd);
437
438         return 0;
439 }
440
441 /*************************************************************************************/
442
443 static const struct afb_auth _afb_auths_v2_supervisor[] = {
444         /* 0 */
445         {
446                 .type = afb_auth_Permission,
447                 .text = "urn:AGL:permission:#supervision:platform:access"
448         }
449 };
450
451 static const struct afb_verb_v2 _afb_verbs_v2_supervisor[] = {
452     {
453         .verb = "list",
454         .callback = f_list,
455         .auth = &_afb_auths_v2_supervisor[0],
456         .info = NULL,
457         .session = AFB_SESSION_CHECK_V2
458     },
459     {
460         .verb = "config",
461         .callback = f_config,
462         .auth = &_afb_auths_v2_supervisor[0],
463         .info = NULL,
464         .session = AFB_SESSION_CHECK_V2
465     },
466     {
467         .verb = "do",
468         .callback = f_do,
469         .auth = &_afb_auths_v2_supervisor[0],
470         .info = NULL,
471         .session = AFB_SESSION_CHECK_V2
472     },
473     {
474         .verb = "trace",
475         .callback = f_trace,
476         .auth = &_afb_auths_v2_supervisor[0],
477         .info = NULL,
478         .session = AFB_SESSION_CHECK_V2
479     },
480     {
481         .verb = "sessions",
482         .callback = f_sessions,
483         .auth = &_afb_auths_v2_supervisor[0],
484         .info = NULL,
485         .session = AFB_SESSION_CHECK_V2
486     },
487     {
488         .verb = "session-close",
489         .callback = f_session_close,
490         .auth = &_afb_auths_v2_supervisor[0],
491         .info = NULL,
492         .session = AFB_SESSION_CHECK_V2
493     },
494     {
495         .verb = "exit",
496         .callback = f_exit,
497         .auth = &_afb_auths_v2_supervisor[0],
498         .info = NULL,
499         .session = AFB_SESSION_CHECK_V2
500     },
501     {
502         .verb = "debug-wait",
503         .callback = f_debug_wait,
504         .auth = &_afb_auths_v2_supervisor[0],
505         .info = NULL,
506         .session = AFB_SESSION_CHECK_V2
507     },
508     {
509         .verb = "debug-break",
510         .callback = f_debug_break,
511         .auth = &_afb_auths_v2_supervisor[0],
512         .info = NULL,
513         .session = AFB_SESSION_CHECK_V2
514     },
515     {
516         .verb = "discover",
517         .callback = f_discover,
518         .auth = &_afb_auths_v2_supervisor[0],
519         .info = NULL,
520         .session = AFB_SESSION_CHECK_V2
521     },
522     { .verb = NULL }
523 };
524
525 static const struct afb_binding_v2 _afb_binding_v2_supervisor = {
526     .api = supervisor_apiname,
527     .specification = NULL,
528     .info = NULL,
529     .verbs = _afb_verbs_v2_supervisor,
530     .preinit = NULL,
531     .init = init_supervisor,
532     .onevent = NULL,
533     .noconcurrency = 0
534 };
535
536 int afs_supervisor_add(struct afb_apiset *apiset)
537 {
538         return afb_api_so_v2_add_binding(&_afb_binding_v2_supervisor, NULL, apiset, &datav2);
539 }
540