nsswitch/idmap_tdb.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003 
00004    idmap TDB backend
00005 
00006    Copyright (C) Tim Potter 2000
00007    Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
00008    Copyright (C) Jeremy Allison 2006
00009    Copyright (C) Simo Sorce 2003-2006
00010    
00011    This program is free software; you can redistribute it and/or modify
00012    it under the terms of the GNU General Public License as published by
00013    the Free Software Foundation; either version 2 of the License, or
00014    (at your option) any later version.
00015    
00016    This program is distributed in the hope that it will be useful,
00017    but WITHOUT ANY WARRANTY; without even the implied warranty of
00018    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019    GNU General Public License for more details.
00020    
00021    You should have received a copy of the GNU General Public License
00022    along with this program; if not, write to the Free Software
00023    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00024 */
00025 
00026 #include "includes.h"
00027 #include "winbindd.h"
00028 
00029 #undef DBGC_CLASS
00030 #define DBGC_CLASS DBGC_IDMAP
00031 
00032 /* High water mark keys */
00033 #define HWM_GROUP  "GROUP HWM"
00034 #define HWM_USER   "USER HWM"
00035 
00036 static struct idmap_tdb_state {
00037 
00038         /* User and group id pool */
00039         uid_t low_uid, high_uid;               /* Range of uids to allocate */
00040         gid_t low_gid, high_gid;               /* Range of gids to allocate */
00041 
00042 } idmap_tdb_state;
00043 
00044 /*****************************************************************************
00045  For idmap conversion: convert one record to new format
00046  Ancient versions (eg 2.2.3a) of winbindd_idmap.tdb mapped DOMAINNAME/rid
00047  instead of the SID.
00048 *****************************************************************************/
00049 static int convert_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA data, void *state)
00050 {
00051         struct winbindd_domain *domain;
00052         char *p;
00053         DOM_SID sid;
00054         uint32 rid;
00055         fstring keystr;
00056         fstring dom_name;
00057         TDB_DATA key2;
00058         BOOL *failed = (BOOL *)state;
00059 
00060         DEBUG(10,("Converting %s\n", key.dptr));
00061 
00062         p = strchr(key.dptr, '/');
00063         if (!p)
00064                 return 0;
00065 
00066         *p = 0;
00067         fstrcpy(dom_name, key.dptr);
00068         *p++ = '/';
00069 
00070         domain = find_domain_from_name(dom_name);
00071         if (domain == NULL) {
00072                 /* We must delete the old record. */
00073                 DEBUG(0,("Unable to find domain %s\n", dom_name ));
00074                 DEBUG(0,("deleting record %s\n", key.dptr ));
00075 
00076                 if (tdb_delete(tdb, key) != 0) {
00077                         DEBUG(0, ("Unable to delete record %s\n", key.dptr));
00078                         *failed = True;
00079                         return -1;
00080                 }
00081 
00082                 return 0;
00083         }
00084 
00085         rid = atoi(p);
00086 
00087         sid_copy(&sid, &domain->sid);
00088         sid_append_rid(&sid, rid);
00089 
00090         sid_to_string(keystr, &sid);
00091         key2.dptr = keystr;
00092         key2.dsize = strlen(keystr) + 1;
00093 
00094         if (tdb_store(tdb, key2, data, TDB_INSERT) != 0) {
00095                 DEBUG(0,("Unable to add record %s\n", key2.dptr ));
00096                 *failed = True;
00097                 return -1;
00098         }
00099 
00100         if (tdb_store(tdb, data, key2, TDB_REPLACE) != 0) {
00101                 DEBUG(0,("Unable to update record %s\n", data.dptr ));
00102                 *failed = True;
00103                 return -1;
00104         }
00105 
00106         if (tdb_delete(tdb, key) != 0) {
00107                 DEBUG(0,("Unable to delete record %s\n", key.dptr ));
00108                 *failed = True;
00109                 return -1;
00110         }
00111 
00112         return 0;
00113 }
00114 
00115 /*****************************************************************************
00116  Convert the idmap database from an older version.
00117 *****************************************************************************/
00118 
00119 static BOOL idmap_tdb_convert(const char *idmap_name)
00120 {
00121         int32 vers;
00122         BOOL bigendianheader;
00123         BOOL failed = False;
00124         TDB_CONTEXT *idmap_tdb;
00125 
00126         if (!(idmap_tdb = tdb_open_log(idmap_name, 0,
00127                                         TDB_DEFAULT, O_RDWR,
00128                                         0600))) {
00129                 DEBUG(0, ("Unable to open idmap database\n"));
00130                 return False;
00131         }
00132 
00133         bigendianheader = (tdb_get_flags(idmap_tdb) & TDB_BIGENDIAN) ? True : False;
00134 
00135         vers = tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION");
00136 
00137         if (((vers == -1) && bigendianheader) || (IREV(vers) == IDMAP_VERSION)) {
00138                 /* Arrggghh ! Bytereversed or old big-endian - make order independent ! */
00139                 /*
00140                  * high and low records were created on a
00141                  * big endian machine and will need byte-reversing.
00142                  */
00143 
00144                 int32 wm;
00145 
00146                 wm = tdb_fetch_int32(idmap_tdb, HWM_USER);
00147 
00148                 if (wm != -1) {
00149                         wm = IREV(wm);
00150                 }  else {
00151                         wm = idmap_tdb_state.low_uid;
00152                 }
00153 
00154                 if (tdb_store_int32(idmap_tdb, HWM_USER, wm) == -1) {
00155                         DEBUG(0, ("Unable to byteswap user hwm in idmap database\n"));
00156                         tdb_close(idmap_tdb);
00157                         return False;
00158                 }
00159 
00160                 wm = tdb_fetch_int32(idmap_tdb, HWM_GROUP);
00161                 if (wm != -1) {
00162                         wm = IREV(wm);
00163                 } else {
00164                         wm = idmap_tdb_state.low_gid;
00165                 }
00166 
00167                 if (tdb_store_int32(idmap_tdb, HWM_GROUP, wm) == -1) {
00168                         DEBUG(0, ("Unable to byteswap group hwm in idmap database\n"));
00169                         tdb_close(idmap_tdb);
00170                         return False;
00171                 }
00172         }
00173 
00174         /* the old format stored as DOMAIN/rid - now we store the SID direct */
00175         tdb_traverse(idmap_tdb, convert_fn, &failed);
00176 
00177         if (failed) {
00178                 DEBUG(0, ("Problem during conversion\n"));
00179                 tdb_close(idmap_tdb);
00180                 return False;
00181         }
00182 
00183         if (tdb_store_int32(idmap_tdb, "IDMAP_VERSION", IDMAP_VERSION) == -1) {
00184                 DEBUG(0, ("Unable to dtore idmap version in databse\n"));
00185                 tdb_close(idmap_tdb);
00186                 return False;
00187         }
00188 
00189         tdb_close(idmap_tdb);
00190         return True;
00191 }
00192 
00193 /*****************************************************************************
00194  Convert the idmap database from an older version if necessary
00195 *****************************************************************************/
00196 
00197 BOOL idmap_tdb_upgrade(TALLOC_CTX *ctx, const char *tdbfile)
00198 {
00199         char *backup_name;
00200 
00201         DEBUG(0, ("Upgrading winbindd_idmap.tdb from an old version\n"));
00202 
00203         backup_name = talloc_asprintf(ctx, "%s.bak", tdbfile);
00204         if ( ! backup_name) {
00205                 DEBUG(0, ("Out of memory!\n"));
00206                 return False;
00207         }
00208 
00209         if (backup_tdb(tdbfile, backup_name, 0) != 0) {
00210                 DEBUG(0, ("Could not backup idmap database\n"));
00211                 talloc_free(backup_name);
00212                 return False;
00213         }
00214 
00215         talloc_free(backup_name);
00216         return idmap_tdb_convert(tdbfile);
00217 }
00218 
00219 /* WARNING: We can't open a tdb twice inthe same process, for that reason
00220  * I'm going to use a hack with open ref counts to open the winbindd_idmap.tdb
00221  * only once. We will later decide whether to split the db in multiple files
00222  * or come up with a better solution to share them. */
00223 
00224 static TDB_CONTEXT *idmap_tdb_common_ctx;
00225 static int idmap_tdb_open_ref_count = 0;
00226 
00227 static NTSTATUS idmap_tdb_open_db(TALLOC_CTX *memctx, TDB_CONTEXT **tdbctx)
00228 {
00229         NTSTATUS ret;
00230         TALLOC_CTX *ctx;
00231         SMB_STRUCT_STAT stbuf;
00232         char *tdbfile = NULL;
00233         int32 version;
00234         BOOL tdb_is_new = False;
00235 
00236         if (idmap_tdb_open_ref_count) { /* the tdb has already been opened */
00237                 idmap_tdb_open_ref_count++;
00238                 *tdbctx = idmap_tdb_common_ctx;
00239                 return NT_STATUS_OK;
00240         }
00241 
00242         /* use our own context here */
00243         ctx = talloc_new(memctx);
00244         if (!ctx) {
00245                 DEBUG(0, ("Out of memory!\n"));
00246                 return NT_STATUS_NO_MEMORY;
00247         }
00248 
00249         /* use the old database if present */
00250         tdbfile = talloc_strdup(ctx, lock_path("winbindd_idmap.tdb"));
00251         if (!tdbfile) {
00252                 DEBUG(0, ("Out of memory!\n"));
00253                 ret = NT_STATUS_NO_MEMORY;
00254                 goto done;
00255         }
00256 
00257         if (!file_exist(tdbfile, &stbuf)) {
00258                 tdb_is_new = True;
00259         }
00260 
00261         DEBUG(10,("Opening tdbfile %s\n", tdbfile ));
00262 
00263         /* Open idmap repository */
00264         if (!(idmap_tdb_common_ctx = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644))) {
00265                 DEBUG(0, ("Unable to open idmap database\n"));
00266                 ret = NT_STATUS_UNSUCCESSFUL;
00267                 goto done;
00268         }
00269 
00270         if (tdb_is_new) {
00271                 /* the file didn't existed before opening it, let's
00272                  * store idmap version as nobody else yet opened and
00273                  * stored it. I do not like this method but didn't
00274                  * found a way to understand if an opened tdb have
00275                  * been just created or not --- SSS */
00276                 tdb_store_int32(idmap_tdb_common_ctx, "IDMAP_VERSION", IDMAP_VERSION);
00277         }
00278 
00279         /* check against earlier versions */
00280         version = tdb_fetch_int32(idmap_tdb_common_ctx, "IDMAP_VERSION");
00281         if (version != IDMAP_VERSION) {
00282                 
00283                 /* backup_tdb expects the tdb not to be open */
00284                 tdb_close(idmap_tdb_common_ctx);
00285 
00286                 if ( ! idmap_tdb_upgrade(ctx, tdbfile)) {
00287                 
00288                         DEBUG(0, ("Unable to open idmap database, it's in an old formati, and upgrade failed!\n"));
00289                         ret = NT_STATUS_INTERNAL_DB_ERROR;
00290                         goto done;
00291                 }
00292 
00293                 /* Re-Open idmap repository */
00294                 if (!(idmap_tdb_common_ctx = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644))) {
00295                         DEBUG(0, ("Unable to open idmap database\n"));
00296                         ret = NT_STATUS_UNSUCCESSFUL;
00297                         goto done;
00298                 }
00299         }
00300 
00301         *tdbctx = idmap_tdb_common_ctx;
00302         idmap_tdb_open_ref_count++;
00303         ret = NT_STATUS_OK;
00304 
00305 done:
00306         talloc_free(ctx);
00307         return ret;
00308 }
00309 
00310  /* NEVER use tdb_close() except for the conversion routines that are guaranteed
00311  * to run only when the database is opened the first time, always use this function. */ 
00312 
00313 BOOL idmap_tdb_tdb_close(TDB_CONTEXT *tdbctx)
00314 {
00315         if (tdbctx != idmap_tdb_common_ctx) {
00316                 DEBUG(0, ("ERROR: Invalid tdb context!"));
00317                 return False;
00318         }
00319 
00320         idmap_tdb_open_ref_count--;
00321         if (idmap_tdb_open_ref_count) {
00322                 return True;
00323         }
00324 
00325         return tdb_close(idmap_tdb_common_ctx);
00326 }
00327 
00328 /**********************************************************************
00329  IDMAP ALLOC TDB BACKEND
00330 **********************************************************************/
00331  
00332 static TDB_CONTEXT *idmap_alloc_tdb;
00333 
00334 /**********************************
00335  Initialise idmap alloc database. 
00336 **********************************/
00337 
00338 static NTSTATUS idmap_tdb_alloc_init( const char *params )
00339 {
00340         NTSTATUS ret;
00341         TALLOC_CTX *ctx;
00342         const char *range;
00343         uid_t low_uid = 0;
00344         uid_t high_uid = 0;
00345         gid_t low_gid = 0;
00346         gid_t high_gid = 0;
00347 
00348         /* use our own context here */
00349         ctx = talloc_new(NULL);
00350         if (!ctx) {
00351                 DEBUG(0, ("Out of memory!\n"));
00352                 return NT_STATUS_NO_MEMORY;
00353         }
00354 
00355         ret = idmap_tdb_open_db(ctx, &idmap_alloc_tdb);
00356         if ( ! NT_STATUS_IS_OK(ret)) {
00357                 talloc_free(ctx);
00358                 return ret;
00359         }
00360 
00361         talloc_free(ctx);
00362 
00363         /* load ranges */
00364         idmap_tdb_state.low_uid = 0;
00365         idmap_tdb_state.high_uid = 0;
00366         idmap_tdb_state.low_gid = 0;
00367         idmap_tdb_state.high_gid = 0;
00368 
00369         range = lp_parm_const_string(-1, "idmap alloc config", "range", NULL);
00370         if (range && range[0]) {
00371                 unsigned low_id, high_id;
00372 
00373                 if (sscanf(range, "%u - %u", &low_id, &high_id) == 2) {
00374                         if (low_id < high_id) {
00375                                 idmap_tdb_state.low_gid = idmap_tdb_state.low_uid = low_id;
00376                                 idmap_tdb_state.high_gid = idmap_tdb_state.high_uid = high_id;
00377                         } else {
00378                                 DEBUG(1, ("ERROR: invalid idmap alloc range [%s]", range));
00379                         }
00380                 } else {
00381                         DEBUG(1, ("ERROR: invalid syntax for idmap alloc config:range [%s]", range));
00382                 }
00383         }
00384 
00385         /* Create high water marks for group and user id */
00386         if (lp_idmap_uid(&low_uid, &high_uid)) {
00387                 idmap_tdb_state.low_uid = low_uid;
00388                 idmap_tdb_state.high_uid = high_uid;
00389         }
00390 
00391         if (lp_idmap_gid(&low_gid, &high_gid)) {
00392                 idmap_tdb_state.low_gid = low_gid;
00393                 idmap_tdb_state.high_gid = high_gid;
00394         }
00395 
00396         if (idmap_tdb_state.high_uid <= idmap_tdb_state.low_uid) {
00397                 DEBUG(1, ("idmap uid range missing or invalid\n"));
00398                 DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n"));
00399                 return NT_STATUS_UNSUCCESSFUL;
00400         } else {
00401                 uint32 low_id;
00402 
00403                 if (((low_id = tdb_fetch_int32(idmap_alloc_tdb, HWM_USER)) == -1) ||
00404                     (low_id < idmap_tdb_state.low_uid)) {
00405                         if (tdb_store_int32(idmap_alloc_tdb, HWM_USER, idmap_tdb_state.low_uid) == -1) {
00406                                 DEBUG(0, ("Unable to initialise user hwm in idmap database\n"));
00407                                 return NT_STATUS_INTERNAL_DB_ERROR;
00408                         }
00409                 }
00410         }
00411 
00412         if (idmap_tdb_state.high_gid <= idmap_tdb_state.low_gid) {
00413                 DEBUG(1, ("idmap gid range missing or invalid\n"));
00414                 DEBUGADD(1, ("idmap will be unable to map foreign SIDs\n"));
00415                 return NT_STATUS_UNSUCCESSFUL;
00416         } else {
00417                 uint32 low_id;
00418 
00419                 if (((low_id = tdb_fetch_int32(idmap_alloc_tdb, HWM_GROUP)) == -1) ||
00420                     (low_id < idmap_tdb_state.low_gid)) {
00421                         if (tdb_store_int32(idmap_alloc_tdb, HWM_GROUP, idmap_tdb_state.low_gid) == -1) {
00422                                 DEBUG(0, ("Unable to initialise group hwm in idmap database\n"));
00423                                 return NT_STATUS_INTERNAL_DB_ERROR;
00424                         }
00425                 }
00426         }
00427 
00428         return NT_STATUS_OK;
00429 }
00430 
00431 /**********************************
00432  Allocate a new id. 
00433 **********************************/
00434 
00435 static NTSTATUS idmap_tdb_allocate_id(struct unixid *xid)
00436 {
00437         BOOL ret;
00438         const char *hwmkey;
00439         const char *hwmtype;
00440         uint32_t high_hwm;
00441         uint32_t hwm;
00442 
00443         /* Get current high water mark */
00444         switch (xid->type) {
00445 
00446         case ID_TYPE_UID:
00447                 hwmkey = HWM_USER;
00448                 hwmtype = "UID";
00449                 high_hwm = idmap_tdb_state.high_uid;
00450                 break;
00451 
00452         case ID_TYPE_GID:
00453                 hwmkey = HWM_GROUP;
00454                 hwmtype = "GID";
00455                 high_hwm = idmap_tdb_state.high_gid;
00456                 break;
00457 
00458         default:
00459                 DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type));
00460                 return NT_STATUS_INVALID_PARAMETER;
00461         }
00462 
00463         if ((hwm = tdb_fetch_int32(idmap_alloc_tdb, hwmkey)) == -1) {
00464                 return NT_STATUS_INTERNAL_DB_ERROR;
00465         }
00466 
00467         /* check it is in the range */
00468         if (hwm > high_hwm) {
00469                 DEBUG(1, ("Fatal Error: %s range full!! (max: %lu)\n", 
00470                           hwmtype, (unsigned long)high_hwm));
00471                 return NT_STATUS_UNSUCCESSFUL;
00472         }
00473 
00474         /* fetch a new id and increment it */
00475         ret = tdb_change_uint32_atomic(idmap_alloc_tdb, hwmkey, &hwm, 1);
00476         if (!ret) {
00477                 DEBUG(1, ("Fatal error while fetching a new %s value\n!", hwmtype));
00478                 return NT_STATUS_UNSUCCESSFUL;
00479         }
00480 
00481         /* recheck it is in the range */
00482         if (hwm > high_hwm) {
00483                 DEBUG(1, ("Fatal Error: %s range full!! (max: %lu)\n", 
00484                           hwmtype, (unsigned long)high_hwm));
00485                 return NT_STATUS_UNSUCCESSFUL;
00486         }
00487         
00488         xid->id = hwm;
00489         DEBUG(10,("New %s = %d\n", hwmtype, hwm));
00490 
00491         return NT_STATUS_OK;
00492 }
00493 
00494 /**********************************
00495  Get current highest id. 
00496 **********************************/
00497 
00498 static NTSTATUS idmap_tdb_get_hwm(struct unixid *xid)
00499 {
00500         const char *hwmkey;
00501         const char *hwmtype;
00502         uint32_t hwm;
00503         uint32_t high_hwm;
00504 
00505         /* Get current high water mark */
00506         switch (xid->type) {
00507 
00508         case ID_TYPE_UID:
00509                 hwmkey = HWM_USER;
00510                 hwmtype = "UID";
00511                 high_hwm = idmap_tdb_state.high_uid;
00512                 break;
00513 
00514         case ID_TYPE_GID:
00515                 hwmkey = HWM_GROUP;
00516                 hwmtype = "GID";
00517                 high_hwm = idmap_tdb_state.high_gid;
00518                 break;
00519 
00520         default:
00521                 return NT_STATUS_INVALID_PARAMETER;
00522         }
00523 
00524         if ((hwm = tdb_fetch_int32(idmap_alloc_tdb, hwmkey)) == -1) {
00525                 return NT_STATUS_INTERNAL_DB_ERROR;
00526         }
00527 
00528         xid->id = hwm;
00529 
00530         /* Warn if it is out of range */
00531         if (hwm >= high_hwm) {
00532                 DEBUG(0, ("Warning: %s range full!! (max: %lu)\n", 
00533                           hwmtype, (unsigned long)high_hwm));
00534         }
00535 
00536         return NT_STATUS_OK;
00537 }
00538 
00539 /**********************************
00540  Set high id. 
00541 **********************************/
00542 
00543 static NTSTATUS idmap_tdb_set_hwm(struct unixid *xid)
00544 {
00545         const char *hwmkey;
00546         const char *hwmtype;
00547         uint32_t hwm;
00548         uint32_t high_hwm;
00549 
00550         /* Get current high water mark */
00551         switch (xid->type) {
00552 
00553         case ID_TYPE_UID:
00554                 hwmkey = HWM_USER;
00555                 hwmtype = "UID";
00556                 high_hwm = idmap_tdb_state.high_uid;
00557                 break;
00558 
00559         case ID_TYPE_GID:
00560                 hwmkey = HWM_GROUP;
00561                 hwmtype = "GID";
00562                 high_hwm = idmap_tdb_state.high_gid;
00563                 break;
00564 
00565         default:
00566                 return NT_STATUS_INVALID_PARAMETER;
00567         }
00568 
00569         hwm = xid->id;
00570 
00571         if ((hwm = tdb_store_int32(idmap_alloc_tdb, hwmkey, hwm)) == -1) {
00572                 return NT_STATUS_INTERNAL_DB_ERROR;
00573         }
00574 
00575         /* Warn if it is out of range */
00576         if (hwm >= high_hwm) {
00577                 DEBUG(0, ("Warning: %s range full!! (max: %lu)\n", 
00578                           hwmtype, (unsigned long)high_hwm));
00579         }
00580 
00581         return NT_STATUS_OK;
00582 }
00583 
00584 /**********************************
00585  Close the alloc tdb 
00586 **********************************/
00587 
00588 static NTSTATUS idmap_tdb_alloc_close(void)
00589 {
00590         if (idmap_alloc_tdb) {
00591                 if (idmap_tdb_tdb_close(idmap_alloc_tdb) == 0) {
00592                         return NT_STATUS_OK;
00593                 } else {
00594                         return NT_STATUS_UNSUCCESSFUL;
00595                 }
00596         }
00597         return NT_STATUS_OK;
00598 }
00599 
00600 /**********************************************************************
00601  IDMAP MAPPING TDB BACKEND
00602 **********************************************************************/
00603  
00604 struct idmap_tdb_context {
00605         TDB_CONTEXT *tdb;
00606         uint32_t filter_low_id;
00607         uint32_t filter_high_id;
00608 };
00609 
00610 /*****************************
00611  Initialise idmap database. 
00612 *****************************/
00613 
00614 static NTSTATUS idmap_tdb_db_init(struct idmap_domain *dom)
00615 {
00616         NTSTATUS ret;
00617         struct idmap_tdb_context *ctx;
00618         char *config_option = NULL;
00619         const char *range;
00620 
00621         ctx = talloc(dom, struct idmap_tdb_context);
00622         if ( ! ctx) {
00623                 DEBUG(0, ("Out of memory!\n"));
00624                 return NT_STATUS_NO_MEMORY;
00625         }
00626 
00627         config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
00628         if ( ! config_option) {
00629                 DEBUG(0, ("Out of memory!\n"));
00630                 ret = NT_STATUS_NO_MEMORY;
00631                 goto failed;
00632         }
00633 
00634         ret = idmap_tdb_open_db(ctx, &ctx->tdb);
00635         if ( ! NT_STATUS_IS_OK(ret)) {
00636                 goto failed;
00637         }
00638 
00639         range = lp_parm_const_string(-1, config_option, "range", NULL);
00640         if (( ! range) ||
00641             (sscanf(range, "%u - %u", &ctx->filter_low_id, &ctx->filter_high_id) != 2) ||
00642             (ctx->filter_low_id > ctx->filter_high_id)) {
00643                 ctx->filter_low_id = 0;
00644                 ctx->filter_high_id = 0;
00645         }
00646 
00647         dom->private_data = ctx;
00648         dom->initialized = True;
00649 
00650         talloc_free(config_option);
00651         return NT_STATUS_OK;
00652 
00653 failed:
00654         talloc_free(ctx);
00655         return ret;
00656 }
00657 
00658 /**********************************
00659  Single id to sid lookup function. 
00660 **********************************/
00661 
00662 static NTSTATUS idmap_tdb_id_to_sid(struct idmap_tdb_context *ctx, struct id_map *map)
00663 {
00664         NTSTATUS ret;
00665         TDB_DATA key, data;
00666 
00667         if (!ctx || !map) {
00668                 return NT_STATUS_INVALID_PARAMETER;
00669         }
00670 
00671         /* apply filters before checking */
00672         if ((ctx->filter_low_id && (map->xid.id < ctx->filter_low_id)) ||
00673             (ctx->filter_high_id && (map->xid.id > ctx->filter_high_id))) {
00674                 DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
00675                                 map->xid.id, ctx->filter_low_id, ctx->filter_high_id));
00676                 return NT_STATUS_NONE_MAPPED;
00677         }
00678 
00679         switch (map->xid.type) {
00680 
00681         case ID_TYPE_UID:
00682                 key.dptr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id);
00683                 break;
00684                 
00685         case ID_TYPE_GID:
00686                 key.dptr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id);
00687                 break;
00688 
00689         default:
00690                 DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type));
00691                 return NT_STATUS_INVALID_PARAMETER;
00692         }
00693 
00694         /* final SAFE_FREE safe */
00695         data.dptr = NULL;
00696 
00697         if (key.dptr == NULL) {
00698                 DEBUG(0, ("Out of memory!\n"));
00699                 ret = NT_STATUS_NO_MEMORY;
00700                 goto done;
00701         }
00702 
00703         key.dsize = strlen(key.dptr) + 1;
00704 
00705         DEBUG(10,("Fetching record %s\n", key.dptr));
00706 
00707         /* Check if the mapping exists */
00708         data = tdb_fetch(ctx->tdb, key);
00709 
00710         if (!data.dptr) {
00711                 DEBUG(10,("Record %s not found\n", key.dptr));
00712                 ret = NT_STATUS_NONE_MAPPED;
00713                 goto done;
00714         }
00715                 
00716         if (!string_to_sid(map->sid, data.dptr)) {
00717                 DEBUG(10,("INVALID SID (%s) in record %s\n",
00718                                 data.dptr, key.dptr));
00719                 ret = NT_STATUS_INTERNAL_DB_ERROR;
00720                 goto done;
00721         }
00722 
00723         DEBUG(10,("Found record %s -> %s\n", key.dptr, data.dptr));
00724         ret = NT_STATUS_OK;
00725 
00726 done:
00727         SAFE_FREE(data.dptr);
00728         talloc_free(key.dptr);
00729         return ret;
00730 }
00731 
00732 /**********************************
00733  Single sid to id lookup function. 
00734 **********************************/
00735 
00736 static NTSTATUS idmap_tdb_sid_to_id(struct idmap_tdb_context *ctx, struct id_map *map)
00737 {
00738         NTSTATUS ret;
00739         TDB_DATA key, data;
00740         unsigned long rec_id = 0;
00741 
00742         if ((key.dptr = talloc_asprintf(ctx, "%s", sid_string_static(map->sid))) == NULL) {
00743                 DEBUG(0, ("Out of memory!\n"));
00744                 ret = NT_STATUS_NO_MEMORY;
00745                 goto done;
00746         }
00747 
00748         key.dsize = strlen(key.dptr) + 1;
00749 
00750         DEBUG(10,("Fetching record %s\n", key.dptr));
00751 
00752         /* Check if sid is present in database */
00753         data = tdb_fetch(ctx->tdb, key);
00754         if (!data.dptr) {
00755                 DEBUG(10,("Record %s not found\n", key.dptr));
00756                 ret = NT_STATUS_NONE_MAPPED;
00757                 goto done;
00758         }
00759 
00760         /* What type of record is this ? */
00761         if (sscanf(data.dptr, "UID %lu", &rec_id) == 1) { /* Try a UID record. */
00762                 map->xid.id = rec_id;
00763                 map->xid.type = ID_TYPE_UID;
00764                 DEBUG(10,("Found uid record %s -> %s \n", key.dptr, data.dptr ));
00765                 ret = NT_STATUS_OK;
00766 
00767         } else if (sscanf(data.dptr, "GID %lu", &rec_id) == 1) { /* Try a GID record. */
00768                 map->xid.id = rec_id;
00769                 map->xid.type = ID_TYPE_GID;
00770                 DEBUG(10,("Found gid record %s -> %s \n", key.dptr, data.dptr ));
00771                 ret = NT_STATUS_OK;
00772 
00773         } else { /* Unknown record type ! */
00774                 DEBUG(2, ("Found INVALID record %s -> %s\n", key.dptr, data.dptr));
00775                 ret = NT_STATUS_INTERNAL_DB_ERROR;
00776         }
00777         
00778         SAFE_FREE(data.dptr);
00779 
00780         /* apply filters before returning result */
00781         if ((ctx->filter_low_id && (map->xid.id < ctx->filter_low_id)) ||
00782             (ctx->filter_high_id && (map->xid.id > ctx->filter_high_id))) {
00783                 DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
00784                                 map->xid.id, ctx->filter_low_id, ctx->filter_high_id));
00785                 ret = NT_STATUS_NONE_MAPPED;
00786         }
00787 
00788 done:
00789         talloc_free(key.dptr);
00790         return ret;
00791 }
00792 
00793 /**********************************
00794  lookup a set of unix ids. 
00795 **********************************/
00796 
00797 static NTSTATUS idmap_tdb_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
00798 {
00799         struct idmap_tdb_context *ctx;
00800         NTSTATUS ret;
00801         int i;
00802 
00803         /* make sure we initialized */
00804         if ( ! dom->initialized) {
00805                 ret = idmap_tdb_db_init(dom);
00806                 if ( ! NT_STATUS_IS_OK(ret)) {
00807                         return ret;
00808                 }
00809         }
00810 
00811         ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
00812 
00813         for (i = 0; ids[i]; i++) {
00814                 ret = idmap_tdb_id_to_sid(ctx, ids[i]);
00815                 if ( ! NT_STATUS_IS_OK(ret)) {
00816 
00817                         /* if it is just a failed mapping continue */
00818                         if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
00819 
00820                                 /* make sure it is marked as unmapped */
00821                                 ids[i]->status = ID_UNMAPPED;
00822                                 continue;
00823                         }
00824                         
00825                         /* some fatal error occurred, return immediately */
00826                         goto done;
00827                 }
00828 
00829                 /* all ok, id is mapped */
00830                 ids[i]->status = ID_MAPPED;
00831         }
00832 
00833         ret = NT_STATUS_OK;
00834 
00835 done:
00836         return ret;
00837 }
00838 
00839 /**********************************
00840  lookup a set of sids. 
00841 **********************************/
00842 
00843 static NTSTATUS idmap_tdb_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
00844 {
00845         struct idmap_tdb_context *ctx;
00846         NTSTATUS ret;
00847         int i;
00848 
00849         /* make sure we initialized */
00850         if ( ! dom->initialized) {
00851                 ret = idmap_tdb_db_init(dom);
00852                 if ( ! NT_STATUS_IS_OK(ret)) {
00853                         return ret;
00854                 }
00855         }
00856 
00857         ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
00858 
00859         for (i = 0; ids[i]; i++) {
00860                 ret = idmap_tdb_sid_to_id(ctx, ids[i]);
00861                 if ( ! NT_STATUS_IS_OK(ret)) {
00862 
00863                         /* if it is just a failed mapping continue */
00864                         if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
00865 
00866                                 /* make sure it is marked as unmapped */
00867                                 ids[i]->status = ID_UNMAPPED;
00868                                 continue;
00869                         }
00870                         
00871                         /* some fatal error occurred, return immediately */
00872                         goto done;
00873                 }
00874 
00875                 /* all ok, id is mapped */
00876                 ids[i]->status = ID_MAPPED;
00877         }
00878 
00879         ret = NT_STATUS_OK;
00880 
00881 done:
00882         return ret;
00883 }
00884 
00885 /**********************************
00886  set a mapping. 
00887 **********************************/
00888 
00889 static NTSTATUS idmap_tdb_set_mapping(struct idmap_domain *dom, const struct id_map *map)
00890 {
00891         struct idmap_tdb_context *ctx;
00892         NTSTATUS ret;
00893         TDB_DATA ksid, kid, data;
00894 
00895         /* make sure we initialized */
00896         if ( ! dom->initialized) {
00897                 ret = idmap_tdb_db_init(dom);
00898                 if ( ! NT_STATUS_IS_OK(ret)) {
00899                         return ret;
00900                 }
00901         }
00902 
00903         if (!map || !map->sid) {
00904                 return NT_STATUS_INVALID_PARAMETER;
00905         }
00906 
00907         ksid.dptr = kid.dptr = data.dptr = NULL;
00908 
00909         /* TODO: should we filter a set_mapping using low/high filters ? */
00910         
00911         ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
00912 
00913         switch (map->xid.type) {
00914 
00915         case ID_TYPE_UID:
00916                 kid.dptr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id);
00917                 break;
00918                 
00919         case ID_TYPE_GID:
00920                 kid.dptr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id);
00921                 break;
00922 
00923         default:
00924                 DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type));
00925                 return NT_STATUS_INVALID_PARAMETER;
00926         }
00927 
00928         if (kid.dptr == NULL) {
00929                 DEBUG(0, ("ERROR: Out of memory!\n"));
00930                 ret = NT_STATUS_NO_MEMORY;
00931                 goto done;
00932         }
00933         kid.dsize = strlen(kid.dptr) + 1;
00934 
00935         if ((ksid.dptr = talloc_asprintf(ctx, "%s", sid_string_static(map->sid))) == NULL) {
00936                 DEBUG(0, ("Out of memory!\n"));
00937                 ret = NT_STATUS_NO_MEMORY;
00938                 goto done;
00939         }
00940         ksid.dsize = strlen(ksid.dptr) + 1;
00941 
00942         DEBUG(10, ("Storing %s <-> %s map\n", ksid.dptr, kid.dptr));
00943 
00944         /* *DELETE* previous mappings if any.
00945          * This is done both SID and [U|G]ID passed in */
00946         
00947         /* Lock the record for this SID. */
00948         if (tdb_chainlock(ctx->tdb, ksid) != 0) {
00949                 DEBUG(10,("Failed to lock record %s. Error %s\n",
00950                                 ksid.dptr, tdb_errorstr(ctx->tdb) ));
00951                 return NT_STATUS_UNSUCCESSFUL;
00952         }
00953 
00954         data = tdb_fetch(ctx->tdb, ksid);
00955         if (data.dptr) {
00956                 DEBUG(10, ("Deleting existing mapping %s <-> %s\n", data.dptr, ksid.dptr ));
00957                 tdb_delete(ctx->tdb, data);
00958                 tdb_delete(ctx->tdb, ksid);
00959                 SAFE_FREE(data.dptr);
00960         }
00961 
00962         data = tdb_fetch(ctx->tdb, kid);
00963         if (data.dptr) {
00964                 DEBUG(10,("Deleting existing mapping %s <-> %s\n", data.dptr, kid.dptr ));
00965                 tdb_delete(ctx->tdb, data);
00966                 tdb_delete(ctx->tdb, kid);
00967                 SAFE_FREE(data.dptr);
00968         }
00969 
00970         if (tdb_store(ctx->tdb, ksid, kid, TDB_INSERT) == -1) {
00971                 DEBUG(0, ("Error storing SID -> ID: %s\n", tdb_errorstr(ctx->tdb)));
00972                 tdb_chainunlock(ctx->tdb, ksid);
00973                 ret = NT_STATUS_UNSUCCESSFUL;
00974                 goto done;
00975         }
00976         if (tdb_store(ctx->tdb, kid, ksid, TDB_INSERT) == -1) {
00977                 DEBUG(0, ("Error stroing ID -> SID: %s\n", tdb_errorstr(ctx->tdb)));
00978                 /* try to remove the previous stored SID -> ID map */
00979                 tdb_delete(ctx->tdb, ksid);
00980                 tdb_chainunlock(ctx->tdb, ksid);
00981                 ret = NT_STATUS_UNSUCCESSFUL;
00982                 goto done;
00983         }
00984 
00985         tdb_chainunlock(ctx->tdb, ksid);
00986         DEBUG(10,("Stored %s <-> %s\n", ksid.dptr, kid.dptr));
00987         ret = NT_STATUS_OK;
00988 
00989 done:
00990         talloc_free(ksid.dptr);
00991         talloc_free(kid.dptr);
00992         SAFE_FREE(data.dptr);
00993         return ret;
00994 }
00995 
00996 /**********************************
00997  remove a mapping. 
00998 **********************************/
00999 
01000 static NTSTATUS idmap_tdb_remove_mapping(struct idmap_domain *dom, const struct id_map *map)
01001 {
01002         struct idmap_tdb_context *ctx;
01003         NTSTATUS ret;
01004         TDB_DATA ksid, kid, data;
01005 
01006         /* make sure we initialized */
01007         if ( ! dom->initialized) {
01008                 ret = idmap_tdb_db_init(dom);
01009                 if ( ! NT_STATUS_IS_OK(ret)) {
01010                         return ret;
01011                 }
01012         }
01013 
01014         if (!map || !map->sid) {
01015                 return NT_STATUS_INVALID_PARAMETER;
01016         }
01017 
01018         ksid.dptr = kid.dptr = data.dptr = NULL;
01019 
01020         /* TODO: should we filter a remove_mapping using low/high filters ? */
01021         
01022         ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
01023 
01024         switch (map->xid.type) {
01025 
01026         case ID_TYPE_UID:
01027                 kid.dptr = talloc_asprintf(ctx, "UID %lu", (unsigned long)map->xid.id);
01028                 break;
01029                 
01030         case ID_TYPE_GID:
01031                 kid.dptr = talloc_asprintf(ctx, "GID %lu", (unsigned long)map->xid.id);
01032                 break;
01033 
01034         default:
01035                 DEBUG(2, ("INVALID unix ID type: 0x02%x\n", map->xid.type));
01036                 return NT_STATUS_INVALID_PARAMETER;
01037         }
01038 
01039         if (kid.dptr == NULL) {
01040                 DEBUG(0, ("ERROR: Out of memory!\n"));
01041                 ret = NT_STATUS_NO_MEMORY;
01042                 goto done;
01043         }
01044         kid.dsize = strlen(kid.dptr) + 1;
01045 
01046         if ((ksid.dptr = talloc_asprintf(ctx, "%s", sid_string_static(map->sid))) == NULL) {
01047                 DEBUG(0, ("Out of memory!\n"));
01048                 ret = NT_STATUS_NO_MEMORY;
01049                 goto done;
01050         }
01051         ksid.dsize = strlen(ksid.dptr) + 1;
01052 
01053         DEBUG(10, ("Checking %s <-> %s map\n", ksid.dptr, kid.dptr));
01054 
01055         /* Lock the record for this SID. */
01056         if (tdb_chainlock(ctx->tdb, ksid) != 0) {
01057                 DEBUG(10,("Failed to lock record %s. Error %s\n",
01058                                 ksid.dptr, tdb_errorstr(ctx->tdb) ));
01059                 return NT_STATUS_UNSUCCESSFUL;
01060         }
01061 
01062         /* Check if sid is present in database */
01063         data = tdb_fetch(ctx->tdb, ksid);
01064         if (!data.dptr) {
01065                 DEBUG(10,("Record %s not found\n", ksid.dptr));
01066                 tdb_chainunlock(ctx->tdb, ksid);
01067                 ret = NT_STATUS_NONE_MAPPED;
01068                 goto done;
01069         }
01070 
01071         /* Check if sid is mapped to the specified ID */
01072         if ((data.dsize != kid.dsize) ||
01073             (memcmp(data.dptr, kid.dptr, data.dsize) != 0)) {
01074                 DEBUG(10,("Specified SID does not map to specified ID\n"));
01075                 DEBUGADD(10,("Actual mapping is %s -> %s\n", ksid.dptr, data.dptr));
01076                 tdb_chainunlock(ctx->tdb, ksid);
01077                 ret = NT_STATUS_NONE_MAPPED;
01078                 goto done;
01079         }
01080         
01081         DEBUG(10, ("Removing %s <-> %s map\n", ksid.dptr, kid.dptr));
01082 
01083         /* Delete previous mappings. */
01084         
01085         DEBUG(10, ("Deleting existing mapping %s -> %s\n", ksid.dptr, kid.dptr ));
01086         tdb_delete(ctx->tdb, ksid);
01087 
01088         DEBUG(10,("Deleting existing mapping %s -> %s\n", kid.dptr, ksid.dptr ));
01089         tdb_delete(ctx->tdb, kid);
01090 
01091         tdb_chainunlock(ctx->tdb, ksid);
01092         ret = NT_STATUS_OK;
01093 
01094 done:
01095         talloc_free(ksid.dptr);
01096         talloc_free(kid.dptr);
01097         SAFE_FREE(data.dptr);
01098         return ret;
01099 }
01100 
01101 /**********************************
01102  Close the idmap tdb instance
01103 **********************************/
01104 
01105 static NTSTATUS idmap_tdb_close(struct idmap_domain *dom)
01106 {
01107         struct idmap_tdb_context *ctx;
01108 
01109         if (dom->private_data) {
01110                 ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
01111 
01112                 if (idmap_tdb_tdb_close(ctx->tdb) == 0) {
01113                         return NT_STATUS_OK;
01114                 } else {
01115                         return NT_STATUS_UNSUCCESSFUL;
01116                 }
01117         }
01118         return NT_STATUS_OK;
01119 }
01120 
01121 struct dump_data {
01122         TALLOC_CTX *memctx;
01123         struct id_map **maps;
01124         int *num_maps;
01125         NTSTATUS ret;
01126 };
01127 
01128 static int idmap_tdb_dump_one_entry(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value, void *pdata)
01129 {
01130         struct dump_data *data = talloc_get_type(pdata, struct dump_data);
01131         struct id_map *maps;
01132         int num_maps = *data->num_maps;
01133 
01134         /* ignore any record but the ones with a SID as key */
01135         if (strncmp(key.dptr, "S-", 2) == 0) {
01136 
01137                 maps = talloc_realloc(NULL, *data->maps, struct id_map, num_maps+1);
01138                 if ( ! maps) {
01139                         DEBUG(0, ("Out of memory!\n"));
01140                         data->ret = NT_STATUS_NO_MEMORY;
01141                         return -1;
01142                 }
01143                 *data->maps = maps;
01144                 maps[num_maps].sid = talloc(maps, DOM_SID);
01145                 if ( ! maps[num_maps].sid) {
01146                         DEBUG(0, ("Out of memory!\n"));
01147                         data->ret = NT_STATUS_NO_MEMORY;
01148                         return -1;
01149                 }
01150 
01151                 if (!string_to_sid(maps[num_maps].sid, key.dptr)) {
01152                         DEBUG(10,("INVALID record %s\n", key.dptr));
01153                         /* continue even with errors */
01154                         return 0;
01155                 }
01156 
01157                 /* Try a UID record. */
01158                 if (sscanf(value.dptr, "UID %u", &(maps[num_maps].xid.id)) == 1) {
01159                         maps[num_maps].xid.type = ID_TYPE_UID;
01160                         maps[num_maps].status = ID_MAPPED;
01161                         *data->num_maps = num_maps + 1;
01162 
01163                 /* Try a GID record. */
01164                 } else
01165                 if (sscanf(value.dptr, "GID %u", &(maps[num_maps].xid.id)) == 1) {
01166                         maps[num_maps].xid.type = ID_TYPE_GID;
01167                         maps[num_maps].status = ID_MAPPED;
01168                         *data->num_maps = num_maps + 1;
01169 
01170                 /* Unknown record type ! */
01171                 } else {
01172                         maps[num_maps].status = ID_UNKNOWN;
01173                         DEBUG(2, ("Found INVALID record %s -> %s\n", key.dptr, value.dptr));
01174                         /* do not increment num_maps */
01175                 }
01176         }
01177 
01178         return 0;
01179 }
01180 
01181 /**********************************
01182  Dump all mappings out
01183 **********************************/
01184 
01185 static NTSTATUS idmap_tdb_dump_data(struct idmap_domain *dom, struct id_map **maps, int *num_maps)
01186 {
01187         struct idmap_tdb_context *ctx;
01188         struct dump_data *data;
01189         NTSTATUS ret = NT_STATUS_OK;
01190 
01191         /* make sure we initialized */
01192         if ( ! dom->initialized) {
01193                 ret = idmap_tdb_db_init(dom);
01194                 if ( ! NT_STATUS_IS_OK(ret)) {
01195                         return ret;
01196                 }
01197         }
01198 
01199         ctx = talloc_get_type(dom->private_data, struct idmap_tdb_context);
01200 
01201         data = TALLOC_ZERO_P(ctx, struct dump_data);
01202         if ( ! data) {
01203                 DEBUG(0, ("Out of memory!\n"));
01204                 return NT_STATUS_NO_MEMORY;
01205         }
01206         data->maps = maps;
01207         data->num_maps = num_maps;
01208         data->ret = NT_STATUS_OK;
01209 
01210         tdb_traverse(ctx->tdb, idmap_tdb_dump_one_entry, data);
01211 
01212         if ( ! NT_STATUS_IS_OK(data->ret)) {
01213                 ret = data->ret;
01214         }
01215 
01216         talloc_free(data);
01217         return ret;
01218 }
01219 
01220 static struct idmap_methods db_methods = {
01221 
01222         .init = idmap_tdb_db_init,
01223         .unixids_to_sids = idmap_tdb_unixids_to_sids,
01224         .sids_to_unixids = idmap_tdb_sids_to_unixids,
01225         .set_mapping = idmap_tdb_set_mapping,
01226         .remove_mapping = idmap_tdb_remove_mapping,
01227         .dump_data = idmap_tdb_dump_data,
01228         .close_fn = idmap_tdb_close
01229 };
01230 
01231 static struct idmap_alloc_methods db_alloc_methods = {
01232 
01233         .init = idmap_tdb_alloc_init,
01234         .allocate_id = idmap_tdb_allocate_id,
01235         .get_id_hwm = idmap_tdb_get_hwm,
01236         .set_id_hwm = idmap_tdb_set_hwm,
01237         .close_fn = idmap_tdb_alloc_close
01238 };
01239 
01240 NTSTATUS idmap_alloc_tdb_init(void)
01241 {
01242         return smb_register_idmap_alloc(SMB_IDMAP_INTERFACE_VERSION, "tdb", &db_alloc_methods);
01243 }
01244 
01245 NTSTATUS idmap_tdb_init(void)
01246 {
01247         NTSTATUS ret;
01248 
01249         /* FIXME: bad hack to actually register also the alloc_tdb module without changining configure.in */
01250         ret = idmap_alloc_tdb_init();
01251         if (! NT_STATUS_IS_OK(ret)) {
01252                 return ret;
01253         }
01254         return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "tdb", &db_methods);
01255 }

Sambaに対してSat Aug 29 21:23:09 2009に生成されました。  doxygen 1.4.7