📄 stream.c
字号:
/* iksemel (XML parser for Jabber)** Copyright (C) 2000-2007 Gurer Ozen <madcat@e-kolay.net>** This code is free software; you can redistribute it and/or** modify it under the terms of GNU Lesser General Public License.*/#include "common.h"#include "iksemel.h"#ifdef HAVE_GNUTLS#include <gnutls/gnutls.h>#endif#define SF_FOREIGN 1#define SF_TRY_SECURE 2#define SF_SECURE 4struct stream_data { iksparser *prs; ikstack *s; ikstransport *trans; char *name_space; void *user_data; const char *server; iksStreamHook *streamHook; iksLogHook *logHook; iks *current; char *buf; void *sock; unsigned int flags; char *auth_username; char *auth_pass;#ifdef HAVE_GNUTLS gnutls_session sess; gnutls_certificate_credentials cred;#endif};#ifdef HAVE_GNUTLSstatic size_ttls_push (iksparser *prs, const char *buffer, size_t len){ struct stream_data *data = iks_user_data (prs); int ret; ret = data->trans->send (data->sock, buffer, len); if (ret) return (size_t) -1; return len;}static size_ttls_pull (iksparser *prs, char *buffer, size_t len){ struct stream_data *data = iks_user_data (prs); int ret; ret = data->trans->recv (data->sock, buffer, len, -1); if (ret == -1) return (size_t) -1; return ret;}static inthandshake (struct stream_data *data){ const int protocol_priority[] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 }; const int kx_priority[] = { GNUTLS_KX_RSA, 0 }; const int cipher_priority[] = { GNUTLS_CIPHER_3DES_CBC, GNUTLS_CIPHER_ARCFOUR, 0}; const int comp_priority[] = { GNUTLS_COMP_ZLIB, GNUTLS_COMP_NULL, 0 }; const int mac_priority[] = { GNUTLS_MAC_SHA, GNUTLS_MAC_MD5, 0 }; int ret; if (gnutls_global_init () != 0) return IKS_NOMEM; if (gnutls_certificate_allocate_credentials (&data->cred) < 0) return IKS_NOMEM; if (gnutls_init (&data->sess, GNUTLS_CLIENT) != 0) { gnutls_certificate_free_credentials (data->cred); return IKS_NOMEM; } gnutls_protocol_set_priority (data->sess, protocol_priority); gnutls_cipher_set_priority(data->sess, cipher_priority); gnutls_compression_set_priority(data->sess, comp_priority); gnutls_kx_set_priority(data->sess, kx_priority); gnutls_mac_set_priority(data->sess, mac_priority); gnutls_credentials_set (data->sess, GNUTLS_CRD_CERTIFICATE, data->cred); gnutls_transport_set_push_function (data->sess, (gnutls_push_func) tls_push); gnutls_transport_set_pull_function (data->sess, (gnutls_pull_func) tls_pull); gnutls_transport_set_ptr (data->sess, data->prs); ret = gnutls_handshake (data->sess); if (ret != 0) { gnutls_deinit (data->sess); gnutls_certificate_free_credentials (data->cred); return IKS_NET_TLSFAIL; } data->flags &= (~SF_TRY_SECURE); data->flags |= SF_SECURE; iks_send_header (data->prs, data->server); return IKS_OK;}#endifstatic voidinsert_attribs (iks *x, char **atts){ if (atts) { int i = 0; while (atts[i]) { iks_insert_attrib (x, atts[i], atts[i+1]); i += 2; } }}#define CNONCE_LEN 4static voidparse_digest (char *message, const char *key, char **value_ptr, char **value_end_ptr){ char *t; *value_ptr = NULL; *value_end_ptr = NULL; t = strstr(message, key); if (t) { t += strlen(key); *value_ptr = t; while (t[0] != '\0') { if (t[0] != '\\' && t[1] == '"') { ++t; *value_end_ptr = t; return; } ++t; } }}static iks *make_sasl_response (struct stream_data *data, char *message){ iks *x = NULL; char *realm, *realm_end; char *nonce, *nonce_end; char cnonce[CNONCE_LEN*8 + 1]; iksmd5 *md5; unsigned char a1_h[16], a1[33], a2[33], response_value[33]; char *response, *response_coded; int i; parse_digest(message, "realm=\"", &realm, &realm_end); parse_digest(message, "nonce=\"", &nonce, &nonce_end); /* nonce is necessary for auth */ if (!nonce || !nonce_end) return NULL; *nonce_end = '\0'; /* if no realm is given use the server hostname */ if (realm) { if (!realm_end) return NULL; *realm_end = '\0'; } else { realm = (char *) data->server; } /* generate random client challenge */ for (i = 0; i < CNONCE_LEN; ++i) sprintf (cnonce + i*8, "%08x", rand()); md5 = iks_md5_new(); if (!md5) return NULL; iks_md5_hash (md5, (const unsigned char*)data->auth_username, iks_strlen (data->auth_username), 0); iks_md5_hash (md5, (const unsigned char*)":", 1, 0); iks_md5_hash (md5, (const unsigned char*)realm, iks_strlen (realm), 0); iks_md5_hash (md5, (const unsigned char*)":", 1, 0); iks_md5_hash (md5, (const unsigned char*)data->auth_pass, iks_strlen (data->auth_pass), 1); iks_md5_digest (md5, a1_h); iks_md5_reset (md5); iks_md5_hash (md5, (const unsigned char*)a1_h, 16, 0); iks_md5_hash (md5, (const unsigned char*)":", 1, 0); iks_md5_hash (md5, (const unsigned char*)nonce, iks_strlen (nonce), 0); iks_md5_hash (md5, (const unsigned char*)":", 1, 0); iks_md5_hash (md5, (const unsigned char*)cnonce, iks_strlen (cnonce), 1); iks_md5_print (md5, (char*)a1); iks_md5_reset (md5); iks_md5_hash (md5, (const unsigned char*)"AUTHENTICATE:xmpp/", 18, 0); iks_md5_hash (md5, (const unsigned char*)data->server, iks_strlen (data->server), 1); iks_md5_print (md5, (char*)a2); iks_md5_reset (md5); iks_md5_hash (md5, (const unsigned char*)a1, 32, 0); iks_md5_hash (md5, (const unsigned char*)":", 1, 0); iks_md5_hash (md5, (const unsigned char*)nonce, iks_strlen (nonce), 0); iks_md5_hash (md5, (const unsigned char*)":00000001:", 10, 0); iks_md5_hash (md5, (const unsigned char*)cnonce, iks_strlen (cnonce), 0); iks_md5_hash (md5, (const unsigned char*)":auth:", 6, 0); iks_md5_hash (md5, (const unsigned char*)a2, 32, 1); iks_md5_print (md5, (char*)response_value); iks_md5_delete (md5); i = iks_strlen (data->auth_username) + iks_strlen (realm) + iks_strlen (nonce) + iks_strlen (data->server) + CNONCE_LEN*8 + 136; response = iks_malloc (i); if (!response) return NULL; sprintf (response, "username=\"%s\",realm=\"%s\",nonce=\"%s\"" ",cnonce=\"%s\",nc=00000001,qop=auth,digest-uri=\"" "xmpp/%s\",response=%s,charset=utf-8", data->auth_username, realm, nonce, cnonce, data->server, response_value); response_coded = iks_base64_encode (response, 0); if (response_coded) { x = iks_new ("response"); iks_insert_cdata (x, response_coded, 0); iks_free (response_coded); } iks_free (response); return x;}static voidiks_sasl_challenge (struct stream_data *data, iks *challenge){ char *message; iks *x; char *tmp; tmp = iks_cdata (iks_child (challenge)); if (!tmp) return; /* decode received blob */ message = iks_base64_decode (tmp); if (!message) return; /* reply the challenge */ if (strstr (message, "rspauth")) { x = iks_new ("response"); } else { x = make_sasl_response (data, message); } if (x) { iks_insert_attrib (x, "xmlns", IKS_NS_XMPP_SASL); iks_send (data->prs, x); iks_delete (x); } iks_free (message);}static inttagHook (struct stream_data *data, char *name, char **atts, int type){ iks *x; int err; switch (type) { case IKS_OPEN: case IKS_SINGLE:#ifdef HAVE_GNUTLS if (data->flags & SF_TRY_SECURE) { if (strcmp (name, "proceed") == 0) { err = handshake (data); return err; } else if (strcmp (name, "failure") == 0){ return IKS_NET_TLSFAIL; } }#endif if (data->current) { x = iks_insert (data->current, name); insert_attribs (x, atts); } else { x = iks_new (name); insert_attribs (x, atts); if (iks_strcmp (name, "stream:stream") == 0) { err = data->streamHook (data->user_data, IKS_NODE_START, x); if (err != IKS_OK) return err; break; } } data->current = x; if (IKS_OPEN == type) break; case IKS_CLOSE: x = data->current; if (NULL == x) { err = data->streamHook (data->user_data, IKS_NODE_STOP, NULL); if (err != IKS_OK) return err; break; } if (NULL == iks_parent (x)) { data->current = NULL; if (iks_strcmp (name, "challenge") == 0) iks_sasl_challenge(data, x); else if (iks_strcmp (name, "stream:error") == 0) { err = data->streamHook (data->user_data, IKS_NODE_ERROR, x); if (err != IKS_OK) return err; } else { err = data->streamHook (data->user_data, IKS_NODE_NORMAL, x); if (err != IKS_OK) return err; } break; } data->current = iks_parent (x); } return IKS_OK;}static int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -