ead1ee578e3536895dc1a70be0262230659a39eb
[tlspool] / src / service.c
1 /* tlspool/service.c -- TLS pool service, socket handling, command dispatcher */
2
3 #include "whoami.h"
4
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <stdint.h>
8 #include <string.h>
9 #include <pthread.h>
10 #include <assert.h>
11
12 #include <errno.h>
13 #include <com_err.h>
14 #include <errortable.h>
15
16 #ifndef WINDOWS_PORT
17 #include <unistd.h>
18 #endif /* WINDOWS_PORT */
19
20 #include <syslog.h>
21 #include <fcntl.h>
22
23 #include <tlspool/commands.h>
24 #include <tlspool/internal.h>
25
26 #ifdef WINDOWS_PORT
27 #include <winsock2.h>
28 #else
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <sys/un.h>
32 #include <poll.h>
33 #endif
34
35 #ifdef WINDOWS_PORT
36 #include <windows.h>
37 #ifndef __MINGW64__
38 #define WEOF ((wint_t)(0xFFFF))
39 #endif
40
41 #define _tprintf printf
42 #define _tmain main
43 #endif /* WINDOWS_PORT */
44
45 /* The data stored in this module consists of lists of sockets to listen to
46  * for connection setup and command exchange, but not data communication.
47  * Commands are received from the various clients and processed, always
48  * ensuring exactly one reply.
49  *
50  * Some command requests are actually callbacks in reaction to something
51  * the TLS pool sent to an application.  Those callbacks are recognised
52  * by their pio_cbid parameter, and after security scrutiny they are passed
53  * on directly to the requester, bypassing normal command processing and
54  * instead processing it where it was requested.  This parser-like spread
55  * of acceptable cases over processing nodes simplifies the complexity
56  * and available alternatives in each node.  It also helps to benefit from
57  * overlap between (semantics versions of) similar commands.
58  *
59  * Anything that may take up more than a trivial amount of time (perhaps
60  * because it must wait for remote operations to complete) is sent off to
61  * a separate thread, which may interact with its client or with a client
62  * serving a special purpose (that is, the PIN entry client).
63  *
64  * When a thread wants to request a callback, it sends a command response
65  * to that end, after creating a suitable structure in the callback list.
66  * This structure includes a place where the callback command can be
67  * stored, and a mutex that must be unlocked when that has been done.  The
68  * callback structure may at that point be released.  The structures for
69  * these exchanges with the callback list and, complicating matters, the
70  * free list of callback structures, is arranged in this module and offered
71  * to the rest of the TLS pool as an abstract service.
72  */
73
74
75 static int stop_service = 0;
76 static uint32_t facilities;
77
78 static struct callback cblist [1024];
79 static struct callback *cbfree;
80 static pthread_mutex_t cbfree_mutex = PTHREAD_MUTEX_INITIALIZER;
81
82 static int os_send_command (struct command *cmd, int passfd);
83 static void os_run_service ();
84
85 /* Setup the service module.
86  */
87 void setup_service (void) {
88         facilities = cfg_facilities ();
89 }
90
91 /* Cleanup the service module.
92  */
93 void cleanup_service (void) {
94         ;
95 }
96
97
98 /* Allocate a free command structure for the processing cycle.  Commands are
99  * considered claimed between allocate_command_for_clientfd() and the freeing
100  * of the command that takes place while sending a reply.  Note that sending
101  * a callback request does not count as a reply; it defers the freeing-up of
102  * the command structure.
103  *
104  * As for locking... this function is only called by the master thread, so
105  * it requires no locks.  It merely sets the "claimed" flag (after setting
106  * up the "clientfd" field) after which it is airborne.  Unlocking is done
107  * by the thread that happens to be working on the command at that time,
108  * and is effectively done by resetting the "claimed" flag to zero, and not
109  * doing _anything_ with the command afterwards.
110  */
111 static struct command *cmdpool = NULL;
112 static int cmdpool_len = 1000;
113 static struct command *allocate_command_for_clientfd (pool_handle_t fd) {
114         static int cmdpool_pos = 0;
115         int pos;
116         struct command *cmd;
117         if (!cmdpool) {
118                 cmdpool = (struct command *) calloc (1000, sizeof (struct command));
119                 if (!cmdpool) {
120                         tlog (TLOG_UNIXSOCK, LOG_CRIT, "Failed to allocate command pool");
121                         exit (1);
122                 }
123                 memset (cmdpool, 0, 1000 * sizeof (struct command));
124         }
125         pos = cmdpool_pos;
126         while (cmdpool [pos].claimed) {
127                 pos++;
128                 if (pos >= cmdpool_len) {
129                         cmdpool = 0;
130                 }
131                 if (pos == cmdpool_pos) {
132                         /* A full rotation -- delay of 10ms */
133                         _usleep (10000);
134                 }
135         }
136         cmdpool [pos].clientfd = fd;
137         cmdpool [pos].passfd = -1;
138         cmdpool [pos].handler = pthread_self ();        // Not fit for cancel
139         cmdpool [pos].claimed = 1;
140         return &cmdpool [pos];
141 }
142
143
144 /* Free any commands that were allocated to the given client file descriptor.
145  * This is disruptive; the commands will not continue their behaviour by
146  * responding to the requests.  This means that it should only be used for
147  * situations where the client file descriptor was closed.
148  * Any threads that may be running or waiting on the command are cancelled.
149  *
150  * TODO: This is O(cmdpool_len) so linked lists could help to avoid trouble.
151  */
152 static void free_commands_by_clientfd (pool_handle_t clientfd) {
153         int i;
154         if (cmdpool == NULL) {
155                 return;
156         }
157         for (i=0; i<cmdpool_len; i++) {
158                 if (cmdpool [i].claimed) {
159                         if (cmdpool [i].clientfd == clientfd) {
160                                 //TODO// don't be so disruptive
161                                 pthread_cancel (cmdpool [i].handler);
162                                 cmdpool [i].claimed = 0;
163                         }
164                 }
165         }
166 }
167
168 int send_command (struct command *cmd, int passfd) {
169         int rc;
170
171         if (cmd == NULL) {
172                 return 1;       // Success guaranteed when nobody is listening
173         }
174         assert (passfd == -1);  // Working passfd code retained but not used
175         cmd->claimed = 0;
176         return os_send_command(cmd, passfd);
177 }
178
179 /* Report success to the user.  Note that this function does not terminate
180  * actions, but it should be the last response to the client.
181  *
182  * We accept the situation where cmd==NULL to accommodate code that deals
183  * with re-run commands that were internally stored.  This saves massively
184  * in re-coding such code.
185  *
186  * We accept the situation where cmd==NULL to accommodate code that deals
187  * with re-run commands that were internally stored.  This saves massively
188  * in re-coding such code.
189  */
190 void send_success (struct command *cmd) {
191         if (cmd == NULL) {
192                 return;
193         }
194         cmd->cmd.pio_cmd = PIOC_SUCCESS_V2;
195         cmd->cmd.pio_cbid = 0;
196         if (!send_command (cmd, -1)) {
197                 perror ("Failed to send success reply");
198         }
199 }
200
201
202 /* Report an error response to the user.  Report with the given errno and msg.
203  * Note that this function does not terminate actions, but it should be the
204  * last response to the client.
205  *
206  * We accept the situation where cmd==NULL to accommodate code that deals
207  * with re-run commands that were internally stored.  This saves massively
208  * in re-coding such code.
209  */
210 void send_error (struct command *cmd, int tlserrno, char *msg) {
211         if (cmd == NULL) {
212                 return;
213         }
214         if (tlserrno == 0) {
215                 send_success (cmd);
216                 return;
217         }
218         cmd->cmd.pio_cmd = PIOC_ERROR_V2;
219         cmd->cmd.pio_cbid = 0;
220         cmd->cmd.pio_data.pioc_error.tlserrno = tlserrno;
221         strncpy (cmd->cmd.pio_data.pioc_error.message, msg, sizeof (cmd->cmd.pio_data.pioc_error.message));
222         if (!send_command (cmd, -1)) {
223                 perror ("Failed to send error reply");
224         }
225 }
226
227 void copy_tls_command(struct command *cmd, struct tlspool_command *tls_command) {
228         memcpy(&cmd->cmd, tls_command, sizeof(struct tlspool_command));
229 }
230
231 /* Check if a command request is a proper callback response.
232  * Return 1 if it is, othterwise return 0.
233  */
234 static int is_callback (struct command *cmd) {
235         uint16_t cbid = cmd->cmd.pio_cbid;
236         if (cbid == 0) {
237                 return 0;
238         }
239         if (cbid > 1024) {      /* TODO: dynamicity */
240                 return 0;
241         }
242         cbid--;
243         if (cblist [cbid].fd < 0) {
244                 return 0;
245         }
246         if (cblist [cbid].fd != cmd->clientfd) {
247                 return 0;
248         }
249         if (cblist [cbid].followup) {
250                 return 0;
251         }
252         return 1;
253 }
254
255
256 /* Desire a callback and in the process of doing so, send a callback response.
257  * This must be called from another thread than the main TLS pool thread.
258  *
259  * The code below and the signaling post_callback call claim the cbfree_mutex
260  * as a condition to protect (keep atomic) the conditioning and signaling.
261  * The condition awaited for which the callback's condition presents a hint
262  * is the setting of the followup pointer in the callback structure, which
263  * links in the command that responds to the callback placed.
264  *
265  * The caller may supply the absolute time_t value at which it times out.
266  * If opt_timeout is 0, it is not considered to be a timeout value.  If it
267  * is supplied, the return value may be NULL to signal timeout.  There is
268  * no information fed back from the caller, but at least the TLS Pool does
269  * not block on it, but can continue to process failure.  Later submissions
270  * of the callback response are swallowed silently (although a log entry
271  * will be made).
272  */
273 struct command *send_callback_and_await_response (struct command *cmdresp, time_t opt_timeout) {
274         struct callback *cb;
275         struct command *followup;
276         assert (pthread_mutex_lock (&cbfree_mutex) == 0);
277         cb = cbfree;
278         if (!cb) {
279                 //TODO// Allocate more...
280                 tlog (TLOG_UNIXSOCK, LOG_CRIT, "Ran out of callback structures.  Crashing as a coward");
281                 exit (1);
282         }
283         //TODO// It's simpler to administer index numbers and not pointers
284         cbfree = cb->next;
285         cmdresp->cmd.pio_cbid = 1 + (((intptr_t) cb) - ((intptr_t) cblist)) / ((intptr_t) sizeof (struct callback));
286         cb->fd = cmdresp->clientfd;
287         cb->followup = NULL;
288         cb->next = NULL; //TODO// Enqueue in fd-queue
289         cb->timedout = 0;
290         send_command (cmdresp, -1);
291         do {
292                 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Waiting with fd=%d and cbid=%d on semaphone 0x%08x", cb->fd, cmdresp->cmd.pio_cbid, cb);
293                 if (opt_timeout != 0) {
294                         struct timespec ts;
295                         memset (&ts, 0, sizeof (ts));
296                         ts.tv_sec = opt_timeout;
297                         if (pthread_cond_timedwait (&cb->semaphore, &cbfree_mutex, &ts) != 0) {
298                                 // Timed out (or interrupted) so give up
299                                 followup = NULL;
300                                 break;
301                         }
302                 } else {
303                         pthread_cond_wait (&cb->semaphore, &cbfree_mutex);
304                 }
305                 followup = cb->followup;
306         } while (!followup);
307         //TODO// Remove cb from the fd's cblist
308         if (followup) {
309                 cb->next = cbfree;
310                 cbfree = cb;
311         } else {
312                 cb->timedout = 1;       // Defer freeing it to the signaler
313         }
314         pthread_mutex_unlock (&cbfree_mutex);
315         if (!followup) {
316                 tlog (TLOG_UNIXSOCK, LOG_NOTICE, "Requested callback over %d timed out, cleanup of structures deferred", cmdresp->clientfd);
317         }
318         return followup;
319 }
320
321
322 /* Present a callback command request to the thread that is waiting for it.
323  * This must be called from the main thread of the TLS pool, and it will
324  * spark life to the thread that is awaiting the callback.
325  */
326 static void post_callback (struct command *cmd) {
327         uint16_t cbid = cmd->cmd.pio_cbid - 1;
328         cblist [cbid].fd = INVALID_POOL_HANDLE;
329         cblist [cbid].followup = cmd;
330         assert (pthread_mutex_lock (&cbfree_mutex) == 0);
331         tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Signaling on the semaphore of callback 0x%08x", &cblist [cbid]);
332         if (!cblist [cbid].timedout) {
333                 // Still waiting, send a signal to the requester
334                 pthread_cond_signal (&cblist [cbid].semaphore);
335         } else {
336                 // Timed out, but the callback structure awaits cleanup
337                 cblist [cbid].next = cbfree;
338                 cbfree = &cblist [cbid];
339                 cmd->claimed = 0;
340                 //TODO// Might report an error back, to indicate ignorance
341         }
342         pthread_mutex_unlock (&cbfree_mutex);
343 }
344
345
346 /* Forget all callbacks that were sent to the given clientfd, by posting an
347  * ERROR message to them.  This is used to avoid infinitely waiting threads
348  * in the TLS Pool when a clientfd is closed by the client (perhaps due to
349  * a crash in response to the callback).
350  */
351 static void free_callbacks_by_clientfd (pool_handle_t clientfd) {
352         int i;
353         for (i=0; i<1024; i++) {
354 //TODO// == clientfd was >= 0 (and managed to get closes sent back to all)
355                 if (cblist [i].fd == clientfd) {
356                         struct command *errcmd;
357                         errcmd = allocate_command_for_clientfd (clientfd);
358                         errcmd->clientfd = clientfd;
359                         errcmd->passfd = -1;
360                         errcmd->claimed = 1;
361                         errcmd->cmd.pio_reqid = 0;  // Don't know how to set it
362                         errcmd->cmd.pio_cbid = i + 1;
363                         errcmd->cmd.pio_cmd = PIOC_ERROR_V2;
364                         errcmd->cmd.pio_data.pioc_error.tlserrno = E_TLSPOOL_CLIENT_DISCONNECT;
365                         snprintf (errcmd->cmd.pio_data.pioc_error.message, 127, "TLS Pool client fd %d closed", clientfd);
366 printf ("DEBUG: Freeing callback with cbid=%d for clientfd %d\n", i+1, clientfd);
367                         post_callback (errcmd);
368 printf ("DEBUG: Freed   callback with cbid=%d for clientfd %d\n", i+1, clientfd);
369                 }
370         }
371 }
372
373
374 /* Process an info query; it depends on what is being asked,
375  * where it should be directed.  Not everything is TLS :-)
376  */
377 static void  process_command_info (struct command *cmd) {
378         uint8_t *ctlkey = cmd->cmd.pio_data.pioc_info.ctlkey;
379         uint32_t kind   = cmd->cmd.pio_data.pioc_info.info_kind;
380         uint16_t len    = cmd->cmd.pio_data.pioc_info.len;
381         uint8_t *buf    = cmd->cmd.pio_data.pioc_info.buffer;
382         //
383         // Is the control key valid?
384         struct ctlkeynode *node = ctlkey_find (cmd->cmd.pio_data.pioc_info.ctlkey, security_tls, cmd->clientfd);
385         if (node == NULL) {
386                 send_error (cmd, E_TLSPOOL_CTLKEY_NOT_FOUND,
387                                         "TLS Pool cannot find the control key");
388                 goto done;
389         }
390         //
391         // Ensure proper sizing of the request
392         if ((len > sizeof (cmd->cmd.pio_data.pioc_info.buffer)) && (len != 0xffff)) {
393                 send_error (cmd, E_TLSPOOL_COMMAND_NOTIMPL, "TLS Pool command or variety not implemented");
394                 goto done_unfind;
395         }
396         //
397         // Invoke a handler specific to the kind of information
398         switch (kind) {
399         case PIOK_INFO_PEERCERT_SUBJECT:
400         case PIOK_INFO_MYCERT_SUBJECT:
401                 starttls_info_cert_subject (cmd, node, len, buf);
402                 break;
403         case PIOK_INFO_PEERCERT_ISSUER:
404         case PIOK_INFO_MYCERT_ISSUER:
405                 starttls_info_cert_issuer (cmd, node, len, buf);
406                 break;
407         case PIOK_INFO_PEERCERT_SUBJECTALTNAME:
408         case PIOK_INFO_MYCERT_SUBJECTALTNAME:
409                 starttls_info_cert_subjectaltname (cmd, node, len, buf);
410                 break;
411         case PIOK_INFO_CHANBIND_TLS_UNIQUE:
412                 starttls_info_chanbind_tls_unique (cmd, node, len, buf);
413                 break;
414         case PIOK_INFO_CHANBIND_TLS_SERVER_END_POINT:
415                 starttls_info_chanbind_tls_server_end_point (cmd, node, len, buf);
416                 break;
417         default:
418                 send_error (cmd, E_TLSPOOL_INFOKIND_UNKNOWN, "TLS Pool does not support that kind of info");
419                 break;
420         }
421         //
422         // Cleanup; this involves unlocking the ctlkey to other messages
423 done_unfind:
424         ctlkey_unfind (node);
425 done:
426         ;
427 }
428
429
430 /* Process a command packet that entered on a TLS pool socket
431  */
432 static void process_command (struct command *cmd) {
433         tlog (TLOG_UNIXSOCK, LOG_DEBUG, "Processing command 0x%08x, passfd=%d", cmd->cmd.pio_cmd, cmd->passfd);
434         union pio_data *d = &cmd->cmd.pio_data;
435         if (is_callback (cmd)) {
436 tlog (TLOG_UNIXSOCK, LOG_DEBUG, "DEBUG: Processing callback command sent over fd=%d\n", cmd->clientfd);
437                 post_callback (cmd);
438                 return;
439         }
440         switch (cmd->cmd.pio_cmd) {
441         case PIOC_PING_V2:
442                 strcpy (d->pioc_ping.YYYYMMDD_producer, TLSPOOL_IDENTITY_V2);
443                 d->pioc_ping.facilities &= facilities;
444                 send_command (cmd, -1);
445                 return;
446         case PIOC_STARTTLS_V2:
447                 starttls (cmd);
448                 return;
449         case PIOC_PRNG_V2:
450                 if (facilities & PIOF_FACILITY_STARTTLS) {
451                         starttls_prng (cmd);
452                 } else {
453                         send_error (cmd, E_TLSPOOL_FACILITY_STARTTLS,
454                                 "TLS Pool setup excludes STARTTLS facility");
455                 }
456                 return;
457         case PIOC_INFO_V2:
458                 process_command_info (cmd);
459                 return;
460         case PIOC_CONTROL_DETACH_V2:
461                 ctlkey_detach (cmd);
462                 return;
463         case PIOC_CONTROL_REATTACH_V2:
464                 ctlkey_reattach (cmd);
465                 return;
466         case PIOC_PINENTRY_V2:
467                 register_pinentry_command (cmd);
468                 return;
469         case PIOC_LIDENTRY_REGISTER_V2:
470                 register_lidentry_command (cmd);
471                 return;
472         default:
473                 send_error (cmd, E_TLSPOOL_COMMAND_UNKNOWN, "TLS Pool command unrecognised");
474                 return;
475         }
476 }
477
478 /* Request orderly hangup of the service.
479  */
480 void hangup_service (void) {
481         stop_service = 1;
482         tlog (TLOG_UNIXSOCK, LOG_NOTICE, "Requested service to hangup soon");
483 }
484
485 /* The main service loop.  It uses poll() to find things to act upon. */
486 void run_service (void) {
487         int i;
488
489         cbfree = NULL;
490         errno = pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
491         if (errno) {
492                 tlog (TLOG_UNIXSOCK | TLOG_DAEMON, LOG_ERR, "Service routine thread cancellability refused");
493                 exit (1);
494         }
495         for (i=0; i<1024; i++) {
496                 cblist [i].next = cbfree;
497                 cblist [i].fd = INVALID_POOL_HANDLE; // Mark as unused
498                 pthread_cond_init (&cblist [i].semaphore, NULL);
499                 cblist [i].followup = NULL;
500                 cbfree = &cblist [i];
501         }
502         os_run_service ();
503 }
504
505 #ifdef WINDOWS_PORT
506 #include "service_windows.c"
507 #else
508 #include "service_posix.c"
509 #endif
510