/** * $Id: scanner_smtp.cpp,v 1.25.2.1 2002/10/31 22:32:23 plasmahh Exp $ * $Revision: 1.25.2.1 $ * $Author: plasmahh $ * $Date: 2002/10/31 22:32:23 $ */ #include "scanner_smtp.h" scanner_smtp::~scanner_smtp()/*{{{*/ { conffp.clear(); rfcfp.clear(); returnfp.clear(); if ( scanned_conf ) delete scanned_conf; if ( scanned_rfc ) delete scanned_rfc; if ( scanned_return ) delete scanned_return; }/*}}}*/ BOOL scanner_smtp::initialize (void)/*{{{*/ { if ( debuglevel > 1 ) { cout << "Reading fingerprints from file..." << endl; } BOOL ret = true; ret &= load_return_fps (); ret &= load_rfc_fps (); ret &= load_conf_fps (); if ( debuglevel > 1 ) { cout << "Done reading fingerprints, error : " << !ret << endl; } return ret; }/*}}}*/ BOOL scanner_smtp::load_rfc_fps (void)/*{{{*/ { return load_fp("fingerprints-rfc","FP_RFC",FP_Rfc); }/*}}}*/ BOOL scanner_smtp::load_return_fps (void)/*{{{*/ { return load_fp("fingerprints-return","FP_RETURN",FP_Return); }/*}}}*/ BOOL scanner_smtp::load_conf_fps (void)/*{{{*/ { return load_fp("fingerprints-conf","FP_CONF",FP_Conf); }/*}}}*/ //######## New Version of this load function !! BOOL scanner_smtp::load_fp (const mstring& file, const mstring& identifier, fp_type fpt)/*{{{*/ { mstring filename; filename.format ("%s/share/smtpmap/%s", _PREFIX, (const char*) file ); mfile datei (filename); // Check if the file could be opened if (!datei.Open ()) { cout << "Error opening file " << filename << endl; perror (NULL); return false; } mstring line; mstring version; mstring fp_line; fp *cfp = NULL; uint32 fps; uint32 lenge = 0; uint32 lines = 0; BOOL was = true; // false means last was a version, true means last was a fingerprint. BOOL ret = true; // As long as there is data, read it ;) while (!datei.Eof ()) { line = get_next_line(datei); lines++; // because of this, we need a comment line to if (line.length () == 0) continue; // In this case, it was only an empty line, so ignore... if (line.strip_all_whitespaces().matches("VERSION=")) { if (!was) // if we have multiple lines, this was already set { printerror("Version line without a fingerprint found!",lines); ret = false; } was = false; version = line.substring( 9,0 ); } else if(line.strip_all_whitespaces().matches(identifier)) { if (was) { printerror("Fingerprint line without a Version found!",lines); ret=false; } was = true; fp_line = line.substring (identifier.length()+2, 0); } else { printerror("Invalid line found!",lines); ret = false; } if ( (!ret || lenge<0) && !polite) return false; if ( !was ) continue; switch (fpt) { case FP_Conf : cfp = new fp_conf(version); break; case FP_Return : cfp = new fp_return(version); break; case FP_Rfc : cfp = new fp_rfc(version); break; case FP_Pop3 : case FP_Ftp : case FP_Imap : case FP_Base : throw new x_implemented("Trying to load non-existend fingerprint types",__FLF__); break; } fps = gen_fp_data (cfp, fp_line); if (fps <= 0) // In this case, there was an error during generation { printerror("Invalid FP_CONF line found",lines); ret = false;//if (polite) { continue; } else { return false; } } if ( debuglevel > 1 ) { cout << "Found this fingerprint : " << endl; switch (fpt) { case FP_Conf : cout << *((fp_conf*)cfp) << endl; break; case FP_Return : cout << *((fp_return*)cfp) << endl; break; case FP_Rfc : cout << *((fp_rfc*)cfp) << endl; break; case FP_Pop3 : case FP_Ftp : case FP_Imap : case FP_Base : throw new x_implemented("Trying to load non-existend fingerprint types",__FLF__); break; } } switch (fpt) { case FP_Conf : conffp.add(*((fp_conf*)cfp)); break; case FP_Return : returnfp.add(*((fp_return*)cfp)); break; case FP_Rfc : rfcfp.add(*((fp_rfc*)cfp)); break; case FP_Pop3 : case FP_Ftp : case FP_Imap : case FP_Base : throw new x_implemented("Trying to load non-existend fingerprint types",__FLF__); break; } delete cfp; try { lenge = check_lenge (lenge, fps, lines,polite ); } catch(...) { if (!polite) return false; } } return true; }/*}}}*/ void scanner_smtp::printerror( const mstring & error, uint32 line )/*{{{*/ { cout << "Error in line " << line << " : " << error; if (polite) { cout << " ( --polite set, ignoring ) " << endl; } else { cout << endl; } }/*}}}*/ uint32 scanner_smtp::check_lenge (uint32 lenge, uint32 fps, uint32 lines ,BOOL polite)/*{{{*/ { if (lenge == 0) { lenge = fps; } else if (lenge != fps) { printerror( "FP Size does not match previously ones.", lines); throw(-1); } return lenge; }/*}}}*/ sint32 scanner_smtp::gen_fp_data (fp * cfp, mstring & fp)/*{{{*/ { uint32 nk=0; uint32 fps=0; uint32 sfp=0; char * end=NULL; mstring num; do { nk = fp.lsearch (","); num = fp.substring (1, nk - 1); fp = fp.substring (nk + 1, 0); fps++; sfp = strtol (num, &end, 10); if ( end != num[num.length()] ) { return -1; } // generate a more elaborate version of this stuff here cfp->add (sfp); } while (fp.lsearch (",") > 0); sfp = strtol (fp, NULL, 10); cfp->add (sfp); return fps; }/*}}}*/ mstring scanner_smtp::is_server (void)/*{{{*/ { mstring server("Unknown"); sock.Send ("EHLO myhost.domain.com\r\n"); // and look if Receive() == 250 = OK sock.Disconnect(); return server; }/*}}}*/ void scanner_smtp::finalize (void)/*{{{*/ { if ( debuglevel > 1 ) { cout << "Finalizing fingerprints ..." ; } // iterate through the fingerprints and set error values dlliterator < fp_conf > itc (conffp); dlliterator < fp_rfc > itf (rfcfp); dlliterator < fp_return > itr (returnfp); for (itc.first (); itc.valid (); itc.next ()) { itc.item ().gen_error (*scanned_conf); } for (itf.first (); itf.valid (); itf.next ()) { itf.item ().gen_error (*scanned_rfc); } for (itr.first (); itr.valid (); itr.next ()) { itr.item ().gen_error (*scanned_return); } if (debuglevel > 1) { cout << " done." << endl; } }/*}}}*/ dllist < dllist < fp > >scanner_smtp::get_fps (void)/*{{{*/ { /* * We return all the fingerprints here in a dllist. * 1. Item : dllist of all the config fingerprints we have * 2. Item : dllist of all the rfc fingerprints we have. * 3. Item : dllist of all the generic return fingerprints. * * Since we return all of them as FP, not as FP_CONF or whatever, we will only * get description and error values !!! Not the real fingerprint, which means * we can output it only in this class !!! this needs us to get the debuglevel * in the future */ dlliterator < fp_conf > itc (conffp); dlliterator < fp_rfc > itf (rfcfp); dlliterator < fp_return > itr (returnfp); dllist < fp > fpc, fpf, fpr; // iterate through the config fingerprints for (itc.first (); itc.valid (); itc.next ()) { fpc.add (itc.item ()); } for (itf.first (); itf.valid (); itf.next ()) { fpf.add (itf.item ()); } for (itr.first (); itr.valid (); itr.next ()) { fpr.add (itr.item ()); } // all have been added, generate the "big" dllist dllist < dllist < fp > >allfps; allfps.add (fpc); allfps.add (fpf); allfps.add (fpr); return allfps; // return a list of lists of fingerprints }/*}}}*/ dllist < mstring > scanner_smtp::get_descs (void)/*{{{*/ { // return a list of descriptions of the fingerprint types... // hardcode this here a bit... dllist < mstring > desc; desc.add ("Configuration Fingerprinting"); desc.add ("RFC Fingerprinting"); desc.add ("Overall Fingerprinting"); return desc; }/*}}}*/ BOOL scanner_smtp::do_scan (void)/*{{{*/ { // do the actual scan... humm, this will be a lot I guess const char **cmd; mstring answer; mstring temp; mstring banner; uint32 numbers, count; uint32 recon = 0; cmd = testcmds; numbers = sizeof (testcmds) / sizeof(cmd); // connect to target if (debuglevel > 2) { cout << "scanner_smtp calls Connect ( " << target_host << ")" << endl; } if ( ! sock.Connect (target_host, target_port, conn_timeout) ) { cout << "Could not connect to host, aborting scan ! " << endl; cout << "Reason : " ; cout << sock.GetLastErrorMsg() << endl; return false; } if ( debuglevel > 2 ) { cout << "Connection stuff is done..." << endl; } banner = get_rfc_answer(); if ( debuglevel > 1 ) { cout << "Connection Data : " << endl; cout << "port " << sock.get_port () << endl; cout << "socket " << sock.get_fd () << endl; cout << "target " << sock.get_peer () << endl; cout << "RECV \"" << banner << "\"" << endl; cout << "SEND " << "EHLO myhost.domain.com\r\n" << endl; } sock.Send ((mstring)"EHLO myhost.domain.com\r\n",recv_timeout); answer = get_rfc_answer(); if ( debuglevel > 1 ) { cout << "RECV \"" << answer << "\""< 1 ) { cout << "\nSEND " << *cmd; } sock.Send (*cmd); answer = get_rfc_answer(); // delete the answer... if ( ! sock.Connected() ) { cout << endl << "Disconnection detected, trying to reconnect" << endl; // disconnection detected... try to reconnet recon++; if ( recon > 3 ) { cout << "too much disconnects detected, aborting this scan" << endl; return false; } if ( ! sock.Reconnect(conn_timeout) ) { cout << "failed to reconnect" << endl; return false; } banner = get_rfc_answer(); sock.Send ("EHLO myhost.domain.com\r\n"); temp = get_rfc_answer(); } scanned_return->add (answer); scanned_conf->add (answer); scanned_rfc->add (answer); if (debuglevel > 1 ) { cout << "RECV " << answer << endl; } count ++; if ( debuglevel > 2 ) { cout << count << ". Result Checksum is : " << answer.checksum_sum() << endl; } cout << "\r" << (double) count / (double) numbers * 100.0 << " %" << flush; } cout << "\r100 % done scan" << endl; if ( debuglevel > 0) { cout << "The scanned fingerprints are : " << endl; cout << *scanned_return; cout << *scanned_rfc; cout << *scanned_conf; } return true; }/*}}}*/ /** *$Log: scanner_smtp.cpp,v $ *Revision 1.25.2.1 2002/10/31 22:32:23 plasmahh *fix mstring class ;) * *Revision 1.25 2002/10/21 08:38:29 plasmahh *begin cleanup and structure changes for smtpmap 0.8-stable * *Revision 1.24 2002/10/16 23:06:17 plasmahh *new function for reading fingerprints from file *fixes some stuff * *Revision 1.23 2002/10/01 20:59:02 plasmahh *some new structures, to maintain multiple protocols bette * *Revision 1.22 2002/08/12 13:13:05 plasmahh *removed some memory leaks * *Revision 1.21 2002/08/08 21:52:59 plasmahh *better debug * *Revision 1.20 2002/08/08 21:47:28 plasmahh *more debug * *Revision 1.19 2002/07/24 18:06:47 plasmahh *some slight fixes *fingerprint changes and cleanups *default value changes * *Revision 1.18 2002/06/20 20:37:01 plasmahh *new fingerprints *fixed correct fingerprinting on multiple hosts * *Revision 1.17 2002/06/18 13:42:39 plasmahh *fixed timeout behaviour *new fingerprints added *improved documentation * *Revision 1.16 2002/06/17 12:23:48 plasmahh *fixed timeout bugs * *Revision 1.14 2002/06/12 23:05:07 plasmahh *New fingerprints * *Revision 1.13 2002/06/11 21:39:31 plasmahh *improved reconnection behaviour * *Revision 1.12 2002/06/11 21:01:53 plasmahh *forgot debug messages * *Revision 1.11 2002/06/11 20:57:38 plasmahh *hopefully fixed "hanging" bug * *Revision 1.10 2002/06/11 20:04:15 plasmahh *fixed bad connection behaviour bug * *Revision 1.9 2002/06/11 18:54:35 plasmahh *fixed timeout behaviour, need only to fix reconnects... *new fingerprint * *Revision 1.8 2002/06/11 18:23:53 plasmahh *reverified fingerprints * *Revision 1.7 2002/06/09 21:22:39 plasmahh *lots of changes *some slight fingerprint changes, also in constructor *scanner changes and fixes in constructor *read fixes *test programs fixes, no more segfaults *new TODO * *Revision 1.6 2002/05/29 12:10:35 plasmahh *öhm, ja... dont know ;) * *Revision 1.5 2002/05/27 06:26:17 plasmahh *Implemented, tested and fixed fingerprinting. Test Programs generate good fingerprints, only need to put all in a program and generateerror values * *Revision 1.4 2002/05/23 22:37:55 plasmahh *fixed small things in scanner *split fps into .cpp files, because of linker errors in operators * *Revision 1.3 2002/05/23 19:50:04 plasmahh *refined include structure. *implemented and fixed some parts, still not working *BUG !! FIX THIS !!! : multiple definition of some operators, we will never compile !! * *Revision 1.2 2002/05/16 23:32:12 plasmahh *Added fingerprint reading, first version needs to be heavily tested ! * *Revision 1.1 2002/05/14 16:31:59 plasmahh *implementing new scanner structure, that will be e xtendible * */