]> git.ozlabs.org Git - petitboot/blob - discover/discover-server.c
discover/grub2: Allow to separate the --id argument using a space char
[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 = 0;
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         case AUTH_MSG_DECRYPT:
369                 if (!client->can_modify) {
370                         pb_log("Unauthenticated client tried to open encrypted device %s\n",
371                                         auth_msg->decrypt_dev.device_id);
372                         rc = -1;
373                         status->type = STATUS_ERROR;
374                         status->message = talloc_asprintf(status,
375                                         _("Must authenticate before opening encrypted device"));
376                         break;
377                 }
378
379                 device_handler_open_encrypted_dev(client->server->device_handler,
380                                 auth_msg->decrypt_dev.password,
381                                 auth_msg->decrypt_dev.device_id);
382                 break;
383         default:
384                 pb_log("%s: unknown op\n", __func__);
385                 rc = -1;
386                 break;
387         }
388
389         if (status->message)
390                 write_boot_status_message(client->server, client, status);
391         talloc_free(status);
392
393         return rc;
394 }
395
396 static int discover_server_process_message(void *arg)
397 {
398         struct autoboot_option *autoboot_opt;
399         struct pb_protocol_message *message;
400         struct boot_command *boot_command;
401         struct auth_message *auth_msg;
402         struct status *status;
403         struct client *client = arg;
404         struct config *config;
405         char *url;
406         int rc = 0;
407
408         message = pb_protocol_read_message(client, client->fd);
409
410         if (!message) {
411                 talloc_free(client);
412                 return 0;
413         }
414
415         /*
416          * If crypt support is enabled, non-authorised clients can only delay
417          * boot, not configure options or change the default boot option.
418          */
419         if (!client->can_modify) {
420                 switch (message->action) {
421                 case PB_PROTOCOL_ACTION_BOOT:
422                         boot_command = talloc(client, struct boot_command);
423
424                         rc = pb_protocol_deserialise_boot_command(boot_command,
425                                         message);
426                         if (rc) {
427                                 pb_log("%s: no boot command?", __func__);
428                                 return 0;
429                         }
430
431                         device_handler_boot(client->server->device_handler,
432                                         client->can_modify, boot_command);
433                         break;
434                 case PB_PROTOCOL_ACTION_CANCEL_DEFAULT:
435                         device_handler_cancel_default(client->server->device_handler);
436                         break;
437                 case PB_PROTOCOL_ACTION_AUTHENTICATE:
438                         auth_msg = talloc(client, struct auth_message);
439                         rc = pb_protocol_deserialise_authenticate(
440                                         auth_msg, message);
441                         if (rc) {
442                                 pb_log("Couldn't parse client's auth request\n");
443                                 break;
444                         }
445
446                         rc = discover_server_handle_auth_message(client,
447                                         auth_msg);
448                         talloc_free(auth_msg);
449                         break;
450                 default:
451                         pb_log("non-root client tried to perform action %d\n",
452                                         message->action);
453                         status = talloc_zero(client, struct status);
454                         if (status) {
455                                 status->type = STATUS_ERROR;
456                                 status->message = talloc_asprintf(status,
457                                                 "Client must run as root to make changes");
458                                 write_boot_status_message(client->server, client,
459                                                 status);
460                                 talloc_free(status);
461                         }
462                 }
463                 return rc;
464         }
465
466         switch (message->action) {
467         case PB_PROTOCOL_ACTION_BOOT:
468                 boot_command = talloc(client, struct boot_command);
469
470                 rc = pb_protocol_deserialise_boot_command(boot_command,
471                                 message);
472                 if (rc) {
473                         pb_log_fn("no boot command?\n");
474                         return 0;
475                 }
476
477                 device_handler_boot(client->server->device_handler,
478                                 client->can_modify, boot_command);
479                 break;
480
481         case PB_PROTOCOL_ACTION_CANCEL_DEFAULT:
482                 device_handler_cancel_default(client->server->device_handler);
483                 break;
484
485         case PB_PROTOCOL_ACTION_REINIT:
486                 device_handler_reinit(client->server->device_handler);
487                 break;
488
489         case PB_PROTOCOL_ACTION_CONFIG:
490                 config = talloc_zero(client, struct config);
491
492                 rc = pb_protocol_deserialise_config(config, message);
493                 if (rc) {
494                         pb_log_fn("no config?\n");
495                         return 0;
496                 }
497
498                 device_handler_update_config(client->server->device_handler,
499                                 config);
500                 break;
501
502         case PB_PROTOCOL_ACTION_ADD_URL:
503                 url = pb_protocol_deserialise_string((void *) client, message);
504
505                 device_handler_process_url(client->server->device_handler,
506                                 url, NULL, NULL);
507                 break;
508
509         case PB_PROTOCOL_ACTION_PLUGIN_INSTALL:
510                 url = pb_protocol_deserialise_string((void *) client, message);
511
512                 device_handler_install_plugin(client->server->device_handler,
513                                 url);
514                 break;
515
516         case PB_PROTOCOL_ACTION_TEMP_AUTOBOOT:
517                 autoboot_opt = talloc_zero(client, struct autoboot_option);
518                 rc = pb_protocol_deserialise_temp_autoboot(autoboot_opt,
519                                 message);
520                 if (rc) {
521                         pb_log("can't parse temporary autoboot message\n");
522                         return 0;
523                 }
524
525                 device_handler_apply_temp_autoboot(
526                                 client->server->device_handler,
527                                 autoboot_opt);
528                 break;
529
530         /* For AUTH_MSG_SET */
531         case PB_PROTOCOL_ACTION_AUTHENTICATE:
532                 auth_msg = talloc(client, struct auth_message);
533                 rc = pb_protocol_deserialise_authenticate(
534                                 auth_msg, message);
535                 if (rc) {
536                         pb_log("Couldn't parse client's auth request\n");
537                         break;
538                 }
539
540                 discover_server_handle_auth_message(client, auth_msg);
541                 talloc_free(auth_msg);
542                 break;
543         default:
544                 pb_log_fn("invalid action %d\n", message->action);
545                 return 0;
546         }
547
548
549         return 0;
550 }
551
552 void discover_server_set_auth_mode(struct discover_server *server,
553                 bool restrict_clients)
554 {
555         struct client *client;
556
557         server->restrict_clients = restrict_clients;
558
559         list_for_each_entry(&server->clients, client, list) {
560                 client->can_modify = !restrict_clients;
561                 write_authenticate_message(server, client);
562         }
563 }
564
565 static int discover_server_process_connection(void *arg)
566 {
567         struct discover_server *server = arg;
568         struct statuslog_entry *entry;
569         int fd, rc, i, n_devices, n_plugins;
570         struct client *client;
571         struct ucred ucred;
572         socklen_t len;
573
574         /* accept the incoming connection */
575         fd = accept(server->socket, NULL, NULL);
576         if (fd < 0) {
577                 pb_log("accept: %s\n", strerror(errno));
578                 return 0;
579         }
580
581         /* add to our list of clients */
582         client = talloc_zero(server, struct client);
583         list_add(&server->clients, &client->list);
584
585         talloc_set_destructor(client, client_destructor);
586
587         client->fd = fd;
588         client->server = server;
589         client->waiter = waiter_register_io(server->waitset, client->fd,
590                                 WAIT_IN, discover_server_process_message,
591                                 client);
592
593         /*
594          * get some info on the connecting process - if the client is being
595          * run as root allow them to make changes
596          */
597         if (server->restrict_clients) {
598                 len = sizeof(struct ucred);
599                 rc = getsockopt(client->fd, SOL_SOCKET, SO_PEERCRED, &ucred,
600                                 &len);
601                 if (rc) {
602                         pb_log("Failed to get socket info - restricting client\n");
603                         client->can_modify = false;
604                 } else {
605                         pb_log("Client details: pid: %d, uid: %d, egid: %d\n",
606                                         ucred.pid, ucred.uid, ucred.gid);
607                         client->can_modify = ucred.uid == 0;
608                 }
609         } else
610                 client->can_modify = true;
611
612         /* send auth status to client */
613         rc = write_authenticate_message(server, client);
614         if (rc)
615                 return 0;
616
617         /* send sysinfo to client */
618         rc = write_system_info_message(server, client, system_info_get());
619         if (rc)
620                 return 0;
621
622         /* send config to client */
623         rc = write_config_message(server, client, config_get());
624         if (rc)
625                 return 0;
626
627         /* send existing devices to client */
628         n_devices = device_handler_get_device_count(server->device_handler);
629         for (i = 0; i < n_devices; i++) {
630                 const struct discover_boot_option *opt;
631                 const struct discover_device *device;
632
633                 device = device_handler_get_device(server->device_handler, i);
634                 rc = write_device_add_message(server, client, device->device);
635                 if (rc)
636                         return 0;
637
638                 list_for_each_entry(&device->boot_options, opt, list) {
639                         rc = write_boot_option_add_message(server, client,
640                                         opt->option);
641                         if (rc)
642                                 return 0;
643                 }
644         }
645
646         /* send status backlog to client */
647         list_for_each_entry(&server->status, entry, list)
648                 write_boot_status_message(server, client, entry->status);
649
650         /* send installed plugins to client */
651         n_plugins = device_handler_get_plugin_count(server->device_handler);
652         for (i = 0; i < n_plugins; i++) {
653                 const struct plugin_option *plugin;
654
655                 plugin = device_handler_get_plugin(server->device_handler, i);
656                 write_plugin_option_add_message(server, client, plugin);
657         }
658
659         return 0;
660 }
661
662 void discover_server_notify_device_add(struct discover_server *server,
663                 struct device *device)
664 {
665         struct client *client;
666
667         list_for_each_entry(&server->clients, client, list)
668                 write_device_add_message(server, client, device);
669
670 }
671
672 void discover_server_notify_boot_option_add(struct discover_server *server,
673                 struct boot_option *boot_option)
674 {
675         struct client *client;
676
677         list_for_each_entry(&server->clients, client, list)
678                 write_boot_option_add_message(server, client, boot_option);
679 }
680
681 void discover_server_notify_device_remove(struct discover_server *server,
682                 struct device *device)
683 {
684         struct client *client;
685
686         list_for_each_entry(&server->clients, client, list)
687                 write_device_remove_message(server, client, device->id);
688
689 }
690
691 void discover_server_notify_boot_status(struct discover_server *server,
692                 struct status *status)
693 {
694         struct statuslog_entry *entry;
695         struct client *client;
696
697         /* Duplicate the status struct to add to the backlog */
698         entry = talloc(server, struct statuslog_entry);
699         if (!entry) {
700                 pb_log("Failed to allocated saved status!\n");
701         } else {
702                 entry->status = talloc(entry, struct status);
703                 if (entry->status) {
704                         entry->status->type = status->type;
705                         entry->status->message = talloc_strdup(entry->status,
706                                                                status->message);
707                         entry->status->backlog = true;
708                         list_add_tail(&server->status, &entry->list);
709                 } else {
710                         talloc_free(entry);
711                 }
712         }
713
714         list_for_each_entry(&server->clients, client, list)
715                 write_boot_status_message(server, client, status);
716 }
717
718 void discover_server_notify_system_info(struct discover_server *server,
719                 const struct system_info *sysinfo)
720 {
721         struct client *client;
722
723         list_for_each_entry(&server->clients, client, list)
724                 write_system_info_message(server, client, sysinfo);
725 }
726
727 void discover_server_notify_config(struct discover_server *server,
728                 const struct config *config)
729 {
730         struct client *client;
731
732         list_for_each_entry(&server->clients, client, list)
733                 write_config_message(server, client, config);
734 }
735
736 void discover_server_notify_plugin_option_add(struct discover_server *server,
737                 struct plugin_option *opt)
738 {
739         struct client *client;
740
741         list_for_each_entry(&server->clients, client, list)
742                 write_plugin_option_add_message(server, client, opt);
743 }
744
745 void discover_server_notify_plugins_remove(struct discover_server *server)
746 {
747         struct client *client;
748
749         list_for_each_entry(&server->clients, client, list)
750                 write_plugins_remove_message(server, client);
751 }
752
753 void discover_server_set_device_source(struct discover_server *server,
754                 struct device_handler *handler)
755 {
756         server->device_handler = handler;
757 }
758
759 struct discover_server *discover_server_init(struct waitset *waitset)
760 {
761         struct discover_server *server;
762         struct sockaddr_un addr;
763         struct group *group;
764
765         server = talloc(NULL, struct discover_server);
766         if (!server)
767                 return NULL;
768
769         server->waiter = NULL;
770         server->waitset = waitset;
771         list_init(&server->clients);
772         list_init(&server->status);
773
774         unlink(PB_SOCKET_PATH);
775
776         server->socket = socket(AF_UNIX, SOCK_STREAM, 0);
777         if (server->socket < 0) {
778                 pb_log("error creating server socket: %s\n", strerror(errno));
779                 goto out_err;
780         }
781
782         talloc_set_destructor(server, server_destructor);
783         addr.sun_family = AF_UNIX;
784         strcpy(addr.sun_path, PB_SOCKET_PATH);
785
786         if (bind(server->socket, (struct sockaddr *)&addr, sizeof(addr))) {
787                 pb_log("error binding server socket: %s\n", strerror(errno));
788                 goto out_err;
789         }
790
791         /* Allow all clients to communicate on this socket */
792         group = getgrnam("petitgroup");
793         if (group) {
794                 if (chown(PB_SOCKET_PATH, 0, group->gr_gid))
795                         pb_log_fn("Error setting socket ownership: %m\n");
796                 errno = 0;
797                 if (chmod(PB_SOCKET_PATH, 0660))
798                         pb_log_fn("Error setting socket permissions: %m\n");
799         }
800
801         if (listen(server->socket, 8)) {
802                 pb_log("server socket listen: %s\n", strerror(errno));
803                 goto out_err;
804         }
805
806         server->waiter = waiter_register_io(server->waitset, server->socket,
807                         WAIT_IN, discover_server_process_connection, server);
808
809         return server;
810
811 out_err:
812         talloc_free(server);
813         return NULL;
814 }
815
816 void discover_server_destroy(struct discover_server *server)
817 {
818         talloc_free(server);
819 }
820