⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 auth.c

📁 Linux下的多协议即时通讯程序源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		js->auth_type = JABBER_AUTH_DIGEST_MD5;		auth = xmlnode_new("auth");		xmlnode_set_namespace(auth, "urn:ietf:params:xml:ns:xmpp-sasl");		xmlnode_set_attrib(auth, "mechanism", "DIGEST-MD5");		jabber_send(js, auth);		xmlnode_free(auth);	} else if(plain) {		js->auth_type = JABBER_AUTH_PLAIN;		if(js->gsc == NULL && !purple_account_get_bool(js->gc->account, "auth_plain_in_clear", FALSE)) {			char *msg = g_strdup_printf(_("%s requires plaintext authentication over an unencrypted connection.  Allow this and continue authentication?"),					js->gc->account->username);			purple_request_yes_no(js->gc, _("Plaintext Authentication"),					_("Plaintext Authentication"),					msg,					2,					purple_connection_get_account(js->gc), NULL, NULL,					purple_connection_get_account(js->gc), allow_plaintext_auth,					disallow_plaintext_auth);			g_free(msg);			return;		}		finish_plaintext_authentication(js);	} else {		purple_connection_error(js->gc,				_("Server does not use any supported authentication method"));	}#endif}static void auth_old_result_cb(JabberStream *js, xmlnode *packet, gpointer data){	const char *type = xmlnode_get_attrib(packet, "type");	if(type && !strcmp(type, "result")) {		jabber_stream_set_state(js, JABBER_STREAM_CONNECTED);	} else {		char *msg = jabber_parse_error(js, packet);		xmlnode *error;		const char *err_code;		if((error = xmlnode_get_child(packet, "error")) &&					(err_code = xmlnode_get_attrib(error, "code")) &&					!strcmp(err_code, "401")) {			js->gc->wants_to_die = TRUE;		}		purple_connection_error(js->gc, msg);		g_free(msg);	}}static void auth_old_cb(JabberStream *js, xmlnode *packet, gpointer data){	JabberIq *iq;	xmlnode *query, *x;	const char *type = xmlnode_get_attrib(packet, "type");	const char *pw = purple_connection_get_password(js->gc);	if(!type) {		purple_connection_error(js->gc, _("Invalid response from server."));		return;	} else if(!strcmp(type, "error")) {		char *msg = jabber_parse_error(js, packet);		purple_connection_error(js->gc, msg);		g_free(msg);	} else if(!strcmp(type, "result")) {		query = xmlnode_get_child(packet, "query");		if(js->stream_id && xmlnode_get_child(query, "digest")) {			unsigned char hashval[20];			char *s, h[41], *p;			int i;			iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:auth");			query = xmlnode_get_child(iq->node, "query");			x = xmlnode_new_child(query, "username");			xmlnode_insert_data(x, js->user->node, -1);			x = xmlnode_new_child(query, "resource");			xmlnode_insert_data(x, js->user->resource, -1);			x = xmlnode_new_child(query, "digest");			s = g_strdup_printf("%s%s", js->stream_id, pw);			purple_cipher_digest_region("sha1", (guchar *)s, strlen(s),									  sizeof(hashval), hashval, NULL);			p = h;			for(i=0; i<20; i++, p+=2)				snprintf(p, 3, "%02x", hashval[i]);			xmlnode_insert_data(x, h, -1);			g_free(s);			jabber_iq_set_callback(iq, auth_old_result_cb, NULL);			jabber_iq_send(iq);		} else if(xmlnode_get_child(query, "password")) {			if(js->gsc == NULL && !purple_account_get_bool(js->gc->account,						"auth_plain_in_clear", FALSE)) {				purple_request_yes_no(js->gc, _("Plaintext Authentication"),						_("Plaintext Authentication"),						_("This server requires plaintext authentication over an unencrypted connection.  Allow this and continue authentication?"),						2,						purple_connection_get_account(js->gc), NULL, NULL,						purple_connection_get_account(js->gc), allow_plaintext_auth,						disallow_plaintext_auth);				return;			}			finish_plaintext_authentication(js);		} else {			purple_connection_error(js->gc,					_("Server does not use any supported authentication method"));			return;		}	}}void jabber_auth_start_old(JabberStream *js){	JabberIq *iq;	xmlnode *query, *username;#ifdef HAVE_CYRUS_SASL	/* If we have Cyrus SASL, then passwords will have been set	 * to OPTIONAL for this protocol. So, we need to do our own	 * password prompting here	 */		if (!purple_account_get_password(js->gc->account)) {		purple_account_request_password(js->gc->account, G_CALLBACK(auth_old_pass_cb), G_CALLBACK(auth_no_pass_cb), js);		return;	}#endif	iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:auth");	query = xmlnode_get_child(iq->node, "query");	username = xmlnode_new_child(query, "username");	xmlnode_insert_data(username, js->user->node, -1);	jabber_iq_set_callback(iq, auth_old_cb, NULL);	jabber_iq_send(iq);}/* Parts of this algorithm are inspired by stuff in libgsasl */static GHashTable* parse_challenge(const char *challenge){	const char *token_start, *val_start, *val_end, *cur;	GHashTable *ret = g_hash_table_new_full(g_str_hash, g_str_equal,			g_free, g_free);	cur = challenge;	while(*cur != '\0') {		/* Find the end of the token */		gboolean in_quotes = FALSE;		char *name, *value = NULL;		token_start = cur;		while(*cur != '\0' && (in_quotes || (!in_quotes && *cur != ','))) {			if (*cur == '"')				in_quotes = !in_quotes;			cur++;		}		/* Find start of value.  */		val_start = strchr(token_start, '=');		if (val_start == NULL || val_start > cur)			val_start = cur;		if (token_start != val_start) {			name = g_strndup(token_start, val_start - token_start);			if (val_start != cur) {				val_start++;				while (val_start != cur && (*val_start == ' ' || *val_start == '\t'						|| *val_start == '\r' || *val_start == '\n'						|| *val_start == '"'))					val_start++;				val_end = cur;				while (val_end != val_start && (*val_end == ' ' || *val_end == ',' || *val_end == '\t'						|| *val_end == '\r' || *val_start == '\n'						|| *val_end == '"'))					val_end--;				if (val_start != val_end)					value = g_strndup(val_start, val_end - val_start + 1);			}			g_hash_table_replace(ret, name, value);		}		/* Find the start of the next token, if there is one */		if (*cur != '\0') {			cur++;			while (*cur == ' ' || *cur == ',' || *cur == '\t'					|| *cur == '\r' || *cur == '\n')				cur++;		}	}	return ret;}static char *generate_response_value(JabberID *jid, const char *passwd, const char *nonce,		const char *cnonce, const char *a2, const char *realm){	PurpleCipher *cipher;	PurpleCipherContext *context;	guchar result[16];	size_t a1len;	gchar *a1, *convnode=NULL, *convpasswd = NULL, *ha1, *ha2, *kd, *x, *z;	if((convnode = g_convert(jid->node, strlen(jid->node), "iso-8859-1", "utf-8",					NULL, NULL, NULL)) == NULL) {		convnode = g_strdup(jid->node);	}	if(passwd && ((convpasswd = g_convert(passwd, strlen(passwd), "iso-8859-1",						"utf-8", NULL, NULL, NULL)) == NULL)) {		convpasswd = g_strdup(passwd);	}	cipher = purple_ciphers_find_cipher("md5");	context = purple_cipher_context_new(cipher, NULL);	x = g_strdup_printf("%s:%s:%s", convnode, realm, convpasswd ? convpasswd : "");	purple_cipher_context_append(context, (const guchar *)x, strlen(x));	purple_cipher_context_digest(context, sizeof(result), result, NULL);	a1 = g_strdup_printf("xxxxxxxxxxxxxxxx:%s:%s", nonce, cnonce);	a1len = strlen(a1);	g_memmove(a1, result, 16);	purple_cipher_context_reset(context, NULL);	purple_cipher_context_append(context, (const guchar *)a1, a1len);	purple_cipher_context_digest(context, sizeof(result), result, NULL);	ha1 = purple_base16_encode(result, 16);	purple_cipher_context_reset(context, NULL);	purple_cipher_context_append(context, (const guchar *)a2, strlen(a2));	purple_cipher_context_digest(context, sizeof(result), result, NULL);	ha2 = purple_base16_encode(result, 16);	kd = g_strdup_printf("%s:%s:00000001:%s:auth:%s", ha1, nonce, cnonce, ha2);	purple_cipher_context_reset(context, NULL);	purple_cipher_context_append(context, (const guchar *)kd, strlen(kd));	purple_cipher_context_digest(context, sizeof(result), result, NULL);	purple_cipher_context_destroy(context);	z = purple_base16_encode(result, 16);	g_free(convnode);	g_free(convpasswd);	g_free(x);	g_free(a1);	g_free(ha1);	g_free(ha2);	g_free(kd);	return z;}voidjabber_auth_handle_challenge(JabberStream *js, xmlnode *packet){	if(js->auth_type == JABBER_AUTH_DIGEST_MD5) {		char *enc_in = xmlnode_get_data(packet);		char *dec_in;		char *enc_out;		GHashTable *parts;		if(!enc_in) {			purple_connection_error(js->gc, _("Invalid response from server."));			return;		}		dec_in = (char *)purple_base64_decode(enc_in, NULL);		purple_debug(PURPLE_DEBUG_MISC, "jabber", "decoded challenge (%d): %s\n",				strlen(dec_in), dec_in);		parts = parse_challenge(dec_in);		if (g_hash_table_lookup(parts, "rspauth")) {			char *rspauth = g_hash_table_lookup(parts, "rspauth");			if(rspauth && js->expected_rspauth &&					!strcmp(rspauth, js->expected_rspauth)) {				jabber_send_raw(js,						"<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl' />",						-1);			} else {				purple_connection_error(js->gc, _("Invalid challenge from server"));			}			g_free(js->expected_rspauth);		} else {			/* assemble a response, and send it */			/* see RFC 2831 */			char *realm;			char *nonce;			/* Make sure the auth string contains everything that should be there.			   This isn't everything in RFC2831, but it is what we need. */			nonce = g_hash_table_lookup(parts, "nonce");			/* we're actually supposed to prompt the user for a realm if			 * the server doesn't send one, but that really complicates things,			 * so i'm not gonna worry about it until is poses a problem to			 * someone, or I get really bored */			realm = g_hash_table_lookup(parts, "realm");			if(!realm)				realm = js->user->domain;			if (nonce == NULL || realm == NULL)				purple_connection_error(js->gc, _("Invalid challenge from server"));			else {				GString *response = g_string_new("");				char *a2;				char *auth_resp;				char *buf;				char *cnonce;				cnonce = g_strdup_printf("%x%u%x", g_random_int(), (int)time(NULL),						g_random_int());				a2 = g_strdup_printf("AUTHENTICATE:xmpp/%s", realm);				auth_resp = generate_response_value(js->user,						purple_connection_get_password(js->gc), nonce, cnonce, a2, realm);				g_free(a2);				a2 = g_strdup_printf(":xmpp/%s", realm);				js->expected_rspauth = generate_response_value(js->user,						purple_connection_get_password(js->gc), nonce, cnonce, a2, realm);				g_free(a2);				g_string_append_printf(response, "username=\"%s\"", js->user->node);				g_string_append_printf(response, ",realm=\"%s\"", realm);				g_string_append_printf(response, ",nonce=\"%s\"", nonce);				g_string_append_printf(response, ",cnonce=\"%s\"", cnonce);				g_string_append_printf(response, ",nc=00000001");				g_string_append_printf(response, ",qop=auth");				g_string_append_printf(response, ",digest-uri=\"xmpp/%s\"", realm);				g_string_append_printf(response, ",response=%s", auth_resp);				g_string_append_printf(response, ",charset=utf-8");				g_free(auth_resp);				g_free(cnonce);				enc_out = purple_base64_encode((guchar *)response->str, response->len);				purple_debug(PURPLE_DEBUG_MISC, "jabber", "decoded response (%d): %s\n", response->len, response->str);				buf = g_strdup_printf("<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>%s</response>", enc_out);				jabber_send_raw(js, buf, -1);				g_free(buf);				g_free(enc_out);				g_string_free(response, TRUE);			}		}		g_free(enc_in);		g_free(dec_in);		g_hash_table_destroy(parts);	}#ifdef HAVE_CYRUS_SASL	else if (js->auth_type == JABBER_AUTH_CYRUS) {		char *enc_in = xmlnode_get_data(packet);		unsigned char *dec_in;		char *enc_out;		const char *c_out;		unsigned int clen;		gsize declen;		xmlnode *response;		dec_in = purple_base64_decode(enc_in, &declen);		js->sasl_state = sasl_client_step(js->sasl, (char*)dec_in, declen,						  NULL, &c_out, &clen);		g_free(enc_in);		g_free(dec_in);		if (js->sasl_state != SASL_CONTINUE && js->sasl_state != SASL_OK) {			purple_debug_error("jabber", "Error is %d : %s\n",js->sasl_state,sasl_errdetail(js->sasl));			purple_connection_error(js->gc, _("SASL error"));			return;		} else {			response = xmlnode_new("response");			xmlnode_set_namespace(response, "urn:ietf:params:xml:ns:xmpp-sasl");			if (clen > 0) {				enc_out = purple_base64_encode((unsigned char*)c_out, clen);				xmlnode_insert_data(response, enc_out, -1);				g_free(enc_out);			}			jabber_send(js, response);			xmlnode_free(response);		}	}#endif}void jabber_auth_handle_success(JabberStream *js, xmlnode *packet){	const char *ns = xmlnode_get_namespace(packet);#ifdef HAVE_CYRUS_SASL	const void *x;#endif	if(!ns || strcmp(ns, "urn:ietf:params:xml:ns:xmpp-sasl")) {		purple_connection_error(js->gc, _("Invalid response from server."));		return;	}#ifdef HAVE_CYRUS_SASL	/* The SASL docs say that if the client hasn't returned OK yet, we	 * should try one more round against it	 */	if (js->sasl_state != SASL_OK) {		char *enc_in = xmlnode_get_data(packet);		unsigned char *dec_in = NULL;		const char *c_out;		unsigned int clen;		gsize declen = 0;		if(enc_in != NULL)			dec_in = purple_base64_decode(enc_in, &declen);		js->sasl_state = sasl_client_step(js->sasl, (char*)dec_in, declen, NULL, &c_out, &clen);		g_free(enc_in);		g_free(dec_in);		if (js->sasl_state != SASL_OK) {			/* This should never happen! */			purple_connection_error(js->gc, _("Invalid response from server."));		}	}	/* If we've negotiated a security layer, we need to enable it */	sasl_getprop(js->sasl, SASL_SSF, &x);	if (*(int *)x > 0) {		sasl_getprop(js->sasl, SASL_MAXOUTBUF, &x);		js->sasl_maxbuf = *(int *)x;	}#endif	jabber_stream_set_state(js, JABBER_STREAM_REINITIALIZING);}void jabber_auth_handle_failure(JabberStream *js, xmlnode *packet){	char *msg = jabber_parse_error(js, packet);	if(!msg) {		purple_connection_error(js->gc, _("Invalid response from server."));	} else {		purple_connection_error(js->gc, msg);		g_free(msg);	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -