2 * Copyright (c) 2009-2010 The FreeBSD Foundation
5 * This software was developed by Pawel Jakub Dawidek under sponsorship from
6 * the FreeBSD Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
29 * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/proto.c#1 $
32 #include <sys/types.h>
33 #include <sys/queue.h>
34 #include <sys/socket.h>
43 #include "proto_impl.h"
45 #define PROTO_CONN_MAGIC 0x907041c
48 struct proto *pc_proto;
51 #define PROTO_SIDE_CLIENT 0
52 #define PROTO_SIDE_SERVER_LISTEN 1
53 #define PROTO_SIDE_SERVER_WORK 2
56 static TAILQ_HEAD(, proto) protos = TAILQ_HEAD_INITIALIZER(protos);
59 proto_register(struct proto *proto, bool isdefault)
61 static bool seen_default = false;
64 TAILQ_INSERT_HEAD(&protos, proto, prt_next);
66 PJDLOG_ASSERT(!seen_default);
68 TAILQ_INSERT_TAIL(&protos, proto, prt_next);
72 static struct proto_conn *
73 proto_alloc(struct proto *proto, int side)
75 struct proto_conn *conn;
77 PJDLOG_ASSERT(proto != NULL);
78 PJDLOG_ASSERT(side == PROTO_SIDE_CLIENT ||
79 side == PROTO_SIDE_SERVER_LISTEN ||
80 side == PROTO_SIDE_SERVER_WORK);
82 conn = malloc(sizeof(*conn));
84 conn->pc_proto = proto;
86 conn->pc_magic = PROTO_CONN_MAGIC;
92 proto_free(struct proto_conn *conn)
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);
102 bzero(conn, sizeof(*conn));
107 proto_common_setup(const char *srcaddr, const char *dstaddr, int timeout,
108 int side, struct proto_conn **connp)
111 struct proto_conn *conn;
115 PJDLOG_ASSERT(side == PROTO_SIDE_CLIENT ||
116 side == PROTO_SIDE_SERVER_LISTEN);
118 TAILQ_FOREACH(proto, &protos, prt_next) {
119 if (side == PROTO_SIDE_CLIENT) {
120 if (proto->prt_connect == NULL) {
123 ret = proto->prt_connect(srcaddr, dstaddr,
126 } else /* if (side == PROTO_SIDE_SERVER_LISTEN) */ {
127 if (proto->prt_server == NULL)
130 ret = proto->prt_server(dstaddr, &ctx);
134 * ret == -1 - dstaddr is not for this protocol
135 * ret > 0 - right protocol, but an error occured
141 /* Unrecognized address. */
146 /* An error occured. */
150 conn = proto_alloc(proto, side);
152 if (proto->prt_close != NULL)
153 proto->prt_close(ctx);
164 proto_connect(const char *srcaddr, const char *dstaddr, int timeout,
165 struct proto_conn **connp)
168 PJDLOG_ASSERT(srcaddr == NULL || srcaddr[0] != '\0');
169 PJDLOG_ASSERT(dstaddr != NULL);
170 PJDLOG_ASSERT(timeout >= -1);
172 return (proto_common_setup(srcaddr, dstaddr, timeout,
173 PROTO_SIDE_CLIENT, connp));
177 proto_connect_wait(struct proto_conn *conn, int timeout)
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);
188 error = conn->pc_proto->prt_connect_wait(conn->pc_ctx, timeout);
198 proto_server(const char *addr, struct proto_conn **connp)
201 PJDLOG_ASSERT(addr != NULL);
203 return (proto_common_setup(NULL, addr, -1, PROTO_SIDE_SERVER_LISTEN,
208 proto_accept(struct proto_conn *conn, struct proto_conn **newconnp)
210 struct proto_conn *newconn;
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);
219 newconn = proto_alloc(conn->pc_proto, PROTO_SIDE_SERVER_WORK);
223 error = conn->pc_proto->prt_accept(conn->pc_ctx, &newconn->pc_ctx);
236 proto_send(const struct proto_conn *conn, const void *data, size_t size)
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);
245 error = conn->pc_proto->prt_send(conn->pc_ctx, data, size, -1);
254 proto_recv(const struct proto_conn *conn, void *data, size_t size)
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);
263 error = conn->pc_proto->prt_recv(conn->pc_ctx, data, size, NULL);
272 proto_connection_send(const struct proto_conn *conn, struct proto_conn *mconn)
274 const char *protoname;
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);
289 error = conn->pc_proto->prt_send(conn->pc_ctx,
290 (const unsigned char *)protoname, strlen(protoname) + 1, fd);
300 proto_wrap(const char *protoname, bool client, int fd,
301 struct proto_conn **newconnp)
304 struct proto_conn *newconn;
307 TAILQ_FOREACH(proto, &protos, prt_next) {
308 if (strcmp(proto->prt_name, protoname) == 0)
316 newconn = proto_alloc(proto,
317 client ? PROTO_SIDE_CLIENT : PROTO_SIDE_SERVER_WORK);
320 PJDLOG_ASSERT(newconn->pc_proto->prt_wrap != NULL);
321 error = newconn->pc_proto->prt_wrap(fd, client, &newconn->pc_ctx);
334 proto_connection_recv(const struct proto_conn *conn, bool client,
335 struct proto_conn **newconnp)
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);
346 bzero(protoname, sizeof(protoname));
348 error = conn->pc_proto->prt_recv(conn->pc_ctx,
349 (unsigned char *)protoname, sizeof(protoname) - 1, &fd);
355 PJDLOG_ASSERT(fd >= 0);
357 return (proto_wrap(protoname, client, fd, newconnp));
361 proto_descriptor(const struct proto_conn *conn)
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);
369 return (conn->pc_proto->prt_descriptor(conn->pc_ctx));
373 proto_address_match(const struct proto_conn *conn, const char *addr)
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);
381 return (conn->pc_proto->prt_address_match(conn->pc_ctx, addr));
385 proto_local_address(const struct proto_conn *conn, char *addr, size_t size)
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);
393 conn->pc_proto->prt_local_address(conn->pc_ctx, addr, size);
397 proto_remote_address(const struct proto_conn *conn, char *addr, size_t size)
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);
405 conn->pc_proto->prt_remote_address(conn->pc_ctx, addr, size);
409 proto_timeout(const struct proto_conn *conn, int timeout)
414 PJDLOG_ASSERT(conn != NULL);
415 PJDLOG_ASSERT(conn->pc_magic == PROTO_CONN_MAGIC);
416 PJDLOG_ASSERT(conn->pc_proto != NULL);
418 fd = proto_descriptor(conn);
424 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0)
426 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
433 proto_close(struct proto_conn *conn)
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);
441 conn->pc_proto->prt_close(conn->pc_ctx);
446 proto_exec(int argc, char *argv[])
455 TAILQ_FOREACH(proto, &protos, prt_next) {
456 if (strcmp(proto->prt_name, argv[0]) == 0)
463 if (proto->prt_exec == NULL) {
467 error = proto->prt_exec(argc, argv);
476 struct proto_nvpair {
479 TAILQ_ENTRY(proto_nvpair) pnv_next;
482 static TAILQ_HEAD(, proto_nvpair) proto_nvpairs =
483 TAILQ_HEAD_INITIALIZER(proto_nvpairs);
486 proto_set(const char *name, const char *value)
488 struct proto_nvpair *pnv;
490 TAILQ_FOREACH(pnv, &proto_nvpairs, pnv_next) {
491 if (strcmp(pnv->pnv_name, name) == 0)
495 TAILQ_REMOVE(&proto_nvpairs, pnv, pnv_next);
496 free(pnv->pnv_value);
498 pnv = malloc(sizeof(*pnv));
501 pnv->pnv_name = strdup(name);
502 if (pnv->pnv_name == NULL) {
507 pnv->pnv_value = strdup(value);
508 if (pnv->pnv_value == NULL) {
513 TAILQ_INSERT_TAIL(&proto_nvpairs, pnv, pnv_next);
518 proto_get(const char *name)
520 struct proto_nvpair *pnv;
522 TAILQ_FOREACH(pnv, &proto_nvpairs, pnv_next) {
523 if (strcmp(pnv->pnv_name, name) == 0)
527 return (pnv->pnv_value);