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 ); }
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 ); }