コード例 #1
0
ファイル: progress.c プロジェクト: Radmind/radmind
    off_t
loadsetsize( FILE *tran )
{
    char	tline[ LINE_MAX ], line[ LINE_MAX ];
    char	**targv;
    int		tac, linenum = 0;
    off_t	size = 0;

    while ( fgets( tline, LINE_MAX, tran ) != NULL ) {
	linenum++;
	strcpy( line, tline );
	if (( tac = argcargv( tline, &targv )) == 0 ) {
	    continue;
	}

    	switch ( *targv[ 0 ] ) {
	case 'a':
	case 'f':
	    break;

	default:
	    continue;
	}

	linecheck( line, tac, linenum );
	size += strtoofft( targv[ 6 ], NULL, 10 );
    }

    rewind( tran );

    return( size );
}
コード例 #2
0
ファイル: argcargv.c プロジェクト: Chandra-MARX/marx
int main (int argc, char **argv) /*{{{*/
{
   argc--; argv++;
   if (-1 == argcargv (&argc, &argv, Table))
     {
	fprintf (stderr, "Error.\n");
	return -1;
     }
   if (argc)
     {
	fprintf (stderr, "Unprocessed: %s\n", *argv);
     }

   fprintf (stdout, "i1 = %d\n", I1);
   fprintf (stdout, "i2 = %d\n", I2);
   fprintf (stdout, "s1 = %s\n", (S1 == NULL) ? "NULL" : S1);
   fprintf (stdout, "s2 = %s\n", (S2 == NULL) ? "NULL" : S2);
   return 0;
}
コード例 #3
0
ファイル: progress.c プロジェクト: Radmind/radmind
    off_t
lcksum_loadsetsize( FILE *tran, char *prefix )
{
    char	tline[ LINE_MAX ], line[ LINE_MAX ];
    char	*d_path = NULL;
    char	**targv;
    int		tac, linenum = 0;
    off_t	size = 0;

    while ( fgets( tline, LINE_MAX, tran ) != NULL ) {
	linenum++;
	strcpy( line, tline );
	if (( tac = argcargv( tline, &targv )) <= 1 ) {
	    continue;
	}

	if ( prefix != NULL ) {
	    if (( d_path = decode( targv[ 1 ] )) == NULL ) {
		fprintf( stderr, "%d: path too long\n", linenum );
		exit( 2 );
	    }
	    if ( strncmp( d_path, prefix, strlen( prefix )) != 0 ) {
		continue;
	    }
	}

	switch ( *targv[ 0 ] ) {
	case 'a':
	case 'f':
	    linecheck( line, tac, linenum );
	    size += strtoofft( targv[ 6 ], NULL, 10 );

	default:
	    size += PROGRESSUNIT;
	    break;
	}
    }
	
    rewind( tran );
    return( size );
}
コード例 #4
0
ファイル: progress.c プロジェクト: Radmind/radmind
    off_t
applyloadsetsize( FILE *tran )
{
    char	tline[ LINE_MAX ], line[ LINE_MAX ];
    char	**targv;
    int		tac, linenum = 0;
    off_t	size = 0;

    while ( fgets( tline, LINE_MAX, tran ) != NULL ) {
	linenum++;
	strcpy( line, tline );
	/* skip empty lines and transcript marker lines */
	if (( tac = argcargv( tline, &targv )) <= 1 ) {
	    continue;
	}

	switch ( *targv[ 0 ] ) {
	case '+':
	    switch ( *targv[ 1 ] ) {
	    case 'a':
	    case 'f':
		linecheck( line, tac, linenum );
		size += strtoofft( targv[ 7 ], NULL, 10 );

	    default:
		break;
	    }

	default:
	    break;
	}

	size += PROGRESSUNIT;
    }

    rewind( tran );

    return( size );
}
コード例 #5
0
ファイル: command.c プロジェクト: Radmind/radmind
    int
