Exemplo n.º 1
0
/** Send a raw string to the XMPP server.
 *  This function is a convenience function to send raw string data to the
 *  XMPP server.  It is used by Strophe to send short messages instead of
 *  building up an XML stanza with DOM methods.  This should be used with care
 *  as it does not validate the data; invalid data may result in immediate
 *  stream termination by the XMPP server.
 *
 *  @param conn a Strophe connection object
 *  @param fmt a printf-style format string followed by a variable list of
 *      arguments to format
 */
void xmpp_send_raw_string(xmpp_conn_t * const conn,
			  const char * const fmt, ...)
{
	va_list ap;
	size_t len;
	char buf[1024]; /* small buffer for common case */
	char *bigbuf;

	va_start(ap, fmt);
	len = xmpp_vsnprintf(buf, 1024, fmt, ap);
	va_end(ap);

	if (len >= 1024) {
		/* we need more space for this data, so we allocate a big
		 * enough buffer and print to that */
		len++; /* account for trailing \0 */
		bigbuf = xmpp_alloc(conn->ctx, len);
		if (!bigbuf) {
			xmpp_debug(conn->ctx, "xmpp",
				   "Could not allocate memory for send_raw_string");
			return;
		}
		va_start(ap, fmt);
		xmpp_vsnprintf(bigbuf, len, fmt, ap);
		va_end(ap);

		xmpp_debug(conn->ctx, "conn", "SENT: %s", bigbuf);
		/* len - 1 so we don't send trailing \0 */
		xmpp_send_raw(conn, bigbuf, len - 1);

		xmpp_free(conn->ctx, bigbuf);
	} else {
		xmpp_debug(conn->ctx, "conn", "SENT: %s", buf);
		xmpp_send_raw(conn, buf, len);
	}
}
Exemplo n.º 2
0
/** Create a new Strophe connection object.
 *
 *  @param ctx a Strophe context object
 *
 *  @return a Strophe connection object or NULL on an error
 *
 *  @ingroup Connections
 */
xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
{
    xmpp_conn_t *conn = NULL;
    xmpp_connlist_t *tail, *item;

    if (ctx == NULL) return NULL;
	conn = xmpp_alloc(ctx, sizeof(xmpp_conn_t));
    
    if (conn != NULL) {
	conn->ctx = ctx;

	conn->type = XMPP_UNKNOWN;
        conn->state = XMPP_STATE_DISCONNECTED;
	conn->sock = -1;
	conn->tls = NULL;
	conn->timeout_stamp = 0;
	conn->error = 0;
	conn->stream_error = NULL;

	/* default send parameters */
	conn->blocking_send = 0;
	conn->send_queue_max = DEFAULT_SEND_QUEUE_MAX;
	conn->send_queue_len = 0;
	conn->send_queue_head = NULL;
	conn->send_queue_tail = NULL;

	/* default timeouts */
	conn->connect_timeout = CONNECT_TIMEOUT;

	conn->lang = xmpp_strdup(conn->ctx, "en");
	if (!conn->lang) {
	    xmpp_free(conn->ctx, conn);
	    return NULL;
	}
	conn->domain = NULL;
	conn->jid = NULL;
	conn->pass = NULL;
	conn->stream_id = NULL;
        conn->bound_jid = NULL;

	conn->tls_support = 0;
	conn->tls_disabled = 0;
	conn->tls_failed = 0;
	conn->sasl_support = 0;
        conn->secured = 0;

	conn->bind_required = 0;
	conn->session_required = 0;

	conn->parser = parser_new(conn->ctx, 
                                  _handle_stream_start,
                                  _handle_stream_end,
                                  _handle_stream_stanza,
                                  conn);
        conn->reset_parser = 0;
        conn_prepare_reset(conn, auth_handle_open);

	conn->authenticated = 0;
	conn->conn_handler = NULL;
	conn->userdata = NULL;
	conn->timed_handlers = NULL;
	/* we own (and will free) the hash values */
	conn->id_handlers = hash_new(conn->ctx, 32, NULL);
	conn->handlers = NULL;

	/* give the caller a reference to connection */
	conn->ref = 1;

	/* add connection to ctx->connlist */
	tail = conn->ctx->connlist;
	while (tail && tail->next) tail = tail->next;

	item = xmpp_alloc(conn->ctx, sizeof(xmpp_connlist_t));
	if (!item) {
	    xmpp_error(conn->ctx, "xmpp", "failed to allocate memory");
	    xmpp_free(conn->ctx, conn->lang);
            parser_free(conn->parser);
	    xmpp_free(conn->ctx, conn);
	    conn = NULL;
	} else {
	    item->conn = conn;
	    item->next = NULL;

	    if (tail) tail->next = item;
	    else conn->ctx->connlist = item;
	}
    }
    
    return conn;
}
Exemplo n.º 3
0
tls_t *tls_new(xmpp_ctx_t *ctx, sock_t sock)
{
    tls_t *tls;
    PSecurityFunctionTable (*pInitSecurityInterface)(void);
    SCHANNEL_CRED scred;
    int ret;
    ALG_ID algs[1];

    SecPkgCred_SupportedAlgs spc_sa;
    SecPkgCred_CipherStrengths spc_cs;
    SecPkgCred_SupportedProtocols spc_sp;

    OSVERSIONINFO osvi;

    memset(&osvi, 0, sizeof(osvi));
    osvi.dwOSVersionInfoSize = sizeof(osvi);

    GetVersionEx(&osvi);

    /* no TLS support on win9x/me, despite what anyone says */
    if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
	return NULL;
    }

    tls = xmpp_alloc(ctx, sizeof(*tls));

    if (!tls) {
	return NULL;
    }

    memset(tls, 0, sizeof(*tls));
    tls->ctx = ctx;
    tls->sock = sock;

    if (!(tls->hsec32 = LoadLibrary ("secur32.dll"))) {
	tls_free(tls);
	return NULL;
    }

    if (!(pInitSecurityInterface =
	  (void *)GetProcAddress(tls->hsec32, "InitSecurityInterfaceA"))) {
	tls_free(tls);
	return NULL;
    }

    tls->sft = pInitSecurityInterface();

    if (!tls->sft) {
	tls_free(tls);
	return NULL;
    }

    ret = tls->sft->QuerySecurityPackageInfo(UNISP_NAME, &(tls->spi));

    if (ret != SEC_E_OK)
    {
	tls_free(tls);
	return NULL;
    }

    xmpp_debug(ctx, "TLSS", "QuerySecurityPackageInfo() success");

    memset(&scred, 0, sizeof(scred));
    scred.dwVersion = SCHANNEL_CRED_VERSION;
    /*scred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT;*/
    /* Remote server closes connection with forced RC4.
       The below lines are commented to leave default system configuration */
