Improvements in Python support and installation of Python and includes
[tlspool] / lib / libtlspool_pinentry.c
1 /* tlspool/libfun.c -- Library function for starttls go-get-it */
2
3 #include "whoami.h"
4
5 #include <stdlib.h>
6 #include <errno.h>
7 #include <string.h>
8 #include <syslog.h>
9
10 #include <unistd.h>
11 #include <pthread.h>
12
13 #include <tlspool/starttls.h>
14 #include <tlspool/commands.h>
15
16 #ifdef WINDOWS_PORT
17 #include <winsock2.h>
18 #else
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <sys/un.h>
22 #include <sys/select.h>
23 #include <sys/resource.h>
24 #endif
25
26 /* Cleanup routine */
27 static void tlspool_pin_service_closepool (void *poolfdptr) {
28         int poolfd = * (int *) poolfdptr;
29         if (poolfd >= 0) {
30                 close (poolfd);
31         }
32 }
33
34
35 /* The library function to service PIN entry callbacks.  It registers
36  * with the TLS Pool and will service callback requests until it is no
37  * longer welcomed.  Of course, if another process already has a claim on
38  * this functionality, the service offering will not be welcome from the
39  * start.
40  *
41  * This function differs from most other TLS Pool library functions in
42  * setting up a private socket.  This helps to avoid the overhead in the
43  * foreseeable applications that only do this; it also helps to close
44  * down the exclusive claim on local identity resolution when (part of)
45  * the program is torn down.  The function has been built to cleanup
46  * properly when it is subjected to pthread_cancel().
47  *
48  * The path parameter offers a mechanism to specify the socket path.  When
49  * set to NULL, the library's compiled-in default path will be used.
50  *
51  * In terms of linking, this routine is a separate archive object.  This
52  * minimizes the amount of code carried around in statically linked binaries.
53  *
54  * This function returns -1 on error, or 0 on success.
55  */
56 int tlspool_pin_service (char *path, uint32_t regflags, int responsetimeout_usec, void (*cb) (struct pioc_pinentry *entry, void *data), void *data) {
57         struct sockaddr_un sun;
58         int poolfd = -1;
59         struct tlspool_command cmd;
60
61         /* Access the TLS Pool socket */
62         if (path == NULL) {
63                 path = tlspool_configvar (NULL, "daemon_pidfile");
64         }
65         if (path == NULL) {
66                 path = TLSPOOL_DEFAULT_SOCKET_PATH;
67         }
68         if (strlen (path) + 1 > sizeof (sun.sun_path)) {
69                 errno = EINVAL;
70                 return -1;
71         }
72         memset (&sun, 0, sizeof (sun));
73         sun.sun_family = AF_UNIX;
74         strcpy (sun.sun_path, path);
75         pthread_cleanup_push (tlspool_pin_service_closepool, &poolfd);
76         poolfd = socket (AF_UNIX, SOCK_STREAM, 0);
77         if (poolfd < 0) {
78                 return -1;
79         }
80         if (connect (poolfd, (struct sockaddr *) &sun, sizeof (sun)) == -1) {
81                 close (poolfd);
82                 poolfd = -1;
83                 return -1;
84         }
85
86         /* Prepare command structure */
87         memset (&cmd, 0, sizeof (cmd)); /* Do not leak old stack info */
88         cmd.pio_cbid = 0;
89         cmd.pio_cmd = PIOC_PINENTRY_V2;
90         cmd.pio_data.pioc_pinentry.flags = regflags;
91         cmd.pio_data.pioc_pinentry.timeout_us = responsetimeout_usec;
92
93         /* Loop forever... or until an error occurs */
94         while (1) {
95
96                 /* send the request or, when looping, the callback result */
97 //DEBUG// printf ("DEBUG: PINENTRY command 0x%08lx with cbid=%d and flags 0x%08lx\n", cmd.pio_cmd, cmd.pio_cbid, cmd.pio_data.pioc_pinentry.flags);
98                 if (send (poolfd, &cmd, sizeof (cmd), MSG_NOSIGNAL) == -1) {
99                         // errno inherited from send()
100                         // let SIGPIPE be reported as EPIPE
101                         close (poolfd);
102                         return -1;
103                 }
104
105                 /* Erase the password that has just been sent */
106                 memset (&cmd.pio_data.pioc_pinentry.pin,
107                                 0,
108                                 sizeof (cmd.pio_data.pioc_pinentry.pin));
109
110                 /* receive and process the response */
111                 if (recv (poolfd, &cmd, sizeof (cmd), MSG_NOSIGNAL) == -1) {
112                         // Let SIGPIPE be reported as EPIPE
113                         // errno inherited from recv()
114                         close (poolfd);
115                         return -1;
116                 }
117 //DEBUG// printf ("DEBUG: PINENTRY callback command 0x%08lx with cbid=%d and flags 0x%08lx\n", cmd.pio_cmd, cmd.pio_cbid, cmd.pio_data.pioc_pinentry.flags);
118                 switch (cmd.pio_cmd) {
119                 case PIOC_PINENTRY_V2:
120                         (*cb) (&cmd.pio_data.pioc_pinentry, data);
121                         //TODO// Claim on regent lost?
122                         break;
123                 case PIOC_ERROR_V2:
124                         errno = cmd.pio_data.pioc_error.tlserrno;
125                         syslog (LOG_INFO, "TLS Pool error to tlspool_localid_service(): %s", cmd.pio_data.pioc_error.message);
126                         close (poolfd);
127                         return -1;
128                 default:
129                         errno = EPROTO;
130                         close (poolfd);
131                         return -1;
132                 }
133         }
134
135         /* Never end up here... */
136         pthread_cleanup_pop (1);
137         return 0;
138 }
139