Improves compatibility with AddressSanitizers
[src/app-framework-binder.git] / src / afs-supervisor.c
1 /*
2  * Copyright (C) 2015-2020 "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
32 #define AFB_BINDING_VERSION 3
33 #define AFB_BINDING_NO_ROOT
34 #include <afb/afb-binding.h>
35
36 #include "afb-cred.h"
37 #include "afb-stub-ws.h"
38 #include "afb-api.h"
39 #include "afb-xreq.h"
40 #include "afb-api-v3.h"
41 #include "afb-apiset.h"
42 #include "afb-fdev.h"
43 #include "afb-socket.h"
44
45 #include "fdev.h"
46 #include "verbose.h"
47 #include "wrap-json.h"
48
49 #include "afs-supervision.h"
50 #include "afs-supervisor.h"
51 #include "afs-discover.h"
52
53 /* supervised items */
54 struct supervised
55 {
56         /* link to the next supervised */
57         struct supervised *next;
58
59         /* credentials of the supervised */
60         struct afb_cred *cred;
61
62         /* connection with the supervised */
63         struct afb_stub_ws *stub;
64 };
65
66 /* api and apiset name */
67 static const char supervision_apiname[] = AFS_SUPERVISION_APINAME;
68 static const char supervisor_apiname[] = AFS_SUPERVISOR_APINAME;
69
70 /* the empty apiset */
71 static struct afb_apiset *empty_apiset;
72
73 /* supervision socket path */
74 static const char supervision_socket_path[] = AFS_SUPERVISION_SOCKET;
75 static struct fdev *supervision_fdev;
76
77 /* global mutex */
78 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
79
80 /* list of supervised daemons */
81 static struct supervised *superviseds;
82
83 /* events */
84 static afb_event_t event_add_pid;
85 static afb_event_t event_del_pid;
86
87 /*************************************************************************************/
88
89
90 /*************************************************************************************/
91
92 /**
93  * send on 'fd' an initiator with 'command'
94  * return 0 on success or -1 on failure
95  */
96 static int send_initiator(int fd, const char *command)
97 {
98         int rc;
99         ssize_t swr;
100         struct afs_supervision_initiator asi;
101
102         /* set  */
103         memset(&asi, 0, sizeof asi);
104         strcpy(asi.interface, AFS_SUPERVISION_INTERFACE_1);
105         if (command)
106                 strncpy(asi.extra, command, sizeof asi.extra - 1);
107
108         /* send the initiator */
109         swr = write(fd, &asi, sizeof asi);
110         if (swr < 0) {
111                 ERROR("Can't send initiator: %m");
112                 rc = -1;
113         } else if (swr < sizeof asi) {
114                 ERROR("Sending incomplete initiator: %m");
115                 rc = -1;
116         } else
117                 rc = 0;
118         return rc;
119 }
120
121 /*
122  * checks whether the incoming supervised represented by its creds
123  * is to be accepted or not.
124  * return 1 if yes or 0 otherwise.
125  */
126 static int should_accept(struct afb_cred *cred)
127 {
128         return cred && cred->pid != getpid(); /* not me! */
129 }
130
131 static void on_supervised_hangup(struct afb_stub_ws *stub)
132 {
133         struct supervised *s, **ps;
134
135         /* Search the supervised of the ws-stub */
136         pthread_mutex_lock(&mutex);
137         ps = &superviseds;
138         while ((s = *ps) && s->stub != stub)
139                 ps = &s->next;
140
141         /* unlink the supervised if found */
142         if (s)
143                 *ps = s->next;
144         pthread_mutex_unlock(&mutex);
145
146         /* forgive the ws-stub */
147         afb_stub_ws_unref(stub);
148
149         /* forgive the supervised */
150         if (s) {
151                 afb_event_push(event_del_pid, json_object_new_int((int)s->cred->pid));
152                 afb_cred_unref(s->cred);
153                 free(s);
154         }
155 }
156
157 /*
158  * create a supervised for socket 'fd' and 'cred'
159  * return 0 in case of success or -1 in case of error
160  */
161 static int make_supervised(int fd, struct afb_cred *cred)
162 {
163         struct supervised *s;
164         struct fdev *fdev;
165
166         s = malloc(sizeof *s);
167         if (!s)
168                 return -1;
169
170         fdev = afb_fdev_create(fd);
171         if (!fdev) {
172                 free(s);
173                 return -1;
174         }
175
176         s->cred = cred;
177         s->stub = afb_stub_ws_create_client(fdev, supervision_apiname, empty_apiset);
178         if (!s->stub) {
179                 free(s);
180                 return -1;
181         }
182         pthread_mutex_lock(&mutex);
183         s->next = superviseds;
184         superviseds = s;
185         pthread_mutex_unlock(&mutex);
186         afb_stub_ws_set_on_hangup(s->stub, on_supervised_hangup);
187         return 0;
188 }
189
190 /**
191  * Search the supervised of 'pid', return it or NULL.
192  */
193 static struct supervised *supervised_of_pid(pid_t pid)
194 {
195         struct supervised *s;
196
197         pthread_mutex_lock(&mutex);
198         s = superviseds;
199         while (s && pid != s->cred->pid)
200                 s = s->next;
201         pthread_mutex_unlock(&mutex);
202
203         return s;
204 }
205
206 /*
207  * handles incoming connection on 'sock'
208  */
209 static void accept_supervision_link(int sock)
210 {
211         int rc, fd;
212         struct sockaddr addr;
213         socklen_t lenaddr;
214         struct afb_cred *cred;
215
216         lenaddr = (socklen_t)sizeof addr;
217         fd = accept(sock, &addr, &lenaddr);
218         if (fd >= 0) {
219                 cred = afb_cred_create_for_socket(fd);
220                 rc = should_accept(cred);
221                 if (rc) {
222                         rc = send_initiator(fd, NULL);
223                         if (!rc) {
224                                 rc = make_supervised(fd, cred);
225                                 if (!rc) {
226                                         afb_event_push(event_add_pid, json_object_new_int((int)cred->pid));
227                                         return;
228                                 }
229                         }
230                 }
231                 afb_cred_unref(cred);
232                 close(fd);
233         }
234 }
235
236 /*
237  * handle even on server socket
238  */
239 static void listening(void *closure, uint32_t revents, struct fdev *fdev)
240 {
241         if ((revents & EPOLLHUP) != 0) {
242                 ERROR("supervision socket closed");
243                 exit(1);
244         }
245         if ((revents & EPOLLIN) != 0)
246                 accept_supervision_link((int)(intptr_t)closure);
247 }
248
249 /*
250  */
251 static void discovered_cb(void *closure, pid_t pid)
252 {
253         struct supervised *s;
254
255         s = supervised_of_pid(pid);
256         if (!s) {
257                 (*(int*)closure)++;
258                 kill(pid, SIGHUP);
259         }
260 }
261
262 int afs_supervisor_discover()
263 {
264         int n = 0;
265         afs_discover("afb-daemon", discovered_cb, &n);
266         return n;
267 }
268
269 /*************************************************************************************/
270
271 static void f_subscribe(afb_req_t req)
272 {
273         struct json_object *args = afb_req_json(req);
274         int revoke, ok;
275
276         revoke = json_object_is_type(args, json_type_boolean)
277                 && !json_object_get_boolean(args);
278
279         ok = 1;
280         if (!revoke) {
281                 ok = !afb_req_subscribe(req, event_add_pid)
282                         && !afb_req_subscribe(req, event_del_pid);
283         }
284         if (revoke || !ok) {
285                 afb_req_unsubscribe(req, event_add_pid);
286                 afb_req_unsubscribe(req, event_del_pid);
287         }
288         afb_req_reply(req, NULL, ok ? NULL : "error", NULL);
289 }
290
291 static void f_list(afb_req_t req)
292 {
293         char pid[50];
294         struct json_object *resu, *item;
295         struct supervised *s;
296
297         resu = json_object_new_object();
298         s = superviseds;
299         while (s) {
300                 sprintf(pid, "%d", (int)s->cred->pid);
301                 item = NULL;
302                 wrap_json_pack(&item, "{si si si ss ss ss}",
303                                 "pid", (int)s->cred->pid,
304                                 "uid", (int)s->cred->uid,
305                                 "gid", (int)s->cred->gid,
306                                 "id", s->cred->id,
307                                 "label", s->cred->label,
308                                 "user", s->cred->user
309                                 );
310                 json_object_object_add(resu, pid, item);
311                 s = s->next;
312         }
313         afb_req_success(req, resu, NULL);
314 }
315
316 static void f_discover(afb_req_t req)
317 {
318         afs_supervisor_discover();
319         afb_req_success(req, NULL, NULL);
320 }
321
322 static void propagate(afb_req_t req, const char *verb)
323 {
324         struct afb_xreq *xreq;
325         struct json_object *args, *item;
326         struct supervised *s;
327         struct afb_api_item api;
328         int p;
329
330         xreq = xreq_from_req_x2(req);
331         args = afb_xreq_json(xreq);
332
333         /* extract the pid */
334         if (!json_object_object_get_ex(args, "pid", &item)) {
335                 afb_xreq_reply(xreq, NULL, "no-pid", NULL);
336                 return;
337         }
338         errno = 0;
339         p = json_object_get_int(item);
340         if (!p && errno) {
341                 afb_xreq_reply(xreq, NULL, "bad-pid", NULL);
342                 return;
343         }
344
345         /* get supervised of pid */
346         s = supervised_of_pid((pid_t)p);
347         if (!s) {
348                 afb_req_reply(req, NULL, "unknown-pid", NULL);
349                 return;
350         }
351         json_object_object_del(args, "pid");
352
353         /* replace the verb to call if needed */
354         if (verb)
355                 xreq->request.called_verb = verb;
356
357         /* call it now */
358         api = afb_stub_ws_client_api(s->stub);
359         api.itf->call(api.closure, xreq);
360 }
361
362 static void f_do(afb_req_t req)
363 {
364         propagate(req, NULL);
365 }
366
367 static void f_config(afb_req_t req)
368 {
369         propagate(req, NULL);
370 }
371
372 static void f_trace(afb_req_t req)
373 {
374         propagate(req, NULL);
375 }
376
377 static void f_sessions(afb_req_t req)
378 {
379         propagate(req, "slist");
380 }
381
382 static void f_session_close(afb_req_t req)
383 {
384         propagate(req, "sclose");
385 }
386
387 static void f_exit(afb_req_t req)
388 {
389         propagate(req, NULL);
390         afb_req_success(req, NULL, NULL);
391 }
392
393 static void f_debug_wait(afb_req_t req)
394 {
395         propagate(req, "wait");
396         afb_req_success(req, NULL, NULL);
397 }
398
399 static void f_debug_break(afb_req_t req)
400 {
401         propagate(req, "break");
402         afb_req_success(req, NULL, NULL);
403 }
404
405 /*************************************************************************************/
406
407 /**
408  * initialize the supervisor
409  */
410 static int init_supervisor(afb_api_t api)
411 {
412         event_add_pid = afb_api_make_event(api, "add-pid");
413         if (!afb_event_is_valid(event_add_pid)) {
414                 ERROR("Can't create added event");
415                 return -1;
416         }
417
418         event_del_pid = afb_api_make_event(api, "del-pid");
419         if (!afb_event_is_valid(event_del_pid)) {
420                 ERROR("Can't create deleted event");
421                 return -1;
422         }
423
424         /* create an empty set for superviseds */
425         empty_apiset = afb_apiset_create(supervision_apiname, 0);
426         if (!empty_apiset) {
427                 ERROR("Can't create supervision apiset");
428                 return -1;
429         }
430
431         /* create the supervision socket */
432         supervision_fdev = afb_socket_open_fdev(supervision_socket_path, 1);
433         if (!supervision_fdev)
434                 return -1;
435
436         fdev_set_events(supervision_fdev, EPOLLIN);
437         fdev_set_callback(supervision_fdev, listening,
438                           (void*)(intptr_t)fdev_fd(supervision_fdev));
439
440         return 0;
441 }
442
443 /*************************************************************************************/
444
445 static const struct afb_auth _afb_auths_v2_supervisor[] = {
446         /* 0 */
447         {
448                 .type = afb_auth_Permission,
449                 .text = "urn:AGL:permission:#supervision:platform:access"
450         }
451 };
452
453 static const struct afb_verb_v3 _afb_verbs_supervisor[] = {
454     {
455         .verb = "subscribe",
456         .callback = f_subscribe,
457         .auth = &_afb_auths_v2_supervisor[0],
458         .info = NULL,
459         .session = AFB_SESSION_CHECK_X2
460     },
461     {
462         .verb = "list",
463         .callback = f_list,
464         .auth = &_afb_auths_v2_supervisor[0],
465         .info = NULL,
466         .session = AFB_SESSION_CHECK_X2
467     },
468     {
469         .verb = "config",
470         .callback = f_config,
471         .auth = &_afb_auths_v2_supervisor[0],
472         .info = NULL,
473         .session = AFB_SESSION_CHECK_X2
474     },
475     {
476         .verb = "do",
477         .callback = f_do,
478         .auth = &_afb_auths_v2_supervisor[0],
479         .info = NULL,
480         .session = AFB_SESSION_CHECK_X2
481     },
482     {
483         .verb = "trace",
484         .callback = f_trace,
485         .auth = &_afb_auths_v2_supervisor[0],
486         .info = NULL,
487         .session = AFB_SESSION_CHECK_X2
488     },
489     {
490         .verb = "sessions",
491         .callback = f_sessions,
492         .auth = &_afb_auths_v2_supervisor[0],
493         .info = NULL,
494         .session = AFB_SESSION_CHECK_X2
495     },
496     {
497         .verb = "session-close",
498         .callback = f_session_close,
499         .auth = &_afb_auths_v2_supervisor[0],
500         .info = NULL,
501         .session = AFB_SESSION_CHECK_X2
502     },
503     {
504         .verb = "exit",
505         .callback = f_exit,
506         .auth = &_afb_auths_v2_supervisor[0],
507         .info = NULL,
508         .session = AFB_SESSION_CHECK_X2
509     },
510     {
511         .verb = "debug-wait",
512         .callback = f_debug_wait,
513         .auth = &_afb_auths_v2_supervisor[0],
514         .info = NULL,
515         .session = AFB_SESSION_CHECK_X2
516     },
517     {
518         .verb = "debug-break",
519         .callback = f_debug_break,
520         .auth = &_afb_auths_v2_supervisor[0],
521         .info = NULL,
522         .session = AFB_SESSION_CHECK_X2
523     },
524     {
525         .verb = "discover",
526         .callback = f_discover,
527         .auth = &_afb_auths_v2_supervisor[0],
528         .info = NULL,
529         .session = AFB_SESSION_CHECK_X2
530     },
531     { .verb = NULL }
532 };
533
534 static const struct afb_binding_v3 _afb_binding_supervisor = {
535     .api = supervisor_apiname,
536     .specification = NULL,
537     .info = NULL,
538     .verbs = _afb_verbs_supervisor,
539     .preinit = NULL,
540     .init = init_supervisor,
541     .onevent = NULL,
542     .noconcurrency = 0
543 };
544
545 int afs_supervisor_add(
546                 struct afb_apiset *declare_set,
547                 struct afb_apiset * call_set)
548 {
549         return -!afb_api_v3_from_binding(&_afb_binding_supervisor, declare_set, call_set);
550 }
551