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