hi_ad.cc
hi_ad.h
hi_client.cc
+ hi_client_init.cc
hi_client.h
hi_client_norm.cc
hi_client_norm.h
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 \
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::
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::
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::
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
-
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
--- /dev/null
+//--------------------------------------------------------------------------
+// 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 <rucombs@cisco.com>
+//
+// 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;
+}
+
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)
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
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;
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;
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
"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
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//--------------------------------------------------------------------------
-//dce_smb.h author Rashmi Pitre <rrp@cisco.com>
+// dce_smb.h author Rashmi Pitre <rrp@cisco.com>
// based on work by Todd Wease
#ifndef DCE_SMB_H
#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"
#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;
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,
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
uint8_t* data;
};
+enum DCE2_SmbVersion
+{
+ DCE2_SMB_VERISON_NULL,
+ DCE2_SMB_VERISON_1,
+ DCE2_SMB_VERISON_2
+};
+
struct DCE2_SmbFileTracker
{
union
#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 */
bool is_ipc;
};
-#pragma pack()
-
struct DCE2_SmbSsnData
{
DCE2_SsnData sd; // This member must be first
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;
DCE2_SmbSsnData* get_dce2_smb_session_data(Flow*);
+const char* get_smb_com_string(uint8_t);
#endif
--- /dev/null
+//--------------------------------------------------------------------------
+// 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 <rucombs@cisco.com>
+
+// extracted from dce_smb.h originally written by Todd Wease
+
+#ifndef SMB_COMMON_H
+#define SMB_COMMON_H
+
+#include <stdint.h>
+
+#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
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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 <rrp@cisco.com>
+
+#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);
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// 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 <rucombs@cisco.com>
+
+// extracted from dce_smb.h originally written by Todd Wease
+
+#ifndef SMB_MESSAGE_H
+#define SMB_MESSAGE_H
+
+#include <stdint.h>
+
+/********************************************************************
+ * 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
+