コード例 #1
0
    int
env_outfile( struct envelope *env )
{
    yastr	    headers;
    yastr	    tmp;

    headers = env->e_extra_headers;
    env->e_extra_headers = NULL;

#ifdef HAVE_LIBOPENDKIM
    if ( env->e_flags & ENV_FLAG_DKIMSIGN ) {
	tmp = env_dkim_sign( env );
	if ( headers != NULL ) {
	    tmp = yaslcatyasl( yaslcat( tmp, "\n" ), headers );
	    yaslfree( headers );
	}
	headers = tmp;
	env->e_flags ^= ENV_FLAG_DKIMSIGN;
    }
#endif /* HAVE_LIBOPENDKIM */

    if ( headers ) {
	env_dfile_copy( env, NULL, headers );
	yaslfree( headers );
    }

    if (( env->e_flags & ENV_FLAG_TFILE ) == 0 ) {
	if ( env_tfile( env ) != 0 ) {
	    return( 1 );
	}
    }

    if ( env_efile( env ) != 0 ) {
	return( 1 );
    }

    return( 0 );
}
コード例 #2
0
    yastr
env_dkim_sign( struct envelope *env )
{
    char	    df[ MAXPATHLEN + 1 ];
    DKIM_LIB	    *libhandle;
    unsigned int    flags;
    DKIM	    *dkim;
    DKIM_STAT	    result;
    yastr	    signature = NULL;
    yastr	    key = NULL;
    yastr	    tmp = NULL;
    yastr	    *split = NULL;
    size_t	    tok_count = 0;
    char	    buf[ 1024 * 1024 ];
    unsigned char   *dkim_header;
    SNET	    *snet;
    ssize_t	    chunk;

    sprintf( df, "%s/D%s", env->e_dir, env->e_id );

    if (( snet = snet_open( simta_dkim_key, O_RDONLY, 0,
	    1024 * 1024 )) == NULL ) {
	syslog( LOG_ERR, "Liberror: env_dkim_sign snet_open %s: %m",
		simta_dkim_key );
	return( NULL );
    }
    key = yaslempty();
    while (( chunk = snet_read( snet, buf, 1024 * 1024, NULL )) > 0 ) {
	key = yaslcatlen( key, buf, chunk );
    }
    snet_close( snet );

    if (( libhandle = dkim_init( NULL, NULL )) == NULL ) {
	syslog( LOG_ERR, "Liberror: env_dkim_sign dkim_init" );
	return( NULL );
    }

    /* Data is stored in UNIX format, so tell libopendkim to fix
     * CRLF issues.
     */
    flags = DKIM_LIBFLAGS_FIXCRLF;
    dkim_options( libhandle, DKIM_OP_SETOPT, DKIM_OPTS_FLAGS, &flags,
	    sizeof( flags ));

    /* Only sign the headers recommended by RFC 6376 */
    dkim_options( libhandle, DKIM_OP_SETOPT, DKIM_OPTS_SIGNHDRS,
	    dkim_should_signhdrs, sizeof( unsigned char ** ));

    if (( dkim = dkim_sign( libhandle, (unsigned char *)(env->e_id), NULL,
	    (unsigned char *)key, (unsigned char *)simta_dkim_selector,
	    (unsigned char *)simta_dkim_domain,
	    DKIM_CANON_RELAXED, DKIM_CANON_RELAXED, DKIM_SIGN_RSASHA256,
	    -1, &result )) == NULL ) {
	syslog( LOG_NOTICE, "Liberror: env_dkim_sign dkim_sign: %s",
		dkim_getresultstr( result ));
	goto error;
    }

    if (( snet = snet_open( df, O_RDONLY, 0, 1024 * 1024 )) == NULL ) {
	syslog( LOG_ERR, "Liberror: env_dkim_sign snet_open %s: %m",
		buf );
	goto error;
    }

    while (( chunk = snet_read( snet, buf, 1024 * 1024, NULL )) > 0 ) {
	if (( result = dkim_chunk( dkim, (unsigned char *)buf,
		chunk )) != 0 ) {
	    syslog( LOG_NOTICE, "Liberror: env_dkim_sign dkim_chunk: %s: %s",
		    dkim_getresultstr( result ),
		    dkim_geterror( dkim ));
	    snet_close( snet );
	    goto error;
	}
    }

    snet_close( snet );

    if (( result = dkim_chunk( dkim, NULL, 0 )) != 0 ) {
	syslog( LOG_NOTICE, "Liberror: env_dkim_sign dkim_chunk: %s: %s",
		dkim_getresultstr( result ),
		dkim_geterror( dkim ));
	goto error;
    }
    if (( result = dkim_eom( dkim, NULL )) != 0 ) {
	syslog( LOG_NOTICE, "Liberror: env_dkim_sign dkim_eom: %s: %s",
		dkim_getresultstr( result ),
		dkim_geterror( dkim ));
	goto error;
    }
    if (( result = dkim_getsighdr_d( dkim, 16, &dkim_header,
	    (size_t *)&chunk )) != 0 ) {
	syslog( LOG_NOTICE,
		"Liberror: env_dkim_sign dkim_getsighdr_d: %s: %s",
		dkim_getresultstr( result ),
		dkim_geterror( dkim ));
	goto error;
    }

    /* Get rid of carriage returns in libopendkim output */
    split = yaslsplitlen( (const char *)dkim_header,
	    strlen( (const char *)dkim_header ), "\r", 1, &tok_count );
    tmp = yasljoinyasl( split, tok_count, "", 0 );
    signature = yaslcatyasl( yaslauto( "DKIM-Signature: " ), tmp );

error:
    yaslfree( tmp );
    yaslfreesplitres( split, tok_count );
    yaslfree( key );
    dkim_free( dkim );
    dkim_close( libhandle );

    return( signature );
}
コード例 #3
0
    static yastr