cmdloop( int fd, struct sockaddr_in *sin )
{
    SNET		*sn;
    struct hostent	*hp;
    char		*p;
    int			ac, i;
    int			one = 1;
    unsigned int	n;
    char		**av, *line;
    struct timeval	tv;
    extern char		*version;
    extern int		connections;
    extern int		maxconnections;
    extern int		rap_extensions;

    if ( authlevel == 0 ) {
	commands = noauth;
	ncommands = sizeof( noauth ) / sizeof( noauth[ 0 ] );
    } else {
	commands = notls;
	ncommands = sizeof( notls ) / sizeof( notls[ 0 ] );
    }

    if (( sn = snet_attach( fd, 1024 * 1024 )) == NULL ) {
	syslog( LOG_ERR, "snet_attach: %m" );
	exit( 1 );
    }
    remote_addr = strdup( inet_ntoa( sin->sin_addr ));

    if (( hp = gethostbyaddr( (char *)&sin->sin_addr,
	    sizeof( struct in_addr ), AF_INET )) == NULL ) {
	remote_host = strdup( remote_addr );
    } else {
	/* set global remote_host for retr command */
	remote_host = strdup( hp->h_name );
	for ( p = remote_host; *p != '\0'; p++ ) {
	    *p = tolower( *p );
	}
    }

    syslog( LOG_INFO, "child for [%s] %s",
	    inet_ntoa( sin->sin_addr ), remote_host );

    if ( setsockopt( fd, 6, TCP_NODELAY, &one, sizeof( one )) < 0 ) {
	syslog( LOG_ERR, "setsockopt: %m" );
    }

    if ( maxconnections != 0 ) {
	if ( connections > maxconnections ) {
	    syslog( LOG_INFO, "%s: connection refused: server busy\r\n",
		    remote_host );
	    snet_writef( sn, "%d Server busy\r\n", 420 );
	    exit( 1 );
	}
    }

    if (( access_list = list_new( )) == NULL ) {
	syslog( LOG_ERR, "new_list: %m" );
	snet_writef( sn,
	    "%d Service not available, closing transmission channel\r\n", 421 );
	return( -1 );
    }
    
    if ( authlevel == 0 ) {
	/* lookup proper command file based on the hostname, IP or CN */
	if ( command_k( "config", 0 ) < 0 ) {
	    syslog( LOG_INFO, "%s: Access denied: Not in config file",
		remote_host );
	    snet_writef( sn, "%d No access for %s\r\n", 500, remote_host );
	    exit( 1 );
	} else {
	    if ( read_kfile( sn, command_file ) != 0 ) {
		/* error message given in read_kfile */
		exit( 1 );
	    }
	    commands = auth;
	    ncommands = sizeof( auth ) / sizeof( auth[ 0 ] );
	}
    }

    if ( gethostname( hostname, MAXHOSTNAMELEN ) < 0 ) {
	syslog( LOG_ERR, "gethostname: %m" );
	exit( 1 );
    }

    snet_writef( sn, "200%sRAP 1 %s %s radmind access protocol\r\n",
	rap_extensions ? "-" : " ", hostname, version );
    if ( rap_extensions ) {
	snet_writef( sn, "200 CAPA" ); 
#ifdef HAVE_ZLIB
	if ( max_zlib_level > 0 ) {
	    snet_writef( sn, " ZLIB" ); 
	}
#endif /* HAVE_ZLIB */
	snet_writef( sn, " REPO" ); 
	snet_writef( sn, "\r\n" ); 
    }

    /*
     * 60 minutes
     * To make fsdiff | lapply work, when fsdiff will take a long time,
     * we allow the server to wait a long time.
     */
    tv.tv_sec = 60 * 60;
    tv.tv_usec = 0 ;
    while (( line = snet_getline( sn, &tv )) != NULL ) {
	tv.tv_sec = 60 * 60;
	tv.tv_usec = 0; 

	if ( debug ) {
	    fprintf( stderr, "<<< %s\n", line );
	}

	if (( ac = argcargv( line, &av )) < 0 ) {
	    syslog( LOG_ERR, "argcargv: %m" );
	    return( 1 );
	}

	if ( ac == 0 ) {
	    snet_writef( sn, "%d Illegal null command\r\n", 501 );
	    continue;
	}

	for ( i = 0; i < ncommands; i++ ) {
	    n = MAX( strlen( av[ 0 ] ), 4 );
	    if ( strncasecmp( av[ 0 ], commands[ i ].c_name, n ) == 0 ) {
		break;
	    }
	}
	if ( i >= ncommands ) {
	    snet_writef( sn, "%d Command %s unrecognized\r\n", 500, av[ 0 ] );
	    continue;
	}
	if ( (*(commands[ i ].c_func))( sn, ac, av ) < 0 ) {
	    break;
	}

    }

    snet_writef( sn, "%d Server closing connection\r\n", 444 );

    if ( line == NULL ) {
	syslog( LOG_ERR, "snet_getline: %m" );
    }
    return( 0 );
}
コード例 #6
0
ファイル: command.c プロジェクト: Radmind/radmind
/* sets command file for connected host */
    int
