source: trunk/src/ifd/ria-server.c @ 964

Revision 964, 7.7 KB checked in by aj, 5 years ago (diff)

indent changes only.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
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#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <unistd.h>
20#include <fcntl.h>
21#include <errno.h>
22
23#include <openct/socket.h>
24#include <openct/server.h>
25#include <openct/logging.h>
26#include <openct/ifd.h>
27#include "internal.h"
28#include "ria.h"
29
30typedef struct ria_peer {
31        struct ria_peer *next;
32        struct ria_peer *prev;
33        ct_socket_t *sock;
34        struct ria_peer *peer;
35        ria_device_t device;
36} ria_peer_t;
37
38static unsigned int dev_handle = 1;
39
40static ria_peer_t clients = { &clients, &clients };
41
42static int ria_svc_accept(ct_socket_t *);
43static int ria_svc_app_handler(ct_socket_t *, header_t *,
44                               ct_buf_t *, ct_buf_t *);
45static int ria_svc_dev_handler(ct_socket_t *, header_t *,
46                               ct_buf_t *, ct_buf_t *);
47static void ria_svc_app_close(ct_socket_t *);
48static void ria_svc_dev_close(ct_socket_t *);
49static ria_peer_t *ria_peer_new(ct_socket_t *);
50static void ria_peer_free(ria_peer_t *, int);
51static ria_peer_t *ria_find_device(const char *, size_t);
52static void ria_svc_link(ria_peer_t *);
53static void ria_svc_unlink(ria_peer_t *);
54
55int ria_svc_listen(const char *address, int trusted)
56{
57        ct_socket_t *sock;
58        int rc;
59
60        sock = ct_socket_new(1024);
61        if ((rc = ct_socket_listen(sock, address, 0666)) < 0) {
62                ct_error("Cannot bind to network address \"%s\"\n", address);
63                ct_socket_free(sock);
64                return rc;
65        }
66
67        sock->recv = ria_svc_accept;
68        sock->send = NULL;
69        if (trusted) {
70                sock->process = ria_svc_app_handler;
71                sock->close = ria_svc_app_close;
72        } else {
73                sock->process = ria_svc_dev_handler;
74                sock->close = ria_svc_dev_close;
75        }
76
77        ct_mainloop_add_socket(sock);
78        return 0;
79}
80
81static int ria_svc_accept(ct_socket_t * listener)
82{
83        ria_peer_t *clnt;
84        ct_socket_t *sock;
85        int rc;
86
87        if (!(sock = ct_socket_accept(listener)))
88                return 0;
89
90        clnt = ria_peer_new(sock);
91        rc = ct_socket_getpeername(sock,
92                                   clnt->device.address,
93                                   sizeof(clnt->device.address));
94        if (rc < 0) {
95                ria_peer_free(clnt, 0);
96                return rc;
97        }
98
99        ifd_debug(1, "New connection from %s", clnt->device.address);
100        sock->user_data = clnt;
101        sock->process = listener->process;
102        sock->close = listener->close;
103        return 0;
104}
105
106static void ria_svc_app_close(ct_socket_t * sock)
107{
108        ria_peer_t *clnt = (ria_peer_t *) sock->user_data;
109
110        ifd_debug(1, "Application on %s closed connection",
111                  clnt->device.address);
112        ria_peer_free((ria_peer_t *) sock->user_data, 0);
113}
114
115static void ria_svc_dev_close(ct_socket_t * sock)
116{
117        ria_peer_t *clnt = (ria_peer_t *) sock->user_data;
118
119        ifd_debug(1, "Device on %s closed connection", clnt->device.address);
120        ria_peer_free((ria_peer_t *) sock->user_data, 1);
121}
122
123/*
124 * Process commands from local clients (i.e. those allowed
125 * to claim a device).
126 */
127static int ria_svc_app_handler(ct_socket_t * sock, header_t * hdr,
128                               ct_buf_t * args, ct_buf_t * resp)
129{
130        unsigned char cmd;
131        ria_peer_t *clnt, *peer;
132        int rc;
133
134        clnt = (ria_peer_t *) sock->user_data;
135        ria_print_packet(sock, 2, "app >>", hdr, args);
136
137        if (ct_buf_get(args, &cmd, 1) < 0)
138                return IFD_ERROR_INVALID_MSG;
139
140        switch (cmd) {
141        case RIA_MGR_LIST:
142                peer = &clients;
143                ifd_debug(1, "%s requests a device listing",
144                          clnt->device.address);
145                while ((peer = peer->next) != &clients) {
146                        if (peer->device.name[0] != '\0')
147                                ct_buf_put(resp, &peer->device,
148                                           sizeof(peer->device));
149                }
150                return 0;
151
152        case RIA_MGR_INFO:
153                peer =
154                    ria_find_device((const char *)ct_buf_head(args),
155                                    ct_buf_avail(args));
156                if (peer == NULL)
157                        return IFD_ERROR_UNKNOWN_DEVICE;
158                ct_buf_put(resp, &peer->device, sizeof(peer->device));
159                return 0;
160
161        case RIA_MGR_CLAIM:
162                peer =
163                    ria_find_device((const char *)ct_buf_head(args),
164                                    ct_buf_avail(args));
165                if (peer == NULL)
166                        return IFD_ERROR_UNKNOWN_DEVICE;
167                if (peer->peer)
168                        return IFD_ERROR_DEVICE_BUSY;
169                ifd_debug(1, "%s claimed %s device %s/%s",
170                          clnt->device.address,
171                          peer->device.type,
172                          peer->device.address, peer->device.name);
173                ct_buf_put(resp, &peer->device, sizeof(peer->device));
174                clnt->peer = peer;
175                peer->peer = clnt;
176                return 0;
177        }
178
179        if (cmd < __RIA_PEER_CMD_BASE)
180                return IFD_ERROR_INVALID_CMD;
181
182        /* All subsequent commands require a device */
183        if ((peer = clnt->peer) == NULL)
184                return IFD_ERROR_NOT_CONNECTED;
185
186        /* Push back the command byte */
187        ct_buf_push(args, &cmd, 1);
188        rc = ct_socket_put_packet(peer->sock, hdr, args);
189
190        /* Tell the caller not to send a response */
191        hdr->xid = 0;
192        return rc;
193}
194
195/*
196 * Process commands from remote clients (i.e. those offering a device).
197 */
198static int ria_svc_dev_handler(ct_socket_t * sock, header_t * hdr,
199                               ct_buf_t * args, ct_buf_t * resp)
200{
201        unsigned char cmd;
202        ria_peer_t *clnt, *peer;
203        ria_device_t devinfo;
204        int rc;
205
206        clnt = (ria_peer_t *) sock->user_data;
207        ria_print_packet(sock, 2, "dev <<", hdr, args);
208
209        /* bounce response to peer right away */
210        if (hdr->dest)
211                goto bounce_to_peer;
212
213        if (ct_buf_get(args, &cmd, 1) < 0)
214                return IFD_ERROR_INVALID_MSG;
215
216        switch (cmd) {
217        case RIA_MGR_REGISTER:
218                if (clnt->device.name[0])
219                        return IFD_ERROR_INVALID_ARG;
220                if ((rc = ct_buf_get(args, &devinfo, sizeof(devinfo))) < 0)
221                        return IFD_ERROR_INVALID_ARG;
222                if (devinfo.type[0] == '\0')
223                        return IFD_ERROR_INVALID_ARG;
224                /* For security reasons, don't allow the handle counter
225                 * to wrap around. */
226                if (dev_handle == 0)
227                        return IFD_ERROR_GENERIC;
228
229                memcpy(&devinfo.address, clnt->device.address, RIA_NAME_MAX);
230                clnt->device = devinfo;
231                snprintf(clnt->device.handle, RIA_NAME_MAX,
232                         "%s%u", clnt->device.type, dev_handle++);
233                ifd_debug(1,
234                          "%s registered new %s device , handle '%s', name `%s'",
235                          clnt->device.address, clnt->device.type,
236                          clnt->device.handle, clnt->device.name);
237                return 0;
238        }
239
240        if (cmd < __RIA_PEER_CMD_BASE)
241                return IFD_ERROR_INVALID_CMD;
242
243        /* Push back the command byte */
244        ct_buf_push(args, &cmd, 1);
245
246      bounce_to_peer:
247        if ((peer = clnt->peer) == NULL)
248                return IFD_ERROR_NOT_CONNECTED;
249
250        rc = ct_socket_put_packet(peer->sock, hdr, args);
251
252        /* Tell the caller not to send a response */
253        hdr->xid = 0;
254        return rc;
255}
256
257static ria_peer_t *ria_peer_new(ct_socket_t * sock)
258{
259        ria_peer_t *clnt;
260
261        clnt = (ria_peer_t *) calloc(1, sizeof(ria_peer_t));
262        if (!clnt) {
263                ct_error("out of memory");
264                return NULL;
265        }
266        clnt->sock = sock;
267        ria_svc_link(clnt);
268
269        return clnt;
270}
271
272static void ria_peer_free(ria_peer_t * clnt, int detach_peer)
273{
274        ria_peer_t *peer;
275
276        if ((peer = clnt->peer) != NULL) {
277                if (detach_peer)
278                        shutdown(peer->sock->fd, SHUT_RD);
279                peer->peer = NULL;
280        }
281        if (clnt->device.name[0])
282                ifd_debug(1, "Removing device `%s' on %s",
283                          clnt->device.name, clnt->device.address);
284        ria_svc_unlink(clnt);
285        memset(clnt, 0, sizeof(*clnt));
286        free(clnt);
287}
288
289static void ria_svc_link(ria_peer_t * clnt)
290{
291        ria_peer_t *prev;
292
293        prev = clients.prev;
294        clnt->next = &clients;
295        clnt->prev = prev;
296        prev->next = clnt;
297        clients.prev = clnt;
298}
299
300static ria_peer_t *ria_find_device(const char *handle, size_t len)
301{
302        ria_peer_t *peer;
303
304        ifd_debug(2, "handle=%*.*s", (int)len, (int)len, handle);
305
306        if (len == 0 || len > RIA_NAME_MAX - 1)
307                return NULL;
308
309        peer = &clients;
310        while ((peer = peer->next) != &clients) {
311                if (!memcmp(peer->device.handle, handle, len)
312                    && peer->device.handle[len] == '\0')
313                        return peer;
314                if (!memcmp(peer->device.name, handle, len)
315                    && peer->device.name[len] == '\0')
316                        return peer;
317        }
318
319        return NULL;
320}
321
322static void ria_svc_unlink(ria_peer_t * clnt)
323{
324        ria_peer_t *prev, *next;
325
326        prev = clnt->prev;
327        next = clnt->next;
328        prev->next = next;
329        next->prev = prev;
330        clnt->prev = clnt->next = clnt;
331}
Note: See TracBrowser for help on using the repository browser.