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