Page 1 of 1

[S] Dokumentenindexer

Posted: 2011-03-25 14:33
by Joe User
Moin,

ich suche eine leichtgewichtige Alternative zu Sphinx mit der statische Dokumente (HTML, XML, PDF, PlainText) indexiert und durchsucht werden können.
Die Dokumente liegen direkt im Dateisystem, also keine Skriptsprachen und Datenbanken im Spiel, über mehrere Verzeichnisse verteilt und es werden bis zu 100.000 Dokumente erwartet. Der Index soll stündlich per Cron aktualisiert und webbasiert durchsucht werden können.

Voraussetzungen:
  • Open-Source
  • C, C++, Perl, Python oder PHP5
  • Dateibasierter Index (keine Datenbank)
  • Kostenfreie kommerzielle Nutzung
Gruss,
Joe User

Re: [S] Dokumentenindexer

Posted: 2011-03-25 18:57
by daemotron
Da ich Deine Abneigung gegen Java kenne, Lucene aber die defacto-Referenz im FOSS-Umfeld ist, hier ein Port von Lucene auf C:

http://incubator.apache.org/lucy/

Leider gibt es noch kein Release, man muss also mit dem Code aus dem Development-Branch hantieren. Erfahrungen habe ich mit Lucy bisher keine.

Re: [S] Dokumentenindexer

Posted: 2011-03-26 00:40
by Roger Wilco
Prinzipiell könnte ht://Dig die Anforderungen erfüllen, allerdings ist das letzte Release schon etwas angestaubt.

Re: [S] Dokumentenindexer

Posted: 2011-03-29 12:00
by Joe User
Es kommt jetzt erstmal mnoGoSearch zum Einsatz, da es relativ leichtgewichtig und unkompliziert zu konfigurieren ist. Ich hoffe nur, dass es sich langfristig auch im Praxiseinsatz bewährt ;)

Unabhängig davon suche ich weiterhin nach Alternativen.

Re: [S] Dokumentenindexer

Posted: 2011-03-30 12:33
by Joe User
Ich brauche mal ein wenig C-Nachhilfe ;)
Folgende Funktion ersetzt offenbar 'selected="$&(*)"' durch 'selected="selected"'
oder durch '', soweit OK. Ich brauche aber eine Erweiterung der Funktion zum
Ersetzen von 'checked="$&(*)' nach gleichem Muster.

Code: Select all

static size_t PrintTagTemplate(UDM_AGENT *Agent,FILE *stream,
                               char *dst,size_t dst_len,
                               UDM_VARLIST *vars,const char *tok,
                               const char *HlBeg, 
                               const char *HlEnd)
{
  char * opt;
  UDM_HTMLTOK ltag, *tag = &ltag;
  const char *last;
  UDM_VAR * var=NULL;
  char * vname = NULL, *value = NULL;
  size_t i, res = 0;
  
  opt = (char*)UdmMalloc(strlen(tok) + 200);
  UdmHTMLTOKInit(tag);
  UdmHTMLToken(tok, &last, tag);
  sprintf(opt, "<");

  for (i = 0; i < ltag.ntoks; i++)
  {
    const char *space= (i == 0) ? "" : " ";
    if (ISTAG(i, "selected") && ltag.toks[i].vlen)
    {
      vname = UdmStrndup(ltag.toks[i].val, ltag.toks[i].vlen);
    }
    else if (ISTAG(i, "value"))
    {
      value = UdmStrndup(ltag.toks[i].val, ltag.toks[i].vlen);
      sprintf(UDM_STREND(opt), "%svalue=\"%s\"", space, value);
    }
    else
    {
      char *tname = UdmStrndup(ltag.toks[i].name, ltag.toks[i].nlen);
      if (ltag.toks[i].vlen)
      {
        char *tval = UdmStrndup(ltag.toks[i].val, ltag.toks[i].vlen);
        sprintf(UDM_STREND(opt), "%s%s=\"%s\"", space, tname, tval);
        UDM_FREE(tval);
      }
      else
      {
         sprintf(UDM_STREND(opt), "%s%s", space, tname);
      }
      UDM_FREE(tname);
    }
  }

  if(vname)
  {
    var= UdmVarListFindWithValue(vars, UdmTrim(vname, "$&()"), value ? value:"");
  }

  sprintf(UDM_STREND(opt), "%s>", var ? " selected=\"selected\"":"");

  if (vname) { UDM_FREE(vname); }
  if (value) { UDM_FREE(value); }

  res = PrintTextTemplate(Agent, stream, dst, dst_len, vars, opt, HlBeg, HlEnd);
  UDM_FREE(opt);
  return res;
}
Das if..else im for-Loop bekomme ich ja noch selbst erweitert, aber beim letzten sprintf muss ich dann doch passen :/

Vermutlich sehr primitiv und ich stehe momentan nur gewaltig auf dem Schlauch, aber ich bekomme es gerade ums Verrecken nicht gebacken.


BTW: Wie schiebe ich dem FreeBSD-Port den Patch am Geschicktesten unter, ohne es bei jedem Portupdate manuell wiederholen zu müssen?

Re: [S] Dokumentenindexer

Posted: 2011-03-30 18:17
by daemotron
Das könnte es tun:

Code: Select all

static size_t PrintTagTemplate(UDM_AGENT *Agent,FILE *stream,
                               char *dst,size_t dst_len,
                               UDM_VARLIST *vars,const char *tok,
                               const char *HlBeg, 
                               const char *HlEnd)
{
  char * opt;
  UDM_HTMLTOK ltag, *tag = &ltag;
  const char *last;
  UDM_VAR * var=NULL;
  UDM_VAR * var2=NULL;
  char * vname = NULL, *value = NULL;
  char * vname2 = NULL, *value2 = NULL;
  size_t i, res = 0;
  
  opt = (char*)UdmMalloc(strlen(tok) + 200);
  UdmHTMLTOKInit(tag);
  UdmHTMLToken(tok, &last, tag);
  sprintf(opt, "<");

  for (i = 0; i < ltag.ntoks; i++)
  {
    const char *space= (i == 0) ? "" : " ";
    if (ISTAG(i, "selected") && ltag.toks[i].vlen)
    {
      vname = UdmStrndup(ltag.toks[i].val, ltag.toks[i].vlen);
    }
    else if (ISTAG(i, "checked") && ltag.toks[i].vlen)
    {
      vname2 = UdmStrndup(ltag.toks[i].val, ltag.toks[i].vlen);
    }
    else if (ISTAG(i, "value"))
    {
      value = UdmStrndup(ltag.toks[i].val, ltag.toks[i].vlen);
      sprintf(UDM_STREND(opt), "%svalue=\"%s\"", space, value);
    }
    else
    {
      char *tname = UdmStrndup(ltag.toks[i].name, ltag.toks[i].nlen);
      if (ltag.toks[i].vlen)
      {
        char *tval = UdmStrndup(ltag.toks[i].val, ltag.toks[i].vlen);
        sprintf(UDM_STREND(opt), "%s%s=\"%s\"", space, tname, tval);
        UDM_FREE(tval);
      }
      else
      {
         sprintf(UDM_STREND(opt), "%s%s", space, tname);
      }
      UDM_FREE(tname);
    }
  }

  if(vname)
  {
    var= UdmVarListFindWithValue(vars, UdmTrim(vname, "$&()"), value ? value:"");
  }
  
  if(vname2)
  {
    var2= UdmVarListFindWithValue(vars, UdmTrim(vname2, "$&()"), value2 ? value2:"");
  }

  sprintf(UDM_STREND(opt), "%s%s>", var ? " selected=\"selected\"":"", var2 ? " checked=\"checked\"":"");

  if (vname) { UDM_FREE(vname); }
  if (value) { UDM_FREE(value); }
  if (vname2) { UDM_FREE(vname2); }
  if (value2) { UDM_FREE(value2); }

  res = PrintTextTemplate(Agent, stream, dst, dst_len, vars, opt, HlBeg, HlEnd);
  UDM_FREE(opt);
  return res;
}

Re: [S] Dokumentenindexer

Posted: 2011-03-30 19:40
by Joe User
Wunderbar, danke Dir! Das hätte mir eigentlich auch einfallen müssen :/

Re: [S] Dokumentenindexer

Posted: 2011-03-30 21:06
by daemotron
Hm, mir gefällt der Code ehrlich gesagt nicht besonders... gerade das sprintf ist nicht ungefährlich, da in einen begrenzt großen Buffer geschrieben wird, ohne dass eine Prüfung auf die Anzahl der zu schreibenden Bytes stattfindet. snprintf wäre eine sicherere Alternative, oder ich müsste mich noch mal in den gesamten Code reinfummeln und versuchen herauszufinden, wie groß opt schlimmstenfalls werden kann.

Kleine Optimierung:

Code: Select all

snprintf(UDM_STREND(opt), strlen(tok) + 200 - 1, "%s%s>", var ? " selected=\"selected\"":"", var2 ? " checked=\"checked\"":"");
P. S. hab grade gesehen, dass da noch mehr sprintf()s drinne sind, bei denen kein Buffer Overflow abgefangen wird :(

Re: [S] Dokumentenindexer

Posted: 2011-03-30 22:25
by Joe User
mnogosearch-3.3.11/src/template.c ist das Sourcefile. Das Template ist statisch und wird zur Runtime geparsed. Es müsste also das Templatefile gegen ein manipuliertes im Filesystem ersetzt werden. Wenn der Angreifer soweit kommt, hat er ohnehin genug Rechte, so dass er sich den Spass schenken kann. Trotzdem könnte ein Audit natürlich nie schaden, insbesondere bei einer so stark verbreiteten und mehrfach geforkten Software.

Re: [S] Dokumentenindexer

Posted: 2011-03-30 23:30
by Joe User
Punkt für Dich! Noch bin ich auf der betroffenen Maschine zwar mein eigener Kollege, aber das könnte sich langfristig ändern. Andererseits hoffe ich, dass die potentiellen Overflows an anderer Stelle (UDMMalloc?) abgefangen werden. Habe von C leider immernoch zu wenig Ahnung :/ Wird Zeit, dass ich mal wieder Zeit zum Lernen finde...

Re: [S] Dokumentenindexer

Posted: 2011-03-31 18:39
by daemotron
So, ich hab mir das ganze noch mal etwas genauer angeschaut. Zunächst einmal, das von mir angemäkelte sprintf() schreibt in einen (vermutlich) ausreichend dimensionierten Buffer. Sollten allerdings noch weitere Anhänge drangebastelt werden, sollten die +200 Bytes (in Zeile 16 in obigem Code, original Zeile 770) nach oben gesetzt werden.

Sodann hat ein bisschen weiteres Graben tatsächlich zu Tage gefördert, dass UdmMalloc() die Ausnutzbarkeit eines Buffer Overflows einschränkt. Speicher für Buffer werden dabei so allokiert, dass dahinter immer ein für den Prozess ungültiger Speicherbereich liegt. Das führt dazu, dass die Anwendung mit einem Segfault stirbt, wenn jemand versucht, da einen Buffer Overflow zu triggern.

Das ist insofern interessant, als man es als zusätzliches Sicherheitsnetz betrachten kann. Eine solche Strategie mit entsprechender Implementierung habe ich noch nirgendwo anders gesehen; malloc()-Wrapper sind zwar üblich, aber meist tun sie nicht mehr, als ENOMEM auf geeignete Weise abzufangen, damit das nicht an jeder Stelle im Code nach einem malloc() ausprogrammiert werden muss. Echt clever, muss ich sagen. Ob das tatsächlich immer und überall auch so funktioniert, kann ich auf die Schnelle allerdings nicht sehen.

Also erst mal Entwarnung: der oder die Programmierer wussten offenbar, was sie da tun. sprinft() anstelle von snprintf() ist stilistisch trotzdem nicht schön - so könnte man den Segfault von vornherein vermeiden und würde so doppelte Sicherheit erreichen - grade auch dann, wenn jemand mal am Code fummelt, um eine zusätzliche Property reinzubasteln, ohne die Speicherallokierung dabei anzupassen :wink:

Re: [S] Dokumentenindexer

Posted: 2011-03-31 20:42
by Joe User
Vielen Dank für den Quick-Audit, das beruhigt doch ungemein. Mit Segfaults kann man deutlich ruhiger leben als mit Overflows.

Schön, dass Du wieder etwas für Dich Neues entdeckt hast ;)