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

📄 krb4-security.c

📁 开源备份软件源码 AMANDA, the Advanced Maryland Automatic Network Disk Archiver, is a backup system that a
💻 C
📖 第 1 页 / 共 3 页
字号:
    } else {	security = NULL;	body = pkt->body;    }    /*     * Get a checksum of the non-security parts of the body     */    cksum = krb4_cksum(body);    /*     * Now deal with the data we did (or didn't) parse above     */    switch (pkt->type) {    case P_REQ:	/*	 * Request packets have a ticket after the security tag	 * Get the ticket, make sure the checksum agrees with the	 * checksum of the request we sent.	 *	 * Must look like: SECURITY TICKET [ticket str]	 */	/* there must be some security info */	if (security == NULL)	    return (-1);	/* second word must be TICKET */	if ((tok = strtok(security, " ")) == NULL)	    return (-1);	if (strcmp(tok, "TICKET") != 0) {	    security_seterror(&kh->sech,		_("REQ SECURITY line parse error, expecting TICKET, got %s"), tok);	    return (-1);	}	/* the third word is the encoded ticket */	if ((tok = strtok(NULL, "")) == NULL)	    return (-1);	if (check_ticket(kh, pkt, tok, cksum) < 0)	    return (-1);	/* we're good to go */	break;    case P_REP:	/*	 * Reply packets check the mutual authenticator for this host.	 *	 * Must look like: SECURITY MUTUAL-AUTH [mutual auth str]	 */	if (security == NULL)	    return (-1);	if ((tok = strtok(security, " ")) == NULL)	    return (-1);	if (strcmp(tok, "MUTUAL-AUTH") != 0)  {	    security_seterror(&kh->sech,		"REP SECURITY line parse error, expecting MUTUAL-AUTH, got %s",		tok);	    return (-1);	}	if ((tok = strtok(NULL, "")) == NULL)	    return (-1);	if (check_mutual_auth(kh, tok) < 0)	    return (-1);    case P_ACK:    case P_NAK:    default:	/*	 * These packets have no security.  They should, but such	 * is life.  We can't change it without breaking compatibility.	 *	 * XXX Should we complain if argc > 0? (ie, some security info was	 * sent?)	 */	break;    }    /*     * If there is security info at the front of the packet, we need     * to shift the rest of the data up and nuke it.     */    if (body != pkt->body)	memmove(pkt->body, body, strlen(body) + 1);    return (0);}/* * Check the ticket in a REQ packet for authenticity */static intcheck_ticket(    struct krb4_handle *kh,    const pkt_t *	pkt,    const char *	ticket_str,    unsigned long	cksum){    char inst[INST_SZ];    KTEXT_ST ticket;    AUTH_DAT auth;    struct passwd *pwd;    char *user;    int rc;    (void)pkt;		/* Quiet unused parameter warning */    assert(kh != NULL);    assert(pkt != NULL);    assert(ticket_str != NULL);    ticket.length = (int)sizeof(ticket.dat);    astr2bin((unsigned char *)ticket_str, ticket.dat, &ticket.length);    assert(ticket.length > 0);    /* get a copy of the instance into writable memory */#if CLIENT_HOST_INSTANCE == HOSTNAME_INSTANCE    strncpy(inst, krb_get_phost(hostname), SIZEOF(inst) - 1);#else    strncpy(inst, CLIENT_HOST_INSTANCE, SIZEOF(inst) - 1);#endif    inst[SIZEOF(inst) - 1] = '\0';    /* get the checksum out of the ticket */    rc = krb_rd_req(&ticket, CLIENT_HOST_PRINCIPAL, inst,	kh->peer.sin6_addr.s_addr, &auth, CLIENT_HOST_KEY_FILE);    if (rc != 0) {	security_seterror(&kh->sech,	    _("krb_rd_req failed for %s: %s (%d)"), kh->hostname,	    error_message(rc), rc);	return (-1);    }    /* verify and save the checksum and session key */    if (auth.checksum != cksum) {	security_seterror(&kh->sech,	    _("krb4 checksum mismatch for %s (remote=%lu, local=%lu)"),	    kh->hostname, (long)auth.checksum, cksum);	return (-1);    }    kh->cksum = (unsigned long)cksum;    memcpy(kh->session_key, auth.session, SIZEOF(kh->session_key));    /*     * If CHECK_USERID is set, then we need to specifically     * check the userid we're forcing ourself to.  Otherwise,     * just check the login we're currently setuid to.     */#ifdef CHECK_USERID    if ((pwd = getpwnam(CLIENT_LOGIN)) == NULL)	error(_("error [getpwnam(%s) fails]"), CLIENT_LOGIN);#else    if ((pwd = getpwuid(getuid())) == NULL)	error(_("error  [getpwuid(%d) fails]"), getuid());#endif    /* save the username in case it's overwritten */    user = stralloc(pwd->pw_name);    /* check the klogin file */    if (kuserok(&auth, user)) {	security_seterror(&kh->sech,	    _("access as %s not allowed from %s.%s@%s"), user, auth.pname,	    auth.pinst, auth.prealm);	amfree(user);	return (-1);    }    amfree(user);    /* it's good */    return (0);}/* * Verify that the packet received is secure by verifying that it has * the same checksum as our request + 1. */static intcheck_mutual_auth(    struct krb4_handle *kh,    const char *	mutual_auth_str){    union mutual mutual;    int len;    assert(kh != NULL);    assert(mutual_auth_str != NULL);    assert(kh->inst[0] != '\0');    /* we had better have a checksum from a request we sent */    assert(kh->cksum != 0);    /* convert the encoded string into binary data */    len = (int)sizeof(mutual);    astr2bin((unsigned char *)mutual_auth_str, (unsigned char *)&mutual, &len);    /* unencrypt the string using the key in the ticket file */    host2key(kh->hostname, kh->inst, &kh->session_key);    decrypt_data(&mutual, (size_t)len, &kh->session_key);    mutual.cksum = (unsigned long)ntohl((guint32)mutual.cksum);    /* the data must be the same as our request cksum + 1 */    if (mutual.cksum != (kh->cksum + 1)) {	security_seterror(&kh->sech,	    _("krb4 checksum mismatch from %s (remote=%lu, local=%lu)"),	    kh->hostname, mutual.cksum, kh->cksum + 1);	return (-1);    }    return (0);}/* * Convert a pkt_t into a header string for our packet */static const char *kpkthdr2str(    const struct krb4_handle *	kh,    const pkt_t *		pkt){    static char retbuf[256];    assert(kh != NULL);    assert(pkt != NULL);    g_snprintf(retbuf, SIZEOF(retbuf), "Amanda %d.%d %s HANDLE %s SEQ %d\n",	VERSION_MAJOR, VERSION_MINOR, pkt_type2str(pkt->type),	kh->proto_handle, kh->sequence);    /* check for truncation.  If only we had asprintf()... */    assert(retbuf[strlen(retbuf) - 1] == '\n');    return (retbuf);}/* * Parses out the header line in 'str' into the pkt and handle * Returns negative on parse error. */static intstr2kpkthdr(    const char *origstr,    pkt_t *	pkt,    char *	handle,    size_t	handlesize,    int *	sequence){    char *str;    const char *tok;    assert(origstr != NULL);    assert(pkt != NULL);    str = stralloc(origstr);    /* "Amanda %d.%d <ACK,NAK,...> HANDLE %s SEQ %d\n" */    /* Read in "Amanda" */    if ((tok = strtok(str, " ")) == NULL || strcmp(tok, "Amanda") != 0)	goto parse_error;    /* nothing is done with the major/minor numbers currently */    if ((tok = strtok(NULL, " ")) == NULL || strchr(tok, '.') == NULL)	goto parse_error;    /* Read in the packet type */    if ((tok = strtok(NULL, " ")) == NULL)	goto parse_error;    pkt_init(pkt, pkt_str2type(tok), "");    if (pkt->type == (pktype_t)-1)	goto parse_error;    /* Read in "HANDLE" */    if ((tok = strtok(NULL, " ")) == NULL || strcmp(tok, "HANDLE") != 0)	goto parse_error;    /* parse the handle */    if ((tok = strtok(NULL, " ")) == NULL)	goto parse_error;    strncpy(handle, tok, handlesize - 1);    handle[handlesize - 1] = '\0';    /* Read in "SEQ" */    if ((tok = strtok(NULL, " ")) == NULL || strcmp(tok, "SEQ") != 0)	goto parse_error;    /* parse the sequence number */    if ((tok = strtok(NULL, "\n")) == NULL)	goto parse_error;    *sequence = atoi(tok);    /* Save the body, if any */    if ((tok = strtok(NULL, "")) != NULL)	pkt_cat(pkt, tok);    amfree(str);    return (0);parse_error:#if 0 /* XXX we have no way of passing this back up */    security_seterror(&kh->sech,	_("parse error in packet header : '%s'"), origstr);#endif    amfree(str);    return (-1);}static voidhost2key(    const char *hostname,    const char *inst,    des_cblock *key){    char realm[256];    CREDENTIALS cred;    strncpy(realm, krb_realmofhost((char *)hostname), SIZEOF(realm) - 1);    realm[SIZEOF(realm) - 1] = '\0';#if CLIENT_HOST_INSTANCE != HOSTNAME_INSTANCE    inst = CLIENT_HOST_INSTANCE#endif    krb_get_cred(CLIENT_HOST_PRINCIPAL, (char *)inst, realm, &cred);    memcpy(key, cred.session, SIZEOF(des_cblock));}/* * Convert a chunk of data into a string. */static const char *bin2astr(    const unsigned char *buf,    int			len){    static const char tohex[] = "0123456789ABCDEF";    static char *str = NULL;    char *q;    const unsigned char *p;    size_t slen;    int	i;    /*     * calculate output string len     * We quote everything, so each input byte == 3 output chars, plus     * two more for quotes     */    slen = ((size_t)len * 3) + 2;    /* allocate string and fill it in */    if (str != NULL)	amfree(str);    str = alloc(slen + 1);    p = buf;    q = str;    *q++ = '"';    for (i = 0; i < len; i++) {	*q++ = '$';	*q++ = tohex[(*p >> 4) & 0xF];	*q++ = tohex[*p & 0xF];	p++;    }    *q++ = '"';    *q = '\0';    /* make sure we didn't overrun our allocated buffer */    assert((size_t)(q - str) == slen);    return (str);}/* * Convert an encoded string into a block of data bytes */static voidastr2bin(    const unsigned char *astr,    unsigned char *	buf,    int *		lenp){    const unsigned char *p;    unsigned char *q;#define fromhex(h)	(isdigit((int)h) ? (h) - '0' : (h) - 'A' + 10)    /*     * Skip leading quote, if any     */    if (*astr == '"')	astr++;    /*     * Run through the string.  Anything starting with a $ is a three     * char representation of this byte.  Everything else is literal.     */    for (p = astr, q = buf; *p != '"' && *p != '\0'; ) {	if (*p != '$') {	    *q++ = *p++;	} else {	    *q++ = (fromhex(p[1]) << 4) + fromhex(p[2]);	     p += 3;	}	if ((int)(q - buf) >= *lenp)	    break;    }    *lenp = q - buf;}static unsigned longkrb4_cksum(    const char *str){    des_cblock seed;    memset(seed, 0, SIZEOF(seed));    /*     * The first arg is an unsigned char * in some krb4 implementations,     * and in others, it's a des_cblock *.  Just make it void here     * to shut them all up.     */    return (quad_cksum((void *)str, NULL, (long)strlen(str), 1, &seed));}static voidkrb4_getinst(    const char *hname,    char *	inst,    size_t	size){    /*     * Copy the first part of the hostname up to the first '.' into     * the buffer provided.  Leave room for a NULL.     */    while (size > 1 && *hname != '\0' && *hname != '.') {	*inst++ = isupper((int)*hname) ? tolower((int)*hname) : *hname;	hname++;	size--;    }    *inst = '\0';}static voidencrypt_data(    void *	data,    size_t	length,    des_cblock *key){    des_key_schedule sched;    /*     * First arg is des_cblock * in some places, and just des_cblock in     * others.  Since des_cblock is a char array, they are equivalent.     * Just cast it to void * to keep both compilers quiet.  typedefing     * arrays should be outlawed.     */    des_key_sched((void *)key, sched);    des_pcbc_encrypt(data, data, (long)length, sched, key, DES_ENCRYPT);}static voiddecrypt_data(    void *	data,    size_t	length,    des_cblock *key){    des_key_schedule sched;    des_key_sched((void *)key, sched);    des_pcbc_encrypt(data, data, (long)length, sched, key, DES_DECRYPT);}/* * like write(), but always writes out the entire buffer. */static intknet_write(    int		fd,    const void *vbuf,    size_t	size){    const char *buf = vbuf;	/* so we can do ptr arith */    ssize_t n;    while (size > 0) {	n = write(fd, buf, size);	if (n < 0)	    return (-1);	buf += n;	size -= n;    }    return (0);}/* * Like read(), but waits until the entire buffer has been filled. */static intknet_read(    int		fd,    void *	vbuf,    size_t	size,    int		timeout){    char *buf = vbuf;	/* ptr arith */    ssize_t n;    int neof = 0;    SELECT_ARG_TYPE readfds;    struct timeval tv;    while (size > 0) {	FD_ZERO(&readfds);	FD_SET(fd, &readfds);	tv.tv_sec = timeout;	tv.tv_usec = 0;	switch (select(fd + 1, &readfds, NULL, NULL, &tv)) {	case 0:	    errno = ETIMEDOUT;	    /* FALLTHROUGH */	case -1:	    return (-1);	case 1:	    assert(FD_ISSET(fd, &readfds));	    break;	default:	    assert(0);	    break;	}	n = read(fd, buf, size);	if (n < 0)	    return (-1);	/* we only tolerate so many eof's */	if (n == 0 && ++neof > 1024) {	    errno = EIO;	    return (-1);	}	buf += n;	size -= n;    }    return (0);}#if 0/* -------------------------- *//* debug routines */static voidprint_hex(    const char *		str,    const unsigned char *	buf,    size_t			len){    int i;    dbprintf("%s:", str);    for(i=0;i<len;i++) {	if(i%25 == 0)		dbprintf("\n");	dbprintf(" %02X", buf[i]);    }    dbprintf("\n");}static voidprint_ticket(    const char *str,    KTEXT	tktp){    dbprintf(_("%s: length %d chk %lX\n"), str, tktp->length, tktp->mbz);    print_hex(_("ticket data"), tktp->dat, tktp->length);    fflush(stdout);}static voidprint_auth(    AUTH_DAT *authp){    g_printf("\nAuth Data:\n");    g_printf("  Principal \"%s\" Instance \"%s\" Realm \"%s\"\n",	   authp->pname, authp->pinst, authp->prealm);    g_printf("  cksum %d life %d keylen %ld\n", authp->checksum,	   authp->life, SIZEOF(authp->session));    print_hex("session key", authp->session, SIZEOF(authp->session));    fflush(stdout);}static voidprint_credentials(    CREDENTIALS *credp){    g_printf("\nCredentials:\n");    g_printf("  service \"%s\" instance \"%s\" realm \"%s\" life %d kvno %d\n",	   credp->service, credp->instance, credp->realm, credp->lifetime,	   credp->kvno);    print_hex("session key", credp->session, SIZEOF(credp->session));    print_hex("ticket", credp->ticket_st.dat, credp->ticket_st.length);    fflush(stdout);}#endif

⌨️ 快捷键说明

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