discover/discover-server: Restrict clients based on uid
[petitboot] / discover / discover-server.c
1 #define _GNU_SOURCE
2
3 #include <unistd.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <stdint.h>
7 #include <errno.h>
8 #include <assert.h>
9 #include <string.h>
10
11 #include <sys/socket.h>
12 #include <sys/un.h>
13 #include <asm/byteorder.h>
14 #include <grp.h>
15 #include <sys/stat.h>
16
17 #include <pb-config/pb-config.h>
18 #include <talloc/talloc.h>
19 #include <waiter/waiter.h>
20 #include <log/log.h>
21 #include <crypt/crypt.h>
22 #include <i18n/i18n.h>
23
24 #include "pb-protocol/pb-protocol.h"
25 #include "list/list.h"
26
27 #include "device-handler.h"
28 #include "discover-server.h"
29 #include "platform.h"
30 #include "sysinfo.h"
31
32 struct discover_server {
33         int socket;
34         struct waitset *waitset;
35         struct waiter *waiter;
36         struct list clients;
37         struct list status;
38         struct device_handler *device_handler;
39         bool restrict_clients;
40 };
41
42 struct client {
43         struct discover_server *server;
44         struct list_item list;
45         struct waiter *waiter;
46         int fd;
47         bool remote_closed;
48         bool can_modify;
49         struct waiter *auth_waiter;
50 };
51
52
53 static int server_destructor(void *arg)
54 {
55         struct discover_server *server = arg;
56
57         if (server->waiter)
58                 waiter_remove(server->waiter);
59
60         if (server->socket >= 0)
61                 close(server->socket);
62
63         return 0;
64 }
65
66 static int client_destructor(void *arg)
67 {
68         struct client *client = arg;
69
70         if (client->fd >= 0)
71                 close(client->fd);
72
73         if (client->waiter)
74                 waiter_remove(client->waiter);
75
76         if (client->auth_waiter)
77                 waiter_remove(client->auth_waiter);
78
79         list_remove(&client->list);
80
81         return 0;
82
83 }
84
85 static void print_clients(struct discover_server *server)
86         __attribute__((unused));
87
88 static void print_clients(struct discover_server *server)
89 {
90         struct client *client;
91
92         pb_debug("current clients [%p,%p,%p]:\n",
93                         &server->clients.head,
94                         server->clients.head.prev,
95                         server->clients.head.next);
96         list_for_each_entry(&server->clients, client, list)
97                 pb_debug("\t[%p,%p,%p] client: %d\n", &client->list,
98                                 client->list.prev, client->list.next,
99                                 client->fd);
100 }
101
102 static int client_write_message(
103                 struct discover_server *server __attribute__((unused)),
104                 struct client *client, struct pb_protocol_message *message)
105 {
106         int rc;
107
108         if (client->remote_closed)
109                 return -1;
110
111         rc = pb_protocol_write_message(client->fd, message);
112         if (rc)
113                 client->remote_closed = true;
114
115         return rc;
116 }
117
118 static int write_device_add_message(struct discover_server *server,
119                 struct client *client, const struct device *dev)
120 {
121         struct pb_protocol_message *message;
122         int len;
123
124         len = pb_protocol_device_len(dev);
125
126         message = pb_protocol_create_message(client,
127                         PB_PROTOCOL_ACTION_DEVICE_ADD, len);
128         if (!message)
129                 return -1;
130
131         pb_protocol_serialise_device(dev, message->payload, len);
132
133         return client_write_message(server, client, message);
134 }
135
136 static int write_boot_option_add_message(struct discover_server *server,
137                 struct client *client, const struct boot_option *opt)
138 {
139         struct pb_protocol_message *message;
140         int len;
141
142         len = pb_protocol_boot_option_len(opt);
143
144         message = pb_protocol_create_message(client,
145                         PB_PROTOCOL_ACTION_BOOT_OPTION_ADD, len);
146         if (!message)
147                 return -1;
148
149         pb_protocol_serialise_boot_option(opt, message->payload, len);
150
151         return client_write_message(server, client, message);
152 }
153
154 static int write_plugin_option_add_message(struct discover_server *server,
155                 struct client *client, const struct plugin_option *opt)
156 {
157         struct pb_protocol_message *message;
158         int len;
159
160         len = pb_protocol_plugin_option_len(opt);
161
162         message = pb_protocol_create_message(client,
163                         PB_PROTOCOL_ACTION_PLUGIN_OPTION_ADD, len);
164         if (!message)
165                 return -1;
166
167         pb_protocol_serialise_plugin_option(opt, message->payload, len);
168
169         return client_write_message(server, client, message);
170 }
171
172 static int write_plugins_remove_message(struct discover_server *server,
173                 struct client *client)
174 {
175         struct pb_protocol_message *message;
176
177         message = pb_protocol_create_message(client,
178                         PB_PROTOCOL_ACTION_PLUGINS_REMOVE, 0);
179         if (!message)
180                 return -1;
181
182         /* No payload so nothing to serialise */
183
184         return client_write_message(server, client, message);
185 }
186
187 static int write_device_remove_message(struct discover_server *server,
188                 struct client *client, char *dev_id)
189 {
190         struct pb_protocol_message *message;
191         int len;
192
193         len = strlen(dev_id) + sizeof(uint32_t);
194
195         message = pb_protocol_create_message(client,
196                         PB_PROTOCOL_ACTION_DEVICE_REMOVE, len);
197         if (!message)
198                 return -1;
199
200         pb_protocol_serialise_string(message->payload, dev_id);
201
202         return client_write_message(server, client, message);
203 }
204
205 static int write_boot_status_message(struct discover_server *server,
206                 struct client *client, const struct status *status)
207 {
208         struct pb_protocol_message *message;
209         int len;
210
211         len = pb_protocol_boot_status_len(status);
212
213         message = pb_protocol_create_message(client,
214                         PB_PROTOCOL_ACTION_STATUS, len);
215         if (!message)
216                 return -1;
217
218         pb_protocol_serialise_boot_status(status, message->payload, len);
219
220         return client_write_message(server, client, message);
221 }
222
223 static int write_system_info_message(struct discover_server *server,
224                 struct client *client, const struct system_info *sysinfo)
225 {
226         struct pb_protocol_message *message;
227         int len;
228
229         len = pb_protocol_system_info_len(sysinfo);
230
231         message = pb_protocol_create_message(client,
232                         PB_PROTOCOL_ACTION_SYSTEM_INFO, len);
233         if (!message)
234                 return -1;
235
236         pb_protocol_serialise_system_info(sysinfo, message->payload, len);
237
238         return client_write_message(server, client, message);
239 }
240
241 static int write_config_message(struct discover_server *server,
242                 struct client *client, const struct config *config)
243 {
244         struct pb_protocol_message *message;
245         int len;
246
247         len = pb_protocol_config_len(config);
248
249         message = pb_protocol_create_message(client,
250                         PB_PROTOCOL_ACTION_CONFIG, len);
251         if (!message)
252                 return -1;
253
254         pb_protocol_serialise_config(config, message->payload, len);
255
256         return client_write_message(server, client, message);
257 }
258
259 static int write_authenticate_message(struct discover_server *server,
260                 struct client *client)
261 {
262         struct pb_protocol_message *message;
263         struct auth_message auth_msg;
264         int len;
265
266         auth_msg.op = AUTH_MSG_RESPONSE;
267         auth_msg.authenticated = client->can_modify;
268
269         len = pb_protocol_authenticate_len(&auth_msg);
270
271         message = pb_protocol_create_message(client,
272                         PB_PROTOCOL_ACTION_AUTHENTICATE, len);
273         if (!message)
274                 return -1;
275
276         pb_protocol_serialise_authenticate(&auth_msg, message->payload, len);
277
278         return client_write_message(server, client, message);
279 }
280
281 static int client_auth_timeout(void *arg)
282 {
283         struct client *client = arg;
284         int rc;
285
286         client->auth_waiter = NULL;
287         client->can_modify = false;
288
289         rc = write_authenticate_message(client->server, client);
290         if (rc)
291                 pb_log("failed to send client auth timeout\n");
292
293         return 0;
294 }
295
296 static int discover_server_handle_auth_message(struct client *client,
297                 struct auth_message *auth_msg)
298 {
299         struct status *status;
300         char *hash;
301         int rc;
302
303         status = talloc_zero(client, struct status);
304
305         switch (auth_msg->op) {
306         case AUTH_MSG_REQUEST:
307                 if (!crypt_check_password(auth_msg->password)) {
308                         rc = -1;
309                         pb_log("Client failed to authenticate\n");
310                         status->type = STATUS_ERROR;
311                         status->message = talloc_asprintf(status,
312                                         _("Password incorrect"));
313                 } else {
314                         client->can_modify = true;
315                         rc = write_authenticate_message(client->server,
316                                         client);
317                         if (client->auth_waiter)
318                                 waiter_remove(client->auth_waiter);
319                         client->auth_waiter = waiter_register_timeout(
320                                         client->server->waitset,
321                                         300000, /* 5 min */
322                                         client_auth_timeout, client);
323                         pb_log("Client authenticated\n");
324                         status->type = STATUS_INFO;
325                         status->message = talloc_asprintf(status,
326                                         _("Authenticated successfully"));
327                 }
328                 break;
329         case AUTH_MSG_SET:
330                 if (client->server->restrict_clients) {
331                         if (!crypt_check_password(auth_msg->set_password.password)) {
332                                 rc = -1;
333                                 pb_log("Wrong password for set request\n");
334                                 status->type = STATUS_ERROR;
335                                 status->message = talloc_asprintf(status,
336                                                 _("Password incorrect"));
337                                 break;
338                         }
339                 }
340
341                 rc = crypt_set_password(auth_msg,
342                                 auth_msg->set_password.new_password);
343                 if (rc) {
344                         pb_log("Failed to set password\n");
345                         status->type = STATUS_ERROR;
346                         status->message = talloc_asprintf(status,
347                                         _("Error setting password"));
348                 } else {
349                         if (!auth_msg->set_password.new_password ||
350                                 !strlen(auth_msg->set_password.new_password)) {
351                                 platform_set_password("");
352                                 discover_server_set_auth_mode(client->server,
353                                                 false);
354                                 pb_log("Password cleared\n");
355                         } else {
356                                 hash = crypt_get_hash(auth_msg);
357                                 platform_set_password(hash);
358                                 talloc_free(hash);
359                                 discover_server_set_auth_mode(client->server,
360                                                 true);
361                         }
362                         pb_log("System password changed\n");
363                         status->type = STATUS_ERROR;
364                         status->message = talloc_asprintf(status,
365                                         _("Password updated successfully"));
366                 }
367                 break;
368         default:
369                 pb_log("%s: unknown op\n", __func__);
370                 rc = -1;
371                 break;
372         }
373
374         write_boot_status_message(client->server, client, status);
375         talloc_free(status);
376
377         return rc;
378 }
379
380 static int discover_server_process_message(void *arg)
381 {
382         struct autoboot_option *autoboot_opt;
383         struct pb_protocol_message *message;
384         struct boot_command *boot_command;
385         struct auth_message *auth_msg;
386         struct status *status;
387         struct client *client = arg;
388         struct config *config;
389         char *url;
390         int rc;
391
392         message = pb_protocol_read_message(client, client->fd);
393
394         if (!message) {
395                 talloc_free(client);
396                 return 0;
397         }
398
399         /*
400          * If crypt support is enabled, non-authorised clients can only delay
401          * boot, not configure options or change the default boot option.
402          */
403         if (!client->can_modify) {
404                 switch (message->action) {
405                 case PB_PROTOCOL_ACTION_BOOT:
406                         boot_command = talloc(client, struct boot_command);
407
408                         rc = pb_protocol_deserialise_boot_command(boot_command,
409                                         message);
410                         if (rc) {
411                                 pb_log("%s: no boot command?", __func__);
412                                 return 0;
413                         }
414
415                         device_handler_boot(client->server->device_handler,
416                                         client->can_modify, boot_command);
417                         break;
418                 case PB_PROTOCOL_ACTION_CANCEL_DEFAULT:
419                         device_handler_cancel_default(client->server->device_handler);
420                         break;
421                 case PB_PROTOCOL_ACTION_AUTHENTICATE:
422                         auth_msg = talloc(client, struct auth_message);
423                         rc = pb_protocol_deserialise_authenticate(
424                                         auth_msg, message);
425                         if (rc) {
426                                 pb_log("Couldn't parse client's auth request\n");
427                                 break;
428                         }
429
430                         rc = discover_server_handle_auth_message(client,
431                                         auth_msg);
432                         talloc_free(auth_msg);
433                         break;
434                 default:
435                         pb_log("non-root client tried to perform action %d\n",
436                                         message->action);
437                         status = talloc_zero(client, struct status);
438                         if (status) {
439                                 status->type = STATUS_ERROR;
440                                 status->message = talloc_asprintf(status,
441                                                 "Client must run as root to make changes");
442                                 write_boot_status_message(client->server, client,
443                                                 status);
444                                 talloc_free(status);
445                         }
446                 }
447                 return 0;
448         }
449
450         switch (message->action) {
451         case PB_PROTOCOL_ACTION_BOOT:
452                 boot_command = talloc(client, struct boot_command);
453
454                 rc = pb_protocol_deserialise_boot_command(boot_command,
455                                 message);
456                 if (rc) {
457                         pb_log_fn("no boot command?\n");
458                         return 0;
459                 }
460
461                 device_handler_boot(client->server->device_handler,
462                                 client->can_modify, boot_command);
463                 break;
464
465         case PB_PROTOCOL_ACTION_CANCEL_DEFAULT:
466                 device_handler_cancel_default(client->server->device_handler);
467                 break;
468
469         case PB_PROTOCOL_ACTION_REINIT:
470                 device_handler_reinit(client->server->device_handler);
471                 break;
472
473         case PB_PROTOCOL_ACTION_CONFIG:
474                 config = talloc_zero(client, struct config);
475
476                 rc = pb_protocol_deserialise_config(config, message);
477                 if (rc) {
478                         pb_log_fn("no config?\n");
479                         return 0;
480                 }
481
482                 device_handler_update_config(client->server->device_handler,
483                                 config);
484                 break;
485
486         case PB_PROTOCOL_ACTION_ADD_URL:
487                 url = pb_protocol_deserialise_string((void *) client, message);
488
489                 device_handler_process_url(client->server->device_handler,
490                                 url, NULL, NULL);
491                 break;
492
493         case PB_PROTOCOL_ACTION_PLUGIN_INSTALL:
494                 url = pb_protocol_deserialise_string((void *) client, message);
495
496                 device_handler_install_plugin(client->server->device_handler,
497                                 url);
498                 break;
499
500         case PB_PROTOCOL_ACTION_TEMP_AUTOBOOT:
501                 autoboot_opt = talloc_zero(client, struct autoboot_option);
502                 rc = pb_protocol_deserialise_temp_autoboot(autoboot_opt,
503                                 message);
504                 if (rc) {
505                         pb_log("can't parse temporary autoboot message\n");
506                         return 0;
507                 }
508
509                 device_handler_apply_temp_autoboot(
510                                 client->server->device_handler,
511                                 autoboot_opt);
512                 break;
513
514         /* For AUTH_MSG_SET */
515         case PB_PROTOCOL_ACTION_AUTHENTICATE:
516                 auth_msg = talloc(client, struct auth_message);
517                 rc = pb_protocol_deserialise_authenticate(
518                                 auth_msg, message);
519                 if (rc) {
520                         pb_log("Couldn't parse client's auth request\n");
521                         break;
522                 }
523
524                 rc = discover_server_handle_auth_message(client, auth_msg);
525                 talloc_free(auth_msg);
526                 break;
527         default:
528                 pb_log_fn("invalid action %d\n", message->action);
529                 return 0;
530         }
531
532
533         return 0;
534 }
535
536 void discover_server_set_auth_mode(struct discover_server *server,
537                 bool restrict_clients)
538 {
539         struct client *client;
540
541         server->restrict_clients = restrict_clients;
542
543         list_for_each_entry(&server->clients, client, list) {
544                 client->can_modify = !restrict_clients;
545                 write_authenticate_message(server, client);
546         }
547 }
548
549 static int discover_server_process_connection(void *arg)
550 {
551         struct discover_server *server = arg;
552         struct statuslog_entry *entry;
553         int fd, rc, i, n_devices, n_plugins;
554         struct client *client;
555         struct ucred ucred;
556         socklen_t len;
557
558         /* accept the incoming connection */
559         fd = accept(server->socket, NULL, NULL);
560         if (fd < 0) {
561                 pb_log("accept: %s\n", strerror(errno));
562                 return 0;
563         }
564
565         /* add to our list of clients */
566         client = talloc_zero(server, struct client);
567         list_add(&server->clients, &client->list);
568
569         talloc_set_destructor(client, client_destructor);
570
571         client->fd = fd;
572         client->server = server;
573         client->waiter = waiter_register_io(server->waitset, client->fd,
574                                 WAIT_IN, discover_server_process_message,
575                                 client);
576
577         /*
578          * get some info on the connecting process - if the client is being
579          * run as root allow them to make changes
580          */
581         if (server->restrict_clients) {
582                 len = sizeof(struct ucred);
583                 rc = getsockopt(client->fd, SOL_SOCKET, SO_PEERCRED, &ucred,
584                                 &len);
585                 if (rc) {
586                         pb_log("Failed to get socket info - restricting client\n");
587                         client->can_modify = false;
588                 } else {
589                         pb_log("Client details: pid: %d, uid: %d, egid: %d\n",
590                                         ucred.pid, ucred.uid, ucred.gid);
591                         client->can_modify = ucred.uid == 0;
592                 }
593         } else
594                 client->can_modify = true;
595
596         /* send auth status to client */
597         rc = write_authenticate_message(server, client);
598         if (rc)
599                 return 0;
600
601         /* send sysinfo to client */
602         rc = write_system_info_message(server, client, system_info_get());
603         if (rc)
604                 return 0;
605
606         /* send config to client */
607         rc = write_config_message(server, client, config_get());
608         if (rc)
609                 return 0;
610
611         /* send existing devices to client */
612         n_devices = device_handler_get_device_count(server->device_handler);
613         for (i = 0; i < n_devices; i++) {
614                 const struct discover_boot_option *opt;
615                 const struct discover_device *device;
616
617                 device = device_handler_get_device(server->device_handler, i);
618                 rc = write_device_add_message(server, client, device->device);
619                 if (rc)
620                         return 0;
621
622                 list_for_each_entry(&device->boot_options, opt, list) {
623                         rc = write_boot_option_add_message(server, client,
624                                         opt->option);
625                         if (rc)
626                                 return 0;
627                 }
628         }
629
630         /* send status backlog to client */
631         list_for_each_entry(&server->status, entry, list)
632                 write_boot_status_message(server, client, entry->status);
633
634         /* send installed plugins to client */
635         n_plugins = device_handler_get_plugin_count(server->device_handler);
636         for (i = 0; i < n_plugins; i++) {
637                 const struct plugin_option *plugin;
638
639                 plugin = device_handler_get_plugin(server->device_handler, i);
640                 write_plugin_option_add_message(server, client, plugin);
641         }
642
643         return 0;
644 }
645
646 void discover_server_notify_device_add(struct discover_server *server,
647                 struct device *device)
648 {
649         struct client *client;
650
651         list_for_each_entry(&server->clients, client, list)
652                 write_device_add_message(server, client, device);
653
654 }
655
656 void discover_server_notify_boot_option_add(struct discover_server *server,
657                 struct boot_option *boot_option)
658 {
659         struct client *client;
660
661         list_for_each_entry(&server->clients, client, list)
662                 write_boot_option_add_message(server, client, boot_option);
663 }
664
665 void discover_server_notify_device_remove(struct discover_server *server,
666                 struct device *device)
667 {
668         struct client *client;
669
670         list_for_each_entry(&server->clients, client, list)
671                 write_device_remove_message(server, client, device->id);
672
673 }
674
675 void discover_server_notify_boot_status(struct discover_server *server,
676                 struct status *status)
677 {
678         struct statuslog_entry *entry;
679         struct client *client;
680
681         /* Duplicate the status struct to add to the backlog */
682         entry = talloc(server, struct statuslog_entry);
683         if (!entry) {
684                 pb_log("Failed to allocated saved status!\n");
685         } else {
686                 entry->status = talloc(entry, struct status);
687                 if (entry->status) {
688                         entry->status->type = status->type;
689                         entry->status->message = talloc_strdup(entry->status,
690                                                                status->message);
691                         entry->status->backlog = true;
692                         list_add_tail(&server->status, &entry->list);
693                 } else {
694                         talloc_free(entry);
695                 }
696         }
697
698         list_for_each_entry(&server->clients, client, list)
699                 write_boot_status_message(server, client, status);
700 }
701
702 void discover_server_notify_system_info(struct discover_server *server,
703                 const struct system_info *sysinfo)
704 {
705         struct client *client;
706
707         list_for_each_entry(&server->clients, client, list)
708                 write_system_info_message(server, client, sysinfo);
709 }
710
711 void discover_server_notify_config(struct discover_server *server,
712                 const struct config *config)
713 {
714         struct client *client;
715
716         list_for_each_entry(&server->clients, client, list)
717                 write_config_message(server, client, config);
718 }
719
720 void discover_server_notify_plugin_option_add(struct discover_server *server,
721                 struct plugin_option *opt)
722 {
723         struct client *client;
724
725         list_for_each_entry(&server->clients, client, list)
726                 write_plugin_option_add_message(server, client, opt);
727 }
728
729 void discover_server_notify_plugins_remove(struct discover_server *server)
730 {
731         struct client *client;
732
733         list_for_each_entry(&server->clients, client, list)
734                 write_plugins_remove_message(server, client);
735 }
736
737 void discover_server_set_device_source(struct discover_server *server,
738                 struct device_handler *handler)
739 {
740         server->device_handler = handler;
741 }
742
743 struct discover_server *discover_server_init(struct waitset *waitset)
744 {
745         struct discover_server *server;
746         struct sockaddr_un addr;
747         struct group *group;
748
749         server = talloc(NULL, struct discover_server);
750         if (!server)
751                 return NULL;
752
753         server->waiter = NULL;
754         server->waitset = waitset;
755         list_init(&server->clients);
756         list_init(&server->status);
757
758         unlink(PB_SOCKET_PATH);
759
760         server->socket = socket(AF_UNIX, SOCK_STREAM, 0);
761         if (server->socket < 0) {
762                 pb_log("error creating server socket: %s\n", strerror(errno));
763                 goto out_err;
764         }
765
766         talloc_set_destructor(server, server_destructor);
767         addr.sun_family = AF_UNIX;
768         strcpy(addr.sun_path, PB_SOCKET_PATH);
769
770         if (bind(server->socket, (struct sockaddr *)&addr, sizeof(addr))) {
771                 pb_log("error binding server socket: %s\n", strerror(errno));
772                 goto out_err;
773         }
774
775         /* Allow all clients to communicate on this socket */
776         group = getgrnam("petitgroup");
777         if (group) {
778                 chown(PB_SOCKET_PATH, 0, group->gr_gid);
779                 chmod(PB_SOCKET_PATH, 0660);
780         }
781
782         if (listen(server->socket, 8)) {
783                 pb_log("server socket listen: %s\n", strerror(errno));
784                 goto out_err;
785         }
786
787         server->waiter = waiter_register_io(server->waitset, server->socket,
788                         WAIT_IN, discover_server_process_connection, server);
789
790         return server;
791
792 out_err:
793         talloc_free(server);
794         return NULL;
795 }
796
797 void discover_server_destroy(struct discover_server *server)
798 {
799         talloc_free(server);
800 }
801