DirSet DirSet::oneElement(Dir dir) { return DirSet(1 << int(dir)); }
/** ** This function inspects the normalized chars for any other processing ** that we need to do, such as directory traversals. ** ** The main things that we check for here are '/' and '?'. There reason ** for '/' is that we do directory traversals. If it's a slash, we call ** the routine that will normalize mutli-slashes, self-referential dirs, ** and dir traversals. We do all that processing here and call the ** appropriate functions. ** ** The '?' is so we can mark the parameter field, and check for oversize ** directories one last time. Once the parameter field is set, we don't ** do any more oversize directory checks since we aren't in the url ** any more. ** ** @param Session pointer to the current session ** @param iChar the char to inspect ** @param norm_state the normalization state ** @param start the start of the URI buffer ** @param end the end of the URI buffer ** @param ptr the address of the pointer index into the URI buffer ** @param ub_start the start of the norm buffer ** @param ub_end the end of the norm buffer ** @param ub_ptr the address of the pointer index into the norm buffer ** ** @return integer ** ** @retval END_OF_BUFFER we've reached the end of the URI or norm buffer ** @retval HI_NONFATAL_ERR no special char, so just write the char and ** increment the ub_ptr. ** @retval HI_SUCCESS normalized the special char and already ** incremented the buffers. */ static inline int InspectUriChar(HI_SESSION *Session, int iChar, URI_NORM_STATE *norm_state, const u_char *start, const u_char *end, const u_char **ptr, u_char *ub_start, u_char *ub_end, u_char **ub_ptr, uint16_t *encodeType) { HTTPINSPECT_CONF *ServerConf = Session->server_conf; int iDir; /* ** Let's add absolute URI/proxy support everyone. */ if(!norm_state->dir_count && (u_char)iChar == ':' && hi_util_in_bounds(start, end, ((*ptr)+2))) { if(**ptr == '/' && *((*ptr)+1) == '/') { /* ** We've found absolute vodka. */ if(!hi_util_in_bounds(ub_start, ub_end, ((*ub_ptr)+2))) return END_OF_BUFFER; /* ** Write the : */ **ub_ptr = (u_char)iChar; (*ub_ptr)++; /* ** This increments us past the first slash, so at the next ** slash we will track a directory. ** ** The reason we do this is so that an attacker can't trick ** us into normalizing a directory away that ended in a :. ** For instance, if we got a URL that was separated in by a ** packet boundary like this, and we were looking for the ** URL real_dir:/file.html: ** real_dir://obfuscate_dir/../file.html ** we would normalize it with proxy support to: ** /file.html ** because we never tracked the :// as a valid directory. So ** even though this isn't the best solution, it is the best ** we can do given that we are working with stateless ** inspection. */ (*ptr)++; return HI_SUCCESS; } } /* ** Now that we have the "true" byte, we check this byte for other ** types of normalization: ** - directory traversals ** - multiple slashes */ if((u_char)iChar == '/') { /* ** First thing we do is check for a long directory. */ CheckLongDir(Session, norm_state, *ub_ptr); iDir = DirNorm(Session, start, end, ptr, norm_state, encodeType); if(iDir == DIR_TRAV) { /* ** This is the case where we have a directory traversal. ** ** The DirTrav function will reset the ub_ptr to the previous ** slash. After that, we just continue through the loop because ** DirNorm has already set ptr to the slash, so we can just ** continue on. */ DirTrav(Session,norm_state, ub_start, ub_ptr); } else { /* ** This is the case where we didn't have a directory traversal, ** and we are now just writing the char after the '/'. ** ** We call DirSet, because all this function does is write a ** '/' into the buffer and increment the ub_ptr. We then ** check the return code and return END_OF_BUFFER if ** needed. */ DirSet(norm_state, ub_ptr); if(iDir == END_OF_BUFFER) return END_OF_BUFFER; /* ** We check the bounds before we write the next byte */ if(!hi_util_in_bounds(ub_start, ub_end, *ub_ptr)) return END_OF_BUFFER; /* ** Set the char to what we got in DirNorm() */ /* ** Look for user-defined Non-Rfc chars. If we find them ** then log an alert. */ if(ServerConf->non_rfc_chars[(u_char)iDir]) { if(hi_eo_generate_event(Session, HI_EO_CLIENT_NON_RFC_CHAR) && !norm_state->param) { hi_eo_client_event_log(Session, HI_EO_CLIENT_NON_RFC_CHAR, NULL, NULL); } } **ub_ptr = (u_char)iDir; (*ub_ptr)++; } return HI_SUCCESS; } if((!byte_decoded && (u_char)iChar == '?')) { /* ** We assume that this is the beginning of the parameter field, ** and check for a long directory following. Event though seeing ** a question mark does not guarantee the parameter field, thanks ** IIS. */ CheckLongDir(Session, norm_state, *ub_ptr); norm_state->param = *ub_ptr; } /* ** This is neither char, so we just bail and let the loop finish ** for us. */ return HI_NONFATAL_ERR; }