00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "includes.h"
00025 #include "winbindd.h"
00026
00027 #define TIMEOUT_LEN 12
00028 #define IDMAP_CACHE_DATA_FMT "%12u/%s"
00029 #define IDMAP_READ_CACHE_DATA_FMT_TEMPLATE "%%12u/%%%us"
00030
00031 struct idmap_cache_ctx {
00032 TDB_CONTEXT *tdb;
00033 };
00034
00035 static int idmap_cache_destructor(struct idmap_cache_ctx *cache)
00036 {
00037 int ret = 0;
00038
00039 if (cache && cache->tdb) {
00040 ret = tdb_close(cache->tdb);
00041 cache->tdb = NULL;
00042 }
00043
00044 return ret;
00045 }
00046
00047 struct idmap_cache_ctx *idmap_cache_init(TALLOC_CTX *memctx)
00048 {
00049 struct idmap_cache_ctx *cache;
00050 char* cache_fname = NULL;
00051
00052 cache = talloc(memctx, struct idmap_cache_ctx);
00053 if ( ! cache) {
00054 DEBUG(0, ("Out of memory!\n"));
00055 return NULL;
00056 }
00057
00058 cache_fname = lock_path("idmap_cache.tdb");
00059
00060 DEBUG(10, ("Opening cache file at %s\n", cache_fname));
00061
00062 cache->tdb = tdb_open_log(cache_fname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
00063
00064 if (!cache->tdb) {
00065 DEBUG(5, ("Attempt to open %s has failed.\n", cache_fname));
00066 return NULL;
00067 }
00068
00069 talloc_set_destructor(cache, idmap_cache_destructor);
00070
00071 return cache;
00072 }
00073
00074 void idmap_cache_shutdown(struct idmap_cache_ctx *cache)
00075 {
00076 talloc_free(cache);
00077 }
00078
00079 NTSTATUS idmap_cache_build_sidkey(TALLOC_CTX *ctx, char **sidkey, const struct id_map *id)
00080 {
00081 *sidkey = talloc_asprintf(ctx, "IDMAP/SID/%s", sid_string_static(id->sid));
00082 if ( ! *sidkey) {
00083 DEBUG(1, ("failed to build sidkey, OOM?\n"));
00084 return NT_STATUS_NO_MEMORY;
00085 }
00086
00087 return NT_STATUS_OK;
00088 }
00089
00090 NTSTATUS idmap_cache_build_idkey(TALLOC_CTX *ctx, char **idkey, const struct id_map *id)
00091 {
00092 *idkey = talloc_asprintf(ctx, "IDMAP/%s/%lu",
00093 (id->xid.type==ID_TYPE_UID)?"UID":"GID",
00094 (unsigned long)id->xid.id);
00095 if ( ! *idkey) {
00096 DEBUG(1, ("failed to build idkey, OOM?\n"));
00097 return NT_STATUS_NO_MEMORY;
00098 }
00099
00100 return NT_STATUS_OK;
00101 }
00102
00103 NTSTATUS idmap_cache_set(struct idmap_cache_ctx *cache, const struct id_map *id)
00104 {
00105 NTSTATUS ret;
00106 time_t timeout = time(NULL) + lp_idmap_cache_time();
00107 TDB_DATA keybuf, databuf;
00108 char *sidkey;
00109 char *idkey;
00110 char *valstr;
00111
00112
00113 if ( (id->xid.type == ID_TYPE_UID) &&
00114 sid_check_is_in_unix_users(id->sid) )
00115 {
00116 return NT_STATUS_OK;
00117 }
00118 if ( (id->xid.type == ID_TYPE_GID) &&
00119 sid_check_is_in_unix_groups(id->sid) )
00120 {
00121 return NT_STATUS_OK;
00122 }
00123
00124
00125 ret = idmap_cache_build_sidkey(cache, &sidkey, id);
00126 if (!NT_STATUS_IS_OK(ret)) return ret;
00127
00128
00129 ret = idmap_cache_build_idkey(sidkey, &idkey, id);
00130 if (!NT_STATUS_IS_OK(ret)) {
00131 goto done;
00132 }
00133
00134
00135
00136
00137 valstr = talloc_asprintf(sidkey, IDMAP_CACHE_DATA_FMT, (int)timeout, idkey);
00138 if (!valstr) {
00139 DEBUG(0, ("Out of memory!\n"));
00140 ret = NT_STATUS_NO_MEMORY;
00141 goto done;
00142 }
00143
00144 keybuf.dptr = sidkey;
00145 keybuf.dsize = strlen(sidkey)+1;
00146 databuf.dptr = valstr;
00147 databuf.dsize = strlen(valstr)+1;
00148 DEBUG(10, ("Adding cache entry with key = %s; value = %s and timeout ="
00149 " %s (%d seconds %s)\n", keybuf.dptr, valstr , ctime(&timeout),
00150 (int)(timeout - time(NULL)),
00151 timeout > time(NULL) ? "ahead" : "in the past"));
00152
00153 if (tdb_store(cache->tdb, keybuf, databuf, TDB_REPLACE) != 0) {
00154 DEBUG(3, ("Failed to store cache entry!\n"));
00155 ret = NT_STATUS_UNSUCCESSFUL;
00156 goto done;
00157 }
00158
00159
00160
00161
00162 valstr = talloc_asprintf(sidkey, IDMAP_CACHE_DATA_FMT, (int)timeout, sidkey);
00163 if (!valstr) {
00164 DEBUG(0, ("Out of memory!\n"));
00165 ret = NT_STATUS_NO_MEMORY;
00166 goto done;
00167 }
00168
00169 keybuf.dptr = idkey;
00170 keybuf.dsize = strlen(idkey)+1;
00171 databuf.dptr = valstr;
00172 databuf.dsize = strlen(valstr)+1;
00173 DEBUG(10, ("Adding cache entry with key = %s; value = %s and timeout ="
00174 " %s (%d seconds %s)\n", keybuf.dptr, valstr, ctime(&timeout),
00175 (int)(timeout - time(NULL)),
00176 timeout > time(NULL) ? "ahead" : "in the past"));
00177
00178 if (tdb_store(cache->tdb, keybuf, databuf, TDB_REPLACE) != 0) {
00179 DEBUG(3, ("Failed to store cache entry!\n"));
00180 ret = NT_STATUS_UNSUCCESSFUL;
00181 goto done;
00182 }
00183
00184 ret = NT_STATUS_OK;
00185
00186 done:
00187 talloc_free(sidkey);
00188 return ret;
00189 }
00190
00191 NTSTATUS idmap_cache_del(struct idmap_cache_ctx *cache, const struct id_map *id)
00192 {
00193 NTSTATUS ret;
00194 TDB_DATA keybuf;
00195 char *sidkey = NULL;
00196 char *idkey = NULL;
00197
00198 ret = idmap_cache_build_sidkey(cache, &sidkey, id);
00199 if (!NT_STATUS_IS_OK(ret)) return ret;
00200
00201 ret = idmap_cache_build_idkey(cache, &idkey, id);
00202 if (!NT_STATUS_IS_OK(ret)) {
00203 goto done;
00204 }
00205
00206
00207
00208 keybuf.dptr = sidkey;
00209 keybuf.dsize = strlen(sidkey)+1;
00210 DEBUG(10, ("Deleting cache entry (key = %s)\n", keybuf.dptr));
00211
00212 if (tdb_delete(cache->tdb, keybuf) != 0) {
00213 DEBUG(3, ("Failed to delete cache entry!\n"));
00214 }
00215
00216
00217
00218 keybuf.dptr = idkey;
00219 keybuf.dsize = strlen(idkey)+1;
00220 DEBUG(10, ("Deleting cache entry (key = %s)\n", keybuf.dptr));
00221
00222 if (tdb_delete(cache->tdb, keybuf) != 0) {
00223 DEBUG(3, ("Failed to delete cache entry!\n"));
00224 }
00225
00226 done:
00227 talloc_free(sidkey);
00228 talloc_free(idkey);
00229 return ret;
00230 }
00231
00232 NTSTATUS idmap_cache_set_negative_sid(struct idmap_cache_ctx *cache, const struct id_map *id)
00233 {
00234 NTSTATUS ret;
00235 time_t timeout = time(NULL) + lp_idmap_negative_cache_time();
00236 TDB_DATA keybuf, databuf;
00237 char *sidkey;
00238 char *valstr;
00239
00240 ret = idmap_cache_build_sidkey(cache, &sidkey, id);
00241 if (!NT_STATUS_IS_OK(ret)) return ret;
00242
00243
00244 valstr = talloc_asprintf(sidkey, IDMAP_CACHE_DATA_FMT, (int)timeout, "IDMAP/NEGATIVE");
00245 if (!valstr) {
00246 DEBUG(0, ("Out of memory!\n"));
00247 ret = NT_STATUS_NO_MEMORY;
00248 goto done;
00249 }
00250
00251 keybuf.dptr = sidkey;
00252 keybuf.dsize = strlen(sidkey)+1;
00253 databuf.dptr = valstr;
00254 databuf.dsize = strlen(valstr)+1;
00255 DEBUG(10, ("Adding cache entry with key = %s; value = %s and timeout ="
00256 " %s (%d seconds %s)\n", keybuf.dptr, valstr, ctime(&timeout),
00257 (int)(timeout - time(NULL)),
00258 timeout > time(NULL) ? "ahead" : "in the past"));
00259
00260 if (tdb_store(cache->tdb, keybuf, databuf, TDB_REPLACE) != 0) {
00261 DEBUG(3, ("Failed to store cache entry!\n"));
00262 ret = NT_STATUS_UNSUCCESSFUL;
00263 goto done;
00264 }
00265
00266 done:
00267 talloc_free(sidkey);
00268 return ret;
00269 }
00270
00271 NTSTATUS idmap_cache_set_negative_id(struct idmap_cache_ctx *cache, const struct id_map *id)
00272 {
00273 NTSTATUS ret;
00274 time_t timeout = time(NULL) + lp_idmap_negative_cache_time();
00275 TDB_DATA keybuf, databuf;
00276 char *idkey;
00277 char *valstr;
00278
00279 ret = idmap_cache_build_idkey(cache, &idkey, id);
00280 if (!NT_STATUS_IS_OK(ret)) return ret;
00281
00282
00283 valstr = talloc_asprintf(idkey, IDMAP_CACHE_DATA_FMT, (int)timeout, "IDMAP/NEGATIVE");
00284 if (!valstr) {
00285 DEBUG(0, ("Out of memory!\n"));
00286 ret = NT_STATUS_NO_MEMORY;
00287 goto done;
00288 }
00289
00290 keybuf.dptr = idkey;
00291 keybuf.dsize = strlen(idkey)+1;
00292 databuf.dptr = valstr;
00293 databuf.dsize = strlen(valstr)+1;
00294 DEBUG(10, ("Adding cache entry with key = %s; value = %s and timeout ="
00295 " %s (%d seconds %s)\n", keybuf.dptr, valstr, ctime(&timeout),
00296 (int)(timeout - time(NULL)),
00297 timeout > time(NULL) ? "ahead" : "in the past"));
00298
00299 if (tdb_store(cache->tdb, keybuf, databuf, TDB_REPLACE) != 0) {
00300 DEBUG(3, ("Failed to store cache entry!\n"));
00301 ret = NT_STATUS_UNSUCCESSFUL;
00302 goto done;
00303 }
00304
00305 done:
00306 talloc_free(idkey);
00307 return ret;
00308 }
00309
00310 NTSTATUS idmap_cache_fill_map(struct id_map *id, const char *value)
00311 {
00312 char *rem;
00313
00314
00315 if ( ! strncmp("IDMAP/SID/", value, 10)) {
00316
00317 if ( ! string_to_sid(id->sid, &value[10])) {
00318 goto failed;
00319 }
00320
00321 id->status = ID_MAPPED;
00322
00323 return NT_STATUS_OK;
00324 }
00325
00326
00327 if ( ! strncmp("IDMAP/UID/", value, 10)) {
00328
00329
00330 id->xid.type = ID_TYPE_UID;
00331
00332 } else if ( ! strncmp("IDMAP/GID/", value, 10)) {
00333
00334
00335 id->xid.type = ID_TYPE_GID;
00336
00337 } else {
00338
00339
00340 goto failed;
00341 }
00342
00343 id->xid.id = strtol(&value[10], &rem, 0);
00344 if (*rem != '\0') {
00345 goto failed;
00346 }
00347
00348 id->status = ID_MAPPED;
00349
00350 return NT_STATUS_OK;
00351
00352 failed:
00353 DEBUG(1, ("invalid value: %s\n", value));
00354 id->status = ID_UNKNOWN;
00355 return NT_STATUS_INTERNAL_DB_CORRUPTION;
00356 }
00357
00358 BOOL idmap_cache_is_negative(const char *val)
00359 {
00360 if ( ! strcmp("IDMAP/NEGATIVE", val)) {
00361 return True;
00362 }
00363 return False;
00364 }
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381 NTSTATUS idmap_cache_map_sid(struct idmap_cache_ctx *cache, struct id_map *id)
00382 {
00383 NTSTATUS ret;
00384 TDB_DATA keybuf, databuf;
00385 time_t t, now;
00386 char *sidkey;
00387 char *endptr;
00388
00389
00390 id->status = ID_UNKNOWN;
00391
00392 ret = idmap_cache_build_sidkey(cache, &sidkey, id);
00393 if (!NT_STATUS_IS_OK(ret)) return ret;
00394
00395 keybuf.dptr = sidkey;
00396 keybuf.dsize = strlen(sidkey)+1;
00397
00398 databuf = tdb_fetch(cache->tdb, keybuf);
00399
00400 if (databuf.dptr == NULL) {
00401 DEBUG(10, ("Cache entry with key = %s couldn't be found\n", sidkey));
00402 ret = NT_STATUS_NONE_MAPPED;
00403 goto done;
00404 }
00405
00406 t = strtol(databuf.dptr, &endptr, 10);
00407
00408 if ((endptr == NULL) || (*endptr != '/')) {
00409 DEBUG(2, ("Invalid gencache data format: %s\n", databuf.dptr));
00410
00411 tdb_delete(cache->tdb, keybuf);
00412 ret = NT_STATUS_NONE_MAPPED;
00413 goto done;
00414 }
00415
00416 now = time(NULL);
00417
00418
00419 if (strcmp("IDMAP/NEGATIVE", endptr+1) != 0) {
00420
00421 DEBUG(10, ("Returning %s cache entry: key = %s, value = %s, "
00422 "timeout = %s", t > now ? "valid" :
00423 "expired", sidkey, endptr+1, ctime(&t)));
00424
00425
00426 ret = idmap_cache_fill_map(id, endptr+1);
00427 if ( ! NT_STATUS_IS_OK(ret)) {
00428
00429 tdb_delete(cache->tdb, keybuf);
00430 ret = NT_STATUS_NONE_MAPPED;
00431 goto done;
00432 }
00433
00434
00435
00436 if (t <= now) {
00437
00438
00439 id->status = ID_EXPIRED;
00440
00441
00442
00443 ret = NT_STATUS_SYNCHRONIZATION_REQUIRED;
00444 }
00445 } else {
00446 if (t <= now) {
00447
00448
00449 tdb_delete(cache->tdb, keybuf);
00450 ret = NT_STATUS_NONE_MAPPED;
00451 } else {
00452
00453 id->status = ID_UNMAPPED;
00454 ret = NT_STATUS_OK;
00455 }
00456 }
00457
00458 done:
00459 SAFE_FREE(databuf.dptr);
00460 talloc_free(sidkey);
00461 return ret;
00462 }
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479 NTSTATUS idmap_cache_map_id(struct idmap_cache_ctx *cache, struct id_map *id)
00480 {
00481 NTSTATUS ret;
00482 TDB_DATA keybuf, databuf;
00483 time_t t, now;
00484 char *idkey;
00485 char *endptr;
00486
00487
00488 id->status = ID_UNKNOWN;
00489
00490 ret = idmap_cache_build_idkey(cache, &idkey, id);
00491 if (!NT_STATUS_IS_OK(ret)) return ret;
00492
00493 keybuf.dptr = idkey;
00494 keybuf.dsize = strlen(idkey)+1;
00495
00496 databuf = tdb_fetch(cache->tdb, keybuf);
00497
00498 if (databuf.dptr == NULL) {
00499 DEBUG(10, ("Cache entry with key = %s couldn't be found\n", idkey));
00500 ret = NT_STATUS_NONE_MAPPED;
00501 goto done;
00502 }
00503
00504 t = strtol(databuf.dptr, &endptr, 10);
00505
00506 if ((endptr == NULL) || (*endptr != '/')) {
00507 DEBUG(2, ("Invalid gencache data format: %s\n", databuf.dptr));
00508
00509 tdb_delete(cache->tdb, keybuf);
00510 ret = NT_STATUS_NONE_MAPPED;
00511 goto done;
00512 }
00513
00514 now = time(NULL);
00515
00516
00517 if (strcmp("IDMAP/NEGATIVE", endptr+1) != 0) {
00518
00519 DEBUG(10, ("Returning %s cache entry: key = %s, value = %s, "
00520 "timeout = %s", t > now ? "valid" :
00521 "expired", idkey, endptr+1, ctime(&t)));
00522
00523
00524 ret = idmap_cache_fill_map(id, endptr+1);
00525 if ( ! NT_STATUS_IS_OK(ret)) {
00526
00527 tdb_delete(cache->tdb, keybuf);
00528 ret = NT_STATUS_NONE_MAPPED;
00529 goto done;
00530 }
00531
00532
00533
00534 if (t <= now) {
00535
00536
00537 id->status = ID_EXPIRED;
00538
00539
00540
00541 ret = NT_STATUS_SYNCHRONIZATION_REQUIRED;
00542 }
00543 } else {
00544 if (t <= now) {
00545
00546
00547 tdb_delete(cache->tdb, keybuf);
00548 ret = NT_STATUS_NONE_MAPPED;
00549 } else {
00550
00551 id->status = ID_UNMAPPED;
00552 ret = NT_STATUS_OK;
00553 }
00554 }
00555 done:
00556 SAFE_FREE(databuf.dptr);
00557 talloc_free(idkey);
00558 return ret;
00559 }
00560