diff -ur jabberd-2.0s9/c2s/c2s.c jabberd-2.0s9-sasl/c2s/c2s.c --- jabberd-2.0s9/c2s/c2s.c 2005-03-23 18:01:24.000000000 +0000 +++ jabberd-2.0s9-sasl/c2s/c2s.c 2005-07-27 23:23:13.000000000 +0100 @@ -461,21 +461,12 @@ #ifdef HAVE_SSL /* go ssl wrappermode if they're on the ssl port */ if(port == c2s->local_ssl_port) - sx_server_init(sess->s, SX_SSL_WRAPPER | SX_SASL_OFFER | - ((c2s->ar_mechanisms & AR_MECH_SASL_ANONYMOUS) ? SX_SASL_MECH_ANONYMOUS : 0) | - ((c2s->ar_mechanisms & AR_MECH_SASL_PLAIN) ? SX_SASL_MECH_PLAIN : 0) | - ((c2s->ar_mechanisms & AR_MECH_SASL_DIGESTMD5) ? SX_SASL_MECH_DIGESTMD5 : 0)); + sx_server_init(sess->s, SX_SSL_WRAPPER | SX_SASL_OFFER); else sx_server_init(sess->s, ((c2s->local_pemfile != NULL) ? SX_SSL_STARTTLS_OFFER : 0) | SX_SASL_OFFER | - ((c2s->ar_mechanisms & AR_MECH_SASL_ANONYMOUS) ? SX_SASL_MECH_ANONYMOUS : 0) | - ((c2s->ar_mechanisms & AR_MECH_SASL_PLAIN) ? SX_SASL_MECH_PLAIN : 0) | - ((c2s->ar_mechanisms & AR_MECH_SASL_DIGESTMD5) ? SX_SASL_MECH_DIGESTMD5 : 0) | (c2s->local_require_starttls ? SX_SSL_STARTTLS_REQUIRE : 0)); #else - sx_server_init(sess->s, SX_SASL_OFFER | - ((c2s->ar_mechanisms & AR_MECH_SASL_ANONYMOUS) ? SX_SASL_MECH_ANONYMOUS : 0) | - ((c2s->ar_mechanisms & AR_MECH_SASL_PLAIN) ? SX_SASL_MECH_PLAIN : 0) | - ((c2s->ar_mechanisms & AR_MECH_SASL_DIGESTMD5) ? SX_SASL_MECH_DIGESTMD5 : 0)); + sx_server_init(sess->s, SX_SASL_OFFER); #endif break; } @@ -674,7 +665,7 @@ * if there isn't an appropriate one, error and bail */ /* authenticate */ - sx_sasl_auth(c2s->sx_sasl, s, "DIGEST-MD5", c2s->router_user, c2s->router_pass, NULL); + sx_sasl_auth(c2s->sx_sasl, s, "jabberd-router", "DIGEST-MD5", c2s->router_user, c2s->router_pass); nad_free(nad); return 0; diff -ur jabberd-2.0s9/c2s/c2s.h jabberd-2.0s9-sasl/c2s/c2s.h --- jabberd-2.0s9/c2s/c2s.h 2005-03-23 18:01:24.000000000 +0000 +++ jabberd-2.0s9-sasl/c2s/c2s.h 2005-07-27 23:23:13.000000000 +0100 @@ -80,9 +80,6 @@ #define AR_MECH_TRAD_PLAIN (1<<0) #define AR_MECH_TRAD_DIGEST (1<<1) #define AR_MECH_TRAD_ZEROK (1<<2) -#define AR_MECH_SASL_ANONYMOUS (1<<3) -#define AR_MECH_SASL_PLAIN (1<<4) -#define AR_MECH_SASL_DIGESTMD5 (1<<5) struct c2s_st { /** our id (hostname) with the router */ diff -ur jabberd-2.0s9/c2s/main.c jabberd-2.0s9-sasl/c2s/main.c --- jabberd-2.0s9/c2s/main.c 2005-06-02 05:58:46.000000000 +0100 +++ jabberd-2.0s9-sasl/c2s/main.c 2005-07-27 23:23:13.000000000 +0100 @@ -148,9 +148,6 @@ if(config_get(c2s->config, "authreg.mechanisms.traditional.plain") != NULL) c2s->ar_mechanisms |= AR_MECH_TRAD_PLAIN; if(config_get(c2s->config, "authreg.mechanisms.traditional.digest") != NULL) c2s->ar_mechanisms |= AR_MECH_TRAD_DIGEST; if(config_get(c2s->config, "authreg.mechanisms.traditional.zerok") != NULL) c2s->ar_mechanisms |= AR_MECH_TRAD_ZEROK; - if(config_get(c2s->config, "authreg.mechanisms.sasl.anonymous") != NULL) c2s->ar_mechanisms |= AR_MECH_SASL_ANONYMOUS; - if(config_get(c2s->config, "authreg.mechanisms.sasl.plain") != NULL) c2s->ar_mechanisms |= AR_MECH_SASL_PLAIN; - if(config_get(c2s->config, "authreg.mechanisms.sasl.digest-md5") != NULL) c2s->ar_mechanisms |= AR_MECH_SASL_DIGESTMD5; elem = config_get(c2s->config, "io.limits.bytes"); if(elem != NULL) @@ -234,18 +231,17 @@ return 0; } -static int _c2s_sx_sasl_callback(int cb, void *arg, void **res, scod_t sd, void *cbarg) { +static int _c2s_sx_sasl_callback(int cb, void *arg, void **res, sx_t s, void *cbarg) { c2s_t c2s = (c2s_t) cbarg; - sx_t s; - char *realm, *my_realm, pass[257]; - scod_cb_creds_t creds; + char *my_realm, *mech; + sx_sasl_creds_t creds; + static char buf[3072]; + char mechbuf[256]; struct jid_st jid; int i, r; switch(cb) { case sx_sasl_cb_GET_REALM: - s = (sx_t) arg; - realm = (char *) res; if(s->req_to == NULL) /* this shouldn't happen */ my_realm = ""; @@ -256,66 +252,77 @@ my_realm = s->req_to; } - strncpy(realm, my_realm, 256); - - log_debug(ZONE, "sx sasl callback: get realm: realm is '%s'", realm); + strncpy(buf, my_realm, 256); + *res = buf; + log_debug(ZONE, "sx sasl callback: get realm: realm is '%s'", buf); + return sx_sasl_ret_OK; break; case sx_sasl_cb_GET_PASS: - creds = (scod_cb_creds_t) arg; + creds = (sx_sasl_creds_t) arg; log_debug(ZONE, "sx sasl callback: get pass (authnid=%s, realm=%s)", creds->authnid, creds->realm); - if(*res == NULL) - return 1; - - if((c2s->ar->get_password)(c2s->ar, creds->authnid, (creds->realm != NULL) ? creds->realm : "", pass) != 0) - return 1; - - strncpy(* (char **) res, pass, 256); - (* (char **) res)[256] = '\0'; + if(c2s->ar->get_password && (c2s->ar->get_password)(c2s->ar, (char *)creds->authnid, (creds->realm != NULL) ? (char *)creds->realm: "", buf) == 0) { + *res = buf; + return sx_sasl_ret_OK; + } - return 0; + return sx_sasl_ret_FAIL; case sx_sasl_cb_CHECK_PASS: - creds = (scod_cb_creds_t) arg; + creds = (sx_sasl_creds_t) arg; log_debug(ZONE, "sx sasl callback: check pass (authnid=%s, realm=%s)", creds->authnid, creds->realm); - if(c2s->ar->check_password != NULL) - return (c2s->ar->check_password)(c2s->ar, creds->authnid, (creds->realm != NULL) ? creds->realm : "", creds->pass); + if(c2s->ar->check_password != NULL) { + if ((c2s->ar->check_password)(c2s->ar, (char *)creds->authnid, (creds->realm != NULL) ? (char *)creds->realm : "", (char *)creds->pass)) + return sx_sasl_ret_OK; + else + return sx_sasl_ret_FAIL; + } - if((c2s->ar->get_password)(c2s->ar, creds->authnid, (creds->realm != NULL) ? creds->realm : "", pass) != 0) - return 1; + if(c2s->ar->get_password != NULL) { + if ((c2s->ar->get_password)(c2s->ar, (char *)creds->authnid, (creds->realm != NULL) ? (char *)creds->realm : "", buf) != 0) + return sx_sasl_ret_FAIL; - return strcmp(creds->pass, pass); + if (strcmp(creds->pass, buf)==0) + return sx_sasl_ret_OK; + } + return sx_sasl_ret_FAIL; + break; + case sx_sasl_cb_CHECK_AUTHZID: - creds = (scod_cb_creds_t) arg; - s = (sx_t) sd->app_private; /* no authzid, we should build one */ - if(creds->authzid[0] == '\0') - snprintf(creds->authzid, 3072, "%s@%s", creds->authnid, s->req_to); + if(creds->authzid == NULL || creds->authzid[0] == '\0') { + snprintf(buf, 3072, "%s@%s", creds->authnid, s->req_to); + creds->authzid = (void *)buf; + } /* authzid must be a valid jid */ jid.pc = c2s->pc; if(jid_reset(&jid, creds->authzid, -1) == NULL) - return 1; + return sx_sasl_ret_FAIL; /* and have domain == stream to addr */ if(strcmp(jid.domain, s->req_to) != 0) - return 1; + return sx_sasl_ret_FAIL; /* and have no resource */ if(jid.resource[0] != '\0') - return 1; + return sx_sasl_ret_FAIL; + + /* and exist ! */ + + if((c2s->ar->user_exists)(c2s->ar, (char *)creds->authnid, (char *)creds->realm)) + return sx_sasl_ret_OK; - return 0; + return sx_sasl_ret_FAIL; case sx_sasl_cb_GEN_AUTHZID: - s = (sx_t) sd->app_private; jid.pc = c2s->pc; jid_reset(&jid, s->req_to, -1); @@ -331,15 +338,37 @@ jid_prep(&jid); - strcpy((char *) res, jid_full(&jid)); + strcpy(buf, jid_full(&jid)); + + *res = (void *)buf; - return 0; + return sx_sasl_ret_OK; + break; + + case sx_sasl_cb_CHECK_MECH: + mech = (char *)arg; + i=0; + while(i sizeof(buf)) + return sx_sasl_ret_FAIL; + + /* Work out if our configuration will let us use this mechanism */ + if(config_get(c2s->config,buf) != NULL) + return sx_sasl_ret_OK; + else + return sx_sasl_ret_FAIL; default: break; } - return 0; + return sx_sasl_ret_FAIL; } static void _c2s_time_checks(c2s_t c2s) { sess_t sess; @@ -514,12 +543,8 @@ /* get sasl online */ sd_flags = 0; - if(c2s->ar->get_password != NULL) - sd_flags = sd_flag_GET_PASS | sd_flag_CHECK_PASS; - else if(c2s->ar->check_password != NULL) - sd_flags = sd_flag_CHECK_PASS; - c2s->sx_sasl = sx_env_plugin(c2s->sx_env, sx_sasl_init, _c2s_sx_sasl_callback, (void *) c2s, sd_flags); + c2s->sx_sasl = sx_env_plugin(c2s->sx_env, sx_sasl_init, "xmpp", sd_flags, _c2s_sx_sasl_callback, (void *) c2s, sd_flags); if(c2s->sx_sasl == NULL) { log_write(c2s->log, LOG_ERR, "failed to initialise SASL context, aborting"); exit(1); Only in jabberd-2.0s9-sasl/c2s: main.c.orig diff -ur jabberd-2.0s9/c2s/Makefile.am jabberd-2.0s9-sasl/c2s/Makefile.am --- jabberd-2.0s9/c2s/Makefile.am 2004-04-08 07:51:08.000000000 +0100 +++ jabberd-2.0s9-sasl/c2s/Makefile.am 2005-07-27 23:23:14.000000000 +0100 @@ -6,7 +6,6 @@ noinst_HEADERS = c2s.h c2s_LDADD = $(top_builddir)/sx/libsx.la \ - $(top_builddir)/scod/libscod.la \ $(top_builddir)/mio/libmio.la \ $(top_builddir)/util/libutil.la \ $(top_builddir)/subst/libsubst.la \ diff -ur jabberd-2.0s9/config.h.in jabberd-2.0s9-sasl/config.h.in --- jabberd-2.0s9/config.h.in 2005-07-26 08:43:35.000000000 +0100 +++ jabberd-2.0s9-sasl/config.h.in 2005-07-27 23:23:14.000000000 +0100 @@ -127,6 +127,9 @@ /* Define to 1 if you have the `resolv' library (-lresolv). */ #undef HAVE_LIBRESOLV +/* Define to 1 if you have the `sasl2' library (-lsasl2). */ +#undef HAVE_LIBSASL2 + /* Define to 1 if you have the `socket' library (-lsocket). */ #undef HAVE_LIBSOCKET diff -ur jabberd-2.0s9/configure.in jabberd-2.0s9-sasl/configure.in --- jabberd-2.0s9/configure.in 2005-07-26 08:39:15.000000000 +0100 +++ jabberd-2.0s9-sasl/configure.in 2005-07-27 23:23:14.000000000 +0100 @@ -282,6 +282,8 @@ fi +AC_CHECK_LIB(sasl2,sasl_client_init) + dnl find openssl >= 0.9.6b AC_ARG_ENABLE(ssl, AC_HELP_STRING([--enable-ssl], [enable SSL/TLS support (yes)]), want_ssl=$enableval, want_ssl=yes) if test "x-$want_ssl" = "x-yes" ; then @@ -769,7 +771,6 @@ man/Makefile \ expat/Makefile \ mio/Makefile \ - scod/Makefile \ subst/Makefile \ sx/Makefile \ util/Makefile \ Only in jabberd-2.0s9-sasl: configure.in.orig diff -ur jabberd-2.0s9/Makefile.am jabberd-2.0s9-sasl/Makefile.am --- jabberd-2.0s9/Makefile.am 2005-03-31 09:48:46.000000000 +0100 +++ jabberd-2.0s9-sasl/Makefile.am 2005-07-27 23:23:14.000000000 +0100 @@ -1,6 +1,6 @@ EXTRA_DIST = PROTOCOL Doxyfile.in README.win32 contrib -SUBDIRS = etc tools man expat mio scod subst sx util c2s resolver router s2s sm +SUBDIRS = etc tools man expat mio subst sx util c2s resolver router s2s sm docs: Doxyfile @doxygen diff -ur jabberd-2.0s9/resolver/Makefile.am jabberd-2.0s9-sasl/resolver/Makefile.am --- jabberd-2.0s9/resolver/Makefile.am 2004-04-08 07:51:17.000000000 +0100 +++ jabberd-2.0s9-sasl/resolver/Makefile.am 2005-07-27 23:23:14.000000000 +0100 @@ -6,7 +6,6 @@ resolver_SOURCES = resolver.c dns.c resolver_LDADD = $(top_builddir)/sx/libsx.la \ - $(top_builddir)/scod/libscod.la \ $(top_builddir)/mio/libmio.la \ $(top_builddir)/util/libutil.la \ $(top_builddir)/subst/libsubst.la \ diff -ur jabberd-2.0s9/resolver/resolver.c jabberd-2.0s9-sasl/resolver/resolver.c --- jabberd-2.0s9/resolver/resolver.c 2005-01-19 17:56:25.000000000 +0000 +++ jabberd-2.0s9-sasl/resolver/resolver.c 2005-07-27 23:23:14.000000000 +0100 @@ -255,7 +255,7 @@ * if there isn't an appropriate one, error and bail */ /* authenticate */ - sx_sasl_auth(r->sx_sasl, s, "DIGEST-MD5", r->router_user, r->router_pass, NULL); + sx_sasl_auth(r->sx_sasl, s, "jabberd-router", "DIGEST-MD5", r->router_user, r->router_pass); nad_free(nad); return 0; @@ -607,7 +607,7 @@ #endif /* get sasl online */ - r->sx_sasl = sx_env_plugin(r->sx_env, sx_sasl_init, NULL, NULL, 0); + r->sx_sasl = sx_env_plugin(r->sx_env, sx_sasl_init, "jabberd-router", NULL, NULL, 0); if(r->sx_sasl == NULL) { log_write(r->log, LOG_ERR, "failed to initialise SASL context, aborting"); exit(1); diff -ur jabberd-2.0s9/router/main.c jabberd-2.0s9-sasl/router/main.c --- jabberd-2.0s9/router/main.c 2005-06-02 05:41:44.000000000 +0100 +++ jabberd-2.0s9-sasl/router/main.c 2005-07-27 23:23:14.000000000 +0100 @@ -190,50 +190,58 @@ r->check_keepalive = j_atoi(config_get_one(r->config, "check.keepalive", 0), 0); } -static int _router_sx_sasl_callback(int cb, void *arg, void **res, scod_t sd, void *cbarg) { +static int _router_sx_sasl_callback(int cb, void *arg, void ** res, sx_t s, void *cbarg) { router_t r = (router_t) cbarg; - sx_t s; - scod_cb_creds_t creds; + sx_sasl_creds_t creds; + char buf[1024]; char *pass; switch(cb) { case sx_sasl_cb_GET_REALM: - s = (sx_t) arg; - strcpy((char *) res, "jabberd-router"); + strcpy(buf, "jabberd-router"); + *res = (void *)buf; + return sx_sasl_ret_OK; break; case sx_sasl_cb_GET_PASS: - creds = (scod_cb_creds_t) arg; + creds = (sx_sasl_creds_t) arg; log_debug(ZONE, "sx sasl callback: get pass (authnid=%s, realm=%s)", creds->authnid, creds->realm); - *res = xhash_get(r->users, creds->authnid); - if(*res == NULL) - return 1; + pass = xhash_get(r->users, creds->authnid); + if(pass == NULL) + return sx_sasl_ret_FAIL; - return 0; + *res = (void *)pass; + return sx_sasl_ret_OK; + break; case sx_sasl_cb_CHECK_PASS: - creds = (scod_cb_creds_t) arg; + creds = (sx_sasl_creds_t) arg; log_debug(ZONE, "sx sasl callback: check pass (authnid=%s, realm=%s)", creds->authnid, creds->realm); pass = xhash_get(r->users, creds->authnid); if(pass == NULL || strcmp(creds->pass, pass) != 0) - return 1; + return sx_sasl_ret_OK; - return 0; + return sx_sasl_ret_FAIL; + break; case sx_sasl_cb_CHECK_AUTHZID: - creds = (scod_cb_creds_t) arg; - if(creds->authzid[0] == '\0') - strcpy(creds->authzid, creds->authnid); + /* We just need to ensure that authnid == authzid, which top + * level does for us at the moment. Must revist this if this + * changes, however */ + return sx_sasl_ret_OK; + break; - if(strcmp(creds->authnid, creds->authzid) != 0) { - log_debug(ZONE, "authnid '%s' doesn't match authzid '%s'", creds->authnid, creds->authzid); - return 1; - } - return 0; + case sx_sasl_cb_CHECK_MECH: + + if (strcasecmp((char *)arg,"DIGEST-MD5")==0) + return sx_sasl_ret_OK; + + return sx_sasl_ret_FAIL; + break; default: break; @@ -391,7 +399,7 @@ #endif /* get sasl online */ - r->sx_sasl = sx_env_plugin(r->sx_env, sx_sasl_init, _router_sx_sasl_callback, (void *) r, sd_flag_GET_PASS); + r->sx_sasl = sx_env_plugin(r->sx_env, sx_sasl_init, "jabberd-router", SASL_SEC_NOANONYMOUS, _router_sx_sasl_callback, (void *) r, 0); if(r->sx_sasl == NULL) { log_write(r->log, LOG_ERR, "failed to initialise SASL context, aborting"); exit(1); Only in jabberd-2.0s9-sasl/router: main.c.orig diff -ur jabberd-2.0s9/router/Makefile.am jabberd-2.0s9-sasl/router/Makefile.am --- jabberd-2.0s9/router/Makefile.am 2004-04-08 07:51:19.000000000 +0100 +++ jabberd-2.0s9-sasl/router/Makefile.am 2005-07-27 23:23:14.000000000 +0100 @@ -6,7 +6,6 @@ router_SOURCES = aci.c main.c router.c user.c router_LDADD = $(top_builddir)/sx/libsx.la \ - $(top_builddir)/scod/libscod.la \ $(top_builddir)/mio/libmio.la \ $(top_builddir)/util/libutil.la \ $(top_builddir)/subst/libsubst.la \ diff -ur jabberd-2.0s9/router/router.c jabberd-2.0s9-sasl/router/router.c --- jabberd-2.0s9/router/router.c 2005-04-14 17:10:57.000000000 +0100 +++ jabberd-2.0s9-sasl/router/router.c 2005-07-27 23:23:14.000000000 +0100 @@ -916,9 +916,9 @@ xhash_put(r->components, comp->ipport, (void *) comp); #ifdef HAVE_SSL - sx_server_init(comp->s, SX_SSL_STARTTLS_OFFER | SX_SASL_OFFER | SX_SASL_MECH_PLAIN | SX_SASL_MECH_DIGESTMD5); + sx_server_init(comp->s, SX_SSL_STARTTLS_OFFER | SX_SASL_OFFER); #else - sx_server_init(comp->s, SX_SASL_OFFER | SX_SASL_MECH_PLAIN | SX_SASL_MECH_DIGESTMD5); + sx_server_init(comp->s, SX_SASL_OFFER); #endif break; diff -ur jabberd-2.0s9/s2s/main.c jabberd-2.0s9-sasl/s2s/main.c --- jabberd-2.0s9/s2s/main.c 2005-06-02 05:47:18.000000000 +0100 +++ jabberd-2.0s9-sasl/s2s/main.c 2005-07-27 23:23:14.000000000 +0100 @@ -500,7 +500,7 @@ #endif /* get sasl online */ - s2s->sx_sasl = sx_env_plugin(s2s->sx_env, sx_sasl_init, NULL, NULL, 0); + s2s->sx_sasl = sx_env_plugin(s2s->sx_env, sx_sasl_init, "xmpp", SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT, NULL, NULL, 0); if(s2s->sx_sasl == NULL) { log_write(s2s->log, LOG_ERR, "failed to initialise SASL context, aborting"); exit(1); diff -ur jabberd-2.0s9/s2s/Makefile.am jabberd-2.0s9-sasl/s2s/Makefile.am --- jabberd-2.0s9/s2s/Makefile.am 2004-04-08 07:51:21.000000000 +0100 +++ jabberd-2.0s9-sasl/s2s/Makefile.am 2005-07-27 23:23:14.000000000 +0100 @@ -6,7 +6,6 @@ s2s_SOURCES = in.c main.c out.c router.c sx.c util.c s2s_LDADD = $(top_builddir)/sx/libsx.la \ - $(top_builddir)/scod/libscod.la \ $(top_builddir)/mio/libmio.la \ $(top_builddir)/util/libutil.la \ $(top_builddir)/subst/libsubst.la \ diff -ur jabberd-2.0s9/s2s/router.c jabberd-2.0s9-sasl/s2s/router.c --- jabberd-2.0s9/s2s/router.c 2005-01-07 11:46:30.000000000 +0000 +++ jabberd-2.0s9-sasl/s2s/router.c 2005-07-27 23:23:14.000000000 +0100 @@ -159,7 +159,7 @@ * if there isn't an appropriate one, error and bail */ /* authenticate */ - sx_sasl_auth(s2s->sx_sasl, s, "DIGEST-MD5", s2s->router_user, s2s->router_pass, NULL); + sx_sasl_auth(s2s->sx_sasl, s, "jabberd-router", "DIGEST-MD5", s2s->router_user, s2s->router_pass); nad_free(nad); return 0; diff -ur jabberd-2.0s9/sm/main.c jabberd-2.0s9-sasl/sm/main.c --- jabberd-2.0s9/sm/main.c 2005-06-02 06:01:02.000000000 +0100 +++ jabberd-2.0s9-sasl/sm/main.c 2005-07-27 23:23:14.000000000 +0100 @@ -313,7 +313,7 @@ #endif /* get sasl online */ - sm->sx_sasl = sx_env_plugin(sm->sx_env, sx_sasl_init, NULL, NULL, 0); + sm->sx_sasl = sx_env_plugin(sm->sx_env, sx_sasl_init, "xmpp", SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT, NULL, NULL, 0); if(sm->sx_sasl == NULL) { log_write(sm->log, LOG_ERR, "failed to initialise SASL context, aborting"); exit(1); Only in jabberd-2.0s9-sasl/sm: main.c.orig diff -ur jabberd-2.0s9/sm/Makefile.am jabberd-2.0s9-sasl/sm/Makefile.am --- jabberd-2.0s9/sm/Makefile.am 2005-06-02 06:57:54.000000000 +0100 +++ jabberd-2.0s9-sasl/sm/Makefile.am 2005-07-27 23:23:14.000000000 +0100 @@ -43,7 +43,6 @@ mod_template_roster.c sm_LDADD = $(top_builddir)/sx/libsx.la \ - $(top_builddir)/scod/libscod.la \ $(top_builddir)/mio/libmio.la \ $(top_builddir)/util/libutil.la \ $(top_builddir)/subst/libsubst.la \ Only in jabberd-2.0s9-sasl/sm: Makefile.am.orig diff -ur jabberd-2.0s9/sm/sm.c jabberd-2.0s9-sasl/sm/sm.c --- jabberd-2.0s9/sm/sm.c 2005-01-07 11:46:52.000000000 +0000 +++ jabberd-2.0s9-sasl/sm/sm.c 2005-07-27 23:23:14.000000000 +0100 @@ -163,7 +163,7 @@ * if there isn't an appropriate one, error and bail */ /* authenticate */ - sx_sasl_auth(sm->sx_sasl, s, "DIGEST-MD5", sm->router_user, sm->router_pass, NULL); + sx_sasl_auth(sm->sx_sasl, s, "jabberd-router", "DIGEST-MD5", sm->router_user, sm->router_pass); nad_free(nad); return 0; diff -ur jabberd-2.0s9/sx/sasl.c jabberd-2.0s9-sasl/sx/sasl.c --- jabberd-2.0s9/sx/sasl.c 2005-07-26 08:32:48.000000000 +0100 +++ jabberd-2.0s9-sasl/sx/sasl.c 2005-07-27 23:23:14.000000000 +0100 @@ -23,7 +23,11 @@ #include "sx.h" #include "ssl.h" #include "sasl.h" +/* Gack - need this otherwise SASL's MD5 definitions conflict with OpenSSLs */ +#define MD5_H +#include +/* RFC 3290 defines a number of failure messages */ #define _sasl_err_ABORTED "aborted" #define _sasl_err_INCORRECT_ENCODING "incorrect-encoding" #define _sasl_err_INVALID_AUTHZID "invalid-authzid" @@ -32,47 +36,386 @@ #define _sasl_err_NOT_AUTHORIZED "not-authorized" #define _sasl_err_TEMPORARY_FAILURE "temporary-auth-failure" +/* Forward definitions */ +static void _sx_sasl_free(sx_t, sx_plugin_t); + +/* Support auxprop so that we can use the standard Jabber authreg plugins + * with SASL mechanisms requiring passwords + */ +static void _sx_auxprop_lookup(void *glob_context, + sasl_server_params_t *sparams, + unsigned flags, + const char *user, + unsigned ulen) { + char *userid = NULL; + char *realm = NULL; + int ret; + const struct propval *to_fetch, *current; + char *user_buf = NULL; + char *value; + _sx_sasl_t ctx = (_sx_sasl_t) glob_context; + struct sx_sasl_creds_st creds = {NULL, NULL, NULL, NULL}; + + if (!sparams || !user) + return; + + /* It would appear that there's no guarantee that 'user' is NULL + * terminated, so we'd better terminate it ... + */ + + user_buf = sparams->utils->malloc(ulen + 1); + if (!user_buf) + goto done; + + memcpy(user_buf, user, ulen); + user_buf[ulen] = '\0'; + + /* Parse the supplied username, splitting it into user and realm + * components. I suspect that 'parseuser' isn't actually part of the + * exported API, so maybe we should reimplement this. */ + + ret = _plug_parseuser(sparams->utils, &userid, &realm, + sparams->user_realm?sparams->user_realm: + sparams->serverFQDN, + user_buf); + if (ret != SASL_OK) + goto done; + + + /* At present, we only handle fetching the user's password */ + to_fetch = sparams->utils->prop_get(sparams->propctx); + if (!to_fetch) + goto done; + for (current = to_fetch; current->name; current++) { + if (strcmp(current->name, SASL_AUX_PASSWORD) == 0) { + /* If we've already got a value, see if we can override it */ + if (current->values) { + if (flags & SASL_AUXPROP_OVERRIDE) + sparams->utils->prop_erase(sparams->propctx, current->name); + else + continue; + } + + /* Do the lookup, returning the results into value and value_len */ + if (strcmp(SASL_AUX_PASSWORD_PROP, current->name)) { + creds.authnid = userid; + creds.realm = realm; + if ((ctx->cb)(sx_sasl_cb_GET_PASS, &creds, (void **)&value, + NULL, ctx->cbarg) == sx_sasl_ret_OK) { + sparams->utils->prop_set(sparams->propctx, current->name, + value, strlen(value)); + } + } + } + } + done: + if (userid) sparams->utils->free(userid); + if (realm) sparams->utils->free(realm); + if (user_buf) sparams->utils->free(user_buf); +} + +static sasl_auxprop_plug_t _sx_auxprop_plugin = + {0, 0, NULL, NULL, _sx_auxprop_lookup, "jabberdsx", NULL}; + +static int +sx_auxprop_init(const sasl_utils_t *utils, int max_version, int *out_version, + sasl_auxprop_plug_t **plug, const char *plugname) { + + if (!out_version || !plug) + return SASL_BADPARAM; + if (max_version < SASL_AUXPROP_PLUG_VERSION ) + return SASL_BADVERS; + + *out_version = SASL_AUXPROP_PLUG_VERSION; + *plug = &_sx_auxprop_plugin; + + return SASL_OK; +} + +/* This handles those authreg plugins which won't provide plaintext access + * to the user's password. Note that there are very few mechanisms which + * call the verify function, rather than asking for the password + */ +static int _sx_sasl_checkpass(sasl_conn_t *conn, void *ctx, const char *user, const char *pass, unsigned passlen, struct propctx *propctx) { + _sx_sasl_data_t sd = (_sx_sasl_data_t)ctx; + struct sx_sasl_creds_st creds = {NULL, NULL, NULL, NULL}; + + creds.authnid = user; + creds.pass = pass; + + if (sd->ctx->cb(sx_sasl_cb_CHECK_PASS, &creds, NULL, sd->stream, sd->ctx->cbarg)==sx_sasl_ret_OK) { + return SASL_OK; + } else { + return SASL_BADAUTH; + } +} + +/* Canonicalize the username. Normally this does nothing, but if we're + * calling from an anonymous plugin, then we need to generate a JID for + * the user + */ + +static int _sx_sasl_canon_user(sasl_conn_t *conn, void *ctx, const char *user, unsigned ulen, unsigned flags, const char *user_realm, char *out_user, unsigned out_umax, unsigned *out_ulen) { + char *buf; + _sx_sasl_data_t sd = (_sx_sasl_data_t)ctx; + sasl_getprop(conn, SASL_MECHNAME, (const void **) &buf); + if (strcmp(buf, "ANONYMOUS") == 0) { + sd->ctx->cb(sx_sasl_cb_GEN_AUTHZID, NULL, (void **)&buf, sd->stream, sd->ctx->cbarg); + strncpy(out_user, buf, out_umax); + out_user[out_umax]='\0'; + *out_ulen=strlen(out_user); + } else { + memcpy(out_user,user,ulen); + *out_ulen = ulen; + } + return SASL_OK; +} + +/* Need to make sure that + * *) The authnid is permitted to become the given authzid + * *) The authnid is included in the given authreg systems DB + */ +static int _sx_sasl_proxy_policy(sasl_conn_t *conn, void *ctx, const char *requested_user, int rlen, const char *auth_identity, int alen, const char *realm, int urlen, struct propctx *propctx) { + _sx_sasl_data_t sd = (_sx_sasl_data_t) ctx; + struct sx_sasl_creds_st creds = {NULL, NULL, NULL, NULL}; + char *buf; + + sasl_getprop(conn, SASL_MECHNAME, (const void **) &buf); + if (strcmp(buf, "ANONYMOUS") == 0) { + /* If they're anonymous, their ID comes from us, so it must be OK! */ + return SASL_OK; + } else { + if (!requested_user || !auth_identity || alen != rlen || + (memcmp(requested_user, auth_identity, rlen) !=0)) { + sasl_seterror(conn, 0, + "Requested identity is not authenticated identity"); + return SASL_BADAUTH; + } + creds.authnid = auth_identity; + creds.realm = realm; + creds.authzid = requested_user; + /* If we start being fancy and allow auth_identity to be different from + * requested_user, then this will need to be changed to permit it! + */ + if ((sd->ctx->cb)(sx_sasl_cb_CHECK_AUTHZID, &creds, NULL, sd->stream, sd->ctx->cbarg)==sx_sasl_ret_OK) + return SASL_OK; + else + return SASL_BADAUTH; + } +} + +static int _sx_sasl_wio(sx_t s, sx_plugin_t p, sx_buf_t buf) { + sasl_conn_t *sasl; + int *x, len, pos, reslen, maxbuf; + char *out, *result; + + sasl = ((_sx_sasl_data_t) s->plugin_data[p->index])->sasl; + + /* if there's no security layer, don't bother */ + sasl_getprop(sasl, SASL_SSF, (const void **) &x); + if(*x == 0) + return 1; + + _sx_debug(ZONE, "doing sasl encode"); + + /* can only encode x bytes at a time */ + sasl_getprop(sasl, SASL_MAXOUTBUF, (const void **) &x); + maxbuf = *x; + + /* encode the output */ + pos = 0; + result = NULL; reslen = 0; + while(pos < buf->len) { + if((buf->len - pos) < maxbuf) + maxbuf = buf->len - pos; + + sasl_encode(sasl, &buf->data[pos], maxbuf, (const char **) &out, &len); + + result = (char *) realloc(result, sizeof(char) * (reslen + len)); + memcpy(&result[reslen], out, len); + reslen += len; + + pos += maxbuf; + } + + /* replace the buffer */ + _sx_buffer_set(buf, result, reslen, result); + + _sx_debug(ZONE, "%d bytes encoded for sasl channel", buf->len); + + return 1; +} + +static int _sx_sasl_rio(sx_t s, sx_plugin_t p, sx_buf_t buf) { + sasl_conn_t *sasl; + int *x, len; + char *out; + + sasl = ((_sx_sasl_data_t) s->plugin_data[p->index])->sasl; + + /* if there's no security layer, don't bother */ + sasl_getprop(sasl, SASL_SSF, (const void **) &x); + if(*x == 0) + return 1; + + _sx_debug(ZONE, "doing sasl decode"); + + /* decode the input */ + sasl_decode(sasl, buf->data, buf->len, (const char **) &out, &len); + + /* replace the buffer */ + _sx_buffer_set(buf, out, len, NULL); + + _sx_debug(ZONE, "%d bytes decoded from sasl channel", len); + + return 1; +} + /** move the stream to the auth state */ -void _sx_sasl_open(sx_t s, scod_t sd) { +void _sx_sasl_open(sx_t s, sasl_conn_t *sasl) { char *method; + char *buf; + int *ssf; /* get the method */ - method = (char *) malloc(sizeof(char) * (strlen(sd->mech->name) + 6)); - sprintf(method, "SASL/%s", sd->mech->name); + sasl_getprop(sasl, SASL_MECHNAME, (const void **) &buf); + + method = (char *) malloc(sizeof(char) * (strlen(buf) + 17)); + sprintf(method, "SASL/%s", buf); + + /* get the ssf */ + if(s->ssf == 0) { + sasl_getprop(sasl, SASL_SSF, (const void **) &ssf); + s->ssf = *ssf; + } + /* and the authenticated id */ + sasl_getprop(sasl, SASL_USERNAME, (const void **) &buf); + /* schwing! */ - sx_auth(s, method, sd->authzid); + sx_auth(s, method, buf); free(method); } /** make the stream suthenticated second time round */ static void _sx_sasl_stream(sx_t s, sx_plugin_t p) { - scod_t sd = (scod_t) s->plugin_data[p->index]; + _sx_sasl_t ctx = (_sx_sasl_t) p->private; + sasl_conn_t *sasl; + _sx_sasl_data_t sd; + int ret, i; + char *realm, *ext_id, *mech; + sasl_security_properties_t sec_props; + + /* First time around, we need to set up our SASL connection, otherwise + * features will fall flat on its face */ + if (s->plugin_data[p->index] == NULL) { + if(s->type == type_SERVER) { + + if(!(s->flags & SX_SASL_OFFER)) { + _sx_debug(ZONE, "application did not request sasl offer, not offering for this conn"); + return; + } + + _sx_debug(ZONE, "setting up sasl for this server conn"); + + /* Initialise our data object */ + sd = (_sx_sasl_data_t) malloc(sizeof(struct _sx_sasl_data_st)); + memset(sd, 0, sizeof(struct _sx_sasl_data_st)); + + /* get the realm */ + if(ctx->cb != NULL) + (ctx->cb)(sx_sasl_cb_GET_REALM, NULL, (void **) &realm, s, ctx->cbarg); + + /* Initialize our callbacks */ + sd->callbacks = calloc(sizeof(sasl_callback_t),4); + + sd->callbacks[0].id = SASL_CB_PROXY_POLICY; + sd->callbacks[0].proc = &_sx_sasl_proxy_policy; + sd->callbacks[0].context = sd; + + sd->callbacks[1].id = SASL_CB_CANON_USER; + sd->callbacks[1].proc = &_sx_sasl_canon_user; + sd->callbacks[1].context = sd; + + sd->callbacks[2].id = SASL_CB_SERVER_USERDB_CHECKPASS; + sd->callbacks[2].proc = &_sx_sasl_checkpass; + sd->callbacks[2].context = sd; + + sd->callbacks[3].id = SASL_CB_LIST_END; + + /* startup */ + ret = sasl_server_new(ctx->appname, NULL, + realm[0] == '\0' ? NULL : realm, + NULL, NULL, NULL, + ctx->sec_props.security_flags, &sasl); + if(ret != SASL_OK) { + _sx_debug(ZONE, "sasl_server_new failed (%s), not offering sasl for this conn", sasl_errstring(ret, NULL, NULL)); + return; + } + + /* get external data from the ssl plugin */ + ext_id = NULL; + for(i = 0; i < s->env->nplugins; i++) + if(s->env->plugins[i]->magic == SX_SASL_SSL_MAGIC) + ext_id = (char *) s->plugin_data[s->env->plugins[i]->index]; + + /* if we've got some, setup for external auth */ + ret = SASL_OK; + if(ext_id != NULL) { + ret = sasl_setprop(sasl, SASL_AUTH_EXTERNAL, ext_id); + if(ret == SASL_OK) + ret = sasl_setprop(sasl, SASL_SSF_EXTERNAL, &s->ssf); + } + + /* security properties */ + sec_props = ctx->sec_props; + if(s->ssf > 0) + /* if we're already encrypted, then no security layers */ + sec_props.max_ssf = 0; + + if(ret == SASL_OK) + ret = sasl_setprop(sasl, SASL_SEC_PROPS, &sec_props); + + if(ret != SASL_OK) { + _sx_debug(ZONE, "sasl_setprop failed (%s), not offering sasl for this conn", sasl_errstring(ret, NULL, NULL)); + return; + } + + sd->sasl = sasl; + sd->stream = s; + sd->ctx = ctx; + + _sx_debug(ZONE, "sasl context initialised for %d", s->tag); + + s->plugin_data[p->index] = (void *) sd; + + } - /* do nothing the first time */ - if(sd == NULL) return; + } + + sasl = ((_sx_sasl_data_t) s->plugin_data[p->index])->sasl; /* are we auth'd? */ - if(!sd->authd) { + if (sasl_getprop(sasl, SASL_MECHNAME, (void *) &mech) == SASL_NOTDONE) { _sx_debug(ZONE, "not auth'd, not advancing to auth'd state yet"); return; } /* otherwise, its auth time */ - _sx_sasl_open(s, sd); + _sx_sasl_open(s, sasl); } static void _sx_sasl_features(sx_t s, sx_plugin_t p, nad_t nad) { - _sx_sasl_t ctx = (_sx_sasl_t) p->private; - scod_t sd = (scod_t) s->plugin_data[p->index]; - int i, ns; + _sx_sasl_data_t sd = (_sx_sasl_data_t) s->plugin_data[p->index]; + int ret, nmechs, ns; + char *mechs, *mech, *c; - if(s->type != type_SERVER) + if(s->type != type_SERVER || sd == NULL || sd->sasl == NULL) return; - if(sd != NULL && sd->authd) { + if((ret = sasl_getprop(sd->sasl, SASL_MECHNAME, (void *) &mech)) != SASL_NOTDONE) { _sx_debug(ZONE, "already auth'd, not offering sasl mechanisms"); return; } @@ -82,11 +425,6 @@ return; } - if(!(s->flags & SX_SASL_MECH_ANONYMOUS || s->flags & SX_SASL_MECH_PLAIN || s->flags & SX_SASL_MECH_DIGESTMD5)) { - _sx_debug(ZONE, "application didn't provide any mechanisms we can offer"); - return; - } - #ifdef HAVE_SSL if((s->flags & SX_SSL_STARTTLS_REQUIRE) && s->ssf == 0) { _sx_debug(ZONE, "ssl not established yet but the app requires it, not offering mechanisms"); @@ -95,21 +433,44 @@ #endif _sx_debug(ZONE, "offering sasl mechanisms"); - - ns = nad_add_namespace(nad, uri_SASL, NULL); - nad_append_elem(nad, ns, "mechanisms", 1); - for(i = 0; i < ctx->scod_ctx->nmechs; i++) - if(ctx->scod_ctx->mechs[i]->flags == 0 || ctx->flags & ctx->scod_ctx->mechs[i]->flags) { - if((s->flags & SX_SASL_MECH_ANONYMOUS && strcmp("ANONYMOUS", ctx->scod_ctx->names[i]) == 0) || - (s->flags & SX_SASL_MECH_PLAIN && strcmp("PLAIN", ctx->scod_ctx->names[i]) == 0) || - (s->flags & SX_SASL_MECH_DIGESTMD5 && strcmp("DIGEST-MD5", ctx->scod_ctx->names[i]) == 0)) { - _sx_debug(ZONE, "offering mechanism: %s", ctx->scod_ctx->names[i]); + ret = sasl_listmech(sd->sasl, NULL, "", "|", "", (const char **) &mechs, NULL, &nmechs); + if(ret != SASL_OK) { + _sx_debug(ZONE, "sasl_listmech failed (%s), not offering sasl for this conn", sasl_errstring(ret, NULL, NULL)); + _sx_sasl_free(s,p); + return; + } + + if(nmechs <= 0) { + _sx_debug(ZONE, "sasl_listmech returned no mechanisms, not offering sasl for this conn"); + _sx_sasl_free(s,p); + return; + } - nad_append_elem(nad, ns, "mechanism", 2); - nad_append_cdata(nad, ctx->scod_ctx->names[i], strlen(ctx->scod_ctx->names[i]), 3); + mech = mechs; + nmechs = 0; + while(mech != NULL) { + c = strchr(mech, '|'); + if(c != NULL) + *c = '\0'; + + if ((sd->ctx->cb)(sx_sasl_cb_CHECK_MECH, mech, NULL, sd->stream, sd->ctx->cbarg)==sx_sasl_ret_OK) { + if (nmechs == 0) { + ns = nad_add_namespace(nad, uri_SASL, NULL); + nad_append_elem(nad, ns, "mechanisms", 1); } + _sx_debug(ZONE, "offering mechanism: %s", mech); + + nad_append_elem(nad, ns, "mechanism", 2); + nad_append_cdata(nad, mech, strlen(mech), 3); + nmechs++; } + + if(c == NULL) + mech = NULL; + else + mech = ++c; + } } /** utility: generate a success nad */ @@ -200,6 +561,9 @@ /** auth done, restart the stream */ static void _sx_sasl_notify_success(sx_t s, void *arg) { + sx_plugin_t p = (sx_plugin_t) arg; + + _sx_chain_io_plugin(s, p); _sx_debug(ZONE, "auth completed, resetting"); _sx_reset(s); @@ -208,63 +572,32 @@ } /** process handshake packets from the client */ -static void _sx_sasl_client_process(sx_t s, sx_plugin_t p, scod_t sd, char *mech, char *in, int inlen) { - _sx_sasl_t ctx = (_sx_sasl_t) p->private; - char realm[256]; +static void _sx_sasl_client_process(sx_t s, sx_plugin_t p, char *mech, char *in, int inlen) { + _sx_sasl_data_t sd = (_sx_sasl_data_t) s->plugin_data[p->index]; char *buf, *out; int buflen, outlen, ret; if(mech != NULL) { _sx_debug(ZONE, "auth request from client (mechanism=%s)", mech); - - if(!((s->flags & SX_SASL_MECH_ANONYMOUS && strcmp("ANONYMOUS", mech) == 0) || - (s->flags & SX_SASL_MECH_PLAIN && strcmp("PLAIN", mech) == 0) || - (s->flags & SX_SASL_MECH_DIGESTMD5 && strcmp("DIGEST-MD5", mech) == 0))) { - _sx_debug(ZONE, "client requested mechanism that we didn't offer"); - _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_INVALID_MECHANISM), 0); - return; - } - - /* startup */ - sd = scod_new(ctx->scod_ctx, sd_type_SERVER); - if(sd == NULL) { - _sx_debug(ZONE, "scod_new failed, no sasl for this conn"); - _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_TEMPORARY_FAILURE), 0); - return; - } - - _sx_debug(ZONE, "sasl context initialised for %d", s->tag); - - s->plugin_data[p->index] = (void *) sd; - - sd->app_private = (void *) s; - - /* get the realm */ - realm[0] = '\0'; - assert((int) ctx->cb); - (ctx->cb)(sx_sasl_cb_GET_REALM, (void *) s, (void **) realm, sd, ctx->cbarg); - - /* decode and process */ - _sx_sasl_decode(in, inlen, &buf, &buflen); - ret = scod_server_start(sd, mech, realm, buf, buflen, &out, &outlen); + } else { + _sx_debug(ZONE, "response from client"); } - else { - _sx_debug(ZONE, "response from client"); + /* decode the response */ + _sx_sasl_decode(in, inlen, &buf, &buflen); - /* decode and process */ - _sx_sasl_decode(in, inlen, &buf, &buflen); - ret = scod_server_step(sd, buf, buflen, &out, &outlen); - } + /* process the data */ + if(mech != NULL) + ret = sasl_server_start(sd->sasl, mech, buf, buflen, (const char **) &out, &outlen); + else + ret = sasl_server_step(sd->sasl, buf, buflen, (const char **) &out, &outlen); if(buf != NULL) free(buf); /* auth completed */ - if(ret == sd_SUCCESS) { + if(ret == SASL_OK) { _sx_debug(ZONE, "sasl handshake completed"); - if(out != NULL) free(out); - /* send success */ _sx_nad_write(s, _sx_sasl_success(s), 0); @@ -276,13 +609,11 @@ } /* in progress */ - if(ret == sd_CONTINUE) { + if(ret == SASL_CONTINUE) { _sx_debug(ZONE, "sasl handshake in progress (challenge: %.*s)", outlen, out); /* encode the challenge */ _sx_sasl_encode(out, outlen, &buf, &buflen); - - if(out != NULL) free(out); _sx_nad_write(s, _sx_sasl_challenge(s, buf, buflen), 0); @@ -291,19 +622,22 @@ return; } - if(out != NULL) free(out); - /* its over */ - _sx_debug(ZONE, "sasl handshake failed: (%d)", ret); + buf = (char *) sasl_errdetail(sd->sasl); + if(buf == NULL) + buf = "[no error message available]"; + + _sx_debug(ZONE, "sasl handshake failed: %s", buf); - /* !!! check ret and flag error appropriately */ _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_TEMPORARY_FAILURE), 0); } /** process handshake packets from the server */ -static void _sx_sasl_server_process(sx_t s, sx_plugin_t p, scod_t sd, char *in, int inlen) { +static void _sx_sasl_server_process(sx_t s, sx_plugin_t p, char *in, int inlen) { + _sx_sasl_data_t sd = (_sx_sasl_data_t)s->plugin_data[p->index]; char *buf, *out; int buflen, outlen, ret; + const char *err_buf; _sx_debug(ZONE, "challenge from client"); @@ -311,18 +645,16 @@ _sx_sasl_decode(in, inlen, &buf, &buflen); /* process the data */ - ret = scod_client_step(sd, buf, buflen, &out, &outlen); + ret = sasl_client_step(sd->sasl, buf, buflen, NULL, (const char **) &out, &outlen); if(buf != NULL) free(buf); /* in progress */ - if(ret == sd_SUCCESS || ret == sd_CONTINUE) { + if(ret == SASL_OK || ret == SASL_CONTINUE) { _sx_debug(ZONE, "sasl handshake in progress (response: %.*s)", outlen, out); /* encode the response */ _sx_sasl_encode(out, outlen, &buf, &buflen); - if(out != NULL) free(out); - _sx_nad_write(s, _sx_sasl_response(s, buf, buflen), 0); if(buf != NULL) free(buf); @@ -330,17 +662,19 @@ return; } - if(out != NULL) free(out); - /* its over */ - _sx_debug(ZONE, "sasl handshake aborted: (%d)", ret); + err_buf = sasl_errdetail(sd->sasl); + if (err_buf == NULL) + err_buf = "[no error message available]"; + + _sx_debug(ZONE, "sasl handshake aborted: %s", err_buf); _sx_nad_write(s, _sx_sasl_abort(s), 0); } /** main nad processor */ static int _sx_sasl_process(sx_t s, sx_plugin_t p, nad_t nad) { - scod_t sd = (scod_t) s->plugin_data[p->index]; + _sx_sasl_data_t sd = (_sx_sasl_data_t)s->plugin_data[p->index]; int attr; char mech[128]; sx_error_t sxe; @@ -352,7 +686,7 @@ return 1; /* quietly drop it if sasl is disabled, or if not ready */ - if(s->state != state_STREAM) { + if(s->state != state_STREAM || sd == NULL) { _sx_debug(ZONE, "not correct state for sasl, ignoring"); nad_free(nad); return 0; @@ -387,7 +721,7 @@ snprintf(mech, 127, "%.*s", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr)); /* go */ - _sx_sasl_client_process(s, p, sd, mech, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0)); + _sx_sasl_client_process(s, p, mech, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0)); nad_free(nad); return 0; @@ -396,7 +730,7 @@ /* response */ else if(NAD_ENAME_L(nad, 0) == 8 && strncmp("response", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) { /* process it */ - _sx_sasl_client_process(s, p, sd, NULL, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0)); + _sx_sasl_client_process(s, p, NULL, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0)); nad_free(nad); return 0; @@ -424,7 +758,7 @@ /* challenge */ if(NAD_ENAME_L(nad, 0) == 9 && strncmp("challenge", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) { /* process it */ - _sx_sasl_server_process(s, p, sd, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0)); + _sx_sasl_server_process(s, p, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0)); nad_free(nad); return 0; @@ -444,6 +778,9 @@ if(s->req_from != NULL) from = strdup(s->req_from); if(s->req_version != NULL) version = strdup(s->req_version); + /* setup the encoder */ + _sx_chain_io_plugin(s, p); + /* reset state */ _sx_reset(s); @@ -468,9 +805,7 @@ _sx_event(s, event_ERROR, (void *) &sxe); /* cleanup */ - scod_free(sd); - - s->plugin_data[p->index] = NULL; + _sx_sasl_free(s,p); nad_free(nad); return 0; @@ -486,90 +821,85 @@ /** cleanup */ static void _sx_sasl_free(sx_t s, sx_plugin_t p) { - scod_t sd = (scod_t) s->plugin_data[p->index]; + _sx_sasl_data_t sd = (_sx_sasl_data_t) s->plugin_data[p->index]; if(sd == NULL) return; _sx_debug(ZONE, "cleaning up conn state"); - scod_free(sd); - s->plugin_data[p->index] = NULL; -} + if(sd->sasl != NULL) sasl_dispose(&sd->sasl); + if(sd->user != NULL) free(sd->user); + if(sd->psecret != NULL) free(sd->psecret); -static int _sx_sasl_scod_callback(scod_t sd, int cb, void *arg, void **res, void *cbarg) { - _sx_sasl_t ctx = (_sx_sasl_t) cbarg; - xht realms; - - switch(cb) { - case sd_cb_DIGEST_MD5_CHOOSE_REALM: - realms = (xht) arg; - if(xhash_iter_first(realms)) - xhash_iter_get(realms, (const char **) res, NULL); - else - *res = NULL; - break; - - case sd_cb_GET_PASS: - assert((int) ctx->cb); - return (ctx->cb)(sx_sasl_cb_GET_PASS, arg, res, sd, ctx->cbarg); - - case sd_cb_CHECK_PASS: - assert((int) ctx->cb); - return (ctx->cb)(sx_sasl_cb_CHECK_PASS, arg, res, sd, ctx->cbarg); - - case sd_cb_CHECK_AUTHZID: - assert((int) ctx->cb); - return (ctx->cb)(sx_sasl_cb_CHECK_AUTHZID, arg, res, sd, ctx->cbarg); - - case sd_cb_ANONYMOUS_GEN_AUTHZID: - assert((int) ctx->cb); - return (ctx->cb)(sx_sasl_cb_GEN_AUTHZID, arg, res, sd, ctx->cbarg); - - default: - break; - } + free(sd); - return 0; + s->plugin_data[p->index] = NULL; } static void _sx_sasl_unload(sx_plugin_t p) { - scod_ctx_free( ((_sx_sasl_t) p->private)->scod_ctx); - free(p->private); + + if (p->private) + free(p->private); } -/** args: realm callback, cb arg, scod flags */ +/** args: appname, flags, callback, cb arg */ int sx_sasl_init(sx_env_t env, sx_plugin_t p, va_list args) { + char *appname; + int flags; sx_sasl_callback_t cb; void *cbarg; - int flags; + int ret; _sx_sasl_t ctx; _sx_debug(ZONE, "initialising sasl plugin"); + appname = va_arg(args, char *); + if(appname == NULL) { + _sx_debug(ZONE, "appname was NULL, failing"); + return 1; + } + + flags = va_arg(args, int); + cb = va_arg(args, sx_sasl_callback_t); cbarg = va_arg(args, void *); - flags = va_arg(args, int); + + /* Set up the auxiliary property plugin, which we use to gave SASL + * mechanism plugins access to our passwords + */ + sasl_auxprop_add_plugin("jabbersx", sx_auxprop_init); ctx = (_sx_sasl_t) malloc(sizeof(struct _sx_sasl_st)); memset(ctx, 0, sizeof(struct _sx_sasl_st)); + ctx->appname = strdup(appname); + + ctx->sec_props.min_ssf = 0; + ctx->sec_props.max_ssf = -1; /* sasl_ssf_t is typedef'd to unsigned, so -1 gets us the max possible ssf */ + ctx->sec_props.maxbufsize = 1024; + ctx->sec_props.security_flags = flags; + ctx->cb = cb; ctx->cbarg = cbarg; - ctx->flags = flags; + + /* Push the location of our callbacks into the auxprop structure */ + + _sx_auxprop_plugin.glob_context = (void *) ctx; - ctx->scod_ctx = scod_ctx_new(_sx_sasl_scod_callback, ctx); - if(ctx->scod_ctx == NULL) { - _sx_debug(ZONE, "couldn't create scod context, disabling"); - free(ctx); + ret = sasl_server_init(NULL, appname); + if(ret != SASL_OK) { + _sx_debug(ZONE, "sasl_server_init() failed (%s), disabling", sasl_errstring(ret, NULL, NULL)); return 1; } - _sx_debug(ZONE, "sasl context initialised"); + _sx_debug(ZONE, "sasl context initialised; appname=%s", appname); p->private = (void *) ctx; p->unload = _sx_sasl_unload; + p->wio = _sx_sasl_wio; + p->rio = _sx_sasl_rio; p->stream = _sx_sasl_stream; p->features = _sx_sasl_features; @@ -580,19 +910,48 @@ return 0; } +/* callback functions for client auth */ +static int _sx_sasl_cb_get_simple(void *ctx, int id, const char **result, unsigned *len) +{ + _sx_sasl_data_t sd = (_sx_sasl_data_t) ctx; + + _sx_debug(ZONE, "in _sx_sasl_cb_get_simple (id 0x%x)", id); + + *result = sd->user; + if(len != NULL) + *len = strlen(*result); + + return SASL_OK; +} + +static int _sx_sasl_cb_get_secret(sasl_conn_t *conn, void *ctx, int id, sasl_secret_t **psecret) +{ + _sx_sasl_data_t sd = (_sx_sasl_data_t) ctx; + + _sx_debug(ZONE, "in _sx_sasl_cb_get_secret (id 0x%x)", id); + + /* sanity check */ + if(conn == NULL || psecret == NULL || id != SASL_CB_PASS) + return SASL_BADPARAM; + + *psecret = sd->psecret; + + return SASL_OK; +} + /** kick off the auth handshake */ -int sx_sasl_auth(sx_plugin_t p, sx_t s, char *mech, char *user, char *pass, char *authzid) { +int sx_sasl_auth(sx_plugin_t p, sx_t s, char *appname, char *mech, char *user, char *pass) { _sx_sasl_t ctx = (_sx_sasl_t) p->private; - scod_t sd; - char *buf, *out; - int ret, buflen, outlen, ns; + _sx_sasl_data_t sd; + char *buf, *out, *ext_id; + int i, ret, buflen, outlen, ns; + sasl_security_properties_t sec_props; nad_t nad; assert((int) p); assert((int) s); + assert((int) appname); assert((int) mech); - assert((int) user); - assert((int) pass); if(s->type != type_CLIENT || s->state != state_STREAM) { _sx_debug(ZONE, "need client in stream state for sasl auth"); @@ -600,20 +959,108 @@ } /* startup */ - sd = scod_new(ctx->scod_ctx, sd_type_CLIENT); - if(sd == NULL) { - _sx_debug(ZONE, "couldn't create scod instance, not authing"); + ret = sasl_client_init(NULL); + if(ret != SASL_OK) { + _sx_debug(ZONE, "sasl_client_init() failed (%s), not authing", sasl_errstring(ret, NULL, NULL)); return 1; } + sd = (_sx_sasl_data_t) malloc(sizeof(struct _sx_sasl_data_st)); + memset(sd, 0, sizeof(struct _sx_sasl_data_st)); + + if(user != NULL) + sd->user = strdup(user); + + if(pass != NULL) { + sd->psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + strlen(pass) + 1); + strcpy(sd->psecret->data, pass); + sd->psecret->len = strlen(pass); + } + + sd->callbacks=calloc(sizeof(sasl_callback_t),4); + + /* authentication name callback */ + sd->callbacks[0].id = SASL_CB_AUTHNAME; + sd->callbacks[0].proc = &_sx_sasl_cb_get_simple; + sd->callbacks[0].context = (void *) sd; + + /* password callback */ + sd->callbacks[1].id = SASL_CB_PASS; + sd->callbacks[1].proc = &_sx_sasl_cb_get_secret; + sd->callbacks[1].context = (void *) sd; + + /* user identity callback */ + sd->callbacks[2].id = SASL_CB_USER; + sd->callbacks[2].proc = &_sx_sasl_cb_get_simple; + sd->callbacks[2].context = (void *) sd; + + /* end of callbacks */ + sd->callbacks[3].id = SASL_CB_LIST_END; + sd->callbacks[3].proc = NULL; + sd->callbacks[3].context = NULL; + /* handshake start */ - ret = scod_client_start(sd, mech, authzid, user, pass, &out, &outlen); - if(ret != sd_SUCCESS && ret != sd_CONTINUE) { - _sx_debug(ZONE, "scod_client_start failed (%d), not authing", ret); + ret = sasl_client_new(appname, (s->req_to != NULL) ? s->req_to : "", NULL, NULL, sd->callbacks, 0, &sd->sasl); + if(ret != SASL_OK) { + _sx_debug(ZONE, "sasl_client_new failed, (%s), not authing", sasl_errstring(ret, NULL, NULL)); + + free(sd->user); + free(sd->psecret); + free(sd); - if(out != NULL) free(out); - - scod_free(sd); + return 1; + } + + /* get external data from the ssl plugin */ + ext_id = NULL; + for(i = 0; i < s->env->nplugins; i++) + if(s->env->plugins[i]->magic == SX_SASL_SSL_MAGIC) + ext_id = (char *) s->plugin_data[s->env->plugins[i]->index]; + + /* !!! XXX certs */ + /* + if(ext != NULL) { + ext->external_id = "foo"; + ext->external_ssf = 20; + } + */ + + /* if we've got some, setup for external auth */ + ret = SASL_OK; + if(ext_id != NULL) { + ret = sasl_setprop(sd->sasl, SASL_AUTH_EXTERNAL, ext_id); + if(ret == SASL_OK) ret = sasl_setprop(sd->sasl, SASL_SSF_EXTERNAL, &s->ssf); + } + + /* setup security properties */ + sec_props = ctx->sec_props; + if(s->ssf > 0) + /* if we're already encrypted, then no security layers */ + sec_props.max_ssf = 0; + + ret = sasl_setprop(sd->sasl, SASL_SEC_PROPS, &sec_props); + if(ret != SASL_OK) { + _sx_debug(ZONE, "sasl_setprop failed (%s), not authing", sasl_errstring(ret, NULL, NULL)); + + sasl_dispose(&sd->sasl); + + free(sd->user); + free(sd->psecret); + free(sd); + + return 1; + } + + /* handshake start */ + ret = sasl_client_start(sd->sasl, mech, NULL, (const char **) &out, &outlen, NULL); + if(ret != SASL_OK && ret != SASL_CONTINUE) { + _sx_debug(ZONE, "sasl_client_start failed (%s), not authing", sasl_errstring(ret, NULL, NULL)); + + sasl_dispose(&sd->sasl); + + free(sd->user); + free(sd->psecret); + free(sd); return 1; } @@ -626,7 +1073,6 @@ /* encode the challenge */ _sx_sasl_encode(out, outlen, &buf, &buflen); - free(out); /* build the nad */ nad = nad_new(s->nad_cache); diff -ur jabberd-2.0s9/sx/sasl.h jabberd-2.0s9-sasl/sx/sasl.h --- jabberd-2.0s9/sx/sasl.h 2004-04-15 03:26:12.000000000 +0100 +++ jabberd-2.0s9-sasl/sx/sasl.h 2005-07-27 23:23:14.000000000 +0100 @@ -23,7 +23,8 @@ #include "sx.h" -#include "scod/scod.h" +#include +#include #ifdef __cplusplus extern "C" { @@ -35,13 +36,8 @@ /** server init flag, don't offer sasl without this */ #define SX_SASL_OFFER (1<<3) -/* mechanisms to offer */ -#define SX_SASL_MECH_ANONYMOUS (1<<4) -#define SX_SASL_MECH_PLAIN (1<<5) -#define SX_SASL_MECH_DIGESTMD5 (1<<6) - /** the callback function */ -typedef int (*sx_sasl_callback_t)(int cb, void *arg, void **res, scod_t sd, void *cbarg); +typedef int (*sx_sasl_callback_t)(int cb, void *arg, void **res, sx_t s, void *cbarg); /* callbacks */ #define sx_sasl_cb_GET_REALM (0x00) @@ -49,20 +45,43 @@ #define sx_sasl_cb_CHECK_PASS (0x02) #define sx_sasl_cb_CHECK_AUTHZID (0x03) #define sx_sasl_cb_GEN_AUTHZID (0x04) +#define sx_sasl_cb_CHECK_MECH (0x05) + +/* error codes */ +#define sx_sasl_ret_OK 0 +#define sx_sasl_ret_FAIL 1 /** trigger for client auth */ -int sx_sasl_auth(sx_plugin_t p, sx_t s, char *mech, char *user, char *pass, char *authzid); +int sx_sasl_auth(sx_plugin_t p, sx_t s, char *appname, char *mech, char *user, char *pass); /** our context */ typedef struct _sx_sasl_st { - scod_ctx_t scod_ctx; + char *appname; + sasl_security_properties_t sec_props; sx_sasl_callback_t cb; void *cbarg; - - int flags; } *_sx_sasl_t; +/* data for per-conncetion sasl handshakes */ +typedef struct _sx_sasl_data_st { + char *user; + sasl_secret_t *psecret; + + sasl_callback_t *callbacks; + + _sx_sasl_t ctx; + sasl_conn_t *sasl; + sx_t stream; +} *_sx_sasl_data_t; + +typedef struct sx_sasl_creds_st { + const char *authnid; + const char *realm; + const char *authzid; + const char *pass; +} *sx_sasl_creds_t; + /** magic number of the ssl plugin, must match SX_SSL_MAGIC in sx/ssl.h */ #define SX_SASL_SSL_MAGIC (0x01)