📄 security-util.c
字号:
/* * Amanda, The Advanced Maryland Automatic Network Disk Archiver * Copyright (c) 1999 University of Maryland * All Rights Reserved. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of U.M. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. U.M. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Authors: the Amanda Development Team. Its members are listed in a * file named AUTHORS, in the root directory of this distribution. *//* * $Id: security-util.c,v 1.25 2006/07/22 12:04:47 martinea Exp $ * * sec-security.c - security and transport over sec or a sec-like command. * * XXX still need to check for initial keyword on connect so we can skip * over shell garbage and other stuff that sec might want to spew out. */#include "amanda.h"#include "util.h"#include "event.h"#include "packet.h"#include "queue.h"#include "security.h"#include "security-util.h"#include "stream.h"#include "version.h"#include "sockaddr-util.h"/* * Magic values for sec_conn->handle */#define H_TAKEN -1 /* sec_conn->tok was already read */#define H_EOF -2 /* this connection has been shut down *//* * This is a queue of open connections */struct connq_s connq = { TAILQ_HEAD_INITIALIZER(connq.tailq), 0};static int newhandle = 1;static int newevent = 1;/* * Local functions */static void recvpkt_callback(void *, void *, ssize_t);static void stream_read_callback(void *);static void stream_read_sync_callback(void *);static void sec_tcp_conn_read_cancel(struct tcp_conn *);static void sec_tcp_conn_read_callback(void *);/* * Authenticate a stream * Nothing needed for sec. The connection is authenticated by secd * on startup. */intsec_stream_auth( void * s){ (void)s; /* Quiet unused parameter warning */ return (0);}/* * Returns the stream id for this stream. This is just the local * port. */intsec_stream_id( void * s){ struct sec_stream *rs = s; assert(rs != NULL); return (rs->handle);}/* * Setup to handle new incoming connections */voidsec_accept( const security_driver_t *driver, char *(*conf_fn)(char *, void *), int in, int out, void (*fn)(security_handle_t *, pkt_t *), void *datap){ struct tcp_conn *rc; rc = sec_tcp_conn_get("unknown",0); rc->read = in; rc->write = out; rc->accept_fn = fn; rc->driver = driver; rc->conf_fn = conf_fn; rc->datap = datap; sec_tcp_conn_read(rc);}/* * frees a handle allocated by the above */voidsec_close( void * inst){ struct sec_handle *rh = inst; assert(rh != NULL); auth_debug(1, _("sec: closing handle to %s\n"), rh->hostname); if (rh->rs != NULL) { /* This may be null if we get here on an error */ stream_recvpkt_cancel(rh); security_stream_close(&rh->rs->secstr); } /* keep us from getting here again */ rh->sech.driver = NULL; amfree(rh->hostname); amfree(rh);}/* * Called when a sec connection is finished connecting and is ready * to be authenticated. */voidsec_connect_callback( void * cookie){ struct sec_handle *rh = cookie; event_release(rh->rs->ev_read); rh->rs->ev_read = NULL; event_release(rh->ev_timeout); rh->ev_timeout = NULL; (*rh->fn.connect)(rh->arg, &rh->sech, S_OK);}/* * Called if a connection times out before completion. */voidsec_connect_timeout( void * cookie){ struct sec_handle *rh = cookie; event_release(rh->rs->ev_read); rh->rs->ev_read = NULL; event_release(rh->ev_timeout); rh->ev_timeout = NULL; (*rh->fn.connect)(rh->arg, &rh->sech, S_TIMEOUT);}voidsec_close_connection_none( void *h, char *hostname){ h = h; hostname = hostname; return;}/* * Transmit a packet. */ssize_tstream_sendpkt( void * cookie, pkt_t * pkt){ char *buf; struct sec_handle *rh = cookie; size_t len; char *s; assert(rh != NULL); assert(pkt != NULL); auth_debug(1, _("sec: stream_sendpkt: enter\n")); if (rh->rc->prefix_packet) s = rh->rc->prefix_packet(rh, pkt); else s = ""; len = strlen(pkt->body) + strlen(s) + 2; buf = alloc(len); buf[0] = (char)pkt->type; strncpy(&buf[1], s, len - 1); strncpy(&buf[1 + strlen(s)], pkt->body, (len - strlen(s) - 1)); if (strlen(s) > 0) amfree(s); auth_debug(1, _("sec: stream_sendpkt: %s (%d) pkt_t (len %zu) contains:\n\n\"%s\"\n\n"), pkt_type2str(pkt->type), pkt->type, strlen(pkt->body), pkt->body); if (security_stream_write(&rh->rs->secstr, buf, len) < 0) { security_seterror(&rh->sech, security_stream_geterror(&rh->rs->secstr)); return (-1); } amfree(buf); return (0);}/* * Set up to receive a packet asyncronously, and call back when * it has been read. */voidstream_recvpkt( void * cookie, void (*fn)(void *, pkt_t *, security_status_t), void * arg, int timeout){ struct sec_handle *rh = cookie; assert(rh != NULL); auth_debug(1, _("sec: recvpkt registered for %s\n"), rh->hostname); /* * Reset any pending timeout on this handle */ if (rh->ev_timeout != NULL) event_release(rh->ev_timeout); /* * Negative timeouts mean no timeout */ if (timeout < 0) { rh->ev_timeout = NULL; } else { rh->ev_timeout = event_register((event_id_t)timeout, EV_TIME, stream_recvpkt_timeout, rh); } rh->fn.recvpkt = fn; rh->arg = arg; security_stream_read(&rh->rs->secstr, recvpkt_callback, rh);}/* * This is called when a handle times out before receiving a packet. */voidstream_recvpkt_timeout( void * cookie){ struct sec_handle *rh = cookie; assert(rh != NULL); auth_debug(1, _("sec: recvpkt timeout for %s\n"), rh->hostname); stream_recvpkt_cancel(rh); (*rh->fn.recvpkt)(rh->arg, NULL, S_TIMEOUT);}/* * Remove a async receive request from the queue */voidstream_recvpkt_cancel( void * cookie){ struct sec_handle *rh = cookie; auth_debug(1, _("sec: cancelling recvpkt for %s\n"), rh->hostname); assert(rh != NULL); security_stream_read_cancel(&rh->rs->secstr); if (rh->ev_timeout != NULL) { event_release(rh->ev_timeout); rh->ev_timeout = NULL; }}/* * Write a chunk of data to a stream. Blocks until completion. */inttcpm_stream_write( void * s, const void *buf, size_t size){ struct sec_stream *rs = s; assert(rs != NULL); assert(rs->rc != NULL); auth_debug(1, _("sec: stream_write: writing %zu bytes to %s:%d %d\n"), size, rs->rc->hostname, rs->handle, rs->rc->write); if (tcpm_send_token(rs->rc, rs->rc->write, rs->handle, &rs->rc->errmsg, buf, size)) { security_stream_seterror(&rs->secstr, rs->rc->errmsg); return (-1); } return (0);}/* * Submit a request to read some data. Calls back with the given * function and arg when completed. */voidtcpm_stream_read( void * s, void (*fn)(void *, void *, ssize_t), void * arg){ struct sec_stream *rs = s; assert(rs != NULL); /* * Only one read request can be active per stream. */ if (rs->ev_read == NULL) { rs->ev_read = event_register((event_id_t)rs->rc, EV_WAIT, stream_read_callback, rs); sec_tcp_conn_read(rs->rc); } rs->fn = fn; rs->arg = arg;}/* * Write a chunk of data to a stream. Blocks until completion. */ssize_ttcpm_stream_read_sync( void * s, void ** buf){ struct sec_stream *rs = s; assert(rs != NULL); /* * Only one read request can be active per stream. */ if (rs->ev_read != NULL) { return -1; } rs->ev_read = event_register((event_id_t)rs->rc, EV_WAIT, stream_read_sync_callback, rs); sec_tcp_conn_read(rs->rc); event_wait(rs->ev_read); *buf = rs->rc->pkt; return (rs->rc->pktlen);}/* * Cancel a previous stream read request. It's ok if we didn't have a read * scheduled. */voidtcpm_stream_read_cancel( void * s){ struct sec_stream *rs = s; assert(rs != NULL); if (rs->ev_read != NULL) { event_release(rs->ev_read); rs->ev_read = NULL; sec_tcp_conn_read_cancel(rs->rc); }}/* * Transmits a chunk of data over a rsh_handle, adding * the necessary headers to allow the remote end to decode it. */ssize_ttcpm_send_token( struct tcp_conn *rc, int fd, int handle, char ** errmsg, const void *buf, size_t len){ guint32 nethandle; guint32 netlength; struct iovec iov[3]; int nb_iov = 3; int rval; char *encbuf; ssize_t encsize; assert(SIZEOF(netlength) == 4); auth_debug(1, "tcpm_send_token: write %zd bytes to handle %d\n", len, handle); /* * Format is: * 32 bit length (network byte order) * 32 bit handle (network byte order) * data */ netlength = htonl(len); iov[0].iov_base = (void *)&netlength; iov[0].iov_len = SIZEOF(netlength); nethandle = htonl((guint32)handle); iov[1].iov_base = (void *)&nethandle; iov[1].iov_len = SIZEOF(nethandle); encbuf = (char *)buf; encsize = len; if(len == 0) { nb_iov = 2; } else { if (rc->driver->data_encrypt == NULL) { iov[2].iov_base = (void *)buf; iov[2].iov_len = len; } else { /* (the extra (void *) cast is to quiet type-punning warnings) */ rc->driver->data_encrypt(rc, (void *)buf, len, (void **)(void *)&encbuf, &encsize); iov[2].iov_base = (void *)encbuf; iov[2].iov_len = encsize; netlength = htonl(encsize); } nb_iov = 3; } rval = net_writev(fd, iov, nb_iov); if (len != 0 && rc->driver->data_encrypt != NULL && buf != encbuf) { amfree(encbuf); } if (rval < 0) { if (errmsg) *errmsg = newvstrallocf(*errmsg, _("write error to: %s"), strerror(errno)); return (-1); } return (0);}/* * return -1 on error * return 0 on EOF: *handle = H_EOF && *size = 0 if socket closed * return 0 on EOF: *handle = handle && *size = 0 if stream closed * return size : *handle = handle && *size = size for data read */ssize_ttcpm_recv_token( struct tcp_conn *rc, int fd, int * handle, char ** errmsg, char ** buf, ssize_t * size, int timeout){ unsigned int netint[2]; assert(SIZEOF(netint) == 8); switch (net_read(fd, &netint, SIZEOF(netint), timeout)) { case -1: if (errmsg) *errmsg = newvstrallocf(*errmsg, _("recv error: %s"), strerror(errno)); auth_debug(1, _("tcpm_recv_token: A return(-1)\n")); return (-1); case 0: *size = 0; *handle = H_EOF; *errmsg = newvstrallocf(*errmsg, _("SOCKET_EOF")); auth_debug(1, _("tcpm_recv_token: A return(0)\n")); return (0); default: break; } *size = (ssize_t)ntohl(netint[0]); *handle = (int)ntohl(netint[1]); /* amanda protocol packet can be above NETWORK_BLOCK_BYTES */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -