1 /*
2  * Remote device access - debugging utility that allows to
3  * test smart card readers on remote hosts.
4  *
5  * Copyright (C) 2003, Olaf Kirch <okir@suse.de>
6  */
7 
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <sys/poll.h>
14 #include <sys/socket.h>
15 #include <arpa/inet.h>
16 #ifdef HAVE_GETOPT_H
17 #include <getopt.h>
18 #endif
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <pwd.h>
26 #include <grp.h>
27 #include <limits.h>
28 
29 #include <openct/path.h>
30 #include <openct/socket.h>
31 #include <openct/server.h>
32 #include <openct/logging.h>
33 #include "internal.h"
34 #include "ria.h"
35 
36 static int opt_foreground = 0;
37 static char *opt_config = NULL;
38 static const char *opt_device_port = ":6666";
39 static const char *opt_server_port = "proxy";
40 static const char *opt_chroot = NULL;
41 static const char *opt_user = NULL;
42 
43 static int get_ports(void);
44 static int run_server(int, char **);
45 static int run_client(int, char **);
46 static int list_devices(int, char **);
47 static void usage(int);
48 static void version(void);
49 
main(int argc,char ** argv)50 int main(int argc, char **argv)
51 {
52 	char *command;
53 	int c;
54 
55 	if (argc < 2)
56 		usage(1);
57 
58 	ct_log_destination("@stderr");
59 
60 	while ((c = getopt(argc, argv, "df:FR:U:v")) != -1) {
61 		switch (c) {
62 		case 'd':
63 			ct_config.debug++;
64 			break;
65 		case 'f':
66 			opt_config = optarg;
67 			break;
68 		case 'F':
69 			opt_foreground++;
70 			break;
71 		case 'R':
72 			opt_chroot = optarg;
73 			break;
74 		case 'U':
75 			opt_user = optarg;
76 			break;
77 		case 'v':
78 			version();
79 			break;
80 		default:
81 			usage(1);
82 		}
83 	}
84 
85 	if (ifd_config_parse(opt_config) < 0)
86 		return 1;
87 
88 	if (optind >= argc)
89 		usage(1);
90 	command = argv[optind++];
91 
92 	if (get_ports() < 0)
93 		return 1;
94 
95 	if (!strcmp(command, "server")) {
96 		run_server(argc - optind, argv + optind);
97 	} else if (!strcmp(command, "export")) {
98 		return run_client(argc - optind, argv + optind);
99 	} else if (!strcmp(command, "list")) {
100 		list_devices(argc - optind, argv + optind);
101 	} else if (!strcmp(command, "version")) {
102 		version();
103 	} else {
104 		ct_error("Unknown command `%s'\n", command);
105 		return 1;
106 	}
107 
108 	return 0;
109 }
110 
enter_jail(void)111 static void enter_jail(void)
112 {
113 	struct passwd *pw = NULL;
114 
115 	if (opt_chroot && !opt_user)
116 		opt_user = "nobody";
117 	if (opt_user) {
118 		if (!(pw = getpwnam(opt_user))) {
119 			ct_error("Unknown user %s\n", opt_user);
120 			exit(1);
121 		}
122 		endpwent();
123 	}
124 
125 	if (opt_chroot) {
126 		if (chdir("/") < 0 || chroot(opt_chroot) < 0) {
127 			ct_error("chroot(%s) failed: %m", opt_chroot);
128 			exit(1);
129 		}
130 	}
131 
132 	if (pw) {
133 		if (setgroups(0, NULL) < 0
134 		    || setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
135 			ct_error("Failed to drop privileges: %m");
136 			exit(1);
137 		}
138 	}
139 }
140 
background_process(void)141 static void background_process(void)
142 {
143 	int fd;
144 
145 	if (daemon(0, 0) < 0) {
146 		ct_error("failed to background process: %m");
147 		exit(1);
148 	}
149 
150 	if ((fd = open("/dev/null", O_RDWR)) >= 0) {
151 		dup2(fd, 0);
152 		dup2(fd, 1);
153 		dup2(fd, 2);
154 		if (fd > 2)
155 			close(fd);
156 	}
157 
158 	ct_log_destination("@syslog");
159 	setsid();
160 }
161 
get_ports(void)162 static int get_ports(void)
163 {
164 	char *address;
165 	int rc;
166 
167 	if ((rc = ifd_conf_get_string("ifdproxy.device-port", &address)) >= 0)
168 		opt_device_port = address;
169 	if ((rc = ifd_conf_get_string("ifdproxy.server-port", &address)) >= 0)
170 		opt_server_port = address;
171 	return 0;
172 }
173 
run_server(int argc,char ** argv)174 static int run_server(int argc, char **argv)
175 {
176 	int rc;
177 	char path[PATH_MAX];
178 
179 	if (!ct_format_path(path, PATH_MAX, opt_server_port)) {
180 		return -1;
181 	}
182 
183 	if (argc != 0)
184 		usage(1);
185 	if (ct_config.debug)
186 		ct_socket_reuseaddr(1);
187 
188 	if ((rc = ria_svc_listen(path, 1)) < 0) {
189 		ct_error("Cannot bind to server port \"%s\": %s\n",
190 			 path, ct_strerror(rc));
191 		return rc;
192 	}
193 	if ((rc = ria_svc_listen(opt_device_port, 0)) < 0) {
194 		ct_error("Cannot bind to device port \"%s\": %s\n",
195 			 opt_device_port, ct_strerror(rc));
196 		return rc;
197 	}
198 
199 	enter_jail();
200 	if (!opt_foreground)
201 		background_process();
202 
203 	ct_mainloop();
204 	return 0;
205 }
206 
run_client(int argc,char ** argv)207 static int run_client(int argc, char **argv)
208 {
209 	const char *name, *device, *address;
210 	ria_client_t *ria;
211 	int rc;
212 
213 	/* Initialize IFD library */
214 	if (ifd_init())
215 		return 1;
216 
217 	if (argc != 2 && argc != 3)
218 		usage(1);
219 	name = argv[0];
220 	device = argv[1];
221 	address = argc == 3 ? argv[2] : opt_device_port;
222 
223 	ria = ria_export_device(address, device);
224 
225 	ifd_debug(1, "About to register device as \"%s\"", name);
226 	if ((rc = ria_register_device(ria, name)) < 0) {
227 		ct_error("Unable to register device: %s\n", ct_strerror(rc));
228 		exit(1);
229 	}
230 
231 	enter_jail();
232 	if (!opt_foreground)
233 		background_process();
234 
235 	ct_mainloop();
236 	return 0;
237 }
238 
list_devices(int argc,char ** argv)239 static int list_devices(int argc, char **argv)
240 {
241 	unsigned char buffer[8192];
242 	ria_device_t *info;
243 	ria_client_t *clnt;
244 	unsigned int n, count;
245 	int rc;
246 
247 	if (argc == 1)
248 		opt_server_port = argv[0];
249 	else if (argc > 1)
250 		usage(1);
251 
252 	if (!(clnt = ria_connect(opt_server_port)))
253 		exit(1);
254 	rc = ria_command(clnt, RIA_MGR_LIST, NULL, 0, buffer, sizeof(buffer),
255 			 -1);
256 	if (rc < 0) {
257 		ct_error("Failed to list exported devices: %s",
258 			 ct_strerror(rc));
259 		ria_free(clnt);
260 		return 1;
261 	}
262 
263 	count = rc / sizeof(ria_device_t);
264 	if (count == 0) {
265 		printf("No exported devices\n");
266 		ria_free(clnt);
267 		return 0;
268 	}
269 
270 	printf("Exported devices\n");
271 	for (info = (ria_device_t *) buffer, n = 0; n < count; info++, n++) {
272 		printf("  %-16s %-30s %s\n",
273 		       info->handle, info->address, info->name);
274 	}
275 
276 	ria_free(clnt);
277 	return 0;
278 }
279 
version(void)280 static void version(void)
281 {
282 	fprintf(stderr, "OpenCT " VERSION "\n");
283 	exit(0);
284 }
285 
usage(int exval)286 static void usage(int exval)
287 {
288 	fprintf(exval ? stderr : stdout,
289 		"Usage:\n"
290 		"ifdproxy server [-dF]\n"
291 		"ifdproxy export [-dF] name device address\n"
292 		"ifdproxy list [-dF] address\n" "ifdproxy version\n");
293 	exit(exval);
294 }
295