command_k( char *path_config, int depth )
{
    SNET	*sn;
    char	**av, *line, *p;
    char	*valid_host;
    char	temp[ MAXPATHLEN ];
    int		ac;
    int		rc = -1;
    int		linenum = 0;

    if (( sn = snet_open( path_config, O_RDONLY, 0, 0 )) == NULL ) {
        syslog( LOG_ERR, "command_k: snet_open: %s: %m", path_config );
	return( -1 );
    }

    while (( line = snet_getline( sn, NULL )) != NULL ) {
	linenum++;

        if (( ac = argcargv( line, &av )) < 0 ) {
	    syslog( LOG_ERR, "argvargc: %m" );
	    goto command_k_done;
	}

	if ( ( ac == 0 ) || ( *av[ 0 ] == '#' ) ) {
	    continue;
	}
	if ( ac < 2 ) {
	    syslog( LOG_ERR, "%s: line %d: invalid number of arguments",
			path_config, linenum );
	    continue;
	}
	if ( strcmp( av[ 0 ], "@include" ) == 0 ) {
	    if ( depth >= RADMIND_MAX_INCLUDE_DEPTH ) {
		syslog( LOG_ERR, "%s: line %d: include %s exceeds max depth",
			path_config, linenum, av[ 1 ] );
		goto command_k_done;
	    }
	    if ( ac > 3 ) {
		syslog( LOG_ERR, "%s: line %d: invalid number of arguments",
			path_config, linenum );
		continue;
	    } else if ( ac == 3 ) {
		if ( match_config_entry( av[ 2 ] ) == NULL ) {
		    /* connecting host doesn't match pattern, skip include. */
		    continue;
		}
	    }
	    if ( command_k( av[ 1 ], depth + 1 ) != 0 ) {
		continue;
	    }

	    rc = 0;
	    goto command_k_done;
	}

        if (( ac > 2 ) && ( *av[ 2 ] != '#' )) { 
	    syslog( LOG_ERR, "%s: line %d: invalid number of arguments",
		    path_config, linenum );
	    continue;
	}

	if (( p = strrchr( av[ 1 ], '/' )) == NULL ) {
	    sprintf( special_dir, "special" );
	} else {
	    *p = '\0';
	    if ( snprintf( special_dir, MAXPATHLEN, "special/%s", av[ 1 ] )
		    >= MAXPATHLEN ) {
		syslog( LOG_ERR, "config file: line %d: path too long\n",
		    linenum );
		continue;
	    }
	    *p = '/';
	}

	if (( valid_host = match_config_entry( av[ 0 ] )) != NULL ) {
	    if ( strlen( av[ 1 ] ) >= MAXPATHLEN ) {
		syslog( LOG_ERR,
		    "config file: line %d: command file too long\n", linenum );
		continue;
	    }
	    strcpy( command_file, av[ 1 ] );
	    if ( snprintf( temp, MAXPATHLEN, "%s/%s", special_dir,
		    valid_host ) >= MAXPATHLEN ) {
		syslog( LOG_ERR, "config file: line %d: special dir too long\n",
		    linenum );
		continue;
	    }
	    strcpy( special_dir, temp );
	    rc = 0;
	    goto command_k_done;
	}
    }

    /* If we get here, the host that connected is not in the config
       file. So screw him. */
    syslog( LOG_ERR, "host %s not in config file %s",
		remote_host, path_config );

command_k_done:
    snet_close( sn );
    return( rc );
}
コード例 #7
0
ファイル: command.c プロジェクト: JorjBauer/cosign
    int
