Beispiel #1
0
    int
f_daemon( SNET *sn, int ac, char *av[], SNET *pushersn )
{
    /* DAEMON hostname */

    char	hostname[ MAXHOSTNAMELEN ];

    if ( al->al_key != CGI ) {
	syslog( LOG_ERR, "%s is not a daemon", al->al_hostname );
	snet_writef( sn, "%d DAEMON: %s not a daemon.\r\n",
		470, al->al_hostname );
	return( 1 );
    }

    if ( ac != 2 ) {
	syslog( LOG_ERR, "f_daemon: expected 2 arguments, got %d", ac );
	snet_writef( sn, "%d Syntax error\r\n", 571 );
	return( 1 );
    }

    if ( gethostname( hostname, sizeof( hostname )) < 0 ) {
	syslog( LOG_ERR, "f_daemon: gethostname: %m" );
	snet_writef( sn, "%d DAEMON error. Sorry!\r\n", 572 );
	return( 1 );
    }

    if ( strcasecmp( hostname, av[ 1 ] ) == 0 ) {
	snet_writef( sn, "%d Schizophrenia!\r\n", 471 );
	return( 1 );
    }
    replicated = 1;

    snet_writef( sn, "%d Daemon flag set\r\n", 271 );
    return( 0 );
}
Beispiel #2
0
    int
f_repo( SNET *sn, int ac, char **av )
{
    char			*cn = "-";
    char			*d_msg;

    if ( ac != 3 ) {
	snet_writef( sn, "%d Syntax error (invalid parameters)\r\n", 501 );
	return( 1 );
    }

    if (( d_msg = decode( av[ 2 ] )) == NULL ) {
	syslog( LOG_ERR, "f_repo: decode: buffer too small" );
	snet_writef( sn, "%d Syntax error (invalid parameter)\r\n", 501 );
	return( 1 );
    }

    if ( remote_cn != NULL ) {
	cn = remote_cn;
    }

    syslog( LOG_NOTICE, "report %s %s %s %s %s %s",
		remote_host, remote_addr,
		cn, "-", /* reserve for user specified ID, e.g. sasl */
		av[ 1 ], d_msg );

    snet_writef( sn, "%d Report successful\r\n", 215 );
    
    return( 0 );
}
Beispiel #3
0
    static int
retr_proxy( SNET *sn, char *login, SNET *pushersn )
{
    char		cookiebuf[ 128 ], lpath[ MAXPATHLEN ];
    char		cbuf[ MAXCOOKIELEN ], spath[ MAXPATHLEN ];
    struct proxies	*proxy;
    int			rc;

    /* S: 241-[cookiename] [hostname to use cookie with]
     * S: 241- ... 
     * S: 241 Cookies registered and sent.
     */
    
    if (( al->al_flag & AL_PROXY ) == 0 ) {
	syslog( LOG_ERR, "%s cannot retrieve cookies", al->al_hostname );
	snet_writef( sn, "%d RETR: %s cannot retrieve cookies.\r\n",
		443, al->al_hostname );
	return( 1 );
    }

    for ( proxy = al->al_proxies; proxy != NULL; proxy = proxy->pr_next ) {
	if ( mkcookie( sizeof( cookiebuf ), cookiebuf ) != 0 ) {
	    syslog( LOG_ERR, "retr_proxy: mkcookie error" );
	    return( -1 );
	}

	if ( snprintf( cbuf, sizeof( cbuf ), "%s=%s",
		proxy->pr_cookie, cookiebuf ) >= sizeof( cbuf )) {
	    syslog( LOG_ERR, "retr_proxy: full cookie too long" );
	    return( -1 );
	}

	if ( mkcookiepath( NULL, hashlen, cbuf, spath, sizeof( spath )) < 0 ) {
	    syslog( LOG_ERR, "retr_proxy: mkcookiepath error" );
	    return( 1 );
	}

	if ( mkcookiepath( NULL, hashlen, login, lpath, sizeof( lpath )) < 0 ) {
	    syslog( LOG_ERR, "retr_proxy: mkcookiepath error" );
	    return( 1 );
	}
	if (( rc = do_register( login, lpath, spath )) < 0 ) {
	    continue;
	}

	if (( pushersn != NULL ) && ( !replicated )) {
	    snet_writef( pushersn, "REGISTER %s - %s\r\n", login, cbuf );
	}
	snet_writef( sn, "%d-%s %s\r\n", 241, cbuf, proxy->pr_hostname );
    }
    snet_writef( sn, "%d Cookies registered and sent\r\n", 241 );

    return( 0 );
}
Beispiel #4
0
/* banner sent to client on connection & after successful TLS negotiation */
    static void
banner( SNET *sn )
{
    snet_writef( sn, "220 2 Collaborative Web Single Sign-On "
		"[COSIGNv%d FACTORS=%d REKEY]\r\n",
		COSIGN_PROTO_CURRENT, COSIGN_MAXFACTORS );
}
Beispiel #5
0
    static void
close_sn( struct connlist *cl, void *s )
{
    char		*line;
    struct timeval      tv;

    /* Close network connection */
    if (( snet_writef( cl->conn_sn, "QUIT\r\n" )) <  0 ) {
	cosign_log( APLOG_ERR, s, "mod_cosign: close_sn: snet_writef failed" );
	goto finish;
    }
    tv = timeout;
    if ( ( line = snet_getline_multi( cl->conn_sn, logger, &tv ) ) == NULL ) {
	cosign_log( APLOG_ERR, s,
		"mod_cosign: close_sn: snet_getline_multi failed" );
	goto finish;
    }
    if ( *line != '2' ) {
	cosign_log( APLOG_ERR, s, "mod_cosign: close_sn: %s", line );
    }

finish:
    if ( snet_close( cl->conn_sn ) != 0 ) {
	cosign_log( APLOG_ERR, s, "mod_cosign: close_sn: snet_close failed" );
    }
    cl->conn_sn = NULL;

    return;
}
Beispiel #6
0
    int
f_quit( SNET *sn, int ac, char **av )
{
    snet_writef( sn, "%d QUIT OK, closing connection\r\n", 201 );
#ifdef HAVE_ZLIB
    if ( debug && max_zlib_level > 0 ) print_stats( sn );
#endif /* HAVE_ZLIB */
    exit( 0 );
}
Beispiel #7
0
    int
f_logout( SNET *sn, int ac, char *av[], SNET *pushersn )
{
    struct cinfo	ci;
    char		path[ MAXPATHLEN ];

    /* LOGOUT login_cookie ip */

    if ( al->al_key != CGI ) {
	syslog( LOG_ERR, "f_logout: %s not allowed", al->al_hostname );
	snet_writef( sn, "%d LOGOUT: %s not allowed to logout.\r\n",
		410, al->al_hostname );
	return( 1 );
    }

    if ( ac != 3 ) {
	syslog( LOG_ERR, "f_logout: %s wrong number of args", al->al_hostname );
	snet_writef( sn, "%d LOGOUT: Wrong number of args.\r\n", 510 );
	return( 1 );
    }

    if ( mkcookiepath( NULL, hashlen, av[ 1 ], path, sizeof( path )) < 0 ) {
	syslog( LOG_ERR, "f_login: mkcookiepath error" );
	snet_writef( sn, "%d LOGIN: Invalid cookie path.\r\n", 511 );
	return( 1 );
    }

    if ( read_cookie( path, &ci ) != 0 ) {
	snet_writef( sn, "%d LOGOUT error: Sorry\r\n", 513 );
	return( 1 );
    }

    /* double action policy?? */
    if ( ci.ci_state == 0 ) {
	syslog( LOG_ERR, "f_logout: %s already logged out", av[ 1 ] );
	snet_writef( sn, "%d LOGOUT: Already logged out\r\n", 411 );
	return( 1 );
    }

    if ( do_logout( path ) < 0 ) {
	syslog( LOG_ERR, "f_logout: %s: %m", path );
	return( -1 );
    }

    snet_writef( sn, "%d LOGOUT successful: cookie no longer valid\r\n", 210 );
    if (( pushersn != NULL ) && ( !replicated )) {
	snet_writef( pushersn, "LOGOUT %s %s\r\n", av[ 1 ], av [ 2 ] );
    }
    if ( !replicated ) {
	syslog( LOG_INFO, "LOGOUT %s %s %s", ci.ci_user, ci.ci_realm, av[ 2 ] );
    }
    return( 0 );

}
Beispiel #8
0
    int
f_compress( SNET *sn, int ac, char **av )
{
    int		level;

    if ( max_zlib_level <= 0 ) {
	syslog( LOG_WARNING, "f_compress: compression not enabled" );
	snet_writef( sn, "501 Compression not enabled\r\n" );
	return( 1 );
    }

    if ( ac != 2 && ac != 3 ) {
	syslog( LOG_WARNING, "f_compress: syntax error" );
	snet_writef( sn, "%d Syntax error\r\n", 501 );
	return( 1 );
    }
    if ( snet_flags( sn ) & SNET_ZLIB ) {
	syslog( LOG_WARNING, "f_compress: compression already enabled" );
	snet_writef( sn, "%d Compression already enabled\r\n", 501 );
	return( 1 );
    }
    if ( strcasecmp( av[ 1 ], "ZLIB" ) == 0 ) {
	if( ac == 3 ) {
	    level = atoi( av[2] );
	    level = MAX( level, 1 );
	    level = MIN( level, max_zlib_level );
	} else {
	    /* If no level given, use max compression */
	    level = max_zlib_level;
	}
	snet_writef( sn, "320 Ready to start ZLIB compression level %d\r\n", level );
	if ( snet_setcompression( sn, SNET_ZLIB, level ) != 0 ) {
	    syslog( LOG_ERR, "f_compress: snet_setcompression failed" );
	    return( -1 );
	}
	snet_writef( sn, "220 ZLIB compression level %d enabled\r\n", level );
    } else {
	syslog( LOG_WARNING, "%s: Unknown compression requested", av[ 1 ] );
	snet_writef( sn, "525 %s: unknown compression type\r\n", av[ 1 ] );
    }
    return( 0 );
}
Beispiel #9
0
    int
f_noop( SNET *sn, int ac, char **av )
{
    snet_writef( sn, "%d NOOP OK\r\n", 202 );
    return( 0 );
}
Beispiel #10
0
    int
f_noop( SNET *sn, int ac, char *av[], SNET *pushersn )
{
    snet_writef( sn, "%d cosign v%s\r\n", 250, cosign_version );
    return( 0 );
}
Beispiel #11
0
    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 );
}
Beispiel #12
0
    int
read_kfile( SNET *sn, char *kfile )
{
    int		ac;
    int		linenum = 0;
    char	**av;
    char        line[ MAXPATHLEN ];
    char	path[ MAXPATHLEN ];
    ACAV	*acav;
    FILE	*f;

    if ( snprintf( path, MAXPATHLEN, "command/%s", kfile ) >= MAXPATHLEN ) {
	syslog( LOG_ERR, "read_kfile: command/%s: path too long", kfile );
	snet_writef( sn,
	    "%d Service not available, closing transmission channel\r\n", 421 );
	return( -1 );
    }

    if (( acav = acav_alloc( )) == NULL ) {
	syslog( LOG_ERR, "acav_alloc: %m" );
	snet_writef( sn,
	    "%d Service not available, closing transmission channel\r\n", 421 );
	return( -1 );
    }

    if (( f = fopen( path, "r" )) == NULL ) {
	syslog( LOG_ERR, "fopen: %s: %m", path );
	snet_writef( sn,
	    "%d Service not available, closing transmission channel\r\n", 421 );
	return( -1 );
    }

    while ( fgets( line, MAXPATHLEN, f ) != NULL ) {
	linenum++;

	ac = acav_parse( acav, line, &av );

	if (( ac == 0 ) || ( *av[ 0 ] == '#' )) {
	    continue;
	}

	/* Skip minus lines in command files for now.  Eventually,
	 * the server should not give access to command files, special files
	 * and transcripts that have been ultimately removed with a '-'.
	 * This is difficult as ktcheck reads command files line by line
	 * and will request info on a file that might be removed with a
	 * later '-'.
	 */
	if ( *av[ 0 ] == '-' ) {
	    continue;
	}

	if ( ac != 2 ) {
	    syslog( LOG_ERR, "%s: line %d: invalid number of arguments",
		kfile, linenum );
	    snet_writef( sn,
		"%d Service not available, closing transmission channel\r\n",
		421 );
	    goto error;
	}

	switch( *av[ 0 ] ) {
	case 'k':
	    if ( !list_check( access_list, av[ 1 ] )) {
		if ( list_insert( access_list, av[ 1 ] ) != 0 ) {
		    syslog( LOG_ERR, "list_insert: %m" );
		    snet_writef( sn,
	"%d Service not available, closing transmission channel\r\n", 421 );
		    goto error;
		}
		if ( read_kfile( sn, av[ 1 ] ) != 0 ) {
		    goto error;
		}
	    }
	    break;

	case 'p':
	case 'n':
	    if ( !list_check( access_list, av[ 1 ] )) {
		if ( list_insert( access_list, av[ 1 ] ) != 0 ) {
		    syslog( LOG_ERR, "list_insert: %m" );
		    snet_writef( sn,
	"%d Service not available, closing transmission channel\r\n", 421 );
		    goto error;
		}
	    }
	    break;

	case 's':
	case 'x':
	    break;

	default:
	    syslog( LOG_ERR, "%s: line %d: %c: unknown file type", kfile,
		linenum, *av[ 0 ] );
	    snet_writef( sn,
		"%d Service not available, closing transmission channel\r\n",
		421 );
	    goto error;

	}

	if ( ferror( f )) {
	    syslog( LOG_ERR, "fgets: %m" );
	    snet_writef( sn,
		"%d Service not available, closing transmission channel\r\n",
		421 );
	    goto error;
	}
    }

    if ( fclose( f ) != 0 ) {
	syslog( LOG_ERR, "fclose: %m" );
	snet_writef( sn,
	    "%d Service not available, closing transmission channel\r\n", 421 );
	goto error;
    }

    if ( acav_free( acav ) != 0 ) {
	syslog( LOG_ERR, "acav_free: %m" );
	snet_writef( sn,
	    "%d Service not available, closing transmission channel\r\n", 421 );
	return( -1 );
    }

    return( 0 );

error:
    fclose( f );
    acav_free( acav );

    return( -1 );
}
Beispiel #13
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 );

}
Beispiel #14
0
    static int
retr_ticket( SNET *sn, struct servicelist *sl, char *krbpath )
{
    struct stat		st;
    int			fd;
    ssize_t             readlen;
    char                buf[ 8192 ];
    struct timeval      tv;

    /* S: 240 Retrieving file
     * S: [size]
     * S: [data]
     * S: .
     */

    if (( sl->sl_flag & SL_TICKET ) == 0 ) {
	syslog( LOG_ERR, "%s not allowed to retrieve tkts",
		sl->sl_auth->al_hostname );
	snet_writef( sn, "%d RETR: %s not allowed to retrieve tkts.\r\n",
		441, sl->sl_auth->al_hostname );
	return( 1 );
    }

    if (( fd = open( krbpath, O_RDONLY, 0 )) < 0 ) {
        syslog( LOG_ERR, "open: %s: %m", krbpath );
        snet_writef( sn, "%d Unable to access %s.\r\n", 547, krbpath );
        return( 1 );
    }

    if ( fstat( fd, &st ) < 0 ) {
        syslog( LOG_ERR, "f_retr: fstat: %m" );
        snet_writef( sn, "%d Access Error: %s\r\n", 548, krbpath );
        if ( close( fd ) < 0 ) {
            syslog( LOG_ERR, "close: %m" );
            return( -1 );
        }
        return( 1 );
    }

    snet_writef( sn, "%d Retrieving file\r\n", 240 );
    snet_writef( sn, "%d\r\n", (int)st.st_size );

    while (( readlen = read( fd, buf, sizeof( buf ))) > 0 ) {
        tv = cosign_net_timeout;
        if ( snet_write( sn, buf, (int)readlen, &tv ) != readlen ) {
            syslog( LOG_ERR, "snet_write: %m" );
            return( -1 );
        }
    }

    if ( readlen < 0 ) {
        syslog( LOG_ERR, "read: %m" );
	close( fd );
        return( -1 );
    }

    if ( close( fd ) < 0 ) {
        syslog( LOG_ERR, "close: %m" );
        return( -1 );
    }

    snet_writef( sn, ".\r\n" );

    return( 0 );
}
Beispiel #15
0
    int
f_notls( SNET *sn, int ac, char **av )
{
    snet_writef( sn, "%d Must issue a STARTTLS command first\r\n", 530 );
    exit( 1 );
}
Beispiel #16
0
    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 );
}
Beispiel #17
0
    int
f_stat( SNET *sn, int ac, char *av[] )
{

    char 		path[ MAXPATHLEN ];
    char		cksum_b64[ SZ_BASE64_E( EVP_MAX_MD_SIZE ) ];
    struct stat		st;
    int			key;
    char		*enc_file, *d_tran, *d_path;

    switch ( key = keyword( ac, av )) {
    case K_COMMAND:
	if ( ac == 2 ) { 
	    if ( snprintf( path, MAXPATHLEN, "command/%s", command_file )
		    >= MAXPATHLEN ) {
		syslog( LOG_ERR, "f_stat: command/%s: path too long",
		    command_file );
		snet_writef( sn, "%d Path too long\r\n", 540 );
		return( 1 );
	    }
	} else {
	    if (( d_path = decode( av[ 2 ] )) == NULL ) {
		syslog( LOG_ERR, "f_stat: decode: buffer too small" );
		snet_writef( sn, "%d Line too long\r\n", 540 );
		return( 1 );
	    } 

	    /* Check for access */
	    if ( !list_check( access_list, d_path )) {
		syslog( LOG_WARNING | LOG_AUTH, "attempt to access: %s",
		    d_path );
		snet_writef( sn, "%d No access for %s\r\n", 540, d_path );
		return( 1 );
	    }

	    if ( snprintf( path, MAXPATHLEN, "command/%s", d_path )
		    >= MAXPATHLEN ) {
		syslog( LOG_ERR, "f_stat: command path too long" );
		snet_writef( sn, "%d Path too long\r\n", 540 );
		return( 1 );
	    }
	}
	break;

    case K_TRANSCRIPT:
	if (( d_tran = decode( av[ 2 ] )) == NULL ) {
	    syslog( LOG_ERR, "f_stat: decode: buffer too small" );
	    snet_writef( sn, "%d Line too long\r\n", 540 );
	    return( 1 );
	} 

	/* Check for access */
	if ( !list_check( access_list, d_tran )) {
	    syslog( LOG_WARNING | LOG_AUTH, "attempt to access: %s", d_tran );
	    snet_writef( sn, "%d No access for %s\r\n", 540, d_tran );
	    return( 1 );
	}

	if ( snprintf( path, MAXPATHLEN, "transcript/%s", d_tran )
		>= MAXPATHLEN ) {
	    syslog( LOG_ERR, "f_stat: transcript path too long" );
	    snet_writef( sn, "%d Path too long\r\n", 540 );
	    return( 1 );
	}
	break;

    case K_SPECIAL:
	if (( d_path = decode( av[ 2 ] )) == NULL ) {
	    syslog( LOG_ERR, "f_stat: decode: buffer too small" );
	    snet_writef( sn, "%d Line too long\r\n", 540 );
	    return( 1 );
	} 

	if ( snprintf( path, MAXPATHLEN, "%s/%s", special_dir, d_path) 
		>= MAXPATHLEN ) {
	    syslog( LOG_ERR, "f_stat: special path too long" );
	    snet_writef( sn, "%d Path too long\r\n", 540 );
	    return( 1 );
	}
	break;

    default:
	snet_writef( sn, "%d STAT Syntax error\r\n", 530 );
	return( 1 );
    }
        
    syslog( LOG_DEBUG, "f_stat: returning infomation for %s", path );

    if ( stat( path, &st ) < 0 ) {
        syslog( LOG_ERR, "f_stat: stat: %m" );
	snet_writef( sn, "%d Access Error: %s\r\n", 531, path );
	return( 1 );
    }

    /* XXX cksums here, totally the wrong place to do this! */
    OpenSSL_add_all_digests();
    md = EVP_get_digestbyname( "sha1" );
    if ( !md ) {
	/* XXX */
	fprintf( stderr, "%s: unsupported checksum\n", "sha1" );
	exit( 1 );
    }
    if ( do_cksum( path, cksum_b64 ) < 0 ) {
	syslog( LOG_ERR, "do_cksum: %s: %m", path );
	snet_writef( sn, "%d Checksum Error: %s: %m\r\n", 500, path );
	return( 1 );
    }

    snet_writef( sn, "%d Returning STAT information\r\n", 230 );
    switch ( key ) {
    case K_COMMAND:
	if ( ac == 2 ) {
	    snet_writef( sn, RADMIND_STAT_FMT,
		"f", "command", DEFAULT_MODE, DEFAULT_UID, DEFAULT_GID,
		st.st_mtime, st.st_size, cksum_b64 );
	} else {
	    snet_writef( sn, RADMIND_STAT_FMT,
		"f", av[ 2 ], DEFAULT_MODE, DEFAULT_UID, DEFAULT_GID,
		st.st_mtime, st.st_size, cksum_b64 );
	}
	return( 0 );
        
		    
    case K_TRANSCRIPT:
	snet_writef( sn, RADMIND_STAT_FMT,
		"f", av[ 2 ], 
		DEFAULT_MODE, DEFAULT_UID, DEFAULT_GID,
		st.st_mtime, st.st_size, cksum_b64 );
	return( 0 );
    
    case K_SPECIAL:
	/*
	 * store value of av[ 2 ], because argcargv will be called
	 * from special_t(), and that will blow away the current values
	 * for av[ 2 ].
	 */
	if (( enc_file = strdup( av[ 2 ] )) == NULL ) {
	    syslog( LOG_ERR, "f_stat: strdup: %s %m", av[ 2 ] );
	    return( -1 );
	}

	if (( av = special_t( path, enc_file )) == NULL ) {
	    /* no special transcript match found, return defaults. */
	    snet_writef( sn, RADMIND_STAT_FMT,
		    "f", enc_file, 
		    DEFAULT_MODE, DEFAULT_UID, DEFAULT_GID, 
		    st.st_mtime, st.st_size, cksum_b64 );
	    free( enc_file );
	    return( 0 );
	}
	snet_writef( sn, RADMIND_STAT_FMT,
		av[ 0 ], enc_file,
		av[ 2 ], av[ 3 ], av[ 4 ],
		st.st_mtime, st.st_size, cksum_b64 );

	free( enc_file );
	return( 0 );

    default:
        return( 1 );
    }
}
Beispiel #18
0
    int
f_help( SNET *sn, int ac, char *av[], SNET *pushersn )
{
    snet_writef( sn, "%d Slainte Mhath! http://weblogin.org\r\n", 203 );
    return( 0 );
}
Beispiel #19
0
    int
f_login( SNET *sn, int ac, char *av[], SNET *pushersn )
{
    FILE		*tmpfile;
    ACAV		*facav;
    char		tmppath[ MAXCOOKIELEN ], path[ MAXPATHLEN ];
    char		tmpkrb[ 16 ], krbpath [ MAXPATHLEN ];
    char                *sizebuf, *line;
    char                buf[ 8192 ];
    char		**fv;
    int			fd, i, j, fc, already_krb = 0;
    int			krb = 0, err = 1, addinfo = 0, newinfo = 0;
    struct timeval	tv;
    struct cinfo	ci;
    unsigned int        len, rc;
    extern int		errno;

    /*
     * C: LOGIN login_cookie ip principal factor [factor2]
     * S: 200 LOGIN successful: Cookie Stored.
     */

    /*
     * C: LOGIN login_cookie ip principal factor "kerberos"
     * S: 300 LOGIN: Send length then file.
     * C: [length]
     * C: [data]
     * C: .
     */

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

    if ( ac < 5 ) {
	syslog( LOG_ERR, "f_login: got %d args, need at least 5", ac );
	snet_writef( sn, "%d LOGIN: Wrong number of args.\r\n", 500 );
	return( 1 );
    }

    if ( ac >= 6 ) {
	if ( strcmp( av[ ac - 1 ], "kerberos" ) == 0 ) {
	    krb = 1;
	    ac--;
	    if ( mkcookie( sizeof( tmpkrb ), tmpkrb ) != 0 ) {
		syslog( LOG_ERR, "f_login: mkcookie error." );
		return( -1 );
	    }
	    if ( snprintf( krbpath, sizeof( krbpath ), "%s/%s",
		    cosign_tickets, tmpkrb ) >= sizeof( krbpath )) {
		syslog( LOG_ERR, "f_login: krbpath too long." );
		return( -1 );
	    }
	}
    }

    if ( mkcookiepath( NULL, hashlen, av[ 1 ], path, sizeof( path )) < 0 ) {
	syslog( LOG_ERR, "f_login: mkcookiepath error" );
	snet_writef( sn, "%d LOGIN: Invalid cookie path.\r\n", 501 );
	return( 1 );
    }

    if ( read_cookie( path, &ci ) == 0 ) {
	addinfo = 1;
	if ( ci.ci_state == 0 ) {
	    syslog( LOG_ERR,
		    "f_login: %s already logged out", av[ 1 ] );
	    snet_writef( sn, "%d LOGIN: Already logged out\r\n", 505 );
	    return( 1 );
	}
	if ( strcmp( av[ 3 ], ci.ci_user ) != 0 ) {
	    syslog( LOG_ERR, "%s in cookie %s does not match %s",
		    ci.ci_user, av[ 1 ], av[ 3 ] );
	    snet_writef( sn,
		"%d user name given does not match cookie\r\n", 402 );
	    return( 1 );
	}
    }

    if ( gettimeofday( &tv, NULL ) != 0 ) {
	syslog( LOG_ERR, "f_login: gettimeofday: %m" );
	return( -1 );
    }

    if ( snprintf( tmppath, sizeof( tmppath ), "%x%x.%i",
	    (int)tv.tv_sec, (int)tv.tv_usec, (int)getpid()) >=
	    sizeof( tmppath )) {
	syslog( LOG_ERR, "f_login: tmppath too long" );
	return( -1 );
    }

    if (( fd = open( tmppath, O_CREAT|O_EXCL|O_WRONLY, 0644 )) < 0 ) {
	syslog( LOG_ERR, "f_login: open: %s: %m", tmppath );
	return( -1 );
    }

    if (( tmpfile = fdopen( fd, "w" )) == NULL ) {
	/* close */
	if ( unlink( tmppath ) != 0 ) {
	    syslog( LOG_ERR, "f_login: unlink: %m" );
	}
	syslog( LOG_ERR, "f_login: fdopen: %m" );
	return( -1 );
    }

    fprintf( tmpfile, "v2\n" );
    fprintf( tmpfile, "s1\n" );	 /* 1 is logged in, 0 is logged out */

    if ( strlen( av[ 2 ] ) >= sizeof( ci.ci_ipaddr )) {
	goto file_err;
    }
    if ( addinfo ) {
	fprintf( tmpfile, "i%s\n", ci.ci_ipaddr );
    } else {
	fprintf( tmpfile, "i%s\n", av[ 2 ] );
    }

    if ( addinfo ) {
	if ( strcmp( ci.ci_ipaddr_cur, av[ 2 ] ) != 0 ) {
	    newinfo = 1;
	}
    }
    if ( strlen( av[ 2 ] ) >= sizeof( ci.ci_ipaddr_cur )) {
	goto file_err;
    }
    fprintf( tmpfile, "j%s\n", av[ 2 ] );

    if ( strlen( av[ 3 ] ) >= sizeof( ci.ci_user )) {
	goto file_err;
    }
    fprintf( tmpfile, "p%s\n", av[ 3 ] );
    if ( strlen( av[ 4 ] ) >= sizeof( ci.ci_realm )) {
	goto file_err;
    }

    if ( addinfo ) {
	if (( facav = acav_alloc()) == NULL ) {
	    syslog( LOG_ERR, "acav_alloc: %m" );
	    goto file_err;
	}
	if (( fc = acav_parse( facav, ci.ci_realm, &fv )) < 0 ) {
	    syslog( LOG_ERR, "acav_parse: %m" );
	    goto file_err;
	}
	fprintf( tmpfile, "r%s", fv[ 0 ] );
	for ( i = 1; i < fc; i++ ) {
	    fprintf( tmpfile, " %s", fv[ i ] );
	}
	for ( i = 4; i < ac; i++ ) {
	    for ( j = 0; j < fc; j++ ) {
		if ( strcmp( fv[ j ], av[ i ] ) == 0 ) {
		    break;
		}
	    }
	    if ( j >= fc ) {
		fprintf( tmpfile, " %s", av[ i ] );
		newinfo = 1;
	    }
	}
	if ( newinfo == 0 ) {
	    snet_writef( sn, "%d LOGIN Cookie Already Stored.\r\n", 202 );
	    if ( fclose ( tmpfile ) != 0 ) {
		syslog( LOG_ERR, "f_login: fclose: %m" );
	    }
	    if ( unlink( tmppath ) != 0 ) {
		syslog( LOG_ERR, "f_login: unlink %s: %m", tmppath );
	    }
	    return( 0 );
	}
    } else {
	fprintf( tmpfile, "r%s", av[ 4 ] );
	for ( i = 5; i < ac; i++ ) {
	    fprintf( tmpfile, " %s", av[ i ] );
	}
    }
    fprintf( tmpfile, "\n" );

    if ( addinfo ) {
	fprintf( tmpfile, "t%lu\n", ci.ci_itime);
    } else {
	fprintf( tmpfile, "t%lu\n", tv.tv_sec );
    }

    if ( krb ) {
	if (( addinfo ) && ( *ci.ci_krbtkt != '\0' )) {
	    fprintf( tmpfile, "k%s\n", ci.ci_krbtkt );
	    already_krb = 1;
	} else {
	    fprintf( tmpfile, "k%s\n", krbpath );
	}
    } else if ( *ci.ci_krbtkt != '\0' ) {
	fprintf( tmpfile, "k%s\n", ci.ci_krbtkt );
	already_krb = 1;
    }

    if ( fclose ( tmpfile ) != 0 ) {
	if ( unlink( tmppath ) != 0 ) {
	    syslog( LOG_ERR, "f_login: unlink %s: %m", tmppath );
	}
	syslog( LOG_ERR, "f_login: fclose: %m" );
	return( -1 );
    }

    if ( addinfo ) {
	if ( rename( tmppath, path ) != 0 ) {
	    syslog( LOG_ERR, "f_login: rename %s to %s: %m", tmppath, path );
	    err = -1;
	    goto file_err2;
	}
    } else {
	if ( link( tmppath, path ) != 0 ) {
	    syslog( LOG_ERR, "f_login: link %s to %s: %m", tmppath, path );
	    err = -1;
	    goto file_err2;
	}
	if ( unlink( tmppath ) != 0 ) {
	    syslog( LOG_ERR, "f_login: unlink %s: %m", tmppath );
	}
    }

    if (( !krb ) || ( already_krb )) {
	snet_writef( sn, "%d LOGIN successful: Cookie Stored.\r\n", 200 );
	if (( pushersn != NULL ) && ( !replicated )) {
	    snet_writef( pushersn, "LOGIN %s %s %s %s\r\n",
		    av[ 1 ], av[ 2 ], av[ 3 ], av[ 4 ]);
	}
	if ( !replicated ) {
	    syslog( LOG_INFO, "LOGIN %s %s %s", av[ 3 ], av [ 4 ], av [ 2 ] );
	}
	return( 0 );
    }

    snet_writef( sn, "%d LOGIN: Send length then file.\r\n", 300 );

    if (( fd = open( krbpath, O_CREAT|O_EXCL|O_WRONLY, 0644 )) < 0 ) {
	syslog( LOG_ERR, "f_login: open: %s: %m", krbpath );
	return( -1 );
    }

    tv = cosign_net_timeout;
    if (( sizebuf = snet_getline( sn, &tv )) == NULL ) {
        syslog( LOG_ERR, "f_login: snet_getline: %m" );
        return( -1 );
    }

    for ( len = atoi( sizebuf ); len > 0; len -= rc ) {
        tv = cosign_net_timeout;
        if (( rc = snet_read(
                sn, buf, (int)MIN( len, sizeof( buf )), &tv )) <= 0 ) {
            syslog( LOG_ERR, "f_login: snet_read: %m" );
            return( -1 );
        }

        if ( write( fd, buf, rc ) != rc ) {
	    syslog( LOG_ERR, "f_login: write to %s: %m", krbpath );
            snet_writef( sn, "%d %s: %s\r\n", 504, krbpath, strerror( errno ));
            return( 1 );
        }
    }

    if ( close( fd ) < 0 ) {
	syslog( LOG_ERR, "f_login: close %s: %m", krbpath );
        snet_writef( sn, "%d %s: %s\r\n", 504, krbpath, strerror( errno ));
        return( 1 );
    }


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

    /* make sure client agrees we're at the end */
    if ( strcmp( line, "." ) != 0 ) {
        snet_writef( sn, "%d Length doesn't match sent data\r\n", 505 );
        (void)unlink( krbpath );

	/* if the krb tkt didn't store, unlink the cookie as well */
	if ( unlink( av[ 1 ] ) != 0 ) {
	    syslog( LOG_ERR, "f_login: unlink: %m" );
	}

        tv = cosign_net_timeout;
        tv.tv_usec = 0;
        for (;;) {
            if (( line = snet_getline( sn, &tv )) == NULL ) {
                syslog( LOG_ERR, "f_login: snet_getline: %m" );
                exit( 1 );
            }
            if ( strcmp( line, "." ) == 0 ) {
                break;
            }
        }
        exit( 1 );
    }


    snet_writef( sn, "%d LOGIN successful: Cookie & Ticket Stored.\r\n", 201 );
    if (( pushersn != NULL ) && ( !replicated )) {
	snet_writef( pushersn, "LOGIN %s %s %s %s %s\r\n",
		av[ 1 ], av[ 2 ], av[ 3 ], av[ 4 ], av[ 5 ]);
    }
    if ( !replicated ) {
	syslog( LOG_INFO, "LOGIN %s %s %s", av[ 3 ], av [ 4 ], av [ 2 ] );
    }
    return( 0 );

file_err:
    (void)fclose( tmpfile );
    if ( unlink( tmppath ) != 0 ) {
	syslog( LOG_ERR, "f_login: unlink: %m" );
    }
    syslog( LOG_ERR, "f_login: bad file format" );
    snet_writef( sn, "%d LOGIN Syntax Error: Bad File Format\r\n", 504 );
    return( 1 );

file_err2:
    if ( unlink( tmppath ) != 0 ) {
	syslog( LOG_ERR, "f_login: unlink: %m" );
    }
    return( err );
}
Beispiel #20
0
    int