spf_macro_expand( struct spf *s, const yastr domain, const yastr macro )
{
    int			urlescape, rtransform;
    long		dtransform, i, j;
    char		*p, *pp;
    char		delim;
    yastr		expanded, tmp, escaped;
    yastr		*split;
    size_t		tok_count;

    expanded = yaslempty( );
    escaped = yaslempty( );
    tmp = yaslempty( );

    for ( p = macro ; *p != '\0' ; p++ ) {
	if ( *p != '%' ) {
	    expanded = yaslcatlen( expanded, p, 1 );
	    continue;
	}
	p++;
	switch( *p ) {
	case '%':
	    expanded = yaslcat( expanded, "%" );
	    break;
	case '_':
	    expanded = yaslcat( expanded, "_" );
	    break;
	case '-':
	    expanded = yaslcat( expanded, "%20" );
	    break;
	case '{':
	    p++;
	    /* RFC 7208 7.3 Macro Processing Details
	     * Uppercase macros expand exactly as their lowercase equivalents,
	     * and are then URL escaped.
	     */
	    urlescape = isupper( *p );
	    switch( *p ) {
		case 'S':
		case 's':
		    yaslclear( tmp );
		    tmp = yaslcatprintf( tmp, "%s@%s", s->spf_localpart,
			    s->spf_domain );
		    break;
		case 'L':
		case 'l':
		    tmp = yaslcpy( tmp, s->spf_localpart );
		    break;
		case 'O':
		case 'o':
		    tmp = yaslcpy( tmp, s->spf_domain );
		    break;
		case 'D':
		case 'd':
		    tmp = yaslcpy( tmp, domain );
		    break;
		case 'I':
		case 'i':
		    if ( s->spf_sockaddr->sa_family == AF_INET ) {
			tmp = yaslgrowzero( tmp, INET_ADDRSTRLEN );
			if ( inet_ntop( s->spf_sockaddr->sa_family,
				&((struct sockaddr_in *)s->spf_sockaddr)->sin_addr,
				tmp, (socklen_t)yasllen( tmp )) == NULL ) {
			    goto error;
			}
			yaslupdatelen( tmp );
		    }
		    break;
		case 'P':
		case 'p':
		    /* This is overly complex and should not be used,
		     * so we're not going to implement it. */
		    tmp = yaslcpy( tmp, "unknown" );
		    break;
		case 'V':
		case 'v':
		    tmp = yaslcpy( tmp, ( s->spf_sockaddr->sa_family == AF_INET6 ) ?
			    "ip6" : "in-addr" );
		    break;
		case 'H':
		case 'h':
		    tmp = yaslcpy( tmp, s->spf_helo );
		    break;
		default:
		    syslog( LOG_WARNING,
			    "SPF %s [%s]: invalid macro-letter: %c",
			    s->spf_domain, domain, *p );
		    goto error;
	    }

	    if ( urlescape ) {
		/* RFC 7208 7.3 Macro Processing Details
		 * Uppercase macros expand exactly as their lowercase
		 * equivalents, and are then URL escaped. URL escaping MUST be
		 * performed for characters not in the "unreserved" set, which
		 * is defined in [RFC3986].
		 */
		yaslclear( escaped );
		for ( pp = tmp ; *pp != '\0' ; pp++ ) {
		    /* RFC 3986 2.3 Unreserved Characters
		     * Characters that are allowed in a URI but do not have a
		     * reserved purpose are called unreserved.  These include
		     * uppercase and lowercase letters, decimal digits, hyphen,
		     * period, underscore, and tilde.
		     */
		    if ( isalnum( *pp ) || *pp == '-' || *pp == '.' ||
			    *pp == '_' || *pp == '~' ) {
			escaped = yaslcatlen( escaped, pp, 1 );
		    } else {
			/* Reserved */
			escaped = yaslcatprintf( escaped, "%%%X", *pp );
		    }
		}
		tmp = yaslcpylen( tmp, escaped, yasllen( escaped ));
	    }
	    p++;

	    /* Check for transformers */
	    dtransform = 0;
	    rtransform = 0;
	    if ( isdigit( *p )) {
		dtransform = strtoul( p, &pp, 10 );
		p = pp;
	    }

	    if ( *p == 'r' ) {
		rtransform = 1;
		p++;
	    }

	    delim = '\0';
	    for ( pp = p ; *pp != '\0' ; pp++ ) {
		if ( *pp == '}' ) {
		    break;
		}
		switch( *pp ) {
		/* RFC 7208 7.1 Formal Specification
		 * delimiter        = "." / "-" / "+" / "," / "/" / "_" / "="
		 */
		case '.':
		case '-':
		case '+':
		case ',':
		case '/':
		case '_':
		case '=':
			if ( delim != '\0' ) {
			    tmp = yaslmapchars( tmp, pp, &delim, 1 );
			} else {
			    delim = *pp;
			}
		    break;
		default:
		    syslog( LOG_WARNING, "SPF %s [%s]: invalid delimiter: %c",
			    s->spf_domain, domain, *pp );
		    goto error;
		}
	    }

	    if (( rtransform == 1 ) || ( dtransform > 0 ) ||
		    ( delim != '\0' )) {
		if ( delim == '\0' ) {
		    delim = '.';
		}
		split = yaslsplitlen( tmp, yasllen( tmp ), &delim, 1,
		    &tok_count );
		yaslclear( tmp );
		if ( rtransform == 1 ) {
		    if (( dtransform > 0 ) && ( tok_count > dtransform )) {
			j = tok_count - dtransform;
		    } else {
			j = 0;
		    }
		    for ( i = tok_count - 1 ; i >= j ; i-- ) {
			if ( yasllen( tmp ) > 0 ) {
			    tmp = yaslcat( tmp, "." );
			}
			tmp = yaslcatyasl( tmp, split [ i ] );
		    }
		} else {
		    if (( dtransform > 0 ) && (tok_count > dtransform )) {
			j = dtransform;
		    } else {
			j = tok_count;
		    }
		    for ( i = 0 ; i < j ; i++ ) {
			if ( yasllen( tmp ) > 0 ) {
			    tmp = yaslcat( tmp, "." );
			}
			tmp = yaslcatyasl( tmp, split[ i ] );
		    }
		}
		yaslfreesplitres( split, tok_count );
	    }
	    expanded = yaslcatyasl( expanded, tmp );
	    break;
	default:
	    syslog( LOG_WARNING, "SPF %s [%s]: invalid macro-expand: %s",
		    s->spf_domain, domain, p );
	    goto error;
	}
    }

    if ( yaslcmp( macro, expanded )) {
	simta_debuglog( 3, "SPF %s [%s]: expanded %s to %s",
		s->spf_domain, domain, macro, expanded );
    }

    yaslfree( tmp );
    yaslfree( escaped );
    return( expanded );

error:
    yaslfree( tmp );
    yaslfree( escaped );
    yaslfree( expanded );
    return( NULL );
}