f_time( SNET *sn, int ac, char *av[], SNET *pushersn )
{
    struct utimbuf	new_time;
    struct stat		st;
    struct timeval	tv;
    int			timestamp, state;
    int			total = 0, fail = 0;
    char		*line, path[ MAXPATHLEN ];

    /* TIME */
    /* 3xx */
    /* login_cookie timestamp state */
    /* . */

    if ( al->al_key != CGI ) {
	syslog( LOG_ERR, "%s not allowed to tell time", al->al_hostname );
	snet_writef( sn, "%d TIME: %s not allowed to propogate time.\r\n",
		460, al->al_hostname );
	return( 1 );
    }

    if ( ac != 1 ) {
	syslog( LOG_ERR, "f_time: expected 1 argument, got %d", ac );
	snet_writef( sn, "%d TIME: Wrong number of args.\r\n", 560 );
	return( 1 );
    }

    snet_writef( sn, "%d TIME: Send timestamps.\r\n", 360 );

    tv = cosign_net_timeout;
    while (( line = snet_getline( sn, &tv )) != NULL ) {
	tv = cosign_net_timeout;
	if (( ac = argcargv( line, &av )) < 0 ) {
	    syslog( LOG_ERR, "argcargv: %m" );
	    break;
	}

	if ( strcmp( line, "." ) == 0 ) {
	    break;
	}

	if ( ac != 3 ) {
	    syslog( LOG_ERR, "f_time: wrong number of args" );
	    continue;
	}

	if ( strncmp( av[ 0 ], "cosign=", 7 ) != 0 ) {
	    syslog( LOG_ERR, "f_time: cookie name malformat" );
	    continue;
	}

	if ( mkcookiepath( NULL, hashlen, av[ 0 ], path, sizeof( path )) < 0 ) {
	    syslog( LOG_ERR, "f_time: path name malformat" );
	    continue;
	}

	total++;
	if ( stat( path, &st ) != 0 ) {
	    /* record a missing cookie here */
	    fail++;
	    continue;
	}

	timestamp = atoi( av[ 1 ] ); 
	if ( timestamp > st.st_mtime ) {
	    new_time.modtime = timestamp;
	    utime( path, &new_time );
	}

	state = atoi( av[ 2 ] );
	if (( state == 0 ) && (( st.st_mode & S_ISGID ) != 0 )) {
	    if ( do_logout( path ) < 0 ) {
		syslog( LOG_ERR, "f_time: %s should be logged out!", path );
	    }
	}
    }

    if ( total != 0 ) {
	syslog( LOG_NOTICE, "STATS TIME %s: %d tried, %d%% success",
		al->al_hostname, total, 100 * ( total - fail ) / total );
    }
    snet_writef( sn, "%d TIME successful: we are now up-to-date\r\n", 260 );
    return( 0 );
}
コード例 #8
0
ファイル: command.c プロジェクト: JorjBauer/cosign
    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 );

}
コード例 #9
0
    static int
