root/source4/dsdb/samdb/ldb_modules/proxy.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. load_proxy_info
  2. proxy_convert_blob
  3. proxy_convert_value
  4. proxy_convert_tree
  5. proxy_convert_record
  6. proxy_search_callback
  7. proxy_search_bytree
  8. proxy_request

   1 /* 
   2    samdb proxy module
   3 
   4    Copyright (C) Andrew Tridgell 2005
   5 
   6      ** NOTE! The following LGPL license applies to the ldb
   7      ** library. This does NOT imply that all of Samba is released
   8      ** under the LGPL
   9    
  10    This library is free software; you can redistribute it and/or
  11    modify it under the terms of the GNU Lesser General Public
  12    License as published by the Free Software Foundation; either
  13    version 3 of the License, or (at your option) any later version.
  14 
  15    This library is distributed in the hope that it will be useful,
  16    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18    Lesser General Public License for more details.
  19 
  20    You should have received a copy of the GNU Lesser General Public
  21    License along with this library; if not, see <http://www.gnu.org/licenses/>.
  22 */
  23 
  24 /*
  25   ldb proxy module. At startup this looks for a record like this:
  26 
  27    dn=@PROXYINFO
  28    url=destination url
  29    olddn = basedn to proxy in upstream server
  30    newdn = basedn in local server
  31    username = username to connect to upstream
  32    password = password for upstream
  33 
  34    NOTE: this module is a complete hack at this stage. I am committing it just
  35    so others can know how I am investigating mmc support
  36    
  37  */
  38 
  39 #include "includes.h"
  40 #include "ldb_module.h"
  41 #include "auth/credentials/credentials.h"
  42 
  43 struct proxy_data {
  44         struct ldb_context *upstream;
  45         struct ldb_dn *olddn;
  46         struct ldb_dn *newdn;
  47         const char **oldstr;
  48         const char **newstr;
  49 };
  50 
  51 struct proxy_ctx {
  52         struct ldb_module *module;
  53         struct ldb_request *req;
  54 
  55 #ifdef DEBUG_PROXY
  56         int count;
  57 #endif
  58 };
  59 
  60 /*
  61   load the @PROXYINFO record
  62 */
  63 static int load_proxy_info(struct ldb_module *module)
     /* [<][>][^][v][top][bottom][index][help] */
  64 {
  65         struct ldb_context *ldb = ldb_module_get_ctx(module);
  66         struct proxy_data *proxy = talloc_get_type(ldb_module_get_private(module), struct proxy_data);
  67         struct ldb_dn *dn;
  68         struct ldb_result *res = NULL;
  69         int ret;
  70         const char *olddn, *newdn, *url, *username, *password, *oldstr, *newstr;
  71         struct cli_credentials *creds;
  72 
  73         /* see if we have already loaded it */
  74         if (proxy->upstream != NULL) {
  75                 return LDB_SUCCESS;
  76         }
  77 
  78         dn = ldb_dn_new(proxy, ldb, "@PROXYINFO");
  79         if (dn == NULL) {
  80                 goto failed;
  81         }
  82         ret = ldb_search(ldb, proxy, &res, dn, LDB_SCOPE_BASE, NULL, NULL);
  83         talloc_free(dn);
  84         if (ret != LDB_SUCCESS || res->count != 1) {
  85                 ldb_debug(ldb, LDB_DEBUG_FATAL, "Can't find @PROXYINFO\n");
  86                 goto failed;
  87         }
  88 
  89         url      = ldb_msg_find_attr_as_string(res->msgs[0], "url", NULL);
  90         olddn    = ldb_msg_find_attr_as_string(res->msgs[0], "olddn", NULL);
  91         newdn    = ldb_msg_find_attr_as_string(res->msgs[0], "newdn", NULL);
  92         username = ldb_msg_find_attr_as_string(res->msgs[0], "username", NULL);
  93         password = ldb_msg_find_attr_as_string(res->msgs[0], "password", NULL);
  94         oldstr   = ldb_msg_find_attr_as_string(res->msgs[0], "oldstr", NULL);
  95         newstr   = ldb_msg_find_attr_as_string(res->msgs[0], "newstr", NULL);
  96 
  97         if (url == NULL || olddn == NULL || newdn == NULL || username == NULL || password == NULL) {
  98                 ldb_debug(ldb, LDB_DEBUG_FATAL, "Need url, olddn, newdn, oldstr, newstr, username and password in @PROXYINFO\n");
  99                 goto failed;
 100         }
 101 
 102         proxy->olddn = ldb_dn_new(proxy, ldb, olddn);
 103         if (proxy->olddn == NULL) {
 104                 ldb_debug(ldb, LDB_DEBUG_FATAL, "Failed to explode olddn '%s'\n", olddn);
 105                 goto failed;
 106         }
 107         
 108         proxy->newdn = ldb_dn_new(proxy, ldb, newdn);
 109         if (proxy->newdn == NULL) {
 110                 ldb_debug(ldb, LDB_DEBUG_FATAL, "Failed to explode newdn '%s'\n", newdn);
 111                 goto failed;
 112         }
 113 
 114         proxy->upstream = ldb_init(proxy, ldb_get_event_context(ldb));
 115         if (proxy->upstream == NULL) {
 116                 ldb_oom(ldb);
 117                 goto failed;
 118         }
 119 
 120         proxy->oldstr = str_list_make(proxy, oldstr, ", ");
 121         if (proxy->oldstr == NULL) {
 122                 ldb_oom(ldb);
 123                 goto failed;
 124         }
 125 
 126         proxy->newstr = str_list_make(proxy, newstr, ", ");
 127         if (proxy->newstr == NULL) {
 128                 ldb_oom(ldb);
 129                 goto failed;
 130         }
 131 
 132         /* setup credentials for connection */
 133         creds = cli_credentials_init(proxy->upstream);
 134         if (creds == NULL) {
 135                 ldb_oom(ldb);
 136                 goto failed;
 137         }
 138         cli_credentials_guess(creds, ldb_get_opaque(ldb, "loadparm"));
 139         cli_credentials_set_username(creds, username, CRED_SPECIFIED);
 140         cli_credentials_set_password(creds, password, CRED_SPECIFIED);
 141 
 142         ldb_set_opaque(proxy->upstream, "credentials", creds);
 143 
 144         ret = ldb_connect(proxy->upstream, url, 0, NULL);
 145         if (ret != 0) {
 146                 ldb_debug(ldb, LDB_DEBUG_FATAL, "proxy failed to connect to %s\n", url);
 147                 goto failed;
 148         }
 149 
 150         ldb_debug(ldb, LDB_DEBUG_TRACE, "proxy connected to %s\n", url);
 151 
 152         talloc_free(res);
 153 
 154         return LDB_SUCCESS;
 155 
 156 failed:
 157         talloc_free(res);
 158         talloc_free(proxy->olddn);
 159         talloc_free(proxy->newdn);
 160         talloc_free(proxy->upstream);
 161         proxy->upstream = NULL;
 162         return LDB_ERR_OPERATIONS_ERROR;
 163 }
 164 
 165 
 166 /*
 167   convert a binary blob
 168 */
 169 static void proxy_convert_blob(TALLOC_CTX *mem_ctx, struct ldb_val *v,
     /* [<][>][^][v][top][bottom][index][help] */
 170                                const char *oldstr, const char *newstr)
 171 {
 172         int len1, len2, len3;
 173         uint8_t *olddata = v->data;
 174         char *p = strcasestr((char *)v->data, oldstr);
 175 
 176         len1 = (p - (char *)v->data);
 177         len2 = strlen(newstr);
 178         len3 = v->length - (p+strlen(oldstr) - (char *)v->data);
 179         v->length = len1+len2+len3;
 180         v->data = talloc_size(mem_ctx, v->length);
 181         memcpy(v->data, olddata, len1);
 182         memcpy(v->data+len1, newstr, len2);
 183         memcpy(v->data+len1+len2, olddata + len1 + strlen(oldstr), len3);
 184 }
 185 
 186 /*
 187   convert a returned value
 188 */
 189 static void proxy_convert_value(struct proxy_data *proxy, struct ldb_message *msg, struct ldb_val *v)
     /* [<][>][^][v][top][bottom][index][help] */
 190 {
 191         int i;
 192 
 193         for (i=0;proxy->oldstr[i];i++) {
 194                 char *p = strcasestr((char *)v->data, proxy->oldstr[i]);
 195                 if (p == NULL) continue;
 196                 proxy_convert_blob(msg, v, proxy->oldstr[i], proxy->newstr[i]);
 197         }
 198 }
 199 
 200 
 201 /*
 202   convert a returned value
 203 */
 204 static struct ldb_parse_tree *proxy_convert_tree(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 205                                                  struct proxy_data *proxy,
 206                                                  struct ldb_parse_tree *tree)
 207 {
 208         int i;
 209         char *expression = ldb_filter_from_tree(mem_ctx, tree);
 210 
 211         for (i=0;proxy->newstr[i];i++) {
 212                 struct ldb_val v;
 213                 char *p = strcasestr(expression, proxy->newstr[i]);
 214                 if (p == NULL) continue;
 215                 v.data = (uint8_t *)expression;
 216                 v.length = strlen(expression)+1;
 217                 proxy_convert_blob(mem_ctx, &v, proxy->newstr[i], proxy->oldstr[i]);
 218                 return ldb_parse_tree(mem_ctx, (const char *)v.data);
 219         }
 220         return tree;
 221 }
 222 
 223 
 224 
 225 /*
 226   convert a returned record
 227 */
 228 static void proxy_convert_record(struct ldb_context *ldb,
     /* [<][>][^][v][top][bottom][index][help] */
 229                                  struct proxy_data *proxy,
 230                                  struct ldb_message *msg)
 231 {
 232         int attr, v;
 233 
 234         /* fix the message DN */
 235         if (ldb_dn_compare_base(proxy->olddn, msg->dn) == 0) {
 236                 ldb_dn_remove_base_components(msg->dn, ldb_dn_get_comp_num(proxy->olddn));
 237                 ldb_dn_add_base(msg->dn, proxy->newdn);
 238         }
 239 
 240         /* fix any attributes */
 241         for (attr=0;attr<msg->num_elements;attr++) {
 242                 for (v=0;v<msg->elements[attr].num_values;v++) {
 243                         proxy_convert_value(proxy, msg, &msg->elements[attr].values[v]);
 244                 }
 245         }
 246 
 247         /* fix any DN components */
 248         for (attr=0;attr<msg->num_elements;attr++) {
 249                 for (v=0;v<msg->elements[attr].num_values;v++) {
 250                         proxy_convert_value(proxy, msg, &msg->elements[attr].values[v]);
 251                 }
 252         }
 253 }
 254 
 255 static int proxy_search_callback(struct ldb_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 256                                   struct ldb_reply *ares)
 257 {
 258         struct ldb_context *ldb;
 259         struct proxy_data *proxy;
 260         struct proxy_ctx *ac;
 261         int ret;
 262 
 263         ac = talloc_get_type(req->context, struct proxy_ctx);
 264         ldb = ldb_module_get_ctx(ac->module);
 265         proxy = talloc_get_type(ldb_module_get_private(module), struct proxy_data);
 266 
 267         if (!ares) {
 268                 return ldb_module_done(ac->req, NULL, NULL,
 269                                         LDB_ERR_OPERATIONS_ERROR);
 270         }
 271         if (ares->error != LDB_SUCCESS) {
 272                 return ldb_module_done(ac->req, ares->controls,
 273                                         ares->response, ares->error);
 274         }
 275 
 276         /* Only entries are interesting, and we only want the olddn */
 277         switch (ares->type) {
 278         case LDB_REPLY_ENTRY:
 279 
 280 #ifdef DEBUG_PROXY
 281                 ac->count++;
 282 #endif
 283                 proxy_convert_record(ldb, proxy, ares->message);
 284                 ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
 285                 break;
 286 
 287         case LDB_REPLY_REFERRAL:
 288 
 289                 /* ignore remote referrals */
 290                 break;
 291 
 292         case LDB_REPLY_DONE:
 293 
 294 #ifdef DEBUG_PROXY
 295                 printf("# record %d\n", ac->count+1);
 296 #endif
 297 
 298                 return ldb_module_done(ac->req, NULL, NULL, LDB_SUCCESS);
 299         }
 300 
 301         talloc_free(ares);
 302         return ret;
 303 }
 304 
 305 /* search */
 306 static int proxy_search_bytree(struct ldb_module *module, struct ldb_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 307 {
 308         struct ldb_context *ldb;
 309         struct proxy_ctx *ac;
 310         struct ldb_parse_tree *newtree;
 311         struct proxy_data *proxy = talloc_get_type(ldb_module_get_private(module), struct proxy_data);
 312         struct ldb_request *newreq;
 313         struct ldb_dn *base;
 314         int ret, i;
 315 
 316         ldb = ldb_module_get_ctx(module);
 317 
 318         if (req->op.search.base == NULL ||
 319                 (req->op.search.base->comp_num == 1 &&
 320                         req->op.search.base->components[0].name[0] == '@')) {
 321                 goto passthru;
 322         }
 323 
 324         if (load_proxy_info(module) != LDB_SUCCESS) {
 325                 return LDB_ERR_OPERATIONS_ERROR;
 326         }
 327 
 328         /* see if the dn is within olddn */
 329         if (ldb_dn_compare_base(proxy->newdn, req->op.search.base) != 0) {
 330                 goto passthru;
 331         }
 332 
 333         ac = talloc(req, struct proxy_ctx);
 334         if (ac == NULL) {
 335                 return LDB_ERR_OPERATIONS_ERROR;
 336         }
 337 
 338         ac->module = module;
 339         ac->req = req;
 340 #ifdef DEBUG_PROXY
 341         ac->count = 0;
 342 #endif
 343 
 344         newtree = proxy_convert_tree(ac, proxy, req->op.search.tree);
 345 
 346         /* convert the basedn of this search */
 347         base = ldb_dn_copy(ac, req->op.search.base);
 348         if (base == NULL) {
 349                 goto failed;
 350         }
 351         ldb_dn_remove_base_components(base, ldb_dn_get_comp_num(proxy->newdn));
 352         ldb_dn_add_base(base, proxy->olddn);
 353 
 354         ldb_debug(ldb, LDB_DEBUG_FATAL, "proxying: '%s' with dn '%s' \n", 
 355                   ldb_filter_from_tree(ac, newreq->op.search.tree), ldb_dn_get_linearized(newreq->op.search.base));
 356         for (i = 0; req->op.search.attrs && req->op.search.attrs[i]; i++) {
 357                 ldb_debug(ldb, LDB_DEBUG_FATAL, "attr: '%s'\n", req->op.search.attrs[i]);
 358         }
 359 
 360         ret = ldb_build_search_req_ex(&newreq, ldb, ac,
 361                                       base, req->op.search.scope,
 362                                       newtree, req->op.search.attrs,
 363                                       req->controls,
 364                                       ac, proxy_search_callback,
 365                                       req);
 366 
 367         /* FIXME: warning, need a real event system hooked up for this to work properly,
 368          *        for now this makes the module *not* ASYNC */
 369         ret = ldb_request(proxy->upstream, newreq);
 370         if (ret != LDB_SUCCESS) {
 371                 ldb_set_errstring(ldb, ldb_errstring(proxy->upstream));
 372         }
 373         ret = ldb_wait(newreq->handle, LDB_WAIT_ALL);
 374         if (ret != LDB_SUCCESS) {
 375                 ldb_set_errstring(ldb, ldb_errstring(proxy->upstream));
 376         }
 377         return ret;
 378 
 379 failed:
 380         ldb_debug(ldb, LDB_DEBUG_TRACE, "proxy failed for %s\n", 
 381                   ldb_dn_get_linearized(req->op.search.base));
 382 
 383 passthru:
 384         return ldb_next_request(module, req); 
 385 }
 386 
 387 static int proxy_request(struct ldb_module *module, struct ldb_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 388 {
 389         switch (req->operation) {
 390 
 391         case LDB_REQ_SEARCH:
 392                 return proxy_search_bytree(module, req);
 393 
 394         default:
 395                 return ldb_next_request(module, req);
 396 
 397         }
 398 }
 399 
 400 _PUBLIC_ const struct ldb_module_ops ldb_proxy_module_ops = {
 401         .name           = "proxy",
 402         .request        = proxy_request
 403 };

/* [<][>][^][v][top][bottom][index][help] */