Exemple #1
0
    int
command( int fd, SNET *pushersn )
{
    SNET				*snet;
    int					ac, i, zero = 0;
    char				**av, *line;
    struct timeval			tv;
    extern int				errno;
    double				rate;
    struct protoent			*proto;

    if (( proto = getprotobyname( "tcp" )) != NULL ) {
	if ( setsockopt( fd, proto->p_proto, TCP_NODELAY,
		&zero, sizeof( zero )) < 0 ) {
	    syslog( LOG_ERR, "setsockopt TCP_NODELAY: %m" );
	}
    }

    if (( snet = snet_attach( fd, 1024 * 1024 )) == NULL ) {
	syslog( LOG_ERR, "snet_attach: %m" );
	exit( 1 );
    }

    /* for debugging, TLS not required but still available. we
     * need to do the authlist look up here b/c it normally happens
     * in the starttls code which we may not even call. All the
     * f_cmds require an "al".
     */

    if ( tlsopt ) {
	commands = auth_commands;
	ncommands = sizeof( auth_commands ) / sizeof( auth_commands[ 0 ] );
	if (( al = authlist_find( "NOTLS" )) == NULL ) {
	    syslog( LOG_ERR, "No debugging access" );
	    snet_writef( snet, "%d No NOTLS access\r\n", 508 );
	    exit( 1 );
	}
    }

    /*
     * because of problems with legacy client protocol checks, we return a
     * list of capabilities on the same line as the banner. a multi-line
     * banner would be more in the SMTP-like vernacular, but the IIS & Java
     * legacy clients don't handle multi-line banner output gracefully.
     * 
     * 220 2 Collaborative Web Single Sign-On [ CAPA1 CAPA2 ... ]\r\n
     */
    banner( snet );

    tv = cosign_net_timeout;
    while (( line = snet_getline( snet, &tv )) != NULL ) {
	/* log everything we get to stdout if we're debugging */
	tv = cosign_net_timeout;
	if ( debug ) {
	    printf( "debug: %s\n", line );
	}
	if (( ac = argcargv( line, &av )) < 0 ) {
	    syslog( LOG_ERR, "argcargv: %m" );
	    break;
	}

	if ( ac == 0 ) {
	    snet_writef( snet, "%d Command unrecognized\r\n", 501 );
	    continue;
	}

	for ( i = 0; i < ncommands; i++ ) {
	    if ( strcasecmp( av[ 0 ], commands[ i ].c_name ) == 0 ) {
		break;
	    }
	}
	if ( i >= ncommands ) {
	    snet_writef( snet, "%d Command %s unregcognized\r\n",
		    500, av[ 0 ] );
	    continue;
	}

	if ( (*(commands[ i ].c_func))( snet, ac, av, pushersn ) < 0 ) {
	    break;
	}
    }

    if (( rate = rate_get( &checkpass )) != 0.0 ) {
	syslog( LOG_NOTICE, "STATS CHECK %s: PASS %.5f / sec",
		inet_ntoa( cosign_sin.sin_addr), rate );
    }
    if (( rate = rate_get( &checkfail )) != 0.0 ) {
	syslog( LOG_NOTICE, "STATS CHECK %s: FAIL %.5f / sec",
		inet_ntoa( cosign_sin.sin_addr), rate );
    }
    if (( rate = rate_get( &checkunknown )) != 0.0 ) {
	syslog( LOG_NOTICE, "STATS CHECK %s: UNKNOWN %.5f / sec",
		inet_ntoa( cosign_sin.sin_addr), rate );
    }

    if ( line != NULL ) {
	snet_writef( snet,
		"491 Service not available, closing transmission channel\r\n" );
    } else {
	if ( snet_eof( snet )) {
	    exit( 0 );
	} else if ( errno == ETIMEDOUT ) {
	    exit( 0 );
	} else {
	    syslog( LOG_ERR, "snet_getline: %m" );
	}
    }

    exit( 1 );

}
Exemple #2
0
    int
