diff --git a/SConscript b/SConscript index 9444732..7ddb851 100644 --- a/SConscript +++ b/SConscript @@ -35,7 +35,7 @@ import os import GenApps # imports from SConstruct -Import('env libFileName elfFileName binDir coreDir driversDir genDir appBase toolsList chuncksNbits sourcesMap gzipped test') +Import('env libFileName elfFileName binDir coreDir driversDir genDir appBase toolsList chuncksNbits dirsMap sourcesMap restrictMap httpAuthType gzipped test') # returns the list of .c and .s files in dir, prefixed by dstDir def getAllSourceFiles(dir, dstDir): @@ -52,10 +52,25 @@ def getAllSourceFiles(dir, dstDir): # builders for web applicative resources creation # used to generate both static and dynamic resources def generateResource(target, source, env): + realm = '' + offsetCount = (-1, -1) + + # Checking for HTTP Authentication data + finalUri = sourcesMap[str(source[0])] + + maxlen = 0 + for r in restrictMap: + for uri in restrictMap[r]: + if finalUri.startswith(uri) and len(uri) > maxlen: + offsetCount = (restrictMap[r][uri][0], + restrictMap[r][uri][1]) + realm = r + maxlen = len(uri) + if propsFilesMap.has_key(str(source[0])): - GenApps.generateResource(str(source[0]),str(target[0]),chuncksNbits,gzipped,propsFilesMap[str(source[0])]) + GenApps.generateResource(str(source[0]),str(target[0]),chuncksNbits,gzipped,propsFilesMap[str(source[0])], httpAuthType, realm, offsetCount, finalUri) else: - GenApps.generateResource(str(source[0]),str(target[0]),chuncksNbits,gzipped,None) + GenApps.generateResource(str(source[0]),str(target[0]),chuncksNbits,gzipped,None,httpAuthType, realm, offsetCount, finalUri) return None # builder used to generate the file index, with the URLs tree diff --git a/SConstruct b/SConstruct index d2af229..ae558fd 100644 --- a/SConstruct +++ b/SConstruct @@ -35,6 +35,7 @@ import os import sys sys.path.append('tools') import GenApps +import GenAuthData from SCons.Errors import BuildError import sys, string @@ -66,6 +67,7 @@ toolsDir = 'tools' tmpBase = 'tmp' appBase = 'apps' httpCodesDir = 'httpCodes' +httpAuthType = '' # the list of python files used by this SConstruct toolsList = map(lambda x: os.path.join(toolsDir,x),filter(lambda x: x.endswith('.py'), os.listdir(toolsDir))) projectName = 'smews' @@ -81,6 +83,7 @@ opts.Add(BoolVariable('debug', 'Set to 1 to build for debug', False)) opts.Add(BoolVariable('sdump', 'Set to 1 to include stack dump', False)) opts.Add(BoolVariable('test', 'Set to 1 to test the test apps', False)) opts.Add('ipaddr', 'Set the IP address of Smews', None) +opts.Add('accessfile', 'Set the path to XML-defined restrictions file', None) # the list of disableable options disabledHash = {} disabledHash['timers'] = 'DISABLE_TIMERS' @@ -190,6 +193,15 @@ for appDir in dirsMap.keys(): appSource = os.path.join(appBase,appDir,file) sourcesMap[appSource] = os.path.join(dirsMap[appDir],file) +# Contains a data structure for HTTP authentication restrictions. +# Refer to GenAuthData.py for more details. +# TODO: Improve the file generation by stripping the "core/" path and +# allow automatic generation in gen/target +restrictMap = { } +if globalEnv.has_key('accessfile'): + httpAuthType = GenAuthData.parseXMLFile(globalEnv['accessfile']) + restrictMap = GenAuthData.genHTTPAuthDataFile('core/http_auth_data') + # compilation options globalEnv.Replace(CC = 'gcc') globalEnv.Replace(AS = 'as') @@ -203,6 +215,12 @@ else: globalEnv.Append(CCFLAGS = '-Os -ffunction-sections -fdata-sections -fno-strict-aliasing') globalEnv.Append(LINKFLAGS = '-Wl,--gc-sections -Wl,--print-gc-sections') globalEnv.Append(CPPDEFINES = {'CHUNCKS_NBITS' : str(chuncksNbits)}) + +if httpAuthType == 'basic': + globalEnv.Append(CPPDEFINES = { 'HTTP_AUTH' : 'HTTP_AUTH_BASIC' }) +elif httpAuthType == 'digest': + globalEnv.Append(CPPDEFINES = { 'HTTP_AUTH' : 'HTTP_AUTH_DIGEST' }) + for func in toDisable: globalEnv.Append(CPPDEFINES = { disabledHash[func] : '1'}) if endian: @@ -235,7 +253,7 @@ for target in targets: # export variables for external SConscript files Export('env libFileName elfFileName binDir coreDir driversDir genDir appBase toolsList chuncksNbits sourcesMap gzipped test') Export('env targetDir binDir projectName elfName') - Export('dirsMap sourcesMap target sconsBasePath httpCodesDir tmpBase') + Export('dirsMap sourcesMap restrictMap httpAuthType target sconsBasePath httpCodesDir tmpBase') # target dependent SConscript call SConscript(os.path.join(targetDir,'SConscript'),variant_dir = binDir,duplicate = 0) # possible web applications SConscript calls diff --git a/accessfile_example.xml b/accessfile_example.xml new file mode 100644 index 0000000..a4cfeae --- /dev/null +++ b/accessfile_example.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + diff --git a/apps/httpCodes/401.html b/apps/httpCodes/401.html new file mode 100644 index 0000000..6e53480 --- /dev/null +++ b/apps/httpCodes/401.html @@ -0,0 +1,10 @@ + + + + 401 Authorization required + + +

Error 401: Authorization required

+

Please authenticate

+ + diff --git a/core/auth.c b/core/auth.c new file mode 100644 index 0000000..cb322fb --- /dev/null +++ b/core/auth.c @@ -0,0 +1,257 @@ +/* + * Copyright or © or Copr. 2008, Simon Duquennoy + * + * Author e-mail: simon.duquennoy@lifl.fr + * + * This software is a computer program whose purpose is to design an + * efficient Web server for very-constrained embedded system. + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. + */ + +/* + * Author: Christophe Bacara + * `-Mail: christophe.bacara@etudiant.univ-lille1.fr + */ + +#include "auth.h" +#include "md5.h" + +#ifdef HTTP_AUTH + +#include "http_auth_data.h" + +#if HTTP_AUTH == HTTP_AUTH_BASIC +CONST_VAR(unsigned char, HttpAuthenticateScheme[]) = "basic"; + +CONST_VAR(char, HttpAuthenticateHeader[]) = "\ +HTTP/1.1 401 Authorization required\r\nWWW-Authenticate: Basic realm=\ +"; + +#elif HTTP_AUTH == HTTP_AUTH_DIGEST +CONST_VAR(unsigned char, HttpAuthenticateScheme[]) = "digest"; + +CONST_VAR(char, HttpAuthenticateHeader[]) = "\ +HTTP/1.1 401 Authorization required\r\nWWW-Authenticate: Digest realm=\ +"; + +CONST_VAR(char, HttpAuthenticateHeaderNonce[]) = "\ +, nonce=\ +"; + +CONST_VAR(char, HttpAuthenticateHeaderStale[]) = "\ +, stale=true\ +"; + +struct nonce_state_s nonce_state = { + .requester = NULL, + .nonce = "\0" +}; + +#endif + +uint32_t http_401_handler_dynamic_header_length(const struct output_handler_t *restricted_handler +#if HTTP_AUTH == HTTP_AUTH_DIGEST + , const uint8_t stale +#endif + ) +{ + unsigned const char *char_p = restricted_handler->handler_restriction.realm; + uint32_t length = 0; + + /* Error checking */ + if (char_p == NULL) + return -1; + + /* Realm length computation */ + while (*char_p++) + ++length; + + /* If realm length is odd, we'll add a space after it */ + if (length & 1) + ++length; + +#if HTTP_AUTH == HTTP_AUTH_BASIC + + /* Remaining size computation */ + length += sizeof (HttpAuthenticateHeader) - 1; + length += 2; /* Realm must be double quoted */ + +#elif HTTP_AUTH == HTTP_AUTH_DIGEST + + /* Remaining size computation */ + length += sizeof (HttpAuthenticateHeader) - 1; + length += sizeof (HttpAuthenticateHeaderNonce) - 1; + if (stale) + length += sizeof (HttpAuthenticateHeaderStale) - 1; + + length += 32; /* Nonce is a 32-Hex character string */ + length += 4; /* Realm and nonce must be double quoted. */ + +#endif + + return length; +} + +uint32_t http_401_handler_length(const struct output_handler_t *restricted_handler +#if HTTP_AUTH == HTTP_AUTH_DIGEST + , const uint8_t stale +#endif + ) +{ + /* Add the size of remaining bytes */ + return http_401_handler_dynamic_header_length (restricted_handler +#if HTTP_AUTH == HTTP_AUTH_DIGEST + , stale +#endif + ) + + CONST_UI32 (GET_FILE (&http_401_handler).length); +} + +#if HTTP_AUTH == HTTP_AUTH_BASIC +char http_basic_authenticate(const struct output_handler_t *handler, + unsigned const char *credentials) +{ + unsigned const char *current_credentials; + unsigned const char *given_credentials; + uint8_t i; + + /* For each valid credentials ... */ + for (i = handler->handler_restriction.credentials_offset; + i < (handler->handler_restriction.credentials_offset + + handler->handler_restriction.credentials_count); + ++i) { + + current_credentials = http_auth_basic_credentials_data[i]; + given_credentials = credentials; + + /* String comparison loop */ + while (*given_credentials == *current_credentials) { + /* If we reach end of both string simultaneously, they match. */ + if (*given_credentials == '\0' && *current_credentials == '\0') + return HTTP_AUTHENTICATE_SUCCESS; + + ++given_credentials; + ++current_credentials; + } + } + + return HTTP_AUTHENTICATE_FAILURE; +} + +#elif HTTP_AUTH == HTTP_AUTH_DIGEST +char http_digest_authenticate(const struct connection *requester, + const struct output_handler_t *handler, + const struct auth_data_s *auth_data) +{ + credentials_digest_t *digest_infos = NULL; + uint8_t i, j; + + /* Nonce validity check */ + for (i = 0; i < NONCE_LEN; ++i) + if (auth_data->nonce[i] != nonce_state.nonce[i]) + return HTTP_AUTHENTICATE_STALE; + + /* User validity check */ + for (i = handler->handler_restriction.credentials_offset; + i < (handler->handler_restriction.credentials_offset + + handler->handler_restriction.credentials_count); + ++i) { + + if (http_auth_digest_credentials_table[i] != auth_data->username_blob) + continue; + + /* Once username has been validated, get the matching credentials */ + for (j = 0; j < USER_DIGEST_COUNT; ++j) { + if (http_auth_digest_credentials_data[j].username_blob == auth_data->username_blob + && + http_auth_digest_credentials_data[j].realm == handler->handler_restriction.realm) { + digest_infos = (credentials_digest_t *) &http_auth_digest_credentials_data[j]; + break; + } + } + break; + } + + /* No digest informations: invalid username */ + if (digest_infos == NULL) + return HTTP_AUTHENTICATE_FAILURE; + + /* Compute the valid md5 digest : + * md5(user_digest:nonce:resource_digest) */ + md5_init(); + md5_append((const md5_byte_t *) digest_infos->user_digest, MD5_DIGEST_LEN); + md5_append((const md5_byte_t *) ":", 1); + md5_append((const md5_byte_t *) nonce_state.nonce, NONCE_LEN); + md5_append((const md5_byte_t *) ":", 1); + md5_append((const md5_byte_t *) handler->handler_restriction.resource_digest, + MD5_DIGEST_LEN); + md5_end(); + + /* Compare given credentials with computed credentials */ + for (i = 0; i < MD5_DIGEST_LEN; ++i) { + /* WARNING: md5_digest is a 16-byte table, whereas credentials is a classic + * C character string ! + * Don't try something like "credentials[i] == md5_digest[i]" */ + if (auth_data->response[i] != MD5_DIGEST_GET_NTH_HEXC(i)) + return HTTP_AUTHENTICATE_FAILURE; + } + + return HTTP_AUTHENTICATE_SUCCESS; +} + +void http_auth_gen_nonce() +{ + static uint32_t x = 123456789; /* XORSHIFT data */ + static uint32_t y = 362436069; /* XORSHIFT data */ + static uint32_t z = 521288629; /* XORSHIFT data */ + static uint32_t w = 88675123; /* XORSHIFT data */ + uint32_t tmp; + uint8_t i; + + for (i = 0; i < NONCE_LEN; i += 8) { + /* Compute xorshift */ + tmp = x ^ (x << 1); + x = y; + y = z; + z = w; + w = w ^ (w >> 19) ^ (tmp ^ (tmp >> 8)); + + /* Fill nonce with hex character */ + nonce_state.nonce[i] = hex_char[(w & 0xf0000000) >> 28]; + nonce_state.nonce[i + 1] = hex_char[(w & 0x0f000000) >> 24]; + nonce_state.nonce[i + 2] = hex_char[(w & 0x00f00000) >> 20]; + nonce_state.nonce[i + 3] = hex_char[(w & 0x000f0000) >> 16]; + nonce_state.nonce[i + 4] = hex_char[(w & 0x0000f000) >> 12]; + nonce_state.nonce[i + 5] = hex_char[(w & 0x00000f00) >> 8]; + nonce_state.nonce[i + 6] = hex_char[(w & 0x000000f0) >> 4]; + nonce_state.nonce[i + 7] = hex_char[(w & 0x0000000f)]; + } +} + +#endif +#endif diff --git a/core/auth.h b/core/auth.h new file mode 100644 index 0000000..9ab0947 --- /dev/null +++ b/core/auth.h @@ -0,0 +1,157 @@ +/* + * Copyright or © or Copr. 2008, Simon Duquennoy + * + * Author e-mail: simon.duquennoy@lifl.fr + * + * This software is a computer program whose purpose is to design an + * efficient Web server for very-constrained embedded system. + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. + */ + +/* + * Author: Christophe Bacara + * `-Mail: christophe.bacara@etudiant.univ-lille1.fr + */ + +#ifndef __AUTH_H__ +#define __AUTH_H__ + +#define HTTP_AUTH_BASIC 0 +#define HTTP_AUTH_DIGEST 1 + +#include "handlers.h" +#include "connections.h" +#include "types.h" + +/* Readability++ macros */ +#define IS_RESTRICTED(handler) (handler->handler_restriction.realm) + +#define HTTP_AUTHENTICATE_SUCCESS 1 +#define HTTP_AUTHENTICATE_FAILURE 0 +#define NO_OFFSET (127) /* Useful for parsing nonce/response in input.c */ + +/* Shortcut to the http 401 handler */ +#define http_401_handler apps_httpCodes_401_html_handler + +struct auth_data_s { + uint8_t scheme_parsed: 1; /* Flag set on 1 if scheme has been parsed */ + uint8_t parsing_offset: 7; /* Offset into fields while parsing */ +#if HTTP_AUTH == HTTP_AUTH_BASIC + unsigned char *credentials; /* Dynamically allocated storage for + * basic credentials: b64(user:passwd) */ +#elif HTTP_AUTH == HTTP_AUTH_DIGEST + uint8_t username_blob; /* Username identifier in blob tree */ + unsigned char response[32]; /* Response digest as given by the client */ + unsigned char nonce[32]; /* Nonce used by the client to compute digest */ +#endif +}; + +/* Http 401 handler */ +extern CONST_VAR(struct output_handler_t, apps_httpCodes_401_html_handler); + +/* Store the character string representation of the authentication scheme */ +extern CONST_VAR(unsigned char, HttpAuthenticateScheme[]); +/* Store the character string representation of the http authenticate header */ +extern CONST_VAR(char, HttpAuthenticateHeader[]); + +/* Returns the length of the 401 handler that matches the specified + * restricted handler, including the dynamically generated http header with + * correct realm and nonce (if digest auth). */ +extern uint32_t http_401_handler_length(const struct output_handler_t *restricted_handler +#if HTTP_AUTH == HTTP_AUTH_DIGEST + , const uint8_t stale +#endif + ); + +/* Returns the length of the dynamically generated http header for a 401 handler. */ +extern uint32_t http_401_handler_dynamic_header_length(const struct output_handler_t *restricted_handler +#if HTTP_AUTH == HTTP_AUTH_DIGEST + , const uint8_t stale +#endif + ); + +/*************************************************************************/ +/********************* AUTHENTICATION KIND SPECIFICS *********************/ +/*************************************************************************/ + +/*********************** BASIC AUTHENTICATION DATA ***********************/ +#if HTTP_AUTH == HTTP_AUTH_BASIC + +#define HTTP_AUTHENTICATE_HEADER_LEN 68 +#define HTTP_AUTHENTICATE_HEADER_CHK 0x428Cu + +/* Returns 1 if given credentials are valid for the requested handler, 0 if not. */ +extern char http_basic_authenticate(const struct output_handler_t *handler, + unsigned const char *credentials); + +/*********************** DIGEST AUTHENTICATION DATA **********************/ +#elif HTTP_AUTH == HTTP_AUTH_DIGEST + +#define HTTP_AUTHENTICATE_STALE -1 + +#define HTTP_AUTHENTICATE_HEADER_LEN 68 +#define HTTP_AUTHENTICATE_HEADER_CHK 0x9A92u + +extern CONST_VAR(char, HttpAuthenticateHeaderNonce[]); +extern CONST_VAR(char, HttpAuthenticateHeaderStale[]); + +#define HTTP_AUTHENTICATE_HEADER_NONCE_LEN 8 +#define HTTP_AUTHENTICATE_HEADER_NONCE_CHK 0x6E30u + +#define HTTP_AUTHENTICATE_HEADER_STALE_LEN 12 +#define HTTP_AUTHENTICATE_HEADER_STALE_CHK 0x5016u + +#define NONCE_LEN 32 + +/* Digest authentication data structure */ +typedef struct credentials_digest_s { + const uint8_t username_blob; /* Corresponding blob into users blob tree */ + const unsigned char *realm; /* Realm for which this credentials stand */ + const unsigned char user_digest[33]; /* Digest for this user & realm. */ +} credentials_digest_t; + +/* Nonce control structure */ +extern struct nonce_state_s { + struct connection *requester; /* Last connection requesting a nonce */ + unsigned char nonce[NONCE_LEN]; /* Last nonce generated */ +} nonce_state; + +/* Returns 1 if given credentials are valid for the requested handler, 0 if not. + * Returns -1 if nonce is not valid (response will contain "stale" in WWW-Auth) */ +extern char http_digest_authenticate(const struct connection *requester, + const struct output_handler_t *handler, + const struct auth_data_s *auth_data); + +/* Generate a new nonce based on a xorshift randomizer. */ +extern void http_auth_gen_nonce(); + +#endif +/**************************** END OF SPECIFICS ***************************/ + +#endif + diff --git a/core/connections.h b/core/connections.h index ef09b51..aa64bb9 100644 --- a/core/connections.h +++ b/core/connections.h @@ -1,41 +1,42 @@ /* -* Copyright or © or Copr. 2008, Simon Duquennoy -* -* Author e-mail: simon.duquennoy@lifl.fr -* -* This software is a computer program whose purpose is to design an -* efficient Web server for very-constrained embedded system. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -*/ + * Copyright or © or Copr. 2008, Simon Duquennoy + * + * Author e-mail: simon.duquennoy@lifl.fr + * + * This software is a computer program whose purpose is to design an + * efficient Web server for very-constrained embedded system. + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. + */ #ifndef __CONNECTIONS_H__ #define __CONNECTIONS_H__ +#include "auth.h" #include "handlers.h" #include "coroutines.h" @@ -54,150 +55,196 @@ #ifndef DISABLE_POST /* Boundary structure (for multipart) */ struct boundary_t { - char *boundary_ref; /* boundary which separates parts in multipart post data */ - char *boundary_buffer; /* buffer used to detect boundary */ - uint8_t boundary_size; /* size of boundary */ - uint8_t index; - uint8_t ready_to_count; /* true when post header is parsed */ - uint8_t multi_part_counter; /* to know index of part parsed */ + char *boundary_ref; /* boundary which separates parts in multipart post data */ + char *boundary_buffer; /* buffer used to detect boundary */ + uint8_t boundary_size; /* size of boundary */ + uint8_t index; + uint8_t ready_to_count; /* true when post header is parsed */ + uint8_t multi_part_counter; /* to know index of part parsed */ }; /* Post data structure */ struct post_data_t { - uint16_t content_length; - struct boundary_t *boundary; - struct coroutine_t coroutine; - char *filename; /* filename of current part */ - void *post_data; /* data flowing between dopostin and dopostout functions */ - uint8_t content_type; + uint16_t content_length; + struct boundary_t *boundary; + struct coroutine_t coroutine; + char *filename; /* filename of current part */ + void *post_data; /* data flowing between dopostin and dopostout functions */ + uint8_t content_type; }; #endif /* Possible http headers being used */ -enum service_header_e { header_none, header_standard, header_chunks }; +enum service_header_e { header_none, header_standard, header_chunks, header_authenticate }; /* Information about one in-flight segment (several per service) */ struct in_flight_infos_t { - unsigned char next_outseqno[4]; /* associated sequence number */ - unsigned char checksum[2]; /* segment checksum */ - union if_infos_e { /* either a coroutine context or a data buffer */ + unsigned char next_outseqno[4]; /* associated sequence number */ + unsigned char checksum[2]; /* segment checksum */ + union if_infos_e { /* either a coroutine context or a data buffer */ #ifndef DISABLE_COROUTINES - struct cr_context_t *context; + struct cr_context_t *context; #endif - char *buffer; - } infos; - struct in_flight_infos_t *next; /* the next in-flight segment */ - enum service_header_e service_header: 2; /* http header infos */ + char *buffer; + } infos; + struct in_flight_infos_t *next; /* the next in-flight segment */ + enum service_header_e service_header: 2; /* http header infos */ }; struct generator_service_t { - unsigned char curr_outseqno[4]; + unsigned char curr_outseqno[4]; #ifndef DISABLE_COROUTINES - struct coroutine_t coroutine; + struct coroutine_t coroutine; #endif - struct in_flight_infos_t *in_flight_infos; - enum service_header_e service_header: 2; - unsigned is_persistent: 1; + struct in_flight_infos_t *in_flight_infos; + enum service_header_e service_header: 2; + unsigned is_persistent: 1; }; /* Connection structure */ struct http_connection { - unsigned tcp_mss: 12; - unsigned ready_to_send:1; - enum tcp_state_e {tcp_listen, tcp_syn_rcvd, tcp_established, tcp_closing, tcp_last_ack} tcp_state: 3; - unsigned char next_outseqno[4]; - unsigned char final_outseqno[4]; - unsigned char current_inseqno[4]; + unsigned tcp_mss: 12; + unsigned ready_to_send:1; + enum tcp_state_e {tcp_listen, tcp_syn_rcvd, tcp_established, tcp_closing, tcp_last_ack} tcp_state: 3; + unsigned char next_outseqno[4]; + unsigned char final_outseqno[4]; + unsigned char current_inseqno[4]; - unsigned char port[2]; - unsigned char cwnd[2]; - unsigned char inflight[2]; + unsigned char port[2]; + unsigned char cwnd[2]; + unsigned char inflight[2]; - unsigned const char * /*CONST_VAR*/ blob; - struct generator_service_t *generator_service; + unsigned const char * /*CONST_VAR*/ blob; + struct generator_service_t *generator_service; #ifndef DISABLE_ARGS - struct args_t *args; - unsigned char *curr_arg; - unsigned char arg_ref_index; + struct args_t *args; + unsigned char *curr_arg; + unsigned char arg_ref_index; #endif + #ifndef DISABLE_TIMERS - unsigned char transmission_time; + unsigned char transmission_time; #endif - enum parsing_state_e {parsing_out, parsing_cmd, parsing_url, parsing_end + #ifndef DISABLE_POST - , parsing_post_attributes, parsing_post_end, parsing_post_content_type, parsing_post_args, parsing_post_data, parsing_boundary, parsing_init_buffer } parsing_state: 4; - uint8_t post_url_detected:1; /* bit used to know if url is post or get request */ - struct post_data_t *post_data; + enum parsing_state_e { + parsing_out, + parsing_cmd, + parsing_url, + parsing_end, +#if defined(HTTP_AUTH) && HTTP_AUTH == HTTP_AUTH_DIGEST + parsing_authorization_username, +#endif + parsing_post_attributes, + parsing_post_end, + parsing_post_content_type, + parsing_post_args, + parsing_post_data, + parsing_boundary, + parsing_init_buffer, + } parsing_state : 4; + + uint8_t post_url_detected : 1; + struct post_data_t *post_data; +#else +#ifdef HTTP_AUTH + enum parsing_state_e { + parsing_out, + parsing_cmd, + parsing_url, + parsing_end, +#if HTTP_AUTH == HTTP_AUTH_DIGEST + parsing_authorization_username, +#endif + parsing_post_attributes, + parsing_post_end + } parsing_state : 3; #else -} parsing_state/*: 2*/; /* this field will be on one byte anyway as previous fields are exactly 16 bits. - Using a full char does not change the struct size, but lower the code size needed to access it */ + enum parsing_state_e { + parsing_out, + parsing_cmd, + parsing_url, + parsing_end + } parsing_state : 2; #endif +#endif + +/* enum parsing_state_e {parsing_out, parsing_cmd, parsing_url, parsing_end */ +/* #ifndef DISABLE_POST */ +/* , parsing_post_attributes, parsing_post_end, parsing_post_content_type, parsing_post_args, parsing_post_data, parsing_boundary, parsing_init_buffer } parsing_state: 4; */ +/* uint8_t post_url_detected:1; /\* bit used to know if url is post or get request *\/ */ +/* struct post_data_t *post_data; */ +/* #else */ +/* } parsing_state/\*: 2*\/; /\* this field will be on one byte anyway as previous fields are exactly 16 bits. */ +/* Using a full char does not change the struct size, but lower the code size needed to access it *\/ */ +/* #endif */ + #ifndef DISABLE_COMET - unsigned char comet_passive: 1; - unsigned char comet_send_ack: 1; - unsigned char comet_streaming: 1; + unsigned char comet_passive: 1; + unsigned char comet_send_ack: 1; + unsigned char comet_streaming: 1; #endif }; #ifndef DISABLE_GP_IP_HANDLER struct gp_ip_connection { - uint16_t payload_size; - uint8_t protocol; - uint8_t want_to_send; + uint16_t payload_size; + uint8_t protocol; + uint8_t want_to_send; }; #endif /* Generic connection structure */ struct connection { #ifndef IPV6 - unsigned char ip_addr[4]; + unsigned char ip_addr[4]; #endif - const struct output_handler_t * /*CONST_VAR*/ output_handler; - union { + const struct output_handler_t * /*CONST_VAR*/ output_handler; + union { #ifndef DISABLE_GP_IP_HANDLER - struct gp_ip_connection gpip; + struct gp_ip_connection gpip; #endif - struct http_connection http; - } protocol; + struct http_connection http; + } protocol; - struct connection *next; - struct connection *prev; + struct connection *next; + struct connection *prev; #ifdef IPV6 - unsigned char ip_addr[0]; + unsigned char ip_addr[0]; #endif }; #ifndef DISABLE_GP_IP_HANDLER - #define IS_GPIP(connection) (connection && connection->output_handler && IS_GPIP_HANDLER(connection->output_handler)) - #define IS_HTTP(connection) (!IS_GPIP(connection)) +#define IS_GPIP(connection) (connection && connection->output_handler && IS_GPIP_HANDLER(connection->output_handler)) +#define IS_HTTP(connection) (!IS_GPIP(connection)) #else - #define IS_HTTP(connection) (connection) +#define IS_HTTP(connection) (connection) #endif /* Loop on each connection */ -#define FOR_EACH_CONN(item, code) \ - if(all_connections) { \ - struct connection *(item) = all_connections; \ - do { \ - {code} \ - (item) = (item)->next; \ - } while((item) != all_connections); \ - } \ +#define FOR_EACH_CONN(item, code) \ + if(all_connections) { \ + struct connection *(item) = all_connections; \ + do { \ + {code} \ + (item) = (item)->next; \ + } while((item) != all_connections); \ + } \ #define NEXT_CONN(item) (item) = (item)->next /* Pseudo connection for RST */ struct http_rst_connection { #ifdef IPV6 - unsigned char ip_addr[16]; + unsigned char ip_addr[16]; #else - unsigned char ip_addr[4]; + unsigned char ip_addr[4]; #endif - unsigned char current_inseqno[4]; - unsigned char next_outseqno[4]; - unsigned char port[2]; + unsigned char current_inseqno[4]; + unsigned char next_outseqno[4]; + unsigned char port[2]; }; /* Shared global connections structures */ @@ -208,16 +255,16 @@ extern struct http_rst_connection rst_connection; struct curr_output_t { - struct generator_service_t *service; - char *buffer; - unsigned char checksum[2]; - uint16_t content_length; - uint16_t max_bytes; - unsigned char next_outseqno[4]; - enum service_header_e service_header: 2; + struct generator_service_t *service; + char *buffer; + unsigned char checksum[2]; + uint16_t content_length; + uint16_t max_bytes; + unsigned char next_outseqno[4]; + enum service_header_e service_header: 2; #ifdef DISABLE_COROUTINES - enum dynamic_state {none, in_dynamic, sending_segment,waiting_ack, ack_received, connection_terminated} dynamic_service_state:3; - unsigned char in_handler:1; + enum dynamic_state {none, in_dynamic, sending_segment,waiting_ack, ack_received, connection_terminated} dynamic_service_state:3; + unsigned char in_handler:1; #endif }; @@ -235,11 +282,11 @@ extern unsigned char * decompress_ip(const unsigned char comp_ip_addr[], unsigne extern unsigned char * compress_ip(const unsigned char full_ip_addr[], unsigned char comp_ip_addr[], unsigned char * indexes); static inline uint8_t compressed_ip_size(const unsigned char ip[]) { - return (17-((ip[0])&15)); + return (17-((ip[0])&15)); } static inline unsigned char * copy_compressed_ip(unsigned char dst[], const unsigned char src[]) { - return memcpy(dst, src, compressed_ip_size(src)); + return memcpy(dst, src, compressed_ip_size(src)); } @@ -255,10 +302,10 @@ extern void free_connection(const struct connection *connection); /* Allocates and insert a new connection. The inserted connection will be a copy of the from parameter */ extern struct connection *add_connection(const struct connection *from #ifdef IPV6 - , uint8_t compressed_ip_size /* Used in ipv6 to allocation enough bytes to - store the compressed ip */ + , uint8_t compressed_ip_size /* Used in ipv6 to allocation enough bytes to + store the compressed ip */ #endif - ); + ); /* deallocate all the memory used by in-flight segments that are now acknowledged (with out_seqno < inack) */ extern void clean_service(struct generator_service_t *service, unsigned char inack[]); @@ -266,7 +313,7 @@ extern void clean_service(struct generator_service_t *service, unsigned char ina #ifndef DISABLE_POST /* Shared coroutine state (in = 0 / out = 1)*/ struct coroutine_state_t { - enum coroutine_state_e {cor_in, cor_out} state:1; + enum coroutine_state_e {cor_in, cor_out} state:1; }; extern struct coroutine_state_t coroutine_state; #endif diff --git a/core/handlers.h b/core/handlers.h index 91140c4..cbb466b 100644 --- a/core/handlers.h +++ b/core/handlers.h @@ -59,17 +59,17 @@ typedef char (generator_dopost_out_func_t)(uint8_t,void *); /* Generator: init and run functions */ struct dynamic_resource { - generator_init_func_t *init; - union handlers_u { - struct get_handlers { - generator_initget_func_t *initget; - generator_doget_func_t *doget; - } get; + generator_init_func_t *init; + union handlers_u { + struct get_handlers { + generator_initget_func_t *initget; + generator_doget_func_t *doget; + } get; #ifndef DISABLE_POST - struct post_handlers{ - generator_dopost_in_func_t *dopostin; - generator_dopost_out_func_t *dopostout; - } post; + struct post_handlers{ + generator_dopost_in_func_t *dopostin; + generator_dopost_out_func_t *dopostout; + } post; #endif #ifndef DISABLE_GP_IP_HANDLER struct gp_ip_handlers { @@ -136,7 +136,7 @@ struct output_handler_t { const struct dynamic_resource generator; } handler_data; #ifndef DISABLE_ARGS - struct handler_args_t { + struct handler_args_t { unsigned const char * /*CONST_VAR*/ args_tree; const struct arg_ref_t * /*CONST_VAR*/ args_index; uint16_t args_size; @@ -148,6 +148,17 @@ struct output_handler_t { uint8_t mimes_size; }handler_mimes; #endif +#ifdef HTTP_AUTH + struct handler_restriction_t { + unsigned const char *realm; /* Realm of restriction : + - no restriction if NULL */ + uint8_t credentials_offset; /* Offset to the first credential */ + uint8_t credentials_count; /* Credentials count from offset */ +#if HTTP_AUTH == HTTP_AUTH_DIGEST + unsigned const char resource_digest[33]; /* Digest of md5("METHOD:uri") */ +#endif + } handler_restriction; +#endif }; #ifndef DISABLE_GP_IP_HANDLER diff --git a/core/input.c b/core/input.c index b718c54..c1694e3 100644 --- a/core/input.c +++ b/core/input.c @@ -42,6 +42,14 @@ #include "coroutines.h" #include "blobs.h" #include "defines.h" +#include "utils.h" + +#ifdef HTTP_AUTH +#include "auth.h" +#include "md5.h" +#endif + +#include /* Used to dump the runtime stack */ #ifdef STACK_DUMP @@ -57,7 +65,7 @@ extern CONST_VAR(struct output_handler_t, apps_httpCodes_404_html_handler); #ifndef DEV_MTU #define MAX_MSS 0xffff #else -#define MAX_MSS (DEV_MTU - (IP_HEADER_SIZE+ TCP_HEADER_SIZE)) +#define MAX_MSS (DEV_MTU - (IP_HEADER_SIZE + TCP_HEADER_SIZE)) #endif /* IP and TCP constants */ @@ -73,7 +81,7 @@ extern CONST_VAR(struct output_handler_t, apps_httpCodes_404_html_handler); /* Initial sequence number */ #define BASIC_SEQNO 0x42b7a491 -#ifndef DISABLE_POST +#if !defined(DISABLE_POST) || defined(HTTP_AUTH) #define URL_POST_END 255 #define HEADER_POST_END 128 static CONST_VAR(unsigned char, blob_http_header_end[]) = {13,10,13,128}; @@ -84,97 +92,97 @@ extern CONST_VAR(struct output_handler_t, apps_httpCodes_505_html_handler); /* gets 16 bits and checks if nothing wrong appened */ static char dev_get16(unsigned char *word) { - int16_t tmp; - DEV_GET(tmp); - if(tmp == -1) - return -1; - word[1] = tmp; - DEV_GET(tmp); - if(tmp == -1) - return -1; - word[0] = tmp; - return 1; + int16_t tmp; + DEV_GET(tmp); + if(tmp == -1) + return -1; + word[1] = tmp; + DEV_GET(tmp); + if(tmp == -1) + return -1; + word[0] = tmp; + return 1; } /* gets 32 bits and checks if nothing wrong appened */ static char dev_get32(unsigned char *dword) { - if(dev_get16(&dword[2]) == -1) - return -1; - if(dev_get16(&dword[0]) == -1) - return -1; - return 1; + if(dev_get16(&dword[2]) == -1) + return -1; + if(dev_get16(&dword[0]) == -1) + return -1; + return 1; } #ifdef IPV6 /* gets 128 bits and checks if nothing wrong appened */ static char dev_get128(unsigned char *dword) { - if(dev_get32(&dword[12]) == -1) - return -1; - if(dev_get32(&dword[8]) == -1) - return -1; - if(dev_get32(&dword[4]) == -1) - return -1; - if(dev_get32(&dword[0]) == -1) - return -1; - return 1; + if(dev_get32(&dword[12]) == -1) + return -1; + if(dev_get32(&dword[8]) == -1) + return -1; + if(dev_get32(&dword[4]) == -1) + return -1; + if(dev_get32(&dword[0]) == -1) + return -1; + return 1; } /* Get 2 bytes */ -#define DEV_GET16(c) { \ - if(dev_get16((unsigned char*)(c)) == -1) \ - return 1; \ - } +#define DEV_GET16(c) { \ + if(dev_get16((unsigned char*)(c)) == -1) \ + return 1; \ + } /* Get 4 bytes */ -#define DEV_GET32(c) { \ - if(dev_get32((unsigned char*)(c)) == -1) \ - return 1; \ - } +#define DEV_GET32(c) { \ + if(dev_get32((unsigned char*)(c)) == -1) \ + return 1; \ + } /* Get 16 bytes */ -#define DEV_GET128(c) { \ - if(dev_get128((unsigned char*)(c)) == -1) \ - return 1; \ - } +#define DEV_GET128(c) { \ + if(dev_get128((unsigned char*)(c)) == -1) \ + return 1; \ + } #endif /* Get and checksum a byte */ #define DEV_GETC(c) { int16_t getc; \ - DEV_GET(getc); \ - if(getc == -1) return 1; \ - c = getc; \ - checksum_add(c);} \ + DEV_GET(getc); \ + if(getc == -1) return 1; \ + c = getc; \ + checksum_add(c);} \ /* Get and checksum 2 bytes */ -#define DEV_GETC16(c) { \ - if(dev_get16((unsigned char*)(c)) == -1) \ - return 1; \ - checksum_add16(UI16(c)); \ - } +#define DEV_GETC16(c) { \ + if(dev_get16((unsigned char*)(c)) == -1) \ + return 1; \ + checksum_add16(UI16(c)); \ + } /* Get and checksum 4 bytes */ -#define DEV_GETC32(c) { \ - if(dev_get32((unsigned char*)(c)) == -1) \ - return 1; \ - checksum_add32(c); \ - } +#define DEV_GETC32(c) { \ + if(dev_get32((unsigned char*)(c)) == -1) \ + return 1; \ + checksum_add32(c); \ + } #ifdef IPV6 /* Get and checksum 16 bytes */ -#define DEV_GETC128(c) { \ - if(dev_get128((unsigned char*)(c)) == -1) \ - return 1; \ - checksum_add32(&c[12]); \ - checksum_add32(&c[8]); \ - checksum_add32(&c[4]); \ - checksum_add32(&c[0]); \ - } +#define DEV_GETC128(c) { \ + if(dev_get128((unsigned char*)(c)) == -1) \ + return 1; \ + checksum_add32(&c[12]); \ + checksum_add32(&c[8]); \ + checksum_add32(&c[4]); \ + checksum_add32(&c[0]); \ + } #endif #ifndef DISABLE_POST struct curr_input_t { - struct connection *connection; - uint16_t length; + struct connection *connection; + uint16_t length; } curr_input; #endif @@ -183,87 +191,87 @@ struct curr_input_t { * for general purpose ip handler is very simple */ short in() { - unsigned char tmp; - DEV_GET(tmp); - return tmp; + unsigned char tmp; + DEV_GET(tmp); + return tmp; } #endif #ifndef DISABLE_POST /* called from dopostin or dopacketin */ short in(){ - unsigned char tmp; + unsigned char tmp; #ifndef DISABLE_GP_IP_HANDLER - /* If post AND general purpose ip, then check if the connection is null - * if so, it is called from packetin */ - if (curr_input.connection == NULL) + /* If post AND general purpose ip, then check if the connection is null + * if so, it is called from packetin */ + if (curr_input.connection == NULL) { - DEV_GET(tmp); - return tmp; + DEV_GET(tmp); + return tmp; } #endif - if(coroutine_state.state == cor_out) - return -1; - if(!curr_input.connection->protocol.http.post_data->content_length) - return -1; - if(curr_input.connection->protocol.http.post_data->boundary && (curr_input.connection->protocol.http.post_data->boundary->index == (uint8_t)-1)) /* index = -1 => boundary found */ - return -1; - if(!curr_input.length) - cr_run(NULL,cor_type_get); /* input buffer is empty, changing context */ - if(curr_input.connection->protocol.http.post_data->boundary){ - /* getting next value in input buffer */ - tmp = curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[curr_input.connection->protocol.http.post_data->boundary->index]; - DEV_GETC(curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[curr_input.connection->protocol.http.post_data->boundary->index]); - curr_input.connection->protocol.http.post_data->boundary->index++; - /* searching boundary */ - if(curr_input.connection->protocol.http.post_data->boundary->index == curr_input.connection->protocol.http.post_data->boundary->boundary_size) - curr_input.connection->protocol.http.post_data->boundary->index = 0; - /* comparing first and last characters of buffer with boundary, then all characters */ - if(curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[(unsigned char)(curr_input.connection->protocol.http.post_data->boundary->index - 1) % curr_input.connection->protocol.http.post_data->boundary->boundary_size] - == curr_input.connection->protocol.http.post_data->boundary->boundary_ref[curr_input.connection->protocol.http.post_data->boundary->boundary_size-1] - && curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[curr_input.connection->protocol.http.post_data->boundary->index] - == curr_input.connection->protocol.http.post_data->boundary->boundary_ref[0]){ - unsigned char index = curr_input.connection->protocol.http.post_data->boundary->index + 1; - unsigned char i; - for(i = 1 ; i < curr_input.connection->protocol.http.post_data->boundary->boundary_size-1 ; i++){ - if(index == curr_input.connection->protocol.http.post_data->boundary->boundary_size) - index = 0; - if(curr_input.connection->protocol.http.post_data->boundary->boundary_ref[i] != curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[index]) - break; - index++; - } - if(i == curr_input.connection->protocol.http.post_data->boundary->boundary_size-1) - curr_input.connection->protocol.http.post_data->boundary->index = -1; - } + if(coroutine_state.state == cor_out) + return -1; + if(!curr_input.connection->protocol.http.post_data->content_length) + return -1; + if(curr_input.connection->protocol.http.post_data->boundary && (curr_input.connection->protocol.http.post_data->boundary->index == (uint8_t)-1)) /* index = -1 => boundary found */ + return -1; + if(!curr_input.length) + cr_run(NULL,cor_type_get); /* input buffer is empty, changing context */ + if(curr_input.connection->protocol.http.post_data->boundary){ + /* getting next value in input buffer */ + tmp = curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[curr_input.connection->protocol.http.post_data->boundary->index]; + DEV_GETC(curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[curr_input.connection->protocol.http.post_data->boundary->index]); + curr_input.connection->protocol.http.post_data->boundary->index++; + /* searching boundary */ + if(curr_input.connection->protocol.http.post_data->boundary->index == curr_input.connection->protocol.http.post_data->boundary->boundary_size) + curr_input.connection->protocol.http.post_data->boundary->index = 0; + /* comparing first and last characters of buffer with boundary, then all characters */ + if(curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[(unsigned char)(curr_input.connection->protocol.http.post_data->boundary->index - 1) % curr_input.connection->protocol.http.post_data->boundary->boundary_size] + == curr_input.connection->protocol.http.post_data->boundary->boundary_ref[curr_input.connection->protocol.http.post_data->boundary->boundary_size-1] + && curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[curr_input.connection->protocol.http.post_data->boundary->index] + == curr_input.connection->protocol.http.post_data->boundary->boundary_ref[0]){ + unsigned char index = curr_input.connection->protocol.http.post_data->boundary->index + 1; + unsigned char i; + for(i = 1 ; i < curr_input.connection->protocol.http.post_data->boundary->boundary_size-1 ; i++){ + if(index == curr_input.connection->protocol.http.post_data->boundary->boundary_size) + index = 0; + if(curr_input.connection->protocol.http.post_data->boundary->boundary_ref[i] != curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[index]) + break; + index++; + } + if(i == curr_input.connection->protocol.http.post_data->boundary->boundary_size-1) + curr_input.connection->protocol.http.post_data->boundary->index = -1; } - else - DEV_GETC(tmp); - /* updating counters */ - if(curr_input.connection->protocol.http.post_data->content_length != (uint16_t)-1) - curr_input.connection->protocol.http.post_data->content_length--; - curr_input.length--; - return tmp; + } + else + DEV_GETC(tmp); + /* updating counters */ + if(curr_input.connection->protocol.http.post_data->content_length != (uint16_t)-1) + curr_input.connection->protocol.http.post_data->content_length--; + curr_input.length--; + return tmp; } #endif #ifndef DISABLE_GP_IP_HANDLER const struct output_handler_t *smews_gpip_get_output_handler(uint8_t protocol) { - /* Try to find a handler that match the protocol number */ - uint8_t i; - for (i = 0 ; ; ++i) - { - struct output_handler_t *handler = (struct output_handler_t*)CONST_ADDR(resources_index[i]); - if (handler == NULL) - return NULL; - if (!IS_GPIP_HANDLER(handler)) - continue; - if (CONST_UI8(handler->handler_data.generator.handlers.gp_ip.protocol) == protocol) /* found one */ - return handler; - } + /* Try to find a handler that match the protocol number */ + uint8_t i; + for (i = 0 ; ; ++i) + { + struct output_handler_t *handler = (struct output_handler_t*)CONST_ADDR(resources_index[i]); + if (handler == NULL) return NULL; + if (!IS_GPIP_HANDLER(handler)) + continue; + if (CONST_UI8(handler->handler_data.generator.handlers.gp_ip.protocol) == protocol) /* found one */ + return handler; + } + return NULL; } /*static struct connection *smews_gpip_get_connection(uint8_t protocol, unsigned char *source_ip) @@ -284,1170 +292,1620 @@ const struct output_handler_t *smews_gpip_get_output_handler(uint8_t protocol) /*-----------------------------------------------------------------------------------*/ char smews_receive(void) { - /* local variables */ - unsigned char current_inseqno[4]; - unsigned char current_inack[4]; - unsigned char tmp_ui32[4]; - unsigned char tmp_ui16[2]; - uint16_t packet_length; - unsigned char tcp_header_length; - uint16_t segment_length; - struct connection *connection; - unsigned char tmp_char; - uint16_t x; - unsigned char new_tcp_data; + /* local variables */ + unsigned char current_inseqno[4]; + unsigned char current_inack[4]; + unsigned char tmp_ui32[4]; + unsigned char tmp_ui16[2]; + uint16_t packet_length; + unsigned char tcp_header_length; + uint16_t segment_length; + struct connection *connection; + unsigned char tmp_blob; + unsigned char tmp_char; + uint16_t x; + unsigned char new_tcp_data; + +#ifdef HTTP_AUTH + /* (bacara): Temporary solution, this will need to be stored into a + * connection struct later */ + struct auth_data_s auth_data = { + .scheme_parsed = 0, + .parsing_offset = NO_OFFSET, +#if HTTP_AUTH == HTTP_AUTH_BASIC + .credentials = NULL, +#elif HTTP_AUTH == HTTP_AUTH_DIGEST + .username_blob = 0, + .response = { 0 }, + .nonce = { 0 }, +#endif + }; +#endif + #ifndef DISABLE_GP_IP_HANDLER - uint8_t protocol; + uint8_t protocol; #endif #ifdef IPV6 - /* Full and compressed IPv6 adress of the received packet */ - unsigned char full_ipv6_addr[16]; - unsigned char comp_ipv6_addr[17]; /* 16 bytes (addr) + 1 byte (compression indexes) = 17 bytes */ + /* Full and compressed IPv6 adress of the received packet */ + unsigned char full_ipv6_addr[16]; + unsigned char comp_ipv6_addr[17]; /* 16 bytes (addr) + 1 byte (compression indexes) = 17 bytes */ #endif - /* variables used to defer processing with side effects until the incomming packet has been checked (with checksum) */ - unsigned char defer_clean_service = 0; - unsigned char defer_free_handler = 0; + /* variables used to defer processing with side effects until the incomming packet has been checked (with checksum) */ + unsigned char defer_clean_service = 0; + unsigned char defer_free_handler = 0; #ifndef DISABLE_ARGS - struct args_t *defer_free_args; - uint16_t defer_free_args_size; + struct args_t *defer_free_args; + uint16_t defer_free_args_size; #endif - /* tmp connection used to store the current state until checksums are checked */ - struct connection tmp_connection; + /* tmp connection used to store the current state until checksums are checked */ + struct connection tmp_connection; - if(!DEV_DATA_TO_READ) - return 0; + if(!DEV_DATA_TO_READ) + return 0; + + printf("##### SMEWS IS RECEIVING A PACKET #####\n"); #ifdef IPV6 - /* Get IP Version (and 4 bits of the traffic class) */ - DEV_GET(tmp_char); + /* Get IP Version (and 4 bits of the traffic class) */ + DEV_GET(tmp_char); #else - checksum_init(); + checksum_init(); - /* get IP version & header length */ - DEV_GETC(tmp_char); + /* get IP version & header length */ + DEV_GETC(tmp_char); #endif #ifdef SMEWS_RECEIVING - SMEWS_RECEIVING; + SMEWS_RECEIVING; #endif - /* Starting to decode IP */ + /* Starting to decode IP */ #ifdef IPV6 - /* 0x06 : IPV6, 4 bits right because we don't care (yet?) - about the Traffic Class */ - if(tmp_char>>4 != 0x6) + /* 0x06 : IPV6, 4 bits right because we don't care (yet?) + about the Traffic Class */ + if(tmp_char>>4 != 0x6) #else - /* 0x45 : IPv4, no option in header */ - if(tmp_char != 0x45) + /* 0x45 : IPv4, no option in header */ + if(tmp_char != 0x45) #endif - return 1; + return 1; #ifdef IPV6 - /* Discard the rest of the traffic class and the Flow Label (still unused) */ - DEV_GET(tmp_char); - DEV_GET16(tmp_ui16); + /* Discard the rest of the traffic class and the Flow Label (still unused) */ + DEV_GET(tmp_char); + DEV_GET16(tmp_ui16); - /* Get IP packet payload length in len */ - DEV_GET16(((uint16_t *)&packet_length)); + /* Get IP packet payload length in len */ + DEV_GET16(((uint16_t *)&packet_length)); - DEV_GET(tmp_char); - /* What's the next header? */ + DEV_GET(tmp_char); + /* What's the next header? */ #ifndef DISABLE_GP_IP_HANDLER - protocol = tmp_char; + protocol = tmp_char; #else - if (tmp_char != IP_PROTO_TCP) /* If not TCP and general purpose IP is disabled, drop packet */ - return 1; + if (tmp_char != IP_PROTO_TCP) /* If not TCP and general purpose IP is disabled, drop packet */ + return 1; #endif - /* We don't care about the Hop Limit (TTL) */ - DEV_GET(tmp_char); + /* We don't care about the Hop Limit (TTL) */ + DEV_GET(tmp_char); - /* get & store IP source address */ - DEV_GET128(&full_ipv6_addr[0]); + /* get & store IP source address */ + DEV_GET128(&full_ipv6_addr[0]); - /* Compress the received IPv6 adress - compress_ip(FullIPv6, IP's Offset, Indexe's offset) */ - compress_ip(full_ipv6_addr, comp_ipv6_addr+1, &comp_ipv6_addr[0]); - /* discard the dest IP */ - DEV_GET32(tmp_ui32); - DEV_GET32(tmp_ui32); - DEV_GET32(tmp_ui32); - DEV_GET32(tmp_ui32); + /* Compress the received IPv6 adress + compress_ip(FullIPv6, IP's Offset, Indexe's offset) */ + compress_ip(full_ipv6_addr, comp_ipv6_addr+1, &comp_ipv6_addr[0]); + /* discard the dest IP */ + DEV_GET32(tmp_ui32); + DEV_GET32(tmp_ui32); + DEV_GET32(tmp_ui32); + DEV_GET32(tmp_ui32); #else - /* discard IP type of service */ - DEV_GETC(tmp_char); + /* discard IP type of service */ + DEV_GETC(tmp_char); - /* get IP packet length in len */ - DEV_GETC16(((uint16_t *)&packet_length)); - /* The packet_length is the size of the IP payload, without the IP header size. - * This make the value homegeneous for IPv4 and IPv6 and simplifies code for TCP segment length calculation (no more #ifndef hacks) */ - packet_length = packet_length - IP_HEADER_SIZE; + /* get IP packet length in len */ + DEV_GETC16(((uint16_t *)&packet_length)); + /* The packet_length is the size of the IP payload, without the IP header size. + * This make the value homegeneous for IPv4 and IPv6 and simplifies code for TCP segment length calculation (no more #ifndef hacks) */ + packet_length = packet_length - IP_HEADER_SIZE; - /* discard IP ID */ - DEV_GETC16(tmp_ui16); + /* discard IP ID */ + DEV_GETC16(tmp_ui16); - /* get IP fragmentation flags (fragmentation is not supported) */ - DEV_GETC16(tmp_ui16); - if((tmp_ui16[S0] & 0x20) || (tmp_ui16[S0] & 0x1f) != 0) - return 1; + /* get IP fragmentation flags (fragmentation is not supported) */ + DEV_GETC16(tmp_ui16); + if((tmp_ui16[S0] & 0x20) || (tmp_ui16[S0] & 0x1f) != 0) + return 1; - /* get IP fragmentation offset */ - if(tmp_ui16[S1] != 0) - return 1; + /* get IP fragmentation offset */ + if(tmp_ui16[S1] != 0) + return 1; - /* discard IP TTL */ - DEV_GETC16(tmp_ui16); + /* discard IP TTL */ + DEV_GETC16(tmp_ui16); #ifndef DISABLE_GP_IP_HANDLER - protocol = tmp_ui16[S1]; + protocol = tmp_ui16[S1]; #else - if(tmp_ui16[S1] != IP_PROTO_TCP) /* If not TCP and general purpose IP is disabled, drop packet */ - return 1; + if(tmp_ui16[S1] != IP_PROTO_TCP) /* If not TCP and general purpose IP is disabled, drop packet */ + return 1; #endif - /* discard IP checksum */ - DEV_GETC16(tmp_ui16); + /* discard IP checksum */ + DEV_GETC16(tmp_ui16); - /* get & store IP source address */ - DEV_GETC32(tmp_connection.ip_addr); + /* get & store IP source address */ + DEV_GETC32(tmp_connection.ip_addr); - /* discard the IP destination address 2*16*/ - DEV_GETC32(tmp_ui32); + /* discard the IP destination address 2*16*/ + DEV_GETC32(tmp_ui32); - /* check IP checksum */ - checksum_end(); + /* check IP checksum */ + checksum_end(); - if(UI16(current_checksum) != 0xffff) - return 1; + if(UI16(current_checksum) != 0xffff) + return 1; #endif #ifndef DISABLE_GP_IP_HANDLER - if (protocol != IP_PROTO_TCP) + if (protocol != IP_PROTO_TCP) { - /* Finaly, the decision has been made to create a new connection for each packet and to - * free it after having called the output handler. - * Previous code left in comments if we change our mind later */ - connection = NULL; /* smews_gpip_get_connection(protocol, NULL);*/ + /* Finaly, the decision has been made to create a new connection for each packet and to + * free it after having called the output handler. + * Previous code left in comments if we change our mind later */ + connection = NULL; /* smews_gpip_get_connection(protocol, NULL);*/ - if (connection == NULL) /* no connection found, create one */ + if (connection == NULL) /* no connection found, create one */ { - tmp_connection.output_handler = smews_gpip_get_output_handler(protocol); - if (tmp_connection.output_handler == NULL) - return 1; - tmp_connection.protocol.gpip.protocol = protocol; - /* add the connection */ - connection = add_connection(&tmp_connection + tmp_connection.output_handler = smews_gpip_get_output_handler(protocol); + if (tmp_connection.output_handler == NULL) + return 1; + tmp_connection.protocol.gpip.protocol = protocol; + /* add the connection */ + connection = add_connection(&tmp_connection #ifdef IPV6 - , compressed_ip_size(comp_ipv6_addr) + , compressed_ip_size(comp_ipv6_addr) #endif - ); - if (connection == NULL) - return 1; + ); + if (connection == NULL) + return 1; } - /* update the connection */ + /* update the connection */ #ifdef IPV6 - copy_compressed_ip(connection->ip_addr, comp_ipv6_addr); + copy_compressed_ip(connection->ip_addr, comp_ipv6_addr); #else - memcpy(connection->ip_addr, tmp_connection.ip_addr, sizeof(tmp_connection.ip_addr)); + memcpy(connection->ip_addr, tmp_connection.ip_addr, sizeof(tmp_connection.ip_addr)); #endif #ifndef DISABLE_POST /* if post is available, must set the curr_input connection to null so that the in function knows that we are in dopacketin */ - curr_input.connection = NULL; -#endif - connection->protocol.gpip.payload_size = packet_length; - //connection->protocol.gpip.want_to_send = connection->output_handler->handler_data.generator.handlers.gp_ip.dopacketin(connection); - generator_dopacket_in_func_t *callback = CONST_ADDR(connection->output_handler->handler_data.generator.handlers.gp_ip.dopacketin); - connection->protocol.gpip.want_to_send = callback(connection); - if (!connection->protocol.gpip.want_to_send) - free_connection(connection); - return 1; + curr_input.connection = NULL; +#endif + connection->protocol.gpip.payload_size = packet_length; + //connection->protocol.gpip.want_to_send = connection->output_handler->handler_data.generator.handlers.gp_ip.dopacketin(connection); + generator_dopacket_in_func_t *callback = CONST_ADDR(connection->output_handler->handler_data.generator.handlers.gp_ip.dopacketin); + connection->protocol.gpip.want_to_send = callback(connection); + if (!connection->protocol.gpip.want_to_send) + free_connection(connection); + return 1; } #endif - /* End of IP, starting TCP */ - checksum_init(); + /* End of IP, starting TCP */ + checksum_init(); - /* get TCP source port */ - DEV_GETC16(tmp_connection.protocol.http.port); + /* get TCP source port */ + DEV_GETC16(tmp_connection.protocol.http.port); - /* current connection selection */ - connection = NULL; - /* search an existing TCP connection using the current port */ + /* current connection selection */ + connection = NULL; + /* search an existing TCP connection using the current port */ - FOR_EACH_CONN(conn, { - /* Only search http connection */ - if (!IS_HTTP(conn)) - { - NEXT_CONN(conn); - continue; - } - if(UI16(conn->protocol.http.port) == UI16(tmp_connection.protocol.http.port) && + FOR_EACH_CONN(conn, { + /* Only search http connection */ + if (!IS_HTTP(conn)) + { + NEXT_CONN(conn); + continue; + } + if(UI16(conn->protocol.http.port) == UI16(tmp_connection.protocol.http.port) && #ifdef IPV6 - ipcmp(conn->ip_addr, comp_ipv6_addr)) { + ipcmp(conn->ip_addr, comp_ipv6_addr)) { #else - UI32(conn->ip_addr) == UI32(tmp_connection.ip_addr)) { -#endif - /* connection already existing */ - connection = conn; - break; - } - }) - - if(connection) { - /* a connection has been found */ - tmp_connection = *connection; - } else { - tmp_connection.protocol.http.tcp_state = tcp_listen; - tmp_connection.output_handler = NULL; - UI32(tmp_connection.protocol.http.next_outseqno) = BASIC_SEQNO; - UI32(tmp_connection.protocol.http.current_inseqno) = 0; - tmp_connection.protocol.http.parsing_state = parsing_out; - UI16(tmp_connection.protocol.http.inflight) = 0; - tmp_connection.protocol.http.generator_service = NULL; - tmp_connection.protocol.http.ready_to_send = 1; + UI32(conn->ip_addr) == UI32(tmp_connection.ip_addr)) { +#endif + /* connection already existing */ + connection = conn; + break; + } + }) + + if(connection) { + /* a connection has been found */ + tmp_connection = *connection; + } else { + tmp_connection.protocol.http.tcp_state = tcp_listen; + tmp_connection.output_handler = NULL; + UI32(tmp_connection.protocol.http.next_outseqno) = BASIC_SEQNO; + UI32(tmp_connection.protocol.http.current_inseqno) = 0; + tmp_connection.protocol.http.parsing_state = parsing_out; + UI16(tmp_connection.protocol.http.inflight) = 0; + tmp_connection.protocol.http.generator_service = NULL; + tmp_connection.protocol.http.ready_to_send = 1; #ifndef DISABLE_COMET - tmp_connection.protocol.http.comet_send_ack = 0; - tmp_connection.protocol.http.comet_passive = 0; + tmp_connection.protocol.http.comet_send_ack = 0; + tmp_connection.protocol.http.comet_passive = 0; #endif #ifndef DISABLE_TIMERS - tmp_connection.protocol.http.transmission_time = last_transmission_time; + tmp_connection.protocol.http.transmission_time = last_transmission_time; #endif #ifndef DISABLE_POST - tmp_connection.protocol.http.post_data = NULL; - tmp_connection.protocol.http.post_url_detected = 0; + tmp_connection.protocol.http.post_data = NULL; + tmp_connection.protocol.http.post_url_detected = 0; #endif - } + } - /* get and check the destination port */ + /* get and check the destination port */ - DEV_GETC16(tmp_ui16); - if(tmp_ui16[S1] != HTTP_PORT) { + DEV_GETC16(tmp_ui16); + if(tmp_ui16[S1] != HTTP_PORT) { #ifdef STACK_DUMP - DEV_PREPARE_OUTPUT(STACK_DUMP_SIZE); - for(stack_i = 0; stack_i < STACK_DUMP_SIZE ; stack_i++) { - DEV_PUT(stack_base[-stack_i]); - } - DEV_OUTPUT_DONE; -#endif - return 1; + DEV_PREPARE_OUTPUT(STACK_DUMP_SIZE); + for(stack_i = 0; stack_i < STACK_DUMP_SIZE ; stack_i++) { + DEV_PUT(stack_base[-stack_i]); } + DEV_OUTPUT_DONE; +#endif + return 1; + } - /* get TCP sequence number */ - DEV_GETC32(current_inseqno); + /* get TCP sequence number */ + DEV_GETC32(current_inseqno); - /* get TCP ack */ - DEV_GETC32(current_inack); + /* get TCP ack */ + DEV_GETC32(current_inack); - /* duplicate ACK: set nextoutseqno for retransmission */ - if(UI32(tmp_connection.protocol.http.next_outseqno) - UI16(tmp_connection.protocol.http.inflight) == UI32(current_inack)) { - UI32(tmp_connection.protocol.http.next_outseqno) = UI32(current_inack); - } + /* duplicate ACK: set nextoutseqno for retransmission */ + if(UI32(tmp_connection.protocol.http.next_outseqno) - UI16(tmp_connection.protocol.http.inflight) == UI32(current_inack)) { + UI32(tmp_connection.protocol.http.next_outseqno) = UI32(current_inack); + } - /* TCP ack management */ - if(UI32(current_inack) && UI32(current_inack) <= UI32(tmp_connection.protocol.http.next_outseqno)) { - UI16(tmp_connection.protocol.http.inflight) = UI32(tmp_connection.protocol.http.next_outseqno) - UI32(current_inack); - if(tmp_connection.protocol.http.generator_service) { - /* deferred because current segment has not yet been checked */ - defer_clean_service = 1; - } + /* TCP ack management */ + if(UI32(current_inack) && UI32(current_inack) <= UI32(tmp_connection.protocol.http.next_outseqno)) { + UI16(tmp_connection.protocol.http.inflight) = UI32(tmp_connection.protocol.http.next_outseqno) - UI32(current_inack); + if(tmp_connection.protocol.http.generator_service) { + /* deferred because current segment has not yet been checked */ + defer_clean_service = 1; } - /* clear output_handler if needed */ - if(tmp_connection.output_handler && UI16(tmp_connection.protocol.http.inflight) == 0 && !something_to_send(&tmp_connection)) { - if(tmp_connection.protocol.http.generator_service) { - /* deferred because current segment has not yet been checked */ - defer_free_handler = 1; + } + /* clear output_handler if needed */ + if(tmp_connection.output_handler && UI16(tmp_connection.protocol.http.inflight) == 0 && !something_to_send(&tmp_connection)) { + if(tmp_connection.protocol.http.generator_service) { + /* deferred because current segment has not yet been checked */ + defer_free_handler = 1; #ifndef DISABLE_ARGS - defer_free_args = tmp_connection.protocol.http.args; - defer_free_args_size = CONST_UI16(tmp_connection.output_handler->handler_args.args_size); + defer_free_args = tmp_connection.protocol.http.args; + defer_free_args_size = CONST_UI16(tmp_connection.output_handler->handler_args.args_size); #endif - } + } #ifndef DISABLE_COMET - if(/*tmp_connection.protocol.http.parsing_state == parsing_out &&*/ tmp_connection.protocol.http.comet_streaming == 0) { - tmp_connection.output_handler = NULL; - } -#endif + if(/*tmp_connection.protocol.http.parsing_state == parsing_out &&*/ tmp_connection.protocol.http.comet_streaming == 0) { + tmp_connection.output_handler = NULL; } +#endif + } - /* get TCP offset and flags */ - DEV_GETC16(tmp_ui16); - tcp_header_length = (tmp_ui16[S0] >> 4) * 4; - - /* TCP segment length calculation */ - - /* packet_length is the length of the IP payload *without* IP headers */ - segment_length = packet_length - tcp_header_length; - - if(packet_length - tcp_header_length > 0) - UI32(current_inseqno) += segment_length; - - new_tcp_data = UI32(current_inseqno) > UI32(tmp_connection.protocol.http.current_inseqno); - - if(UI32(current_inseqno) >= UI32(tmp_connection.protocol.http.current_inseqno)) { - UI32(tmp_connection.protocol.http.current_inseqno) = UI32(current_inseqno); - /* TCP state machine management */ - switch(tmp_connection.protocol.http.tcp_state) { - case tcp_established: - if(tmp_ui16[S1] & TCP_FIN) { - tmp_connection.protocol.http.tcp_state = tcp_last_ack; - tmp_connection.output_handler = &ref_finack; - UI32(tmp_connection.protocol.http.current_inseqno)++; - } else if(tmp_ui16[S1] & TCP_RST) { - tmp_connection.protocol.http.tcp_state = tcp_listen; - } - break; - case tcp_listen: - if(tmp_ui16[S1] & TCP_SYN) { - tmp_connection.protocol.http.tcp_state = tcp_syn_rcvd; - tmp_connection.output_handler = &ref_synack; - UI32(tmp_connection.protocol.http.current_inseqno)++; - } - break; - case tcp_syn_rcvd: - if(UI16(tmp_connection.protocol.http.inflight) == 0) { - tmp_connection.protocol.http.tcp_state = tcp_established; - } else { - tmp_connection.output_handler = &ref_synack; - } - break; - case tcp_last_ack: - tmp_connection.protocol.http.tcp_state = tcp_listen; - break; - default: - break; - } + /* get TCP offset and flags */ + DEV_GETC16(tmp_ui16); + tcp_header_length = (tmp_ui16[S0] >> 4) * 4; + + /* TCP segment length calculation */ + + /* packet_length is the length of the IP payload *without* IP headers */ + segment_length = packet_length - tcp_header_length; + + if(packet_length - tcp_header_length > 0) + UI32(current_inseqno) += segment_length; + + new_tcp_data = UI32(current_inseqno) > UI32(tmp_connection.protocol.http.current_inseqno); + + if(UI32(current_inseqno) >= UI32(tmp_connection.protocol.http.current_inseqno)) { + UI32(tmp_connection.protocol.http.current_inseqno) = UI32(current_inseqno); + /* TCP state machine management */ + switch(tmp_connection.protocol.http.tcp_state) { + case tcp_established: + if(tmp_ui16[S1] & TCP_FIN) { + tmp_connection.protocol.http.tcp_state = tcp_last_ack; + tmp_connection.output_handler = &ref_finack; + UI32(tmp_connection.protocol.http.current_inseqno)++; + } else if(tmp_ui16[S1] & TCP_RST) { + tmp_connection.protocol.http.tcp_state = tcp_listen; + } + break; + case tcp_listen: + if(tmp_ui16[S1] & TCP_SYN) { + tmp_connection.protocol.http.tcp_state = tcp_syn_rcvd; + tmp_connection.output_handler = &ref_synack; + UI32(tmp_connection.protocol.http.current_inseqno)++; + } + break; + case tcp_syn_rcvd: + if(UI16(tmp_connection.protocol.http.inflight) == 0) { + tmp_connection.protocol.http.tcp_state = tcp_established; + } else { + tmp_connection.output_handler = &ref_synack; + } + break; + case tcp_last_ack: + tmp_connection.protocol.http.tcp_state = tcp_listen; + break; + default: + break; } + } - /* get the advertissed TCP window in order to limit our sending rate if needed */ - DEV_GETC16(tmp_connection.protocol.http.cwnd); + /* get the advertissed TCP window in order to limit our sending rate if needed */ + DEV_GETC16(tmp_connection.protocol.http.cwnd); - /* discard the checksum (which is checksummed as other data) and the urgent pointer */ - DEV_GETC32(tmp_ui32); + /* discard the checksum (which is checksummed as other data) and the urgent pointer */ + DEV_GETC32(tmp_ui32); - /* add the changing part of the TCP pseudo header checksum */ + /* add the changing part of the TCP pseudo header checksum */ #ifdef IPV6 - checksum_add32(&local_ip_addr[0]); - checksum_add32(&local_ip_addr[4]); - checksum_add32(&local_ip_addr[8]); - checksum_add32(&local_ip_addr[12]); - - checksum_add32(&full_ipv6_addr[0]); - checksum_add32(&full_ipv6_addr[4]); - checksum_add32(&full_ipv6_addr[8]); - checksum_add32(&full_ipv6_addr[12]); + checksum_add32(&local_ip_addr[0]); + checksum_add32(&local_ip_addr[4]); + checksum_add32(&local_ip_addr[8]); + checksum_add32(&local_ip_addr[12]); + + checksum_add32(&full_ipv6_addr[0]); + checksum_add32(&full_ipv6_addr[4]); + checksum_add32(&full_ipv6_addr[8]); + checksum_add32(&full_ipv6_addr[12]); #else - checksum_add32(local_ip_addr); - checksum_add32(tmp_connection.ip_addr); + checksum_add32(local_ip_addr); + checksum_add32(tmp_connection.ip_addr); #endif - checksum_add16(packet_length); + checksum_add16(packet_length); - /* get TCP mss (for initial negociation) */ - tcp_header_length -= TCP_HEADER_SIZE; - if(tcp_header_length >= 4) { - tcp_header_length -= 4; - DEV_GETC16(tmp_ui16); - DEV_GETC16(tmp_ui16); - tmp_connection.protocol.http.tcp_mss = UI16(tmp_ui16) > MAX_MSS ? MAX_MSS : UI16(tmp_ui16); - } + /* get TCP mss (for initial negociation) */ + tcp_header_length -= TCP_HEADER_SIZE; + if(tcp_header_length >= 4) { + tcp_header_length -= 4; + DEV_GETC16(tmp_ui16); + DEV_GETC16(tmp_ui16); + tmp_connection.protocol.http.tcp_mss = UI16(tmp_ui16) > MAX_MSS ? MAX_MSS : UI16(tmp_ui16); + } - /* discard the remaining part of the TCP header */ - for(; tcp_header_length > 0; tcp_header_length-=4) { - DEV_GETC32(tmp_ui32); - } + /* discard the remaining part of the TCP header */ + for(; tcp_header_length > 0; tcp_header_length-=4) { + DEV_GETC32(tmp_ui32); + } - /* End of TCP, starting HTTP */ - x = 0; - if(segment_length && tmp_connection.protocol.http.tcp_state == tcp_established && (new_tcp_data || tmp_connection.output_handler == NULL)) { - const struct output_handler_t * /*CONST_VAR*/ output_handler = NULL; + /* End of TCP, starting HTTP */ + x = 0; + if(segment_length && tmp_connection.protocol.http.tcp_state == tcp_established && (new_tcp_data || tmp_connection.output_handler == NULL)) { + const struct output_handler_t * /*CONST_VAR*/ output_handler = NULL; - /* parse the eventual GET request */ - unsigned const char * /*CONST_VAR*/ blob; - unsigned char blob_curr; + /* parse the eventual GET request */ + unsigned const char * /*CONST_VAR*/ blob; + unsigned char blob_curr; #ifndef DISABLE_ARGS - struct arg_ref_t tmp_arg_ref = {0,0,0}; - uint16_t tmp_args_size_ref; + struct arg_ref_t tmp_arg_ref = {0,0,0}; + uint16_t tmp_args_size_ref; #endif - if(tmp_connection.protocol.http.parsing_state == parsing_out) { + if(tmp_connection.protocol.http.parsing_state == parsing_out) { #ifndef DISABLE_ARGS - tmp_connection.protocol.http.args = NULL; - tmp_connection.protocol.http.arg_ref_index = 128; + tmp_connection.protocol.http.args = NULL; + tmp_connection.protocol.http.arg_ref_index = 128; #endif - tmp_connection.protocol.http.blob = blob_http_rqt; - tmp_connection.protocol.http.parsing_state = parsing_cmd; - tmp_connection.protocol.http.ready_to_send = 1; - tmp_connection.output_handler = NULL; + tmp_connection.protocol.http.blob = blob_http_rqt; + tmp_connection.protocol.http.parsing_state = parsing_cmd; + tmp_connection.protocol.http.ready_to_send = 1; + tmp_connection.output_handler = NULL; #ifndef DISABLE_POST - tmp_connection.protocol.http.post_data = NULL; - tmp_connection.protocol.http.post_url_detected = 0; + tmp_connection.protocol.http.post_data = NULL; + tmp_connection.protocol.http.post_url_detected = 0; #endif - } - else if(tmp_connection.output_handler) - output_handler = tmp_connection.output_handler; - blob = tmp_connection.protocol.http.blob; + } + else if(tmp_connection.output_handler) + output_handler = tmp_connection.output_handler; + blob = tmp_connection.protocol.http.blob; #ifndef DISABLE_ARGS - if(tmp_connection.protocol.http.arg_ref_index != 128) { - struct arg_ref_t * /*CONST_VAR*/ tmp_arg_ref_ptr; - tmp_arg_ref_ptr = &(((struct arg_ref_t*)CONST_ADDR(output_handler->handler_args.args_index))[tmp_connection.protocol.http.arg_ref_index]); - tmp_arg_ref.arg_type = CONST_UI8(tmp_arg_ref_ptr->arg_type); - tmp_arg_ref.arg_size = CONST_UI8(tmp_arg_ref_ptr->arg_size); - tmp_arg_ref.arg_offset = CONST_UI8(tmp_arg_ref_ptr->arg_offset); - tmp_args_size_ref = CONST_UI16(output_handler->handler_args.args_size); - } -#endif - while(x < segment_length && output_handler != &http_404_handler -#ifndef DISABLE_POST - && output_handler != &http_505_handler + if(tmp_connection.protocol.http.arg_ref_index != 128) { + struct arg_ref_t * /*CONST_VAR*/ tmp_arg_ref_ptr; + tmp_arg_ref_ptr = &(((struct arg_ref_t*)CONST_ADDR(output_handler->handler_args.args_index))[tmp_connection.protocol.http.arg_ref_index]); + tmp_arg_ref.arg_type = CONST_UI8(tmp_arg_ref_ptr->arg_type); + tmp_arg_ref.arg_size = CONST_UI8(tmp_arg_ref_ptr->arg_size); + tmp_arg_ref.arg_offset = CONST_UI8(tmp_arg_ref_ptr->arg_offset); + tmp_args_size_ref = CONST_UI16(output_handler->handler_args.args_size); + } +#endif + while(x < segment_length + && output_handler != &http_404_handler +#ifdef HTTP_AUTH + && output_handler != &http_401_handler #endif - ) { - blob_curr = CONST_READ_UI8(blob); #ifndef DISABLE_POST - /* testing end multipart */ - if(tmp_connection.protocol.http.post_data - && tmp_connection.protocol.http.post_data->boundary - && tmp_connection.protocol.http.post_data->boundary->ready_to_count - && tmp_connection.protocol.http.post_data->content_length < 3){ - tmp_connection.protocol.http.ready_to_send = 1; - tmp_connection.protocol.http.parsing_state = parsing_end; - break; - } - if(tmp_connection.protocol.http.parsing_state != parsing_post_data){ -#endif - x++; - DEV_GETC(tmp_char); + && output_handler != &http_505_handler +#endif + ) { + blob_curr = CONST_READ_UI8(blob); #ifndef DISABLE_POST - /* updating content length */ - if((tmp_connection.protocol.http.parsing_state == parsing_init_buffer - || tmp_connection.protocol.http.parsing_state == parsing_post_args - ||(tmp_connection.protocol.http.post_data - && tmp_connection.protocol.http.post_data->boundary - && tmp_connection.protocol.http.post_data->boundary->ready_to_count)) - && tmp_connection.protocol.http.post_data->content_length != (uint16_t)-1) - tmp_connection.protocol.http.post_data->content_length--; - } - /* initializing buffer before parsing data */ - if(tmp_connection.protocol.http.parsing_state == parsing_init_buffer){ - tmp_connection.protocol.http.post_data->boundary->boundary_buffer[tmp_connection.protocol.http.post_data->boundary->index] = tmp_char; - tmp_connection.protocol.http.post_data->boundary->index++; - if(tmp_connection.protocol.http.post_data->boundary->index == tmp_connection.protocol.http.post_data->boundary->boundary_size){ - tmp_connection.protocol.http.parsing_state = parsing_post_data; - /* verifying buffer */ - if(tmp_connection.protocol.http.post_data->boundary->boundary_buffer[(tmp_connection.protocol.http.post_data->boundary->index-1) % tmp_connection.protocol.http.post_data->boundary->boundary_size] - == tmp_connection.protocol.http.post_data->boundary->boundary_ref[tmp_connection.protocol.http.post_data->boundary->boundary_size-1] - && tmp_connection.protocol.http.post_data->boundary->boundary_buffer[tmp_connection.protocol.http.post_data->boundary->index] - == tmp_connection.protocol.http.post_data->boundary->boundary_ref[0]){ - unsigned char index = tmp_connection.protocol.http.post_data->boundary->index + 1; - unsigned char i; - for(i = 1 ; i < tmp_connection.protocol.http.post_data->boundary->boundary_size-1 ; i++){ - if(index == tmp_connection.protocol.http.post_data->boundary->boundary_size) - index = 0; - if(tmp_connection.protocol.http.post_data->boundary->boundary_ref[i] != tmp_connection.protocol.http.post_data->boundary->boundary_buffer[index]) - break; - index++; - } - if(i == tmp_connection.protocol.http.post_data->boundary->boundary_size-1){ - tmp_connection.protocol.http.parsing_state = parsing_post_attributes; - blob = blob_http_header_content; - tmp_connection.protocol.http.post_data->boundary->index = -1; - } - } - } - else - continue; - } - /* parsing boundary */ - else if(tmp_connection.protocol.http.parsing_state == parsing_boundary){ - if(tmp_connection.protocol.http.post_data->boundary->index == tmp_connection.protocol.http.post_data->boundary->boundary_size) - tmp_connection.protocol.http.post_data->boundary->index = 0; /* update index */ - /* comparing first and last characters then all */ - if(tmp_connection.protocol.http.post_data->boundary->boundary_buffer[(tmp_connection.protocol.http.post_data->boundary->index-1) % tmp_connection.protocol.http.post_data->boundary->boundary_size] - == tmp_connection.protocol.http.post_data->boundary->boundary_ref[tmp_connection.protocol.http.post_data->boundary->boundary_size-1] - && tmp_connection.protocol.http.post_data->boundary->boundary_buffer[tmp_connection.protocol.http.post_data->boundary->index] - == tmp_connection.protocol.http.post_data->boundary->boundary_ref[0]){ - unsigned char index = tmp_connection.protocol.http.post_data->boundary->index + 1; - unsigned char i; - for(i = 1 ; i < tmp_connection.protocol.http.post_data->boundary->boundary_size-1 ; i++){ - if(index == tmp_connection.protocol.http.post_data->boundary->boundary_size) - index = 0; - if(tmp_connection.protocol.http.post_data->boundary->boundary_ref[i] != tmp_connection.protocol.http.post_data->boundary->boundary_buffer[index]) - break; - index++; - } - if(i == tmp_connection.protocol.http.post_data->boundary->boundary_size-1){ - tmp_connection.protocol.http.parsing_state = parsing_post_attributes; - blob = blob_http_header_content; - tmp_connection.protocol.http.post_data->boundary->index = -1; - continue; - } - } - tmp_connection.protocol.http.post_data->boundary->boundary_buffer[tmp_connection.protocol.http.post_data->boundary->index] = tmp_char; - tmp_connection.protocol.http.post_data->boundary->index++; - continue; - } -#endif - /* search for the web applicative resource to send */ - if(blob_curr >= 128 && output_handler != &http_404_handler + /* testing end multipart */ + if(tmp_connection.protocol.http.post_data + && tmp_connection.protocol.http.post_data->boundary + && tmp_connection.protocol.http.post_data->boundary->ready_to_count + && tmp_connection.protocol.http.post_data->content_length < 3){ + tmp_connection.protocol.http.ready_to_send = 1; + tmp_connection.protocol.http.parsing_state = parsing_end; + break; + } + if(tmp_connection.protocol.http.parsing_state != parsing_post_data){ +#endif + x++; + DEV_GETC(tmp_char); + #ifndef DISABLE_POST - && output_handler != &http_505_handler + /* updating content length */ + if((tmp_connection.protocol.http.parsing_state == parsing_init_buffer + || tmp_connection.protocol.http.parsing_state == parsing_post_args + ||(tmp_connection.protocol.http.post_data + && tmp_connection.protocol.http.post_data->boundary + && tmp_connection.protocol.http.post_data->boundary->ready_to_count)) + && tmp_connection.protocol.http.post_data->content_length != (uint16_t)-1) + tmp_connection.protocol.http.post_data->content_length--; + } + /* initializing buffer before parsing data */ + if(tmp_connection.protocol.http.parsing_state == parsing_init_buffer){ + tmp_connection.protocol.http.post_data->boundary->boundary_buffer[tmp_connection.protocol.http.post_data->boundary->index] = tmp_char; + tmp_connection.protocol.http.post_data->boundary->index++; + if(tmp_connection.protocol.http.post_data->boundary->index == tmp_connection.protocol.http.post_data->boundary->boundary_size){ + tmp_connection.protocol.http.parsing_state = parsing_post_data; + /* verifying buffer */ + if(tmp_connection.protocol.http.post_data->boundary->boundary_buffer[(tmp_connection.protocol.http.post_data->boundary->index-1) % tmp_connection.protocol.http.post_data->boundary->boundary_size] + == tmp_connection.protocol.http.post_data->boundary->boundary_ref[tmp_connection.protocol.http.post_data->boundary->boundary_size-1] + && tmp_connection.protocol.http.post_data->boundary->boundary_buffer[tmp_connection.protocol.http.post_data->boundary->index] + == tmp_connection.protocol.http.post_data->boundary->boundary_ref[0]){ + unsigned char index = tmp_connection.protocol.http.post_data->boundary->index + 1; + unsigned char i; + for(i = 1 ; i < tmp_connection.protocol.http.post_data->boundary->boundary_size-1 ; i++){ + if(index == tmp_connection.protocol.http.post_data->boundary->boundary_size) + index = 0; + if(tmp_connection.protocol.http.post_data->boundary->boundary_ref[i] != tmp_connection.protocol.http.post_data->boundary->boundary_buffer[index]) + break; + index++; + } + if(i == tmp_connection.protocol.http.post_data->boundary->boundary_size-1){ + tmp_connection.protocol.http.parsing_state = parsing_post_attributes; + blob = blob_http_header_content; + tmp_connection.protocol.http.post_data->boundary->index = -1; + } + } + } + else + continue; + } + /* parsing boundary */ + else if(tmp_connection.protocol.http.parsing_state == parsing_boundary){ + if(tmp_connection.protocol.http.post_data->boundary->index == tmp_connection.protocol.http.post_data->boundary->boundary_size) + tmp_connection.protocol.http.post_data->boundary->index = 0; /* update index */ + /* comparing first and last characters then all */ + if(tmp_connection.protocol.http.post_data->boundary->boundary_buffer[(tmp_connection.protocol.http.post_data->boundary->index-1) % tmp_connection.protocol.http.post_data->boundary->boundary_size] + == tmp_connection.protocol.http.post_data->boundary->boundary_ref[tmp_connection.protocol.http.post_data->boundary->boundary_size-1] + && tmp_connection.protocol.http.post_data->boundary->boundary_buffer[tmp_connection.protocol.http.post_data->boundary->index] + == tmp_connection.protocol.http.post_data->boundary->boundary_ref[0]){ + unsigned char index = tmp_connection.protocol.http.post_data->boundary->index + 1; + unsigned char i; + for(i = 1 ; i < tmp_connection.protocol.http.post_data->boundary->boundary_size-1 ; i++){ + if(index == tmp_connection.protocol.http.post_data->boundary->boundary_size) + index = 0; + if(tmp_connection.protocol.http.post_data->boundary->boundary_ref[i] != tmp_connection.protocol.http.post_data->boundary->boundary_buffer[index]) + break; + index++; + } + if(i == tmp_connection.protocol.http.post_data->boundary->boundary_size-1){ + tmp_connection.protocol.http.parsing_state = parsing_post_attributes; + blob = blob_http_header_content; + tmp_connection.protocol.http.post_data->boundary->index = -1; + continue; + } + } + tmp_connection.protocol.http.post_data->boundary->boundary_buffer[tmp_connection.protocol.http.post_data->boundary->index] = tmp_char; + tmp_connection.protocol.http.post_data->boundary->index++; + continue; + } #endif - ) { + /* search for the web applicative resource to send */ + if(blob_curr >= 128 && output_handler != &http_404_handler #ifndef DISABLE_POST - /* "\n\r\n\r" detected (end header or end part of multipart )*/ - if(tmp_connection.protocol.http.parsing_state == parsing_post_end){ - if(tmp_connection.protocol.http.post_data->content_type == (uint8_t)-1){ /* no content type */ - output_handler = &http_505_handler; - break; - } - if(tmp_connection.protocol.http.post_data->boundary){ - tmp_connection.protocol.http.post_data->boundary->ready_to_count = 1; - /* parsing header part of multipart */ - if(tmp_connection.protocol.http.post_data->content_type == CONTENT_TYPE_MULTIPART_47_FORM_45_DATA){ - tmp_connection.protocol.http.parsing_state = parsing_post_attributes; - blob = blob_http_header_content; - continue; - } - else - /* parsing data */ - tmp_connection.protocol.http.parsing_state = parsing_post_data; - } - /* parsing form */ - else if(tmp_connection.protocol.http.post_data->content_type == CONTENT_TYPE_APPLICATION_47_X_45_WWW_45_FORM_45_URLENCODED) - tmp_connection.protocol.http.parsing_state = parsing_post_args; - else{ - /* no content length detected = boundary is "\r\n\r\n" */ - if(tmp_connection.protocol.http.post_data->content_length == (uint16_t)-1){ - tmp_connection.protocol.http.post_data->boundary = mem_alloc(sizeof(struct boundary_t)); - if(!tmp_connection.protocol.http.post_data->boundary){ - output_handler = &http_404_handler; - break; - } - tmp_connection.protocol.http.post_data->boundary->boundary_size = 4; - tmp_connection.protocol.http.post_data->boundary->index = -1; - tmp_connection.protocol.http.post_data->boundary->multi_part_counter = 0; - tmp_connection.protocol.http.post_data->boundary->boundary_ref = "\r\n\r\n"; - tmp_connection.protocol.http.post_data->boundary->boundary_buffer = mem_alloc(4*sizeof(char)); - if(!tmp_connection.protocol.http.post_data->boundary->boundary_buffer){ - /* If boundary buffer can not be allocated, also free the boundary itself */ - mem_free(tmp_connection.protocol.http.post_data->boundary, sizeof(struct boundary_t)); - output_handler = &http_404_handler; - break; - } - } - tmp_connection.protocol.http.parsing_state = parsing_post_data; - } - } - /* parsing post data => run coroutine */ - if(tmp_connection.protocol.http.parsing_state == parsing_post_data){ - /* starting buffer init */ - if(tmp_connection.protocol.http.post_data->coroutine.curr_context.status == cr_terminated - && tmp_connection.protocol.http.post_data->boundary - && tmp_connection.protocol.http.post_data->boundary->index == 255){ - tmp_connection.protocol.http.post_data->boundary->index = 0; - tmp_connection.protocol.http.parsing_state = parsing_init_buffer; - continue; - } - uint16_t length_temp = segment_length - x; - /* initialization coroutine */ - if(tmp_connection.protocol.http.post_data->coroutine.curr_context.status == cr_terminated){ - cr_init(&(tmp_connection.protocol.http.post_data->coroutine)); - tmp_connection.protocol.http.post_data->coroutine.func.func_post_in = CONST_ADDR(GET_GENERATOR(output_handler).handlers.post.dopostin); - tmp_connection.protocol.http.post_data->coroutine.params.in.content_type = tmp_connection.protocol.http.post_data->content_type; - tmp_connection.protocol.http.post_data->coroutine.params.in.filename = tmp_connection.protocol.http.post_data->filename; - tmp_connection.protocol.http.post_data->coroutine.params.in.post_data = tmp_connection.protocol.http.post_data->post_data; - if(tmp_connection.protocol.http.post_data->boundary){ - tmp_connection.protocol.http.post_data->coroutine.params.in.part_number = tmp_connection.protocol.http.post_data->boundary->multi_part_counter; - tmp_connection.protocol.http.post_data->boundary->index = 0; - } - else - tmp_connection.protocol.http.post_data->coroutine.params.in.part_number = 0; - if(cr_prepare(&(tmp_connection.protocol.http.post_data->coroutine)) == NULL) - { - /* TODO: shoudn't the boundary and boundary_buffer be free ? */ - return 1; - } - } - curr_input.length = length_temp; - curr_input.connection = &tmp_connection; - coroutine_state.state = cor_in; - /* running coroutine */ - cr_run(&(tmp_connection.protocol.http.post_data->coroutine),cor_type_post_in); - coroutine_state.state = cor_out; - x += (length_temp-curr_input.length); - if(tmp_connection.protocol.http.post_data->coroutine.curr_context.status == cr_terminated){ /* if is terminated */ - tmp_connection.protocol.http.post_data->post_data = tmp_connection.protocol.http.post_data->coroutine.params.in.post_data; - cr_clean(&(tmp_connection.protocol.http.post_data->coroutine)); - /* cleaning filename memory */ - if(tmp_connection.protocol.http.post_data->filename){ - uint8_t i = 0; - while(tmp_connection.protocol.http.post_data->filename[i++] != '\0'); - mem_free(tmp_connection.protocol.http.post_data->filename,i*sizeof(char)); - tmp_connection.protocol.http.post_data->filename = NULL; - } - /* if no boundary, there is no data to parse */ - if(!tmp_connection.protocol.http.post_data->boundary){ - tmp_connection.protocol.http.parsing_state = parsing_end; - tmp_connection.protocol.http.ready_to_send = 1; - } - else{ - /* starting search of boundary if no found, or ready for next part */ - tmp_connection.protocol.http.post_data->boundary->multi_part_counter++; - if(tmp_connection.protocol.http.post_data->boundary->index != (uint8_t)-1) - tmp_connection.protocol.http.parsing_state = parsing_boundary; - else{ - tmp_connection.protocol.http.parsing_state = parsing_post_attributes; - blob = blob_http_header_content; - } - /* if no content length, parsing is terminated */ - if(tmp_connection.protocol.http.post_data->content_length == (uint16_t)-1){ - tmp_connection.protocol.http.parsing_state = parsing_end; - tmp_connection.protocol.http.ready_to_send = 1; - break; - } - } - } - if(tmp_connection.protocol.http.post_data->boundary) - continue; - break; - } - /* searching end character of post url detection */ - if(tmp_connection.protocol.http.parsing_state == parsing_url && blob_curr == URL_POST_END){ - if(tmp_connection.protocol.http.post_data){ - tmp_connection.protocol.http.post_url_detected = 1; - blob_curr = CONST_READ_UI8(++blob); - } - else{ /* get unauthorized */ - output_handler = &http_404_handler; - break; - } - } - /* parsing attributes of post header */ - if(tmp_connection.protocol.http.parsing_state == parsing_post_attributes){ - if(blob_curr == ATTRIBUT_CONTENT_45_TYPE + 128) { /* content-type */ - blob = mimes_tree; - tmp_connection.protocol.http.parsing_state = parsing_post_content_type; - } - else if(blob_curr == ATTRIBUT_CONTENT_45_LENGTH + 128){ /* content-length */ - if(tmp_connection.protocol.http.post_data->content_length == (uint8_t)-1) - tmp_connection.protocol.http.post_data->content_length = 0; - if(tmp_char != ' ' && tmp_char != '\r'){ - tmp_connection.protocol.http.post_data->content_length *= 10; - tmp_connection.protocol.http.post_data->content_length += tmp_char - '0'; - } - } - else if(blob_curr == ATTRIBUT_FILENAME_61_ + 128){ /* filename */ - if(!tmp_connection.protocol.http.post_data->filename){ - tmp_connection.protocol.http.post_data->filename = mem_alloc(10 * sizeof(char)); - if(!tmp_connection.protocol.http.post_data->filename){ - output_handler = &http_404_handler; - break; - } - tmp_connection.protocol.http.post_data->filename[0] = 2; /* first value is the size of filename */ - tmp_connection.protocol.http.post_data->filename[1] = 10; /* seconde value is the size allocated */ - } - else if(tmp_char == '\"'){ /* end of filename, the indexes are removed */ - uint8_t i = 0; - char *new_tab = mem_alloc((tmp_connection.protocol.http.post_data->filename[0]-1)*sizeof(char)); - if(!new_tab){ - output_handler = &http_404_handler; - break; - } - for(i = 0 ; i < tmp_connection.protocol.http.post_data->filename[0]-2 ; i++) - new_tab[i] = tmp_connection.protocol.http.post_data->filename[i+2]; - new_tab[i]='\0'; - mem_free(tmp_connection.protocol.http.post_data->filename,(tmp_connection.protocol.http.post_data->filename[1])*sizeof(char)); - tmp_connection.protocol.http.post_data->filename = new_tab; - tmp_connection.protocol.http.parsing_state = parsing_post_attributes; - blob = blob_http_header_content; - } - else{ - /* reallocating filename */ - if(tmp_connection.protocol.http.post_data->filename[0] == tmp_connection.protocol.http.post_data->filename[1]){ - tmp_connection.protocol.http.post_data->filename = mem_realloc(tmp_connection.protocol.http.post_data->filename,tmp_connection.protocol.http.post_data->filename[1],10); - if(!tmp_connection.protocol.http.post_data->filename){ - output_handler = &http_404_handler; - break; - } - /* updating size */ - tmp_connection.protocol.http.post_data->filename[1] = tmp_connection.protocol.http.post_data->filename[1] + 10; - } - /* add current character */ - tmp_connection.protocol.http.post_data->filename[tmp_connection.protocol.http.post_data->filename[0]] = tmp_char; - tmp_connection.protocol.http.post_data->filename[0]++; - } - } - /* parsing boundary */ - else if(blob_curr == ATTRIBUT_BOUNDARY_61_ + 128){ - if(tmp_char != '\r'){ - /* reallocating tab */ - if(tmp_connection.protocol.http.post_data->boundary->index == tmp_connection.protocol.http.post_data->boundary->boundary_size){ - tmp_connection.protocol.http.post_data->boundary->boundary_ref = mem_realloc(tmp_connection.protocol.http.post_data->boundary->boundary_ref,tmp_connection.protocol.http.post_data->boundary->boundary_size,10); - if(!tmp_connection.protocol.http.post_data->boundary->boundary_ref){ - output_handler = &http_404_handler; - break; - } - /* updating size */ - tmp_connection.protocol.http.post_data->boundary->boundary_size += 10; - } - tmp_connection.protocol.http.post_data->boundary->boundary_ref[tmp_connection.protocol.http.post_data->boundary->index++] = tmp_char; /* saving boundary char */ - } - else{ - /* final reallocation */ - uint8_t i = 0; - char *new_tab = mem_alloc((tmp_connection.protocol.http.post_data->boundary->index+5)*sizeof(char)); - if(!new_tab){ - output_handler = &http_404_handler; - break; - } - new_tab[0] = '\n'; - new_tab[1] = '\r'; - new_tab[2] = '\n'; - new_tab[3] = '-'; - new_tab[4] = '-'; - /* copying boundary */ - for(i = 0 ; i < tmp_connection.protocol.http.post_data->boundary->index ; i++) - new_tab[i+5] = tmp_connection.protocol.http.post_data->boundary->boundary_ref[i]; - mem_free(tmp_connection.protocol.http.post_data->boundary->boundary_ref,(tmp_connection.protocol.http.post_data->boundary->boundary_size)*sizeof(char)); - tmp_connection.protocol.http.post_data->boundary->boundary_size = tmp_connection.protocol.http.post_data->boundary->index + 5; - tmp_connection.protocol.http.post_data->boundary->boundary_ref = new_tab; - tmp_connection.protocol.http.post_data->boundary->index = -1; - tmp_connection.protocol.http.post_data->boundary->boundary_buffer = mem_alloc(tmp_connection.protocol.http.post_data->boundary->boundary_size*sizeof(char)); - if(!tmp_connection.protocol.http.post_data->boundary->boundary_buffer){ - /* If no space for boundary_ref, free boundary */ - mem_free(tmp_connection.protocol.http.post_data->boundary, sizeof(struct boundary_t)); - output_handler = &http_404_handler; - break; - } - } - } - } - /* parsing content-type */ - else if(tmp_connection.protocol.http.parsing_state == parsing_post_content_type){ - if(blob_curr - 128 == CONTENT_TYPE_MULTIPART_47_FORM_45_DATA){ /* multipart */ - /* allocating boundary structure */ - tmp_connection.protocol.http.post_data->boundary = mem_alloc(sizeof(struct boundary_t)); - if(!tmp_connection.protocol.http.post_data->boundary){ - output_handler = &http_404_handler; - break; - } - tmp_connection.protocol.http.post_data->boundary->boundary_size = 10; - tmp_connection.protocol.http.post_data->boundary->index = 0; - tmp_connection.protocol.http.post_data->boundary->multi_part_counter = 0; - tmp_connection.protocol.http.post_data->boundary->ready_to_count = 0; - tmp_connection.protocol.http.post_data->boundary->boundary_ref = mem_alloc(10*sizeof(char)); - if(!tmp_connection.protocol.http.post_data->boundary->boundary_ref){ - /* If no space for boundary_ref, free boundary */ - mem_free(tmp_connection.protocol.http.post_data->boundary, sizeof(struct boundary_t)); - output_handler = &http_404_handler; - break; - } - tmp_connection.protocol.http.post_data->content_type = CONTENT_TYPE_MULTIPART_47_FORM_45_DATA; - } - else{ /* searching content-type in application to verify it */ - tmp_connection.protocol.http.post_data->content_type = (uint8_t) -1; - if(!output_handler->handler_mimes.mimes_size) - tmp_connection.protocol.http.post_data->content_type = blob_curr - 128; - else{ - uint8_t i; - for(i = 0 ; i < output_handler->handler_mimes.mimes_size ; i++){ - if(output_handler->handler_mimes.mimes_index[i] == blob_curr - 128) - tmp_connection.protocol.http.post_data->content_type = blob_curr - 128; - } - } - if(tmp_connection.protocol.http.post_data->content_type == (uint8_t) -1){ - output_handler = &http_404_handler; - break; - } - } - tmp_connection.protocol.http.parsing_state = parsing_post_attributes; - blob = blob_http_header_content; - } else -#endif - if(tmp_connection.protocol.http.parsing_state == parsing_cmd) { + && output_handler != &http_505_handler +#endif + ) { + +#if !defined(DISABLE_POST) || defined(HTTP_AUTH) + /* "\n\r\n\r" detected (end header or end part of multipart )*/ + if(tmp_connection.protocol.http.parsing_state == parsing_post_end) { + +#ifdef HTTP_AUTH + /* HTTP-Auth: + * We are ready to send if there is no more header to parse and if + * requested url is not a post url. + */ + if (IS_RESTRICTED (output_handler) #ifndef DISABLE_POST - if(blob_curr == REQUEST_POST_32_ + 128){ /* post request */ - /* allocating post data structure */ - tmp_connection.protocol.http.post_data = mem_alloc(sizeof(struct post_data_t)); - if(!tmp_connection.protocol.http.post_data){ - output_handler = &http_404_handler; - break; - } - tmp_connection.protocol.http.post_data->content_type = -1; - tmp_connection.protocol.http.post_data->content_length = -1; - tmp_connection.protocol.http.post_data->boundary = NULL; - tmp_connection.protocol.http.post_data->post_data = NULL; - tmp_connection.protocol.http.post_data->filename = NULL; - tmp_connection.protocol.http.post_data->coroutine.curr_context.status = cr_terminated; - } -#endif - tmp_connection.protocol.http.parsing_state = parsing_url; - blob = urls_tree; - } else { - if(tmp_char == ' ') { + && !tmp_connection.protocol.http.post_data +#endif + ) { + tmp_connection.protocol.http.parsing_state = parsing_end; + tmp_connection.protocol.http.ready_to_send = 1; + break; + } +#endif + #ifndef DISABLE_POST - if(tmp_connection.protocol.http.post_data && tmp_connection.protocol.http.post_url_detected == 0) { /* post unauthorized */ - output_handler = &http_404_handler; - break; - } - else{ -#endif - if(!output_handler) - output_handler = (struct output_handler_t*)CONST_ADDR(resources_index[blob_curr - 128]); + if(tmp_connection.protocol.http.post_data->content_type == (uint8_t)-1) { /* no content type */ + output_handler = &http_505_handler; + break; + } + + if(tmp_connection.protocol.http.post_data->boundary){ + tmp_connection.protocol.http.post_data->boundary->ready_to_count = 1; + /* parsing header part of multipart */ + if(tmp_connection.protocol.http.post_data->content_type == CONTENT_TYPE_MULTIPART_47_FORM_45_DATA){ + tmp_connection.protocol.http.parsing_state = parsing_post_attributes; + blob = blob_http_header_content; + continue; + } + else + /* parsing data */ + tmp_connection.protocol.http.parsing_state = parsing_post_data; + } + /* parsing form */ + else if(tmp_connection.protocol.http.post_data->content_type == CONTENT_TYPE_APPLICATION_47_X_45_WWW_45_FORM_45_URLENCODED) + tmp_connection.protocol.http.parsing_state = parsing_post_args; + else{ + /* no content length detected = boundary is "\r\n\r\n" */ + if(tmp_connection.protocol.http.post_data->content_length == (uint16_t)-1){ + tmp_connection.protocol.http.post_data->boundary = mem_alloc(sizeof(struct boundary_t)); + if(!tmp_connection.protocol.http.post_data->boundary){ + output_handler = &http_404_handler; + break; + } + tmp_connection.protocol.http.post_data->boundary->boundary_size = 4; + tmp_connection.protocol.http.post_data->boundary->index = -1; + tmp_connection.protocol.http.post_data->boundary->multi_part_counter = 0; + tmp_connection.protocol.http.post_data->boundary->boundary_ref = "\r\n\r\n"; + tmp_connection.protocol.http.post_data->boundary->boundary_buffer = mem_alloc(4*sizeof(char)); + if(!tmp_connection.protocol.http.post_data->boundary->boundary_buffer){ + /* If boundary buffer can not be allocated, also free the boundary itself */ + mem_free(tmp_connection.protocol.http.post_data->boundary, sizeof(struct boundary_t)); + output_handler = &http_404_handler; + break; + } + } + tmp_connection.protocol.http.parsing_state = parsing_post_data; + } +#endif +#endif +#if !defined(DISABLE_POST) || defined(HTTP_AUTH) + } +#endif #ifndef DISABLE_POST - if(tmp_connection.protocol.http.post_data){ - tmp_connection.protocol.http.parsing_state = parsing_post_attributes; - blob = blob_http_header_content; - tmp_connection.protocol.http.ready_to_send = 0; - } - else{ -#endif - tmp_connection.protocol.http.parsing_state = parsing_end; - break; + /* parsing post data => run coroutine */ + if(tmp_connection.protocol.http.parsing_state == parsing_post_data){ + /* starting buffer init */ + if(tmp_connection.protocol.http.post_data->coroutine.curr_context.status == cr_terminated + && tmp_connection.protocol.http.post_data->boundary + && tmp_connection.protocol.http.post_data->boundary->index == 255){ + tmp_connection.protocol.http.post_data->boundary->index = 0; + tmp_connection.protocol.http.parsing_state = parsing_init_buffer; + continue; + } + uint16_t length_temp = segment_length - x; + /* initialization coroutine */ + if(tmp_connection.protocol.http.post_data->coroutine.curr_context.status == cr_terminated){ + cr_init(&(tmp_connection.protocol.http.post_data->coroutine)); + tmp_connection.protocol.http.post_data->coroutine.func.func_post_in = CONST_ADDR(GET_GENERATOR(output_handler).handlers.post.dopostin); + tmp_connection.protocol.http.post_data->coroutine.params.in.content_type = tmp_connection.protocol.http.post_data->content_type; + tmp_connection.protocol.http.post_data->coroutine.params.in.filename = tmp_connection.protocol.http.post_data->filename; + tmp_connection.protocol.http.post_data->coroutine.params.in.post_data = tmp_connection.protocol.http.post_data->post_data; + if(tmp_connection.protocol.http.post_data->boundary){ + tmp_connection.protocol.http.post_data->coroutine.params.in.part_number = tmp_connection.protocol.http.post_data->boundary->multi_part_counter; + tmp_connection.protocol.http.post_data->boundary->index = 0; + } + else + tmp_connection.protocol.http.post_data->coroutine.params.in.part_number = 0; + if(cr_prepare(&(tmp_connection.protocol.http.post_data->coroutine)) == NULL) + { + /* TODO: shoudn't the boundary and boundary_buffer be free ? */ + return 1; + } + } + curr_input.length = length_temp; + curr_input.connection = &tmp_connection; + coroutine_state.state = cor_in; + /* running coroutine */ + cr_run(&(tmp_connection.protocol.http.post_data->coroutine),cor_type_post_in); + coroutine_state.state = cor_out; + x += (length_temp-curr_input.length); + if(tmp_connection.protocol.http.post_data->coroutine.curr_context.status == cr_terminated){ /* if is terminated */ + tmp_connection.protocol.http.post_data->post_data = tmp_connection.protocol.http.post_data->coroutine.params.in.post_data; + cr_clean(&(tmp_connection.protocol.http.post_data->coroutine)); + /* cleaning filename memory */ + if(tmp_connection.protocol.http.post_data->filename){ + uint8_t i = 0; + while(tmp_connection.protocol.http.post_data->filename[i++] != '\0'); + mem_free(tmp_connection.protocol.http.post_data->filename,i*sizeof(char)); + tmp_connection.protocol.http.post_data->filename = NULL; + } + /* if no boundary, there is no data to parse */ + if(!tmp_connection.protocol.http.post_data->boundary){ + tmp_connection.protocol.http.parsing_state = parsing_end; + tmp_connection.protocol.http.ready_to_send = 1; + } + else{ + /* starting search of boundary if no found, or ready for next part */ + tmp_connection.protocol.http.post_data->boundary->multi_part_counter++; + if(tmp_connection.protocol.http.post_data->boundary->index != (uint8_t)-1) + tmp_connection.protocol.http.parsing_state = parsing_boundary; + else{ + tmp_connection.protocol.http.parsing_state = parsing_post_attributes; + blob = blob_http_header_content; + } + /* if no content length, parsing is terminated */ + if(tmp_connection.protocol.http.post_data->content_length == (uint16_t)-1){ + tmp_connection.protocol.http.parsing_state = parsing_end; + tmp_connection.protocol.http.ready_to_send = 1; + break; + } + } + } + if(tmp_connection.protocol.http.post_data->boundary) + continue; + break; + } + + /* searching end character of post url detection */ + if(tmp_connection.protocol.http.parsing_state == parsing_url && blob_curr == URL_POST_END){ + if(tmp_connection.protocol.http.post_data){ + tmp_connection.protocol.http.post_url_detected = 1; + blob_curr = CONST_READ_UI8(++blob); + } + else{ /* get unauthorized */ + output_handler = &http_404_handler; + break; + } + } +#endif + +#if defined(HTTP_AUTH) && HTTP_AUTH == HTTP_AUTH_DIGEST + if (tmp_connection.protocol.http.parsing_state == parsing_authorization_username) { + if (blob_curr >= 128) { + /* Username has been successfully parsed. */ + auth_data.username_blob = blob_curr; + blob = blob_http_header_content; + tmp_connection.protocol.http.parsing_state = parsing_post_attributes; + continue; /* Skip the final '"' */ + } + else { + /* Error: invalid username */ + tmp_connection.protocol.http.blob = (unsigned char *)(output_handler); + output_handler = &http_401_handler; + tmp_connection.protocol.http.parsing_state = parsing_end; + break; + } + } +#endif + +#if !defined(DISABLE_POST) || defined(HTTP_AUTH) + /* parsing attributes of post header */ + if(tmp_connection.protocol.http.parsing_state == parsing_post_attributes) { +#endif + +#ifdef HTTP_AUTH + if (blob_curr == ATTRIBUT_AUTHORIZATION_58_ + 128) { + + if (!auth_data.scheme_parsed) { + if (IS_LWS_CHAR (tmp_char)) { + /* Parsing did not start yet (escape unsignificant whitespaces) */ + if (auth_data.parsing_offset == NO_OFFSET) + continue; + + /* Parsing just ended */ + if (HttpAuthenticateScheme[auth_data.parsing_offset] == '\0') { + auth_data.scheme_parsed = 1; + auth_data.parsing_offset = NO_OFFSET; + continue; + } + } + else { + /* Parsing just started */ + if (auth_data.parsing_offset == NO_OFFSET) + auth_data.parsing_offset = 0; + + if (LOWER_CASE (tmp_char) + == HttpAuthenticateScheme[auth_data.parsing_offset]) { + ++auth_data.parsing_offset; + continue; + } + } + + /* If execution flow reach this point, scheme parsing failed. */ + tmp_connection.protocol.http.blob = (unsigned char *)(output_handler); + output_handler = &http_401_handler; + auth_data.parsing_offset = NO_OFFSET; + tmp_connection.protocol.http.parsing_state = parsing_end; + break; + } + else { +#if HTTP_AUTH == HTTP_AUTH_BASIC + /* If no space has been allocated to store given credentials, + * allocate it ! */ + if (!auth_data.credentials) { + auth_data.credentials = mem_alloc(10 * sizeof(char)); + if (!auth_data.credentials) { + output_handler = &http_404_handler; + break; + } + + auth_data.credentials[0] = 2; /* First byte is the used space */ + auth_data.credentials[1] = 10; /* Second byte is the allocated space */ + } + + /* Escape unsignificant whitespace */ + if (IS_LWS_CHAR(tmp_char) && auth_data.credentials[0] == 2) + continue; + + /* As long as the character read is a base64 character, fill + * credentials string */ + if (IS_B64_CHAR (tmp_char)) { + /* String container reallocation if needed */ + if (auth_data.credentials[0] == auth_data.credentials[1]) { + auth_data.credentials = mem_realloc(auth_data.credentials, + auth_data.credentials[0], + 10); + if (!auth_data.credentials) { + output_handler = &http_404_handler; + break; + } + + auth_data.credentials[1] += 10; + } + + /* Add current character */ + auth_data.credentials[auth_data.credentials[0]++] = tmp_char; + } + else { + uint8_t i = 0; + unsigned char *final_credentials; + + final_credentials = mem_alloc((auth_data.credentials[0] - 1) + * sizeof (unsigned char)); + if (!final_credentials) { + output_handler = &http_404_handler; + break; + } + + /* Copy credentials string into final buffer */ + for (i = 0; i < auth_data.credentials[0] - 2; ++i) + final_credentials[i] = auth_data.credentials[i + 2]; + final_credentials[i] = '\0'; + + mem_free (auth_data.credentials, + auth_data.credentials[1] * sizeof (unsigned char)); + + auth_data.credentials = final_credentials; + tmp_connection.protocol.http.parsing_state = parsing_post_attributes; + blob = blob_http_header_content; + } +#elif HTTP_AUTH == HTTP_AUTH_DIGEST + blob = blob_http_header_content; +#endif + } + } +#if HTTP_AUTH == HTTP_AUTH_DIGEST + else if (blob_curr == ATTRIBUT_USERNAME_61_ + 128) { + blob = usernames_tree; + tmp_connection.protocol.http.parsing_state = parsing_authorization_username; + continue; /* Skip the current '"' */ + } + else if (blob_curr == ATTRIBUT_NONCE_61_ + 128) { + + if (tmp_char == '"') { + switch (auth_data.parsing_offset) { + /* Parsing just started: set offset and skip the double quote */ + case NO_OFFSET: + auth_data.parsing_offset = 0; + continue; + + /* Parsing just ended: reset offset and skip the double quote */ + case NONCE_LEN: + auth_data.parsing_offset = NO_OFFSET; + blob = blob_http_header_content; + continue; + + /* Error: nonce value doesn't have a valid length */ + default: + tmp_connection.protocol.http.blob = (unsigned char *)(output_handler); + output_handler = &http_401_handler; + auth_data.parsing_offset = NO_OFFSET; + break; + } + } + else { + switch (auth_data.parsing_offset) { + /* Parsing didn't start yet, but tmp_char is not a double quote */ + case NO_OFFSET: // WARNING: Fall through + /* Parsed string has a length > NONCE_LEN */ + case NONCE_LEN: + tmp_connection.protocol.http.blob = (unsigned char *)(output_handler); + output_handler = &http_401_handler; + auth_data.parsing_offset = NO_OFFSET; + tmp_connection.protocol.http.ready_to_send = 1; + break; + + default: + auth_data.nonce[auth_data.parsing_offset++] = tmp_char; + break; + } + } + } + else if (blob_curr == ATTRIBUT_RESPONSE_61_ + 128) { + + if (tmp_char == '"') { + switch (auth_data.parsing_offset) { + /* Parsing just started: set offset and skip the double quote */ + case NO_OFFSET: + auth_data.parsing_offset = 0; + continue; + + /* Parsing just ended: reset offset and skip the double quote */ + case MD5_DIGEST_LEN: + auth_data.parsing_offset = NO_OFFSET; + blob = blob_http_header_content; + continue; + + /* Error: response value doesn't have a valid length */ + default: + auth_data.parsing_offset = NO_OFFSET; + tmp_connection.protocol.http.blob = (unsigned char *)(output_handler); + output_handler = &http_401_handler; + break; + } + } + else { + switch (auth_data.parsing_offset) { + /* Parsing didn't start yet, but tmp_char is not a double quote */ + case NO_OFFSET: // WARNING: Fall through + /* Parsed string has a length > NONCE_LEN */ + case MD5_DIGEST_LEN: + auth_data.parsing_offset = NO_OFFSET; + tmp_connection.protocol.http.blob = (unsigned char *)(output_handler); + output_handler = &http_401_handler; + break; + + default: + auth_data.response[auth_data.parsing_offset++] = tmp_char; + break; + } + } + } +#endif + #ifndef DISABLE_POST - } - } + else #endif - } else { -#ifndef DISABLE_ARGS - if(tmp_char == '?' +#endif + #ifndef DISABLE_POST - || (tmp_connection.protocol.http.parsing_state == parsing_post_args && tmp_char == 10) -#endif - ){ - uint16_t tmp_args_size; - if(!output_handler) - output_handler = (struct output_handler_t*)CONST_ADDR(resources_index[blob_curr - 128]); - tmp_args_size = CONST_UI16(output_handler->handler_args.args_size); - tmp_args_size_ref = tmp_args_size; - tmp_connection.protocol.http.ready_to_send = 0; - if(tmp_args_size) { - uint16_t i; - blob = (const unsigned char *)CONST_ADDR(output_handler->handler_args.args_tree); - tmp_connection.protocol.http.args = mem_alloc(tmp_args_size); /* test NULL: done */ - if(tmp_connection.protocol.http.args == NULL) { - output_handler = &http_404_handler; - break; - } - for(i =0 ; i < tmp_args_size ; ++i) { - ((unsigned char *)tmp_connection.protocol.http.args)[i] = 0; - } - continue; - } - } else if(tmp_char == '=' && tmp_connection.protocol.http.args) { - struct arg_ref_t * /*CONST_VAR*/ tmp_arg_ref_ptr; - tmp_connection.protocol.http.arg_ref_index = blob_curr - 128; - tmp_arg_ref_ptr = &(((struct arg_ref_t*)CONST_ADDR(output_handler->handler_args.args_index))[tmp_connection.protocol.http.arg_ref_index]); - tmp_arg_ref.arg_type = CONST_UI8(tmp_arg_ref_ptr->arg_type); - tmp_arg_ref.arg_size = CONST_UI8(tmp_arg_ref_ptr->arg_size); - tmp_arg_ref.arg_offset = CONST_UI8(tmp_arg_ref_ptr->arg_offset); - tmp_connection.protocol.http.curr_arg = ((unsigned char*)tmp_connection.protocol.http.args) + tmp_arg_ref.arg_offset; - if(tmp_arg_ref.arg_type == arg_str) - (*((unsigned char*)tmp_connection.protocol.http.curr_arg + tmp_arg_ref.arg_size - 1)) = tmp_arg_ref.arg_size - 1; - continue; - } else if(tmp_char == '&') { - blob = (const unsigned char *)CONST_ADDR(output_handler->handler_args.args_tree); - } else { - blob++; - } -#else - blob++; + if(blob_curr == ATTRIBUT_CONTENT_45_TYPE + 128) { /* content-type */ + blob = mimes_tree; + tmp_connection.protocol.http.parsing_state = parsing_post_content_type; + } + else if(blob_curr == ATTRIBUT_CONTENT_45_LENGTH + 128){ /* content-length */ + if(tmp_connection.protocol.http.post_data->content_length == (uint8_t)-1) + tmp_connection.protocol.http.post_data->content_length = 0; + if(tmp_char != ' ' && tmp_char != '\r'){ + tmp_connection.protocol.http.post_data->content_length *= 10; + tmp_connection.protocol.http.post_data->content_length += tmp_char - '0'; + } + } + else if(blob_curr == ATTRIBUT_FILENAME_61_ + 128){ /* filename */ + if(!tmp_connection.protocol.http.post_data->filename){ + tmp_connection.protocol.http.post_data->filename = mem_alloc(10 * sizeof(char)); + if(!tmp_connection.protocol.http.post_data->filename){ + output_handler = &http_404_handler; + break; + } + tmp_connection.protocol.http.post_data->filename[0] = 2; /* first value is the size of filename */ + tmp_connection.protocol.http.post_data->filename[1] = 10; /* second value is the size allocated */ + } + else if(tmp_char == '\"'){ /* end of filename, the indexes are removed */ + uint8_t i = 0; + char *new_tab = mem_alloc((tmp_connection.protocol.http.post_data->filename[0]-1)*sizeof(char)); + if(!new_tab){ + output_handler = &http_404_handler; + break; + } + for(i = 0 ; i < tmp_connection.protocol.http.post_data->filename[0]-2 ; i++) + new_tab[i] = tmp_connection.protocol.http.post_data->filename[i+2]; + new_tab[i]='\0'; + mem_free(tmp_connection.protocol.http.post_data->filename,(tmp_connection.protocol.http.post_data->filename[1])*sizeof(char)); + tmp_connection.protocol.http.post_data->filename = new_tab; + tmp_connection.protocol.http.parsing_state = parsing_post_attributes; + blob = blob_http_header_content; + } + else{ + /* reallocating filename */ + if(tmp_connection.protocol.http.post_data->filename[0] == tmp_connection.protocol.http.post_data->filename[1]){ + tmp_connection.protocol.http.post_data->filename = mem_realloc(tmp_connection.protocol.http.post_data->filename,tmp_connection.protocol.http.post_data->filename[1],10); + if(!tmp_connection.protocol.http.post_data->filename){ + output_handler = &http_404_handler; + break; + } + /* updating size */ + tmp_connection.protocol.http.post_data->filename[1] = tmp_connection.protocol.http.post_data->filename[1] + 10; + } + /* add current character */ + tmp_connection.protocol.http.post_data->filename[tmp_connection.protocol.http.post_data->filename[0]] = tmp_char; + tmp_connection.protocol.http.post_data->filename[0]++; + } + } + /* parsing boundary */ + else if(blob_curr == ATTRIBUT_BOUNDARY_61_ + 128){ + if(tmp_char != '\r'){ + /* reallocating tab */ + if(tmp_connection.protocol.http.post_data->boundary->index == tmp_connection.protocol.http.post_data->boundary->boundary_size){ + tmp_connection.protocol.http.post_data->boundary->boundary_ref = mem_realloc(tmp_connection.protocol.http.post_data->boundary->boundary_ref,tmp_connection.protocol.http.post_data->boundary->boundary_size,10); + if(!tmp_connection.protocol.http.post_data->boundary->boundary_ref){ + output_handler = &http_404_handler; + break; + } + /* updating size */ + tmp_connection.protocol.http.post_data->boundary->boundary_size += 10; + } + tmp_connection.protocol.http.post_data->boundary->boundary_ref[tmp_connection.protocol.http.post_data->boundary->index++] = tmp_char; /* saving boundary char */ + } + else{ + /* final reallocation */ + uint8_t i = 0; + char *new_tab = mem_alloc((tmp_connection.protocol.http.post_data->boundary->index+5)*sizeof(char)); + if(!new_tab){ + output_handler = &http_404_handler; + break; + } + new_tab[0] = '\n'; + new_tab[1] = '\r'; + new_tab[2] = '\n'; + new_tab[3] = '-'; + new_tab[4] = '-'; + /* copying boundary */ + for(i = 0 ; i < tmp_connection.protocol.http.post_data->boundary->index ; i++) + new_tab[i+5] = tmp_connection.protocol.http.post_data->boundary->boundary_ref[i]; + mem_free(tmp_connection.protocol.http.post_data->boundary->boundary_ref,(tmp_connection.protocol.http.post_data->boundary->boundary_size)*sizeof(char)); + tmp_connection.protocol.http.post_data->boundary->boundary_size = tmp_connection.protocol.http.post_data->boundary->index + 5; + tmp_connection.protocol.http.post_data->boundary->boundary_ref = new_tab; + tmp_connection.protocol.http.post_data->boundary->index = -1; + tmp_connection.protocol.http.post_data->boundary->boundary_buffer = mem_alloc(tmp_connection.protocol.http.post_data->boundary->boundary_size*sizeof(char)); + if(!tmp_connection.protocol.http.post_data->boundary->boundary_buffer){ + /* If no space for boundary_ref, free boundary */ + mem_free(tmp_connection.protocol.http.post_data->boundary, sizeof(struct boundary_t)); + output_handler = &http_404_handler; + break; + } + } + } +#endif +#if !defined(DISABLE_POST) || defined(HTTP_AUTH) + } #endif - } - } - blob_curr = CONST_READ_UI8(blob); - } #ifndef DISABLE_POST - /* end header detection */ - if(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && tmp_char == 13){ - blob = blob_http_header_end; - tmp_connection.protocol.http.parsing_state = parsing_post_end; - } - else if(tmp_connection.protocol.http.parsing_state == parsing_post_end){ - if(tmp_char != blob_curr){ - blob = blob_http_header_content; - tmp_connection.protocol.http.parsing_state = parsing_post_attributes; - } - } + /* parsing content-type */ + else if(tmp_connection.protocol.http.parsing_state == parsing_post_content_type){ + if(blob_curr - 128 == CONTENT_TYPE_MULTIPART_47_FORM_45_DATA){ /* multipart */ + /* allocating boundary structure */ + tmp_connection.protocol.http.post_data->boundary = mem_alloc(sizeof(struct boundary_t)); + if(!tmp_connection.protocol.http.post_data->boundary){ + output_handler = &http_404_handler; + break; + } + tmp_connection.protocol.http.post_data->boundary->boundary_size = 10; + tmp_connection.protocol.http.post_data->boundary->index = 0; + tmp_connection.protocol.http.post_data->boundary->multi_part_counter = 0; + tmp_connection.protocol.http.post_data->boundary->ready_to_count = 0; + tmp_connection.protocol.http.post_data->boundary->boundary_ref = mem_alloc(10*sizeof(char)); + if(!tmp_connection.protocol.http.post_data->boundary->boundary_ref){ + /* If no space for boundary_ref, free boundary */ + mem_free(tmp_connection.protocol.http.post_data->boundary, sizeof(struct boundary_t)); + output_handler = &http_404_handler; + break; + } + tmp_connection.protocol.http.post_data->content_type = CONTENT_TYPE_MULTIPART_47_FORM_45_DATA; + } + else{ /* searching content-type in application to verify it */ + tmp_connection.protocol.http.post_data->content_type = (uint8_t) -1; + if(!output_handler->handler_mimes.mimes_size) + tmp_connection.protocol.http.post_data->content_type = blob_curr - 128; + else{ + uint8_t i; + for(i = 0 ; i < output_handler->handler_mimes.mimes_size ; i++){ + if(output_handler->handler_mimes.mimes_index[i] == blob_curr - 128) + tmp_connection.protocol.http.post_data->content_type = blob_curr - 128; + } + } + if(tmp_connection.protocol.http.post_data->content_type == (uint8_t) -1){ + output_handler = &http_404_handler; + break; + } + } + tmp_connection.protocol.http.parsing_state = parsing_post_attributes; + blob = blob_http_header_content; + } #endif -#ifndef DISABLE_ARGS - if(tmp_connection.protocol.http.arg_ref_index != 128) { - if(tmp_char == '&') { - tmp_connection.protocol.http.arg_ref_index = 128; - blob = (const unsigned char *)CONST_ADDR(output_handler->handler_args.args_tree); - continue; - } else if(tmp_char == ' ') { - tmp_connection.protocol.http.ready_to_send = 1; - tmp_connection.protocol.http.parsing_state = parsing_end; - break; - } else { - switch(tmp_arg_ref.arg_type) { - case arg_str: { - unsigned char *tmp_size_ptr = ((unsigned char*)tmp_connection.protocol.http.curr_arg + tmp_arg_ref.arg_size - 1); - if(*tmp_size_ptr) { - *((unsigned char*)tmp_connection.protocol.http.curr_arg + (tmp_arg_ref.arg_size - *tmp_size_ptr - 1)) = tmp_char; - (*tmp_size_ptr)--; - } - break; - } - case arg_ui8: - *((unsigned char*)tmp_connection.protocol.http.curr_arg) *= 10; - *((unsigned char*)tmp_connection.protocol.http.curr_arg) += tmp_char - '0'; - break; - case arg_ui16: - *((uint16_t*)tmp_connection.protocol.http.curr_arg) *= 10; - *((uint16_t*)tmp_connection.protocol.http.curr_arg) += tmp_char - '0'; - break; - } - } - } else +#if !defined(DISABLE_POST) || defined(HTTP_AUTH) + else #endif + + if(tmp_connection.protocol.http.parsing_state == parsing_cmd) { +#ifndef DISABLE_POST + if(blob_curr == REQUEST_POST_32_ + 128) { /* post request */ + /* allocating post data structure */ + tmp_connection.protocol.http.post_data = mem_alloc(sizeof(struct post_data_t)); + if(!tmp_connection.protocol.http.post_data){ + output_handler = &http_404_handler; + break; + } + tmp_connection.protocol.http.post_data->content_type = -1; + tmp_connection.protocol.http.post_data->content_length = -1; + tmp_connection.protocol.http.post_data->boundary = NULL; + tmp_connection.protocol.http.post_data->post_data = NULL; + tmp_connection.protocol.http.post_data->filename = NULL; + tmp_connection.protocol.http.post_data->coroutine.curr_context.status = cr_terminated; + } +#endif + tmp_connection.protocol.http.parsing_state = parsing_url; + blob = urls_tree; + } else { + if(tmp_char == ' ') { #ifndef DISABLE_POST - if(tmp_connection.protocol.http.parsing_state == parsing_post_end && blob_curr != HEADER_POST_END){ - blob++; - } - else if( - !(tmp_connection.protocol.http.parsing_state == parsing_post_content_type && (tmp_char == 32 || tmp_char == 58)) - && !(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && blob_curr == ATTRIBUT_CONTENT_45_LENGTH + 128) - && !(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && blob_curr == ATTRIBUT_BOUNDARY_61_ + 128) - && !(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && blob_curr == ATTRIBUT_FILENAME_61_ + 128) - ) -#endif - { - do { - - unsigned char offsetInf = 0; - unsigned char offsetEq = 0; - unsigned char blob_next; + if(tmp_connection.protocol.http.post_data && tmp_connection.protocol.http.post_url_detected == 0) { /* post unauthorized */ + output_handler = &http_404_handler; + break; + } + else{ +#endif + if(!output_handler) { + output_handler = (struct output_handler_t*)CONST_ADDR(resources_index[blob_curr - 128]); + tmp_blob = blob_curr - 128; + } + +#if !defined(DISABLE_POST) || defined(HTTP_AUTH) + if ( #ifndef DISABLE_POST - if(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && tmp_char < 123 && tmp_char > 96) - tmp_char = tmp_char - 'a' + 'A'; -#endif - blob_curr = CONST_READ_UI8(blob); - blob_next = CONST_READ_UI8(++blob); - if (tmp_char != blob_curr && blob_next >= 128) { - blob_next = CONST_READ_UI8(++blob); - } - if (blob_next < 32) { - offsetInf += ((blob_next>>2) & 1) + ((blob_next>>1) & 1) + (blob_next & 1); - offsetEq = offsetInf + ((blob_next & 2)?CONST_READ_UI8(blob+1):0); - } - if (tmp_char == blob_curr) { - if (blob_next < 32) { - if (blob_next & 2) { - blob += offsetEq; - } else { + tmp_connection.protocol.http.post_data +#endif +#if !defined(DISABLE_POST) && defined(HTTP_AUTH) + || +#endif +#ifdef HTTP_AUTH + IS_RESTRICTED(output_handler) +#endif + ) { + tmp_connection.protocol.http.parsing_state = parsing_post_attributes; + blob = blob_http_header_content; + tmp_connection.protocol.http.ready_to_send = 0; + } + else { +#endif + tmp_connection.protocol.http.parsing_state = parsing_end; + break; +#if !defined(DISABLE_POST) || defined(HTTP_AUTH) + } +#endif +#ifndef DISABLE_POST + } +#endif + } else { + +#ifndef DISABLE_ARGS + if(tmp_char == '?' #ifndef DISABLE_POST - if(tmp_connection.protocol.http.parsing_state == parsing_post_attributes) - blob = blob_http_header_content; - else -#endif - output_handler = &http_404_handler; - break; - } - } - break; - } else if (tmp_char < blob_curr) { - if (blob_next < 32 && blob_next & 1) { - blob += offsetInf; - } else { + || (tmp_connection.protocol.http.parsing_state == parsing_post_args && tmp_char == 10) +#endif + ){ + uint16_t tmp_args_size; + if(!output_handler) { + output_handler = (struct output_handler_t*)CONST_ADDR(resources_index[blob_curr - 128]); + tmp_blob = blob_curr - 128; + } + tmp_args_size = CONST_UI16(output_handler->handler_args.args_size); + tmp_args_size_ref = tmp_args_size; + tmp_connection.protocol.http.ready_to_send = 0; + if(tmp_args_size) { + uint16_t i; + blob = (const unsigned char *)CONST_ADDR(output_handler->handler_args.args_tree); + tmp_connection.protocol.http.args = mem_alloc(tmp_args_size); /* test NULL: done */ + if(tmp_connection.protocol.http.args == NULL) { + output_handler = &http_404_handler; + break; + } + for(i =0 ; i < tmp_args_size ; ++i) { + ((unsigned char *)tmp_connection.protocol.http.args)[i] = 0; + } + continue; + } + } else if(tmp_char == '=' && tmp_connection.protocol.http.args) { + struct arg_ref_t * /*CONST_VAR*/ tmp_arg_ref_ptr; + tmp_connection.protocol.http.arg_ref_index = blob_curr - 128; + tmp_arg_ref_ptr = &(((struct arg_ref_t*)CONST_ADDR(output_handler->handler_args.args_index))[tmp_connection.protocol.http.arg_ref_index]); + tmp_arg_ref.arg_type = CONST_UI8(tmp_arg_ref_ptr->arg_type); + tmp_arg_ref.arg_size = CONST_UI8(tmp_arg_ref_ptr->arg_size); + tmp_arg_ref.arg_offset = CONST_UI8(tmp_arg_ref_ptr->arg_offset); + tmp_connection.protocol.http.curr_arg = ((unsigned char*)tmp_connection.protocol.http.args) + tmp_arg_ref.arg_offset; + if(tmp_arg_ref.arg_type == arg_str) + (*((unsigned char*)tmp_connection.protocol.http.curr_arg + tmp_arg_ref.arg_size - 1)) = tmp_arg_ref.arg_size - 1; + continue; + } else if(tmp_char == '&') { + blob = (const unsigned char *)CONST_ADDR(output_handler->handler_args.args_tree); + } else { + blob++; + } +#else + blob++; +#endif + } + } + blob_curr = CONST_READ_UI8(blob); + } + +#if !defined(DISABLE_POST) || defined(HTTP_AUTH) + /* end header detection */ + if(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && tmp_char == 13){ + blob = blob_http_header_end; + tmp_connection.protocol.http.parsing_state = parsing_post_end; + } + else if(tmp_connection.protocol.http.parsing_state == parsing_post_end){ + if(tmp_char != blob_curr){ + blob = blob_http_header_content; + tmp_connection.protocol.http.parsing_state = parsing_post_attributes; + } + } +#endif +#ifndef DISABLE_ARGS + if(tmp_connection.protocol.http.arg_ref_index != 128) { + if(tmp_char == '&') { + tmp_connection.protocol.http.arg_ref_index = 128; + blob = (const unsigned char *)CONST_ADDR(output_handler->handler_args.args_tree); + continue; + } + else if(tmp_char == ' ') { + tmp_connection.protocol.http.ready_to_send = 1; + tmp_connection.protocol.http.parsing_state = parsing_end; + break; + } + else { + switch(tmp_arg_ref.arg_type) { + case arg_str: { + unsigned char *tmp_size_ptr = ((unsigned char*)tmp_connection.protocol.http.curr_arg + tmp_arg_ref.arg_size - 1); + if(*tmp_size_ptr) { + *((unsigned char*)tmp_connection.protocol.http.curr_arg + (tmp_arg_ref.arg_size - *tmp_size_ptr - 1)) = tmp_char; + (*tmp_size_ptr)--; + } + break; + } + case arg_ui8: + *((unsigned char*)tmp_connection.protocol.http.curr_arg) *= 10; + *((unsigned char*)tmp_connection.protocol.http.curr_arg) += tmp_char - '0'; + break; + case arg_ui16: + *((uint16_t*)tmp_connection.protocol.http.curr_arg) *= 10; + *((uint16_t*)tmp_connection.protocol.http.curr_arg) += tmp_char - '0'; + break; + } + } + } else +#endif +#if !defined(DISABLE_POST) || defined(HTTP_AUTH) + if(tmp_connection.protocol.http.parsing_state == parsing_post_end && blob_curr != HEADER_POST_END){ + blob++; + } + else if ( #ifndef DISABLE_POST - if(tmp_connection.protocol.http.parsing_state == parsing_post_attributes) - blob = blob_http_header_content; - else -#endif - output_handler = &http_404_handler; - break; - } - } else { - if (blob_next < 32 && blob_next & 4) { - unsigned char offsetSup = offsetEq + ((blob_next & 3)?CONST_READ_UI8(blob+(offsetInf-1)):0); - blob += offsetSup; - } else { + !(tmp_connection.protocol.http.parsing_state == parsing_post_content_type && (tmp_char == 32 || tmp_char == 58)) + && !(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && blob_curr == ATTRIBUT_CONTENT_45_LENGTH + 128) + && !(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && blob_curr == ATTRIBUT_BOUNDARY_61_ + 128) + && !(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && blob_curr == ATTRIBUT_FILENAME_61_ + 128) +#endif +#if !defined(DISABLE_POST) && defined(HTTP_AUTH) + && +#endif +#ifdef HTTP_AUTH + !(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && blob_curr == ATTRIBUT_AUTHORIZATION_58_ + 128) +#if HTTP_AUTH == HTTP_AUTH_DIGEST + && !(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && blob_curr == ATTRIBUT_USERNAME_61_ + 128) + && !(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && blob_curr == ATTRIBUT_NONCE_61_ + 128) + && !(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && blob_curr == ATTRIBUT_RESPONSE_61_ + 128) +#endif +#endif + ) +#endif + { + do { + + unsigned char offsetInf = 0; + unsigned char offsetEq = 0; + unsigned char blob_next; + +#if !defined(DISABLE_POST) || defined(HTTP_AUTH) + if ((tmp_connection.protocol.http.parsing_state == parsing_post_attributes +#if defined(HTTP_AUTH) && HTTP_AUTH == HTTP_AUTH_DIGEST + || tmp_connection.protocol.http.parsing_state == parsing_authorization_username +#endif + ) + && tmp_char < 123 && tmp_char > 96) + tmp_char = tmp_char - 'a' + 'A'; +#endif + + blob_curr = CONST_READ_UI8(blob); + blob_next = CONST_READ_UI8(++blob); + + if (tmp_char != blob_curr && blob_next >= 128) { + blob_next = CONST_READ_UI8(++blob); + } + + if (blob_next < 32) { + offsetInf += ((blob_next>>2) & 1) + ((blob_next>>1) & 1) + (blob_next & 1); + offsetEq = offsetInf + ((blob_next & 2)?CONST_READ_UI8(blob+1):0); + } + + if (tmp_char == blob_curr) { + if (blob_next < 32) { + if (blob_next & 2) { + blob += offsetEq; + } + else { +#if !defined(DISABLE_POST) || defined(HTTP_AUTH) + if (tmp_connection.protocol.http.parsing_state == parsing_post_attributes) + blob = blob_http_header_content; + else +#endif +#if defined(HTTP_AUTH) && HTTP_AUTH == HTTP_AUTH_DIGEST + if (tmp_connection.protocol.http.parsing_state == parsing_authorization_username) + break; + else +#endif + output_handler = &http_404_handler; + break; + } + } + break; + } + else if (tmp_char < blob_curr) { + if (blob_next < 32 && blob_next & 1) { + blob += offsetInf; + } + else { +#if !defined(DISABLE_POST) || defined(HTTP_AUTH) + if(tmp_connection.protocol.http.parsing_state == parsing_post_attributes) + blob = blob_http_header_content; + else +#endif +#if defined(HTTP_AUTH) && HTTP_AUTH == HTTP_AUTH_DIGEST + if (tmp_connection.protocol.http.parsing_state == parsing_authorization_username) + break; + else +#endif + output_handler = &http_404_handler; + break; + } + } + else { + if (blob_next < 32 && blob_next & 4) { + unsigned char offsetSup = offsetEq + ((blob_next & 3)?CONST_READ_UI8(blob+(offsetInf-1)):0); + blob += offsetSup; + } + else { +#if !defined(DISABLE_POST) || defined(HTTP_AUTH) + if(tmp_connection.protocol.http.parsing_state == parsing_post_attributes) { + blob = blob_http_header_content; + } + else +#endif +#if defined(HTTP_AUTH) && HTTP_AUTH == HTTP_AUTH_DIGEST + if (tmp_connection.protocol.http.parsing_state == parsing_authorization_username) + break; + else +#endif + output_handler = &http_404_handler; + break; + } + } + } while(1); + } + } + + /* detecting parsing_end */ + if( #ifndef DISABLE_POST - if(tmp_connection.protocol.http.parsing_state == parsing_post_attributes) - blob = blob_http_header_content; - else -#endif - output_handler = &http_404_handler; - break; - } - } - } while(1); - } - } - /* detecting parsing_end */ - if( + (tmp_connection.protocol.http.parsing_state == parsing_post_args && !tmp_connection.protocol.http.post_data->content_length) || +#endif + ((output_handler == &http_404_handler #ifndef DISABLE_POST - (tmp_connection.protocol.http.parsing_state == parsing_post_args && !tmp_connection.protocol.http.post_data->content_length) || + || output_handler == &http_505_handler +#endif +#ifdef HTTP_AUTH + || output_handler == &http_401_handler #endif - ((output_handler == &http_404_handler + ) && tmp_connection.protocol.http.parsing_state != parsing_cmd)) { + tmp_connection.protocol.http.parsing_state = parsing_end; + tmp_connection.protocol.http.ready_to_send = 1; + } + + if(!output_handler) { + tmp_connection.protocol.http.blob = blob; + } + else { +#ifdef HTTP_AUTH + char stale; + + /* [HTTP-Auth]: + * If the requested handler is restricted, we set the output handler + * on 401 if credentials are bad or missing, in which case we need to + * store the requested resource's handler into the blob field of the + * connection structure, in order to be able to determine when sending + * later which uri was requested. */ + if (IS_RESTRICTED (output_handler) + && output_handler != &http_401_handler + && output_handler != &http_404_handler #ifndef DISABLE_POST - || output_handler == &http_505_handler -#endif - ) && tmp_connection.protocol.http.parsing_state != parsing_cmd)){ - tmp_connection.protocol.http.parsing_state = parsing_end; - tmp_connection.protocol.http.ready_to_send = 1; - } - if(!output_handler) - tmp_connection.protocol.http.blob = blob; - else { - if(tmp_connection.protocol.http.parsing_state != parsing_cmd) { - tmp_connection.output_handler = output_handler; - UI32(tmp_connection.protocol.http.next_outseqno) = UI32(current_inack); - if(CONST_UI8(output_handler->handler_type) == type_file) { - UI32(tmp_connection.protocol.http.final_outseqno) = UI32(tmp_connection.protocol.http.next_outseqno) + CONST_UI32(GET_FILE(output_handler).length); - } else { - UI32(tmp_connection.protocol.http.final_outseqno) = UI32(tmp_connection.protocol.http.next_outseqno) - 1; - } + && output_handler != &http_505_handler +#endif +#if HTTP_AUTH == HTTP_AUTH_BASIC + && (!auth_data.credentials + || (http_basic_authenticate (output_handler, + (unsigned const char *)(auth_data.credentials)) + != HTTP_AUTHENTICATE_SUCCESS)) +#elif HTTP_AUTH == HTTP_AUTH_DIGEST + && (!auth_data.scheme_parsed + || auth_data.username_blob < 128 + || auth_data.nonce[NONCE_LEN - 1] == '\0' + || auth_data.response[MD5_DIGEST_LEN - 1] == '\0' + || (stale = http_digest_authenticate (connection, + output_handler, + &auth_data) + ) != HTTP_AUTHENTICATE_SUCCESS) +#endif + ) { + + tmp_connection.protocol.http.blob = (unsigned char*)output_handler; + output_handler = &http_401_handler; + + /* Set ready_to_send and parsing_state on correct values if not. */ + if (!tmp_connection.protocol.http.ready_to_send) + tmp_connection.protocol.http.ready_to_send = 1; + if (tmp_connection.protocol.http.parsing_state != parsing_end) + tmp_connection.protocol.http.parsing_state = parsing_end; + +#if HTTP_AUTH == HTTP_AUTH_BASIC + /* Compute credentials length and free memory */ + if (auth_data.credentials) { + uint8_t i = 0; + while (auth_data.credentials[i++] != '\0'); /* Don't forget to count the '\0' */ + mem_free (auth_data.credentials, i * sizeof (char)); + } +#endif + } +#endif + + if (tmp_connection.protocol.http.parsing_state != parsing_cmd) { + tmp_connection.output_handler = output_handler; + UI32(tmp_connection.protocol.http.next_outseqno) = UI32(current_inack); + + if (CONST_UI8(output_handler->handler_type) == type_file) { +#ifdef HTTP_AUTH + /* [HTTP-Auth]: + * Here, we need to compute the full length of the file, including + * the missing header that we dynamically generate. Please refer to + * http_401_handler_length definitions in auth.c for more details. */ + if (output_handler == &http_401_handler) { + UI32(tmp_connection.protocol.http.final_outseqno) = + UI32(tmp_connection.protocol.http.next_outseqno) + + http_401_handler_length ((struct output_handler_t*)tmp_connection.protocol.http.blob, 0); + } + else { + UI32(tmp_connection.protocol.http.final_outseqno) = + UI32(tmp_connection.protocol.http.next_outseqno) + + CONST_UI32(GET_FILE(output_handler).length); + } +#else + UI32(tmp_connection.protocol.http.final_outseqno) = + UI32(tmp_connection.protocol.http.next_outseqno) + + CONST_UI32(GET_FILE(output_handler).length); +#endif + } + else { + UI32(tmp_connection.protocol.http.final_outseqno) = UI32(tmp_connection.protocol.http.next_outseqno) - 1; + } + #ifndef DISABLE_COMET - tmp_connection.protocol.http.comet_send_ack = CONST_UI8(output_handler->handler_comet) ? 1 : 0; - tmp_connection.protocol.http.comet_passive = 0; - tmp_connection.protocol.http.comet_streaming = 0; + tmp_connection.protocol.http.comet_send_ack = CONST_UI8(output_handler->handler_comet) ? 1 : 0; + tmp_connection.protocol.http.comet_passive = 0; + tmp_connection.protocol.http.comet_streaming = 0; #endif - } - if(tmp_connection.protocol.http.parsing_state == parsing_end || tmp_connection.protocol.http.parsing_state == parsing_cmd){ + } + + if(tmp_connection.protocol.http.parsing_state == parsing_end || tmp_connection.protocol.http.parsing_state == parsing_cmd){ #ifndef DISABLE_POST - /* cleaning memory */ - if(tmp_connection.protocol.http.post_data){ /* Warning : don't clean post_data, useful in output function (unless error 404 or 505) */ - if(tmp_connection.protocol.http.post_data->filename){ - uint8_t i = 0; - while(tmp_connection.protocol.http.post_data->filename[i++] != '\0'); - mem_free(tmp_connection.protocol.http.post_data->filename,i*sizeof(char)); - tmp_connection.protocol.http.post_data->filename = NULL; - } - if(tmp_connection.protocol.http.post_data->boundary){ - if(tmp_connection.protocol.http.post_data->boundary->boundary_ref && tmp_connection.protocol.http.post_data->content_length != (uint16_t)-1) - mem_free(tmp_connection.protocol.http.post_data->boundary->boundary_ref,tmp_connection.protocol.http.post_data->boundary->boundary_size*sizeof(char)); - if(tmp_connection.protocol.http.post_data->boundary->boundary_buffer) - mem_free(tmp_connection.protocol.http.post_data->boundary->boundary_buffer,(tmp_connection.protocol.http.post_data->boundary->boundary_size)*sizeof(char)); - mem_free(tmp_connection.protocol.http.post_data->boundary,sizeof(struct boundary_t)); - } - tmp_connection.protocol.http.post_data->boundary = NULL; - } - if(output_handler == &http_404_handler + /* cleaning memory */ + if(tmp_connection.protocol.http.post_data){ /* Warning : don't clean post_data, useful in output function (unless error 404 or 505) */ + if(tmp_connection.protocol.http.post_data->filename){ + uint8_t i = 0; + while(tmp_connection.protocol.http.post_data->filename[i++] != '\0'); + mem_free(tmp_connection.protocol.http.post_data->filename,i*sizeof(char)); + tmp_connection.protocol.http.post_data->filename = NULL; + } + if(tmp_connection.protocol.http.post_data->boundary){ + if(tmp_connection.protocol.http.post_data->boundary->boundary_ref && tmp_connection.protocol.http.post_data->content_length != (uint16_t)-1) + mem_free(tmp_connection.protocol.http.post_data->boundary->boundary_ref,tmp_connection.protocol.http.post_data->boundary->boundary_size*sizeof(char)); + if(tmp_connection.protocol.http.post_data->boundary->boundary_buffer) + mem_free(tmp_connection.protocol.http.post_data->boundary->boundary_buffer,(tmp_connection.protocol.http.post_data->boundary->boundary_size)*sizeof(char)); + mem_free(tmp_connection.protocol.http.post_data->boundary,sizeof(struct boundary_t)); + } + tmp_connection.protocol.http.post_data->boundary = NULL; + } + + if(output_handler == &http_404_handler #ifndef DISABLE_POST - || output_handler == &http_505_handler -#endif - ){ - /* cleaning post_data if error */ - if(tmp_connection.protocol.http.post_data){ - mem_free(tmp_connection.protocol.http.post_data,sizeof(struct post_data_t)); - tmp_connection.protocol.http.post_data = NULL; - } + || output_handler == &http_505_handler +#endif + ){ + /* cleaning post_data if error */ + if(tmp_connection.protocol.http.post_data){ + mem_free(tmp_connection.protocol.http.post_data,sizeof(struct post_data_t)); + tmp_connection.protocol.http.post_data = NULL; + } #ifndef DISABLE_ARGS - /* cleaning args data if error */ - if(tmp_connection.protocol.http.args){ - mem_free(tmp_connection.protocol.http.args,tmp_args_size_ref); - tmp_connection.protocol.http.args = NULL; - } + /* cleaning args data if error */ + if(tmp_connection.protocol.http.args){ + mem_free(tmp_connection.protocol.http.args,tmp_args_size_ref); + tmp_connection.protocol.http.args = NULL; + } #endif - } + } +#endif + tmp_connection.protocol.http.parsing_state = parsing_out; + +#ifdef HTTP_AUTH + /* [HTTP-Auth]: + * If output_handler is the 401 handler, we cannot reset the blob field + * of the temporary connection structure for now, 'cause we need to + * keep a reference to the originally requested handler. */ + if (output_handler != &http_401_handler) + tmp_connection.protocol.http.blob = blob_http_rqt; +#else + tmp_connection.protocol.http.blob = blob_http_rqt; #endif - tmp_connection.protocol.http.parsing_state = parsing_out; - tmp_connection.protocol.http.blob = blob_http_rqt; + #ifndef DISABLE_ARGS - tmp_connection.protocol.http.arg_ref_index = 128; + tmp_connection.protocol.http.arg_ref_index = 128; #endif - } - else - tmp_connection.protocol.http.blob = blob; - } + } + else + tmp_connection.protocol.http.blob = blob; } - /* drop remaining TCP data */ - while(x++ < segment_length) - DEV_GETC(tmp_char); + } - /* acknowledge received and processed TCP data if no there is no current output_handler */ - if(!tmp_connection.output_handler && tmp_connection.protocol.http.tcp_state == tcp_established && segment_length) { - tmp_connection.output_handler = &ref_ack; - } + /* drop remaining TCP data */ + while(x++ < segment_length) + DEV_GETC(tmp_char); - /* check TCP checksum using the partially precalculated pseudo header checksum */ - checksum_end(); - if(UI16(current_checksum) == TCP_CHK_CONSTANT_PART) { - if(defer_clean_service) { /* free in-flight segment information for acknowledged segments */ + /* acknowledge received and processed TCP data if no there is no current output_handler */ + if(!tmp_connection.output_handler && tmp_connection.protocol.http.tcp_state == tcp_established && segment_length) { + tmp_connection.output_handler = &ref_ack; + } + + /* check TCP checksum using the partially precalculated pseudo header checksum */ + checksum_end(); + if(UI16(current_checksum) == TCP_CHK_CONSTANT_PART) { + if(defer_clean_service) { /* free in-flight segment information for acknowledged segments */ #ifdef DISABLE_COROUTINES - DYNAMIC_STATE_CHANGE(ack_received); - /* received ack of the last dynamic segment, dynamic handling is done */ - if (curr_output.dynamic_service_state != none && /* Dynamic content is served */ - tmp_connection.protocol.http.generator_service == curr_output.service && /* This is the currently served dynamic connection */ - !curr_output.in_handler && /* Dynamic handler is finished */ - (curr_output.service_header == header_standard || /* Ack from a single segment data */ - (curr_output.service_header == header_none && curr_output.content_length == 0))) /* or the ack of the last void chunk */ - { - DYNAMIC_STATE_CHANGE(none); - /* When no coroutine, we only have one in_flight_infos. Thus, it has do be freed only at the end */ - clean_service(tmp_connection.protocol.http.generator_service, current_inack); - } + DYNAMIC_STATE_CHANGE(ack_received); + /* received ack of the last dynamic segment, dynamic handling is done */ + if (curr_output.dynamic_service_state != none && /* Dynamic content is served */ + tmp_connection.protocol.http.generator_service == curr_output.service && /* This is the currently served dynamic connection */ + !curr_output.in_handler && /* Dynamic handler is finished */ + (curr_output.service_header == header_standard || /* Ack from a single segment data */ + (curr_output.service_header == header_none && curr_output.content_length == 0))) /* or the ack of the last void chunk */ + { + DYNAMIC_STATE_CHANGE(none); + /* When no coroutine, we only have one in_flight_infos. Thus, it has do be freed only at the end */ + clean_service(tmp_connection.protocol.http.generator_service, current_inack); + } #else - clean_service(tmp_connection.protocol.http.generator_service, current_inack); + clean_service(tmp_connection.protocol.http.generator_service, current_inack); #endif - if(defer_free_handler) { /* free handler and generator service if the service is completely acknowledged */ + if(defer_free_handler) { /* free handler and generator service if the service is completely acknowledged */ #ifndef DISABLE_COROUTINES - cr_clean(&tmp_connection.protocol.http.generator_service->coroutine); + cr_clean(&tmp_connection.protocol.http.generator_service->coroutine); #endif - mem_free(tmp_connection.protocol.http.generator_service, sizeof(struct generator_service_t)); - tmp_connection.protocol.http.generator_service = NULL; + mem_free(tmp_connection.protocol.http.generator_service, sizeof(struct generator_service_t)); + tmp_connection.protocol.http.generator_service = NULL; #ifndef DISABLE_ARGS - mem_free(defer_free_args, defer_free_args_size); + mem_free(defer_free_args, defer_free_args_size); #endif - } - } + } + } - if(!connection && tmp_connection.protocol.http.tcp_state == tcp_syn_rcvd) { - connection = add_connection(&tmp_connection + if(!connection && tmp_connection.protocol.http.tcp_state == tcp_syn_rcvd) { + connection = add_connection(&tmp_connection #ifdef IPV6 - , compressed_ip_size(comp_ipv6_addr) -#endif - ); - /* update the pointer in the tmp_connection because - * it will be copied later so if the pointers do not have the right value, the list - * will be screwed */ - if (connection) - { - tmp_connection.prev = connection->prev; - tmp_connection.next = connection->next; - } + , compressed_ip_size(comp_ipv6_addr) +#endif + ); + /* update the pointer in the tmp_connection because + * it will be copied later so if the pointers do not have the right value, the list + * will be screwed */ + if (connection) + { + tmp_connection.prev = connection->prev; + tmp_connection.next = connection->next; } - - if(!connection) { - /* no valid connection has been found for this packet, send a reset */ - UI32(tmp_connection.protocol.http.next_outseqno) = UI32(current_inack); + } + + if(!connection) { + /* no valid connection has been found for this packet, send a reset */ + UI32(tmp_connection.protocol.http.next_outseqno) = UI32(current_inack); #ifdef IPV6 - memcpy(rst_connection.ip_addr, full_ipv6_addr, 16); + memcpy(rst_connection.ip_addr, full_ipv6_addr, 16); #else - UI32(rst_connection.ip_addr) = UI32(tmp_connection.ip_addr); + UI32(rst_connection.ip_addr) = UI32(tmp_connection.ip_addr); #endif - UI16(rst_connection.port) = UI16(tmp_connection.protocol.http.port); - UI32(rst_connection.current_inseqno) = UI32(tmp_connection.protocol.http.current_inseqno); - UI32(rst_connection.next_outseqno) = UI32(tmp_connection.protocol.http.next_outseqno); - } else { - if(tmp_connection.protocol.http.tcp_state == tcp_listen) { + UI16(rst_connection.port) = UI16(tmp_connection.protocol.http.port); + UI32(rst_connection.current_inseqno) = UI32(tmp_connection.protocol.http.current_inseqno); + UI32(rst_connection.next_outseqno) = UI32(tmp_connection.protocol.http.next_outseqno); + } + else { + if (tmp_connection.protocol.http.tcp_state == tcp_listen) { #ifdef DISABLE_COROUTINES - if (curr_output.dynamic_service_state != none && tmp_connection.protocol.http.generator_service == curr_output.service) - { - if (curr_output.in_handler) - { - DYNAMIC_STATE_CHANGE(connection_terminated); /* If we are still in the handler, we have to notify it of the end of the connection */ - } - else - DYNAMIC_STATE_CHANGE(none); /* Otherwise, the connection was closed while handling last data segment or last chunk, thus can be fully discarded. - Turn the state to not serving dynamic */ - } + if (curr_output.dynamic_service_state != none && tmp_connection.protocol.http.generator_service == curr_output.service) + { + if (curr_output.in_handler) + { + DYNAMIC_STATE_CHANGE(connection_terminated); /* If we are still in the handler, we have to notify it of the end of the connection */ + } + else + DYNAMIC_STATE_CHANGE(none); /* Otherwise, the connection was closed while handling last data segment or last chunk, thus can be fully discarded. + Turn the state to not serving dynamic */ + } +#endif + free_connection(connection); + } + else { + /* update the current connection */ + *connection = tmp_connection; +#ifdef HTTP_AUTH + /* [HTTP-Auth]: + * Reset the blob field of the temporary connection structure, + * 'cause it wasn't done before if output handler is 401. */ + if (tmp_connection.output_handler == &http_401_handler) { + tmp_connection.protocol.http.blob = blob_http_rqt; + } #endif - free_connection(connection); - } else { - /* update the current connection */ - *connection = tmp_connection; + #ifdef IPV6 - copy_compressed_ip(connection->ip_addr, comp_ipv6_addr); + copy_compressed_ip(connection->ip_addr, comp_ipv6_addr); #endif - } - } + } } - return 1; + } + + return 1; } diff --git a/core/md5.c b/core/md5.c new file mode 100644 index 0000000..188d69f --- /dev/null +++ b/core/md5.c @@ -0,0 +1,345 @@ +/* + * Copyright or © or Copr. 2008, Simon Duquennoy + * + * Author e-mail: simon.duquennoy@lifl.fr + * + * This software is a computer program whose purpose is to design an + * efficient Web server for very-constrained embedded system. + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. + */ + +/* + * Author: Christophe Bacara + * Author e-mail: christophe.bacara@etudiant.univ-lille1.fr + * + * Original software written by L. Peter Deutsch, for Aladdin Enterprises + * Improvements and optimizations for embedded target by Christophe Bacara + */ + +#include "md5.h" + +#define T1 T[0] +#define T2 T[1] +#define T3 T[2] +#define T4 T[3] +#define T5 T[4] +#define T6 T[5] +#define T7 T[6] +#define T8 T[7] +#define T9 T[8] +#define T10 T[9] +#define T11 T[10] +#define T12 T[11] +#define T13 T[12] +#define T14 T[13] +#define T15 T[14] +#define T16 T[15] +#define T17 T[16] +#define T18 T[17] +#define T19 T[18] +#define T20 T[19] +#define T21 T[20] +#define T22 T[21] +#define T23 T[22] +#define T24 T[23] +#define T25 T[24] +#define T26 T[25] +#define T27 T[26] +#define T28 T[27] +#define T29 T[28] +#define T30 T[29] +#define T31 T[30] +#define T32 T[31] +#define T33 T[32] +#define T34 T[33] +#define T35 T[34] +#define T36 T[35] +#define T37 T[36] +#define T38 T[37] +#define T39 T[38] +#define T40 T[39] +#define T41 T[40] +#define T42 T[41] +#define T43 T[42] +#define T44 T[43] +#define T45 T[44] +#define T46 T[45] +#define T47 T[46] +#define T48 T[47] +#define T49 T[48] +#define T50 T[49] +#define T51 T[50] +#define T52 T[51] +#define T53 T[52] +#define T54 T[53] +#define T55 T[54] +#define T56 T[55] +#define T57 T[56] +#define T58 T[57] +#define T59 T[58] +#define T60 T[59] +#define T61 T[60] +#define T62 T[61] +#define T63 T[62] +#define T64 T[63] + +static const uint32_t T[64] = { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 +}; + +/* Define the state of the MD5 Algorithm. */ +static struct { + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ +} md5_state; + +/* Store the final MD5 digest */ +md5_byte_t md5_digest[16]; + +static void md5_process(const md5_byte_t *data /* [64] */) +{ + md5_word_t /* Temporary word a,b,c,d */ + a = md5_state.abcd[0], b = md5_state.abcd[1], + c = md5_state.abcd[2], d = md5_state.abcd[3]; + md5_word_t t; + md5_word_t X[16]; + unsigned char i; + +#if ENDIANNESS == LITTLE_ENDIAN + memcopy(X, data, 64); +#else + for (i = 0; i < 16; ++i, data += 4) + X[i] = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24); +#endif + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation */ + /* a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti) \ + t = a + F(b,c,d) + X[k] + Ti; \ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation */ + /* a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti) \ + t = a + G(b,c,d) + X[k] + Ti; \ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation */ + /* a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti) \ + t = a + H(b,c,d) + X[k] + Ti; \ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation */ + /* a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti) \ + t = a + I(b,c,d) + X[k] + Ti; \ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each */ + /* of the four registers by the value it had before this block */ + /* was started.) */ + md5_state.abcd[0] += a; + md5_state.abcd[1] += b; + md5_state.abcd[2] += c; + md5_state.abcd[3] += d; +} + +void md5_init() +{ + md5_state.count[0] = 0; + md5_state.count[1] = 0; + md5_state.abcd[0] = 0x67452301; + md5_state.abcd[1] = 0xefcdab89; + md5_state.abcd[2] = 0x98badcfe; + md5_state.abcd[3] = 0x10325476; +} + +void md5_append(const md5_byte_t *data, uint32_t nbytes) +{ + uint32_t offset = (md5_state.count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + md5_state.count[1] += nbytes >> 29; + md5_state.count[0] += nbits; + if (md5_state.count[0] < nbits) + md5_state.count[1]++; + + /* Process an initial partial block. */ + if (offset) { + uint32_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcopy(md5_state.buf + offset, data, copy); + if (offset + copy < 64) + return; + data += copy; + nbytes -= copy; + md5_process(md5_state.buf); + } + + /* Process full blocks. */ + for (; nbytes >= 64; data += 64, nbytes -= 64) + md5_process(data); + + /* Process a final partial block. */ + if (nbytes) + memcopy(md5_state.buf, data, nbytes); +} + +void md5_end() +{ + static const md5_byte_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(md5_state.count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pad, ((55 - (md5_state.count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(data, 8); + + for (i = 0; i < 16; ++i) + md5_digest[i] = (md5_byte_t)(md5_state.abcd[i >> 2] >> ((i & 3) << 3)); +} + +/* Useful for improved version of processing */ +/* static const uint8_t R[64] = { */ +/* 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, */ +/* 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, */ +/* 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, */ +/* 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 */ +/* }; */ diff --git a/core/md5.h b/core/md5.h new file mode 100644 index 0000000..d7662ee --- /dev/null +++ b/core/md5.h @@ -0,0 +1,73 @@ +/* + * Copyright or © or Copr. 2008, Simon Duquennoy + * + * Author e-mail: simon.duquennoy@lifl.fr + * + * This software is a computer program whose purpose is to design an + * efficient Web server for very-constrained embedded system. + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. + */ + +/* + * Author: Christophe Bacara + * `-Mail: christophe.bacara@etudiant.univ-lille1.fr + * + * Original software written by L. Peter Deutsch, for Aladdin Enterprises + * Few improvements for embedded target by Christophe Bacara + */ + +#ifndef __MD5_H__ +#define __MD5_H__ + +#include "utils.h" + +#include +#include + +#define MD5_DIGEST_LEN 32 + +/* As digest is stored on 16 bytes, useful to get the nth character + * of the hexadecimal representation of the digest */ +#define MD5_DIGEST_GET_NTH_HEXC(i) \ + (hex_char[((i & 1) ? (md5_digest[i >> 1] & 0x0f) : ((md5_digest[i >> 1] & 0xf0) >> 4))]) + +/* Internal type definitions */ +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef uint32_t md5_word_t; /* 32-bit word */ + +/* Digest storage */ +extern md5_byte_t md5_digest[16]; + +/* Initialize the algorithm. */ +extern void md5_init(); +/* Append a string to the message. */ +extern void md5_append(const md5_byte_t *data, uint32_t nbytes); +/* Finish the message and return the digest. */ +extern void md5_end(); + +#endif diff --git a/core/output.c b/core/output.c index 74b064c..ea9745d 100644 --- a/core/output.c +++ b/core/output.c @@ -43,11 +43,14 @@ #include "memory.h" #include "input.h" /* for *_HEADER_SIZE defines */ #include "handlers.h" - -#ifndef DISABLE_POST #include "defines.h" + +#ifdef HTTP_AUTH +#include "auth.h" /* For authentication header and nonce control */ #endif +#include + /* IPV6 Common values */ #ifdef IPV6 @@ -101,7 +104,6 @@ static CONST_VAR (char, serviceHttpHeaderChunked[]) = "HTTP/1.1 200 OK\r\nConten #define MIN(a,b) ((a) < (b) ? (a) : (b)) - struct curr_output_t curr_output; /* default DEV_PUT16 */ @@ -264,6 +266,13 @@ void smews_send_packet (struct connection *connection) unsigned char full_ipv6_addr[16]; #endif +#ifdef HTTP_AUTH + /* Buffer for dynamic header length */ + uint16_t dynamic_header_length; + /* Buffer for static file length */ + uint16_t static_length; +#endif + #ifdef SMEWS_SENDING SMEWS_SENDING; #endif @@ -312,7 +321,25 @@ void smews_send_packet (struct connection *connection) max_out_size = MAX_OUT_SIZE (connection->protocol.http.tcp_mss); file_remaining_bytes = UI32 (connection->protocol.http.final_outseqno) - UI32 (next_outseqno); segment_length = file_remaining_bytes > max_out_size ? max_out_size : file_remaining_bytes; + +#ifdef HTTP_AUTH + if (output_handler == &http_401_handler) { + /* Compute generated header length */ + dynamic_header_length = http_401_handler_dynamic_header_length + ((struct output_handler_t*)connection->protocol.http.blob, 0); + /* Compute index in file while aware of the generated length */ + index_in_file = + CONST_UI32 (GET_FILE (output_handler).length) + + dynamic_header_length + - file_remaining_bytes; + /* Save static length */ + static_length = segment_length - dynamic_header_length; + } + else + index_in_file = CONST_UI32 (GET_FILE (output_handler).length) - file_remaining_bytes; +#else index_in_file = CONST_UI32 (GET_FILE (output_handler).length) - file_remaining_bytes; +#endif break; } case type_generator: @@ -394,7 +421,7 @@ void smews_send_packet (struct connection *connection) } else #endif - UI16 (current_checksum) = BASIC_IP_CHK; + UI16 (current_checksum) = BASIC_IP_CHK; checksum_add32 (local_ip_addr); checksum_add16 (segment_length + IP_HEADER_SIZE + TCP_HEADER_SIZE); @@ -538,16 +565,68 @@ void smews_send_packet (struct connection *connection) { uint16_t i; uint32_t tmp_sum = 0; + uint16_t *tmpptr = - (uint16_t *) CONST_ADDR (GET_FILE (output_handler).chk) + - DIV_BY_CHUNCKS_SIZE (index_in_file); + (uint16_t *) CONST_ADDR (GET_FILE (output_handler).chk) + + DIV_BY_CHUNCKS_SIZE (index_in_file); + +#ifdef HTTP_AUTH + /* [HTTP-Auth]: + * Checksum the dynamically generated header. Be careful + * about odd alignment solved by space insertion. */ + if (output_handler == &http_401_handler) { + /* Getting the realm */ + unsigned const char *char_p = + ((struct output_handler_t*)(connection->protocol.http.blob))->handler_restriction.realm; + + /* Precalculated checksum */ + checksum_add16 (HTTP_AUTHENTICATE_HEADER_CHK); + + /* Checksum the double quoted realm */ + checksum_add ('"'); + while (*char_p){ + checksum_add (*char_p++); + ++tmp_sum; + } + checksum_add ('"'); + + /* Add a space after the double quote if realm is odd string */ + if (tmp_sum % 2) + checksum_add (0x20); + +#if HTTP_AUTH == HTTP_AUTH_DIGEST + /* Precalculated checksum */ + checksum_add16 (HTTP_AUTHENTICATE_HEADER_NONCE_CHK); + + /* Checksum the double quoted nonce */ + checksum_add ('"'); + for (i = 0; i < NONCE_LEN; ++i) + checksum_add (nonce_state.nonce[i]); + checksum_add ('"'); +#endif + } + else + /* If output_handler is not the 401 handler, static length + * is segment length. */ + static_length = segment_length; + tmp_sum = 0; + for (i = 0; i < GET_NB_BLOCKS (static_length); i++) + { + tmp_sum += CONST_READ_UI16 (tmpptr++); + } + + checksum_add32 ((const unsigned char *) &tmp_sum); + break; +#else for (i = 0; i < GET_NB_BLOCKS (segment_length); i++) { tmp_sum += CONST_READ_UI16 (tmpptr++); } + checksum_add32 ((const unsigned char *) &tmp_sum); break; +#endif } default: /* Should never happen but avoids compile warnings */ return; @@ -597,12 +676,56 @@ void smews_send_packet (struct connection *connection) break; case type_file: { - /* Send the payload of the packet */ - const char *tmpptr = - (const char *) (CONST_ADDR (GET_FILE (output_handler).data) + - index_in_file); + /* Send the payload of the packet */ + unsigned const char *tmpptr; +#ifdef HTTP_AUTH + unsigned const char *param; + uint8_t tmp; + + if (output_handler == &http_401_handler) { + /* Sending the http header */ + DEV_PUTN_CONST (HttpAuthenticateHeader, HTTP_AUTHENTICATE_HEADER_LEN); + + /* Sending the double quoted realm */ + param = + ((struct output_handler_t*)(connection->protocol.http.blob))->handler_restriction.realm; + tmpptr = param; + tmp = 0; + while (*tmpptr++) + ++tmp; + + DEV_PUT ('"'); + DEV_PUTN_CONST (param, tmp); + DEV_PUT ('"'); + + if (tmp % 2) + DEV_PUT (' '); + +#if HTTP_AUTH == HTTP_AUTH_DIGEST + /* Sending the second part of the http header */ + DEV_PUTN_CONST (HttpAuthenticateHeaderNonce, HTTP_AUTHENTICATE_HEADER_NONCE_LEN); + + /* Sending the double quoted nonce */ + DEV_PUT ('"'); + DEV_PUTN (nonce_state.nonce, NONCE_LEN); + DEV_PUT ('"'); +#endif + } +#endif + + tmpptr = (unsigned const char*)(CONST_ADDR (GET_FILE (output_handler).data) + index_in_file); + +#ifdef HTTP_AUTH + if (output_handler == &http_401_handler) { + DEV_PUTN_CONST (tmpptr, static_length); + } + else { DEV_PUTN_CONST (tmpptr, segment_length); - break; + } +#else + DEV_PUTN_CONST (tmpptr, segment_length); +#endif + break; } default: /* Should never happen but avoid warnings */ return; @@ -680,7 +803,6 @@ char smews_send (void) struct connection *active_connection = NULL; const struct output_handler_t * /*CONST_VAR */ old_output_handler = NULL; - /* sending reset has the highest priority */ if (UI16 (rst_connection.port)) { @@ -880,6 +1002,7 @@ char smews_send (void) * This step has to be done before before any context_restore or context_backup */ if (cr_prepare (&curr_output.service->coroutine) == NULL) return 1; + #else /* If no coroutines, then having smews_send called while in a handler is equivalent to retransmit the buffer (as the type is forced to persistent) diff --git a/core/smews.h b/core/smews.h index d58cef9..edcce16 100644 --- a/core/smews.h +++ b/core/smews.h @@ -43,6 +43,10 @@ #include "timers.h" #include "memory.h" +#if defined(HTTP_AUTH) && HTTP_AUTH == HTTP_AUTH_DIGEST +#include "auth.h" +#endif + extern void smews_retransmit(void); /* Inlinged because used only once */ @@ -102,6 +106,9 @@ static inline void smews_init(void) { #ifndef DISABLE_TIMERS set_timer(&smews_retransmit,1000); #endif +#if defined(HTTP_AUTH) && HTTP_AUTH == HTTP_AUTH_DIGEST + http_auth_gen_nonce(); +#endif } #endif /* __SMEWS_H__ */ diff --git a/core/utils.c b/core/utils.c new file mode 100644 index 0000000..e488bf2 --- /dev/null +++ b/core/utils.c @@ -0,0 +1,52 @@ +/* + * Copyright or © or Copr. 2008, Simon Duquennoy + * + * Author e-mail: simon.duquennoy@lifl.fr + * + * This software is a computer program whose purpose is to design an + * efficient Web server for very-constrained embedded system. + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. + */ + +/* + * Author: Christophe Bacara + * `-Mail: christophe.bacara@etudiant.univ-lille1.fr + */ + +#include "utils.h" + +unsigned const char hex_char[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' +}; + +void memcopy(void *dst, const void *src, uint32_t nbytes) +{ + while (nbytes--) + *(uint8_t *)(dst++) = *(uint8_t *)(src++); +} diff --git a/core/utils.h b/core/utils.h new file mode 100644 index 0000000..da5a05f --- /dev/null +++ b/core/utils.h @@ -0,0 +1,76 @@ +/* + * Copyright or © or Copr. 2008, Simon Duquennoy + * + * Author e-mail: simon.duquennoy@lifl.fr + * + * This software is a computer program whose purpose is to design an + * efficient Web server for very-constrained embedded system. + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. + */ + +/* + * Author: Christophe Bacara + * `-Mail: christophe.bacara@etudiant.univ-lille1.fr + */ + +#ifndef __UTILS_H__ +#define __UTILS_H__ + +#include "types.h" + +#define LOWER_CASE(c) \ + (c >= 65 && c <= 90 ? c - 'A' + 'a' : c) +#define UPPER_CASE(c) \ + (c >= 97 && c <= 122 ? c - 'a' + 'A' : c) + +#define IS_B64_CHAR(c) \ + ((c >= 97 && c <= 122) \ + || (c >= 65 && c <= 90) \ + || (c >= 48 && c <= 57) \ + || (c == '/') \ + || (c == '+') \ + || (c == '=')) +#define IS_HEX_CHAR(c) \ + ((c >= 97 && c <= 102) \ + || (c >= 65 && c <= 70) \ + || (c >= 48 && c <= 57)) +#define IS_LWS_CHAR(c) \ + (c == ' ' || c == '\t') + +#define GET_HEXC(i) \ + ((i >= 0 && i <= 16) ? hex_char[i] : 0) + +/* Store each hexadecimal character with its value as index */ +extern unsigned const char hex_char[16]; + +/* Copy nbytes bytes from src to dst. */ +extern void memcopy(void *dst, const void *src, uint32_t nbytes); + + + +#endif diff --git a/doc/userguide.pdf b/doc/userguide.pdf index 8e8ff28..29982cb 100644 Binary files a/doc/userguide.pdf and b/doc/userguide.pdf differ diff --git a/tools/GenApps.py b/tools/GenApps.py index 83ca98b..730992a 100755 --- a/tools/GenApps.py +++ b/tools/GenApps.py @@ -34,6 +34,7 @@ import xml.parsers.expat import GenBlob +import GenAuthData import os import gzip import StringIO @@ -42,6 +43,7 @@ import time import datetime import re +import hashlib # initialization propertiesInfos = None @@ -53,6 +55,7 @@ requestList = [] attributListFileName = os.path.join('tools','supportedPostAttributList') attributList = [] +httpAuthUsedUsernames = GenAuthData.getUsedUsernamesList() contentTypeList = [] postList = [] # doGet:1 doPost:2 doPostIn:4 doPostOut:8 args:16 content-types:32 doPacketIn:64 doPacketOut: 128 @@ -105,6 +108,12 @@ def generateBlobsH(dstFile): GenBlob.genBlobTree(hOut,requestList,'blob_http_rqt',False) GenBlob.genBlobTree(hOut,mimesListPost,'mimes_tree',False) GenBlob.genBlobTree(hOut,attributList,'blob_http_header_content',False) + + userList = [ ] + for user in httpAuthUsedUsernames: + userList.append(user.upper()) + GenBlob.genBlobTree(hOut,userList,'usernames_tree',False) + hOut.write('\n#endif\n') hOut.close() @@ -367,14 +376,20 @@ def generateResourceProps(srcFile,dstFileInfos): pOut.close() # launches a Web applicative resource file generation -def generateResource(srcFile,dstFile,chuncksNbits,gzipped,dstFileInfos): +def generateResource(srcFile,dstFile,chuncksNbits,gzipped,dstFileInfos,authType,realm,offsetCountCouple,finalUri): if getResourceType(srcFile) == DynamicResource: - generateDynamicResource(srcFile,dstFile,dstFileInfos) + generateDynamicResource(srcFile,dstFile,dstFileInfos,authType,realm,offsetCountCouple,finalUri) else: - generateStaticResource(srcFile,dstFile,chuncksNbits,gzipped) + generateStaticResource(srcFile,dstFile,chuncksNbits,gzipped,authType,realm,offsetCountCouple,finalUri) # dynamic resources: the generator file is enriched -def generateDynamicResource(srcFile,dstFile,dstFileInfos): +def generateDynamicResource(srcFile, + dstFile, + dstFileInfos, + authType, + realm, + offsetCountCouple, + finalUri): # extract the properties from the XML (if needed) fileData = extractPropsFromXml(srcFile,dstFileInfos) # if the c/h file does not conatin any XML, we simply copy it: this is not a generator @@ -390,6 +405,9 @@ def generateDynamicResource(srcFile,dstFile,dstFileInfos): generatedHeader += '#include "stddef.h"\n\n' generatedHeader += '#include "defines.h"\n\n' + if realm != '': + generatedHeader += '#include "http_auth_data.h"\n\n' + generatedOutputHandler = '/********** Output handler **********/\n' # handler functions declaration if dstFileInfos.has_key('init'): @@ -513,6 +531,57 @@ def generateDynamicResource(srcFile,dstFile,dstFileInfos): generatedOutputHandler += '\t},\n' generatedOutputHandler += '#endif\n' + + # HTTP Authentication data generation + generatedOutputHandler += '#ifdef HTTP_AUTH\n' + + if realm != '': + realmVar = realm + for c in realmVar: + if (re.search('\W', c)): + realmVar = realmVar.replace(c, '_' + str(ord(c)) + '_') + generatedOutputHandler += '\t.handler_restriction = {\n' + generatedOutputHandler += '\t\t.realm = (unsigned char*)&' + realmVar.lower() + ',\n' + generatedOutputHandler += '\t\t.credentials_offset = ' + str(offsetCountCouple[0]) + ',\n' + generatedOutputHandler += '\t\t.credentials_count = ' + str(offsetCountCouple[1]) + if authType == 'digest': + generatedOutputHandler += ',\n' + # Setting method string + if (dstFileInfos.has_key('doPost') + or dstFileInfos.has_key('doPostIn') + or dstFileInfos.has_key('doPostOut')): + method = 'POST' + else: + method = 'GET' + + (fileName, fileExt) = os.path.splitext(finalUri) + if (fileExt == '.c' or fileExt == '.h'): + print 'URI EXTENSION STRIP !!!' + finalUri = fileName + md5 = hashlib.md5() + md5.update('%s:%s' % (method, finalUri)) + hexdigest = md5.hexdigest() + generatedOutputHandler += '\t\t.resource_digest = "%s"\n' % hexdigest + # DEBUG PURPOSE + print 'MD5 Digest: %s (%s:%s)' % (hexdigest, method, finalUri) + else: + generatedOutputHandler += "\n" + + generatedOutputHandler += '\t}\n' + else: + generatedOutputHandler += '\t.handler_restriction = {\n' + generatedOutputHandler += '\t\t.realm = NULL,\n' + generatedOutputHandler += '\t\t.credentials_offset = 0,\n' + generatedOutputHandler += '\t\t.credentials_count = 0' + if authType == 'digest': + generatedOutputHandler += ',\n' + generatedOutputHandler += '\t\t.resource_digest = ""\n' + else: + generatedOutputHandler += '\n' + generatedOutputHandler += '\t}\n' + + generatedOutputHandler += '#endif\n' + generatedOutputHandler += '};\n' if (dstFileInfos.has_key('doPost') or dstFileInfos.has_key('doPostIn')): @@ -595,7 +664,7 @@ def generateDynamicResource(srcFile,dstFile,dstFileInfos): # static file: the file is completely pre-processed into a c file: # HTTP header insertion # chuncks checksums calculation -def generateStaticResource(srcFile,dstFile,chuncksNbits,gzipped): +def generateStaticResource(srcFile,dstFile,chuncksNbits,gzipped,authType,realm,offsetCountCouple,finalUri): # HTTP header generation and concatenation with file data try: # open the source file @@ -627,6 +696,11 @@ def generateStaticResource(srcFile,dstFile,chuncksNbits,gzipped): fileData = 'HTTP/1.1 404 Not Found\r\nContent-Length: ' + fileData elif os.path.basename(srcFile) == '505.html': fileData = 'HTTP/1.1 505 HTTP Version Not Supported\r\nContent-Length: ' + fileData + # bacara: + # HTTP Authentication needs runtime data, such as realm and nonce. At this + # point, we cannot process the full generation for 401.html. + elif os.path.basename(srcFile) == '401.html': + fileData = '\r\nContent-Length: ' + fileData else: fileData = 'HTTP/1.1 200 OK\r\nContent-Length: ' + fileData @@ -654,6 +728,8 @@ def generateStaticResource(srcFile,dstFile,chuncksNbits,gzipped): # inclusions cOut.write('#include "handlers.h"\n') + if realm != '': + cOut.write('#include "http_auth_data.h"\n') # data structures declaration cName = getCName(srcFile) @@ -672,6 +748,38 @@ def generateStaticResource(srcFile,dstFile,chuncksNbits,gzipped): + '\t\t\t.data = data_' + cName + '\n' + '\t\t}\n' + '\t},\n') + + cOut.write('#ifdef HTTP_AUTH\n') + if realm != '': + realmVar = realm + for c in realmVar: + if (re.search('\W', c)): + realmVar = realmVar.replace(c, '_' + str(ord(c)) + '_') + cOut.write('\t.handler_restriction = {\n' + + '\t\t.realm = (unsigned char*)&' + realmVar.lower() + ',\n' + + '\t\t.credentials_offset = ' + str(offsetCountCouple[0]) + ',\n' + + '\t\t.credentials_count = ' + str(offsetCountCouple[1]) + ',\n') + if authType == 'digest': + m = hashlib.md5() + m.update('%s:%s' % ('GET', finalUri)) + hexdigest = m.hexdigest() + cOut.write('\t\t.resource_digest = "%s"\n' % hexdigest) + # DEBUG PURPOSE + print 'MD5 Digest: %s (GET:%s)' % (hexdigest, finalUri) + cOut.write('\t}\n') + else: + cOut.write('\t.handler_restriction = {\n' + + '\t\t.realm = NULL,\n' + + '\t\t.credentials_offset = 0,\n' + + '\t\t.credentials_count = 0') + if authType == 'digest': + cOut.write(',\n\t\t.resource_digest = ""\n') + else: + cOut.write('\n') + cOut.write('\t}\n') + + cOut.write('#endif\n') + cOut.write('};\n') # chuncks checksums data generation diff --git a/tools/GenAuthData.py b/tools/GenAuthData.py new file mode 100644 index 0000000..716bc8b --- /dev/null +++ b/tools/GenAuthData.py @@ -0,0 +1,408 @@ +#!/usr/bin/python + +from xml.dom import minidom + +import base64 +import re +import hashlib + +import GenApps +import GenBlob + +# -------------------------------------------------- # +# Class: User +# -------------------------------------------------- # +class User: + def __init__(self, username, password): + self.username = username + self.password = password + + def toBasicHTTPAuthString(self): + return base64.b64encode('%s:%s' % (self.username, self.password)) +# -------------------------------------------------- # + +# Script initialisation +authenticationType = '' # 'basic' | 'digest' +realmUrisMap = { } # Read parseAuthData description for details + +# XML Tag Names +rootNodeTag = "http-authentication" +authNodeTag = "authorizations" +restNodeTag = "restrictions" +userNodeTag = "user" +realmNodeTag = "realm" +uriNodeTag = "uri" + +# Effectively used usernames list +usedUsernames = [ ] + +# parseAuthData(xmlFilename): +# Parse authentication data from the corresponding XML file. +def parseXMLFile(xmlFilename): + global authenticationType + # Getting XML document + xmlDoc = minidom.parse(xmlFilename) + + # Getting root, authorizations, restrictions + rootNodeList = xmlDoc.getElementsByTagName(rootNodeTag) + authNodeList = xmlDoc.getElementsByTagName(authNodeTag) + restNodeList = xmlDoc.getElementsByTagName(restNodeTag) + + if (len(rootNodeList) != 1): + print '%s: Must contain only one node: %s' % (xmlFilename, rootNodeTag) + exit() + if (len(authNodeList) != 1): + print '%s: Must contain only one node: %s' % (xmlFilename, authNodeTag) + exit() + if (len(restNodeList) != 1): + print '%s: Must contain only one node: %s' % (xmlFilename, restNodeTag) + exit() + + rootNode = rootNodeList[0] + authNode = authNodeList[0] + restNode = restNodeList[0] + + # Checking authentication type + authenticationType = rootNode.attributes['type'].value.lower() + + if authenticationType != 'basic' and authenticationType != 'digest': + print '%s: Unknown authentication scheme: %s' % (xmlFilename, authenticationType) + exit() + + parseAuthData(restNode, parseUsersList(authNode)) + + return authenticationType + +# parseUsersList(authorizationNode): +# Parse the authorization node and return a list of User objects corresponding +# to the XML data. +def parseUsersList(authorizationNode): + usernames = [] # Twins checking purpose + usersList = [] + + userNodeList = authorizationNode.getElementsByTagName(userNodeTag) + + # Parsing username and passwd for each user + for userNode in userNodeList: + login = userNode.attributes['login'].value + passwd = userNode.attributes['passwd'].value + + if login in usernames: # Twins check + print '%s: Username is duplicated.' % (login) + exit() + if passwd == '': + print '%s: Password field not set or empty.' % (login) + exit() + + usernames.append(login) + usersList.append(User(login, passwd)) + + return usersList + +# Parse the data corresponding to the specified restriction node, and +# build the data structure according to the previously parsed users list. +# +# The returned data structure looks like this : +# +# /!\ HTTP BASIC AUTHENTICATION /!\ +# ret = { 'realm' : [ { 'uri' : [credentials] } ] } +# where credentials is the base 64 encoding of the string "username:passwd" +# . +# |- realm1 +# | |- uri1 +# | | |- credentials1 +# | | `- credentials2 +# | `- uri2 +# | `- credentials3 +# `- realm2 +# `- uri3 +# |- credentials4 +# `- credentials5 +# +# /!\ HTTP DIGEST AUTHENTICATION /*\ +# ret = { ('users' | 'realms') } +# where the value associated with users is a dictionnary with username as key +# and password as value +# AND +# where the value associated with realms is the same data structure as for +# basic authentication, except about the credentials list which becomes now +# a username list. +# . +# |- users +# | `- { username : password } +# `- realms +# |- uri1 +# | |- user1 +# | `- user2 +# |- uri2 +# | `- user1 +# `- uri3 +# |- user1 +# `- user3 +# +def parseAuthData(restrictionNode, usersList): + global realmUrisMap + realmNodeList = restrictionNode.getElementsByTagName(realmNodeTag) + mapBuilt = { } + + # Parsing each restriction list (1x list/realm) + for realmNode in realmNodeList: + uriCredentialsMap = { } + realmName = realmNode.attributes['name'].value + + if realmName in mapBuilt: # Twins check + print '%s: Realm is duplicated.' % (realmName) + exit() + if len(realmName) > 32: # Length check + print '%s: Realm name is too long.' % (realmName) + exit() + + uriNodeList = realmNode.getElementsByTagName(uriNodeTag) + + for uriNode in uriNodeList: + uri = uriNode.attributes['path'].value + + if uri in uriCredentialsMap: # Twins check + print '%s: Uri is duplicated.' % (uri) + exit() + + # Building allowed users list + allowedUsers = uriNode.attributes['users'].value.split(';') + credentials = [] + + for username in allowedUsers: + # Existence check + if username not in [user.username for user in usersList]: + print '%s: User "%s" doesn\'t exist' % (uri, username) + exit() + + # Getting corresponding string + for user in usersList: + if user.username == username: + if authenticationType == 'basic': + credentials.append(user.toBasicHTTPAuthString()) + elif authenticationType == 'digest': + credentials.append(username) + + uriCredentialsMap[uri] = credentials + + mapBuilt[realmName] = uriCredentialsMap + + if authenticationType == 'digest': + digestMap = { } + digestMap['users'] = { } + for user in usersList: + digestMap['users'][user.username] = user.password + digestMap['realms'] = mapBuilt; + mapBuilt = digestMap; + + # DEBUG PURPOSE +# print 'USERS:' +# for user in mapBuilt['users']: +# print '\t' + user + ' : ' + mapBuilt['users'][user] +# +# print 'REALMS:' +# for realm in mapBuilt['realms']: +# print '\t' + realm + ':' +# for uri in mapBuilt['realms'][realm]: +# print '\t\t' + uri +# for user in mapBuilt['realms'][realm][uri]: +# print '\t\t\t' + user + + realmUrisMap = mapBuilt # Saving result for code generation purpose + return mapBuilt + +def genHTTPAuthDataFile(dstFile): + global realmUrisMap + global authenticationType + realmUrisCredentialsDataMap = { } + uriDatasMap = { } + + uChar = 'unsigned char' + + generatedHeader = '' + generatedCode = '' + + defHeader = '__HTTP_AUTH_DATA_H__' + generatedHeader += '#ifndef ' + defHeader + '\n' + generatedHeader += '#define ' + defHeader + '\n' + generatedHeader += '\n' + generatedHeader += '#include "types.h"\n' + generatedHeader += '#include "auth.h"\n' + generatedHeader += '\n' + + generatedCode += '#include "http_auth_data.h"\n\n' + + # Basic authentication + if (authenticationType == 'basic'): + credentialsList = [] # Ordered list of credentials, app by app + credentialsVarMap = { } # Dictionnary where key is a credentials string, + # and value the credentials' C identifier string. + credentialsCount = 0 + + # Write realm string declarations + commentary = '/*********** Realm list ***********/\n' + generatedHeader += commentary + generatedCode += commentary + + offset = 0 + for realm in realmUrisMap: + realmVar = realm.lower() + for c in realmVar: + if (re.search('\W', c)): + realmVar = realmVar.replace(c, '_' + str(ord(c)) + '_') + + generatedHeader += 'extern CONST_VAR(%s, %s[]);\n' % (uChar, realmVar) + generatedCode += 'CONST_VAR(%s, %s[]) = "%s";\n' % (uChar, realmVar, realm) + + for uri in realmUrisMap[realm]: + count = 0 + for credentials in realmUrisMap[realm][uri]: + credentialsList.append(credentials) + count += 1 + + uriDatasMap[uri] = (offset, count) + offset += count + + realmUrisCredentialsDataMap[realm] = uriDatasMap + + generatedHeader += '\n' + generatedCode += '\n' + + # Write basic credentials string declarations + commentary = '/*********** Credentials list ***********/\n' + generatedHeader += commentary + generatedCode += commentary + + for credentials in credentialsList: + credentialsVar = credentials.lower() + for c in credentialsVar: + if (re.search('\W', c)): + credentialsVar = credentialsVar.replace(c, '_' + str(ord(c)) + '_') + + if credentials not in credentialsVarMap: + credentialsVarMap[credentials] = credentialsVar + generatedHeader += 'extern CONST_VAR(%s, %s[]);\n' % (uChar, credentialsVar) + generatedCode += 'CONST_VAR(%s, %s[]) = "%s";\n' % (uChar, credentialsVar, credentials) + + generatedHeader += '\n' + generatedCode += '\n' + + # Write association table for handler->credentials + commentary = '/*********** Credentials string table ***********/\n' + generatedHeader += commentary + generatedCode += commentary + + generatedHeader += 'extern CONST_VAR(%s*, http_auth_basic_credentials_data[]);' % (uChar) + generatedCode += 'CONST_VAR(%s *, http_auth_basic_credentials_data[]) = {\n' %(uChar) + for credentials in credentialsList: + generatedCode += '\t(%s *)&%s,\n' % (uChar, credentialsVarMap[credentials]) + + generatedHeader += '\n' + generatedCode += '};\n' + + # Digest authentication + elif (authenticationType == 'digest'): + credentialsByUserRealm = { } # Key is (user,realm) + + # Write realm string declarations + commentary = '/*********** Realm List ***********/\n' + generatedHeader += commentary + generatedCode += commentary + + realmVars = { } # Will store the name of the character string for realms + realmUsers = { } # Will store the usernames used for each realm + global usedUsernames + + for realm in realmUrisMap['realms']: + # Building the string identifier + realmVar = realm.lower() + for c in realmVar: + if (re.search('\W', c)): + realmVar = realmVar.replace(c, '_' + str(ord(c)) + '_') + # Generating the string + generatedHeader += 'extern CONST_VAR(%s, %s[]);\n' % (uChar, realmVar) + generatedCode += 'CONST_VAR(%s, %s[]) = "%s";\n' % (uChar, realmVar, realm) + + realmVars[realm] = realmVar + + # Building the list of users per realm + realmUsers[realm] = [ ] + for uri in realmUrisMap['realms'][realm]: + for user in realmUrisMap['realms'][realm][uri]: + realmUsers[realm].append(user) + if user not in usedUsernames: + usedUsernames.append(user) + + # Building the map where (user,realm) is a key corresponding to a credentials digest + for realm in realmUsers: + for user in realmUsers[realm]: + m = hashlib.md5() + m.update(user + ':' + realm + ':' + realmUrisMap['users'][user]) + credentialsByUserRealm[(user,realm)] = m.hexdigest() + + # Write credentials digest struct table + commentary = '\n/*********** Credentials digest table ***********/\n' + generatedHeader += commentary + generatedCode += commentary + + generatedHeader += '#define USER_DIGEST_COUNT %s\n' % len(credentialsByUserRealm) + + generatedHeader += 'extern CONST_VAR(%s, %s[]);\n' % ('credentials_digest_t', 'http_auth_digest_credentials_data') + + generatedCode += 'CONST_VAR(%s, %s[]) = {\n' % ('credentials_digest_t', 'http_auth_digest_credentials_data') + + for key in credentialsByUserRealm: + generatedCode += '\t{\n' + generatedCode += '\t\t.username_blob = %s,\n' % str(usedUsernames.index(key[0])) + generatedCode += '\t\t.realm = (unsigned const char *)&%s,\n' % realmVars[key[1]] + generatedCode += '\t\t.user_digest = "%s"\n' % credentialsByUserRealm[key] + generatedCode += '\t},\n' + + generatedCode += '};\n' + + # Write credentials table + commentary = '\n/*********** Credentials table ***********/\n' + generatedHeader += commentary + generatedCode += commentary + + generatedHeader += 'extern CONST_VAR(%s, %s[]);\n' % ('uint8_t', 'http_auth_digest_credentials_table') + + generatedCode += 'CONST_VAR(%s, %s[]) = {\n' % ('uint8_t', 'http_auth_digest_credentials_table') + offset = 0; + + for realm in realmUrisMap['realms']: + uriDatasMap = { } + for uri in realmUrisMap['realms'][realm]: + count = 0; + for user in realmUrisMap['realms'][realm][uri]: + generatedCode += '\t%s, /* %s => %s */\n' % (usedUsernames.index(user), uri, user) + count += 1 + + uriDatasMap[uri] = (offset, count) + offset += count + + realmUrisCredentialsDataMap[realm] = uriDatasMap + + generatedCode += '};\n' + + generatedHeader += '\n/*********** Username blobs ***********/\n' + for u in usedUsernames: + user = u.upper() + generatedHeader += '#define HTTP_AUTH_USERNAME_%s\t%s\n' % (user, usedUsernames.index(u)) + + generatedHeader += '\n#endif\n' + + headerFile = open(dstFile + '.h', 'w') + GenApps.writeHeader(headerFile, 0) + headerFile.write(generatedHeader) + + cFile = open(dstFile + '.c', 'w') + GenApps.writeHeader(cFile, 0) + cFile.write(generatedCode) + + return realmUrisCredentialsDataMap + +def getUsedUsernamesList(): + global userUsernames + return usedUsernames diff --git a/tools/supportedHttpAuthTypeList b/tools/supportedHttpAuthTypeList new file mode 100644 index 0000000..29e858b --- /dev/null +++ b/tools/supportedHttpAuthTypeList @@ -0,0 +1,2 @@ +Basic +Digest \ No newline at end of file diff --git a/tools/supportedPostAttributList b/tools/supportedPostAttributList index cc2dcc3..26602c0 100644 --- a/tools/supportedPostAttributList +++ b/tools/supportedPostAttributList @@ -1,4 +1,8 @@ CONTENT-TYPE CONTENT-LENGTH +AUTHORIZATION: FILENAME= BOUNDARY= +USERNAME= +NONCE= +RESPONSE=