Author: ArcRiley Date: 2009-02-26 17:03:31 -0500 (Thu, 26 Feb 2009) New Revision: 1526
Modified: trunk/concordance/include/concordance.sockets.h trunk/concordance/src/sockets/Client.c Log: SASL authentication working (if a bit hackish for now) Modified: trunk/concordance/include/concordance.sockets.h =================================================================== --- trunk/concordance/include/concordance.sockets.h 2009-02-26 22:03:27 UTC (rev 1525) +++ trunk/concordance/include/concordance.sockets.h 2009-02-26 22:03:31 UTC (rev 1526) @@ -71,6 +71,7 @@ gchar skey[16]; /* session key (stream id="") */ concordVersion vers; /* XMPP major.minor version */ gboolean tls; /* flag for whether tls is enabled */ + gchar* user; /* NULL or authenticated username */ gint state; /* current session state */ gint depth; /* parser element depth */ GString* wbuff; /* write buffer */ @@ -93,6 +94,7 @@ CONCORD_E_OPEN, /* inside <stream> */ CONCORD_E_CLIENT, /* <iq> <message> <presence> */ CONCORD_E_SASL, /* <auth> <response> */ + CONCORD_E_RESET, /* pending stream reset */ }; #endif Modified: trunk/concordance/src/sockets/Client.c =================================================================== --- trunk/concordance/src/sockets/Client.c 2009-02-26 22:03:27 UTC (rev 1525) +++ trunk/concordance/src/sockets/Client.c 2009-02-26 22:03:31 UTC (rev 1526) @@ -66,6 +66,7 @@ session->self = self; session->node = NULL; session->lock = g_mutex_new(); + session->user = NULL; /* create a new channel using an OS-dependent function @@ -179,9 +180,25 @@ the session->state will be reset to CONCORD_E_CLOSE (== FALSE) to indicate that the session needs to get wrapped up. */ - if (XML_Parse(session->pars, buff, buff_len, FALSE) && session->state) + if (XML_Parse(session->pars, buff, buff_len, FALSE) && + session->state) { + if (session->state == CONCORD_E_RESET) { + /* reset XML parser and stream state + + XML_Bool XML_ParserReset (XML_Parser p, + const XML_Char *encoding); + */ + XML_Parse(session->pars, NULL, 0, TRUE); + XML_ParserReset(session->pars, NULL); + XML_SetUserData(session->pars, session); + XML_SetElementHandler(session->pars, _xmlStart, _xmlEnd); + XML_SetCharacterDataHandler(session->pars, _xmlCharData); + session->depth = 0; + session->state = CONCORD_E_OPEN; + } /* return true so GMainLoop will continue watching this channel */ return TRUE; + } } } @@ -302,6 +319,39 @@ # ########################################################################### # + # GNU SASL Callback + # */ + static int + _saslCallback(Gsasl* ctx, Gsasl_session* sctx, Gsasl_property prop) { /*\ + cdef : \*/ + socketsClient_Data* session; + gint ret; + + /* get session data + + void* gsasl_session_hook_get (Gsasl_session * sctx); + */ + session = (socketsClient_Data*) gsasl_session_hook_get(sctx); + + switch (prop) { + case GSASL_PASSWORD : { + gsasl_property_set(sctx, GSASL_PASSWORD, "tester"); + ret = GSASL_OK; + break; + } + default : { + ret = GSASL_NO_CALLBACK; + break; + } + } + + return ret; + } + + /* + # + ########################################################################### + # # Element responses # */ static void @@ -444,24 +494,30 @@ return; } - /* open stream:features and mechanisms element */ - buff = g_string_append(buff, "<stream:features><mechanisms" - " xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"); + if (session->user) { + /* don't provide features to authenticated users */ + buff = g_string_append(buff, "<stream:features/>"); + } + else { + /* open stream:features and mechanisms element */ + buff = g_string_append(buff, "<stream:features><mechanisms" + " xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"); - /* add a <mechanism> element for each supported SASL mechanism + /* add a <mechanism> element for each supported SASL mechanism - int gsasl_server_support_p (Gsasl* ctx, + int gsasl_server_support_p (Gsasl* ctx, const char* name); - GString* g_string_append (GString *string, + GString* g_string_append (GString *string, const gchar *val); - */ - if (gsasl_server_support_p(self->saslCntx, "DIGEST-MD5")) - buff = g_string_append(buff, "<mechanism>DIGEST-MD5</mechanism>"); - if (gsasl_server_support_p(self->saslCntx, "PLAIN")) - buff = g_string_append(buff, "<mechanism>PLAIN</mechanism>"); + */ + if (gsasl_server_support_p(self->saslCntx, "DIGEST-MD5")) + buff = g_string_append(buff, "<mechanism>DIGEST-MD5</mechanism>"); + if (gsasl_server_support_p(self->saslCntx, "PLAIN")) + buff = g_string_append(buff, "<mechanism>PLAIN</mechanism>"); - /* close <mechanisms> and <stream:features>, then send buffer */ - buff = g_string_append(buff, "</mechanisms></stream:features>"); + /* close <mechanisms> and <stream:features>, then send buffer */ + buff = g_string_append(buff, "</mechanisms></stream:features>"); + } _gioSend(session, buff->str, buff->len); /* free response buffer before returning @@ -474,44 +530,75 @@ static void - _reply_saslChallenge(socketsClient_Data* session) { /*\ + _reply_sasl(socketsClient_Data* session) { /*\ cdef : \*/ + GString* buff; + gchar* element; + gchar* output = ""; + gint status; - - return; - /* - gchar* g_base64_encode (const guchar *data, - gsize len); + /* process gsasl step with base64 conversion + + int gsasl_step64 (Gsasl_session *sctx, + const char *b64input, + char **b64output); */ + status = gsasl_step64(session->sctx, session->ebuff->str, &output); + buff = g_string_new(""); + switch (status) { + case GSASL_OK : { + element = "success"; + session->state = CONCORD_E_RESET; + break; + } + case GSASL_NEEDS_MORE : { + element = "challenge"; + break; + } + case GSASL_UNKNOWN_MECHANISM : { + element = "failure"; + output = "<invalid-mechanism/>"; + break; + } + case GSASL_BASE64_ERROR : { + element = "failure"; + output = "<incorrect-encoding/>"; + break; + } + case GSASL_AUTHENTICATION_ERROR : { + element = "failure"; + output = "<not-authorized/>"; + break; + } + default : { + element = "failure"; + output = "<temporary-auth-failure/>"; + break; + } + } - /*g_string_printf(buff, - "<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" - "%s</challenge>", ""); */ - } + /* switch how output is generated based on whether element is populated */ + if (output[0] == 0) { + g_string_printf(buff, + "<%s xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>", + element); + } + else { + g_string_printf(buff, + "<%s xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>%s</%s>", + element, output, element); + } + _gioSend(session, buff->str, buff->len); - static void - _reply_saslFailure(socketsClient_Data* session, gchar* failure) { /*\ - cdef : \*/ - GString* buff; - - /* printf failure to a GString, then send it - - GString* g_string_new (const gchar *init); - void g_string_printf (GString *string, - const gchar *format, - ...); - gchar* g_string_free (GString *string, - gboolean free_segment); - */ - buff = g_string_new(""); - g_string_printf(buff, "<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" - "%s</failure>", failure); - _gioSend(session, buff->str, buff->len); + /* free buffer and sasl output before returning */ g_string_free(buff, TRUE); + if (status == GSASL_OK || status == GSASL_NEEDS_MORE) { + g_free(output); + } } - + /* # ########################################################################### @@ -535,15 +622,6 @@ */ element = g_strsplit(name, " ", 2); - /* this from http://www.xml.com/pub/a/1999/09/expat/index.html?page=2 */ - for (i = 0; i < session->depth; i++) - printf(" "); - - printf("<%s xmlns='%s'", element[1], element[0]); - for (i = 0; atts[i]; i += 2) - printf(" %s='%s'", atts[i], atts[i + 1]); - printf(">\n"); - switch (session->depth) { /* match element by depth, namespace, and finally element name @@ -591,8 +669,6 @@ if (!(attr = concordFindAttr(atts, "from"))) attr = ""; session->efrom = g_string_assign(session->efrom, attr); - printf("--------- from: %s to: %s\n", - session->efrom->str, session->eto->str); /* copy element and attributes to ebuff @@ -618,21 +694,27 @@ "urn:ietf:params:xml:ns:xmpp-sasl") == 0) { if (g_ascii_strcasecmp(element[1], "auth") == 0) { gchar* mec = concordFindAttr(atts, "mechanism"); - if (mec && gsasl_server_support_p(self->saslCntx, mec)) { - /* initiate server session + if (!mec) { + mec = ""; + } + /* initiate server session - int gsasl_server_start (Gsasl* ctx, + int gsasl_server_start (Gsasl* ctx, const char* mech, Gsasl_session** sctx); - */ - printf("------ init %s mechanism\n", mec); - gsasl_server_start(self->saslCntx, mec, &session->sctx); - session->state = CONCORD_E_SASL; - } - else { - _reply_saslFailure(session, "<invalid-mechanism/>"); - session->state = CONCORD_E_CLOSE; - } + void gsasl_session_hook_set (Gsasl_session * sctx, + void * hook); + void gsasl_callback_set (Gsasl * ctx, + Gsasl_callback_function cb); + void gsasl_property_set (Gsasl_session *sctx, + Gsasl_property prop, + const char *data); + */ + gsasl_server_start(self->saslCntx, mec, &session->sctx); + gsasl_session_hook_set(session->sctx, (gpointer) session); + gsasl_callback_set(self->saslCntx, _saslCallback); + gsasl_property_set(session->sctx, GSASL_REALM, "selket.apogean.org"); + session->state = CONCORD_E_SASL; } /* remaining: response, abort */ @@ -692,10 +774,6 @@ */ element = g_strsplit(name, " ", 2); - for (i = 0; i < session->depth; i++) - printf(" "); - printf("</%s>\n", element[1]); - switch (session->depth) { case 0 : { /* close session when </stream:stream> is sent */ @@ -716,7 +794,7 @@ break; } case CONCORD_E_SASL : { - _reply_saslChallenge(session); + _reply_sasl(session); break; } } @@ -729,7 +807,6 @@ session->ebuff = g_string_assign(session->ebuff, ""); session->efrom = g_string_assign(session->efrom, ""); session->eto = g_string_assign(session->eto, ""); - break; } default : { @@ -759,15 +836,7 @@ cdef : \*/ socketsClient_Data* session = (socketsClient_Data*) data; gint i; - gchar* strn; - /* output to stdout for debugging */ - strn = g_strndup(str, str_len); - for (i = 0; i < session->depth; i++) - printf(" "); - printf("\"%s\"\n", strn); - g_free(strn); - if (session->state == CONCORD_E_OPEN) /* character data should be ignored at the stream level */ return; _______________________________________________ PySoy-SVN mailing list PySoy-SVN@pysoy.org http://www.pysoy.org/mailman/listinfo/pysoy-svn