int main( int argc, char *argv[] ) { SNET *snet; char *hold = NULL; char *line; if ( argc < 2 ) { exit( 1 ); } if (( snet = snet_open( argv[ 1 ], O_RDONLY, 0, 1024 * 1024 )) == NULL ) { fprintf( stderr, "%s: snet_open %s: ", argv[ 0 ], argv[ 1 ] ); perror( NULL ); } while (( line = snet_getline( snet, NULL )) != NULL ) { if (( hold != NULL ) && ( strncmp( hold, line, 16 ) != 0 )) { if ( strcmp( hold, line ) != 0 ) { printf( "%s\n", hold ); } printf( "%s\n", line ); } free( hold ); hold = strdup( line ); } exit( 0 ); }
int main( int argc, char *argv[]) { int fd; SNET *snet; char *line; u_int line_len; struct message_digest md; if ( argc != 3 ) { fprintf( stderr, "Usage: %s <checksum_algorithm> <file>\n", argv[ 0 ]); return( 1 ); } /* OpenSSL 1.1.0 added auto-init */ #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) OpenSSL_add_all_digests(); #endif /* OpenSSL < 1.1.0 */ simta_checksum_md = EVP_get_digestbyname((const char*)(argv[ 1 ])); if ( simta_checksum_md == NULL ) { fprintf( stderr, "%s: unknown checksum algorithm\n", argv[ 1 ]); return( 1 ); } md_init( &md ); md_reset( &md ); if (( fd = open( argv[ 2 ], O_RDONLY, 0 )) < 0 ) { perror( "open" ); exit( 1 ); } if (( snet = snet_attach( fd, 1024 * 1024 )) == NULL ) { perror( "snet_attach" ); exit( 1 ); } while (( line = snet_getline( snet, NULL )) != NULL ) { line_len = strlen( line ); md_update( &md, line, line_len ); } md_finalize( &md ); md_cleanup( &md ); if ( snet_close( snet ) != 0 ) { perror( "snet_close" ); return( 1 ); } printf( "\nChecksum: %s\n", md.md_b16 ); return( 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 ); }
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 ); }
/* sets command file for connected host */ int command_k( char *path_config, int depth ) { SNET *sn; char **av, *line, *p; char *valid_host; char temp[ MAXPATHLEN ]; int ac; int rc = -1; int linenum = 0; if (( sn = snet_open( path_config, O_RDONLY, 0, 0 )) == NULL ) { syslog( LOG_ERR, "command_k: snet_open: %s: %m", path_config ); return( -1 ); } while (( line = snet_getline( sn, NULL )) != NULL ) { linenum++; if (( ac = argcargv( line, &av )) < 0 ) { syslog( LOG_ERR, "argvargc: %m" ); goto command_k_done; } if ( ( ac == 0 ) || ( *av[ 0 ] == '#' ) ) { continue; } if ( ac < 2 ) { syslog( LOG_ERR, "%s: line %d: invalid number of arguments", path_config, linenum ); continue; } if ( strcmp( av[ 0 ], "@include" ) == 0 ) { if ( depth >= RADMIND_MAX_INCLUDE_DEPTH ) { syslog( LOG_ERR, "%s: line %d: include %s exceeds max depth", path_config, linenum, av[ 1 ] ); goto command_k_done; } if ( ac > 3 ) { syslog( LOG_ERR, "%s: line %d: invalid number of arguments", path_config, linenum ); continue; } else if ( ac == 3 ) { if ( match_config_entry( av[ 2 ] ) == NULL ) { /* connecting host doesn't match pattern, skip include. */ continue; } } if ( command_k( av[ 1 ], depth + 1 ) != 0 ) { continue; } rc = 0; goto command_k_done; } if (( ac > 2 ) && ( *av[ 2 ] != '#' )) { syslog( LOG_ERR, "%s: line %d: invalid number of arguments", path_config, linenum ); continue; } if (( p = strrchr( av[ 1 ], '/' )) == NULL ) { sprintf( special_dir, "special" ); } else { *p = '\0'; if ( snprintf( special_dir, MAXPATHLEN, "special/%s", av[ 1 ] ) >= MAXPATHLEN ) { syslog( LOG_ERR, "config file: line %d: path too long\n", linenum ); continue; } *p = '/'; } if (( valid_host = match_config_entry( av[ 0 ] )) != NULL ) { if ( strlen( av[ 1 ] ) >= MAXPATHLEN ) { syslog( LOG_ERR, "config file: line %d: command file too long\n", linenum ); continue; } strcpy( command_file, av[ 1 ] ); if ( snprintf( temp, MAXPATHLEN, "%s/%s", special_dir, valid_host ) >= MAXPATHLEN ) { syslog( LOG_ERR, "config file: line %d: special dir too long\n", linenum ); continue; } strcpy( special_dir, temp ); rc = 0; goto command_k_done; } } /* If we get here, the host that connected is not in the config file. So screw him. */ syslog( LOG_ERR, "host %s not in config file %s", remote_host, path_config ); command_k_done: snet_close( sn ); return( rc ); }
int read_scookie( char *path, struct sinfo *si, void *s ) { SNET *sn; struct stat st; char *p, *line; memset( si, 0, sizeof( struct sinfo )); if (( sn = snet_open( path, O_RDONLY, 0, 0 )) == NULL ) { if ( errno != ENOENT ) { perror( path ); } return( 1 ); } if ( fstat( snet_fd( sn ), &st ) != 0 ) { (void)snet_close( sn ); perror( path ); return( -1 ); } si->si_itime = st.st_mtime; while (( line = snet_getline( sn, NULL )) != NULL ) { p = line + 1; switch( line[0] ) { case 'v': errno = 0; si->si_protocol = strtol( p, (char **)NULL, 10 ); if ( errno ) { cosign_log( APLOG_NOTICE, s, "mod_cosign: read_scookie: " "invalid protocol version %s, " "falling back to protocol v0.", p ); si->si_protocol = 0; } break; case 'i': strcpy( si->si_ipaddr, p ); break; case 'p': strcpy( si->si_user, p ); break; case 'r': strcpy( si->si_realm, p ); break; case 'f': strcpy( si->si_factor, p ); break; #ifdef KRB case 'k': strcpy( si->si_krb5tkt, p ); break; #endif /* KRB */ default: cosign_log( APLOG_ERR, s, "mod_cosign: read_scookie: unknown key %c", line[0] ); (void)snet_close( sn ); return( -1 ); } } if ( snet_close( sn ) != 0 ) { cosign_log( APLOG_ERR, s, "mod_cosign: read_scookie: %s", path ); return( -1 ); } return( 0 ); }
int env_read( int mode, struct envelope *env, SNET **s_lock ) { char *line; SNET *snet; char filename[ MAXPATHLEN + 1 ]; char *hostname; int ret = 1; ino_t dinode; int version; int exp_level; int jail; int line_no = 1; struct dll_entry *e_dll; switch ( mode ) { default: syslog( LOG_ERR, "Envelope.read unknown mode: %d", mode ); return( 1 ); case READ_QUEUE_INFO: if ( s_lock != NULL ) { syslog( LOG_ERR, "Envelope.read no lock allowed in READ_QUEUE_INFO mode" ); return( 1 ); } break; case READ_DELIVER_INFO: case READ_JAIL_INFO: break; } sprintf( filename, "%s/E%s", env->e_dir, env->e_id ); if (( snet = snet_open( filename, O_RDWR, 0, 1024 * 1024 )) == NULL ) { if ( errno != ENOENT ) { syslog( LOG_ERR, "Syserror: env_read snet_open %s: %m", filename ); } return( 1 ); } switch ( mode ) { default: syslog( LOG_ERR, "Envelope.read invalid mode change: %d", mode ); goto cleanup; case READ_QUEUE_INFO: /* test to see if env is locked by a q_runner */ if ( lockf( snet_fd( snet ), F_TEST, 0 ) != 0 ) { syslog( LOG_ERR, "Syserror: env_read lockf %s: %m", filename ); goto cleanup; } break; case READ_DELIVER_INFO: case READ_JAIL_INFO: if ( s_lock != NULL ) { *s_lock = snet; /* lock envelope fd */ if ( lockf( snet_fd( snet ), F_TLOCK, 0 ) != 0 ) { if ( errno != EAGAIN ) { /* file not locked by a diferent process */ syslog( LOG_ERR, "Syserror: env_read lockf %s: %m", filename ); } goto cleanup; } } break; } /* Vsimta-version */ if ((( line = snet_getline( snet, NULL )) == NULL ) || ( *line != 'V' )) { syslog( LOG_ERR, "Envelope.read %s %d: expected version syntax", filename, line_no ); goto cleanup; } sscanf( line + 1, "%d", &version ); if (( version < 1 ) || ( version > SIMTA_EFILE_VERSION )) { syslog( LOG_ERR, "Envelope.read %s %d: unsupported efile version %d", filename, line_no, version ); goto cleanup; } if ( version >= 2 ) { /* Emessage-id */ line_no++; if ((( line = snet_getline( snet, NULL )) == NULL ) || ( *line != 'E' )) { syslog( LOG_ERR, "Envelope.read %s %d: expected Equeue-id syntax", filename, line_no ); goto cleanup; } if ( strcmp( line + 1, env->e_id ) != 0 ) { syslog( LOG_WARNING, "Envelope.read %s %d: queue-id mismatch: %s", filename, line_no, line + 1 ); goto cleanup; } } line_no++; if (( line = snet_getline( snet, NULL )) == NULL ) { syslog( LOG_ERR, "Envelope.read %s %d: expected Dinode syntax", filename, line_no ); goto cleanup; } /* ignore optional M for now */ if ( *line == 'M' ) { line_no++; if (( line = snet_getline( snet, NULL )) == NULL ) { syslog( LOG_ERR, "Envelope.read %s %d: expected Dinode syntax", filename, line_no ); goto cleanup; } } /* Dinode info */ if ( *line != 'I' ) { syslog( LOG_ERR, "Envelope.read %s %d: expected Dinode syntax", filename, line_no ); goto cleanup; } sscanf( line + 1, "%lu", &dinode ); switch ( mode ) { default: syslog( LOG_ERR, "Envelope.read invalid mode change: %d", mode ); goto cleanup; case READ_JAIL_INFO: case READ_DELIVER_INFO: if ( dinode != env->e_dinode ) { syslog( LOG_WARNING, "Envelope.read %s %d: Dinode reread mismatch: " "old %d new %d, ignoring", filename, line_no, (int)env->e_dinode, (int)dinode ); } break; case READ_QUEUE_INFO: if ( dinode == 0 ) { syslog( LOG_WARNING, "Envelope.read %s %d: Dinode is 0", filename, line_no ); } env->e_dinode = dinode; break; } /* expansion info */ if ( version >= 3 ) { line_no++; if ((( line = snet_getline( snet, NULL )) == NULL ) || ( *line != 'X' )) { syslog( LOG_ERR, "Envelope.read %s %d: expected Xpansion syntax", filename, line_no ); goto cleanup; } if ( sscanf( line + 1, "%d", &exp_level) != 1 ) { syslog( LOG_ERR, "Envelope.read %s %d: bad Xpansion syntax", filename, line_no ); goto cleanup; } switch ( mode ) { default: syslog( LOG_ERR, "Envelope.read: invalid mode change: %d", mode ); goto cleanup; case READ_DELIVER_INFO: case READ_JAIL_INFO: if ( exp_level == env->e_n_exp_level ) { break; } syslog( LOG_WARNING, "Envelope.read %s %d: Xpansion mismatch: " "old %d new %d, ignoring", filename, line_no, env->e_n_exp_level, exp_level ); break; case READ_QUEUE_INFO: env->e_n_exp_level = exp_level; break; } } /* Jail info */ if ( version >= 5 ) { line_no++; if ((( line = snet_getline( snet, NULL )) == NULL ) || ( *line != 'J' )) { syslog( LOG_ERR, "Envelope.read %s %d: expected Jail syntax", filename, line_no ); goto cleanup; } if ( sscanf( line + 1, "%d", &jail) != 1 ) { syslog( LOG_ERR, "Envelope.read %s %d: bad Jail syntax", filename, line_no ); goto cleanup; } switch ( mode ) { default: syslog( LOG_ERR, "Envelope.read: invalid mode change: %d", mode ); goto cleanup; case READ_JAIL_INFO: case READ_DELIVER_INFO: if ( env->e_jail == jail ) { break; } syslog( LOG_WARNING, "Envelope.read %s %d: Jail mismatch: " "old %d new %d, ignoring", filename, line_no, env->e_jail, jail ); break; case READ_QUEUE_INFO: env_jail_set( env, jail ); break; } } line_no++; if ((( line = snet_getline( snet, NULL )) == NULL ) || ( *line != 'H' )) { syslog( LOG_ERR, "Envelope.read %s %d: expected host syntax", filename, line_no ); goto cleanup; } hostname = line + 1; switch ( mode ) { default: syslog( LOG_ERR, "Envelope.read: invalid mode change: %d", mode ); goto cleanup; case READ_DELIVER_INFO: case READ_JAIL_INFO: if ( env->e_hostname == NULL ) { if ( *hostname != '\0' ) { syslog( LOG_ERR, "Envelope.read %s %d: hostname reread mismatch, " "old \"\" new \"%s\"", filename, line_no, hostname ); goto cleanup; } } else if ( strcasecmp( hostname, env->e_hostname ) != 0 ) { syslog( LOG_ERR, "Envelope.read %s %d: hostname reread mismatch, " "old \"%s\" new \"%s\"", filename, line_no, env->e_hostname, hostname ); goto cleanup; } break; case READ_QUEUE_INFO: if ( env_hostname( env, hostname ) != 0 ) { goto cleanup; } break; } /* Dattributes */ if ( version >= 4 ) { line_no++; if (( line = snet_getline( snet, NULL )) == NULL ) { syslog( LOG_ERR, "Envelope.read %s: unexpected EOF", filename ); goto cleanup; } if ( *line != 'D' ) { syslog( LOG_ERR, "Envelope.read %s: expected Dattributes syntax", filename ); goto cleanup; } if ( sscanf( line + 1, "%d", &exp_level) != 1 ) { syslog( LOG_ERR, "Envelope.read %s: bad Dattributes syntax", filename ); goto cleanup; } if ( mode == READ_QUEUE_INFO ) { env->e_attributes = exp_level; } else if ( exp_level != env->e_attributes ) { syslog( LOG_WARNING, "Envelope.read %s: " "Dattributes reread mismatch old %d new %d", filename, env->e_attributes, exp_level ); } } /* Ffrom-address */ line_no++; if ((( line = snet_getline( snet, NULL )) == NULL ) || ( *line != 'F' )) { syslog( LOG_ERR, "Envelope.read %s %d: expected Ffrom syntax", filename, line_no ); goto cleanup; } switch ( mode ) { default: syslog( LOG_ERR, "Envelope.read: invalid mode change: %d", mode ); goto cleanup; case READ_QUEUE_INFO: if ( env_sender( env, line + 1 ) == 0 ) { ret = 0; } goto cleanup; case READ_JAIL_INFO: case READ_DELIVER_INFO: if ( strcmp( env->e_mail, line + 1 ) != 0 ) { syslog( LOG_ERR, "Envelope.read %s %d: bad sender re-read: " "old <%s> new <%s>", filename, line_no, env->e_mail, line + 1 ); goto cleanup; } break; } /* Rto-addresses */ for ( line_no++; ( line = snet_getline( snet, NULL )) != NULL; line_no++ ) { if ( *line != 'R' ) { syslog( LOG_ERR, "Envelope.read %s %d: expected Recipient syntax", filename, line_no ); goto cleanup; } if ( env_recipient( env, line + 1 ) != 0 ) { goto cleanup; } } if ( env->e_rcpt == NULL ) { syslog( LOG_ERR, "Envelope.read %s %d: no recipients", filename, line_no ); goto cleanup; } ret = 0; /* close snet if no need to maintain lock */ if ( s_lock == NULL ) { cleanup: if ( snet_close( snet ) < 0 ) { syslog( LOG_ERR, "Liberror: env_read snet_close %s: %m", filename ); ret = 1; } } if (( simta_mid_list_enable != 0 ) && ( ret == 0 )) { if (( e_dll = dll_lookup_or_create( &simta_env_list, env->e_id, 0 )) == NULL ) { return( 1 ); } if ( e_dll->dll_data == NULL ) { e_dll->dll_data = env; env->e_env_list_entry = e_dll; } } if (( simta_sender_list_enable != 0 ) && ( ret == 0 )) { if ( sender_list_add( env ) != 0 ) { return( 1 ); } } return( ret ); }
ino_t env_dfile_copy( struct envelope *env, char *source, char *header ) { int dfile_fd = -1; ino_t retval = 0; FILE *dfile = NULL; struct stat sbuf; SNET *snet = NULL; char *line; char df[ MAXPATHLEN + 1 ]; /* If the tfile has already been written it has incorrect Dinode * information. */ if ( env->e_flags & ENV_FLAG_TFILE ) { env_tfile_unlink( env ); } if ( source == NULL ) { if ( ! ( env->e_flags & ENV_FLAG_DFILE )) { syslog( LOG_ERR, "env_dfile_copy: no source" ); return( 0 ); } sprintf( df, "%s/D%s", env->e_dir, env->e_id ); if (( snet = snet_open( df, O_RDONLY, 0, 1024 * 1024 )) != NULL ) { if ( unlink( df )) { syslog( LOG_ERR, "Syserror: env_dfile_copy unlink %s: %m", df ); goto error; } } } else { snet = snet_open( source, O_RDONLY, 0, 1024 * 1024 ); } if ( snet == NULL ) { syslog( LOG_ERR, "Liberror: env_dfile_copy snet_open: %m" ); return( 0 ); } if (( dfile_fd = env_dfile_open( env )) < 0 ) { goto error; } if (( dfile = fdopen( dfile_fd, "w" )) == NULL ) { syslog( LOG_ERR, "Syserror: env_dfile_copy fdopen: %m" ); if ( close( dfile_fd ) != 0 ) { syslog( LOG_ERR, "Syserror: env_dfile_copy close: %m" ); } goto error; } if ( header ) { if ( fprintf( dfile, "%s\n", header ) < 0 ) { syslog( LOG_ERR, "Syserror: env_dfile_copy fprintf: %m" ); goto error; } } while (( line = snet_getline( snet, NULL )) != NULL ) { if ( fprintf( dfile, "%s\n", line ) < 0 ) { syslog( LOG_ERR, "Syserror: env_dfile_copy fprintf: %m" ); goto error; } } if ( fstat( dfile_fd, &sbuf ) == 0 ) { retval = sbuf.st_ino; } else { syslog( LOG_ERR, "Syserror: env_dfile_copy fstat: %m" ); } error: if ( dfile != NULL && ( fclose( dfile ) != 0 )) { syslog( LOG_ERR, "Syserror: env_dfile_copy fclose: %m" ); } if ( snet != NULL && ( snet_close( snet ) != 0 )) { syslog( LOG_ERR, "Liberror: env_dfile_copy snet_close: %m" ); } if ( retval == 0 ) { env_dfile_unlink( env ); } return( retval ); }
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 ); }
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 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 ); }
int main( int argc, char *argv[] ) { SNET *in; SNET *out; char *line; int x; struct timeval tv; char path[ MAXPATHLEN ]; int c; if ( simta_gettimeofday( &tv ) != 0 ) { perror( "gettimeofday" ); return( 1 ); } /* XXX hard path */ sprintf( path, "%s/%ld.%ld", "/var/simta/log", tv.tv_sec, tv.tv_usec ); if (( in = snet_attach( 0, 1024 * 1024 )) == NULL ) { perror( "snet_attach" ); exit( 1 ); } if (( out = snet_open( path, O_CREAT | O_WRONLY, S_IRUSR | S_IRGRP | S_IROTH, 1024 * 1024 )) == NULL ) { perror( "snet_open" ); exit( 1 ); } snet_writef( out, "%s", argv[ 0 ] ); for ( x = 1; x < argc; x++ ) { snet_writef( out, " %s", argv[ x ] ); } snet_writef( out, "\n\n" ); opterr = 0; while (( c = getopt( argc, argv, "b:" )) != -1 ) { switch ( c ) { case 'b': if ( strlen( optarg ) == 1 ) { switch ( *optarg ) { case 'a': /* -ba ARPANET mode */ case 'd': /* -bd Daemon mode, background */ case 's': /* 501 Permission denied */ printf( "501 Mode not supported\r\n" ); exit( 1 ); } } break; default: break; } } while (( line = snet_getline( in, NULL )) != NULL ) { snet_writef( out, "%s\n", line ); } if ( snet_close( in ) != 0 ) { perror( "snet_close" ); exit( 1 ); } if ( snet_close( out ) != 0 ) { perror( "snet_close" ); exit( 1 ); } return( 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 ); }
static int netretr_ticket( char *scookie, struct sinfo *si, SNET *sn, char *tkt_prefix, void *s ) { char *line; char tmpkrb[ 16 ], krbpath [ MAXPATHLEN ]; char buf[ 8192 ]; int fd; size_t size = 0; ssize_t rr; struct timeval tv; extern int errno; /* clear it, in case we can't get it later */ *si->si_krb5tkt = '\0'; /* RETR service-cookie TicketType */ if ( snet_writef( sn, "RETR %s tgt\r\n", scookie ) < 0 ) { cosign_log( APLOG_ERR, s, "mod_cosign: netretr_ticket: snet_writef failed"); return( COSIGN_ERROR ); } tv = timeout; if (( line = snet_getline_multi( sn, logger, &tv )) == NULL ) { cosign_log( APLOG_ERR, s, "mod_cosign: netretr_ticket: %s", strerror( errno )); return( COSIGN_ERROR ); } switch( *line ) { case '2': break; case '4': cosign_log( APLOG_ERR, s, "mod_cosign: netretr_ticket: %s", line ); return( COSIGN_LOGGED_OUT ); case '5': /* choose another connection */ cosign_log( APLOG_ERR, s, "mod_cosign: netretr_ticket: 5xx" ); return( COSIGN_RETRY ); default: cosign_log( APLOG_ERR, s, "mod_cosign: netretr_ticket: %s", line ); return( COSIGN_ERROR ); } if ( mkcookie( sizeof( tmpkrb ), tmpkrb ) != 0 ) { cosign_log( APLOG_ERR, s, "mod_cosign: netretr_ticket: mkcookie failed" ); return( COSIGN_ERROR ); } if ( snprintf( krbpath, sizeof( krbpath ), "%s/%s", tkt_prefix, tmpkrb ) >= sizeof( krbpath )) { cosign_log( APLOG_ERR, s, "mod_cosign: netretr_ticket: krbpath too long" ); return( COSIGN_ERROR ); } tv = timeout; if (( line = snet_getline( sn, &tv )) == NULL ) { cosign_log( APLOG_ERR, s, "mod_cosign: netretr_ticket: failed for %s", scookie ); return( COSIGN_ERROR ); } size = atoi( line ); if (( fd = open( krbpath, O_WRONLY | O_CREAT | O_EXCL, 0600 )) < 0 ) { perror( krbpath ); return( COSIGN_ERROR ); } /* Get file from server */ while ( size > 0 ) { tv = timeout; if (( rr = snet_read( sn, buf, (int)MIN( sizeof( buf ), size ), &tv )) <= 0 ) { cosign_log( APLOG_ERR, s, "mod_cosign: retrieve tgt failed: %s", strerror( errno )); goto error2; } if ( write( fd, buf, (size_t)rr ) != rr ) { perror( krbpath ); goto error2; } size -= rr; } if ( close( fd ) != 0 ) { perror( krbpath ); goto error1; } if ( size != 0 ) { cosign_log( APLOG_ERR, s, "mod_cosign: retrieve tickets: size from server did " "not match size read from server" ); goto error1; } tv = timeout; if (( line = snet_getline( sn, &tv )) == NULL ) { cosign_log( APLOG_ERR, s, "mod_cosign: retrieve for %s failed: %s", scookie, strerror( errno )); goto error1; } if ( strcmp( line, "." ) != 0 ) { cosign_log( APLOG_ERR, s, "mod_cosign: netretr_ticket: %s", line ); goto error1; } /* copy the path to the ticket file */ if ( strlen( krbpath ) >= sizeof( si->si_krb5tkt )) { cosign_log( APLOG_ERR, s, "mod_cosign: netretr_ticket: krb5tkt path too long" ); goto error1; } strcpy( si->si_krb5tkt, krbpath ); return( COSIGN_OK ); error2: close( fd ); error1: unlink( krbpath ); return( COSIGN_ERROR ); }
static int netretr_proxy( char *scookie, struct sinfo *si, SNET *sn, char *proxydb, void *s ) { int fd; char *line; char path[ MAXPATHLEN ], tmppath[ MAXPATHLEN ]; struct timeval tv; FILE *tmpfile; /* RETR service-cookie cookies */ if ( snet_writef( sn, "RETR %s cookies\r\n", scookie ) < 0 ) { cosign_log( APLOG_ERR, s, "mod_cosign: netretr_proxy: snet_writef failed"); return( COSIGN_ERROR ); } /* name our file and open tmp file */ if ( snprintf( path, sizeof( path ), "%s/%s", proxydb, scookie ) >= sizeof( path )) { cosign_log( APLOG_ERR, s, "mod_cosign: netretr_proxy: cookie path too long"); return( COSIGN_ERROR ); } if ( gettimeofday( &tv, NULL ) < 0 ) { perror( "gettimeofday" ); return( COSIGN_ERROR ); } if ( snprintf( tmppath, sizeof( tmppath ), "%s/%x%x.%i", proxydb, (int)tv.tv_sec, (int)tv.tv_usec, (int)getpid()) >= sizeof( tmppath )) { cosign_log( APLOG_ERR, s, "mod_cosign: netretr_proxy: tmppath too long"); return( COSIGN_ERROR ); } if (( fd = open( tmppath, O_CREAT|O_EXCL|O_WRONLY, 0644 )) < 0 ) { perror( tmppath ); return( COSIGN_ERROR ); } if (( tmpfile = fdopen( fd, "w" )) == NULL ) { if ( unlink( tmppath ) != 0 ) { perror( tmppath ); } perror( tmppath ); return( COSIGN_ERROR ); } tv = timeout; do { if (( line = snet_getline( sn, &tv )) == NULL ) { cosign_log( APLOG_ERR, s, "mod_cosign: netretr_proxy: snet_getline failed" ); return ( COSIGN_ERROR ); } switch( *line ) { case '2': break; case '4': cosign_log( APLOG_ERR, s, "mod_cosign: netretr_proxy: %s", line ); return( COSIGN_LOGGED_OUT ); case '5': /* choose another connection */ cosign_log( APLOG_ERR, s, "mod_cosign: netretr_proxy: 5xx" ); return( COSIGN_RETRY ); default: cosign_log( APLOG_ERR, s, "mod_cosign: netretr_proxy: %s", line ); return( COSIGN_ERROR ); } if ( strlen( line ) < 3 ) { cosign_log( APLOG_ERR, s, "mod_cosign: netretr_proxy: short line: %s", line ); return( COSIGN_ERROR ); } if ( !isdigit( (int)line[ 1 ] ) || !isdigit( (int)line[ 2 ] )) { cosign_log( APLOG_ERR, s, "mod_cosign: netretr_proxy: bad response: %s", line ); return( COSIGN_ERROR ); } if ( line[ 3 ] != '\0' && line[ 3 ] != ' ' && line [ 3 ] != '-' ) { cosign_log( APLOG_ERR, s, "mod_cosign: netretr_proxy: bad response: %s", line ); return( COSIGN_ERROR ); } if ( line[ 3 ] == '-' ) { fprintf( tmpfile, "x%s\n", &line[ 4 ] ); } } while ( line[ 3 ] == '-' ); if ( fclose ( tmpfile ) != 0 ) { if ( unlink( tmppath ) != 0 ) { perror( tmppath ); } perror( tmppath ); return( COSIGN_ERROR ); } if ( link( tmppath, path ) != 0 ) { if ( unlink( tmppath ) != 0 ) { perror( tmppath ); } perror( tmppath ); return( COSIGN_ERROR ); } if ( unlink( tmppath ) != 0 ) { perror( tmppath ); } return( COSIGN_OK ); }