liquid_feedback_frontend

annotate lib/mldap/mldap.c @ 1858:3d1f0464a3ea

Handle missing ldap.member.allowed function
author bsw
date Tue Sep 20 17:35:29 2022 +0200 (21 months ago)
parents ab837b075cf7
children
rev   line source
bsw@1071 1 /*
bsw@1071 2 * minimalistic Lua LDAP interface library
bsw@1071 3 *
bsw@1071 4 * The library does not set any global variable itself and must thus be
bsw@1071 5 * loaded with
bsw@1071 6 *
bsw@1071 7 * mldap = require("mldap")
bsw@1071 8 *
bsw@1071 9 * or a similar statement.
bsw@1071 10 *
bsw@1071 11 * The library provides two functions, conn = bind{...} and unbind(conn)
bsw@1071 12 * to connect to and disconnect from the LDAP server respectively. The
bsw@1071 13 * unbind function is also provided as a method of the connection userdata
bsw@1071 14 * object (see below).
bsw@1071 15 *
bsw@1071 16 * The arguments to the bind{...} function are documented in the source code
bsw@1071 17 * (see C function mldap_bind). In case of success, the bind function returns
bsw@1071 18 * a userdata object that provides two methods: query{...} and unbind(). In
bsw@1071 19 * case of error, the bind function returns nil as first return value, an
bsw@1071 20 * error string as second return value, and a numeric error code as third
bsw@1071 21 * return value. A positive error code is an LDAP resultCode, a negative
bsw@1071 22 * error code is an OpenLDAP API error code:
bsw@1071 23 *
bsw@1071 24 * connection, error_string, numeric_error_code = mldap.bind{...}
bsw@1071 25 *
bsw@1071 26 * For translating numeric error codes to an identifying (machine readable)
bsw@1071 27 * string identifier, the library provides in addition to the two functions
bsw@1071 28 * a table named 'errorcodes', for example:
bsw@1071 29 *
bsw@1071 30 * 49 == mldap.errorcodes["invalid_credentials"]
bsw@1071 31 *
bsw@1071 32 * and
bsw@1071 33 *
bsw@1071 34 * mldap.errorcodes[49] == "invalid_credentials"
bsw@1071 35 *
bsw@1071 36 * The arguments and return value of the query{...} method of the connection
bsw@1071 37 * userdata object are also documented in the source code below (see
bsw@1071 38 * C function mldap_query). Error conditions are reported the same way as the
bsw@1071 39 * bind{...} function does.
bsw@1071 40 *
bsw@1071 41 * To close the connection, either the unbind() function of the library or
bsw@1071 42 * the unbind() method can be called; it is allowed to call them multiple
bsw@1071 43 * times, and they are also invoked by the garbage collector.
bsw@1071 44 *
bsw@1071 45 */
bsw@1071 46
bsw@1071 47 // Lua header inclusions:
bsw@1071 48 #include <lua.h>
bsw@1071 49 #include <lauxlib.h>
bsw@1071 50
bsw@1071 51 // OpenLDAP header inclusions:
bsw@1071 52 #include <ldap.h>
bsw@1071 53
bsw@1071 54 // Standard C inclusions:
bsw@1071 55 #include <stdlib.h>
bsw@1071 56 #include <stdbool.h>
bsw@1071 57 #include <unistd.h>
bsw@1071 58
bsw@1071 59 // Error code translation is included from separate C file:
bsw@1071 60 #include "mldap_errorcodes.c"
bsw@1071 61
bsw@1071 62 // Provide compatibility with Lua 5.1:
bsw@1071 63 #if LUA_VERSION_NUM < 502
bsw@1071 64 #define luaL_newlib(L, t) lua_newtable((L)); luaL_register(L, NULL, t)
bsw@1071 65 #define lua_rawlen lua_objlen
bsw@1071 66 #define lua_len lua_objlen
bsw@1071 67 #define luaL_setmetatable(L, regkey) \
bsw@1071 68 lua_getfield((L), LUA_REGISTRYINDEX, (regkey)); \
bsw@1071 69 lua_setmetatable((L), -2);
bsw@1071 70 #endif
bsw@1071 71
bsw@1071 72 // prefix for all Lua registry entries of this library:
bsw@1071 73 #define MLDAP_REGKEY "556aeaf3c864af2e_mldap_"
bsw@1071 74
bsw@1071 75
bsw@1071 76 static const char *mldap_get_named_string_arg(
bsw@1071 77 // gets a named argument of type "string" from a table at the given stack position
bsw@1071 78
bsw@1071 79 lua_State *L, // pointer to lua_State variable
bsw@1071 80 int idx, // stack index of the table containing the named arguments
bsw@1071 81 const char *argname, // name of the argument
jbe@1641 82 bool mandatory // if not 0, then the argument is mandatory and an error is raised if it isn't found
bsw@1071 83
bsw@1071 84 // leaves the string as new element on top of the stack
bsw@1071 85 ) {
bsw@1071 86
bsw@1071 87 // pushes the table entry with the given argument name on top of the stack:
bsw@1071 88 lua_getfield(L, idx, argname);
bsw@1071 89
bsw@1071 90 // check, if the entry is nil or false:
bsw@1071 91 if (!lua_toboolean(L, -1)) {
bsw@1071 92
bsw@1071 93 // throw error, if named argument is mandatory:
bsw@1071 94 if (mandatory) return luaL_error(L, "Named argument '%s' missing", argname), NULL;
bsw@1071 95
bsw@1071 96 // return NULL pointer, if named argument is not mandatory:
bsw@1071 97 return NULL;
bsw@1071 98
bsw@1071 99 }
bsw@1071 100
bsw@1071 101 // throw error, if the value of the argument is not string:
bsw@1071 102 if (lua_type(L, -1) != LUA_TSTRING) return luaL_error(L, "Named argument '%s' is not a string", argname), NULL;
bsw@1071 103
bsw@1071 104 // return a pointer to the string, leaving the string on top of the stack to avoid garbage collection:
bsw@1071 105 return lua_tostring(L, -1);
bsw@1071 106
bsw@1071 107 // leaves one element on the stack
bsw@1071 108 }
bsw@1071 109
bsw@1071 110
bsw@1071 111 static int mldap_get_named_number_arg(
bsw@1071 112 // gets a named argument of type "number" from a table at the given stack position
bsw@1071 113
bsw@1071 114 lua_State *L, // pointer to lua_State variable
bsw@1071 115 int idx, // stack index of the table containing the named arguments
bsw@1071 116 const char *argname, // name of the argument
jbe@1641 117 bool mandatory, // if not 0, then the argument is mandatory and an error is raised if it isn't found
jbe@1641 118 lua_Number default_value // default value to return, if the argument is not mandatory and nil
bsw@1071 119
bsw@1071 120 // opposed to 'mldap_get_named_string_arg', this function leaves no element on the stack
bsw@1071 121 ) {
bsw@1071 122
bsw@1071 123 lua_Number value; // value to return
bsw@1071 124
bsw@1071 125 // pushes the table entry with the given argument name on top of the stack:
bsw@1071 126 lua_getfield(L, idx, argname);
bsw@1071 127
bsw@1071 128 // check, if the entry is nil or false:
bsw@1071 129 if (lua_isnil(L, -1)) {
bsw@1071 130
bsw@1071 131 // throw error, if named argument is mandatory:
bsw@1071 132 if (mandatory) return luaL_error(L, "Named argument '%s' missing", argname), 0;
bsw@1071 133
bsw@1071 134 // set default value as return value, if named argument is not mandatory:
bsw@1071 135 value = default_value;
bsw@1071 136
bsw@1071 137 } else {
bsw@1071 138
bsw@1071 139 // throw error, if the value of the argument is not a number:
bsw@1071 140 if (lua_type(L, -1) != LUA_TNUMBER) return luaL_error(L, "Named argument '%s' is not a number", argname), 0;
bsw@1071 141
bsw@1071 142 // set return value to the number:
bsw@1071 143 value = lua_tonumber(L, -1);
bsw@1071 144
bsw@1071 145 }
bsw@1071 146
bsw@1071 147 // remove unnecessary element from stack (not needed to avoid garbage collection):
jbe@1641 148 lua_pop(L, 1);
jbe@1641 149
bsw@1071 150 return value;
bsw@1071 151
bsw@1071 152 // leaves no new elements on the stack
bsw@1071 153 }
bsw@1071 154
bsw@1071 155
bsw@1640 156 static bool mldap_get_named_boolean_arg(
bsw@1640 157 // gets a named argument of type "boolean" from a table at the given stack position
bsw@1640 158
bsw@1640 159 lua_State *L, // pointer to lua_State variable
bsw@1640 160 int idx, // stack index of the table containing the named arguments
bsw@1640 161 const char *argname, // name of the argument
jbe@1641 162 bool mandatory, // if not 0, then the argument is mandatory and an error is raised if it isn't found
bsw@1640 163 bool default_value // default value to return, if the argument is not mandatory and nil
bsw@1640 164
bsw@1640 165 // opposed to 'mldap_get_named_string_arg', this function leaves no element on the stack
bsw@1640 166 ) {
bsw@1640 167
bsw@1640 168 bool value; // value to return
bsw@1640 169
bsw@1640 170 // pushes the table entry with the given argument name on top of the stack:
bsw@1640 171 lua_getfield(L, idx, argname);
bsw@1640 172
bsw@1640 173 // check, if the entry is nil:
bsw@1640 174 if (lua_isnil(L, -1)) {
bsw@1640 175
bsw@1640 176 // throw error, if named argument is mandatory:
bsw@1640 177 if (mandatory) return luaL_error(L, "Named argument '%s' missing", argname), 0;
bsw@1640 178
bsw@1640 179 // set default value as return value, if named argument is not mandatory:
bsw@1640 180 value = default_value;
bsw@1640 181
bsw@1640 182 } else {
bsw@1640 183
bsw@1640 184 // throw error, if the value of the argument is not a number:
bsw@1640 185 if (lua_type(L, -1) != LUA_TBOOLEAN) return luaL_error(L, "Named argument '%s' is not a boolean", argname), 0;
bsw@1640 186
bsw@1640 187 // set return value to the number:
bsw@1640 188 value = lua_toboolean(L, -1);
bsw@1640 189
bsw@1640 190 }
bsw@1640 191
bsw@1640 192 // remove unnecessary element from stack (not needed to avoid garbage collection):
bsw@1640 193 lua_pop(L, 1);
bsw@1640 194
bsw@1640 195 return value;
bsw@1640 196
bsw@1640 197 // leaves no new elements on the stack
bsw@1640 198 }
bsw@1640 199
bsw@1640 200
bsw@1071 201 static int mldap_scope(
bsw@1071 202 // converts a string ("base", "onelevel", "subtree", "children") to an integer representing the LDAP scope
bsw@1071 203 // and throws an error for any unknown string
bsw@1071 204
bsw@1071 205 lua_State *L, // pointer to lua_State variable (needed to throw errors)
bsw@1071 206 const char *scope_string // string that is either ("base", "onelevel", "subtree", "children")
bsw@1071 207
bsw@1071 208 // does not affect or use the Lua stack at all
bsw@1071 209 ) {
bsw@1071 210
bsw@1071 211 // return integer according to string value:
bsw@1071 212 if (!strcmp(scope_string, "base")) return LDAP_SCOPE_BASE;
bsw@1071 213 if (!strcmp(scope_string, "onelevel")) return LDAP_SCOPE_ONELEVEL;
bsw@1071 214 if (!strcmp(scope_string, "subtree")) return LDAP_SCOPE_SUBTREE;
bsw@1071 215 if (!strcmp(scope_string, "children")) return LDAP_SCOPE_CHILDREN;
bsw@1071 216
bsw@1071 217 // throw error for unknown string values:
bsw@1071 218 return luaL_error(L, "Invalid LDAP scope: '%s'", scope_string), 0;
bsw@1071 219
bsw@1071 220 }
bsw@1071 221
bsw@1071 222
bsw@1071 223 static int mldap_bind(lua_State *L) {
bsw@1071 224 // Lua C function that takes named arguments as a table
bsw@1071 225 // and returns a userdata object, representing the LDAP connection
bsw@1071 226 // or returns nil, an error string, and an error code (integer) on error
bsw@1071 227
bsw@1071 228 // named arguments:
bsw@1071 229 // "uri" (string) server URI to connect to
bsw@1071 230 // "who" (string) DN to bind as
bsw@1071 231 // "password" (string) password for DN to bind as
bsw@1071 232 // "timeout" (number) timeout in seconds
bsw@1640 233 // "tls" (boolean) use TLS
bsw@1071 234
bsw@1071 235 static const int ldap_version = LDAP_VERSION3; // providing a pointer (&ldap_version) to set LDAP protocol version 3
bsw@1071 236 const char *uri; // C string for "uri" argument
bsw@1640 237 bool tls; // boolean indicating if TLS is to be used
bsw@1071 238 const char *who; // C string for "who" argument
bsw@1071 239 struct berval cred; // credentials ("password") are stored as struct berval
bsw@1071 240 lua_Number timeout_float; // float (lua_Number) for timeout
bsw@1071 241 struct timeval timeout; // timeout is stored as struct timeval
bsw@1071 242 int ldap_error; // LDAP error code (as returned by libldap calls)
bsw@1071 243 LDAP *ldp; // pointer to an opaque OpenLDAP structure representing the connection
bsw@1071 244 LDAP **ldp_ptr; // pointer to a Lua userdata structure (that only contains the 'ldp' pointer)
bsw@1071 245
bsw@1071 246 // throw error if first argument is not a table:
bsw@1071 247 if (lua_type(L, 1) != LUA_TTABLE) {
bsw@1071 248 luaL_error(L, "Argument to function 'bind' is not a table.");
bsw@1071 249 }
bsw@1071 250
bsw@1071 251 // extract arguments:
bsw@1071 252 uri = mldap_get_named_string_arg(L, 1, "uri", true);
bsw@1640 253 tls = mldap_get_named_boolean_arg(L, 1, "tls", false, false);
bsw@1071 254 who = mldap_get_named_string_arg(L, 1, "who", false);
jbe@1638 255 cred.bv_val = (char *)mldap_get_named_string_arg(L, 1, "password", false);
jbe@1638 256 // use (char *) cast to suppress compiler warning (should be const anyway)
bsw@1071 257 if (cred.bv_val) cred.bv_len = strlen(cred.bv_val);
bsw@1071 258 else cred.bv_len = 0;
bsw@1071 259 timeout_float = mldap_get_named_number_arg(L, 1, "timeout", false, -1);
bsw@1071 260 timeout.tv_sec = timeout_float;
bsw@1071 261 timeout.tv_usec = (timeout_float - timeout.tv_sec) * 1000000;
bsw@1071 262
bsw@1071 263 // initialize OpenLDAP structure and provide URI for connection:
bsw@1071 264 ldap_error = ldap_initialize(&ldp, uri);
bsw@1071 265 // on error, jump to label "mldap_queryconn_error1", as no ldap_unbind_ext_s() is needed:
bsw@1071 266 if (ldap_error != LDAP_SUCCESS) goto mldap_queryconn_error1;
bsw@1071 267
bsw@1071 268 // set LDAP protocol version 3:
bsw@1071 269 ldap_error = ldap_set_option(ldp, LDAP_OPT_PROTOCOL_VERSION, &ldap_version);
bsw@1071 270 // on error, jump to label "mldap_queryconn_error2", as ldap_unbind_ext_s() must be called:
bsw@1071 271 if (ldap_error != LDAP_SUCCESS) goto mldap_queryconn_error2;
bsw@1071 272
bsw@1071 273 // set timeout for asynchronous OpenLDAP library calls:
bsw@1071 274 ldap_error = ldap_set_option(ldp, LDAP_OPT_TIMEOUT, &timeout);
bsw@1071 275 // on error, jump to label "mldap_queryconn_error2", as ldap_unbind_ext_s() must be called:
bsw@1071 276 if (ldap_error != LDAP_SUCCESS) goto mldap_queryconn_error2;
bsw@1071 277
bsw@1640 278 // initiate TLS if requested
bsw@1640 279 if (tls) {
bsw@1640 280 ldap_error = ldap_start_tls_s(ldp, NULL, NULL);
bsw@1640 281 if (ldap_error != LDAP_SUCCESS) goto mldap_queryconn_error2;
bsw@1640 282 }
bsw@1640 283
bsw@1071 284 // connect to LDAP server:
bsw@1071 285 ldap_error = ldap_sasl_bind_s(
bsw@1071 286 ldp, // pointer to opaque OpenLDAP structure representing the connection
bsw@1071 287 who, // DN to bind as
bsw@1071 288 LDAP_SASL_SIMPLE, // SASL mechanism "simple" for password authentication
bsw@1071 289 &cred, // password as struct berval
bsw@1071 290 NULL, // no server controls
bsw@1071 291 NULL, // no client controls
bsw@1071 292 NULL // do not store server credentials
bsw@1071 293 );
bsw@1071 294
bsw@1071 295 // error handling:
bsw@1071 296 if (ldap_error != LDAP_SUCCESS) {
bsw@1071 297
bsw@1071 298 // error label to jump to, if a call of ldap_unbind_ext_s() is required:
bsw@1071 299 mldap_queryconn_error2:
bsw@1071 300
bsw@1071 301 // close connection and free resources:
bsw@1071 302 ldap_unbind_ext_s(ldp, NULL, NULL);
bsw@1071 303
bsw@1071 304 // error label to jump to, if no call of ldap_unbind_ext_s() is required:
bsw@1071 305 mldap_queryconn_error1:
bsw@1071 306
bsw@1071 307 // return three values:
bsw@1071 308 lua_pushnil(L); // return nil as first value
bsw@1071 309 lua_pushstring(L, ldap_err2string(ldap_error)); // return error string as second value
bsw@1071 310 lua_pushinteger(L, ldap_error); // return error code (integer) as third value
bsw@1071 311 return 3;
bsw@1071 312
bsw@1071 313 }
bsw@1071 314
bsw@1071 315 // create new Lua userdata object (that will contain the 'ldp' pointer) on top of stack:
bsw@1071 316 ldp_ptr = lua_newuserdata(L, sizeof(LDAP *));
bsw@1071 317
bsw@1071 318 // set metatable of Lua userdata object:
bsw@1071 319 luaL_setmetatable(L, MLDAP_REGKEY "connection_metatable");
bsw@1071 320
bsw@1071 321 // write contents of Lua userdata object (the 'ldp' pointer):
bsw@1071 322 *ldp_ptr = ldp;
bsw@1071 323
bsw@1071 324 // return Lua userdata object from top of stack:
bsw@1071 325 return 1;
bsw@1071 326
bsw@1071 327 }
bsw@1071 328
bsw@1071 329
bsw@1071 330 static int mldap_search(lua_State *L) {
bsw@1071 331 // Lua C function used as "search" method of Lua userdata object representing the LDAP connection
bsw@1071 332 // that takes a Lua userdata object (the LDAP connection) as first argument,
bsw@1071 333 // a table with named arguments as second argument,
bsw@1071 334 // and returns a result table on success (see below)
bsw@1071 335 // or returns nil, an error string, and an error code (integer) on error
bsw@1071 336
bsw@1071 337 // named arguments:
bsw@1071 338 // "base" (string) DN of the entry at which to start the search
bsw@1071 339 // "scope" (string) scope of the search, one of:
bsw@1071 340 // "base" to search the object itself
bsw@1071 341 // "onelevel" to search the object's immediate children
bsw@1071 342 // "subtree" to search the object and all its descendants
bsw@1071 343 // "children" to search all of the descendants
bsw@1071 344 // "filter" (string) string representation of the filter to apply in the search
bsw@1071 345 // (conforming to RFC 4515 as extended in RFC 4526)
bsw@1071 346 // "attrs" (table) list of attribute descriptions (each a string) to return from matching entries
bsw@1071 347
bsw@1071 348 // structure of result table:
bsw@1071 349 // {
bsw@1071 350 // { dn = <distinguished name (DN)>,
bsw@1071 351 // <attr1> = { <value1>, <value2>, ... },
bsw@1071 352 // <attr2> = { <value1>, <value2>, ... },
bsw@1071 353 // ...
bsw@1071 354 // },
bsw@1071 355 // { dn = <distinguished name (DN)>,
bsw@1071 356 // <attr1> = { <value1>, <value2>, ... },
bsw@1071 357 // <attr2> = { <value1>, <value2>, ... },
bsw@1071 358 // ...
bsw@1071 359 // },
bsw@1071 360 // ...
bsw@1071 361 // }
bsw@1071 362
bsw@1071 363 const char *base; // C string for "base" argument
bsw@1071 364 const char *scope_string; // C string for "scope" argument
bsw@1071 365 int scope; // integer representing the scope
bsw@1071 366 const char *filter; // C string for "filter" argument
bsw@1071 367 size_t nattrs; // number of attributes in "attrs" argument
jbe@1638 368 const char **attrs; // C string array of "attrs" argument
bsw@1071 369 size_t attr_idx; // index variable for building the C string array of "attrs"
bsw@1071 370 int ldap_error; // LDAP error code (as returned by libldap calls)
bsw@1071 371 LDAP **ldp_ptr; // pointer to a pointer to the OpenLDAP structure representing the connection
bsw@1071 372 LDAPMessage *res; // pointer to the result of ldap_search_ext_s() call
bsw@1071 373 LDAPMessage *ent; // pointer to an entry in the result of ldap_search_ext_s() call
bsw@1071 374 int i; // integer to fill the Lua table returned as result
bsw@1071 375
bsw@1071 376 // truncate the Lua stack to 2 elements:
bsw@1071 377 lua_settop(L, 2);
bsw@1071 378
bsw@1071 379 // check if the first argument is a Lua userdata object with the correct metatable
bsw@1071 380 // and get a C pointer to that userdata object:
bsw@1071 381 ldp_ptr = luaL_checkudata(L, 1, MLDAP_REGKEY "connection_metatable");
bsw@1071 382
bsw@1071 383 // throw an error, if the connection has already been closed:
bsw@1071 384 if (!*ldp_ptr) {
bsw@1071 385 return luaL_error(L, "LDAP connection has already been closed");
bsw@1071 386 }
bsw@1071 387
bsw@1071 388 // check if the second argument is a table, and throw an error if it's not a table:
bsw@1071 389 if (lua_type(L, 2) != LUA_TTABLE) {
bsw@1071 390 luaL_error(L, "Argument to function 'bind' is not a table.");
bsw@1071 391 }
bsw@1071 392
bsw@1071 393 // extract named arguments (requires memory allocation for 'attrs'):
bsw@1071 394 base = mldap_get_named_string_arg(L, 2, "base", true); // pushed to 3
bsw@1071 395 scope_string = mldap_get_named_string_arg(L, 2, "scope", true); // pushed to 4
bsw@1071 396 scope = mldap_scope(L, scope_string);
bsw@1071 397 lua_pop(L, 1); // removes stack element 4
bsw@1071 398 filter = mldap_get_named_string_arg(L, 2, "filter", false); // pushed to 4
bsw@1071 399 lua_getfield(L, 2, "attrs"); // pushed to 5
bsw@1634 400 nattrs = luaL_len(L, -1);
bsw@1071 401 attrs = calloc(nattrs + 1, sizeof(char *)); // memory allocation, +1 for terminating NULL
bsw@1071 402 if (!attrs) return luaL_error(L, "Memory allocation error in C function 'mldap_queryconn'");
bsw@1071 403 for (attr_idx=0; attr_idx<nattrs; attr_idx++) {
bsw@1071 404 lua_pushinteger(L, attr_idx+1);
bsw@1071 405 lua_gettable(L, 5); // pushed onto variable stack position
bsw@1071 406 if (lua_type(L, -1) != LUA_TSTRING) {
bsw@1071 407 free(attrs);
bsw@1071 408 return luaL_error(L, "Element in attribute list is not a string");
bsw@1071 409 }
bsw@1636 410 attrs[attr_idx] = lua_tostring(L, -1);
bsw@1071 411 }
bsw@1071 412 // attrs[nattrs] = NULL; // unnecessary due to calloc
bsw@1071 413
bsw@1071 414 // execute LDAP search and store pointer to the result in 'res':
bsw@1071 415 ldap_error = ldap_search_ext_s(
bsw@1071 416 *ldp_ptr, // pointer to the opaque OpenLDAP structure representing the connection
bsw@1071 417 base, // DN of the entry at which to start the search
bsw@1071 418 scope, // scope of the search
bsw@1071 419 filter, // string representation of the filter to apply in the search
jbe@1638 420 (char **)attrs, // array of attribute descriptions (array of strings)
jbe@1638 421 // cast to suppress compiler warning (should be const anyway)
bsw@1071 422 0, // do not only request attribute descriptions but also values
bsw@1071 423 NULL, // no server controls
bsw@1071 424 NULL, // no client controls
bsw@1071 425 NULL, // do not set another timeout
bsw@1071 426 0, // no sizelimit
bsw@1071 427 &res // store result in 'res'
bsw@1071 428 );
bsw@1071 429
bsw@1071 430 // free data structures that have been allocated for the 'attrs' array:
bsw@1071 431 free(attrs);
bsw@1071 432
bsw@1071 433 // return nil, an error string, and an error code (integer) in case of error:
bsw@1071 434 if (ldap_error != LDAP_SUCCESS) {
bsw@1071 435 lua_pushnil(L);
bsw@1071 436 lua_pushstring(L, ldap_err2string(ldap_error));
bsw@1071 437 lua_pushinteger(L, ldap_error);
bsw@1071 438 return 3;
bsw@1071 439 }
bsw@1071 440
bsw@1071 441 // clear Lua stack:
bsw@1071 442 lua_settop(L, 0);
bsw@1071 443
bsw@1071 444 // create result table for all entries at stack position 1:
bsw@1071 445 lua_newtable(L);
bsw@1071 446
bsw@1071 447 // use ldap_first_entry() and ldap_next_entry() functions
bsw@1071 448 // to iterate through all entries in the result 'res'
bsw@1071 449 // and count 'i' from 1 up:
bsw@1071 450 for (
bsw@1071 451 ent=ldap_first_entry(*ldp_ptr, res), i=1;
bsw@1071 452 ent;
bsw@1071 453 ent=ldap_next_entry(*ldp_ptr, ent), i++
bsw@1071 454 ) {
bsw@1071 455
bsw@1071 456 char *attr; // name of attribute
bsw@1071 457 BerElement *ber; // structure to iterate through attributes
bsw@1071 458 char *dn; // LDAP entry name (distinguished name)
bsw@1071 459
bsw@1071 460 // create result table for one entry at stack position 2:
bsw@1071 461 lua_newtable(L);
bsw@1071 462
bsw@1071 463 // use ldap_first_attribute() and ldap_next_attribute()
bsw@1071 464 // as well as 'BerElement *ber' to iterate through all attributes
bsw@1071 465 // ('ber' must be free'd with ber_free(ber, 0) call later):
bsw@1071 466 for (
bsw@1071 467 attr=ldap_first_attribute(*ldp_ptr, ent, &ber);
bsw@1071 468 attr;
bsw@1071 469 attr=ldap_next_attribute(*ldp_ptr, ent, ber)
bsw@1071 470 ) {
bsw@1071 471
bsw@1071 472 struct berval **vals; // pointer to (first element of) array of values
bsw@1071 473 struct berval **val; // pointer to a value represented as 'struct berval' structure
bsw@1071 474 int j; // integer to fill a Lua table
bsw@1071 475
bsw@1071 476 // push the attribute name to Lua stack position 3:
bsw@1071 477 lua_pushstring(L, attr);
bsw@1071 478
bsw@1071 479 // create a new table for the attribute's values on Lua stack position 4:
bsw@1071 480 lua_newtable(L);
bsw@1071 481
bsw@1071 482 // call ldap_get_values_len() to obtain the values
bsw@1071 483 // (required to be free'd later with ldap_value_free_len()):
bsw@1071 484 vals = ldap_get_values_len(*ldp_ptr, ent, attr);
bsw@1071 485
bsw@1071 486 // iterate through values and count 'j' from 1 up:
bsw@1071 487 for (val=vals, j=1; *val; val++, j++) {
bsw@1071 488
bsw@1071 489 // push value to Lua stack position 5:
bsw@1071 490 lua_pushlstring(L, (*val)->bv_val, (*val)->bv_len);
bsw@1071 491
bsw@1071 492 // pop value from Lua stack position 5
bsw@1071 493 // and store it in table on Lua stack position 4:
bsw@1071 494 lua_rawseti(L, 4, j);
bsw@1071 495
bsw@1071 496 }
bsw@1071 497
bsw@1071 498 // free data structure of values:
bsw@1071 499 ldap_value_free_len(vals);
bsw@1071 500
bsw@1071 501 // pop attribute name from Lua stack position 3
bsw@1071 502 // and pop value table from Lua stack position 4
bsw@1071 503 // and store them in result table for entry at Lua stack position 2:
bsw@1071 504 lua_settable(L, 2);
bsw@1071 505
bsw@1071 506 }
bsw@1071 507
bsw@1071 508 // free 'BerElement *ber' stucture that has been used to iterate through all attributes
bsw@1071 509 // (second argument is zero due to manpage of ldap_first_attribute()):
bsw@1071 510 ber_free(ber, 0);
bsw@1071 511
bsw@1071 512 // store distinguished name (DN) on Lua stack position 3
bsw@1071 513 // (aquired memory is free'd with ldap_memfree()):
bsw@1071 514 dn = ldap_get_dn(*ldp_ptr, ent);
bsw@1071 515 lua_pushstring(L, dn);
bsw@1071 516 ldap_memfree(dn);
bsw@1071 517
bsw@1071 518 // pop distinguished name (DN) from Lua stack position 3
bsw@1071 519 // and store it in field "dn" of entry result table at stack position 2
bsw@1071 520 lua_setfield(L, 2, "dn");
bsw@1071 521
bsw@1071 522 // pop entry result table from Lua stack position 2
bsw@1071 523 // and store it in table at stack position 1:
bsw@1071 524 lua_rawseti(L, 1, i);
bsw@1071 525
bsw@1071 526 }
bsw@1071 527
bsw@1071 528 // return result table from top of Lua stack (stack position 1):
bsw@1071 529 return 1;
bsw@1071 530
bsw@1071 531 }
bsw@1071 532
bsw@1071 533 static int mldap_unbind(lua_State *L) {
bsw@1071 534 // Lua C function used as "unbind" function of module and "unbind" method of Lua userdata object
bsw@1071 535 // closing the LDAP connection (if still open)
bsw@1071 536 // returning nothing
bsw@1071 537
bsw@1071 538 LDAP **ldp_ptr; // pointer to a pointer to the OpenLDAP structure representing the connection
bsw@1071 539
bsw@1071 540 // check if the first argument is a Lua userdata object with the correct metatable
bsw@1071 541 // and get a C pointer to that userdata object:
bsw@1071 542 ldp_ptr = luaL_checkudata(L, 1, MLDAP_REGKEY "connection_metatable");
bsw@1071 543
bsw@1071 544 // check if the Lua userdata object still contains a pointer:
bsw@1071 545 if (*ldp_ptr) {
bsw@1071 546
bsw@1071 547 // if it does, then call ldap_unbind_ext_s():
bsw@1071 548 ldap_unbind_ext_s(
bsw@1071 549 *ldp_ptr, // pointer to the opaque OpenLDAP structure representing the connection
bsw@1071 550 NULL, // no server controls
bsw@1071 551 NULL // no client controls
bsw@1071 552 );
bsw@1071 553
bsw@1071 554 // store NULL pointer in Lua userdata to mark connection as closed
bsw@1071 555 *ldp_ptr = NULL;
bsw@1071 556 }
bsw@1071 557
bsw@1071 558 // returning nothing:
bsw@1071 559 return 0;
bsw@1071 560
bsw@1071 561 }
bsw@1071 562
bsw@1071 563
bsw@1071 564 // registration information for library functions:
bsw@1071 565 static const struct luaL_Reg mldap_module_functions[] = {
bsw@1071 566 {"bind", mldap_bind},
bsw@1071 567 {"unbind", mldap_unbind},
bsw@1071 568 {NULL, NULL}
bsw@1071 569 };
bsw@1071 570
bsw@1071 571
bsw@1071 572 // registration information for methods of connection object:
bsw@1071 573 static const struct luaL_Reg mldap_connection_methods[] = {
bsw@1071 574 {"search", mldap_search},
bsw@1071 575 {"unbind", mldap_unbind},
bsw@1071 576 {NULL, NULL}
bsw@1071 577 };
bsw@1071 578
bsw@1071 579
bsw@1071 580 // registration information for connection metatable:
bsw@1071 581 static const struct luaL_Reg mldap_connection_metamethods[] = {
bsw@1071 582 {"__gc", mldap_unbind},
bsw@1071 583 {NULL, NULL}
bsw@1071 584 };
bsw@1071 585
bsw@1071 586
bsw@1071 587 // luaopen function to initialize/register library:
bsw@1071 588 int luaopen_mldap(lua_State *L) {
bsw@1071 589
bsw@1071 590 // clear Lua stack:
bsw@1071 591 lua_settop(L, 0);
bsw@1071 592
bsw@1071 593 // create table with library functions on Lua stack position 1:
bsw@1071 594 luaL_newlib(L, mldap_module_functions);
bsw@1071 595
bsw@1071 596 // create metatable for connection objects on Lua stack position 2:
bsw@1071 597 luaL_newlib(L, mldap_connection_metamethods);
bsw@1071 598
bsw@1071 599 // create table with methods for connection object on Lua stack position 3:
bsw@1071 600 luaL_newlib(L, mldap_connection_methods);
bsw@1071 601
bsw@1071 602 // pop table with methods for connection object from Lua stack position 3
bsw@1071 603 // and store it as "__index" in metatable:
bsw@1071 604 lua_setfield(L, 2, "__index");
bsw@1071 605
bsw@1071 606 // pop table with metatable for connection objects from Lua stack position 2
bsw@1071 607 // and store it in the Lua registry:
bsw@1071 608 lua_setfield(L, LUA_REGISTRYINDEX, MLDAP_REGKEY "connection_metatable");
bsw@1071 609
bsw@1071 610 // create table for error code mappings on Lua stack position 2:
bsw@1071 611 lua_newtable(L);
bsw@1071 612
bsw@1071 613 // fill table for error code mappings
bsw@1071 614 // that maps integer error codes to error code strings
bsw@1071 615 // and vice versa:
bsw@1071 616 mldap_set_errorcodes(L);
bsw@1071 617
bsw@1071 618 // pop table for error code mappings from Lua stack position 2
bsw@1071 619 // and store it as "errorcodes" in table with library functions:
bsw@1071 620 lua_setfield(L, 1, "errorcodes");
bsw@1071 621
bsw@1071 622 // return table with library functions from top of Lua stack:
bsw@1071 623 return 1;
bsw@1071 624
bsw@1071 625 }

Impressum / About Us