Mercurial > noffle
changeset 250:93d5d8b098da noffle
[svn] *** empty log message ***
author | mirkol |
---|---|
date | Wed, 05 Jun 2002 23:03:44 +0100 |
parents | 0340b9c17edc |
children | 030c41dfd9ba |
files | ChangeLog src/client.c src/common.h src/group.c src/group.h src/noffle.c src/protocol.c |
diffstat | 7 files changed, 152 insertions(+), 118 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Tue May 14 15:25:45 2002 +0100 +++ b/ChangeLog Wed Jun 05 23:03:44 2002 +0100 @@ -1,3 +1,17 @@ +Wed Jun 5 2002 Mirko Liß <mirko.liss@web.de> + +* src/group.c,src/client.c,src/noffle.c: rename Grp_isValidGroupname + to Grp_isValidName; create Grp_isForbiddenName(); delete + client.c:isForbiddenGroupName(). I should be have done it + the right way from the beginning. +* src/protocol.c:Prt_getLn(): Skip line if connection to server + lost before end of line. Prt_getLn() used to return incomplete + lines. +* src/common.h,src/client.c: Replace sscanf() format "%s" by + MAXCHAR_FMT. +* src/client.c: Get each line of grouplist in processGrps(), don't + collect the whole list beforehand. + Tue May 14 2002 Mirko Liß <mirko.liss@web.de> * src/configfile.c,src/filter.c,src/filter.h,src/fetch.c,src/noffle.c,
--- a/src/client.c Tue May 14 15:25:45 2002 +0100 +++ b/src/client.c Wed Jun 05 23:03:44 2002 +0100 @@ -1,7 +1,7 @@ /* client.c - $Id: client.c 371 2002-02-26 17:13:31Z bears $ + $Id: client.c 382 2002-06-05 22:03:44Z mirkol $ */ #if HAVE_CONFIG_H @@ -44,23 +44,6 @@ in C.Lindsay, "News Article Format", <draft-ietf-usefor-article-03.txt>. */ -struct ForbiddenGroupName -{ - const char *pattern; - Bool match; -} forbiddenGroupNames[] = -{ - { "*.*", FALSE }, /* Single component */ - { "control.*", TRUE }, /* control.* groups */ - { "to.*", TRUE }, /* to.* groups */ - { "*.all", TRUE }, /* 'all' as a component */ - { "*.all.*", TRUE }, - { "all.*", TRUE }, - { "*.ctl", TRUE }, /* 'ctl' as a component */ - { "*.ctl.*", TRUE }, - { "ctl.*", TRUE } -}; - struct { FILE* in; /* Receiving socket from server */ @@ -268,7 +251,7 @@ Str line; Bool err; - res = new_DynStr(2048); + res = new_DynStr( MAXCHAR ); if ( res == NULL ) return NULL; @@ -418,51 +401,35 @@ } static Bool -isForbiddenGroupName( const char *name ) -{ - size_t i; - - for ( i = 0; - i < sizeof( forbiddenGroupNames ) / - sizeof( struct ForbiddenGroupName ); - i++ ) - { - /* Negate result of Wld_match to ensure it is 1 or 0. */ - if ( forbiddenGroupNames[i].match != - ( ! Wld_match( name, forbiddenGroupNames[i].pattern ) ) ) - return TRUE; - } - - return FALSE; -} - -static void -processGrps( const char *lines, Bool noServerPattern ) +processGrps( Bool noServerPattern ) { char postAllow; + Bool groupupdate; + Bool err; int first, last; - Str grp, line, file; - Bool groupupdate; + Str grp, file; + Str line; ASSERT( ! Lock_gotLock() ); if ( ! Lock_openDatabases() ) - return; + return TRUE; /* silently ignore */ groupupdate = FALSE; - while ( ( lines = Utl_getLn( line, lines) ) != NULL ) + + while ( getTxtLn( line, &err ) && !err ) { - if ( sscanf( line, "%s %d %d %c", + if ( sscanf( line, MAXCHAR_FMT " %d %d %c", grp, &last, &first, &postAllow ) != 4 ) { Log_err( "Unknown reply to LIST or NEWGROUPS: %s", line ); continue; } - if ( ! Grp_isValidGroupName( grp ) ) + if ( ! Grp_isValidName( grp ) ) { Log_inf( "Group name %s invalid", grp ); continue; } - if ( isForbiddenGroupName( grp ) ) + if ( Grp_isForbiddenName( grp ) ) { Log_inf( "Group %s forbidden", grp ); continue; @@ -513,7 +480,13 @@ Cfg_spoolDir() ); Utl_stamp( file ); } + + /* I'm absolutely not sure about this. */ + if ( err && groupupdate ) + Log_err( "Group list may be corrupted with bogus data." ); + Lock_closeDatabases(); + return !err; } void @@ -531,7 +504,6 @@ { Str cmd; int stat; - DynStr *response; Utl_cpyStr( cmd, "LIST ACTIVE" ); if ( pattern[ 0 ] != '\0' ) @@ -564,12 +536,10 @@ return stat; } - response = collectTxt(); - if ( response == NULL ) + + if ( processGrps( *noServerPattern ) == FALSE ) return STAT_CONNECTION_LOST; - - processGrps( DynStr_str( response ), *noServerPattern ); - del_DynStr( response ); + return STAT_OK; } @@ -650,7 +620,7 @@ result = STAT_OK; while ( ( lines = Utl_getLn( line, lines) ) != NULL ) { - if ( sscanf( line, "%s", name ) != 1 ) + if ( sscanf( line, MAXCHAR_FMT, name ) != 1 ) { Log_err( "Unknown reply to LIST NEWSGROUPS: %s", line ); result = STAT_PROGRAM_FAULT; @@ -703,7 +673,6 @@ { Str s; const char *p; - DynStr *response; int stat; ASSERT( *lastTime > 0 ); @@ -723,12 +692,9 @@ return stat; } - response = collectTxt(); - if ( response == NULL ) + if( processGrps( TRUE ) == FALSE ) return STAT_CONNECTION_LOST; - - processGrps( DynStr_str( response ), TRUE ); - del_DynStr( response ); + return STAT_OK; }
--- a/src/common.h Tue May 14 15:25:45 2002 +0100 +++ b/src/common.h Wed Jun 05 23:03:44 2002 +0100 @@ -3,7 +3,7 @@ Common declarations. - $Id: common.h 51 2000-05-05 23:49:38Z uh1763 $ + $Id: common.h 382 2002-06-05 22:03:44Z mirkol $ */ #ifndef COMMON_H @@ -20,6 +20,8 @@ #define FALSE 0 #define TRUE !0 #define MAXCHAR 2048 +/* limited sscanf() format string: */ +#define MAXCHAR_FMT "%2048s" #ifdef DEBUG #include <assert.h>
--- a/src/group.c Tue May 14 15:25:45 2002 +0100 +++ b/src/group.c Wed Jun 05 23:03:44 2002 +0100 @@ -7,7 +7,7 @@ loadGrp() and saveGrp(). This is done transparently. Access to the groups database is done by group name, by the functions defined in group.h. - $Id: group.c 381 2002-05-14 14:25:45Z mirkol $ + $Id: group.c 382 2002-06-05 22:03:44Z mirkol $ */ #if HAVE_CONFIG_H @@ -20,11 +20,15 @@ #include <fcntl.h> #include <sys/stat.h> #include "configfile.h" +#include "wildmat.h" #include "group.h" #include "log.h" #include "util.h" #include "portable.h" +/* max length of a group name: */ +#define MAX_GROUPNAME 78 + /* currently only used within grp */ typedef struct { @@ -63,6 +67,30 @@ return gdbm_strerror( gdbm_errno ); } +/* forbidden hierarchies */ +struct ForbiddenGroupName +{ + const char *pattern; + Bool match; +} forbiddenGroupNames[] = +{ +/* { "*[^-+_.0-9a-zA-Z]*", TRUE}, */ /* allow only traditional group names */ + { "*.*", FALSE }, /* Single component */ + { "control.*", TRUE }, /* control.* groups */ + { "to.*", TRUE }, /* to.* groups */ + { "*.all", TRUE }, /* 'all' as a component */ + { "*.all.*", TRUE }, + { "all.*", TRUE }, + { "*.ctl", TRUE }, /* 'ctl' as a component */ + { "*.ctl.*", TRUE }, + { "ctl.*", TRUE }, + { "example.*", TRUE }, /* example.* groups */ + { "*,*", TRUE }, /* newsgroups separator */ +/* { "_*", TRUE }, */ /* reserved for future use, but accept nevertheless */ + { "+*", TRUE }, /* reserved */ + { "-*", TRUE } +}; + Bool Grp_open( void ) { @@ -412,58 +440,51 @@ return ( cursor.dptr != NULL ); } +/* Group names' sanity checks. Groups with forbidden names + can't be safely deleted or created. */ Bool -Grp_isValidGroupName( const char *name) +Grp_isForbiddenName( const char *name) { - const char *pname, *ppat; - const char *illegalchars = "\t\n\r,/:\\"; /* Are there any other dangerous characters? */ - - /* Find directory prefixes to prevent exploits. */ - switch ( name[0] ) - { - case '.': /* prevent noffle -C ../fetchlist */ - case '+': - case '-': /* reserved for internal use of implementations - * rf. draft-ietf-usefor-article-06.txt, ch 5.5.1 */ - return FALSE; /* group name invalid */ - break; - default: - break; - } - + const char *illegalchars = "\t\n\v\r /:\\"; +/* "\t\n\v\r " whitespace + "/:\\" directory prefix (Unix, MacOS, Freedos filesystems) */ /* Find illegal characters. */ if ( strpbrk( name, illegalchars ) ) - return FALSE; + return TRUE; + /* Find '.' dot directory prefix to prevent exploits. */ + if ( name[0] == '.') /* prevent noffle -C ../fetchlist */ + return TRUE; /* group name invalid */ + return FALSE; +} - /* Find "all", "all.*", "*.all" or "*.all.*" */ - pname = name; - while ( ( ppat = strstr( pname, "all" ) ) != NULL ) - { - if ( ( ppat == name || *(ppat - 1) == '.' ) - && ( *(ppat+4) == '\0' || *(ppat+4) == '.' ) ) - return FALSE; - else - pname += 3; - } +/* + Forbidden or restricted group names or hierarchies. Please refer to + draft-ietf-usefor-article-06, chapter 5.5.1. Groups with invalid + names can't be created, but can still be deleted. + */ +Bool +Grp_isValidName( const char *name) +{ + size_t i; - /* Find "ctl", "ctl.*", "*.ctl" or "*.ctl.*" */ - pname = name; - while ( ( ppat = strstr( pname, "ctl" ) ) != NULL ) + for ( i = 0; + i < sizeof( forbiddenGroupNames ) / + sizeof( struct ForbiddenGroupName ); + ++i ) { - if ( ( ppat == name || *(ppat - 1) == '.' ) - && ( *(ppat+4) == '\0' || *(ppat+4) == '.' ) ) + /* Negate result of Wld_match to ensure it is 1 or 0. */ + if ( forbiddenGroupNames[i].match != + ( ! Wld_match( name, forbiddenGroupNames[i].pattern ) ) ) return FALSE; - else - pname += 3; } - /* Find some special groups and hierarchies. */ - if ( !( strcmp( name, "poster" ) && strcmp( name, "junk" ) - && strcmp( name, "control" ) && strcmp( name, "to" ) - && strncmp( name, "control.", 8 ) && strncmp( name, "to.", 3 ) - && strncmp( name, "example.", 8 ) ) ) - return FALSE; - - - /* Group name is hopefully valid. */ + /* Groups with lengthy names like + alt.the.lame.troll.should.be.posting.again.in.just.a.few.more.weeks.from.what.he.said + or + microsoft.public.windows.inetexplorer.ie55.programming.components.codedownload + are most likely bogus groups that have been mistakenly created. + */ + if ( strlen( name ) > MAX_GROUPNAME ) + return FALSE; + /* no match? then assume the group is valid. */ return TRUE; }
--- a/src/group.h Tue May 14 15:25:45 2002 +0100 +++ b/src/group.h Wed Jun 05 23:03:44 2002 +0100 @@ -3,7 +3,7 @@ Groups database - $Id: group.h 358 2001-12-18 15:27:08Z mirkol $ + $Id: group.h 382 2002-06-05 22:03:44Z mirkol $ */ #ifndef GRP_H @@ -129,10 +129,16 @@ Bool Grp_nextGrp( const char **name ); -/* Check group name for validity. Returns false if the group name is - invalid. It should be called before Grp_create() or before deleting an - overview file. This function doesn't call Grp_exists(), though. */ +/* Check group name for forbidden patterns. Returns true if the group name + contains patterns like "*.all.*, "*.ctl.", etc. It should be called + before Grp_create(). This function doesn't call Grp_exists(), though. */ Bool -Grp_isValidGroupName( const char *name ); +Grp_isForbiddenName( const char *name ); + +/* Check group name for invalid characters. Returns false if the group + name contains file name separators or whitespace characters. It should + be called before deleting an overview file or before Grp_create(). */ +Bool +Grp_isValidName( const char *name ); #endif
--- a/src/noffle.c Tue May 14 15:25:45 2002 +0100 +++ b/src/noffle.c Wed Jun 05 23:03:44 2002 +0100 @@ -10,7 +10,7 @@ received for some seconds (to allow multiple clients connect at the same time). - $Id: noffle.c 381 2002-05-14 14:25:45Z mirkol $ + $Id: noffle.c 382 2002-06-05 22:03:44Z mirkol $ */ #if HAVE_CONFIG_H @@ -330,8 +330,10 @@ fprintf( stderr, "'%s' already exists.\n", name ); return; } - if ( ! Grp_isValidGroupName( name ) ) + if ( ! Grp_isValidName( name ) ) fprintf( stderr, "'%s' invalid group name.\n", name ); + else if ( Grp_isForbiddenName( name ) ) + fprintf( stderr, "'%s' forbidden group name.\n", name ); else { Log_inf( "Creating new local group '%s'", name ); @@ -358,7 +360,7 @@ fprintf( stderr, "'%s' does not exist.\n", name ); return; } - if ( ! Grp_isValidGroupName( name ) ) + if ( ! Grp_isValidName( name ) ) { fprintf( stderr, "'%s' invalid group name. Skipping deletion of overviews.\n", name ); Log_inf( "Deleting invalid group '%s' without deleting overviews.", name );
--- a/src/protocol.c Tue May 14 15:25:45 2002 +0100 +++ b/src/protocol.c Wed Jun 05 23:03:44 2002 +0100 @@ -1,7 +1,7 @@ /* protocol.c - $Id: protocol.c 381 2002-05-14 14:25:45Z mirkol $ + $Id: protocol.c 382 2002-06-05 22:03:44Z mirkol $ */ #if HAVE_CONFIG_H @@ -37,6 +37,7 @@ size_t len; char *ret; sig_t oldHandler = NULL; + int line_too_long; if ( timeoutSeconds >= 0 ) { @@ -62,11 +63,33 @@ if ( ret == NULL ) return FALSE; len = strlen( line ); - if ( len > 0 && line[ len - 1 ] == '\n' ) + if ( len > 0 ) { - line[ len - 1 ] = '\0'; - if ( len > 1 && line[ len - 2 ] == '\r' ) - line[ len - 2 ] = '\0'; + if ( line[ len - 1 ] == '\n' ) + { + line[ len - 1 ] = '\0'; + if ( len > 1 && line[ len - 2 ] == '\r' ) + line[ len - 2 ] = '\0'; + } + else + { + /* line too long, skip the rest */ + if( len == MAXCHAR ) + { + Log_err( "Line too long:" ); + do + { + line_too_long = fgetc( f ); + } + while( line_too_long == EOF || line_too_long == '\n' ); + } + else + /* EOF occured in line, skip line. */ + { + Log_err( "Ignoring incomplete line %s", line); + return FALSE; + } + } } Log_dbg( LOG_DBG_PROTOCOL, "[R] %s", line ); return TRUE;