pax_global_header00006660000000000000000000000064114146605330014515gustar00rootroot0000000000000052 comment=cac727df57d5ec19b4905d171eb6cac698e63815 JorjBauer-lua-cyrussasl-cac727d/000077500000000000000000000000001141466053300167015ustar00rootroot00000000000000JorjBauer-lua-cyrussasl-cac727d/.branch_version000066400000000000000000000000021141466053300216740ustar00rootroot000000000000000 JorjBauer-lua-cyrussasl-cac727d/.gitignore000066400000000000000000000000171141466053300206670ustar00rootroot00000000000000.build_version JorjBauer-lua-cyrussasl-cac727d/CONVENTIONS000066400000000000000000000012651141466053300204350ustar00rootroot00000000000000Two spaces to a tab. I put braces on the same line as their 'if', but not on the same line as function definitions or structs/enums. Functions which are not for use outside of a module are named starting with underscores. While it is safe to say that the definition void _func() should actually be static void _func() the reverse is not necessarily true - a function could be destined to be called from outside this module via a dispatch table. For example, the function static int cyrussasl_get_username(lua_State *l) is for direct consumption by Lua, but via a dispatch table. (It is not for consumption by other C methods directly, which is why I have attributed it static.) JorjBauer-lua-cyrussasl-cac727d/LICENSE000066400000000000000000000026331141466053300177120ustar00rootroot00000000000000Copyright (c) 2009, Jorj Bauer All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The name of Jorj Bauer may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY Jorj Bauer ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. JorjBauer-lua-cyrussasl-cac727d/Makefile000066400000000000000000000026751141466053300203530ustar00rootroot00000000000000# Linux (Debian Lenny) #CFLAGS=-g -O2 -fpic -I/usr/include/lua5.1 #LDFLAGS=-O -shared -fpic -lsasl2 #LUAPATH=/usr/share/lua/5.1 #CPATH=/usr/lib/lua/5.1 # MacOS CFLAGS=-g -Wall -O2 LDFLAGS=-bundle -undefined dynamic_lookup -lsasl2 MACOSX_VERSION=10.5 LUAPATH=/usr/local/share/lua/5.1 CPATH=/usr/local/lib/lua/5.1 ######################################################### # # YOU SHOULD NOT HAVE TO CHANGE ANYTHING BELOW THIS LINE. # If you do, then send me email letting me know what and # why! # -- Jorj Bauer # ######################################################### BRANCH_VERSION=.branch_version BUILD_VERSION=.build_version TARGET=cyrussasl.so OBJS=cyrussasl.o luaabstract.o context.o all: $(TARGET) install: $(TARGET) cp $(TARGET) $(CPATH) clean: rm -f *.o *.so *~ distclean: clean rm -f $(BUILD_VERSION) $(BRANCH_VERSION) $(TARGET): version $(OBJS) $(CC) $(LDFLAGS) -o $(TARGET) $(OBJS) .c.o: $(CC) $(CFLAGS) -DVERSION="\"$$(cat VERSION).$$(cat $(BRANCH_VERSION))-$$(cat $(BUILD_VERSION))\"" -fno-common -c $< -o $@ # Dependencies cyrussasl.c: context.h luaabstract.c luaabstract.h luaabstract.c: luaabstract.h context.c: context.h # build_version stuff .PHONY: version branch_version version: @if ! test -f $(BUILD_VERSION); then echo 0 > $(BUILD_VERSION); fi @echo $$(($$(cat $(BUILD_VERSION)) + 1)) > $(BUILD_VERSION) @if ! test -f $(BRANCH_VERSION); then git log --pretty=oneline -1|cut -c1-8 > $(BRANCH_VERSION); fi JorjBauer-lua-cyrussasl-cac727d/README000066400000000000000000000025561141466053300175710ustar00rootroot00000000000000Cyrus SASL library for Lua 5.1 (c) 2009 Jorj Bauer This is released under a BSD license; see the file LICENSE for details. ************************** Installation instructions: ************************** 0. Install Cyrus SASL. 1. Edit the Makefile. You'll need to comment out the architecture blocks that don't pertain to your platform. (As of this writing, this package works on MacOS 10.5 and Debian Lenny. This will likely function on other platforms as well, but I have not explicitly tested on them. If you have a Makefile configuration that works on another platform, send me email with your configuration so that I may include it in a future verison.) 2. make 3. sudo make install 4. Enjoy. ***** Bugs: ***** * Does not contain any client-side functionality. To be added; should not be difficult, now that the general architecture is in place. * To install this properly, you must edit the Makefile. This should be abstracted into autoconf (or something lighter weight to accomplish the same thing). * There is no test suite. I have some unit tests I've been using for pieces of this code, but the harness isn't good enough for me to include it as part of the package yet. * Installation has been tested under MacOS 10.5, 10.6 and Linux (specifically, Debian Lenny and RHEL 5.5). Other platforms should be tested. JorjBauer-lua-cyrussasl-cac727d/VERSION000066400000000000000000000000041141466053300177430ustar00rootroot000000000000001.0 JorjBauer-lua-cyrussasl-cac727d/context.c000066400000000000000000000106461141466053300205400ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "context.h" #include "luaabstract.h" /* strdup() is a POSIX function that is not part of the ANSI standard. This * simple wrapper provides the same functionality for platforms that don't * have POSIX defined. */ char *local_strdup(const char *s1) { #ifdef POSIX return strdup(s1); #else char *ret = malloc(strlen(s1)+1); if (!ret) return NULL; strcpy(ret, s1); return ret; #endif } /* new_context returns a lua userdata variable which has two important * properties: * * 1. It is a pointer to the pointer to a context struct, which carries the * C-internal state for this SASL negotiation; and * 2. It has a metatable associated with it that will call our destructor when * Lua decides to garbage-collect the userdata variable. */ struct _sasl_ctx **new_context(lua_State *L) { struct _sasl_ctx *data = NULL; struct _sasl_ctx **luserdata = NULL; data = malloc(sizeof(struct _sasl_ctx)); if (!data) return NULL; data->magic = CYRUSSASL_MAGIC; data->L = L; data->conn = NULL; data->last_message = NULL; data->user = NULL; data->authname = NULL; data->canon_cb_ref = LUA_REFNIL; /* Now that we have the context struct, we need to construct a Lua variable * to carry the data. And that variable needs to callback to our __gc method * for it in order to deallocate the memory we've just allocated. * * Note that we're allocing a new userdata object of the size of the * _pointer_ to our new struct. */ luserdata = (struct _sasl_ctx **) lua_newuserdata(L, sizeof(data)); if (!luserdata) { lua_pushstring(L, "Unable to alloc newuserdata"); lua_error(L); free(data); return NULL; } *luserdata = data; /* Store the pointer in the userdata */ luaL_getmetatable(L, MODULENAME); /* Retrieve the metatable w/ __gc hook */ lua_setmetatable(L, -2); /* Set luserdata's metatable to that one */ return luserdata; } struct _sasl_ctx *get_context(lua_State *l, int idx) { struct _sasl_ctx **ctxp = (struct _sasl_ctx **)lua_touserdata(l, idx); if (ctxp == NULL) luaL_typerror(l, idx, MODULENAME); return *ctxp; } void free_context(struct _sasl_ctx *ctx) { if (!ctx || ctx->magic != CYRUSSASL_MAGIC) return; if (ctx->conn) sasl_dispose(&ctx->conn); if (ctx->last_message) free(ctx->last_message); if (ctx->user) free(ctx->user); if (ctx->authname) free(ctx->authname); free(ctx); } int gc_context(lua_State *L) { struct _sasl_ctx **luadata = (struct _sasl_ctx **)lua_touserdata(L, 1); if (luadata == NULL) luaL_typerror(L, 1, MODULENAME); if ((*luadata)->canon_cb_ref != LUA_REFNIL) luaL_unref(L, LUA_REGISTRYINDEX, (*luadata)->canon_cb_ref); free_context(*luadata); return 0; } void set_context_conn(struct _sasl_ctx *ctx, sasl_conn_t *conn) { if (!ctx || ctx->magic != CYRUSSASL_MAGIC) return; ctx->conn = conn; } void set_context_message(struct _sasl_ctx *ctx, const char *msg) { if (!ctx || ctx->magic != CYRUSSASL_MAGIC) return; if (!msg) return; if (ctx->last_message) free(ctx->last_message); ctx->last_message = local_strdup(msg); } void set_context_user(struct _sasl_ctx *ctx, const char *usr, unsigned ulen) { if (!ctx || ctx->magic != CYRUSSASL_MAGIC) return; if (!usr) return; if (ctx->user) free(ctx->user); ctx->ulen = ulen; if (usr == NULL || ulen == 0) { ctx->user = NULL; return; } ctx->user = malloc(ulen+1); if (!ctx->user) return; memcpy(ctx->user, usr, ulen); ctx->user[ulen] = '\0'; } void set_context_authname(struct _sasl_ctx *ctx, const char *usr) { if (!ctx || ctx->magic != CYRUSSASL_MAGIC) return; if (!usr) return; if (ctx->authname) free(ctx->authname); ctx->authname = local_strdup(usr); } const char *get_context_message(struct _sasl_ctx *ctx) { if (!ctx || ctx->magic != CYRUSSASL_MAGIC) return NULL; return ctx->last_message; } const char *get_context_user(struct _sasl_ctx *ctx, unsigned *ulen_out) { if (!ctx || ctx->magic != CYRUSSASL_MAGIC) return NULL; if (ulen_out) *ulen_out = ctx->ulen; return ctx->user; } const char *get_context_authname(struct _sasl_ctx *ctx) { if (!ctx || ctx->magic != CYRUSSASL_MAGIC) return NULL; return ctx->authname; } JorjBauer-lua-cyrussasl-cac727d/context.h000066400000000000000000000023061141466053300205370ustar00rootroot00000000000000#ifndef __CONTEXT_H #define __CONTEXT_H #include #include #include #include #include #include #include #include "luaabstract.h" #define CYRUSSASL_MAGIC 0x53415376 #define MODULENAME "cyrussasl" struct _sasl_ctx { unsigned long magic; lua_State *L; sasl_conn_t *conn; sasl_callback_t callbacks[3]; char *last_message; char *user; unsigned ulen; char *authname; int canon_cb_ref; }; struct _sasl_ctx **new_context(lua_State *L); struct _sasl_ctx *get_context(lua_State *l, int idx); int gc_context (lua_State *L); void free_context(struct _sasl_ctx *ctx); void set_context_conn (struct _sasl_ctx *ctx, sasl_conn_t *conn); void set_context_message (struct _sasl_ctx *ctx, const char *msg); void set_context_user (struct _sasl_ctx *ctx, const char *usr, unsigned ulen); void set_context_authname(struct _sasl_ctx *ctx, const char *usr); const char *get_context_message (struct _sasl_ctx *ctx); const char *get_context_user (struct _sasl_ctx *ctx, unsigned *ulen_out); const char *get_context_authname(struct _sasl_ctx *ctx); #endif JorjBauer-lua-cyrussasl-cac727d/cyrussasl.c000066400000000000000000000561301141466053300211020ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "context.h" #include "luaabstract.h" #ifndef VERSION #define VERSION "undefined" #endif /* It's unfortunate that Cyrus SASL doesn't export these strings itself; it * only exports constants that refer to them. We could go crazy and * dynamically build this list but that seems like a lot of overhead for * something that they're unlikely to change. * Of course, now that I've written this, they'll certainly reorder the * error levels and these strings will no longer reflect reality :P */ static const char * const level_strings[] = { "none", "error", "fail", "warn", "note", "debug", "trace", "pass", NULL }; static int log_cb_ref = LUA_REFNIL; static int minimum_log_prio = SASL_LOG_NONE; static int _sasl_log(void *context, int priority, const char *message) { struct _sasl_ctx *ctxp = context; if (!message || !context || ctxp->magic != CYRUSSASL_MAGIC) return SASL_BADPARAM; if (priority < 0 || priority >= sizeof(level_strings) - 1) return SASL_BADPARAM; set_context_message(context, message); if (priority != SASL_LOG_NONE && priority <= minimum_log_prio && log_cb_ref != LUA_REFNIL) { /* Function to call */ lua_rawgeti(ctxp->L, LUA_REGISTRYINDEX, log_cb_ref); /* Message */ lua_pushstring(ctxp->L, message); /* Priority */ lua_pushstring(ctxp->L, level_strings[priority]); /* Perform: cb(message, priority) */ lua_call(ctxp->L, 2, 0); } return SASL_OK; } static int _sasl_canon_user(sasl_conn_t *conn, void *context, const char *user, unsigned ulen, unsigned flags, const char *user_realm, char *out_user, unsigned out_umax, unsigned *out_ulen) { struct _sasl_ctx *ctxp = context; if (!conn || !context || !user || ctxp->magic != CYRUSSASL_MAGIC) return SASL_BADPARAM; if (!(flags & SASL_CU_AUTHID) && !(flags & SASL_CU_AUTHZID)) return SASL_BADPARAM; if (!out_user || !out_ulen || out_umax == 0) return SASL_BADPARAM; if (ctxp->canon_cb_ref == LUA_REFNIL) { if (ulen >= out_umax) return SASL_BUFOVER; /* out_user may be the same as user, so memmove, not memcpy */ memmove(out_user, user, ulen); out_user[ulen] = '\0'; *out_ulen = ulen; set_context_user(context, user, ulen); return SASL_OK; } /* We have a callback to deal with. */ int ret = SASL_OK; const char *str = NULL; size_t len = 0; /* Function to call */ lua_rawgeti(ctxp->L, LUA_REGISTRYINDEX, ctxp->canon_cb_ref); /* Username */ lua_pushlstring(ctxp->L, user, ulen); /* Realm */ lua_pushstring(ctxp->L, user_realm); /* flags (the type of username) */ if ((flags & SASL_CU_AUTHID) && (flags & SASL_CU_AUTHZID)) lua_pushliteral(ctxp->L, "both"); else if (flags & SASL_CU_AUTHID) lua_pushliteral(ctxp->L, "authcid"); else lua_pushliteral(ctxp->L, "authzid"); /* Perform: str = cb(user, user_realm, "both|authcid|authzid") */ lua_call(ctxp->L, 3, 1); /* Get the result */ str = lua_tolstring(ctxp->L, -1, &len); if (str == NULL) ret = SASL_BADPROT; else if (len >= out_umax) ret = SASL_BUFOVER; else { memcpy(out_user, str, len + 1); *out_ulen = len; } /* Pop the result of the call off the stack */ lua_pop(ctxp->L, 1); if (ret == SASL_OK) set_context_user(context, out_user, *out_ulen); else set_context_user(context, NULL, 0); return ret; } /* version = cyrussasl.get_version() * * Returns a string of the lua_cyrussasl library version. */ static int cyrussasl_get_version(lua_State *l) { int numargs = lua_gettop(l); if (numargs != 0) { lua_pushstring(l, "usage: cyrussasl.get_version()"); lua_error(l); return 0; } lua_pushstring(l, VERSION); return 1; } /* * cyrussasl.server_init("appname") * * appname: the name of this application, from SASL's perspective. * * This function does not return any values. On failure, it will throw an * error. */ static int cyrussasl_sasl_server_init(lua_State *l) { const char *appname; int numargs = lua_gettop(l); int err; if (numargs != 1) { lua_pushstring(l, "usage: cyrussasl.server_init(appname)"); lua_error(l); return 0; } appname = tostring(l, 1); err = sasl_server_init( NULL, /* Global callbacks */ appname ); if (err != SASL_OK) { lua_pushstring(l, "sasl_server_init failed"); lua_error(l); return 0; } return 0; } static void _init_callbacks(struct _sasl_ctx *ctx) { ctx->callbacks[0].id = SASL_CB_LOG; /* Callback for error msg */ ctx->callbacks[0].proc = &_sasl_log; ctx->callbacks[0].context = ctx; ctx->callbacks[1].id = SASL_CB_CANON_USER; /* Callback for username */ ctx->callbacks[1].proc = &_sasl_canon_user; ctx->callbacks[1].context = ctx; ctx->callbacks[2].id = SASL_CB_LIST_END; /* Terminator */ ctx->callbacks[2].proc = NULL; ctx->callbacks[2].context = NULL; } /* conn = cyrussasl.server_new("serice_name", "host FQDN", "user realm", * "iplocal", "ipremote") * * conn: an opaque data structure (from Lua's perspective) related to this * specific authentication attempt. * service_name: the name of the service that's being protected by SASL (e.g. * xmpp, smtp, ...) * host FQDN: the fully-qualified domain name of the server that users * are connecting to. May be nil. * user realm: the authentication user realm to use for AuthN purposes. * May be nil. * iplocal: Either nil or a string of the form "a.b.c.d;port" (for IPv4). * Used to tell the SASL library what the local side of the connection * is using. * ipremote: Either nil or a string denoting the remote side of the connection. * * On error, this throws Lua error exceptions. (It is not the typical * case that this method might cause an error, except when attempting * to set up SASL initially during development.) */ static int cyrussasl_sasl_server_new(lua_State *l) { const char *service_name, *fqdn, *realm, *iplocal, *ipremote; int numargs = lua_gettop(l); int err; sasl_conn_t *conn = NULL; struct _sasl_ctx **ctxp = NULL; if (numargs != 5) { lua_pushstring(l, "usage: " "conn = " "cyrussasl.server_new(service_name, fqdn, realm, " "iplocal, ipremote)"); lua_error(l); return 0; } service_name = tostring(l, 1); fqdn = tostring(l, 2); realm = tostring(l, 3); iplocal = tostring(l, 4); ipremote = tostring(l, 5); ctxp = new_context(l); if (!ctxp) { lua_pushstring(l, "Unable to allocate a new context"); lua_error(l); return 0; } _init_callbacks(*ctxp); err = sasl_server_new( service_name, /* service name (passed in) */ fqdn, /* serverFQDN */ realm, /* user_realm */ iplocal, /* iplocalport */ ipremote, /* ipremoteport */ (*ctxp)->callbacks, /* per-connection callbacks */ 0, /* flags */ &conn ); /* returned connection ptr */ (*ctxp)->conn = conn; if ( err != SASL_OK ) { lua_pushstring(l, "sasl_server_new failed"); lua_error(l); return 0; } /* Return 1 item on the stack (a userdata pointer to our state struct). * It was already pushed on the stack by new_context(). */ return 1; /* return # of arguments returned on stack */ } /* (err, data) = cyrussasl.server_start(conn, mech, data) * * Arguments: * conn: the return result from a previous call to server_new * mech: the mechanism to use during this attempt (e.g. "PLAIN" or "GSSAPI") * data: any data that the client might have sent with its * mech choice. Data may be an empty string or nil. Note that * the non-nil case is specifically a Lua string object * (which, by definition, is allowed to contain '\0' bytes). * Return values: * err: the (integer) SASL error code reflecting the state of the attempt * (e.g. SASL_OK, SASL_CONTINUE, SASL_BADMECH, ...) * data: data that the server wants to send to the client in order * to continue the authN attempt. Returned as a Lua string object. */ static int cyrussasl_sasl_server_start(lua_State *l) { int numargs = lua_gettop(l); int err; struct _sasl_ctx *ctx = NULL; const char *mech = NULL; const char *data = NULL; size_t len; unsigned outlen; if (numargs != 3) { lua_pushstring(l, "usage: " "(err, data) = cyrussasl.server_start(conn, mech, data)"); lua_error(l); return 0; } /* Pull arguments off of the stack... */ ctx = get_context(l, 1); mech = tostring(l, 2); /* Allow the 'data' param to be nil, or an empty string. */ if ( lua_type(l, 3) == LUA_TNIL ) { data = NULL; len = 0; } else { data = tolstring(l, 3, &len); } err = sasl_server_start( ctx->conn, /* saved sasl connection */ mech, /* mech, which the client chose */ data, /* data that the client sent */ len, /* length of the client's data */ &data, /* data with which the server will reply */ &outlen /* size of the server's reply */ ); /* Form the reply and push onto the stack */ lua_pushinteger(l, err); /* SASL_CONTINUE, SASL_OK, et al */ lua_pushlstring(l, data, outlen); /* server's reply to the client */ return 2; /* returning 2 items on Lua stack */ } /* (err, data) = cyrussasl.server_step(conn, data) * * Arguments: * conn: the return result from a previous call to server_new * data: any data that the client might have sent from the previous step. * Note that data may still be an empty string or nil. (Like the * argument of the same name to server_start.) * * Return values: * err: the (integer) SASL error code reflecting the state of the attempt * (e.g. SASL_OK, SASL_CONTINUE, SASL_BADMECH, ...) * data: data that the server wants to send to the client in order * to continue the authN attempt. Returned as a Lua string object. */ static int cyrussasl_sasl_server_step(lua_State *l) { int numargs = lua_gettop(l); int err; struct _sasl_ctx *ctx = NULL; const char *data = NULL; size_t len; unsigned outlen; if (numargs != 2) { lua_pushstring(l, "usage: (err, data) = cyrussasl.server_step(conn, data)"); lua_error(l); return 0; } ctx = get_context(l, 1); data = tolstring(l, 2, &len); err = sasl_server_step( ctx->conn, data, len, &data, &outlen ); /* Form the reply and push onto the stack */ lua_pushinteger(l, err); /* SASL_CONTINUE, SASL_OK, et al */ lua_pushlstring(l, data, outlen); /* server's reply to the client */ return 2; /* returning 2 items on Lua stack */ } /* cyrussasl.setssf(conn, min_ssf, max_ssf) * * conn: the conn pointer from cyrussasl.server_new(). * min_ssf, max_ssf: set the minimum and maximum security strength factor * required for this AuthN. * * Throws Lua errors if it fails (as it should not typically fail). * Does not return any value. */ static int cyrussasl_setssf(lua_State *l) { sasl_security_properties_t secprops; int err; int min_ssf, max_ssf; struct _sasl_ctx *ctx = NULL; int numargs = lua_gettop(l); if (numargs != 3) { lua_pushstring(l, "usage: cyrussasl.setssf(conn, min_ssf, max_ssf)"); lua_error(l); return 0; } ctx = get_context(l, 1); min_ssf = tointeger(l, 2); max_ssf = tointeger(l, 3); memset(&secprops, 0L, sizeof(secprops)); secprops.min_ssf = min_ssf; secprops.max_ssf = max_ssf; err = sasl_setprop(ctx->conn, SASL_SEC_PROPS, &secprops); if ( err != SASL_OK ) { lua_pushstring(l, "setssf failed"); lua_error(l); return 0; } return 0; } /* cyrussasl.setprop(conn, propnum, val) * * conn: the conn pointer from cyrussasl.server_new(). * propnum: an integer corresponding to the property to set * val: a lua string object * * Throws Lua errors if it fails (as it should not typically fail). * Does not return any value. */ static int cyrussasl_sasl_setprop(lua_State *l) { sasl_security_properties_t secprops; int err; int proptype; const void *proparg; struct _sasl_ctx *ctx = NULL; int numargs = lua_gettop(l); if (numargs != 3) { lua_pushstring(l, "usage: cyrussasl.setprop(conn, propnum, propval)"); lua_error(l); return 0; } ctx = get_context(l, 1); proptype = tointeger(l, 2); proparg = tolstring(l, 3, NULL); memset(&secprops, 0L, sizeof(secprops)); secprops.max_ssf = UINT_MAX; err = sasl_setprop(ctx->conn, proptype, &proparg); if ( err != SASL_OK ) { lua_pushstring(l, "sasl_setprop failed"); lua_error(l); return 0; } return 0; } /* b64data = cyrussasl.encode64(data) * * A convenience method to use the Cyrus SASL library implementation of base64 * encoding data. Takes, and returns, a Lua string object. Since Lua strings * may contain true 8-bit data (including '\0'), the length of the data is * obtained by examining the length of the string. */ static int cyrussasl_sasl_encode64(lua_State *l) { unsigned len_out; int alloclen; char *buf = NULL; const char *data = NULL; size_t len; int err; int numargs = lua_gettop(l); if (numargs != 2) { lua_pushstring(l, "usage: b64data = cyrussasl.encode64(data, len)"); lua_error(l); return 0; } len = 0; data = tolstring(l, 1, &len); /* Allocate a new buffer that will accommodate the data in its most-possibly- * expanded state. */ alloclen = ((len / 3) + 1) * 4 + 1; buf = malloc(alloclen); if (!buf) { lua_pushstring(l, "malloc failed"); lua_error(l); return 0; } err = sasl_encode64(data, len, buf, alloclen, &len_out); if ( err != SASL_OK ) { free(buf); lua_pushstring(l, "sasl_encode64 failed"); lua_error(l); return 0; } lua_pushlstring(l, buf, len_out); free(buf); return 1; } /* data = cyrussasl.decode64(b64data) * * Partner function to encode64(). */ static int cyrussasl_sasl_decode64(lua_State *l) { const char *data = NULL; char *outdata = NULL; size_t len; unsigned outlen; int err; int numargs = lua_gettop(l); if (numargs != 1) { lua_pushstring(l, "usage: data = cyrussasl.decode64(b64data)"); lua_error(l); return 0; } data = tostring(l, 1); len = strlen(data); outdata = malloc(len); if (!outdata) { lua_pushstring(l, "failed to malloc in decode64"); lua_error(l); return 0; } /* Perform a decode-in-place, which is kosher according to docs. */ err = sasl_decode64(data, len, outdata, len, &outlen); if ( err != SASL_OK ) { free(outdata); lua_pushstring(l, "sasl_decode64 failed"); lua_error(l); return 0; } lua_pushlstring(l, outdata, outlen); free(outdata); return 1; } /* mechslist = cyrussasl.listmech((conn, authid, prefix, separator, suffix) * * Return all of the available mechanisms to the Cyrus SASL library. * * conn: the conn pointer from cyrussasl.server_new(). * authid: the username trying to authenticate. May be nil. * prefix: prefix to prepend to the returned string. May be an empty string. * separator: the string to use to separate mechanisms. May be empty. * suffix: suffix to postpend to the returned string. May be empty. * * mechslist: a Lua string object containing the mechanisms (GSSAPI, et al) */ static int cyrussasl_sasl_listmech(lua_State *l) { int err; struct _sasl_ctx *ctx = NULL; const char *ext_authid = NULL; const char *data = NULL; const char *prefix = NULL; const char *separator = NULL; const char *suffix = NULL; unsigned len; int count; int numargs = lua_gettop(l); if (numargs != 5) { lua_pushstring(l, "usage: " "mechslist = cyrussasl.listmech" "(conn, authid, prefix, separator, suffix)"); lua_error(l); return 0; } ctx = get_context(l, 1); ext_authid = tostring(l, 2); prefix = tostring(l, 3); separator = tostring(l, 4); suffix = tostring(l, 5); err = sasl_listmech(ctx->conn, ext_authid, prefix, separator, suffix, &data, &len, &count); if ( err != SASL_OK ) { lua_pushstring(l, "sasl_listmech failed"); lua_error(l); return 0; } lua_pushlstring(l, data, len); return 1; } /* user = cyrussasl.get_username(conn) * * conn: the conn pointer from cyrussasl.server_new(). * user: the username decoded from user data as part of the negotiation. * * Note that 'user' may be an empty string if the negotiation hasn't * extracted a username for any reason (e.g. incomplete negotiation). * * Typically used after negotation is successful to find the username * associated with the authentication that just took place. */ static int cyrussasl_get_username(lua_State *l) { struct _sasl_ctx *ctx = NULL; const char *ret; unsigned ulen; int numargs = lua_gettop(l); if (numargs != 1) { lua_pushstring(l, "usage: user = cyrussasl.get_username(conn)"); lua_error(l); return 0; } ctx = get_context(l, 1); ret = get_context_user(ctx, &ulen); if (ret && ulen) lua_pushstring(l, ret); /* Not quite right - username might contain NULLs... */ else lua_pushstring(l, ""); return 1; } /* user = cyrussasl.get_authname(conn) * * conn: the conn pointer from cyrussasl.server_new(). * user: the authname decoded from user data as part of the negotiation. */ static int cyrussasl_get_authname(lua_State *l) { struct _sasl_ctx *ctx = NULL; const char *ret; int numargs = lua_gettop(l); if (numargs != 1) { lua_pushstring(l, "usage: user = cyrussasl.get_authname(conn)"); lua_error(l); return 0; } ctx = get_context(l, 1); ret = get_context_authname(ctx); if (ret) lua_pushstring(l, ret); else lua_pushstring(l, ""); return 1; } /* message = cyrussasl.get_message(conn) * * conn: the conn pointer from cyrussasl.server_new(). * message: the last message emitted by the SASL library during the * negotiation. May be an empty string. * * Typically used to find the specifics about a failed negotation. */ static int cyrussasl_get_message(lua_State *l) { struct _sasl_ctx *ctx = NULL; const char *ret; int numargs = lua_gettop(l); if (numargs != 1) { lua_pushstring(l, "usage: cyrussasl.get_message(conn)"); lua_error(l); return 0; } ctx = get_context(l, 1); ret = get_context_message(ctx); if (ret) lua_pushstring(l, ret); else lua_pushstring(l, ""); return 1; } /* old_cb = cyrussasl.set_canon_cb(conn, cb) * * conn: the conn pointer from cyrussasl.server_new() * cb: a function that is passed the username, realm (may be nil), and * either "authcid", "authzid", or "both" to indicate whether * the username is the authentication identity, the authorization * identity, or both (both seems to happen under some circumstances). * The function should return a normalized username. * old_cb: the previous callback (or nil) * * Used to canonicalize usernames. * */ static int cyrussasl_set_canon_cb(lua_State *l) { struct _sasl_ctx *ctx = NULL; int numargs = lua_gettop(l); int old_ref; int type; if (numargs != 2) { lua_pushstring(l, "usage: cyrussasl.set_canon_cb(conn, cb)"); lua_error(l); return 0; } ctx = get_context(l, 1); type = lua_type(l, 2); if (type != LUA_TFUNCTION && type != LUA_TNIL) { char err[256]; snprintf(err, sizeof(err), "expected function or nil, got %s", lua_typename(l, type)); lua_pushstring(l, err); lua_error(l); return 0; } old_ref = ctx->canon_cb_ref; /* Store the new function */ ctx->canon_cb_ref = luaL_ref(l, LUA_REGISTRYINDEX); /* Push the old function onto the stack and free its ref */ lua_rawgeti(l, LUA_REGISTRYINDEX, old_ref); luaL_unref(l, LUA_REGISTRYINDEX, old_ref); return 1; } /* old_cb = cyrussasl.set_log_cb(cb, minimum priority level) * * cb: a function that is passed the log message and priority. * priority is one of "error", "fail" (auth failures), "warn", * "note", "debug", "trace", and "pass" (includes passwords). * minimum priority level: the minimum severity level messages to call * in the cb. The default is "warn". * old_cb: the previous callback (or nil) * * Used for debug logging. */ static int cyrussasl_set_log_cb(lua_State *l) { int old_ref; int numargs = lua_gettop(l); int type; type = lua_type(l, 1); if (type != LUA_TFUNCTION && type != LUA_TNIL) { char err[256]; snprintf(err, sizeof(err), "expected function or nil, got %s", lua_typename(l, type)); lua_pushstring(l, err); lua_error(l); return 0; } /* Store the minimum desired log level */ minimum_log_prio = luaL_checkoption(l, 2, "warn", level_strings); if (numargs > 1) lua_pop(l, numargs - 1); old_ref = log_cb_ref; /* Store the new function */ log_cb_ref = luaL_ref(l, LUA_REGISTRYINDEX); /* Push the old function onto the stack and free its ref */ lua_rawgeti(l, LUA_REGISTRYINDEX, old_ref); luaL_unref(l, LUA_REGISTRYINDEX, old_ref); return 1; } /* metatable, hook for calling gc_context on context structs */ static const luaL_reg meta[] = { { "__gc", gc_context }, { NULL, NULL } }; /* function table for this module */ static const struct luaL_reg methods[] = { { "setssf", cyrussasl_setssf }, { "setprop", cyrussasl_sasl_setprop }, { "listmech", cyrussasl_sasl_listmech }, { "encode64", cyrussasl_sasl_encode64 }, { "decode64", cyrussasl_sasl_decode64 }, { "get_version", cyrussasl_get_version }, { "server_init", cyrussasl_sasl_server_init }, { "server_new", cyrussasl_sasl_server_new }, { "server_start", cyrussasl_sasl_server_start }, { "server_step", cyrussasl_sasl_server_step }, { "get_username", cyrussasl_get_username }, { "get_authname", cyrussasl_get_authname }, { "get_message", cyrussasl_get_message }, { "set_canon_cb", cyrussasl_set_canon_cb }, { "set_log_cb", cyrussasl_set_log_cb }, { NULL, NULL } }; /* Module initializer, called from Lua when the module is loaded. */ int luaopen_cyrussasl(lua_State *l) { /* Construct a new namespace table for Lua, and register it as the global * named "cyrussasl". */ luaL_openlib(l, MODULENAME, methods, 0); /* Create metatable, which is used to tie C data structures to our garbage * collection function. */ luaL_newmetatable(l, MODULENAME); luaL_openlib(l, 0, meta, 0); lua_pushliteral(l, "__index"); lua_pushvalue(l, -3); /* dup methods table*/ lua_rawset(l, -3); /* metatable.__index = methods */ lua_pushliteral(l, "__metatable"); lua_pushvalue(l, -3); /* dup methods table*/ lua_rawset(l, -3); /* hide metatable: metatable.__metatable = methods */ lua_pop(l, 1); /* drop metatable */ return 1; /* return methods on the stack */ } JorjBauer-lua-cyrussasl-cac727d/luaabstract.c000066400000000000000000000015461141466053300213600ustar00rootroot00000000000000#include #include #include "luaabstract.h" const char *tolstring(lua_State *l, int index, size_t *len) { int type = lua_type(l, index); if (type != LUA_TSTRING) { char err[256]; snprintf(err, sizeof(err), "expected string, got %s", lua_typename(l, type)); lua_pushstring(l, err); lua_error(l); return NULL; } return lua_tolstring(l, index, len); } const char *tostring(lua_State *l, int index) { if (lua_type(l, index) == LUA_TNIL) return NULL; return tolstring(l, index, NULL); } int tointeger(lua_State *l, int index) { int type = lua_type(l, index); if (type != LUA_TNUMBER) { char err[256]; snprintf(err, sizeof(err), "expected integer, got %s", lua_typename(l, type)); lua_pushstring(l, err); lua_error(l); return 0; } return lua_tointeger(l, index); } JorjBauer-lua-cyrussasl-cac727d/luaabstract.h000066400000000000000000000003471141466053300213630ustar00rootroot00000000000000#ifndef __LUAABSTRACT_H #define __LUAABSTRACT_H #include const char *tolstring(lua_State *l, int index, size_t *len); const char *tostring(lua_State *l, int index); int tointeger(lua_State *l, int index); #endif