#if 0
    /* Something down the line doesn't like AES, so force it to RC4 */
    algs[0] = CALG_RC4;
    scred.cSupportedAlgs = 1;
    scred.palgSupportedAlgs = algs;
#else
    (void)algs;
#endif

    ret = tls->sft->AcquireCredentialsHandleA(NULL, UNISP_NAME,
	SECPKG_CRED_OUTBOUND, NULL, &scred, NULL, NULL, &(tls->hcred), NULL);

    if (ret != SEC_E_OK)
    {
	tls_free(tls);
	return NULL;
    }

    xmpp_debug(ctx, "TLSS", "AcquireCredentialsHandle() success");

    tls->init = 1;

    /* This bunch of queries should trip up wine until someone fixes
     * schannel support there */
    ret = tls->sft->QueryCredentialsAttributes(&(tls->hcred), SECPKG_ATTR_SUPPORTED_ALGS, &spc_sa);
    if (ret != SEC_E_OK)
    {
	tls_free(tls);
	return NULL;
    }

    ret = tls->sft->QueryCredentialsAttributes(&(tls->hcred), SECPKG_ATTR_CIPHER_STRENGTHS, &spc_cs);
    if (ret != SEC_E_OK)
    {
	tls_free(tls);
	return NULL;
    }

    ret = tls->sft->QueryCredentialsAttributes(&(tls->hcred), SECPKG_ATTR_SUPPORTED_PROTOCOLS, &spc_sp);
    if (ret != SEC_E_OK)
    {
	tls_free(tls);
	return NULL;
    }

    return tls;
}
Exemplo n.º 4
0
int tls_start(tls_t *tls)
{
    ULONG ctxtreq = 0, ctxtattr = 0;
    SecBufferDesc sbdin, sbdout;
    SecBuffer sbin[2], sbout[1];
    SECURITY_STATUS ret;
    int sent;
    char *name = NULL;

    /* search the ctx's conns for our sock, and use the domain there as our
     * name */
    {
	xmpp_connlist_t *listentry = tls->ctx->connlist;

	while (listentry) {
	    xmpp_conn_t *conn = listentry->conn;

	    if (conn->sock == tls->sock) {
		name = strdup(conn->domain);
		listentry = NULL;
	    } else {
		listentry = listentry->next;
	    }
	}
    }

    ctxtreq = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT
	    | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR
	    | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM
	    | ISC_REQ_MANUAL_CRED_VALIDATION | ISC_REQ_INTEGRITY;

    memset(&(sbout[0]), 0, sizeof(sbout[0]));
    sbout[0].BufferType = SECBUFFER_TOKEN;

    memset(&sbdout, 0, sizeof(sbdout));
    sbdout.ulVersion = SECBUFFER_VERSION;
    sbdout.cBuffers = 1;
    sbdout.pBuffers = sbout;

    memset(&(sbin[0]), 0, sizeof(sbin[0]));
    sbin[0].BufferType = SECBUFFER_TOKEN;
    sbin[0].pvBuffer = xmpp_alloc(tls->ctx, tls->spi->cbMaxToken);
    sbin[0].cbBuffer = tls->spi->cbMaxToken;

    memset(&(sbin[1]), 0, sizeof(sbin[1]));
    sbin[1].BufferType = SECBUFFER_EMPTY;

    memset(&sbdin, 0, sizeof(sbdin));
    sbdin.ulVersion = SECBUFFER_VERSION;
    sbdin.cBuffers = 2;
    sbdin.pBuffers = sbin;

    ret = tls->sft->InitializeSecurityContextA(&(tls->hcred), NULL, name, ctxtreq, 0, 0,
					  NULL, 0, &(tls->hctxt), &sbdout,
					  &ctxtattr, NULL);

    while (ret == SEC_I_CONTINUE_NEEDED
	   || ret == SEC_I_INCOMPLETE_CREDENTIALS) {
	unsigned char *p = sbin[0].pvBuffer;
	int len = 0, inbytes = 0;

	if (sbdout.pBuffers[0].cbBuffer) {
	    unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer;
	    unsigned int writelen = sbdout.pBuffers[0].cbBuffer;

	    sent = sock_write(tls->sock, writebuff, writelen);
	    if (sent == -1) {
		tls->lasterror = sock_error();
	    }
	    else
	    {
		writebuff += sent;
		writelen -= sent;
	    }
	    tls->sft->FreeContextBuffer(sbdout.pBuffers[0].pvBuffer);
	    sbdout.pBuffers[0].pvBuffer = NULL;
	    sbdout.pBuffers[0].cbBuffer = 0;
	}

	/* poll for a bit until the remote server stops sending data, ie it
	 * finishes sending the token */
	inbytes = 1;
	{
	    fd_set fds;
	    struct timeval tv;

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

	    FD_ZERO(&fds);
	    FD_SET(tls->sock, &fds);
    
	    select(tls->sock, &fds, NULL, NULL, &tv);
	}

	while (inbytes > 0) {
	    fd_set fds;
	    struct timeval tv;

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

	    FD_ZERO(&fds);
	    FD_SET(tls->sock, &fds);
    
	    select(tls->sock, &fds, NULL, NULL, &tv);

	    inbytes = sock_read(tls->sock, p, tls->spi->cbMaxToken - len);

	    if (inbytes > 0) {
		len += inbytes;
		p += inbytes;
	    }
	    else
	    {
	        tls->lasterror = sock_error();
	    }

	}

	sbin[0].cbBuffer = len;

	ret = tls->sft->InitializeSecurityContextA(&(tls->hcred), &(tls->hctxt), name,
					      ctxtreq, 0, 0, &sbdin, 0,
					      &(tls->hctxt), &sbdout,
					      &ctxtattr, NULL);
    }

    if (ret == SEC_E_OK) {
	if (sbdout.pBuffers[0].cbBuffer) {
	    unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer;
	    unsigned int writelen = sbdout.pBuffers[0].cbBuffer;
	    sent = sock_write(tls->sock, writebuff, writelen);
	    if (sent == -1) {
		tls->lasterror = sock_error();
	    }
	    else
	    {
		writebuff += sent;
		writelen -= sent;
	    }
	    tls->sft->FreeContextBuffer(sbdout.pBuffers[0].pvBuffer);
	    sbdout.pBuffers[0].pvBuffer = NULL;
	    sbdout.pBuffers[0].cbBuffer = 0;
	}
    }

    xmpp_free(tls->ctx, sbin[0].pvBuffer);

    if (ret != SEC_E_OK) {
	tls->lasterror = ret;
	xmpp_error(tls->ctx, "TLSS", "Schannel error 0x%lx", (unsigned long)ret);
	return 0;
    }

    tls->sft->QueryContextAttributes(&(tls->hctxt), SECPKG_ATTR_STREAM_SIZES,
				&(tls->spcss));

    tls->recvbuffermaxlen = tls->spcss.cbHeader + tls->spcss.cbMaximumMessage
			    + tls->spcss.cbTrailer;
    tls->recvbuffer       = xmpp_alloc(tls->ctx, tls->recvbuffermaxlen);
    tls->recvbufferpos    = 0;

    tls->sendbuffermaxlen = tls->spcss.cbHeader + tls->spcss.cbMaximumMessage
			    + tls->spcss.cbTrailer;
    tls->sendbuffer       = xmpp_alloc(tls->ctx, tls->sendbuffermaxlen);
    tls->sendbufferpos    = 0;
    tls->sendbufferlen    = 0;

    tls->readybuffer      = xmpp_alloc(tls->ctx, tls->spcss.cbMaximumMessage);
    tls->readybufferpos   = 0;
    tls->readybufferlen   = 0;

    return 1;
}
Exemplo n.º 5
0
/* stream:error handler */
static int _handle_error(xmpp_conn_t * const conn,
			 xmpp_stanza_t * const stanza,
			 void * const userdata)
{
    xmpp_stanza_t *child;
    char *name;

    /* free old stream error if it's still there */
    if (conn->stream_error) {
	xmpp_stanza_release(conn->stream_error->stanza);
	if (conn->stream_error->text)
	    xmpp_free(conn->ctx, conn->stream_error->text);
	xmpp_free(conn->ctx, conn->stream_error);
    }

    /* create stream error structure */
    conn->stream_error = (xmpp_stream_error_t *)xmpp_alloc(conn->ctx, sizeof(xmpp_stream_error_t));

	conn->stream_error->text = NULL;
	conn->stream_error->type = XMPP_SE_UNDEFINED_CONDITION;

    if (conn->stream_error) {
	child = xmpp_stanza_get_children(stanza);
	do {
	    char *ns = NULL;

	    if (child) {
		ns = xmpp_stanza_get_ns(child);
	    }

	    if (ns && strcmp(ns, XMPP_NS_STREAMS_IETF) == 0) {
		name = xmpp_stanza_get_name(child);
		if (strcmp(name, "text") == 0) {
		    if (conn->stream_error->text)
			xmpp_free(conn->ctx, conn->stream_error->text);
		    conn->stream_error->text = xmpp_stanza_get_text(child);
		} else if (strcmp(name, "bad-format") == 0)
		    conn->stream_error->type = XMPP_SE_BAD_FORMAT;
		else if (strcmp(name, "bad-namespace-prefix") == 0)
		    conn->stream_error->type = XMPP_SE_BAD_NS_PREFIX;
		else if (strcmp(name, "conflict") == 0)
		    conn->stream_error->type = XMPP_SE_CONFLICT;
		else if (strcmp(name, "connection-timeout") == 0)
		    conn->stream_error->type = XMPP_SE_CONN_TIMEOUT;
		else if (strcmp(name, "host-gone") == 0)
		    conn->stream_error->type = XMPP_SE_HOST_GONE;
		else if (strcmp(name, "host-unknown") == 0)
		    conn->stream_error->type = XMPP_SE_HOST_UNKNOWN;
		else if (strcmp(name, "improper-addressing") == 0)
		    conn->stream_error->type = XMPP_SE_IMPROPER_ADDR;
		else if (strcmp(name, "internal-server-error") == 0)
		    conn->stream_error->type = XMPP_SE_INTERNAL_SERVER_ERROR;
		else if (strcmp(name, "invalid-from") == 0)
		    conn->stream_error->type = XMPP_SE_INVALID_FROM;
		else if (strcmp(name, "invalid-id") == 0)
		    conn->stream_error->type = XMPP_SE_INVALID_ID;
		else if (strcmp(name, "invalid-namespace") == 0)
		    conn->stream_error->type = XMPP_SE_INVALID_NS;
		else if (strcmp(name, "invalid-xml") == 0)
		    conn->stream_error->type = XMPP_SE_INVALID_XML;
		else if (strcmp(name, "not-authorized") == 0)
		    conn->stream_error->type = XMPP_SE_NOT_AUTHORIZED;
		else if (strcmp(name, "policy-violation") == 0)
		    conn->stream_error->type = XMPP_SE_POLICY_VIOLATION;
		else if (strcmp(name, "remote-connection-failed") == 0)
		    conn->stream_error->type = XMPP_SE_REMOTE_CONN_FAILED;
		else if (strcmp(name, "resource-constraint") == 0)
		    conn->stream_error->type = XMPP_SE_RESOURCE_CONSTRAINT;
		else if (strcmp(name, "restricted-xml") == 0)
		    conn->stream_error->type = XMPP_SE_RESTRICTED_XML;
		else if (strcmp(name, "see-other-host") == 0)
		    conn->stream_error->type = XMPP_SE_SEE_OTHER_HOST;
		else if (strcmp(name, "system-shutdown") == 0)
		    conn->stream_error->type = XMPP_SE_SYSTEM_SHUTDOWN;
		else if (strcmp(name, "undefined-condition") == 0)
		    conn->stream_error->type = XMPP_SE_UNDEFINED_CONDITION;
		else if (strcmp(name, "unsupported-encoding") == 0)
		    conn->stream_error->type = XMPP_SE_UNSUPPORTED_ENCODING;
		else if (strcmp(name, "unsupported-stanza-type") == 0)
		    conn->stream_error->type = XMPP_SE_UNSUPPORTED_STANZA_TYPE;
		else if (strcmp(name, "unsupported-version") == 0)
		    conn->stream_error->type = XMPP_SE_UNSUPPORTED_VERSION;
		else if (strcmp(name, "xml-not-well-formed") == 0)
		    conn->stream_error->type = XMPP_SE_XML_NOT_WELL_FORMED;
	    }
	} while ((child = xmpp_stanza_get_next(child)));

	conn->stream_error->stanza = xmpp_stanza_clone(stanza);
    }

    return 1;
}
Exemplo n.º 6
0
/** generate auth response string for the SASL SCRAM-SHA-1 mechanism */
char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
                      const char *first_bare, const char *jid,
                      const char *password)
{
    uint8_t key[SHA1_DIGEST_SIZE];
    uint8_t sign[SHA1_DIGEST_SIZE];
    char *r = NULL;
    char *s = NULL;
    char *i = NULL;
    unsigned char *sval;
    size_t sval_len;
    long ival;
    char *tmp;
    char *ptr;
    char *saveptr = NULL;
    char *response;
    char *auth;
    char *response_b64;
    char *sign_b64;
    char *result = NULL;
    size_t response_len;
    size_t auth_len;
    int j;

    tmp = xmpp_strdup(ctx, challenge);
    if (!tmp) {
        return NULL;
    }

    ptr = strtok_r(tmp, ",", &saveptr);
    while (ptr) {
        if (strncmp(ptr, "r=", 2) == 0) {
            r = ptr;
        } else if (strncmp(ptr, "s=", 2) == 0) {
            s = ptr + 2;
        } else if (strncmp(ptr, "i=", 2) == 0) {
            i = ptr + 2;
        }
        ptr = strtok_r(NULL, ",", &saveptr);
    }

    if (!r || !s || !i) {
        goto out;
    }

    xmpp_base64_decode_bin(ctx, s, strlen(s), &sval, &sval_len);
    if (!sval) {
        goto out;
    }
    ival = strtol(i, &saveptr, 10);

    auth_len = 10 + strlen(r) + strlen(first_bare) + strlen(challenge);
    auth = xmpp_alloc(ctx, auth_len);
    if (!auth) {
        goto out_sval;
    }

    response_len = 39 + strlen(r);
    response = xmpp_alloc(ctx, response_len);
    if (!response) {
        goto out_auth;
    }

    xmpp_snprintf(response, response_len, "c=biws,%s", r);
    xmpp_snprintf(auth, auth_len, "%s,%s,%s", first_bare + 3, challenge,
                  response);

    SCRAM_SHA1_ClientKey((uint8_t *)password, strlen(password),
                         (uint8_t *)sval, sval_len, (uint32_t)ival, key);
    SCRAM_SHA1_ClientSignature(key, (uint8_t *)auth, strlen(auth), sign);
    for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
        sign[j] ^= key[j];
    }

    sign_b64 = xmpp_base64_encode(ctx, sign, sizeof(sign));
    if (!sign_b64) {
        goto out_response;
    }

    if (strlen(response) + strlen(sign_b64) + 3 + 1 > response_len) {
        xmpp_free(ctx, sign_b64);
        goto out_response;
    }
    strcat(response, ",p=");
    strcat(response, sign_b64);
    xmpp_free(ctx, sign_b64);

    response_b64 = xmpp_base64_encode(ctx, (unsigned char *)response,
                                      strlen(response));
    if (!response_b64) {
        goto out_response;
    }
    result = response_b64;

