1 /*
2  * Copyright (c) 2006-2007 Zeljko Vrba <zvrba@globalnet.hr>
3  * Copyright (c) 2006-2017 Alon Bar-Lev <alon.barlev@gmail.com>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  *     o Redistributions of source code must retain the above copyright notice,
10  *       this list of conditions and the following disclaimer.
11  *     o Redistributions in binary form must reproduce the above copyright
12  *       notice, this list of conditions and the following disclaimer in the
13  *       documentation and/or other materials provided with the distribution.
14  *     o Neither the name of the <ORGANIZATION> nor the names of its
15  *       contributors may be used to endorse or promote products derived from
16  *       this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 /**
32    @file
33    Main command loop for scdaemon. For compatibility with GnuPG's scdaemon,
34    all command-line options are silently ignored.
35 
36    @todo True daemon mode and multi-server mode are not yet implemented. Only
37    one card is currently supported. Client notification of card status change
38    is not implemented.
39 */
40 
41 #include "common.h"
42 #include "command.h"
43 #include "dconfig.h"
44 #include <signal.h>
45 #include <getopt.h>
46 #include <errno.h>
47 #include <pkcs11-helper-1.0/pkcs11h-core.h>
48 #if !defined(HAVE_W32_SYSTEM)
49 #include <sys/stat.h>
50 #include <sys/types.h>
51 #include <sys/socket.h>
52 #include <sys/un.h>
53 #include <sys/select.h>
54 #ifdef HAVE_SYS_UCRED_H
55 #include <sys/ucred.h>
56 #endif
57 #endif
58 
59 #if defined(USE_GNUTLS)
60 #include <gnutls/gnutls.h>
61 #endif
62 
63 #ifdef HAVE_W32_SYSTEM
64 typedef void *gnupg_fd_t;
65 #define GNUPG_INVALID_FD ((void*)(-1))
66 #define INT2FD(s) ((void *)(s))
67 #define FD2INT(h) ((unsigned int)(h))
68 #else
69 typedef int gnupg_fd_t;
70 #define GNUPG_INVALID_FD (-1)
71 #define INT2FD(s) (s)
72 #define FD2INT(h) (h)
73 #endif
74 
75 typedef enum {
76 	ACCEPT_THREAD_STOP,
77 	ACCEPT_THREAD_CLEAN
78 } accept_command_t;
79 
80 struct global_s;
81 
82 #if !defined(HAVE_W32_SYSTEM)
83 typedef struct thread_list_s {
84 	struct thread_list_s *next;
85 	int fd;
86 	pthread_t thread;
87 	int stopped;
88 	struct global_s *global;
89 } *thread_list_t;
90 #endif
91 
92 typedef struct global_s {
93 	dconfig_data_t config;
94 	char *socket_name;
95 #if !defined(HAVE_W32_SYSTEM)
96 	thread_list_t *threads;
97 	char *socket_dir;
98 	int fd_accept_terminate[2];
99 	uid_t uid_acl;
100 #endif
101 
102 } global_t;
103 
104 #if !defined(HAVE_W32_SYSTEM)
105 static int s_parent_pid = -1;
106 #endif
107 
108 #define ALARM_INTERVAL 10
109 #define SOCKET_DIR_TEMPLATE ( PACKAGE ".XXXXXX" )
110 
111 /** Register commands with assuan. */
112 static
113 int
register_commands(const assuan_context_t ctx)114 register_commands (const assuan_context_t ctx)
115 {
116 	static struct {
117 		const char *name;
118 		assuan_handler_t handler;
119 		const char * const help;
120 	} table[] = {
121 		{ "SERIALNO",	cmd_serialno, NULL },
122 		{ "LEARN",	cmd_learn, NULL },
123 		{ "READCERT",	cmd_readcert, NULL },
124 		{ "READKEY",	cmd_readkey, NULL },
125 		{ "KEY-DATA",	NULL, NULL },
126 		{ "SETDATA",	cmd_setdata, NULL },
127 		{ "PKSIGN",	cmd_pksign, NULL },
128 		{ "PKAUTH",	NULL, NULL },
129 		{ "PKDECRYPT",	cmd_pkdecrypt, NULL },
130 		{ "INPUT",	NULL, NULL },
131 		{ "OUTPUT",	NULL, NULL },
132 		{ "GETATTR",	cmd_getattr, NULL },
133 		{ "SETATTR",	cmd_setattr, NULL },
134 		{ "WRITECERT",	NULL, NULL },
135 		{ "WRITEKEY",	NULL, NULL },
136 		{ "GENKEY",	cmd_genkey, NULL },
137 		{ "RANDOM",	NULL, NULL },
138 		{ "PASSWD",	NULL, NULL },
139 		{ "CHECKPIN",	cmd_null, NULL },
140 		{ "LOCK",	NULL, NULL },
141 		{ "UNLOCK",	NULL, NULL },
142 		{ "GETINFO",	cmd_getinfo, NULL },
143 		{ "RESTART",	cmd_restart, NULL },
144 		{ "DISCONNECT",	cmd_null, NULL },
145 		{ "APDU",	NULL, NULL },
146 		{ "CHV-STATUS-1", cmd_null, NULL },	/* gnupg-1.X */
147 		{ NULL, NULL, NULL }
148 	};
149 	int i, ret;
150 
151 	for(i=0; table[i].name; i++) {
152 		if (
153 			(ret = assuan_register_command (
154 				ctx,
155 				table[i].name,
156 				table[i].handler,
157 				table[i].help
158 			))
159 		) {
160 			return ret;
161 		}
162 	}
163 
164 	assuan_set_hello_line (ctx, "PKCS#11 smart-card server for GnuPG ready");
165 	/*assuan_register_reset_notify(ctx, reset_notify);*/
166 	/*assuan_register_option_handler(ctx, option_handler);*/
167 	return 0;
168 }
169 
170 /**
171    Command handler (single-threaded). If fd == -1, this is a pipe server,
172    otherwise fd is UNIX socket fd to which client connected.
173 */
174 static
175 void
command_handler(global_t * global,const int fd)176 command_handler (global_t *global, const int fd)
177 {
178 	assuan_context_t ctx = NULL;
179 	cmd_data_t data;
180 	int ret;
181 
182 #if !defined(HAVE_W32_SYSTEM)
183 	if (fd != -1 && global->uid_acl != (uid_t)-1) {
184 		uid_t peeruid = -1;
185 #if HAVE_DECL_LOCAL_PEERCRED
186 		struct xucred xucred;
187 		socklen_t len = sizeof(xucred);
188 		if (getsockopt(fd, SOL_SOCKET, LOCAL_PEERCRED, &xucred, &len) == -1) {
189 			common_log (LOG_WARNING, "Cannot get socket credentials: %s", strerror (errno));
190 			goto cleanup;
191 		}
192 		if (xucred.cr_version != XUCRED_VERSION) {
193 			common_log (LOG_WARNING, "Mismatch credentials version actual %d expected %d", xucred.cr_version, XUCRED_VERSION);
194 			goto cleanup;
195 		}
196 		peeruid = xucred.cr_uid;
197 #elif HAVE_DECL_SO_PEERCRED
198 		struct ucred ucred;
199 		socklen_t len = sizeof(ucred);
200 		if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1) {
201 			common_log (LOG_WARNING, "Cannot get socket credentials: %s", strerror (errno));
202 			goto cleanup;
203 		}
204 		peeruid = ucred.uid;
205 #endif
206 		if (peeruid != global->uid_acl) {
207 			common_log (LOG_WARNING, "Mismatch credentials actual %d expected %d", peeruid, global->uid_acl);
208 			goto cleanup;
209 		}
210 	}
211 #endif
212 
213 	memset (&data, 0, sizeof (data));
214 	data.config = &global->config;
215 	data.socket_name = global->socket_name;
216 
217 	if ((ret = assuan_new(&ctx)) != 0) {
218 		common_log (LOG_ERROR,"failed to create assuan context %s", gpg_strerror (ret));
219 		goto cleanup;
220 	}
221 
222 	if(fd < 0) {
223 #if !defined(HAVE_W32_SYSTEM)
224 		assuan_fd_t fds[2] = {INT2FD(0), INT2FD(1)};
225 #else
226 		assuan_fd_t fds[2] = {GetStdHandle(STD_INPUT_HANDLE), GetStdHandle(STD_OUTPUT_HANDLE)};
227 #endif
228 		ret = assuan_init_pipe_server (ctx, fds);
229 	} else {
230 		ret = assuan_init_socket_server (ctx, INT2FD(fd), ASSUAN_SOCKET_SERVER_ACCEPTED);
231 	}
232 
233 	if (ret != 0) {
234 		common_log (LOG_ERROR,"failed to initialize server: %s", gpg_strerror (ret));
235 		goto cleanup;
236 	}
237 
238 	if(((ret = register_commands(ctx))) != 0) {
239 		common_log (LOG_ERROR,"failed to register assuan commands: %s", gpg_strerror (ret));
240 		goto cleanup;
241 	}
242 
243 	if (global->config.verbose) {
244 		assuan_set_log_stream (ctx, common_get_log_stream());
245 	}
246 
247 	assuan_set_pointer (ctx, &data);
248 
249 	while (1) {
250 		common_log (LOG_DEBUG, "accepting connection");
251 
252 		if ((ret = assuan_accept (ctx)) == -1) {
253 			break;
254 		}
255 
256 		if (ret != 0) {
257 			common_log (LOG_WARNING,"assuan_accept failed: %s", gpg_strerror(ret));
258 			break;
259 		}
260 
261 		common_log (LOG_DEBUG, "processing connection");
262 
263 		if ((ret = assuan_process (ctx)) != 0) {
264 			common_log (LOG_WARNING,"assuan_process failed: %s", gpg_strerror(ret));
265 		}
266 
267 		common_log (LOG_DEBUG, "post-processing connection");
268 	}
269 
270 cleanup:
271 
272 	common_log (LOG_DEBUG, "cleanup connection");
273 
274 	if (ctx != NULL) {
275 		cmd_free_data (ctx);
276 		assuan_release (ctx);
277 		ctx = NULL;
278 	}
279 }
280 
281 #if !defined(HAVE_W32_SYSTEM)
282 static
283 void
server_socket_close(global_t * global,const int fd)284 server_socket_close (global_t *global, const int fd) {
285 	if (fd != -1) {
286 		assuan_sock_close (fd);
287 	}
288 	if (global->socket_name != NULL) {
289 		unlink (global->socket_name);
290 		free (global->socket_name);
291 		global->socket_name = NULL;
292 	}
293 	if (global->socket_dir != NULL) {
294 		rmdir (global->socket_dir);
295 		free (global->socket_dir);
296 		global->socket_dir = NULL;
297 	}
298 	assuan_sock_deinit();
299 }
300 
301 static
302 void
server_socket_create_name(global_t * global)303 server_socket_create_name (global_t *global) {
304 
305 	char *socketdir = getenv("GNUPG_PKCS11_SOCKETDIR");
306 	if (socketdir == NULL) {
307 		socketdir = getenv("TMPDIR");
308 	}
309 	if (socketdir == NULL) {
310 		socketdir = "/tmp";
311 	}
312 
313 	if ((global->socket_dir = malloc(strlen(socketdir) + strlen(SOCKET_DIR_TEMPLATE) + 100)) == NULL) {
314 		common_log (LOG_FATAL, "malloc");
315 	}
316 	sprintf(global->socket_dir, "%s/%s", socketdir, SOCKET_DIR_TEMPLATE);
317 
318 	if (mkdtemp (global->socket_dir) == NULL) {
319 		common_log (LOG_FATAL, "Cannot mkdtemp");
320 	}
321 
322 	if ((global->socket_name = (char *)malloc (strlen (global->socket_dir) + 100)) == NULL) {
323 		common_log (LOG_FATAL, "Cannot malloc");
324 	}
325 
326 	sprintf (global->socket_name, "%s/agent.S", global->socket_dir);
327 
328 }
329 
330 static
331 int
server_socket_create(global_t * global)332 server_socket_create (global_t *global) {
333 	struct sockaddr_un serv_addr;
334 	int fd = -1;
335 	int rc = -1;
336 
337 	if ((rc = assuan_sock_init()) != 0) {
338 		common_log (LOG_ERROR,"Cannot init socket %s", gpg_strerror (rc));
339 		goto cleanup;
340 	}
341 
342 	memset (&serv_addr, 0, sizeof (serv_addr));
343 	serv_addr.sun_family = AF_UNIX;
344 	assert (strlen (global->socket_name) + 1 < sizeof (serv_addr.sun_path));
345 	strcpy (serv_addr.sun_path, global->socket_name);
346 
347 	if ((fd = assuan_sock_new (AF_UNIX, SOCK_STREAM, 0)) == -1) {
348 		common_log (LOG_ERROR, "Cannot create  socket", global->socket_name);
349 		goto cleanup;
350 	}
351 
352 	if ((rc = assuan_sock_bind (fd, (struct sockaddr*)&serv_addr, sizeof (serv_addr))) == -1) {
353 		common_log (LOG_ERROR, "Cannot bing to  socket '%s'", global->socket_name);
354 		goto cleanup;
355 	}
356 
357 #if !defined(HAVE_W32_SYSTEM)
358 	if (global->uid_acl != (uid_t)-1) {
359 		if (chmod(global->socket_name, 0666) == -1) {
360 			common_log (LOG_ERROR, "Cannot chmod '%s'", global->socket_name);
361 			goto cleanup;
362 		}
363 		if (chmod(global->socket_dir, 0755) == -1) {
364 			common_log (LOG_ERROR, "Cannot chmod '%s'", global->socket_dir);
365 			goto cleanup;
366 		}
367 	}
368 #endif
369 
370 	if ((rc = listen (fd, SOMAXCONN)) == -1) {
371 		common_log (LOG_ERROR, "Cannot listen to socket '%s'", global->socket_name);
372 		goto cleanup;
373 	}
374 
375 	rc = 0;
376 
377 cleanup:
378 
379 	if (rc != 0) {
380 		server_socket_close (global, fd);
381 		common_log (LOG_FATAL, "Cannot handle socket");
382 	}
383 
384 	common_log (LOG_INFO, "Listening to socket '%s'", global->socket_name);
385 
386 	return fd;
387 }
388 
389 static
390 void *
_server_socket_command_handler(void * arg)391 _server_socket_command_handler (void *arg) {
392 	thread_list_t entry = (thread_list_t)arg;
393 	accept_command_t clean = ACCEPT_THREAD_CLEAN;
394 
395 	command_handler (entry->global, entry->fd);
396 	entry->stopped = 1;
397 
398 	if (write (entry->global->fd_accept_terminate[1], &clean, sizeof (clean)) == -1) {
399 		common_log (LOG_FATAL, "write failed");
400 	}
401 
402 	return NULL;
403 }
404 
405 static
406 void *
_server_socket_accept(void * arg)407 _server_socket_accept (void *arg) {
408 	thread_list_t _entry = (thread_list_t)arg;
409 	global_t *global = _entry->global;
410 	int fd = _entry->fd;
411 	thread_list_t thread_list_head = NULL;
412 	int rc = 0;
413 
414 	free (_entry);
415 	_entry = NULL;
416 
417 	if (pipe (global->fd_accept_terminate) == -1) {
418 		common_log (LOG_FATAL, "pipe failed");
419 	}
420 
421 	while (rc != -1) {
422 		fd_set fdset;
423 
424 		FD_ZERO (&fdset);
425 		FD_SET (global->fd_accept_terminate[0], &fdset);
426 		FD_SET (fd, &fdset);
427 
428 		rc = select (FD_SETSIZE, &fdset, NULL, NULL, NULL);
429 
430 		if (rc != -1 && rc != 0) {
431 			if (FD_ISSET (global->fd_accept_terminate[0], &fdset)) {
432 				accept_command_t cmd;
433 
434 				if (
435 					(rc = read (
436 						global->fd_accept_terminate[0],
437 						&cmd,
438 						sizeof (cmd))
439 					) == sizeof (cmd)
440 				) {
441 					if (cmd == ACCEPT_THREAD_STOP) {
442 						common_log (LOG_DEBUG, "Thread command terminate");
443 						rc = -1;
444 					}
445 					else if (cmd == ACCEPT_THREAD_CLEAN) {
446 						thread_list_t entry = thread_list_head;
447 						thread_list_t prev = NULL;
448 
449 						common_log (LOG_DEBUG, "Cleaning up closed thread");
450 						while (entry != NULL) {
451 							if (entry->stopped) {
452 								thread_list_t temp = entry;
453 
454 								common_log (LOG_DEBUG, "Cleaning up closed thread1");
455 								pthread_join (entry->thread, NULL);
456 								close (entry->fd);
457 
458 								if (prev == NULL) {
459 									thread_list_head = entry->next;
460 								}
461 								else {
462 									prev->next = entry->next;
463 								}
464 
465 								entry = entry->next;
466 
467 								free (temp);
468 							}
469 							else {
470 								prev = entry;
471 								entry = entry->next;
472 							}
473 						}
474 					}
475 				}
476 			}
477 			else if (FD_ISSET (fd, &fdset)) {
478 				struct sockaddr_un addr;
479 				socklen_t addrlen = sizeof (addr);
480 				int fd2;
481 
482 				if ((rc = fd2 = accept (fd, (struct sockaddr *)&addr, &addrlen)) != -1) {
483 					thread_list_t entry = NULL;
484 
485 					common_log (LOG_DEBUG, "Accepted new socket connection");
486 
487 					if ((entry = (thread_list_t)malloc (sizeof (struct thread_list_s))) == NULL) {
488 						common_log (LOG_FATAL, "malloc failed");
489 					}
490 					memset (entry, 0, sizeof (struct thread_list_s));
491 					entry->next = thread_list_head;
492 					entry->fd = fd2;
493 					entry->global = global;
494 					thread_list_head = entry;
495 
496 					if (
497 						pthread_create (
498 							&entry->thread,
499 							NULL,
500 							_server_socket_command_handler,
501 							entry
502 						)
503 					) {
504 						common_log (LOG_FATAL, "pthread failed");
505 					}
506 
507 				}
508 			}
509 		}
510 	}
511 
512 	common_log (LOG_DEBUG, "Cleaning up threads");
513 	while (thread_list_head != NULL) {
514 		thread_list_t entry = thread_list_head;
515 		thread_list_head = thread_list_head->next;
516 		common_log (LOG_DEBUG, "Cleaning up thread1");
517 		close (entry->fd);
518 		pthread_join (entry->thread, NULL);
519 		free (entry);
520 	}
521 
522 	return NULL;
523 }
524 
525 static
526 void
server_socket_accept(global_t * global,const int fd,pthread_t * thread)527 server_socket_accept (global_t *global, const int fd, pthread_t *thread) {
528 	thread_list_t entry = malloc (sizeof (struct thread_list_s));
529 	memset (entry, 0, sizeof (struct thread_list_s));
530 	entry->fd = fd;
531 	entry->global = global;
532 	if (pthread_create (thread, NULL, _server_socket_accept, (void *)entry)) {
533 		common_log (LOG_FATAL, "pthread failed");
534 	}
535 }
536 
537 static
538 void
server_socket_accept_terminate(global_t * global,pthread_t thread)539 server_socket_accept_terminate (global_t *global, pthread_t thread) {
540 	accept_command_t stop = ACCEPT_THREAD_STOP;
541 	if (write (global->fd_accept_terminate[1], &stop, sizeof (stop)) == -1) {
542 		common_log (LOG_FATAL, "write failed");
543 	}
544 	pthread_join (thread, NULL);
545 	close (global->fd_accept_terminate[0]);
546 	close (global->fd_accept_terminate[1]);
547 }
548 #endif				/* HAVE_W32_SYSTEM */
549 
550 static
551 void
pkcs11_log_hook(void * const data,const unsigned flags,const char * const fmt,va_list args)552 pkcs11_log_hook (
553 	void * const data,
554 	const unsigned flags,
555 	const char * const fmt,
556 	va_list args
557 ) {
558 	(void)data;
559 	(void)flags;
560 
561 	common_vlog (LOG_INFO, fmt, args);
562 }
563 
564 static
565 PKCS11H_BOOL
pkcs11_token_prompt_hook(void * const global_data,void * const user_data,const pkcs11h_token_id_t token,const unsigned retry)566 pkcs11_token_prompt_hook (
567 	void * const global_data,
568 	void * const user_data,
569 	const pkcs11h_token_id_t token,
570 	const unsigned retry
571 ) {
572 	char cmd[1024];
573 	unsigned char *user_read = NULL;
574 	size_t user_read_len = 0;
575 	assuan_context_t ctx = user_data;
576 	int rc;
577 	int ret = FALSE;
578 
579 	(void)global_data;
580 	(void)retry;
581 
582 	snprintf (
583 		cmd,
584 		sizeof(cmd),
585 		"NEEDPIN Please insert token '%s' !!!DO NOT ENTER PIN HERE!!!!",
586 		token->display
587 	);
588 
589 	if ((rc = assuan_inquire (ctx, cmd, &user_read, &user_read_len, 1024))) {
590 		common_log (LOG_WARNING, "Token inquire error: %d", rc);
591 		goto cleanup;
592 	}
593 
594 	if (!strcmp ((char *)user_read, "cancel")) {
595 		goto cleanup;
596 	}
597 
598 	ret = TRUE;
599 
600 cleanup:
601 
602 	if (user_read != NULL) {
603 		memset (user_read, 0, strlen ((char *)user_read));
604 		free (user_read);
605 		user_read = NULL;
606 	}
607 
608 	return ret;
609 }
610 
611 static
612 PKCS11H_BOOL
pkcs11_pin_prompt_hook(void * const global_data,void * const user_data,const pkcs11h_token_id_t token,const unsigned retry,char * const pin,const size_t max_pin)613 pkcs11_pin_prompt_hook (
614 	void * const global_data,
615 	void * const user_data,
616 	const pkcs11h_token_id_t token,
617 	const unsigned retry,
618 	char * const pin,
619 	const size_t max_pin
620 ) {
621 	char cmd[1024];
622 	assuan_context_t ctx = user_data;
623 	unsigned char *pin_read = NULL;
624 	size_t pin_len;
625 	int rc;
626 	int ret = FALSE;
627 
628 	(void)global_data;
629 
630 	snprintf (
631 		cmd,
632 		sizeof(cmd),
633 		"NEEDPIN PIN required for token '%s' (try %u)",
634 		token->display,
635 		retry
636 	);
637 
638 	if ((rc = assuan_inquire (ctx, cmd, &pin_read, &pin_len, 1024))) {
639 		common_log (LOG_WARNING,"PIN inquire error: %d", rc);
640 		goto cleanup;
641 	}
642 
643 	if (pin_len==0 || (pin_len+1 > max_pin)) {
644 		goto cleanup;
645 	}
646 
647 	strcpy (pin, (char *)pin_read);
648 
649 	ret = TRUE;
650 
651 cleanup:
652 
653 	if (pin_read != NULL) {
654 		memset (pin_read, 0, strlen ((char *)pin_read));
655 		free (pin_read);
656 		pin_read = NULL;
657 	}
658 
659 	return ret;
660 }
661 
662 #if !defined(HAVE_W32_SYSTEM)
on_alarm(int signo)663 static RETSIGTYPE on_alarm (int signo)
664 {
665 	(void)signo;
666 
667 	if (s_parent_pid != -1 && kill (s_parent_pid, 0) == -1) {
668 		kill (getpid (), SIGTERM);
669 	}
670 
671 	signal (SIGALRM, on_alarm);
672 	alarm (ALARM_INTERVAL);
673 
674 #if RETSIGTYPE != void
675 	return 0
676 #endif
677 }
678 
679 static RETSIGTYPE on_signal (int signo)
680 {
681 	(void)signo;
682 
683 	/*
684 	 * This is the only way to notify
685 	 * assuan to return from its main loop...
686 	 */
687 	close (0);
688 	close (1);
689 
690 #if RETSIGTYPE != void
691 	return 0
692 #endif
693 }
694 #endif				/* HAVE_W32_SYSTEM */
695 
696 static void usage (const char * const argv0)
697 {
698 
699 	printf (
700 		(
701 "%s %s\n"
702 "\n"
703 "Copyright (c) 2006-2007 Zeljko Vrba <zvrba@globalnet.hr>\n"
704 "Copyright (c) 2006-2017 Alon Bar-Lev <alon.barlev@gmail.com>\n"
705 "This program comes with ABSOLUTELY NO WARRANTY.\n"
706 "This is free software, and you are welcome to redistribute it\n"
707 "under certain conditions. See the file COPYING for details.\n"
708 "\n"
709 "Syntax: %s [options]\n"
710 "Smartcard daemon for GnuPG\n"
711 "\n"
712 "Options:\n"
713 " \n"
714 "     --server              run in server mode (foreground)\n"
715 "     --multi-server        run in multi server mode (foreground)\n"
716 "     --daemon              run in daemon mode (background)\n"
717 " -v, --verbose             verbose\n"
718 " -q, --quiet               be somewhat more quiet\n"
719 " -s, --sh                  sh-style command output\n"
720 " -c, --csh                 csh-style command output\n"
721 "     --options             read options from file\n"
722 "     --no-detach           do not detach from the console\n"
723 "     --homedir             specify home directory\n"
724 #if !defined(HAVE_W32_SYSTEM)
725 "     --uid-acl             accept only this uid, implies world read/write socket\n"
726 #endif
727 "     --log-file            use a log file for the server\n"
728 "     --help                print this information\n"
729 		),
730 		PACKAGE,
731 		PACKAGE_VERSION,
732 		argv0
733 	);
734 }
735 
736 static char *get_home_dir (void) {
737 #if defined(HAVE_W32_SYSTEM)
738 	static const char * GPG_HOME_KEY = "Software\\GNU\\GnuPG";
739 	const char *HOME_ENV = getenv ("USERPROFILE");
740 #else
741 	const char *HOME_ENV = getenv ("HOME");
742 #endif
743 	char *home_dir = NULL;
744 
745 	if (home_dir == NULL && getenv ("GNUPGHOME") != NULL) {
746 		home_dir=strdup (getenv ("GNUPGHOME"));
747 	}
748 #if defined(HAVE_W32_SYSTEM)
749 	if (home_dir == NULL) {
750 		char key_val[1024];
751 		HKEY hkey = NULL;
752 		DWORD dw = 0;
753 
754 		if (RegOpenKeyEx (HKEY_CURRENT_USER, GPG_HOME_KEY, 0, KEY_READ, &hkey) != ERROR_SUCCESS) {
755 			if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, GPG_HOME_KEY, 0, KEY_READ, &hkey) != ERROR_SUCCESS) {
756 				hkey = NULL;
757 			}
758 		}
759 		if (hkey != NULL) {
760 			if (
761 				RegQueryValueEx (
762 					hkey,
763 					"HomeDir",
764 					NULL,
765 					NULL,
766 					(PBYTE)key_val,
767 					&dw
768 				) == ERROR_SUCCESS
769 			) {
770 				home_dir = strdup (key_val);
771 			}
772 		}
773 		if (hkey != NULL) {
774 			RegCloseKey (hkey);
775 		}
776 
777 	}
778 #endif
779 
780 	if (home_dir == NULL) {
781 		if (
782 			CONFIG_GPG_HOME[0] == '~' &&
783 			HOME_ENV != NULL
784 		) {
785 			if ((home_dir=(char *)malloc (strlen (CONFIG_GPG_HOME) + strlen (HOME_ENV))) == NULL) {
786 				common_log (LOG_FATAL, "malloc failed");
787 			}
788 			sprintf (home_dir, "%s%s", HOME_ENV, CONFIG_GPG_HOME+1);
789 		}
790 		else {
791 			home_dir = strdup (CONFIG_GPG_HOME);
792 		}
793 	}
794 
795 	return home_dir;
796 }
797 
798 int main (int argc, char *argv[])
799 {
800 	enum {
801 		OPT_SERVER,
802 		OPT_MUTLI_SERVER,
803 		OPT_DAEMON,
804 		OPT_VERBOSE,
805 		OPT_QUIET,
806 		OPT_SH,
807 		OPT_CSH,
808 		OPT_OPTIONS,
809 		OPT_NO_DETACH,
810 		OPT_HOMEDIR,
811 #if !defined(HAVE_W32_SYSTEM)
812 		OPT_UID_ACL,
813 #endif
814 		OPT_LOG_FILE,
815 		OPT_VERSION,
816 		OPT_HELP
817 	};
818 
819 	static struct option long_options[] = {
820 		{ "server", no_argument, NULL, OPT_SERVER },
821 		{ "multi-server", no_argument, NULL, OPT_MUTLI_SERVER },
822 		{ "daemon", no_argument, NULL, OPT_DAEMON },
823 		{ "verbose", no_argument, NULL, OPT_VERBOSE },
824 		{ "quiet", no_argument, NULL, OPT_QUIET },
825 		{ "sh", no_argument, NULL, OPT_SH },
826 		{ "csh", no_argument, NULL, OPT_CSH },
827 		{ "options", required_argument, NULL, OPT_OPTIONS },
828 		{ "no-detach", no_argument, NULL, OPT_NO_DETACH },
829 		{ "homedir", required_argument, NULL, OPT_HOMEDIR },
830 #if !defined(HAVE_W32_SYSTEM)
831 		{ "uid-acl", required_argument, NULL, OPT_UID_ACL },
832 #endif
833 		{ "log-file", required_argument, NULL, OPT_LOG_FILE },
834 		{ "version", no_argument, NULL, OPT_VERSION },
835 		{ "help", no_argument, NULL, OPT_HELP },
836 		{ NULL, 0, NULL, 0 }
837 	};
838 	int opt;
839 	enum {
840 		RUN_MODE_NONE,
841 		RUN_MODE_SERVER,
842 		RUN_MODE_MULTI_SERVER,
843 		RUN_MODE_DAEMON
844 	} run_mode = RUN_MODE_NONE;
845 	int env_is_csh = 0;
846 	int log_verbose = 0;
847 	int log_quiet = 0;
848 	int no_detach = 0;
849 	char *config_file = NULL;
850 	char *log_file = NULL;
851 	char *home_dir = NULL;
852 	int have_at_least_one_provider=0;
853 	FILE *fp_log = NULL;
854 	int i;
855 	CK_RV rv;
856 
857 	global_t global;
858 
859 	const char * CONFIG_SUFFIX = ".conf";
860 	char *default_config_file = NULL;
861 
862 	/* unused intentionally */
863 	(void)log_quiet;
864 
865 	memset(&global, 0, sizeof(global));
866 
867 #if !defined(HAVE_W32_SYSTEM)
868 	s_parent_pid = getpid ();
869 	global.fd_accept_terminate[0] = -1;
870 	global.fd_accept_terminate[1] = -1;
871 	global.uid_acl = (uid_t)-1;
872 #endif
873 
874 	if ((default_config_file = (char *)malloc (strlen (PACKAGE)+strlen (CONFIG_SUFFIX)+1)) == NULL) {
875 		common_log (LOG_FATAL, "malloc failed");
876 	}
877 	sprintf (default_config_file, "%s%s", PACKAGE, CONFIG_SUFFIX);
878 
879 	common_set_log_stream (stderr);
880 
881 	while ((opt = getopt_long (argc, argv, "vqsc", long_options, NULL)) != -1) {
882 		switch (opt) {
883 			case OPT_SERVER:
884 				run_mode = RUN_MODE_SERVER;
885 			break;
886 			case OPT_MUTLI_SERVER:
887 				run_mode = RUN_MODE_MULTI_SERVER;
888 			break;
889 			case OPT_DAEMON:
890 				run_mode = RUN_MODE_DAEMON;
891 			break;
892 			case OPT_VERBOSE:
893 			case 'v':
894 				log_verbose = 1;
895 			break;
896 			case OPT_QUIET:
897 			case 'q':
898 				log_quiet = 1;
899 			break;
900 			case OPT_SH:
901 			case 's':
902 			break;
903 			case OPT_CSH:
904 			case 'c':
905 				env_is_csh = 1;
906 			break;
907 			case OPT_OPTIONS:
908 				config_file = strdup (optarg);
909 			break;
910 			case OPT_NO_DETACH:
911 				no_detach = 1;
912 			break;
913 			case OPT_HOMEDIR:
914 				home_dir = strdup (optarg);
915 			break;
916 #if !defined(HAVE_W32_SYSTEM)
917 			case OPT_UID_ACL:
918 				global.uid_acl = atoi(optarg);
919 			break;
920 #endif
921 			case OPT_LOG_FILE:
922 				log_file = optarg;
923 			break;
924 			case OPT_VERSION:
925 				printf (
926 					"%s %s\n"
927 					"\n"
928 					"Copyright (c) 2006-2007 Zeljko Vrba <zvrba@globalnet.hr>\n"
929 					"Copyright (c) 2006-2017 Alon Bar-Lev <alon.barlev@gmail.com>\n"
930 					"\n"
931 					"This is free software; see the source for copying conditions.\n"
932 					"There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
933 					PACKAGE,
934 					PACKAGE_VERSION
935 				);
936 				exit (0);
937 			break;
938 			case OPT_HELP:
939 				usage(argv[0]);
940 				exit(0);
941 			break;
942 			default:
943 				fprintf(stderr, "Invalid usage\n");
944 				exit(1);
945 			break;
946 		}
947 	}
948 
949 	if (run_mode == RUN_MODE_NONE) {
950 		common_log (LOG_FATAL, "please use the option `--daemon' to run the program in the background");
951 	}
952 
953 #if defined(HAVE_W32_SYSTEM)
954 	if (run_mode == RUN_MODE_DAEMON) {
955 		common_log (LOG_FATAL, "daemon mode is not supported");
956 	}
957 #endif
958 
959 	if (home_dir == NULL) {
960 		home_dir = get_home_dir ();
961 	}
962 
963 	if (config_file == NULL) {
964 		if ((config_file = (char *)malloc (strlen (home_dir) + strlen (default_config_file)+2)) == NULL) {
965 			common_log (LOG_FATAL, "malloc failed");
966 		}
967 		sprintf (config_file, "%s%c%s", home_dir, CONFIG_PATH_SEPARATOR, default_config_file);
968 	}
969 
970 	if (
971 		!dconfig_read (config_file, &global.config) &&
972 		!dconfig_read (CONFIG_SYSTEM_CONFIG, &global.config)
973 	) {
974 		common_log (LOG_FATAL, "Cannot open configuration file");
975 	}
976 
977 	if (log_verbose) {
978 		global.config.verbose = 1;
979 	}
980 
981 #if !defined(HAVE_W32_SYSTEM)
982 	signal (SIGPIPE, SIG_IGN);
983 	{
984 		struct sigaction action;
985 		memset(&action, 0, sizeof(action));
986 		action.sa_handler = on_signal;
987 		sigaction(SIGINT, &action, NULL);
988 		sigaction(SIGTERM, &action, NULL);
989 		sigaction(SIGABRT, &action, NULL);
990 		sigaction(SIGHUP, &action, NULL);
991 	}
992 #endif
993 
994 	if (log_file == NULL) {
995 		log_file = global.config.log_file;
996 	}
997 
998 	if (log_file != NULL) {
999 		if (strcmp (log_file, "stderr") != 0) {
1000 			if ((fp_log = fopen (log_file, "a")) != NULL) {
1001 #if !defined(HAVE_W32_SYSTEM)
1002 				fchmod(fileno(fp_log), 0600);
1003 #else
1004 				_chmod(log_file, 0600);
1005 #endif
1006 				common_set_log_stream (fp_log);
1007 			}
1008 		}
1009 	}
1010 
1011 	if (global.config.debug) {
1012 		common_log (LOG_DEBUG, "version: %s", PACKAGE_VERSION);
1013 		dconfig_print (&global.config);
1014 		common_log (LOG_DEBUG, "run_mode: %d", run_mode);
1015 		common_log (LOG_DEBUG, "crypto: %s",
1016 #if defined(ENABLE_OPENSSL)
1017 			"openssl"
1018 #elif defined(ENABLE_GNUTLS)
1019 			"gnutls"
1020 #else
1021 			"invalid"
1022 #endif
1023 		);
1024 	}
1025 
1026 	if (!gcry_check_version (GCRYPT_VERSION)) {
1027 		common_log (LOG_FATAL, "Cannot initialize libcrypt");
1028 	}
1029 	gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
1030 	gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
1031 
1032 #if !defined(HAVE_W32_SYSTEM)
1033 	if (run_mode == RUN_MODE_DAEMON || run_mode == RUN_MODE_MULTI_SERVER) {
1034 		server_socket_create_name (&global);
1035 	}
1036 
1037 	/*
1038 	 * fork before doing PKCS#11 stuff
1039 	 * some providers don't behave well
1040 	 */
1041 	if (run_mode == RUN_MODE_DAEMON) {
1042 		pid_t pid;
1043 
1044 		pid = fork ();
1045 
1046 		if (pid == -1) {
1047 			common_log (LOG_FATAL, "fork failed");
1048 		}
1049 
1050 		if (pid != 0) {
1051 			static const char *key = "SCDAEMON_INFO";
1052 			char env[1024];
1053 			snprintf (env, sizeof (env), "%s:%lu:1", global.socket_name, (unsigned long)pid);
1054 
1055 			if (optind < argc) {
1056 				setenv(key, env, 1);
1057 				execvp (argv[optind], &(argv[optind]));
1058 				kill (pid, SIGTERM);
1059 				exit (1);
1060 			}
1061 			else {
1062 				if (env_is_csh) {
1063 					*strchr (env, '=') = ' ';
1064 					printf ("setenv %s %s\n", key, env);
1065 				}
1066 				else {
1067 					printf ("%s=%s; export %s\n", key, env, key);
1068 				}
1069 				exit (0);
1070 			}
1071 		}
1072 
1073 		if (!no_detach) {
1074 			int i;
1075 
1076 			for (i=0;i<3;i++) {
1077 				if (fileno (common_get_log_stream ()) != i) {
1078 					close (i);
1079 				}
1080 			}
1081 
1082 			if (setsid () == -1) {
1083 				common_log (LOG_FATAL, "setsid failed");
1084 			}
1085 		}
1086 
1087 		if (chdir ("/") == -1) {
1088 			common_log (LOG_FATAL, "chdir failed");
1089 		}
1090 
1091 		if (optind < argc) {
1092 			struct sigaction sa;
1093 
1094 			memset (&sa, 0, sizeof (sa));
1095 			sigemptyset (&sa.sa_mask);
1096 #if defined(SA_INTERRUPT)
1097 			sa.sa_flags |= SA_INTERRUPT;
1098 #endif
1099 			sa.sa_handler = on_alarm;
1100 			sigaction (SIGALRM, &sa, NULL);
1101 			alarm (10);
1102 		}
1103 	}
1104 #endif				/* HAVE_W32_SYSTEM */
1105 
1106 	assuan_set_assuan_log_prefix (PACKAGE);
1107 	assuan_set_assuan_log_stream (common_get_log_stream ());
1108 
1109 #if defined(USE_GNUTLS)
1110 	if (gnutls_global_init () != GNUTLS_E_SUCCESS) {
1111 		common_log (LOG_FATAL, "Cannot initialize gnutls");
1112 	}
1113 #endif
1114 
1115 	if ((rv = pkcs11h_initialize ()) != CKR_OK) {
1116 		common_log (LOG_FATAL, "Cannot initialize PKCS#11: %s", pkcs11h_getMessage (rv));
1117 	}
1118 
1119 	pkcs11h_setLogLevel (global.config.verbose ? PKCS11H_LOG_DEBUG2 : PKCS11H_LOG_INFO);
1120 	pkcs11h_setLogHook (pkcs11_log_hook, NULL);
1121 	pkcs11h_setTokenPromptHook (pkcs11_token_prompt_hook, NULL);
1122 	pkcs11h_setPINPromptHook (pkcs11_pin_prompt_hook, NULL);
1123 	pkcs11h_setProtectedAuthentication (TRUE);
1124 	pkcs11h_setPINCachePeriod(global.config.pin_cache);
1125 
1126 	for (i=0;i<DCONFIG_MAX_PROVIDERS;i++) {
1127 		if (
1128 			global.config.providers[i].name != NULL &&
1129 			global.config.providers[i].library != NULL
1130 		) {
1131 			if (
1132 				(rv = pkcs11h_addProvider (
1133 					global.config.providers[i].name,
1134 					global.config.providers[i].library,
1135 					global.config.providers[i].allow_protected,
1136 					global.config.providers[i].private_mask,
1137 					PKCS11H_SLOTEVENT_METHOD_POLL,
1138 					0,
1139 					global.config.providers[i].cert_is_private
1140 				)) != CKR_OK
1141 			) {
1142 				common_log (LOG_WARNING, "Cannot add PKCS#11 provider '%s': %ld-'%s'", global.config.providers[i].name, rv, pkcs11h_getMessage (rv));
1143 			}
1144 			else {
1145 				have_at_least_one_provider = 1;
1146 			}
1147 		}
1148 	}
1149 
1150 	if (!have_at_least_one_provider) {
1151 		common_log (LOG_FATAL, "Could not load any provider");
1152 	}
1153 
1154 #if defined(HAVE_W32_SYSTEM)
1155 	command_handler (&global, -1);
1156 #else
1157 {
1158 	pthread_t accept_thread = 0;
1159 	int accept_socket = -1;
1160 
1161 	if (run_mode == RUN_MODE_DAEMON || run_mode == RUN_MODE_MULTI_SERVER) {
1162 		accept_socket = server_socket_create (&global);
1163 
1164 		server_socket_accept (&global, accept_socket, &accept_thread);
1165 	}
1166 
1167 	if (run_mode == RUN_MODE_DAEMON) {
1168 		/*
1169 		 * Emulate assuan behavior
1170 		 */
1171 		int fds[2];
1172 		char c;
1173 		if (pipe (fds)==-1) {
1174 			common_log (LOG_FATAL, "Could not create pipe");
1175 		}
1176 		close (0);
1177 		dup2 (fds[0], 0);
1178 		close (fds[0]);
1179 		while (read (0, &c, 1) == -1 && errno == EINTR);
1180 		close (fds[1]);
1181 	}
1182 	else {
1183 		command_handler (&global, -1);
1184 	}
1185 
1186 	common_log (LOG_DEBUG, "Terminating");
1187 
1188 	if (run_mode == RUN_MODE_DAEMON || run_mode == RUN_MODE_MULTI_SERVER) {
1189 		server_socket_accept_terminate (&global, accept_thread);
1190 		server_socket_close (&global, accept_socket);
1191 	}
1192 }
1193 #endif
1194 
1195 	pkcs11h_terminate ();
1196 
1197 #if defined(USE_GNUTLS)
1198 	gnutls_global_deinit ();
1199 #endif
1200 
1201 	dconfig_free (&global.config);
1202 
1203 	if (config_file != NULL) {
1204 		free (config_file);
1205 		config_file = NULL;
1206 	}
1207 
1208 	if (default_config_file != NULL) {
1209 		free (default_config_file);
1210 		default_config_file = NULL;
1211 	}
1212 
1213 	if (home_dir != NULL) {
1214 		free (home_dir);
1215 		home_dir = NULL;
1216 	}
1217 
1218 	if (fp_log != NULL) {
1219 		fclose (fp_log);
1220 		fp_log = NULL;
1221 	}
1222 
1223 	return 0;
1224 }
1225 
1226