f_starttls( SNET *sn, int ac, char *av[], SNET *pushersn )
{
    int				rc;
    X509			*peer;
    char			buf[ 1024 ];

    /* STARTTLS with no additional parameters is assumed to be protocol 0 */
    if ( ac >= 2 ) {
	errno = 0;
	protocol = strtol( av[ 1 ], (char **)NULL, 10 );
	if ( !COSIGN_PROTO_MIN_REQUIRED( protocol, COSIGN_PROTO_V2) || errno ) {
	    if ( errno ) {
		syslog( LOG_ERR, "f_starttls: protocol: strtol %s: %s",
			av[ 1 ], strerror( errno ));
	    }
	    snet_writef( sn, "%d Protocol version %s unrecognized\r\n",
			 502, av[ 1 ] );

	    protocol = COSIGN_PROTO_V0;

	    return( 1 );
	}
    }

    snet_writef( sn, "%d Ready to start TLS\r\n", 220 );

    /*
     * Begin TLS
     */
    if (( rc = snet_starttls( sn, ctx, 1 )) != 1 ) {
	syslog( LOG_ERR, "f_starttls: snet_starttls: %s",
		ERR_error_string( ERR_get_error(), NULL ) );
	snet_writef( sn, "%d SSL didn't work error!\r\n", 501 );
	return( 1 );
    }
    if (( peer = SSL_get_peer_certificate( sn->sn_ssl ))
	    == NULL ) {
	syslog( LOG_ERR, "no peer certificate" );
	return( -1 );
    }

    X509_NAME_get_text_by_NID( X509_get_subject_name( peer ),
		NID_commonName, buf, sizeof( buf ));
    X509_free( peer );
    if (( al = authlist_find( buf )) == NULL ) {
	syslog( LOG_ERR, "f_starttls: No access for %s", buf );
	snet_writef( sn, "%d No access for %s\r\n", 401, buf );
	exit( 1 );
    }

    /* store CN for use with CHECK and RETR */
    if (( remote_cn = strdup( buf )) == NULL ) {
	syslog( LOG_ERR, "f_starttls: strdup %s: %m", buf );
	return( -1 );
    }

    syslog( LOG_INFO, "STARTTLS %s %d %s",
	    inet_ntoa( cosign_sin.sin_addr ), protocol, buf );

    commands = auth_commands;
    ncommands = sizeof( auth_commands ) / sizeof( auth_commands[ 0 ] );
    if ( COSIGN_PROTO_MIN_REQUIRED( protocol, COSIGN_PROTO_V2 )) {
	banner( sn );
    }
    return( 0 );
}
Beispiel #21
0
    int
f_help( SNET *sn, int ac, char **av )
{
    snet_writef( sn, "%d What is this, SMTP?\r\n", 203 );
    return( 0 );
}
Beispiel #22
0
    int
f_quit( SNET *sn, int ac, char *av[], SNET *pushersn )
{
    snet_writef( sn, "%d Service closing transmission channel\r\n", 221 );
    exit( 0 );
}
Beispiel #23
0
    int
f_noauth( SNET *sn, int ac, char **av )
{
    snet_writef( sn, "%d No access for %s\r\n", 500, remote_host );
    exit( 1 );
}
Beispiel #24
0
    int