out_response:
    xmpp_free(ctx, response);
out_auth:
    xmpp_free(ctx, auth);
out_sval:
    xmpp_free(ctx, sval);
out:
    xmpp_free(ctx, tmp);
    return result;
}
Exemplo n.º 7
0
/** generate auth response string for the SASL DIGEST-MD5 mechanism */
char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
			const char *jid, const char *password) {
    hash_t *table;
    char *result = NULL;
    char *node, *domain, *realm;
    char *value;
    char *response;
    int rlen;
    struct MD5Context MD5;
    unsigned char digest[16], HA1[16], HA2[16];
    char hex[32];
    char cnonce[13];

    /* our digest response is
	Hex( KD( HEX(MD5(A1)),
	  nonce ':' nc ':' cnonce ':' qop ':' HEX(MD5(A2))
	))

       where KD(k, s) = MD5(k ':' s),
	A1 = MD5( node ':' realm ':' password ) ':' nonce ':' cnonce
	A2 = "AUTHENTICATE" ':' "xmpp/" domain

       If there is an authzid it is ':'-appended to A1 */

    /* parse the challenge */
    table = _parse_digest_challenge(ctx, challenge);
    if (table == NULL) {
	xmpp_error(ctx, "SASL", "couldn't parse digest challenge");
	return NULL;
    }

    node = xmpp_jid_node(ctx, jid);
    domain = xmpp_jid_domain(ctx, jid);

    /* generate default realm of domain if one didn't come from the
       server */
    realm = hash_get(table, "realm");
    if (realm == NULL || strlen(realm) == 0) {
	hash_add(table, "realm", xmpp_strdup(ctx, domain));
	realm = hash_get(table, "realm");
    }

    /* add our response fields */
    hash_add(table, "username", xmpp_strdup(ctx, node));
    xmpp_rand_nonce(ctx->rand, cnonce, sizeof(cnonce));
    hash_add(table, "cnonce", xmpp_strdup(ctx, cnonce));
    hash_add(table, "nc", xmpp_strdup(ctx, "00000001"));
    hash_add(table, "qop", xmpp_strdup(ctx, "auth"));
    value = xmpp_alloc(ctx, 5 + strlen(domain) + 1);
    memcpy(value, "xmpp/", 5);
    memcpy(value+5, domain, strlen(domain));
    value[5+strlen(domain)] = '\0';
    hash_add(table, "digest-uri", value);

    /* generate response */

    /* construct MD5(node : realm : password) */
    MD5Init(&MD5);
    MD5Update(&MD5, (unsigned char *)node, strlen(node));
    MD5Update(&MD5, (unsigned char *)":", 1);
    MD5Update(&MD5, (unsigned char *)realm, strlen(realm));
    MD5Update(&MD5, (unsigned char *)":", 1);
    MD5Update(&MD5, (unsigned char *)password, strlen(password));
    MD5Final(digest, &MD5);

    /* digest now contains the first field of A1 */

    MD5Init(&MD5);
    MD5Update(&MD5, digest, 16);
    MD5Update(&MD5, (unsigned char *)":", 1);
    value = hash_get(table, "nonce");
    MD5Update(&MD5, (unsigned char *)value, strlen(value));
    MD5Update(&MD5, (unsigned char *)":", 1);
    value = hash_get(table, "cnonce");
    MD5Update(&MD5, (unsigned char *)value, strlen(value));
    MD5Final(digest, &MD5);

    /* now digest is MD5(A1) */
    memcpy(HA1, digest, 16);

    /* construct MD5(A2) */
    MD5Init(&MD5);
    MD5Update(&MD5, (unsigned char *)"AUTHENTICATE:", 13);
    value = hash_get(table, "digest-uri");
    MD5Update(&MD5, (unsigned char *)value, strlen(value));
    if (strcmp(hash_get(table, "qop"), "auth") != 0) {
	MD5Update(&MD5, (unsigned char *)":00000000000000000000000000000000",
		  33);
    }
    MD5Final(digest, &MD5);

    memcpy(HA2, digest, 16);

    /* construct response */
    MD5Init(&MD5);
    _digest_to_hex((char *)HA1, hex);
    MD5Update(&MD5, (unsigned char *)hex, 32);
    MD5Update(&MD5, (unsigned char *)":", 1);
    value = hash_get(table, "nonce");
    MD5Update(&MD5, (unsigned char *)value, strlen(value));
    MD5Update(&MD5, (unsigned char *)":", 1);
    value = hash_get(table, "nc");
    MD5Update(&MD5, (unsigned char *)value, strlen(value));
    MD5Update(&MD5, (unsigned char *)":", 1);
    value = hash_get(table, "cnonce");
    MD5Update(&MD5, (unsigned char *)value, strlen(value));
    MD5Update(&MD5, (unsigned char *)":", 1);
    value = hash_get(table, "qop");
    MD5Update(&MD5, (unsigned char *)value, strlen(value));
    MD5Update(&MD5, (unsigned char *)":", 1);
    _digest_to_hex((char *)HA2, hex);
    MD5Update(&MD5, (unsigned char *)hex, 32);
    MD5Final(digest, &MD5);

    response = xmpp_alloc(ctx, 32+1);
    _digest_to_hex((char *)digest, hex);
    memcpy(response, hex, 32);
    response[32] = '\0';
    hash_add(table, "response", response);

    /* construct reply */
    result = NULL;
    rlen = 0;
    result = _add_key(ctx, table, "username", result, &rlen, 1);
    result = _add_key(ctx, table, "realm", result, &rlen, 1);
    result = _add_key(ctx, table, "nonce", result, &rlen, 1);
    result = _add_key(ctx, table, "cnonce", result, &rlen, 1);
    result = _add_key(ctx, table, "nc", result, &rlen, 0);
    result = _add_key(ctx, table, "qop", result, &rlen, 0);
    result = _add_key(ctx, table, "digest-uri", result, &rlen, 1);
    result = _add_key(ctx, table, "response", result, &rlen, 0);
    result = _add_key(ctx, table, "charset", result, &rlen, 0);

    xmpp_free(ctx, node);
    xmpp_free(ctx, domain);
    hash_release(table); /* also frees value strings */

    /* reuse response for the base64 encode of our result */
    response = xmpp_base64_encode(ctx, (unsigned char *)result, strlen(result));
    xmpp_free(ctx, result);

    return response;
}
Exemplo n.º 8
0
/* add a stanza handler */
static void _handler_add(xmpp_conn_t * const conn,
			 xmpp_handler handler,
			 const char * const ns,
			 const char * const name,
			 const char * const type,
			 void * const userdata, int user_handler)
{
    xmpp_handlist_t *item, *tail;

    /* check if handler already in list */
    for (item = conn->handlers; item; item = item->next) {
	if (item->handler == (void *)handler)
	    break;
    }
    if (item) return;

    /* build new item */
    item = (xmpp_handlist_t *)xmpp_alloc(conn->ctx, sizeof(xmpp_handlist_t));
    if (!item) return;

    item->user_handler = user_handler;
    item->handler = (void *)handler;
    item->userdata = userdata;
    item->enabled = 0;
    item->next = NULL;
    
    if (ns) {
	item->ns = xmpp_strdup(conn->ctx, ns);
	if (!item->ns) {
	    xmpp_free(conn->ctx, item);
	    return;
	}
    } else
	item->ns = NULL;
    if (name) {
	item->name = xmpp_strdup(conn->ctx, name);
	if (!item->name) {
	    if (item->ns) xmpp_free(conn->ctx, item->ns);
	    xmpp_free(conn->ctx, item);
	    return;
	}
    } else
	item->name = NULL;
    if (type) {
	item->type = xmpp_strdup(conn->ctx, type);
	if (!item->type) {
	    if (item->ns) xmpp_free(conn->ctx, item->ns);
	    if (item->name) xmpp_free(conn->ctx, item->name);
	    xmpp_free(conn->ctx, item);
	}
    } else
	item->type = NULL;

    /* append to list */
    if (!conn->handlers)
	conn->handlers = item;
    else {
	tail = conn->handlers;
	while (tail->next) 
	    tail = tail->next;
	tail->next = item;
    }
}
Exemplo n.º 9
0
tls_t *tls_new(xmpp_conn_t *conn)
{
    tls_t *tls = xmpp_alloc(conn->ctx, sizeof(*tls));
    int mode;

    if (tls) {
        int ret;
        memset(tls, 0, sizeof(*tls));

        tls->ctx = conn->ctx;
        tls->sock = conn->sock;
        tls->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
        if (tls->ssl_ctx == NULL)
            goto err;

        /* Enable bug workarounds. */
        SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_ALL);

        /* Disable insecure SSL/TLS versions. */
        SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_SSLv2); /* DROWN */
        SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_SSLv3); /* POODLE */
        SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_TLSv1); /* BEAST */

        SSL_CTX_set_client_cert_cb(tls->ssl_ctx, NULL);
        SSL_CTX_set_mode(tls->ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
        SSL_CTX_set_default_verify_paths(tls->ssl_ctx);

        tls->ssl = SSL_new(tls->ssl_ctx);
        if (tls->ssl == NULL)
            goto err_free_ctx;

        /* Trust server's certificate when user sets the flag explicitly. */
        mode = conn->tls_trust ? SSL_VERIFY_NONE : SSL_VERIFY_PEER;
        SSL_set_verify(tls->ssl, mode, 0);
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
        /* Hostname verification is supported in OpenSSL 1.0.2 and newer. */
        X509_VERIFY_PARAM *param = SSL_get0_param(tls->ssl);

        /*
         * Allow only complete wildcards.  RFC 6125 discourages wildcard usage
         * completely, and lists internationalized domain names as a reason
         * against partial wildcards.
         * See https://tools.ietf.org/html/rfc6125#section-7.2 for more information.
         */
        X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
        X509_VERIFY_PARAM_set1_host(param, conn->domain, 0);
#endif

        ret = SSL_set_fd(tls->ssl, conn->sock);
        if (ret <= 0)
            goto err_free_ssl;
    }

    return tls;

