CFStringRef
SecUnwrapRecoveryPasswordWithAnswers(CFDictionaryRef recref, CFArrayRef answers)
{    
	if(answers == NULL || CFArrayGetCount(answers) < 3) return NULL;

	CFStringRef theLocaleString = (CFStringRef) CFDictionaryGetValue(recref, kSecRecLocale);
	CFDataRef tmpIV = (CFDataRef) CFDictionaryGetValue(recref, kSecRecIV);
	CFDataRef wrappedPassword = (CFDataRef) CFDictionaryGetValue(recref, kSecRecWrappedPassword);
	
	if(theLocaleString == NULL || tmpIV == NULL || wrappedPassword == NULL) {
		return NULL;
	}
	

    CFLocaleRef theLocale = CFLocaleCreate(kCFAllocatorDefault, theLocaleString);
	SecKeyRef wrapKey = secDeriveKeyFromAnswers(answers, theLocale);
	CFRelease(theLocaleString);
	CFRelease(theLocale);
	
    CFDataRef iv = b64decode(tmpIV);
	
	CFStringRef recoveryPassword =  decryptString(wrapKey, iv, wrappedPassword);
	CFRelease(wrapKey);
   
    if(recoveryPassword != NULL) {
    	CFDataRef comphash = createIVFromPassword(recoveryPassword);
       	if(!CFEqual(comphash, iv)) {
            secDebug(ASL_LEVEL_ERR, "Failed reconstitution of password for recovery\n", NULL);
			CFRelease(recoveryPassword);
			recoveryPassword = NULL;
		}
		CFRelease(comphash);
    }
	CFRelease(iv);
	return recoveryPassword;
}
Example #2
0
int
auth_cram_md5_client(
  auth_instance *ablock,                 /* authenticator block */
  smtp_inblock *inblock,                 /* input connection */
  smtp_outblock *outblock,               /* output connection */
  int timeout,                           /* command timeout */
  uschar *buffer,                        /* for reading response */
  int buffsize)                          /* size of buffer */
{
auth_cram_md5_options_block *ob =
  (auth_cram_md5_options_block *)(ablock->options_block);
uschar *secret = expand_string(ob->client_secret);
uschar *name = expand_string(ob->client_name);
uschar *challenge, *p;
int i;
uschar digest[16];

/* If expansion of either the secret or the user name failed, return CANCELLED
or ERROR, as approriate. */

if (!secret || !name)
  {
  if (expand_string_forcedfail)
    {
    *buffer = 0;           /* No message */
    return CANCELLED;
    }
  string_format(buffer, buffsize, "expansion of \"%s\" failed in "
    "%s authenticator: %s",
    !secret ? ob->client_secret : ob->client_name,
    ablock->name, expand_string_message);
  return ERROR;
  }

/* Initiate the authentication exchange and read the challenge, which arrives
in base 64. */

if (smtp_write_command(outblock, FALSE, "AUTH %s\r\n", ablock->public_name) < 0)
  return FAIL_SEND;
if (!smtp_read_response(inblock, buffer, buffsize, '3', timeout))
  return FAIL;

if (b64decode(buffer + 4, &challenge) < 0)
  {
  string_format(buffer, buffsize, "bad base 64 string in challenge: %s",
    big_buffer + 4);
  return ERROR;
  }

/* Run the CRAM-MD5 algorithm on the secret and the challenge */

compute_cram_md5(secret, challenge, digest);

/* Create the response from the user name plus the CRAM-MD5 digest */

string_format(big_buffer, big_buffer_size - 36, "%s", name);
for (p = big_buffer; *p; ) p++;
*p++ = ' ';

for (i = 0; i < 16; i++)
  {
  sprintf(CS p, "%02x", digest[i]);
  p += 2;
  }

/* Send the response, in base 64, and check the result. The response is
in big_buffer, but b64encode() returns its result in working store,
so calling smtp_write_command(), which uses big_buffer, is OK. */

buffer[0] = 0;
if (smtp_write_command(outblock, FALSE, "%s\r\n", b64encode(big_buffer,
  p - big_buffer)) < 0) return FAIL_SEND;

return smtp_read_response(inblock, (uschar *)buffer, buffsize, '2', timeout)
  ? OK : FAIL;
}
Example #3
0
int
auth_cyrus_sasl_server(auth_instance *ablock, uschar *data)
{
auth_cyrus_sasl_options_block *ob =
  (auth_cyrus_sasl_options_block *)(ablock->options_block);
uschar *output, *out2, *input, *clear, *hname;
uschar *debug = NULL;   /* Stops compiler complaining */
sasl_callback_t cbs[] = {{SASL_CB_LIST_END, NULL, NULL}};
sasl_conn_t *conn;
char * realm_expanded = NULL;
int rc, firsttime = 1, clen, *negotiated_ssf_ptr = NULL, negotiated_ssf;
unsigned int inlen, outlen;

input = data;
inlen = Ustrlen(data);

HDEBUG(D_auth) debug = string_copy(data);

hname = expand_string(ob->server_hostname);
if (hname && ob->server_realm)
  realm_expanded = CS expand_string(ob->server_realm);
if (!hname  ||  !realm_expanded  && ob->server_realm)
  {
  auth_defer_msg = expand_string_message;
  return DEFER;
  }

if (inlen)
  {
  if ((clen = b64decode(input, &clear)) < 0)
    return BAD64;
  input = clear;
  inlen = clen;
  }

if ((rc = sasl_server_init(cbs, "exim")) != SASL_OK)
  {
  auth_defer_msg = US"couldn't initialise Cyrus SASL library";
  return DEFER;
  }

rc = sasl_server_new(CS ob->server_service, CS hname, realm_expanded, NULL,
  NULL, NULL, 0, &conn);

HDEBUG(D_auth)
  debug_printf("Initialised Cyrus SASL server connection; service=\"%s\" fqdn=\"%s\" realm=\"%s\"\n",
      ob->server_service, hname, realm_expanded);

if (rc != SASL_OK )
  {
  auth_defer_msg = US"couldn't initialise Cyrus SASL connection";
  sasl_done();
  return DEFER;
  }

if (tls_in.cipher)
  {
  if ((rc = sasl_setprop(conn, SASL_SSF_EXTERNAL, (sasl_ssf_t *) &tls_in.bits)) != SASL_OK)
    {
    HDEBUG(D_auth) debug_printf("Cyrus SASL EXTERNAL SSF set %d failed: %s\n",
        tls_in.bits, sasl_errstring(rc, NULL, NULL));
    auth_defer_msg = US"couldn't set Cyrus SASL EXTERNAL SSF";
    sasl_done();
    return DEFER;
    }
  else
    HDEBUG(D_auth) debug_printf("Cyrus SASL set EXTERNAL SSF to %d\n", tls_in.bits);
  }
else
  HDEBUG(D_auth) debug_printf("Cyrus SASL: no TLS, no EXTERNAL SSF set\n");

/* So sasl_setprop() documents non-shorted IPv6 addresses which is incredibly
annoying; looking at cyrus-imapd-2.3.x source, the IP address is constructed
with their iptostring() function, which just wraps
getnameinfo(..., NI_NUMERICHOST|NI_NUMERICSERV), which is equivalent to the
inet_ntop which we wrap in our host_ntoa() function.

So the docs are too strict and we shouldn't worry about :: contractions. */

/* Set properties for remote and local host-ip;port */
for (int i = 0; i < 2; ++i)
  {
  struct sockaddr_storage ss;
  int (*query)(int, struct sockaddr *, socklen_t *);
  int propnum, port;
  const uschar *label;
  uschar *address, *address_port;
  const char *s_err;
  socklen_t sslen;

  if (i)
    {
    query = &getpeername;
    propnum = SASL_IPREMOTEPORT;
    label = CUS"peer";
    }
  else
    {
    query = &getsockname;
    propnum = SASL_IPLOCALPORT;
    label = CUS"local";
    }

  sslen = sizeof(ss);
  if ((rc = query(fileno(smtp_in), (struct sockaddr *) &ss, &sslen)) < 0)
    {
    HDEBUG(D_auth)
      debug_printf("Failed to get %s address information: %s\n",
          label, strerror(errno));
    break;
    }

  address = host_ntoa(-1, &ss, NULL, &port);
  address_port = string_sprintf("%s;%d", address, port);

  if ((rc = sasl_setprop(conn, propnum, address_port)) != SASL_OK)
    {
    s_err = sasl_errdetail(conn);
    HDEBUG(D_auth)
      debug_printf("Failed to set %s SASL property: [%d] %s\n",
          label, rc, s_err ? s_err : "<unknown reason>");
    break;
    }
  HDEBUG(D_auth) debug_printf("Cyrus SASL set %s hostport to: %s\n",
      label, address_port);
  }

for (rc = SASL_CONTINUE; rc == SASL_CONTINUE; )
  {
  if (firsttime)
    {
    firsttime = 0;
    HDEBUG(D_auth) debug_printf("Calling sasl_server_start(%s,\"%s\")\n", ob->server_mech, debug);
    rc = sasl_server_start(conn, CS ob->server_mech, inlen?CS input:NULL, inlen,
           (const char **)(&output), &outlen);
    }
  else
    {
    /* make sure that we have a null-terminated string */
    out2 = string_copyn(output, outlen);

    if ((rc = auth_get_data(&input, out2, outlen)) != OK)
      {
      /* we couldn't get the data, so free up the library before
       * returning whatever error we get */
      sasl_dispose(&conn);
      sasl_done();
      return rc;
      }
    inlen = Ustrlen(input);

    HDEBUG(D_auth) debug = string_copy(input);
    if (inlen)
      {
      if ((clen = b64decode(input, &clear)) < 0)
       {
       sasl_dispose(&conn);
       sasl_done();
       return BAD64;
       }
      input = clear;
      inlen = clen;
      }

    HDEBUG(D_auth) debug_printf("Calling sasl_server_step(\"%s\")\n", debug);
    rc = sasl_server_step(conn, CS input, inlen, (const char **)(&output), &outlen);
    }

  if (rc == SASL_BADPROT)
    {
    sasl_dispose(&conn);
    sasl_done();
    return UNEXPECTED;
    }
  if (rc == SASL_CONTINUE)
    continue;

  /* Get the username and copy it into $auth1 and $1. The former is now the
  preferred variable; the latter is the original variable. */

  if ((sasl_getprop(conn, SASL_USERNAME, (const void **)(&out2))) != SASL_OK)
    {
    HDEBUG(D_auth)
      debug_printf("Cyrus SASL library will not tell us the username: %s\n",
	  sasl_errstring(rc, NULL, NULL));
    log_write(0, LOG_REJECT, "%s authenticator (%s):\n  "
       "Cyrus SASL username fetch problem: %s", ablock->name, ob->server_mech,
       sasl_errstring(rc, NULL, NULL));
    sasl_dispose(&conn);
    sasl_done();
    return FAIL;
    }
  auth_vars[0] = expand_nstring[1] = string_copy(out2);
  expand_nlength[1] = Ustrlen(out2);
  expand_nmax = 1;

  switch (rc)
    {
    case SASL_FAIL: case SASL_BUFOVER: case SASL_BADMAC: case SASL_BADAUTH:
    case SASL_NOAUTHZ: case SASL_ENCRYPT: case SASL_EXPIRED:
    case SASL_DISABLED: case SASL_NOUSER:
      /* these are considered permanent failure codes */
      HDEBUG(D_auth)
	debug_printf("Cyrus SASL permanent failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
      log_write(0, LOG_REJECT, "%s authenticator (%s):\n  "
	 "Cyrus SASL permanent failure: %s", ablock->name, ob->server_mech,
	 sasl_errstring(rc, NULL, NULL));
      sasl_dispose(&conn);
      sasl_done();
      return FAIL;

    case SASL_NOMECH:
      /* this is a temporary failure, because the mechanism is not
       * available for this user. If it wasn't available at all, we
       * shouldn't have got here in the first place...
       */
      HDEBUG(D_auth)
	debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
      auth_defer_msg =
	  string_sprintf("Cyrus SASL: mechanism %s not available", ob->server_mech);
      sasl_dispose(&conn);
      sasl_done();
      return DEFER;

    case SASL_OK:
      HDEBUG(D_auth)
	debug_printf("Cyrus SASL %s authentication succeeded for %s\n",
	    ob->server_mech, auth_vars[0]);

      if ((rc = sasl_getprop(conn, SASL_SSF, (const void **)(&negotiated_ssf_ptr)))!= SASL_OK)
	{
	HDEBUG(D_auth)
	  debug_printf("Cyrus SASL library will not tell us the SSF: %s\n",
	      sasl_errstring(rc, NULL, NULL));
	log_write(0, LOG_REJECT, "%s authenticator (%s):\n  "
	    "Cyrus SASL SSF value not available: %s", ablock->name, ob->server_mech,
	    sasl_errstring(rc, NULL, NULL));
	sasl_dispose(&conn);
	sasl_done();
	return FAIL;
	}
      negotiated_ssf = *negotiated_ssf_ptr;
      HDEBUG(D_auth)
	debug_printf("Cyrus SASL %s negotiated SSF: %d\n", ob->server_mech, negotiated_ssf);
      if (negotiated_ssf > 0)
	{
	HDEBUG(D_auth)
	  debug_printf("Exim does not implement SASL wrapping (needed for SSF %d).\n", negotiated_ssf);
	log_write(0, LOG_REJECT, "%s authenticator (%s):\n  "
	    "Cyrus SASL SSF %d not supported by Exim", ablock->name, ob->server_mech, negotiated_ssf);
	sasl_dispose(&conn);
	sasl_done();
	return FAIL;
	}

      /* close down the connection, freeing up library's memory */
      sasl_dispose(&conn);
      sasl_done();

      /* Expand server_condition as an authorization check */
      return auth_check_serv_cond(ablock);

    default:
      /* Anything else is a temporary failure, and we'll let SASL print out
       * the error string for us
       */
      HDEBUG(D_auth)
	debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
      auth_defer_msg =
	  string_sprintf("Cyrus SASL: %s", sasl_errstring(rc, NULL, NULL));
      sasl_dispose(&conn);
      sasl_done();
      return DEFER;
    }
  }
/* NOTREACHED */
return 0;  /* Stop compiler complaints */
}
Example #4
0
int
auth_cram_md5_server(auth_instance *ablock, uschar *data)
{
auth_cram_md5_options_block *ob =
  (auth_cram_md5_options_block *)(ablock->options_block);
uschar *challenge = string_sprintf("<%d.%ld@%s>", getpid(),
    (long int) time(NULL), primary_hostname);
uschar *clear, *secret;
uschar digest[16];
int i, rc, len;

/* If we are running in the test harness, always send the same challenge,
an example string taken from the RFC. */

if (running_in_test_harness)
  challenge = US"<*****@*****.**>";

/* No data should have been sent with the AUTH command */

if (*data != 0) return UNEXPECTED;

/* Send the challenge, read the return */

if ((rc = auth_get_data(&data, challenge, Ustrlen(challenge))) != OK) return rc;
if ((len = b64decode(data, &clear)) < 0) return BAD64;

/* The return consists of a user name, space-separated from the CRAM-MD5
digest, expressed in hex. Extract the user name and put it in $auth1 and $1.
The former is now the preferred variable; the latter is the original one. Then
check that the remaining length is 32. */

auth_vars[0] = expand_nstring[1] = clear;
while (*clear != 0 && !isspace(*clear)) clear++;
if (!isspace(*clear)) return FAIL;
*clear++ = 0;

expand_nlength[1] = clear - expand_nstring[1] - 1;
if (len - expand_nlength[1] - 1 != 32) return FAIL;
expand_nmax = 1;

/* Expand the server_secret string so that it can compute a value dependent on
the user name if necessary. */

debug_print_string(ablock->server_debug_string);    /* customized debugging */
secret = expand_string(ob->server_secret);

/* A forced fail implies failure of authentication - i.e. we have no secret for
the given name. */

if (secret == NULL)
  {
  if (expand_string_forcedfail) return FAIL;
  auth_defer_msg = expand_string_message;
  return DEFER;
  }

/* Compute the CRAM-MD5 digest that we should have received from the client. */

compute_cram_md5(secret, challenge, digest);

HDEBUG(D_auth)
  {
  uschar buff[64];
  debug_printf("CRAM-MD5: user name = %s\n", auth_vars[0]);
  debug_printf("          challenge = %s\n", challenge);
  debug_printf("          received  = %s\n", clear);
  Ustrcpy(buff,"          digest    = ");
  for (i = 0; i < 16; i++) sprintf(CS buff+22+2*i, "%02x", digest[i]);
  debug_printf("%.54s\n", buff);
  }

/* We now have to compare the digest, which is 16 bytes in binary, with the
data received, which is expressed in lower case hex. We checked above that
there were 32 characters of data left. */

for (i = 0; i < 16; i++)
  {
  int a = *clear++;
  int b = *clear++;
  if (((((a >= 'a')? a - 'a' + 10 : a - '0') << 4) +
        ((b >= 'a')? b - 'a' + 10 : b - '0')) != digest[i]) return FAIL;
  }

/* Expand server_condition as an authorization check */
return auth_check_serv_cond(ablock);
}
Example #5
0
std::string verifyne::Api::provider_key(void)
{
    /* HTTP query */

    verifyne::HttpInvoker hi;
    std::map<std::string, std::string> params;

    std::string url = API_BASE_URL + "/provider-key";

    std::string resp = hi.GET(url, params);

    ApiResponse *ar = new ApiResponse(resp);

    std::string pkey_b64 = (*ar->content)["pkey"].asString();
    std::string psig_b64 = (*ar->content)["psig"].asString();

    delete ar;

    /* Base64 decode - CA signature */

    std::string psig = b64decode(psig_b64);

    /* Verify CA signature */

    const unsigned char ca_key[] = {
        0x8B,0xB7,0x5B,0x5A,0xF9,0x45,0x74,0x7C,
        0x2F,0x89,0x45,0xDA,0xBF,0xB3,0x75,0x2F,
        0x0A,0x22,0xF8,0x33,0x89,0x0C,0x6F,0x52,
        0xB8,0x51,0xCD,0xC0,0xFF,0xC0,0x52,0x35 };

    if(0 != crypto_sign_verify_detached((unsigned char *)psig.c_str(), (unsigned char *)pkey_b64.c_str(), pkey_b64.length(), ca_key))
    {
        throw std::runtime_error("Provider key signature verification failed");
    }

    /* Base64 decode - Public Key data */

    std::string pkey = b64decode(pkey_b64);

    /* Split on ':' */

    std::size_t pos = pkey.find(":");
    if(pos == std::string::npos || pos < 2 || pos > (pkey.length() - 2))
    {
        throw std::runtime_error("Invalid provider key");
    }

    std::string algo = pkey.substr(0, pos);
    std::string key_b64 = pkey.substr(pos+1, std::string::npos);

    /* Verify */

    if(algo != "ed25519")
    {
        throw std::runtime_error("Unsupported algorithm: " + algo);
    }

    /* Base64 decode - Provider key */

    std::string key = b64decode(key_b64);

    return key;
}
Example #6
0
int main(int argc, char **argv)
{
	argc = argc;
	char test_string[] = "We dont need no education\0";

	int status;

	//TEST CLONELIB
	char *gob;
	int gob_length;
	printf("Testing clonelib.h\n");

	//Test function getOwnBytes
	gob_length = getOwnBytes(&gob, argv[0]);
	printf("getOwnBytes:\t%s(%d bytes)\n",
	       gob_length > 256 ? "OK" : "Failed", gob_length);

	//Test function infectTarget
	status = infectTarget(TEST_DIR "hello.exe", gob, gob_length);
	printf("infectTarget:\t%s\n", status ? "OK" : "Failed");

	//free
	free(gob);

	//TEST B64
	printf("\nTesting b64.h\n");
	int b64_decoded_msg_length;
	char *b64_decoded_msg;

	//Test function b64decode
	b64_decoded_msg_length = b64decode(&b64_decoded_msg, "T0s=");
	printf("b64decode:\t%s(%s)\n",
	       (b64_decoded_msg_length == 2
		&& !strcmp(b64_decoded_msg, "OK")) ? "OK" : "Failed",
	       b64_decoded_msg);


	//Test functions b16decode and b16encode
	status =
	    strcmp(b16decode(b16encode(test_string, strlen(test_string))),
		   test_string);
	printf("b16en/decode:\t%s", status ? "Failed" : "OK");
	if (status)
		printf("(%s!=%s)", test_string,b16decode(b16encode(test_string, strlen(test_string))));
	printf("\n");

	//free
	free(b64_decoded_msg);

	//Test CRYPT
	printf("\nTesting crypt.h\n");


	//Test function secureRand
	/*
	   status =
	   secureRand(&keyiv, SYMMETRIC_IV_SIZE + SYMMETRIC_KEY_SIZE);
	   printf("secureRand:\t%s\n", status ? "OK" : "Failed"); */

	//Test functions symEn/Decrypt
	char keyiv[] = "0123456789abcdef0123*56789abcdef";
	char encrypted_msg[16];
	char decrypted_msg[16];
	status = symEncrypt(encrypted_msg, keyiv, test_string, 16);
	printf("symEncrypt:\t%s\n", status ? "OK" : "Failed");

	status = symDecrypt(decrypted_msg, keyiv, encrypted_msg, 16);
	printf("symDecrypt:\t%s\n", status ? "OK" : "Failed",
	       decrypted_msg);
	/*printf("Together:\t%s(%s)\n",
	   !strcmp(decrypted_msg, test_string) ? "OK" : "Failed",
	   decrypted_msg); */


	//TESTING RANSOMLIB
	printf("\nTesting ransomlib.h\n");

	//Test encryption
	status = partialEncryptFile(keyiv, TEST_DIR "dummy.txt", 16, 0);
	printf("partialEncryptFile:\t%s\n", status ? "OK" : "Failed");

	//Test Decryption
	status = partialEncryptFile(keyiv, TEST_DIR "dummy.txt", 16, 1);
	printf("partialEncryptFile-d:\t%s\n", status ? "OK" : "Failed");


	//Tests paths
	printf("\nTestings paths.h\n");

	//Test
	char *harp = NULL;
	printf("getExternalPaths: %s\n",getExternalPaths(&harp)?"OK":"Failed");
	return 0;
}
Example #7
0
bool CClient :: Update( )
{
	if( gbDebug && ( gucDebugLevel & DEBUG_CLIENT ) )
		UTIL_LogPrint( "client: update start\n" );

	if( GetTime( ) > m_ulLast + m_uiTimeOut )
	{
		if( gbDebug && ( gucDebugLevel & DEBUG_CLIENT ) )
			UTIL_LogPrint( "client warning: socket timed out (%d s, state(%d), reset(%d))\n", m_uiTimeOut, m_ucState, m_bReset );

		return true;
	}

	bool bGrabParams = true;
	bool bGrabHeaders = true;
	bool bGrabCookies = true;

	fd_set fdClient;
	//FD_ZERO( &fdClient );

	struct timeval tv;

	char cCompress = COMPRESS_NONE;
	char *szAuth = 0; 
	unsigned char *pBuf = 0;
	unsigned char *pNextIn = 0;

	unsigned char szMD5[16];

	string :: size_type iNewLine = 0;
	string :: size_type iDoubleNewLine = 0;
	string :: size_type iMethodEnd = 0;
	string :: size_type iParamsStart = 0;
	string :: size_type iURLEnd = 0;
	string :: size_type iWhite = 0;
	string :: size_type iSplit = 0;
	string :: size_type iEnd = 0;

	string strAuthorization = string( );
	string strContentLength = string( );
	string strCookies = string( );
	string strLogin = string( );
	string strMD5 = string( );
	string strRequest = string( );
	string strTemp = string( );
	string strType = string( );
	string strBase64 = string( );
	string strAuth = string( );
	string strPass = string( );
	string strA1 = string( );
	string strAcceptEncoding = string( );
	string strKey = string( );
	string strValue = string( );

	int iRecv = 0;
	int iSend = 0;
	int windowBits = 0;
	int iResult = 0;
	unsigned int uiSize = 0;

	switch( m_ucState )
	{
	case CS_RECVHEADERS :
		if( gbDebug && ( gucDebugLevel & DEBUG_CLIENT ) )
			UTIL_LogPrint( "client: receive headers\n" );

		FD_ZERO( &fdClient );
		//FD_CLR( m_sckClient, &fdClient );
		FD_SET( m_sckClient, &fdClient );

		tv.tv_sec = 0;
		tv.tv_usec = 0;

#ifdef WIN32
		if( select( 1, &fdClient, 0, 0, &tv ) == SOCKET_ERROR )
#else
		if( select( m_sckClient + 1, &fdClient, 0, 0, &tv ) == SOCKET_ERROR )
#endif
		{
			UTIL_LogPrint( "client error: select error headers (error %s)\n", GetLastErrorString( ) );

			return true;
		}

		if( FD_ISSET( m_sckClient, &fdClient ) )
		{
			m_ulLast = GetTime( );

			memset( gpBuf, 0, sizeof(gpBuf) / sizeof(char) );

			iRecv = recv( m_sckClient, gpBuf, sizeof(gpBuf), 0 );

			if( iRecv == SOCKET_ERROR && GetLastError( ) != EWOULDBLOCK )
			{
				if( gbDebug && ( gucDebugLevel & DEBUG_CLIENT ) )
					UTIL_LogPrint( "client error: receive headers error (error %s)\n", GetLastErrorString( ) );
				else if( GetLastError( ) != EPIPE && GetLastError( ) != ECONNRESET )
					UTIL_LogPrint( "client error: receive headers error (error %s)\n", GetLastErrorString( ) );

				return true;
			}
			else if( iRecv == 0 )
			{
				if( gbDebug && ( gucDebugLevel & DEBUG_CLIENT ) )
					UTIL_LogPrint( "client error: receive headers returned 0\n" );

				return true;
			}
			else if( iRecv > 0 )
			{
				m_strReceiveBuf += string( gpBuf, iRecv );

				if( m_strReceiveBuf.size( ) > guiMaxRecvSize )
				{
					UTIL_LogPrint( "client error: exceeded max receive header size\n" );

					return true;
				}

				gtXStats.tcp.iRecv += iRecv;
			}
			else
			{
				UTIL_LogPrint( "client error: receive header returned garbage\n" );

				return true;
			}
		}

		if( m_strReceiveBuf.find( C_STR_DOUBLE_NEWLINE ) != string :: npos )
			m_ucState = CS_PROCESSHEADERS;
		else
			break;

	case CS_PROCESSHEADERS:
		if( gbDebug && ( gucDebugLevel & DEBUG_CLIENT ) )
			UTIL_LogPrint( "client: process headers\n" );

		// grab method

		iMethodEnd = m_strReceiveBuf.find( C_STR_WSPACE );

		if( iMethodEnd == string :: npos )
		{
			UTIL_LogPrint( "client error: malformed HTTP request (can't find method)\n" );

			return true;
		}

		rqst.strMethod = m_strReceiveBuf.substr( 0, iMethodEnd );

		// grab url

		strTemp = m_strReceiveBuf.substr( iMethodEnd + 1 );

		iURLEnd = strTemp.find( C_STR_WSPACE );

		if( iURLEnd == string :: npos )
		{
			UTIL_LogPrint( "client error: malformed HTTP request (can't find URL)\n" );

			return true;
		}

		strTemp = strTemp.substr( 0, iURLEnd );

		iParamsStart = strTemp.find( C_STR_ITEMQU );

		if( iParamsStart == string :: npos )
		{
			rqst.strURL = strTemp;
			rqst.hasQuery = false;
		}
		else
		{
			rqst.strURL = strTemp.substr( 0, iParamsStart );
			rqst.hasQuery = true;
		}

		// grab params

		if( iParamsStart != string :: npos )
		{
			strTemp = strTemp.substr( iParamsStart + 1 );
			rqst.hasQuery = true;

			iSplit = 0;
			iEnd = 0;

			strKey = string( );
			strValue = string( );

			bGrabParams = true;

			while( bGrabParams )
			{
				iSplit = strTemp.find( C_STR_ITEMEQ );
				iEnd = strTemp.find( C_STR_ITEMAND );

				if( iSplit == string :: npos )
				{
					UTIL_LogPrint( "client warning: malformed HTTP request (found param key without value)\n" );

					bGrabParams = false;
				}

				strKey = UTIL_EscapedToString( strTemp.substr( 0, iSplit ) );
				strValue = UTIL_EscapedToString( strTemp.substr( iSplit + 1, iEnd - iSplit - 1 ) );

				// multimap for scrape, regular map for everything else
				if ( rqst.strURL == RESPONSE_STR_SCRAPE )
					rqst.multiParams.insert( pair<string,string>( strKey, strValue ) );
				else
					rqst.mapParams.insert( pair<string, string>( strKey, strValue ) );

				strTemp = strTemp.substr( iEnd + 1, strTemp.size( ) - iEnd - 1 );

				if( iEnd == string :: npos )
					bGrabParams = false;
			}
		}

		// grab headers

		iNewLine = m_strReceiveBuf.find( C_STR_NEWLINE );
		iDoubleNewLine = m_strReceiveBuf.find( C_STR_DOUBLE_NEWLINE );

		if( iNewLine != iDoubleNewLine )
		{
			strTemp = m_strReceiveBuf.substr( iNewLine + ( sizeof(C_STR_NEWLINE) - 1 ), iDoubleNewLine - iNewLine - ( sizeof(C_STR_NEWLINE) - 1 ) );

			iSplit = 0;
			iEnd = 0;

			strKey = string( );
			strValue = string( );

			bGrabHeaders = true;

			while( bGrabHeaders )
			{
				iSplit = strTemp.find( C_STR_COLON );
				iEnd = strTemp.find( C_STR_NEWLINE );

				// http://www.addict3d.org/index.php?page=viewarticle&type=security&ID=4861
				if( iSplit == string :: npos || iSplit == 0 )
				{
					UTIL_LogPrint( "client warning: malformed HTTP request (bad header)\n" );

					bGrabHeaders = false;
				}

				strKey = strTemp.substr( 0, iSplit );
				strValue = strTemp.substr( iSplit + ( sizeof(": ") - 1 ), iEnd - iSplit - ( sizeof(C_STR_NEWLINE) - 1 ) );

				rqst.mapHeaders.insert( pair<string, string>( strKey, strValue ) );

				strTemp = strTemp.substr( iEnd + ( sizeof(C_STR_NEWLINE) - 1 ) );

				if( iEnd == string :: npos )
					bGrabHeaders = false;
			}
		}

		// grab cookies

		strCookies = rqst.mapHeaders["Cookie"];

		if( !strCookies.empty( ) )
		{
			iWhite = 0;

			iSplit = 0;
			iEnd = 0;		

			strKey = string( );
			strValue = string( );

			bGrabCookies = true;

			while( bGrabCookies )
			{
				iWhite = strCookies.find_first_not_of( C_STR_WSPACE );

				if( iWhite != string :: npos )
					strCookies = strCookies.substr( iWhite );

				iSplit = strCookies.find( C_STR_ITEMEQ );
				iEnd = strCookies.find( C_STR_SEMICOLON );

				if( iSplit == string :: npos )
				{
					UTIL_LogPrint( "client warning: malformed HTTP request (found cookie key without value)\n" );

					bGrabCookies = false;
				}

				strKey = UTIL_EscapedToString( strCookies.substr( 0, iSplit ) );
				strValue = UTIL_EscapedToString( strCookies.substr( iSplit + 1, iEnd - iSplit - 1 ) );

				// strip quotes

				if( strValue.size( ) > 1 && strValue[0] == CHAR_QUOTE )
					strValue = strValue.substr( 1, strValue.size( ) - 2 );

				rqst.mapCookies.insert( pair<string, string>( strKey, strValue ) );

				strCookies = strCookies.substr( iEnd + 1, strCookies.size( ) - iEnd - 1 );

				if( iEnd == string :: npos )
					bGrabCookies = false;
			}
		}

		// grab authentication
		strLogin = rqst.mapCookies["login"];
		strMD5 = rqst.mapCookies["md5"];

		strAuthorization = rqst.mapHeaders["Authorization"];
		
// 		if( ( !strAuthorization.empty( ) && strLogout != "1" ) || ( !strLogin.empty( ) ) )
		if( !strAuthorization.empty( ) )
		{
			iWhite = strAuthorization.find( C_STR_WSPACE );

			if( iWhite != string :: npos )
			{
				strType = strAuthorization.substr( 0, iWhite );
				strBase64 = strAuthorization.substr( iWhite + 1 );

				if( strType == "Basic" )
				{
					szAuth = b64decode( strBase64.c_str( ) );

					if( szAuth )
					{
						strAuth = szAuth;

						free( szAuth );

						iSplit = strAuth.find( C_STR_COLON );

						if( iSplit != string :: npos )
						{
							strLogin = strAuth.substr( 0, iSplit );
							strPass = strAuth.substr( iSplit + 1 );

#if defined ( XBNBT_MYSQL )
							// XBNBT MySQL Users Integration
							if( gbMySQLUsersOverrideUsers )
							{
								CMD5 md5( ( const char* )strPass.c_str( ) );
								strMD5 = md5.getMD5Digest( );
							}
							else
							{
#endif
								// Original code
								// calculate md5 hash of A1

								strA1 = strLogin + C_STR_COLON + gstrRealm + C_STR_COLON + strPass;

								memset( szMD5, 0, sizeof(szMD5) / sizeof(unsigned char) );

								MD5_CTX md5;

								MD5Init( &md5 );
								MD5Update( &md5, (const unsigned char *)strA1.c_str( ), (unsigned int)strA1.size( ) );
								MD5Final( szMD5, &md5 );

								strMD5 = string( (char *)szMD5, sizeof(szMD5) / sizeof(unsigned char) );

#if defined ( XBNBT_MYSQL )
							}
#endif
						}
					}
				}
			}
		}

// 		if ( strOldLogin.empty( ) )
// 		{
// 			if ( !strLogin.empty( ) )
// 				UTIL_LogPrint( "NewLogin: (%s)\n", strLogin.c_str( ) );
// 				rqst.user = gpServer->getTracker( )->checkUser( strOldLogin, strOldMD5 );
// 			if ( strLogout != "1" )
// 				if ( !strLogin.empty( ) )
		rqst.user = gpServer->getTracker( )->checkUser( strLogin, strMD5 );
				
				
// 			else
// 				rqst.user = gpServer->getTracker( )->checkUser( strOldLogin, strOldMD5 );
// 		}
		
// 		}
// 		else
// 		{
// 			rqst.user.strLogin.erase( );
// 			rqst.user.strLowerLogin.erase( );
// 			rqst.user.strMD5.erase( );
// 			rqst.user.strMail.erase( );
// 			rqst.user.strLowerMail.erase( );
// 			rqst.user.strCreated.erase( );
// 			rqst.user.ucAccess = 0;
// 		}

		if( rqst.strMethod == "POST" )
			m_ucState = CS_RECVBODY;
		else
		{
			m_ucState = CS_MAKERESPONSE;

			break;
		}

	case CS_RECVBODY:
		if( gbDebug && ( gucDebugLevel & DEBUG_CLIENT ) )
			UTIL_LogPrint( "client: receive body\n" );

		strContentLength = rqst.mapHeaders["Content-Length"];

		if( strContentLength.empty( ) )
		{
			UTIL_LogPrint( "client error: malformed HTTP request (no Content-Length with POST)\n" );

			return true;
		}

		FD_ZERO( &fdClient );
		//FD_CLR( m_sckClient, &fdClient );
		FD_SET( m_sckClient, &fdClient );

		tv.tv_sec = 0;
		tv.tv_usec = 0;

#ifdef WIN32
		if( select( 1, &fdClient, 0, 0, &tv ) == SOCKET_ERROR )
#else
		if( select( m_sckClient + 1, &fdClient, 0, 0, &tv ) == SOCKET_ERROR )
#endif
		{
			UTIL_LogPrint( "client error: select error body (error %s)\n", GetLastErrorString( ) );

			return true;
		}

		if( FD_ISSET( m_sckClient, &fdClient ) )
		{
			m_ulLast = GetTime( );

			memset( gpBuf, 0, sizeof(gpBuf) / sizeof(char) );

			iRecv = recv( m_sckClient, gpBuf, sizeof(gpBuf), 0 );

			if( iRecv == SOCKET_ERROR && GetLastError( ) != EWOULDBLOCK )
			{
				if( gbDebug && ( gucDebugLevel & DEBUG_CLIENT ) )
					UTIL_LogPrint( "client error: receive body error (error %s)\n", GetLastErrorString( ) );
				else if( GetLastError( ) != EPIPE && GetLastError( ) != ECONNRESET )
					UTIL_LogPrint( "client error: receive body error (error %s)\n", GetLastErrorString( ) );

				return true;
			}
			else if( iRecv == 0 )
			{
				UTIL_LogPrint( "client error: receive body returned 0\n" );

				return true;
			}
			else if( iRecv > 0 )
			{
				m_strReceiveBuf += string( gpBuf, iRecv );

				if( m_strReceiveBuf.size( ) > guiMaxRecvSize )
				{
					UTIL_LogPrint( "client error: exceeded max receive body size\n" );

					return true;
				}

				gtXStats.tcp.iRecv += iRecv;
			}
			else
			{
				UTIL_LogPrint( "client error: receive body returned garbage\n" );

				return true;
			}
		}

		if( m_strReceiveBuf.size( ) >= m_strReceiveBuf.find( C_STR_DOUBLE_NEWLINE ) + ( sizeof(C_STR_DOUBLE_NEWLINE) - 1 ) + atol( strContentLength.c_str( ) ) )
			m_ucState = CS_MAKERESPONSE;
		else
			break;

	case CS_MAKERESPONSE:
		if( gbDebug )
			UTIL_LogPrint( "client - make response\n" );

		if( rqst.strMethod == "GET" )
			gpServer->getTracker( )->serverResponseGET( &rqst, &rsp );
		else if( rqst.strMethod == "POST" )
		{
			CAtomList *pPost = UTIL_DecodeHTTPPost( m_strReceiveBuf );

			gpServer->getTracker( )->serverResponsePOST( &rqst, &rsp, pPost );

			if( pPost )
				delete pPost;
		}
		else
			rsp.strCode = "400 Bad Request";

		// compress

		cCompress = COMPRESS_NONE;

		if( rsp.bCompressOK && m_cCompression > 0 )
		{
			strAcceptEncoding = UTIL_ToLower( rqst.mapHeaders["Accept-Encoding"] );

			if( strAcceptEncoding.find( "gzip" ) != string :: npos )
				cCompress = COMPRESS_GZIP;
			else if( strAcceptEncoding.find( "deflate" ) != string :: npos )
				cCompress = COMPRESS_DEFLATE;
		}

		if( !rsp.strContent.empty( ) && cCompress != COMPRESS_NONE )
		{
			// allocate avail_in * 1.001 + 18 bytes (12 + 6 for gzip)

			uiSize = (unsigned int)( rsp.strContent.size( ) * 1.001 + 18 );

			pBuf = new unsigned char[uiSize];
			memset( pBuf, 0, sizeof(pBuf) / sizeof(unsigned char) );

			z_stream_s zCompress;

			//unsigned char
			pNextIn = new unsigned char[uiSize];
			memset( pNextIn, 0, sizeof(pNextIn) / sizeof(unsigned char) );
			snprintf( (char *)pNextIn, uiSize / sizeof(unsigned char), "%s", rsp.strContent.c_str( ) );

			zCompress.next_in = pNextIn;
			zCompress.avail_in = (unsigned int)rsp.strContent.size( );
			zCompress.next_out = pBuf;
			zCompress.avail_out = uiSize;
			zCompress.zalloc = (alloc_func)0;
			zCompress.zfree = (free_func)0;
			zCompress.opaque = (voidpf)0;
			zCompress.total_in = 0;
			zCompress.total_out = 0;

			windowBits = 15;

			if( cCompress == COMPRESS_GZIP )
				windowBits = 31;

			iResult = deflateInit2( &zCompress, m_cCompression, Z_DEFLATED, windowBits, 8, Z_DEFAULT_STRATEGY );

			if( iResult == Z_OK )
			{
				iResult = deflate( &zCompress, Z_FINISH );

				if( iResult == Z_STREAM_END )
				{
					if( zCompress.total_in > zCompress.total_out )
					{
						if( gbDebug )
							UTIL_LogPrint( "client: (zlib) compressed %lu bytes to %lu bytes\n", zCompress.total_in, zCompress.total_out );

						if( cCompress == COMPRESS_GZIP )
							rsp.mapHeaders.insert( pair<string, string>( "Content-Encoding", "gzip" ) );
						else
							rsp.mapHeaders.insert( pair<string, string>( "Content-Encoding", "deflate" ) );

						rsp.strContent = string( (char *)pBuf, zCompress.total_out );
					}

					deflateEnd( &zCompress );

					delete [] pBuf;
				}
				else
				{
					if( iResult != Z_OK )
						UTIL_LogPrint( "client warning: (zlib) deflate error (%d) on \"%s\", in = %u, sending raw\n", iResult, rqst.strURL.c_str( ), rsp.strContent.size( ) );

					deflateEnd( &zCompress );

					delete [] pBuf;
				}
			}
			else
			{
				UTIL_LogPrint( "client warning: (zlib) deflateInit2 error (%d), sending raw\n", iResult );

				delete [] pBuf;
			}

			delete [] pNextIn;
		}

		// keep alive

		if( UTIL_ToLower( rqst.mapHeaders["Connection"] ) == "keep-alive" )
		{
			m_bKeepAlive = true;

			rsp.mapHeaders.insert( pair<string, string>( "Connection", "Keep-Alive" ) );
			rsp.mapHeaders.insert( pair<string, string>( "Keep-Alive", CAtomInt( m_uiTimeOut - 1 ).toString( ) ) );
		}
		else
		{
			m_bKeepAlive = false;

			rsp.mapHeaders.insert( pair<string, string>( "Connection", "Close" ) );
		}

		rsp.mapHeaders.insert( pair<string, string>( "Content-Length", CAtomLong( rsp.strContent.size( ) ).toString( ) ) );

		// access log

		strRequest = string( );

		iNewLine = m_strReceiveBuf.find( C_STR_NEWLINE );

		if( iNewLine != string :: npos )
			strRequest = m_strReceiveBuf.substr( 0, iNewLine );

		UTIL_AccessLogPrint( inet_ntoa( rqst.sin.sin_addr ), rqst.user.strLogin, strRequest, atoi( rsp.strCode.substr( 0, 3 ).c_str( ) ), (int)rsp.strContent.size( ) );

		// compose send buffer

		// fix for \r\n issues with non-tolerant HTTP client implementations - DWK
		m_strSendBuf += "HTTP/1.1 " + rsp.strCode + "\r\n";

		for( multimap<string, string> :: iterator it = rsp.mapHeaders.begin( ); it != rsp.mapHeaders.end( ); it++ )
			m_strSendBuf += (*it).first + ": " + (*it).second + "\r\n";

		m_strSendBuf += "\r\n";
		m_strSendBuf += rsp.strContent;

		m_ucState = CS_SEND;

	case CS_SEND:
		if( gbDebug )
			UTIL_LogPrint( "client - send\n" );

		FD_ZERO( &fdClient );
		//FD_CLR( m_sckClient, &fdClient );
		FD_SET( m_sckClient, &fdClient );

		tv.tv_sec = 0;
		tv.tv_usec = 0;

#ifdef WIN32
		if( select( 1, 0, &fdClient, 0, &tv ) == SOCKET_ERROR )
#else
		if( select( m_sckClient + 1, 0, &fdClient, 0, &tv ) == SOCKET_ERROR )
#endif
		{
			UTIL_LogPrint( "client error: select error send (error %s)\n", GetLastErrorString( ) );

			return true;
		}

		if( FD_ISSET( m_sckClient, &fdClient ) )
		{
			m_ulLast = GetTime( );

			iSend = send( m_sckClient, m_strSendBuf.c_str( ), (int)m_strSendBuf.size( ), MSG_NOSIGNAL );

			if( iSend == SOCKET_ERROR && GetLastError( ) != EWOULDBLOCK )
			{
				if( gbDebug && ( gucDebugLevel & DEBUG_CLIENT ) )
					UTIL_LogPrint( "client error: send error (error %s)\n", GetLastErrorString( ) );
				else if( GetLastError( ) != EPIPE && GetLastError( ) != ECONNRESET )
					UTIL_LogPrint( "client error: send error (error %s)\n", GetLastErrorString( ) );

				return true;
			}
			else if( iSend == 0 )
			{
				UTIL_LogPrint( "client error: send returned 0\n" );

				return true;
			}
			else if( iSend > 0 )
			{
				m_strSendBuf = m_strSendBuf.substr( iSend );

				gtXStats.tcp.iSend += iSend;

				if( m_strSendBuf.empty( ) )
				{
					if( m_bKeepAlive )
					{
						if( gbDebug && ( gucDebugLevel & DEBUG_CLIENT ) )
							UTIL_LogPrint( "client: keep alive\n" );

						Reset( );

						return false;
					}
					else
						return true;
				}
			}
			else
			{
				UTIL_LogPrint( "client error: send returned garbage\n" );

				return true;
			}
		}

		break;

	default:
		UTIL_LogPrint( "client error: unknown state\n" );
	}

	if( gbDebug && ( gucDebugLevel & DEBUG_CLIENT ) )
		UTIL_LogPrint( "client: update end\n" );

	m_bReset = false;
	return false;
}
Example #8
0
static int32_t ghttp_recv_chk(struct s_client *client, uchar *dcw, int32_t *rc, uchar *buf, int32_t n)
{
	char *data;
	char *hdrstr;
	uchar *content;
	int rcode, len, clen = 0;
	s_ghttp *context = (s_ghttp *)client->ghttp;
	ECM_REQUEST *er = NULL;

	if(n < 5) { return -1; }

	data = strstr((char *)buf, "HTTP/1.1 ");
	if(!data || ll_count(context->ecm_q) > 6)
	{
		cs_debug_mask(D_CLIENT, "%s: non http or otherwise corrupt response: %s", client->reader->label, buf);
		cs_ddump_mask(D_CLIENT, buf, n, "%s: ", client->reader->label);
		network_tcp_connection_close(client->reader, "receive error");
		NULLFREE(context->session_id);
		ll_clear(context->ecm_q);
		return -1;
	}

	LL_ITER itr = ll_iter_create(context->ecm_q);
	er = (ECM_REQUEST *)ll_iter_next(&itr);

	rcode = _get_int_header(buf, "HTTP/1.1 ");
	clen = _get_int_header(buf, "Content-Length: ");

	content = (uchar *)(strstr(data, "\r\n\r\n") + 4);

	hdrstr = _get_header_substr(buf, "ETag: \"", "\"\r\n");
	if(hdrstr)
	{
		NULLFREE(context->host_id);
		context->host_id = (uchar *)hdrstr;
		cs_debug_mask(D_CLIENT, "%s: new name: %s", client->reader->label, context->host_id);
		len = b64decode(context->host_id);
		if(len == 0 || len >= 64)
		{
			NULLFREE(context->host_id);
		}
		else
		{
			cs_debug_mask(D_CLIENT, "%s: redirected...", client->reader->label);
			NULLFREE(context->session_id);
			ll_clear_data(ghttp_ignored_contexts);
			ll_clear(context->ecm_q);
			return -1;
		}
	}

	hdrstr = _get_header_substr(buf, "ETag: W/\"", "\"\r\n");
	if(hdrstr)
	{
		NULLFREE(context->fallback_id);
		context->fallback_id = (uchar *)hdrstr;
		cs_debug_mask(D_CLIENT, "%s: new fallback name: %s", client->reader->label, context->fallback_id);
		len = b64decode(context->fallback_id);
		if(len == 0 || len >= 64)
		{
			NULLFREE(context->fallback_id);
		}
	}

	hdrstr = _get_header(buf, "Set-Cookie: GSSID=");
	if(hdrstr)
	{
		NULLFREE(context->session_id);
		context->session_id = (uchar *)hdrstr;
		cs_debug_mask(D_CLIENT, "%s: set session_id to: %s", client->reader->label, context->session_id);
	}

	// buf[n] = '\0';
	// cs_ddump_mask(D_TRACE, content, clen, "%s: reply\n%s", client->reader->label, buf);

	if(rcode < 200 || rcode > 204)
	{
		cs_debug_mask(D_CLIENT, "%s: http error code %d", client->reader->label, rcode);
		data = strstr((char *)buf, "Content-Type: application/octet-stream"); // if not octet-stream, google error. need reconnect?
		if(data)    // we have error info string in the post content
		{
			if(clen > 0)
			{
				content[clen] = '\0';
				cs_debug_mask(D_CLIENT, "%s: http error message: %s", client->reader->label, content);
			}
		}
		if(rcode == 503)
		{
			if(er && _is_post_context(context->post_contexts, er, false))
			{
				if(_swap_hosts(context))
				{
					cs_debug_mask(D_CLIENT, "%s: switching to fallback", client->reader->label);
				}
				else
				{
					cs_debug_mask(D_CLIENT, "%s: recv_chk got 503 despite post, trying reconnect", client->reader->label);
					network_tcp_connection_close(client->reader, "reconnect");
					ll_clear(context->ecm_q);
				}
			}
			else
			{
				// on 503 cache timeout, retry with POST immediately (and switch to POST for subsequent)
				if(er)
				{
					_set_pid_status(context->post_contexts, er->onid, er->tsid, er->srvid, 0);
					cs_debug_mask(D_CLIENT, "%s: recv_chk got 503, trying direct post", client->reader->label);
					_ghttp_post_ecmdata(client, er);
				}
			}
		}
		else if(rcode == 401)
		{
			NULLFREE(context->session_id);
			if(er)
			{
				cs_debug_mask(D_CLIENT, "%s: session expired, trying direct post", client->reader->label);
				_ghttp_post_ecmdata(client, er);
			}
		}
		else if(rcode == 403)
		{
			client->reader->enable = 0;
			network_tcp_connection_close(client->reader, "login failure");
			ll_clear(context->ecm_q);
			cs_log("%s: invalid username/password, disabling reader.", client->reader->label);
		}

		// not sure if this is needed on failure, copied from newcamd
		*rc = 0;
		memset(dcw, 0, 16);

		return -1;
	}

	// successful http reply (200 ok or 204 no content)

	hdrstr = _get_header(buf,  "Pragma: context-ignore=");
	if(hdrstr)
	{
		if(clen > 1)
		{
			cs_ddump_mask(D_CLIENT, content, clen, "%s: pmt ignore reply - %s (%d pids)", client->reader->label, hdrstr, clen / 2);
			uint32_t onid = 0, tsid = 0, sid = 0;
			if(sscanf(hdrstr, "%4x-%4x-%4x", &onid, &tsid, &sid) == 3)
				{ _set_pids_status(ghttp_ignored_contexts, onid, tsid, sid, content, clen); }
			NULLFREE(hdrstr);
			return -1;
		}
		NULLFREE(hdrstr);
	}

	data = strstr((char *)buf, "Pragma: context-ignore-clear");
	if(data)
	{
		cs_debug_mask(D_CLIENT, "%s: clearing local ignore list (size %d)", client->reader->label, ll_count(ghttp_ignored_contexts));
		ll_clear_data(ghttp_ignored_contexts);
	}

	// switch back to cache get after rapid ecm response (arbitrary atm), only effect is a slight bw save for client
	if(!er || _is_post_context(context->post_contexts, er, false))
	{
		data = strstr((char *)buf, "Pragma: cached");
		if(data || (client->cwlastresptime > 0 && client->cwlastresptime < 640))
		{
			cs_debug_mask(D_CLIENT, "%s: probably cached cw (%d ms), switching back to cache get for next req", client->reader->label, client->cwlastresptime);
			if(er) { _is_post_context(context->post_contexts, er, true); }
		}
	}

	if(clen == 16)    // cw in content
	{
		memcpy(dcw, content, 16);
		*rc = 1;
		er = ll_remove_first(context->ecm_q);
		if(!er) { return -1; }
		cs_ddump_mask(D_TRACE, dcw, 16, "%s: cw recv chk for idx %d", client->reader->label, er->idx);
		return er->idx;
	}
	else
	{
		if(clen != 0) { cs_ddump_mask(D_CLIENT, content, clen, "%s: recv_chk fail, clen = %d", client->reader->label, clen); }
	}
	return -1;
}
Example #9
0
int
auth_heimdal_gssapi_server(auth_instance *ablock, uschar *initial_data)
{
  gss_name_t gclient = GSS_C_NO_NAME;
  gss_name_t gserver = GSS_C_NO_NAME;
  gss_cred_id_t gcred = GSS_C_NO_CREDENTIAL;
  gss_ctx_id_t gcontext = GSS_C_NO_CONTEXT;
  uschar *ex_server_str;
  gss_buffer_desc gbufdesc = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc gbufdesc_in = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc gbufdesc_out = GSS_C_EMPTY_BUFFER;
  gss_OID mech_type;
  OM_uint32 maj_stat, min_stat;
  int step, error_out, i;
  uschar *tmp1, *tmp2, *from_client;
  auth_heimdal_gssapi_options_block *ob =
    (auth_heimdal_gssapi_options_block *)(ablock->options_block);
  BOOL handled_empty_ir;
  uschar *store_reset_point;
  uschar *keytab;
  uschar sasl_config[4];
  uschar requested_qop;

  store_reset_point = store_get(0);

  HDEBUG(D_auth)
    debug_printf("heimdal: initialising auth context for %s\n", ablock->name);

  /* Construct our gss_name_t gserver describing ourselves */
  tmp1 = expand_string(ob->server_service);
  tmp2 = expand_string(ob->server_hostname);
  ex_server_str = string_sprintf("%s@%s", tmp1, tmp2);
  gbufdesc.value = (void *) ex_server_str;
  gbufdesc.length = Ustrlen(ex_server_str);
  maj_stat = gss_import_name(&min_stat,
      &gbufdesc, GSS_C_NT_HOSTBASED_SERVICE, &gserver);
  if (GSS_ERROR(maj_stat))
    return exim_gssapi_error_defer(store_reset_point, maj_stat, min_stat,
        "gss_import_name(%s)", CS gbufdesc.value);

  /* Use a specific keytab, if specified */
  if (ob->server_keytab) {
    keytab = expand_string(ob->server_keytab);
    maj_stat = gsskrb5_register_acceptor_identity(CCS keytab);
    if (GSS_ERROR(maj_stat))
      return exim_gssapi_error_defer(store_reset_point, maj_stat, min_stat,
          "registering keytab \"%s\"", keytab);
    HDEBUG(D_auth)
      debug_printf("heimdal: using keytab \"%s\"\n", keytab);
  }

  /* Acquire our credentials */
  maj_stat = gss_acquire_cred(&min_stat,
      gserver,             /* desired name */
      0,                   /* time */
      GSS_C_NULL_OID_SET,  /* desired mechs */
      GSS_C_ACCEPT,        /* cred usage */
      &gcred,              /* handle */
      NULL                 /* actual mechs */,
      NULL                 /* time rec */);
  if (GSS_ERROR(maj_stat))
    return exim_gssapi_error_defer(store_reset_point, maj_stat, min_stat,
        "gss_acquire_cred(%s)", ex_server_str);

  maj_stat = gss_release_name(&min_stat, &gserver);

  HDEBUG(D_auth) debug_printf("heimdal: have server credentials.\n");

  /* Loop talking to client */
  step = 0;
  from_client = initial_data;
  handled_empty_ir = FALSE;
  error_out = OK;

  /* buffer sizes: auth_get_data() uses big_buffer, which we grow per
  GSSAPI RFC in _init, if needed, to meet the SHOULD size of 64KB.
  (big_buffer starts life at the MUST size of 16KB). */

  /* step values
  0: getting initial data from client to feed into GSSAPI
  1: iterating for as long as GSS_S_CONTINUE_NEEDED
  2: GSS_S_COMPLETE, SASL wrapping for authz and qop to send to client
  3: unpick final auth message from client
  4: break/finish (non-step)
  */
  while (step < 4) {
    switch (step) {
      case 0:
        if (!from_client || *from_client == '\0') {
          if (handled_empty_ir) {
            HDEBUG(D_auth) debug_printf("gssapi: repeated empty input, grr.\n");
            error_out = BAD64;
            goto ERROR_OUT;
          } else {
            HDEBUG(D_auth) debug_printf("gssapi: missing initial response, nudging.\n");
            error_out = auth_get_data(&from_client, US"", 0);
            if (error_out != OK)
              goto ERROR_OUT;
            handled_empty_ir = TRUE;
            continue;
          }
        }
        /* We should now have the opening data from the client, base64-encoded. */
        step += 1;
        HDEBUG(D_auth) debug_printf("heimdal: have initial client data\n");
        break;

      case 1:
        gbufdesc_in.length = b64decode(from_client, USS &gbufdesc_in.value);
        if (gclient) {
          maj_stat = gss_release_name(&min_stat, &gclient);
          gclient = GSS_C_NO_NAME;
        }
        maj_stat = gss_accept_sec_context(&min_stat,
            &gcontext,          /* context handle */
            gcred,              /* acceptor cred handle */
            &gbufdesc_in,       /* input from client */
            GSS_C_NO_CHANNEL_BINDINGS,  /* XXX fixme: use the channel bindings from GnuTLS */
            &gclient,           /* client identifier */
            &mech_type,         /* mechanism in use */
            &gbufdesc_out,      /* output to send to client */
            NULL,               /* return flags */
            NULL,               /* time rec */
            NULL                /* delegated cred_handle */
            );
        if (GSS_ERROR(maj_stat)) {
          exim_gssapi_error_defer(NULL, maj_stat, min_stat,
              "gss_accept_sec_context()");
          error_out = FAIL;
          goto ERROR_OUT;
        }
        if (&gbufdesc_out.length != 0) {
          error_out = auth_get_data(&from_client,
              gbufdesc_out.value, gbufdesc_out.length);
          if (error_out != OK)
            goto ERROR_OUT;

          gss_release_buffer(&min_stat, &gbufdesc_out);
          EmptyBuf(gbufdesc_out);
        }
        if (maj_stat == GSS_S_COMPLETE) {
          step += 1;
          HDEBUG(D_auth) debug_printf("heimdal: GSS complete\n");
        } else {
          HDEBUG(D_auth) debug_printf("heimdal: need more data\n");
        }
        break;

      case 2:
        memset(sasl_config, 0xFF, 4);
        /* draft-ietf-sasl-gssapi-06.txt defines bitmasks for first octet
        0x01 No security layer
        0x02 Integrity protection
        0x04 Confidentiality protection

        The remaining three octets are the maximum buffer size for wrapped
        content. */
        sasl_config[0] = 0x01;  /* Exim does not wrap/unwrap SASL layers after auth */
        gbufdesc.value = (void *) sasl_config;
        gbufdesc.length = 4;
        maj_stat = gss_wrap(&min_stat,
            gcontext,
            0,                    /* conf_req_flag: integrity only */
            GSS_C_QOP_DEFAULT,    /* qop requested */
            &gbufdesc,            /* message to protect */
            NULL,                 /* conf_state: no confidentiality applied */
            &gbufdesc_out         /* output buffer */
            );
        if (GSS_ERROR(maj_stat)) {
          exim_gssapi_error_defer(NULL, maj_stat, min_stat,
              "gss_wrap(SASL state after auth)");
          error_out = FAIL;
          goto ERROR_OUT;
        }

        HDEBUG(D_auth) debug_printf("heimdal SASL: requesting QOP with no security layers\n");

        error_out = auth_get_data(&from_client,
            gbufdesc_out.value, gbufdesc_out.length);
        if (error_out != OK)
          goto ERROR_OUT;

        gss_release_buffer(&min_stat, &gbufdesc_out);
        EmptyBuf(gbufdesc_out);
        step += 1;
        break;

      case 3:
        gbufdesc_in.length = b64decode(from_client, USS &gbufdesc_in.value);
        maj_stat = gss_unwrap(&min_stat,
            gcontext,
            &gbufdesc_in,       /* data from client */
            &gbufdesc_out,      /* results */
            NULL,               /* conf state */
            NULL                /* qop state */
            );
        if (GSS_ERROR(maj_stat)) {
          exim_gssapi_error_defer(NULL, maj_stat, min_stat,
              "gss_unwrap(final SASL message from client)");
          error_out = FAIL;
          goto ERROR_OUT;
        }
        if (gbufdesc_out.length < 4) {
          HDEBUG(D_auth)
            debug_printf("gssapi: final message too short; "
                "need flags, buf sizes and optional authzid\n");
          error_out = FAIL;
          goto ERROR_OUT;
        }

        requested_qop = (CS gbufdesc_out.value)[0];
        if ((requested_qop & 0x01) == 0) {
          HDEBUG(D_auth)
            debug_printf("gssapi: client requested security layers (%x)\n",
                (unsigned int) requested_qop);
          error_out = FAIL;
          goto ERROR_OUT;
        }

        for (i = 0; i < AUTH_VARS; i++) auth_vars[i] = NULL;
        expand_nmax = 0;

        /* Identifiers:
        The SASL provided identifier is an unverified authzid.
        GSSAPI provides us with a verified identifier, but it might be empty
        for some clients.
        */

        /* $auth2 is authzid requested at SASL layer */
        if (gbufdesc_out.length > 4) {
          expand_nlength[2] = gbufdesc_out.length - 4;
          auth_vars[1] = expand_nstring[2] =
            string_copyn((US gbufdesc_out.value) + 4, expand_nlength[2]);
          expand_nmax = 2;
        }

        gss_release_buffer(&min_stat, &gbufdesc_out);
        EmptyBuf(gbufdesc_out);

        /* $auth1 is GSSAPI display name */
        maj_stat = gss_display_name(&min_stat,
            gclient,
            &gbufdesc_out,
            &mech_type);
        if (GSS_ERROR(maj_stat)) {
          auth_vars[1] = expand_nstring[2] = NULL;
          expand_nmax = 0;
          exim_gssapi_error_defer(NULL, maj_stat, min_stat,
              "gss_display_name(client identifier)");
          error_out = FAIL;
          goto ERROR_OUT;
        }

        expand_nlength[1] = gbufdesc_out.length;
        auth_vars[0] = expand_nstring[1] =
          string_copyn(gbufdesc_out.value, gbufdesc_out.length);

        if (expand_nmax == 0) { /* should be: authzid was empty */
          expand_nmax = 2;
          expand_nlength[2] = expand_nlength[1];
          auth_vars[1] = expand_nstring[2] = string_copyn(expand_nstring[1], expand_nlength[1]);
          HDEBUG(D_auth)
            debug_printf("heimdal SASL: empty authzid, set to dup of GSSAPI display name\n");
        }

        HDEBUG(D_auth)
          debug_printf("heimdal SASL: happy with client request\n"
             "  auth1 (verified GSSAPI display-name): \"%s\"\n"
             "  auth2 (unverified SASL requested authzid): \"%s\"\n",
             auth_vars[0], auth_vars[1]);

        step += 1;
        break;

    } /* switch */
  } /* while step */


ERROR_OUT:
  maj_stat = gss_release_cred(&min_stat, &gcred);
  if (gclient) {
    gss_release_name(&min_stat, &gclient);
    gclient = GSS_C_NO_NAME;
  }
  if (gbufdesc_out.length) {
    gss_release_buffer(&min_stat, &gbufdesc_out);
    EmptyBuf(gbufdesc_out);
  }
  if (gcontext != GSS_C_NO_CONTEXT) {
    gss_delete_sec_context(&min_stat, &gcontext, GSS_C_NO_BUFFER);
  }

  store_reset(store_reset_point);

  if (error_out != OK)
    return error_out;

  /* Auth succeeded, check server_condition */
  return auth_check_serv_cond(ablock);
}
Example #10
0
File: gw-http.c Project: Voxar/spot
int http_handle_request (RESTSESSION * r)
{
	struct buf *b;
	char buf[512];
	char *p;
	SPOTIFYSESSION *client;

	/*
	 * r->httpreq->url has path that was requested
	 * r->httpreq->authheader MIGHT be non-NULL and 
	 * have username:password in base64
	 *
	 */

	/* Default to process next command */
	r->state = REST_STATE_LOAD_COMMAND;

	if ((client = spotify_find_http_client ()) == NULL) {
		/* Force auth if not sent or likely invalid */
		if (!r->httpreq->authheader
				|| strlen (r->httpreq->authheader) > 100)
			return http_reply_need_auth (r);

		memset (buf, 0, sizeof (buf));
		b64decode (r->httpreq->authheader, buf);
		if ((p = strchr (buf, ':')) == NULL) {
			printf ("b64 decode failed '%s'\n", buf);
			return http_reply_need_auth (r);
		}

		*p++ = 0;
		strcpy (r->username, buf);
		strcpy (r->password, p);
		spotify_client_allocate (r);
		spotify_client_mark_for_http (r->client);
		if (r->client->state == CLIENT_STATE_IDLE_CONNECTED)
			return http_complete_login (r);

		r->state = REST_STATE_WAITING;
		r->httpreq->callback = http_complete_login;
		return 0;
	}

	if (0) {

	}
	else {
		b = buf_new ();
		sprintf (buf,
			 "You're logged in as '%s' with password '%s'<br />\n",
			 r->username, r->password);
		if (client)
			buf_append_data(b, buf, strlen (buf));
		sprintf (buf, "The requested URL '%s' was not found!\n",
			 r->httpreq->url);
		buf_append_data(b, buf, strlen (buf));
		return http_reply (r, 404, b);
	}

	return 0;
}
Example #11
0
int cmd_join(int argc, char *argv[]) {
	free(data);
	data = NULL;
	datalen = 0;

	if(argc > 2) {
		fprintf(stderr, "Too many arguments!\n");
		return 1;
	}

	// Make sure confbase exists and is accessible.
	if(!confbase_given && mkdir(confdir, 0755) && errno != EEXIST) {
		fprintf(stderr, "Could not create directory %s: %s\n", confdir, strerror(errno));
		return 1;
	}

	if(mkdir(confbase, 0777) && errno != EEXIST) {
		fprintf(stderr, "Could not create directory %s: %s\n", confbase, strerror(errno));
		return 1;
	}

	if(access(confbase, R_OK | W_OK | X_OK)) {
		fprintf(stderr, "No permission to write in directory %s: %s\n", confbase, strerror(errno));
		return 1;
	}

	// If a netname or explicit configuration directory is specified, check for an existing tinc.conf.
	if((netname || confbasegiven) && !access(tinc_conf, F_OK)) {
		fprintf(stderr, "Configuration file %s already exists!\n", tinc_conf);
		return 1;
	}

	// Either read the invitation from the command line or from stdin.
	char *invitation;

	if(argc > 1) {
		invitation = argv[1];
	} else {
		if(tty)
			fprintf(stderr, "Enter invitation URL: ");
		errno = EPIPE;
		if(!fgets(line, sizeof line, stdin)) {
			fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno));
			return false;
		}
		invitation = line;
	}

	// Parse the invitation URL.
	rstrip(line);

	char *slash = strchr(invitation, '/');
	if(!slash)
		goto invalid;

	*slash++ = 0;

	if(strlen(slash) != 48)
		goto invalid;

	char *address = invitation;
	char *port = NULL;
	if(*address == '[') {
		address++;
		char *bracket = strchr(address, ']');
		if(!bracket)
			goto invalid;
		*bracket = 0;
		if(bracket[1] == ':')
			port = bracket + 2;
	} else {
		port = strchr(address, ':');
		if(port)
			*port++ = 0;
	}

	if(!port || !*port)
		port = "655";

	if(!b64decode(slash, hash, 24) || !b64decode(slash + 24, cookie, 24))
		goto invalid;

	// Generate a throw-away key for the invitation.
	ecdsa_t *key = ecdsa_generate();
	if(!key)
		return 1;

	char *b64key = ecdsa_get_base64_public_key(key);

	// Connect to the tinc daemon mentioned in the URL.
	struct addrinfo *ai = str2addrinfo(address, port, SOCK_STREAM);
	if(!ai)
		return 1;

	struct addrinfo *aip = NULL;

