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;