err_free_ssl:
    SSL_free(tls->ssl);
err_free_ctx:
    SSL_CTX_free(tls->ssl_ctx);
err:
    xmpp_free(conn->ctx, tls);
    _tls_log_error(conn->ctx);
    return NULL;
}
Exemplo n.º 10
0
/** Create a new Strophe connection object.
 *
 *  @param ctx a Strophe context object
 *
 *  @return a Strophe connection object or NULL on an error
 *
 *  @ingroup Connections
 */
xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
{
	xmpp_conn_t *conn;
	list_t *item;

	if (!ctx)
		return NULL;
	conn = xmpp_alloc(ctx, sizeof(xmpp_conn_t));

	if (!conn)
		return NULL;

	conn->ctx = ctx;

	conn->type = XMPP_UNKNOWN;
	conn->state = XMPP_STATE_DISCONNECTED;
	conn->sock = -1;
	conn->tls = NULL;
	conn->timeout_stamp = 0;
	conn->error = 0;
	conn->stream_error = NULL;

	/* default send parameters */
	conn->blocking_send = 0;
	conn->send_queue_max = DEFAULT_SEND_QUEUE_MAX;
	conn->send_queue = list_init(ctx);
	if (!conn->send_queue)
		goto out_free_conn;

	/* default timeouts */
	conn->connect_timeout = CONNECT_TIMEOUT;

	conn->lang = xmpp_strdup(ctx, "en");
	if (!conn->lang)
		goto out_free_send_queue;

	conn->domain = NULL;
	conn->jid = NULL;
	conn->pass = NULL;
	conn->stream_id = NULL;
	conn->bound_jid = NULL;

	conn->tls_support = 0;
	conn->tls_disabled = 0;
	conn->tls_failed = 0;
	conn->sasl_support = 0;
	conn->secured = 0;

	conn->bind_required = 0;
	conn->session_required = 0;

	conn->parser = parser_new(ctx,
				  _handle_stream_start,
				  _handle_stream_end,
				  _handle_stream_stanza,
				  conn);
	if (!conn->parser)
		goto out_free_lang;
	conn->reset_parser = 0;
	conn_prepare_reset(conn, auth_handle_open);

	conn->authenticated = 0;
	conn->conn_handler = NULL;
	conn->userdata = NULL;
	/* we own (and will free) the hash values */
	conn->id_handlers = hash_new(ctx, 32, NULL);
	conn->timed_handlers = list_init(ctx);
	if (!conn->timed_handlers)
		goto out_free_parser;
	conn->handlers = list_init(ctx);
	if (!conn->handlers)
		goto out_free_timed_handlers;

	/* give the caller a reference to connection */
	conn->ref = 1;

	/* add connection to ctx->connlist */
	item = list_init_item(ctx);
	if (!item)
		goto out_free_handlers;
	else {
		item->data = (void *)conn;
		list_push(ctx->connlist, item);
	}

	return conn;

out_free_handlers:
	list_destroy(conn->handlers);
out_free_timed_handlers:
	list_destroy(conn->timed_handlers);
out_free_parser:
	parser_free(conn->parser);
out_free_lang:
	xmpp_free(ctx, conn->lang);
out_free_send_queue:
	list_destroy(conn->send_queue);
out_free_conn:
	xmpp_free(ctx, conn);
	return NULL;
}