f_login( SNET *sn, int ac, char **av )
{
    int				retval;
    pam_handle_t		*pamh;
    struct pam_conv		pam_conv = {
	(int (*)())exchange,
	NULL
    };

    if ( !checkuser ) {
	snet_writef( sn, "%d login not enabled\r\n", 502 );
	return( 1 );
    }
    /*
    if ( authlevel < 1 ) {
	snet_writef( sn, "%d login requires TLS\r\n", 503 );
	return( 1 );
    }
    */
    if ( ac != 3 ) {  
        snet_writef( sn, "%d Syntax error\r\n", 501 );
        return( 1 );
    }
    if ( user != NULL ) {
	free( user );
	user = NULL;
    }
    if ( password != NULL ) {
	free( password );
	password = NULL;
    }
    if (( user = strdup( av[ 1 ] )) == NULL ) {
	syslog( LOG_ERR, "f_login: strdup: %m" );
	return( -1 );
    }

    if (( password = strdup( av[ 2 ] )) == NULL ) {
	syslog( LOG_ERR, "f_login: strdup: %m" );
	return( -1 );
    }

    if (( retval =  pam_start( "radmind", user, &pam_conv,
	    &pamh )) != PAM_SUCCESS ) {
        syslog( LOG_ERR, "f_login: pam_start: %s\n",
	    pam_strerror( pamh, retval ));
        snet_writef( sn, "%d Authentication Failed\r\n", 535 );
	return( 1 );
    }

    /* is user really user? */
    if (( retval =  pam_authenticate( pamh, PAM_SILENT )) != PAM_SUCCESS ) {
        syslog( LOG_ERR, "f_login: pam_authenticate: %s\n",
	    pam_strerror( pamh, retval ));
        snet_writef( sn, "%d Authentication Failed\r\n", 535 );
	return( 1 );
    }
    free( password );

    /* permitted access? */
    if (( retval = pam_acct_mgmt( pamh, 0 )) != PAM_SUCCESS ) {
        syslog( LOG_ERR, "f_login: pam_acct_mgmt: %s\n",
	    pam_strerror( pamh, retval ));
        snet_writef( sn, "%d Authentication Failed\r\n", 535 );
	return( 1 );
    }

    if (( retval = pam_end( pamh, retval )) != PAM_SUCCESS ) {
        syslog( LOG_ERR, "f_login: pam_end: %s\n",
	    pam_strerror( pamh, retval ));
        snet_writef( sn, "%d Authentication Failed\r\n", 535 );
	return( 1 );
    }
    syslog( LOG_INFO, "%s: successfully logged in\n", user );
    snet_writef( sn, "%d %s successfully logged in\r\n", 205, user );
    authorized = 1;

    return( 0 );
}
Beispiel #25
0
    int
f_retr( SNET *sn, int ac, char **av )
{

    ssize_t		readlen;
    struct stat		st;
    struct timeval	tv;
    char		buf[8192];
    char		path[ MAXPATHLEN ];
    char		*d_path, *d_tran;
    int			fd;

    switch ( keyword( ac, av )) {
    case K_COMMAND:
	if ( ac == 2 ) { 

	    if ( snprintf( path, MAXPATHLEN, "command/%s", command_file )
		    >= MAXPATHLEN ) {
		syslog( LOG_ERR, "f_retr: command/%s: path too long",
		    command_file );
		snet_writef( sn, "%d Path too long\r\n", 540 );
		return( 1 );
	    }
	} else {
	    if (( d_path = decode( av[ 2 ] )) == NULL ) {
		syslog( LOG_ERR, "f_retr: decode: buffer too small" );
		snet_writef( sn, "%d Line too long\r\n", 540 );
		return( 1 );
	    } 

	    /* Check for access */
	    if ( !list_check( access_list, d_path )) {
		syslog( LOG_WARNING | LOG_AUTH, "attempt to access: %s",
		    d_path );
		snet_writef( sn, "%d No access for %s\r\n", 540, d_path );
		return( 1 );
	    }

	    if ( snprintf( path, MAXPATHLEN, "command/%s", d_path )
		    >= MAXPATHLEN ) {
		syslog( LOG_ERR, "f_retr: command path too long" );
		snet_writef( sn, "%d Path too long\r\n", 540 );
		return( 1 );
	    }
	}
	break;

    case K_TRANSCRIPT:
	if (( d_tran = decode( av[ 2 ] )) == NULL ) {
	    syslog( LOG_ERR, "f_retr: decode: buffer too small" );
	    snet_writef( sn, "%d Line too long\r\n", 540 );
	    return( 1 );
	} 

	/* Check for access */
	if ( !list_check( access_list, d_tran )) {
	    syslog( LOG_WARNING | LOG_AUTH, "attempt to access: %s", d_tran );
	    snet_writef( sn, "%d No access for %s\r\n", 540, d_tran );
	    return( 1 );
	}

	if ( snprintf( path, MAXPATHLEN, "transcript/%s", d_tran )
		>= MAXPATHLEN ) {
	    syslog( LOG_ERR, "f_retr: transcript path too long" );
	    snet_writef( sn, "%d Path too long\r\n", 540 );
	    return( 1 );
	}
	break;

    case K_SPECIAL:
	if (( d_path = decode( av[ 2 ] )) == NULL ) {
	    syslog( LOG_ERR, "f_retr: decode: buffer too small" );
	    snet_writef( sn, "%d Line too long\r\n", 540 );
	    return( 1 );
	} 

	if ( snprintf( path, MAXPATHLEN, "%s/%s", special_dir, d_path )
		>= MAXPATHLEN ) {
	    syslog( LOG_ERR, "f_retr: special path too long" );
	    snet_writef( sn, "%d Path too long\r\n", 540 );
	    return( 1 );
	}

	break;

    case K_FILE:
	if (( d_path = decode( av[ 3 ] )) == NULL ) {
	    syslog( LOG_ERR, "f_retr: 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_retr: strdup: %s: %m", d_path );
	    return( -1 );
	}
	if (( d_tran = decode( av[ 2 ] )) == NULL ) {
	    syslog( LOG_ERR, "f_retr: decode: buffer too small" );
	    snet_writef( sn, "%d Line too long\r\n", 540 );
	    return( 1 );
	} 

	/* Check for access */
	if ( !list_check( access_list, d_tran )) {
	    syslog( LOG_WARNING | LOG_AUTH, "attempt to access: %s", d_tran );
	    snet_writef( sn, "%d No access for %s:%s\r\n", 540, d_tran,
		d_path );
	    return( 1 );
	}

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

    default:
	snet_writef( sn, "%d RETR Syntax error\r\n", 540 );
	return( 1 );
    }

    if (( fd = open( path, O_RDONLY, 0 )) < 0 ) {
    	syslog( LOG_ERR, "open: %s: %m", path );
	snet_writef( sn, "%d Unable to access %s.\r\n", 543, path );
	return( 1 );
    }
    
    /* dump file info */

    if ( fstat( fd, &st ) < 0 ) { 
	syslog( LOG_ERR, "f_retr: fstat: %m" );
	snet_writef( sn, "%d Access Error: %s\r\n", 543, path );
	if ( close( fd ) < 0 ) {
	    syslog( LOG_ERR, "close: %m" );
	    return( -1 );
	}
	return( 1 );
    }

    /*
     * Here's a problem.  Do we need to add long long support to
     * snet_writef?
     */
    snet_writef( sn, "240 Retrieving file\r\n%" PRIofft "d\r\n", st.st_size );

    /* dump file */

    while (( readlen = read( fd, buf, sizeof( buf ))) > 0 ) {
	tv.tv_sec = 60 ;
	tv.tv_usec = 0;
	if ( snet_write( sn, buf, readlen, &tv ) != readlen ) {
	    syslog( LOG_ERR, "snet_write: %m" );
	    return( -1 );
	}
    }

    if ( readlen < 0 ) {
	syslog( LOG_ERR, "read: %m" );
	return( -1 );
    }

    snet_writef( sn, ".\r\n" );

    if ( close( fd ) < 0 ) {
        syslog( LOG_ERR, "close: %m" );
	return( -1 );
    }

    syslog( LOG_DEBUG, "f_retr: 'file' %s retrieved", path );

    return( 0 );
}
Beispiel #26
0
    int
