root/source3/winbindd/idmap_tdb2.c

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

DEFINITIONS

This source file includes following definitions.
  1. idmap_tdb2_load_ranges
  2. idmap_tdb2_open_db
  3. idmap_tdb2_alloc_load
  4. idmap_tdb2_alloc_init
  5. idmap_tdb2_allocate_id
  6. idmap_tdb2_get_hwm
  7. idmap_tdb2_set_hwm
  8. idmap_tdb2_alloc_close
  9. idmap_tdb2_db_init
  10. idmap_tdb2_script
  11. idmap_tdb2_id_to_sid
  12. idmap_tdb2_sid_to_id
  13. idmap_tdb2_unixids_to_sids
  14. idmap_tdb2_sids_to_unixids
  15. idmap_tdb2_set_mapping
  16. idmap_tdb2_remove_mapping
  17. idmap_tdb2_close
  18. idmap_tdb2_dump_data
  19. idmap_tdb2_init

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    idmap TDB2 backend, used for clustered Samba setups.
   5 
   6    This uses dbwrap to access tdb files. The location can be set
   7    using tdb:idmap2.tdb =" in smb.conf
   8 
   9    Copyright (C) Andrew Tridgell 2007
  10 
  11    This is heavily based upon idmap_tdb.c, which is:
  12 
  13    Copyright (C) Tim Potter 2000
  14    Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
  15    Copyright (C) Jeremy Allison 2006
  16    Copyright (C) Simo Sorce 2003-2006
  17    
  18    This program is free software; you can redistribute it and/or modify
  19    it under the terms of the GNU General Public License as published by
  20    the Free Software Foundation; either version 2 of the License, or
  21    (at your option) any later version.
  22    
  23    This program is distributed in the hope that it will be useful,
  24    but WITHOUT ANY WARRANTY; without even the implied warranty of
  25    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  26    GNU General Public License for more details.
  27    
  28    You should have received a copy of the GNU General Public License
  29    along with this program; if not, write to the Free Software
  30    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  31 */
  32 
  33 #include "includes.h"
  34 #include "winbindd.h"
  35 
  36 #undef DBGC_CLASS
  37 #define DBGC_CLASS DBGC_IDMAP
  38 
  39 /* High water mark keys */
  40 #define HWM_GROUP  "GROUP HWM"
  41 #define HWM_USER   "USER HWM"
  42 
  43 static struct idmap_tdb2_state {
  44         /* User and group id pool */
  45         uid_t low_uid, high_uid;               /* Range of uids to allocate */
  46         gid_t low_gid, high_gid;               /* Range of gids to allocate */
  47         const char *idmap_script;
  48 } idmap_tdb2_state;
  49 
  50 
  51 
  52 /* handle to the permanent tdb */
  53 static struct db_context *idmap_tdb2;
  54 
  55 static NTSTATUS idmap_tdb2_alloc_load(void);
  56 
  57 static NTSTATUS idmap_tdb2_load_ranges(void)
     /* [<][>][^][v][top][bottom][index][help] */
  58 {
  59         uid_t low_uid = 0;
  60         uid_t high_uid = 0;
  61         gid_t low_gid = 0;
  62         gid_t high_gid = 0;
  63 
  64         if (!lp_idmap_uid(&low_uid, &high_uid)) {
  65                 DEBUG(1, ("idmap uid missing\n"));
  66                 return NT_STATUS_UNSUCCESSFUL;
  67         }
  68 
  69         if (!lp_idmap_gid(&low_gid, &high_gid)) {
  70                 DEBUG(1, ("idmap gid missing\n"));
  71                 return NT_STATUS_UNSUCCESSFUL;
  72         }
  73 
  74         idmap_tdb2_state.low_uid = low_uid;
  75         idmap_tdb2_state.high_uid = high_uid;
  76         idmap_tdb2_state.low_gid = low_gid;
  77         idmap_tdb2_state.high_gid = high_gid;
  78 
  79         if (idmap_tdb2_state.high_uid <= idmap_tdb2_state.low_uid) {
  80                 DEBUG(1, ("idmap uid range missing or invalid\n"));
  81                 DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n"));
  82                 return NT_STATUS_UNSUCCESSFUL;
  83         }
  84 
  85         if (idmap_tdb2_state.high_gid <= idmap_tdb2_state.low_gid) {
  86                 DEBUG(1, ("idmap gid range missing or invalid\n"));
  87                 DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n"));
  88                 return NT_STATUS_UNSUCCESSFUL;
  89         }
  90 
  91         return NT_STATUS_OK;
  92 }
  93 
  94 /*
  95   open the permanent tdb
  96  */
  97 static NTSTATUS idmap_tdb2_open_db(void)
     /* [<][>][^][v][top][bottom][index][help] */
  98 {
  99         char *db_path;
 100         
 101         if (idmap_tdb2) {
 102                 /* its already open */
 103                 return NT_STATUS_OK;
 104         }
 105 
 106         db_path = lp_parm_talloc_string(-1, "tdb", "idmap2.tdb", NULL);
 107         if (db_path == NULL) {
 108                 /* fall back to the private directory, which, despite
 109                    its name, is usually on shared storage */
 110                 db_path = talloc_asprintf(NULL, "%s/idmap2.tdb", lp_private_dir());
 111         }
 112         NT_STATUS_HAVE_NO_MEMORY(db_path);
 113 
 114         /* Open idmap repository */
 115         idmap_tdb2 = db_open(NULL, db_path, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0644);
 116         TALLOC_FREE(db_path);
 117 
 118         if (idmap_tdb2 == NULL) {
 119                 DEBUG(0, ("Unable to open idmap_tdb2 database '%s'\n",
 120                           db_path));
 121                 return NT_STATUS_UNSUCCESSFUL;
 122         }
 123 
 124         /* load the ranges and high/low water marks */
 125         return idmap_tdb2_alloc_load();
 126 }
 127 
 128 
 129 /*
 130   load the idmap allocation ranges and high/low water marks
 131 */
 132 static NTSTATUS idmap_tdb2_alloc_load(void)
     /* [<][>][^][v][top][bottom][index][help] */
 133 {
 134         NTSTATUS status;
 135         uint32 low_id;
 136 
 137         /* see if a idmap script is configured */
 138         idmap_tdb2_state.idmap_script = lp_parm_const_string(-1, "idmap",
 139                                                              "script", NULL);
 140 
 141         if (idmap_tdb2_state.idmap_script) {
 142                 DEBUG(1, ("using idmap script '%s'\n",
 143                           idmap_tdb2_state.idmap_script));
 144         }
 145 
 146         /* load ranges */
 147 
 148         status = idmap_tdb2_load_ranges();
 149         if (!NT_STATUS_IS_OK(status)) {
 150                 return status;
 151         }
 152 
 153         /* Create high water marks for group and user id */
 154 
 155         low_id = dbwrap_fetch_int32(idmap_tdb2, HWM_USER);
 156         if ((low_id == -1) || (low_id < idmap_tdb2_state.low_uid)) {
 157                 if (!NT_STATUS_IS_OK(dbwrap_trans_store_int32(
 158                                              idmap_tdb2, HWM_USER,
 159                                              idmap_tdb2_state.low_uid))) {
 160                         DEBUG(0, ("Unable to initialise user hwm in idmap "
 161                                   "database\n"));
 162                         return NT_STATUS_INTERNAL_DB_ERROR;
 163                 }
 164         }
 165 
 166         low_id = dbwrap_fetch_int32(idmap_tdb2, HWM_GROUP);
 167         if ((low_id == -1) || (low_id < idmap_tdb2_state.low_gid)) {
 168                 if (!NT_STATUS_IS_OK(dbwrap_trans_store_int32(
 169                                              idmap_tdb2, HWM_GROUP,
 170                                              idmap_tdb2_state.low_gid))) {
 171                         DEBUG(0, ("Unable to initialise group hwm in idmap "
 172                                   "database\n"));
 173                         return NT_STATUS_INTERNAL_DB_ERROR;
 174                 }
 175         }
 176 
 177         return NT_STATUS_OK;
 178 }
 179 
 180 
 181 /*
 182   Initialise idmap alloc database. 
 183 */
 184 static NTSTATUS idmap_tdb2_alloc_init(const char *params)
     /* [<][>][^][v][top][bottom][index][help] */
 185 {
 186         /* nothing to do - we want to avoid opening the permanent
 187            database if possible. Instead we load the params when we
 188            first need it. */
 189         return NT_STATUS_OK;
 190 }
 191 
 192 
 193 /*
 194   Allocate a new id. 
 195 */
 196 static NTSTATUS idmap_tdb2_allocate_id(struct unixid *xid)
     /* [<][>][^][v][top][bottom][index][help] */
 197 {
 198         bool ret;
 199         const char *hwmkey;
 200         const char *hwmtype;
 201         uint32_t high_hwm;
 202         uint32_t hwm;
 203         int res;
 204         NTSTATUS status;
 205 
 206         status = idmap_tdb2_open_db();
 207         NT_STATUS_NOT_OK_RETURN(status);
 208 
 209         /* Get current high water mark */
 210         switch (xid->type) {
 211 
 212         case ID_TYPE_UID:
 213                 hwmkey = HWM_USER;
 214                 hwmtype = "UID";
 215                 high_hwm = idmap_tdb2_state.high_uid;
 216                 break;
 217 
 218         case ID_TYPE_GID:
 219                 hwmkey = HWM_GROUP;
 220                 hwmtype = "GID";
 221                 high_hwm = idmap_tdb2_state.high_gid;
 222                 break;
 223 
 224         default:
 225                 DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type));
 226                 return NT_STATUS_INVALID_PARAMETER;
 227         }
 228 
 229         res = idmap_tdb2->transaction_start(idmap_tdb2);
 230         if (res != 0) {
 231                 DEBUG(1,(__location__ " Failed to start transaction\n"));
 232                 return NT_STATUS_UNSUCCESSFUL;
 233         }
 234 
 235         if ((hwm = dbwrap_fetch_int32(idmap_tdb2, hwmkey)) == -1) {
 236                 idmap_tdb2->transaction_cancel(idmap_tdb2);
 237                 return NT_STATUS_INTERNAL_DB_ERROR;
 238         }
 239 
 240         /* check it is in the range */
 241         if (hwm > high_hwm) {
 242                 DEBUG(1, ("Fatal Error: %s range full!! (max: %lu)\n", 
 243                           hwmtype, (unsigned long)high_hwm));
 244                 idmap_tdb2->transaction_cancel(idmap_tdb2);
 245                 return NT_STATUS_UNSUCCESSFUL;
 246         }
 247 
 248         /* fetch a new id and increment it */
 249         ret = dbwrap_change_uint32_atomic(idmap_tdb2, hwmkey, &hwm, 1);
 250         if (ret == -1) {
 251                 DEBUG(1, ("Fatal error while fetching a new %s value\n!", hwmtype));
 252                 idmap_tdb2->transaction_cancel(idmap_tdb2);
 253                 return NT_STATUS_UNSUCCESSFUL;
 254         }
 255 
 256         /* recheck it is in the range */
 257         if (hwm > high_hwm) {
 258                 DEBUG(1, ("Fatal Error: %s range full!! (max: %lu)\n", 
 259                           hwmtype, (unsigned long)high_hwm));
 260                 idmap_tdb2->transaction_cancel(idmap_tdb2);
 261                 return NT_STATUS_UNSUCCESSFUL;
 262         }
 263 
 264         res = idmap_tdb2->transaction_commit(idmap_tdb2);
 265         if (res != 0) {
 266                 DEBUG(1,(__location__ " Failed to commit transaction\n"));
 267                 return NT_STATUS_UNSUCCESSFUL;
 268         }
 269         
 270         xid->id = hwm;
 271         DEBUG(10,("New %s = %d\n", hwmtype, hwm));
 272 
 273         return NT_STATUS_OK;
 274 }
 275 
 276 /*
 277   Get current highest id. 
 278 */
 279 static NTSTATUS idmap_tdb2_get_hwm(struct unixid *xid)
     /* [<][>][^][v][top][bottom][index][help] */
 280 {
 281         const char *hwmkey;
 282         const char *hwmtype;
 283         uint32_t hwm;
 284         uint32_t high_hwm;
 285         NTSTATUS status;
 286 
 287         status = idmap_tdb2_open_db();
 288         NT_STATUS_NOT_OK_RETURN(status);
 289 
 290         /* Get current high water mark */
 291         switch (xid->type) {
 292 
 293         case ID_TYPE_UID:
 294                 hwmkey = HWM_USER;
 295                 hwmtype = "UID";
 296                 high_hwm = idmap_tdb2_state.high_uid;
 297                 break;
 298 
 299         case ID_TYPE_GID:
 300                 hwmkey = HWM_GROUP;
 301                 hwmtype = "GID";
 302                 high_hwm = idmap_tdb2_state.high_gid;
 303                 break;
 304 
 305         default:
 306                 return NT_STATUS_INVALID_PARAMETER;
 307         }
 308 
 309         if ((hwm = dbwrap_fetch_int32(idmap_tdb2, hwmkey)) == -1) {
 310                 return NT_STATUS_INTERNAL_DB_ERROR;
 311         }
 312 
 313         xid->id = hwm;
 314 
 315         /* Warn if it is out of range */
 316         if (hwm >= high_hwm) {
 317                 DEBUG(0, ("Warning: %s range full!! (max: %lu)\n", 
 318                           hwmtype, (unsigned long)high_hwm));
 319         }
 320 
 321         return NT_STATUS_OK;
 322 }
 323 
 324 /*
 325   Set high id. 
 326 */
 327 static NTSTATUS idmap_tdb2_set_hwm(struct unixid *xid)
     /* [<][>][^][v][top][bottom][index][help] */
 328 {
 329         /* not supported, or we would invalidate the cache tdb on
 330            other nodes */
 331         DEBUG(0,("idmap_tdb2_set_hwm not supported\n"));
 332         return NT_STATUS_NOT_SUPPORTED;
 333 }
 334 
 335 /*
 336   Close the alloc tdb 
 337 */
 338 static NTSTATUS idmap_tdb2_alloc_close(void)
     /* [<][>][^][v][top][bottom][index][help] */
 339 {
 340         /* don't actually close it */
 341         return NT_STATUS_OK;
 342 }
 343 
 344 /*
 345   IDMAP MAPPING TDB BACKEND
 346 */
 347 struct idmap_tdb2_context {
 348         uint32_t filter_low_id;
 349         uint32_t filter_high_id;
 350 };
 351 
 352 /*
 353   Initialise idmap database. 
 354 */
 355 static NTSTATUS idmap_tdb2_db_init(struct idmap_domain *dom,
     /* [<][>][^][v][top][bottom][index][help] */
 356                                    const char *params)
 357 {
 358         NTSTATUS ret;
 359         struct idmap_tdb2_context *ctx;
 360         NTSTATUS status;
 361 
 362         status = idmap_tdb2_open_db();
 363         NT_STATUS_NOT_OK_RETURN(status);
 364 
 365         ctx = talloc(dom, struct idmap_tdb2_context);
 366         if ( ! ctx) {
 367                 DEBUG(0, ("Out of memory!\n"));
 368                 return NT_STATUS_NO_MEMORY;
 369         }
 370 
 371         if (strequal(dom->name, "*")) {
 372                 uid_t low_uid = 0;
 373                 uid_t high_uid = 0;
 374                 gid_t low_gid = 0;
 375                 gid_t high_gid = 0;
 376 
 377                 ctx->filter_low_id = 0;
 378                 ctx->filter_high_id = 0;
 379 
 380                 if (lp_idmap_uid(&low_uid, &high_uid)) {
 381                         ctx->filter_low_id = low_uid;
 382                         ctx->filter_high_id = high_uid;
 383                 } else {
 384                         DEBUG(3, ("Warning: 'idmap uid' not set!\n"));
 385                 }
 386 
 387                 if (lp_idmap_gid(&low_gid, &high_gid)) {
 388                         if ((low_gid != low_uid) || (high_gid != high_uid)) {
 389                                 DEBUG(1, ("Warning: 'idmap uid' and 'idmap gid'"
 390                                       " ranges do not agree -- building "
 391                                       "intersection\n"));
 392                                 ctx->filter_low_id = MAX(ctx->filter_low_id,
 393                                                          low_gid);
 394                                 ctx->filter_high_id = MIN(ctx->filter_high_id,
 395                                                           high_gid);
 396                         }
 397                 } else {
 398                         DEBUG(3, ("Warning: 'idmap gid' not set!\n"));
 399                 }
 400         } else {
 401                 char *config_option = NULL;
 402                 const char *range;
 403                 config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
 404                 if ( ! config_option) {
 405                         DEBUG(0, ("Out of memory!\n"));
 406                         ret = NT_STATUS_NO_MEMORY;
 407                         goto failed;
 408                 }
 409 
 410                 range = lp_parm_const_string(-1, config_option, "range", NULL);
 411                 if (( ! range) ||
 412                     (sscanf(range, "%u - %u", &ctx->filter_low_id, &ctx->filter_high_id) != 2))
 413                 {
 414                         ctx->filter_low_id = 0;
 415                         ctx->filter_high_id = 0;
 416                 }
 417 
 418                 talloc_free(config_option);
 419         }
 420 
 421         if (ctx->filter_low_id > ctx->filter_high_id) {
 422                 ctx->filter_low_id = 0;
 423                 ctx->filter_high_id = 0;
 424         }
 425 
 426         dom->private_data = ctx;
 427 
 428         return NT_STATUS_OK;
 429 
 430 failed:
 431         talloc_free(ctx);
 432         return ret;
 433 }
 434 
 435 
 436 /*
 437   run a script to perform a mapping
 438 
 439   The script should the following command lines:
 440 
 441       SIDTOID S-1-xxxx
 442       IDTOSID UID xxxx
 443       IDTOSID GID xxxx
 444 
 445   and should return one of the following as a single line of text
 446      UID:xxxx
 447      GID:xxxx
 448      SID:xxxx
 449      ERR:xxxx
 450  */
 451 static NTSTATUS idmap_tdb2_script(struct idmap_tdb2_context *ctx, struct id_map *map,
     /* [<][>][^][v][top][bottom][index][help] */
 452                                   const char *fmt, ...)
 453 {
 454         va_list ap;
 455         char *cmd;
 456         FILE *p;
 457         char line[64];
 458         unsigned long v;
 459 
 460         cmd = talloc_asprintf(ctx, "%s ", idmap_tdb2_state.idmap_script);
 461         NT_STATUS_HAVE_NO_MEMORY(cmd);  
 462 
 463         va_start(ap, fmt);
 464         cmd = talloc_vasprintf_append(cmd, fmt, ap);
 465         va_end(ap);
 466         NT_STATUS_HAVE_NO_MEMORY(cmd);
 467 
 468         p = popen(cmd, "r");
 469         talloc_free(cmd);
 470         if (p == NULL) {
 471                 return NT_STATUS_NONE_MAPPED;
 472         }
 473 
 474         if (fgets(line, sizeof(line)-1, p) == NULL) {
 475                 pclose(p);
 476                 return NT_STATUS_NONE_MAPPED;
 477         }
 478         pclose(p);
 479 
 480         DEBUG(10,("idmap script gave: %s\n", line));
 481 
 482         if (sscanf(line, "UID:%lu", &v) == 1) {
 483                 map->xid.id   = v;
 484                 map->xid.type = ID_TYPE_UID;
 485         } else if (sscanf(line, "GID:%lu", &v) == 1) {
 486                 map->xid.id   = v;
 487                 map->xid.type = ID_TYPE_GID;            
 488         } else if (strncmp(line, "SID:S-", 6) == 0) {
 489                 if (!string_to_sid(map->sid, &line[4])) {
 490                         DEBUG(0,("Bad SID in '%s' from idmap script %s\n",
 491                                  line, idmap_tdb2_state.idmap_script));
 492                         return NT_STATUS_NONE_MAPPED;                   
 493                 }
 494         } else {
 495                 DEBUG(0,("Bad reply '%s' from idmap script %s\n",
 496                          line, idmap_tdb2_state.idmap_script));
 497                 return NT_STATUS_NONE_MAPPED;
 498         }
 499 
 500         return NT_STATUS_OK;
 501 }
 502 
 503 
 504 
 505 /*
 506   Single id to sid lookup function. 
 507 */
 508 static NTSTATUS idmap_tdb2_id_to_sid(struct idmap_tdb2_context *ctx, struct id_map *map)
     /* [<][>][^][v][top][bottom][index][help] */
 509 {
 510         NTSTATUS ret;
 511         TDB_DATA data;
 512         char *keystr;
 513         NTSTATUS status;
 514 
 515         status = idmap_tdb2_open_db();
 516         NT_STATUS_NOT_OK_RETURN(status);
 517 
 518         if (!ctx || !map) {
 519                 return NT_STATUS_INVALID_PARAMETER;
 520         }
 521 
 522         /* apply filters before checking */
 523         if ((ctx->filter_low_id && (map->xid.id < ctx->filter_low_id)) ||
 524             (ctx->filter_high_id && (map->xid.id > ctx->filter_high_id))) {
 525                 DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
 526                                 map->xid.id, ctx->filter_low_id, ctx->filter_high_id));
 527                 return NT_STATUS_NONE_MAPPED;
 528         }
 529 
 530         switch (map->xid.type) {
 531 
 532         case ID_TYPE_UID:
 533                 keystr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id);
 534                 break;
 535                 
 536         case ID_TYPE_GID:
 537                 keystr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id);
 538                 break;
 539 
 540         default:
 541                 DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type));
 542                 return NT_STATUS_INVALID_PARAMETER;
 543         }
 544 
 545         /* final SAFE_FREE safe */
 546         data.dptr = NULL;
 547 
 548         if (keystr == NULL) {
 549                 DEBUG(0, ("Out of memory!\n"));
 550                 ret = NT_STATUS_NO_MEMORY;
 551                 goto done;
 552         }
 553 
 554         DEBUG(10,("Fetching record %s\n", keystr));
 555 
 556         /* Check if the mapping exists */
 557         data = dbwrap_fetch_bystring(idmap_tdb2, keystr, keystr);
 558 
 559         if (!data.dptr) {
 560                 fstring sidstr;
 561 
 562                 DEBUG(10,("Record %s not found\n", keystr));
 563                 if (idmap_tdb2_state.idmap_script == NULL) {
 564                         ret = NT_STATUS_NONE_MAPPED;
 565                         goto done;
 566                 }
 567 
 568                 ret = idmap_tdb2_script(ctx, map, "IDTOSID %s", keystr);
 569 
 570                 /* store it on shared storage */
 571                 if (!NT_STATUS_IS_OK(ret)) {
 572                         goto done;
 573                 }
 574 
 575                 if (sid_to_fstring(sidstr, map->sid)) {
 576                         /* both forward and reverse mappings */
 577                         dbwrap_store_bystring(idmap_tdb2, keystr,
 578                                             string_term_tdb_data(sidstr), 
 579                                             TDB_REPLACE);
 580                         dbwrap_store_bystring(idmap_tdb2, sidstr,
 581                                             string_term_tdb_data(keystr), 
 582                                             TDB_REPLACE);
 583                 }
 584                 goto done;
 585         }
 586                 
 587         if (!string_to_sid(map->sid, (const char *)data.dptr)) {
 588                 DEBUG(10,("INVALID SID (%s) in record %s\n",
 589                         (const char *)data.dptr, keystr));
 590                 ret = NT_STATUS_INTERNAL_DB_ERROR;
 591                 goto done;
 592         }
 593 
 594         DEBUG(10,("Found record %s -> %s\n", keystr, (const char *)data.dptr));
 595         ret = NT_STATUS_OK;
 596 
 597 done:
 598         talloc_free(keystr);
 599         return ret;
 600 }
 601 
 602 
 603 /*
 604  Single sid to id lookup function. 
 605 */
 606 static NTSTATUS idmap_tdb2_sid_to_id(struct idmap_tdb2_context *ctx, struct id_map *map)
     /* [<][>][^][v][top][bottom][index][help] */
 607 {
 608         NTSTATUS ret;
 609         TDB_DATA data;
 610         char *keystr;
 611         unsigned long rec_id = 0;
 612         TALLOC_CTX *tmp_ctx = talloc_stackframe();
 613 
 614         ret = idmap_tdb2_open_db();
 615         NT_STATUS_NOT_OK_RETURN(ret);
 616 
 617         keystr = sid_string_talloc(tmp_ctx, map->sid);
 618         if (keystr == NULL) {
 619                 DEBUG(0, ("Out of memory!\n"));
 620                 ret = NT_STATUS_NO_MEMORY;
 621                 goto done;
 622         }
 623 
 624         DEBUG(10,("Fetching record %s\n", keystr));
 625 
 626         /* Check if sid is present in database */
 627         data = dbwrap_fetch_bystring(idmap_tdb2, tmp_ctx, keystr);
 628         if (!data.dptr) {
 629                 fstring idstr;
 630 
 631                 DEBUG(10,(__location__ " Record %s not found\n", keystr));
 632 
 633                 if (idmap_tdb2_state.idmap_script == NULL) {
 634                         ret = NT_STATUS_NONE_MAPPED;
 635                         goto done;
 636                 }
 637                         
 638                 ret = idmap_tdb2_script(ctx, map, "SIDTOID %s", keystr);
 639                 /* store it on shared storage */
 640                 if (!NT_STATUS_IS_OK(ret)) {
 641                         goto done;
 642                 }
 643 
 644                 snprintf(idstr, sizeof(idstr), "%cID %lu", 
 645                          map->xid.type == ID_TYPE_UID?'U':'G',
 646                          (unsigned long)map->xid.id);
 647                 /* store both forward and reverse mappings */
 648                 dbwrap_store_bystring(idmap_tdb2, keystr, string_term_tdb_data(idstr),
 649                                     TDB_REPLACE);
 650                 dbwrap_store_bystring(idmap_tdb2, idstr, string_term_tdb_data(keystr),
 651                                     TDB_REPLACE);
 652                 goto done;
 653         }
 654 
 655         /* What type of record is this ? */
 656         if (sscanf((const char *)data.dptr, "UID %lu", &rec_id) == 1) { /* Try a UID record. */
 657                 map->xid.id = rec_id;
 658                 map->xid.type = ID_TYPE_UID;
 659                 DEBUG(10,("Found uid record %s -> %s \n", keystr, (const char *)data.dptr ));
 660                 ret = NT_STATUS_OK;
 661 
 662         } else if (sscanf((const char *)data.dptr, "GID %lu", &rec_id) == 1) { /* Try a GID record. */
 663                 map->xid.id = rec_id;
 664                 map->xid.type = ID_TYPE_GID;
 665                 DEBUG(10,("Found gid record %s -> %s \n", keystr, (const char *)data.dptr ));
 666                 ret = NT_STATUS_OK;
 667 
 668         } else { /* Unknown record type ! */
 669                 DEBUG(2, ("Found INVALID record %s -> %s\n", keystr, (const char *)data.dptr));
 670                 ret = NT_STATUS_INTERNAL_DB_ERROR;
 671         }
 672         
 673         /* apply filters before returning result */
 674         if ((ctx->filter_low_id && (map->xid.id < ctx->filter_low_id)) ||
 675             (ctx->filter_high_id && (map->xid.id > ctx->filter_high_id))) {
 676                 DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
 677                                 map->xid.id, ctx->filter_low_id, ctx->filter_high_id));
 678                 ret = NT_STATUS_NONE_MAPPED;
 679         }
 680 
 681 done:
 682         talloc_free(tmp_ctx);
 683         return ret;
 684 }
 685 
 686 /*
 687   lookup a set of unix ids. 
 688 */
 689 static NTSTATUS idmap_tdb2_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
     /* [<][>][^][v][top][bottom][index][help] */
 690 {
 691         struct idmap_tdb2_context *ctx;
 692         NTSTATUS ret;
 693         int i;
 694 
 695         /* initialize the status to avoid suprise */
 696         for (i = 0; ids[i]; i++) {
 697                 ids[i]->status = ID_UNKNOWN;
 698         }
 699         
 700         ctx = talloc_get_type(dom->private_data, struct idmap_tdb2_context);
 701 
 702         for (i = 0; ids[i]; i++) {
 703                 ret = idmap_tdb2_id_to_sid(ctx, ids[i]);
 704                 if ( ! NT_STATUS_IS_OK(ret)) {
 705 
 706                         /* if it is just a failed mapping continue */
 707                         if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
 708 
 709                                 /* make sure it is marked as unmapped */
 710                                 ids[i]->status = ID_UNMAPPED;
 711                                 continue;
 712                         }
 713                         
 714                         /* some fatal error occurred, return immediately */
 715                         goto done;
 716                 }
 717 
 718                 /* all ok, id is mapped */
 719                 ids[i]->status = ID_MAPPED;
 720         }
 721 
 722         ret = NT_STATUS_OK;
 723 
 724 done:
 725         return ret;
 726 }
 727 
 728 /*
 729   lookup a set of sids. 
 730 */
 731 static NTSTATUS idmap_tdb2_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
     /* [<][>][^][v][top][bottom][index][help] */
 732 {
 733         struct idmap_tdb2_context *ctx;
 734         NTSTATUS ret;
 735         int i;
 736 
 737         /* initialize the status to avoid suprise */
 738         for (i = 0; ids[i]; i++) {
 739                 ids[i]->status = ID_UNKNOWN;
 740         }
 741         
 742         ctx = talloc_get_type(dom->private_data, struct idmap_tdb2_context);
 743 
 744         for (i = 0; ids[i]; i++) {
 745                 ret = idmap_tdb2_sid_to_id(ctx, ids[i]);
 746                 if ( ! NT_STATUS_IS_OK(ret)) {
 747 
 748                         /* if it is just a failed mapping continue */
 749                         if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
 750 
 751                                 /* make sure it is marked as unmapped */
 752                                 ids[i]->status = ID_UNMAPPED;
 753                                 continue;
 754                         }
 755                         
 756                         /* some fatal error occurred, return immediately */
 757                         goto done;
 758                 }
 759 
 760                 /* all ok, id is mapped */
 761                 ids[i]->status = ID_MAPPED;
 762         }
 763 
 764         ret = NT_STATUS_OK;
 765 
 766 done:
 767         return ret;
 768 }
 769 
 770 
 771 /*
 772   set a mapping. 
 773 */
 774 static NTSTATUS idmap_tdb2_set_mapping(struct idmap_domain *dom, const struct id_map *map)
     /* [<][>][^][v][top][bottom][index][help] */
 775 {
 776         struct idmap_tdb2_context *ctx;
 777         NTSTATUS ret;
 778         TDB_DATA data;
 779         char *ksidstr, *kidstr;
 780         int res;
 781         bool started_transaction = false;
 782 
 783         if (!map || !map->sid) {
 784                 return NT_STATUS_INVALID_PARAMETER;
 785         }
 786 
 787         ksidstr = kidstr = NULL;
 788 
 789         /* TODO: should we filter a set_mapping using low/high filters ? */
 790         
 791         ctx = talloc_get_type(dom->private_data, struct idmap_tdb2_context);
 792 
 793         switch (map->xid.type) {
 794 
 795         case ID_TYPE_UID:
 796                 kidstr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id);
 797                 break;
 798                 
 799         case ID_TYPE_GID:
 800                 kidstr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id);
 801                 break;
 802 
 803         default:
 804                 DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type));
 805                 return NT_STATUS_INVALID_PARAMETER;
 806         }
 807 
 808         if (kidstr == NULL) {
 809                 DEBUG(0, ("ERROR: Out of memory!\n"));
 810                 ret = NT_STATUS_NO_MEMORY;
 811                 goto done;
 812         }
 813 
 814         if (!(ksidstr = sid_string_talloc(ctx, map->sid))) {
 815                 DEBUG(0, ("Out of memory!\n"));
 816                 ret = NT_STATUS_NO_MEMORY;
 817                 goto done;
 818         }
 819 
 820         DEBUG(10, ("Storing %s <-> %s map\n", ksidstr, kidstr));
 821 
 822         res = idmap_tdb2->transaction_start(idmap_tdb2);
 823         if (res != 0) {
 824                 DEBUG(1,(__location__ " Failed to start transaction\n"));
 825                 ret = NT_STATUS_UNSUCCESSFUL;
 826                 goto done;
 827         }
 828 
 829         started_transaction = true;
 830         
 831         /* check wheter sid mapping is already present in db */
 832         data = dbwrap_fetch_bystring(idmap_tdb2, ksidstr, ksidstr);
 833         if (data.dptr) {
 834                 ret = NT_STATUS_OBJECT_NAME_COLLISION;
 835                 goto done;
 836         }
 837 
 838         ret = dbwrap_store_bystring(idmap_tdb2, ksidstr, string_term_tdb_data(kidstr),
 839                                   TDB_INSERT);
 840         if (!NT_STATUS_IS_OK(ret)) {
 841                 DEBUG(0, ("Error storing SID -> ID: %s\n", nt_errstr(ret)));
 842                 goto done;
 843         }
 844         ret = dbwrap_store_bystring(idmap_tdb2, kidstr, string_term_tdb_data(ksidstr),
 845                                   TDB_INSERT);
 846         if (!NT_STATUS_IS_OK(ret)) {
 847                 DEBUG(0, ("Error storing ID -> SID: %s\n", nt_errstr(ret)));
 848                 /* try to remove the previous stored SID -> ID map */
 849                 dbwrap_delete_bystring(idmap_tdb2, ksidstr);
 850                 goto done;
 851         }
 852 
 853         started_transaction = false;
 854 
 855         res = idmap_tdb2->transaction_commit(idmap_tdb2);
 856         if (res != 0) {
 857                 DEBUG(1,(__location__ " Failed to commit transaction\n"));
 858                 ret = NT_STATUS_UNSUCCESSFUL;
 859                 goto done;
 860         }
 861 
 862         DEBUG(10,("Stored %s <-> %s\n", ksidstr, kidstr));
 863         ret = NT_STATUS_OK;
 864 
 865 done:
 866         if (started_transaction) {
 867                 idmap_tdb2->transaction_cancel(idmap_tdb2);
 868         }
 869         talloc_free(ksidstr);
 870         talloc_free(kidstr);
 871         return ret;
 872 }
 873 
 874 /*
 875   remove a mapping. 
 876 */
 877 static NTSTATUS idmap_tdb2_remove_mapping(struct idmap_domain *dom, const struct id_map *map)
     /* [<][>][^][v][top][bottom][index][help] */
 878 {
 879         /* not supported as it would invalidate the cache tdb on other
 880            nodes */
 881         DEBUG(0,("idmap_tdb2_remove_mapping not supported\n"));
 882         return NT_STATUS_NOT_SUPPORTED;
 883 }
 884 
 885 /*
 886   Close the idmap tdb instance
 887 */
 888 static NTSTATUS idmap_tdb2_close(struct idmap_domain *dom)
     /* [<][>][^][v][top][bottom][index][help] */
 889 {
 890         /* don't do anything */
 891         return NT_STATUS_OK;
 892 }
 893 
 894 
 895 /*
 896   Dump all mappings out
 897 */
 898 static NTSTATUS idmap_tdb2_dump_data(struct idmap_domain *dom, struct id_map **maps, int *num_maps)
     /* [<][>][^][v][top][bottom][index][help] */
 899 {
 900         DEBUG(0,("idmap_tdb2_dump_data not supported\n"));
 901         return NT_STATUS_NOT_SUPPORTED;
 902 }
 903 
 904 static struct idmap_methods db_methods = {
 905         .init            = idmap_tdb2_db_init,
 906         .unixids_to_sids = idmap_tdb2_unixids_to_sids,
 907         .sids_to_unixids = idmap_tdb2_sids_to_unixids,
 908         .set_mapping     = idmap_tdb2_set_mapping,
 909         .remove_mapping  = idmap_tdb2_remove_mapping,
 910         .dump_data       = idmap_tdb2_dump_data,
 911         .close_fn        = idmap_tdb2_close
 912 };
 913 
 914 static struct idmap_alloc_methods db_alloc_methods = {
 915         .init        = idmap_tdb2_alloc_init,
 916         .allocate_id = idmap_tdb2_allocate_id,
 917         .get_id_hwm  = idmap_tdb2_get_hwm,
 918         .set_id_hwm  = idmap_tdb2_set_hwm,
 919         .close_fn    = idmap_tdb2_alloc_close
 920 };
 921 
 922 NTSTATUS idmap_tdb2_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 923 {
 924         NTSTATUS ret;
 925 
 926         /* register both backends */
 927         ret = smb_register_idmap_alloc(SMB_IDMAP_INTERFACE_VERSION, "tdb2", &db_alloc_methods);
 928         if (! NT_STATUS_IS_OK(ret)) {
 929                 DEBUG(0, ("Unable to register idmap alloc tdb2 module: %s\n", get_friendly_nt_error_msg(ret)));
 930                 return ret;
 931         }
 932 
 933         return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "tdb2", &db_methods);
 934 }

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