]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/openbsm/bin/auditdistd/proto.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / openbsm / bin / auditdistd / proto.c
1 /*-
2  * Copyright (c) 2009-2010 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Pawel Jakub Dawidek under sponsorship from
6  * the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/proto.c#1 $
30  */
31
32 #include <sys/types.h>
33 #include <sys/queue.h>
34 #include <sys/socket.h>
35
36 #include <errno.h>
37 #include <stdint.h>
38 #include <string.h>
39 #include <strings.h>
40
41 #include "pjdlog.h"
42 #include "proto.h"
43 #include "proto_impl.h"
44
45 #define PROTO_CONN_MAGIC        0x907041c
46 struct proto_conn {
47         int              pc_magic;
48         struct proto    *pc_proto;
49         void            *pc_ctx;
50         int              pc_side;
51 #define PROTO_SIDE_CLIENT               0
52 #define PROTO_SIDE_SERVER_LISTEN        1
53 #define PROTO_SIDE_SERVER_WORK          2
54 };
55
56 static TAILQ_HEAD(, proto) protos = TAILQ_HEAD_INITIALIZER(protos);
57
58 void
59 proto_register(struct proto *proto, bool isdefault)
60 {
61         static bool seen_default = false;
62
63         if (!isdefault)
64                 TAILQ_INSERT_HEAD(&protos, proto, prt_next);
65         else {
66                 PJDLOG_ASSERT(!seen_default);
67                 seen_default = true;
68                 TAILQ_INSERT_TAIL(&protos, proto, prt_next);
69         }
70 }
71
72 static struct proto_conn *
73 proto_alloc(struct proto *proto, int side)
74 {
75         struct proto_conn *conn;
76
77         PJDLOG_ASSERT(proto != NULL);
78         PJDLOG_ASSERT(side == PROTO_SIDE_CLIENT ||
79             side == PROTO_SIDE_SERVER_LISTEN ||
80             side == PROTO_SIDE_SERVER_WORK);
81
82         conn = malloc(sizeof(*conn));
83         if (conn != NULL) {
84                 conn->pc_proto = proto;
85                 conn->pc_side = side;
86                 conn->pc_magic = PROTO_CONN_MAGIC;
87         }
88         return (conn);
89 }
90
91 static void
92 proto_free(struct proto_conn *conn)
93 {
94
95         PJDLOG_ASSERT(conn != NULL);
96         PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
97         PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_CLIENT ||
98             conn->pc_side == PROTO_SIDE_SERVER_LISTEN ||
99             conn->pc_side == PROTO_SIDE_SERVER_WORK);
100         PJDLOG_ASSERT(conn->pc_proto != NULL);
101
102         bzero(conn, sizeof(*conn));
103         free(conn);
104 }
105
106 static int
107 proto_common_setup(const char *srcaddr, const char *dstaddr, int timeout,
108     int side, struct proto_conn **connp)
109 {
110         struct proto *proto;
111         struct proto_conn *conn;
112         void *ctx;
113         int ret;
114
115         PJDLOG_ASSERT(side == PROTO_SIDE_CLIENT ||
116             side == PROTO_SIDE_SERVER_LISTEN);
117
118         TAILQ_FOREACH(proto, &protos, prt_next) {
119                 if (side == PROTO_SIDE_CLIENT) {
120                         if (proto->prt_connect == NULL) {
121                                 ret = -1;
122                         } else {
123                                 ret = proto->prt_connect(srcaddr, dstaddr,
124                                     timeout, &ctx);
125                         }
126                 } else /* if (side == PROTO_SIDE_SERVER_LISTEN) */ {
127                         if (proto->prt_server == NULL)
128                                 ret = -1;
129                         else
130                                 ret = proto->prt_server(dstaddr, &ctx);
131                 }
132                 /*
133                  * ret == 0  - success
134                  * ret == -1 - dstaddr is not for this protocol
135                  * ret > 0   - right protocol, but an error occured
136                  */
137                 if (ret >= 0)
138                         break;
139         }
140         if (proto == NULL) {
141                 /* Unrecognized address. */
142                 errno = EINVAL;
143                 return (-1);
144         }
145         if (ret > 0) {
146                 /* An error occured. */
147                 errno = ret;
148                 return (-1);
149         }
150         conn = proto_alloc(proto, side);
151         if (conn == NULL) {
152                 if (proto->prt_close != NULL)
153                         proto->prt_close(ctx);
154                 errno = ENOMEM;
155                 return (-1);
156         }
157         conn->pc_ctx = ctx;
158         *connp = conn;
159
160         return (0);
161 }
162
163 int
164 proto_connect(const char *srcaddr, const char *dstaddr, int timeout,
165     struct proto_conn **connp)
166 {
167
168         PJDLOG_ASSERT(srcaddr == NULL || srcaddr[0] != '\0');
169         PJDLOG_ASSERT(dstaddr != NULL);
170         PJDLOG_ASSERT(timeout >= -1);
171
172         return (proto_common_setup(srcaddr, dstaddr, timeout,
173             PROTO_SIDE_CLIENT, connp));
174 }
175
176 int
177 proto_connect_wait(struct proto_conn *conn, int timeout)
178 {
179         int error;
180
181         PJDLOG_ASSERT(conn != NULL);
182         PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
183         PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_CLIENT);
184         PJDLOG_ASSERT(conn->pc_proto != NULL);
185         PJDLOG_ASSERT(conn->pc_proto->prt_connect_wait != NULL);
186         PJDLOG_ASSERT(timeout >= 0);
187
188         error = conn->pc_proto->prt_connect_wait(conn->pc_ctx, timeout);
189         if (error != 0) {
190                 errno = error;
191                 return (-1);
192         }
193
194         return (0);
195 }
196
197 int
198 proto_server(const char *addr, struct proto_conn **connp)
199 {
200
201         PJDLOG_ASSERT(addr != NULL);
202
203         return (proto_common_setup(NULL, addr, -1, PROTO_SIDE_SERVER_LISTEN,
204             connp));
205 }
206
207 int
208 proto_accept(struct proto_conn *conn, struct proto_conn **newconnp)
209 {
210         struct proto_conn *newconn;
211         int error;
212
213         PJDLOG_ASSERT(conn != NULL);
214         PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
215         PJDLOG_ASSERT(conn->pc_side == PROTO_SIDE_SERVER_LISTEN);
216         PJDLOG_ASSERT(conn->pc_proto != NULL);
217         PJDLOG_ASSERT(conn->pc_proto->prt_accept != NULL);
218
219         newconn = proto_alloc(conn->pc_proto, PROTO_SIDE_SERVER_WORK);
220         if (newconn == NULL)
221                 return (-1);
222
223         error = conn->pc_proto->prt_accept(conn->pc_ctx, &newconn->pc_ctx);
224         if (error != 0) {
225                 proto_free(newconn);
226                 errno = error;
227                 return (-1);
228         }
229
230         *newconnp = newconn;
231
232         return (0);
233 }
234
235 int
236 proto_send(const struct proto_conn *conn, const void *data, size_t size)
237 {
238         int error;
239
240         PJDLOG_ASSERT(conn != NULL);
241         PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
242         PJDLOG_ASSERT(conn->pc_proto != NULL);
243         PJDLOG_ASSERT(conn->pc_proto->prt_send != NULL);
244
245         error = conn->pc_proto->prt_send(conn->pc_ctx, data, size, -1);
246         if (error != 0) {
247                 errno = error;
248                 return (-1);
249         }
250         return (0);
251 }
252
253 int
254 proto_recv(const struct proto_conn *conn, void *data, size_t size)
255 {
256         int error;
257
258         PJDLOG_ASSERT(conn != NULL);
259         PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
260         PJDLOG_ASSERT(conn->pc_proto != NULL);
261         PJDLOG_ASSERT(conn->pc_proto->prt_recv != NULL);
262
263         error = conn->pc_proto->prt_recv(conn->pc_ctx, data, size, NULL);
264         if (error != 0) {
265                 errno = error;
266                 return (-1);
267         }
268         return (0);
269 }
270
271 int
272 proto_connection_send(const struct proto_conn *conn, struct proto_conn *mconn)
273 {
274         const char *protoname;
275         int error, fd;
276
277         PJDLOG_ASSERT(conn != NULL);
278         PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
279         PJDLOG_ASSERT(conn->pc_proto != NULL);
280         PJDLOG_ASSERT(conn->pc_proto->prt_send != NULL);
281         PJDLOG_ASSERT(mconn != NULL);
282         PJDLOG_ASSERT(mconn->pc_magic == PROTO_CONN_MAGIC);
283         PJDLOG_ASSERT(mconn->pc_proto != NULL);
284         fd = proto_descriptor(mconn);
285         PJDLOG_ASSERT(fd >= 0);
286         protoname = mconn->pc_proto->prt_name;
287         PJDLOG_ASSERT(protoname != NULL);
288
289         error = conn->pc_proto->prt_send(conn->pc_ctx,
290             (const unsigned char *)protoname, strlen(protoname) + 1, fd);
291         proto_close(mconn);
292         if (error != 0) {
293                 errno = error;
294                 return (-1);
295         }
296         return (0);
297 }
298
299 int
300 proto_wrap(const char *protoname, bool client, int fd,
301     struct proto_conn **newconnp)
302 {
303         struct proto *proto;
304         struct proto_conn *newconn;
305         int error;
306
307         TAILQ_FOREACH(proto, &protos, prt_next) {
308                 if (strcmp(proto->prt_name, protoname) == 0)
309                         break;
310         }
311         if (proto == NULL) {
312                 errno = EINVAL;
313                 return (-1);
314         }
315
316         newconn = proto_alloc(proto,
317             client ? PROTO_SIDE_CLIENT : PROTO_SIDE_SERVER_WORK);
318         if (newconn == NULL)
319                 return (-1);
320         PJDLOG_ASSERT(newconn->pc_proto->prt_wrap != NULL);
321         error = newconn->pc_proto->prt_wrap(fd, client, &newconn->pc_ctx);
322         if (error != 0) {
323                 proto_free(newconn);
324                 errno = error;
325                 return (-1);
326         }
327
328         *newconnp = newconn;
329
330         return (0);
331 }
332
333 int
334 proto_connection_recv(const struct proto_conn *conn, bool client,
335     struct proto_conn **newconnp)
336 {
337         char protoname[128];
338         int error, fd;
339
340         PJDLOG_ASSERT(conn != NULL);
341         PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
342         PJDLOG_ASSERT(conn->pc_proto != NULL);
343         PJDLOG_ASSERT(conn->pc_proto->prt_recv != NULL);
344         PJDLOG_ASSERT(newconnp != NULL);
345
346         bzero(protoname, sizeof(protoname));
347
348         error = conn->pc_proto->prt_recv(conn->pc_ctx,
349             (unsigned char *)protoname, sizeof(protoname) - 1, &fd);
350         if (error != 0) {
351                 errno = error;
352                 return (-1);
353         }
354
355         PJDLOG_ASSERT(fd >= 0);
356
357         return (proto_wrap(protoname, client, fd, newconnp));
358 }
359
360 int
361 proto_descriptor(const struct proto_conn *conn)
362 {
363
364         PJDLOG_ASSERT(conn != NULL);
365         PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
366         PJDLOG_ASSERT(conn->pc_proto != NULL);
367         PJDLOG_ASSERT(conn->pc_proto->prt_descriptor != NULL);
368
369         return (conn->pc_proto->prt_descriptor(conn->pc_ctx));
370 }
371
372 bool
373 proto_address_match(const struct proto_conn *conn, const char *addr)
374 {
375
376         PJDLOG_ASSERT(conn != NULL);
377         PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
378         PJDLOG_ASSERT(conn->pc_proto != NULL);
379         PJDLOG_ASSERT(conn->pc_proto->prt_address_match != NULL);
380
381         return (conn->pc_proto->prt_address_match(conn->pc_ctx, addr));
382 }
383
384 void
385 proto_local_address(const struct proto_conn *conn, char *addr, size_t size)
386 {
387
388         PJDLOG_ASSERT(conn != NULL);
389         PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
390         PJDLOG_ASSERT(conn->pc_proto != NULL);
391         PJDLOG_ASSERT(conn->pc_proto->prt_local_address != NULL);
392
393         conn->pc_proto->prt_local_address(conn->pc_ctx, addr, size);
394 }
395
396 void
397 proto_remote_address(const struct proto_conn *conn, char *addr, size_t size)
398 {
399
400         PJDLOG_ASSERT(conn != NULL);
401         PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
402         PJDLOG_ASSERT(conn->pc_proto != NULL);
403         PJDLOG_ASSERT(conn->pc_proto->prt_remote_address != NULL);
404
405         conn->pc_proto->prt_remote_address(conn->pc_ctx, addr, size);
406 }
407
408 int
409 proto_timeout(const struct proto_conn *conn, int timeout)
410 {
411         struct timeval tv;
412         int fd;
413
414         PJDLOG_ASSERT(conn != NULL);
415         PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
416         PJDLOG_ASSERT(conn->pc_proto != NULL);
417
418         fd = proto_descriptor(conn);
419         if (fd < 0)
420                 return (-1);
421
422         tv.tv_sec = timeout;
423         tv.tv_usec = 0;
424         if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0)
425                 return (-1);
426         if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
427                 return (-1);
428
429         return (0);
430 }
431
432 void
433 proto_close(struct proto_conn *conn)
434 {
435
436         PJDLOG_ASSERT(conn != NULL);
437         PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
438         PJDLOG_ASSERT(conn->pc_proto != NULL);
439         PJDLOG_ASSERT(conn->pc_proto->prt_close != NULL);
440
441         conn->pc_proto->prt_close(conn->pc_ctx);
442         proto_free(conn);
443 }
444
445 int
446 proto_exec(int argc, char *argv[])
447 {
448         struct proto *proto;
449         int error;
450
451         if (argc == 0) {
452                 errno = EINVAL;
453                 return (-1);
454         }
455         TAILQ_FOREACH(proto, &protos, prt_next) {
456                 if (strcmp(proto->prt_name, argv[0]) == 0)
457                         break;
458         }
459         if (proto == NULL) {
460                 errno = EINVAL;
461                 return (-1);
462         }
463         if (proto->prt_exec == NULL) {
464                 errno = EOPNOTSUPP;
465                 return (-1);
466         }
467         error = proto->prt_exec(argc, argv);
468         if (error != 0) {
469                 errno = error;
470                 return (-1);
471         }
472         /* NOTREACHED */
473         return (0);
474 }
475
476 struct proto_nvpair {
477         char    *pnv_name;
478         char    *pnv_value;
479         TAILQ_ENTRY(proto_nvpair) pnv_next;
480 };
481
482 static TAILQ_HEAD(, proto_nvpair) proto_nvpairs =
483     TAILQ_HEAD_INITIALIZER(proto_nvpairs);
484
485 int
486 proto_set(const char *name, const char *value)
487 {
488         struct proto_nvpair *pnv;
489
490         TAILQ_FOREACH(pnv, &proto_nvpairs, pnv_next) {
491                 if (strcmp(pnv->pnv_name, name) == 0)
492                         break;
493         }
494         if (pnv != NULL) {
495                 TAILQ_REMOVE(&proto_nvpairs, pnv, pnv_next);
496                 free(pnv->pnv_value);
497         } else {
498                 pnv = malloc(sizeof(*pnv));
499                 if (pnv == NULL)
500                         return (-1);
501                 pnv->pnv_name = strdup(name);
502                 if (pnv->pnv_name == NULL) {
503                         free(pnv);
504                         return (-1);
505                 }
506         }
507         pnv->pnv_value = strdup(value);
508         if (pnv->pnv_value == NULL) {
509                 free(pnv->pnv_name);
510                 free(pnv);
511                 return (-1);
512         }
513         TAILQ_INSERT_TAIL(&proto_nvpairs, pnv, pnv_next);
514         return (0);
515 }
516
517 const char *
518 proto_get(const char *name)
519 {
520         struct proto_nvpair *pnv;
521
522         TAILQ_FOREACH(pnv, &proto_nvpairs, pnv_next) {
523                 if (strcmp(pnv->pnv_name, name) == 0)
524                         break;
525         }
526         if (pnv != NULL)
527                 return (pnv->pnv_value);
528         return (NULL);
529 }