bool http_connection::loop(unsigned fd)
{
	socket_wrapper::io_vector io_vector[2];
	size_t total = 0;
	size_t count;
	bool ret;

	do {
		logger::instance().log(logger::LOG_DEBUG, "[http_connection::loop] (fd %d) State = %s.", fd, state_to_string(_M_state));

		switch (_M_state) {
			case BEGIN_REQUEST_STATE:
				if ((!_M_readable) && (_M_inp == (off_t) _M_in.count())) {
					return true;
				}

				if (!read_request_line(fd, total)) {
					return false;
				}

				break;
			case READING_HEADERS_STATE:
				if (!_M_readable) {
					return true;
				}

				if (!read_headers(fd, total)) {
					return false;
				}

				break;
			case PROCESSING_REQUEST_STATE:
				if (!process_request(fd)) {
					return false;
				}

				if (_M_error != http_error::OK) {
					total = 0;

					_M_state = PREPARING_ERROR_PAGE_STATE;
				} else {
					if ((_M_state != PREPARING_HTTP_REQUEST_STATE) && (_M_state != READING_BODY_STATE) && (_M_state != READING_CHUNKED_BODY_STATE)) {
						if (!modify(fd, tcp_server::WRITE)) {
							return false;
						}

						total = 0;
					}
				}

				break;
			case READING_BODY_STATE:
				if (!_M_readable) {
					return true;
				}

				if (!read_body(fd, total)) {
					return false;
				}

				break;
			case READING_CHUNKED_BODY_STATE:
				if (!_M_readable) {
					return true;
				}

				if (!read_chunked_body(fd, total)) {
					return false;
				}

				break;
			case PREPARING_HTTP_REQUEST_STATE:
				if (!prepare_http_request(fd)) {
					_M_state = PREPARING_ERROR_PAGE_STATE;
				} else {
					_M_state = WAITING_FOR_BACKEND_STATE;
				}

				break;
			case WAITING_FOR_BACKEND_STATE:
				return true;
			case PREPARING_ERROR_PAGE_STATE:
				if ((!prepare_error_page()) || (!modify(fd, tcp_server::WRITE))) {
					return false;
				}

				break;
			case SENDING_TWO_BUFFERS_STATE:
				if (!_M_writable) {
					return true;
				}

				io_vector[0].iov_base = _M_out.data();
				io_vector[0].iov_len = _M_out.count();

				io_vector[1].iov_base = _M_bodyp->data();
				io_vector[1].iov_len = _M_bodyp->count();

				if (!writev(fd, io_vector, 2, total)) {
					return false;
				} else if (_M_outp == (off_t) (_M_out.count() + _M_bodyp->count())) {
					_M_state = REQUEST_COMPLETED_STATE;
				}

				break;
			case SENDING_HEADERS_STATE:
				if (!_M_writable) {
					return true;
				}

				if (!write(fd, total)) {
					return false;
				} else if (_M_outp == (off_t) _M_out.count()) {
					if (_M_method == http_method::HEAD) {
						_M_state = REQUEST_COMPLETED_STATE;
					} else if (_M_error != http_error::OK) {
						_M_state = REQUEST_COMPLETED_STATE;
					} else if (_M_filesize == 0) {
						_M_state = REQUEST_COMPLETED_STATE;
					} else {
						if (_M_ranges.count() == 0) {
							_M_outp = 0;
						} else {
							const range_list::range* range = _M_ranges.get(0);
							_M_outp = range->from;
						}

						_M_state = SENDING_BODY_STATE;
					}
				}

				break;
			case SENDING_BODY_STATE:
				if (!_M_writable) {
					return true;
				}

				if (!sendfile(fd, _M_fd, _M_filesize, &_M_ranges, _M_nrange, total)) {
					return false;
				} else {
					size_t nranges = _M_ranges.count();

					if (nranges == 0) {
						if (_M_outp == _M_filesize) {
							socket_wrapper::uncork(fd);

							_M_state = REQUEST_COMPLETED_STATE;
						}
					} else {
						const range_list::range* range = _M_ranges.get(_M_nrange);
						if (_M_outp == range->to + 1) {
							if (nranges == 1) {
								socket_wrapper::uncork(fd);

								_M_state = REQUEST_COMPLETED_STATE;
							} else {
								_M_out.reset();

								// Last part?
								if (++_M_nrange == nranges) {
									if (!_M_out.format("\r\n--%0*u--\r\n", http_headers::BOUNDARY_WIDTH, _M_boundary)) {
										return false;
									}

									_M_state = SENDING_MULTIPART_FOOTER_STATE;
								} else {
									if (!build_part_header()) {
										return false;
									}

									_M_state = SENDING_PART_HEADER_STATE;
								}

								_M_outp = 0;
							}
						}
					}
				}

				break;
			case SENDING_PART_HEADER_STATE:
				if (!_M_writable) {
					return true;
				}

				if (!write(fd, total)) {
					return false;
				} else if (_M_outp == (off_t) _M_out.count()) {
					const range_list::range* range = _M_ranges.get(_M_nrange);
					_M_outp = range->from;

					_M_state = SENDING_BODY_STATE;
				}

				break;
			case SENDING_MULTIPART_FOOTER_STATE:
				if (!_M_writable) {
					return true;
				}

				if (!write(fd, total)) {
					return false;
				} else if (_M_outp == (off_t) _M_out.count()) {
					socket_wrapper::uncork(fd);

					_M_state = REQUEST_COMPLETED_STATE;
				}

				break;
			case SENDING_BACKEND_HEADERS_STATE:
				if (!_M_writable) {
					return true;
				}

				if ((!_M_payload_in_memory) || (_M_filesize == 0) || (_M_method == http_method::HEAD)) {
					count = _M_out.count();

					ret = write(fd, total);
				} else {
					io_vector[0].iov_base = _M_out.data();
					io_vector[0].iov_len = _M_out.count();

					if (_M_error == http_error::OK) {
						io_vector[1].iov_base = _M_body.data() + _M_backend_response_header_size;
					} else {
						io_vector[1].iov_base = _M_bodyp->data();
					}

					io_vector[1].iov_len = _M_filesize;

					count = io_vector[0].iov_len + io_vector[1].iov_len;

					ret = writev(fd, io_vector, 2, total);
				}

				if (!ret) {
					return false;
				} else if (_M_outp == (off_t) count) {
					if (_M_payload_in_memory) {
						_M_state = REQUEST_COMPLETED_STATE;
					} else {
						_M_outp = 0;

						_M_state = SENDING_BACKEND_BODY_STATE;
					}
				}

				break;
			case SENDING_BACKEND_BODY_STATE:
				if (!_M_writable) {
					return true;
				}

				if (!sendfile(fd, _M_tmpfile, _M_filesize, total)) {
					return false;
				} else if (_M_outp == _M_filesize) {
					socket_wrapper::uncork(fd);

					_M_state = REQUEST_COMPLETED_STATE;
				}

				break;
			case REQUEST_COMPLETED_STATE:
				if ((_M_vhost) && (_M_vhost->log_requests)) {
					_M_vhost->log->log(*this, fd);
				}

				// Close connection?
				if (!_M_keep_alive) {
					return false;
				} else {
					if (!modify(fd, tcp_server::READ)) {
						return false;
					}

					reset();

					// If there is more data in the input buffer...
					size_t left = _M_in.count() - _M_inp;
					if (left > 0) {
						// Move data at the beginning of the buffer.
						char* data = _M_in.data();
						memmove(data, data + _M_inp, left);
						_M_in.set_count(left);
					} else {
						_M_in.reset();
					}

					_M_inp = 0;
				}

				break;
		}
	} while (!_M_in_ready_list);

	return true;
}
示例#2
0
/*
int analyze_server_response(int socket)
return 0 or 1 when the cond regex is matched
return -1 if no response from server
*/
int analyze_server_response(int s) {
  int runs = 0;

  while ((buf = hydra_receive_line(s)) != NULL) {
    runs++;
    //check for http redirection
    if (strstr(buf, "HTTP/1.1 3") != NULL || strstr(buf, "HTTP/1.0 3") != NULL || strstr(buf, "Status: 3") != NULL) {
      redirected_flag = 1;
    } else if (strstr(buf, "HTTP/1.1 401") != NULL || strstr(buf, "HTTP/1.0 401") != NULL) {
      auth_flag = 1;
    } else if ((strstr(buf, "HTTP/1.1 403") != NULL) || (strstr(buf, "HTTP/1.1 404") != NULL) || (strstr(buf, "HTTP/1.0 403") != NULL) || (strstr(buf, "HTTP/1.0 404") != NULL)) {
      return 0;
    }

    if (hydra_strcasestr(buf, "Location: ") != NULL) {
      char *startloc, *endloc;
      char str[2048];

      startloc = hydra_strcasestr(buf, "Location: ") + strlen("Location: ");
      strncpy(str, startloc, sizeof(str) - 1);
      str[sizeof(str) - 1] = 0;
      endloc = strchr(str, '\n');
      if (endloc != NULL)
        *endloc = 0;
      endloc = strchr(str, '\r');
      if (endloc != NULL)
        *endloc = 0;
      strcpy(redirected_url_buff, str);
    }
    //there can be multiple cookies
    if (hydra_strcasestr(buf, "Set-Cookie: ") != NULL) {
      char *cookiebuf = buf;

      do {
        char *startcookie, *endcookie1, *endcookie2;
        char str[1024], tmpcookie[4096] = "", tmpname[128] = "", *ptr, *ptr2;

        memset(str, 0, sizeof(str));
        startcookie = hydra_strcasestr(cookiebuf, "Set-Cookie: ") + strlen("Set-Cookie: ");
        strncpy(str, startcookie, sizeof(str) - 1);
        str[sizeof(str) - 1] = 0;
        endcookie1 = strchr(str, '\n');
        endcookie2 = strchr(str, ';');
        //terminate string after cookie data
        if (endcookie1 != NULL && ((endcookie1 < endcookie2) || (endcookie2 == NULL))) {
          if (*(endcookie1 - 1) == '\r')
            endcookie1--;
          *endcookie1 = 0;
        } else if (endcookie2 != NULL)
          *endcookie2 = 0;
        // is the cookie already there? if yes, remove it!
        if (index(startcookie, '=') != NULL && (ptr = index(startcookie, '=')) - startcookie + 1 <= sizeof(tmpname)) {
          strncpy(tmpname, startcookie, sizeof(tmpname) - 2);
          tmpname[sizeof(tmpname) - 2] = 0;
          ptr = index(tmpname, '=');
          *(++ptr) = 0;
          // is the cookie already in the cookiejar? (so, does it have to be replaced?)
          if ((ptr = hydra_strcasestr(cookie, tmpname)) != NULL) {
            // yes it is.
            // if the cookie is not in the beginning of the cookiejar, copy the ones before
            if (ptr != cookie && *(ptr - 1) == ' ') {
              strncpy(tmpcookie, cookie, ptr - cookie - 2);
              tmpcookie[ptr - cookie - 2] = 0;
            }
            ptr += strlen(tmpname);
            // if there are any cookies after this one in the cookiejar, copy them over
            if ((ptr2 = strstr(ptr, "; ")) != NULL) {
              ptr2 += 2;
              strncat(tmpcookie, ptr2, sizeof(tmpcookie) - strlen(tmpcookie) - 1);
            }
            if (debug)
              printf("[DEBUG] removing cookie %s in jar\n before: %s\n after:  %s\n", tmpname, cookie, tmpcookie);
            strcpy(cookie, tmpcookie);
          }
        }
        ptr = index(str, '=');
        // only copy the cookie if it has a value (otherwise the server wants to delete the cookie)
        if (ptr != NULL && *(ptr + 1) != ';' && *(ptr + 1) != 0 && *(ptr + 1) != '\n' && *(ptr + 1) != '\r') {
          if (strlen(cookie) > 0)
            strncat(cookie, "; ", sizeof(cookie) - strlen(cookie) - 1);
          strncat(cookie, str, sizeof(cookie) - strlen(cookie) - 1);
        }
        cookiebuf = startcookie;
      } while (hydra_strcasestr(cookiebuf, "Set-Cookie: ") != NULL);
    }
#ifdef HAVE_PCRE
    if (hydra_string_match(buf, cond) == 1) {
#else
    if (strstr(buf, cond) != NULL) {
#endif
      free(buf);
//      printf("DEBUG: STRING %s FOUND!!:\n%s\n", cond, buf);
      return 1;
    }
//    else printf("DEBUG: STRING %s NOT FOUND:\n%s\n", cond, buf);
    free(buf);
  }
  if (runs == 0) {
    if (debug)
      hydra_report(stderr, "DEBUG: no response from server\n");
    return -1;
  }
  return 0;
}

void hydra_reconnect(int s, char *ip, int port, unsigned char options) {
  if (s >= 0)
    s = hydra_disconnect(s);
  if ((options & OPTION_SSL) == 0) {
    s = hydra_connect_tcp(ip, port);
  } else {
    s = hydra_connect_ssl(ip, port);
  }
}

int start_http_form(int s, char *ip, int port, unsigned char options, char *miscptr, FILE * fp, char *type, ptr_header_node ptr_head) {
  char *empty = "";
  char *login, *pass, clogin[256], cpass[256];
  char header[8096], *upd3variables;
  char *http_request;
  int found = !success_cond, i, j;
  char content_length[MAX_CONTENT_LENGTH], proxy_string[MAX_PROXY_LENGTH];

  memset(header, 0, sizeof(header));
  cookie[0] = 0;                // reset cookies from potential previous attempt

  // Take the next login/pass pair
  if (strlen(login = hydra_get_next_login()) == 0)
    login = empty;
  if (strlen(pass = hydra_get_next_password()) == 0)
    pass = empty;
  strncpy(clogin, html_encode(login), sizeof(clogin) - 1);
  clogin[sizeof(clogin) - 1] = 0;
  strncpy(cpass, html_encode(pass), sizeof(cpass) - 1);
  cpass[sizeof(cpass) - 1] = 0;
  upd3variables = hydra_strrep(variables, "^USER^", clogin);
  upd3variables = hydra_strrep(upd3variables, "^PASS^", cpass);

  // Replace the user/pass placeholders in the user-supplied headers
  hdrrep(&ptr_head, "^USER^", clogin);
  hdrrep(&ptr_head, "^PASS^", cpass);

  /* again: no snprintf to be portable. dont worry, buffer cant overflow */
  if (use_proxy == 1 && proxy_authentication != NULL) {
    if (getcookie) {
      memset(proxy_string, 0, sizeof(proxy_string));
      snprintf(proxy_string, MAX_PROXY_LENGTH - 1, "http://%s:%d%.600s", webtarget, webport, cookieurl);
      http_request = prepare_http_request("GET", proxy_string, NULL, cookie_request);
      if (hydra_send(s, http_request, strlen(http_request), 0) < 0)
        return 1;
      i = analyze_server_response(s);   // ignore result
      if (strlen(cookie) > 0)
        add_header(&ptr_head, "Cookie", cookie, HEADER_TYPE_DEFAULT_REPL);
      hydra_reconnect(s, ip, port, options);
    }
    // now prepare for the "real" request
    if (strcmp(type, "POST") == 0) {
      memset(proxy_string, 0, sizeof(proxy_string));
      snprintf(proxy_string, MAX_PROXY_LENGTH - 1, "http://%s:%d%.600s", webtarget, webport, url);
      snprintf(content_length, MAX_CONTENT_LENGTH - 1, "%d", (int) strlen(upd3variables));
      if (header_exists(&ptr_head, "Content-Length", HEADER_TYPE_DEFAULT))
        hdrrepv(&ptr_head, "Content-Length", content_length);
      else
        add_header(&ptr_head, "Content-Length", content_length, HEADER_TYPE_DEFAULT);
      if (!header_exists(&ptr_head, "Content-Type", HEADER_TYPE_DEFAULT))
        add_header(&ptr_head, "Content-Type", "application/x-www-form-urlencoded", HEADER_TYPE_DEFAULT);
      normal_request = stringify_headers(&ptr_head);
      http_request = prepare_http_request("POST", proxy_string, upd3variables, normal_request);
      if (hydra_send(s, http_request, strlen(http_request), 0) < 0)
        return 1;
    } else {
      normal_request = stringify_headers(&ptr_head);
      http_request = prepare_http_request("GET", url, upd3variables, normal_request);
      if (hydra_send(s, http_request, strlen(http_request), 0) < 0)
        return 1;
    }
  } else {
    if (use_proxy == 1) {
      // proxy without authentication
      if (getcookie) {
        //doing a GET to get cookies
        memset(proxy_string, 0, sizeof(proxy_string));
        snprintf(proxy_string, MAX_PROXY_LENGTH - 1, "http://%s:%d%.600s", webtarget, webport, cookieurl);
        http_request = prepare_http_request("GET", proxy_string, NULL, cookie_request);
        if (hydra_send(s, http_request, strlen(http_request), 0) < 0)
          return 1;
        i = analyze_server_response(s); // ignore result
        if (strlen(cookie) > 0)
          add_header(&ptr_head, "Cookie", cookie, HEADER_TYPE_DEFAULT_REPL);
        hydra_reconnect(s, ip, port, options);
      }
      // now prepare for the "real" request
      if (strcmp(type, "POST") == 0) {
        memset(proxy_string, 0, sizeof(proxy_string));
        snprintf(proxy_string, MAX_PROXY_LENGTH - 1, "http://%s:%d%.600s", webtarget, webport, url);
        snprintf(content_length, MAX_CONTENT_LENGTH - 1, "%d", (int) strlen(upd3variables));
        if (header_exists(&ptr_head, "Content-Length", HEADER_TYPE_DEFAULT))
          hdrrepv(&ptr_head, "Content-Length", content_length);
        else
          add_header(&ptr_head, "Content-Length", content_length, HEADER_TYPE_DEFAULT);
        if (!header_exists(&ptr_head, "Content-Type", HEADER_TYPE_DEFAULT))
          add_header(&ptr_head, "Content-Type", "application/x-www-form-urlencoded", HEADER_TYPE_DEFAULT);
        normal_request = stringify_headers(&ptr_head);
        http_request = prepare_http_request("POST", proxy_string, upd3variables, normal_request);
        if (hydra_send(s, http_request, strlen(http_request), 0) < 0)
          return 1;
      } else {
        normal_request = stringify_headers(&ptr_head);
        http_request = prepare_http_request("GET", url, upd3variables, normal_request);
        if (hydra_send(s, http_request, strlen(http_request), 0) < 0)
          return 1;
      }
    } else {
      // direct web server, no proxy
      if (getcookie) {
        //doing a GET to save cookies
        http_request = prepare_http_request("GET", cookieurl, NULL, cookie_request);
        if (hydra_send(s, http_request, strlen(http_request), 0) < 0)
          return 1;
        i = analyze_server_response(s); // ignore result
        if (strlen(cookie) > 0) {
          add_header(&ptr_head, "Cookie", cookie, HEADER_TYPE_DEFAULT_REPL);
          normal_request = stringify_headers(&ptr_head);
        }
        hydra_reconnect(s, ip, port, options);
      }
      // now prepare for the "real" request
      if (strcmp(type, "POST") == 0) {
        snprintf(content_length, MAX_CONTENT_LENGTH - 1, "%d", (int) strlen(upd3variables));
        if (header_exists(&ptr_head, "Content-Length", HEADER_TYPE_DEFAULT))
          hdrrepv(&ptr_head, "Content-Length", content_length);
        else
          add_header(&ptr_head, "Content-Length", content_length, HEADER_TYPE_DEFAULT);
        if (!header_exists(&ptr_head, "Content-Type", HEADER_TYPE_DEFAULT))
          add_header(&ptr_head, "Content-Type", "application/x-www-form-urlencoded", HEADER_TYPE_DEFAULT);
        normal_request = stringify_headers(&ptr_head);
        http_request = prepare_http_request("POST", url, upd3variables, normal_request);
        if (hydra_send(s, http_request, strlen(http_request), 0) < 0)
          return 1;
      } else {
        normal_request = stringify_headers(&ptr_head);
        http_request = prepare_http_request("GET", url, upd3variables, normal_request);
        if (hydra_send(s, http_request, strlen(http_request), 0) < 0)
          return 1;
      }
    }
  }

  if (debug)
  	hydra_report_debug(stdout, "HTTP request sent:\n%s\n", http_request);

  found = analyze_server_response(s);

  if (auth_flag) {              // we received a 401 error - user using wrong module
    hydra_report(stderr, "[ERROR] the target is using HTTP auth, not a web form, received HTTP error code 401. Use module \"http%s-get\" instead.\n",
                 (options & OPTION_SSL) > 0 ? "s" : "");
    return 4;
  }

  if (strlen(cookie) > 0)
    add_header(&ptr_head, "Cookie", cookie, HEADER_TYPE_DEFAULT_REPL);

  //if page was redirected, follow the location header
  redirected_cpt = MAX_REDIRECT;
  if (debug)
    printf("[DEBUG] attempt result: found %d, redirect %d, location: %s\n", found, redirected_flag, redirected_url_buff);

  while (found == 0 && redirected_flag && (redirected_url_buff[0] != 0) && (redirected_cpt > 0)) {
    //we have to split the location
    char *startloc, *endloc;
    char str[2048];
    char str2[2048];
    char str3[2048];

    redirected_cpt--;
    redirected_flag = 0;
    //check if the redirect page contains the fail/success condition
#ifdef HAVE_PCRE
    if (hydra_string_match(redirected_url_buff, cond) == 1) {
#else
    if (strstr(redirected_url_buff, cond) != NULL) {
#endif
      found = success_cond;
    } else {
      //location could be either absolute http(s):// or / something
      //or relative
      startloc = strstr(redirected_url_buff, "://");
      if (startloc != NULL) {
        startloc += strlen("://");

        if ((endloc = strchr(startloc, '\r')) != NULL) {
          startloc[endloc - startloc] = 0;
        }
        if ((endloc = strchr(startloc, '\n')) != NULL) {
          startloc[endloc - startloc] = 0;
        }
        strcpy(str, startloc);

        endloc = strchr(str, '/');
        if (endloc != NULL) {
          strncpy(str2, str, endloc - str);
          str2[endloc - str] = 0;
        } else
          strncpy(str2, str, sizeof(str));

        if (strlen(str) - strlen(str2) == 0) {
          strcpy(str3, "/");
        } else {
          strncpy(str3, str + strlen(str2), strlen(str) - strlen(str2) - 1);
          str3[strlen(str) - strlen(str2) - 1] = 0;
        }
      } else {
        strncpy(str2, webtarget, sizeof(str2));
        if (redirected_url_buff[0] != '/') {
          //it's a relative path, so we have to concatenate it
          //with the path from the first url given
          char *urlpath;
          char urlpath_extracted[2048];

          memset(urlpath_extracted, 0, sizeof(urlpath_extracted));

          urlpath = strrchr(url, '/');
          if (urlpath != NULL) {
            strncpy(urlpath_extracted, url, urlpath - url);
            sprintf(str3, "%.1000s/%.1000s", urlpath_extracted, redirected_url_buff);
          } else {
            sprintf(str3, "%.1000s/%.1000s", url, redirected_url_buff);
          }
        } else
          strncpy(str3, redirected_url_buff, sizeof(str3));
        if (debug)
          hydra_report(stderr, "[DEBUG] host=%s redirect=%s origin=%s\n", str2, str3, url);
      }
      if (str3[0] != '/') {
        j = strlen(str3);
        str3[j + 1] = 0;
        for (i = j; i > 0; i--)
          str3[i] = str3[i - 1];
        str3[0] = '/';
      }

      if (verbose)
        hydra_report(stderr, "[VERBOSE] Page redirected to http://%s%s\n", str2, str3);

      //re-use the code above to check for proxy use
      if (use_proxy == 1 && proxy_authentication != NULL) {
        // proxy with authentication
        hdrrepv(&ptr_head, "Host", str2);
        memset(proxy_string, 0, sizeof(proxy_string));
        snprintf(proxy_string, MAX_PROXY_LENGTH - 1, "http://%s:%d%.600s", webtarget, webport, str3);
        normal_request = stringify_headers(&ptr_head);
        http_request = prepare_http_request("GET", proxy_string, NULL, normal_request);
      } else {
        if (use_proxy == 1) {
          // proxy without authentication
          hdrrepv(&ptr_head, "Host", str2);
          memset(proxy_string, 0, sizeof(proxy_string));
          snprintf(proxy_string, MAX_PROXY_LENGTH - 1, "http://%s:%d%.600s", webtarget, webport, str3);
          normal_request = stringify_headers(&ptr_head);
          http_request = prepare_http_request("GET", proxy_string, NULL, normal_request);
        } else {
          //direct web server, no proxy
          hdrrepv(&ptr_head, "Host", str2);
          normal_request = stringify_headers(&ptr_head);
          http_request = prepare_http_request("GET", str3, NULL, normal_request);
        }
      }

      hydra_reconnect(s, ip, port, options);

      if (hydra_send(s, http_request, strlen(http_request), 0) < 0)
        return 1;

      found = analyze_server_response(s);
      if (strlen(cookie) > 0)
        add_header(&ptr_head, "Cookie", cookie, HEADER_TYPE_DEFAULT_REPL);
    }
  }

  //if the last status is still 3xx, set it as a false
  if (found != -1 && found == success_cond && (redirected_flag == 0 || success_cond == 1) && redirected_cpt >= 0) {
    hydra_report_found_host(port, ip, "www-form", fp);
    hydra_completed_pair_found();
  } else {
    hydra_completed_pair();
  }

  return 1;
}

void service_http_form(char *ip, int sp, unsigned char options, char *miscptr, FILE * fp, int port, char *type, ptr_header_node * ptr_head) {
  int run = 1, next_run = 1, sock = -1;
  int myport = PORT_HTTP, mysslport = PORT_HTTP_SSL;

  // register our socket descriptor
  hydra_register_socket(sp);

  /*
   * Iterate through the runs. Possible values are the following:
   *    - 1 -> Open connection to remote server.
   *    - 2 -> Run password attempts.
   *    - 3 -> Disconnect and end with success.
   *    - 4 -> Disconnect and end with error.
   */
  while (1) {
    if (run == 2) {
      if (memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0) {
        if (freemischttpform)
          free(miscptr);
        freemischttpform = 0;
        hydra_child_exit(1);
      }
    }
    switch (run) {
    case 1:                    /* connect and service init function */
      {
        if (sock >= 0)
          sock = hydra_disconnect(sock);
        if ((options & OPTION_SSL) == 0) {
          if (port != 0)
            myport = port;
          sock = hydra_connect_tcp(ip, myport);
          port = myport;
        } else {
          if (port != 0)
            mysslport = port;
          sock = hydra_connect_ssl(ip, mysslport);
          port = mysslport;
        }
        if (sock < 0) {
          hydra_report(stderr, "[ERROR] Child with pid %d terminating, cannot connect\n", (int) getpid());
          if (freemischttpform)
            free(miscptr);
          freemischttpform = 0;
          hydra_child_exit(1);
        }
        next_run = 2;
        break;
      }
    case 2:                    /* run the cracking function */
      next_run = start_http_form(sock, ip, port, options, miscptr, fp, type, *ptr_head);
      break;
    case 3:                    /* clean exit */
      if (sock >= 0)
        sock = hydra_disconnect(sock);
      if (freemischttpform)
        free(miscptr);
      freemischttpform = 0;
      hydra_child_exit(0);
      break;
    case 4:                    /* silent error exit */
      if (sock >= 0)
        sock = hydra_disconnect(sock);
      if (freemischttpform)
        free(miscptr);
      freemischttpform = 0;
      hydra_child_exit(1);
      break;
    default:
      if (freemischttpform)
        free(miscptr);
      freemischttpform = 0;
      hydra_report(stderr, "[ERROR] Caught unknown return code, exiting!\n");
      hydra_child_exit(0);
    }
    run = next_run;
  }
  if (freemischttpform)
    free(miscptr);
}