⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 krb4-security.c

📁 开源备份软件源码 AMANDA, the Advanced Maryland Automatic Network Disk Archiver, is a backup system that a
💻 C
📖 第 1 页 / 共 3 页
字号:
 * for our network fd. */static voidkrb4_recvpkt_cancel(    void *	cookie){    struct krb4_handle *kh = cookie;    assert(kh != NULL);    if (kh->fn != NULL) {	handleq_remove(kh);	kh->fn = NULL;	kh->arg = NULL;    }    if (kh->ev_timeout != NULL)	event_release(kh->ev_timeout);    kh->ev_timeout = NULL;    if (handleq.qlength == 0 && accept_fn == NULL &&	ev_netfd != NULL) {	event_release(ev_netfd);	ev_netfd = NULL;    }}/* * Create the server end of a stream.  For krb4, this means setup a tcp * socket for receiving a connection. */static void *krb4_stream_server(    void *	h){    struct krb4_handle *kh = h;    struct krb4_stream *ks;    assert(kh != NULL);    ks = alloc(SIZEOF(*ks));    security_streaminit(&ks->secstr, &krb4_security_driver);    ks->socket = stream_server(&ks->port, STREAM_BUFSIZE, STREAM_BUFSIZE, 1);    if (ks->socket < 0) {	security_seterror(&kh->sech,	    _("can't create server stream: %s"), strerror(errno));	amfree(ks);	return (NULL);    }    ks->fd = -1;    ks->krb4_handle = kh;    ks->ev_read = NULL;    return (ks);}/* * Accept an incoming connection on a stream_server socket */static intkrb4_stream_accept(    void *	s){    struct krb4_stream *ks = s;    struct krb4_handle *kh;    assert(ks != NULL);    kh = ks->krb4_handle;    assert(kh != NULL);    assert(ks->socket >= 0);    assert(ks->fd == -1);    ks->fd = stream_accept(ks->socket, 30, STREAM_BUFSIZE, STREAM_BUFSIZE);    if (ks->fd < 0) {	security_stream_seterror(&ks->secstr,	    _("can't accept new stream connection: %s"), strerror(errno));	return (-1);    }    return (0);}/* * Return a connected stream. */static void *krb4_stream_client(    void *	h,    int		id){    struct krb4_handle *kh = h;    struct krb4_stream *ks;    assert(kh != NULL);    ks = alloc(SIZEOF(*ks));    security_streaminit(&ks->secstr, &krb4_security_driver);    ks->fd = stream_client(kh->hostname, id, STREAM_BUFSIZE, STREAM_BUFSIZE,	&ks->port, 0);    if (ks->fd < 0) {	security_seterror(&kh->sech,	    _("can't connect stream to %s port %d: %s"), kh->hostname, id,	    strerror(errno));	amfree(ks);	return (NULL);    }    ks->socket = -1;	/* we're a client */    ks->krb4_handle = kh;    ks->ev_read = NULL;    return (ks);}/* * Close and unallocate resources for a stream. */static voidkrb4_stream_close(    void *	s){    struct krb4_stream *ks = s;    assert(ks != NULL);    if (ks->fd != -1)	aclose(ks->fd);    if (ks->socket != -1)	aclose(ks->socket);    krb4_stream_read_cancel(ks);    amfree(ks);}/* * Authenticate a stream * * XXX this whole thing assumes the size of struct timeval is consistent, * which is may not be!  We need to extract the network byte order data * into byte arrays and send those. */static intkrb4_stream_auth(    void *	s){    struct krb4_stream *ks = s;    struct krb4_handle *kh;    int fd;    struct timeval local, enc;    struct timezone tz;    assert(ks != NULL);    assert(ks->fd >= 0);    fd = ks->fd;    kh = ks->krb4_handle;    /* make sure we're open */    assert(fd >= 0);    /* make sure our timeval is what we're expecting, see above */    assert(SIZEOF(struct timeval) == 8);    /*     * Get the current time, put it in network byte order, encrypt it     * and present it to the other side.     */    gettimeofday(&local, &tz);    enc.tv_sec = (long)htonl((guint32)local.tv_sec);    enc.tv_usec = (long)htonl((guint32)local.tv_usec);    encrypt_data(&enc, SIZEOF(enc), &kh->session_key);    if (knet_write(fd, &enc, SIZEOF(enc)) < 0) {	security_stream_seterror(&ks->secstr,	    _("krb4 stream handshake write error: %s"), strerror(errno));	return (-1);    }    /*     * Read back the other side's presentation.  Increment the seconds     * and useconds by one.  Reencrypt, and present to the other side.     * Timeout in 10 seconds.     */    if (knet_read(fd, &enc, SIZEOF(enc), 60) < 0) {	security_stream_seterror(&ks->secstr,	    _("krb4 stream handshake read error: %s"), strerror(errno));	return (-1);    }    decrypt_data(&enc, SIZEOF(enc), &kh->session_key);    /* XXX do timestamp checking here */    enc.tv_sec = (long)htonl(ntohl((guint32)enc.tv_sec) + 1);    enc.tv_usec =(long)htonl(ntohl((guint32)enc.tv_usec) + 1);    encrypt_data(&enc, SIZEOF(enc), &kh->session_key);    if (knet_write(fd, &enc, SIZEOF(enc)) < 0) {	security_stream_seterror(&ks->secstr,	    _("krb4 stream handshake write error: %s"), strerror(errno));	return (-1);    }    /*     * Read back the other side's processing of our data.     * If they incremented it properly, then succeed.     * Timeout in 10 seconds.     */    if (knet_read(fd, &enc, SIZEOF(enc), 60) < 0) {	security_stream_seterror(&ks->secstr,	    _("krb4 stream handshake read error: %s"), strerror(errno));	return (-1);    }    decrypt_data(&enc, SIZEOF(enc), &kh->session_key);    if ((ntohl((guint32)enc.tv_sec)  == (uint32_t)(local.tv_sec + 1)) &&	(ntohl((guint32)enc.tv_usec) == (uint32_t)(local.tv_usec + 1)))	    return (0);    security_stream_seterror(&ks->secstr,	_("krb4 handshake failed: sent %ld,%ld - recv %ld,%ld"),	    (long)(local.tv_sec + 1), (long)(local.tv_usec + 1),	    (long)ntohl((guint32)enc.tv_sec),	    (long)ntohl((guint32)enc.tv_usec));    return (-1);}/* * Returns the stream id for this stream.  This is just the local * port. */static intkrb4_stream_id(    void *	s){    struct krb4_stream *ks = s;    assert(ks != NULL);    return (ks->port);}/* * Write a chunk of data to a stream.  Blocks until completion. */static intkrb4_stream_write(    void *	s,    const void *buf,    size_t	size){    struct krb4_stream *ks = s;    assert(ks != NULL);    if (knet_write(ks->fd, buf, size) < 0) {	security_stream_seterror(&ks->secstr,	    _("write error on stream %d: %s"), ks->fd, strerror(errno));	return (-1);    }    return (0);}/* * Submit a request to read some data.  Calls back with the given * function and arg when completed. */static voidkrb4_stream_read(    void *	s,    void	(*fn)(void *, void *, ssize_t),    void *	arg){    struct krb4_stream *ks = s;    assert(ks != NULL);    /*     * Only one read request can be active per stream.     */    if (ks->ev_read != NULL)	event_release(ks->ev_read);    ks->ev_read = event_register((event_id_t)ks->fd, EV_READFD,			stream_read_callback, ks);    ks->fn = fn;    ks->arg = arg;}/* * Write a chunk of data to a stream.  Blocks until completion. */static ssize_tkrb4_stream_read_sync(    void *	s,    void **	buf){    struct krb4_stream *ks = s;    (void)buf;	/* Quiet unused variable warning */    assert(ks != NULL);    if (ks->ev_read != NULL)	event_release(ks->ev_read);    ks->ev_read = event_register((event_id_t)ks->fd, EV_READFD,			stream_read_sync_callback, ks);    event_wait(ks->ev_read);    return((ssize_t)ks->len);}/* * Callback for krb4_stream_read_sync */static voidstream_read_sync_callback(    void *	arg){    struct krb4_stream *ks = arg;    ssize_t n;    assert(ks != NULL);    assert(ks->fd != -1);    /*     * Remove the event first, and then call the callback.     * We remove it first because we don't want to get in their     * way if they reschedule it.     */    krb4_stream_read_cancel(ks);    n = read(ks->fd, ks->databuf, sizeof(ks->databuf));    if (n < 0)	security_stream_seterror(&ks->secstr,	    strerror(errno));    ks->len = (int)n;}/* * Cancel a previous stream read request.  It's ok if we didn't have a read * scheduled. */static voidkrb4_stream_read_cancel(    void *	s){    struct krb4_stream *ks = s;    assert(ks != NULL);    if (ks->ev_read != NULL) {	event_release(ks->ev_read);	ks->ev_read = NULL;    }}/* * Callback for krb4_stream_read */static voidstream_read_callback(    void *	arg){    struct krb4_stream *ks = arg;    ssize_t n;    assert(ks != NULL);    assert(ks->fd != -1);    /*     * Remove the event first, and then call the callback.     * We remove it first because we don't want to get in their     * way if they reschedule it.     */    krb4_stream_read_cancel(ks);    n = read(ks->fd, ks->databuf, SIZEOF(ks->databuf));    if (n < 0)	security_stream_seterror(&ks->secstr,	    strerror(errno));    (*ks->fn)(ks->arg, ks->databuf, n);}/* * The callback for recvpkt() for the event handler * Determines if this packet is for this security handle, * and does the real callback if so. */static voidrecvpkt_callback(    void *	cookie){    char handle[32];    struct sockaddr_in6 peer;    pkt_t pkt;    int sequence;    struct krb4_handle *kh;    struct hostent *he;    void (*fn)(void *, pkt_t *, security_status_t);    void *arg;    (void)cookie;		/* Quiet unused parameter warning */    assert(cookie == NULL);    /*     * Find the handle that this packet is associated with.  We     * need to peek at the packet to see what is in it, but we     * want to save the actual reading for later.     */    dgram_zero(&netfd);    if (dgram_recv(&netfd, 0, &peer) < 0)	return;    if (str2kpkthdr(netfd.cur, &pkt, handle, SIZEOF(handle), &sequence) < 0)	return;    for (kh = handleq_first(); kh != NULL; kh = handleq_next(kh)) {	if (strcmp(kh->proto_handle, handle) == 0 &&	    cmp_sockaddr(&kh->peer, &peer, 0) == 0) {	    kh->sequence = sequence;	    /*	     * We need to cancel the recvpkt request before calling	     * the callback because the callback may reschedule us.	     */	    fn = kh->fn;	    arg = kh->arg;	    krb4_recvpkt_cancel(kh);	    if (recv_security_ok(kh, &pkt) < 0)		(*fn)(arg, NULL, S_ERROR);	    else		(*fn)(arg, &pkt, S_OK);	    return;	}    }    /*     * If we didn't find a handle, then check for a new incoming packet.     * If no accept handler was setup, then just return.     */    if (accept_fn == NULL)	return;    he = gethostbyaddr((void *)&peer.sin6_addr, SIZEOF(peer.sin6_addr), AF_INET6);    if (he == NULL)	return;    kh = alloc(SIZEOF(*kh));    security_handleinit(&kh->sech, &krb4_security_driver);    inithandle(kh, he, (int)peer.sin6_port, handle);    /*     * Check the security of the packet.  If it is bad, then pass NULL     * to the accept function instead of a packet.     */    if (recv_security_ok(kh, &pkt) < 0)	(*accept_fn)(&kh->sech, NULL);    else	(*accept_fn)(&kh->sech, &pkt);}/* * This is called when a handle times out before receiving a packet. */static voidrecvpkt_timeout(    void *	cookie){    struct krb4_handle *kh = cookie;    void (*fn)(void *, pkt_t *, security_status_t);    void *arg;    assert(kh != NULL);    assert(kh->ev_timeout != NULL);    fn = kh->fn;    arg = kh->arg;    krb4_recvpkt_cancel(kh);    (*fn)(arg, NULL, S_TIMEOUT);}/* * Add a ticket to the message */static intadd_ticket(    struct krb4_handle *kh,    const pkt_t *	pkt,    dgram_t *		msg){    char inst[INST_SZ];    KTEXT_ST ticket;    char *security;    int rc;    kh->cksum = (long)krb4_cksum(pkt->body);#if CLIENT_HOST_INSTANCE == HOSTNAME_INSTANCE    /*     * User requested that all instances be based on the target     * hostname.     */    strncpy(inst, kh->inst, SIZEOF(inst) - 1);#else    /*     * User requested a fixed instance.     */    strncpy(inst, CLIENT_HOST_INSTANCE, SIZEOF(inst) - 1);#endif    inst[SIZEOF(inst) - 1] = '\0';    /*     * Get a ticket with the user-defined service and instance,     * and using the checksum of the body of the request packet.     */    rc = krb_mk_req(&ticket, CLIENT_HOST_PRINCIPAL, inst, kh->realm,	kh->cksum);    if (rc == NO_TKT_FIL) {	/* It's been kdestroyed.  Get a new one and try again */	get_tgt();	rc = krb_mk_req(&ticket, CLIENT_HOST_PRINCIPAL, inst, kh->realm,	    kh->cksum);    }    if (rc != 0) {	security_seterror(&kh->sech,	    _("krb_mk_req failed: %s (%d)"), error_message(rc), rc);	return (-1);    }    /*     * We now have the ticket.  Put it into the packet, and send     * it.     */    security = vstralloc("SECURITY TICKET ",	bin2astr(ticket.dat, ticket.length), "\n", NULL);    dgram_cat(msg, security);    amfree(security);    return (0);}/* * Add the mutual authenticator.  This is the checksum from * the req, + 1 */static voidadd_mutual_auth(    struct krb4_handle *kh,    dgram_t *		msg){    union mutual mutual;    char *security;    assert(kh != NULL);    assert(msg != NULL);    assert(kh->cksum != 0);    assert(kh->session_key[0] != '\0');    memset(&mutual, 0, SIZEOF(mutual));    mutual.cksum = (unsigned long)htonl((guint32)kh->cksum + 1);    encrypt_data(&mutual, SIZEOF(mutual), &kh->session_key);    security = vstralloc("SECURITY MUTUAL-AUTH ",	bin2astr((unsigned char *)mutual.pad,			(int)sizeof(mutual.pad)), "\n", NULL);    dgram_cat(msg, security);    amfree(security);}/* * Check the security of a received packet.  Returns negative on error * or security violation and otherwise returns 0 and fills in the * passed packet. */static intrecv_security_ok(    struct krb4_handle *kh,    pkt_t *		pkt){    char *tok, *security, *body;    unsigned long cksum;    assert(kh != NULL);    assert(pkt != NULL);    /*     * Set this preemptively before we mangle the body.     */    security_seterror(&kh->sech,	_("bad %s SECURITY line from %s: '%s'"), pkt_type2str(pkt->type),	kh->hostname, pkt->body);    /*     * The first part of the body should be the security info.  Deal with it.     * We only need to do this on a few packet types.     *     * First, parse the SECURITY line in the packet, if it exists.     * Increment the cur pointer past it to the data section after     * parsing is finished.     */    if (strncmp(pkt->body, "SECURITY", SIZEOF("SECURITY") - 1) == 0) {	tok = strtok(pkt->body, " ");	assert(strcmp(tok, "SECURITY") == 0);	/* security info goes until the newline */	security = strtok(NULL, "\n");	body = strtok(NULL, "");	/*	 * If the body is f-ked, then try to recover.	 */	if (body == NULL) {	    if (security != NULL)		body = security + strlen(security) + 2;	    else		body = pkt->body;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -