#pragma implementation #include #include #include #include #include #include #include #include #include #include #include "inetdconf.h" #include "inetdconf.m" #include "etcservice.h" #include "etcprotocol.h" #include "../../paths.h" static HELP_FILE help_etcservice ("inetdconf","etcservice"); static CONFIG_FILE f_config_file( ETC_SERVICES ,help_etcservice ,CONFIGF_MANAGED ,"root" ,"root" ,0644 ,subsys_inetdconf ); static ETCSERVICELIST *etcservicelist = NULL; static ETCPROTOCOLLIST *etcprotocollist = NULL; static long modified_time = 0; static bool config_file_modified = false; static SSTRINGS sorted; /* * ETCSERVICE */ #define K_FIELD_SERVICE 1 #define K_FIELD_PORT_PROTOCOL 2 #define K_FIELD_ALIASES 3 #define K_FIELD_COMMENT 4 PRIVATE void ETCSERVICE::init() { //fprintf(stderr,"ETCSERVICE::init\n"); port = 0; etcservice_line = 0; new_etcservice = 0; protocol.setfrom( "tcp" ); } PUBLIC ETCSERVICE::ETCSERVICE(const char *_service_name) { //fprintf(stderr,"ETCSERVICE::ETCSERVICE _service_name=%s\n", _service_name); service_name.setfrom (_service_name); init(); } PUBLIC ETCSERVICE::ETCSERVICE( ) { //fprintf(stderr,"ETCSERVICE::ETCSERVICE\n"); init(); } PUBLIC int ETCSERVICE::write( int button ) { //fprintf(stderr,"ETCSERVICE::write\n"); int ret = -1; if ( ! perm_rootaccess( MSG_U(P_EDITETCSERVICE, "change service configuration") ) ) { return( ret ); } long this_modified_time = file_date( f_config_file.getpath() ); if ( this_modified_time > modified_time ) { xconf_error(MSG_R(E_FILE_MODIFIED), f_config_file.getpath() ); config_file_modified = true; return( ret ); } VIEWITEMS items; items.setcomcar( '\002' ); // Set comment to "impossible" char items.read( f_config_file ); // Read current version of config file if ( new_etcservice ) { VIEWITEM *item = new VIEWITEM(""); etcservice_line = items.getnb(); modify_service( item ); items.add( item ); } else { for ( int line=0; lineline.get()); char line[2048]; if ( aliases.is_empty() ) { snprintf( line, sizeof(line), "%s\t\t%d/%s\t\t%s%s", service_name.get(), port, protocol.get(), comment.is_empty()?"":"\t# ", comment.is_empty()?"":comment.get() ); } else { snprintf( line, sizeof(line), "%s\t\t%d/%s\t%s%s%s", service_name.get(), port, protocol.get(), aliases.get(), comment.is_empty()?"":"\t\t# ", comment.is_empty()?"":comment.get() ); } item->line.setfrom( line ); } /** * Edit etcservice entry */ PUBLIC int ETCSERVICE::edit() { //fprintf(stderr,"ETCSERVICE::edit\n"); DIALOG dia; if ( new_etcservice ) { dia.newf_str( MSG_R(F_SERVICES), service_name ); } else { dia.newf_info( MSG_R(F_SERVICES), service_name.get() ); } dia.newf_num( MSG_R(F_ETCSERVICEPORT), port ); { FIELD_LIST *combo = dia.newf_list(MSG_R(F_PROTOCOLS),protocol); ETCPROTOCOL *etcprotocol = NULL; for (int i=0; igetnb(); i++ ) { etcprotocol = etcprotocollist->getitem( i ); combo->addopt (etcprotocol->protocol_name.get(),etcprotocol->comment.get()); } } dia.newf_str( MSG_U(F_ETCSERVICEALIASES,"Aliases for service"), aliases ); dia.newf_str( MSG_U(F_ETCSERVICECOMMENT,"Comment"), comment ); int buttons; if ( new_etcservice ) { buttons = (MENUBUT_CANCEL|MENUBUT_ACCEPT); } else { buttons = (MENUBUT_DEL|MENUBUT_CANCEL|MENUBUT_ACCEPT); } int ret = 0; int nof = 0; while (1){ MENU_STATUS code = dia.edit( MSG_U(T_ETCSERVICE, "Internet services") ,"" ,help_etcservice ,nof ,buttons); if (code == MENU_CANCEL || code == MENU_ESCAPE){ ret = -1; break; }else if (code == MENU_DEL){ if ( xconf_delok() ) { write( MENU_DEL ); ret = 1; break; } }else if (code == MENU_ACCEPT ) { if ( input_error( ) ) continue; write ( MENU_ACCEPT ); ret = 0; break; } } return ret; } PRIVATE int ETCSERVICE::input_error( ) { if ( new_etcservice ) { SSTRING pp; pp.setfrom(port); pp.append( "/" ); pp.append( protocol.get() ); char word[100]; char service[100]; for (int i=0; iget(); p = str_copyword( service, p, sizeof( word ) ); p = str_copyword( word, p, sizeof( word ) ); if ( pp.cmp( word ) == 0 ) { xconf_error(MSG_U(E_PORTPROTOCOL, "Port and protocol (%s) previously defined\n" "in service %s\n"), word, service ); return( 1 ); } } } return( 0 ); } /** * ETCSERVICELIST */ PUBLIC ETCSERVICE *ETCSERVICELIST::getitem (int no) const { return (ETCSERVICE*)ARRAY::getitem (no); } PUBLIC ETCSERVICE *ETCSERVICELIST::getitem (const char *_service_name) const { ETCSERVICE *ret = NULL; int n = getnb(); for (int i=0; iservice_name.cmp(_service_name)==0){ etcservice->index = i; ret = etcservice; break; } } return ret; } PUBLIC ETCSERVICE *ETCSERVICELIST::getitem(const char *_protocol, int _port) const { //fprintf(stderr,"etcservice.cc: getitem: protocol=%s port=%d\n", _protocol, _port ); ETCSERVICE *ret = NULL; int n = getnb(); for (int i=0; iprotocol.cmp( _protocol ) == 0 ) && ( etcservice->port == _port )) { //fprintf(stderr,"etcservice.cc: getitem: found: protocol=%s port=%d\n", _protocol, _port ); etcservice->index = i; return( etcservice ); } } return ret; } PUBLIC ETCSERVICE *ETCSERVICELIST::getitem_alias(const char *_service_name) const { ETCSERVICE *ret = NULL; int n = getnb(); for (int i=0; ialiases.get( ); while ( *p ) { p = str_copyword( word, p, sizeof( word ) ); //fprintf(stderr,"etcservice.cc: getitem_alias: service_name=%s word=%s\n", _service_name, word ); if (strcmp(word, _service_name)==0) { etcservice->index = i; return( etcservice ); } } } return ret; } PUBLIC ETCSERVICE *ETCSERVICELIST::getitem_service(const char *_service) const { ETCSERVICE *ret = NULL; int n = getnb(); for (int i=0; iservice_name.get(), etcservice->port, etcservice->protocol.get() ); if (strcmp(word, _service)==0) { //fprintf(stderr,"etcservice.cc: getitem_service: service=%s word=%s\n", _service, word ); etcservice->index = i; return( etcservice ); } } return ret; } PUBLIC ETCSERVICELIST::ETCSERVICELIST( ) { //fprintf(stderr,"ETCSERVICELIST::ETCSERVICELIST\n"); } PRIVATE char * ETCSERVICELIST::next_word( char *d, char *s, int size ) { while ( *s ) { switch ( *s ) { case ' ': case '\t': s++; continue; default: break; } break; } for ( size--; *s && size; size-- ) { switch ( *s ) { case ' ': case '\t': case '\n': *d = '\0'; return( s ); case '#': *d++ = *s++; *d = '\0'; return( s ); default: *d++ = *s++; break; } } *d = '\0'; return( s ); } PRIVATE int ETCSERVICELIST::valid_port_protocol( char *word, ETCSERVICE *etcservice ) { char *p = word; char *s = word; for ( s = p; *p && isdigit( (int)*p); p++ ); if ( ! *p ) return( 0 ); *p++ = '\0'; etcservice->port = atoi( s ); for ( s = p ; *p ; p++ ); etcservice->protocol.setfrom( s ); if ( etcservice->protocol.is_empty( ) ) { return ( 0 ); } //fprintf(stderr,"valid_port_protocol: %d/%s\n", etcservice->port,etcservice->protocol.get() ); return( 1 ); } PRIVATE void ETCSERVICELIST::valid_aliases( char *word, ETCSERVICE *etcservice ) { //fprintf(stderr,"etcservice.cc: valid_aliases: %s\n", word); if ( etcservice->aliases.is_empty( ) ) { etcservice->aliases.setfrom( word ); } else { etcservice->aliases.append( " " ); etcservice->aliases.append( word ); } } PUBLIC void ETCSERVICELIST::add_service( int line_number, VIEWITEM *item ) { //fprintf(stderr,"etcservice.cc: add_service: item->line.get()=%s\n", item->line.get()); ETCSERVICE *etcservice = NULL; char word[1024]; char *line = (char *)item->line.get(); char *p = line; if ( *p && *p == '#' ) { return; } if ( strlen( p ) < 3 ) return; int field = 1; int valid_keywords = 0; while ( 1 ) { p = next_word( word, p, sizeof( word )); if ( strlen( word ) == 0 ) { break; } //fprintf(stderr,"etcservice.cc: add_service: field=%d word=\"%s\" length=%d\n", field, word, strlen(word)); switch ( field ) { case K_FIELD_SERVICE: etcservice = new ETCSERVICE(); etcservice->service_name.setfrom( word ); field++; break; case K_FIELD_PORT_PROTOCOL: if ( word[0] == '#' ) { field = K_FIELD_COMMENT; break; } if ( valid_port_protocol( word, etcservice ) ) { valid_keywords++; } field++; break; case K_FIELD_ALIASES: if ( word[0] == '#' ) { field = K_FIELD_COMMENT; break; } valid_aliases( word, etcservice ); break; case K_FIELD_COMMENT: if ( etcservice->comment.is_empty( ) ) { etcservice->comment.setfrom( word ); } else { etcservice->comment.append( " " ); etcservice->comment.append( word ); } break; } } if ( valid_keywords > 0 ) { etcservice->etcservice_line = line_number; add( etcservice ); } else { delete( etcservice ); } return; } /** * Read config file and parse etc/services */ PUBLIC void ETCSERVICELIST::read() { if ( etcprotocollist == NULL ) { etcprotocollist = new ETCPROTOCOLLIST(); etcprotocollist->read( ); } VIEWITEMS items; items.setcomcar( '\002' ); // Set comment to "impossible" char items.read( f_config_file ); // Read config file //fprintf(stderr,"ETCSERVICELIST::read items.getnb()=%d\n", items.getnb()); for ( int i=0; inewf_head ("",MSG_U(H_ETCSERVICE,"Service\tPort/Protocol")); sorted.remove_all(); for (int i=0; iservice_name.get() ); SSTRING p; pp->append( " " ); p.setfrom(etcservice->port); pp->append( p.get() ); pp->append( "/" ); pp->append( etcservice->protocol.get() ); sorted.add( pp ); } sorted.sort(); for (int i=0; iget(), sizeof( p1 ) ); strcat( p1, "\t" ); p = str_copyword( p2, p, sizeof( p2 ) ); dia->new_menuitem( p1, p2 ); } dia->addwhat (MSG_U(I_ADDETCSERVICE,"Select [Add] to add a new service.\n")); } MENU_STATUS code = dia->editmenu (MSG_U(T_ETCSERVICELIST,"Services") ,MSG_U(I_ETCSERVICELIST, "This is the list of all services which are\n" "potentially available.\n" ) ,help_etcservice ,nof,MENUBUT_ADD); bool mustdelete=false; if (code == MENU_QUIT || code == MENU_ESCAPE) { break; } else if (code == MENU_ADD) { ETCSERVICE *etcservice = new ETCSERVICE; etcservice->new_etcservice = true; if ( editone(etcservice) != -1 ) { mustdelete = true; } } else { const char *service = sorted.getitem( nof )->get(); ETCSERVICE *etcservice = getitem_service( service ); //fprintf(stderr,"editone: service=%s\n", service ); etcservice->new_etcservice = false; //fprintf(stderr,"editone: etcservice->service_name=%s\n", etcservice->service_name.get()); switch ( editone(etcservice->index) ) { case -1: mustdelete = false; break; case 1: mustdelete = true; break; case 0: mustdelete = false; break; } } if (mustdelete){ delete dia; dia = NULL; if ( config_file_modified ) { etcservicelist->remove_all(); etcservicelist->read(); config_file_modified = false; } } } delete dia; return 0; } PUBLIC void etcservice_edit( void ) { etcservicelist = new ETCSERVICELIST(); etcservicelist->read(); etcservicelist->edit(); delete etcservicelist; }