From: Russ Combs (rucombs) Date: Tue, 22 Nov 2016 22:54:41 +0000 (-0500) Subject: Merge pull request #720 in SNORT/snort3 from cut_down to master X-Git-Tag: 3.0.0-233~175 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=72ad3d61a79b4b8f41dc5d052eb689011eea75f5;p=thirdparty%2Fsnort3.git Merge pull request #720 in SNORT/snort3 from cut_down to master Squashed commit of the following: commit f3bb19f43167cdda20698247fa21ba25f77b6dc5 Author: Russ Combs Date: Tue Nov 22 14:29:52 2016 -0500 refactor dce_smb.cc commit d61f30962fd70cfbb2ec66c0cbe017760f5a42a9 Author: Russ Combs Date: Tue Nov 22 12:54:31 2016 -0500 refactor smb message definitions commit 806617d70753418e348724443d0b655bc63d91b8 Author: Russ Combs Date: Tue Nov 22 11:50:24 2016 -0500 split hi_client.cc init methods into separate file --- diff --git a/extra/src/inspectors/http_server/CMakeLists.txt b/extra/src/inspectors/http_server/CMakeLists.txt index e66e2b26e..ffa5a7731 100644 --- a/extra/src/inspectors/http_server/CMakeLists.txt +++ b/extra/src/inspectors/http_server/CMakeLists.txt @@ -6,6 +6,7 @@ set (FILE_LIST hi_ad.cc hi_ad.h hi_client.cc + hi_client_init.cc hi_client.h hi_client_norm.cc hi_client_norm.h diff --git a/extra/src/inspectors/http_server/Makefile.am b/extra/src/inspectors/http_server/Makefile.am index c4fbb75b9..946a9d127 100644 --- a/extra/src/inspectors/http_server/Makefile.am +++ b/extra/src/inspectors/http_server/Makefile.am @@ -3,7 +3,7 @@ file_list = \ http_inspect.cc \ hi_main.cc hi_main.h \ hi_ad.cc hi_ad.h \ -hi_client.cc hi_client.h \ +hi_client.cc hi_client_init.cc hi_client.h \ hi_client_norm.cc hi_client_norm.h \ hi_cmd_lookup.cc hi_cmd_lookup.h \ hi_events.cc hi_events.h \ diff --git a/extra/src/inspectors/http_server/hi_client.cc b/extra/src/inspectors/http_server/hi_client.cc index b0eee62d8..004f54229 100644 --- a/extra/src/inspectors/http_server/hi_client.cc +++ b/extra/src/inspectors/http_server/hi_client.cc @@ -96,17 +96,8 @@ const u_char* proxy_end = NULL; NULL };*/ -/** This makes passing function arguments much more readable and easier -** to follow. -*/ -typedef int (* LOOKUP_FCN)(HI_SESSION*, const u_char*, const u_char*, const u_char**, - URI_PTR*); - -/* -** The lookup table contains functions for different HTTP delimiters -** (like whitespace and the HTTP delimiter \r and \n). -*/ LOOKUP_FCN lookup_table[256]; + /* ** NAME ** CheckChunkEncoding:: @@ -512,265 +503,6 @@ static inline const u_char* FindPipelineReq(HI_SESSION* session, return NULL; } -/* -** NAME -** NextNonWhiteSpace:: -*/ -/** -** Update the URI_PTR fields spaces, find the next non-white space char, -** and validate the HTTP version identifier after the spaces. -** -** This is the main part of the URI algorithm. This verifies that there -** isn't too many spaces in the data to be a URI, it checks that after the -** second space that there is an HTTP identifier or otherwise it's no good. -** Also, if we've found an identifier after the first whitespace, and -** find another whitespace, there is no URI. -** -** The uri and uri_end pointers are updated in this function depending -** on what space we are at, and if the space was followed by the HTTP -** identifier. (NOTE: the HTTP delimiter is no longer "HTTP/", but -** can also be "\r\n", "\n", or "\r". This is the defunct method, and -** we deal with it in the IsHttpVersion and delimiter functions.) -** -** @param ServerConf pointer to the server configuration -** @param start pointer to the start of payload -** @param end pointer to the end of the payload -** @param ptr pointer to the pointer of the current index -** @param uri_ptr pointer to the URI_PTR construct -** -** @return integer -** -** @retval HI_SUCCESS found the next non-whitespace -** @retval HI_OUT_OF_BOUNDS whitespace to the end of the buffer -** @retval URI_END delimiter found, end of URI -** @retval NO_URI -*/ -static int NextNonWhiteSpace(HI_SESSION* session, const u_char* start, - const u_char* end, const u_char** ptr, URI_PTR* uri_ptr) -{ - HTTPINSPECT_CONF* ServerConf = session->server_conf; - const u_char** start_sp; - const u_char** end_sp; - - /* - ** Horizontal tab is only accepted by apache web servers, not IIS. - ** Some IIS exploits contain a tab (0x09) in the URI, so we don't want - ** to treat it as a URI delimiter and cut off the URI. - */ - if ( **ptr == '\t' && !ServerConf->tab_uri_delimiter ) - { - (*ptr)++; - return HI_SUCCESS; - } - - /* - ** Reset the identifier, because we've just seen another space. We - ** should only see the identifier immediately after a space followed - ** by a delimiter. - */ - if (uri_ptr->ident) - { - if (ServerConf->non_strict) - { - /* - ** In non-strict mode it is ok to see spaces after the - ** "identifier", so we just increment the ptr and return. - */ - (*ptr)++; - return HI_SUCCESS; - } - else - { - /* - ** This means that we've already seen a space and a version - ** identifier, and now that we've seen another space, we know - ** that this can't be the URI so we just bail out with no - ** URI. - */ - return NO_URI; - } - } - - uri_ptr->ident = NULL; - - /* - ** We only check for one here, because both should be set if one - ** is. - */ - if (uri_ptr->first_sp_end) - { - /* - ** If the second space has been set, then this means that we have - ** seen a third space, which we shouldn't see in the URI so we - ** are now done and know there is no URI in this packet. - */ - if (uri_ptr->second_sp_end) - { - return NO_URI; - } - - /* - ** Treat whitespace differently at the end of the URI than we did - ** at the beginning. Ignore and return if special characters are - ** not defined as whitespace after the URI. - */ - if (ServerConf->whitespace[**ptr] - && !(ServerConf->whitespace[**ptr] & HI_UI_CONFIG_WS_AFTER_URI)) - { - (*ptr)++; - return HI_SUCCESS; - } - - /* - ** Since we've seen the second space, we need to update the uri ptr - ** to the end of the first space, since the URI cannot be before the - ** first space. - */ - uri_ptr->uri = uri_ptr->first_sp_end; - - uri_ptr->second_sp_start = *ptr; - uri_ptr->second_sp_end = NULL; - - start_sp = &uri_ptr->second_sp_start; - end_sp = &uri_ptr->second_sp_end; - } - else - { - /* - ** This means that there is whitespace at the beginning of the line - ** and we unset the URI so we can set it later if need be. - ** - ** This is mainly so we handle data that is all spaces correctly. - ** - ** In the normal case where we've seen text and then the first space, - ** we leave the uri ptr pointing at the beginning of the data, and - ** set the uri end after we've determined where to put it. - */ - if (start == *ptr) - uri_ptr->uri = NULL; - - uri_ptr->first_sp_start = *ptr; - uri_ptr->first_sp_end = NULL; - - start_sp = &uri_ptr->first_sp_start; - end_sp = &uri_ptr->first_sp_end; - } - - while (hi_util_in_bounds(start, end, *ptr)) - { - /* - ** Check for whitespace - */ - if (**ptr == ' ') - { - (*ptr)++; - continue; - } - else if (ServerConf->whitespace[**ptr]) - { - if (ServerConf->apache_whitespace.on) - { - hi_set_event(GID_HTTP_CLIENT, HI_CLIENT_APACHE_WS); - } - (*ptr)++; - continue; - } - else - { - /* - ** This sets the sp_end for whatever space delimiter we are on, - ** whether that is the first space or the second space. - */ - *end_sp = *ptr; - - if (!IsHttpVersion(ptr, end)) - { - /* - ** This is the default method and what we've been doing - ** since the start of development. - */ - if (uri_ptr->second_sp_start) - { - /* - ** There is no HTTP version indentifier at the beginning - ** of the second space, and this means that there is no - ** URI. - */ - if (ServerConf->non_strict) - { - /* - ** In non-strict mode, we must assume the URI is - ** between the first and second space, so now - ** that we've seen the second space that's the - ** identifier. - */ - uri_ptr->ident = *end_sp; - uri_ptr->uri_end = *start_sp; - - return HI_SUCCESS; - } - else - { - /* - ** Since we are in strict mode here, it means that - ** we haven't seen a valid identifier, so there was - ** no URI. - */ - - return NO_URI; - } - } - - /* - ** RESET NECESSARY URI_PTRs HERE. This is the place where - ** the uri is updated. It can only happen once, so do it - ** right here. - ** - ** When we get here it means that we have found the end of - ** the FIRST whitespace, and that there was no delimiter, - ** so we reset the uri pointers and other related - ** pointers. - */ - uri_ptr->uri = *end_sp; - uri_ptr->uri_end = end; - uri_ptr->norm = NULL; - uri_ptr->last_dir = NULL; - uri_ptr->param = NULL; - uri_ptr->proxy = NULL; - } - else - { - /* - ** Means we found the HTTP version identifier and we reset - ** the uri_end pointer to point to the beginning of the - ** whitespace detected. - ** - ** This works for both "uri_is_here HTTP/1.0" and - ** "METHOD uri_is_here HTTP/1.0", so it works when the - ** identifier is after either the first or the second - ** whitespace. - */ - uri_ptr->ident = *end_sp; - uri_ptr->uri_end = *start_sp; - } - - /* - ** We found a non-whitespace char - */ - return HI_SUCCESS; - } - } - - /* - ** This is the case where we've seen text and found a whitespace until - ** the end of the buffer. In that case, we set the uri_end to the - ** beginning of the whitespace. - */ - uri_ptr->uri_end = *start_sp; - - return HI_OUT_OF_BOUNDS; -} - /* ** NAME ** IsHttpVersion:: @@ -858,495 +590,6 @@ int IsHttpVersion(const u_char** ptr, const u_char* end) return 1; } -/* -** NAME -** find_rfc_delimiter:: -*/ -/** -** Check for standard RFC HTTP delimiter. -** -** If we find the delimiter, we return that URI_PTR structures should -** be checked, which bails us out of the loop. If there isn't a RFC -** delimiter, then we bail with a no URI. Otherwise, we check for out -** of bounds. -** -** @param ServerConf pointer to the server configuration -** @param start pointer to the start of payload -** @param end pointer to the end of the payload -** @param ptr pointer to the pointer of the current index -** @param uri_ptr pointer to the URI_PTR construct -** -** @return integer -** -** @retval HI_OUT_OF_BOUNDS -** @retval URI_END end of the URI is found, check URI_PTR. -** @retval NO_URI malformed delimiter, no URI. -*/ -static int find_rfc_delimiter(HI_SESSION* session, const u_char* start, - const u_char* end, const u_char** ptr, URI_PTR* uri_ptr) -{ - if (*ptr == start || !uri_ptr->uri) - return NO_URI; - - /* - ** This is important to catch the defunct way of getting URIs without - ** specifying "HTTP/major.minor\r\n\r\n". This is a quick way for - ** us to tell if we are in that state. - ** - ** We check for a legal identifier to deal with the case of - ** "some_of_the_uri_in segmented packet \r\n" in the defunct case. - ** Since we find a "valid" (still defunct) delimiter, we account for - ** it here, so that we don't set the uri_end to the delimiter. - ** - ** NOTE: - ** We now assume that the defunct method is in effect and if there is - ** a valid identifier, then we don't update the uri_end because it's - ** already been set when the identifier was validated. - */ - - (*ptr)++; - if (!hi_util_in_bounds(start, end, *ptr)) - { - return HI_OUT_OF_BOUNDS; - } - - if (**ptr == '\n') - { - uri_ptr->delimiter = (*ptr)-1; - - if (!uri_ptr->ident) - uri_ptr->uri_end = uri_ptr->delimiter; - - return URI_END; - } - - return NextNonWhiteSpace(session, start, end, ptr, uri_ptr); -} - -/* -** NAME -** find_non_rfc_delimiter:: -*/ -/** -** Check for non standard delimiter '\n'. -** -** It now appears that apache and iis both take this non-standard -** delimiter. So, we most likely will always look for it, but maybe -** give off a special alert or something. -** -** @param ServerConf pointer to the server configuration -** @param start pointer to the start of payload -** @param end pointer to the end of the payload -** @param ptr pointer to the pointer of the current index -** @param uri_ptr pointer to the URI_PTR construct -** -** @return integer -** -** @retval URI_END delimiter found, end of URI -** @retval NO_URI -*/ -static int find_non_rfc_delimiter( - HI_SESSION* session, const u_char* start, - const u_char*, const u_char** ptr, URI_PTR* uri_ptr) -{ - HTTPINSPECT_CONF* ServerConf = session->server_conf; - - if (*ptr == start || !uri_ptr->uri) - return NO_URI; - - /* - ** This is important to catch the defunct way of getting URIs without - ** specifying "HTTP/major.minor\r\n\r\n". This is a quick way for - ** us to tell if we are in that state. - ** - ** We check for a legal identifier to deal with the case of - ** "some_of_the_uri_in segmented packet \r\n" in the defunct case. - ** Since we find a "valid" (still defunct) delimiter, we account for - ** it here, so that we don't set the uri_end to the delimiter. - ** - ** NOTE: - ** We now assume that the defunct method is in effect and if there is - ** a valid identifier, then we don't update the uri_end because it's - ** already been set when the identifier was validated. - */ - if (ServerConf->iis_delimiter.on) - { - hi_set_event(GID_HTTP_CLIENT, HI_CLIENT_IIS_DELIMITER); - - uri_ptr->delimiter = *ptr; - - if (!uri_ptr->ident) - uri_ptr->uri_end = uri_ptr->delimiter; - - return URI_END; - } - - /* - ** This allows us to do something if the delimiter check is not turned - ** on. Most likely this is worthy of an alert, IF it's not normal to - ** see these requests. - ** - ** But for now, we always return true. - */ - uri_ptr->delimiter = *ptr; - - if (!uri_ptr->ident) - uri_ptr->uri_end = uri_ptr->delimiter; - - return URI_END; -} - -/* -** NAME -** SetPercentNorm:: -*/ -/** -** Check for percent normalization in the URI buffer. -** -** We don't do much here besides check the configuration, set the pointer, -** and continue processing. -** -** @param ServerConf pointer to the server configuration -** @param start pointer to the start of payload -** @param end pointer to the end of the payload -** @param ptr pointer to the pointer of the current index -** @param uri_ptr pointer to the URI_PTR construct -** -** @return integer -** -** @retval HI_SUCCESS function successful -*/ -static int SetPercentNorm( - HI_SESSION* session, const u_char*, - const u_char*, const u_char** ptr, URI_PTR* uri_ptr) -{ - HTTPINSPECT_CONF* ServerConf = session->server_conf; - - if (!uri_ptr->norm && !uri_ptr->ident) - { - if (ServerConf->ascii.on) - { - uri_ptr->norm = *ptr; - } - } - - (*ptr)++; - - return HI_SUCCESS; -} - -/* -** NAME -** CheckLongDir:: -*/ -/** -** We check the directory length against the global config. -** -** @param session pointer to the current session -** @param uri_ptr pointer to the URI state -** @param ptr pointer to the current index in buffer -** -** @return integer -** -** @retval HI_SUCCESS -*/ -static inline int CheckLongDir(HI_SESSION* session, URI_PTR* uri_ptr, - const u_char* ptr) -{ - int iDirLen; - - /* - ** Check for oversize directory - */ - if (session->server_conf->long_dir && - uri_ptr->last_dir && !uri_ptr->param) - { - iDirLen = ptr - uri_ptr->last_dir; - - if ( iDirLen > session->server_conf->long_dir ) - { - hi_set_event(GID_HTTP_CLIENT, HI_CLIENT_OVERSIZE_DIR); - } - } - - return HI_SUCCESS; -} - -/* -** NAME -** SetSlashNorm:: -*/ -/** -** Check for any directory traversal or multi-slash normalization. -** -** @param ServerConf pointer to the server configuration -** @param start pointer to the start of payload -** @param end pointer to the end of the payload -** @param ptr pointer to the pointer of the current index -** @param uri_ptr pointer to the URI_PTR construct -** -** @return integer -** -** @retval HI_SUCCESS function successful -** @retval HI_OUT_OF_BOUNDS reached the end of the buffer -*/ -static int SetSlashNorm(HI_SESSION* session, const u_char* start, - const u_char* end, const u_char** ptr, URI_PTR* uri_ptr) -{ - HTTPINSPECT_CONF* ServerConf = session->server_conf; - - CheckLongDir(session, uri_ptr, *ptr); - if ( proxy_start) - { - // This is the first dir after http:// - if (!uri_ptr->ident && !uri_ptr->last_dir) - proxy_end = *ptr; - } - uri_ptr->last_dir = *ptr; - - if (!uri_ptr->norm && !uri_ptr->ident) - { - uri_ptr->norm = *ptr; - - (*ptr)++; - - if (!hi_util_in_bounds(start,end, *ptr)) - { - /* - ** This is the case where there is a slash as the last char - ** and we don't want to normalize that since there really - ** is nothing to normalize. - */ - uri_ptr->norm = NULL; - return HI_OUT_OF_BOUNDS; - } - - /* - ** Check for directory traversals - */ - if (ServerConf->directory.on) - { - if (**ptr == '.') - { - (*ptr)++; - if (!hi_util_in_bounds(start, end, *ptr)) - { - uri_ptr->norm = NULL; - return HI_OUT_OF_BOUNDS; - } - - if (**ptr == '.' || **ptr == '/') - { - return HI_SUCCESS; - } - } - } - - /* - ** Check for multiple slash normalization - */ - if (ServerConf->multiple_slash.on) - { - if (**ptr == '/') - { - return HI_SUCCESS; - } - } - - uri_ptr->norm = NULL; - return HI_SUCCESS; - } - - (*ptr)++; - - return HI_SUCCESS; -} - -/* -** NAME -** SetBackSlashNorm:: -*/ -/** -** Check for backslashes and if we need to normalize. -** -** This really just checks the configuration option, and sets the norm -** variable if applicable. -** -** @param ServerConf pointer to the server configuration -** @param start pointer to the start of payload -** @param end pointer to the end of the payload -** @param ptr pointer to the pointer of the current index -** @param uri_ptr pointer to the URI_PTR construct -** -** @return integer -** -** @retval HI_SUCCESS function successful -*/ -static int SetBackSlashNorm( - HI_SESSION* session, const u_char*, - const u_char*, const u_char** ptr, URI_PTR* uri_ptr) -{ - HTTPINSPECT_CONF* ServerConf = session->server_conf; - - if (!uri_ptr->norm && !uri_ptr->ident) - { - if (ServerConf->iis_backslash.on) - { - uri_ptr->norm = *ptr; - } - } - - (*ptr)++; - - return HI_SUCCESS; -} - -/* - * ** NAME - * ** SetPlusNorm:: - * */ -/** - * ** Check for "+" and if we need to normalize. - * ** - * ** - * ** @param ServerConf pointer to the server configuration - * ** @param start pointer to the start of payload - * ** @param end pointer to the end of the payload - * ** @param ptr pointer to the pointer of the current index - * ** @param uri_ptr pointer to the URI_PTR construct - * ** - * ** @return integer - * ** - * ** @retval HI_SUCCESS function successful - * */ - -static int SetPlusNorm( - HI_SESSION*, const u_char*, - const u_char*, const u_char** ptr, URI_PTR* uri_ptr) -{ - if (!uri_ptr->norm && !uri_ptr->ident) - { - uri_ptr->norm = *ptr; - } - - (*ptr)++; - - return HI_SUCCESS; -} - -/* -** NAME -** SetBinaryNorm:: -*/ -/** -** Look for non-ASCII chars in the URI. -** -** We look for these chars in the URI and set the normalization variable -** if it's not already set. I think we really only need this for IIS -** servers, but we may want to know if it's in the URI too. -** -** @param ServerConf pointer to the server configuration -** @param start pointer to the start of payload -** @param end pointer to the end of the payload -** @param ptr pointer to the pointer of the current index -** @param uri_ptr pointer to the URI_PTR construct -** -** @return integer -** -** @retval HI_SUCCESS function successful -*/ -static int SetBinaryNorm( - HI_SESSION*, const u_char*, - const u_char*, const u_char** ptr, URI_PTR* uri_ptr) -{ - if (!uri_ptr->norm && !uri_ptr->ident) - { - uri_ptr->norm = *ptr; - } - - (*ptr)++; - - return HI_SUCCESS; -} - -/* -** NAME -** SetParamField:: -*/ -/** -** This function sets the parameter field as the first '?'. The big thing -** is that we set the param value, so we don't false positive long dir -** events when it's really just a long parameter field. -** -** @param ServerConf pointer to the server configuration -** @param start pointer to the start of payload -** @param end pointer to the end of the payload -** @param ptr pointer to the pointer of the current index -** @param uri_ptr pointer to the URI_PTR construct -** -** @return integer -** -** @retval HI_SUCCESS function successful -*/ -static int SetParamField( - HI_SESSION*, const u_char*, - const u_char*, const u_char** ptr, URI_PTR* uri_ptr) -{ - if (!uri_ptr->ident) - { - uri_ptr->param = *ptr; - } - - (*ptr)++; - - return HI_SUCCESS; -} - -/* -** NAME -** SetProxy:: -*/ -/** -** This function checks for an absolute URI in the URI. -** -** @param ServerConf pointer to the server configuration -** @param start pointer to the start of payload -** @param end pointer to the end of the payload -** @param ptr pointer to the pointer of the current index -** @param uri_ptr pointer to the URI_PTR construct -** -** @return integer -** -** @retval HI_SUCCESS function successful -*/ -static int SetProxy(HI_SESSION* session, const u_char* start, - const u_char* end, const u_char** ptr, URI_PTR* uri_ptr) -{ - HTTPINSPECT_CONF* ServerConf = session->server_conf; - - if (!uri_ptr->ident && !uri_ptr->last_dir) - { - if (hi_util_in_bounds(start, end, ((*ptr)+2))) - { - if (*((*ptr)+1) == '/' && *((*ptr)+2) == '/') - { - if (session->global_conf->proxy_alert && !ServerConf->allow_proxy) - uri_ptr->proxy = *ptr; - // If we found :// check to see if it is preceeded by http. If so, this is a proxy - proxy_start = (u_char*)SnortStrcasestr((const char*)uri_ptr->uri, (*ptr - - uri_ptr->uri), "http"); - proxy_end = end; - (*ptr) = (*ptr) + 3; - return HI_SUCCESS; - } - } - } - - (*ptr)++; - - return HI_SUCCESS; -} - /* ** NAME ** SetClientVars:: @@ -3048,110 +2291,3 @@ int hi_client_inspection(Packet* p, void* S, HttpSessionData* hsd, int stream_in return StatelessInspection(p, session, hsd, stream_ins); } -/* -** NAME -** hi_client_init:: -*/ -/** -** Initializes arrays and search algorithms depending on the type of -** inspection that we are doing. -** -** @retval HI_SUCCESS function successful. -*/ -int hi_client_init() -{ - int iCtr; - - memset(lookup_table, 0x00, sizeof(lookup_table)); - - // Set up the non-ASCII register for processing. - for (iCtr = 0x80; iCtr <= 0xff; iCtr++) - { - lookup_table[iCtr] = SetBinaryNorm; - } - lookup_table[0x00] = SetBinaryNorm; - - lookup_table[(uint8_t)' '] = NextNonWhiteSpace; - lookup_table[(uint8_t)'\r'] = find_rfc_delimiter; - lookup_table[(uint8_t)'\n'] = find_non_rfc_delimiter; - - // ASCII encoding - lookup_table[(uint8_t)'%'] = SetPercentNorm; - - // Looking for multiple slashes - lookup_table[(uint8_t)'/'] = SetSlashNorm; - - // Looking for backslashs - lookup_table[(uint8_t)'\\'] = SetBackSlashNorm; - - lookup_table[(uint8_t)'+'] = SetPlusNorm; - - // Look up parameter field, so we don't alert on long directory - // strings, when the next slash in the parameter field. - lookup_table[(uint8_t)'?'] = SetParamField; - - // Look for absolute URI and proxy communication. - lookup_table[(uint8_t)':'] = SetProxy; - - return HI_SUCCESS; -} - -/** -** This was just an initial testing program for these functions. -*/ -#ifdef TEST_ME - -int main(int argc, char** argv) -{ - HTTPINSPECT_GLOBAL_CONF GlobalConf; - HI_SESSION* session; - HI_SI_INPUT SiInput; - int iInspectMode = 0; - int iRet; - char data[] = "Hdslkfjaslfkj HTTP/00000.111111"; - - if ((iRet = hi_ui_config_init_global_conf(&GlobalConf))) - { - printf("** error during global init.\n"); - return iRet; - } - - if ((iRet = hi_ui_config_default(&GlobalConf))) - { - printf("** error config default.\n"); - return iRet; - } - - hi_ui_config_print_config(&GlobalConf); - - if ((iRet = hi_client_init())) - { - printf("** error client init\n"); - return iRet; - } - - SiInput.sip = inet_addr("1.1.1.1"); - SiInput.sip = inet_addr("1.1.1.2"); - SiInput.dport = 80; - SiInput.sport = 7880; - - if ((iRet = hi_si_session_inspection(&GlobalConf, &session, &SiInput, - &iInspectMode))) - { - printf("** error session inspection\n"); - return iRet; - } - - printf("** iInspectMode = %d\n", iInspectMode); - if ((iRet = hi_mi_mode_inspection(session, iInspectMode, data, - strlen(data)))) - { - printf("** error mode_inspection\n"); - return iRet; - } - - return 0; -} - -#endif - diff --git a/extra/src/inspectors/http_server/hi_client.h b/extra/src/inspectors/http_server/hi_client.h index 7b200b9cb..0e685b901 100644 --- a/extra/src/inspectors/http_server/hi_client.h +++ b/extra/src/inspectors/http_server/hi_client.h @@ -171,5 +171,23 @@ char** hi_client_get_field_names(); extern const u_char* proxy_start; extern const u_char* proxy_end; +struct HI_SESSION; + +int CheckLongDir(HI_SESSION* session, URI_PTR* uri_ptr, const u_char* ptr); + +/** This makes passing function arguments much more readable and easier +** to follow. +*/ +typedef int (* LOOKUP_FCN)( + HI_SESSION*, const u_char* start, const u_char* end, const u_char**, URI_PTR*); + +int NextNonWhiteSpace(HI_SESSION*, const u_char*, const u_char*, const u_char**, URI_PTR*); + +/* +** The lookup table contains functions for different HTTP delimiters +** (like whitespace and the HTTP delimiter \r and \n). +*/ +extern LOOKUP_FCN lookup_table[256]; + #endif diff --git a/extra/src/inspectors/http_server/hi_client_init.cc b/extra/src/inspectors/http_server/hi_client_init.cc new file mode 100644 index 000000000..53398ed68 --- /dev/null +++ b/extra/src/inspectors/http_server/hi_client_init.cc @@ -0,0 +1,832 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2014-2016 Cisco and/or its affiliates. All rights reserved. +// Copyright (C) 2003-2013 Sourcefire, Inc. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// hi_client_init.cc author Russ Combs +// +// this file was split from hi_client.cc; look there for the real +// culprits ;) + +#include "hi_client.h" +#include "hi_return_codes.h" +#include "hi_si.h" +#include "hi_util.h" + +//------------------------------------------------------------------------- +// private methods +//------------------------------------------------------------------------- + +/* +** NAME +** SetBinaryNorm:: +*/ +/** +** Look for non-ASCII chars in the URI. +** +** We look for these chars in the URI and set the normalization variable +** if it's not already set. I think we really only need this for IIS +** servers, but we may want to know if it's in the URI too. +** +** @param ServerConf pointer to the server configuration +** @param start pointer to the start of payload +** @param end pointer to the end of the payload +** @param ptr pointer to the pointer of the current index +** @param uri_ptr pointer to the URI_PTR construct +** +** @return integer +** +** @retval HI_SUCCESS function successful +*/ +static int SetBinaryNorm( + HI_SESSION*, const u_char*, + const u_char*, const u_char** ptr, URI_PTR* uri_ptr) +{ + if (!uri_ptr->norm && !uri_ptr->ident) + { + uri_ptr->norm = *ptr; + } + + (*ptr)++; + + return HI_SUCCESS; +} + +/* +** NAME +** find_rfc_delimiter:: +*/ +/** +** Check for standard RFC HTTP delimiter. +** +** If we find the delimiter, we return that URI_PTR structures should +** be checked, which bails us out of the loop. If there isn't a RFC +** delimiter, then we bail with a no URI. Otherwise, we check for out +** of bounds. +** +** @param ServerConf pointer to the server configuration +** @param start pointer to the start of payload +** @param end pointer to the end of the payload +** @param ptr pointer to the pointer of the current index +** @param uri_ptr pointer to the URI_PTR construct +** +** @return integer +** +** @retval HI_OUT_OF_BOUNDS +** @retval URI_END end of the URI is found, check URI_PTR. +** @retval NO_URI malformed delimiter, no URI. +*/ +static int find_rfc_delimiter(HI_SESSION* session, const u_char* start, + const u_char* end, const u_char** ptr, URI_PTR* uri_ptr) +{ + if (*ptr == start || !uri_ptr->uri) + return NO_URI; + + /* + ** This is important to catch the defunct way of getting URIs without + ** specifying "HTTP/major.minor\r\n\r\n". This is a quick way for + ** us to tell if we are in that state. + ** + ** We check for a legal identifier to deal with the case of + ** "some_of_the_uri_in segmented packet \r\n" in the defunct case. + ** Since we find a "valid" (still defunct) delimiter, we account for + ** it here, so that we don't set the uri_end to the delimiter. + ** + ** NOTE: + ** We now assume that the defunct method is in effect and if there is + ** a valid identifier, then we don't update the uri_end because it's + ** already been set when the identifier was validated. + */ + + (*ptr)++; + if (!hi_util_in_bounds(start, end, *ptr)) + { + return HI_OUT_OF_BOUNDS; + } + + if (**ptr == '\n') + { + uri_ptr->delimiter = (*ptr)-1; + + if (!uri_ptr->ident) + uri_ptr->uri_end = uri_ptr->delimiter; + + return URI_END; + } + + return NextNonWhiteSpace(session, start, end, ptr, uri_ptr); +} + +/* +** NAME +** find_non_rfc_delimiter:: +*/ +/** +** Check for non standard delimiter '\n'. +** +** It now appears that apache and iis both take this non-standard +** delimiter. So, we most likely will always look for it, but maybe +** give off a special alert or something. +** +** @param ServerConf pointer to the server configuration +** @param start pointer to the start of payload +** @param end pointer to the end of the payload +** @param ptr pointer to the pointer of the current index +** @param uri_ptr pointer to the URI_PTR construct +** +** @return integer +** +** @retval URI_END delimiter found, end of URI +** @retval NO_URI +*/ +static int find_non_rfc_delimiter( + HI_SESSION* session, const u_char* start, + const u_char*, const u_char** ptr, URI_PTR* uri_ptr) +{ + HTTPINSPECT_CONF* ServerConf = session->server_conf; + + if (*ptr == start || !uri_ptr->uri) + return NO_URI; + + /* + ** This is important to catch the defunct way of getting URIs without + ** specifying "HTTP/major.minor\r\n\r\n". This is a quick way for + ** us to tell if we are in that state. + ** + ** We check for a legal identifier to deal with the case of + ** "some_of_the_uri_in segmented packet \r\n" in the defunct case. + ** Since we find a "valid" (still defunct) delimiter, we account for + ** it here, so that we don't set the uri_end to the delimiter. + ** + ** NOTE: + ** We now assume that the defunct method is in effect and if there is + ** a valid identifier, then we don't update the uri_end because it's + ** already been set when the identifier was validated. + */ + if (ServerConf->iis_delimiter.on) + { + hi_set_event(GID_HTTP_CLIENT, HI_CLIENT_IIS_DELIMITER); + + uri_ptr->delimiter = *ptr; + + if (!uri_ptr->ident) + uri_ptr->uri_end = uri_ptr->delimiter; + + return URI_END; + } + + /* + ** This allows us to do something if the delimiter check is not turned + ** on. Most likely this is worthy of an alert, IF it's not normal to + ** see these requests. + ** + ** But for now, we always return true. + */ + uri_ptr->delimiter = *ptr; + + if (!uri_ptr->ident) + uri_ptr->uri_end = uri_ptr->delimiter; + + return URI_END; +} + +/* +** NAME +** SetPercentNorm:: +*/ +/** +** Check for percent normalization in the URI buffer. +** +** We don't do much here besides check the configuration, set the pointer, +** and continue processing. +** +** @param ServerConf pointer to the server configuration +** @param start pointer to the start of payload +** @param end pointer to the end of the payload +** @param ptr pointer to the pointer of the current index +** @param uri_ptr pointer to the URI_PTR construct +** +** @return integer +** +** @retval HI_SUCCESS function successful +*/ +static int SetPercentNorm( + HI_SESSION* session, const u_char*, + const u_char*, const u_char** ptr, URI_PTR* uri_ptr) +{ + HTTPINSPECT_CONF* ServerConf = session->server_conf; + + if (!uri_ptr->norm && !uri_ptr->ident) + { + if (ServerConf->ascii.on) + { + uri_ptr->norm = *ptr; + } + } + + (*ptr)++; + + return HI_SUCCESS; +} + +/* +** NAME +** SetSlashNorm:: +*/ +/** +** Check for any directory traversal or multi-slash normalization. +** +** @param ServerConf pointer to the server configuration +** @param start pointer to the start of payload +** @param end pointer to the end of the payload +** @param ptr pointer to the pointer of the current index +** @param uri_ptr pointer to the URI_PTR construct +** +** @return integer +** +** @retval HI_SUCCESS function successful +** @retval HI_OUT_OF_BOUNDS reached the end of the buffer +*/ +static int SetSlashNorm(HI_SESSION* session, const u_char* start, + const u_char* end, const u_char** ptr, URI_PTR* uri_ptr) +{ + HTTPINSPECT_CONF* ServerConf = session->server_conf; + + CheckLongDir(session, uri_ptr, *ptr); + if ( proxy_start) + { + // This is the first dir after http:// + if (!uri_ptr->ident && !uri_ptr->last_dir) + proxy_end = *ptr; + } + uri_ptr->last_dir = *ptr; + + if (!uri_ptr->norm && !uri_ptr->ident) + { + uri_ptr->norm = *ptr; + + (*ptr)++; + + if (!hi_util_in_bounds(start,end, *ptr)) + { + /* + ** This is the case where there is a slash as the last char + ** and we don't want to normalize that since there really + ** is nothing to normalize. + */ + uri_ptr->norm = NULL; + return HI_OUT_OF_BOUNDS; + } + + /* + ** Check for directory traversals + */ + if (ServerConf->directory.on) + { + if (**ptr == '.') + { + (*ptr)++; + if (!hi_util_in_bounds(start, end, *ptr)) + { + uri_ptr->norm = NULL; + return HI_OUT_OF_BOUNDS; + } + + if (**ptr == '.' || **ptr == '/') + { + return HI_SUCCESS; + } + } + } + + /* + ** Check for multiple slash normalization + */ + if (ServerConf->multiple_slash.on) + { + if (**ptr == '/') + { + return HI_SUCCESS; + } + } + + uri_ptr->norm = NULL; + return HI_SUCCESS; + } + + (*ptr)++; + + return HI_SUCCESS; +} + +/* +** NAME +** SetBackSlashNorm:: +*/ +/** +** Check for backslashes and if we need to normalize. +** +** This really just checks the configuration option, and sets the norm +** variable if applicable. +** +** @param ServerConf pointer to the server configuration +** @param start pointer to the start of payload +** @param end pointer to the end of the payload +** @param ptr pointer to the pointer of the current index +** @param uri_ptr pointer to the URI_PTR construct +** +** @return integer +** +** @retval HI_SUCCESS function successful +*/ +static int SetBackSlashNorm( + HI_SESSION* session, const u_char*, + const u_char*, const u_char** ptr, URI_PTR* uri_ptr) +{ + HTTPINSPECT_CONF* ServerConf = session->server_conf; + + if (!uri_ptr->norm && !uri_ptr->ident) + { + if (ServerConf->iis_backslash.on) + { + uri_ptr->norm = *ptr; + } + } + + (*ptr)++; + + return HI_SUCCESS; +} + +/* + * ** NAME + * ** SetPlusNorm:: + * */ +/** + * ** Check for "+" and if we need to normalize. + * ** + * ** + * ** @param ServerConf pointer to the server configuration + * ** @param start pointer to the start of payload + * ** @param end pointer to the end of the payload + * ** @param ptr pointer to the pointer of the current index + * ** @param uri_ptr pointer to the URI_PTR construct + * ** + * ** @return integer + * ** + * ** @retval HI_SUCCESS function successful + * */ + +static int SetPlusNorm( + HI_SESSION*, const u_char*, + const u_char*, const u_char** ptr, URI_PTR* uri_ptr) +{ + if (!uri_ptr->norm && !uri_ptr->ident) + { + uri_ptr->norm = *ptr; + } + + (*ptr)++; + + return HI_SUCCESS; +} + +/* +** NAME +** SetParamField:: +*/ +/** +** This function sets the parameter field as the first '?'. The big thing +** is that we set the param value, so we don't false positive long dir +** events when it's really just a long parameter field. +** +** @param ServerConf pointer to the server configuration +** @param start pointer to the start of payload +** @param end pointer to the end of the payload +** @param ptr pointer to the pointer of the current index +** @param uri_ptr pointer to the URI_PTR construct +** +** @return integer +** +** @retval HI_SUCCESS function successful +*/ +static int SetParamField( + HI_SESSION*, const u_char*, + const u_char*, const u_char** ptr, URI_PTR* uri_ptr) +{ + if (!uri_ptr->ident) + { + uri_ptr->param = *ptr; + } + + (*ptr)++; + + return HI_SUCCESS; +} + +/* +** NAME +** SetProxy:: +*/ +/** +** This function checks for an absolute URI in the URI. +** +** @param ServerConf pointer to the server configuration +** @param start pointer to the start of payload +** @param end pointer to the end of the payload +** @param ptr pointer to the pointer of the current index +** @param uri_ptr pointer to the URI_PTR construct +** +** @return integer +** +** @retval HI_SUCCESS function successful +*/ +static int SetProxy(HI_SESSION* session, const u_char* start, + const u_char* end, const u_char** ptr, URI_PTR* uri_ptr) +{ + HTTPINSPECT_CONF* ServerConf = session->server_conf; + + if (!uri_ptr->ident && !uri_ptr->last_dir) + { + if (hi_util_in_bounds(start, end, ((*ptr)+2))) + { + if (*((*ptr)+1) == '/' && *((*ptr)+2) == '/') + { + if (session->global_conf->proxy_alert && !ServerConf->allow_proxy) + uri_ptr->proxy = *ptr; + // If we found :// check to see if it is preceeded by http. If so, this is a proxy + proxy_start = (u_char*)SnortStrcasestr((const char*)uri_ptr->uri, (*ptr - + uri_ptr->uri), "http"); + proxy_end = end; + (*ptr) = (*ptr) + 3; + return HI_SUCCESS; + } + } + } + + (*ptr)++; + + return HI_SUCCESS; +} + +//------------------------------------------------------------------------- +// public methods +//------------------------------------------------------------------------- + +/* +** NAME +** hi_client_init:: +*/ +/** +** Initializes arrays and search algorithms depending on the type of +** inspection that we are doing. +** +** @retval HI_SUCCESS function successful. +*/ +int hi_client_init() +{ + int iCtr; + + memset(lookup_table, 0x00, sizeof(lookup_table)); + + // Set up the non-ASCII register for processing. + for (iCtr = 0x80; iCtr <= 0xff; iCtr++) + { + lookup_table[iCtr] = SetBinaryNorm; + } + lookup_table[0x00] = SetBinaryNorm; + + lookup_table[(uint8_t)' '] = NextNonWhiteSpace; + lookup_table[(uint8_t)'\r'] = find_rfc_delimiter; + lookup_table[(uint8_t)'\n'] = find_non_rfc_delimiter; + + // ASCII encoding + lookup_table[(uint8_t)'%'] = SetPercentNorm; + + // Looking for multiple slashes + lookup_table[(uint8_t)'/'] = SetSlashNorm; + + // Looking for backslashs + lookup_table[(uint8_t)'\\'] = SetBackSlashNorm; + + lookup_table[(uint8_t)'+'] = SetPlusNorm; + + // Look up parameter field, so we don't alert on long directory + // strings, when the next slash in the parameter field. + lookup_table[(uint8_t)'?'] = SetParamField; + + // Look for absolute URI and proxy communication. + lookup_table[(uint8_t)':'] = SetProxy; + + return HI_SUCCESS; +} + +/* +** NAME +** NextNonWhiteSpace:: +*/ +/** +** Update the URI_PTR fields spaces, find the next non-white space char, +** and validate the HTTP version identifier after the spaces. +** +** This is the main part of the URI algorithm. This verifies that there +** isn't too many spaces in the data to be a URI, it checks that after the +** second space that there is an HTTP identifier or otherwise it's no good. +** Also, if we've found an identifier after the first whitespace, and +** find another whitespace, there is no URI. +** +** The uri and uri_end pointers are updated in this function depending +** on what space we are at, and if the space was followed by the HTTP +** identifier. (NOTE: the HTTP delimiter is no longer "HTTP/", but +** can also be "\r\n", "\n", or "\r". This is the defunct method, and +** we deal with it in the IsHttpVersion and delimiter functions.) +** +** @param ServerConf pointer to the server configuration +** @param start pointer to the start of payload +** @param end pointer to the end of the payload +** @param ptr pointer to the pointer of the current index +** @param uri_ptr pointer to the URI_PTR construct +** +** @return integer +** +** @retval HI_SUCCESS found the next non-whitespace +** @retval HI_OUT_OF_BOUNDS whitespace to the end of the buffer +** @retval URI_END delimiter found, end of URI +** @retval NO_URI +*/ +int NextNonWhiteSpace(HI_SESSION* session, const u_char* start, + const u_char* end, const u_char** ptr, URI_PTR* uri_ptr) +{ + HTTPINSPECT_CONF* ServerConf = session->server_conf; + const u_char** start_sp; + const u_char** end_sp; + + /* + ** Horizontal tab is only accepted by apache web servers, not IIS. + ** Some IIS exploits contain a tab (0x09) in the URI, so we don't want + ** to treat it as a URI delimiter and cut off the URI. + */ + if ( **ptr == '\t' && !ServerConf->tab_uri_delimiter ) + { + (*ptr)++; + return HI_SUCCESS; + } + + /* + ** Reset the identifier, because we've just seen another space. We + ** should only see the identifier immediately after a space followed + ** by a delimiter. + */ + if (uri_ptr->ident) + { + if (ServerConf->non_strict) + { + /* + ** In non-strict mode it is ok to see spaces after the + ** "identifier", so we just increment the ptr and return. + */ + (*ptr)++; + return HI_SUCCESS; + } + else + { + /* + ** This means that we've already seen a space and a version + ** identifier, and now that we've seen another space, we know + ** that this can't be the URI so we just bail out with no + ** URI. + */ + return NO_URI; + } + } + + uri_ptr->ident = NULL; + + /* + ** We only check for one here, because both should be set if one + ** is. + */ + if (uri_ptr->first_sp_end) + { + /* + ** If the second space has been set, then this means that we have + ** seen a third space, which we shouldn't see in the URI so we + ** are now done and know there is no URI in this packet. + */ + if (uri_ptr->second_sp_end) + { + return NO_URI; + } + + /* + ** Treat whitespace differently at the end of the URI than we did + ** at the beginning. Ignore and return if special characters are + ** not defined as whitespace after the URI. + */ + if (ServerConf->whitespace[**ptr] + && !(ServerConf->whitespace[**ptr] & HI_UI_CONFIG_WS_AFTER_URI)) + { + (*ptr)++; + return HI_SUCCESS; + } + + /* + ** Since we've seen the second space, we need to update the uri ptr + ** to the end of the first space, since the URI cannot be before the + ** first space. + */ + uri_ptr->uri = uri_ptr->first_sp_end; + + uri_ptr->second_sp_start = *ptr; + uri_ptr->second_sp_end = NULL; + + start_sp = &uri_ptr->second_sp_start; + end_sp = &uri_ptr->second_sp_end; + } + else + { + /* + ** This means that there is whitespace at the beginning of the line + ** and we unset the URI so we can set it later if need be. + ** + ** This is mainly so we handle data that is all spaces correctly. + ** + ** In the normal case where we've seen text and then the first space, + ** we leave the uri ptr pointing at the beginning of the data, and + ** set the uri end after we've determined where to put it. + */ + if (start == *ptr) + uri_ptr->uri = NULL; + + uri_ptr->first_sp_start = *ptr; + uri_ptr->first_sp_end = NULL; + + start_sp = &uri_ptr->first_sp_start; + end_sp = &uri_ptr->first_sp_end; + } + + while (hi_util_in_bounds(start, end, *ptr)) + { + /* + ** Check for whitespace + */ + if (**ptr == ' ') + { + (*ptr)++; + continue; + } + else if (ServerConf->whitespace[**ptr]) + { + if (ServerConf->apache_whitespace.on) + { + hi_set_event(GID_HTTP_CLIENT, HI_CLIENT_APACHE_WS); + } + (*ptr)++; + continue; + } + else + { + /* + ** This sets the sp_end for whatever space delimiter we are on, + ** whether that is the first space or the second space. + */ + *end_sp = *ptr; + + if (!IsHttpVersion(ptr, end)) + { + /* + ** This is the default method and what we've been doing + ** since the start of development. + */ + if (uri_ptr->second_sp_start) + { + /* + ** There is no HTTP version indentifier at the beginning + ** of the second space, and this means that there is no + ** URI. + */ + if (ServerConf->non_strict) + { + /* + ** In non-strict mode, we must assume the URI is + ** between the first and second space, so now + ** that we've seen the second space that's the + ** identifier. + */ + uri_ptr->ident = *end_sp; + uri_ptr->uri_end = *start_sp; + + return HI_SUCCESS; + } + else + { + /* + ** Since we are in strict mode here, it means that + ** we haven't seen a valid identifier, so there was + ** no URI. + */ + + return NO_URI; + } + } + + /* + ** RESET NECESSARY URI_PTRs HERE. This is the place where + ** the uri is updated. It can only happen once, so do it + ** right here. + ** + ** When we get here it means that we have found the end of + ** the FIRST whitespace, and that there was no delimiter, + ** so we reset the uri pointers and other related + ** pointers. + */ + uri_ptr->uri = *end_sp; + uri_ptr->uri_end = end; + uri_ptr->norm = NULL; + uri_ptr->last_dir = NULL; + uri_ptr->param = NULL; + uri_ptr->proxy = NULL; + } + else + { + /* + ** Means we found the HTTP version identifier and we reset + ** the uri_end pointer to point to the beginning of the + ** whitespace detected. + ** + ** This works for both "uri_is_here HTTP/1.0" and + ** "METHOD uri_is_here HTTP/1.0", so it works when the + ** identifier is after either the first or the second + ** whitespace. + */ + uri_ptr->ident = *end_sp; + uri_ptr->uri_end = *start_sp; + } + + /* + ** We found a non-whitespace char + */ + return HI_SUCCESS; + } + } + + /* + ** This is the case where we've seen text and found a whitespace until + ** the end of the buffer. In that case, we set the uri_end to the + ** beginning of the whitespace. + */ + uri_ptr->uri_end = *start_sp; + + return HI_OUT_OF_BOUNDS; +} + +/* +** NAME +** CheckLongDir:: +*/ +/** +** We check the directory length against the global config. +** +** @param session pointer to the current session +** @param uri_ptr pointer to the URI state +** @param ptr pointer to the current index in buffer +** +** @return integer +** +** @retval HI_SUCCESS +*/ +int CheckLongDir(HI_SESSION* session, URI_PTR* uri_ptr, const u_char* ptr) +{ + int iDirLen; + + /* + ** Check for oversize directory + */ + if (session->server_conf->long_dir && + uri_ptr->last_dir && !uri_ptr->param) + { + iDirLen = ptr - uri_ptr->last_dir; + + if ( iDirLen > session->server_conf->long_dir ) + { + hi_set_event(GID_HTTP_CLIENT, HI_CLIENT_OVERSIZE_DIR); + } + } + + return HI_SUCCESS; +} + diff --git a/src/service_inspectors/dce_rpc/CMakeLists.txt b/src/service_inspectors/dce_rpc/CMakeLists.txt index 32bcb2836..69126cdb0 100644 --- a/src/service_inspectors/dce_rpc/CMakeLists.txt +++ b/src/service_inspectors/dce_rpc/CMakeLists.txt @@ -1,44 +1,46 @@ set( FILE_LIST - dce_co.cc - dce_co.h - dce_common.cc - dce_common.h - dce_list.h - dce_list.cc - dce_smb.cc - dce_smb.h - dce_smb2.cc - dce_smb2.h - dce_smb_commands.cc - dce_smb_commands.h - dce_smb_module.cc - dce_smb_module.h - dce_smb_paf.cc - dce_smb_paf.h - dce_smb_transaction.cc - dce_smb_transaction.h - dce_smb_transaction_utils.cc - dce_smb_transaction_utils.h - dce_smb_utils.cc - dce_smb_utils.h - dce_tcp.cc - dce_tcp.h - dce_tcp_module.cc - dce_tcp_module.h - dce_tcp_paf.cc - dce_tcp_paf.h - dce_udp.cc - dce_udp.h - dce_udp_module.cc - dce_udp_module.h - dce_udp_processing.cc - dce_utils.cc - dce_utils.h - ips_dce_iface.cc - ips_dce_opnum.cc - ips_dce_stub_data.cc - + dce_co.cc + dce_co.h + dce_common.cc + dce_common.h + dce_list.h + dce_list.cc + dce_smb.cc + dce_smb.h + dce_smb2.cc + dce_smb2.h + dce_smb_commands.cc + dce_smb_commands.h + dce_smb_module.cc + dce_smb_module.h + dce_smb_paf.cc + dce_smb_paf.h + dce_smb_transaction.cc + dce_smb_transaction.h + dce_smb_transaction_utils.cc + dce_smb_transaction_utils.h + dce_smb_utils.cc + dce_smb_utils.h + dce_tcp.cc + dce_tcp.h + dce_tcp_module.cc + dce_tcp_module.h + dce_tcp_paf.cc + dce_tcp_paf.h + dce_udp.cc + dce_udp.h + dce_udp_module.cc + dce_udp_module.h + dce_udp_processing.cc + dce_utils.cc + dce_utils.h + ips_dce_iface.cc + ips_dce_opnum.cc + ips_dce_stub_data.cc + smb_common.h + smb_message.cc + smb_message.h ) if (STATIC_INSPECTORS) diff --git a/src/service_inspectors/dce_rpc/Makefile.am b/src/service_inspectors/dce_rpc/Makefile.am index 3bd481622..38ce2ea8c 100644 --- a/src/service_inspectors/dce_rpc/Makefile.am +++ b/src/service_inspectors/dce_rpc/Makefile.am @@ -36,8 +36,10 @@ dce_utils.cc \ dce_utils.h \ ips_dce_iface.cc \ ips_dce_opnum.cc \ -ips_dce_stub_data.cc - +ips_dce_stub_data.cc \ +smb_common.h \ +smb_message.cc \ +smb_message.h if STATIC_INSPECTORS noinst_LIBRARIES = libdce_rpc.a diff --git a/src/service_inspectors/dce_rpc/dce_smb.cc b/src/service_inspectors/dce_rpc/dce_smb.cc index d03a4f7bf..f6c3732ac 100644 --- a/src/service_inspectors/dce_rpc/dce_smb.cc +++ b/src/service_inspectors/dce_rpc/dce_smb.cc @@ -38,9 +38,13 @@ THREAD_LOCAL dce2SmbStats dce2_smb_stats; THREAD_LOCAL Packet* dce2_smb_rpkt[DCE2_SMB_RPKT_TYPE_MAX] = { nullptr, nullptr, nullptr, nullptr }; +// used here THREAD_LOCAL ProfileStats dce2_smb_pstat_main; THREAD_LOCAL ProfileStats dce2_smb_pstat_session; THREAD_LOCAL ProfileStats dce2_smb_pstat_new_session; +THREAD_LOCAL ProfileStats dce2_smb_pstat_smb_req; + +// used elsewhere THREAD_LOCAL ProfileStats dce2_smb_pstat_detect; THREAD_LOCAL ProfileStats dce2_smb_pstat_log; THREAD_LOCAL ProfileStats dce2_smb_pstat_co_seg; @@ -48,7 +52,6 @@ THREAD_LOCAL ProfileStats dce2_smb_pstat_co_frag; THREAD_LOCAL ProfileStats dce2_smb_pstat_co_reass; THREAD_LOCAL ProfileStats dce2_smb_pstat_co_ctx; THREAD_LOCAL ProfileStats dce2_smb_pstat_smb_seg; -THREAD_LOCAL ProfileStats dce2_smb_pstat_smb_req; THREAD_LOCAL ProfileStats dce2_smb_pstat_smb_uid; THREAD_LOCAL ProfileStats dce2_smb_pstat_smb_tid; THREAD_LOCAL ProfileStats dce2_smb_pstat_smb_fid; @@ -58,21 +61,12 @@ THREAD_LOCAL ProfileStats dce2_smb_pstat_smb_file_api; THREAD_LOCAL ProfileStats dce2_smb_pstat_smb_fingerprint; THREAD_LOCAL ProfileStats dce2_smb_pstat_smb_negotiate; -/******************************************************************** - * Global variables - ********************************************************************/ -typedef DCE2_Ret (* DCE2_SmbComFunc)(DCE2_SmbSsnData*, const SmbNtHdr*, - const DCE2_SmbComInfo*, const uint8_t*, uint32_t); - -DCE2_SmbComFunc smb_com_funcs[SMB_MAX_NUM_COMS]; -uint8_t smb_wcts[SMB_MAX_NUM_COMS][2][32]; -uint16_t smb_bccs[SMB_MAX_NUM_COMS][2][2]; -DCE2_SmbComFunc smb_chain_funcs[DCE2_POLICY__MAX][SMB_ANDX_COM__MAX][SMB_MAX_NUM_COMS]; -bool smb_deprecated_coms[SMB_MAX_NUM_COMS]; -bool smb_unusual_coms[SMB_MAX_NUM_COMS]; -SmbAndXCom smb_chain_map[SMB_MAX_NUM_COMS]; +//------------------------------------------------------------------------- +// debug stuff +//------------------------------------------------------------------------- -const char* smb_com_strings[SMB_MAX_NUM_COMS] = +#ifdef DEBUG +static const char* smb_com_strings[SMB_MAX_NUM_COMS] = { "Create Directory", // 0x00 "Delete Directory", // 0x01 @@ -332,2621 +326,9 @@ const char* smb_com_strings[SMB_MAX_NUM_COMS] = "No AndX Command" // 0xFF }; -/******************************************************************** - * Private function prototypes - ********************************************************************/ -static inline bool DCE2_SmbIsRawData(DCE2_SmbSsnData*); -static inline uint32_t* DCE2_SmbGetIgnorePtr(DCE2_SmbSsnData*); -static inline DCE2_SmbDataState* DCE2_SmbGetDataState(DCE2_SmbSsnData*); -static inline void DCE2_SmbSetValidWordCount(uint8_t, uint8_t, uint8_t); -static inline bool DCE2_SmbIsValidWordCount(uint8_t, uint8_t, uint8_t); -static inline void DCE2_SmbSetValidByteCount(uint8_t, uint8_t, uint16_t, uint16_t); -static inline bool DCE2_SmbIsValidByteCount(uint8_t, uint8_t, uint16_t); -static DCE2_Ret DCE2_SmbHdrChecks(DCE2_SmbSsnData*, const SmbNtHdr*); -static uint32_t DCE2_IgnoreJunkData(const uint8_t*, uint16_t, uint32_t); -static void DCE2_SmbCheckCommand(DCE2_SmbSsnData*, - const SmbNtHdr*, const uint8_t, const uint8_t*, uint32_t, DCE2_SmbComInfo&); -static void DCE2_SmbProcessCommand(DCE2_SmbSsnData*, const SmbNtHdr*, const uint8_t*, uint32_t); -static DCE2_SmbRequestTracker* DCE2_SmbInspect(DCE2_SmbSsnData*, const SmbNtHdr*); -static DCE2_SmbRequestTracker* DCE2_SmbFindRequestTracker(DCE2_SmbSsnData*, - const SmbNtHdr*); -static inline DCE2_Ret DCE2_SmbCheckAndXOffset(const uint8_t*, - const uint8_t*, const uint32_t); -static void DCE2_SmbProcessRawData(DCE2_SmbSsnData*, const uint8_t*, uint32_t); - -/******************************************************************** - * Function: DCE2_SmbIsRawData() - * - * Purpose: - * To determine if the current state is such that a raw read or - * write is expected. - * - * Arguments: - * DCE2_SmbSsnData * - Pointer to SMB session data. - * - * Returns: - * bool - True if expecting raw data. - * False if not. - * - ********************************************************************/ -static inline bool DCE2_SmbIsRawData(DCE2_SmbSsnData* ssd) -{ - return (ssd->pdu_state == DCE2_SMB_PDU_STATE__RAW_DATA); -} - -/******************************************************************** - * Function: DCE2_SmbCheckAndXOffset() - * - * Purpose: - * Validates that the AndXOffset is within bounds of the remaining - * data we have to work with. - * - * Arguments: - * uint8_t * - pointer to where the offset would take us. - * uint8_t * - pointer to bound offset - * uint8_t * - length of data where offset should be within - * - * Returns: - * DCE2_RET__SUCCESS - Offset is okay. - * DCE2_RET__ERROR - Offset is bad. - * - ********************************************************************/ -static inline DCE2_Ret DCE2_SmbCheckAndXOffset(const uint8_t* off_ptr, const uint8_t* start_bound, - const uint32_t length) -{ - /* Offset should not point within data we just looked at or be equal to - * or beyond the length of the NBSS length left */ - if ((off_ptr < start_bound) || - (off_ptr > (start_bound + length))) - { - dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats); - - return DCE2_RET__ERROR; - } - - return DCE2_RET__SUCCESS; -} - -/******************************************************************** - * Function: DCE2_SmbGetIgnorePtr() - * - * Returns a pointer to the bytes we are ignoring on client or - * server side. Bytes are ignored if they are associated with - * data we are not interested in. - * - * Arguments: - * DCE2_SmbSsnData * - Pointer to SMB session data. - * - * Returns: - * uint32_t * - * Pointer to the client or server ignore bytes. - * - ********************************************************************/ -static inline uint32_t* DCE2_SmbGetIgnorePtr(DCE2_SmbSsnData* ssd) -{ - if (DCE2_SsnFromServer(ssd->sd.wire_pkt)) - return &ssd->srv_ignore_bytes; - return &ssd->cli_ignore_bytes; -} - -/******************************************************************** - * Function: DCE2_SmbGetDataState() - * - * Returns a pointer to the data state of client or server - * - * Arguments: - * DCE2_SmbSsnData * - Pointer to SMB session data. - * - * Returns: - * DCE2_SmbDataState * - * Pointer to the client or server data state. - * - ********************************************************************/ -static inline DCE2_SmbDataState* DCE2_SmbGetDataState(DCE2_SmbSsnData* ssd) -{ - if (DCE2_SsnFromServer(ssd->sd.wire_pkt)) - return &ssd->srv_data_state; - return &ssd->cli_data_state; -} - -/******************************************************************** - * Function: DCE2_SmbSetValidWordCount() - * - * Purpose: - * Initializes global data for valid word counts for supported - * SMB command requests and responses. - * - * Arguments: - * uint8_t - the SMB command code - * uint8_t - SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE - * uint8_t - the valid word count - * - * Returns: None - * - ********************************************************************/ -static inline void DCE2_SmbSetValidWordCount(uint8_t com, - uint8_t resp, uint8_t wct) -{ - smb_wcts[com][resp][wct/8] |= (1 << (wct % 8)); -} - -/******************************************************************** - * Function: DCE2_SmbIsValidWordCount() - * - * Purpose: - * Checks if a word count is valid for a given command request - * or response. - * - * Arguments: - * uint8_t - the SMB command code - * uint8_t - SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE - * uint8_t - the word count to validate - * - * Returns: - * bool - true if valid, false if not valid. - * - ********************************************************************/ -static inline bool DCE2_SmbIsValidWordCount(uint8_t com, - uint8_t resp, uint8_t wct) -{ - return (smb_wcts[com][resp][wct/8] & (1 << (wct % 8))) ? true : false; -} - -/******************************************************************** - * Function: DCE2_SmbSetValidByteCount() - * - * Purpose: - * Initializes global data for valid byte counts as a range for - * supported SMB command requests and responses. - * Since a byte count is 2 bytes, a 4 byte type is used to store - * the range. The maximum is in the most significant 2 bytes and - * the minimum in the least significant 2 bytes. - * - * Arguments: - * uint8_t - the SMB command code - * uint8_t - SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE - * uint8_t - the minimum word count that is valid - * uint8_t - the maximum word count that is valid - * - * Returns: None - * - ********************************************************************/ -static inline void DCE2_SmbSetValidByteCount(uint8_t com, - uint8_t resp, uint16_t min, uint16_t max) -{ - smb_bccs[com][resp][0] = min; - smb_bccs[com][resp][1] = max; -} - -/******************************************************************** - * Function: DCE2_SmbIsValidByteCount() - * - * Purpose: - * Checks if a byte count is valid for a given command request - * or response. - * - * Arguments: - * uint8_t - the SMB command code - * uint8_t - SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE - * uint8_t - the byte count to validate - * - * Returns: - * bool - true if valid, false if not valid. - * - ********************************************************************/ -static inline bool DCE2_SmbIsValidByteCount(uint8_t com, - uint8_t resp, uint16_t bcc) -{ - return ((bcc < smb_bccs[com][resp][0]) - || (bcc > smb_bccs[com][resp][1])) ? false : true; -} - -// This function is obviously deficient. Need to do a lot more -// testing, research and reading MS-CIFS, MS-SMB and MS-ERREF. -static bool SmbError(const SmbNtHdr* hdr) -{ - if (SmbStatusNtCodes(hdr)) - { - /* Nt status codes are being used. First 2 bits indicate - * severity. */ - switch (SmbNtStatusSeverity(hdr)) - { - case SMB_NT_STATUS_SEVERITY__SUCCESS: - case SMB_NT_STATUS_SEVERITY__INFORMATIONAL: - case SMB_NT_STATUS_SEVERITY__WARNING: - return false; - case SMB_NT_STATUS_SEVERITY__ERROR: - default: - break; - } - } - else - { - switch (SmbStatusClass(hdr)) - { - case SMB_ERROR_CLASS__SUCCESS: - return false; - case SMB_ERROR_CLASS__ERRDOS: - if (SmbStatusCode(hdr) == SMB_ERRDOS__MORE_DATA) - return false; - break; - case SMB_ERROR_CLASS__ERRSRV: - case SMB_ERROR_CLASS__ERRHRD: - case SMB_ERROR_CLASS__ERRCMD: - default: - break; - } - } - - return true; -} - -static bool SmbBrokenPipe(const SmbNtHdr* hdr) -{ - if (SmbStatusNtCodes(hdr)) - { - uint32_t nt_status = SmbNtStatus(hdr); - if ((nt_status == SMB_NT_STATUS__PIPE_BROKEN) - || (nt_status == SMB_NT_STATUS__PIPE_DISCONNECTED)) - return true; - } - else - { - if (SmbStatusClass(hdr) == SMB_ERROR_CLASS__ERRDOS) - { - uint16_t smb_status = SmbStatusCode(hdr); - if ((smb_status == SMB_ERRDOS__BAD_PIPE) - || (smb_status == SMB_ERRDOS__PIPE_NOT_CONNECTED)) - return true; - } - } - - return false; -} - -/******************************************************************** - * Function: DCE2_IgnoreJunkData() - * - * Purpose: - * An evasion technique can be to put a bunch of junk data before - * the actual SMB request and it seems the MS implementation has - * no problem with it and seems to just ignore the data. This - * function attempts to move past all the junk to get to the - * actual NetBIOS message request. - * - * Arguments: - * const uint8_t * - pointer to the current position in the data - * being inspected - * uint16_t - the amount of data left to look at - * uint32_t - the amount of data to ignore if there doesn't seem - * to be any junk data. Just use the length as if the bad - * NetBIOS header was good. - * - * Returns: - * uint32_t - the amount of bytes to ignore as junk. - * - ********************************************************************/ -static uint32_t DCE2_IgnoreJunkData(const uint8_t* data_ptr, uint16_t data_len, - uint32_t assumed_nb_len) -{ - const uint8_t* tmp_ptr = data_ptr; - uint32_t ignore_bytes = 0; - - /* Try to find \xffSMB and go back 8 bytes to beginning - * of what should be a Netbios header with type Session - * Message (\x00) - do appropriate buffer checks to make - * sure the index is in bounds. Ignore all intervening - * bytes */ - - while ((tmp_ptr + sizeof(uint32_t)) <= (data_ptr + data_len)) - { - if ((SmbId((SmbNtHdr*)tmp_ptr) == DCE2_SMB_ID) - || (SmbId((SmbNtHdr*)tmp_ptr) == DCE2_SMB2_ID)) - { - break; - } - - tmp_ptr++; - } - - if ((tmp_ptr + sizeof(uint32_t)) > (data_ptr + data_len)) - { - ignore_bytes = data_len; - } - else - { - if ((tmp_ptr - sizeof(NbssHdr)) > data_ptr) - ignore_bytes = (tmp_ptr - data_ptr) - sizeof(NbssHdr); - else /* Just ignore whatever the bad NB header had as a length */ - ignore_bytes = assumed_nb_len; - } - - return ignore_bytes; -} - -/******************************************************************** - * Function: DCE2_SmbHdrChecks() - * - * Checks some relevant fields in the header to make sure they're - * sane. - * Side effects are potential alerts for anomolous behavior. - * - * Arguments: - * DCE2_SmbSsnData * - * Pointer to the session data structure. - * SmbNtHdr * - * Pointer to the header struct layed over the packet data. - * - * Returns: - * DCE2_Ret - * DCE2_RET__IGNORE if we should continue processing, but - * ignore data because of the error. - * DCE2_RET__SUCCESS if we should continue processing. - * - ********************************************************************/ -static DCE2_Ret DCE2_SmbHdrChecks(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr) -{ - Packet* p = ssd->sd.wire_pkt; - bool is_seg_buf = DCE2_SmbIsSegBuffer(ssd, (uint8_t*)smb_hdr); - - if ((DCE2_SsnFromServer(p) && (SmbType(smb_hdr) == SMB_TYPE__REQUEST)) || - (DCE2_SsnFromClient(p) && (SmbType(smb_hdr) == SMB_TYPE__RESPONSE))) - { - if (is_seg_buf) - DCE2_SmbSegAlert(ssd, DCE2_SMB_BAD_TYPE); - else - dce_alert(GID_DCE2, DCE2_SMB_BAD_TYPE, (dce2CommonStats*)&dce2_smb_stats); - - // Continue looking at traffic. Neither Windows nor Samba seem - // to care, or even look at this flag - } - - if ((SmbId(smb_hdr) != DCE2_SMB_ID) - && (SmbId(smb_hdr) != DCE2_SMB2_ID)) - { - if (is_seg_buf) - DCE2_SmbSegAlert(ssd, DCE2_SMB_BAD_ID); - else - dce_alert(GID_DCE2, DCE2_SMB_BAD_ID, (dce2CommonStats*)&dce2_smb_stats); - - return DCE2_RET__IGNORE; - } - - return DCE2_RET__SUCCESS; -} - -/******************************************************************** - * Function: DCE2_SmbGetMinByteCount() - * - * Purpose: - * Returns the minimum byte count for the given command request - * or response. - * - * Arguments: - * uint8_t - the SMB command code - * uint8_t - SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE - * - * Returns: - * uint16_t - the minimum byte count - * - ********************************************************************/ -static inline uint16_t DCE2_SmbGetMinByteCount(uint8_t com, uint8_t resp) -{ - return smb_bccs[com][resp][0]; -} - -static DCE2_SmbRequestTracker* DCE2_SmbFindRequestTracker(DCE2_SmbSsnData* ssd, - const SmbNtHdr* smb_hdr) -{ - uint16_t uid = SmbUid(smb_hdr); - uint16_t tid = SmbTid(smb_hdr); - uint16_t pid = SmbPid(smb_hdr); - uint16_t mid = SmbMid(smb_hdr); - - Profile profile(dce2_smb_pstat_smb_req); - - DebugFormat(DEBUG_DCE_SMB, "Find request tracker => " - "Uid: %hu, Tid: %hu, Pid: %hu, Mid: %hu ... ", uid, tid, pid, mid); - - DCE2_SmbRequestTracker* tmp_rtracker = &ssd->rtracker; - int smb_com = SmbCom(smb_hdr); - switch (smb_com) - { - case SMB_COM_TRANSACTION_SECONDARY: - smb_com = SMB_COM_TRANSACTION; - break; - case SMB_COM_TRANSACTION2_SECONDARY: - smb_com = SMB_COM_TRANSACTION2; - break; - case SMB_COM_NT_TRANSACT_SECONDARY: - smb_com = SMB_COM_NT_TRANSACT; - break; - case SMB_COM_WRITE_COMPLETE: - smb_com = SMB_COM_WRITE_RAW; - break; - default: - break; - } - - DCE2_SmbRequestTracker* first_rtracker = nullptr; - DCE2_SmbRequestTracker* win_rtracker = nullptr; - DCE2_SmbRequestTracker* first_mid_rtracker = nullptr; - DCE2_SmbRequestTracker* ret_rtracker = nullptr; - while (tmp_rtracker != nullptr) - { - if ((tmp_rtracker->mid == (int)mid) && (tmp_rtracker->smb_com == smb_com)) - { - // This is the normal case except for SessionSetupAndX and - // TreeConnect/TreeConnectAndX which will fall into the - // default case below. - if ((tmp_rtracker->pid == pid) && (tmp_rtracker->uid == uid) - && (tmp_rtracker->tid == tid)) - { - ret_rtracker = tmp_rtracker; - } - else - { - switch (smb_com) - { - case SMB_COM_TRANSACTION: - case SMB_COM_TRANSACTION2: - case SMB_COM_NT_TRANSACT: - case SMB_COM_TRANSACTION_SECONDARY: - case SMB_COM_TRANSACTION2_SECONDARY: - case SMB_COM_NT_TRANSACT_SECONDARY: - // These should conform to above - break; - default: - if (tmp_rtracker->pid == pid) - ret_rtracker = tmp_rtracker; - break; - } - } - - if (ret_rtracker != nullptr) - { - DebugMessage(DEBUG_DCE_SMB, "Found.\n"); - return ret_rtracker; - } - - // Take the first one where the PIDs also match - // in the case of the Transacts above - if ((tmp_rtracker->pid == pid) && (win_rtracker == nullptr)) - win_rtracker = tmp_rtracker; - - // Set this to the first matching request in the queue - // where the Mid matches. Don't set for Windows if from - // client since PID/MID are necessary - if (((DCE2_SmbType(ssd) == SMB_TYPE__RESPONSE) - || !DCE2_SsnIsWindowsPolicy(&ssd->sd)) - && first_mid_rtracker == nullptr) - { - first_mid_rtracker = tmp_rtracker; - } - } - - // Set the first one we see for early Samba versions - if ((first_rtracker == nullptr) && (tmp_rtracker->mid != DCE2_SENTINEL) - && (tmp_rtracker->smb_com == smb_com)) - first_rtracker = tmp_rtracker; - - // Look at the next request in the queue - if (tmp_rtracker == &ssd->rtracker) - tmp_rtracker = (DCE2_SmbRequestTracker*)DCE2_QueueFirst(ssd->rtrackers); - else - tmp_rtracker = (DCE2_SmbRequestTracker*)DCE2_QueueNext(ssd->rtrackers); - } - - DCE2_Policy policy = DCE2_SsnGetPolicy(&ssd->sd); - switch (policy) - { - case DCE2_POLICY__SAMBA_3_0_20: - case DCE2_POLICY__SAMBA_3_0_22: - ret_rtracker = first_rtracker; - break; - case DCE2_POLICY__SAMBA: - case DCE2_POLICY__SAMBA_3_0_37: - ret_rtracker = first_mid_rtracker; - break; - case DCE2_POLICY__WIN2000: - case DCE2_POLICY__WINXP: - case DCE2_POLICY__WINVISTA: - case DCE2_POLICY__WIN2003: - case DCE2_POLICY__WIN2008: - case DCE2_POLICY__WIN7: - if (win_rtracker != nullptr) - ret_rtracker = win_rtracker; - else - ret_rtracker = first_mid_rtracker; - break; - default: - DebugFormat(DEBUG_DCE_SMB, "%s(%d) Invalid policy: %d", - __FILE__, __LINE__, policy); - break; - } - - return ret_rtracker; -} - -/******************************************************************** - * Function: DCE2_SmbCheckCommand() - * - * Purpose: - * Checks basic validity of an SMB command. - * - * Arguments: - * DCE2_SmbSsnData * - pointer to session data structure - * SmbNtHdr * - pointer to the SMB header structure - * uint8_t - the SMB command code, i.e. SMB_COM_* - * uint8_t * - current pointer to data, i.e. the command - * uint32_t - the remaining length - * DCE2_SmbComInfo & - - * Populated structure for command processing - * - * Returns: None - * - ********************************************************************/ -static void DCE2_SmbCheckCommand(DCE2_SmbSsnData* ssd, - const SmbNtHdr* smb_hdr, const uint8_t smb_com, - const uint8_t* nb_ptr, uint32_t nb_len, DCE2_SmbComInfo& com_info) -{ - // Check for server error response - if (com_info.smb_type == SMB_TYPE__RESPONSE) - { - const SmbEmptyCom* ec = (SmbEmptyCom*)nb_ptr; - - // Verify there is enough data to do checks - if (nb_len < sizeof(SmbEmptyCom)) - { - dce_alert(GID_DCE2, DCE2_SMB_NB_LT_COM, (dce2CommonStats*)&dce2_smb_stats); - com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH; - return; - } - - // If word and byte counts are zero and there is an error - // the server didn't accept client request - if ((SmbEmptyComWct(ec) == 0) - && (SmbEmptyComBcc(ec) == 0) && SmbError(smb_hdr)) - { - DebugFormat(DEBUG_DCE_SMB, - "Response error: 0x%08X\n", SmbNtStatus(smb_hdr)); - - // If broken pipe, clean up data associated with open named pipe - if (SmbBrokenPipe(smb_hdr)) - { - DebugMessage(DEBUG_DCE_SMB, "Broken or disconnected pipe.\n"); - DCE2_SmbRemoveFileTracker(ssd, ssd->cur_rtracker->ftracker); - } - - com_info.cmd_error |= DCE2_SMB_COM_ERROR__STATUS_ERROR; - return; - } - } - - // Set the header size to the minimum size the command can be - // without the byte count to make sure there is enough data to - // get the word count. - SmbAndXCom andx_com = smb_chain_map[smb_com]; - int chk_com_size; - if (andx_com == SMB_ANDX_COM__NONE) - chk_com_size = sizeof(SmbCommon); - else - chk_com_size = sizeof(SmbAndXCommon); - - // Verify there is enough data to do checks - if (nb_len < (uint32_t)chk_com_size) - { - dce_alert(GID_DCE2, DCE2_SMB_NB_LT_COM, (dce2CommonStats*)&dce2_smb_stats); - com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH; - return; - } - - const SmbCommon* sc = (SmbCommon*)nb_ptr; - com_info.word_count = SmbWct(sc); - - // Make sure the word count is a valid one for the command. If not - // testing shows an error will be returned. And command structures - // won't lie on data correctly and out of bounds data accesses are possible. - if (!DCE2_SmbIsValidWordCount(smb_com, (uint8_t)com_info.smb_type, com_info.word_count)) - { - dce_alert(GID_DCE2, DCE2_SMB_BAD_WCT, (dce2CommonStats*)&dce2_smb_stats); - com_info.cmd_error |= DCE2_SMB_COM_ERROR__INVALID_WORD_COUNT; - return; - } - - // This gets the size of the SMB command from word count through byte count - // using the advertised value in the word count field. - com_info.cmd_size = (uint16_t)SMB_COM_SIZE(com_info.word_count); - if (nb_len < com_info.cmd_size) - { - dce_alert(GID_DCE2, DCE2_SMB_NB_LT_COM, (dce2CommonStats*)&dce2_smb_stats); - com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH; - return; - } - - uint16_t smb_bcc = SmbBcc(nb_ptr, com_info.cmd_size); - - // SMB_COM_NT_CREATE_ANDX is a special case. Who know what's going - // on with the word count (see MS-CIFS and MS-SMB). A 42 word count - // command seems to actually have 50 words, so who knows where the - // byte count is. Just set to zero since it's not needed. - if ((smb_com == SMB_COM_NT_CREATE_ANDX) - && (com_info.smb_type == SMB_TYPE__RESPONSE)) - smb_bcc = 0; - - // If byte count is deemed invalid, alert but continue processing - switch (smb_com) - { - // Interim responses - case SMB_COM_TRANSACTION: - case SMB_COM_TRANSACTION2: - case SMB_COM_NT_TRANSACT: - // If word count is 0, byte count must be 0 - if ((com_info.word_count == 0) && (com_info.smb_type == SMB_TYPE__RESPONSE)) - { - if (smb_bcc != 0) - { - dce_alert(GID_DCE2, DCE2_SMB_BAD_BCC, (dce2CommonStats*)&dce2_smb_stats); - com_info.cmd_error |= DCE2_SMB_COM_ERROR__INVALID_BYTE_COUNT; - } - break; - } - // Fall through - default: - if (!DCE2_SmbIsValidByteCount(smb_com, (uint8_t)com_info.smb_type, smb_bcc)) - { - dce_alert(GID_DCE2, DCE2_SMB_BAD_BCC, (dce2CommonStats*)&dce2_smb_stats); - com_info.cmd_error |= DCE2_SMB_COM_ERROR__INVALID_BYTE_COUNT; - } - break; - } - - // Move just past byte count field which is the end of the command - DCE2_MOVE(nb_ptr, nb_len, com_info.cmd_size); - - // Validate that there is enough data to be able to process the command - if (nb_len < DCE2_SmbGetMinByteCount(smb_com, (uint8_t)com_info.smb_type)) - { - dce_alert(GID_DCE2, DCE2_SMB_NB_LT_BCC, (dce2CommonStats*)&dce2_smb_stats); - com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH; - } - - // The byte count seems to be ignored by Windows and current Samba (3.5.4) - // as long as it is less than the amount of data left. If more, an error - // is returned. - // !!!WARNING!!! the byte count should probably never be used. - if (smb_bcc > nb_len) - { - dce_alert(GID_DCE2, DCE2_SMB_NB_LT_BCC, (dce2CommonStats*)&dce2_smb_stats); - // Large byte count doesn't seem to matter for early Samba - switch (DCE2_SsnGetPolicy(&ssd->sd)) - { - case DCE2_POLICY__SAMBA_3_0_20: - case DCE2_POLICY__SAMBA_3_0_22: - case DCE2_POLICY__SAMBA_3_0_37: - break; - default: - com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH; - break; - } - } - else if ((smb_bcc == 0) && (SmbCom(smb_hdr) == SMB_COM_TRANSACTION) - && (DCE2_SmbType(ssd) == SMB_TYPE__REQUEST) - && (DCE2_SsnGetPolicy(&ssd->sd) == DCE2_POLICY__SAMBA)) - { - // Current Samba errors on a zero byte count Transaction because it - // uses it to get the Name string and if zero Name will be NULL and - // it won't process it. - com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH; - } - - com_info.byte_count = smb_bcc; -} - -/******************************************************************** - * Function: DCE2_SmbProcessCommand() - * - * Purpose: - * This is the main function for handling SMB commands and command - * chaining. - * It does an initial check of the command to determine validity - * and gets basic information about the command. Then it calls the - * specific command function (setup in DCE2_SmbInitGlobals). - * If there is command chaining, it will do the chaining foo to - * get to the next command. - * - * Arguments: - * DCE2_SmbSsnData * - pointer to session data structure - * SmbNtHdr * - pointer to the SMB header structure - * uint8_t * - current pointer to data, i.e. the command - * uint32_t - the remaining length - * - * Returns: None - * - ********************************************************************/ -static void DCE2_SmbProcessCommand(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr, - const uint8_t* nb_ptr, uint32_t nb_len) -{ - uint8_t smb_com = SmbCom(smb_hdr); - DCE2_Ret status = DCE2_RET__ERROR; - bool sess_chain = false; - bool tree_chain = false; - bool open_chain = false; - int num_chained = 0; - - while (nb_len > 0) - { - // Break out if command not supported - if (smb_com_funcs[smb_com] == nullptr) - break; - - if (smb_deprecated_coms[smb_com]) - { - dce_alert(GID_DCE2, DCE2_SMB_DEPR_COMMAND_USED, (dce2CommonStats*)&dce2_smb_stats); - } - - if (smb_unusual_coms[smb_com]) - { - dce_alert(GID_DCE2, DCE2_SMB_UNUSUAL_COMMAND_USED, (dce2CommonStats*)&dce2_smb_stats); - } - - DCE2_SmbComInfo com_info; - com_info.smb_type = DCE2_SmbType(ssd); - com_info.cmd_error = DCE2_SMB_COM_ERROR__COMMAND_OK; - com_info.word_count = 0; - com_info.smb_com = smb_com; - com_info.cmd_size = 0; - com_info.byte_count = 0; - DCE2_SmbCheckCommand(ssd, smb_hdr, smb_com, nb_ptr, nb_len, com_info); - DebugFormat(DEBUG_DCE_SMB, "Processing command: %s (0x%02X)\n", - smb_com_strings[smb_com], smb_com); - - // Note that even if the command shouldn't be processed, some of - // the command functions need to know and do cleanup or some other - // processing. - status = smb_com_funcs[smb_com](ssd, smb_hdr, - &com_info, nb_ptr, nb_len); - - if (status != DCE2_RET__SUCCESS) - break; - - // This command is not chainable - SmbAndXCom andx_com = smb_chain_map[smb_com]; - if (andx_com == SMB_ANDX_COM__NONE) - break; - - /********************************************************** - * AndX Chaining - **********************************************************/ - const SmbAndXCommon* andx_ptr = (SmbAndXCommon*)nb_ptr; - uint8_t smb_com2 = SmbAndXCom2(andx_ptr); - if (smb_com2 == SMB_COM_NO_ANDX_COMMAND) - break; - - DebugFormat(DEBUG_DCE_SMB, "Chained SMB command: %s\n", smb_com_strings[smb_com2]); - - num_chained++; - if (DCE2_ScSmbMaxChain((dce2SmbProtoConf*)ssd->sd.config) && - (num_chained >= DCE2_ScSmbMaxChain((dce2SmbProtoConf*)ssd->sd.config))) - { - dce_alert(GID_DCE2, DCE2_SMB_EXCESSIVE_CHAINING, (dce2CommonStats*)&dce2_smb_stats); - } - - // Multiple SessionSetupAndX, TreeConnectAndX, OpenAndX and NtCreateAndX - // are only allowed by Samba. - if (smb_com == SMB_COM_SESSION_SETUP_ANDX) - sess_chain = true; - - // Check for multiple chained SessionSetupAndX - if ((smb_com2 == SMB_COM_SESSION_SETUP_ANDX) && sess_chain) - { - // There is only one place to return a uid. - dce_alert(GID_DCE2, DCE2_SMB_MULT_CHAIN_SS, (dce2CommonStats*)&dce2_smb_stats); - // FIXIT-L Should we continue processing? - break; - } - - // Check for chained SessionSetupAndX => .? => LogoffAndX - if ((smb_com2 == SMB_COM_LOGOFF_ANDX) && sess_chain) - { - // This essentially deletes the uid created by the login - // and doesn't make any sense. - dce_alert(GID_DCE2, DCE2_SMB_CHAIN_SS_LOGOFF, (dce2CommonStats*)&dce2_smb_stats); - } - - if (smb_com == SMB_COM_TREE_CONNECT_ANDX) - tree_chain = true; - - // Check for multiple chained TreeConnects - if (((smb_com2 == SMB_COM_TREE_CONNECT_ANDX) - || (smb_com2 == SMB_COM_TREE_CONNECT)) && tree_chain) - { - // There is only one place to return a tid. - dce_alert(GID_DCE2, DCE2_SMB_MULT_CHAIN_TC, (dce2CommonStats*)&dce2_smb_stats); - // FIXIT-L Should we continue processing? - break; - } - - // Check for chained TreeConnectAndX => .? => TreeDisconnect - if ((smb_com2 == SMB_COM_TREE_DISCONNECT) && tree_chain) - { - // This essentially deletes the tid created by the tree connect - // and doesn't make any sense. - dce_alert(GID_DCE2, DCE2_SMB_CHAIN_TC_TDIS, (dce2CommonStats*)&dce2_smb_stats); - } - - if ((smb_com == SMB_COM_OPEN_ANDX) || (smb_com == SMB_COM_NT_CREATE_ANDX)) - open_chain = true; - - // Check for chained OpenAndX/NtCreateAndX => .? => Close - if ((smb_com2 == SMB_COM_CLOSE) && open_chain) - { - // This essentially deletes the fid created by the open command - // and doesn't make any sense. - dce_alert(GID_DCE2, DCE2_SMB_CHAIN_OPEN_CLOSE, (dce2CommonStats*)&dce2_smb_stats); - } - - // Check that policy allows for such chaining - DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd); - if (smb_chain_funcs[policy][andx_com][smb_com2] == nullptr) - break; - - DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(&com_info)); - - // FIXIT-L Need to test out of order chaining - const uint8_t* off2_ptr = (uint8_t*)smb_hdr + SmbAndXOff2(andx_ptr); - if (DCE2_SmbCheckAndXOffset(off2_ptr, nb_ptr, nb_len) != DCE2_RET__SUCCESS) - break; - - DCE2_MOVE(nb_ptr, nb_len, (off2_ptr - nb_ptr)); - - // FIXIT-L Need to test more. - switch (smb_com) - { - case SMB_COM_SESSION_SETUP_ANDX: - case SMB_COM_TREE_CONNECT_ANDX: - case SMB_COM_OPEN_ANDX: - case SMB_COM_NT_CREATE_ANDX: - switch (smb_com2) - { - case SMB_COM_WRITE: - case SMB_COM_WRITE_ANDX: - case SMB_COM_TRANSACTION: - case SMB_COM_READ_ANDX: - if (DCE2_SsnFromClient(ssd->sd.wire_pkt) && open_chain) - { - DCE2_SmbQueueTmpFileTracker(ssd, ssd->cur_rtracker, - SmbUid(smb_hdr), SmbTid(smb_hdr)); - } - break; - default: - break; - } - break; - default: - break; - } - - smb_com = smb_com2; - } - - int smb_type = DCE2_SmbType(ssd); - if (smb_type == SMB_TYPE__RESPONSE) - { - switch (smb_com) - { - case SMB_COM_TRANSACTION: - case SMB_COM_TRANSACTION2: - case SMB_COM_NT_TRANSACT: - case SMB_COM_TRANSACTION_SECONDARY: - case SMB_COM_TRANSACTION2_SECONDARY: - case SMB_COM_NT_TRANSACT_SECONDARY: - // This case means there was an error with the initial response - // so the tracker isn't yet officially in response mode - if (ssd->cur_rtracker->ttracker.smb_type == SMB_TYPE__REQUEST) - { - // Samba throws out entire transaction and Windows just this request - if (DCE2_SsnIsServerSambaPolicy(&ssd->sd) && (status != DCE2_RET__SUCCESS)) - break; - - if (!DCE2_SmbIsTransactionComplete(&ssd->cur_rtracker->ttracker)) - return; - } - else - { - if ((status == DCE2_RET__SUCCESS) - && !DCE2_SmbIsTransactionComplete(&ssd->cur_rtracker->ttracker)) - return; - } - break; - case SMB_COM_WRITE_RAW: - if ((status == DCE2_RET__SUCCESS) - && (ssd->cur_rtracker->writeraw_remaining != 0)) - return; - break; - default: - break; - } - } - else if (status != DCE2_RET__IGNORE) - { - switch (smb_com) - { - case SMB_COM_TRANSACTION: - case SMB_COM_TRANSACTION_SECONDARY: - if (DCE2_SsnIsWindowsPolicy(&ssd->sd)) - { - if (!ssd->cur_rtracker->ttracker.one_way - || !DCE2_SmbIsTransactionComplete(&ssd->cur_rtracker->ttracker)) - return; - - // Remove the request tracker if transaction is one-way and - // all data and parameters have been sent - break; - } - default: - // Anything else, keep the request tracker - return; - } - } - - DCE2_SmbRemoveRequestTracker(ssd, ssd->cur_rtracker); - ssd->cur_rtracker = nullptr; -} - -/******************************************************************** - * Function: DCE2_SmbInspect() - * - * Purpose: - * Determines whether the SMB command is something the preprocessor - * needs to inspect. - * This function returns a DCE2_SmbRequestTracker which tracks command - * requests / responses. - * - * Arguments: - * DCE2_SmbSsnData * - the session data structure. - * const SmbNtHdr * - pointer to the SMB header. - * - * Returns: - * DCE2_SmbRequestTracker * - nullptr if it's not something we want to or can - * inspect. - * Otherwise an initialized structure if request - * and the found structure if response. - * - ********************************************************************/ -static DCE2_SmbRequestTracker* DCE2_SmbInspect(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr) -{ - int smb_com = SmbCom(smb_hdr); - - DebugFormat(DEBUG_DCE_SMB, "SMB command: %s (0x%02X)\n", - smb_com_strings[smb_com], smb_com); - - if (smb_com_funcs[smb_com] == nullptr) - { - DebugMessage(DEBUG_DCE_SMB, "Command isn't processed " - "by preprocessor.\n"); - return nullptr; - } - - // See if this is something we need to inspect - DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd); - DCE2_SmbRequestTracker* rtracker = nullptr; - if (DCE2_SmbType(ssd) == SMB_TYPE__REQUEST) - { - switch (smb_com) - { - case SMB_COM_NEGOTIATE: - if (ssd->ssn_state_flags & DCE2_SMB_SSN_STATE__NEGOTIATED) - { - dce_alert(GID_DCE2, DCE2_SMB_MULTIPLE_NEGOTIATIONS, - (dce2CommonStats*)&dce2_smb_stats); - return nullptr; - } - break; - case SMB_COM_SESSION_SETUP_ANDX: - break; - case SMB_COM_TREE_CONNECT: - case SMB_COM_TREE_CONNECT_ANDX: - case SMB_COM_RENAME: - case SMB_COM_LOGOFF_ANDX: - if (DCE2_SmbFindUid(ssd, SmbUid(smb_hdr)) != DCE2_RET__SUCCESS) - return nullptr; - break; - default: - if (DCE2_SmbFindTid(ssd, SmbTid(smb_hdr)) != DCE2_RET__SUCCESS) - { - DebugFormat(DEBUG_DCE_SMB, - "Couldn't find Tid (%hu)\n", SmbTid(smb_hdr)); - return nullptr; - } - - if (DCE2_SmbIsTidIPC(ssd, SmbTid(smb_hdr))) - { - switch (smb_com) - { - case SMB_COM_OPEN: - case SMB_COM_CREATE: - case SMB_COM_CREATE_NEW: - case SMB_COM_WRITE_AND_CLOSE: - case SMB_COM_WRITE_AND_UNLOCK: - case SMB_COM_READ: - // Samba doesn't allow these commands under an IPC tree - switch (policy) - { - case DCE2_POLICY__SAMBA: - case DCE2_POLICY__SAMBA_3_0_37: - case DCE2_POLICY__SAMBA_3_0_22: - case DCE2_POLICY__SAMBA_3_0_20: - DebugMessage(DEBUG_DCE_SMB, "Samba doesn't " - "process this command under an IPC tree.\n"); - return nullptr; - default: - break; - } - break; - case SMB_COM_READ_RAW: - case SMB_COM_WRITE_RAW: - // Samba and Windows Vista on don't allow these commands - // under an IPC tree, whether or not the raw read/write - // flag is set in the Negotiate capabilities. - // Windows RSTs the connection and Samba FINs it. - switch (policy) - { - case DCE2_POLICY__WINVISTA: - case DCE2_POLICY__WIN2008: - case DCE2_POLICY__WIN7: - case DCE2_POLICY__SAMBA: - case DCE2_POLICY__SAMBA_3_0_37: - case DCE2_POLICY__SAMBA_3_0_22: - case DCE2_POLICY__SAMBA_3_0_20: - DebugMessage(DEBUG_DCE_SMB, "Samba and " - "Windows Vista on don't process this " - "command under an IPC tree.\n"); - return nullptr; - default: - break; - } - break; - case SMB_COM_LOCK_AND_READ: - // The lock will fail so the read won't happen - return nullptr; - default: - break; - } - } - else // Not IPC - { - switch (smb_com) - { - // These commands are only used for IPC - case SMB_COM_TRANSACTION: - case SMB_COM_TRANSACTION_SECONDARY: - DebugMessage(DEBUG_DCE_SMB, "secondary transaction not IPC.\n"); - return nullptr; - case SMB_COM_READ_RAW: - case SMB_COM_WRITE_RAW: - // Windows Vista on don't seem to support these - // commands, whether or not the raw read/write - // flag is set in the Negotiate capabilities. - // Windows RSTs the connection. - switch (policy) - { - case DCE2_POLICY__WINVISTA: - case DCE2_POLICY__WIN2008: - case DCE2_POLICY__WIN7: - DebugMessage(DEBUG_DCE_SMB, - "Windows Vista on don't process " - "this command.\n"); - return nullptr; - default: - break; - } - break; - default: - break; - } - } - break; - } - - switch (smb_com) - { - case SMB_COM_TRANSACTION_SECONDARY: - case SMB_COM_TRANSACTION2_SECONDARY: - case SMB_COM_NT_TRANSACT_SECONDARY: - rtracker = DCE2_SmbFindRequestTracker(ssd, smb_hdr); - break; - case SMB_COM_TRANSACTION: - case SMB_COM_TRANSACTION2: - case SMB_COM_NT_TRANSACT: - // If there is already and existing request tracker - // and the transaction is not complete, server will - // return an error. - rtracker = DCE2_SmbFindRequestTracker(ssd, smb_hdr); - if (rtracker != nullptr) - break; - // Fall through - default: - rtracker = DCE2_SmbNewRequestTracker(ssd, smb_hdr); - break; - } - } - else - { - rtracker = DCE2_SmbFindRequestTracker(ssd, smb_hdr); - } - - return rtracker; -} - -static void DCE2_SmbProcessRawData(DCE2_SmbSsnData* ssd, const uint8_t* nb_ptr, uint32_t nb_len) -{ - DCE2_SmbFileTracker* ftracker = ssd->cur_rtracker->ftracker; - bool remove_rtracker = false; - - if (ftracker == nullptr) - { - DCE2_SmbRemoveRequestTracker(ssd, ssd->cur_rtracker); - ssd->cur_rtracker = nullptr; - return; - } - - if (DCE2_SsnFromClient(ssd->sd.wire_pkt)) - { - DebugMessage(DEBUG_DCE_SMB, "Raw data: Write Raw\n"); - DebugFormat(DEBUG_DCE_SMB, "Request Fid: 0x%04X\n", ftracker->fid_v1); - - if (nb_len > ssd->cur_rtracker->writeraw_remaining) - { - dce_alert(GID_DCE2, DCE2_SMB_TDCNT_LT_DSIZE, (dce2CommonStats*)&dce2_smb_stats); - - // If this happens, Windows never responds regardless of - // WriteThrough flag, so get rid of request tracker - remove_rtracker = true; - } - else if (!ssd->cur_rtracker->writeraw_writethrough) - { - // If WriteThrough flag was not set on initial request, a - // SMB_COM_WRITE_COMPLETE will not be sent so need to get - // rid of request tracker. - remove_rtracker = true; - } - else - { - ssd->cur_rtracker->writeraw_writethrough = false; - ssd->cur_rtracker->writeraw_remaining = 0; - } - } - else - { - DebugMessage(DEBUG_DCE_SMB, "Raw data: Read Raw\n"); - DebugFormat(DEBUG_DCE_SMB, "Response Fid: 0x%04X\n", ftracker->fid_v1); - - remove_rtracker = true; - } - - // Only one raw read/write allowed - ssd->pdu_state = DCE2_SMB_PDU_STATE__COMMAND; - - if (ftracker->is_ipc) - { - // Maximum possible fragment length is 16 bit - if (nb_len > UINT16_MAX) - nb_len = UINT16_MAX; - - DCE2_CoProcess(&ssd->sd, ftracker->fp_co_tracker, nb_ptr, (uint16_t)nb_len); - } - else - { - bool upload = DCE2_SsnFromClient(ssd->sd.wire_pkt) ? true : false; - DCE2_SmbProcessFileData(ssd, ftracker, nb_ptr, nb_len, upload); - } - - if (remove_rtracker) - { - DCE2_SmbRemoveRequestTracker(ssd, ssd->cur_rtracker); - ssd->cur_rtracker = nullptr; - } -} - -static void DCE2_SmbDataFree(DCE2_SmbSsnData* ssd) -{ - if (ssd == nullptr) - return; - - // FIXIT This tries to account for the situation where we never knew the file - // size and the TCP session was shutdown before an SMB_COM_CLOSE on the file. - // Possibly need to add callback to fileAPI since it may have already - // released it's resources. - //DCE2_SmbFinishFileAPI(ssd); - - if (ssd->uids != nullptr) - { - DCE2_ListDestroy(ssd->uids); - ssd->uids = nullptr; - } - - if (ssd->tids != nullptr) - { - DCE2_ListDestroy(ssd->tids); - ssd->tids = nullptr; - } - - DCE2_SmbCleanFileTracker(&ssd->ftracker); - if (ssd->ftrackers != nullptr) - { - DCE2_ListDestroy(ssd->ftrackers); - ssd->ftrackers = nullptr; - } - - DCE2_SmbCleanRequestTracker(&ssd->rtracker); - if (ssd->rtrackers != nullptr) - { - DCE2_QueueDestroy(ssd->rtrackers); - ssd->rtrackers = nullptr; - } - - if (ssd->cli_seg != nullptr) - { - DCE2_BufferDestroy(ssd->cli_seg); - ssd->cli_seg = nullptr; - } - - if (ssd->srv_seg != nullptr) - { - DCE2_BufferDestroy(ssd->srv_seg); - ssd->srv_seg = nullptr; - } - - if (ssd->smb2_requests != nullptr) - { - DCE2_Smb2CleanRequests(ssd->smb2_requests); - ssd->smb2_requests = nullptr; - } -} - -Dce2SmbFlowData::Dce2SmbFlowData() : FlowData(flow_id) -{ -} - -Dce2SmbFlowData::~Dce2SmbFlowData() -{ - DCE2_SmbDataFree(&dce2_smb_session); -} - -unsigned Dce2SmbFlowData::flow_id = 0; - -DCE2_SmbSsnData* get_dce2_smb_session_data(Flow* flow) -{ - Dce2SmbFlowData* fd = (Dce2SmbFlowData*)flow->get_flow_data(Dce2SmbFlowData::flow_id); - return fd ? &fd->dce2_smb_session : nullptr; -} - -static DCE2_SmbSsnData* set_new_dce2_smb_session(Packet* p) -{ - Dce2SmbFlowData* fd = new Dce2SmbFlowData; - memset(&fd->dce2_smb_session,0,sizeof(DCE2_SmbSsnData)); - p->flow->set_flow_data(fd); - return(&fd->dce2_smb_session); -} - -static DCE2_SmbSsnData* dce2_create_new_smb_session(Packet* p, dce2SmbProtoConf* config) -{ - DCE2_SmbSsnData* dce2_smb_sess = nullptr; - Profile profile(dce2_smb_pstat_new_session); - - DebugMessage(DEBUG_DCE_SMB, "DCE over SMB packet detected\n"); - DebugMessage(DEBUG_DCE_SMB, "Creating new session\n"); - - dce2_smb_sess = set_new_dce2_smb_session(p); - if ( dce2_smb_sess ) - { - dce2_smb_sess->dialect_index = DCE2_SENTINEL; - dce2_smb_sess->max_outstanding_requests = 10; // Until Negotiate/SessionSetupAndX - dce2_smb_sess->cli_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; - dce2_smb_sess->srv_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; - dce2_smb_sess->pdu_state = DCE2_SMB_PDU_STATE__COMMAND; - dce2_smb_sess->uid = DCE2_SENTINEL; - dce2_smb_sess->tid = DCE2_SENTINEL; - dce2_smb_sess->ftracker.fid_v1 = DCE2_SENTINEL; - dce2_smb_sess->rtracker.mid = DCE2_SENTINEL; - dce2_smb_sess->max_file_depth = FileService::get_max_file_depth(); - - DCE2_ResetRopts(&dce2_smb_sess->sd.ropts); - - dce2_smb_stats.smb_sessions++; - DebugFormat(DEBUG_DCE_SMB,"Created (%p)\n", (void*)dce2_smb_sess); - - dce2_smb_sess->sd.trans = DCE2_TRANS_TYPE__SMB; - dce2_smb_sess->sd.server_policy = config->common.policy; - dce2_smb_sess->sd.client_policy = DCE2_POLICY__WINXP; - dce2_smb_sess->sd.wire_pkt = p; - dce2_smb_sess->sd.config = (void*)config; - } - - return dce2_smb_sess; -} - -static DCE2_SmbSsnData* dce2_handle_smb_session(Packet* p, dce2SmbProtoConf* config) -{ - Profile profile(dce2_smb_pstat_session); - - DCE2_SmbSsnData* dce2_smb_sess = get_dce2_smb_session_data(p->flow); - - if (dce2_smb_sess == nullptr) - { - dce2_smb_sess = dce2_create_new_smb_session(p, config); - } - - DebugFormat(DEBUG_DCE_SMB, "Session pointer: %p\n", (void*)dce2_smb_sess); - - return dce2_smb_sess; -} - -/******************************************************************** - * Function: DCE2_NbssHdrChecks() - * - * Purpose: - * Does validation of the NetBIOS header. SMB will only run over - * the Session Message type. On port 139, there is always an - * initial Session Request / Session Positive/Negative response - * followed by the normal SMB conversation, i.e. Negotiate, - * SessionSetupAndX, etc. - * Side effects are potential alerts for anomolous behavior. - * - * Arguments: - * DCE2_SmbSsnData * - the session data structure. - * const NbssHdr * - pointer to the NetBIOS Session Service - * header structure. Size is already validated. - * - * Returns: - * DCE2_Ret - DCE2_RET__SUCCESS if all goes well and processing - * should continue. - * DCE2_RET__IGNORE if it's not something we need to - * look at. - * DCE2_RET__ERROR if an invalid NetBIOS Session - * Service type is found. - * - ********************************************************************/ -static DCE2_Ret DCE2_NbssHdrChecks(DCE2_SmbSsnData* ssd, const NbssHdr* nb_hdr) -{ - Packet* p = ssd->sd.wire_pkt; - bool is_seg_buf = DCE2_SmbIsSegBuffer(ssd, (uint8_t*)nb_hdr); - - DebugMessage(DEBUG_DCE_SMB, "NetBIOS Session Service type: "); - - switch (NbssType(nb_hdr)) - { - case NBSS_SESSION_TYPE__MESSAGE: - /* Only want to look at session messages */ - DebugMessage(DEBUG_DCE_SMB, "Session Message\n"); - - if (!DCE2_SmbIsRawData(ssd)) - { - uint32_t nb_len = NbssLen(nb_hdr); - - if (nb_len == 0) - return DCE2_RET__IGNORE; - - if (nb_len < sizeof(SmbNtHdr)) - { - DebugFormat(DEBUG_DCE_SMB, "NetBIOS SS len(%zu) < SMB header len(%zu).\n", - sizeof(SmbNtHdr), sizeof(NbssHdr) + nb_len); - - if (is_seg_buf) - DCE2_SmbSegAlert(ssd, DCE2_SMB_NB_LT_SMBHDR); - else - dce_alert(GID_DCE2, DCE2_SMB_NB_LT_SMBHDR, (dce2CommonStats*)&dce2_smb_stats); - - return DCE2_RET__IGNORE; - } - } - - return DCE2_RET__SUCCESS; - - case NBSS_SESSION_TYPE__REQUEST: - DebugMessage(DEBUG_DCE_SMB, "Session Request\n"); - if (DCE2_SsnFromServer(p)) - { - if (is_seg_buf) - DCE2_SmbSegAlert(ssd, DCE2_SMB_BAD_NBSS_TYPE); - else - dce_alert(GID_DCE2, DCE2_SMB_BAD_NBSS_TYPE, (dce2CommonStats*)&dce2_smb_stats); - } - - break; - - case NBSS_SESSION_TYPE__POS_RESPONSE: - case NBSS_SESSION_TYPE__NEG_RESPONSE: - case NBSS_SESSION_TYPE__RETARGET_RESPONSE: - if (DCE2_SsnFromClient(p)) - { - if (is_seg_buf) - DCE2_SmbSegAlert(ssd, DCE2_SMB_BAD_NBSS_TYPE); - else - dce_alert(GID_DCE2, DCE2_SMB_BAD_NBSS_TYPE, (dce2CommonStats*)&dce2_smb_stats); - } - - break; - - case NBSS_SESSION_TYPE__KEEP_ALIVE: - DebugMessage(DEBUG_DCE_SMB, "Session Keep Alive\n"); - break; - - default: - DebugFormat(DEBUG_DCE_SMB, - "Invalid Session Service type: 0x%02X\n", NbssType(nb_hdr)); - - if (is_seg_buf) - DCE2_SmbSegAlert(ssd, DCE2_SMB_BAD_NBSS_TYPE); - else - dce_alert(GID_DCE2, DCE2_SMB_BAD_NBSS_TYPE, (dce2CommonStats*)&dce2_smb_stats); - - return DCE2_RET__ERROR; - } - - return DCE2_RET__IGNORE; -} - - -// This is the main entry point for SMB1 processing. -static void DCE2_Smb1Process(DCE2_SmbSsnData* ssd) -{ - DebugMessage(DEBUG_DCE_SMB, "Processing SMB packet.\n"); - dce2_smb_stats.smb_pkts++; - - const Packet* p = ssd->sd.wire_pkt; - const uint8_t* data_ptr = p->data; - uint16_t data_len = p->dsize; - DCE2_Buffer** seg_buf = DCE2_SmbGetSegBuffer(ssd); - - /* Have to account for segmentation. Even though stream will give - * us larger chunks, we might end up in the middle of something */ - while (data_len > 0) - { - // We are ignoring an entire PDU or junk data so state should be NETBIOS_HEADER - // Note that it could be TCP segmented so ignore_bytes could be greater than - // the amount of data we have - uint32_t* ignore_bytes = DCE2_SmbGetIgnorePtr(ssd); - if (*ignore_bytes) - { - DebugFormat(DEBUG_DCE_SMB, "Ignoring %u bytes\n", *ignore_bytes); - - if (data_len <= *ignore_bytes) - { - *ignore_bytes -= data_len; - return; - } - else - { - /* ignore bytes is less than UINT16_MAX */ - DCE2_MOVE(data_ptr, data_len, (uint16_t)*ignore_bytes); - *ignore_bytes = 0; - } - } - - DCE2_SmbDataState* data_state = DCE2_SmbGetDataState(ssd); - DCE2_SmbRequestTracker* rtracker = nullptr; - switch (*data_state) - { - // This state is to verify it's a NetBIOS Session Message packet - // and to get the length of the SMB PDU. Also does the SMB junk - // data check. If it's not a Session Message the data isn't - // processed since it won't be carrying SMB. - case DCE2_SMB_DATA_STATE__NETBIOS_HEADER: - { - uint32_t data_need = sizeof(NbssHdr); - - // See if there is enough data to process the NetBIOS header - if (data_len < data_need) - { - DebugFormat(DEBUG_DCE_SMB, "Data len(%hu) < NetBIOS SS header(%u). " - "Queueing data.\n", data_len, data_need); - - if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, - data_len, sizeof(NbssHdr)) != DCE2_RET__SUCCESS) - { - DCE2_BufferEmpty(*seg_buf); - } - - return; - } - - // Set the NetBIOS header structure - NbssHdr* nb_hdr; - if (DCE2_BufferIsEmpty(*seg_buf)) - { - nb_hdr = (NbssHdr*)data_ptr; - } - else - { - // If data already buffered add the remainder for the - // size of the NetBIOS header - if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, - data_need, sizeof(NbssHdr)) != DCE2_RET__SUCCESS) - { - DCE2_BufferEmpty(*seg_buf); - return; - } - - nb_hdr = (NbssHdr*)DCE2_BufferData(*seg_buf); - } - - uint32_t nb_len = NbssLen(nb_hdr); - - DebugFormat(DEBUG_DCE_SMB, "NetBIOS PDU length: %u\n", nb_len); - - DCE2_Ret status = DCE2_NbssHdrChecks(ssd, nb_hdr); - if (status != DCE2_RET__SUCCESS) - { - DebugMessage(DEBUG_DCE_SMB, "Not a NetBIOS Session Message.\n"); - - if (status == DCE2_RET__IGNORE) - { - DebugMessage(DEBUG_DCE_SMB, "Valid NetBIOS header " - "type so ignoring NetBIOS length bytes.\n"); - *ignore_bytes = data_need + nb_len; - } - else // nb_ret == DCE2_RET__ERROR, i.e. invalid NetBIOS type - { - DebugMessage(DEBUG_DCE_SMB, "Not a valid NetBIOS " - "header type so trying to find \\xffSMB to " - "determine how many bytes to ignore.\n"); - *ignore_bytes = DCE2_IgnoreJunkData(data_ptr, data_len, data_need + nb_len); - } - - DCE2_BufferEmpty(*seg_buf); - dce2_smb_stats.smb_ignored_bytes += *ignore_bytes; - continue; - } - - if (!DCE2_BufferIsEmpty(*seg_buf)) - DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need); - - switch (ssd->pdu_state) - { - case DCE2_SMB_PDU_STATE__COMMAND: - *data_state = DCE2_SMB_DATA_STATE__SMB_HEADER; - break; - case DCE2_SMB_PDU_STATE__RAW_DATA: - *data_state = DCE2_SMB_DATA_STATE__NETBIOS_PDU; - // Continue here because of fall through below - continue; - default: - DebugFormat(DEBUG_DCE_SMB,"%s(%d) Invalid SMB PDU " - "state: %d\n", __FILE__, __LINE__, ssd->pdu_state); - return; - } - } - - // Fall through for DCE2_SMB_DATA_STATE__SMB_HEADER - // This is the normal progression without segmentation. - - // This state is to do validation checks on the SMB header and - // more importantly verify it's data that needs to be inspected. - // If the TID in the SMB header is not referring to the IPC share - // there won't be any DCE/RPC traffic associated with it. - case DCE2_SMB_DATA_STATE__SMB_HEADER: - { - uint32_t data_need = (sizeof(NbssHdr) + sizeof(SmbNtHdr)) - DCE2_BufferLength( - *seg_buf); - - // See if there is enough data to process the SMB header - if (data_len < data_need) - { - DebugFormat(DEBUG_DCE_SMB, "Data len (%hu) < " - "NetBIOS SS header + SMB header (%u). Queueing data.\n", - data_len, data_need); - - if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, data_len, - sizeof(NbssHdr) + sizeof(SmbNtHdr)) != DCE2_RET__SUCCESS) - { - DCE2_BufferEmpty(*seg_buf); - *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; - } - - return; - } - - // Set the SMB header structure - SmbNtHdr* smb_hdr; - if (DCE2_BufferIsEmpty(*seg_buf)) - { - smb_hdr = (SmbNtHdr*)(data_ptr + sizeof(NbssHdr)); - } - else - { - if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, data_need, - sizeof(NbssHdr) + sizeof(SmbNtHdr)) != DCE2_RET__SUCCESS) - { - DCE2_BufferEmpty(*seg_buf); - *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; - return; - } - - smb_hdr = (SmbNtHdr*)(DCE2_BufferData(*seg_buf) + sizeof(NbssHdr)); - } - - if (SmbId(smb_hdr) == DCE2_SMB2_ID) - { - ssd->sd.flags |= DCE2_SSN_FLAG__SMB2; - if (!DCE2_GcIsLegacyMode((dce2SmbProtoConf*)ssd->sd.config)) - { - DCE2_Smb2InitFileTracker(&(ssd->ftracker), false, 0); - DCE2_Smb2Process(ssd); - } - return; - } - - // See if this is something we need to inspect - rtracker = DCE2_SmbInspect(ssd, smb_hdr); - if (rtracker == nullptr) - { - DebugMessage(DEBUG_DCE_SMB, "Not inspecting SMB packet.\n"); - - if (DCE2_BufferIsEmpty(*seg_buf)) - { - *ignore_bytes = sizeof(NbssHdr) + NbssLen((NbssHdr*)data_ptr); - } - else - { - *ignore_bytes = (NbssLen((NbssHdr*)DCE2_BufferData(*seg_buf)) - - sizeof(SmbNtHdr)) + data_need; - DCE2_BufferEmpty(*seg_buf); - } - - *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; - dce2_smb_stats.smb_ignored_bytes += *ignore_bytes; - continue; - } - - // Check the SMB header for anomolies - if (DCE2_SmbHdrChecks(ssd, smb_hdr) != DCE2_RET__SUCCESS) - { - DebugMessage(DEBUG_DCE_SMB, "Bad SMB header.\n"); - - if (DCE2_BufferIsEmpty(*seg_buf)) - { - *ignore_bytes = sizeof(NbssHdr) + NbssLen((NbssHdr*)data_ptr); - } - else - { - *ignore_bytes = (NbssLen((NbssHdr*)DCE2_BufferData(*seg_buf)) - - sizeof(SmbNtHdr)) + data_need; - DCE2_BufferEmpty(*seg_buf); - } - - *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; - - dce2_smb_stats.smb_ignored_bytes += *ignore_bytes; - continue; - } - - if (!DCE2_BufferIsEmpty(*seg_buf)) - DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need); - - *data_state = DCE2_SMB_DATA_STATE__NETBIOS_PDU; - } - - // Fall through - - // This state ensures that we have the entire PDU before continuing - // to process. - case DCE2_SMB_DATA_STATE__NETBIOS_PDU: - { - uint32_t nb_len; - uint32_t data_need; - - if (DCE2_BufferIsEmpty(*seg_buf)) - { - nb_len = NbssLen((NbssHdr*)data_ptr); - data_need = sizeof(NbssHdr) + nb_len; - } - else - { - nb_len = NbssLen((NbssHdr*)DCE2_BufferData(*seg_buf)); - data_need = (sizeof(NbssHdr) + nb_len) - DCE2_BufferLength(*seg_buf); - } - - /* It's something we want to inspect so make sure we have the full NBSS packet */ - if (data_len < data_need) - { - DebugFormat(DEBUG_DCE_SMB, "Data len(%hu) < " - "NetBIOS SS header + NetBIOS len(%zu). " - "Queueing data.\n", data_len, sizeof(NbssHdr) + nb_len); - - if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, data_len, - sizeof(NbssHdr) + nb_len) != DCE2_RET__SUCCESS) - { - DCE2_BufferEmpty(*seg_buf); - *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; - } - - return; - } - - // data_len >= data_need which means data_need <= UINT16_MAX - // So casts below of data_need to uint16_t are okay. - - *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; - - const uint8_t* nb_ptr; - if (DCE2_BufferIsEmpty(*seg_buf)) - { - nb_ptr = data_ptr; - nb_len = data_need; - DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need); - } - else - { - if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, data_need, - sizeof(NbssHdr) + nb_len) != DCE2_RET__SUCCESS) - { - DCE2_BufferEmpty(*seg_buf); - DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need); - continue; - } - - DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need); - - nb_ptr = DCE2_BufferData(*seg_buf); - nb_len = DCE2_BufferLength(*seg_buf); - - // Get reassembled packet - Packet* rpkt = DCE2_SmbGetRpkt(ssd, &nb_ptr, &nb_len, - DCE2_RPKT_TYPE__SMB_SEG); - if (rpkt == nullptr) - { - DCE2_BufferEmpty(*seg_buf); - continue; - } - - nb_ptr = DCE2_BufferData(*seg_buf); - nb_len = DCE2_BufferLength(*seg_buf); - - DebugFormat(DEBUG_DCE_SMB, - "Segmentation buffer: len: %u, size: %u\n", - DCE2_BufferLength(*seg_buf), DCE2_BufferSize(*seg_buf)); - - if (DCE2_SsnFromClient(ssd->sd.wire_pkt)) - dce2_smb_stats.smb_cli_seg_reassembled++; - else - dce2_smb_stats.smb_srv_seg_reassembled++; - - DebugMessage(DEBUG_DCE_SMB, "TCP reassembled SMB PDU\n"); - DCE2_PrintPktData(rpkt->data, rpkt->dsize); - } - - switch (ssd->pdu_state) - { - case DCE2_SMB_PDU_STATE__COMMAND: - { - SmbNtHdr* smb_hdr = (SmbNtHdr*)(nb_ptr + sizeof(NbssHdr)); - DCE2_MOVE(nb_ptr, nb_len, (sizeof(NbssHdr) + sizeof(SmbNtHdr))); - ssd->cur_rtracker = (rtracker != nullptr) - ? rtracker : DCE2_SmbFindRequestTracker(ssd, smb_hdr); - if (ssd->cur_rtracker != nullptr) - DCE2_SmbProcessCommand(ssd, smb_hdr, nb_ptr, nb_len); - break; - } - - case DCE2_SMB_PDU_STATE__RAW_DATA: - DCE2_MOVE(nb_ptr, nb_len, sizeof(NbssHdr)); - if (ssd->cur_rtracker != nullptr) - DCE2_SmbProcessRawData(ssd, nb_ptr, nb_len); - // Only one raw read or write - ssd->pdu_state = DCE2_SMB_PDU_STATE__COMMAND; - break; - default: - DebugFormat(DEBUG_DCE_SMB, "%s(%d) Invalid SMB PDU " - "state: %d\n", __FILE__, __LINE__, ssd->pdu_state); - return; - } - - if (!DCE2_BufferIsEmpty(*seg_buf)) - { - DCE2_SmbReturnRpkt(ssd); - DCE2_BufferDestroy(*seg_buf); - *seg_buf = nullptr; - } - - break; - } - - default: - DebugFormat(DEBUG_DCE_SMB, "%s(%d) Invalid SMB Data " - "state: %d\n", __FILE__, __LINE__, *data_state); - return; - } - } -} - -// This is the main entry point for SMB processing -static void DCE2_SmbProcess(DCE2_SmbSsnData* ssd) -{ - if (DCE2_GcIsLegacyMode((dce2SmbProtoConf*)ssd->sd.config)) - { - DCE2_Smb1Process(ssd); - return; - } - - Packet* p = ssd->sd.wire_pkt; - DCE2_SmbVersion smb_version = DCE2_Smb2Version(p); - if (smb_version == DCE2_SMB_VERISON_1) - { - if ((ssd->sd.flags & DCE2_SSN_FLAG__SMB2)) - { - DebugMessage(DEBUG_DCE_SMB, "SMB1 packet detected!\n"); - ssd->sd.flags &= ~DCE2_SSN_FLAG__SMB2; - DCE2_SmbCleanFileTracker(&(ssd->ftracker)); - ssd->ftracker.is_smb2 = false; - } - } - else if (smb_version == DCE2_SMB_VERISON_2) - { - if (!(ssd->sd.flags & DCE2_SSN_FLAG__SMB2)) - { - DebugMessage(DEBUG_DCE_SMB, "SMB2 packet detected!\n"); - DCE2_SmbCleanFileTracker(&(ssd->ftracker)); - DCE2_Smb2InitFileTracker(&(ssd->ftracker), 0, 0); - ssd->sd.flags |= DCE2_SSN_FLAG__SMB2; - } - } - - if (ssd->sd.flags & DCE2_SSN_FLAG__SMB2) - DCE2_Smb2Process(ssd); - else - DCE2_Smb1Process(ssd); -} - -/******************************************************************** - * Function: DCE2_SmbInitGlobals() - * - * Purpose: - * Initializes global variables for SMB processing. - * Sets up the functions and valid word and byte counts for SMB - * commands. - * Sets up AndX chain mappings and valid command chaining for - * supported policies. - * - * Arguments: None - * - * Returns: None - * - ********************************************************************/ -static void DCE2_SmbInitGlobals() -{ - memset(&smb_wcts, 0, sizeof(smb_wcts)); - memset(&smb_bccs, 0, sizeof(smb_bccs)); - - // Sets up the function to call for the command and valid word and byte - // counts for the command. Ensuring valid word and byte counts is very - // important to processing the command as it will assume the command is - // legitimate and can access data that is acutally there. Note that - // commands with multiple word counts indicate a different command - // structure, however most, if not all just have an extended version - // of the structure for which the extended part isn't used. If the - // extended part of a command structure needs to be used, be sure to - // check the word count in the command function before accessing data - // in the extended version of the command structure. - for (int com = 0; com < SMB_MAX_NUM_COMS; com++) - { - switch (com) - { - case SMB_COM_OPEN: - smb_com_funcs[com] = DCE2_SmbOpen; - - smb_deprecated_coms[com] = true; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 2); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 7); - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); - break; - case SMB_COM_CREATE: - smb_com_funcs[com] = DCE2_SmbCreate; - - smb_deprecated_coms[com] = true; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 3); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); - break; - case SMB_COM_CLOSE: - smb_com_funcs[com] = DCE2_SmbClose; - smb_deprecated_coms[com] = false; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 3); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0); - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); - break; - case SMB_COM_RENAME: - smb_com_funcs[com] = DCE2_SmbRename; - smb_deprecated_coms[com] = false; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 1); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0); - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 4, UINT16_MAX); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); - break; - case SMB_COM_READ: - smb_com_funcs[com] = DCE2_SmbRead; - smb_deprecated_coms[com] = true; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 5); - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 3, UINT16_MAX); - break; - case SMB_COM_WRITE: - smb_com_funcs[com] = DCE2_SmbWrite; - smb_deprecated_coms[com] = true; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 3, UINT16_MAX); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); - break; - case SMB_COM_CREATE_NEW: - smb_com_funcs[com] = DCE2_SmbCreateNew; - smb_deprecated_coms[com] = true; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 3); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); - break; - case SMB_COM_LOCK_AND_READ: - smb_com_funcs[com] = DCE2_SmbLockAndRead; - smb_deprecated_coms[com] = true; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 5); - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 3, UINT16_MAX); - break; - case SMB_COM_WRITE_AND_UNLOCK: - smb_com_funcs[com] = DCE2_SmbWriteAndUnlock; - smb_deprecated_coms[com] = true; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 3, UINT16_MAX); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); - break; - case SMB_COM_READ_RAW: - smb_com_funcs[com] = DCE2_SmbReadRaw; - smb_deprecated_coms[com] = true; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 8); - // With optional OffsetHigh - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 10); - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0); - // Response is raw data, i.e. without SMB - break; - case SMB_COM_WRITE_RAW: - smb_com_funcs[com] = DCE2_SmbWriteRaw; - smb_deprecated_coms[com] = true; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12); - // With optional OffsetHigh - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 14); - // Interim server response - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); - break; - case SMB_COM_WRITE_COMPLETE: - // Final server response to SMB_COM_WRITE_RAW - smb_com_funcs[com] = DCE2_SmbWriteComplete; - smb_deprecated_coms[com] = true; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); - break; - case SMB_COM_TRANSACTION: - smb_com_funcs[com] = DCE2_SmbTransaction; - smb_deprecated_coms[com] = false; - smb_unusual_coms[com] = false; - - // Word count depends on setup count - //for (i = 14; i < 256; i++) - // DCE2_SmbSetValidWordCount(com, SMB_TYPE__REQUEST, i); - // In reality, all subcommands of SMB_COM_TRANSACTION requests - // have a setup count of 2 words. - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 16); - - // \PIPE\LANMAN - // Not something the preprocessor is looking at as it - // doesn't carry DCE/RPC but don't want to false positive - // on the preprocessor event. - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 14); - - // Word count depends on setup count - //for (i = 10; i < 256; i++) - // DCE2_SmbSetValidWordCount(com, SMB_TYPE__RESPONSE, i); - // In reality, all subcommands of SMB_COM_TRANSACTION responses - // have a setup count of 0 words. - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 10); - - // Interim server response - // When client sends an incomplete transaction and needs to - // send TransactionSecondary requests to complete request. - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0); - - // Exception will be made for Interim responses when - // byte count is checked. - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); - break; - case SMB_COM_TRANSACTION_SECONDARY: - smb_com_funcs[com] = DCE2_SmbTransactionSecondary; - smb_deprecated_coms[com] = false; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 8); - // Response is an SMB_COM_TRANSACTION - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); - break; - case SMB_COM_WRITE_AND_CLOSE: - smb_com_funcs[com] = DCE2_SmbWriteAndClose; - smb_deprecated_coms[com] = true; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 6); - // For some reason MS-CIFS specifies a version of this command - // with 6 extra words (12 bytes) of reserved, i.e. useless data. - // Maybe had intentions of extending and defining the data at - // some point, but there is no documentation that I could find - // that does. - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 1, UINT16_MAX); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); - break; - case SMB_COM_OPEN_ANDX: - smb_com_funcs[com] = DCE2_SmbOpenAndX; - smb_deprecated_coms[com] = true; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 15); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 15); - // Extended response - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 19); - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX); - // MS-SMB says that Windows 2000, XP and Vista set this to - // some arbitrary value that is ignored on receipt. - //DCE2_SmbSetValidByteCount(com, SMB_TYPE__RESPONSE, 0, 0); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); - break; - case SMB_COM_READ_ANDX: - smb_com_funcs[com] = DCE2_SmbReadAndX; - smb_deprecated_coms[com] = false; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 10); - // With optional OffsetHigh - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 12); - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); - break; - case SMB_COM_WRITE_ANDX: - smb_com_funcs[com] = DCE2_SmbWriteAndX; - smb_deprecated_coms[com] = false; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12); - // With optional OffsetHigh - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 14); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 6); - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 1, UINT16_MAX); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); - break; - case SMB_COM_TRANSACTION2: - smb_com_funcs[com] = DCE2_SmbTransaction2; - smb_deprecated_coms[com] = false; - smb_unusual_coms[com] = false; - - // Word count depends on setup count - //for (i = 14; i < 256; i++) - // DCE2_SmbSetValidWordCount(com, SMB_TYPE__REQUEST, i); - // In reality, all subcommands of SMB_COM_TRANSACTION2 - // requests have a setup count of 1 word. - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 15); - - // Word count depends on setup count - //for (i = 10; i < 256; i++) - // DCE2_SmbSetValidWordCount(com, SMB_TYPE__RESPONSE, i); - // In reality, all subcommands of SMB_COM_TRANSACTION2 - // responses have a setup count of 0 or 1 word. - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 10); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 11); - - // Interim server response - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0); - - // Exception will be made for Interim responses when - // byte count is checked. - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); - break; - case SMB_COM_TRANSACTION2_SECONDARY: - smb_com_funcs[com] = DCE2_SmbTransaction2Secondary; - smb_deprecated_coms[com] = false; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 9); - // Response is an SMB_COM_TRANSACTION2 - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); - break; - case SMB_COM_TREE_CONNECT: - smb_com_funcs[com] = DCE2_SmbTreeConnect; - smb_deprecated_coms[com] = true; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 0); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 2); - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 6, UINT16_MAX); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); - break; - case SMB_COM_TREE_DISCONNECT: - smb_com_funcs[com] = DCE2_SmbTreeDisconnect; - smb_deprecated_coms[com] = false; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 0); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0); - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); - break; - case SMB_COM_NEGOTIATE: - smb_com_funcs[com] = DCE2_SmbNegotiate; - smb_deprecated_coms[com] = false; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 0); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 13); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 17); - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX); - // This can vary depending on dialect so just set wide. - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); - break; - case SMB_COM_SESSION_SETUP_ANDX: - smb_com_funcs[com] = DCE2_SmbSessionSetupAndX; - smb_deprecated_coms[com] = false; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 10); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 13); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 3); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 4); - - // These can vary so just set wide. - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); - break; - case SMB_COM_LOGOFF_ANDX: - smb_com_funcs[com] = DCE2_SmbLogoffAndX; - smb_deprecated_coms[com] = false; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 2); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 2); - // Windows responds to a LogoffAndX => SessionSetupAndX with just a - // LogoffAndX and with the word count field containing 3, but only - // has 2 words - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 3); - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); - break; - case SMB_COM_TREE_CONNECT_ANDX: - smb_com_funcs[com] = DCE2_SmbTreeConnectAndX; - smb_deprecated_coms[com] = false; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 4); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 2); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 3); - // Extended response - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 7); - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 3, UINT16_MAX); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 2, UINT16_MAX); - break; - case SMB_COM_NT_TRANSACT: - smb_com_funcs[com] = DCE2_SmbNtTransact; - smb_deprecated_coms[com] = false; - smb_unusual_coms[com] = false; - - // Word count depends on setup count - // In reality, all subcommands of SMB_COM_NT_TRANSACT - // requests have a setup count of 0 or 4 words. - //for (i = 19; i < 256; i++) - // DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, i); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 19); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 23); - - // Word count depends on setup count - // In reality, all subcommands of SMB_COM_NT_TRANSACT - // responses have a setup count of 0 or 1 word. - //for (i = 18; i < 256; i++) - // DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, i); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 18); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 19); - - // Interim server response - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0); - - // Exception will be made for Interim responses when - // byte count is checked. - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); - break; - case SMB_COM_NT_TRANSACT_SECONDARY: - smb_com_funcs[com] = DCE2_SmbNtTransactSecondary; - smb_deprecated_coms[com] = false; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 18); - // Response is an SMB_COM_NT_TRANSACT - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); - break; - case SMB_COM_NT_CREATE_ANDX: - smb_com_funcs[com] = DCE2_SmbNtCreateAndX; - smb_deprecated_coms[com] = false; - smb_unusual_coms[com] = false; - - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 24); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 34); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 26); - // Extended response - though there are actually 50 words - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 42); - - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX); - // MS-SMB indicates that this field should be 0 but may be - // sent uninitialized so basically ignore it. - //DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); - break; - default: - smb_com_funcs[com] = nullptr; - smb_deprecated_coms[com] = false; - smb_unusual_coms[com] = false; - // Just set to all valid since the specific command won't - // be processed. Don't want to false positive on these. - for (int i = 0; i < 256; i++) - { - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, (uint8_t)i); - DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, (uint8_t)i); - } - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); - DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); - break; - } - } - - // Maps commands for use in quickly determining if a command - // is chainable and what command it is. - for (int com = 0; com < SMB_MAX_NUM_COMS; com++) - { - switch (com) - { - case SMB_COM_SESSION_SETUP_ANDX: - smb_chain_map[com] = SMB_ANDX_COM__SESSION_SETUP_ANDX; - break; - case SMB_COM_LOGOFF_ANDX: - smb_chain_map[com] = SMB_ANDX_COM__LOGOFF_ANDX; - break; - case SMB_COM_TREE_CONNECT_ANDX: - smb_chain_map[com] = SMB_ANDX_COM__TREE_CONNECT_ANDX; - break; - case SMB_COM_OPEN_ANDX: - smb_chain_map[com] = SMB_ANDX_COM__OPEN_ANDX; - break; - case SMB_COM_NT_CREATE_ANDX: - smb_chain_map[com] = SMB_ANDX_COM__NT_CREATE_ANDX; - break; - case SMB_COM_WRITE_ANDX: - smb_chain_map[com] = SMB_ANDX_COM__WRITE_ANDX; - break; - case SMB_COM_READ_ANDX: - smb_chain_map[com] = SMB_ANDX_COM__READ_ANDX; - break; - default: - smb_chain_map[com] = SMB_ANDX_COM__NONE; - break; - } - } - - // Sets up the valid command chaining combinations per policy - for (int policy = 0; policy < DCE2_POLICY__MAX; policy++) - { - for (int andx = SMB_ANDX_COM__NONE; andx < SMB_ANDX_COM__MAX; andx++) - { - /* com is the chained command or com2 */ - for (int com = 0; com < SMB_MAX_NUM_COMS; com++) - { - DCE2_SmbComFunc com_func = nullptr; - - switch (policy) - { - case DCE2_POLICY__WIN2000: - case DCE2_POLICY__WINXP: - case DCE2_POLICY__WINVISTA: - case DCE2_POLICY__WIN2003: - case DCE2_POLICY__WIN2008: - case DCE2_POLICY__WIN7: - switch (andx) - { - case SMB_ANDX_COM__SESSION_SETUP_ANDX: - switch (com) - { - case SMB_COM_TREE_CONNECT_ANDX: - case SMB_COM_OPEN: - case SMB_COM_OPEN_ANDX: - case SMB_COM_CREATE: - case SMB_COM_CREATE_NEW: - com_func = smb_com_funcs[com]; - break; - case SMB_COM_TRANSACTION: - if (policy == DCE2_POLICY__WIN2000) - com_func = smb_com_funcs[com]; - break; - default: - break; - } - break; - case SMB_ANDX_COM__LOGOFF_ANDX: - switch (com) - { - case SMB_COM_SESSION_SETUP_ANDX: - case SMB_COM_TREE_CONNECT_ANDX: // Only for responses - com_func = smb_com_funcs[com]; - break; - default: - break; - } - break; - case SMB_ANDX_COM__TREE_CONNECT_ANDX: - switch (com) - { - case SMB_COM_OPEN: - case SMB_COM_CREATE: - case SMB_COM_CREATE_NEW: - com_func = smb_com_funcs[com]; - break; - case SMB_COM_TRANSACTION: - if (policy == DCE2_POLICY__WIN2000) - com_func = smb_com_funcs[com]; - break; - default: - break; - } - break; - case SMB_ANDX_COM__OPEN_ANDX: - break; - case SMB_ANDX_COM__NT_CREATE_ANDX: - switch (com) - { - case SMB_COM_READ_ANDX: // Only for normal files - com_func = smb_com_funcs[com]; - break; - default: - break; - } - break; - case SMB_ANDX_COM__WRITE_ANDX: - switch (com) - { - case SMB_COM_CLOSE: - case SMB_COM_WRITE_ANDX: - case SMB_COM_READ: - case SMB_COM_READ_ANDX: - com_func = smb_com_funcs[com]; - break; - default: - break; - } - break; - case SMB_ANDX_COM__READ_ANDX: - break; - default: - break; - } - break; - case DCE2_POLICY__SAMBA: - case DCE2_POLICY__SAMBA_3_0_37: - case DCE2_POLICY__SAMBA_3_0_22: - case DCE2_POLICY__SAMBA_3_0_20: - switch (andx) - { - case SMB_ANDX_COM__SESSION_SETUP_ANDX: - switch (com) - { - case SMB_COM_LOGOFF_ANDX: - case SMB_COM_TREE_CONNECT: - case SMB_COM_TREE_CONNECT_ANDX: - case SMB_COM_TREE_DISCONNECT: - case SMB_COM_OPEN_ANDX: - case SMB_COM_NT_CREATE_ANDX: - case SMB_COM_CLOSE: - case SMB_COM_READ_ANDX: - com_func = smb_com_funcs[com]; - break; - case SMB_COM_WRITE: - if ((policy == DCE2_POLICY__SAMBA_3_0_22) - || (policy == DCE2_POLICY__SAMBA_3_0_20)) - com_func = smb_com_funcs[com]; - break; - default: - break; - } - break; - case SMB_ANDX_COM__LOGOFF_ANDX: - switch (com) - { - case SMB_COM_SESSION_SETUP_ANDX: - case SMB_COM_TREE_DISCONNECT: - com_func = smb_com_funcs[com]; - break; - default: - break; - } - break; - case SMB_ANDX_COM__TREE_CONNECT_ANDX: - switch (com) - { - case SMB_COM_SESSION_SETUP_ANDX: - case SMB_COM_LOGOFF_ANDX: - case SMB_COM_TREE_DISCONNECT: - case SMB_COM_OPEN_ANDX: - case SMB_COM_NT_CREATE_ANDX: - case SMB_COM_CLOSE: - case SMB_COM_WRITE: - case SMB_COM_READ_ANDX: - com_func = smb_com_funcs[com]; - break; - default: - break; - } - break; - case SMB_ANDX_COM__OPEN_ANDX: - switch (com) - { - case SMB_COM_SESSION_SETUP_ANDX: - case SMB_COM_LOGOFF_ANDX: - case SMB_COM_TREE_CONNECT: - case SMB_COM_TREE_CONNECT_ANDX: - case SMB_COM_TREE_DISCONNECT: - case SMB_COM_OPEN_ANDX: - case SMB_COM_NT_CREATE_ANDX: - case SMB_COM_CLOSE: - case SMB_COM_WRITE: - case SMB_COM_READ_ANDX: - com_func = smb_com_funcs[com]; - break; - default: - break; - } - break; - case SMB_ANDX_COM__NT_CREATE_ANDX: - switch (com) - { - case SMB_COM_SESSION_SETUP_ANDX: - case SMB_COM_TREE_CONNECT: - case SMB_COM_TREE_CONNECT_ANDX: - case SMB_COM_OPEN_ANDX: - case SMB_COM_NT_CREATE_ANDX: - case SMB_COM_WRITE: - case SMB_COM_READ_ANDX: - com_func = smb_com_funcs[com]; - break; - case SMB_COM_LOGOFF_ANDX: - case SMB_COM_TREE_DISCONNECT: - case SMB_COM_CLOSE: - if ((policy == DCE2_POLICY__SAMBA) - || (policy == DCE2_POLICY__SAMBA_3_0_37)) - com_func = smb_com_funcs[com]; - break; - default: - break; - } - break; - case SMB_ANDX_COM__WRITE_ANDX: - switch (com) - { - case SMB_COM_SESSION_SETUP_ANDX: - case SMB_COM_LOGOFF_ANDX: - case SMB_COM_TREE_CONNECT: - case SMB_COM_TREE_CONNECT_ANDX: - case SMB_COM_OPEN_ANDX: - case SMB_COM_NT_CREATE_ANDX: - case SMB_COM_CLOSE: - case SMB_COM_WRITE: - case SMB_COM_READ_ANDX: - case SMB_COM_WRITE_ANDX: - com_func = smb_com_funcs[com]; - break; - default: - break; - } - break; - case SMB_ANDX_COM__READ_ANDX: - switch (com) - { - case SMB_COM_SESSION_SETUP_ANDX: - case SMB_COM_WRITE: - com_func = smb_com_funcs[com]; - break; - case SMB_COM_LOGOFF_ANDX: - case SMB_COM_TREE_CONNECT: - case SMB_COM_TREE_CONNECT_ANDX: - case SMB_COM_TREE_DISCONNECT: - case SMB_COM_OPEN_ANDX: - case SMB_COM_NT_CREATE_ANDX: - case SMB_COM_CLOSE: - case SMB_COM_READ_ANDX: - if ((policy == DCE2_POLICY__SAMBA) - || (policy == DCE2_POLICY__SAMBA_3_0_37)) - com_func = smb_com_funcs[com]; - break; - default: - break; - } - break; - default: - break; - } - break; - default: - break; - } - - smb_chain_funcs[policy][andx][com] = com_func; - } - } - } -} +const char* get_smb_com_string(uint8_t b) +{ return smb_com_strings[b]; } +#endif //------------------------------------------------------------------------- // class stuff diff --git a/src/service_inspectors/dce_rpc/dce_smb.h b/src/service_inspectors/dce_rpc/dce_smb.h index beaca6bf1..9947aef6a 100644 --- a/src/service_inspectors/dce_rpc/dce_smb.h +++ b/src/service_inspectors/dce_rpc/dce_smb.h @@ -16,7 +16,7 @@ // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. //-------------------------------------------------------------------------- -//dce_smb.h author Rashmi Pitre +// dce_smb.h author Rashmi Pitre // based on work by Todd Wease #ifndef DCE_SMB_H @@ -27,6 +27,8 @@ #include "profiler/profiler_defs.h" #include "dce_co.h" +#include "smb_common.h" +#include "smb_message.h" #define DCE2_SMB_NAME "dce_smb" #define DCE2_SMB_HELP "dce over smb inspection" @@ -129,44 +131,6 @@ #define DCE2_SMB_BAD_NEXT_COMMAND_OFFSET_STR \ "SMB - Next command specified in SMB2 header is beyond payload boundary" -#define SMB_MAX_NUM_COMS 256 - -#define SMB_FILE_TYPE_DISK 0x0000 -#define SMB_FILE_TYPE_BYTE_MODE_PIPE 0x0001 -#define SMB_FILE_TYPE_MESSAGE_MODE_PIPE 0x0002 -#define SMB_FILE_TYPE_PRINTER 0x0003 -#define SMB_FILE_TYPE_COMMON_DEVICE 0x0004 - -#define SMB_FILE_ATTRIBUTE_NORMAL 0x0000 -#define SMB_FILE_ATTRIBUTE_READONLY 0x0001 -#define SMB_FILE_ATTRIBUTE_HIDDEN 0x0002 -#define SMB_FILE_ATTRIBUTE_SYSTEM 0x0004 -#define SMB_FILE_ATTRIBUTE_VOLUME 0x0008 -#define SMB_FILE_ATTRIBUTE_DIRECTORY 0x0010 -#define SMB_FILE_ATTRIBUTE_ARCHIVE 0x0020 -#define SMB_SEARCH_ATTRIBUTE_READONLY 0x0100 -#define SMB_SEARCH_ATTRIBUTE_HIDDEN 0x0200 -#define SMB_SEARCH_ATTRIBUTE_SYSTEM 0x0400 -#define SMB_SEARCH_ATTRIBUTE_DIRECTORY 0x1000 -#define SMB_SEARCH_ATTRIBUTE_ARCHIVE 0x2000 -#define SMB_FILE_ATTRIBUTE_OTHER 0xC8C0 // Reserved - -#define SMB_EXT_FILE_ATTR_READONLY 0x00000001 -#define SMB_EXT_FILE_ATTR_HIDDEN 0x00000002 -#define SMB_EXT_FILE_ATTR_SYSTEM 0x00000004 -#define SMB_EXT_FILE_ATTR_DIRECTORY 0x00000010 -#define SMB_EXT_FILE_ATTR_ARCHIVE 0x00000020 -#define SMB_EXT_FILE_ATTR_NORMAL 0x00000080 -#define SMB_EXT_FILE_ATTR_TEMPORARY 0x00000100 -#define SMB_EXT_FILE_ATTR_COMPRESSED 0x00000800 -#define SMB_EXT_FILE_POSIX_SEMANTICS 0x01000000 -#define SMB_EXT_FILE_BACKUP_SEMANTICS 0x02000000 -#define SMB_EXT_FILE_DELETE_ON_CLOSE 0x04000000 -#define SMB_EXT_FILE_SEQUENTIAL_SCAN 0x08000000 -#define SMB_EXT_FILE_RANDOM_ACCESS 0x10000000 -#define SMB_EXT_FILE_NO_BUFFERING 0x20000000 -#define SMB_EXT_FILE_WRITE_THROUGH 0x80000000 - struct dce2SmbStats { PegCount events; @@ -247,178 +211,6 @@ extern THREAD_LOCAL ProfileStats dce2_smb_pstat_smb_file_api; extern THREAD_LOCAL ProfileStats dce2_smb_pstat_smb_fingerprint; extern THREAD_LOCAL ProfileStats dce2_smb_pstat_smb_negotiate; -#define NBSS_SESSION_TYPE__MESSAGE 0x00 -#define NBSS_SESSION_TYPE__REQUEST 0x81 -#define NBSS_SESSION_TYPE__POS_RESPONSE 0x82 -#define NBSS_SESSION_TYPE__NEG_RESPONSE 0x83 -#define NBSS_SESSION_TYPE__RETARGET_RESPONSE 0x84 -#define NBSS_SESSION_TYPE__KEEP_ALIVE 0x85 - -#define DCE2_SMB_ID 0xff534d42 /* \xffSMB */ -#define DCE2_SMB2_ID 0xfe534d42 /* \xfeSMB */ - -// MS-FSCC Section 2.1.5 - Pathname -#define DCE2_SMB_MAX_PATH_LEN 32760 -#define DCE2_SMB_MAX_COMP_LEN 255 - -/* SMB command codes */ -#define SMB_COM_CREATE_DIRECTORY 0x00 -#define SMB_COM_DELETE_DIRECTORY 0x01 -#define SMB_COM_OPEN 0x02 -#define SMB_COM_CREATE 0x03 -#define SMB_COM_CLOSE 0x04 -#define SMB_COM_FLUSH 0x05 -#define SMB_COM_DELETE 0x06 -#define SMB_COM_RENAME 0x07 -#define SMB_COM_QUERY_INFORMATION 0x08 -#define SMB_COM_SET_INFORMATION 0x09 -#define SMB_COM_READ 0x0A -#define SMB_COM_WRITE 0x0B -#define SMB_COM_LOCK_BYTE_RANGE 0x0C -#define SMB_COM_UNLOCK_BYTE_RANGE 0x0D -#define SMB_COM_CREATE_TEMPORARY 0x0E -#define SMB_COM_CREATE_NEW 0x0F -#define SMB_COM_CHECK_DIRECTORY 0x10 -#define SMB_COM_PROCESS_EXIT 0x11 -#define SMB_COM_SEEK 0x12 -#define SMB_COM_LOCK_AND_READ 0x13 -#define SMB_COM_WRITE_AND_UNLOCK 0x14 -#define SMB_COM_READ_RAW 0x1A -#define SMB_COM_READ_MPX 0x1B -#define SMB_COM_READ_MPX_SECONDARY 0x1C -#define SMB_COM_WRITE_RAW 0x1D -#define SMB_COM_WRITE_MPX 0x1E -#define SMB_COM_WRITE_MPX_SECONDARY 0x1F -#define SMB_COM_WRITE_COMPLETE 0x20 -#define SMB_COM_QUERY_SERVER 0x21 -#define SMB_COM_SET_INFORMATION2 0x22 -#define SMB_COM_QUERY_INFORMATION2 0x23 -#define SMB_COM_LOCKING_ANDX 0x24 -#define SMB_COM_TRANSACTION 0x25 -#define SMB_COM_TRANSACTION_SECONDARY 0x26 -#define SMB_COM_IOCTL 0x27 -#define SMB_COM_IOCTL_SECONDARY 0x28 -#define SMB_COM_COPY 0x29 -#define SMB_COM_MOVE 0x2A -#define SMB_COM_ECHO 0x2B -#define SMB_COM_WRITE_AND_CLOSE 0x2C -#define SMB_COM_OPEN_ANDX 0x2D -#define SMB_COM_READ_ANDX 0x2E -#define SMB_COM_WRITE_ANDX 0x2F -#define SMB_COM_NEW_FILE_SIZE 0x30 -#define SMB_COM_CLOSE_AND_TREE_DISC 0x31 -#define SMB_COM_TRANSACTION2 0x32 -#define SMB_COM_TRANSACTION2_SECONDARY 0x33 -#define SMB_COM_FIND_CLOSE2 0x34 -#define SMB_COM_FIND_NOTIFY_CLOSE 0x35 -#define SMB_COM_TREE_CONNECT 0x70 -#define SMB_COM_TREE_DISCONNECT 0x71 -#define SMB_COM_NEGOTIATE 0x72 -#define SMB_COM_SESSION_SETUP_ANDX 0x73 -#define SMB_COM_LOGOFF_ANDX 0x74 -#define SMB_COM_TREE_CONNECT_ANDX 0x75 -#define SMB_COM_SECURITY_PACKAGE_ANDX 0x7E -#define SMB_COM_QUERY_INFORMATION_DISK 0x80 -#define SMB_COM_SEARCH 0x81 -#define SMB_COM_FIND 0x82 -#define SMB_COM_FIND_UNIQUE 0x83 -#define SMB_COM_FIND_CLOSE 0x84 -#define SMB_COM_NT_TRANSACT 0xA0 -#define SMB_COM_NT_TRANSACT_SECONDARY 0xA1 -#define SMB_COM_NT_CREATE_ANDX 0xA2 -#define SMB_COM_NT_CANCEL 0xA4 -#define SMB_COM_NT_RENAME 0xA5 -#define SMB_COM_OPEN_PRINT_FILE 0xC0 -#define SMB_COM_WRITE_PRINT_FILE 0xC1 -#define SMB_COM_CLOSE_PRINT_FILE 0xC2 -#define SMB_COM_GET_PRINT_QUEUE 0xC3 -#define SMB_COM_READ_BULK 0xD8 -#define SMB_COM_WRITE_BULK 0xD9 -#define SMB_COM_WRITE_BULK_DATA 0xDA -#define SMB_COM_INVALID 0xFE -#define SMB_COM_NO_ANDX_COMMAND 0xFF - -/* Size of word count field + Word count * 2 bytes + Size of byte count field */ -#define SMB_COM_SIZE(wct) (sizeof(uint8_t) + ((wct) * sizeof(uint16_t)) + sizeof(uint16_t)) - -#define SMB_FLG__TYPE 0x80 -#define SMB_TYPE__REQUEST 0 -#define SMB_TYPE__RESPONSE 1 - -#define SMB_FLG2__UNICODE 0x8000 -#define SMB_FLG2__NT_CODES 0x4000 - -#define SMB_NT_STATUS_SEVERITY__SUCCESS 0 -#define SMB_NT_STATUS_SEVERITY__INFORMATIONAL 1 -#define SMB_NT_STATUS_SEVERITY__WARNING 2 -#define SMB_NT_STATUS_SEVERITY__ERROR 3 - -#define SMB_NT_STATUS__SUCCESS 0x00000000 -#define SMB_NT_STATUS__INVALID_DEVICE_REQUEST 0xc0000010 -#define SMB_NT_STATUS__RANGE_NOT_LOCKED 0xc000007e -#define SMB_NT_STATUS__PIPE_BROKEN 0xc000014b -#define SMB_NT_STATUS__PIPE_DISCONNECTED 0xc00000b0 - -#define SMB_ERROR_CLASS__SUCCESS 0x00 -#define SMB_ERROR_CLASS__ERRDOS 0x01 -#define SMB_ERROR_CLASS__ERRSRV 0x02 -#define SMB_ERROR_CLASS__ERRHRD 0x03 -#define SMB_ERROR_CLASS__ERRXOS 0x04 -#define SMB_ERROR_CLASS__ERRMX1 0xe1 -#define SMB_ERROR_CLASS__ERRMX2 0xe2 -#define SMB_ERROR_CLASS__ERRMX3 0xe3 -#define SMB_ERROR_CLASS__ERRCMD 0xff - -#define SMB_ERRSRV__INVALID_DEVICE 0x0007 -#define SMB_ERRDOS__NOT_LOCKED 0x009e -#define SMB_ERRDOS__BAD_PIPE 0x00e6 -#define SMB_ERRDOS__PIPE_NOT_CONNECTED 0x00e9 -#define SMB_ERRDOS__MORE_DATA 0x00ea - -#pragma pack(1) - -/******************************************************************** - * NetBIOS Session Service header - ********************************************************************/ -struct NbssHdr -{ - uint8_t type; - uint8_t flags; /* Treat flags as the upper byte to length */ - uint16_t length; -}; - -struct SmbNtHdr -{ - uint8_t smb_idf[4]; /* contains 0xFF, 'SMB' */ - uint8_t smb_com; /* command code */ - union - { - struct - { - uint8_t smb_class; /* dos error class */ - uint8_t smb_res; /* reserved for future */ - uint16_t smb_code; /* dos error code */ - } smb_status; - uint32_t nt_status; /* nt status */ - } smb_status; - uint8_t smb_flg; /* flags */ - uint16_t smb_flg2; /* flags */ - uint16_t smb_pid_high; - uint64_t smb_signature; - uint16_t smb_res; /* reserved for future */ - uint16_t smb_tid; /* tree id */ - uint16_t smb_pid; /* caller's process id */ - uint16_t smb_uid; /* authenticated user id */ - uint16_t smb_mid; /* multiplex id */ -}; - -/* For server empty respones indicating client error or interim response */ -struct SmbEmptyCom -{ - uint8_t smb_wct; /* value = 0 */ - uint16_t smb_bcc; /* value = 0 */ -}; - enum DCE2_SmbSsnState { DCE2_SMB_SSN_STATE__START = 0x00, @@ -460,119 +252,6 @@ enum SmbAndXCom SMB_ANDX_COM__MAX }; -enum SmbTransactionSubcommand -{ - TRANS_UNKNOWN_0000 = 0x0000, - TRANS_SET_NMPIPE_STATE = 0x0001, - TRANS_UNKNOWN_0002 = 0x0002, - TRANS_UNKNOWN_0003 = 0x0003, - TRANS_UNKNOWN_0004 = 0x0004, - TRANS_UNKNOWN_0005 = 0x0005, - TRANS_UNKNOWN_0006 = 0x0006, - TRANS_UNKNOWN_0007 = 0x0007, - TRANS_UNKNOWN_0008 = 0x0008, - TRANS_UNKNOWN_0009 = 0x0009, - TRANS_UNKNOWN_000A = 0x000A, - TRANS_UNKNOWN_000B = 0x000B, - TRANS_UNKNOWN_000C = 0x000C, - TRANS_UNKNOWN_000D = 0x000D, - TRANS_UNKNOWN_000E = 0x000E, - TRANS_UNKNOWN_000F = 0x000F, - TRANS_UNKNOWN_0010 = 0x0010, - TRANS_RAW_READ_NMPIPE = 0x0011, - TRANS_UNKNOWN_0012 = 0x0012, - TRANS_UNKNOWN_0013 = 0x0013, - TRANS_UNKNOWN_0014 = 0x0014, - TRANS_UNKNOWN_0015 = 0x0015, - TRANS_UNKNOWN_0016 = 0x0016, - TRANS_UNKNOWN_0017 = 0x0017, - TRANS_UNKNOWN_0018 = 0x0018, - TRANS_UNKNOWN_0019 = 0x0019, - TRANS_UNKNOWN_001A = 0x001A, - TRANS_UNKNOWN_001B = 0x001B, - TRANS_UNKNOWN_001C = 0x001C, - TRANS_UNKNOWN_001D = 0x001D, - TRANS_UNKNOWN_001E = 0x001E, - TRANS_UNKNOWN_001F = 0x001F, - TRANS_UNKNOWN_0020 = 0x0020, - TRANS_QUERY_NMPIPE_STATE = 0x0021, - TRANS_QUERY_NMPIPE_INFO = 0x0022, - TRANS_PEEK_NMPIPE = 0x0023, - TRANS_UNKNOWN_0024 = 0x0024, - TRANS_UNKNOWN_0025 = 0x0025, - TRANS_TRANSACT_NMPIPE = 0x0026, - TRANS_UNKNOWN_0027 = 0x0027, - TRANS_UNKNOWN_0028 = 0x0028, - TRANS_UNKNOWN_0029 = 0x0029, - TRANS_UNKNOWN_002A = 0x002A, - TRANS_UNKNOWN_002B = 0x002B, - TRANS_UNKNOWN_002C = 0x002C, - TRANS_UNKNOWN_002D = 0x002D, - TRANS_UNKNOWN_002E = 0x002E, - TRANS_UNKNOWN_002F = 0x002F, - TRANS_UNKNOWN_0030 = 0x0030, - TRANS_RAW_WRITE_NMPIPE = 0x0031, - TRANS_UNKNOWN_0032 = 0x0032, - TRANS_UNKNOWN_0033 = 0x0033, - TRANS_UNKNOWN_0034 = 0x0034, - TRANS_UNKNOWN_0035 = 0x0035, - TRANS_READ_NMPIPE = 0x0036, - TRANS_WRITE_NMPIPE = 0x0037, - TRANS_UNKNOWN_0038 = 0x0038, - TRANS_UNKNOWN_0039 = 0x0039, - TRANS_UNKNOWN_003A = 0x003A, - TRANS_UNKNOWN_003B = 0x003B, - TRANS_UNKNOWN_003C = 0x003C, - TRANS_UNKNOWN_003D = 0x003D, - TRANS_UNKNOWN_003E = 0x003E, - TRANS_UNKNOWN_003F = 0x003F, - TRANS_UNKNOWN_0040 = 0x0040, - TRANS_UNKNOWN_0041 = 0x0041, - TRANS_UNKNOWN_0042 = 0x0042, - TRANS_UNKNOWN_0043 = 0x0043, - TRANS_UNKNOWN_0044 = 0x0044, - TRANS_UNKNOWN_0045 = 0x0045, - TRANS_UNKNOWN_0046 = 0x0046, - TRANS_UNKNOWN_0047 = 0x0047, - TRANS_UNKNOWN_0048 = 0x0048, - TRANS_UNKNOWN_0049 = 0x0049, - TRANS_UNKNOWN_004A = 0x004A, - TRANS_UNKNOWN_004B = 0x004B, - TRANS_UNKNOWN_004C = 0x004C, - TRANS_UNKNOWN_004D = 0x004D, - TRANS_UNKNOWN_004E = 0x004E, - TRANS_UNKNOWN_004F = 0x004F, - TRANS_UNKNOWN_0050 = 0x0050, - TRANS_UNKNOWN_0051 = 0x0051, - TRANS_UNKNOWN_0052 = 0x0052, - TRANS_WAIT_NMPIPE = 0x0053, - TRANS_CALL_NMPIPE = 0x0054, - TRANS_SUBCOM_MAX = 0x0055 -}; - -enum SmbTransaction2Subcommand -{ - TRANS2_OPEN2 = 0x0000, - TRANS2_FIND_FIRST2 = 0x0001, - TRANS2_FIND_NEXT2 = 0x0002, - TRANS2_QUERY_FS_INFORMATION = 0x0003, - TRANS2_SET_FS_INFORMATION = 0x0004, - TRANS2_QUERY_PATH_INFORMATION = 0x0005, - TRANS2_SET_PATH_INFORMATION = 0x0006, - TRANS2_QUERY_FILE_INFORMATION = 0x0007, - TRANS2_SET_FILE_INFORMATION = 0x0008, - TRANS2_FSCTL = 0x0009, - TRANS2_IOCTL2 = 0x000A, - TRANS2_FIND_NOTIFY_FIRST = 0x000B, - TRANS2_FIND_NOTIFY_NEXT = 0x000C, - TRANS2_CREATE_DIRECTORY = 0x000D, - TRANS2_SESSION_SETUP = 0x000E, - TRANS2_UNKNOWN_000F = 0x000F, - TRANS2_GET_DFS_REFERRAL = 0x0010, - TRANS2_REPORT_DFS_INCONSISTENCY = 0x0011, - TRANS2_SUBCOM_MAX = 0x0012 -}; - struct DCE2_SmbWriteAndXRaw { int remaining; // A signed integer so it can be negative @@ -586,6 +265,13 @@ struct DCE2_SmbFileChunk uint8_t* data; }; +enum DCE2_SmbVersion +{ + DCE2_SMB_VERISON_NULL, + DCE2_SMB_VERISON_1, + DCE2_SMB_VERISON_2 +}; + struct DCE2_SmbFileTracker { union @@ -655,13 +341,6 @@ struct DCE2_SmbFileTracker #define ff_sequential_only tracker.file.sequential_only }; -enum DCE2_SmbVersion -{ - DCE2_SMB_VERISON_NULL, - DCE2_SMB_VERISON_1, - DCE2_SMB_VERISON_2 -}; - struct Smb2Request { uint64_t message_id; /* identifies a message uniquely on connection */ @@ -722,8 +401,6 @@ struct DCE2_SmbRequestTracker bool is_ipc; }; -#pragma pack() - struct DCE2_SmbSsnData { DCE2_SsnData sd; // This member must be first @@ -779,2261 +456,6 @@ struct DCE2_SmbSsnData int64_t max_file_depth; }; -/******************************************************************** - * Structures and inline accessor functions - ********************************************************************/ -/* Pack the structs since we'll be laying them on top of packet data */ -#pragma pack(1) - -/******************************************************************** - * Common fields to all commands - ********************************************************************/ -struct SmbCommon -{ - uint8_t smb_wct; -}; - -inline uint8_t SmbWct(const SmbCommon* hdr) -{ - return hdr->smb_wct; -} - -/* Common fields to all AndX commands */ -struct SmbAndXCommon -{ - uint8_t smb_wct; - uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ - uint8_t smb_reh2; /* reserved (must be zero) */ - uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ -}; - -inline uint32_t NbssLen(const NbssHdr* nb) -{ - /* Treat first bit of flags as the upper byte to length */ - // The left operand of '&' is a garbage value - return ((nb->flags & 0x01) << 16) | ntohs(nb->length); // ... FIXIT-W -} - -inline uint8_t NbssType(const NbssHdr* nb) -{ - return nb->type; -} - -inline uint32_t SmbId(const SmbNtHdr* hdr) -{ - uint8_t* idf = (uint8_t*)hdr->smb_idf; - return *idf << 24 | *(idf + 1) << 16 | *(idf + 2) << 8 | *(idf + 3); -} - -inline uint8_t SmbEmptyComWct(const SmbEmptyCom* ec) -{ - return ec->smb_wct; -} - -inline uint16_t SmbBcc(const uint8_t* ptr, uint16_t com_size) -{ - /* com_size must be at least the size of the command encasing */ - if (com_size < sizeof(SmbEmptyCom)) - return 0; - - return alignedNtohs((uint16_t*)(ptr + com_size - sizeof(uint16_t))); -} - -inline uint16_t SmbEmptyComBcc(const SmbEmptyCom* ec) -{ - return alignedNtohs(&ec->smb_bcc); -} - -inline int SmbType(const SmbNtHdr* hdr) -{ - // Access to field 'smb_flg' results in a dereference of a null pointer - // (loaded from variable 'hdr') - if (hdr->smb_flg & SMB_FLG__TYPE) // ... FIXIT-W - return SMB_TYPE__RESPONSE; - - return SMB_TYPE__REQUEST; -} - -inline uint8_t SmbAndXCom2(const SmbAndXCommon* andx) -{ - return andx->smb_com2; -} - -inline uint16_t SmbAndXOff2(const SmbAndXCommon* andx) -{ - return alignedNtohs(&andx->smb_off2); -} - -/* SMB formats (smb_fmt) Dialect, Pathname and ASCII are all - * NULL terminated ASCII strings unless Unicode is specified - * in the NT LM 1.0 SMB header in which case they are NULL - * terminated unicode strings - */ -#define SMB_FMT__DATA_BLOCK 1 -#define SMB_FMT__DIALECT 2 -#define SMB_FMT__ASCII 4 - -inline bool SmbFmtDataBlock(const uint8_t fmt) -{ - return fmt == SMB_FMT__DATA_BLOCK ? true : false; -} - -inline bool SmbFmtDialect(const uint8_t fmt) -{ - return fmt == SMB_FMT__DIALECT ? true : false; -} - -inline bool SmbFmtAscii(const uint8_t fmt) -{ - return fmt == SMB_FMT__ASCII ? true : false; -} - -/******************************************************************** - * SMB_COM_OPEN - ********************************************************************/ -struct SmbOpenReq /* smb_wct = 2 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint16_t smb_mode; /* r/w/share */ - uint16_t smb_attr; /* attribute */ - uint16_t smb_bcc; /* min = 2 */ -}; - -struct SmbOpenResp /* smb_wct = 7 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint16_t smb_fid; /* file handle */ - uint16_t smb_attr; /* attribute */ - uint32_t smb_time; /* time1 low */ - uint32_t smb_file_size; /* file size low */ - uint16_t smb_access; /* access allowed */ - uint16_t smb_bcc; /* must be 0 */ -}; - -#define SMB_OPEN_ACCESS_MODE__READ 0x0000 -#define SMB_OPEN_ACCESS_MODE__WRITE 0x0001 -#define SMB_OPEN_ACCESS_MODE__READ_WRITE 0x0002 -#define SMB_OPEN_ACCESS_MODE__EXECUTE 0x0003 - -inline uint16_t SmbOpenRespFid(const SmbOpenResp* resp) -{ - return alignedNtohs(&resp->smb_fid); -} - -inline uint32_t SmbOpenRespFileSize(const SmbOpenResp* resp) -{ - return alignedNtohl(&resp->smb_file_size); -} - -inline uint16_t SmbOpenRespFileAttrs(const SmbOpenResp* resp) -{ - return alignedNtohs(&resp->smb_attr); -} - -inline bool SmbFileAttrsDirectory(const uint16_t file_attrs) -{ - if (file_attrs & SMB_FILE_ATTRIBUTE_DIRECTORY) - return true; - return false; -} - -inline uint16_t SmbOpenRespAccessMode(const SmbOpenResp* resp) -{ - return alignedNtohs(&resp->smb_access); -} - -inline bool SmbOpenForWriting(const uint16_t access_mode) -{ - return access_mode == SMB_OPEN_ACCESS_MODE__WRITE; -} - -/******************************************************************** - * SMB_COM_CREATE - ********************************************************************/ -struct SmbCreateReq /* smb_wct = 3 */ -{ - uint8_t smb_wct; - uint16_t smb_file_attrs; - uint32_t smb_creation_time; - uint16_t smb_bcc; -}; - -struct SmbCreateResp /* smb_wct = 1 */ -{ - uint8_t smb_wct; - uint16_t smb_fid; - uint16_t smb_bcc; -}; - -inline uint16_t SmbCreateReqFileAttrs(const SmbCreateReq* req) -{ - return alignedNtohs(&req->smb_file_attrs); -} - -inline bool SmbAttrDirectory(const uint16_t file_attrs) -{ - if (file_attrs & SMB_FILE_ATTRIBUTE_DIRECTORY) - return true; - return false; -} - -inline uint16_t SmbCreateRespFid(const SmbCreateResp* resp) -{ - return alignedNtohs(&resp->smb_fid); -} - -/******************************************************************** - * SMB_COM_CLOSE - ********************************************************************/ -struct SmbCloseReq /* smb_wct = 3 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint16_t smb_fid; /* file handle */ - uint16_t smb_tlow; /* time low */ - uint16_t smb_thigh; /* time high */ - uint16_t smb_bcc; /* must be 0 */ -}; - -struct SmbCloseResp /* smb_wct = 0 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint16_t smb_bcc; /* must be 0 */ -}; - -inline uint16_t SmbCloseReqFid(const SmbCloseReq* req) -{ - return alignedNtohs(&req->smb_fid); -} - -/******************************************************************** - * SMB_COM_READ - ********************************************************************/ -struct SmbReadReq /* smb_wct = 5 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint16_t smb_fid; /* file handle */ - uint16_t smb_cnt; /* count of bytes */ - uint32_t smb_off; /* offset */ - uint16_t smb_left; /* count left */ - uint16_t smb_bcc; /* must be 0 */ -}; - -struct SmbReadResp /* smb_wct = 5 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint16_t smb_cnt; /* count */ - uint16_t smb_res[4]; /* reserved (MBZ) */ - uint16_t smb_bcc; /* length of data + 3 */ -}; - -inline uint16_t SmbReadReqFid(const SmbReadReq* req) -{ - return alignedNtohs(&req->smb_fid); -} - -inline uint32_t SmbReadReqOffset(const SmbReadReq* req) -{ - return alignedNtohl(&req->smb_off); -} - -inline uint16_t SmbReadRespCount(const SmbReadResp* resp) -{ - return alignedNtohs(&resp->smb_cnt); -} - -/******************************************************************** - * SMB_COM_WRITE - ********************************************************************/ -struct SmbWriteReq /* smb_wct = 5 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint16_t smb_fid; /* file handle */ - uint16_t smb_cnt; /* count of bytes */ - uint32_t smb_offset; /* file offset in bytes */ - uint16_t smb_left; /* count left */ - uint16_t smb_bcc; /* length of data + 3 */ -}; - -struct SmbWriteResp /* smb_wct = 1 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint16_t smb_cnt; /* count */ - uint16_t smb_bcc; /* must be 0 */ -}; - -inline uint16_t SmbWriteReqFid(const SmbWriteReq* req) -{ - return alignedNtohs(&req->smb_fid); -} - -inline uint16_t SmbWriteReqCount(const SmbWriteReq* req) -{ - return alignedNtohs(&req->smb_cnt); -} - -inline uint32_t SmbWriteReqOffset(const SmbWriteReq* req) -{ - return alignedNtohl(&req->smb_offset); -} - -inline uint16_t SmbWriteRespCount(const SmbWriteResp* resp) -{ - return alignedNtohs(&resp->smb_cnt); -} - -/******************************************************************** - * SMB_COM_CREATE_NEW - ********************************************************************/ -struct SmbCreateNewReq /* smb_wct = 3 */ -{ - uint8_t smb_wct; - uint16_t smb_file_attrs; - uint32_t smb_creation_time; - uint16_t smb_bcc; -}; - -struct SmbCreateNewResp /* smb_wct = 1 */ -{ - uint8_t smb_wct; - uint16_t smb_fid; - uint16_t smb_bcc; -}; - -inline uint16_t SmbCreateNewReqFileAttrs(const SmbCreateNewReq* req) -{ - return alignedNtohs(&req->smb_file_attrs); -} - -inline uint16_t SmbCreateNewRespFid(const SmbCreateNewResp* resp) -{ - return alignedNtohs(&resp->smb_fid); -} - -/******************************************************************** - * SMB_COM_LOCK_AND_READ - ********************************************************************/ -struct SmbLockAndReadReq /* smb_wct = 5 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint16_t smb_fid; - uint16_t smb_cnt; - uint32_t smb_read_offset; - uint16_t smb_remaining; - uint16_t smb_bcc; /* must be 0 */ -}; - -struct SmbLockAndReadResp /* smb_wct = 5 */ -{ - uint8_t smb_wct; - uint16_t smb_cnt; - uint16_t reserved[4]; - uint16_t smb_bcc; -}; - -inline uint16_t SmbLockAndReadReqFid(const SmbLockAndReadReq* req) -{ - return alignedNtohs(&req->smb_fid); -} - -inline uint32_t SmbLockAndReadReqOffset(const SmbLockAndReadReq* req) -{ - return alignedNtohl(&req->smb_read_offset); -} - -inline uint16_t SmbLockAndReadRespCount(const SmbLockAndReadResp* resp) -{ - return alignedNtohs(&resp->smb_cnt); -} - -/******************************************************************** - * SMB_COM_WRITE_AND_UNLOCK - ********************************************************************/ -struct SmbWriteAndUnlockReq -{ - uint8_t smb_wct; - uint16_t smb_fid; - uint16_t smb_cnt; - uint32_t smb_write_offset; - uint16_t smb_estimate_of_remaining; - uint16_t smb_bcc; -}; - -struct SmbWriteAndUnlockResp /* smb_wct = 1 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint16_t smb_cnt; /* count */ - uint16_t smb_bcc; /* must be 0 */ -}; - -inline uint16_t SmbWriteAndUnlockReqFid(const SmbWriteAndUnlockReq* req) -{ - return alignedNtohs(&req->smb_fid); -} - -inline uint16_t SmbWriteAndUnlockReqCount(const SmbWriteAndUnlockReq* req) -{ - return alignedNtohs(&req->smb_cnt); -} - -inline uint32_t SmbWriteAndUnlockReqOffset(const SmbWriteAndUnlockReq* req) -{ - return alignedNtohl(&req->smb_write_offset); -} - -/******************************************************************** - * SMB_COM_OPEN_ANDX - ********************************************************************/ -struct SmbOpenAndXReq /* smb_wct = 15 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ - uint8_t smb_reh2; /* reserved (must be zero) */ - uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ - uint16_t smb_flags; /* additional information: - bit 0 - if set, return additional information - bit 1 - if set, set single user total file lock (if only access) - bit 2 - if set, the server should notify the consumer on any - action which can modify the file (delete, setattrib, - rename, etc.). if not set, the server need only notify - the consumer on another open request. This bit only has - meaning if bit 1 is set. */ - uint16_t smb_mode; /* file open mode */ - uint16_t smb_sattr; /* search attributes */ - uint16_t smb_attr; /* file attributes (for create) */ - uint32_t smb_time; /* create time */ - uint16_t smb_ofun; /* open function */ - uint32_t smb_size; /* bytes to reserve on "create" or "truncate" */ - uint32_t smb_timeout; /* max milliseconds to wait for resource to open */ - uint32_t smb_rsvd; /* reserved (must be zero) */ - uint16_t smb_bcc; /* minimum value = 1 */ -}; - -struct SmbOpenAndXResp /* smb_wct = 15 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ - uint8_t smb_res2; /* reserved (pad to word) */ - uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ - uint16_t smb_fid; /* file handle */ - uint16_t smb_attribute; /* attributes of file or device */ - uint32_t smb_time; /* last modification time */ - uint32_t smb_size; /* current file size */ - uint16_t smb_access; /* access permissions actually allowed */ - uint16_t smb_type; /* file type */ - uint16_t smb_state; /* state of IPC device (e.g. pipe) */ - uint16_t smb_action; /* action taken */ - uint32_t smb_fileid; /* server unique file id */ - uint16_t smb_rsvd; /* reserved */ - uint16_t smb_bcc; /* value = 0 */ -}; - -inline uint32_t SmbOpenAndXReqAllocSize(const SmbOpenAndXReq* req) -{ - return alignedNtohl(&req->smb_size); -} - -inline uint16_t SmbOpenAndXReqFileAttrs(const SmbOpenAndXReq* req) -{ - return alignedNtohs(&req->smb_attr); -} - -inline uint16_t SmbOpenAndXRespFid(const SmbOpenAndXResp* resp) -{ - return alignedNtohs(&resp->smb_fid); -} - -inline uint16_t SmbOpenAndXRespFileAttrs(const SmbOpenAndXResp* resp) -{ - return alignedNtohs(&resp->smb_attribute); -} - -inline uint32_t SmbOpenAndXRespFileSize(const SmbOpenAndXResp* resp) -{ - return alignedNtohl(&resp->smb_size); -} - -inline uint16_t SmbOpenAndXRespResourceType(const SmbOpenAndXResp* resp) -{ - return alignedNtohs(&resp->smb_type); -} - -#define SMB_OPEN_RESULT__EXISTED 0x0001 -#define SMB_OPEN_RESULT__CREATED 0x0002 -#define SMB_OPEN_RESULT__TRUNCATED 0x0003 - -inline uint16_t SmbOpenAndXRespOpenResults(const SmbOpenAndXResp* resp) -{ - return alignedNtohs(&resp->smb_action); -} - -inline bool SmbOpenResultRead(const uint16_t open_results) -{ - return ((open_results & 0x00FF) == SMB_OPEN_RESULT__EXISTED); -} - -inline bool SmbResourceTypeDisk(const uint16_t resource_type) -{ - return resource_type == SMB_FILE_TYPE_DISK; -} - -/******************************************************************** - * SMB_COM_READ_ANDX - ********************************************************************/ -struct SmbReadAndXReq /* smb_wct = 10 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ - uint8_t smb_reh2; /* reserved (must be zero) */ - uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ - uint16_t smb_fid; /* file handle */ - uint32_t smb_offset; /* offset in file to begin read */ - uint16_t smb_maxcnt; /* max number of bytes to return */ - uint16_t smb_mincnt; /* min number of bytes to return */ - uint32_t smb_timeout; /* number of milliseconds to wait for completion */ - uint16_t smb_countleft; /* bytes remaining to satisfy user’s request */ - uint16_t smb_bcc; /* value = 0 */ -}; - -struct SmbReadAndXExtReq /* smb_wct = 12 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ - uint8_t smb_reh2; /* reserved (must be zero) */ - uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ - uint16_t smb_fid; /* file handle */ - uint32_t smb_offset; /* low offset in file to begin read */ - uint16_t smb_maxcnt; /* max number of bytes to return */ - uint16_t smb_mincnt; /* min number of bytes to return */ - uint32_t smb_timeout; /* number of milliseconds to wait for completion */ - uint16_t smb_countleft; /* bytes remaining to satisfy user’s request */ - uint32_t smb_off_high; /* high offset in file to begin read */ - uint16_t smb_bcc; /* value = 0 */ -}; - -struct SmbReadAndXResp /* smb_wct = 12 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ - uint8_t smb_res2; /* reserved (pad to word) */ - uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ - uint16_t smb_remaining; /* bytes remaining to be read (pipes/devices only) */ - uint32_t smb_rsvd; /* reserved */ - uint16_t smb_dsize; /* number of data bytes (minimum value = 0) */ - uint16_t smb_doff; /* offset (from start of SMB hdr) to data bytes */ - uint16_t smb_dsize_high; /* high bytes of data size */ - uint32_t smb_rsvd1; /* reserved */ - uint32_t smb_rsvd2; /* reserved */ - uint16_t smb_bcc; /* total bytes (including pad bytes) following */ -}; - -inline uint16_t SmbReadAndXReqFid(const SmbReadAndXReq* req) -{ - return alignedNtohs(&req->smb_fid); -} - -inline uint64_t SmbReadAndXReqOffset(const SmbReadAndXExtReq* req) -{ - if (req->smb_wct == 10) - return (uint64_t)alignedNtohl(&req->smb_offset); - return (uint64_t)alignedNtohl(&req->smb_off_high) << 32 | (uint64_t)alignedNtohl( - &req->smb_offset); -} - -inline uint16_t SmbReadAndXRespDataOff(const SmbReadAndXResp* req) -{ - return alignedNtohs(&req->smb_doff); -} - -inline uint32_t SmbReadAndXRespDataCnt(const SmbReadAndXResp* resp) -{ - return (uint32_t)alignedNtohs(&resp->smb_dsize_high) << 16 | (uint32_t)alignedNtohs( - &resp->smb_dsize); -} - -/******************************************************************** - * SMB_COM_WRITE_ANDX - ********************************************************************/ -struct SmbWriteAndXReq /* smb_wct = 12 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ - uint8_t smb_reh2; /* reserved (must be zero) */ - uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ - uint16_t smb_fid; /* file handle */ - uint32_t smb_offset; /* offset in file to begin write */ - uint32_t smb_timeout; /* number of milliseconds to wait for completion */ - uint16_t smb_wmode; /* write mode: - bit0 - complete write before return (write through) - bit1 - return smb_remaining (pipes/devices only) - bit2 - use WriteRawNamedPipe (pipes only) - bit3 - this is the start of a message (pipes only) */ - uint16_t smb_countleft; /* bytes remaining to write to satisfy user’s request */ - uint16_t smb_dsize_high; /* high bytes of data size */ - uint16_t smb_dsize; /* number of data bytes in buffer (min value = 0) */ - uint16_t smb_doff; /* offset (from start of SMB hdr) to data bytes */ - uint16_t smb_bcc; /* total bytes (including pad bytes) following */ -}; - -struct SmbWriteAndXExtReq /* smb_wct = 14 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ - uint8_t smb_reh2; /* reserved (must be zero) */ - uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ - uint16_t smb_fid; /* file handle */ - uint32_t smb_offset; /* low offset in file to begin write */ - uint32_t smb_timeout; /* number of milliseconds to wait for completion */ - uint16_t smb_wmode; /* write mode: - bit0 - complete write before return (write through) - bit1 - return smb_remaining (pipes/devices only) - bit2 - use WriteRawNamedPipe (pipes only) - bit3 - this is the start of a message (pipes only) */ - uint16_t smb_countleft; /* bytes remaining to write to satisfy user’s request */ - uint16_t smb_dsize_high; /* high bytes of data size */ - uint16_t smb_dsize; /* number of data bytes in buffer (min value = 0) */ - uint16_t smb_doff; /* offset (from start of SMB hdr) to data bytes */ - uint32_t smb_off_high; /* high offset in file to begin write */ - uint16_t smb_bcc; /* total bytes (including pad bytes) following */ -}; - -struct SmbWriteAndXResp /* smb_wct = 6 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ - uint8_t smb_res2; /* reserved (pad to word) */ - uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ - uint16_t smb_count; /* number of bytes written */ - uint16_t smb_remaining; /* bytes remaining to be read (pipes/devices only) */ - uint16_t smb_count_high; /* high order bytes of data count */ - uint16_t smb_rsvd; /* reserved */ - uint16_t smb_bcc; /* value = 0 */ -}; - -inline uint16_t SmbWriteAndXReqFid(const SmbWriteAndXReq* req) -{ - return alignedNtohs(&req->smb_fid); -} - -inline uint16_t SmbWriteAndXReqDataOff(const SmbWriteAndXReq* req) -{ - return alignedNtohs(&req->smb_doff); -} - -inline uint16_t SmbWriteAndXReqRemaining(const SmbWriteAndXReq* req) -{ - return alignedNtohs(&req->smb_countleft); -} - -inline uint64_t SmbWriteAndXReqOffset(const SmbWriteAndXExtReq* req) -{ - if (req->smb_wct == 12) - return (uint64_t)alignedNtohl(&req->smb_offset); - return (uint64_t)alignedNtohl(&req->smb_off_high) << 32 | (uint64_t)alignedNtohl( - &req->smb_offset); -} - -inline uint32_t SmbWriteAndXReqDataCnt(const SmbWriteAndXReq* req) -{ - return (uint32_t)alignedNtohs(&req->smb_dsize_high) << 16 | (uint32_t)alignedNtohs( - &req->smb_dsize); -} - -inline uint16_t SmbWriteAndXReqWriteMode(const SmbWriteAndXReq* req) -{ - return alignedNtohs(&req->smb_wmode); -} - -inline bool SmbWriteAndXReqStartRaw(const SmbWriteAndXReq* req) -{ - return ((alignedNtohs(&req->smb_wmode) & 0x000c) == 0x000c) ? true : false; -} - -inline bool SmbWriteAndXReqRaw(const SmbWriteAndXReq* req) -{ - return ((alignedNtohs(&req->smb_wmode) & 0x000c) == 0x0004) ? true : false; -} - -inline uint16_t SmbWriteAndXRespCnt(const SmbWriteAndXResp* resp) -{ - return alignedNtohs(&resp->smb_count); -} - -/******************************************************************** - * SMB_COM_SESSION_SETUP_ANDX - ********************************************************************/ -struct SmbLm10_SessionSetupAndXReq /* smb_wct = 10 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ - uint8_t smb_reh2; /* reserved (must be zero) */ - uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ - uint16_t smb_bufsize; /* the consumers max buffer size */ - uint16_t smb_mpxmax; /* actual maximum multiplexed pending requests */ - uint16_t smb_vc_num; /* 0 = first (only), non zero - additional VC number */ - uint32_t smb_sesskey; /* Session Key (valid only if smb_vc_num != 0) */ - uint16_t smb_apasslen; /* size of account password (smb_apasswd) */ - uint32_t smb_rsvd; /* reserved */ - uint16_t smb_bcc; /* minimum value = 0 */ -}; - -inline uint16_t SmbSessionSetupAndXReqMaxMultiplex(const SmbLm10_SessionSetupAndXReq* req) -{ - return alignedNtohs(&req->smb_mpxmax); -} - -/* Extended request as defined in NT LM 1.0 document */ -struct SmbNt10_SessionSetupAndXReq /* smb_wct = 13 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ - uint8_t smb_reh2; /* reserved (must be zero) */ - uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ - uint16_t smb_bufsize; /* the consumers max buffer size */ - uint16_t smb_mpxmax; /* actual maximum multiplexed pending requests */ - uint16_t smb_vc_num; /* 0 = first (only), non zero - additional VC number */ - uint32_t smb_sesskey; /* Session Key (valid only if smb_vc_num != 0) */ - uint16_t smb_oem_passlen; /* case insensitive password length */ - uint16_t smb_unicode_passlen; /* case sensitive password length */ - uint32_t smb_rsvd; /* reserved */ - uint32_t smb_cap; /* capabilities */ - uint16_t smb_bcc; /* minimum value = 0 */ -}; - -inline uint16_t SmbNt10SessionSetupAndXReqOemPassLen(const SmbNt10_SessionSetupAndXReq* req) -{ - return alignedNtohs(&req->smb_oem_passlen); -} - -inline uint16_t SmbNt10SessionSetupAndXReqUnicodePassLen(const SmbNt10_SessionSetupAndXReq* req) -{ - return alignedNtohs(&req->smb_unicode_passlen); -} - -/* Extended request for security blob */ -struct SmbNt10_SessionSetupAndXExtReq /* smb_wct = 12 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ - uint8_t smb_reh2; /* reserved (must be zero) */ - uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ - uint16_t smb_bufsize; /* the consumers max buffer size */ - uint16_t smb_mpxmax; /* actual maximum multiplexed pending requests */ - uint16_t smb_vc_num; /* 0 = first (only), non zero - additional VC number */ - uint32_t smb_sesskey; /* Session Key (valid only if smb_vc_num != 0) */ - uint16_t smb_blob_len; /* length of security blob */ - uint32_t smb_rsvd; /* reserved */ - uint32_t smb_cap; /* capabilities */ - uint16_t smb_bcc; /* minimum value = 0 */ -}; - -inline uint16_t SmbSessionSetupAndXReqBlobLen(const SmbNt10_SessionSetupAndXExtReq* req) -{ - return alignedNtohs(&req->smb_blob_len); -} - -/* Extended response for security blob */ -struct SmbNt10_SessionSetupAndXExtResp /* smb_wct = 4 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ - uint8_t smb_res2; /* reserved (pad to word) */ - uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ - uint16_t smb_action; /* request mode: - bit0 = Logged in successfully - BUT as GUEST */ - uint16_t smb_blob_len; /* length of security blob */ - uint16_t smb_bcc; /* min value = 0 */ -}; - -inline uint16_t SmbSessionSetupAndXRespBlobLen(const SmbNt10_SessionSetupAndXExtResp* resp) -{ - return alignedNtohs(&resp->smb_blob_len); -} - -/******************************************************************** - * SMB_COM_NEGOTIATE - ********************************************************************/ -/* This is the Lanman response */ -struct SmbLm10_NegotiateProtocolResp /* smb_wct = 13 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint16_t smb_index; /* index identifying dialect selected */ - uint16_t smb_secmode; /* security mode: - bit 0, 1 = User level, 0 = Share level - bit 1, 1 = encrypt passwords, 0 = do not encrypt passwords */ - uint16_t smb_maxxmt; /* max transmit buffer size server supports, 1K min */ - uint16_t smb_maxmux; /* max pending multiplexed requests server supports */ - uint16_t smb_maxvcs; /* max VCs per server/consumer session supported */ - uint16_t smb_blkmode; /* block read/write mode support: - bit 0, Read Block Raw supported (65535 bytes max) - bit 1, Write Block Raw supported (65535 bytes max) */ - uint32_t smb_sesskey; /* Session Key (unique token identifying session) */ - uint16_t smb_srv_time; /* server's current time (hhhhh mmmmmm xxxxx) */ - uint16_t smb_srv_tzone; /* server's current data (yyyyyyy mmmm ddddd) */ - uint32_t smb_rsvd; /* reserved */ - uint16_t smb_bcc; /* value = (size of smb_cryptkey) */ -}; - -/* This is the NT response */ -struct SmbNt_NegotiateProtocolResp /* smb_wct = 17 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint16_t smb_index; /* index identifying dialect selected */ - uint8_t smb_secmode; /* security mode: - bit 0, 1 = User level, 0 = Share level - bit 1, 1 = encrypt passwords, 0 = do not encrypt passwords */ - uint16_t smb_maxmux; /* max pending multiplexed requests server supports */ - uint16_t smb_maxvcs; /* max VCs per server/consumer session supported */ - uint32_t smb_maxbuf; /* maximum buffer size supported */ - uint32_t smb_maxraw; /* maximum raw buffer size supported */ - uint32_t smb_sesskey; /* Session Key (unique token identifying session) */ - uint32_t smb_cap; /* capabilities */ - struct - { - uint32_t low_time; - int32_t high_time; - } smb_srv_time; /* server time */ - uint16_t smb_srv_tzone; /* server's current data (yyyyyyy mmmm ddddd) */ - uint8_t smb_challenge_len; /* Challenge length */ - uint16_t smb_bcc; /* value = (size of smb_cryptkey) */ -}; - -inline uint16_t SmbLm_NegotiateRespMaxMultiplex(const SmbLm10_NegotiateProtocolResp* resp) -{ - return alignedNtohs(&resp->smb_maxmux); -} - -inline uint16_t SmbNt_NegotiateRespMaxMultiplex(const SmbNt_NegotiateProtocolResp* resp) -{ - return alignedNtohs(&resp->smb_maxmux); -} - -/* This is the Core Protocol response */ -struct SmbCore_NegotiateProtocolResp /* smb_wct = 1 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint16_t smb_index; /* index */ - uint16_t smb_bcc; /* must be 0 */ -}; - -inline uint16_t SmbNegotiateRespDialectIndex(const SmbCore_NegotiateProtocolResp* resp) -{ - return alignedNtohs(&resp->smb_index); -} - -/********************************************************************* - * SMB_COM_TREE_CONNECT_ANDX - *********************************************************************/ -struct SmbTreeConnectAndXReq /* smb_wct = 4 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ - uint8_t smb_reh2; /* reserved (must be zero) */ - uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ - uint16_t smb_flags; /* additional information: - bit 0 - if set, disconnect TID in current smb_tid */ - uint16_t smb_spasslen; /* length of smb_spasswd */ - uint16_t smb_bcc; /* minimum value = 3 */ -}; - -inline uint16_t SmbTreeConnectAndXReqPassLen(const SmbTreeConnectAndXReq* req) -{ - return alignedNtohs(&req->smb_spasslen); -} - -/******************************************************************** - * SMB_COM_NT_TRANSACT - ********************************************************************/ -#define SMB_CREATE_OPTIONS__FILE_SEQUENTIAL_ONLY 0x00000004 - -/******************************************************************** - * SMB_COM_NT_CREATE_ANDX - ********************************************************************/ -#define SMB_CREATE_DISPOSITSION__FILE_SUPERCEDE 0x00000000 -#define SMB_CREATE_DISPOSITSION__FILE_OPEN 0x00000001 -#define SMB_CREATE_DISPOSITSION__FILE_CREATE 0x00000002 -#define SMB_CREATE_DISPOSITSION__FILE_OPEN_IF 0x00000003 -#define SMB_CREATE_DISPOSITSION__FILE_OVERWRITE 0x00000004 -#define SMB_CREATE_DISPOSITSION__FILE_OVERWRITE_IF 0x00000005 - -struct SmbNtCreateAndXReq /* smb_wct = 24 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ - uint8_t smb_res2; /* reserved (pad to word) */ - uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ - uint8_t smb_res; /* reserved */ - uint16_t smb_name_len; /* length of name of file */ - uint32_t smb_flags; /* flags */ - uint32_t smb_root_fid; /* fid for previously opened directory */ - uint32_t smb_access; /* specifies the type of file access */ - uint64_t smb_alloc_size; /* initial allocation size of the file */ - uint32_t smb_file_attrs; /* specifies the file attributes for the file */ - uint32_t smb_share_access; /* the type of share access */ - uint32_t smb_create_disp; /* actions to take if file does or does not exist */ - uint32_t smb_create_opts; /* options used when creating or opening file */ - uint32_t smb_impersonation_level; /* security impersonation level */ - uint8_t smb_security_flags; /* security flags */ - uint16_t smb_bcc; /* byte count */ -}; - -struct SmbNtCreateAndXResp /* smb_wct = 34 */ -{ - uint8_t smb_wct; - uint8_t smb_com2; - uint8_t smb_res2; - uint16_t smb_off2; - uint8_t smb_oplock_level; - uint16_t smb_fid; - uint32_t smb_create_disposition; - uint64_t smb_creation_time; - uint64_t smb_last_access_time; - uint64_t smb_last_write_time; - uint64_t smb_change_time; - uint32_t smb_file_attrs; - uint64_t smb_alloc_size; - uint64_t smb_eof; - uint16_t smb_resource_type; - uint16_t smb_nm_pipe_state; - uint8_t smb_directory; - uint16_t smb_bcc; -}; - -// Word count is always set to 42 though there are actually 50 words -struct SmbNtCreateAndXExtResp /* smb_wct = 42 */ -{ - uint8_t smb_wct; - uint8_t smb_com2; - uint8_t smb_res2; - uint16_t smb_off2; - uint8_t smb_oplock_level; - uint16_t smb_fid; - uint32_t smb_create_disposition; - uint64_t smb_creation_time; - uint64_t smb_last_access_time; - uint64_t smb_last_write_time; - uint64_t smb_change_time; - uint32_t smb_file_attrs; - uint64_t smb_alloc_size; - uint64_t smb_eof; - uint16_t smb_resource_type; - uint16_t smb_nm_pipe_state; - uint8_t smb_directory; - uint8_t smb_volume_guid[16]; - uint64_t smb_fileid; - uint32_t smb_max_access_rights; - uint32_t smb_guest_access_rights; - uint16_t smb_bcc; -}; - -inline uint16_t SmbNtCreateAndXReqFileNameLen(const SmbNtCreateAndXReq* req) -{ - return alignedNtohs(&req->smb_name_len); -} - -inline uint32_t SmbNtCreateAndXReqCreateDisposition(const SmbNtCreateAndXReq* req) -{ - return alignedNtohl(&req->smb_create_disp); -} - -inline bool SmbCreateDispositionRead(const uint32_t create_disposition) -{ - return (create_disposition == SMB_CREATE_DISPOSITSION__FILE_OPEN) - || (create_disposition > SMB_CREATE_DISPOSITSION__FILE_OVERWRITE_IF); -} - -inline uint64_t SmbNtCreateAndXReqAllocSize(const SmbNtCreateAndXReq* req) -{ - return alignedNtohq(&req->smb_alloc_size); -} - -inline bool SmbNtCreateAndXReqSequentialOnly(const SmbNtCreateAndXReq* req) -{ - return (alignedNtohl(&req->smb_create_opts) & SMB_CREATE_OPTIONS__FILE_SEQUENTIAL_ONLY); -} - -inline uint32_t SmbNtCreateAndXReqFileAttrs(const SmbNtCreateAndXReq* req) -{ - return alignedNtohl(&req->smb_file_attrs); -} - -inline uint16_t SmbNtCreateAndXRespFid(const SmbNtCreateAndXResp* resp) -{ - return alignedNtohs(&resp->smb_fid); -} - -inline uint32_t SmbNtCreateAndXRespCreateDisposition(const SmbNtCreateAndXResp* resp) -{ - return alignedNtohl(&resp->smb_create_disposition); -} - -inline bool SmbNtCreateAndXRespDirectory(const SmbNtCreateAndXResp* resp) -{ - return (resp->smb_directory ? true : false); -} - -inline uint16_t SmbNtCreateAndXRespResourceType(const SmbNtCreateAndXResp* resp) -{ - return alignedNtohs(&resp->smb_resource_type); -} - -inline uint64_t SmbNtCreateAndXRespEndOfFile(const SmbNtCreateAndXResp* resp) -{ - return alignedNtohq(&resp->smb_eof); -} - -/******************************************************************** - * SMB_COM_TRANSACTION - ********************************************************************/ -struct SmbTransactionReq /* smb_wct = 14 + value of smb_suwcnt */ -{ - /* Note all subcommands use a setup count of 2 */ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint16_t smb_tpscnt; /* total number of parameter bytes being sent */ - uint16_t smb_tdscnt; /* total number of data bytes being sent */ - uint16_t smb_mprcnt; /* max number of parameter bytes to return */ - uint16_t smb_mdrcnt; /* max number of data bytes to return */ - uint8_t smb_msrcnt; /* max number of setup words to return */ - uint8_t smb_rsvd; /* reserved (pad above to word) */ - uint16_t smb_flags; /* additional information: - bit 0 - if set, also disconnect TID in smb_tid - bit 1 - if set, transaction is one way (no final response) */ - uint32_t smb_timeout; /* number of milliseconds to wait for completion */ - uint16_t smb_rsvd1; /* reserved */ - uint16_t smb_pscnt; /* number of parameter bytes being sent this buffer */ - uint16_t smb_psoff; /* offset (from start of SMB hdr) to parameter bytes */ - uint16_t smb_dscnt; /* number of data bytes being sent this buffer */ - uint16_t smb_dsoff; /* offset (from start of SMB hdr) to data bytes */ - uint8_t smb_suwcnt; /* set up word count */ - uint8_t smb_rsvd2; /* reserved (pad above to word) */ - uint16_t smb_setup1; /* function (see below) - TRANS_SET_NM_PIPE_STATE = 0x0001 - TRANS_RAW_READ_NMPIPE = 0x0011 - TRANS_QUERY_NMPIPE_STATE = 0x0021 - TRANS_QUERY_NMPIPE_INFO = 0x0022 - TRANS_PEEK_NMPIPE = 0x0023 - TRANS_TRANSACT_NMPIPE = 0x0026 - TRANS_RAW_WRITE_NMPIPE = 0x0031 - TRANS_READ_NMPIPE = 0x0036 - TRANS_WRITE_NMPIPE = 0x0037 - TRANS_WAIT_NMPIPE = 0x0053 - TRANS_CALL_NMPIPE = 0x0054 */ - uint16_t smb_setup2; /* FID (handle) of pipe (if needed), or priority */ - uint16_t smb_bcc; /* total bytes (including pad bytes) following */ -}; - -struct SmbTransactionInterimResp /* smb_wct = 0 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint16_t smb_bcc; /* must be 0 */ -}; - -struct SmbTransactionResp /* smb_wct = 10 + value of smb_suwcnt */ -{ - /* Note all subcommands use a setup count of 0 */ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint16_t smb_tprcnt; /* total number of parameter bytes being returned */ - uint16_t smb_tdrcnt; /* total number of data bytes being returned */ - uint16_t smb_rsvd; /* reserved */ - uint16_t smb_prcnt; /* number of parameter bytes being returned this buf */ - uint16_t smb_proff; /* offset (from start of SMB hdr) to parameter bytes */ - uint16_t smb_prdisp; /* byte displacement for these parameter bytes */ - uint16_t smb_drcnt; /* number of data bytes being returned this buffer */ - uint16_t smb_droff; /* offset (from start of SMB hdr) to data bytes */ - uint16_t smb_drdisp; /* byte displacement for these data bytes */ - uint8_t smb_suwcnt; /* set up return word count */ - uint8_t smb_rsvd1; /* reserved (pad above to word) */ - uint16_t smb_bcc; /* total bytes (including pad bytes) following */ -}; - -inline uint16_t SmbTransactionReqSubCom(const SmbTransactionReq* req) -{ - return alignedNtohs(&req->smb_setup1); -} - -inline uint16_t SmbTransactionReqFid(const SmbTransactionReq* req) -{ - return alignedNtohs(&req->smb_setup2); -} - -inline bool SmbTransactionReqDisconnectTid(const SmbTransactionReq* req) -{ - return alignedNtohs(&req->smb_flags) & 0x0001 ? true : false; -} - -inline bool SmbTransactionReqOneWay(const SmbTransactionReq* req) -{ - return alignedNtohs(&req->smb_flags) & 0x0002 ? true : false; -} - -inline uint8_t SmbTransactionReqSetupCnt(const SmbTransactionReq* req) -{ - return req->smb_suwcnt; -} - -inline uint16_t SmbTransactionReqTotalDataCnt(const SmbTransactionReq* req) -{ - return alignedNtohs(&req->smb_tdscnt); -} - -inline uint16_t SmbTransactionReqDataCnt(const SmbTransactionReq* req) -{ - return alignedNtohs(&req->smb_dscnt); -} - -inline uint16_t SmbTransactionReqDataOff(const SmbTransactionReq* req) -{ - return alignedNtohs(&req->smb_dsoff); -} - -inline uint16_t SmbTransactionReqTotalParamCnt(const SmbTransactionReq* req) -{ - return alignedNtohs(&req->smb_tpscnt); -} - -inline uint16_t SmbTransactionReqParamCnt(const SmbTransactionReq* req) -{ - return alignedNtohs(&req->smb_pscnt); -} - -inline uint16_t SmbTransactionReqParamOff(const SmbTransactionReq* req) -{ - return alignedNtohs(&req->smb_psoff); -} - -inline uint16_t SmbTransactionRespTotalDataCnt(const SmbTransactionResp* resp) -{ - return alignedNtohs(&resp->smb_tdrcnt); -} - -inline uint16_t SmbTransactionRespDataCnt(const SmbTransactionResp* resp) -{ - return alignedNtohs(&resp->smb_drcnt); -} - -inline uint16_t SmbTransactionRespDataOff(const SmbTransactionResp* resp) -{ - return alignedNtohs(&resp->smb_droff); -} - -inline uint16_t SmbTransactionRespDataDisp(const SmbTransactionResp* resp) -{ - return alignedNtohs(&resp->smb_drdisp); -} - -inline uint16_t SmbTransactionRespTotalParamCnt(const SmbTransactionResp* resp) -{ - return alignedNtohs(&resp->smb_tprcnt); -} - -inline uint16_t SmbTransactionRespParamCnt(const SmbTransactionResp* resp) -{ - return alignedNtohs(&resp->smb_prcnt); -} - -inline uint16_t SmbTransactionRespParamOff(const SmbTransactionResp* resp) -{ - return alignedNtohs(&resp->smb_proff); -} - -inline uint16_t SmbTransactionRespParamDisp(const SmbTransactionResp* resp) -{ - return alignedNtohs(&resp->smb_prdisp); -} - -// Flags for TRANS_SET_NMPIPE_STATE parameters -#define PIPE_STATE_NON_BLOCKING 0x8000 -#define PIPE_STATE_MESSAGE_MODE 0x0100 - -/******************************************************************** - * SMB_COM_TRANSACTION2 - ********************************************************************/ -struct SmbTransaction2Req -{ - uint8_t smb_wct; - uint16_t smb_total_param_count; - uint16_t smb_total_data_count; - uint16_t smb_max_param_count; - uint16_t smb_max_data_count; - uint8_t smb_max_setup_count; - uint8_t smb_res; - uint16_t smb_flags; - uint32_t smb_timeout; - uint16_t smb_res2; - uint16_t smb_param_count; - uint16_t smb_param_offset; - uint16_t smb_data_count; - uint16_t smb_data_offset; - uint8_t smb_setup_count; /* Should be 1 for all subcommands */ - uint8_t smb_res3; - uint16_t smb_setup; /* This is the subcommand */ - uint16_t smb_bcc; -}; - -struct SmbTransaction2InterimResp -{ - uint8_t smb_wct; - uint16_t smb_bcc; -}; - -struct SmbTransaction2Resp -{ - uint8_t smb_wct; - uint16_t smb_total_param_count; - uint16_t smb_total_data_count; - uint16_t smb_res; - uint16_t smb_param_count; - uint16_t smb_param_offset; - uint16_t smb_param_disp; - uint16_t smb_data_count; - uint16_t smb_data_offset; - uint16_t smb_data_disp; - uint16_t smb_setup_count; /* 0 or 1 word */ - uint8_t smb_res2; -}; - -inline uint16_t SmbTransaction2ReqSubCom(const SmbTransaction2Req* req) -{ - return alignedNtohs(&req->smb_setup); -} - -inline uint16_t SmbTransaction2ReqTotalParamCnt(const SmbTransaction2Req* req) -{ - return alignedNtohs(&req->smb_total_param_count); -} - -inline uint16_t SmbTransaction2ReqParamCnt(const SmbTransaction2Req* req) -{ - return alignedNtohs(&req->smb_param_count); -} - -inline uint16_t SmbTransaction2ReqParamOff(const SmbTransaction2Req* req) -{ - return alignedNtohs(&req->smb_param_offset); -} - -inline uint16_t SmbTransaction2ReqTotalDataCnt(const SmbTransaction2Req* req) -{ - return alignedNtohs(&req->smb_total_data_count); -} - -inline uint16_t SmbTransaction2ReqDataCnt(const SmbTransaction2Req* req) -{ - return alignedNtohs(&req->smb_data_count); -} - -inline uint16_t SmbTransaction2ReqDataOff(const SmbTransaction2Req* req) -{ - return alignedNtohs(&req->smb_data_offset); -} - -inline uint8_t SmbTransaction2ReqSetupCnt(const SmbTransaction2Req* req) -{ - return req->smb_setup_count; -} - -inline uint16_t SmbTransaction2RespTotalParamCnt(const SmbTransaction2Resp* resp) -{ - return alignedNtohs(&resp->smb_total_param_count); -} - -inline uint16_t SmbTransaction2RespParamCnt(const SmbTransaction2Resp* resp) -{ - return alignedNtohs(&resp->smb_param_count); -} - -inline uint16_t SmbTransaction2RespParamOff(const SmbTransaction2Resp* resp) -{ - return alignedNtohs(&resp->smb_param_offset); -} - -inline uint16_t SmbTransaction2RespParamDisp(const SmbTransaction2Resp* resp) -{ - return alignedNtohs(&resp->smb_param_disp); -} - -inline uint16_t SmbTransaction2RespTotalDataCnt(const SmbTransaction2Resp* resp) -{ - return alignedNtohs(&resp->smb_total_data_count); -} - -inline uint16_t SmbTransaction2RespDataCnt(const SmbTransaction2Resp* resp) -{ - return alignedNtohs(&resp->smb_data_count); -} - -inline uint16_t SmbTransaction2RespDataOff(const SmbTransaction2Resp* resp) -{ - return alignedNtohs(&resp->smb_data_offset); -} - -inline uint16_t SmbTransaction2RespDataDisp(const SmbTransaction2Resp* resp) -{ - return alignedNtohs(&resp->smb_data_disp); -} - -struct SmbTrans2Open2ReqParams -{ - uint16_t Flags; - uint16_t AccessMode; - uint16_t Reserved1; - uint16_t FileAttributes; - uint32_t CreationTime; - uint16_t OpenMode; - uint32_t AllocationSize; - uint16_t Reserved[5]; -}; - -typedef SmbTransaction2Req SmbTrans2Open2Req; - -inline uint16_t SmbTrans2Open2ReqAccessMode(const SmbTrans2Open2ReqParams* req) -{ - return alignedNtohs(&req->AccessMode); -} - -inline uint16_t SmbTrans2Open2ReqFileAttrs(const SmbTrans2Open2ReqParams* req) -{ - return alignedNtohs(&req->FileAttributes); -} - -inline uint16_t SmbTrans2Open2ReqOpenMode(const SmbTrans2Open2ReqParams* req) -{ - return alignedNtohs(&req->OpenMode); -} - -inline uint32_t SmbTrans2Open2ReqAllocSize(const SmbTrans2Open2ReqParams* req) -{ - return alignedNtohl(&req->AllocationSize); -} - -struct SmbTrans2Open2RespParams -{ - uint16_t smb_fid; - uint16_t file_attributes; - uint32_t creation_time; - uint32_t file_data_size; - uint16_t access_mode; - uint16_t resource_type; - uint16_t nm_pipe_status; - uint16_t action_taken; - uint32_t reserved; - uint16_t extended_attribute_error_offset; - uint32_t extended_attribute_length; -}; - -inline uint16_t SmbTrans2Open2RespFid(const SmbTrans2Open2RespParams* resp) -{ - return alignedNtohs(&resp->smb_fid); -} - -inline uint16_t SmbTrans2Open2RespFileAttrs(const SmbTrans2Open2RespParams* resp) -{ - return alignedNtohs(&resp->file_attributes); -} - -inline uint32_t SmbTrans2Open2RespFileDataSize(const SmbTrans2Open2RespParams* resp) -{ - return alignedNtohl(&resp->file_data_size); -} - -inline uint16_t SmbTrans2Open2RespResourceType(const SmbTrans2Open2RespParams* resp) -{ - return alignedNtohs(&resp->resource_type); -} - -inline uint16_t SmbTrans2Open2RespActionTaken(const SmbTrans2Open2RespParams* resp) -{ - return alignedNtohs(&resp->action_taken); -} - -struct SmbTrans2Open2Resp -{ - uint8_t smb_wct; - uint16_t smb_total_param_count; - uint16_t smb_total_data_count; - uint16_t smb_res; - uint16_t smb_param_count; - uint16_t smb_param_offset; - uint16_t smb_param_disp; - uint16_t smb_data_count; - uint16_t smb_data_offset; - uint16_t smb_data_disp; - uint16_t smb_setup_count; /* 0 */ - uint8_t smb_res2; - uint16_t smb_bcc; -}; - -// See MS-CIFS Section 2.2.2.3.3 -#define SMB_INFO_STANDARD 0x0001 -#define SMB_INFO_QUERY_EA_SIZE 0x0002 -#define SMB_INFO_QUERY_EAS_FROM_LIST 0x0003 -#define SMB_INFO_QUERY_ALL_EAS 0x0004 -#define SMB_INFO_IS_NAME_VALID 0x0006 -#define SMB_QUERY_FILE_BASIC_INFO 0x0101 -#define SMB_QUERY_FILE_STANDARD_INFO 0x0102 -#define SMB_QUERY_FILE_EA_INFO 0x0103 -#define SMB_QUERY_FILE_NAME_INFO 0x0104 -#define SMB_QUERY_FILE_ALL_INFO 0x0107 -#define SMB_QUERY_FILE_ALT_NAME_INFO 0x0108 -#define SMB_QUERY_FILE_STREAM_INFO 0x0109 -#define SMB_QUERY_FILE_COMPRESSION_INFO 0x010b - -// See MS-SMB Section 2.2.2.3.5 -// For added value, see below from MS-FSCC -#define SMB_INFO_PASSTHROUGH 0x03e8 -#define SMB_INFO_PT_FILE_STANDARD_INFO SMB_INFO_PASSTHROUGH+5 -#define SMB_INFO_PT_FILE_ALL_INFO SMB_INFO_PASSTHROUGH+18 -#define SMB_INFO_PT_FILE_STREAM_INFO SMB_INFO_PASSTHROUGH+22 -#define SMB_INFO_PT_NETWORK_OPEN_INFO SMB_INFO_PASSTHROUGH+34 - -struct SmbTrans2QueryFileInfoReqParams -{ - uint16_t fid; - uint16_t information_level; -}; - -inline uint16_t SmbTrans2QueryFileInfoReqFid(const SmbTrans2QueryFileInfoReqParams* req) -{ - return alignedNtohs(&req->fid); -} - -inline uint16_t SmbTrans2QueryFileInfoReqInfoLevel(const SmbTrans2QueryFileInfoReqParams* req) -{ - return alignedNtohs(&req->information_level); -} - -struct SmbQueryInfoStandard -{ - uint16_t CreationDate; - uint16_t CreationTime; - uint16_t LastAccessDate; - uint16_t LastAccessTime; - uint16_t LastWriteDate; - uint16_t LastWriteTime; - uint32_t FileDataSize; - uint32_t AllocationSize; - uint16_t Attributes; -}; - -inline uint32_t SmbQueryInfoStandardFileDataSize(const SmbQueryInfoStandard* q) -{ - return alignedNtohl(&q->FileDataSize); -} - -struct SmbQueryInfoQueryEaSize -{ - uint16_t CreationDate; - uint16_t CreationTime; - uint16_t LastAccessDate; - uint16_t LastAccessTime; - uint16_t LastWriteDate; - uint16_t LastWriteTime; - uint32_t FileDataSize; - uint32_t AllocationSize; - uint16_t Attributes; - uint32_t EaSize; -}; - -inline uint32_t SmbQueryInfoQueryEaSizeFileDataSize(const SmbQueryInfoQueryEaSize* q) -{ - return alignedNtohl(&q->FileDataSize); -} - -struct SmbQueryFileStandardInfo -{ - uint64_t AllocationSize; - uint64_t EndOfFile; - uint32_t NumberOfLinks; - uint8_t DeletePending; - uint8_t Directory; - uint16_t Reserved; -}; - -inline uint64_t SmbQueryFileStandardInfoEndOfFile(const SmbQueryFileStandardInfo* q) -{ - return alignedNtohq(&q->EndOfFile); -} - -struct SmbQueryFileAllInfo -{ - // Basic Info - uint64_t CreationTime; - uint64_t LastAccessTime; - uint64_t LastWriteTime; - uint64_t LastChangeTime; - uint32_t ExtFileAttributes; - uint32_t Reserved1; - uint64_t AllocationSize; - uint64_t EndOfFile; - uint32_t NumberOfLinks; - uint8_t DeletePending; - uint8_t Directory; - uint16_t Reserved2; - uint32_t EaSize; - uint32_t FileNameLength; -}; - -inline uint64_t SmbQueryFileAllInfoEndOfFile(const SmbQueryFileAllInfo* q) -{ - return alignedNtohq(&q->EndOfFile); -} - -struct SmbQueryPTFileAllInfo -{ - // Basic Info - uint64_t CreationTime; - uint64_t LastAccessTime; - uint64_t LastWriteTime; - uint64_t LastChangeTime; - uint32_t ExtFileAttributes; - uint32_t Reserved1; - - // Standard Info - uint64_t AllocationSize; - uint64_t EndOfFile; - uint32_t NumberOfLinks; - uint8_t DeletePending; - uint8_t Directory; - uint16_t Reserved2; - - // Internal Info - uint64_t IndexNumber; - - // EA Info - uint32_t EaSize; - - // Access Info - uint32_t AccessFlags; - - // Position Info - uint64_t CurrentByteOffset; - - // Mode Info - uint32_t Mode; - - // Alignment Info - uint32_t AlignmentRequirement; - - // Name Info - uint32_t FileNameLength; -}; - -inline uint64_t SmbQueryPTFileAllInfoEndOfFile(const SmbQueryPTFileAllInfo* q) -{ - return alignedNtohq(&q->EndOfFile); -} - -struct SmbQueryPTNetworkOpenInfo -{ - uint64_t CreationTime; - uint64_t LastAccessTime; - uint64_t LastWriteTime; - uint64_t LastChangeTime; - uint64_t AllocationSize; - uint64_t EndOfFile; - uint32_t FileAttributes; - uint32_t Reserved; -}; - -inline uint64_t SmbQueryPTNetworkOpenInfoEndOfFile(const SmbQueryPTNetworkOpenInfo* q) -{ - return alignedNtohq(&q->EndOfFile); -} - -struct SmbQueryPTFileStreamInfo -{ - uint32_t NextEntryOffset; - uint32_t StreamNameLength; - uint64_t StreamSize; - uint64_t StreamAllocationSize; -}; - -inline uint64_t SmbQueryPTFileStreamInfoStreamSize(const SmbQueryPTFileStreamInfo* q) -{ - return alignedNtohq(&q->StreamSize); -} - -struct SmbTrans2QueryFileInformationResp -{ - uint8_t smb_wct; - uint16_t smb_total_param_count; - uint16_t smb_total_data_count; - uint16_t smb_res; - uint16_t smb_param_count; - uint16_t smb_param_offset; - uint16_t smb_param_disp; - uint16_t smb_data_count; - uint16_t smb_data_offset; - uint16_t smb_data_disp; - uint16_t smb_setup_count; /* 0 */ - uint8_t smb_res2; - uint16_t smb_bcc; -}; - -#define SMB_INFO_SET_EAS 0x0002 -#define SMB_SET_FILE_BASIC_INFO 0x0101 -#define SMB_SET_FILE_DISPOSITION_INFO 0x0102 -#define SMB_SET_FILE_ALLOCATION_INFO 0x0103 -#define SMB_SET_FILE_END_OF_FILE_INFO 0x0104 - -// For added value, see above File Information Classes -#define SMB_INFO_PT_SET_FILE_BASIC_FILE_INFO SMB_INFO_PASSTHROUGH+4 -#define SMB_INFO_PT_SET_FILE_END_OF_FILE_INFO SMB_INFO_PASSTHROUGH+20 - -struct SmbTrans2SetFileInfoReqParams -{ - uint16_t fid; - uint16_t information_level; - uint16_t reserved; -}; - -inline uint16_t SmbTrans2SetFileInfoReqFid(const SmbTrans2SetFileInfoReqParams* req) -{ - return alignedNtohs(&req->fid); -} - -inline uint16_t SmbTrans2SetFileInfoReqInfoLevel(const SmbTrans2SetFileInfoReqParams* req) -{ - return alignedNtohs(&req->information_level); -} - -inline bool SmbSetFileInfoEndOfFile(const uint16_t info_level) -{ - return ((info_level == SMB_SET_FILE_END_OF_FILE_INFO) - || (info_level == SMB_INFO_PT_SET_FILE_END_OF_FILE_INFO)); -} - -struct SmbSetFileBasicInfo -{ - uint64_t CreationTime; - uint64_t LastAccessTime; - uint64_t LastWriteTime; - uint64_t ChangeTime; - uint32_t ExtFileAttributes; - uint32_t Reserved; -}; - -inline uint32_t SmbSetFileInfoExtFileAttrs(const SmbSetFileBasicInfo* info) -{ - return alignedNtohl(&info->ExtFileAttributes); -} - -inline bool SmbSetFileInfoSetFileBasicInfo(const uint16_t info_level) -{ - return ((info_level == SMB_SET_FILE_BASIC_INFO) - || (info_level == SMB_INFO_PT_SET_FILE_BASIC_FILE_INFO)); -} - -/******************************************************************** - * SMB_COM_NT_TRANSACT - ********************************************************************/ -#define SMB_CREATE_OPTIONS__FILE_SEQUENTIAL_ONLY 0x00000004 - -struct SmbNtTransactReq -{ - uint8_t smb_wct; - uint8_t smb_max_setup_count; - uint16_t smb_res; - uint32_t smb_total_param_count; - uint32_t smb_total_data_count; - uint32_t smb_max_param_count; - uint32_t smb_max_data_count; - uint32_t smb_param_count; - uint32_t smb_param_offset; - uint32_t smb_data_count; - uint32_t smb_data_offset; - uint8_t smb_setup_count; - uint16_t smb_function; -}; - -struct SmbNtTransactInterimResp -{ - uint8_t smb_wct; - uint16_t smb_bcc; -}; - -struct SmbNtTransactResp -{ - uint8_t smb_wct; - uint8_t smb_res[3]; - uint32_t smb_total_param_count; - uint32_t smb_total_data_count; - uint32_t smb_param_count; - uint32_t smb_param_offset; - uint32_t smb_param_disp; - uint32_t smb_data_count; - uint32_t smb_data_offset; - uint32_t smb_data_disp; - uint8_t smb_setup_count; -}; - -inline uint16_t SmbNtTransactReqSubCom(const SmbNtTransactReq* req) -{ - return alignedNtohs(&req->smb_function); -} - -inline uint8_t SmbNtTransactReqSetupCnt(const SmbNtTransactReq* req) -{ - return req->smb_setup_count; -} - -inline uint32_t SmbNtTransactReqTotalParamCnt(const SmbNtTransactReq* req) -{ - return alignedNtohl(&req->smb_total_param_count); -} - -inline uint32_t SmbNtTransactReqParamCnt(const SmbNtTransactReq* req) -{ - return alignedNtohl(&req->smb_param_count); -} - -inline uint32_t SmbNtTransactReqParamOff(const SmbNtTransactReq* req) -{ - return alignedNtohl(&req->smb_param_offset); -} - -inline uint32_t SmbNtTransactReqTotalDataCnt(const SmbNtTransactReq* req) -{ - return alignedNtohl(&req->smb_total_data_count); -} - -inline uint32_t SmbNtTransactReqDataCnt(const SmbNtTransactReq* req) -{ - return alignedNtohl(&req->smb_data_count); -} - -inline uint32_t SmbNtTransactReqDataOff(const SmbNtTransactReq* req) -{ - return alignedNtohl(&req->smb_data_offset); -} - -inline uint32_t SmbNtTransactRespTotalParamCnt(const SmbNtTransactResp* resp) -{ - return alignedNtohl(&resp->smb_total_param_count); -} - -inline uint32_t SmbNtTransactRespParamCnt(const SmbNtTransactResp* resp) -{ - return alignedNtohl(&resp->smb_param_count); -} - -inline uint32_t SmbNtTransactRespParamOff(const SmbNtTransactResp* resp) -{ - return alignedNtohl(&resp->smb_param_offset); -} - -inline uint32_t SmbNtTransactRespParamDisp(const SmbNtTransactResp* resp) -{ - return alignedNtohl(&resp->smb_param_disp); -} - -inline uint32_t SmbNtTransactRespTotalDataCnt(const SmbNtTransactResp* resp) -{ - return alignedNtohl(&resp->smb_total_data_count); -} - -inline uint32_t SmbNtTransactRespDataCnt(const SmbNtTransactResp* resp) -{ - return alignedNtohl(&resp->smb_data_count); -} - -inline uint32_t SmbNtTransactRespDataOff(const SmbNtTransactResp* resp) -{ - return alignedNtohl(&resp->smb_data_offset); -} - -inline uint32_t SmbNtTransactRespDataDisp(const SmbNtTransactResp* resp) -{ - return alignedNtohl(&resp->smb_data_disp); -} - -struct SmbNtTransactCreateReqParams -{ - uint32_t flags; - uint32_t root_dir_fid; - uint32_t desired_access; - uint64_t allocation_size; - uint32_t ext_file_attributes; - uint32_t share_access; - uint32_t create_disposition; - uint32_t create_options; - uint32_t security_descriptor_length; - uint32_t ea_length; - uint32_t name_length; - uint32_t impersonation_level; - uint8_t security_flags; -}; - -inline uint64_t SmbNtTransactCreateReqAllocSize(const SmbNtTransactCreateReqParams* req) -{ - return alignedNtohq(&req->allocation_size); -} - -inline uint32_t SmbNtTransactCreateReqFileNameLength(const SmbNtTransactCreateReqParams* req) -{ - return alignedNtohl(&req->name_length); -} - -inline uint32_t SmbNtTransactCreateReqFileAttrs(const SmbNtTransactCreateReqParams* req) -{ - return alignedNtohl(&req->ext_file_attributes); -} - -inline bool SmbNtTransactCreateReqSequentialOnly(const SmbNtTransactCreateReqParams* req) -{ - return (alignedNtohl(&req->create_options) & SMB_CREATE_OPTIONS__FILE_SEQUENTIAL_ONLY); -} - -struct SmbNtTransactCreateReq -{ - uint8_t smb_wct; - uint8_t smb_max_setup_count; - uint16_t smb_res; - uint32_t smb_total_param_count; - uint32_t smb_total_data_count; - uint32_t smb_max_param_count; - uint32_t smb_max_data_count; - uint32_t smb_param_count; - uint32_t smb_param_offset; - uint32_t smb_data_count; - uint32_t smb_data_offset; - uint8_t smb_setup_count; /* Must be 0x00 */ - uint16_t smb_function; /* NT_TRANSACT_CREATE */ - uint16_t smb_bcc; -}; - -struct SmbNtTransactCreateRespParams -{ - uint8_t op_lock_level; - uint8_t reserved; - uint16_t smb_fid; - uint32_t create_action; - uint32_t ea_error_offset; - uint64_t creation_time; - uint64_t last_access_time; - uint64_t last_write_time; - uint64_t last_change_time; - uint32_t ext_file_attributes; - uint64_t allocation_size; - uint64_t end_of_file; - uint16_t resource_type; - uint16_t nm_pipe_status; - uint8_t directory; -}; - -inline uint16_t SmbNtTransactCreateRespFid(const SmbNtTransactCreateRespParams* resp) -{ - return alignedNtohs(&resp->smb_fid); -} - -inline uint32_t SmbNtTransactCreateRespCreateAction(const SmbNtTransactCreateRespParams* resp) -{ - return alignedNtohl(&resp->create_action); -} - -inline uint64_t SmbNtTransactCreateRespEndOfFile(const SmbNtTransactCreateRespParams* resp) -{ - return alignedNtohq(&resp->end_of_file); -} - -inline uint16_t SmbNtTransactCreateRespResourceType(const SmbNtTransactCreateRespParams* resp) -{ - return alignedNtohs(&resp->resource_type); -} - -inline bool SmbNtTransactCreateRespDirectory(const SmbNtTransactCreateRespParams* resp) -{ - return (resp->directory ? true : false); -} - -struct SmbNtTransactCreateResp -{ - uint8_t smb_wct; - uint8_t smb_res[3]; - uint32_t smb_total_param_count; - uint32_t smb_total_data_count; - uint32_t smb_param_count; - uint32_t smb_param_offset; - uint32_t smb_param_disp; - uint32_t smb_data_count; - uint32_t smb_data_offset; - uint32_t smb_data_disp; - uint8_t smb_setup_count; /* 0x00 */ - uint16_t smb_bcc; -}; - -/******************************************************************** - * SMB_COM_TRANSACTION_SECONDARY - * Continuation command for SMB_COM_TRANSACTION requests if all - * data wasn't sent. - ********************************************************************/ -struct SmbTransactionSecondaryReq /* smb_wct = 8 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint16_t smb_tpscnt; /* total number of parameter bytes being sent */ - uint16_t smb_tdscnt; /* total number of data bytes being sent */ - uint16_t smb_pscnt; /* number of parameter bytes being sent this buffer */ - uint16_t smb_psoff; /* offset (from start of SMB hdr) to parameter bytes */ - uint16_t smb_psdisp; /* byte displacement for these parameter bytes */ - uint16_t smb_dscnt; /* number of data bytes being sent this buffer */ - uint16_t smb_dsoff; /* offset (from start of SMB hdr) to data bytes */ - uint16_t smb_dsdisp; /* byte displacement for these data bytes */ - uint16_t smb_bcc; /* total bytes (including pad bytes) following */ -}; - -inline uint16_t SmbTransactionSecondaryReqTotalDataCnt(const SmbTransactionSecondaryReq* req) -{ - return alignedNtohs(&req->smb_tdscnt); -} - -inline uint16_t SmbTransactionSecondaryReqDataCnt(const SmbTransactionSecondaryReq* req) -{ - return alignedNtohs(&req->smb_dscnt); -} - -inline uint16_t SmbTransactionSecondaryReqDataOff(const SmbTransactionSecondaryReq* req) -{ - return alignedNtohs(&req->smb_dsoff); -} - -inline uint16_t SmbTransactionSecondaryReqDataDisp(const SmbTransactionSecondaryReq* req) -{ - return alignedNtohs(&req->smb_dsdisp); -} - -inline uint16_t SmbTransactionSecondaryReqTotalParamCnt(const SmbTransactionSecondaryReq* req) -{ - return alignedNtohs(&req->smb_tpscnt); -} - -inline uint16_t SmbTransactionSecondaryReqParamCnt(const SmbTransactionSecondaryReq* req) -{ - return alignedNtohs(&req->smb_pscnt); -} - -inline uint16_t SmbTransactionSecondaryReqParamOff(const SmbTransactionSecondaryReq* req) -{ - return alignedNtohs(&req->smb_psoff); -} - -inline uint16_t SmbTransactionSecondaryReqParamDisp(const SmbTransactionSecondaryReq* req) -{ - return alignedNtohs(&req->smb_psdisp); -} - -/******************************************************************** - * SMB_COM_TRANSACTION2_SECONDARY - * Continuation command for SMB_COM_TRANSACTION2 requests if all - * data wasn't sent. - ********************************************************************/ -struct SmbTransaction2SecondaryReq -{ - uint8_t smb_wct; - uint16_t smb_total_param_count; - uint16_t smb_total_data_count; - uint16_t smb_param_count; - uint16_t smb_param_offset; - uint16_t smb_param_disp; - uint16_t smb_data_count; - uint16_t smb_data_offset; - uint16_t smb_data_disp; - uint16_t smb_fid; - uint16_t smb_bcc; -}; - -inline uint16_t SmbTransaction2SecondaryReqTotalParamCnt(const SmbTransaction2SecondaryReq* req) -{ - return alignedNtohs(&req->smb_total_param_count); -} - -inline uint16_t SmbTransaction2SecondaryReqParamCnt(const SmbTransaction2SecondaryReq* req) -{ - return alignedNtohs(&req->smb_param_count); -} - -inline uint16_t SmbTransaction2SecondaryReqParamOff(const SmbTransaction2SecondaryReq* req) -{ - return alignedNtohs(&req->smb_param_offset); -} - -inline uint16_t SmbTransaction2SecondaryReqParamDisp(const SmbTransaction2SecondaryReq* req) -{ - return alignedNtohs(&req->smb_param_disp); -} - -inline uint16_t SmbTransaction2SecondaryReqTotalDataCnt(const SmbTransaction2SecondaryReq* req) -{ - return alignedNtohs(&req->smb_total_data_count); -} - -inline uint16_t SmbTransaction2SecondaryReqDataCnt(const SmbTransaction2SecondaryReq* req) -{ - return alignedNtohs(&req->smb_data_count); -} - -inline uint16_t SmbTransaction2SecondaryReqDataOff(const SmbTransaction2SecondaryReq* req) -{ - return alignedNtohs(&req->smb_data_offset); -} - -inline uint16_t SmbTransaction2SecondaryReqDataDisp(const SmbTransaction2SecondaryReq* req) -{ - return alignedNtohs(&req->smb_data_disp); -} - -/******************************************************************** - * SMB_COM_NT_TRANSACT_SECONDARY - ********************************************************************/ -struct SmbNtTransactSecondaryReq -{ - uint8_t smb_wct; - uint8_t smb_res[3]; - uint32_t smb_total_param_count; - uint32_t smb_total_data_count; - uint32_t smb_param_count; - uint32_t smb_param_offset; - uint32_t smb_param_disp; - uint32_t smb_data_count; - uint32_t smb_data_offset; - uint32_t smb_data_disp; - uint8_t smb_res2; -}; - -inline uint32_t SmbNtTransactSecondaryReqTotalParamCnt(const SmbNtTransactSecondaryReq* req) -{ - return alignedNtohl(&req->smb_total_param_count); -} - -inline uint32_t SmbNtTransactSecondaryReqParamCnt(const SmbNtTransactSecondaryReq* req) -{ - return alignedNtohl(&req->smb_param_count); -} - -inline uint32_t SmbNtTransactSecondaryReqParamOff(const SmbNtTransactSecondaryReq* req) -{ - return alignedNtohl(&req->smb_param_offset); -} - -inline uint32_t SmbNtTransactSecondaryReqParamDisp(const SmbNtTransactSecondaryReq* req) -{ - return alignedNtohl(&req->smb_param_disp); -} - -inline uint32_t SmbNtTransactSecondaryReqTotalDataCnt(const SmbNtTransactSecondaryReq* req) -{ - return alignedNtohl(&req->smb_total_data_count); -} - -inline uint32_t SmbNtTransactSecondaryReqDataCnt(const SmbNtTransactSecondaryReq* req) -{ - return alignedNtohl(&req->smb_data_count); -} - -inline uint32_t SmbNtTransactSecondaryReqDataOff(const SmbNtTransactSecondaryReq* req) -{ - return alignedNtohl(&req->smb_data_offset); -} - -inline uint32_t SmbNtTransactSecondaryReqDataDisp(const SmbNtTransactSecondaryReq* req) -{ - return alignedNtohl(&req->smb_data_disp); -} - -/******************************************************************** - * SMB_COM_READ_RAW - ********************************************************************/ -struct SmbReadRawReq /* smb_wct = 8 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint16_t smb_fid; /* file handle */ - uint32_t smb_offset; /* offset in file to begin read */ - uint16_t smb_maxcnt; /* max number of bytes to return (max 65,535) */ - uint16_t smb_mincnt; /* min number of bytes to return (normally 0) */ - uint32_t smb_timeout; /* number of milliseconds to wait for completion */ - uint16_t smb_rsvd; /* reserved */ - uint16_t smb_bcc; /* value = 0 */ -}; - -struct SmbReadRawExtReq /* smb_wct = 10 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint16_t smb_fid; /* file handle */ - uint32_t smb_offset; /* offset in file to begin read */ - uint16_t smb_maxcnt; /* max number of bytes to return (max 65,535) */ - uint16_t smb_mincnt; /* min number of bytes to return (normally 0) */ - uint32_t smb_timeout; /* number of milliseconds to wait for completion */ - uint16_t smb_rsvd; /* reserved */ - uint32_t smb_off_high; /* high offset in file to begin write */ - uint16_t smb_bcc; /* value = 0 */ -}; - -/* Read Raw response is raw data wrapped in NetBIOS header */ - -inline uint16_t SmbReadRawReqFid(const SmbReadRawReq* req) -{ - return alignedNtohs(&req->smb_fid); -} - -inline uint64_t SmbReadRawReqOffset(const SmbReadRawExtReq* req) -{ - if (req->smb_wct == 8) - return (uint64_t)alignedNtohl(&req->smb_offset); - return (uint64_t)alignedNtohl(&req->smb_off_high) << 32 | (uint64_t)alignedNtohl( - &req->smb_offset); -} - -/******************************************************************** - * SMB_COM_WRITE_RAW - ********************************************************************/ -struct SmbWriteRawReq -{ - uint8_t smb_wct; /* value = 12 */ - uint16_t smb_fid; /* file handle */ - uint16_t smb_tcount; /* total bytes (including this buf, 65,535 max ) */ - uint16_t smb_rsvd; /* reserved */ - uint32_t smb_offset; /* offset in file to begin write */ - uint32_t smb_timeout; /* number of milliseconds to wait for completion */ - uint16_t smb_wmode; /* write mode: - bit0 - complete write to disk and send final result response - bit1 - return smb_remaining (pipes/devices only) */ - uint32_t smb_rsvd2; /* reserved */ - uint16_t smb_dsize; /* number of data bytes this buffer (min value = 0) */ - uint16_t smb_doff; /* offset (from start of SMB hdr) to data bytes */ - uint16_t smb_bcc; /* total bytes (including pad bytes) following */ -}; - -struct SmbWriteRawExtReq -{ - uint8_t smb_wct; /* value = 14 */ - uint16_t smb_fid; /* file handle */ - uint16_t smb_tcount; /* total bytes (including this buf, 65,535 max ) */ - uint16_t smb_rsvd; /* reserved */ - uint32_t smb_offset; /* offset in file to begin write */ - uint32_t smb_timeout; /* number of milliseconds to wait for completion */ - uint16_t smb_wmode; /* write mode: - bit0 - complete write to disk and send final result response - bit1 - return smb_remaining (pipes/devices only) */ - uint32_t smb_rsvd2; /* reserved */ - uint16_t smb_dsize; /* number of data bytes this buffer (min value = 0) */ - uint16_t smb_doff; /* offset (from start of SMB hdr) to data bytes */ - uint32_t smb_off_high; /* high offset in file to begin write */ - uint16_t smb_bcc; /* total bytes (including pad bytes) following */ -}; - -struct SmbWriteRawInterimResp -{ - uint8_t smb_wct; /* value = 1 */ - uint16_t smb_remaining; /* bytes remaining to be read (pipes/devices only) */ - uint16_t smb_bcc; /* value = 0 */ -}; - -inline uint16_t SmbWriteRawReqTotalCount(const SmbWriteRawReq* req) -{ - return alignedNtohs(&req->smb_tcount); -} - -inline bool SmbWriteRawReqWriteThrough(const SmbWriteRawReq* req) -{ - return alignedNtohs(&req->smb_wmode) & 0x0001; -} - -inline uint16_t SmbWriteRawReqFid(const SmbWriteRawReq* req) -{ - return alignedNtohs(&req->smb_fid); -} - -inline uint16_t SmbWriteRawReqDataOff(const SmbWriteRawReq* req) -{ - return alignedNtohs(&req->smb_doff); -} - -inline uint16_t SmbWriteRawReqDataCnt(const SmbWriteRawReq* req) -{ - return alignedNtohs(&req->smb_dsize); -} - -inline uint64_t SmbWriteRawReqOffset(const SmbWriteRawExtReq* req) -{ - if (req->smb_wct == 12) - return (uint64_t)alignedNtohl(&req->smb_offset); - return (uint64_t)alignedNtohl(&req->smb_off_high) << 32 | (uint64_t)alignedNtohl( - &req->smb_offset); -} - -inline uint16_t SmbWriteRawInterimRespRemaining(const SmbWriteRawInterimResp* resp) -{ - return alignedNtohs(&resp->smb_remaining); -} - -/******************************************************************** - * SMB_COM_WRITE_COMPLETE - final response to an SMB_COM_WRITE_RAW - ********************************************************************/ -struct SmbWriteCompleteResp -{ - uint8_t smb_wct; /* value = 1 */ - uint16_t smb_count; /* total number of bytes written */ - uint16_t smb_bcc; /* value = 0 */ -}; - -inline uint16_t SmbWriteCompleteRespCount(const SmbWriteCompleteResp* resp) -{ - return alignedNtohs(&resp->smb_count); -} - -/******************************************************************** - * SMB_COM_WRITE_AND_CLOSE - ********************************************************************/ -struct SmbWriteAndCloseReq /* smb_wct = 6 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint16_t smb_fid; /* file handle (close after write) */ - uint16_t smb_count; /* number of bytes to write */ - uint32_t smb_offset; /* offset in file to begin write */ - uint32_t smb_mtime; /* modification time */ - uint16_t smb_bcc; /* 1 (for pad) + value of smb_count */ -}; - -struct SmbWriteAndCloseExtReq /* smb_wct = 12 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint16_t smb_fid; /* file handle (close after write) */ - uint16_t smb_count; /* number of bytes to write */ - uint32_t smb_offset; /* offset in file to begin write */ - uint32_t smb_mtime; /* modification time */ - uint32_t smb_rsvd1; /* Optional */ - uint32_t smb_rsvd2; /* Optional */ - uint32_t smb_rsvd3; /* Optional */ - uint16_t smb_bcc; /* 1 (for pad) + value of smb_count */ -}; - -struct SmbWriteAndCloseResp /* smb_wct = 1 */ -{ - uint8_t smb_wct; /* count of 16-bit words that follow */ - uint16_t smb_count; /* number of bytes written */ - uint16_t smb_bcc; /* must be 0 */ -}; - -inline uint16_t SmbWriteAndCloseReqFid(const SmbWriteAndCloseReq* req) -{ - return alignedNtohs(&req->smb_fid); -} - -inline uint16_t SmbWriteAndCloseReqCount(const SmbWriteAndCloseReq* req) -{ - return alignedNtohs(&req->smb_count); -} - -inline uint32_t SmbWriteAndCloseReqOffset(const SmbWriteAndCloseReq* req) -{ - return alignedNtohl(&req->smb_offset); -} - -inline uint16_t SmbWriteAndCloseRespCount(const SmbWriteAndCloseResp* resp) -{ - return alignedNtohs(&resp->smb_count); -} - -#pragma pack() - struct DCE2_SmbFsm { char input; @@ -3065,5 +487,6 @@ public: DCE2_SmbSsnData* get_dce2_smb_session_data(Flow*); +const char* get_smb_com_string(uint8_t); #endif diff --git a/src/service_inspectors/dce_rpc/smb_common.h b/src/service_inspectors/dce_rpc/smb_common.h new file mode 100644 index 000000000..10f39d9f4 --- /dev/null +++ b/src/service_inspectors/dce_rpc/smb_common.h @@ -0,0 +1,459 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2016-2016 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// smb_common.h author Russ Combs + +// extracted from dce_smb.h originally written by Todd Wease + +#ifndef SMB_COMMON_H +#define SMB_COMMON_H + +#include + +#define SMB_MAX_NUM_COMS 256 + +#define SMB_FILE_TYPE_DISK 0x0000 +#define SMB_FILE_TYPE_BYTE_MODE_PIPE 0x0001 +#define SMB_FILE_TYPE_MESSAGE_MODE_PIPE 0x0002 +#define SMB_FILE_TYPE_PRINTER 0x0003 +#define SMB_FILE_TYPE_COMMON_DEVICE 0x0004 + +#define SMB_FILE_ATTRIBUTE_NORMAL 0x0000 +#define SMB_FILE_ATTRIBUTE_READONLY 0x0001 +#define SMB_FILE_ATTRIBUTE_HIDDEN 0x0002 +#define SMB_FILE_ATTRIBUTE_SYSTEM 0x0004 +#define SMB_FILE_ATTRIBUTE_VOLUME 0x0008 +#define SMB_FILE_ATTRIBUTE_DIRECTORY 0x0010 +#define SMB_FILE_ATTRIBUTE_ARCHIVE 0x0020 +#define SMB_SEARCH_ATTRIBUTE_READONLY 0x0100 +#define SMB_SEARCH_ATTRIBUTE_HIDDEN 0x0200 +#define SMB_SEARCH_ATTRIBUTE_SYSTEM 0x0400 +#define SMB_SEARCH_ATTRIBUTE_DIRECTORY 0x1000 +#define SMB_SEARCH_ATTRIBUTE_ARCHIVE 0x2000 +#define SMB_FILE_ATTRIBUTE_OTHER 0xC8C0 // Reserved + +#define SMB_EXT_FILE_ATTR_READONLY 0x00000001 +#define SMB_EXT_FILE_ATTR_HIDDEN 0x00000002 +#define SMB_EXT_FILE_ATTR_SYSTEM 0x00000004 +#define SMB_EXT_FILE_ATTR_DIRECTORY 0x00000010 +#define SMB_EXT_FILE_ATTR_ARCHIVE 0x00000020 +#define SMB_EXT_FILE_ATTR_NORMAL 0x00000080 +#define SMB_EXT_FILE_ATTR_TEMPORARY 0x00000100 +#define SMB_EXT_FILE_ATTR_COMPRESSED 0x00000800 +#define SMB_EXT_FILE_POSIX_SEMANTICS 0x01000000 +#define SMB_EXT_FILE_BACKUP_SEMANTICS 0x02000000 +#define SMB_EXT_FILE_DELETE_ON_CLOSE 0x04000000 +#define SMB_EXT_FILE_SEQUENTIAL_SCAN 0x08000000 +#define SMB_EXT_FILE_RANDOM_ACCESS 0x10000000 +#define SMB_EXT_FILE_NO_BUFFERING 0x20000000 +#define SMB_EXT_FILE_WRITE_THROUGH 0x80000000 + +#define NBSS_SESSION_TYPE__MESSAGE 0x00 +#define NBSS_SESSION_TYPE__REQUEST 0x81 +#define NBSS_SESSION_TYPE__POS_RESPONSE 0x82 +#define NBSS_SESSION_TYPE__NEG_RESPONSE 0x83 +#define NBSS_SESSION_TYPE__RETARGET_RESPONSE 0x84 +#define NBSS_SESSION_TYPE__KEEP_ALIVE 0x85 + +#define DCE2_SMB_ID 0xff534d42 /* \xffSMB */ +#define DCE2_SMB2_ID 0xfe534d42 /* \xfeSMB */ + +// MS-FSCC Section 2.1.5 - Pathname +#define DCE2_SMB_MAX_PATH_LEN 32760 +#define DCE2_SMB_MAX_COMP_LEN 255 + +/* SMB command codes */ +#define SMB_COM_CREATE_DIRECTORY 0x00 +#define SMB_COM_DELETE_DIRECTORY 0x01 +#define SMB_COM_OPEN 0x02 +#define SMB_COM_CREATE 0x03 +#define SMB_COM_CLOSE 0x04 +#define SMB_COM_FLUSH 0x05 +#define SMB_COM_DELETE 0x06 +#define SMB_COM_RENAME 0x07 +#define SMB_COM_QUERY_INFORMATION 0x08 +#define SMB_COM_SET_INFORMATION 0x09 +#define SMB_COM_READ 0x0A +#define SMB_COM_WRITE 0x0B +#define SMB_COM_LOCK_BYTE_RANGE 0x0C +#define SMB_COM_UNLOCK_BYTE_RANGE 0x0D +#define SMB_COM_CREATE_TEMPORARY 0x0E +#define SMB_COM_CREATE_NEW 0x0F +#define SMB_COM_CHECK_DIRECTORY 0x10 +#define SMB_COM_PROCESS_EXIT 0x11 +#define SMB_COM_SEEK 0x12 +#define SMB_COM_LOCK_AND_READ 0x13 +#define SMB_COM_WRITE_AND_UNLOCK 0x14 +#define SMB_COM_READ_RAW 0x1A +#define SMB_COM_READ_MPX 0x1B +#define SMB_COM_READ_MPX_SECONDARY 0x1C +#define SMB_COM_WRITE_RAW 0x1D +#define SMB_COM_WRITE_MPX 0x1E +#define SMB_COM_WRITE_MPX_SECONDARY 0x1F +#define SMB_COM_WRITE_COMPLETE 0x20 +#define SMB_COM_QUERY_SERVER 0x21 +#define SMB_COM_SET_INFORMATION2 0x22 +#define SMB_COM_QUERY_INFORMATION2 0x23 +#define SMB_COM_LOCKING_ANDX 0x24 +#define SMB_COM_TRANSACTION 0x25 +#define SMB_COM_TRANSACTION_SECONDARY 0x26 +#define SMB_COM_IOCTL 0x27 +#define SMB_COM_IOCTL_SECONDARY 0x28 +#define SMB_COM_COPY 0x29 +#define SMB_COM_MOVE 0x2A +#define SMB_COM_ECHO 0x2B +#define SMB_COM_WRITE_AND_CLOSE 0x2C +#define SMB_COM_OPEN_ANDX 0x2D +#define SMB_COM_READ_ANDX 0x2E +#define SMB_COM_WRITE_ANDX 0x2F +#define SMB_COM_NEW_FILE_SIZE 0x30 +#define SMB_COM_CLOSE_AND_TREE_DISC 0x31 +#define SMB_COM_TRANSACTION2 0x32 +#define SMB_COM_TRANSACTION2_SECONDARY 0x33 +#define SMB_COM_FIND_CLOSE2 0x34 +#define SMB_COM_FIND_NOTIFY_CLOSE 0x35 +#define SMB_COM_TREE_CONNECT 0x70 +#define SMB_COM_TREE_DISCONNECT 0x71 +#define SMB_COM_NEGOTIATE 0x72 +#define SMB_COM_SESSION_SETUP_ANDX 0x73 +#define SMB_COM_LOGOFF_ANDX 0x74 +#define SMB_COM_TREE_CONNECT_ANDX 0x75 +#define SMB_COM_SECURITY_PACKAGE_ANDX 0x7E +#define SMB_COM_QUERY_INFORMATION_DISK 0x80 +#define SMB_COM_SEARCH 0x81 +#define SMB_COM_FIND 0x82 +#define SMB_COM_FIND_UNIQUE 0x83 +#define SMB_COM_FIND_CLOSE 0x84 +#define SMB_COM_NT_TRANSACT 0xA0 +#define SMB_COM_NT_TRANSACT_SECONDARY 0xA1 +#define SMB_COM_NT_CREATE_ANDX 0xA2 +#define SMB_COM_NT_CANCEL 0xA4 +#define SMB_COM_NT_RENAME 0xA5 +#define SMB_COM_OPEN_PRINT_FILE 0xC0 +#define SMB_COM_WRITE_PRINT_FILE 0xC1 +#define SMB_COM_CLOSE_PRINT_FILE 0xC2 +#define SMB_COM_GET_PRINT_QUEUE 0xC3 +#define SMB_COM_READ_BULK 0xD8 +#define SMB_COM_WRITE_BULK 0xD9 +#define SMB_COM_WRITE_BULK_DATA 0xDA +#define SMB_COM_INVALID 0xFE +#define SMB_COM_NO_ANDX_COMMAND 0xFF + +/* Size of word count field + Word count * 2 bytes + Size of byte count field */ +#define SMB_COM_SIZE(wct) (sizeof(uint8_t) + ((wct) * sizeof(uint16_t)) + sizeof(uint16_t)) + +#define SMB_FLG__TYPE 0x80 +#define SMB_TYPE__REQUEST 0 +#define SMB_TYPE__RESPONSE 1 + +#define SMB_FLG2__UNICODE 0x8000 +#define SMB_FLG2__NT_CODES 0x4000 + +#define SMB_NT_STATUS_SEVERITY__SUCCESS 0 +#define SMB_NT_STATUS_SEVERITY__INFORMATIONAL 1 +#define SMB_NT_STATUS_SEVERITY__WARNING 2 +#define SMB_NT_STATUS_SEVERITY__ERROR 3 + +#define SMB_NT_STATUS__SUCCESS 0x00000000 +#define SMB_NT_STATUS__INVALID_DEVICE_REQUEST 0xc0000010 +#define SMB_NT_STATUS__RANGE_NOT_LOCKED 0xc000007e +#define SMB_NT_STATUS__PIPE_BROKEN 0xc000014b +#define SMB_NT_STATUS__PIPE_DISCONNECTED 0xc00000b0 + +#define SMB_ERROR_CLASS__SUCCESS 0x00 +#define SMB_ERROR_CLASS__ERRDOS 0x01 +#define SMB_ERROR_CLASS__ERRSRV 0x02 +#define SMB_ERROR_CLASS__ERRHRD 0x03 +#define SMB_ERROR_CLASS__ERRXOS 0x04 +#define SMB_ERROR_CLASS__ERRMX1 0xe1 +#define SMB_ERROR_CLASS__ERRMX2 0xe2 +#define SMB_ERROR_CLASS__ERRMX3 0xe3 +#define SMB_ERROR_CLASS__ERRCMD 0xff + +#define SMB_ERRSRV__INVALID_DEVICE 0x0007 +#define SMB_ERRDOS__NOT_LOCKED 0x009e +#define SMB_ERRDOS__BAD_PIPE 0x00e6 +#define SMB_ERRDOS__PIPE_NOT_CONNECTED 0x00e9 +#define SMB_ERRDOS__MORE_DATA 0x00ea + +enum SmbTransactionSubcommand +{ + TRANS_UNKNOWN_0000 = 0x0000, + TRANS_SET_NMPIPE_STATE = 0x0001, + TRANS_UNKNOWN_0002 = 0x0002, + TRANS_UNKNOWN_0003 = 0x0003, + TRANS_UNKNOWN_0004 = 0x0004, + TRANS_UNKNOWN_0005 = 0x0005, + TRANS_UNKNOWN_0006 = 0x0006, + TRANS_UNKNOWN_0007 = 0x0007, + TRANS_UNKNOWN_0008 = 0x0008, + TRANS_UNKNOWN_0009 = 0x0009, + TRANS_UNKNOWN_000A = 0x000A, + TRANS_UNKNOWN_000B = 0x000B, + TRANS_UNKNOWN_000C = 0x000C, + TRANS_UNKNOWN_000D = 0x000D, + TRANS_UNKNOWN_000E = 0x000E, + TRANS_UNKNOWN_000F = 0x000F, + TRANS_UNKNOWN_0010 = 0x0010, + TRANS_RAW_READ_NMPIPE = 0x0011, + TRANS_UNKNOWN_0012 = 0x0012, + TRANS_UNKNOWN_0013 = 0x0013, + TRANS_UNKNOWN_0014 = 0x0014, + TRANS_UNKNOWN_0015 = 0x0015, + TRANS_UNKNOWN_0016 = 0x0016, + TRANS_UNKNOWN_0017 = 0x0017, + TRANS_UNKNOWN_0018 = 0x0018, + TRANS_UNKNOWN_0019 = 0x0019, + TRANS_UNKNOWN_001A = 0x001A, + TRANS_UNKNOWN_001B = 0x001B, + TRANS_UNKNOWN_001C = 0x001C, + TRANS_UNKNOWN_001D = 0x001D, + TRANS_UNKNOWN_001E = 0x001E, + TRANS_UNKNOWN_001F = 0x001F, + TRANS_UNKNOWN_0020 = 0x0020, + TRANS_QUERY_NMPIPE_STATE = 0x0021, + TRANS_QUERY_NMPIPE_INFO = 0x0022, + TRANS_PEEK_NMPIPE = 0x0023, + TRANS_UNKNOWN_0024 = 0x0024, + TRANS_UNKNOWN_0025 = 0x0025, + TRANS_TRANSACT_NMPIPE = 0x0026, + TRANS_UNKNOWN_0027 = 0x0027, + TRANS_UNKNOWN_0028 = 0x0028, + TRANS_UNKNOWN_0029 = 0x0029, + TRANS_UNKNOWN_002A = 0x002A, + TRANS_UNKNOWN_002B = 0x002B, + TRANS_UNKNOWN_002C = 0x002C, + TRANS_UNKNOWN_002D = 0x002D, + TRANS_UNKNOWN_002E = 0x002E, + TRANS_UNKNOWN_002F = 0x002F, + TRANS_UNKNOWN_0030 = 0x0030, + TRANS_RAW_WRITE_NMPIPE = 0x0031, + TRANS_UNKNOWN_0032 = 0x0032, + TRANS_UNKNOWN_0033 = 0x0033, + TRANS_UNKNOWN_0034 = 0x0034, + TRANS_UNKNOWN_0035 = 0x0035, + TRANS_READ_NMPIPE = 0x0036, + TRANS_WRITE_NMPIPE = 0x0037, + TRANS_UNKNOWN_0038 = 0x0038, + TRANS_UNKNOWN_0039 = 0x0039, + TRANS_UNKNOWN_003A = 0x003A, + TRANS_UNKNOWN_003B = 0x003B, + TRANS_UNKNOWN_003C = 0x003C, + TRANS_UNKNOWN_003D = 0x003D, + TRANS_UNKNOWN_003E = 0x003E, + TRANS_UNKNOWN_003F = 0x003F, + TRANS_UNKNOWN_0040 = 0x0040, + TRANS_UNKNOWN_0041 = 0x0041, + TRANS_UNKNOWN_0042 = 0x0042, + TRANS_UNKNOWN_0043 = 0x0043, + TRANS_UNKNOWN_0044 = 0x0044, + TRANS_UNKNOWN_0045 = 0x0045, + TRANS_UNKNOWN_0046 = 0x0046, + TRANS_UNKNOWN_0047 = 0x0047, + TRANS_UNKNOWN_0048 = 0x0048, + TRANS_UNKNOWN_0049 = 0x0049, + TRANS_UNKNOWN_004A = 0x004A, + TRANS_UNKNOWN_004B = 0x004B, + TRANS_UNKNOWN_004C = 0x004C, + TRANS_UNKNOWN_004D = 0x004D, + TRANS_UNKNOWN_004E = 0x004E, + TRANS_UNKNOWN_004F = 0x004F, + TRANS_UNKNOWN_0050 = 0x0050, + TRANS_UNKNOWN_0051 = 0x0051, + TRANS_UNKNOWN_0052 = 0x0052, + TRANS_WAIT_NMPIPE = 0x0053, + TRANS_CALL_NMPIPE = 0x0054, + TRANS_SUBCOM_MAX = 0x0055 +}; + +enum SmbTransaction2Subcommand +{ + TRANS2_OPEN2 = 0x0000, + TRANS2_FIND_FIRST2 = 0x0001, + TRANS2_FIND_NEXT2 = 0x0002, + TRANS2_QUERY_FS_INFORMATION = 0x0003, + TRANS2_SET_FS_INFORMATION = 0x0004, + TRANS2_QUERY_PATH_INFORMATION = 0x0005, + TRANS2_SET_PATH_INFORMATION = 0x0006, + TRANS2_QUERY_FILE_INFORMATION = 0x0007, + TRANS2_SET_FILE_INFORMATION = 0x0008, + TRANS2_FSCTL = 0x0009, + TRANS2_IOCTL2 = 0x000A, + TRANS2_FIND_NOTIFY_FIRST = 0x000B, + TRANS2_FIND_NOTIFY_NEXT = 0x000C, + TRANS2_CREATE_DIRECTORY = 0x000D, + TRANS2_SESSION_SETUP = 0x000E, + TRANS2_UNKNOWN_000F = 0x000F, + TRANS2_GET_DFS_REFERRAL = 0x0010, + TRANS2_REPORT_DFS_INCONSISTENCY = 0x0011, + TRANS2_SUBCOM_MAX = 0x0012 +}; + +/******************************************************************** + * Structures and inline accessor functions + ********************************************************************/ +/* Pack the structs since we'll be laying them on top of packet data */ +#pragma pack(1) + +/******************************************************************** + * NetBIOS Session Service header + ********************************************************************/ +struct NbssHdr +{ + uint8_t type; + uint8_t flags; /* Treat flags as the upper byte to length */ + uint16_t length; +}; + +struct SmbNtHdr +{ + uint8_t smb_idf[4]; /* contains 0xFF, 'SMB' */ + uint8_t smb_com; /* command code */ + union + { + struct + { + uint8_t smb_class; /* dos error class */ + uint8_t smb_res; /* reserved for future */ + uint16_t smb_code; /* dos error code */ + } smb_status; + uint32_t nt_status; /* nt status */ + } smb_status; + uint8_t smb_flg; /* flags */ + uint16_t smb_flg2; /* flags */ + uint16_t smb_pid_high; + uint64_t smb_signature; + uint16_t smb_res; /* reserved for future */ + uint16_t smb_tid; /* tree id */ + uint16_t smb_pid; /* caller's process id */ + uint16_t smb_uid; /* authenticated user id */ + uint16_t smb_mid; /* multiplex id */ +}; + +/* For server empty respones indicating client error or interim response */ +struct SmbEmptyCom +{ + uint8_t smb_wct; /* value = 0 */ + uint16_t smb_bcc; /* value = 0 */ +}; + +/******************************************************************** + * Common fields to all commands + ********************************************************************/ +struct SmbCommon +{ + uint8_t smb_wct; +}; + +inline uint8_t SmbWct(const SmbCommon* hdr) +{ + return hdr->smb_wct; +} + +/* Common fields to all AndX commands */ +struct SmbAndXCommon +{ + uint8_t smb_wct; + uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ + uint8_t smb_reh2; /* reserved (must be zero) */ + uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ +}; + +inline uint32_t NbssLen(const NbssHdr* nb) +{ + /* Treat first bit of flags as the upper byte to length */ + // The left operand of '&' is a garbage value + return ((nb->flags & 0x01) << 16) | ntohs(nb->length); // ... FIXIT-W +} + +inline uint8_t NbssType(const NbssHdr* nb) +{ + return nb->type; +} + +inline uint32_t SmbId(const SmbNtHdr* hdr) +{ + uint8_t* idf = (uint8_t*)hdr->smb_idf; + return *idf << 24 | *(idf + 1) << 16 | *(idf + 2) << 8 | *(idf + 3); +} + +inline uint8_t SmbEmptyComWct(const SmbEmptyCom* ec) +{ + return ec->smb_wct; +} + +inline uint16_t SmbBcc(const uint8_t* ptr, uint16_t com_size) +{ + /* com_size must be at least the size of the command encasing */ + if (com_size < sizeof(SmbEmptyCom)) + return 0; + + return alignedNtohs((uint16_t*)(ptr + com_size - sizeof(uint16_t))); +} + +inline uint16_t SmbEmptyComBcc(const SmbEmptyCom* ec) +{ + return alignedNtohs(&ec->smb_bcc); +} + +inline int SmbType(const SmbNtHdr* hdr) +{ + // Access to field 'smb_flg' results in a dereference of a null pointer + // (loaded from variable 'hdr') + if (hdr->smb_flg & SMB_FLG__TYPE) // ... FIXIT-W + return SMB_TYPE__RESPONSE; + + return SMB_TYPE__REQUEST; +} + +inline uint8_t SmbAndXCom2(const SmbAndXCommon* andx) +{ + return andx->smb_com2; +} + +inline uint16_t SmbAndXOff2(const SmbAndXCommon* andx) +{ + return alignedNtohs(&andx->smb_off2); +} + +/* SMB formats (smb_fmt) Dialect, Pathname and ASCII are all + * NULL terminated ASCII strings unless Unicode is specified + * in the NT LM 1.0 SMB header in which case they are NULL + * terminated unicode strings + */ +#define SMB_FMT__DATA_BLOCK 1 +#define SMB_FMT__DIALECT 2 +#define SMB_FMT__ASCII 4 + +inline bool SmbFmtDataBlock(const uint8_t fmt) +{ + return fmt == SMB_FMT__DATA_BLOCK ? true : false; +} + +inline bool SmbFmtDialect(const uint8_t fmt) +{ + return fmt == SMB_FMT__DIALECT ? true : false; +} + +inline bool SmbFmtAscii(const uint8_t fmt) +{ + return fmt == SMB_FMT__ASCII ? true : false; +} + +#endif + diff --git a/src/service_inspectors/dce_rpc/smb_message.cc b/src/service_inspectors/dce_rpc/smb_message.cc new file mode 100644 index 000000000..915787636 --- /dev/null +++ b/src/service_inspectors/dce_rpc/smb_message.cc @@ -0,0 +1,2648 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2016-2016 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// smb_message.cc author Rashmi Pitre + +#include "dce_smb.h" + +#include "detection/detect.h" +#include "file_api/file_service.h" +#include "protocols/packet.h" +#include "utils/util.h" + +#include "dce_smb_module.h" +#include "dce_smb_utils.h" +#include "dce_smb_paf.h" +#include "dce_smb_commands.h" +#include "dce_smb_transaction.h" +#include "dce_smb2.h" +#include "dce_smb.h" + +/******************************************************************** + * Global variables + ********************************************************************/ +typedef DCE2_Ret (* DCE2_SmbComFunc)(DCE2_SmbSsnData*, const SmbNtHdr*, + const DCE2_SmbComInfo*, const uint8_t*, uint32_t); + +static DCE2_SmbComFunc smb_com_funcs[SMB_MAX_NUM_COMS]; +static uint8_t smb_wcts[SMB_MAX_NUM_COMS][2][32]; +static uint16_t smb_bccs[SMB_MAX_NUM_COMS][2][2]; +static DCE2_SmbComFunc smb_chain_funcs[DCE2_POLICY__MAX][SMB_ANDX_COM__MAX][SMB_MAX_NUM_COMS]; +static bool smb_deprecated_coms[SMB_MAX_NUM_COMS]; +static bool smb_unusual_coms[SMB_MAX_NUM_COMS]; +static SmbAndXCom smb_chain_map[SMB_MAX_NUM_COMS]; + +/******************************************************************** + * Function: DCE2_SmbIsRawData() + * + * Purpose: + * To determine if the current state is such that a raw read or + * write is expected. + * + * Arguments: + * DCE2_SmbSsnData * - Pointer to SMB session data. + * + * Returns: + * bool - True if expecting raw data. + * False if not. + * + ********************************************************************/ +static inline bool DCE2_SmbIsRawData(DCE2_SmbSsnData* ssd) +{ + return (ssd->pdu_state == DCE2_SMB_PDU_STATE__RAW_DATA); +} + +/******************************************************************** + * Function: DCE2_SmbCheckAndXOffset() + * + * Purpose: + * Validates that the AndXOffset is within bounds of the remaining + * data we have to work with. + * + * Arguments: + * uint8_t * - pointer to where the offset would take us. + * uint8_t * - pointer to bound offset + * uint8_t * - length of data where offset should be within + * + * Returns: + * DCE2_RET__SUCCESS - Offset is okay. + * DCE2_RET__ERROR - Offset is bad. + * + ********************************************************************/ +static inline DCE2_Ret DCE2_SmbCheckAndXOffset(const uint8_t* off_ptr, const uint8_t* start_bound, + const uint32_t length) +{ + /* Offset should not point within data we just looked at or be equal to + * or beyond the length of the NBSS length left */ + if ((off_ptr < start_bound) || + (off_ptr > (start_bound + length))) + { + dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats); + + return DCE2_RET__ERROR; + } + + return DCE2_RET__SUCCESS; +} + +/******************************************************************** + * Function: DCE2_SmbGetIgnorePtr() + * + * Returns a pointer to the bytes we are ignoring on client or + * server side. Bytes are ignored if they are associated with + * data we are not interested in. + * + * Arguments: + * DCE2_SmbSsnData * - Pointer to SMB session data. + * + * Returns: + * uint32_t * + * Pointer to the client or server ignore bytes. + * + ********************************************************************/ +static inline uint32_t* DCE2_SmbGetIgnorePtr(DCE2_SmbSsnData* ssd) +{ + if (DCE2_SsnFromServer(ssd->sd.wire_pkt)) + return &ssd->srv_ignore_bytes; + return &ssd->cli_ignore_bytes; +} + +/******************************************************************** + * Function: DCE2_SmbGetDataState() + * + * Returns a pointer to the data state of client or server + * + * Arguments: + * DCE2_SmbSsnData * - Pointer to SMB session data. + * + * Returns: + * DCE2_SmbDataState * + * Pointer to the client or server data state. + * + ********************************************************************/ +static inline DCE2_SmbDataState* DCE2_SmbGetDataState(DCE2_SmbSsnData* ssd) +{ + if (DCE2_SsnFromServer(ssd->sd.wire_pkt)) + return &ssd->srv_data_state; + return &ssd->cli_data_state; +} + +/******************************************************************** + * Function: DCE2_SmbSetValidWordCount() + * + * Purpose: + * Initializes global data for valid word counts for supported + * SMB command requests and responses. + * + * Arguments: + * uint8_t - the SMB command code + * uint8_t - SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE + * uint8_t - the valid word count + * + * Returns: None + * + ********************************************************************/ +static inline void DCE2_SmbSetValidWordCount(uint8_t com, + uint8_t resp, uint8_t wct) +{ + smb_wcts[com][resp][wct/8] |= (1 << (wct % 8)); +} + +/******************************************************************** + * Function: DCE2_SmbIsValidWordCount() + * + * Purpose: + * Checks if a word count is valid for a given command request + * or response. + * + * Arguments: + * uint8_t - the SMB command code + * uint8_t - SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE + * uint8_t - the word count to validate + * + * Returns: + * bool - true if valid, false if not valid. + * + ********************************************************************/ +static inline bool DCE2_SmbIsValidWordCount(uint8_t com, + uint8_t resp, uint8_t wct) +{ + return (smb_wcts[com][resp][wct/8] & (1 << (wct % 8))) ? true : false; +} + +/******************************************************************** + * Function: DCE2_SmbSetValidByteCount() + * + * Purpose: + * Initializes global data for valid byte counts as a range for + * supported SMB command requests and responses. + * Since a byte count is 2 bytes, a 4 byte type is used to store + * the range. The maximum is in the most significant 2 bytes and + * the minimum in the least significant 2 bytes. + * + * Arguments: + * uint8_t - the SMB command code + * uint8_t - SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE + * uint8_t - the minimum word count that is valid + * uint8_t - the maximum word count that is valid + * + * Returns: None + * + ********************************************************************/ +static inline void DCE2_SmbSetValidByteCount(uint8_t com, + uint8_t resp, uint16_t min, uint16_t max) +{ + smb_bccs[com][resp][0] = min; + smb_bccs[com][resp][1] = max; +} + +/******************************************************************** + * Function: DCE2_SmbIsValidByteCount() + * + * Purpose: + * Checks if a byte count is valid for a given command request + * or response. + * + * Arguments: + * uint8_t - the SMB command code + * uint8_t - SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE + * uint8_t - the byte count to validate + * + * Returns: + * bool - true if valid, false if not valid. + * + ********************************************************************/ +static inline bool DCE2_SmbIsValidByteCount(uint8_t com, + uint8_t resp, uint16_t bcc) +{ + return ((bcc < smb_bccs[com][resp][0]) + || (bcc > smb_bccs[com][resp][1])) ? false : true; +} + +// This function is obviously deficient. Need to do a lot more +// testing, research and reading MS-CIFS, MS-SMB and MS-ERREF. +static bool SmbError(const SmbNtHdr* hdr) +{ + if (SmbStatusNtCodes(hdr)) + { + /* Nt status codes are being used. First 2 bits indicate + * severity. */ + switch (SmbNtStatusSeverity(hdr)) + { + case SMB_NT_STATUS_SEVERITY__SUCCESS: + case SMB_NT_STATUS_SEVERITY__INFORMATIONAL: + case SMB_NT_STATUS_SEVERITY__WARNING: + return false; + case SMB_NT_STATUS_SEVERITY__ERROR: + default: + break; + } + } + else + { + switch (SmbStatusClass(hdr)) + { + case SMB_ERROR_CLASS__SUCCESS: + return false; + case SMB_ERROR_CLASS__ERRDOS: + if (SmbStatusCode(hdr) == SMB_ERRDOS__MORE_DATA) + return false; + break; + case SMB_ERROR_CLASS__ERRSRV: + case SMB_ERROR_CLASS__ERRHRD: + case SMB_ERROR_CLASS__ERRCMD: + default: + break; + } + } + + return true; +} + +static bool SmbBrokenPipe(const SmbNtHdr* hdr) +{ + if (SmbStatusNtCodes(hdr)) + { + uint32_t nt_status = SmbNtStatus(hdr); + if ((nt_status == SMB_NT_STATUS__PIPE_BROKEN) + || (nt_status == SMB_NT_STATUS__PIPE_DISCONNECTED)) + return true; + } + else + { + if (SmbStatusClass(hdr) == SMB_ERROR_CLASS__ERRDOS) + { + uint16_t smb_status = SmbStatusCode(hdr); + if ((smb_status == SMB_ERRDOS__BAD_PIPE) + || (smb_status == SMB_ERRDOS__PIPE_NOT_CONNECTED)) + return true; + } + } + + return false; +} + +/******************************************************************** + * Function: DCE2_IgnoreJunkData() + * + * Purpose: + * An evasion technique can be to put a bunch of junk data before + * the actual SMB request and it seems the MS implementation has + * no problem with it and seems to just ignore the data. This + * function attempts to move past all the junk to get to the + * actual NetBIOS message request. + * + * Arguments: + * const uint8_t * - pointer to the current position in the data + * being inspected + * uint16_t - the amount of data left to look at + * uint32_t - the amount of data to ignore if there doesn't seem + * to be any junk data. Just use the length as if the bad + * NetBIOS header was good. + * + * Returns: + * uint32_t - the amount of bytes to ignore as junk. + * + ********************************************************************/ +static uint32_t DCE2_IgnoreJunkData(const uint8_t* data_ptr, uint16_t data_len, + uint32_t assumed_nb_len) +{ + const uint8_t* tmp_ptr = data_ptr; + uint32_t ignore_bytes = 0; + + /* Try to find \xffSMB and go back 8 bytes to beginning + * of what should be a Netbios header with type Session + * Message (\x00) - do appropriate buffer checks to make + * sure the index is in bounds. Ignore all intervening + * bytes */ + + while ((tmp_ptr + sizeof(uint32_t)) <= (data_ptr + data_len)) + { + if ((SmbId((SmbNtHdr*)tmp_ptr) == DCE2_SMB_ID) + || (SmbId((SmbNtHdr*)tmp_ptr) == DCE2_SMB2_ID)) + { + break; + } + + tmp_ptr++; + } + + if ((tmp_ptr + sizeof(uint32_t)) > (data_ptr + data_len)) + { + ignore_bytes = data_len; + } + else + { + if ((tmp_ptr - sizeof(NbssHdr)) > data_ptr) + ignore_bytes = (tmp_ptr - data_ptr) - sizeof(NbssHdr); + else /* Just ignore whatever the bad NB header had as a length */ + ignore_bytes = assumed_nb_len; + } + + return ignore_bytes; +} + +/******************************************************************** + * Function: DCE2_SmbHdrChecks() + * + * Checks some relevant fields in the header to make sure they're + * sane. + * Side effects are potential alerts for anomolous behavior. + * + * Arguments: + * DCE2_SmbSsnData * + * Pointer to the session data structure. + * SmbNtHdr * + * Pointer to the header struct layed over the packet data. + * + * Returns: + * DCE2_Ret + * DCE2_RET__IGNORE if we should continue processing, but + * ignore data because of the error. + * DCE2_RET__SUCCESS if we should continue processing. + * + ********************************************************************/ +static DCE2_Ret DCE2_SmbHdrChecks(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr) +{ + Packet* p = ssd->sd.wire_pkt; + bool is_seg_buf = DCE2_SmbIsSegBuffer(ssd, (uint8_t*)smb_hdr); + + if ((DCE2_SsnFromServer(p) && (SmbType(smb_hdr) == SMB_TYPE__REQUEST)) || + (DCE2_SsnFromClient(p) && (SmbType(smb_hdr) == SMB_TYPE__RESPONSE))) + { + if (is_seg_buf) + DCE2_SmbSegAlert(ssd, DCE2_SMB_BAD_TYPE); + else + dce_alert(GID_DCE2, DCE2_SMB_BAD_TYPE, (dce2CommonStats*)&dce2_smb_stats); + + // Continue looking at traffic. Neither Windows nor Samba seem + // to care, or even look at this flag + } + + if ((SmbId(smb_hdr) != DCE2_SMB_ID) + && (SmbId(smb_hdr) != DCE2_SMB2_ID)) + { + if (is_seg_buf) + DCE2_SmbSegAlert(ssd, DCE2_SMB_BAD_ID); + else + dce_alert(GID_DCE2, DCE2_SMB_BAD_ID, (dce2CommonStats*)&dce2_smb_stats); + + return DCE2_RET__IGNORE; + } + + return DCE2_RET__SUCCESS; +} + +/******************************************************************** + * Function: DCE2_SmbGetMinByteCount() + * + * Purpose: + * Returns the minimum byte count for the given command request + * or response. + * + * Arguments: + * uint8_t - the SMB command code + * uint8_t - SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE + * + * Returns: + * uint16_t - the minimum byte count + * + ********************************************************************/ +static inline uint16_t DCE2_SmbGetMinByteCount(uint8_t com, uint8_t resp) +{ + return smb_bccs[com][resp][0]; +} + +static DCE2_SmbRequestTracker* DCE2_SmbFindRequestTracker(DCE2_SmbSsnData* ssd, + const SmbNtHdr* smb_hdr) +{ + uint16_t uid = SmbUid(smb_hdr); + uint16_t tid = SmbTid(smb_hdr); + uint16_t pid = SmbPid(smb_hdr); + uint16_t mid = SmbMid(smb_hdr); + + Profile profile(dce2_smb_pstat_smb_req); + + DebugFormat(DEBUG_DCE_SMB, "Find request tracker => " + "Uid: %hu, Tid: %hu, Pid: %hu, Mid: %hu ... ", uid, tid, pid, mid); + + DCE2_SmbRequestTracker* tmp_rtracker = &ssd->rtracker; + int smb_com = SmbCom(smb_hdr); + switch (smb_com) + { + case SMB_COM_TRANSACTION_SECONDARY: + smb_com = SMB_COM_TRANSACTION; + break; + case SMB_COM_TRANSACTION2_SECONDARY: + smb_com = SMB_COM_TRANSACTION2; + break; + case SMB_COM_NT_TRANSACT_SECONDARY: + smb_com = SMB_COM_NT_TRANSACT; + break; + case SMB_COM_WRITE_COMPLETE: + smb_com = SMB_COM_WRITE_RAW; + break; + default: + break; + } + + DCE2_SmbRequestTracker* first_rtracker = nullptr; + DCE2_SmbRequestTracker* win_rtracker = nullptr; + DCE2_SmbRequestTracker* first_mid_rtracker = nullptr; + DCE2_SmbRequestTracker* ret_rtracker = nullptr; + while (tmp_rtracker != nullptr) + { + if ((tmp_rtracker->mid == (int)mid) && (tmp_rtracker->smb_com == smb_com)) + { + // This is the normal case except for SessionSetupAndX and + // TreeConnect/TreeConnectAndX which will fall into the + // default case below. + if ((tmp_rtracker->pid == pid) && (tmp_rtracker->uid == uid) + && (tmp_rtracker->tid == tid)) + { + ret_rtracker = tmp_rtracker; + } + else + { + switch (smb_com) + { + case SMB_COM_TRANSACTION: + case SMB_COM_TRANSACTION2: + case SMB_COM_NT_TRANSACT: + case SMB_COM_TRANSACTION_SECONDARY: + case SMB_COM_TRANSACTION2_SECONDARY: + case SMB_COM_NT_TRANSACT_SECONDARY: + // These should conform to above + break; + default: + if (tmp_rtracker->pid == pid) + ret_rtracker = tmp_rtracker; + break; + } + } + + if (ret_rtracker != nullptr) + { + DebugMessage(DEBUG_DCE_SMB, "Found.\n"); + return ret_rtracker; + } + + // Take the first one where the PIDs also match + // in the case of the Transacts above + if ((tmp_rtracker->pid == pid) && (win_rtracker == nullptr)) + win_rtracker = tmp_rtracker; + + // Set this to the first matching request in the queue + // where the Mid matches. Don't set for Windows if from + // client since PID/MID are necessary + if (((DCE2_SmbType(ssd) == SMB_TYPE__RESPONSE) + || !DCE2_SsnIsWindowsPolicy(&ssd->sd)) + && first_mid_rtracker == nullptr) + { + first_mid_rtracker = tmp_rtracker; + } + } + + // Set the first one we see for early Samba versions + if ((first_rtracker == nullptr) && (tmp_rtracker->mid != DCE2_SENTINEL) + && (tmp_rtracker->smb_com == smb_com)) + first_rtracker = tmp_rtracker; + + // Look at the next request in the queue + if (tmp_rtracker == &ssd->rtracker) + tmp_rtracker = (DCE2_SmbRequestTracker*)DCE2_QueueFirst(ssd->rtrackers); + else + tmp_rtracker = (DCE2_SmbRequestTracker*)DCE2_QueueNext(ssd->rtrackers); + } + + DCE2_Policy policy = DCE2_SsnGetPolicy(&ssd->sd); + switch (policy) + { + case DCE2_POLICY__SAMBA_3_0_20: + case DCE2_POLICY__SAMBA_3_0_22: + ret_rtracker = first_rtracker; + break; + case DCE2_POLICY__SAMBA: + case DCE2_POLICY__SAMBA_3_0_37: + ret_rtracker = first_mid_rtracker; + break; + case DCE2_POLICY__WIN2000: + case DCE2_POLICY__WINXP: + case DCE2_POLICY__WINVISTA: + case DCE2_POLICY__WIN2003: + case DCE2_POLICY__WIN2008: + case DCE2_POLICY__WIN7: + if (win_rtracker != nullptr) + ret_rtracker = win_rtracker; + else + ret_rtracker = first_mid_rtracker; + break; + default: + DebugFormat(DEBUG_DCE_SMB, "%s(%d) Invalid policy: %d", + __FILE__, __LINE__, policy); + break; + } + + return ret_rtracker; +} + +/******************************************************************** + * Function: DCE2_SmbCheckCommand() + * + * Purpose: + * Checks basic validity of an SMB command. + * + * Arguments: + * DCE2_SmbSsnData * - pointer to session data structure + * SmbNtHdr * - pointer to the SMB header structure + * uint8_t - the SMB command code, i.e. SMB_COM_* + * uint8_t * - current pointer to data, i.e. the command + * uint32_t - the remaining length + * DCE2_SmbComInfo & - + * Populated structure for command processing + * + * Returns: None + * + ********************************************************************/ +static void DCE2_SmbCheckCommand(DCE2_SmbSsnData* ssd, + const SmbNtHdr* smb_hdr, const uint8_t smb_com, + const uint8_t* nb_ptr, uint32_t nb_len, DCE2_SmbComInfo& com_info) +{ + // Check for server error response + if (com_info.smb_type == SMB_TYPE__RESPONSE) + { + const SmbEmptyCom* ec = (SmbEmptyCom*)nb_ptr; + + // Verify there is enough data to do checks + if (nb_len < sizeof(SmbEmptyCom)) + { + dce_alert(GID_DCE2, DCE2_SMB_NB_LT_COM, (dce2CommonStats*)&dce2_smb_stats); + com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH; + return; + } + + // If word and byte counts are zero and there is an error + // the server didn't accept client request + if ((SmbEmptyComWct(ec) == 0) + && (SmbEmptyComBcc(ec) == 0) && SmbError(smb_hdr)) + { + DebugFormat(DEBUG_DCE_SMB, + "Response error: 0x%08X\n", SmbNtStatus(smb_hdr)); + + // If broken pipe, clean up data associated with open named pipe + if (SmbBrokenPipe(smb_hdr)) + { + DebugMessage(DEBUG_DCE_SMB, "Broken or disconnected pipe.\n"); + DCE2_SmbRemoveFileTracker(ssd, ssd->cur_rtracker->ftracker); + } + + com_info.cmd_error |= DCE2_SMB_COM_ERROR__STATUS_ERROR; + return; + } + } + + // Set the header size to the minimum size the command can be + // without the byte count to make sure there is enough data to + // get the word count. + SmbAndXCom andx_com = smb_chain_map[smb_com]; + int chk_com_size; + if (andx_com == SMB_ANDX_COM__NONE) + chk_com_size = sizeof(SmbCommon); + else + chk_com_size = sizeof(SmbAndXCommon); + + // Verify there is enough data to do checks + if (nb_len < (uint32_t)chk_com_size) + { + dce_alert(GID_DCE2, DCE2_SMB_NB_LT_COM, (dce2CommonStats*)&dce2_smb_stats); + com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH; + return; + } + + const SmbCommon* sc = (SmbCommon*)nb_ptr; + com_info.word_count = SmbWct(sc); + + // Make sure the word count is a valid one for the command. If not + // testing shows an error will be returned. And command structures + // won't lie on data correctly and out of bounds data accesses are possible. + if (!DCE2_SmbIsValidWordCount(smb_com, (uint8_t)com_info.smb_type, com_info.word_count)) + { + dce_alert(GID_DCE2, DCE2_SMB_BAD_WCT, (dce2CommonStats*)&dce2_smb_stats); + com_info.cmd_error |= DCE2_SMB_COM_ERROR__INVALID_WORD_COUNT; + return; + } + + // This gets the size of the SMB command from word count through byte count + // using the advertised value in the word count field. + com_info.cmd_size = (uint16_t)SMB_COM_SIZE(com_info.word_count); + if (nb_len < com_info.cmd_size) + { + dce_alert(GID_DCE2, DCE2_SMB_NB_LT_COM, (dce2CommonStats*)&dce2_smb_stats); + com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH; + return; + } + + uint16_t smb_bcc = SmbBcc(nb_ptr, com_info.cmd_size); + + // SMB_COM_NT_CREATE_ANDX is a special case. Who know what's going + // on with the word count (see MS-CIFS and MS-SMB). A 42 word count + // command seems to actually have 50 words, so who knows where the + // byte count is. Just set to zero since it's not needed. + if ((smb_com == SMB_COM_NT_CREATE_ANDX) + && (com_info.smb_type == SMB_TYPE__RESPONSE)) + smb_bcc = 0; + + // If byte count is deemed invalid, alert but continue processing + switch (smb_com) + { + // Interim responses + case SMB_COM_TRANSACTION: + case SMB_COM_TRANSACTION2: + case SMB_COM_NT_TRANSACT: + // If word count is 0, byte count must be 0 + if ((com_info.word_count == 0) && (com_info.smb_type == SMB_TYPE__RESPONSE)) + { + if (smb_bcc != 0) + { + dce_alert(GID_DCE2, DCE2_SMB_BAD_BCC, (dce2CommonStats*)&dce2_smb_stats); + com_info.cmd_error |= DCE2_SMB_COM_ERROR__INVALID_BYTE_COUNT; + } + break; + } + // Fall through + default: + if (!DCE2_SmbIsValidByteCount(smb_com, (uint8_t)com_info.smb_type, smb_bcc)) + { + dce_alert(GID_DCE2, DCE2_SMB_BAD_BCC, (dce2CommonStats*)&dce2_smb_stats); + com_info.cmd_error |= DCE2_SMB_COM_ERROR__INVALID_BYTE_COUNT; + } + break; + } + + // Move just past byte count field which is the end of the command + DCE2_MOVE(nb_ptr, nb_len, com_info.cmd_size); + + // Validate that there is enough data to be able to process the command + if (nb_len < DCE2_SmbGetMinByteCount(smb_com, (uint8_t)com_info.smb_type)) + { + dce_alert(GID_DCE2, DCE2_SMB_NB_LT_BCC, (dce2CommonStats*)&dce2_smb_stats); + com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH; + } + + // The byte count seems to be ignored by Windows and current Samba (3.5.4) + // as long as it is less than the amount of data left. If more, an error + // is returned. + // !!!WARNING!!! the byte count should probably never be used. + if (smb_bcc > nb_len) + { + dce_alert(GID_DCE2, DCE2_SMB_NB_LT_BCC, (dce2CommonStats*)&dce2_smb_stats); + // Large byte count doesn't seem to matter for early Samba + switch (DCE2_SsnGetPolicy(&ssd->sd)) + { + case DCE2_POLICY__SAMBA_3_0_20: + case DCE2_POLICY__SAMBA_3_0_22: + case DCE2_POLICY__SAMBA_3_0_37: + break; + default: + com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH; + break; + } + } + else if ((smb_bcc == 0) && (SmbCom(smb_hdr) == SMB_COM_TRANSACTION) + && (DCE2_SmbType(ssd) == SMB_TYPE__REQUEST) + && (DCE2_SsnGetPolicy(&ssd->sd) == DCE2_POLICY__SAMBA)) + { + // Current Samba errors on a zero byte count Transaction because it + // uses it to get the Name string and if zero Name will be NULL and + // it won't process it. + com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH; + } + + com_info.byte_count = smb_bcc; +} + +/******************************************************************** + * Function: DCE2_SmbProcessCommand() + * + * Purpose: + * This is the main function for handling SMB commands and command + * chaining. + * It does an initial check of the command to determine validity + * and gets basic information about the command. Then it calls the + * specific command function (setup in DCE2_SmbInitGlobals). + * If there is command chaining, it will do the chaining foo to + * get to the next command. + * + * Arguments: + * DCE2_SmbSsnData * - pointer to session data structure + * SmbNtHdr * - pointer to the SMB header structure + * uint8_t * - current pointer to data, i.e. the command + * uint32_t - the remaining length + * + * Returns: None + * + ********************************************************************/ +static void DCE2_SmbProcessCommand(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr, + const uint8_t* nb_ptr, uint32_t nb_len) +{ + uint8_t smb_com = SmbCom(smb_hdr); + DCE2_Ret status = DCE2_RET__ERROR; + bool sess_chain = false; + bool tree_chain = false; + bool open_chain = false; + int num_chained = 0; + + while (nb_len > 0) + { + // Break out if command not supported + if (smb_com_funcs[smb_com] == nullptr) + break; + + if (smb_deprecated_coms[smb_com]) + { + dce_alert(GID_DCE2, DCE2_SMB_DEPR_COMMAND_USED, (dce2CommonStats*)&dce2_smb_stats); + } + + if (smb_unusual_coms[smb_com]) + { + dce_alert(GID_DCE2, DCE2_SMB_UNUSUAL_COMMAND_USED, (dce2CommonStats*)&dce2_smb_stats); + } + + DCE2_SmbComInfo com_info; + com_info.smb_type = DCE2_SmbType(ssd); + com_info.cmd_error = DCE2_SMB_COM_ERROR__COMMAND_OK; + com_info.word_count = 0; + com_info.smb_com = smb_com; + com_info.cmd_size = 0; + com_info.byte_count = 0; + DCE2_SmbCheckCommand(ssd, smb_hdr, smb_com, nb_ptr, nb_len, com_info); + DebugFormat(DEBUG_DCE_SMB, "Processing command: %s (0x%02X)\n", + get_smb_com_string(smb_com), smb_com); + + // Note that even if the command shouldn't be processed, some of + // the command functions need to know and do cleanup or some other + // processing. + status = smb_com_funcs[smb_com](ssd, smb_hdr, + &com_info, nb_ptr, nb_len); + + if (status != DCE2_RET__SUCCESS) + break; + + // This command is not chainable + SmbAndXCom andx_com = smb_chain_map[smb_com]; + if (andx_com == SMB_ANDX_COM__NONE) + break; + + /********************************************************** + * AndX Chaining + **********************************************************/ + const SmbAndXCommon* andx_ptr = (SmbAndXCommon*)nb_ptr; + uint8_t smb_com2 = SmbAndXCom2(andx_ptr); + if (smb_com2 == SMB_COM_NO_ANDX_COMMAND) + break; + + DebugFormat(DEBUG_DCE_SMB, "Chained SMB command: %s\n", + get_smb_com_string(smb_com2)); + + num_chained++; + if (DCE2_ScSmbMaxChain((dce2SmbProtoConf*)ssd->sd.config) && + (num_chained >= DCE2_ScSmbMaxChain((dce2SmbProtoConf*)ssd->sd.config))) + { + dce_alert(GID_DCE2, DCE2_SMB_EXCESSIVE_CHAINING, (dce2CommonStats*)&dce2_smb_stats); + } + + // Multiple SessionSetupAndX, TreeConnectAndX, OpenAndX and NtCreateAndX + // are only allowed by Samba. + if (smb_com == SMB_COM_SESSION_SETUP_ANDX) + sess_chain = true; + + // Check for multiple chained SessionSetupAndX + if ((smb_com2 == SMB_COM_SESSION_SETUP_ANDX) && sess_chain) + { + // There is only one place to return a uid. + dce_alert(GID_DCE2, DCE2_SMB_MULT_CHAIN_SS, (dce2CommonStats*)&dce2_smb_stats); + // FIXIT-L Should we continue processing? + break; + } + + // Check for chained SessionSetupAndX => .? => LogoffAndX + if ((smb_com2 == SMB_COM_LOGOFF_ANDX) && sess_chain) + { + // This essentially deletes the uid created by the login + // and doesn't make any sense. + dce_alert(GID_DCE2, DCE2_SMB_CHAIN_SS_LOGOFF, (dce2CommonStats*)&dce2_smb_stats); + } + + if (smb_com == SMB_COM_TREE_CONNECT_ANDX) + tree_chain = true; + + // Check for multiple chained TreeConnects + if (((smb_com2 == SMB_COM_TREE_CONNECT_ANDX) + || (smb_com2 == SMB_COM_TREE_CONNECT)) && tree_chain) + { + // There is only one place to return a tid. + dce_alert(GID_DCE2, DCE2_SMB_MULT_CHAIN_TC, (dce2CommonStats*)&dce2_smb_stats); + // FIXIT-L Should we continue processing? + break; + } + + // Check for chained TreeConnectAndX => .? => TreeDisconnect + if ((smb_com2 == SMB_COM_TREE_DISCONNECT) && tree_chain) + { + // This essentially deletes the tid created by the tree connect + // and doesn't make any sense. + dce_alert(GID_DCE2, DCE2_SMB_CHAIN_TC_TDIS, (dce2CommonStats*)&dce2_smb_stats); + } + + if ((smb_com == SMB_COM_OPEN_ANDX) || (smb_com == SMB_COM_NT_CREATE_ANDX)) + open_chain = true; + + // Check for chained OpenAndX/NtCreateAndX => .? => Close + if ((smb_com2 == SMB_COM_CLOSE) && open_chain) + { + // This essentially deletes the fid created by the open command + // and doesn't make any sense. + dce_alert(GID_DCE2, DCE2_SMB_CHAIN_OPEN_CLOSE, (dce2CommonStats*)&dce2_smb_stats); + } + + // Check that policy allows for such chaining + DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd); + if (smb_chain_funcs[policy][andx_com][smb_com2] == nullptr) + break; + + DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(&com_info)); + + // FIXIT-L Need to test out of order chaining + const uint8_t* off2_ptr = (uint8_t*)smb_hdr + SmbAndXOff2(andx_ptr); + if (DCE2_SmbCheckAndXOffset(off2_ptr, nb_ptr, nb_len) != DCE2_RET__SUCCESS) + break; + + DCE2_MOVE(nb_ptr, nb_len, (off2_ptr - nb_ptr)); + + // FIXIT-L Need to test more. + switch (smb_com) + { + case SMB_COM_SESSION_SETUP_ANDX: + case SMB_COM_TREE_CONNECT_ANDX: + case SMB_COM_OPEN_ANDX: + case SMB_COM_NT_CREATE_ANDX: + switch (smb_com2) + { + case SMB_COM_WRITE: + case SMB_COM_WRITE_ANDX: + case SMB_COM_TRANSACTION: + case SMB_COM_READ_ANDX: + if (DCE2_SsnFromClient(ssd->sd.wire_pkt) && open_chain) + { + DCE2_SmbQueueTmpFileTracker(ssd, ssd->cur_rtracker, + SmbUid(smb_hdr), SmbTid(smb_hdr)); + } + break; + default: + break; + } + break; + default: + break; + } + + smb_com = smb_com2; + } + + int smb_type = DCE2_SmbType(ssd); + if (smb_type == SMB_TYPE__RESPONSE) + { + switch (smb_com) + { + case SMB_COM_TRANSACTION: + case SMB_COM_TRANSACTION2: + case SMB_COM_NT_TRANSACT: + case SMB_COM_TRANSACTION_SECONDARY: + case SMB_COM_TRANSACTION2_SECONDARY: + case SMB_COM_NT_TRANSACT_SECONDARY: + // This case means there was an error with the initial response + // so the tracker isn't yet officially in response mode + if (ssd->cur_rtracker->ttracker.smb_type == SMB_TYPE__REQUEST) + { + // Samba throws out entire transaction and Windows just this request + if (DCE2_SsnIsServerSambaPolicy(&ssd->sd) && (status != DCE2_RET__SUCCESS)) + break; + + if (!DCE2_SmbIsTransactionComplete(&ssd->cur_rtracker->ttracker)) + return; + } + else + { + if ((status == DCE2_RET__SUCCESS) + && !DCE2_SmbIsTransactionComplete(&ssd->cur_rtracker->ttracker)) + return; + } + break; + case SMB_COM_WRITE_RAW: + if ((status == DCE2_RET__SUCCESS) + && (ssd->cur_rtracker->writeraw_remaining != 0)) + return; + break; + default: + break; + } + } + else if (status != DCE2_RET__IGNORE) + { + switch (smb_com) + { + case SMB_COM_TRANSACTION: + case SMB_COM_TRANSACTION_SECONDARY: + if (DCE2_SsnIsWindowsPolicy(&ssd->sd)) + { + if (!ssd->cur_rtracker->ttracker.one_way + || !DCE2_SmbIsTransactionComplete(&ssd->cur_rtracker->ttracker)) + return; + + // Remove the request tracker if transaction is one-way and + // all data and parameters have been sent + break; + } + default: + // Anything else, keep the request tracker + return; + } + } + + DCE2_SmbRemoveRequestTracker(ssd, ssd->cur_rtracker); + ssd->cur_rtracker = nullptr; +} + +/******************************************************************** + * Function: DCE2_SmbInspect() + * + * Purpose: + * Determines whether the SMB command is something the preprocessor + * needs to inspect. + * This function returns a DCE2_SmbRequestTracker which tracks command + * requests / responses. + * + * Arguments: + * DCE2_SmbSsnData * - the session data structure. + * const SmbNtHdr * - pointer to the SMB header. + * + * Returns: + * DCE2_SmbRequestTracker * - nullptr if it's not something we want to or can + * inspect. + * Otherwise an initialized structure if request + * and the found structure if response. + * + ********************************************************************/ +static DCE2_SmbRequestTracker* DCE2_SmbInspect(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr) +{ + int smb_com = SmbCom(smb_hdr); + + DebugFormat(DEBUG_DCE_SMB, "SMB command: %s (0x%02X)\n", + get_smb_com_string(smb_com), smb_com); + + if (smb_com_funcs[smb_com] == nullptr) + { + DebugMessage(DEBUG_DCE_SMB, "Command isn't processed " + "by preprocessor.\n"); + return nullptr; + } + + // See if this is something we need to inspect + DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd); + DCE2_SmbRequestTracker* rtracker = nullptr; + if (DCE2_SmbType(ssd) == SMB_TYPE__REQUEST) + { + switch (smb_com) + { + case SMB_COM_NEGOTIATE: + if (ssd->ssn_state_flags & DCE2_SMB_SSN_STATE__NEGOTIATED) + { + dce_alert(GID_DCE2, DCE2_SMB_MULTIPLE_NEGOTIATIONS, + (dce2CommonStats*)&dce2_smb_stats); + return nullptr; + } + break; + case SMB_COM_SESSION_SETUP_ANDX: + break; + case SMB_COM_TREE_CONNECT: + case SMB_COM_TREE_CONNECT_ANDX: + case SMB_COM_RENAME: + case SMB_COM_LOGOFF_ANDX: + if (DCE2_SmbFindUid(ssd, SmbUid(smb_hdr)) != DCE2_RET__SUCCESS) + return nullptr; + break; + default: + if (DCE2_SmbFindTid(ssd, SmbTid(smb_hdr)) != DCE2_RET__SUCCESS) + { + DebugFormat(DEBUG_DCE_SMB, + "Couldn't find Tid (%hu)\n", SmbTid(smb_hdr)); + return nullptr; + } + + if (DCE2_SmbIsTidIPC(ssd, SmbTid(smb_hdr))) + { + switch (smb_com) + { + case SMB_COM_OPEN: + case SMB_COM_CREATE: + case SMB_COM_CREATE_NEW: + case SMB_COM_WRITE_AND_CLOSE: + case SMB_COM_WRITE_AND_UNLOCK: + case SMB_COM_READ: + // Samba doesn't allow these commands under an IPC tree + switch (policy) + { + case DCE2_POLICY__SAMBA: + case DCE2_POLICY__SAMBA_3_0_37: + case DCE2_POLICY__SAMBA_3_0_22: + case DCE2_POLICY__SAMBA_3_0_20: + DebugMessage(DEBUG_DCE_SMB, "Samba doesn't " + "process this command under an IPC tree.\n"); + return nullptr; + default: + break; + } + break; + case SMB_COM_READ_RAW: + case SMB_COM_WRITE_RAW: + // Samba and Windows Vista on don't allow these commands + // under an IPC tree, whether or not the raw read/write + // flag is set in the Negotiate capabilities. + // Windows RSTs the connection and Samba FINs it. + switch (policy) + { + case DCE2_POLICY__WINVISTA: + case DCE2_POLICY__WIN2008: + case DCE2_POLICY__WIN7: + case DCE2_POLICY__SAMBA: + case DCE2_POLICY__SAMBA_3_0_37: + case DCE2_POLICY__SAMBA_3_0_22: + case DCE2_POLICY__SAMBA_3_0_20: + DebugMessage(DEBUG_DCE_SMB, "Samba and " + "Windows Vista on don't process this " + "command under an IPC tree.\n"); + return nullptr; + default: + break; + } + break; + case SMB_COM_LOCK_AND_READ: + // The lock will fail so the read won't happen + return nullptr; + default: + break; + } + } + else // Not IPC + { + switch (smb_com) + { + // These commands are only used for IPC + case SMB_COM_TRANSACTION: + case SMB_COM_TRANSACTION_SECONDARY: + DebugMessage(DEBUG_DCE_SMB, "secondary transaction not IPC.\n"); + return nullptr; + case SMB_COM_READ_RAW: + case SMB_COM_WRITE_RAW: + // Windows Vista on don't seem to support these + // commands, whether or not the raw read/write + // flag is set in the Negotiate capabilities. + // Windows RSTs the connection. + switch (policy) + { + case DCE2_POLICY__WINVISTA: + case DCE2_POLICY__WIN2008: + case DCE2_POLICY__WIN7: + DebugMessage(DEBUG_DCE_SMB, + "Windows Vista on don't process " + "this command.\n"); + return nullptr; + default: + break; + } + break; + default: + break; + } + } + break; + } + + switch (smb_com) + { + case SMB_COM_TRANSACTION_SECONDARY: + case SMB_COM_TRANSACTION2_SECONDARY: + case SMB_COM_NT_TRANSACT_SECONDARY: + rtracker = DCE2_SmbFindRequestTracker(ssd, smb_hdr); + break; + case SMB_COM_TRANSACTION: + case SMB_COM_TRANSACTION2: + case SMB_COM_NT_TRANSACT: + // If there is already and existing request tracker + // and the transaction is not complete, server will + // return an error. + rtracker = DCE2_SmbFindRequestTracker(ssd, smb_hdr); + if (rtracker != nullptr) + break; + // Fall through + default: + rtracker = DCE2_SmbNewRequestTracker(ssd, smb_hdr); + break; + } + } + else + { + rtracker = DCE2_SmbFindRequestTracker(ssd, smb_hdr); + } + + return rtracker; +} + +static void DCE2_SmbProcessRawData(DCE2_SmbSsnData* ssd, const uint8_t* nb_ptr, uint32_t nb_len) +{ + DCE2_SmbFileTracker* ftracker = ssd->cur_rtracker->ftracker; + bool remove_rtracker = false; + + if (ftracker == nullptr) + { + DCE2_SmbRemoveRequestTracker(ssd, ssd->cur_rtracker); + ssd->cur_rtracker = nullptr; + return; + } + + if (DCE2_SsnFromClient(ssd->sd.wire_pkt)) + { + DebugMessage(DEBUG_DCE_SMB, "Raw data: Write Raw\n"); + DebugFormat(DEBUG_DCE_SMB, "Request Fid: 0x%04X\n", ftracker->fid_v1); + + if (nb_len > ssd->cur_rtracker->writeraw_remaining) + { + dce_alert(GID_DCE2, DCE2_SMB_TDCNT_LT_DSIZE, (dce2CommonStats*)&dce2_smb_stats); + + // If this happens, Windows never responds regardless of + // WriteThrough flag, so get rid of request tracker + remove_rtracker = true; + } + else if (!ssd->cur_rtracker->writeraw_writethrough) + { + // If WriteThrough flag was not set on initial request, a + // SMB_COM_WRITE_COMPLETE will not be sent so need to get + // rid of request tracker. + remove_rtracker = true; + } + else + { + ssd->cur_rtracker->writeraw_writethrough = false; + ssd->cur_rtracker->writeraw_remaining = 0; + } + } + else + { + DebugMessage(DEBUG_DCE_SMB, "Raw data: Read Raw\n"); + DebugFormat(DEBUG_DCE_SMB, "Response Fid: 0x%04X\n", ftracker->fid_v1); + + remove_rtracker = true; + } + + // Only one raw read/write allowed + ssd->pdu_state = DCE2_SMB_PDU_STATE__COMMAND; + + if (ftracker->is_ipc) + { + // Maximum possible fragment length is 16 bit + if (nb_len > UINT16_MAX) + nb_len = UINT16_MAX; + + DCE2_CoProcess(&ssd->sd, ftracker->fp_co_tracker, nb_ptr, (uint16_t)nb_len); + } + else + { + bool upload = DCE2_SsnFromClient(ssd->sd.wire_pkt) ? true : false; + DCE2_SmbProcessFileData(ssd, ftracker, nb_ptr, nb_len, upload); + } + + if (remove_rtracker) + { + DCE2_SmbRemoveRequestTracker(ssd, ssd->cur_rtracker); + ssd->cur_rtracker = nullptr; + } +} + +static void DCE2_SmbDataFree(DCE2_SmbSsnData* ssd) +{ + if (ssd == nullptr) + return; + + // FIXIT This tries to account for the situation where we never knew the file + // size and the TCP session was shutdown before an SMB_COM_CLOSE on the file. + // Possibly need to add callback to fileAPI since it may have already + // released it's resources. + //DCE2_SmbFinishFileAPI(ssd); + + if (ssd->uids != nullptr) + { + DCE2_ListDestroy(ssd->uids); + ssd->uids = nullptr; + } + + if (ssd->tids != nullptr) + { + DCE2_ListDestroy(ssd->tids); + ssd->tids = nullptr; + } + + DCE2_SmbCleanFileTracker(&ssd->ftracker); + if (ssd->ftrackers != nullptr) + { + DCE2_ListDestroy(ssd->ftrackers); + ssd->ftrackers = nullptr; + } + + DCE2_SmbCleanRequestTracker(&ssd->rtracker); + if (ssd->rtrackers != nullptr) + { + DCE2_QueueDestroy(ssd->rtrackers); + ssd->rtrackers = nullptr; + } + + if (ssd->cli_seg != nullptr) + { + DCE2_BufferDestroy(ssd->cli_seg); + ssd->cli_seg = nullptr; + } + + if (ssd->srv_seg != nullptr) + { + DCE2_BufferDestroy(ssd->srv_seg); + ssd->srv_seg = nullptr; + } + + if (ssd->smb2_requests != nullptr) + { + DCE2_Smb2CleanRequests(ssd->smb2_requests); + ssd->smb2_requests = nullptr; + } +} + +Dce2SmbFlowData::Dce2SmbFlowData() : FlowData(flow_id) +{ +} + +Dce2SmbFlowData::~Dce2SmbFlowData() +{ + DCE2_SmbDataFree(&dce2_smb_session); +} + +unsigned Dce2SmbFlowData::flow_id = 0; + +DCE2_SmbSsnData* get_dce2_smb_session_data(Flow* flow) +{ + Dce2SmbFlowData* fd = (Dce2SmbFlowData*)flow->get_flow_data(Dce2SmbFlowData::flow_id); + return fd ? &fd->dce2_smb_session : nullptr; +} + +static DCE2_SmbSsnData* set_new_dce2_smb_session(Packet* p) +{ + Dce2SmbFlowData* fd = new Dce2SmbFlowData; + memset(&fd->dce2_smb_session,0,sizeof(DCE2_SmbSsnData)); + p->flow->set_flow_data(fd); + return(&fd->dce2_smb_session); +} + +static DCE2_SmbSsnData* dce2_create_new_smb_session(Packet* p, dce2SmbProtoConf* config) +{ + DCE2_SmbSsnData* dce2_smb_sess = nullptr; + Profile profile(dce2_smb_pstat_new_session); + + DebugMessage(DEBUG_DCE_SMB, "DCE over SMB packet detected\n"); + DebugMessage(DEBUG_DCE_SMB, "Creating new session\n"); + + dce2_smb_sess = set_new_dce2_smb_session(p); + if ( dce2_smb_sess ) + { + dce2_smb_sess->dialect_index = DCE2_SENTINEL; + dce2_smb_sess->max_outstanding_requests = 10; // Until Negotiate/SessionSetupAndX + dce2_smb_sess->cli_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; + dce2_smb_sess->srv_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; + dce2_smb_sess->pdu_state = DCE2_SMB_PDU_STATE__COMMAND; + dce2_smb_sess->uid = DCE2_SENTINEL; + dce2_smb_sess->tid = DCE2_SENTINEL; + dce2_smb_sess->ftracker.fid_v1 = DCE2_SENTINEL; + dce2_smb_sess->rtracker.mid = DCE2_SENTINEL; + dce2_smb_sess->max_file_depth = FileService::get_max_file_depth(); + + DCE2_ResetRopts(&dce2_smb_sess->sd.ropts); + + dce2_smb_stats.smb_sessions++; + DebugFormat(DEBUG_DCE_SMB,"Created (%p)\n", (void*)dce2_smb_sess); + + dce2_smb_sess->sd.trans = DCE2_TRANS_TYPE__SMB; + dce2_smb_sess->sd.server_policy = config->common.policy; + dce2_smb_sess->sd.client_policy = DCE2_POLICY__WINXP; + dce2_smb_sess->sd.wire_pkt = p; + dce2_smb_sess->sd.config = (void*)config; + } + + return dce2_smb_sess; +} + +/******************************************************************** + * Function: DCE2_NbssHdrChecks() + * + * Purpose: + * Does validation of the NetBIOS header. SMB will only run over + * the Session Message type. On port 139, there is always an + * initial Session Request / Session Positive/Negative response + * followed by the normal SMB conversation, i.e. Negotiate, + * SessionSetupAndX, etc. + * Side effects are potential alerts for anomolous behavior. + * + * Arguments: + * DCE2_SmbSsnData * - the session data structure. + * const NbssHdr * - pointer to the NetBIOS Session Service + * header structure. Size is already validated. + * + * Returns: + * DCE2_Ret - DCE2_RET__SUCCESS if all goes well and processing + * should continue. + * DCE2_RET__IGNORE if it's not something we need to + * look at. + * DCE2_RET__ERROR if an invalid NetBIOS Session + * Service type is found. + * + ********************************************************************/ +static DCE2_Ret DCE2_NbssHdrChecks(DCE2_SmbSsnData* ssd, const NbssHdr* nb_hdr) +{ + Packet* p = ssd->sd.wire_pkt; + bool is_seg_buf = DCE2_SmbIsSegBuffer(ssd, (uint8_t*)nb_hdr); + + DebugMessage(DEBUG_DCE_SMB, "NetBIOS Session Service type: "); + + switch (NbssType(nb_hdr)) + { + case NBSS_SESSION_TYPE__MESSAGE: + /* Only want to look at session messages */ + DebugMessage(DEBUG_DCE_SMB, "Session Message\n"); + + if (!DCE2_SmbIsRawData(ssd)) + { + uint32_t nb_len = NbssLen(nb_hdr); + + if (nb_len == 0) + return DCE2_RET__IGNORE; + + if (nb_len < sizeof(SmbNtHdr)) + { + DebugFormat(DEBUG_DCE_SMB, "NetBIOS SS len(%zu) < SMB header len(%zu).\n", + sizeof(SmbNtHdr), sizeof(NbssHdr) + nb_len); + + if (is_seg_buf) + DCE2_SmbSegAlert(ssd, DCE2_SMB_NB_LT_SMBHDR); + else + dce_alert(GID_DCE2, DCE2_SMB_NB_LT_SMBHDR, (dce2CommonStats*)&dce2_smb_stats); + + return DCE2_RET__IGNORE; + } + } + + return DCE2_RET__SUCCESS; + + case NBSS_SESSION_TYPE__REQUEST: + DebugMessage(DEBUG_DCE_SMB, "Session Request\n"); + if (DCE2_SsnFromServer(p)) + { + if (is_seg_buf) + DCE2_SmbSegAlert(ssd, DCE2_SMB_BAD_NBSS_TYPE); + else + dce_alert(GID_DCE2, DCE2_SMB_BAD_NBSS_TYPE, (dce2CommonStats*)&dce2_smb_stats); + } + + break; + + case NBSS_SESSION_TYPE__POS_RESPONSE: + case NBSS_SESSION_TYPE__NEG_RESPONSE: + case NBSS_SESSION_TYPE__RETARGET_RESPONSE: + if (DCE2_SsnFromClient(p)) + { + if (is_seg_buf) + DCE2_SmbSegAlert(ssd, DCE2_SMB_BAD_NBSS_TYPE); + else + dce_alert(GID_DCE2, DCE2_SMB_BAD_NBSS_TYPE, (dce2CommonStats*)&dce2_smb_stats); + } + + break; + + case NBSS_SESSION_TYPE__KEEP_ALIVE: + DebugMessage(DEBUG_DCE_SMB, "Session Keep Alive\n"); + break; + + default: + DebugFormat(DEBUG_DCE_SMB, + "Invalid Session Service type: 0x%02X\n", NbssType(nb_hdr)); + + if (is_seg_buf) + DCE2_SmbSegAlert(ssd, DCE2_SMB_BAD_NBSS_TYPE); + else + dce_alert(GID_DCE2, DCE2_SMB_BAD_NBSS_TYPE, (dce2CommonStats*)&dce2_smb_stats); + + return DCE2_RET__ERROR; + } + + return DCE2_RET__IGNORE; +} + + +// This is the main entry point for SMB1 processing. +static void DCE2_Smb1Process(DCE2_SmbSsnData* ssd) +{ + DebugMessage(DEBUG_DCE_SMB, "Processing SMB packet.\n"); + dce2_smb_stats.smb_pkts++; + + const Packet* p = ssd->sd.wire_pkt; + const uint8_t* data_ptr = p->data; + uint16_t data_len = p->dsize; + DCE2_Buffer** seg_buf = DCE2_SmbGetSegBuffer(ssd); + + /* Have to account for segmentation. Even though stream will give + * us larger chunks, we might end up in the middle of something */ + while (data_len > 0) + { + // We are ignoring an entire PDU or junk data so state should be NETBIOS_HEADER + // Note that it could be TCP segmented so ignore_bytes could be greater than + // the amount of data we have + uint32_t* ignore_bytes = DCE2_SmbGetIgnorePtr(ssd); + if (*ignore_bytes) + { + DebugFormat(DEBUG_DCE_SMB, "Ignoring %u bytes\n", *ignore_bytes); + + if (data_len <= *ignore_bytes) + { + *ignore_bytes -= data_len; + return; + } + else + { + /* ignore bytes is less than UINT16_MAX */ + DCE2_MOVE(data_ptr, data_len, (uint16_t)*ignore_bytes); + *ignore_bytes = 0; + } + } + + DCE2_SmbDataState* data_state = DCE2_SmbGetDataState(ssd); + DCE2_SmbRequestTracker* rtracker = nullptr; + switch (*data_state) + { + // This state is to verify it's a NetBIOS Session Message packet + // and to get the length of the SMB PDU. Also does the SMB junk + // data check. If it's not a Session Message the data isn't + // processed since it won't be carrying SMB. + case DCE2_SMB_DATA_STATE__NETBIOS_HEADER: + { + uint32_t data_need = sizeof(NbssHdr); + + // See if there is enough data to process the NetBIOS header + if (data_len < data_need) + { + DebugFormat(DEBUG_DCE_SMB, "Data len(%hu) < NetBIOS SS header(%u). " + "Queueing data.\n", data_len, data_need); + + if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, + data_len, sizeof(NbssHdr)) != DCE2_RET__SUCCESS) + { + DCE2_BufferEmpty(*seg_buf); + } + + return; + } + + // Set the NetBIOS header structure + NbssHdr* nb_hdr; + if (DCE2_BufferIsEmpty(*seg_buf)) + { + nb_hdr = (NbssHdr*)data_ptr; + } + else + { + // If data already buffered add the remainder for the + // size of the NetBIOS header + if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, + data_need, sizeof(NbssHdr)) != DCE2_RET__SUCCESS) + { + DCE2_BufferEmpty(*seg_buf); + return; + } + + nb_hdr = (NbssHdr*)DCE2_BufferData(*seg_buf); + } + + uint32_t nb_len = NbssLen(nb_hdr); + + DebugFormat(DEBUG_DCE_SMB, "NetBIOS PDU length: %u\n", nb_len); + + DCE2_Ret status = DCE2_NbssHdrChecks(ssd, nb_hdr); + if (status != DCE2_RET__SUCCESS) + { + DebugMessage(DEBUG_DCE_SMB, "Not a NetBIOS Session Message.\n"); + + if (status == DCE2_RET__IGNORE) + { + DebugMessage(DEBUG_DCE_SMB, "Valid NetBIOS header " + "type so ignoring NetBIOS length bytes.\n"); + *ignore_bytes = data_need + nb_len; + } + else // nb_ret == DCE2_RET__ERROR, i.e. invalid NetBIOS type + { + DebugMessage(DEBUG_DCE_SMB, "Not a valid NetBIOS " + "header type so trying to find \\xffSMB to " + "determine how many bytes to ignore.\n"); + *ignore_bytes = DCE2_IgnoreJunkData(data_ptr, data_len, data_need + nb_len); + } + + DCE2_BufferEmpty(*seg_buf); + dce2_smb_stats.smb_ignored_bytes += *ignore_bytes; + continue; + } + + if (!DCE2_BufferIsEmpty(*seg_buf)) + DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need); + + switch (ssd->pdu_state) + { + case DCE2_SMB_PDU_STATE__COMMAND: + *data_state = DCE2_SMB_DATA_STATE__SMB_HEADER; + break; + case DCE2_SMB_PDU_STATE__RAW_DATA: + *data_state = DCE2_SMB_DATA_STATE__NETBIOS_PDU; + // Continue here because of fall through below + continue; + default: + DebugFormat(DEBUG_DCE_SMB,"%s(%d) Invalid SMB PDU " + "state: %d\n", __FILE__, __LINE__, ssd->pdu_state); + return; + } + } + + // Fall through for DCE2_SMB_DATA_STATE__SMB_HEADER + // This is the normal progression without segmentation. + + // This state is to do validation checks on the SMB header and + // more importantly verify it's data that needs to be inspected. + // If the TID in the SMB header is not referring to the IPC share + // there won't be any DCE/RPC traffic associated with it. + case DCE2_SMB_DATA_STATE__SMB_HEADER: + { + uint32_t data_need = (sizeof(NbssHdr) + sizeof(SmbNtHdr)) - DCE2_BufferLength( + *seg_buf); + + // See if there is enough data to process the SMB header + if (data_len < data_need) + { + DebugFormat(DEBUG_DCE_SMB, "Data len (%hu) < " + "NetBIOS SS header + SMB header (%u). Queueing data.\n", + data_len, data_need); + + if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, data_len, + sizeof(NbssHdr) + sizeof(SmbNtHdr)) != DCE2_RET__SUCCESS) + { + DCE2_BufferEmpty(*seg_buf); + *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; + } + + return; + } + + // Set the SMB header structure + SmbNtHdr* smb_hdr; + if (DCE2_BufferIsEmpty(*seg_buf)) + { + smb_hdr = (SmbNtHdr*)(data_ptr + sizeof(NbssHdr)); + } + else + { + if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, data_need, + sizeof(NbssHdr) + sizeof(SmbNtHdr)) != DCE2_RET__SUCCESS) + { + DCE2_BufferEmpty(*seg_buf); + *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; + return; + } + + smb_hdr = (SmbNtHdr*)(DCE2_BufferData(*seg_buf) + sizeof(NbssHdr)); + } + + if (SmbId(smb_hdr) == DCE2_SMB2_ID) + { + ssd->sd.flags |= DCE2_SSN_FLAG__SMB2; + if (!DCE2_GcIsLegacyMode((dce2SmbProtoConf*)ssd->sd.config)) + { + DCE2_Smb2InitFileTracker(&(ssd->ftracker), false, 0); + DCE2_Smb2Process(ssd); + } + return; + } + + // See if this is something we need to inspect + rtracker = DCE2_SmbInspect(ssd, smb_hdr); + if (rtracker == nullptr) + { + DebugMessage(DEBUG_DCE_SMB, "Not inspecting SMB packet.\n"); + + if (DCE2_BufferIsEmpty(*seg_buf)) + { + *ignore_bytes = sizeof(NbssHdr) + NbssLen((NbssHdr*)data_ptr); + } + else + { + *ignore_bytes = (NbssLen((NbssHdr*)DCE2_BufferData(*seg_buf)) + - sizeof(SmbNtHdr)) + data_need; + DCE2_BufferEmpty(*seg_buf); + } + + *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; + dce2_smb_stats.smb_ignored_bytes += *ignore_bytes; + continue; + } + + // Check the SMB header for anomolies + if (DCE2_SmbHdrChecks(ssd, smb_hdr) != DCE2_RET__SUCCESS) + { + DebugMessage(DEBUG_DCE_SMB, "Bad SMB header.\n"); + + if (DCE2_BufferIsEmpty(*seg_buf)) + { + *ignore_bytes = sizeof(NbssHdr) + NbssLen((NbssHdr*)data_ptr); + } + else + { + *ignore_bytes = (NbssLen((NbssHdr*)DCE2_BufferData(*seg_buf)) + - sizeof(SmbNtHdr)) + data_need; + DCE2_BufferEmpty(*seg_buf); + } + + *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; + + dce2_smb_stats.smb_ignored_bytes += *ignore_bytes; + continue; + } + + if (!DCE2_BufferIsEmpty(*seg_buf)) + DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need); + + *data_state = DCE2_SMB_DATA_STATE__NETBIOS_PDU; + } + + // Fall through + + // This state ensures that we have the entire PDU before continuing + // to process. + case DCE2_SMB_DATA_STATE__NETBIOS_PDU: + { + uint32_t nb_len; + uint32_t data_need; + + if (DCE2_BufferIsEmpty(*seg_buf)) + { + nb_len = NbssLen((NbssHdr*)data_ptr); + data_need = sizeof(NbssHdr) + nb_len; + } + else + { + nb_len = NbssLen((NbssHdr*)DCE2_BufferData(*seg_buf)); + data_need = (sizeof(NbssHdr) + nb_len) - DCE2_BufferLength(*seg_buf); + } + + /* It's something we want to inspect so make sure we have the full NBSS packet */ + if (data_len < data_need) + { + DebugFormat(DEBUG_DCE_SMB, "Data len(%hu) < " + "NetBIOS SS header + NetBIOS len(%zu). " + "Queueing data.\n", data_len, sizeof(NbssHdr) + nb_len); + + if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, data_len, + sizeof(NbssHdr) + nb_len) != DCE2_RET__SUCCESS) + { + DCE2_BufferEmpty(*seg_buf); + *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; + } + + return; + } + + // data_len >= data_need which means data_need <= UINT16_MAX + // So casts below of data_need to uint16_t are okay. + + *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; + + const uint8_t* nb_ptr; + if (DCE2_BufferIsEmpty(*seg_buf)) + { + nb_ptr = data_ptr; + nb_len = data_need; + DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need); + } + else + { + if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, data_need, + sizeof(NbssHdr) + nb_len) != DCE2_RET__SUCCESS) + { + DCE2_BufferEmpty(*seg_buf); + DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need); + continue; + } + + DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need); + + nb_ptr = DCE2_BufferData(*seg_buf); + nb_len = DCE2_BufferLength(*seg_buf); + + // Get reassembled packet + Packet* rpkt = DCE2_SmbGetRpkt(ssd, &nb_ptr, &nb_len, + DCE2_RPKT_TYPE__SMB_SEG); + if (rpkt == nullptr) + { + DCE2_BufferEmpty(*seg_buf); + continue; + } + + nb_ptr = DCE2_BufferData(*seg_buf); + nb_len = DCE2_BufferLength(*seg_buf); + + DebugFormat(DEBUG_DCE_SMB, + "Segmentation buffer: len: %u, size: %u\n", + DCE2_BufferLength(*seg_buf), DCE2_BufferSize(*seg_buf)); + + if (DCE2_SsnFromClient(ssd->sd.wire_pkt)) + dce2_smb_stats.smb_cli_seg_reassembled++; + else + dce2_smb_stats.smb_srv_seg_reassembled++; + + DebugMessage(DEBUG_DCE_SMB, "TCP reassembled SMB PDU\n"); + DCE2_PrintPktData(rpkt->data, rpkt->dsize); + } + + switch (ssd->pdu_state) + { + case DCE2_SMB_PDU_STATE__COMMAND: + { + SmbNtHdr* smb_hdr = (SmbNtHdr*)(nb_ptr + sizeof(NbssHdr)); + DCE2_MOVE(nb_ptr, nb_len, (sizeof(NbssHdr) + sizeof(SmbNtHdr))); + ssd->cur_rtracker = (rtracker != nullptr) + ? rtracker : DCE2_SmbFindRequestTracker(ssd, smb_hdr); + if (ssd->cur_rtracker != nullptr) + DCE2_SmbProcessCommand(ssd, smb_hdr, nb_ptr, nb_len); + break; + } + + case DCE2_SMB_PDU_STATE__RAW_DATA: + DCE2_MOVE(nb_ptr, nb_len, sizeof(NbssHdr)); + if (ssd->cur_rtracker != nullptr) + DCE2_SmbProcessRawData(ssd, nb_ptr, nb_len); + // Only one raw read or write + ssd->pdu_state = DCE2_SMB_PDU_STATE__COMMAND; + break; + default: + DebugFormat(DEBUG_DCE_SMB, "%s(%d) Invalid SMB PDU " + "state: %d\n", __FILE__, __LINE__, ssd->pdu_state); + return; + } + + if (!DCE2_BufferIsEmpty(*seg_buf)) + { + DCE2_SmbReturnRpkt(ssd); + DCE2_BufferDestroy(*seg_buf); + *seg_buf = nullptr; + } + + break; + } + + default: + DebugFormat(DEBUG_DCE_SMB, "%s(%d) Invalid SMB Data " + "state: %d\n", __FILE__, __LINE__, *data_state); + return; + } + } +} + +//------------------------------------------------------------------------- +// public methods +//------------------------------------------------------------------------- + +/******************************************************************** + * Function: DCE2_SmbInitGlobals() + * + * Purpose: + * Initializes global variables for SMB processing. + * Sets up the functions and valid word and byte counts for SMB + * commands. + * Sets up AndX chain mappings and valid command chaining for + * supported policies. + * + * Arguments: None + * + * Returns: None + * + ********************************************************************/ +void DCE2_SmbInitGlobals() +{ + memset(&smb_wcts, 0, sizeof(smb_wcts)); + memset(&smb_bccs, 0, sizeof(smb_bccs)); + + // Sets up the function to call for the command and valid word and byte + // counts for the command. Ensuring valid word and byte counts is very + // important to processing the command as it will assume the command is + // legitimate and can access data that is acutally there. Note that + // commands with multiple word counts indicate a different command + // structure, however most, if not all just have an extended version + // of the structure for which the extended part isn't used. If the + // extended part of a command structure needs to be used, be sure to + // check the word count in the command function before accessing data + // in the extended version of the command structure. + for (int com = 0; com < SMB_MAX_NUM_COMS; com++) + { + switch (com) + { + case SMB_COM_OPEN: + smb_com_funcs[com] = DCE2_SmbOpen; + + smb_deprecated_coms[com] = true; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 2); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 7); + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); + break; + case SMB_COM_CREATE: + smb_com_funcs[com] = DCE2_SmbCreate; + + smb_deprecated_coms[com] = true; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 3); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); + break; + case SMB_COM_CLOSE: + smb_com_funcs[com] = DCE2_SmbClose; + smb_deprecated_coms[com] = false; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 3); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0); + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); + break; + case SMB_COM_RENAME: + smb_com_funcs[com] = DCE2_SmbRename; + smb_deprecated_coms[com] = false; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 1); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0); + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 4, UINT16_MAX); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); + break; + case SMB_COM_READ: + smb_com_funcs[com] = DCE2_SmbRead; + smb_deprecated_coms[com] = true; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 5); + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 3, UINT16_MAX); + break; + case SMB_COM_WRITE: + smb_com_funcs[com] = DCE2_SmbWrite; + smb_deprecated_coms[com] = true; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 3, UINT16_MAX); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); + break; + case SMB_COM_CREATE_NEW: + smb_com_funcs[com] = DCE2_SmbCreateNew; + smb_deprecated_coms[com] = true; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 3); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); + break; + case SMB_COM_LOCK_AND_READ: + smb_com_funcs[com] = DCE2_SmbLockAndRead; + smb_deprecated_coms[com] = true; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 5); + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 3, UINT16_MAX); + break; + case SMB_COM_WRITE_AND_UNLOCK: + smb_com_funcs[com] = DCE2_SmbWriteAndUnlock; + smb_deprecated_coms[com] = true; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 3, UINT16_MAX); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); + break; + case SMB_COM_READ_RAW: + smb_com_funcs[com] = DCE2_SmbReadRaw; + smb_deprecated_coms[com] = true; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 8); + // With optional OffsetHigh + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 10); + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0); + // Response is raw data, i.e. without SMB + break; + case SMB_COM_WRITE_RAW: + smb_com_funcs[com] = DCE2_SmbWriteRaw; + smb_deprecated_coms[com] = true; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12); + // With optional OffsetHigh + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 14); + // Interim server response + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); + break; + case SMB_COM_WRITE_COMPLETE: + // Final server response to SMB_COM_WRITE_RAW + smb_com_funcs[com] = DCE2_SmbWriteComplete; + smb_deprecated_coms[com] = true; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); + break; + case SMB_COM_TRANSACTION: + smb_com_funcs[com] = DCE2_SmbTransaction; + smb_deprecated_coms[com] = false; + smb_unusual_coms[com] = false; + + // Word count depends on setup count + //for (i = 14; i < 256; i++) + // DCE2_SmbSetValidWordCount(com, SMB_TYPE__REQUEST, i); + // In reality, all subcommands of SMB_COM_TRANSACTION requests + // have a setup count of 2 words. + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 16); + + // \PIPE\LANMAN + // Not something the preprocessor is looking at as it + // doesn't carry DCE/RPC but don't want to false positive + // on the preprocessor event. + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 14); + + // Word count depends on setup count + //for (i = 10; i < 256; i++) + // DCE2_SmbSetValidWordCount(com, SMB_TYPE__RESPONSE, i); + // In reality, all subcommands of SMB_COM_TRANSACTION responses + // have a setup count of 0 words. + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 10); + + // Interim server response + // When client sends an incomplete transaction and needs to + // send TransactionSecondary requests to complete request. + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0); + + // Exception will be made for Interim responses when + // byte count is checked. + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); + break; + case SMB_COM_TRANSACTION_SECONDARY: + smb_com_funcs[com] = DCE2_SmbTransactionSecondary; + smb_deprecated_coms[com] = false; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 8); + // Response is an SMB_COM_TRANSACTION + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); + break; + case SMB_COM_WRITE_AND_CLOSE: + smb_com_funcs[com] = DCE2_SmbWriteAndClose; + smb_deprecated_coms[com] = true; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 6); + // For some reason MS-CIFS specifies a version of this command + // with 6 extra words (12 bytes) of reserved, i.e. useless data. + // Maybe had intentions of extending and defining the data at + // some point, but there is no documentation that I could find + // that does. + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 1, UINT16_MAX); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); + break; + case SMB_COM_OPEN_ANDX: + smb_com_funcs[com] = DCE2_SmbOpenAndX; + smb_deprecated_coms[com] = true; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 15); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 15); + // Extended response + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 19); + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX); + // MS-SMB says that Windows 2000, XP and Vista set this to + // some arbitrary value that is ignored on receipt. + //DCE2_SmbSetValidByteCount(com, SMB_TYPE__RESPONSE, 0, 0); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); + break; + case SMB_COM_READ_ANDX: + smb_com_funcs[com] = DCE2_SmbReadAndX; + smb_deprecated_coms[com] = false; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 10); + // With optional OffsetHigh + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 12); + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); + break; + case SMB_COM_WRITE_ANDX: + smb_com_funcs[com] = DCE2_SmbWriteAndX; + smb_deprecated_coms[com] = false; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12); + // With optional OffsetHigh + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 14); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 6); + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 1, UINT16_MAX); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); + break; + case SMB_COM_TRANSACTION2: + smb_com_funcs[com] = DCE2_SmbTransaction2; + smb_deprecated_coms[com] = false; + smb_unusual_coms[com] = false; + + // Word count depends on setup count + //for (i = 14; i < 256; i++) + // DCE2_SmbSetValidWordCount(com, SMB_TYPE__REQUEST, i); + // In reality, all subcommands of SMB_COM_TRANSACTION2 + // requests have a setup count of 1 word. + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 15); + + // Word count depends on setup count + //for (i = 10; i < 256; i++) + // DCE2_SmbSetValidWordCount(com, SMB_TYPE__RESPONSE, i); + // In reality, all subcommands of SMB_COM_TRANSACTION2 + // responses have a setup count of 0 or 1 word. + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 10); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 11); + + // Interim server response + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0); + + // Exception will be made for Interim responses when + // byte count is checked. + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); + break; + case SMB_COM_TRANSACTION2_SECONDARY: + smb_com_funcs[com] = DCE2_SmbTransaction2Secondary; + smb_deprecated_coms[com] = false; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 9); + // Response is an SMB_COM_TRANSACTION2 + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); + break; + case SMB_COM_TREE_CONNECT: + smb_com_funcs[com] = DCE2_SmbTreeConnect; + smb_deprecated_coms[com] = true; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 0); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 2); + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 6, UINT16_MAX); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); + break; + case SMB_COM_TREE_DISCONNECT: + smb_com_funcs[com] = DCE2_SmbTreeDisconnect; + smb_deprecated_coms[com] = false; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 0); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0); + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); + break; + case SMB_COM_NEGOTIATE: + smb_com_funcs[com] = DCE2_SmbNegotiate; + smb_deprecated_coms[com] = false; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 0); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 13); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 17); + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX); + // This can vary depending on dialect so just set wide. + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); + break; + case SMB_COM_SESSION_SETUP_ANDX: + smb_com_funcs[com] = DCE2_SmbSessionSetupAndX; + smb_deprecated_coms[com] = false; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 10); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 13); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 3); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 4); + + // These can vary so just set wide. + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); + break; + case SMB_COM_LOGOFF_ANDX: + smb_com_funcs[com] = DCE2_SmbLogoffAndX; + smb_deprecated_coms[com] = false; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 2); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 2); + // Windows responds to a LogoffAndX => SessionSetupAndX with just a + // LogoffAndX and with the word count field containing 3, but only + // has 2 words + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 3); + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); + break; + case SMB_COM_TREE_CONNECT_ANDX: + smb_com_funcs[com] = DCE2_SmbTreeConnectAndX; + smb_deprecated_coms[com] = false; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 4); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 2); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 3); + // Extended response + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 7); + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 3, UINT16_MAX); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 2, UINT16_MAX); + break; + case SMB_COM_NT_TRANSACT: + smb_com_funcs[com] = DCE2_SmbNtTransact; + smb_deprecated_coms[com] = false; + smb_unusual_coms[com] = false; + + // Word count depends on setup count + // In reality, all subcommands of SMB_COM_NT_TRANSACT + // requests have a setup count of 0 or 4 words. + //for (i = 19; i < 256; i++) + // DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, i); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 19); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 23); + + // Word count depends on setup count + // In reality, all subcommands of SMB_COM_NT_TRANSACT + // responses have a setup count of 0 or 1 word. + //for (i = 18; i < 256; i++) + // DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, i); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 18); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 19); + + // Interim server response + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0); + + // Exception will be made for Interim responses when + // byte count is checked. + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); + break; + case SMB_COM_NT_TRANSACT_SECONDARY: + smb_com_funcs[com] = DCE2_SmbNtTransactSecondary; + smb_deprecated_coms[com] = false; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 18); + // Response is an SMB_COM_NT_TRANSACT + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); + break; + case SMB_COM_NT_CREATE_ANDX: + smb_com_funcs[com] = DCE2_SmbNtCreateAndX; + smb_deprecated_coms[com] = false; + smb_unusual_coms[com] = false; + + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 24); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 34); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 26); + // Extended response - though there are actually 50 words + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 42); + + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX); + // MS-SMB indicates that this field should be 0 but may be + // sent uninitialized so basically ignore it. + //DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); + break; + default: + smb_com_funcs[com] = nullptr; + smb_deprecated_coms[com] = false; + smb_unusual_coms[com] = false; + // Just set to all valid since the specific command won't + // be processed. Don't want to false positive on these. + for (int i = 0; i < 256; i++) + { + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, (uint8_t)i); + DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, (uint8_t)i); + } + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX); + DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX); + break; + } + } + + // Maps commands for use in quickly determining if a command + // is chainable and what command it is. + for (int com = 0; com < SMB_MAX_NUM_COMS; com++) + { + switch (com) + { + case SMB_COM_SESSION_SETUP_ANDX: + smb_chain_map[com] = SMB_ANDX_COM__SESSION_SETUP_ANDX; + break; + case SMB_COM_LOGOFF_ANDX: + smb_chain_map[com] = SMB_ANDX_COM__LOGOFF_ANDX; + break; + case SMB_COM_TREE_CONNECT_ANDX: + smb_chain_map[com] = SMB_ANDX_COM__TREE_CONNECT_ANDX; + break; + case SMB_COM_OPEN_ANDX: + smb_chain_map[com] = SMB_ANDX_COM__OPEN_ANDX; + break; + case SMB_COM_NT_CREATE_ANDX: + smb_chain_map[com] = SMB_ANDX_COM__NT_CREATE_ANDX; + break; + case SMB_COM_WRITE_ANDX: + smb_chain_map[com] = SMB_ANDX_COM__WRITE_ANDX; + break; + case SMB_COM_READ_ANDX: + smb_chain_map[com] = SMB_ANDX_COM__READ_ANDX; + break; + default: + smb_chain_map[com] = SMB_ANDX_COM__NONE; + break; + } + } + + // Sets up the valid command chaining combinations per policy + for (int policy = 0; policy < DCE2_POLICY__MAX; policy++) + { + for (int andx = SMB_ANDX_COM__NONE; andx < SMB_ANDX_COM__MAX; andx++) + { + /* com is the chained command or com2 */ + for (int com = 0; com < SMB_MAX_NUM_COMS; com++) + { + DCE2_SmbComFunc com_func = nullptr; + + switch (policy) + { + case DCE2_POLICY__WIN2000: + case DCE2_POLICY__WINXP: + case DCE2_POLICY__WINVISTA: + case DCE2_POLICY__WIN2003: + case DCE2_POLICY__WIN2008: + case DCE2_POLICY__WIN7: + switch (andx) + { + case SMB_ANDX_COM__SESSION_SETUP_ANDX: + switch (com) + { + case SMB_COM_TREE_CONNECT_ANDX: + case SMB_COM_OPEN: + case SMB_COM_OPEN_ANDX: + case SMB_COM_CREATE: + case SMB_COM_CREATE_NEW: + com_func = smb_com_funcs[com]; + break; + case SMB_COM_TRANSACTION: + if (policy == DCE2_POLICY__WIN2000) + com_func = smb_com_funcs[com]; + break; + default: + break; + } + break; + case SMB_ANDX_COM__LOGOFF_ANDX: + switch (com) + { + case SMB_COM_SESSION_SETUP_ANDX: + case SMB_COM_TREE_CONNECT_ANDX: // Only for responses + com_func = smb_com_funcs[com]; + break; + default: + break; + } + break; + case SMB_ANDX_COM__TREE_CONNECT_ANDX: + switch (com) + { + case SMB_COM_OPEN: + case SMB_COM_CREATE: + case SMB_COM_CREATE_NEW: + com_func = smb_com_funcs[com]; + break; + case SMB_COM_TRANSACTION: + if (policy == DCE2_POLICY__WIN2000) + com_func = smb_com_funcs[com]; + break; + default: + break; + } + break; + case SMB_ANDX_COM__OPEN_ANDX: + break; + case SMB_ANDX_COM__NT_CREATE_ANDX: + switch (com) + { + case SMB_COM_READ_ANDX: // Only for normal files + com_func = smb_com_funcs[com]; + break; + default: + break; + } + break; + case SMB_ANDX_COM__WRITE_ANDX: + switch (com) + { + case SMB_COM_CLOSE: + case SMB_COM_WRITE_ANDX: + case SMB_COM_READ: + case SMB_COM_READ_ANDX: + com_func = smb_com_funcs[com]; + break; + default: + break; + } + break; + case SMB_ANDX_COM__READ_ANDX: + break; + default: + break; + } + break; + case DCE2_POLICY__SAMBA: + case DCE2_POLICY__SAMBA_3_0_37: + case DCE2_POLICY__SAMBA_3_0_22: + case DCE2_POLICY__SAMBA_3_0_20: + switch (andx) + { + case SMB_ANDX_COM__SESSION_SETUP_ANDX: + switch (com) + { + case SMB_COM_LOGOFF_ANDX: + case SMB_COM_TREE_CONNECT: + case SMB_COM_TREE_CONNECT_ANDX: + case SMB_COM_TREE_DISCONNECT: + case SMB_COM_OPEN_ANDX: + case SMB_COM_NT_CREATE_ANDX: + case SMB_COM_CLOSE: + case SMB_COM_READ_ANDX: + com_func = smb_com_funcs[com]; + break; + case SMB_COM_WRITE: + if ((policy == DCE2_POLICY__SAMBA_3_0_22) + || (policy == DCE2_POLICY__SAMBA_3_0_20)) + com_func = smb_com_funcs[com]; + break; + default: + break; + } + break; + case SMB_ANDX_COM__LOGOFF_ANDX: + switch (com) + { + case SMB_COM_SESSION_SETUP_ANDX: + case SMB_COM_TREE_DISCONNECT: + com_func = smb_com_funcs[com]; + break; + default: + break; + } + break; + case SMB_ANDX_COM__TREE_CONNECT_ANDX: + switch (com) + { + case SMB_COM_SESSION_SETUP_ANDX: + case SMB_COM_LOGOFF_ANDX: + case SMB_COM_TREE_DISCONNECT: + case SMB_COM_OPEN_ANDX: + case SMB_COM_NT_CREATE_ANDX: + case SMB_COM_CLOSE: + case SMB_COM_WRITE: + case SMB_COM_READ_ANDX: + com_func = smb_com_funcs[com]; + break; + default: + break; + } + break; + case SMB_ANDX_COM__OPEN_ANDX: + switch (com) + { + case SMB_COM_SESSION_SETUP_ANDX: + case SMB_COM_LOGOFF_ANDX: + case SMB_COM_TREE_CONNECT: + case SMB_COM_TREE_CONNECT_ANDX: + case SMB_COM_TREE_DISCONNECT: + case SMB_COM_OPEN_ANDX: + case SMB_COM_NT_CREATE_ANDX: + case SMB_COM_CLOSE: + case SMB_COM_WRITE: + case SMB_COM_READ_ANDX: + com_func = smb_com_funcs[com]; + break; + default: + break; + } + break; + case SMB_ANDX_COM__NT_CREATE_ANDX: + switch (com) + { + case SMB_COM_SESSION_SETUP_ANDX: + case SMB_COM_TREE_CONNECT: + case SMB_COM_TREE_CONNECT_ANDX: + case SMB_COM_OPEN_ANDX: + case SMB_COM_NT_CREATE_ANDX: + case SMB_COM_WRITE: + case SMB_COM_READ_ANDX: + com_func = smb_com_funcs[com]; + break; + case SMB_COM_LOGOFF_ANDX: + case SMB_COM_TREE_DISCONNECT: + case SMB_COM_CLOSE: + if ((policy == DCE2_POLICY__SAMBA) + || (policy == DCE2_POLICY__SAMBA_3_0_37)) + com_func = smb_com_funcs[com]; + break; + default: + break; + } + break; + case SMB_ANDX_COM__WRITE_ANDX: + switch (com) + { + case SMB_COM_SESSION_SETUP_ANDX: + case SMB_COM_LOGOFF_ANDX: + case SMB_COM_TREE_CONNECT: + case SMB_COM_TREE_CONNECT_ANDX: + case SMB_COM_OPEN_ANDX: + case SMB_COM_NT_CREATE_ANDX: + case SMB_COM_CLOSE: + case SMB_COM_WRITE: + case SMB_COM_READ_ANDX: + case SMB_COM_WRITE_ANDX: + com_func = smb_com_funcs[com]; + break; + default: + break; + } + break; + case SMB_ANDX_COM__READ_ANDX: + switch (com) + { + case SMB_COM_SESSION_SETUP_ANDX: + case SMB_COM_WRITE: + com_func = smb_com_funcs[com]; + break; + case SMB_COM_LOGOFF_ANDX: + case SMB_COM_TREE_CONNECT: + case SMB_COM_TREE_CONNECT_ANDX: + case SMB_COM_TREE_DISCONNECT: + case SMB_COM_OPEN_ANDX: + case SMB_COM_NT_CREATE_ANDX: + case SMB_COM_CLOSE: + case SMB_COM_READ_ANDX: + if ((policy == DCE2_POLICY__SAMBA) + || (policy == DCE2_POLICY__SAMBA_3_0_37)) + com_func = smb_com_funcs[com]; + break; + default: + break; + } + break; + default: + break; + } + break; + default: + break; + } + + smb_chain_funcs[policy][andx][com] = com_func; + } + } + } +} + +DCE2_SmbSsnData* dce2_handle_smb_session(Packet* p, dce2SmbProtoConf* config) +{ + Profile profile(dce2_smb_pstat_session); + + DCE2_SmbSsnData* dce2_smb_sess = get_dce2_smb_session_data(p->flow); + + if (dce2_smb_sess == nullptr) + { + dce2_smb_sess = dce2_create_new_smb_session(p, config); + } + + DebugFormat(DEBUG_DCE_SMB, "Session pointer: %p\n", (void*)dce2_smb_sess); + + return dce2_smb_sess; +} + +// This is the main entry point for SMB processing +void DCE2_SmbProcess(DCE2_SmbSsnData* ssd) +{ + if (DCE2_GcIsLegacyMode((dce2SmbProtoConf*)ssd->sd.config)) + { + DCE2_Smb1Process(ssd); + return; + } + + Packet* p = ssd->sd.wire_pkt; + DCE2_SmbVersion smb_version = DCE2_Smb2Version(p); + if (smb_version == DCE2_SMB_VERISON_1) + { + if ((ssd->sd.flags & DCE2_SSN_FLAG__SMB2)) + { + DebugMessage(DEBUG_DCE_SMB, "SMB1 packet detected!\n"); + ssd->sd.flags &= ~DCE2_SSN_FLAG__SMB2; + DCE2_SmbCleanFileTracker(&(ssd->ftracker)); + ssd->ftracker.is_smb2 = false; + } + } + else if (smb_version == DCE2_SMB_VERISON_2) + { + if (!(ssd->sd.flags & DCE2_SSN_FLAG__SMB2)) + { + DebugMessage(DEBUG_DCE_SMB, "SMB2 packet detected!\n"); + DCE2_SmbCleanFileTracker(&(ssd->ftracker)); + DCE2_Smb2InitFileTracker(&(ssd->ftracker), 0, 0); + ssd->sd.flags |= DCE2_SSN_FLAG__SMB2; + } + } + + if (ssd->sd.flags & DCE2_SSN_FLAG__SMB2) + DCE2_Smb2Process(ssd); + else + DCE2_Smb1Process(ssd); +} + diff --git a/src/service_inspectors/dce_rpc/smb_message.h b/src/service_inspectors/dce_rpc/smb_message.h new file mode 100644 index 000000000..f68ebf9c0 --- /dev/null +++ b/src/service_inspectors/dce_rpc/smb_message.h @@ -0,0 +1,2179 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2016-2016 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +// smb_message.h author Russ Combs + +// extracted from dce_smb.h originally written by Todd Wease + +#ifndef SMB_MESSAGE_H +#define SMB_MESSAGE_H + +#include + +/******************************************************************** + * SMB_COM_OPEN + ********************************************************************/ +struct SmbOpenReq /* smb_wct = 2 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint16_t smb_mode; /* r/w/share */ + uint16_t smb_attr; /* attribute */ + uint16_t smb_bcc; /* min = 2 */ +}; + +struct SmbOpenResp /* smb_wct = 7 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint16_t smb_fid; /* file handle */ + uint16_t smb_attr; /* attribute */ + uint32_t smb_time; /* time1 low */ + uint32_t smb_file_size; /* file size low */ + uint16_t smb_access; /* access allowed */ + uint16_t smb_bcc; /* must be 0 */ +}; + +#define SMB_OPEN_ACCESS_MODE__READ 0x0000 +#define SMB_OPEN_ACCESS_MODE__WRITE 0x0001 +#define SMB_OPEN_ACCESS_MODE__READ_WRITE 0x0002 +#define SMB_OPEN_ACCESS_MODE__EXECUTE 0x0003 + +inline uint16_t SmbOpenRespFid(const SmbOpenResp* resp) +{ + return alignedNtohs(&resp->smb_fid); +} + +inline uint32_t SmbOpenRespFileSize(const SmbOpenResp* resp) +{ + return alignedNtohl(&resp->smb_file_size); +} + +inline uint16_t SmbOpenRespFileAttrs(const SmbOpenResp* resp) +{ + return alignedNtohs(&resp->smb_attr); +} + +inline bool SmbFileAttrsDirectory(const uint16_t file_attrs) +{ + if (file_attrs & SMB_FILE_ATTRIBUTE_DIRECTORY) + return true; + return false; +} + +inline uint16_t SmbOpenRespAccessMode(const SmbOpenResp* resp) +{ + return alignedNtohs(&resp->smb_access); +} + +inline bool SmbOpenForWriting(const uint16_t access_mode) +{ + return access_mode == SMB_OPEN_ACCESS_MODE__WRITE; +} + +/******************************************************************** + * SMB_COM_CREATE + ********************************************************************/ +struct SmbCreateReq /* smb_wct = 3 */ +{ + uint8_t smb_wct; + uint16_t smb_file_attrs; + uint32_t smb_creation_time; + uint16_t smb_bcc; +}; + +struct SmbCreateResp /* smb_wct = 1 */ +{ + uint8_t smb_wct; + uint16_t smb_fid; + uint16_t smb_bcc; +}; + +inline uint16_t SmbCreateReqFileAttrs(const SmbCreateReq* req) +{ + return alignedNtohs(&req->smb_file_attrs); +} + +inline bool SmbAttrDirectory(const uint16_t file_attrs) +{ + if (file_attrs & SMB_FILE_ATTRIBUTE_DIRECTORY) + return true; + return false; +} + +inline uint16_t SmbCreateRespFid(const SmbCreateResp* resp) +{ + return alignedNtohs(&resp->smb_fid); +} + +/******************************************************************** + * SMB_COM_CLOSE + ********************************************************************/ +struct SmbCloseReq /* smb_wct = 3 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint16_t smb_fid; /* file handle */ + uint16_t smb_tlow; /* time low */ + uint16_t smb_thigh; /* time high */ + uint16_t smb_bcc; /* must be 0 */ +}; + +struct SmbCloseResp /* smb_wct = 0 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint16_t smb_bcc; /* must be 0 */ +}; + +inline uint16_t SmbCloseReqFid(const SmbCloseReq* req) +{ + return alignedNtohs(&req->smb_fid); +} + +/******************************************************************** + * SMB_COM_READ + ********************************************************************/ +struct SmbReadReq /* smb_wct = 5 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint16_t smb_fid; /* file handle */ + uint16_t smb_cnt; /* count of bytes */ + uint32_t smb_off; /* offset */ + uint16_t smb_left; /* count left */ + uint16_t smb_bcc; /* must be 0 */ +}; + +struct SmbReadResp /* smb_wct = 5 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint16_t smb_cnt; /* count */ + uint16_t smb_res[4]; /* reserved (MBZ) */ + uint16_t smb_bcc; /* length of data + 3 */ +}; + +inline uint16_t SmbReadReqFid(const SmbReadReq* req) +{ + return alignedNtohs(&req->smb_fid); +} + +inline uint32_t SmbReadReqOffset(const SmbReadReq* req) +{ + return alignedNtohl(&req->smb_off); +} + +inline uint16_t SmbReadRespCount(const SmbReadResp* resp) +{ + return alignedNtohs(&resp->smb_cnt); +} + +/******************************************************************** + * SMB_COM_WRITE + ********************************************************************/ +struct SmbWriteReq /* smb_wct = 5 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint16_t smb_fid; /* file handle */ + uint16_t smb_cnt; /* count of bytes */ + uint32_t smb_offset; /* file offset in bytes */ + uint16_t smb_left; /* count left */ + uint16_t smb_bcc; /* length of data + 3 */ +}; + +struct SmbWriteResp /* smb_wct = 1 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint16_t smb_cnt; /* count */ + uint16_t smb_bcc; /* must be 0 */ +}; + +inline uint16_t SmbWriteReqFid(const SmbWriteReq* req) +{ + return alignedNtohs(&req->smb_fid); +} + +inline uint16_t SmbWriteReqCount(const SmbWriteReq* req) +{ + return alignedNtohs(&req->smb_cnt); +} + +inline uint32_t SmbWriteReqOffset(const SmbWriteReq* req) +{ + return alignedNtohl(&req->smb_offset); +} + +inline uint16_t SmbWriteRespCount(const SmbWriteResp* resp) +{ + return alignedNtohs(&resp->smb_cnt); +} + +/******************************************************************** + * SMB_COM_CREATE_NEW + ********************************************************************/ +struct SmbCreateNewReq /* smb_wct = 3 */ +{ + uint8_t smb_wct; + uint16_t smb_file_attrs; + uint32_t smb_creation_time; + uint16_t smb_bcc; +}; + +struct SmbCreateNewResp /* smb_wct = 1 */ +{ + uint8_t smb_wct; + uint16_t smb_fid; + uint16_t smb_bcc; +}; + +inline uint16_t SmbCreateNewReqFileAttrs(const SmbCreateNewReq* req) +{ + return alignedNtohs(&req->smb_file_attrs); +} + +inline uint16_t SmbCreateNewRespFid(const SmbCreateNewResp* resp) +{ + return alignedNtohs(&resp->smb_fid); +} + +/******************************************************************** + * SMB_COM_LOCK_AND_READ + ********************************************************************/ +struct SmbLockAndReadReq /* smb_wct = 5 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint16_t smb_fid; + uint16_t smb_cnt; + uint32_t smb_read_offset; + uint16_t smb_remaining; + uint16_t smb_bcc; /* must be 0 */ +}; + +struct SmbLockAndReadResp /* smb_wct = 5 */ +{ + uint8_t smb_wct; + uint16_t smb_cnt; + uint16_t reserved[4]; + uint16_t smb_bcc; +}; + +inline uint16_t SmbLockAndReadReqFid(const SmbLockAndReadReq* req) +{ + return alignedNtohs(&req->smb_fid); +} + +inline uint32_t SmbLockAndReadReqOffset(const SmbLockAndReadReq* req) +{ + return alignedNtohl(&req->smb_read_offset); +} + +inline uint16_t SmbLockAndReadRespCount(const SmbLockAndReadResp* resp) +{ + return alignedNtohs(&resp->smb_cnt); +} + +/******************************************************************** + * SMB_COM_WRITE_AND_UNLOCK + ********************************************************************/ +struct SmbWriteAndUnlockReq +{ + uint8_t smb_wct; + uint16_t smb_fid; + uint16_t smb_cnt; + uint32_t smb_write_offset; + uint16_t smb_estimate_of_remaining; + uint16_t smb_bcc; +}; + +struct SmbWriteAndUnlockResp /* smb_wct = 1 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint16_t smb_cnt; /* count */ + uint16_t smb_bcc; /* must be 0 */ +}; + +inline uint16_t SmbWriteAndUnlockReqFid(const SmbWriteAndUnlockReq* req) +{ + return alignedNtohs(&req->smb_fid); +} + +inline uint16_t SmbWriteAndUnlockReqCount(const SmbWriteAndUnlockReq* req) +{ + return alignedNtohs(&req->smb_cnt); +} + +inline uint32_t SmbWriteAndUnlockReqOffset(const SmbWriteAndUnlockReq* req) +{ + return alignedNtohl(&req->smb_write_offset); +} + +/******************************************************************** + * SMB_COM_OPEN_ANDX + ********************************************************************/ +struct SmbOpenAndXReq /* smb_wct = 15 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ + uint8_t smb_reh2; /* reserved (must be zero) */ + uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ + uint16_t smb_flags; /* additional information: + bit 0 - if set, return additional information + bit 1 - if set, set single user total file lock (if only access) + bit 2 - if set, the server should notify the consumer on any + action which can modify the file (delete, setattrib, + rename, etc.). if not set, the server need only notify + the consumer on another open request. This bit only has + meaning if bit 1 is set. */ + uint16_t smb_mode; /* file open mode */ + uint16_t smb_sattr; /* search attributes */ + uint16_t smb_attr; /* file attributes (for create) */ + uint32_t smb_time; /* create time */ + uint16_t smb_ofun; /* open function */ + uint32_t smb_size; /* bytes to reserve on "create" or "truncate" */ + uint32_t smb_timeout; /* max milliseconds to wait for resource to open */ + uint32_t smb_rsvd; /* reserved (must be zero) */ + uint16_t smb_bcc; /* minimum value = 1 */ +}; + +struct SmbOpenAndXResp /* smb_wct = 15 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ + uint8_t smb_res2; /* reserved (pad to word) */ + uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ + uint16_t smb_fid; /* file handle */ + uint16_t smb_attribute; /* attributes of file or device */ + uint32_t smb_time; /* last modification time */ + uint32_t smb_size; /* current file size */ + uint16_t smb_access; /* access permissions actually allowed */ + uint16_t smb_type; /* file type */ + uint16_t smb_state; /* state of IPC device (e.g. pipe) */ + uint16_t smb_action; /* action taken */ + uint32_t smb_fileid; /* server unique file id */ + uint16_t smb_rsvd; /* reserved */ + uint16_t smb_bcc; /* value = 0 */ +}; + +inline uint32_t SmbOpenAndXReqAllocSize(const SmbOpenAndXReq* req) +{ + return alignedNtohl(&req->smb_size); +} + +inline uint16_t SmbOpenAndXReqFileAttrs(const SmbOpenAndXReq* req) +{ + return alignedNtohs(&req->smb_attr); +} + +inline uint16_t SmbOpenAndXRespFid(const SmbOpenAndXResp* resp) +{ + return alignedNtohs(&resp->smb_fid); +} + +inline uint16_t SmbOpenAndXRespFileAttrs(const SmbOpenAndXResp* resp) +{ + return alignedNtohs(&resp->smb_attribute); +} + +inline uint32_t SmbOpenAndXRespFileSize(const SmbOpenAndXResp* resp) +{ + return alignedNtohl(&resp->smb_size); +} + +inline uint16_t SmbOpenAndXRespResourceType(const SmbOpenAndXResp* resp) +{ + return alignedNtohs(&resp->smb_type); +} + +#define SMB_OPEN_RESULT__EXISTED 0x0001 +#define SMB_OPEN_RESULT__CREATED 0x0002 +#define SMB_OPEN_RESULT__TRUNCATED 0x0003 + +inline uint16_t SmbOpenAndXRespOpenResults(const SmbOpenAndXResp* resp) +{ + return alignedNtohs(&resp->smb_action); +} + +inline bool SmbOpenResultRead(const uint16_t open_results) +{ + return ((open_results & 0x00FF) == SMB_OPEN_RESULT__EXISTED); +} + +inline bool SmbResourceTypeDisk(const uint16_t resource_type) +{ + return resource_type == SMB_FILE_TYPE_DISK; +} + +/******************************************************************** + * SMB_COM_READ_ANDX + ********************************************************************/ +struct SmbReadAndXReq /* smb_wct = 10 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ + uint8_t smb_reh2; /* reserved (must be zero) */ + uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ + uint16_t smb_fid; /* file handle */ + uint32_t smb_offset; /* offset in file to begin read */ + uint16_t smb_maxcnt; /* max number of bytes to return */ + uint16_t smb_mincnt; /* min number of bytes to return */ + uint32_t smb_timeout; /* number of milliseconds to wait for completion */ + uint16_t smb_countleft; /* bytes remaining to satisfy user’s request */ + uint16_t smb_bcc; /* value = 0 */ +}; + +struct SmbReadAndXExtReq /* smb_wct = 12 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ + uint8_t smb_reh2; /* reserved (must be zero) */ + uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ + uint16_t smb_fid; /* file handle */ + uint32_t smb_offset; /* low offset in file to begin read */ + uint16_t smb_maxcnt; /* max number of bytes to return */ + uint16_t smb_mincnt; /* min number of bytes to return */ + uint32_t smb_timeout; /* number of milliseconds to wait for completion */ + uint16_t smb_countleft; /* bytes remaining to satisfy user’s request */ + uint32_t smb_off_high; /* high offset in file to begin read */ + uint16_t smb_bcc; /* value = 0 */ +}; + +struct SmbReadAndXResp /* smb_wct = 12 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ + uint8_t smb_res2; /* reserved (pad to word) */ + uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ + uint16_t smb_remaining; /* bytes remaining to be read (pipes/devices only) */ + uint32_t smb_rsvd; /* reserved */ + uint16_t smb_dsize; /* number of data bytes (minimum value = 0) */ + uint16_t smb_doff; /* offset (from start of SMB hdr) to data bytes */ + uint16_t smb_dsize_high; /* high bytes of data size */ + uint32_t smb_rsvd1; /* reserved */ + uint32_t smb_rsvd2; /* reserved */ + uint16_t smb_bcc; /* total bytes (including pad bytes) following */ +}; + +inline uint16_t SmbReadAndXReqFid(const SmbReadAndXReq* req) +{ + return alignedNtohs(&req->smb_fid); +} + +inline uint64_t SmbReadAndXReqOffset(const SmbReadAndXExtReq* req) +{ + if (req->smb_wct == 10) + return (uint64_t)alignedNtohl(&req->smb_offset); + return (uint64_t)alignedNtohl(&req->smb_off_high) << 32 | (uint64_t)alignedNtohl( + &req->smb_offset); +} + +inline uint16_t SmbReadAndXRespDataOff(const SmbReadAndXResp* req) +{ + return alignedNtohs(&req->smb_doff); +} + +inline uint32_t SmbReadAndXRespDataCnt(const SmbReadAndXResp* resp) +{ + return (uint32_t)alignedNtohs(&resp->smb_dsize_high) << 16 | (uint32_t)alignedNtohs( + &resp->smb_dsize); +} + +/******************************************************************** + * SMB_COM_WRITE_ANDX + ********************************************************************/ +struct SmbWriteAndXReq /* smb_wct = 12 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ + uint8_t smb_reh2; /* reserved (must be zero) */ + uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ + uint16_t smb_fid; /* file handle */ + uint32_t smb_offset; /* offset in file to begin write */ + uint32_t smb_timeout; /* number of milliseconds to wait for completion */ + uint16_t smb_wmode; /* write mode: + bit0 - complete write before return (write through) + bit1 - return smb_remaining (pipes/devices only) + bit2 - use WriteRawNamedPipe (pipes only) + bit3 - this is the start of a message (pipes only) */ + uint16_t smb_countleft; /* bytes remaining to write to satisfy user’s request */ + uint16_t smb_dsize_high; /* high bytes of data size */ + uint16_t smb_dsize; /* number of data bytes in buffer (min value = 0) */ + uint16_t smb_doff; /* offset (from start of SMB hdr) to data bytes */ + uint16_t smb_bcc; /* total bytes (including pad bytes) following */ +}; + +struct SmbWriteAndXExtReq /* smb_wct = 14 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ + uint8_t smb_reh2; /* reserved (must be zero) */ + uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ + uint16_t smb_fid; /* file handle */ + uint32_t smb_offset; /* low offset in file to begin write */ + uint32_t smb_timeout; /* number of milliseconds to wait for completion */ + uint16_t smb_wmode; /* write mode: + bit0 - complete write before return (write through) + bit1 - return smb_remaining (pipes/devices only) + bit2 - use WriteRawNamedPipe (pipes only) + bit3 - this is the start of a message (pipes only) */ + uint16_t smb_countleft; /* bytes remaining to write to satisfy user’s request */ + uint16_t smb_dsize_high; /* high bytes of data size */ + uint16_t smb_dsize; /* number of data bytes in buffer (min value = 0) */ + uint16_t smb_doff; /* offset (from start of SMB hdr) to data bytes */ + uint32_t smb_off_high; /* high offset in file to begin write */ + uint16_t smb_bcc; /* total bytes (including pad bytes) following */ +}; + +struct SmbWriteAndXResp /* smb_wct = 6 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ + uint8_t smb_res2; /* reserved (pad to word) */ + uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ + uint16_t smb_count; /* number of bytes written */ + uint16_t smb_remaining; /* bytes remaining to be read (pipes/devices only) */ + uint16_t smb_count_high; /* high order bytes of data count */ + uint16_t smb_rsvd; /* reserved */ + uint16_t smb_bcc; /* value = 0 */ +}; + +inline uint16_t SmbWriteAndXReqFid(const SmbWriteAndXReq* req) +{ + return alignedNtohs(&req->smb_fid); +} + +inline uint16_t SmbWriteAndXReqDataOff(const SmbWriteAndXReq* req) +{ + return alignedNtohs(&req->smb_doff); +} + +inline uint16_t SmbWriteAndXReqRemaining(const SmbWriteAndXReq* req) +{ + return alignedNtohs(&req->smb_countleft); +} + +inline uint64_t SmbWriteAndXReqOffset(const SmbWriteAndXExtReq* req) +{ + if (req->smb_wct == 12) + return (uint64_t)alignedNtohl(&req->smb_offset); + return (uint64_t)alignedNtohl(&req->smb_off_high) << 32 | (uint64_t)alignedNtohl( + &req->smb_offset); +} + +inline uint32_t SmbWriteAndXReqDataCnt(const SmbWriteAndXReq* req) +{ + return (uint32_t)alignedNtohs(&req->smb_dsize_high) << 16 | (uint32_t)alignedNtohs( + &req->smb_dsize); +} + +inline uint16_t SmbWriteAndXReqWriteMode(const SmbWriteAndXReq* req) +{ + return alignedNtohs(&req->smb_wmode); +} + +inline bool SmbWriteAndXReqStartRaw(const SmbWriteAndXReq* req) +{ + return ((alignedNtohs(&req->smb_wmode) & 0x000c) == 0x000c) ? true : false; +} + +inline bool SmbWriteAndXReqRaw(const SmbWriteAndXReq* req) +{ + return ((alignedNtohs(&req->smb_wmode) & 0x000c) == 0x0004) ? true : false; +} + +inline uint16_t SmbWriteAndXRespCnt(const SmbWriteAndXResp* resp) +{ + return alignedNtohs(&resp->smb_count); +} + +/******************************************************************** + * SMB_COM_SESSION_SETUP_ANDX + ********************************************************************/ +struct SmbLm10_SessionSetupAndXReq /* smb_wct = 10 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ + uint8_t smb_reh2; /* reserved (must be zero) */ + uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ + uint16_t smb_bufsize; /* the consumers max buffer size */ + uint16_t smb_mpxmax; /* actual maximum multiplexed pending requests */ + uint16_t smb_vc_num; /* 0 = first (only), non zero - additional VC number */ + uint32_t smb_sesskey; /* Session Key (valid only if smb_vc_num != 0) */ + uint16_t smb_apasslen; /* size of account password (smb_apasswd) */ + uint32_t smb_rsvd; /* reserved */ + uint16_t smb_bcc; /* minimum value = 0 */ +}; + +inline uint16_t SmbSessionSetupAndXReqMaxMultiplex(const SmbLm10_SessionSetupAndXReq* req) +{ + return alignedNtohs(&req->smb_mpxmax); +} + +/* Extended request as defined in NT LM 1.0 document */ +struct SmbNt10_SessionSetupAndXReq /* smb_wct = 13 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ + uint8_t smb_reh2; /* reserved (must be zero) */ + uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ + uint16_t smb_bufsize; /* the consumers max buffer size */ + uint16_t smb_mpxmax; /* actual maximum multiplexed pending requests */ + uint16_t smb_vc_num; /* 0 = first (only), non zero - additional VC number */ + uint32_t smb_sesskey; /* Session Key (valid only if smb_vc_num != 0) */ + uint16_t smb_oem_passlen; /* case insensitive password length */ + uint16_t smb_unicode_passlen; /* case sensitive password length */ + uint32_t smb_rsvd; /* reserved */ + uint32_t smb_cap; /* capabilities */ + uint16_t smb_bcc; /* minimum value = 0 */ +}; + +inline uint16_t SmbNt10SessionSetupAndXReqOemPassLen(const SmbNt10_SessionSetupAndXReq* req) +{ + return alignedNtohs(&req->smb_oem_passlen); +} + +inline uint16_t SmbNt10SessionSetupAndXReqUnicodePassLen(const SmbNt10_SessionSetupAndXReq* req) +{ + return alignedNtohs(&req->smb_unicode_passlen); +} + +/* Extended request for security blob */ +struct SmbNt10_SessionSetupAndXExtReq /* smb_wct = 12 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ + uint8_t smb_reh2; /* reserved (must be zero) */ + uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ + uint16_t smb_bufsize; /* the consumers max buffer size */ + uint16_t smb_mpxmax; /* actual maximum multiplexed pending requests */ + uint16_t smb_vc_num; /* 0 = first (only), non zero - additional VC number */ + uint32_t smb_sesskey; /* Session Key (valid only if smb_vc_num != 0) */ + uint16_t smb_blob_len; /* length of security blob */ + uint32_t smb_rsvd; /* reserved */ + uint32_t smb_cap; /* capabilities */ + uint16_t smb_bcc; /* minimum value = 0 */ +}; + +inline uint16_t SmbSessionSetupAndXReqBlobLen(const SmbNt10_SessionSetupAndXExtReq* req) +{ + return alignedNtohs(&req->smb_blob_len); +} + +/* Extended response for security blob */ +struct SmbNt10_SessionSetupAndXExtResp /* smb_wct = 4 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ + uint8_t smb_res2; /* reserved (pad to word) */ + uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ + uint16_t smb_action; /* request mode: + bit0 = Logged in successfully - BUT as GUEST */ + uint16_t smb_blob_len; /* length of security blob */ + uint16_t smb_bcc; /* min value = 0 */ +}; + +inline uint16_t SmbSessionSetupAndXRespBlobLen(const SmbNt10_SessionSetupAndXExtResp* resp) +{ + return alignedNtohs(&resp->smb_blob_len); +} + +/******************************************************************** + * SMB_COM_NEGOTIATE + ********************************************************************/ +/* This is the Lanman response */ +struct SmbLm10_NegotiateProtocolResp /* smb_wct = 13 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint16_t smb_index; /* index identifying dialect selected */ + uint16_t smb_secmode; /* security mode: + bit 0, 1 = User level, 0 = Share level + bit 1, 1 = encrypt passwords, 0 = do not encrypt passwords */ + uint16_t smb_maxxmt; /* max transmit buffer size server supports, 1K min */ + uint16_t smb_maxmux; /* max pending multiplexed requests server supports */ + uint16_t smb_maxvcs; /* max VCs per server/consumer session supported */ + uint16_t smb_blkmode; /* block read/write mode support: + bit 0, Read Block Raw supported (65535 bytes max) + bit 1, Write Block Raw supported (65535 bytes max) */ + uint32_t smb_sesskey; /* Session Key (unique token identifying session) */ + uint16_t smb_srv_time; /* server's current time (hhhhh mmmmmm xxxxx) */ + uint16_t smb_srv_tzone; /* server's current data (yyyyyyy mmmm ddddd) */ + uint32_t smb_rsvd; /* reserved */ + uint16_t smb_bcc; /* value = (size of smb_cryptkey) */ +}; + +/* This is the NT response */ +struct SmbNt_NegotiateProtocolResp /* smb_wct = 17 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint16_t smb_index; /* index identifying dialect selected */ + uint8_t smb_secmode; /* security mode: + bit 0, 1 = User level, 0 = Share level + bit 1, 1 = encrypt passwords, 0 = do not encrypt passwords */ + uint16_t smb_maxmux; /* max pending multiplexed requests server supports */ + uint16_t smb_maxvcs; /* max VCs per server/consumer session supported */ + uint32_t smb_maxbuf; /* maximum buffer size supported */ + uint32_t smb_maxraw; /* maximum raw buffer size supported */ + uint32_t smb_sesskey; /* Session Key (unique token identifying session) */ + uint32_t smb_cap; /* capabilities */ + struct + { + uint32_t low_time; + int32_t high_time; + } smb_srv_time; /* server time */ + uint16_t smb_srv_tzone; /* server's current data (yyyyyyy mmmm ddddd) */ + uint8_t smb_challenge_len; /* Challenge length */ + uint16_t smb_bcc; /* value = (size of smb_cryptkey) */ +}; + +inline uint16_t SmbLm_NegotiateRespMaxMultiplex(const SmbLm10_NegotiateProtocolResp* resp) +{ + return alignedNtohs(&resp->smb_maxmux); +} + +inline uint16_t SmbNt_NegotiateRespMaxMultiplex(const SmbNt_NegotiateProtocolResp* resp) +{ + return alignedNtohs(&resp->smb_maxmux); +} + +/* This is the Core Protocol response */ +struct SmbCore_NegotiateProtocolResp /* smb_wct = 1 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint16_t smb_index; /* index */ + uint16_t smb_bcc; /* must be 0 */ +}; + +inline uint16_t SmbNegotiateRespDialectIndex(const SmbCore_NegotiateProtocolResp* resp) +{ + return alignedNtohs(&resp->smb_index); +} + +/********************************************************************* + * SMB_COM_TREE_CONNECT_ANDX + *********************************************************************/ +struct SmbTreeConnectAndXReq /* smb_wct = 4 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ + uint8_t smb_reh2; /* reserved (must be zero) */ + uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ + uint16_t smb_flags; /* additional information: + bit 0 - if set, disconnect TID in current smb_tid */ + uint16_t smb_spasslen; /* length of smb_spasswd */ + uint16_t smb_bcc; /* minimum value = 3 */ +}; + +inline uint16_t SmbTreeConnectAndXReqPassLen(const SmbTreeConnectAndXReq* req) +{ + return alignedNtohs(&req->smb_spasslen); +} + +/******************************************************************** + * SMB_COM_NT_TRANSACT + ********************************************************************/ +#define SMB_CREATE_OPTIONS__FILE_SEQUENTIAL_ONLY 0x00000004 + +/******************************************************************** + * SMB_COM_NT_CREATE_ANDX + ********************************************************************/ +#define SMB_CREATE_DISPOSITSION__FILE_SUPERCEDE 0x00000000 +#define SMB_CREATE_DISPOSITSION__FILE_OPEN 0x00000001 +#define SMB_CREATE_DISPOSITSION__FILE_CREATE 0x00000002 +#define SMB_CREATE_DISPOSITSION__FILE_OPEN_IF 0x00000003 +#define SMB_CREATE_DISPOSITSION__FILE_OVERWRITE 0x00000004 +#define SMB_CREATE_DISPOSITSION__FILE_OVERWRITE_IF 0x00000005 + +struct SmbNtCreateAndXReq /* smb_wct = 24 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint8_t smb_com2; /* secondary (X) command, 0xFF = none */ + uint8_t smb_res2; /* reserved (pad to word) */ + uint16_t smb_off2; /* offset (from SMB hdr start) to next cmd (@smb_wct) */ + uint8_t smb_res; /* reserved */ + uint16_t smb_name_len; /* length of name of file */ + uint32_t smb_flags; /* flags */ + uint32_t smb_root_fid; /* fid for previously opened directory */ + uint32_t smb_access; /* specifies the type of file access */ + uint64_t smb_alloc_size; /* initial allocation size of the file */ + uint32_t smb_file_attrs; /* specifies the file attributes for the file */ + uint32_t smb_share_access; /* the type of share access */ + uint32_t smb_create_disp; /* actions to take if file does or does not exist */ + uint32_t smb_create_opts; /* options used when creating or opening file */ + uint32_t smb_impersonation_level; /* security impersonation level */ + uint8_t smb_security_flags; /* security flags */ + uint16_t smb_bcc; /* byte count */ +}; + +struct SmbNtCreateAndXResp /* smb_wct = 34 */ +{ + uint8_t smb_wct; + uint8_t smb_com2; + uint8_t smb_res2; + uint16_t smb_off2; + uint8_t smb_oplock_level; + uint16_t smb_fid; + uint32_t smb_create_disposition; + uint64_t smb_creation_time; + uint64_t smb_last_access_time; + uint64_t smb_last_write_time; + uint64_t smb_change_time; + uint32_t smb_file_attrs; + uint64_t smb_alloc_size; + uint64_t smb_eof; + uint16_t smb_resource_type; + uint16_t smb_nm_pipe_state; + uint8_t smb_directory; + uint16_t smb_bcc; +}; + +// Word count is always set to 42 though there are actually 50 words +struct SmbNtCreateAndXExtResp /* smb_wct = 42 */ +{ + uint8_t smb_wct; + uint8_t smb_com2; + uint8_t smb_res2; + uint16_t smb_off2; + uint8_t smb_oplock_level; + uint16_t smb_fid; + uint32_t smb_create_disposition; + uint64_t smb_creation_time; + uint64_t smb_last_access_time; + uint64_t smb_last_write_time; + uint64_t smb_change_time; + uint32_t smb_file_attrs; + uint64_t smb_alloc_size; + uint64_t smb_eof; + uint16_t smb_resource_type; + uint16_t smb_nm_pipe_state; + uint8_t smb_directory; + uint8_t smb_volume_guid[16]; + uint64_t smb_fileid; + uint32_t smb_max_access_rights; + uint32_t smb_guest_access_rights; + uint16_t smb_bcc; +}; + +inline uint16_t SmbNtCreateAndXReqFileNameLen(const SmbNtCreateAndXReq* req) +{ + return alignedNtohs(&req->smb_name_len); +} + +inline uint32_t SmbNtCreateAndXReqCreateDisposition(const SmbNtCreateAndXReq* req) +{ + return alignedNtohl(&req->smb_create_disp); +} + +inline bool SmbCreateDispositionRead(const uint32_t create_disposition) +{ + return (create_disposition == SMB_CREATE_DISPOSITSION__FILE_OPEN) + || (create_disposition > SMB_CREATE_DISPOSITSION__FILE_OVERWRITE_IF); +} + +inline uint64_t SmbNtCreateAndXReqAllocSize(const SmbNtCreateAndXReq* req) +{ + return alignedNtohq(&req->smb_alloc_size); +} + +inline bool SmbNtCreateAndXReqSequentialOnly(const SmbNtCreateAndXReq* req) +{ + return (alignedNtohl(&req->smb_create_opts) & SMB_CREATE_OPTIONS__FILE_SEQUENTIAL_ONLY); +} + +inline uint32_t SmbNtCreateAndXReqFileAttrs(const SmbNtCreateAndXReq* req) +{ + return alignedNtohl(&req->smb_file_attrs); +} + +inline uint16_t SmbNtCreateAndXRespFid(const SmbNtCreateAndXResp* resp) +{ + return alignedNtohs(&resp->smb_fid); +} + +inline uint32_t SmbNtCreateAndXRespCreateDisposition(const SmbNtCreateAndXResp* resp) +{ + return alignedNtohl(&resp->smb_create_disposition); +} + +inline bool SmbNtCreateAndXRespDirectory(const SmbNtCreateAndXResp* resp) +{ + return (resp->smb_directory ? true : false); +} + +inline uint16_t SmbNtCreateAndXRespResourceType(const SmbNtCreateAndXResp* resp) +{ + return alignedNtohs(&resp->smb_resource_type); +} + +inline uint64_t SmbNtCreateAndXRespEndOfFile(const SmbNtCreateAndXResp* resp) +{ + return alignedNtohq(&resp->smb_eof); +} + +/******************************************************************** + * SMB_COM_TRANSACTION + ********************************************************************/ +struct SmbTransactionReq /* smb_wct = 14 + value of smb_suwcnt */ +{ + /* Note all subcommands use a setup count of 2 */ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint16_t smb_tpscnt; /* total number of parameter bytes being sent */ + uint16_t smb_tdscnt; /* total number of data bytes being sent */ + uint16_t smb_mprcnt; /* max number of parameter bytes to return */ + uint16_t smb_mdrcnt; /* max number of data bytes to return */ + uint8_t smb_msrcnt; /* max number of setup words to return */ + uint8_t smb_rsvd; /* reserved (pad above to word) */ + uint16_t smb_flags; /* additional information: + bit 0 - if set, also disconnect TID in smb_tid + bit 1 - if set, transaction is one way (no final response) */ + uint32_t smb_timeout; /* number of milliseconds to wait for completion */ + uint16_t smb_rsvd1; /* reserved */ + uint16_t smb_pscnt; /* number of parameter bytes being sent this buffer */ + uint16_t smb_psoff; /* offset (from start of SMB hdr) to parameter bytes */ + uint16_t smb_dscnt; /* number of data bytes being sent this buffer */ + uint16_t smb_dsoff; /* offset (from start of SMB hdr) to data bytes */ + uint8_t smb_suwcnt; /* set up word count */ + uint8_t smb_rsvd2; /* reserved (pad above to word) */ + uint16_t smb_setup1; /* function (see below) + TRANS_SET_NM_PIPE_STATE = 0x0001 + TRANS_RAW_READ_NMPIPE = 0x0011 + TRANS_QUERY_NMPIPE_STATE = 0x0021 + TRANS_QUERY_NMPIPE_INFO = 0x0022 + TRANS_PEEK_NMPIPE = 0x0023 + TRANS_TRANSACT_NMPIPE = 0x0026 + TRANS_RAW_WRITE_NMPIPE = 0x0031 + TRANS_READ_NMPIPE = 0x0036 + TRANS_WRITE_NMPIPE = 0x0037 + TRANS_WAIT_NMPIPE = 0x0053 + TRANS_CALL_NMPIPE = 0x0054 */ + uint16_t smb_setup2; /* FID (handle) of pipe (if needed), or priority */ + uint16_t smb_bcc; /* total bytes (including pad bytes) following */ +}; + +struct SmbTransactionInterimResp /* smb_wct = 0 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint16_t smb_bcc; /* must be 0 */ +}; + +struct SmbTransactionResp /* smb_wct = 10 + value of smb_suwcnt */ +{ + /* Note all subcommands use a setup count of 0 */ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint16_t smb_tprcnt; /* total number of parameter bytes being returned */ + uint16_t smb_tdrcnt; /* total number of data bytes being returned */ + uint16_t smb_rsvd; /* reserved */ + uint16_t smb_prcnt; /* number of parameter bytes being returned this buf */ + uint16_t smb_proff; /* offset (from start of SMB hdr) to parameter bytes */ + uint16_t smb_prdisp; /* byte displacement for these parameter bytes */ + uint16_t smb_drcnt; /* number of data bytes being returned this buffer */ + uint16_t smb_droff; /* offset (from start of SMB hdr) to data bytes */ + uint16_t smb_drdisp; /* byte displacement for these data bytes */ + uint8_t smb_suwcnt; /* set up return word count */ + uint8_t smb_rsvd1; /* reserved (pad above to word) */ + uint16_t smb_bcc; /* total bytes (including pad bytes) following */ +}; + +inline uint16_t SmbTransactionReqSubCom(const SmbTransactionReq* req) +{ + return alignedNtohs(&req->smb_setup1); +} + +inline uint16_t SmbTransactionReqFid(const SmbTransactionReq* req) +{ + return alignedNtohs(&req->smb_setup2); +} + +inline bool SmbTransactionReqDisconnectTid(const SmbTransactionReq* req) +{ + return alignedNtohs(&req->smb_flags) & 0x0001 ? true : false; +} + +inline bool SmbTransactionReqOneWay(const SmbTransactionReq* req) +{ + return alignedNtohs(&req->smb_flags) & 0x0002 ? true : false; +} + +inline uint8_t SmbTransactionReqSetupCnt(const SmbTransactionReq* req) +{ + return req->smb_suwcnt; +} + +inline uint16_t SmbTransactionReqTotalDataCnt(const SmbTransactionReq* req) +{ + return alignedNtohs(&req->smb_tdscnt); +} + +inline uint16_t SmbTransactionReqDataCnt(const SmbTransactionReq* req) +{ + return alignedNtohs(&req->smb_dscnt); +} + +inline uint16_t SmbTransactionReqDataOff(const SmbTransactionReq* req) +{ + return alignedNtohs(&req->smb_dsoff); +} + +inline uint16_t SmbTransactionReqTotalParamCnt(const SmbTransactionReq* req) +{ + return alignedNtohs(&req->smb_tpscnt); +} + +inline uint16_t SmbTransactionReqParamCnt(const SmbTransactionReq* req) +{ + return alignedNtohs(&req->smb_pscnt); +} + +inline uint16_t SmbTransactionReqParamOff(const SmbTransactionReq* req) +{ + return alignedNtohs(&req->smb_psoff); +} + +inline uint16_t SmbTransactionRespTotalDataCnt(const SmbTransactionResp* resp) +{ + return alignedNtohs(&resp->smb_tdrcnt); +} + +inline uint16_t SmbTransactionRespDataCnt(const SmbTransactionResp* resp) +{ + return alignedNtohs(&resp->smb_drcnt); +} + +inline uint16_t SmbTransactionRespDataOff(const SmbTransactionResp* resp) +{ + return alignedNtohs(&resp->smb_droff); +} + +inline uint16_t SmbTransactionRespDataDisp(const SmbTransactionResp* resp) +{ + return alignedNtohs(&resp->smb_drdisp); +} + +inline uint16_t SmbTransactionRespTotalParamCnt(const SmbTransactionResp* resp) +{ + return alignedNtohs(&resp->smb_tprcnt); +} + +inline uint16_t SmbTransactionRespParamCnt(const SmbTransactionResp* resp) +{ + return alignedNtohs(&resp->smb_prcnt); +} + +inline uint16_t SmbTransactionRespParamOff(const SmbTransactionResp* resp) +{ + return alignedNtohs(&resp->smb_proff); +} + +inline uint16_t SmbTransactionRespParamDisp(const SmbTransactionResp* resp) +{ + return alignedNtohs(&resp->smb_prdisp); +} + +// Flags for TRANS_SET_NMPIPE_STATE parameters +#define PIPE_STATE_NON_BLOCKING 0x8000 +#define PIPE_STATE_MESSAGE_MODE 0x0100 + +/******************************************************************** + * SMB_COM_TRANSACTION2 + ********************************************************************/ +struct SmbTransaction2Req +{ + uint8_t smb_wct; + uint16_t smb_total_param_count; + uint16_t smb_total_data_count; + uint16_t smb_max_param_count; + uint16_t smb_max_data_count; + uint8_t smb_max_setup_count; + uint8_t smb_res; + uint16_t smb_flags; + uint32_t smb_timeout; + uint16_t smb_res2; + uint16_t smb_param_count; + uint16_t smb_param_offset; + uint16_t smb_data_count; + uint16_t smb_data_offset; + uint8_t smb_setup_count; /* Should be 1 for all subcommands */ + uint8_t smb_res3; + uint16_t smb_setup; /* This is the subcommand */ + uint16_t smb_bcc; +}; + +struct SmbTransaction2InterimResp +{ + uint8_t smb_wct; + uint16_t smb_bcc; +}; + +struct SmbTransaction2Resp +{ + uint8_t smb_wct; + uint16_t smb_total_param_count; + uint16_t smb_total_data_count; + uint16_t smb_res; + uint16_t smb_param_count; + uint16_t smb_param_offset; + uint16_t smb_param_disp; + uint16_t smb_data_count; + uint16_t smb_data_offset; + uint16_t smb_data_disp; + uint16_t smb_setup_count; /* 0 or 1 word */ + uint8_t smb_res2; +}; + +inline uint16_t SmbTransaction2ReqSubCom(const SmbTransaction2Req* req) +{ + return alignedNtohs(&req->smb_setup); +} + +inline uint16_t SmbTransaction2ReqTotalParamCnt(const SmbTransaction2Req* req) +{ + return alignedNtohs(&req->smb_total_param_count); +} + +inline uint16_t SmbTransaction2ReqParamCnt(const SmbTransaction2Req* req) +{ + return alignedNtohs(&req->smb_param_count); +} + +inline uint16_t SmbTransaction2ReqParamOff(const SmbTransaction2Req* req) +{ + return alignedNtohs(&req->smb_param_offset); +} + +inline uint16_t SmbTransaction2ReqTotalDataCnt(const SmbTransaction2Req* req) +{ + return alignedNtohs(&req->smb_total_data_count); +} + +inline uint16_t SmbTransaction2ReqDataCnt(const SmbTransaction2Req* req) +{ + return alignedNtohs(&req->smb_data_count); +} + +inline uint16_t SmbTransaction2ReqDataOff(const SmbTransaction2Req* req) +{ + return alignedNtohs(&req->smb_data_offset); +} + +inline uint8_t SmbTransaction2ReqSetupCnt(const SmbTransaction2Req* req) +{ + return req->smb_setup_count; +} + +inline uint16_t SmbTransaction2RespTotalParamCnt(const SmbTransaction2Resp* resp) +{ + return alignedNtohs(&resp->smb_total_param_count); +} + +inline uint16_t SmbTransaction2RespParamCnt(const SmbTransaction2Resp* resp) +{ + return alignedNtohs(&resp->smb_param_count); +} + +inline uint16_t SmbTransaction2RespParamOff(const SmbTransaction2Resp* resp) +{ + return alignedNtohs(&resp->smb_param_offset); +} + +inline uint16_t SmbTransaction2RespParamDisp(const SmbTransaction2Resp* resp) +{ + return alignedNtohs(&resp->smb_param_disp); +} + +inline uint16_t SmbTransaction2RespTotalDataCnt(const SmbTransaction2Resp* resp) +{ + return alignedNtohs(&resp->smb_total_data_count); +} + +inline uint16_t SmbTransaction2RespDataCnt(const SmbTransaction2Resp* resp) +{ + return alignedNtohs(&resp->smb_data_count); +} + +inline uint16_t SmbTransaction2RespDataOff(const SmbTransaction2Resp* resp) +{ + return alignedNtohs(&resp->smb_data_offset); +} + +inline uint16_t SmbTransaction2RespDataDisp(const SmbTransaction2Resp* resp) +{ + return alignedNtohs(&resp->smb_data_disp); +} + +struct SmbTrans2Open2ReqParams +{ + uint16_t Flags; + uint16_t AccessMode; + uint16_t Reserved1; + uint16_t FileAttributes; + uint32_t CreationTime; + uint16_t OpenMode; + uint32_t AllocationSize; + uint16_t Reserved[5]; +}; + +typedef SmbTransaction2Req SmbTrans2Open2Req; + +inline uint16_t SmbTrans2Open2ReqAccessMode(const SmbTrans2Open2ReqParams* req) +{ + return alignedNtohs(&req->AccessMode); +} + +inline uint16_t SmbTrans2Open2ReqFileAttrs(const SmbTrans2Open2ReqParams* req) +{ + return alignedNtohs(&req->FileAttributes); +} + +inline uint16_t SmbTrans2Open2ReqOpenMode(const SmbTrans2Open2ReqParams* req) +{ + return alignedNtohs(&req->OpenMode); +} + +inline uint32_t SmbTrans2Open2ReqAllocSize(const SmbTrans2Open2ReqParams* req) +{ + return alignedNtohl(&req->AllocationSize); +} + +struct SmbTrans2Open2RespParams +{ + uint16_t smb_fid; + uint16_t file_attributes; + uint32_t creation_time; + uint32_t file_data_size; + uint16_t access_mode; + uint16_t resource_type; + uint16_t nm_pipe_status; + uint16_t action_taken; + uint32_t reserved; + uint16_t extended_attribute_error_offset; + uint32_t extended_attribute_length; +}; + +inline uint16_t SmbTrans2Open2RespFid(const SmbTrans2Open2RespParams* resp) +{ + return alignedNtohs(&resp->smb_fid); +} + +inline uint16_t SmbTrans2Open2RespFileAttrs(const SmbTrans2Open2RespParams* resp) +{ + return alignedNtohs(&resp->file_attributes); +} + +inline uint32_t SmbTrans2Open2RespFileDataSize(const SmbTrans2Open2RespParams* resp) +{ + return alignedNtohl(&resp->file_data_size); +} + +inline uint16_t SmbTrans2Open2RespResourceType(const SmbTrans2Open2RespParams* resp) +{ + return alignedNtohs(&resp->resource_type); +} + +inline uint16_t SmbTrans2Open2RespActionTaken(const SmbTrans2Open2RespParams* resp) +{ + return alignedNtohs(&resp->action_taken); +} + +struct SmbTrans2Open2Resp +{ + uint8_t smb_wct; + uint16_t smb_total_param_count; + uint16_t smb_total_data_count; + uint16_t smb_res; + uint16_t smb_param_count; + uint16_t smb_param_offset; + uint16_t smb_param_disp; + uint16_t smb_data_count; + uint16_t smb_data_offset; + uint16_t smb_data_disp; + uint16_t smb_setup_count; /* 0 */ + uint8_t smb_res2; + uint16_t smb_bcc; +}; + +// See MS-CIFS Section 2.2.2.3.3 +#define SMB_INFO_STANDARD 0x0001 +#define SMB_INFO_QUERY_EA_SIZE 0x0002 +#define SMB_INFO_QUERY_EAS_FROM_LIST 0x0003 +#define SMB_INFO_QUERY_ALL_EAS 0x0004 +#define SMB_INFO_IS_NAME_VALID 0x0006 +#define SMB_QUERY_FILE_BASIC_INFO 0x0101 +#define SMB_QUERY_FILE_STANDARD_INFO 0x0102 +#define SMB_QUERY_FILE_EA_INFO 0x0103 +#define SMB_QUERY_FILE_NAME_INFO 0x0104 +#define SMB_QUERY_FILE_ALL_INFO 0x0107 +#define SMB_QUERY_FILE_ALT_NAME_INFO 0x0108 +#define SMB_QUERY_FILE_STREAM_INFO 0x0109 +#define SMB_QUERY_FILE_COMPRESSION_INFO 0x010b + +// See MS-SMB Section 2.2.2.3.5 +// For added value, see below from MS-FSCC +#define SMB_INFO_PASSTHROUGH 0x03e8 +#define SMB_INFO_PT_FILE_STANDARD_INFO SMB_INFO_PASSTHROUGH+5 +#define SMB_INFO_PT_FILE_ALL_INFO SMB_INFO_PASSTHROUGH+18 +#define SMB_INFO_PT_FILE_STREAM_INFO SMB_INFO_PASSTHROUGH+22 +#define SMB_INFO_PT_NETWORK_OPEN_INFO SMB_INFO_PASSTHROUGH+34 + +struct SmbTrans2QueryFileInfoReqParams +{ + uint16_t fid; + uint16_t information_level; +}; + +inline uint16_t SmbTrans2QueryFileInfoReqFid(const SmbTrans2QueryFileInfoReqParams* req) +{ + return alignedNtohs(&req->fid); +} + +inline uint16_t SmbTrans2QueryFileInfoReqInfoLevel(const SmbTrans2QueryFileInfoReqParams* req) +{ + return alignedNtohs(&req->information_level); +} + +struct SmbQueryInfoStandard +{ + uint16_t CreationDate; + uint16_t CreationTime; + uint16_t LastAccessDate; + uint16_t LastAccessTime; + uint16_t LastWriteDate; + uint16_t LastWriteTime; + uint32_t FileDataSize; + uint32_t AllocationSize; + uint16_t Attributes; +}; + +inline uint32_t SmbQueryInfoStandardFileDataSize(const SmbQueryInfoStandard* q) +{ + return alignedNtohl(&q->FileDataSize); +} + +struct SmbQueryInfoQueryEaSize +{ + uint16_t CreationDate; + uint16_t CreationTime; + uint16_t LastAccessDate; + uint16_t LastAccessTime; + uint16_t LastWriteDate; + uint16_t LastWriteTime; + uint32_t FileDataSize; + uint32_t AllocationSize; + uint16_t Attributes; + uint32_t EaSize; +}; + +inline uint32_t SmbQueryInfoQueryEaSizeFileDataSize(const SmbQueryInfoQueryEaSize* q) +{ + return alignedNtohl(&q->FileDataSize); +} + +struct SmbQueryFileStandardInfo +{ + uint64_t AllocationSize; + uint64_t EndOfFile; + uint32_t NumberOfLinks; + uint8_t DeletePending; + uint8_t Directory; + uint16_t Reserved; +}; + +inline uint64_t SmbQueryFileStandardInfoEndOfFile(const SmbQueryFileStandardInfo* q) +{ + return alignedNtohq(&q->EndOfFile); +} + +struct SmbQueryFileAllInfo +{ + // Basic Info + uint64_t CreationTime; + uint64_t LastAccessTime; + uint64_t LastWriteTime; + uint64_t LastChangeTime; + uint32_t ExtFileAttributes; + uint32_t Reserved1; + uint64_t AllocationSize; + uint64_t EndOfFile; + uint32_t NumberOfLinks; + uint8_t DeletePending; + uint8_t Directory; + uint16_t Reserved2; + uint32_t EaSize; + uint32_t FileNameLength; +}; + +inline uint64_t SmbQueryFileAllInfoEndOfFile(const SmbQueryFileAllInfo* q) +{ + return alignedNtohq(&q->EndOfFile); +} + +struct SmbQueryPTFileAllInfo +{ + // Basic Info + uint64_t CreationTime; + uint64_t LastAccessTime; + uint64_t LastWriteTime; + uint64_t LastChangeTime; + uint32_t ExtFileAttributes; + uint32_t Reserved1; + + // Standard Info + uint64_t AllocationSize; + uint64_t EndOfFile; + uint32_t NumberOfLinks; + uint8_t DeletePending; + uint8_t Directory; + uint16_t Reserved2; + + // Internal Info + uint64_t IndexNumber; + + // EA Info + uint32_t EaSize; + + // Access Info + uint32_t AccessFlags; + + // Position Info + uint64_t CurrentByteOffset; + + // Mode Info + uint32_t Mode; + + // Alignment Info + uint32_t AlignmentRequirement; + + // Name Info + uint32_t FileNameLength; +}; + +inline uint64_t SmbQueryPTFileAllInfoEndOfFile(const SmbQueryPTFileAllInfo* q) +{ + return alignedNtohq(&q->EndOfFile); +} + +struct SmbQueryPTNetworkOpenInfo +{ + uint64_t CreationTime; + uint64_t LastAccessTime; + uint64_t LastWriteTime; + uint64_t LastChangeTime; + uint64_t AllocationSize; + uint64_t EndOfFile; + uint32_t FileAttributes; + uint32_t Reserved; +}; + +inline uint64_t SmbQueryPTNetworkOpenInfoEndOfFile(const SmbQueryPTNetworkOpenInfo* q) +{ + return alignedNtohq(&q->EndOfFile); +} + +struct SmbQueryPTFileStreamInfo +{ + uint32_t NextEntryOffset; + uint32_t StreamNameLength; + uint64_t StreamSize; + uint64_t StreamAllocationSize; +}; + +inline uint64_t SmbQueryPTFileStreamInfoStreamSize(const SmbQueryPTFileStreamInfo* q) +{ + return alignedNtohq(&q->StreamSize); +} + +struct SmbTrans2QueryFileInformationResp +{ + uint8_t smb_wct; + uint16_t smb_total_param_count; + uint16_t smb_total_data_count; + uint16_t smb_res; + uint16_t smb_param_count; + uint16_t smb_param_offset; + uint16_t smb_param_disp; + uint16_t smb_data_count; + uint16_t smb_data_offset; + uint16_t smb_data_disp; + uint16_t smb_setup_count; /* 0 */ + uint8_t smb_res2; + uint16_t smb_bcc; +}; + +#define SMB_INFO_SET_EAS 0x0002 +#define SMB_SET_FILE_BASIC_INFO 0x0101 +#define SMB_SET_FILE_DISPOSITION_INFO 0x0102 +#define SMB_SET_FILE_ALLOCATION_INFO 0x0103 +#define SMB_SET_FILE_END_OF_FILE_INFO 0x0104 + +// For added value, see above File Information Classes +#define SMB_INFO_PT_SET_FILE_BASIC_FILE_INFO SMB_INFO_PASSTHROUGH+4 +#define SMB_INFO_PT_SET_FILE_END_OF_FILE_INFO SMB_INFO_PASSTHROUGH+20 + +struct SmbTrans2SetFileInfoReqParams +{ + uint16_t fid; + uint16_t information_level; + uint16_t reserved; +}; + +inline uint16_t SmbTrans2SetFileInfoReqFid(const SmbTrans2SetFileInfoReqParams* req) +{ + return alignedNtohs(&req->fid); +} + +inline uint16_t SmbTrans2SetFileInfoReqInfoLevel(const SmbTrans2SetFileInfoReqParams* req) +{ + return alignedNtohs(&req->information_level); +} + +inline bool SmbSetFileInfoEndOfFile(const uint16_t info_level) +{ + return ((info_level == SMB_SET_FILE_END_OF_FILE_INFO) + || (info_level == SMB_INFO_PT_SET_FILE_END_OF_FILE_INFO)); +} + +struct SmbSetFileBasicInfo +{ + uint64_t CreationTime; + uint64_t LastAccessTime; + uint64_t LastWriteTime; + uint64_t ChangeTime; + uint32_t ExtFileAttributes; + uint32_t Reserved; +}; + +inline uint32_t SmbSetFileInfoExtFileAttrs(const SmbSetFileBasicInfo* info) +{ + return alignedNtohl(&info->ExtFileAttributes); +} + +inline bool SmbSetFileInfoSetFileBasicInfo(const uint16_t info_level) +{ + return ((info_level == SMB_SET_FILE_BASIC_INFO) + || (info_level == SMB_INFO_PT_SET_FILE_BASIC_FILE_INFO)); +} + +/******************************************************************** + * SMB_COM_NT_TRANSACT + ********************************************************************/ +#define SMB_CREATE_OPTIONS__FILE_SEQUENTIAL_ONLY 0x00000004 + +struct SmbNtTransactReq +{ + uint8_t smb_wct; + uint8_t smb_max_setup_count; + uint16_t smb_res; + uint32_t smb_total_param_count; + uint32_t smb_total_data_count; + uint32_t smb_max_param_count; + uint32_t smb_max_data_count; + uint32_t smb_param_count; + uint32_t smb_param_offset; + uint32_t smb_data_count; + uint32_t smb_data_offset; + uint8_t smb_setup_count; + uint16_t smb_function; +}; + +struct SmbNtTransactInterimResp +{ + uint8_t smb_wct; + uint16_t smb_bcc; +}; + +struct SmbNtTransactResp +{ + uint8_t smb_wct; + uint8_t smb_res[3]; + uint32_t smb_total_param_count; + uint32_t smb_total_data_count; + uint32_t smb_param_count; + uint32_t smb_param_offset; + uint32_t smb_param_disp; + uint32_t smb_data_count; + uint32_t smb_data_offset; + uint32_t smb_data_disp; + uint8_t smb_setup_count; +}; + +inline uint16_t SmbNtTransactReqSubCom(const SmbNtTransactReq* req) +{ + return alignedNtohs(&req->smb_function); +} + +inline uint8_t SmbNtTransactReqSetupCnt(const SmbNtTransactReq* req) +{ + return req->smb_setup_count; +} + +inline uint32_t SmbNtTransactReqTotalParamCnt(const SmbNtTransactReq* req) +{ + return alignedNtohl(&req->smb_total_param_count); +} + +inline uint32_t SmbNtTransactReqParamCnt(const SmbNtTransactReq* req) +{ + return alignedNtohl(&req->smb_param_count); +} + +inline uint32_t SmbNtTransactReqParamOff(const SmbNtTransactReq* req) +{ + return alignedNtohl(&req->smb_param_offset); +} + +inline uint32_t SmbNtTransactReqTotalDataCnt(const SmbNtTransactReq* req) +{ + return alignedNtohl(&req->smb_total_data_count); +} + +inline uint32_t SmbNtTransactReqDataCnt(const SmbNtTransactReq* req) +{ + return alignedNtohl(&req->smb_data_count); +} + +inline uint32_t SmbNtTransactReqDataOff(const SmbNtTransactReq* req) +{ + return alignedNtohl(&req->smb_data_offset); +} + +inline uint32_t SmbNtTransactRespTotalParamCnt(const SmbNtTransactResp* resp) +{ + return alignedNtohl(&resp->smb_total_param_count); +} + +inline uint32_t SmbNtTransactRespParamCnt(const SmbNtTransactResp* resp) +{ + return alignedNtohl(&resp->smb_param_count); +} + +inline uint32_t SmbNtTransactRespParamOff(const SmbNtTransactResp* resp) +{ + return alignedNtohl(&resp->smb_param_offset); +} + +inline uint32_t SmbNtTransactRespParamDisp(const SmbNtTransactResp* resp) +{ + return alignedNtohl(&resp->smb_param_disp); +} + +inline uint32_t SmbNtTransactRespTotalDataCnt(const SmbNtTransactResp* resp) +{ + return alignedNtohl(&resp->smb_total_data_count); +} + +inline uint32_t SmbNtTransactRespDataCnt(const SmbNtTransactResp* resp) +{ + return alignedNtohl(&resp->smb_data_count); +} + +inline uint32_t SmbNtTransactRespDataOff(const SmbNtTransactResp* resp) +{ + return alignedNtohl(&resp->smb_data_offset); +} + +inline uint32_t SmbNtTransactRespDataDisp(const SmbNtTransactResp* resp) +{ + return alignedNtohl(&resp->smb_data_disp); +} + +struct SmbNtTransactCreateReqParams +{ + uint32_t flags; + uint32_t root_dir_fid; + uint32_t desired_access; + uint64_t allocation_size; + uint32_t ext_file_attributes; + uint32_t share_access; + uint32_t create_disposition; + uint32_t create_options; + uint32_t security_descriptor_length; + uint32_t ea_length; + uint32_t name_length; + uint32_t impersonation_level; + uint8_t security_flags; +}; + +inline uint64_t SmbNtTransactCreateReqAllocSize(const SmbNtTransactCreateReqParams* req) +{ + return alignedNtohq(&req->allocation_size); +} + +inline uint32_t SmbNtTransactCreateReqFileNameLength(const SmbNtTransactCreateReqParams* req) +{ + return alignedNtohl(&req->name_length); +} + +inline uint32_t SmbNtTransactCreateReqFileAttrs(const SmbNtTransactCreateReqParams* req) +{ + return alignedNtohl(&req->ext_file_attributes); +} + +inline bool SmbNtTransactCreateReqSequentialOnly(const SmbNtTransactCreateReqParams* req) +{ + return (alignedNtohl(&req->create_options) & SMB_CREATE_OPTIONS__FILE_SEQUENTIAL_ONLY); +} + +struct SmbNtTransactCreateReq +{ + uint8_t smb_wct; + uint8_t smb_max_setup_count; + uint16_t smb_res; + uint32_t smb_total_param_count; + uint32_t smb_total_data_count; + uint32_t smb_max_param_count; + uint32_t smb_max_data_count; + uint32_t smb_param_count; + uint32_t smb_param_offset; + uint32_t smb_data_count; + uint32_t smb_data_offset; + uint8_t smb_setup_count; /* Must be 0x00 */ + uint16_t smb_function; /* NT_TRANSACT_CREATE */ + uint16_t smb_bcc; +}; + +struct SmbNtTransactCreateRespParams +{ + uint8_t op_lock_level; + uint8_t reserved; + uint16_t smb_fid; + uint32_t create_action; + uint32_t ea_error_offset; + uint64_t creation_time; + uint64_t last_access_time; + uint64_t last_write_time; + uint64_t last_change_time; + uint32_t ext_file_attributes; + uint64_t allocation_size; + uint64_t end_of_file; + uint16_t resource_type; + uint16_t nm_pipe_status; + uint8_t directory; +}; + +inline uint16_t SmbNtTransactCreateRespFid(const SmbNtTransactCreateRespParams* resp) +{ + return alignedNtohs(&resp->smb_fid); +} + +inline uint32_t SmbNtTransactCreateRespCreateAction(const SmbNtTransactCreateRespParams* resp) +{ + return alignedNtohl(&resp->create_action); +} + +inline uint64_t SmbNtTransactCreateRespEndOfFile(const SmbNtTransactCreateRespParams* resp) +{ + return alignedNtohq(&resp->end_of_file); +} + +inline uint16_t SmbNtTransactCreateRespResourceType(const SmbNtTransactCreateRespParams* resp) +{ + return alignedNtohs(&resp->resource_type); +} + +inline bool SmbNtTransactCreateRespDirectory(const SmbNtTransactCreateRespParams* resp) +{ + return (resp->directory ? true : false); +} + +struct SmbNtTransactCreateResp +{ + uint8_t smb_wct; + uint8_t smb_res[3]; + uint32_t smb_total_param_count; + uint32_t smb_total_data_count; + uint32_t smb_param_count; + uint32_t smb_param_offset; + uint32_t smb_param_disp; + uint32_t smb_data_count; + uint32_t smb_data_offset; + uint32_t smb_data_disp; + uint8_t smb_setup_count; /* 0x00 */ + uint16_t smb_bcc; +}; + +/******************************************************************** + * SMB_COM_TRANSACTION_SECONDARY + * Continuation command for SMB_COM_TRANSACTION requests if all + * data wasn't sent. + ********************************************************************/ +struct SmbTransactionSecondaryReq /* smb_wct = 8 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint16_t smb_tpscnt; /* total number of parameter bytes being sent */ + uint16_t smb_tdscnt; /* total number of data bytes being sent */ + uint16_t smb_pscnt; /* number of parameter bytes being sent this buffer */ + uint16_t smb_psoff; /* offset (from start of SMB hdr) to parameter bytes */ + uint16_t smb_psdisp; /* byte displacement for these parameter bytes */ + uint16_t smb_dscnt; /* number of data bytes being sent this buffer */ + uint16_t smb_dsoff; /* offset (from start of SMB hdr) to data bytes */ + uint16_t smb_dsdisp; /* byte displacement for these data bytes */ + uint16_t smb_bcc; /* total bytes (including pad bytes) following */ +}; + +inline uint16_t SmbTransactionSecondaryReqTotalDataCnt(const SmbTransactionSecondaryReq* req) +{ + return alignedNtohs(&req->smb_tdscnt); +} + +inline uint16_t SmbTransactionSecondaryReqDataCnt(const SmbTransactionSecondaryReq* req) +{ + return alignedNtohs(&req->smb_dscnt); +} + +inline uint16_t SmbTransactionSecondaryReqDataOff(const SmbTransactionSecondaryReq* req) +{ + return alignedNtohs(&req->smb_dsoff); +} + +inline uint16_t SmbTransactionSecondaryReqDataDisp(const SmbTransactionSecondaryReq* req) +{ + return alignedNtohs(&req->smb_dsdisp); +} + +inline uint16_t SmbTransactionSecondaryReqTotalParamCnt(const SmbTransactionSecondaryReq* req) +{ + return alignedNtohs(&req->smb_tpscnt); +} + +inline uint16_t SmbTransactionSecondaryReqParamCnt(const SmbTransactionSecondaryReq* req) +{ + return alignedNtohs(&req->smb_pscnt); +} + +inline uint16_t SmbTransactionSecondaryReqParamOff(const SmbTransactionSecondaryReq* req) +{ + return alignedNtohs(&req->smb_psoff); +} + +inline uint16_t SmbTransactionSecondaryReqParamDisp(const SmbTransactionSecondaryReq* req) +{ + return alignedNtohs(&req->smb_psdisp); +} + +/******************************************************************** + * SMB_COM_TRANSACTION2_SECONDARY + * Continuation command for SMB_COM_TRANSACTION2 requests if all + * data wasn't sent. + ********************************************************************/ +struct SmbTransaction2SecondaryReq +{ + uint8_t smb_wct; + uint16_t smb_total_param_count; + uint16_t smb_total_data_count; + uint16_t smb_param_count; + uint16_t smb_param_offset; + uint16_t smb_param_disp; + uint16_t smb_data_count; + uint16_t smb_data_offset; + uint16_t smb_data_disp; + uint16_t smb_fid; + uint16_t smb_bcc; +}; + +inline uint16_t SmbTransaction2SecondaryReqTotalParamCnt(const SmbTransaction2SecondaryReq* req) +{ + return alignedNtohs(&req->smb_total_param_count); +} + +inline uint16_t SmbTransaction2SecondaryReqParamCnt(const SmbTransaction2SecondaryReq* req) +{ + return alignedNtohs(&req->smb_param_count); +} + +inline uint16_t SmbTransaction2SecondaryReqParamOff(const SmbTransaction2SecondaryReq* req) +{ + return alignedNtohs(&req->smb_param_offset); +} + +inline uint16_t SmbTransaction2SecondaryReqParamDisp(const SmbTransaction2SecondaryReq* req) +{ + return alignedNtohs(&req->smb_param_disp); +} + +inline uint16_t SmbTransaction2SecondaryReqTotalDataCnt(const SmbTransaction2SecondaryReq* req) +{ + return alignedNtohs(&req->smb_total_data_count); +} + +inline uint16_t SmbTransaction2SecondaryReqDataCnt(const SmbTransaction2SecondaryReq* req) +{ + return alignedNtohs(&req->smb_data_count); +} + +inline uint16_t SmbTransaction2SecondaryReqDataOff(const SmbTransaction2SecondaryReq* req) +{ + return alignedNtohs(&req->smb_data_offset); +} + +inline uint16_t SmbTransaction2SecondaryReqDataDisp(const SmbTransaction2SecondaryReq* req) +{ + return alignedNtohs(&req->smb_data_disp); +} + +/******************************************************************** + * SMB_COM_NT_TRANSACT_SECONDARY + ********************************************************************/ +struct SmbNtTransactSecondaryReq +{ + uint8_t smb_wct; + uint8_t smb_res[3]; + uint32_t smb_total_param_count; + uint32_t smb_total_data_count; + uint32_t smb_param_count; + uint32_t smb_param_offset; + uint32_t smb_param_disp; + uint32_t smb_data_count; + uint32_t smb_data_offset; + uint32_t smb_data_disp; + uint8_t smb_res2; +}; + +inline uint32_t SmbNtTransactSecondaryReqTotalParamCnt(const SmbNtTransactSecondaryReq* req) +{ + return alignedNtohl(&req->smb_total_param_count); +} + +inline uint32_t SmbNtTransactSecondaryReqParamCnt(const SmbNtTransactSecondaryReq* req) +{ + return alignedNtohl(&req->smb_param_count); +} + +inline uint32_t SmbNtTransactSecondaryReqParamOff(const SmbNtTransactSecondaryReq* req) +{ + return alignedNtohl(&req->smb_param_offset); +} + +inline uint32_t SmbNtTransactSecondaryReqParamDisp(const SmbNtTransactSecondaryReq* req) +{ + return alignedNtohl(&req->smb_param_disp); +} + +inline uint32_t SmbNtTransactSecondaryReqTotalDataCnt(const SmbNtTransactSecondaryReq* req) +{ + return alignedNtohl(&req->smb_total_data_count); +} + +inline uint32_t SmbNtTransactSecondaryReqDataCnt(const SmbNtTransactSecondaryReq* req) +{ + return alignedNtohl(&req->smb_data_count); +} + +inline uint32_t SmbNtTransactSecondaryReqDataOff(const SmbNtTransactSecondaryReq* req) +{ + return alignedNtohl(&req->smb_data_offset); +} + +inline uint32_t SmbNtTransactSecondaryReqDataDisp(const SmbNtTransactSecondaryReq* req) +{ + return alignedNtohl(&req->smb_data_disp); +} + +/******************************************************************** + * SMB_COM_READ_RAW + ********************************************************************/ +struct SmbReadRawReq /* smb_wct = 8 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint16_t smb_fid; /* file handle */ + uint32_t smb_offset; /* offset in file to begin read */ + uint16_t smb_maxcnt; /* max number of bytes to return (max 65,535) */ + uint16_t smb_mincnt; /* min number of bytes to return (normally 0) */ + uint32_t smb_timeout; /* number of milliseconds to wait for completion */ + uint16_t smb_rsvd; /* reserved */ + uint16_t smb_bcc; /* value = 0 */ +}; + +struct SmbReadRawExtReq /* smb_wct = 10 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint16_t smb_fid; /* file handle */ + uint32_t smb_offset; /* offset in file to begin read */ + uint16_t smb_maxcnt; /* max number of bytes to return (max 65,535) */ + uint16_t smb_mincnt; /* min number of bytes to return (normally 0) */ + uint32_t smb_timeout; /* number of milliseconds to wait for completion */ + uint16_t smb_rsvd; /* reserved */ + uint32_t smb_off_high; /* high offset in file to begin write */ + uint16_t smb_bcc; /* value = 0 */ +}; + +/* Read Raw response is raw data wrapped in NetBIOS header */ + +inline uint16_t SmbReadRawReqFid(const SmbReadRawReq* req) +{ + return alignedNtohs(&req->smb_fid); +} + +inline uint64_t SmbReadRawReqOffset(const SmbReadRawExtReq* req) +{ + if (req->smb_wct == 8) + return (uint64_t)alignedNtohl(&req->smb_offset); + return (uint64_t)alignedNtohl(&req->smb_off_high) << 32 | (uint64_t)alignedNtohl( + &req->smb_offset); +} + +/******************************************************************** + * SMB_COM_WRITE_RAW + ********************************************************************/ +struct SmbWriteRawReq +{ + uint8_t smb_wct; /* value = 12 */ + uint16_t smb_fid; /* file handle */ + uint16_t smb_tcount; /* total bytes (including this buf, 65,535 max ) */ + uint16_t smb_rsvd; /* reserved */ + uint32_t smb_offset; /* offset in file to begin write */ + uint32_t smb_timeout; /* number of milliseconds to wait for completion */ + uint16_t smb_wmode; /* write mode: + bit0 - complete write to disk and send final result response + bit1 - return smb_remaining (pipes/devices only) */ + uint32_t smb_rsvd2; /* reserved */ + uint16_t smb_dsize; /* number of data bytes this buffer (min value = 0) */ + uint16_t smb_doff; /* offset (from start of SMB hdr) to data bytes */ + uint16_t smb_bcc; /* total bytes (including pad bytes) following */ +}; + +struct SmbWriteRawExtReq +{ + uint8_t smb_wct; /* value = 14 */ + uint16_t smb_fid; /* file handle */ + uint16_t smb_tcount; /* total bytes (including this buf, 65,535 max ) */ + uint16_t smb_rsvd; /* reserved */ + uint32_t smb_offset; /* offset in file to begin write */ + uint32_t smb_timeout; /* number of milliseconds to wait for completion */ + uint16_t smb_wmode; /* write mode: + bit0 - complete write to disk and send final result response + bit1 - return smb_remaining (pipes/devices only) */ + uint32_t smb_rsvd2; /* reserved */ + uint16_t smb_dsize; /* number of data bytes this buffer (min value = 0) */ + uint16_t smb_doff; /* offset (from start of SMB hdr) to data bytes */ + uint32_t smb_off_high; /* high offset in file to begin write */ + uint16_t smb_bcc; /* total bytes (including pad bytes) following */ +}; + +struct SmbWriteRawInterimResp +{ + uint8_t smb_wct; /* value = 1 */ + uint16_t smb_remaining; /* bytes remaining to be read (pipes/devices only) */ + uint16_t smb_bcc; /* value = 0 */ +}; + +inline uint16_t SmbWriteRawReqTotalCount(const SmbWriteRawReq* req) +{ + return alignedNtohs(&req->smb_tcount); +} + +inline bool SmbWriteRawReqWriteThrough(const SmbWriteRawReq* req) +{ + return alignedNtohs(&req->smb_wmode) & 0x0001; +} + +inline uint16_t SmbWriteRawReqFid(const SmbWriteRawReq* req) +{ + return alignedNtohs(&req->smb_fid); +} + +inline uint16_t SmbWriteRawReqDataOff(const SmbWriteRawReq* req) +{ + return alignedNtohs(&req->smb_doff); +} + +inline uint16_t SmbWriteRawReqDataCnt(const SmbWriteRawReq* req) +{ + return alignedNtohs(&req->smb_dsize); +} + +inline uint64_t SmbWriteRawReqOffset(const SmbWriteRawExtReq* req) +{ + if (req->smb_wct == 12) + return (uint64_t)alignedNtohl(&req->smb_offset); + return (uint64_t)alignedNtohl(&req->smb_off_high) << 32 | (uint64_t)alignedNtohl( + &req->smb_offset); +} + +inline uint16_t SmbWriteRawInterimRespRemaining(const SmbWriteRawInterimResp* resp) +{ + return alignedNtohs(&resp->smb_remaining); +} + +/******************************************************************** + * SMB_COM_WRITE_COMPLETE - final response to an SMB_COM_WRITE_RAW + ********************************************************************/ +struct SmbWriteCompleteResp +{ + uint8_t smb_wct; /* value = 1 */ + uint16_t smb_count; /* total number of bytes written */ + uint16_t smb_bcc; /* value = 0 */ +}; + +inline uint16_t SmbWriteCompleteRespCount(const SmbWriteCompleteResp* resp) +{ + return alignedNtohs(&resp->smb_count); +} + +/******************************************************************** + * SMB_COM_WRITE_AND_CLOSE + ********************************************************************/ +struct SmbWriteAndCloseReq /* smb_wct = 6 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint16_t smb_fid; /* file handle (close after write) */ + uint16_t smb_count; /* number of bytes to write */ + uint32_t smb_offset; /* offset in file to begin write */ + uint32_t smb_mtime; /* modification time */ + uint16_t smb_bcc; /* 1 (for pad) + value of smb_count */ +}; + +struct SmbWriteAndCloseExtReq /* smb_wct = 12 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint16_t smb_fid; /* file handle (close after write) */ + uint16_t smb_count; /* number of bytes to write */ + uint32_t smb_offset; /* offset in file to begin write */ + uint32_t smb_mtime; /* modification time */ + uint32_t smb_rsvd1; /* Optional */ + uint32_t smb_rsvd2; /* Optional */ + uint32_t smb_rsvd3; /* Optional */ + uint16_t smb_bcc; /* 1 (for pad) + value of smb_count */ +}; + +struct SmbWriteAndCloseResp /* smb_wct = 1 */ +{ + uint8_t smb_wct; /* count of 16-bit words that follow */ + uint16_t smb_count; /* number of bytes written */ + uint16_t smb_bcc; /* must be 0 */ +}; + +inline uint16_t SmbWriteAndCloseReqFid(const SmbWriteAndCloseReq* req) +{ + return alignedNtohs(&req->smb_fid); +} + +inline uint16_t SmbWriteAndCloseReqCount(const SmbWriteAndCloseReq* req) +{ + return alignedNtohs(&req->smb_count); +} + +inline uint32_t SmbWriteAndCloseReqOffset(const SmbWriteAndCloseReq* req) +{ + return alignedNtohl(&req->smb_offset); +} + +inline uint16_t SmbWriteAndCloseRespCount(const SmbWriteAndCloseResp* resp) +{ + return alignedNtohs(&resp->smb_count); +} + +#pragma pack() + +void DCE2_SmbInitGlobals(); +void DCE2_SmbProcess(struct DCE2_SmbSsnData*); +DCE2_SmbSsnData* dce2_handle_smb_session(struct Packet*, struct dce2SmbProtoConf*); + +#endif +