f_stor( SNET *sn, int ac, char *av[] )
{
    char 		*sizebuf;
    char		xscriptdir[ MAXPATHLEN ];
    char		upload[ MAXPATHLEN ];
    char		buf[ 8192 ];
    char		*line;
    char		*d_tran, *d_path;
    int			fd;
    int			zero = 0;
    off_t		len;
    ssize_t		rc;
    struct timeval	tv;
    struct protoent	*proto;

    if ( !prevstor ) {
	/* Turn off TCP_NODELAY for stores */
	if (( proto = getprotobyname( "tcp" )) == NULL ) {
	    syslog( LOG_ERR, "f_stor: getprotobyname: %m" );
	    return( -1 );
	}

	if ( setsockopt( snet_fd( sn ), proto->p_proto, TCP_NODELAY, &zero,
		sizeof( zero )) != 0 ) {
	    syslog( LOG_ERR, "f_stor: snet_setopt: %m" );
	    return( -1 );
	}
	prevstor = 1;
    }

    if ( checkuser && ( !authorized )) {
	snet_writef( sn, "%d Not logged in\r\n", 551 );
	exit( 1 );
    }
    /* decode() uses static mem, so strdup() */
    if (( d_tran = decode( av[ 2 ] )) == NULL ) {
	syslog( LOG_ERR, "f_stor: decode: buffer too small" );
	snet_writef( sn, "%d Line too long\r\n", 540 );
	return( 1 );
    } 
    if (( d_tran = strdup( d_tran )) == NULL ) {
	syslog( LOG_ERR, "f_stor: strdup: %s: %m", d_tran );
	return( -1 );
    }

    switch ( keyword( ac, av )) {

    case K_TRANSCRIPT:
        if ( snprintf( xscriptdir, MAXPATHLEN, "tmp/file/%s", d_tran )
		>= MAXPATHLEN ) {
	    syslog( LOG_ERR, "f_stor: xscriptdir path too long" );
	    snet_writef( sn, "%d Path too long\r\n", 540 );
	    return( 1 );
	}
        if ( snprintf( upload, MAXPATHLEN, "tmp/transcript/%s", d_tran )
		>= MAXPATHLEN ) {
	    syslog( LOG_ERR, "f_stor: upload path too long" );
	    snet_writef( sn, "%d Path too long\r\n", 540 );
	    return( 1 );
	}

	/* keep encoded transcript name, since it will just be
	 * used later to compare in a stor file.
	 */
	if ( strlen( av[ 2 ] ) >= MAXPATHLEN ) {
	    syslog( LOG_ERR, "f_stor: upload_xscript path too long" );
	    snet_writef( sn, "%d Path too long\r\n", 540 );
	    return( 1 );
	}
	strcpy( upload_xscript, av[ 2 ] );

	/* make the directory for the files of this xscript to live in. */
	if ( mkdir( xscriptdir, 0777 ) < 0 ) {
	    if ( errno == EEXIST ) {
	        snet_writef( sn, "%d Transcript exists\r\n", 551 );
		exit( 1 );
	    }
	    snet_writef( sn, "%d %s: %s\r\n",
		    551, xscriptdir, strerror( errno ));
	    exit( 1 );
	}
	break;

    case K_FILE:
	/* client must have provided a transcript name before giving 
	 * files in that transcript
	 */
	if (( strcmp( upload_xscript, av[ 2 ] ) != 0 )) {
	    snet_writef( sn, "%d Incorrect Transcript %s\r\n", 552, av[ 2 ] );
	    exit( 1 );
	}

	/* decode() uses static mem, so strdup() */
	if (( d_path = decode( av[ 3 ] )) == NULL ) {
	    syslog( LOG_ERR, "f_stor: decode: buffer too small" );
	    snet_writef( sn, "%d Line too long\r\n", 540 );
	    return( 1 );
	} 
	if (( d_path = strdup( d_path )) == NULL ) {
	    syslog( LOG_ERR, "f_stor: strdup: %s: %m", d_path );
	    return( -1 );
	}

	if ( d_path[ 0 ] == '/' ) {
	    if ( snprintf( upload, MAXPATHLEN, "tmp/file/%s%s", d_tran,
		    d_path ) >= MAXPATHLEN ) {
		syslog( LOG_ERR, "f_stor: upload path too long" );
		snet_writef( sn, "%d Path too long\r\n", 540 );
		return( 1 );
	    }
	} else {
	    if ( snprintf( upload, MAXPATHLEN, "tmp/file/%s/%s", d_tran,
		    d_path ) >= MAXPATHLEN ) {
		syslog( LOG_ERR, "f_stor: upload path too long" );
		snet_writef( sn, "%d Path too long\r\n", 540 );
		return( 1 );
	    }
	}
	free( d_path );
	free( d_tran );
	break;

    default:
        snet_writef( sn, "%d STOR Syntax error\r\n", 550 );
	exit( 1 ); 
    }

    if (( fd = open( upload, O_CREAT|O_EXCL|O_WRONLY, 0666 )) < 0 ) {
	if ( mkdirs( upload ) < 0 ) {
	    syslog( LOG_ERR, "f_stor: mkdir: %s: %m", upload );
	    snet_writef( sn, "%d %s: %s\r\n", 555, upload, strerror( errno ));
	    exit( 1 );
	}
	if (( fd = open( upload, O_CREAT|O_EXCL|O_WRONLY, 0666 )) < 0 ) {
	    syslog( LOG_ERR, "f_stor: open: %s: %m", upload );
	    snet_writef( sn, "%d %s: %s\r\n", 555, upload, strerror( errno ));
	    exit( 1 );
	}
    }


    snet_writef( sn, "%d Storing file\r\n", 350 );

    tv.tv_sec = 60;
    tv.tv_usec = 0;
    if ( ( sizebuf = snet_getline( sn, &tv ) ) == NULL ) {
	syslog( LOG_ERR, "f_stor: snet_getline: %m" );
	return( -1 );
    }
    /* Will there be a limit? */
    len = strtoofft( sizebuf, NULL, 10 );

    for ( ; len > 0; len -= rc ) {
	tv.tv_sec = 60;
	tv.tv_usec = 0;
	if (( rc = snet_read(
		sn, buf, MIN( len, sizeof( buf )), &tv )) <= 0 ) {
	    if ( snet_eof( sn )) {
		syslog( LOG_ERR, "f_stor: snet_read: eof" );
	    } else {
		syslog( LOG_ERR, "f_stor: snet_read: %m" );
	    }
	    return( -1 );
	}

	if ( write( fd, buf, rc ) != rc ) {
	    snet_writef( sn, "%d %s: %s\r\n", 555, upload, strerror( errno ));
	    exit( 1 );
	}
    }

    if ( len != 0 ) {
	syslog( LOG_ERR, "f_stor: len is %" PRIofft "d", len );
	snet_writef( sn, "%d %s: internal error!\r\n", 555, upload );
	exit( 1 );
    }

    if ( close( fd ) < 0 ) {
	snet_writef( sn, "%d %s: %s\r\n", 555, upload, strerror( errno ));
	exit( 1 );
    }

    syslog( LOG_DEBUG, "f_stor: file %s stored", upload );

    tv.tv_sec = 60;
    tv.tv_usec = 0;
    if (( line = snet_getline( sn, &tv )) == NULL ) {
        syslog( LOG_ERR, "f_stor: snet_getline: %m" );
	return( -1 );
    }

    /* make sure client agrees we're at the end */
    if ( strcmp( line, "." ) != 0 ) {
        syslog( LOG_ERR, "f_stor: line is: %s", line );
	snet_writef( sn, "%d Length doesn't match sent data %s\r\n",
		555, upload );
	(void)unlink( upload );
	exit( 1 );
    }

    snet_writef( sn, "%d File stored\r\n", 250 );
    return( 0 );
}
    static int
netcheck_cookie( char *scookie, char **rekey, struct sinfo *si,
	struct connlist *conn, void *s, cosign_host_config *cfg )
{
    int			i, j, ac, rc, mf, fc = cfg->reqfc;
    char		*p, *line, **av, **fv = cfg->reqfv;
    char		*rekeyed_cookie = NULL;
    char		*cmd = "CHECK";
    struct timeval      tv;
    SNET		*sn = conn->conn_sn;
    extern int		errno;

    /* REKEY service-cookie */
    if ( rekey != NULL && COSIGN_CONN_SUPPORTS_REKEY( conn )) {
	cmd = "REKEY";
    }
    if ( snet_writef( sn, "%s %s\r\n", cmd, scookie ) < 0 ) {
	cosign_log( APLOG_ERR, s, "mod_cosign: netcheck_cookie: "
		    "snet_writef %s failed", cmd );
	return( COSIGN_ERROR );
    }

    tv = timeout;
    if (( line = snet_getline_multi( sn, logger, &tv )) == NULL ) {
	if ( !snet_eof( sn )) {
	cosign_log( APLOG_ERR, s,
		"mod_cosign: netcheck_cookie: snet_getline_multi: %s",
		strerror( errno ));
	}
	return( COSIGN_ERROR );
    }

    switch( *line ) {
    case '2':
	if (( rate = rate_tick( &checkpass )) != 0.0 ) {
	    cosign_log( APLOG_NOTICE, s,
		    "mod_cosign: STATS CHECK %s: PASS %.5f / sec",
		    inet_ntoa( conn->conn_sin.sin_addr ), rate );
	}
	break;

    case '4':
	if (( rate = rate_tick( &checkfail )) != 0.0 ) {
	    cosign_log( APLOG_NOTICE, s,
		    "mod_cosign: STATS CHECK %s: FAIL %.5f / sec",
		    inet_ntoa( conn->conn_sin.sin_addr ), rate );
	}
	return( COSIGN_LOGGED_OUT );

    case '5':
	/* choose another connection */
	if (( rate = rate_tick( &checkunknown )) != 0.0 ) {
	    cosign_log( APLOG_NOTICE, s,
		    "mod_cosign: STATS CHECK %s: UNKNOWN %.5f / sec",
		    inet_ntoa( conn->conn_sin.sin_addr ), rate );
	}
	return( COSIGN_RETRY );

    default:
	cosign_log( APLOG_ERR, s, "mod_cosign: netcheck_cookie: %s", line );
	return( COSIGN_ERROR );
    }

    if (( ac = argcargv( line, &av )) < 4 ) {
	cosign_log( APLOG_ERR, s,
		"mod_cosign: netcheck_cookie: wrong num of args: %s", line );
	return( COSIGN_ERROR );
    }
    if ( rekey != NULL && COSIGN_CONN_SUPPORTS_REKEY( conn )) {
	/* last factor is penultimate argument */
	mf = ac - 1;
    } else {
	/* last factor is last argument */
	mf = ac;
    }

    /* I guess we check some sizing here :) */
    if ( strlen( av[ 1 ] ) >= sizeof( si->si_ipaddr )) {
	cosign_log( APLOG_ERR, s,
		"mod_cosign: netcheck_cookie: IP address too long" );
	return( COSIGN_ERROR );
    }
    strcpy( si->si_ipaddr, av[ 1 ] );
    if ( strlen( av[ 2 ] ) >= sizeof( si->si_user )) {
	cosign_log( APLOG_ERR, s,
		"mod_cosign: netcheck_cookie: username too long" );
	return( COSIGN_ERROR );
    }
    strcpy( si->si_user, av[ 2 ] );

    si->si_protocol = conn->conn_proto;
    if ( COSIGN_PROTO_SUPPORTS_FACTORS( conn->conn_proto )) {
	for ( i = 0; i < fc; i++ ) {
	    for ( j = 3; j < mf; j++ ) {
		if ( strcmp( fv[ i ], av[ j ] ) == 0 ) {
		    break;
		}
		    if ( cfg->suffix != NULL ) {
		if (( p = strstr( av[ j ], cfg->suffix )) != NULL ) {
		    if (( strlen( p )) == ( strlen( cfg->suffix ))) {
			*p = '\0';
			rc = strcmp( fv[ i ], av[ j ] );
			*p = *cfg->suffix;
			if ( rc == 0 ) {
			    if ( cfg->fake == 1 ) {
				break;
			    } else {
				cosign_log( APLOG_ERR, s, 
					"mod_cosign: netcheck: factor %s "
					"matches with suffix %s, but suffix " 
					"matching is OFF", av[ j ],
					cfg->suffix );
				return( COSIGN_ERROR );
			    }
			}
		    }
		}
		    }
	    }
	    if ( j >= mf ) {
		/* a required factor wasn't in the check line */
		break;
	    }
	}
	if ( i < fc ) {
	    /* we broke out early */
	    cosign_log( APLOG_ERR, s,
		"mod_cosign: netcheck_cookie: we broke out early" );
	    return( COSIGN_RETRY );
	}

	if ( strlen( av[ 3 ] ) + 1 > sizeof( si->si_factor )) {
	    cosign_log( APLOG_ERR, s,
		    "mod_cosign: netcheck: factor %s too long", av[ 3 ] );
	    return( COSIGN_ERROR );
	}
	strcpy( si->si_factor, av[ 3 ] );

	for ( i = 4; i < mf; i++ ) {
	    if ( strlen( av[ i ] ) + 1 + 1 >
		    sizeof( si->si_factor ) - strlen( si->si_factor )) {
		cosign_log( APLOG_ERR, s,
			"mod_cosign: netcheck: factor %s too long", av[ i ] );
		return( COSIGN_ERROR );
	    }
	    strcat( si->si_factor, " " );
	    strcat( si->si_factor, av[ i ] );
	}
    }

    if ( strlen( av[ 3 ] ) >= sizeof( si->si_realm )) {
	cosign_log( APLOG_ERR, s,
		"mod_cosign: netcheck_cookie: realm too long" );
	return( COSIGN_ERROR );
    }
    strcpy( si->si_realm, av[ 3 ] );

#ifdef KRB
    *si->si_krb5tkt = '\0';
#endif /* KRB */

    if ( rekey != NULL && COSIGN_CONN_SUPPORTS_REKEY( conn )) {
	if ( strncmp( av[ ac - 1 ], "cosign-", strlen( "cosign-" )) != 0 ) {
	    cosign_log( APLOG_ERR, s, "mod_cosign: netcheck_cookie: "
		    "bad rekeyed cookie \"%s\"", av[ ac - 1 ] );
	    return( COSIGN_ERROR );
	}
	if (( rekeyed_cookie = strdup( av[ ac - 1 ] )) == NULL ) {
	    cosign_log( APLOG_ERR, s, "mod_cosign: netcheck_cookie: "
		    "strdup rekeyed cookie: %s", strerror( errno ));
	    return( COSIGN_ERROR );
	}
	*rekey = rekeyed_cookie;
    }

    return( COSIGN_OK );
}