Exemplo n.º 1
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 );
}
Exemplo n.º 2
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 );
}
Exemplo n.º 3
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 );
}