diff --git a/.gitignore b/.gitignore index 645277f8280f489e01fad3d6017aaffaf244f3e8..c1d6c7a9214c2859eac7ae5033a24abd031121b3 100644 --- a/.gitignore +++ b/.gitignore @@ -28,10 +28,15 @@ /win32/Debug_NoLibs/ /win32/*/Debug_NoLibs/ /win32/Debug/ +/win32/Debug_PostgreSQL/ /win32/*/Debug/ +/win32/*/Debug_PostgreSQL/ /win32/Release/ +/win32/Release_PostgreSQL/ /win32/*/Release/ +/win32/*/Release_PostgreSQL/ /win32/*/x64/ +/win32/x64/ /win32/*/*.user win32/ipch win32/BuildErrors.txt diff --git a/bindings/java/build-windows.xml b/bindings/java/build-windows.xml index 52cf2e5fba634c68feb952c81d8cd40dc83ad12b..b01898578287ffc760d64952988c3fab7459b201 100644 --- a/bindings/java/build-windows.xml +++ b/bindings/java/build-windows.xml @@ -56,8 +56,19 @@ <property name="tsk.config" value="Debug"/> <antcall target="copyWinTskLibsToBuild" /> </target> + + <target name="copyLibsPostgreSQL" description="Copy native libs to the correct folder"> + <property name="tsk.config" value="Release_PostgreSQL"/> + <antcall target="copyWinTskLibsToBuildPostgres" /> + </target> - <target name="copyWinTskLibsToBuild" depends="copyWinTskLibs64ToBuild,copyWinTskLibs32ToBuild" description="Copy windows dlls to the correct location." /> + <target name="copyLibsPostgreSQLDebug" description="Copy native libs to the correct folder"> + <property name="tsk.config" value="Debug_PostgreSQL"/> + <antcall target="copyWinTskLibsToBuild" /> + </target> + + + <target name="copyWinTskLibsToBuild" depends="copyWinTskLibs64ToBuild, copyWinTskLibs32ToBuild" description="Copy windows dlls to the correct location." /> <target name="checkTskLibDirs"> <available property="win64.TskLib.exists" type="file" file="${basedir}/../../win32/x64/${tsk.config}/libtsk_jni.dll" /> @@ -73,10 +84,47 @@ <target name="copyWinTskLibs32ToBuild" depends="checkTskLibDirs" if="win32.TskLib.exists"> <property name="tsk.jni.32" location="${basedir}/../../win32/${tsk.config}/libtsk_jni.dll" /> + + <copy file="${tsk.jni.32}" todir="${i386}/win" overwrite="true"/> + <copy file="${tsk.jni.32}" todir="${x86}/win" overwrite="true"/> + <copy file="${tsk.jni.32}" todir="${i586}/win" overwrite="true"/> + <copy file="${tsk.jni.32}" todir="${i686}/win" overwrite="true"/> + </target> + <target name="copyWinTskLibsToBuildPostgres" depends="copyWinTskLibs64ToBuildPostgres" description="Copy windows dlls to the correct location." /> + + <target name="checkTskLibDirsPostgres"> + <available property="win64.TskLib.exists" type="file" file="${basedir}/../../win32/x64/${tsk.config}/libtsk_jni.dll" /> + <available property="win32.TskLib.exists" type="file" file="${basedir}/../../win32/${tsk.config}/libtsk_jni.dll" /> + </target> + + <target name="copyWinTskLibs64ToBuildPostgres" depends="checkTskLibDirsPostgres" if="win64.TskLib.exists"> + <property name="tsk.jni.64" location="${basedir}/../../win32/x64/${tsk.config}/libtsk_jni.dll" /> + <property name="libintl-8.64" location="${basedir}/../../win32/x64/${tsk.config}/libintl-8.dll" /> + <property name="libeay32.64" location="${basedir}/../../win32/x64/${tsk.config}/libeay32.dll" /> + <property name="ssleay32.64" location="${basedir}/../../win32/x64/${tsk.config}/ssleay32.dll" /> + <property name="libpq.64" location="${basedir}/../../win32/x64/${tsk.config}/libpq.dll" /> + + <copy file="${tsk.jni.64}" todir="${amd64}/win" overwrite="true"/> + <copy file="${tsk.jni.64}" todir="${x86_64}/win" overwrite="true"/> + <copy file="${libintl-8.64}" todir="${amd64}/win" overwrite="true"/> + <copy file="${libintl-8.64}" todir="${x86_64}/win" overwrite="true"/> + <copy file="${libeay32.64}" todir="${amd64}/win" overwrite="true"/> + <copy file="${libeay32.64}" todir="${x86_64}/win" overwrite="true"/> + <copy file="${ssleay32.64}" todir="${amd64}/win" overwrite="true"/> + <copy file="${ssleay32.64}" todir="${x86_64}/win" overwrite="true"/> + <copy file="${libpq.64}" todir="${amd64}/win" overwrite="true"/> + <copy file="${libpq.64}" todir="${x86_64}/win" overwrite="true"/> + </target> + + <target name="copyWinTskLibs32ToBuildPostgres" depends="checkTskLibDirsPostgres" if="win32.TskLib.exists"> + <property name="tsk.jni.32" location="${basedir}/../../win32/${tsk.config}/libtsk_jni.dll" /> + <copy file="${tsk.jni.32}" todir="${i386}/win" overwrite="true"/> <copy file="${tsk.jni.32}" todir="${x86}/win" overwrite="true"/> <copy file="${tsk.jni.32}" todir="${i586}/win" overwrite="true"/> <copy file="${tsk.jni.32}" todir="${i686}/win" overwrite="true"/> </target> + + </project> diff --git a/bindings/java/build.xml b/bindings/java/build.xml index 7979fa2b9412481aee5613fa1bd6fd8623b6b385..5898095028f5ac1e3572998bceff222fc503bb7f 100755 --- a/bindings/java/build.xml +++ b/bindings/java/build.xml @@ -130,6 +130,11 @@ <antcall target="dist-do"/> </target> + <target name="dist_PostgreSQL" depends="check-build" unless="up-to-date"> + <antcall target="dist-do-postgres"/> + </target> + + <target name="check-build" depends="check-native-build"> <uptodate property="java-up-to-date" targetfile="${dist}/Tsk_DataModel.jar" > <srcfiles dir="${src}" includes="**/*.java"/> @@ -148,13 +153,24 @@ <jar jarfile="${dist}/Tsk_DataModel.jar" basedir="${build}"/> </target> + <target name="dist-do-postgres" depends="init-ivy, compile, copyLibsPostgreSQL" + description="generate the distribution" > + <!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file --> + <jar jarfile="${dist}/Tsk_DataModel.jar" basedir="${build}"/> + </target> + <target name="dist-debug" depends="init-ivy, compile, copyLibsDebug" description="generate the distribution" > <!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file --> <jar jarfile="${dist}/Tsk_DataModel.jar" basedir="${build}"/> </target> - + <target name="dist-debug-PostgreSQL" depends="init-ivy, compile, copyLibsPostgreSQLDebug" + description="generate the distribution" > + <!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file --> + <jar jarfile="${dist}/Tsk_DataModel.jar" basedir="${build}"/> + </target> + <target name="jni" depends="compile" description="make the jni.h file"> <javah classpath = "${build}" outputFile="jni/dataModel_SleuthkitJNI.h" force="yes"> diff --git a/bindings/java/jni/dataModel_SleuthkitJNI.cpp b/bindings/java/jni/dataModel_SleuthkitJNI.cpp index 7b1d4d4cb69c1cc2d0fbecc1d3a7767e36515f80..88da1ff32ecd2510acc15fd1539f95626efb6a71 100644 --- a/bindings/java/jni/dataModel_SleuthkitJNI.cpp +++ b/bindings/java/jni/dataModel_SleuthkitJNI.cpp @@ -20,6 +20,7 @@ #include <string> #include <algorithm> #include <sstream> + using std::string; using std::vector; using std::map; @@ -248,6 +249,78 @@ JNIEXPORT jlong JNICALL } +/* + * Create a TskCaseDb with an associated database + * @return the pointer to the case + * @param env pointer to java environment this was called from + * @param env pointer to java environment this was called from + * @param cls the java class + * @param host the hostname or IP address + * @param port the port number as a string + * @param user the user name for the database + * @param pass the password for the database + * @param dbType the ordinal value of the enum for the database type + * @param dbName the name of the database to create + * @return 0 on error (sets java exception), pointer to newly opened TskCaseDb object on success + */ +JNIEXPORT jlong JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_newCaseDbMultiNat(JNIEnv *env, jclass cls, jstring host, jstring port, jstring user, jstring pass, jint dbType, jstring dbName) +{ + TSK_TCHAR dbPathT[1024]; + toTCHAR(env, dbPathT, 1024, dbName); + + CaseDbConnectionInfo info(env->GetStringUTFChars(host, false), + env->GetStringUTFChars(port, false), + env->GetStringUTFChars(user, false), + env->GetStringUTFChars(pass, false), + (CaseDbConnectionInfo::DbType)dbType); + + TskCaseDb *tskCase = TskCaseDb::newDb(dbPathT, &info); + + if (tskCase == NULL) { + setThrowTskCoreError(env); + return 0; + } + + return (jlong) tskCase; +} + + +/* + * Open a TskCaseDb with an associated database + * @return the pointer to the case + * @param env pointer to java environment this was called from + * @param cls the java class + * @param host the hostname or IP address + * @param port the port number as a string + * @param user the user name for the database + * @param pass the password for the database + * @param dbType the ordinal value of the enum for the database type + * @param dbName the name of the database to open + * @return Returns pointer to object or exception on error + */ +JNIEXPORT jlong JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_openCaseDbMultiNat(JNIEnv *env, jclass cls, jstring host, jstring port, jstring user, jstring pass, jint dbType, jstring dbName) +{ + TSK_TCHAR dbPathT[1024]; + toTCHAR(env, dbPathT, 1024, dbName); + + CaseDbConnectionInfo info(env->GetStringUTFChars(host, false), + env->GetStringUTFChars(port, false), + env->GetStringUTFChars(user, false), + env->GetStringUTFChars(pass, false), + (CaseDbConnectionInfo::DbType)dbType); + + TskCaseDb *tskCase = TskCaseDb::openDb(dbPathT, &info); + + if (tskCase == NULL) { + setThrowTskCoreError(env); + return 0; + } + + return (jlong) tskCase; +} + + + /* * Open a TskCaseDb with an associated database * @return the pointer to the case @@ -272,6 +345,7 @@ JNIEXPORT jlong JNICALL return (jlong) tskCase; } + /* * Close (cleanup) a case * @param env pointer to java environment this was called from diff --git a/bindings/java/jni/dataModel_SleuthkitJNI.h b/bindings/java/jni/dataModel_SleuthkitJNI.h index 3daa672b8c11c4e0e66c670e30ac067ad51dccff..53c804f6ee7b060d5121be6c320a9be42406d446 100644 --- a/bindings/java/jni/dataModel_SleuthkitJNI.h +++ b/bindings/java/jni/dataModel_SleuthkitJNI.h @@ -33,6 +33,22 @@ JNIEXPORT void JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_startVerboseLog JNIEXPORT jlong JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_newCaseDbNat (JNIEnv *, jclass, jstring); +/* + * Class: org_sleuthkit_datamodel_SleuthkitJNI + * Method: newCaseDbMultiNat + * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;)J + */ +JNIEXPORT jlong JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_newCaseDbMultiNat + (JNIEnv *env, jclass cls, jstring host, jstring port, jstring user, jstring pass, jint asdf, jstring dbName); + +/* + * Class: org_sleuthkit_datamodel_SleuthkitJNI + * Method: openCaseDbMultiNat + * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;)J + */ +JNIEXPORT jlong JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_openCaseDbMultiNat + (JNIEnv *, jclass, jstring, jstring, jstring, jstring, jint, jstring); + /* * Class: org_sleuthkit_datamodel_SleuthkitJNI * Method: openCaseDbNat diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java index 08984ae89bd4597d011af0cf2b09ca3a251d6289..970e4de4b0a117af62f2975a8a1edab1997117e6 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java +++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java @@ -139,6 +139,7 @@ private void initBlackboardArtifactTypes() throws SQLException, TskCoreException statement = connection.createStatement(); for (ARTIFACT_TYPE type : ARTIFACT_TYPE.values()) { resultSet = connection.executeQuery(statement, "SELECT COUNT(*) from blackboard_artifact_types WHERE artifact_type_id = '" + type.getTypeID() + "'"); //NON-NLS + resultSet.next(); if (resultSet.getLong(1) == 0) { connection.executeUpdate(statement, "INSERT INTO blackboard_artifact_types (artifact_type_id, type_name, display_name) VALUES (" + type.getTypeID() + " , '" + type.getLabel() + "', '" + type.getDisplayName() + "')"); //NON-NLS } @@ -165,6 +166,7 @@ private void initBlackboardAttributeTypes() throws SQLException, TskCoreExceptio statement = connection.createStatement(); for (ATTRIBUTE_TYPE type : ATTRIBUTE_TYPE.values()) { resultSet = connection.executeQuery(statement, "SELECT COUNT(*) from blackboard_attribute_types WHERE attribute_type_id = '" + type.getTypeID() + "'"); //NON-NLS + resultSet.next(); if (resultSet.getLong(1) == 0) { connection.executeUpdate(statement, "INSERT INTO blackboard_attribute_types (attribute_type_id, type_name, display_name) VALUES (" + type.getTypeID() + ", '" + type.getLabel() + "', '" + type.getDisplayName() + "')"); //NON-NLS } @@ -193,6 +195,7 @@ private void initNextArtifactId() throws TskCoreException, SQLException { try { statement = connection.createStatement(); resultSet = connection.executeQuery(statement, "SELECT MAX(artifact_id) FROM blackboard_artifacts"); + resultSet.next(); this.nextArtifactId = resultSet.getLong(1) + 1; if (this.nextArtifactId == 1) { this.nextArtifactId = BASE_ARTIFACT_ID; @@ -547,11 +550,22 @@ public static SleuthkitCase openCase(String dbPath) throws TskCoreException { * @throws org.sleuthkit.datamodel.TskCoreException */ public static SleuthkitCase openCase(String databaseName, CaseDbConnectionInfo info) throws TskCoreException { - // TODO - return null; + try { + if (info.getDbType() != CaseDbConnectionInfo.DbType.UNKNOWN) { + if (info.settingsValid()) { + final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(databaseName, info); + return new SleuthkitCase(info.getHost(), Integer.parseInt(info.getPort()), databaseName, info.getUserName(), info.getPassword(), caseHandle, "C:/fake"); /// KDM deal with "fake" + } else { + throw new TskCoreException("Bad database credentials."); + } + } else { + throw new TskCoreException("Multi-user cases are not enabled."); + } + } catch (Exception ex) { + throw new TskCoreException(ex.getMessage(), ex); + } } - /** * Create a new case database. * @@ -577,8 +591,13 @@ public static SleuthkitCase newCase(String dbPath) throws TskCoreException { * @throws org.sleuthkit.datamodel.TskCoreException */ public static SleuthkitCase newCase(String databaseName, CaseDbConnectionInfo info) throws TskCoreException { - // TODO - return null; + SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.newCaseDb(databaseName, info); + try { + return new SleuthkitCase(info.getHost(), Integer.parseInt(info.getPort()), + databaseName, info.getUserName(), info.getPassword(), caseHandle, null); /// KDM last argument (caseDirPath) doesn't make much sense in this context. fix it. + } catch (Exception ex) { + throw new TskCoreException("Failed to create case database " + databaseName, ex); + } } /** @@ -1354,6 +1373,7 @@ public BlackboardArtifact getBlackboardArtifact(long artifactID) throws TskCoreE statement.clearParameters(); statement.setLong(1, artifactID); rs = connection.executeQuery(statement); + rs.next(); long obj_id = rs.getLong(1); int artifact_type_id = rs.getInt(2); return new BlackboardArtifact(this, artifactID, obj_id, artifact_type_id, @@ -2739,13 +2759,15 @@ public List<VirtualDirectory> getVirtualDirectoryRoots() throws TskCoreException Statement s = null; ResultSet rs = null; try { - s = connection.createStatement(); - rs = connection.executeQuery(s, "SELECT tsk_files.* FROM tsk_objects, tsk_files WHERE " //NON-NLS + short firstone = TskData.ObjectType.ABSTRACTFILE.getObjectType(); + short secondone = TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType(); + rs = connection.executeQuery(s, "SELECT tsk_files.* FROM tsk_objects, tsk_files WHERE " //NON-NLS + "tsk_objects.par_obj_id IS NULL AND " //NON-NLS - + "tsk_objects.type = " + TskData.ObjectType.ABSTRACTFILE.getObjectType() + " AND " //NON-NLS + + "tsk_objects.type = " + firstone + " AND " //NON-NLS + "tsk_objects.obj_id = tsk_files.obj_id AND " //NON-NLS - + "tsk_files.type = " + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() - + " ORDER BY tsk_files.dir_type, tsk_files.name COLLATE NOCASE"); //NON-NLS + + "tsk_files.type = " + secondone + + " ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"); //NON-NLS /// KDM is this good enough for SQLite? was "tsk_files.name COLLATE NOCASE" + List<VirtualDirectory> virtDirRootIds = new ArrayList<VirtualDirectory>(); while (rs.next()) { virtDirRootIds.add(rsHelper.virtualDirectory(rs)); @@ -3286,6 +3308,7 @@ public long countFilesWhere(String sqlWhereClause) throws TskCoreException { try { s = connection.createStatement(); rs = connection.executeQuery(s, "SELECT COUNT (*) FROM tsk_files WHERE " + sqlWhereClause); //NON-NLS + rs.next(); return rs.getLong(1); } catch (SQLException e) { throw new TskCoreException("SQLException thrown when calling 'SleuthkitCase.findFilesWhere().", e); @@ -3739,6 +3762,7 @@ public Collection<FileSystem> getFileSystems(Image image) { while (imageID == null) { try { rs = connection.executeQuery(s, "SELECT * FROM tsk_objects WHERE tsk_objects.obj_id = " + currentObjID); //NON-NLS + rs.next(); currentObjID = rs.getLong("par_obj_id"); //NON-NLS if (rs.getInt("type") == TskData.ObjectType.IMG.getObjectType()) { //NON-NLS imageID = rs.getLong("obj_id"); //NON-NLS @@ -4159,12 +4183,9 @@ public void closeRunQuery(ResultSet resultSet) throws SQLException { /** * This method allows developers to run arbitrary SQL "SELECT" - * queries. The CaseDbQuery object will take care of acquiring + * queries. The CaseDbQuery object will take care to acquiring * the necessary database lock and when used in a try-with-resources * block will automatically take care of releasing the lock. - * If you do not use a try-with-resources block you must call - * CaseDbQuery.close() once you are done processing the results of - * the query. * @param query The query string to execute. * @return A CaseDbQuery instance. * @throws TskCoreException @@ -4552,7 +4573,9 @@ public TagName addTagName(String displayName, String description, TagName.HTML_C statement.setString(3, color.getName()); connection.executeUpdate(statement); resultSet = statement.getGeneratedKeys(); - return new TagName(resultSet.getLong(1), displayName, description, color); + resultSet.next(); + long asdf=resultSet.getLong(1); + return new TagName(asdf, displayName, description, color); } catch (SQLException ex) { throw new TskCoreException("Error adding row for " + displayName + " tag name to tag_names table", ex); } finally { @@ -4587,6 +4610,7 @@ public ContentTag addContentTag(Content content, TagName tagName, String comment statement.setLong(5, endByteOffset); connection.executeUpdate(statement); resultSet = statement.getGeneratedKeys(); + resultSet.next(); return new ContentTag(resultSet.getLong(1), content, tagName, comment, beginByteOffset, endByteOffset); } catch (SQLException ex) { throw new TskCoreException("Error adding row to content_tags table (obj_id = " + content.getId() + ", tag_name_id = " + tagName.getId() + ")", ex); @@ -5147,12 +5171,12 @@ enum PREPARED_STATEMENT { + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS + "WHERE (tsk_objects.par_obj_id = ? ) " //NON-NLS - + "ORDER BY tsk_files.dir_type, tsk_files.name COLLATE NOCASE"), //NON-NLS + + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS SELECT_FILES_BY_PARENT_AND_TYPE("SELECT tsk_files.* " //NON-NLS + "FROM tsk_objects INNER JOIN tsk_files " //NON-NLS + "ON tsk_objects.obj_id=tsk_files.obj_id " //NON-NLS + "WHERE (tsk_objects.par_obj_id = ? AND tsk_files.type = ? ) " //NON-NLS - + "ORDER BY tsk_files.dir_type, tsk_files.name COLLATE NOCASE"), //NON-NLS + + "ORDER BY tsk_files.dir_type, LOWER(tsk_files.name)"), //NON-NLS SELECT_FILE_IDS_BY_PARENT("SELECT tsk_files.obj_id FROM tsk_objects INNER JOIN tsk_files " //NON-NLS + "ON tsk_objects.obj_id=tsk_files.obj_id WHERE (tsk_objects.par_obj_id = ?)"), //NON-NLS SELECT_FILE_IDS_BY_PARENT_AND_TYPE("SELECT tsk_files.obj_id " //NON-NLS @@ -5477,6 +5501,11 @@ private static final class PostgreSQLConnection extends CaseDbConnection { } static Connection createConnection(String host, int port, String dbName, String userName, String password) { + try { + return DriverManager.getConnection("jdbc:postgresql://" + host + ":" + port + "/" + dbName, userName, password); // NON-NLS + } catch (SQLException ex) { + Logger.getLogger(SleuthkitCase.class.getName()).log(Level.SEVERE, null, ex); + } return null; } diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java index ffe617cef484990c243d547ed5bd773b263b5768..ee089b8687c0cb44f0ee048c3bb93a0f877dd454 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java +++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java @@ -51,8 +51,12 @@ public class SleuthkitJNI { //database private static native long newCaseDbNat(String dbPath) throws TskCoreException; + private static native long newCaseDbMultiNat(String hostNameOrIP, String portNumber, String userName, String password, int dbTypeOrdinal, String databaseName); + + private static native long openCaseDbMultiNat(String hostNameOrIP, String portNumber, String userName, String password, int dbTypeOrdinal, String databaseName); + private static native long openCaseDbNat(String path) throws TskCoreException; - + private static native void closeCaseDbNat(long db) throws TskCoreException; private static native int hashDbOpenNat(String hashDbPath) throws TskCoreException; @@ -319,6 +323,19 @@ static CaseDbHandle newCaseDb(String path) throws TskCoreException { return new CaseDbHandle(newCaseDbNat(path)); } + /** + * Creates a new case database. Must call .free() on CaseDbHandle instance + * when done. + * + * @param path Location to create the database at. + * @return Handle for a new TskCaseDb instance. + * @throws TskCoreException exception thrown if critical error occurs within + * TSK /// KDM + */ + static CaseDbHandle newCaseDb(String databaseName, CaseDbConnectionInfo info) throws TskCoreException { + return new CaseDbHandle(newCaseDbMultiNat(info.getHost(), info.getPort(), info.getUserName(), info.getPassword(), info.getDbType().ordinal(), databaseName)); + } + /** * Opens an existing case database. Must call .free() on CaseDbHandle * instance when done. @@ -329,9 +346,22 @@ static CaseDbHandle newCaseDb(String path) throws TskCoreException { * TSK */ static CaseDbHandle openCaseDb(String path) throws TskCoreException { - return new CaseDbHandle(openCaseDbNat(path)); + return new CaseDbHandle(openCaseDbNat(path)); } + /** + * Opens an existing case database. Must call .free() on CaseDbHandle + * instance when done. + * + * @param path Location of the existing database. + * @return Handle for a new TskCaseDb instance. + * @throws TskCoreException exception thrown if critical error occurs within + * TSK //// KDM + */ + static CaseDbHandle openCaseDb(String databaseName, CaseDbConnectionInfo info) throws TskCoreException { + return new CaseDbHandle(openCaseDbMultiNat(info.getHost(), info.getPort(), info.getUserName(), info.getPassword(), info.getDbType().ordinal(), databaseName)); + } + /** * get the Sleuth Kit version string * diff --git a/tsk/auto/Makefile.am b/tsk/auto/Makefile.am index 8276c3f9b0ae9153f6201f158b7a3cea21e6f12c..ef9d9991c5ec98242926aaaad10b3b45ef3a4bf6 100755 --- a/tsk/auto/Makefile.am +++ b/tsk/auto/Makefile.am @@ -3,7 +3,7 @@ EXTRA_DIST = .indent.pro noinst_LTLIBRARIES = libtskauto.la # Note that the .h files are in the top-level Makefile -libtskauto_la_SOURCES = auto.cpp auto_db.cpp sqlite3.c sqlite3.h db_sqlite.cpp case_db.cpp tsk_case_db.h tsk_db.cpp tsk_auto.h tsk_auto_i.h tsk_case_db.h tsk_db.h tsk_db_sqlite.h +libtskauto_la_SOURCES = db_connection_info.h auto.cpp auto_db.cpp sqlite3.c sqlite3.h db_sqlite.cpp case_db.cpp tsk_case_db.h tsk_db.cpp tsk_auto.h tsk_auto_i.h tsk_case_db.h tsk_db.h tsk_db_sqlite.h indent: indent *.cpp *.h diff --git a/tsk/auto/case_db.cpp b/tsk/auto/case_db.cpp index e1a6803b05c3c6908c1f614c38aefc9bc25cd213..8609b8159320e5a4356397c12b9adaca25cdfc0e 100644 --- a/tsk/auto/case_db.cpp +++ b/tsk/auto/case_db.cpp @@ -45,24 +45,54 @@ TskCaseDb::~TskCaseDb() } /** -* Creates a new case with a new database and initializes its tables. -* Fails if there's already a file at the given path. Returns a pointer -* to a new TskCaseDb if successful, else NULL. +* Creates a new single-user case with a new database and initializes its tables. +* Fails if there's already a file at the given path. * * @param path Full path to create new database at. +* @returns Pointer to a new TskCaseDb object, NULL on error */ TskCaseDb * TskCaseDb::newDb(const TSK_TCHAR * const path) { + TskDb *db = new TskDbSqlite(path, true); -#if defined(HAVE_POSTGRESQL) && defined(TSK_WIN32) - // ELTODO: check here which database to initialize - //TskDb *db = new TskDbSqlite(path, true); + // Check if the database already exsists + if (db->dbExists()) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_AUTO_DB); + tsk_error_set_errstr("Database %" PRIttocTSK + " already exists. Must be deleted first.", path); + delete(db); + return NULL; + } + + // Open the database. + if (db->open(true)) { + delete(db); + return NULL; + } + + return new TskCaseDb(db); +} +/** +* Creates a new multi-user case with a new database and initializes its tables. +* Fails if multi-user database with requested name already exists. +* +* @param path Full path to create new database at. +* @returns Pointer to a new TskCaseDb object, NULL on error +*/ +TskCaseDb * +TskCaseDb::newDb(const TSK_TCHAR * const path, CaseDbConnectionInfo * info) +{ +#if defined(HAVE_POSTGRESQL) && defined(TSK_WIN32) TskDb *db = new TskDbPostgreSQL(path, true); -#else - TskDb *db = new TskDbSqlite(path, true); -#endif // HAVE_POSTGRESQL && TSK_WIN32 + + // Store connection info for the multi-user database + if (db->setConnectionInfo(info) != TSK_OK) { + delete(db); + return NULL; + } // Check if the database already exsists if (db->dbExists()) { @@ -81,25 +111,59 @@ TskCaseDb::newDb(const TSK_TCHAR * const path) } return new TskCaseDb(db); +#else + return NULL; +#endif // HAVE_POSTGRESQL && TSK_WIN32 } /** -* Opens a case from an existing database. +* Opens a single-user case from an existing database. * * @param path Full path to open database from. +* @returns Pointer to a new TskCaseDb object, NULL on error */ TskCaseDb * TskCaseDb::openDb(const TSK_TCHAR * path) { + TskDb *db = new TskDbSqlite(path, true); + + // Confirm that database already exsists + if (!db->dbExists()) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_AUTO_DB); + tsk_error_set_errstr("Database %" PRIttocTSK + " does not exist. Must be created first.", path); + delete(db); + return NULL; + } + // Open the database. + if (db->open(false)) { + delete(db); + return NULL; + } + + return new TskCaseDb(db); +} + +/** +* Opens a multi-user case from an existing database. +* +* @param CaseDbConnectionInfo object containing datbase connection info. +* @returns Pointer to a new TskCaseDb object, NULL on error +*/ +TskCaseDb * +TskCaseDb::openDb(const TSK_TCHAR * path, CaseDbConnectionInfo * info) +{ #if defined(HAVE_POSTGRESQL) && defined(TSK_WIN32) - // ELTODO: check here which database to initialize - //TskDb *db = new TskDbSqlite(path, true); TskDb *db = new TskDbPostgreSQL(path, true); -#else - TskDb *db = new TskDbSqlite(path, true); -#endif // HAVE_POSTGRESQL && TSK_WIN32 + + // Store connection info for the multi-user database + if (db->setConnectionInfo(info) != TSK_OK) { + delete(db); + return NULL; + } // Confirm that database already exsists if (!db->dbExists()) { @@ -107,6 +171,7 @@ TskCaseDb::openDb(const TSK_TCHAR * path) tsk_error_set_errno(TSK_ERR_AUTO_DB); tsk_error_set_errstr("Database %" PRIttocTSK " does not exist. Must be created first.", path); + delete(db); return NULL; } @@ -117,6 +182,9 @@ TskCaseDb::openDb(const TSK_TCHAR * path) } return new TskCaseDb(db); +#else + return NULL; +#endif // HAVE_POSTGRESQL && TSK_WIN32 } /** diff --git a/tsk/auto/db_postgresql.cpp b/tsk/auto/db_postgresql.cpp index 317d7bd99d365961b37eea12a18a97dca9712e00..3488c807cb69b8eaa29c3c3424e36363a4345c3d 100755 --- a/tsk/auto/db_postgresql.cpp +++ b/tsk/auto/db_postgresql.cpp @@ -33,9 +33,8 @@ TskDbPostgreSQL::TskDbPostgreSQL(const TSK_TCHAR * a_dbFilePath, bool a_blkMapFl : TskDb(a_dbFilePath, a_blkMapFlag) { conn = NULL; - wcsncpy(m_dBName, a_dbFilePath, 255); + wcsncpy(m_dBName, a_dbFilePath, MAX_CONN_INFO_FIELD_LENGTH - 1); m_blkMapFlag = a_blkMapFlag; - setLogInInfo(); } TskDbPostgreSQL::~TskDbPostgreSQL() @@ -46,46 +45,88 @@ TskDbPostgreSQL::~TskDbPostgreSQL() } } -TSK_RETVAL_ENUM TskDbPostgreSQL::setLogInInfo(){ +TSK_RETVAL_ENUM TskDbPostgreSQL::setConnectionInfo(CaseDbConnectionInfo * info){ - strncpy(userName, "postgres", sizeof(userName)); - strncpy(password, "simple41", sizeof(password)); - strncpy(hostIpAddr, "127.0.0.1", sizeof(hostIpAddr)); - strncpy(hostPort, "5432", sizeof(hostPort)); + if (info->getDbType() != CaseDbConnectionInfo::POSTGRESQL) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_AUTO_DB); + tsk_error_set_errstr("TskDbPostgreSQL::setConnectionInfo: Connection info is for wrong database type %d", info->getDbType()); + return TSK_ERR; + } + + // verify input string sizes + if (verifyConnectionInfoStringLengths(info->getUserName().size(), info->getPassword().size(), info->getHost().size(), info->getPort().size()) != TSK_OK) { + return TSK_ERR; + } + + strncpy(userName, info->getUserName().c_str(), sizeof(userName)); + strncpy(password, info->getPassword().c_str(), sizeof(password)); + strncpy(hostNameOrIpAddr, info->getHost().c_str(), sizeof(hostNameOrIpAddr)); + strncpy(hostPort, info->getPort().c_str(), sizeof(hostPort)); + +// strncpy(userName, "postgres", sizeof(userName)); +// strncpy(password, "simple41", sizeof(password)); +// strncpy(hostNameOrIpAddr, "127.0.0.1", sizeof(hostNameOrIpAddr)); +// strncpy(hostPort, "5432", sizeof(hostPort)); return TSK_OK; } -PGconn* TskDbPostgreSQL::connectToDatabase(TSK_TCHAR *dbName) { +TSK_RETVAL_ENUM TskDbPostgreSQL::verifyConnectionInfoStringLengths(size_t userNameStrLen, size_t pwdStrLen, size_t hostNameStrLen, size_t portStrLen) { - // Make a connection to postgres database server - char connectionString[1024]; + if (userNameStrLen >= MAX_CONN_INFO_FIELD_LENGTH - 1) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_AUTO_DB); + tsk_error_set_errstr("TskDbPostgreSQL::connectToDatabase: User name is too long. Length = %d, Max length = %d", userNameStrLen, MAX_CONN_INFO_FIELD_LENGTH - 1); + return TSK_ERR; + } - // verify user name and password string sizes - if (strlen(userName) >= MAX_USER_NAME_PASSWORD_LENGTH) { + if (pwdStrLen >= MAX_CONN_INFO_FIELD_LENGTH - 1) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_AUTO_DB); - tsk_error_set_errstr("User name is too long. Length = %d, Max length = %d", strlen(userName), MAX_USER_NAME_PASSWORD_LENGTH); - return NULL; + tsk_error_set_errstr("TskDbPostgreSQL::connectToDatabase: Password is too long. Length = %d, Max length = %d", pwdStrLen, MAX_CONN_INFO_FIELD_LENGTH - 1); + return TSK_ERR; } - if (strlen(password) >= MAX_USER_NAME_PASSWORD_LENGTH) { + if (hostNameStrLen >= MAX_CONN_INFO_FIELD_LENGTH - 1) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_AUTO_DB); - tsk_error_set_errstr("Password is too long. Length = %d, Max length = %d", strlen(password), MAX_USER_NAME_PASSWORD_LENGTH); + tsk_error_set_errstr("TskDbPostgreSQL::connectToDatabase: Host name is too long. Length = %d, Max length = %d", hostNameStrLen, MAX_CONN_INFO_FIELD_LENGTH - 1); + return TSK_ERR; + } + + if (portStrLen > MAX_CONN_PORT_FIELD_LENGTH) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_AUTO_DB); + tsk_error_set_errstr("TskDbPostgreSQL::connectToDatabase: Host port string is too long. Length = %d, Max length = %d", portStrLen, MAX_CONN_PORT_FIELD_LENGTH); + return TSK_ERR; + } + + return TSK_OK; +} + +PGconn* TskDbPostgreSQL::connectToDatabase(TSK_TCHAR *dbName) { + + // Make a connection to postgres database server + char connectionString[1024]; + + // verify input string sizes + if (verifyConnectionInfoStringLengths(strlen(userName), strlen(password), strlen(hostNameOrIpAddr), strlen(hostPort)) != TSK_OK) { return NULL; } // escape strings for use within an SQL command. Usually use PQescapeLiteral but it requires connection to be already established. - char userName_sql[256]; - char password_sql[256]; + char userName_sql[MAX_CONN_INFO_FIELD_LENGTH]; + char password_sql[MAX_CONN_INFO_FIELD_LENGTH]; + char hostName_sql[MAX_CONN_INFO_FIELD_LENGTH]; PQescapeString(&userName_sql[0], userName, strlen(userName)); PQescapeString(&password_sql[0], password, strlen(password)); + PQescapeString(&hostName_sql[0], hostNameOrIpAddr, strlen(hostNameOrIpAddr)); - snprintf(connectionString, 1024, "user=%s password=%s dbname=%S hostaddr=%s port=%s", userName_sql, password_sql, dbName, hostIpAddr, hostPort); + snprintf(connectionString, 1024, "user=%s password=%s dbname=%S hostaddr=%s port=%s", userName_sql, password_sql, dbName, hostName_sql, hostPort); PGconn *dbConn = PQconnectdb(connectionString); // Check to see that the backend connection was successfully made - if (verifyResultCode(PQstatus(dbConn), CONNECTION_OK, "Connection to PostgreSQL database failed, result code %d")) + if (verifyResultCode(PQstatus(dbConn), CONNECTION_OK, "TskDbPostgreSQL::connectToDatabase: Connection to PostgreSQL database failed, result code %d")) { PQfinish(dbConn); return NULL; @@ -126,7 +167,7 @@ TSK_RETVAL_ENUM TskDbPostgreSQL::createDatabase(){ tsk_error_reset(); tsk_error_set_errno(TSK_ERR_AUTO_DB); char * str = PQerrorMessage(serverConn); - tsk_error_set_errstr("Database creation failed, %s", str); + tsk_error_set_errstr("TskDbPostgreSQL::createDatabase: Database creation failed, %s", str); result = TSK_ERR; } @@ -148,7 +189,7 @@ int TskDbPostgreSQL::open(bool createDbFlag) if (createDbFlag) { // create new database first - if (verifyResultCode(createDatabase(), TSK_OK, "TskDbPostgreSQL::open - Unable to create database, result code %d")){ + if (verifyResultCode(createDatabase(), TSK_OK, "TskDbPostgreSQL::open: Unable to create database, result code %d")){ return -1; } } @@ -158,7 +199,7 @@ int TskDbPostgreSQL::open(bool createDbFlag) if (!conn){ tsk_error_reset(); tsk_error_set_errno(TSK_ERR_AUTO_DB); - tsk_error_set_errstr("TskDbPostgreSQL::open - Couldn't connect to databse %S", m_dBName); + tsk_error_set_errstr("TskDbPostgreSQL::open: Couldn't connect to databse %S", m_dBName); return -1; } @@ -167,7 +208,7 @@ int TskDbPostgreSQL::open(bool createDbFlag) if (initialize()) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_AUTO_DB); - tsk_error_set_errstr("TskDbPostgreSQL::open - Couldn't initialize databse %S", m_dBName); + tsk_error_set_errstr("TskDbPostgreSQL::open: Couldn't initialize databse %S", m_dBName); close(); // close connection to database return -1; } @@ -210,7 +251,7 @@ bool TskDbPostgreSQL::dbExists() { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_AUTO_DB); char * str = PQerrorMessage(conn); - tsk_error_set_errstr("Existing database lookup failed, %s", str); + tsk_error_set_errstr("TskDbPostgreSQL::dbExists: Existing database lookup failed, %s", str); numDb = 0; } else { // number of existing databases that matched name (if search is case sensitive then max is 1) diff --git a/tsk/auto/tsk_case_db.h b/tsk/auto/tsk_case_db.h index 9315ad422c1857a135a1dcb27f8c653e16411a25..ba502cdd44e360694df58f41c432d69a8787b051 100644 --- a/tsk/auto/tsk_case_db.h +++ b/tsk/auto/tsk_case_db.h @@ -172,7 +172,9 @@ class TskCaseDb { ~TskCaseDb(); static TskCaseDb *newDb(const TSK_TCHAR * path); + static TskCaseDb *newDb(const TSK_TCHAR * const path, CaseDbConnectionInfo * info); static TskCaseDb *openDb(const TSK_TCHAR * path); + static TskCaseDb *openDb(const TSK_TCHAR * path, CaseDbConnectionInfo * info); void clearLookupDatabases(); uint8_t setNSRLHashDb(TSK_TCHAR * const indexFile); diff --git a/tsk/auto/tsk_db.cpp b/tsk/auto/tsk_db.cpp index de6279fd8b92cfccb22c2e7ae1339e08af9087dd..8be4bc191a8915709b6e70a5761b9f762ad2f4d6 100755 --- a/tsk/auto/tsk_db.cpp +++ b/tsk/auto/tsk_db.cpp @@ -32,3 +32,11 @@ TskDb::TskDb(const TSK_TCHAR * a_dbFilePath, bool a_blkMapFlag) } #endif +/** +* Store database connection info. NO-OP for single-user database. Multi-user database class +* needs to derive and implement this method. +*/ +TSK_RETVAL_ENUM TskDb::setConnectionInfo(CaseDbConnectionInfo * info){ + return TSK_OK; +} + diff --git a/tsk/auto/tsk_db.h b/tsk/auto/tsk_db.h index 54923e87564027b13e06fcb445b7d61b21d0861d..d2b5c088dbbb0fd6e108a04662c8e420d4097129 100755 --- a/tsk/auto/tsk_db.h +++ b/tsk/auto/tsk_db.h @@ -22,6 +22,7 @@ #include <ostream> #include "tsk_auto_i.h" +#include "db_connection_info.h" using std::ostream; using std::vector; @@ -158,6 +159,7 @@ class TskDb { virtual ~TskDb() {}; virtual int open(bool) = 0; virtual int close() = 0; + virtual TSK_RETVAL_ENUM setConnectionInfo(CaseDbConnectionInfo * info); virtual int addImageInfo(int type, int size, int64_t & objId, const string & timezone) = 0; virtual int addImageInfo(int type, int size, int64_t & objId, const string & timezone, TSK_OFF_T, const string &md5) = 0; virtual int addImageName(int64_t objId, char const *imgName, int sequence) = 0; diff --git a/tsk/auto/tsk_db_postgresql.h b/tsk/auto/tsk_db_postgresql.h index 1ff226cf8f5d702acc2c12e8ffdb24886bc23072..dfb6379422939f3c5f9ff643bfde3d57cb4aea66 100755 --- a/tsk/auto/tsk_db_postgresql.h +++ b/tsk/auto/tsk_db_postgresql.h @@ -30,8 +30,8 @@ #include <map> using std::map; -#define MAX_USER_NAME_PASSWORD_LENGTH 255 - +#define MAX_CONN_INFO_FIELD_LENGTH 256 +#define MAX_CONN_PORT_FIELD_LENGTH 5 // max number of ports on windows is 65535 /** \internal * C++ class that wraps PostgreSQL database internals. @@ -43,7 +43,7 @@ class TskDbPostgreSQL : public TskDb { int open(bool); int close(); - TSK_RETVAL_ENUM setLogInInfo(); + TSK_RETVAL_ENUM setConnectionInfo(CaseDbConnectionInfo * info); int addImageInfo(int type, int size, int64_t & objId, const string & timezone); int addImageInfo(int type, int size, int64_t & objId, const string & timezone, TSK_OFF_T, const string &md5); @@ -92,11 +92,12 @@ class TskDbPostgreSQL : public TskDb { PGconn *conn; bool m_blkMapFlag; - TSK_TCHAR m_dBName[256]; - char userName[128]; - char password[128]; - char hostIpAddr[64]; + TSK_TCHAR m_dBName[MAX_CONN_INFO_FIELD_LENGTH]; + char userName[MAX_CONN_INFO_FIELD_LENGTH]; + char password[MAX_CONN_INFO_FIELD_LENGTH]; + char hostNameOrIpAddr[MAX_CONN_INFO_FIELD_LENGTH]; char hostPort[16]; + TSK_RETVAL_ENUM verifyConnectionInfoStringLengths(size_t userNameStrLen, size_t pwdStrLen, size_t hostNameStrLen, size_t portStrLen); PGconn* connectToDatabase(TSK_TCHAR *dbName); TSK_RETVAL_ENUM createDatabase(); @@ -125,7 +126,7 @@ class TskDbPostgreSQL : public TskDb { int64_t & objId); // ELTODO: delete this: - void test(); + //void test(); }; #endif // TSK_WIN32 diff --git a/win32/libtsk/libtsk.vcxproj b/win32/libtsk/libtsk.vcxproj index 7da655c71abdad41664ab5d21abefbc7905c6b3d..e32c0b0ea0b874baa76b463b5af23165d56708e6 100755 --- a/win32/libtsk/libtsk.vcxproj +++ b/win32/libtsk/libtsk.vcxproj @@ -461,6 +461,7 @@ copy "$(POSTGRESQL_HOME_64)\bin\libintl-8.dll" "$(OutDir)"</Command> <ClCompile Include="..\..\tsk\img\raw.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include="..\..\tsk\auto\db_connection_info.h" /> <ClInclude Include="..\..\tsk\auto\tsk_db.h" /> <ClInclude Include="..\..\tsk\auto\tsk_db_postgresql.h" /> <ClInclude Include="..\..\tsk\fs\tsk_exfatfs.h" /> diff --git a/win32/libtsk/libtsk.vcxproj.filters b/win32/libtsk/libtsk.vcxproj.filters index 5cb27b5d31e6fc336e095657e6ef8c0d0090270d..db1c0e2bff081cda1c664f8f4e8abcb4705b9af2 100755 --- a/win32/libtsk/libtsk.vcxproj.filters +++ b/win32/libtsk/libtsk.vcxproj.filters @@ -419,5 +419,8 @@ <ClInclude Include="..\..\tsk\auto\tsk_db_postgresql.h"> <Filter>auto</Filter> </ClInclude> + <ClInclude Include="..\..\tsk\auto\db_connection_info.h"> + <Filter>auto</Filter> + </ClInclude> </ItemGroup> </Project> \ No newline at end of file