00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00033 #include "ld_cmd.h"
00034 #include "ld_fld.h"
00035 #include "ld_con.h"
00036 #include "ld_mod.h"
00037 #include "ld_uri.h"
00038 #include "ld_cfg.h"
00039 #include "ld_res.h"
00040
00041 #include "../../mem/mem.h"
00042 #include "../../dprint.h"
00043 #include "../../ut.h"
00044
00045 #include <string.h>
00046
00047
00053 static void ld_cmd_free(db_cmd_t* cmd, struct ld_cmd* payload)
00054 {
00055 db_drv_free(&payload->gen);
00056 if (payload->result) pkg_free(payload->result);
00057 pkg_free(payload);
00058 }
00059
00060
00061 static int build_result_array(char*** res, db_cmd_t* cmd)
00062 {
00063 struct ld_fld* lfld;
00064 char** t;
00065 int i;
00066 if (cmd->result_count == 0) {
00067 *res = NULL;
00068 return 0;
00069 }
00070
00071 t = (char**)pkg_malloc(sizeof(char*) * (cmd->result_count + 1));
00072 if (t == NULL) {
00073 ERR("ldap: No memory left\n");
00074 return -1;
00075 }
00076 t[cmd->result_count] = NULL;
00077
00078 for(i = 0; i < cmd->result_count; i++) {
00079 lfld = DB_GET_PAYLOAD(cmd->result + i);
00080
00081 t[i] = lfld->attr.s;
00082 }
00083
00084 *res = t;
00085 return 0;
00086 }
00087
00088
00089 int ld_cmd(db_cmd_t* cmd)
00090 {
00091 struct ld_cmd* lcmd;
00092 struct ld_cfg* cfg;
00093 struct ld_fld* lfld;
00094 int i, j;
00095
00096 lcmd = (struct ld_cmd*)pkg_malloc(sizeof(struct ld_cmd));
00097 if (lcmd == NULL) {
00098 ERR("ldap: No memory left\n");
00099 goto error;
00100 }
00101 memset(lcmd, '\0', sizeof(struct ld_cmd));
00102 if (db_drv_init(&lcmd->gen, ld_cmd_free) < 0) goto error;
00103
00104 switch(cmd->type) {
00105 case DB_PUT:
00106 case DB_DEL:
00107 case DB_UPD:
00108 ERR("ldap: The driver does not support directory modifications yet.\n");
00109 goto error;
00110 break;
00111
00112 case DB_GET:
00113 break;
00114
00115 case DB_SQL:
00116 ERR("ldap: The driver does not support raw queries yet.\n");
00117 goto error;
00118 }
00119
00120 cfg = ld_find_cfg(&cmd->table);
00121 if (cfg == NULL) {
00122 ERR("ldap: Cannot find configuration for '%.*s', giving up\n",
00123 STR_FMT(&cmd->table));
00124 goto error;
00125 }
00126
00127 lcmd->base = cfg->base.s;
00128 lcmd->scope = cfg->scope;
00129
00130 lcmd->sizelimit = cfg->sizelimit;
00131 if (cfg->timelimit) {
00132 lcmd->timelimit.tv_sec = cfg->timelimit;
00133 lcmd->timelimit.tv_usec = 0;
00134 }
00135
00136 if (cfg->filter.s) {
00137 lcmd->filter = cfg->filter;
00138 }
00139 lcmd->chase_references = cfg->chase_references;
00140 lcmd->chase_referrals = cfg->chase_referrals;
00141
00142 if (ld_resolve_fld(cmd->match, cfg) < 0) goto error;
00143 if (ld_resolve_fld(cmd->result, cfg) < 0) goto error;
00144
00145
00146 for(i = 0; !DB_FLD_EMPTY(cmd->result) && !DB_FLD_LAST(cmd->result[i]); i++) {
00147 int n;
00148 lfld = DB_GET_PAYLOAD(cmd->result + i);
00149 lfld->filter = NULL;
00150
00151 for(j = 0, n = 0; !DB_FLD_EMPTY(cmd->match) && !DB_FLD_LAST(cmd->match[j]); j++) {
00152 if (strcmp(cmd->result[i].name, cmd->match[j].name) == 0)
00153 n++;
00154 }
00155
00156 if (n > 0) {
00157 lfld->filter = pkg_malloc((n+1)*sizeof(*(lfld->filter)));
00158 if (!lfld->filter) return -1 ;
00159 for(j = 0, n = 0; !DB_FLD_EMPTY(cmd->match) && !DB_FLD_LAST(cmd->match[j]); j++) {
00160 if (strcmp(cmd->result[i].name, cmd->match[j].name) == 0) {
00161 lfld->filter[n] = cmd->match+j;
00162 n++;
00163 }
00164 }
00165 lfld->filter[n] = NULL;
00166 }
00167 }
00168 if (build_result_array(&lcmd->result, cmd) < 0) goto error;
00169
00170 DB_SET_PAYLOAD(cmd, lcmd);
00171 return 0;
00172
00173 error:
00174 if (lcmd) {
00175 DB_SET_PAYLOAD(cmd, NULL);
00176 db_drv_free(&lcmd->gen);
00177 if (lcmd->result) pkg_free(lcmd->result);
00178 pkg_free(lcmd);
00179 }
00180 return -1;
00181 }
00182
00183
00184 int ld_cmd_exec(db_res_t* res, db_cmd_t* cmd)
00185 {
00186 db_con_t* con;
00187 struct ld_res* lres;
00188 struct ld_cmd* lcmd;
00189 struct ld_con* lcon;
00190 char* filter, *err_desc;
00191 int ret, err;
00192 LDAPMessage *msg, *resmsg;
00193 int reconn_cnt;
00194 int msgid;
00195 char *oid;
00196 struct berval *data;
00197 struct timeval restimeout;
00198
00199 filter = NULL;
00200 err_desc = NULL;
00201 resmsg = NULL;
00202
00203
00204
00205
00206 con = cmd->ctx->con[db_payload_idx];
00207 lcmd = DB_GET_PAYLOAD(cmd);
00208 lcon = DB_GET_PAYLOAD(con);
00209
00210 reconn_cnt = ld_reconnect_attempt;
00211
00212 if (ld_prepare_ldap_filter(&filter, cmd, &lcmd->filter) < 0) {
00213 ERR("ldap: Error while building LDAP search filter\n");
00214 goto error;
00215 }
00216
00217 DBG("ldap: ldap_search(base:'%s', filter:'%s')\n", lcmd->base, filter);
00218 do {
00219 if (lcon->flags & LD_CONNECTED) {
00220 ldap_set_option(lcon->con, LDAP_OPT_DEREF, ((void *)&lcmd->chase_references));
00221
00222 ldap_set_option(lcon->con, LDAP_OPT_REFERRALS, lcmd->chase_referrals?LDAP_OPT_ON:LDAP_OPT_OFF);
00223
00224 ret = ldap_search_ext(lcon->con, lcmd->base, lcmd->scope, filter,
00225 lcmd->result, 0, NULL, NULL,
00226 lcmd->timelimit.tv_sec ? &lcmd->timelimit : NULL,
00227 lcmd->sizelimit,
00228 &msgid);
00229 if (ret != LDAP_SUCCESS) {
00230 ERR("ldap: Error while searching: %s\n", ldap_err2string(ret));
00231 goto error;
00232 }
00233
00234
00235
00236
00237
00238
00239 memset(&restimeout, 0, sizeof(restimeout));
00240 restimeout.tv_sec = 5;
00241 ret = ldap_result(lcon->con,
00242 LDAP_RES_ANY,
00243 LDAP_MSG_ALL,
00244 &restimeout,
00245 &resmsg);
00246 } else {
00247
00248 ret = -1;
00249 }
00250
00251 if (ret <= 0) {
00252 ERR("ldap: Error in ldap_search: %s\n", ret < 0 ? ldap_err2string(ret) : "timeout");
00253 if (ret == LDAP_SERVER_DOWN) {
00254 lcon->flags &= ~LD_CONNECTED;
00255 do {
00256 if (!reconn_cnt) {
00257 ERR("ldap: maximum reconnection attempt reached! giving up\n");
00258 goto error;
00259 }
00260 reconn_cnt--;
00261 err = ld_con_connect(con);
00262 } while (err != 0);
00263 } else {
00264 goto error;
00265 }
00266 }
00267 } while (ret <= 0);
00268
00269
00270 for (msg = ldap_first_message(lcon->con, resmsg);
00271 msg != NULL;
00272 msg = ldap_next_message(lcon->con, msg)) {
00273 if (ldap_msgtype(msg) == LDAP_RES_EXTENDED) {
00274 if (ldap_parse_extended_result(lcon->con,
00275 msg,
00276 &oid,
00277 &data,
00278 0) != LDAP_SUCCESS) {
00279 ERR("ldap: Error while parsing extended result\n");
00280 goto error;
00281 }
00282 if (oid != NULL) {
00283 if (strcmp(oid, LDAP_NOTICE_OF_DISCONNECTION) == 0) {
00284 WARN("ldap: Notice of Disconnection (OID: %s)\n", oid);
00285 } else {
00286 WARN("ldap: Unsolicited message received. OID: %s\n", oid);
00287 }
00288 ldap_memfree(oid);
00289 }
00290 if (data != NULL) {
00291 WARN("ldap: Unsolicited message data: %.*s\n",
00292 (int)data->bv_len, data->bv_val);
00293 ber_bvfree(data);
00294 }
00295 }
00296 }
00297
00298 ret = ldap_parse_result(lcon->con, resmsg, &err, NULL, &err_desc, NULL, NULL, 0);
00299 if (ret != LDAP_SUCCESS) {
00300 ERR("ldap: Error while reading result status: %s\n",
00301 ldap_err2string(ret));
00302 goto error;
00303 }
00304
00305 if (err != LDAP_SUCCESS) {
00306 ERR("ldap: LDAP server reports error: %s\n", ldap_err2string(err));
00307 goto error;
00308 }
00309
00310 if (res) {
00311 lres = DB_GET_PAYLOAD(res);
00312 lres->msg = resmsg;
00313 } else if (resmsg) {
00314 ldap_msgfree(resmsg);
00315 }
00316
00317 if (filter) pkg_free(filter);
00318 if (err_desc) ldap_memfree(err_desc);
00319 return 0;
00320
00321 error:
00322 if (filter) pkg_free(filter);
00323 if (resmsg) ldap_msgfree(resmsg);
00324 if (err_desc) ldap_memfree(err_desc);
00325 return -1;
00326 }
00327
00328
00329
00330
00331
00332
00333 static int search_entry(db_res_t* res, int init)
00334 {
00335 db_con_t* con;
00336 struct ld_res* lres;
00337 struct ld_con* lcon;
00338 int r;
00339 lres = DB_GET_PAYLOAD(res);
00340
00341 con = res->cmd->ctx->con[db_payload_idx];
00342 lcon = DB_GET_PAYLOAD(con);
00343
00344 if (init
00345 || !lres->current
00346 || ldap_msgtype(lres->current) != LDAP_RES_SEARCH_ENTRY
00347
00348 || ld_incindex(res->cmd->result)) {
00349
00350 do {
00351 if (init) {
00352 lres->current = ldap_first_message(lcon->con, lres->msg);
00353 init = 0;
00354 }
00355 else
00356 lres->current = ldap_next_message(lcon->con, lres->current);
00357
00358 while(lres->current) {
00359 if (ldap_msgtype(lres->current) == LDAP_RES_SEARCH_ENTRY) {
00360 break;
00361 }
00362 lres->current = ldap_next_message(lcon->con, lres->current);
00363 }
00364 if (lres->current == NULL) return 1;
00365 r = ld_ldap2fldinit(res->cmd->result, lcon->con, lres->current);
00366 } while (r > 0);
00367 if (r < 0) return -1;
00368 } else {
00369 if (ld_ldap2fld(res->cmd->result, lcon->con, lres->current) < 0) return -1;
00370 }
00371
00372 res->cur_rec->fld = res->cmd->result;
00373 return 0;
00374 }
00375
00376
00377 int ld_cmd_first(db_res_t* res)
00378 {
00379 return search_entry(res, 1);
00380 }
00381
00382
00383 int ld_cmd_next(db_res_t* res)
00384 {
00385 return search_entry(res, 0);
00386 }
00387
00388 #define is_space(c) ((c)==' '||(c)==','||(c)==';'||(c)=='\t'||(c)=='\n'||(c)=='\r'||(c)=='\0')
00389
00390 int ld_cmd_setopt(db_cmd_t* cmd, char* optname, va_list ap)
00391 {
00392 struct ld_fld* lfld;
00393 char* val, *c;
00394 int i;
00395
00396 if (!strcasecmp("client_side_filtering", optname)) {
00397 val = va_arg(ap, char*);
00398
00399 for(i = 0; !DB_FLD_EMPTY(cmd->result) && !DB_FLD_LAST(cmd->result[i]); i++) {
00400 c = val;
00401 do {
00402 c = strstr(c, cmd->result[i].name);
00403 if (c) {
00404 if ((c == val || is_space(*(c-1))) && is_space(*(c+strlen(cmd->result[i].name)))) {
00405 lfld = (struct ld_fld*)DB_GET_PAYLOAD(cmd->result + i);
00406 lfld->client_side_filtering = 1;
00407 break;
00408 }
00409 c += strlen(cmd->result[i].name);
00410 }
00411 } while (c != NULL);
00412 }
00413 }
00414 else
00415 return 1;
00416 return 0;
00417 }
00418