f_notauth( SNET *sn, int ac, char *av[], SNET *pushersn )
{
    snet_writef( sn, "%d You must call STARTTLS first!\r\n", 550 );
    return( 0 );
}
Beispiel #27
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 );
}
Beispiel #28
0
    int
f_register( SNET *sn, int ac, char *av[], SNET *pushersn )
{
    struct cinfo	ci;
    struct timeval	tv;
    int			rc;
    char		lpath[ MAXPATHLEN ], spath[ MAXPATHLEN ];

    /* REGISTER login_cookie ip service_cookie */

    if ( al->al_key != CGI ) {
	syslog( LOG_ERR, "f_register: %s not allowed", al->al_hostname );
	snet_writef( sn, "%d REGISTER: %s not allowed to register.\r\n",
		420, al->al_hostname );
	return( 1 );
    }

    if ( ac != 4 ) {
	syslog( LOG_ERR, "f_register: %s wrong number of args.",
		al->al_hostname );
	snet_writef( sn, "%d REGISTER: Wrong number of args.\r\n", 520 );
	return( 1 );
    }

    if ( mkcookiepath( NULL, hashlen, av[ 1 ], lpath, sizeof( lpath )) < 0 ) {
	syslog( LOG_ERR, "f_register: mkcookiepath login cookie error" );
	snet_writef( sn, "%d REGISTER: Invalid cookie path.\r\n", 521 );
	return( 1 );
    }

    if ( mkcookiepath( NULL, hashlen, av[ 3 ], spath, sizeof( spath )) < 0 ) {
	syslog( LOG_ERR, "f_register: mkcookiepath service cookie error" );
	snet_writef( sn, "%d REGISTER: Invalid cookie path.\r\n", 522 );
	return( 1 );
    }

    if ( read_cookie( lpath, &ci ) != 0 ) {
	snet_writef( sn, "%d REGISTER error: Sorry\r\n", 523 );
	return( 1 );
    }

    if ( ci.ci_state == 0 ) {
	syslog( LOG_ERR,
		"f_register: %s logged out, can't register", ci.ci_user );
	snet_writef( sn, "%d REGISTER: Already logged out\r\n", 421 );
	return( 1 );
    }

    /* check for idle timeout, and if so, log'em out */
    if ( gettimeofday( &tv, NULL ) != 0 ){
	syslog( LOG_ERR, "f_register: gettimeofday: %m" );
	return( -1 );
    }

    if ( tv.tv_sec - ci.ci_itime >= idle_out_time ) {
	if ( tv.tv_sec - ci.ci_itime < ( idle_out_time + grey_time )) {
	    syslog( LOG_NOTICE, "f_register: idle grey window" );
	    snet_writef( sn, "%d REGISTER: Idle Grey Window\r\n", 521 );
	    return( 1 );
	}
	snet_writef( sn, "%d REGISTER: Idle logged out\r\n", 422 );
	if ( do_logout( lpath ) < 0 ) {
	    syslog( LOG_ERR, "f_register: %s: %m", lpath );
	    return( -1 );
	}
	return( 1 );
    }

    if (( rc = do_register( av[ 1 ], lpath, spath )) < 0 ) {
	return( -1 );
    }

    /* double action policy?? */
    if ( rc > 0 ) {
	snet_writef( sn,
		"%d REGISTER error: Cookie already exists\r\n", 226 );
	return( rc );
    }

    snet_writef( sn, "%d REGISTER successful: Cookie Stored.\r\n", 220 );
    if (( pushersn != NULL ) && ( !replicated )) {
	snet_writef( pushersn, "REGISTER %s %s %s\r\n",
		av[ 1 ], av[ 2 ], av [ 3 ] );
    }
    if ( !replicated ) {
	/* just log service name, no need for full cookie */
	(void)strtok( av[ 3 ], "=" );
	syslog( LOG_INFO, "REGISTER %s %s %s %s", 
		ci.ci_user, ci.ci_realm, ci.ci_ipaddr, av[ 3 ] );
    }
    return( 0 );
}
Beispiel #29
0
    int
f_starttls( SNET *sn, int ac, char **av )
{
    int                         rc;
    X509                        *peer;
    char                        buf[ 1024 ];

    if ( ac != 1 ) {  
        snet_writef( sn, "%d Syntax error (no parameters allowed)\r\n", 501 );
        return( 1 );
    } else {
	snet_writef( sn, "%d Ready to start TLS\r\n", 220 );
    }

    /* We get here when the client asks for TLS with the STARTTLS verb */
    /*
     * Client MUST NOT attempt to start a TLS session if a TLS     
     * session is already active.  No mention of what to do if it does...
     *
     * Once STARTTLS has succeeded, the STARTTLS verb is no longer valid
     */

    /*
     * Begin TLS
     */
    /* This is where the TLS start */
    /* At this point the client is also starting TLS */
    /* 1 is for server, 0 is client */
    if (( rc = snet_starttls( sn, ctx, 1 )) != 1 ) {
        syslog( LOG_ERR, "f_starttls: snet_starttls: %s",
                ERR_error_string( ERR_get_error(), NULL ) );
        snet_writef( sn, "%d SSL didn't work error! XXX\r\n", 501 );
        return( 1 );
    }

    if ( authlevel >= 2 ) {
	if (( peer = SSL_get_peer_certificate( sn->sn_ssl ))
		== NULL ) {
	    syslog( LOG_ERR, "no peer certificate" );
	    return( -1 );
	}

	syslog( LOG_INFO, "CERT Subject: %s\n",
	    X509_NAME_oneline( X509_get_subject_name( peer ), buf,
	    sizeof( buf )));

	X509_NAME_get_text_by_NID( X509_get_subject_name( peer ),
	    NID_commonName, buf, sizeof( buf ));
	if (( remote_cn = strdup( buf )) == NULL ) {
	    syslog( LOG_ERR, "strdup: %m" );
	    X509_free( peer );
	    return( -1 );
	}
	X509_free( peer );
    }

    /* get command file */
    if ( command_k( "config", 0 ) < 0 ) {
	/* Client not in config */
	commands  = noauth;
	ncommands = sizeof( noauth ) / sizeof( noauth[ 0 ] );
    } else {
	/* Client in config */
	commands  = auth;
	ncommands = sizeof( auth ) / sizeof( auth[ 0 ] );

	if ( read_kfile( sn, command_file ) != 0 ) {
	    /* error message given in list_transcripts */
	    exit( 1 );
	}
    }

    return( 0 );
}
Beispiel #30
0
    int
f_check( SNET *sn, int ac, char *av[], SNET *pushersn )
{
    struct cinfo 	ci;
    struct timeval	tv;
    char		login[ MAXCOOKIELEN ], path[ MAXPATHLEN ];
    char		rekeybuf[ 128 ], rcookie[ 256 ], scpath[ MAXPATHLEN ];
    char		*p;
    int			status;
    double		rate;

    /*
     * C: CHECK servicecookie
     * S: 231 ip principal realm
     */

    /*
     * C: CHECK logincookie
     * S: 232 ip principal realm
     */

    /*
     * C: REKEY servicecookie
     * S: 233 ip principal realm rekeyed-cookie
     */

    if (( al->al_key != CGI ) && ( al->al_key != SERVICE )) {
	syslog( LOG_ERR, "f_check: %s not allowed", al->al_hostname );
	snet_writef( sn, "%d %s: %s not allowed to check.\r\n",
		430, av[ 0 ], al->al_hostname );
	return( 1 );
    }

    if ( ac < 2 || ac > 3 ) {
	syslog( LOG_ERR, "f_check: %s: wrong number of args. "
		"Expected 2 or 3, got %d", al->al_hostname, ac );
	snet_writef( sn, "%d %s: Wrong number of args.\r\n", 530, av[ 0 ] );
	return( 1 );
    }

    if ( mkcookiepath( NULL, hashlen, av[ 1 ], path, sizeof( path )) < 0 ) {
	syslog( LOG_ERR, "f_check: mkcookiepath error" );
	snet_writef( sn, "%d %s: Invalid cookie name.\r\n", 531, av[ 0 ] );
	return( 1 );
    }

    if ( strncmp( av[ 1 ], "cosign-", 7 ) == 0 ) {
	if ( strict_checks && service_valid( av[ 1 ] ) == NULL ) {
	    snet_writef( sn, "%d %s: Invalid cookie\r\n", 534, av[ 0 ] );
	    return( 1 );
	}

	status = 231;
	if ( service_to_login( path, login ) != 0 ) {
	    if (( rate = rate_tick( &checkunknown )) != 0.0 ) {
		syslog( LOG_NOTICE, "STATS CHECK %s: UNKNOWN %.5f / sec",
			inet_ntoa( cosign_sin.sin_addr), rate );
	    }
	    snet_writef( sn, "%d %s: cookie not in db!\r\n", 533, av[ 0 ] );
	    return( 1 );
	}
	if ( COSIGN_PROTO_SUPPORTS_REKEY( protocol )) {
	    if ( strcasecmp( av[ 0 ], "REKEY" ) == 0 ) {

		/* save service cookie path for rekeying below. */
		if ( strlen( path ) >= sizeof( scpath )) {
		    syslog( LOG_ERR, "f_check: %s exceeds bounds.", path );
		    snet_writef( sn, "%d %s: Invalid cookie name.\r\n",
				 531, av[ 0 ]);
		    return( 1 );
		}
		strcpy( scpath, path );

		status = 233;
	    }
	}

	if ( mkcookiepath( NULL, hashlen, login, path, sizeof( path )) < 0 ) {
	    syslog( LOG_ERR, "f_check: mkcookiepath error.." );
	    snet_writef( sn, "%d %s: Invalid cookie name.\r\n", 532, av[ 0 ] );
	    return( 1 );
	}
    } else if ( strncmp( av[ 1 ], "cosign=", 7 ) == 0 ) {
	status = 232;
    } else {
	syslog( LOG_ERR, "f_check: unknown cookie prefix." );
	snet_writef( sn, "%d %s: unknown cookie prefix!\r\n", 432, av[ 0 ] );
	return( 1 );
    }

    if ( read_cookie( path, &ci ) != 0 ) {
	if (( rate = rate_tick( &checkunknown )) != 0.0 ) {
	    syslog( LOG_NOTICE, "STATS CHECK %s: UNKNOWN %.5f / sec",
		    inet_ntoa( cosign_sin.sin_addr), rate);
	}
	snet_writef( sn, "%d %s: Who me? Dunno.\r\n", 534, av[ 0 ] );
	return( 1 );
    }

    if ( ci.ci_state == 0 ) {
	if (( rate = rate_tick( &checkfail )) != 0.0 ) {
	    syslog( LOG_NOTICE, "STATS CHECK %s: FAIL %.5f / sec",
		    inet_ntoa( cosign_sin.sin_addr), rate);
	}
	snet_writef( sn, "%d %s: Already logged out\r\n", 430, av[ 0 ] );
	return( 1 );
    }

    /* check for idle timeout, and if so, log'em out */
    if ( gettimeofday( &tv, NULL ) != 0 ){
	syslog( LOG_ERR, "f_check: gettimeofday: %m" );
	return( -1 );
    }

    if ( tv.tv_sec - ci.ci_itime >= idle_out_time ) {
	if ( tv.tv_sec - ci.ci_itime < ( idle_out_time + grey_time )) {
	    if (( rate = rate_tick( &checkunknown )) != 0.0 ) {
		syslog( LOG_NOTICE, "STATS CHECK %s: UNKNOWN %.5f / sec",
			inet_ntoa( cosign_sin.sin_addr ), rate );
	    }
	    syslog( LOG_NOTICE, "f_check: idle grey window" );
	    snet_writef( sn, "%d %s: Idle Grey Window\r\n", 531, av[ 0 ] );
	    return( 1 );
	}
	if (( rate = rate_tick( &checkfail )) != 0.0 ) {
	    syslog( LOG_NOTICE, "STATS CHECK %s: FAIL %.5f / sec",
		    inet_ntoa( cosign_sin.sin_addr), rate);
	}
	snet_writef( sn, "%d %s: Idle logged out\r\n", 431, av[ 0 ] );
	if ( do_logout( path ) < 0 ) {
	    syslog( LOG_ERR, "f_check: %s: %m", login );
	    return( -1 );
	}
	return( 1 );
    }

    /* prevent idle out if we are actually using it */
    utime( path, NULL );

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

    if ( status == 233 ) {
	/* rekey service cookie. */

	if ( mkcookie( sizeof( rekeybuf ), rekeybuf ) != 0 ) {
	    syslog( LOG_ERR, "f_check: rekey: mkcookie failed" );
	    snet_writef( sn, "%d %s: rekey failed.\r\n", 536, av[ 0 ] );
	    return( 1 );
	}
	if (( p = strchr( av[ 1 ], '=' )) == NULL ) {
	    syslog( LOG_ERR, "f_check: rekey: bad service name \"%s\".", av[1]);
	    snet_writef( sn, "%d %s rekey failed.\r\n", 536, av[ 0 ] );
	    return( 1 );
	}
	*p = '\0';
	if ( snprintf( rcookie, sizeof( rcookie ), "%s=%s", av[ 1 ], rekeybuf )
		>= sizeof( rcookie )) {
	    syslog( LOG_ERR, "f_check: rekey: new cookie too long." );
	    snet_writef( sn, "%d %s rekey failed.\r\n", 536, av[ 0 ] );
	    return( 1 );
	}
	*p = '=';
	if ( mkcookiepath( NULL, hashlen, rcookie, path, sizeof( path )) < 0 ) {
	    syslog( LOG_ERR, "f_check: rekey: mkcookiepath error." );
	    snet_writef( sn, "%d %s: rekey failed.\r\n", 536, av[ 0 ] );
	    return( 1 );
	}
	if ( rename( scpath, path ) != 0 ) {
	    syslog( LOG_ERR, "f_check: rekey: rename %s to %s failed: %s.",
			scpath, path, strerror( errno ));
	    snet_writef( sn, "%d %s: rekey failed.\r\n", 536, av[ 0 ] );
	    return( 1 );
	}
    }

    if ( COSIGN_PROTO_SUPPORTS_FACTORS( protocol )) {
	snet_writef( sn, "%d %s %s %s %s\r\n",
		status, ci.ci_ipaddr_cur, ci.ci_user, ci.ci_realm,
		( status == 233 ? rcookie : "" ));
    } else {
	/* if there is more than one realm, we just give the first */
	if (( p = strtok( ci.ci_realm, " " )) != NULL ) {
	    snet_writef( sn, "%d %s %s %s\r\n",
		    status, ci.ci_ipaddr, ci.ci_user, p );
	} else {
	    snet_writef( sn, "%d %s %s %s\r\n",
		    status, ci.ci_ipaddr, ci.ci_user, ci.ci_realm );
	}

    }
    return( 0 );
}