next:
	if(!aip)
		aip = ai;
	else {
		aip = aip->ai_next;
		if(!aip)
			return 1;
	}

	sock = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
	if(sock <= 0) {
		fprintf(stderr, "Could not open socket: %s\n", strerror(errno));
		goto next;
	}

	if(connect(sock, aip->ai_addr, aip->ai_addrlen)) {
		char *addrstr, *portstr;
		sockaddr2str((sockaddr_t *)aip->ai_addr, &addrstr, &portstr);
		fprintf(stderr, "Could not connect to %s port %s: %s\n", addrstr, portstr, strerror(errno));
		free(addrstr);
		free(portstr);
		closesocket(sock);
		goto next;
	}

	fprintf(stderr, "Connected to %s port %s...\n", address, port);

	// Tell him we have an invitation, and give him our throw-away key.
	int len = snprintf(line, sizeof line, "0 ?%s %d.%d\n", b64key, PROT_MAJOR, PROT_MINOR);
	if(len <= 0 || len >= sizeof line)
		abort();

	if(!sendline(sock, "0 ?%s %d.%d", b64key, PROT_MAJOR, 1)) {
		fprintf(stderr, "Error sending request to %s port %s: %s\n", address, port, strerror(errno));
		closesocket(sock);
		goto next;
	}

	char hisname[4096] = "";
	int code, hismajor, hisminor = 0;

	if(!recvline(sock, line, sizeof line) || sscanf(line, "%d %s %d.%d", &code, hisname, &hismajor, &hisminor) < 3 || code != 0 || hismajor != PROT_MAJOR || !check_id(hisname) || !recvline(sock, line, sizeof line) || !rstrip(line) || sscanf(line, "%d ", &code) != 1 || code != ACK || strlen(line) < 3) {
		fprintf(stderr, "Cannot read greeting from peer\n");
		closesocket(sock);
		goto next;
	}

	// Check if the hash of the key he gave us matches the hash in the URL.
	char *fingerprint = line + 2;
	char hishash[64];
	if(sha512(fingerprint, strlen(fingerprint), hishash)) {
		fprintf(stderr, "Could not create digest\n%s\n", line + 2);
		return 1;
	}
	if(memcmp(hishash, hash, 18)) {
		fprintf(stderr, "Peer has an invalid key!\n%s\n", line + 2);
		return 1;

	}
	
	ecdsa_t *hiskey = ecdsa_set_base64_public_key(fingerprint);
	if(!hiskey)
		return 1;

	// Start an SPTPS session
	if(!sptps_start(&sptps, NULL, true, false, key, hiskey, "tinc invitation", 15, invitation_send, invitation_receive))
		return 1;

	// Feed rest of input buffer to SPTPS
	if(!sptps_receive_data(&sptps, buffer, blen))
		return 1;

	while((len = recv(sock, line, sizeof line, 0))) {
		if(len < 0) {
			if(errno == EINTR)
				continue;
			fprintf(stderr, "Error reading data from %s port %s: %s\n", address, port, strerror(errno));
			return 1;
		}

		char *p = line;
		while(len) {
			int done = sptps_receive_data(&sptps, p, len);
			if(!done)
				return 1;
			len -= done;
			p += done;
		}
	}
	
	sptps_stop(&sptps);
	ecdsa_free(hiskey);
	ecdsa_free(key);
	closesocket(sock);

	if(!success) {
		fprintf(stderr, "Connection closed by peer, invitation cancelled.\n");
		return 1;
	}

	return 0;

invalid:
	fprintf(stderr, "Invalid invitation URL.\n");
	return 1;
}