liquid_feedback_frontend

diff lib/mldap/mldap.c @ 1071:58f48a8a202a

Imported and merged LDAP patch
author bsw
date Fri Jul 18 21:42:59 2014 +0200 (2014-07-18)
parents
children 96336212e94d
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/lib/mldap/mldap.c	Fri Jul 18 21:42:59 2014 +0200
     1.3 @@ -0,0 +1,567 @@
     1.4 +/*
     1.5 + * minimalistic Lua LDAP interface library
     1.6 + *
     1.7 + * The library does not set any global variable itself and must thus be
     1.8 + * loaded with
     1.9 + *
    1.10 + *     mldap = require("mldap")
    1.11 + *
    1.12 + * or a similar statement.
    1.13 + *
    1.14 + * The library provides two functions, conn = bind{...} and unbind(conn)
    1.15 + * to connect to and disconnect from the LDAP server respectively. The
    1.16 + * unbind function is also provided as a method of the connection userdata
    1.17 + * object (see below).
    1.18 + *
    1.19 + * The arguments to the bind{...} function are documented in the source code
    1.20 + * (see C function mldap_bind). In case of success, the bind function returns
    1.21 + * a userdata object that provides two methods: query{...} and unbind(). In
    1.22 + * case of error, the bind function returns nil as first return value, an
    1.23 + * error string as second return value, and a numeric error code as third
    1.24 + * return value. A positive error code is an LDAP resultCode, a negative
    1.25 + * error code is an OpenLDAP API error code:
    1.26 + *
    1.27 + *     connection, error_string, numeric_error_code = mldap.bind{...}
    1.28 + *
    1.29 + * For translating numeric error codes to an identifying (machine readable)
    1.30 + * string identifier, the library provides in addition to the two functions
    1.31 + * a table named 'errorcodes', for example:
    1.32 + *
    1.33 + *     49 == mldap.errorcodes["invalid_credentials"]
    1.34 + *
    1.35 + * and
    1.36 + *
    1.37 + *     mldap.errorcodes[49] == "invalid_credentials"
    1.38 + *
    1.39 + * The arguments and return value of the query{...} method of the connection
    1.40 + * userdata object are also documented in the source code below (see
    1.41 + * C function mldap_query). Error conditions are reported the same way as the
    1.42 + * bind{...} function does.
    1.43 + *
    1.44 + * To close the connection, either the unbind() function of the library or
    1.45 + * the unbind() method can be called; it is allowed to call them multiple
    1.46 + * times, and they are also invoked by the garbage collector.
    1.47 + *
    1.48 + */
    1.49 +
    1.50 +// Lua header inclusions:
    1.51 +#include <lua.h>
    1.52 +#include <lauxlib.h>
    1.53 +
    1.54 +// OpenLDAP header inclusions:
    1.55 +#include <ldap.h>
    1.56 +
    1.57 +// Standard C inclusions:
    1.58 +#include <stdlib.h>
    1.59 +#include <stdbool.h>
    1.60 +#include <unistd.h>
    1.61 +
    1.62 +// Error code translation is included from separate C file:
    1.63 +#include "mldap_errorcodes.c"
    1.64 +
    1.65 +// Provide compatibility with Lua 5.1:
    1.66 +#if LUA_VERSION_NUM < 502
    1.67 +#define luaL_newlib(L, t) lua_newtable((L)); luaL_register(L, NULL, t)
    1.68 +#define lua_rawlen lua_objlen
    1.69 +#define lua_len lua_objlen
    1.70 +#define luaL_setmetatable(L, regkey) \
    1.71 +  lua_getfield((L), LUA_REGISTRYINDEX, (regkey)); \
    1.72 +  lua_setmetatable((L), -2);
    1.73 +#endif
    1.74 +
    1.75 +// prefix for all Lua registry entries of this library:
    1.76 +#define MLDAP_REGKEY "556aeaf3c864af2e_mldap_"
    1.77 +
    1.78 +
    1.79 +static const char *mldap_get_named_string_arg(
    1.80 +  // gets a named argument of type "string" from a table at the given stack position
    1.81 +
    1.82 +  lua_State *L,         // pointer to lua_State variable
    1.83 +  int idx,              // stack index of the table containing the named arguments
    1.84 +  const char *argname,  // name of the argument
    1.85 +  int mandatory         // if not 0, then the argument is mandatory and an error is raised if it isn't found
    1.86 +
    1.87 +  // leaves the string as new element on top of the stack
    1.88 +) {
    1.89 +
    1.90 +  // pushes the table entry with the given argument name on top of the stack:
    1.91 +  lua_getfield(L, idx, argname);
    1.92 +
    1.93 +  // check, if the entry is nil or false:
    1.94 +  if (!lua_toboolean(L, -1)) {
    1.95 +
    1.96 +    // throw error, if named argument is mandatory:
    1.97 +    if (mandatory) return luaL_error(L, "Named argument '%s' missing", argname), NULL;
    1.98 +
    1.99 +    // return NULL pointer, if named argument is not mandatory:
   1.100 +    return NULL;
   1.101 +
   1.102 +  }
   1.103 +
   1.104 +  // throw error, if the value of the argument is not string:
   1.105 +  if (lua_type(L, -1) != LUA_TSTRING) return luaL_error(L, "Named argument '%s' is not a string", argname), NULL;
   1.106 +
   1.107 +  // return a pointer to the string, leaving the string on top of the stack to avoid garbage collection:
   1.108 +  return lua_tostring(L, -1);
   1.109 +
   1.110 +  // leaves one element on the stack
   1.111 +}
   1.112 +
   1.113 +
   1.114 +static int mldap_get_named_number_arg(
   1.115 +  // gets a named argument of type "number" from a table at the given stack position
   1.116 +
   1.117 +  lua_State *L,             // pointer to lua_State variable
   1.118 +  int idx,                  // stack index of the table containing the named arguments
   1.119 +  const char *argname,      // name of the argument
   1.120 +  int mandatory,            // if not 0, then the argument is mandatory and an error is raised if it isn't found
   1.121 +  lua_Number default_value  // default value to return, if the argument is not mandatory and nil or false
   1.122 +
   1.123 +  // opposed to 'mldap_get_named_string_arg', this function leaves no element on the stack
   1.124 +) {
   1.125 +
   1.126 +  lua_Number value;  // value to return
   1.127 +
   1.128 +  // pushes the table entry with the given argument name on top of the stack:
   1.129 +  lua_getfield(L, idx, argname);
   1.130 +
   1.131 +  // check, if the entry is nil or false:
   1.132 +  if (lua_isnil(L, -1)) {
   1.133 +
   1.134 +    // throw error, if named argument is mandatory:
   1.135 +    if (mandatory) return luaL_error(L, "Named argument '%s' missing", argname), 0;
   1.136 +
   1.137 +    // set default value as return value, if named argument is not mandatory:
   1.138 +    value = default_value;
   1.139 +
   1.140 +  } else {
   1.141 +
   1.142 +    // throw error, if the value of the argument is not a number:
   1.143 +    if (lua_type(L, -1) != LUA_TNUMBER) return luaL_error(L, "Named argument '%s' is not a number", argname), 0;
   1.144 +
   1.145 +    // set return value to the number:
   1.146 +    value = lua_tonumber(L, -1);
   1.147 +
   1.148 +  }
   1.149 +
   1.150 +  // remove unnecessary element from stack (not needed to avoid garbage collection):
   1.151 +  return value;
   1.152 +
   1.153 +  // leaves no new elements on the stack
   1.154 +}
   1.155 +
   1.156 +
   1.157 +static int mldap_scope(
   1.158 +  // converts a string ("base", "onelevel", "subtree", "children") to an integer representing the LDAP scope
   1.159 +  // and throws an error for any unknown string
   1.160 +
   1.161 +  lua_State *L,             // pointer to lua_State variable (needed to throw errors)
   1.162 +  const char *scope_string  // string that is either ("base", "onelevel", "subtree", "children")
   1.163 +
   1.164 +  // does not affect or use the Lua stack at all
   1.165 +) {
   1.166 +
   1.167 +  // return integer according to string value:
   1.168 +  if (!strcmp(scope_string, "base"))     return LDAP_SCOPE_BASE;
   1.169 +  if (!strcmp(scope_string, "onelevel")) return LDAP_SCOPE_ONELEVEL;
   1.170 +  if (!strcmp(scope_string, "subtree"))  return LDAP_SCOPE_SUBTREE;
   1.171 +  if (!strcmp(scope_string, "children")) return LDAP_SCOPE_CHILDREN;
   1.172 +
   1.173 +  // throw error for unknown string values:
   1.174 +  return luaL_error(L, "Invalid LDAP scope: '%s'", scope_string), 0;
   1.175 +
   1.176 +}
   1.177 +
   1.178 +
   1.179 +static int mldap_bind(lua_State *L) {
   1.180 +  // Lua C function that takes named arguments as a table
   1.181 +  // and returns a userdata object, representing the LDAP connection
   1.182 +  // or returns nil, an error string, and an error code (integer) on error
   1.183 +
   1.184 +  // named arguments:
   1.185 +  // "uri"      (string)  server URI to connect to
   1.186 +  // "who"      (string)  DN to bind as
   1.187 +  // "password" (string)  password for DN to bind as
   1.188 +  // "timeout"  (number)  timeout in seconds
   1.189 +
   1.190 +  static const int ldap_version = LDAP_VERSION3;  // providing a pointer (&ldap_version) to set LDAP protocol version 3
   1.191 +  const char *uri;           // C string for "uri" argument
   1.192 +  const char *who;           // C string for "who" argument
   1.193 +  struct berval cred;        // credentials ("password") are stored as struct berval
   1.194 +  lua_Number timeout_float;  // float (lua_Number) for timeout
   1.195 +  struct timeval timeout;    // timeout is stored as struct timeval
   1.196 +  int ldap_error;            // LDAP error code (as returned by libldap calls)
   1.197 +  LDAP *ldp;                 // pointer to an opaque OpenLDAP structure representing the connection
   1.198 +  LDAP **ldp_ptr;            // pointer to a Lua userdata structure (that only contains the 'ldp' pointer)
   1.199 +
   1.200 +  // throw error if first argument is not a table:
   1.201 +  if (lua_type(L, 1) != LUA_TTABLE) {
   1.202 +    luaL_error(L, "Argument to function 'bind' is not a table.");
   1.203 +  }
   1.204 +
   1.205 +  // extract arguments:
   1.206 +  uri = mldap_get_named_string_arg(L, 1, "uri", true);
   1.207 +  who = mldap_get_named_string_arg(L, 1, "who", false);
   1.208 +  cred.bv_val = mldap_get_named_string_arg(L, 1, "password", false);
   1.209 +  if (cred.bv_val) cred.bv_len = strlen(cred.bv_val);
   1.210 +  else cred.bv_len = 0;
   1.211 +  timeout_float = mldap_get_named_number_arg(L, 1, "timeout", false, -1);
   1.212 +  timeout.tv_sec = timeout_float;
   1.213 +  timeout.tv_usec = (timeout_float - timeout.tv_sec) * 1000000;
   1.214 +
   1.215 +  // initialize OpenLDAP structure and provide URI for connection:
   1.216 +  ldap_error = ldap_initialize(&ldp, uri);
   1.217 +  // on error, jump to label "mldap_queryconn_error1", as no ldap_unbind_ext_s() is needed:
   1.218 +  if (ldap_error != LDAP_SUCCESS) goto mldap_queryconn_error1;
   1.219 +
   1.220 +  // set LDAP protocol version 3:
   1.221 +  ldap_error = ldap_set_option(ldp, LDAP_OPT_PROTOCOL_VERSION, &ldap_version);
   1.222 +  // on error, jump to label "mldap_queryconn_error2", as ldap_unbind_ext_s() must be called:
   1.223 +  if (ldap_error != LDAP_SUCCESS) goto mldap_queryconn_error2;
   1.224 +
   1.225 +  // set timeout for asynchronous OpenLDAP library calls:
   1.226 +  ldap_error = ldap_set_option(ldp, LDAP_OPT_TIMEOUT, &timeout);
   1.227 +  // on error, jump to label "mldap_queryconn_error2", as ldap_unbind_ext_s() must be called:
   1.228 +  if (ldap_error != LDAP_SUCCESS) goto mldap_queryconn_error2;
   1.229 +
   1.230 +  // connect to LDAP server:
   1.231 +  ldap_error = ldap_sasl_bind_s(
   1.232 +    ldp,               // pointer to opaque OpenLDAP structure representing the connection
   1.233 +    who,               // DN to bind as
   1.234 +    LDAP_SASL_SIMPLE,  // SASL mechanism "simple" for password authentication
   1.235 +    &cred,             // password as struct berval
   1.236 +    NULL,              // no server controls
   1.237 +    NULL,              // no client controls
   1.238 +    NULL               // do not store server credentials
   1.239 +  );
   1.240 +
   1.241 +  // error handling:
   1.242 +  if (ldap_error != LDAP_SUCCESS) {
   1.243 +
   1.244 +    // error label to jump to, if a call of ldap_unbind_ext_s() is required:
   1.245 +    mldap_queryconn_error2:
   1.246 +
   1.247 +    // close connection and free resources:
   1.248 +    ldap_unbind_ext_s(ldp, NULL, NULL);
   1.249 +
   1.250 +    // error label to jump to, if no call of ldap_unbind_ext_s() is required:
   1.251 +    mldap_queryconn_error1:
   1.252 +
   1.253 +    // return three values:
   1.254 +    lua_pushnil(L);                                  // return nil as first value
   1.255 +    lua_pushstring(L, ldap_err2string(ldap_error));  // return error string as second value
   1.256 +    lua_pushinteger(L, ldap_error);                  // return error code (integer) as third value
   1.257 +    return 3;
   1.258 +
   1.259 +  }
   1.260 +
   1.261 +  // create new Lua userdata object (that will contain the 'ldp' pointer) on top of stack:
   1.262 +  ldp_ptr = lua_newuserdata(L, sizeof(LDAP *));
   1.263 +
   1.264 +  // set metatable of Lua userdata object:
   1.265 +  luaL_setmetatable(L, MLDAP_REGKEY "connection_metatable");
   1.266 +
   1.267 +  // write contents of Lua userdata object (the 'ldp' pointer):
   1.268 +  *ldp_ptr = ldp;
   1.269 +
   1.270 +  // return Lua userdata object from top of stack:
   1.271 +  return 1;
   1.272 +
   1.273 +}
   1.274 +
   1.275 +
   1.276 +static int mldap_search(lua_State *L) {
   1.277 +  // Lua C function used as "search" method of Lua userdata object representing the LDAP connection
   1.278 +  // that takes a Lua userdata object (the LDAP connection) as first argument,
   1.279 +  // a table with named arguments as second argument,
   1.280 +  // and returns a result table on success (see below)
   1.281 +  // or returns nil, an error string, and an error code (integer) on error
   1.282 +
   1.283 +  // named arguments:
   1.284 +  // "base"  (string)   DN of the entry at which to start the search
   1.285 +  // "scope" (string)   scope of the search, one of:
   1.286 +  //                      "base" to search the object itself
   1.287 +  //                      "onelevel" to search the object's immediate children
   1.288 +  //                      "subtree" to search the object and all its descendants
   1.289 +  //                      "children" to search all of the descendants
   1.290 +  // "filter" (string)  string representation of the filter to apply in the search
   1.291 +  //                    (conforming to RFC 4515 as extended in RFC 4526)
   1.292 +  // "attrs"  (table)   list of attribute descriptions (each a string) to return from matching entries
   1.293 +
   1.294 +  // structure of result table:
   1.295 +  // {
   1.296 +  //   { dn      = <distinguished name (DN)>,
   1.297 +  //     <attr1> = { <value1>, <value2>, ... },
   1.298 +  //     <attr2> = { <value1>, <value2>, ... },
   1.299 +  //     ...
   1.300 +  //   },
   1.301 +  //   { dn      = <distinguished name (DN)>,
   1.302 +  //     <attr1> = { <value1>, <value2>, ... },
   1.303 +  //     <attr2> = { <value1>, <value2>, ... },
   1.304 +  //     ...
   1.305 +  //   },
   1.306 +  //   ...
   1.307 +  // }
   1.308 +
   1.309 +  const char *base;          // C string for "base" argument
   1.310 +  const char *scope_string;  // C string for "scope" argument
   1.311 +  int scope;                 // integer representing the scope
   1.312 +  const char *filter;        // C string for "filter" argument
   1.313 +  size_t nattrs;             // number of attributes in "attrs" argument
   1.314 +  char **attrs;              // C string array of "attrs" argument
   1.315 +  size_t attr_idx;           // index variable for building the C string array of "attrs"
   1.316 +  int ldap_error;            // LDAP error code (as returned by libldap calls)
   1.317 +  LDAP **ldp_ptr;            // pointer to a pointer to the OpenLDAP structure representing the connection
   1.318 +  LDAPMessage *res;          // pointer to the result of ldap_search_ext_s() call
   1.319 +  LDAPMessage *ent;          // pointer to an entry in the result of ldap_search_ext_s() call
   1.320 +  int i;                     // integer to fill the Lua table returned as result
   1.321 +
   1.322 +  // truncate the Lua stack to 2 elements:
   1.323 +  lua_settop(L, 2);
   1.324 +
   1.325 +  // check if the first argument is a Lua userdata object with the correct metatable
   1.326 +  // and get a C pointer to that userdata object:
   1.327 +  ldp_ptr = luaL_checkudata(L, 1, MLDAP_REGKEY "connection_metatable");
   1.328 +
   1.329 +  // throw an error, if the connection has already been closed:
   1.330 +  if (!*ldp_ptr) {
   1.331 +    return luaL_error(L, "LDAP connection has already been closed");
   1.332 +  }
   1.333 +
   1.334 +  // check if the second argument is a table, and throw an error if it's not a table:
   1.335 +  if (lua_type(L, 2) != LUA_TTABLE) {
   1.336 +    luaL_error(L, "Argument to function 'bind' is not a table.");
   1.337 +  }
   1.338 +
   1.339 +  // extract named arguments (requires memory allocation for 'attrs'):
   1.340 +  base = mldap_get_named_string_arg(L, 2, "base", true);  // pushed to 3
   1.341 +  scope_string = mldap_get_named_string_arg(L, 2, "scope", true);  // pushed to 4
   1.342 +  scope = mldap_scope(L, scope_string);
   1.343 +  lua_pop(L, 1);  // removes stack element 4
   1.344 +  filter = mldap_get_named_string_arg(L, 2, "filter", false);  // pushed to 4
   1.345 +  lua_getfield(L, 2, "attrs");  // pushed to 5
   1.346 +  nattrs = lua_len(L, -1);
   1.347 +  attrs = calloc(nattrs + 1, sizeof(char *));  // memory allocation, +1 for terminating NULL
   1.348 +  if (!attrs) return luaL_error(L, "Memory allocation error in C function 'mldap_queryconn'");
   1.349 +  for (attr_idx=0; attr_idx<nattrs; attr_idx++) {
   1.350 +    lua_pushinteger(L, attr_idx+1);
   1.351 +    lua_gettable(L, 5);  // pushed onto variable stack position
   1.352 +    if (lua_type(L, -1) != LUA_TSTRING) {
   1.353 +      free(attrs);
   1.354 +      return luaL_error(L, "Element in attribute list is not a string");
   1.355 +    }
   1.356 +    attrs[i] = lua_tostring(L, -1);
   1.357 +  }
   1.358 +  // attrs[nattrs] = NULL;  // unnecessary due to calloc
   1.359 +
   1.360 +  // execute LDAP search and store pointer to the result in 'res':
   1.361 +  ldap_error = ldap_search_ext_s(
   1.362 +    *ldp_ptr,  // pointer to the opaque OpenLDAP structure representing the connection
   1.363 +    base,      // DN of the entry at which to start the search
   1.364 +    scope,     // scope of the search
   1.365 +    filter,    // string representation of the filter to apply in the search
   1.366 +    attrs,     // array of attribute descriptions (array of strings)
   1.367 +    0,         // do not only request attribute descriptions but also values
   1.368 +    NULL,      // no server controls
   1.369 +    NULL,      // no client controls
   1.370 +    NULL,      // do not set another timeout
   1.371 +    0,         // no sizelimit
   1.372 +    &res       // store result in 'res'
   1.373 +  );
   1.374 +
   1.375 +  // free data structures that have been allocated for the 'attrs' array:
   1.376 +  free(attrs);
   1.377 +
   1.378 +  // return nil, an error string, and an error code (integer) in case of error:
   1.379 +  if (ldap_error != LDAP_SUCCESS) {
   1.380 +    lua_pushnil(L);
   1.381 +    lua_pushstring(L, ldap_err2string(ldap_error));
   1.382 +    lua_pushinteger(L, ldap_error);
   1.383 +    return 3;
   1.384 +  }
   1.385 +
   1.386 +  // clear Lua stack:
   1.387 +  lua_settop(L, 0);
   1.388 +
   1.389 +  // create result table for all entries at stack position 1:
   1.390 +  lua_newtable(L);
   1.391 +
   1.392 +  // use ldap_first_entry() and ldap_next_entry() functions
   1.393 +  // to iterate through all entries in the result 'res'
   1.394 +  // and count 'i' from 1 up:
   1.395 +  for (
   1.396 +    ent=ldap_first_entry(*ldp_ptr, res), i=1;
   1.397 +    ent;
   1.398 +    ent=ldap_next_entry(*ldp_ptr, ent), i++
   1.399 +  ) {
   1.400 +
   1.401 +    char *attr;       // name of attribute
   1.402 +    BerElement *ber;  // structure to iterate through attributes
   1.403 +    char *dn;         // LDAP entry name (distinguished name)
   1.404 +
   1.405 +    // create result table for one entry at stack position 2:
   1.406 +    lua_newtable(L);
   1.407 +
   1.408 +    // use ldap_first_attribute() and ldap_next_attribute()
   1.409 +    // as well as 'BerElement *ber' to iterate through all attributes
   1.410 +    // ('ber' must be free'd with ber_free(ber, 0) call later):
   1.411 +    for (
   1.412 +      attr=ldap_first_attribute(*ldp_ptr, ent, &ber);
   1.413 +      attr;
   1.414 +      attr=ldap_next_attribute(*ldp_ptr, ent, ber)
   1.415 +    ) {
   1.416 +
   1.417 +      struct berval **vals;  // pointer to (first element of) array of values
   1.418 +      struct berval **val;   // pointer to a value represented as 'struct berval' structure
   1.419 +      int j;                 // integer to fill a Lua table
   1.420 +
   1.421 +      // push the attribute name to Lua stack position 3:
   1.422 +      lua_pushstring(L, attr);
   1.423 +
   1.424 +      // create a new table for the attribute's values on Lua stack position 4:
   1.425 +      lua_newtable(L);
   1.426 +
   1.427 +      // call ldap_get_values_len() to obtain the values
   1.428 +      // (required to be free'd later with ldap_value_free_len()):
   1.429 +      vals = ldap_get_values_len(*ldp_ptr, ent, attr);
   1.430 +
   1.431 +      // iterate through values and count 'j' from 1 up:
   1.432 +      for (val=vals, j=1; *val; val++, j++) {
   1.433 +
   1.434 +        // push value to Lua stack position 5:
   1.435 +        lua_pushlstring(L, (*val)->bv_val, (*val)->bv_len);
   1.436 +
   1.437 +        // pop value from Lua stack position 5
   1.438 +        // and store it in table on Lua stack position 4:
   1.439 +        lua_rawseti(L, 4, j);
   1.440 +
   1.441 +      }
   1.442 +
   1.443 +      // free data structure of values:
   1.444 +      ldap_value_free_len(vals);
   1.445 +
   1.446 +      // pop attribute name from Lua stack position 3
   1.447 +      // and pop value table from Lua stack position 4
   1.448 +      // and store them in result table for entry at Lua stack position 2:
   1.449 +      lua_settable(L, 2);
   1.450 +
   1.451 +    }
   1.452 +
   1.453 +    // free 'BerElement *ber' stucture that has been used to iterate through all attributes
   1.454 +    // (second argument is zero due to manpage of ldap_first_attribute()):
   1.455 +    ber_free(ber, 0);
   1.456 +
   1.457 +    // store distinguished name (DN) on Lua stack position 3
   1.458 +    // (aquired memory is free'd with ldap_memfree()):
   1.459 +    dn = ldap_get_dn(*ldp_ptr, ent);
   1.460 +    lua_pushstring(L, dn);
   1.461 +    ldap_memfree(dn);
   1.462 +
   1.463 +    // pop distinguished name (DN) from Lua stack position 3
   1.464 +    // and store it in field "dn" of entry result table at stack position 2
   1.465 +    lua_setfield(L, 2, "dn");
   1.466 +
   1.467 +    // pop entry result table from Lua stack position 2
   1.468 +    // and store it in table at stack position 1:
   1.469 +    lua_rawseti(L, 1, i);
   1.470 +    
   1.471 +  }
   1.472 +
   1.473 +  // return result table from top of Lua stack (stack position 1):
   1.474 +  return 1;
   1.475 +
   1.476 +}
   1.477 +
   1.478 +static int mldap_unbind(lua_State *L) {
   1.479 +  // Lua C function used as "unbind" function of module and "unbind" method of Lua userdata object
   1.480 +  // closing the LDAP connection (if still open)
   1.481 +  // returning nothing
   1.482 +
   1.483 +  LDAP **ldp_ptr;  // pointer to a pointer to the OpenLDAP structure representing the connection
   1.484 +
   1.485 +  // check if the first argument is a Lua userdata object with the correct metatable
   1.486 +  // and get a C pointer to that userdata object:
   1.487 +  ldp_ptr = luaL_checkudata(L, 1, MLDAP_REGKEY "connection_metatable");
   1.488 +
   1.489 +  // check if the Lua userdata object still contains a pointer:
   1.490 +  if (*ldp_ptr) {
   1.491 +
   1.492 +    // if it does, then call ldap_unbind_ext_s():
   1.493 +    ldap_unbind_ext_s(
   1.494 +      *ldp_ptr,  // pointer to the opaque OpenLDAP structure representing the connection
   1.495 +      NULL,      // no server controls
   1.496 +      NULL       // no client controls
   1.497 +    );
   1.498 +
   1.499 +    // store NULL pointer in Lua userdata to mark connection as closed
   1.500 +    *ldp_ptr = NULL;
   1.501 +  }
   1.502 +
   1.503 +  // returning nothing:
   1.504 +  return 0;
   1.505 +
   1.506 +}
   1.507 +
   1.508 +
   1.509 +// registration information for library functions:
   1.510 +static const struct luaL_Reg mldap_module_functions[] = {
   1.511 +  {"bind", mldap_bind},
   1.512 +  {"unbind", mldap_unbind},
   1.513 +  {NULL, NULL}
   1.514 +};
   1.515 +
   1.516 +
   1.517 +// registration information for methods of connection object: 
   1.518 +static const struct luaL_Reg mldap_connection_methods[] = {
   1.519 +  {"search", mldap_search},
   1.520 +  {"unbind", mldap_unbind},
   1.521 +  {NULL, NULL}
   1.522 +};
   1.523 +
   1.524 +
   1.525 +// registration information for connection metatable: 
   1.526 +static const struct luaL_Reg mldap_connection_metamethods[] = {
   1.527 +  {"__gc", mldap_unbind},
   1.528 +  {NULL, NULL}
   1.529 +};
   1.530 +
   1.531 +
   1.532 +// luaopen function to initialize/register library:
   1.533 +int luaopen_mldap(lua_State *L) {
   1.534 +
   1.535 +  // clear Lua stack:
   1.536 +  lua_settop(L, 0);
   1.537 +
   1.538 +  // create table with library functions on Lua stack position 1:
   1.539 +  luaL_newlib(L, mldap_module_functions);
   1.540 +
   1.541 +  // create metatable for connection objects on Lua stack position 2:
   1.542 +  luaL_newlib(L, mldap_connection_metamethods);
   1.543 +
   1.544 +  // create table with methods for connection object on Lua stack position 3:
   1.545 +  luaL_newlib(L, mldap_connection_methods);
   1.546 +
   1.547 +  // pop table with methods for connection object from Lua stack position 3
   1.548 +  // and store it as "__index" in metatable:
   1.549 +  lua_setfield(L, 2, "__index");
   1.550 +
   1.551 +  // pop table with metatable for connection objects from Lua stack position 2
   1.552 +  // and store it in the Lua registry:
   1.553 +  lua_setfield(L, LUA_REGISTRYINDEX, MLDAP_REGKEY "connection_metatable");
   1.554 +
   1.555 +  // create table for error code mappings on Lua stack position 2:
   1.556 +  lua_newtable(L);
   1.557 +
   1.558 +  // fill table for error code mappings
   1.559 +  // that maps integer error codes to error code strings
   1.560 +  // and vice versa:
   1.561 +  mldap_set_errorcodes(L);
   1.562 +
   1.563 +  // pop table for error code mappings from Lua stack position 2
   1.564 +  // and store it as "errorcodes" in table with library functions:
   1.565 +  lua_setfield(L, 1, "errorcodes");
   1.566 +
   1.567 +  // return table with library functions from top of Lua stack:
   1.568 +  return 1;
   1.569 +
   1.570 +}

Impressum / About Us