summary refs log tree commit diff stats
path: root/src/common/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/util.c')
-rw-r--r--src/common/util.c94
1 files changed, 83 insertions, 11 deletions
diff --git a/src/common/util.c b/src/common/util.c
index 29a0f3ed..52464621 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -1886,7 +1886,7 @@ int main (int argc, char *argv[])
 	list = get_subdirs ("foo");
 	display_list (list);
 #if GLIB_CHECK_VERSION(2,28,0)
-	g_slist_free_full (list, (GFunc) g_free);
+	g_slist_free_full (list, (GDestroyNotify) g_free);
 #else
 	g_slist_foreach (list, (GFunc) g_free, NULL);
 	g_slist_free (list);
@@ -1931,19 +1931,15 @@ get_subdirs (const char *path)
 char *
 encode_sasl_pass (char *user, char *pass)
 {
-	int passlen;
+	int authlen;
 	char *buffer;
 	char *encoded;
 
-	/* passphrase generation, nicely copy-pasted from the CAP-SASL plugin */
-	passlen = strlen (user) * 2 + 2 + strlen (pass);
-	buffer = (char*) malloc (passlen + 1);
-	strcpy (buffer, user);
-	strcpy (buffer + strlen (user) + 1, user);
-	strcpy (buffer + strlen (user) * 2 + 2, pass);
-	encoded = g_base64_encode ((unsigned char*) buffer, passlen);
-
-	free (buffer);
+	/* we can't call strlen() directly on buffer thanks to the atrocious \0 characters it requires */
+	authlen = strlen (user) * 2 + 2 + strlen (pass);
+	buffer = g_strdup_printf ("%s%c%s%c%s", user, '\0', user, '\0', pass);
+	encoded = g_base64_encode ((unsigned char*) buffer, authlen);
+	g_free (buffer);
 
 	return encoded;
 }
@@ -1978,3 +1974,79 @@ find_font (const char *fontname)
 	return 0;
 }
 #endif
+
+static char *
+str_sha256hash (char *string)
+{
+	int i;
+	unsigned char hash[SHA256_DIGEST_LENGTH];
+	char buf[SHA256_DIGEST_LENGTH * 2 + 1];		/* 64 digit hash + '\0' */
+	SHA256_CTX sha256;
+
+	SHA256_Init (&sha256);
+	SHA256_Update (&sha256, string, strlen (string));
+	SHA256_Final (hash, &sha256);
+
+	for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
+	{
+		sprintf (buf + (i * 2), "%02x", hash[i]);
+	}
+
+	buf[SHA256_DIGEST_LENGTH * 2] = 0;
+
+	return g_strdup (buf);
+}
+
+/**
+ * \brief Generate CHALLENGEAUTH response for QuakeNet login.
+ *
+ * \param username QuakeNet user name
+ * \param password password for the user
+ * \param challenge the CHALLENGE response we got from Q
+ *
+ * After a successful connection to QuakeNet a CHALLENGE is requested from Q.
+ * Generate the CHALLENGEAUTH response from this CHALLENGE and our user
+ * credentials as per the
+ * <a href="http://www.quakenet.org/development/challengeauth">CHALLENGEAUTH</a>
+ * docs. As for using OpenSSL HMAC, see
+ * <a href="http://www.askyb.com/cpp/openssl-hmac-hasing-example-in-cpp/">example 1</a>,
+ * <a href="http://stackoverflow.com/questions/242665/understanding-engine-initialization-in-openssl">example 2</a>.
+ */
+char *
+challengeauth_response (char *username, char *password, char *challenge)
+{
+	int i;
+	char *user;
+	char *pass;
+	char *passhash;
+	char *key;
+	char *keyhash;
+	unsigned char *digest;
+	GString *buf = g_string_new_len (NULL, SHA256_DIGEST_LENGTH * 2);
+
+	user = g_strdup (username);
+	*user = rfc_tolower (*username);			/* convert username to lowercase as per the RFC */
+
+	pass = g_strndup (password, 10);			/* truncate to 10 characters */
+	passhash = str_sha256hash (pass);
+	g_free (pass);
+
+	key = g_strdup_printf ("%s:%s", user, passhash);
+	g_free (user);
+	g_free (passhash);
+
+	keyhash = str_sha256hash (key);
+	g_free (key);
+
+	digest = HMAC (EVP_sha256 (), keyhash, strlen (keyhash), (unsigned char *) challenge, strlen (challenge), NULL, NULL);
+	g_free (keyhash);
+
+	for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
+	{
+		g_string_append_printf (buf, "%02x", (unsigned int) digest[i]);
+	}
+
+	digest = (unsigned char *) g_string_free (buf, FALSE);
+
+	return (char *) digest;
+}