connect_sn( struct connlist *cl, cosign_host_config *cfg, void *s )
{
    int			sock, zero = 0, ac = 0, state, i;
    char		*line, buf[ 1024 ], **av;
    X509		*peer;
    struct timeval      tv;
    struct protoent	*proto;

    if (( sock = socket( PF_INET, SOCK_STREAM, 0 )) < 0 ) {
	cosign_log( APLOG_ERR, s, "mod_cosign: connect_sn: socket" );
	return( -1 );
    }

    if (( proto = getprotobyname( "tcp" )) != NULL ) {
	if ( setsockopt( sock, proto->p_proto, TCP_NODELAY,
		&zero, sizeof( zero )) < 0 ) {
	    cosign_log( APLOG_ERR, s,
		    "mod_cosign: connect_sn: setsockopt: TCP_NODELAY" );
	}
    }

    if ( connect( sock, ( struct sockaddr *)&cl->conn_sin,
	    sizeof( struct sockaddr_in )) != 0 ) {
	cosign_log( APLOG_ERR, s, "mod_cosign: connect_sn: connect" );
	(void)close( sock );
	return( -1 );
    }

    if (( cl->conn_sn = snet_attach( sock, 1024 * 1024 ) ) == NULL ) {
	cosign_log( APLOG_ERR, s,
		"mod_cosign: connect_sn: snet_attach failed" );
	(void)close( sock );
	return( -1 );
    }

    tv = timeout;
    if (( line = snet_getline( cl->conn_sn, &tv )) == NULL ) {
	cosign_log( APLOG_ERR, s,
	    "mod_cosign: connect_sn: snet_getline failed" );
	goto done;
    }

    if ( *line != '2' ) {
	cosign_log( APLOG_ERR, s, "mod_cosign: connect_sn: %s", line );
	goto done;
    }

    if (( ac = argcargv( line, &av )) < 4 ) {
	cosign_log( APLOG_ERR, s, "mod_cosign: argcargv: %s", line );
	goto done;
    }

    errno = 0;
    cl->conn_proto = strtol( av[ 1 ], (char **)NULL, 10 );
    if ( errno ) {
	cosign_log( APLOG_ERR, s, "mod_cosign: unrecognized protocol "
		    "version %s, falling back to protocol v0", av[1]);
	cl->conn_proto = COSIGN_PROTO_V0;
    }
    if ( cfg->reqfc > 0 && !COSIGN_PROTO_SUPPORTS_FACTORS( cl->conn_proto )) {
	cosign_log( APLOG_ERR, s, "mod_cosign: required v2 or greater "
		    "protocol unsupported by server "
		    "(server protocol version: %s)", av[ 1 ] );
	goto done;
    }
	   
    cl->conn_capa = COSIGN_CAPA_DEFAULTS;
    if ( ac > 6 ) {
	/* "220 2 Collaborative Web Single Sign-On [COSIGNv3 REKEY ...]" */
	ac -= 6;
	av += 6;
	
	if ( capa_parse( ac, av, cl, s ) < 0 ) {
	    cosign_log( APLOG_ERR, s, "mod_cosign: failed to parse server "
			"capabilities" );
	    goto done;
	}
    } else {
	/* pre-3.1: "220 2 Collaborative Web Single Sign-On" */
	if ( COSIGN_PROTO_SUPPORTS_FACTORS( cl->conn_proto )) {
	    cl->conn_capa |= COSIGN_CAPA_FACTORS;
	}
    }
    if ( cl->conn_proto >= COSIGN_PROTO_V2 ) {
	if ( snet_writef( cl->conn_sn, "STARTTLS %d\r\n",
		cl->conn_proto ) < 0 ) {
	    cosign_log( APLOG_ERR, s,
		    "mod_cosign: connect_sn: starttls 2 failed" );
	    goto done;
	}
    } else {
	if ( snet_writef( cl->conn_sn, "STARTTLS\r\n" ) < 0 ) {
	    cosign_log( APLOG_ERR, s,
		    "mod_cosign: connect_sn: starttls failed" );
	    goto done;
	}
    }

    tv = timeout;
    if (( line = snet_getline_multi( cl->conn_sn, logger, &tv )) == NULL ) {
	cosign_log( APLOG_ERR, s,
		"mod_cosign: connect_sn: snet_getline_multi failed" );
	goto done;
    }

    if ( snet_starttls( cl->conn_sn, cfg->ctx, 0 ) != 1 ) {
	cosign_log( APLOG_ERR, s, "mod_cosign: snet_starttls: %s",
		ERR_error_string( ERR_get_error(), NULL ));
	goto done;
    }

    if (( peer = SSL_get_peer_certificate( cl->conn_sn->sn_ssl )) == NULL ) {
	cosign_log( APLOG_ERR, s, "mod_cosign: connect_sn: no certificate" );
	goto done;
    }

    X509_NAME_get_text_by_NID( X509_get_subject_name( peer ), NID_commonName,
	    buf, sizeof( buf ));
    X509_free( peer );

    /* cn and host must match */
    if ( strcasecmp( buf, cfg->host ) != 0 ) {
	cosign_log( APLOG_ERR, s, "mod_cosign: connect_sn: cn=%s & host=%s " 
		"don't match!", buf, cfg->host );
	goto done;
    }

    if ( cl->conn_proto >= COSIGN_PROTO_V2 ) {
	tv = timeout;
	if (( line = snet_getline_multi( cl->conn_sn, logger, &tv )) == NULL ) {
	    cosign_log( APLOG_ERR, s,
		    "mod_cosign: connect_sn: snet_getline_multi failed" );
	    goto done;
	}
	if ( *line != '2' ) {
	    cosign_log( APLOG_ERR, s, "mod_cosign: starttls 2: %s", line );
	    goto done;
	}
    }

    return( 0 );
done:
    if ( snet_close( cl->conn_sn ) != 0 ) {
	cosign_log( APLOG_ERR, s, "mod_cosign: connect_sn: snet_close failed" );
    }
    cl->conn_sn = NULL;
    cl->conn_proto = COSIGN_PROTO_V0;

    return( -1 );
}
コード例 #10
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 );
}