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 ); }
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 ); }
int acav_parse( ACAV *acav, char *line, char **argv[] ) { int ac; int state; if ( acav == NULL ) { if ( acavg == NULL ) { acavg = acav_alloc(); } acav = acavg; } ac = 0; state = ACV_WHITE; while ( *line != '\0' ) { switch ( *line ) { case ' ' : case '\t' : case '\n' : if ( state == ACV_WORD ) { *line = '\0'; state = ACV_WHITE; } break; case '"' : if ( acav->acv_flags & ACV_FLAG_QUOTE ) { memmove( line, line + 1, strlen( line )); if ( state & ACV_DQUOTE ) { state &= ~ACV_DQUOTE; continue; /* don't increment line */ } else { state |= ACV_DQUOTE; } } /* fall through */ default : if (( acav->acv_flags & ACV_FLAG_BACKSLASH ) && *line == '\\' ) { memmove( line, line + 1, strlen( line )); } if ( !( state & ACV_WORD )) { acav->acv_argv[ ac++ ] = line; if ( ac >= acav->acv_argc ) { /* realloc */ if (( acav->acv_argv = (char **)realloc( acav->acv_argv, sizeof( char * ) * ( acav->acv_argc + ACV_ARGC ))) == NULL ) { return( -1 ); } acav->acv_argc += ACV_ARGC; } state |= ACV_WORD; } } line++; } acav->acv_argv[ ac ] = NULL; *argv = acav->acv_argv; return( ac ); }