00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "includes.h"
00027 #include "winbindd.h"
00028
00029 #undef DBGC_CLASS
00030 #define DBGC_CLASS DBGC_WINBIND
00031
00032 #define WINBINDD_CACHE_VERSION 1
00033 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
00034
00035 extern struct winbindd_methods reconnect_methods;
00036 extern BOOL opt_nocache;
00037 #ifdef HAVE_ADS
00038 extern struct winbindd_methods ads_methods;
00039 #endif
00040 extern struct winbindd_methods builtin_passdb_methods;
00041
00042
00043
00044
00045
00046
00047
00048 static const char *non_centry_keys[] = {
00049 "SEQNUM/",
00050 "DR/",
00051 "DE/",
00052 "WINBINDD_OFFLINE",
00053 WINBINDD_CACHE_VERSION_KEYSTR,
00054 NULL
00055 };
00056
00057
00058
00059
00060
00061 static BOOL is_non_centry_key(TDB_DATA kbuf)
00062 {
00063 int i;
00064
00065 if (kbuf.dptr == NULL || kbuf.dsize == 0) {
00066 return False;
00067 }
00068 for (i = 0; non_centry_keys[i] != NULL; i++) {
00069 size_t namelen = strlen(non_centry_keys[i]);
00070 if (kbuf.dsize < namelen) {
00071 continue;
00072 }
00073 if (strncmp(non_centry_keys[i], (const char *)kbuf.dptr, namelen) == 0) {
00074 return True;
00075 }
00076 }
00077 return False;
00078 }
00079
00080
00081
00082
00083
00084 static BOOL global_winbindd_offline_state;
00085
00086 struct winbind_cache {
00087 TDB_CONTEXT *tdb;
00088 };
00089
00090 struct cache_entry {
00091 NTSTATUS status;
00092 uint32 sequence_number;
00093 uint8 *data;
00094 uint32 len, ofs;
00095 };
00096
00097 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
00098
00099 static struct winbind_cache *wcache;
00100
00101 void winbindd_check_cache_size(time_t t)
00102 {
00103 static time_t last_check_time;
00104 struct stat st;
00105
00106 if (last_check_time == (time_t)0)
00107 last_check_time = t;
00108
00109 if (t - last_check_time < 60 && t - last_check_time > 0)
00110 return;
00111
00112 if (wcache == NULL || wcache->tdb == NULL) {
00113 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
00114 return;
00115 }
00116
00117 if (fstat(tdb_fd(wcache->tdb), &st) == -1) {
00118 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno) ));
00119 return;
00120 }
00121
00122 if (st.st_size > WINBINDD_MAX_CACHE_SIZE) {
00123 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
00124 (unsigned long)st.st_size,
00125 (unsigned long)WINBINDD_MAX_CACHE_SIZE));
00126 wcache_flush_cache();
00127 }
00128 }
00129
00130
00131 static struct winbind_cache *get_cache(struct winbindd_domain *domain)
00132 {
00133 struct winbind_cache *ret = wcache;
00134 #ifdef HAVE_ADS
00135 struct winbindd_domain *our_domain = domain;
00136 #endif
00137
00138
00139
00140 if (domain->internal) {
00141 domain->backend = &builtin_passdb_methods;
00142 domain->initialized = True;
00143 }
00144 if ( !domain->initialized ) {
00145 init_dc_connection( domain );
00146 }
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166 if (!domain->backend) {
00167 #ifdef HAVE_ADS
00168
00169
00170
00171 if ( !domain->primary )
00172 our_domain = find_our_domain();
00173
00174 if ( (our_domain->active_directory || IS_DC) && domain->active_directory ) {
00175 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain->name));
00176 domain->backend = &ads_methods;
00177 } else {
00178 #endif
00179 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain->name));
00180 domain->backend = &reconnect_methods;
00181 #ifdef HAVE_ADS
00182 }
00183 #endif
00184 }
00185
00186 if (ret)
00187 return ret;
00188
00189 ret = SMB_XMALLOC_P(struct winbind_cache);
00190 ZERO_STRUCTP(ret);
00191
00192 wcache = ret;
00193 wcache_flush_cache();
00194
00195 return ret;
00196 }
00197
00198
00199
00200
00201 static void centry_free(struct cache_entry *centry)
00202 {
00203 if (!centry)
00204 return;
00205 SAFE_FREE(centry->data);
00206 free(centry);
00207 }
00208
00209
00210
00211
00212 static uint32 centry_uint32(struct cache_entry *centry)
00213 {
00214 uint32 ret;
00215 if (centry->len - centry->ofs < 4) {
00216 DEBUG(0,("centry corruption? needed 4 bytes, have %d\n",
00217 centry->len - centry->ofs));
00218 smb_panic("centry_uint32");
00219 }
00220 ret = IVAL(centry->data, centry->ofs);
00221 centry->ofs += 4;
00222 return ret;
00223 }
00224
00225
00226
00227
00228 static uint16 centry_uint16(struct cache_entry *centry)
00229 {
00230 uint16 ret;
00231 if (centry->len - centry->ofs < 2) {
00232 DEBUG(0,("centry corruption? needed 2 bytes, have %d\n",
00233 centry->len - centry->ofs));
00234 smb_panic("centry_uint16");
00235 }
00236 ret = CVAL(centry->data, centry->ofs);
00237 centry->ofs += 2;
00238 return ret;
00239 }
00240
00241
00242
00243
00244 static uint8 centry_uint8(struct cache_entry *centry)
00245 {
00246 uint8 ret;
00247 if (centry->len - centry->ofs < 1) {
00248 DEBUG(0,("centry corruption? needed 1 bytes, have %d\n",
00249 centry->len - centry->ofs));
00250 smb_panic("centry_uint32");
00251 }
00252 ret = CVAL(centry->data, centry->ofs);
00253 centry->ofs += 1;
00254 return ret;
00255 }
00256
00257
00258
00259
00260 static NTTIME centry_nttime(struct cache_entry *centry)
00261 {
00262 NTTIME ret;
00263 if (centry->len - centry->ofs < 8) {
00264 DEBUG(0,("centry corruption? needed 8 bytes, have %d\n",
00265 centry->len - centry->ofs));
00266 smb_panic("centry_nttime");
00267 }
00268 ret = IVAL(centry->data, centry->ofs);
00269 centry->ofs += 4;
00270 ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
00271 centry->ofs += 4;
00272 return ret;
00273 }
00274
00275
00276
00277
00278 static time_t centry_time(struct cache_entry *centry)
00279 {
00280 return (time_t)centry_nttime(centry);
00281 }
00282
00283
00284
00285
00286 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
00287 {
00288 uint32 len;
00289 char *ret;
00290
00291 len = centry_uint8(centry);
00292
00293 if (len == 0xFF) {
00294
00295 return NULL;
00296 }
00297
00298 if (centry->len - centry->ofs < len) {
00299 DEBUG(0,("centry corruption? needed %d bytes, have %d\n",
00300 len, centry->len - centry->ofs));
00301 smb_panic("centry_string");
00302 }
00303
00304 ret = TALLOC_ARRAY(mem_ctx, char, len+1);
00305 if (!ret) {
00306 smb_panic("centry_string out of memory\n");
00307 }
00308 memcpy(ret,centry->data + centry->ofs, len);
00309 ret[len] = 0;
00310 centry->ofs += len;
00311 return ret;
00312 }
00313
00314
00315
00316
00317 static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
00318 {
00319 uint32 len;
00320 char *ret;
00321
00322 len = centry_uint8(centry);
00323
00324 if (len != 16) {
00325 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
00326 len ));
00327 return NULL;
00328 }
00329
00330 if (centry->len - centry->ofs < 16) {
00331 DEBUG(0,("centry corruption? needed 16 bytes, have %d\n",
00332 centry->len - centry->ofs));
00333 return NULL;
00334 }
00335
00336 ret = TALLOC_ARRAY(mem_ctx, char, 16);
00337 if (!ret) {
00338 smb_panic("centry_hash out of memory\n");
00339 }
00340 memcpy(ret,centry->data + centry->ofs, 16);
00341 centry->ofs += 16;
00342 return ret;
00343 }
00344
00345
00346
00347
00348 static BOOL centry_sid(struct cache_entry *centry, TALLOC_CTX *mem_ctx, DOM_SID *sid)
00349 {
00350 char *sid_string;
00351 sid_string = centry_string(centry, mem_ctx);
00352 if ((sid_string == NULL) || (!string_to_sid(sid, sid_string))) {
00353 return False;
00354 }
00355 return True;
00356 }
00357
00358
00359 static BOOL wcache_server_down(struct winbindd_domain *domain)
00360 {
00361 BOOL ret;
00362
00363 if (!wcache->tdb)
00364 return False;
00365
00366 ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
00367
00368 if (ret)
00369 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
00370 domain->name ));
00371 return ret;
00372 }
00373
00374 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
00375 {
00376 TDB_DATA data;
00377 fstring key;
00378 uint32 time_diff;
00379
00380 if (!wcache->tdb) {
00381 DEBUG(10,("fetch_cache_seqnum: tdb == NULL\n"));
00382 return NT_STATUS_UNSUCCESSFUL;
00383 }
00384
00385 fstr_sprintf( key, "SEQNUM/%s", domain->name );
00386
00387 data = tdb_fetch_bystring( wcache->tdb, key );
00388 if ( !data.dptr || data.dsize!=8 ) {
00389 DEBUG(10,("fetch_cache_seqnum: invalid data size key [%s]\n", key ));
00390 return NT_STATUS_UNSUCCESSFUL;
00391 }
00392
00393 domain->sequence_number = IVAL(data.dptr, 0);
00394 domain->last_seq_check = IVAL(data.dptr, 4);
00395
00396 SAFE_FREE(data.dptr);
00397
00398
00399
00400 time_diff = now - domain->last_seq_check;
00401 if ( time_diff > lp_winbind_cache_time() ) {
00402 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
00403 domain->name, domain->sequence_number,
00404 (uint32)domain->last_seq_check));
00405 return NT_STATUS_UNSUCCESSFUL;
00406 }
00407
00408 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
00409 domain->name, domain->sequence_number,
00410 (uint32)domain->last_seq_check));
00411
00412 return NT_STATUS_OK;
00413 }
00414
00415 static NTSTATUS store_cache_seqnum( struct winbindd_domain *domain )
00416 {
00417 TDB_DATA data;
00418 fstring key_str;
00419 char buf[8];
00420
00421 if (!wcache->tdb) {
00422 DEBUG(10,("store_cache_seqnum: tdb == NULL\n"));
00423 return NT_STATUS_UNSUCCESSFUL;
00424 }
00425
00426 fstr_sprintf( key_str, "SEQNUM/%s", domain->name );
00427
00428 SIVAL(buf, 0, domain->sequence_number);
00429 SIVAL(buf, 4, domain->last_seq_check);
00430 data.dptr = buf;
00431 data.dsize = 8;
00432
00433 if ( tdb_store_bystring( wcache->tdb, key_str, data, TDB_REPLACE) == -1 ) {
00434 DEBUG(10,("store_cache_seqnum: tdb_store fail key [%s]\n", key_str ));
00435 return NT_STATUS_UNSUCCESSFUL;
00436 }
00437
00438 DEBUG(10,("store_cache_seqnum: success [%s][%u @ %u]\n",
00439 domain->name, domain->sequence_number,
00440 (uint32)domain->last_seq_check));
00441
00442 return NT_STATUS_OK;
00443 }
00444
00445
00446
00447
00448
00449
00450 static void refresh_sequence_number(struct winbindd_domain *domain, BOOL force)
00451 {
00452 NTSTATUS status;
00453 unsigned time_diff;
00454 time_t t = time(NULL);
00455 unsigned cache_time = lp_winbind_cache_time();
00456
00457 get_cache( domain );
00458
00459 #if 0
00460
00461 if (domain->sequence_number == DOM_SEQUENCE_NONE) {
00462 cache_time *= 8;
00463 }
00464 #endif
00465
00466 time_diff = t - domain->last_seq_check;
00467
00468
00469 if (!force && (time_diff < cache_time)) {
00470 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
00471 goto done;
00472 }
00473
00474
00475
00476
00477 status = fetch_cache_seqnum( domain, t );
00478 if ( NT_STATUS_IS_OK(status) )
00479 goto done;
00480
00481
00482
00483
00484 status = domain->backend->sequence_number(domain, &domain->sequence_number);
00485
00486
00487
00488
00489 get_cache( domain );
00490
00491 if (!NT_STATUS_IS_OK(status)) {
00492 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status)));
00493 domain->sequence_number = DOM_SEQUENCE_NONE;
00494 }
00495
00496 domain->last_status = status;
00497 domain->last_seq_check = time(NULL);
00498
00499
00500 store_cache_seqnum( domain );
00501
00502 done:
00503 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
00504 domain->name, domain->sequence_number));
00505
00506 return;
00507 }
00508
00509
00510
00511
00512 static BOOL centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
00513 {
00514
00515 if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
00516 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
00517 keystr, domain->name ));
00518 return False;
00519 }
00520
00521
00522
00523
00524 if (!domain->online) {
00525 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
00526 keystr, domain->name ));
00527 return False;
00528 }
00529
00530
00531
00532 if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&
00533 (centry->sequence_number == DOM_SEQUENCE_NONE)) {
00534 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
00535 keystr, domain->name ));
00536 return True;
00537 }
00538
00539
00540
00541 if (wcache_server_down(domain) ||
00542 centry->sequence_number == domain->sequence_number) {
00543 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
00544 keystr, domain->name ));
00545 return False;
00546 }
00547
00548 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
00549 keystr, domain->name ));
00550
00551
00552 return True;
00553 }
00554
00555 static struct cache_entry *wcache_fetch_raw(char *kstr)
00556 {
00557 TDB_DATA data;
00558 struct cache_entry *centry;
00559 TDB_DATA key;
00560
00561 key.dptr = kstr;
00562 key.dsize = strlen(kstr);
00563 data = tdb_fetch(wcache->tdb, key);
00564 if (!data.dptr) {
00565
00566 return NULL;
00567 }
00568
00569 centry = SMB_XMALLOC_P(struct cache_entry);
00570 centry->data = (unsigned char *)data.dptr;
00571 centry->len = data.dsize;
00572 centry->ofs = 0;
00573
00574 if (centry->len < 8) {
00575
00576 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr));
00577 centry_free(centry);
00578 return NULL;
00579 }
00580
00581 centry->status = NT_STATUS(centry_uint32(centry));
00582 centry->sequence_number = centry_uint32(centry);
00583
00584 return centry;
00585 }
00586
00587
00588
00589
00590
00591 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
00592 struct winbindd_domain *domain,
00593 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
00594 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
00595 struct winbindd_domain *domain,
00596 const char *format, ...)
00597 {
00598 va_list ap;
00599 char *kstr;
00600 struct cache_entry *centry;
00601
00602 if (opt_nocache) {
00603 return NULL;
00604 }
00605
00606 refresh_sequence_number(domain, False);
00607
00608 va_start(ap, format);
00609 smb_xvasprintf(&kstr, format, ap);
00610 va_end(ap);
00611
00612 centry = wcache_fetch_raw(kstr);
00613 if (centry == NULL) {
00614 free(kstr);
00615 return NULL;
00616 }
00617
00618 if (centry_expired(domain, kstr, centry)) {
00619
00620 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
00621 kstr, domain->name ));
00622
00623 centry_free(centry);
00624 free(kstr);
00625 return NULL;
00626 }
00627
00628 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
00629 kstr, domain->name ));
00630
00631 free(kstr);
00632 return centry;
00633 }
00634
00635 static void wcache_delete(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
00636 static void wcache_delete(const char *format, ...)
00637 {
00638 va_list ap;
00639 char *kstr;
00640 TDB_DATA key;
00641
00642 va_start(ap, format);
00643 smb_xvasprintf(&kstr, format, ap);
00644 va_end(ap);
00645
00646 key.dptr = kstr;
00647 key.dsize = strlen(kstr);
00648
00649 tdb_delete(wcache->tdb, key);
00650 free(kstr);
00651 }
00652
00653
00654
00655
00656 static void centry_expand(struct cache_entry *centry, uint32 len)
00657 {
00658 if (centry->len - centry->ofs >= len)
00659 return;
00660 centry->len *= 2;
00661 centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
00662 centry->len);
00663 if (!centry->data) {
00664 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
00665 smb_panic("out of memory in centry_expand");
00666 }
00667 }
00668
00669
00670
00671
00672 static void centry_put_uint32(struct cache_entry *centry, uint32 v)
00673 {
00674 centry_expand(centry, 4);
00675 SIVAL(centry->data, centry->ofs, v);
00676 centry->ofs += 4;
00677 }
00678
00679
00680
00681
00682 static void centry_put_uint16(struct cache_entry *centry, uint16 v)
00683 {
00684 centry_expand(centry, 2);
00685 SIVAL(centry->data, centry->ofs, v);
00686 centry->ofs += 2;
00687 }
00688
00689
00690
00691
00692 static void centry_put_uint8(struct cache_entry *centry, uint8 v)
00693 {
00694 centry_expand(centry, 1);
00695 SCVAL(centry->data, centry->ofs, v);
00696 centry->ofs += 1;
00697 }
00698
00699
00700
00701
00702 static void centry_put_string(struct cache_entry *centry, const char *s)
00703 {
00704 int len;
00705
00706 if (!s) {
00707
00708 centry_put_uint8(centry, 0xFF);
00709 return;
00710 }
00711
00712 len = strlen(s);
00713
00714 if (len > 254) {
00715 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
00716 len = 254;
00717 }
00718 centry_put_uint8(centry, len);
00719 centry_expand(centry, len);
00720 memcpy(centry->data + centry->ofs, s, len);
00721 centry->ofs += len;
00722 }
00723
00724
00725
00726
00727 static void centry_put_hash16(struct cache_entry *centry, const uint8 val[16])
00728 {
00729 centry_put_uint8(centry, 16);
00730 centry_expand(centry, 16);
00731 memcpy(centry->data + centry->ofs, val, 16);
00732 centry->ofs += 16;
00733 }
00734
00735 static void centry_put_sid(struct cache_entry *centry, const DOM_SID *sid)
00736 {
00737 fstring sid_string;
00738 centry_put_string(centry, sid_to_string(sid_string, sid));
00739 }
00740
00741
00742
00743
00744 static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
00745 {
00746 centry_expand(centry, 8);
00747 SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
00748 centry->ofs += 4;
00749 SIVAL(centry->data, centry->ofs, nt >> 32);
00750 centry->ofs += 4;
00751 }
00752
00753
00754
00755
00756
00757 static void centry_put_time(struct cache_entry *centry, time_t t)
00758 {
00759 NTTIME nt = (NTTIME)t;
00760 centry_put_nttime(centry, nt);
00761 }
00762
00763
00764
00765
00766 struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status)
00767 {
00768 struct cache_entry *centry;
00769
00770 if (!wcache->tdb)
00771 return NULL;
00772
00773 centry = SMB_XMALLOC_P(struct cache_entry);
00774
00775 centry->len = 8192;
00776 centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);
00777 centry->ofs = 0;
00778 centry->sequence_number = domain->sequence_number;
00779 centry_put_uint32(centry, NT_STATUS_V(status));
00780 centry_put_uint32(centry, centry->sequence_number);
00781 return centry;
00782 }
00783
00784
00785
00786
00787 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
00788 static void centry_end(struct cache_entry *centry, const char *format, ...)
00789 {
00790 va_list ap;
00791 char *kstr;
00792 TDB_DATA key, data;
00793
00794 va_start(ap, format);
00795 smb_xvasprintf(&kstr, format, ap);
00796 va_end(ap);
00797
00798 key.dptr = kstr;
00799 key.dsize = strlen(kstr);
00800 data.dptr = (char *)centry->data;
00801 data.dsize = centry->ofs;
00802
00803 tdb_store(wcache->tdb, key, data, TDB_REPLACE);
00804 free(kstr);
00805 }
00806
00807 static void wcache_save_name_to_sid(struct winbindd_domain *domain,
00808 NTSTATUS status, const char *domain_name,
00809 const char *name, const DOM_SID *sid,
00810 enum lsa_SidType type)
00811 {
00812 struct cache_entry *centry;
00813 fstring uname;
00814
00815 centry = centry_start(domain, status);
00816 if (!centry)
00817 return;
00818 centry_put_uint32(centry, type);
00819 centry_put_sid(centry, sid);
00820 fstrcpy(uname, name);
00821 strupper_m(uname);
00822 centry_end(centry, "NS/%s/%s", domain_name, uname);
00823 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s\n", domain_name, uname,
00824 sid_string_static(sid)));
00825 centry_free(centry);
00826 }
00827
00828 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
00829 const DOM_SID *sid, const char *domain_name, const char *name, enum lsa_SidType type)
00830 {
00831 struct cache_entry *centry;
00832 fstring sid_string;
00833
00834 if (is_null_sid(sid)) {
00835 return;
00836 }
00837
00838 centry = centry_start(domain, status);
00839 if (!centry)
00840 return;
00841 if (NT_STATUS_IS_OK(status)) {
00842 centry_put_uint32(centry, type);
00843 centry_put_string(centry, domain_name);
00844 centry_put_string(centry, name);
00845 }
00846 centry_end(centry, "SN/%s", sid_to_string(sid_string, sid));
00847 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\n", sid_string, name));
00848 centry_free(centry);
00849 }
00850
00851
00852 static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WINBIND_USERINFO *info)
00853 {
00854 struct cache_entry *centry;
00855 fstring sid_string;
00856
00857 if (is_null_sid(&info->user_sid)) {
00858 return;
00859 }
00860
00861 centry = centry_start(domain, status);
00862 if (!centry)
00863 return;
00864 centry_put_string(centry, info->acct_name);
00865 centry_put_string(centry, info->full_name);
00866 centry_put_string(centry, info->homedir);
00867 centry_put_string(centry, info->shell);
00868 centry_put_uint32(centry, info->primary_gid);
00869 centry_put_sid(centry, &info->user_sid);
00870 centry_put_sid(centry, &info->group_sid);
00871 centry_end(centry, "U/%s", sid_to_string(sid_string, &info->user_sid));
00872 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
00873 centry_free(centry);
00874 }
00875
00876 static void wcache_save_lockout_policy(struct winbindd_domain *domain, NTSTATUS status, SAM_UNK_INFO_12 *lockout_policy)
00877 {
00878 struct cache_entry *centry;
00879
00880 centry = centry_start(domain, status);
00881 if (!centry)
00882 return;
00883
00884 centry_put_nttime(centry, lockout_policy->duration);
00885 centry_put_nttime(centry, lockout_policy->reset_count);
00886 centry_put_uint16(centry, lockout_policy->bad_attempt_lockout);
00887
00888 centry_end(centry, "LOC_POL/%s", domain->name);
00889
00890 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
00891
00892 centry_free(centry);
00893 }
00894
00895 static void wcache_save_password_policy(struct winbindd_domain *domain, NTSTATUS status, SAM_UNK_INFO_1 *policy)
00896 {
00897 struct cache_entry *centry;
00898
00899 centry = centry_start(domain, status);
00900 if (!centry)
00901 return;
00902
00903 centry_put_uint16(centry, policy->min_length_password);
00904 centry_put_uint16(centry, policy->password_history);
00905 centry_put_uint32(centry, policy->password_properties);
00906 centry_put_nttime(centry, policy->expire);
00907 centry_put_nttime(centry, policy->min_passwordage);
00908
00909 centry_end(centry, "PWD_POL/%s", domain->name);
00910
00911 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
00912
00913 centry_free(centry);
00914 }
00915
00916 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const DOM_SID *sid)
00917 {
00918 struct winbind_cache *cache = get_cache(domain);
00919 TDB_DATA data;
00920 fstring key_str;
00921 uint32 rid;
00922
00923 if (!cache->tdb) {
00924 return NT_STATUS_INTERNAL_DB_ERROR;
00925 }
00926
00927 if (is_null_sid(sid)) {
00928 return NT_STATUS_INVALID_SID;
00929 }
00930
00931 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
00932 return NT_STATUS_INVALID_SID;
00933 }
00934
00935 fstr_sprintf(key_str, "CRED/%s", sid_string_static(sid));
00936
00937 data = tdb_fetch(cache->tdb, make_tdb_data(key_str, strlen(key_str)));
00938 if (!data.dptr) {
00939 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
00940 }
00941
00942 SAFE_FREE(data.dptr);
00943 return NT_STATUS_OK;
00944 }
00945
00946
00947
00948
00949 NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
00950 TALLOC_CTX *mem_ctx,
00951 const DOM_SID *sid,
00952 const uint8 **cached_nt_pass,
00953 const uint8 **cached_salt)
00954 {
00955 struct winbind_cache *cache = get_cache(domain);
00956 struct cache_entry *centry = NULL;
00957 NTSTATUS status;
00958 time_t t;
00959 uint32 rid;
00960
00961 if (!cache->tdb) {
00962 return NT_STATUS_INTERNAL_DB_ERROR;
00963 }
00964
00965 if (is_null_sid(sid)) {
00966 return NT_STATUS_INVALID_SID;
00967 }
00968
00969 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
00970 return NT_STATUS_INVALID_SID;
00971 }
00972
00973
00974
00975
00976 centry = wcache_fetch(cache, domain, "CRED/%s", sid_string_static(sid));
00977 if (!centry) {
00978 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
00979 sid_string_static(sid)));
00980 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
00981 }
00982
00983 t = centry_time(centry);
00984
00985
00986
00987
00988
00989
00990 *cached_nt_pass = (const uint8 *)centry_hash16(centry, mem_ctx);
00991 if (*cached_nt_pass == NULL) {
00992 const char *sidstr = sid_string_static(sid);
00993
00994
00995
00996 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
00997 sidstr));
00998 wcache_delete("CRED/%s", sidstr);
00999 centry_free(centry);
01000 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
01001 }
01002
01003
01004 if (centry->len - centry->ofs == 17) {
01005 *cached_salt = (const uint8 *)centry_hash16(centry, mem_ctx);
01006 } else {
01007 *cached_salt = NULL;
01008 }
01009
01010 #if DEBUG_PASSWORD
01011 dump_data(100, (const char *)*cached_nt_pass, NT_HASH_LEN);
01012 if (*cached_salt) {
01013 dump_data(100, (const char *)*cached_salt, NT_HASH_LEN);
01014 }
01015 #endif
01016 status = centry->status;
01017
01018 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
01019 sid_string_static(sid), nt_errstr(status) ));
01020
01021 centry_free(centry);
01022 return status;
01023 }
01024
01025
01026
01027 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
01028 TALLOC_CTX *mem_ctx,
01029 const DOM_SID *sid,
01030 const uint8 nt_pass[NT_HASH_LEN])
01031 {
01032 struct cache_entry *centry;
01033 fstring sid_string;
01034 uint32 rid;
01035 uint8 cred_salt[NT_HASH_LEN];
01036 uint8 salted_hash[NT_HASH_LEN];
01037
01038 if (is_null_sid(sid)) {
01039 return NT_STATUS_INVALID_SID;
01040 }
01041
01042 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
01043 return NT_STATUS_INVALID_SID;
01044 }
01045
01046 centry = centry_start(domain, NT_STATUS_OK);
01047 if (!centry) {
01048 return NT_STATUS_INTERNAL_DB_ERROR;
01049 }
01050
01051 #if DEBUG_PASSWORD
01052 dump_data(100, (const char *)nt_pass, NT_HASH_LEN);
01053 #endif
01054
01055 centry_put_time(centry, time(NULL));
01056
01057
01058 generate_random_buffer(cred_salt, NT_HASH_LEN);
01059 E_md5hash(cred_salt, nt_pass, salted_hash);
01060
01061 centry_put_hash16(centry, salted_hash);
01062 centry_put_hash16(centry, cred_salt);
01063 centry_end(centry, "CRED/%s", sid_to_string(sid_string, sid));
01064
01065 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
01066
01067 centry_free(centry);
01068
01069 return NT_STATUS_OK;
01070 }
01071
01072
01073
01074 static NTSTATUS query_user_list(struct winbindd_domain *domain,
01075 TALLOC_CTX *mem_ctx,
01076 uint32 *num_entries,
01077 WINBIND_USERINFO **info)
01078 {
01079 struct winbind_cache *cache = get_cache(domain);
01080 struct cache_entry *centry = NULL;
01081 NTSTATUS status;
01082 unsigned int i, retry;
01083
01084 if (!cache->tdb)
01085 goto do_query;
01086
01087 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
01088 if (!centry)
01089 goto do_query;
01090
01091 *num_entries = centry_uint32(centry);
01092
01093 if (*num_entries == 0)
01094 goto do_cached;
01095
01096 (*info) = TALLOC_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
01097 if (! (*info))
01098 smb_panic("query_user_list out of memory");
01099 for (i=0; i<(*num_entries); i++) {
01100 (*info)[i].acct_name = centry_string(centry, mem_ctx);
01101 (*info)[i].full_name = centry_string(centry, mem_ctx);
01102 (*info)[i].homedir = centry_string(centry, mem_ctx);
01103 (*info)[i].shell = centry_string(centry, mem_ctx);
01104 centry_sid(centry, mem_ctx, &(*info)[i].user_sid);
01105 centry_sid(centry, mem_ctx, &(*info)[i].group_sid);
01106 }
01107
01108 do_cached:
01109 status = centry->status;
01110
01111 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
01112 domain->name, nt_errstr(status) ));
01113
01114 centry_free(centry);
01115 return status;
01116
01117 do_query:
01118 *num_entries = 0;
01119 *info = NULL;
01120
01121
01122
01123 if (!NT_STATUS_IS_OK(domain->last_status))
01124 return domain->last_status;
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134 retry = 0;
01135 do {
01136
01137 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
01138 domain->name ));
01139
01140 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
01141 if (!NT_STATUS_IS_OK(status)) {
01142 DEBUG(3, ("query_user_list: returned 0x%08x, "
01143 "retrying\n", NT_STATUS_V(status)));
01144 }
01145 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
01146 DEBUG(3, ("query_user_list: flushing "
01147 "connection cache\n"));
01148 invalidate_cm_connection(&domain->conn);
01149 }
01150
01151 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
01152 (retry++ < 5));
01153
01154
01155 refresh_sequence_number(domain, False);
01156 centry = centry_start(domain, status);
01157 if (!centry)
01158 goto skip_save;
01159 centry_put_uint32(centry, *num_entries);
01160 for (i=0; i<(*num_entries); i++) {
01161 centry_put_string(centry, (*info)[i].acct_name);
01162 centry_put_string(centry, (*info)[i].full_name);
01163 centry_put_string(centry, (*info)[i].homedir);
01164 centry_put_string(centry, (*info)[i].shell);
01165 centry_put_sid(centry, &(*info)[i].user_sid);
01166 centry_put_sid(centry, &(*info)[i].group_sid);
01167 if (domain->backend && domain->backend->consistent) {
01168
01169 wcache_save_name_to_sid(domain, NT_STATUS_OK,
01170 domain->name,
01171 (*info)[i].acct_name,
01172 &(*info)[i].user_sid,
01173 SID_NAME_USER);
01174 wcache_save_sid_to_name(domain, NT_STATUS_OK,
01175 &(*info)[i].user_sid,
01176 domain->name,
01177 (*info)[i].acct_name,
01178 SID_NAME_USER);
01179 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
01180 }
01181 }
01182 centry_end(centry, "UL/%s", domain->name);
01183 centry_free(centry);
01184
01185 skip_save:
01186 return status;
01187 }
01188
01189
01190 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
01191 TALLOC_CTX *mem_ctx,
01192 uint32 *num_entries,
01193 struct acct_info **info)
01194 {
01195 struct winbind_cache *cache = get_cache(domain);
01196 struct cache_entry *centry = NULL;
01197 NTSTATUS status;
01198 unsigned int i;
01199
01200 if (!cache->tdb)
01201 goto do_query;
01202
01203 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
01204 if (!centry)
01205 goto do_query;
01206
01207 *num_entries = centry_uint32(centry);
01208
01209 if (*num_entries == 0)
01210 goto do_cached;
01211
01212 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
01213 if (! (*info))
01214 smb_panic("enum_dom_groups out of memory");
01215 for (i=0; i<(*num_entries); i++) {
01216 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
01217 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
01218 (*info)[i].rid = centry_uint32(centry);
01219 }
01220
01221 do_cached:
01222 status = centry->status;
01223
01224 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
01225 domain->name, nt_errstr(status) ));
01226
01227 centry_free(centry);
01228 return status;
01229
01230 do_query:
01231 *num_entries = 0;
01232 *info = NULL;
01233
01234
01235
01236 if (!NT_STATUS_IS_OK(domain->last_status))
01237 return domain->last_status;
01238
01239 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
01240 domain->name ));
01241
01242 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
01243
01244
01245 refresh_sequence_number(domain, False);
01246 centry = centry_start(domain, status);
01247 if (!centry)
01248 goto skip_save;
01249 centry_put_uint32(centry, *num_entries);
01250 for (i=0; i<(*num_entries); i++) {
01251 centry_put_string(centry, (*info)[i].acct_name);
01252 centry_put_string(centry, (*info)[i].acct_desc);
01253 centry_put_uint32(centry, (*info)[i].rid);
01254 }
01255 centry_end(centry, "GL/%s/domain", domain->name);
01256 centry_free(centry);
01257
01258 skip_save:
01259 return status;
01260 }
01261
01262
01263 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
01264 TALLOC_CTX *mem_ctx,
01265 uint32 *num_entries,
01266 struct acct_info **info)
01267 {
01268 struct winbind_cache *cache = get_cache(domain);
01269 struct cache_entry *centry = NULL;
01270 NTSTATUS status;
01271 unsigned int i;
01272
01273 if (!cache->tdb)
01274 goto do_query;
01275
01276 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
01277 if (!centry)
01278 goto do_query;
01279
01280 *num_entries = centry_uint32(centry);
01281
01282 if (*num_entries == 0)
01283 goto do_cached;
01284
01285 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
01286 if (! (*info))
01287 smb_panic("enum_dom_groups out of memory");
01288 for (i=0; i<(*num_entries); i++) {
01289 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
01290 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
01291 (*info)[i].rid = centry_uint32(centry);
01292 }
01293
01294 do_cached:
01295
01296
01297
01298
01299
01300
01301 if (wcache_server_down(domain)) {
01302 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
01303 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
01304 } else
01305 status = centry->status;
01306
01307 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
01308 domain->name, nt_errstr(status) ));
01309
01310 centry_free(centry);
01311 return status;
01312
01313 do_query:
01314 *num_entries = 0;
01315 *info = NULL;
01316
01317
01318
01319 if (!NT_STATUS_IS_OK(domain->last_status))
01320 return domain->last_status;
01321
01322 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
01323 domain->name ));
01324
01325 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
01326
01327
01328 refresh_sequence_number(domain, False);
01329 centry = centry_start(domain, status);
01330 if (!centry)
01331 goto skip_save;
01332 centry_put_uint32(centry, *num_entries);
01333 for (i=0; i<(*num_entries); i++) {
01334 centry_put_string(centry, (*info)[i].acct_name);
01335 centry_put_string(centry, (*info)[i].acct_desc);
01336 centry_put_uint32(centry, (*info)[i].rid);
01337 }
01338 centry_end(centry, "GL/%s/local", domain->name);
01339 centry_free(centry);
01340
01341 skip_save:
01342 return status;
01343 }
01344
01345
01346 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
01347 TALLOC_CTX *mem_ctx,
01348 const char *domain_name,
01349 const char *name,
01350 DOM_SID *sid,
01351 enum lsa_SidType *type)
01352 {
01353 struct winbind_cache *cache = get_cache(domain);
01354 struct cache_entry *centry = NULL;
01355 NTSTATUS status;
01356 fstring uname;
01357
01358 if (!cache->tdb)
01359 goto do_query;
01360
01361 fstrcpy(uname, name);
01362 strupper_m(uname);
01363 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
01364 if (!centry)
01365 goto do_query;
01366 *type = (enum lsa_SidType)centry_uint32(centry);
01367 status = centry->status;
01368 if (NT_STATUS_IS_OK(status)) {
01369 centry_sid(centry, mem_ctx, sid);
01370 }
01371
01372 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n",
01373 domain->name, nt_errstr(status) ));
01374
01375 centry_free(centry);
01376 return status;
01377
01378 do_query:
01379 ZERO_STRUCTP(sid);
01380
01381
01382
01383
01384
01385
01386
01387
01388 if (!(NT_STATUS_IS_OK(domain->last_status)
01389 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
01390 return domain->last_status;
01391
01392 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
01393 domain->name ));
01394
01395 status = domain->backend->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
01396
01397
01398 refresh_sequence_number(domain, False);
01399
01400 if (domain->online && !is_null_sid(sid)) {
01401 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
01402 }
01403
01404 if (NT_STATUS_IS_OK(status)) {
01405 strupper_m(CONST_DISCARD(char *,domain_name));
01406 strlower_m(CONST_DISCARD(char *,name));
01407 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
01408 }
01409
01410 return status;
01411 }
01412
01413
01414
01415 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
01416 TALLOC_CTX *mem_ctx,
01417 const DOM_SID *sid,
01418 char **domain_name,
01419 char **name,
01420 enum lsa_SidType *type)
01421 {
01422 struct winbind_cache *cache = get_cache(domain);
01423 struct cache_entry *centry = NULL;
01424 NTSTATUS status;
01425 fstring sid_string;
01426
01427 if (!cache->tdb)
01428 goto do_query;
01429
01430 centry = wcache_fetch(cache, domain, "SN/%s", sid_to_string(sid_string, sid));
01431 if (!centry)
01432 goto do_query;
01433 if (NT_STATUS_IS_OK(centry->status)) {
01434 *type = (enum lsa_SidType)centry_uint32(centry);
01435 *domain_name = centry_string(centry, mem_ctx);
01436 *name = centry_string(centry, mem_ctx);
01437 }
01438 status = centry->status;
01439
01440 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: %s\n",
01441 domain->name, nt_errstr(status) ));
01442
01443 centry_free(centry);
01444 return status;
01445
01446 do_query:
01447 *name = NULL;
01448 *domain_name = NULL;
01449
01450
01451
01452
01453
01454
01455
01456
01457 if (!(NT_STATUS_IS_OK(domain->last_status)
01458 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
01459 return domain->last_status;
01460
01461 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
01462 domain->name ));
01463
01464 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
01465
01466
01467 refresh_sequence_number(domain, False);
01468 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
01469
01470
01471
01472
01473 return status;
01474 }
01475
01476 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
01477 TALLOC_CTX *mem_ctx,
01478 const DOM_SID *domain_sid,
01479 uint32 *rids,
01480 size_t num_rids,
01481 char **domain_name,
01482 char ***names,
01483 enum lsa_SidType **types)
01484 {
01485 struct winbind_cache *cache = get_cache(domain);
01486 size_t i;
01487 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
01488 BOOL have_mapped;
01489 BOOL have_unmapped;
01490
01491 *domain_name = NULL;
01492 *names = NULL;
01493 *types = NULL;
01494
01495 if (!cache->tdb) {
01496 goto do_query;
01497 }
01498
01499 if (num_rids == 0) {
01500 return NT_STATUS_OK;
01501 }
01502
01503 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
01504 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
01505
01506 if ((*names == NULL) || (*types == NULL)) {
01507 result = NT_STATUS_NO_MEMORY;
01508 goto error;
01509 }
01510
01511 have_mapped = have_unmapped = False;
01512
01513 for (i=0; i<num_rids; i++) {
01514 DOM_SID sid;
01515 struct cache_entry *centry;
01516
01517 if (!sid_compose(&sid, domain_sid, rids[i])) {
01518 result = NT_STATUS_INTERNAL_ERROR;
01519 goto error;
01520 }
01521
01522 centry = wcache_fetch(cache, domain, "SN/%s",
01523 sid_string_static(&sid));
01524 if (!centry) {
01525 goto do_query;
01526 }
01527
01528 (*types)[i] = SID_NAME_UNKNOWN;
01529 (*names)[i] = talloc_strdup(*names, "");
01530
01531 if (NT_STATUS_IS_OK(centry->status)) {
01532 char *dom;
01533 have_mapped = True;
01534 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
01535 dom = centry_string(centry, mem_ctx);
01536 if (*domain_name == NULL) {
01537 *domain_name = dom;
01538 } else {
01539 talloc_free(dom);
01540 }
01541 (*names)[i] = centry_string(centry, *names);
01542 } else {
01543 have_unmapped = True;
01544 }
01545
01546 centry_free(centry);
01547 }
01548
01549 if (!have_mapped) {
01550 return NT_STATUS_NONE_MAPPED;
01551 }
01552 if (!have_unmapped) {
01553 return NT_STATUS_OK;
01554 }
01555 return STATUS_SOME_UNMAPPED;
01556
01557 do_query:
01558
01559 TALLOC_FREE(*names);
01560 TALLOC_FREE(*types);
01561
01562 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
01563 rids, num_rids, domain_name,
01564 names, types);
01565
01566 if (!NT_STATUS_IS_OK(result) &&
01567 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
01568 return result;
01569 }
01570
01571 refresh_sequence_number(domain, False);
01572
01573 for (i=0; i<num_rids; i++) {
01574 DOM_SID sid;
01575 NTSTATUS status;
01576
01577 if (!sid_compose(&sid, domain_sid, rids[i])) {
01578 result = NT_STATUS_INTERNAL_ERROR;
01579 goto error;
01580 }
01581
01582 status = (*types)[i] == SID_NAME_UNKNOWN ?
01583 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
01584
01585 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
01586 (*names)[i], (*types)[i]);
01587 }
01588
01589 return result;
01590
01591 error:
01592
01593 TALLOC_FREE(*names);
01594 TALLOC_FREE(*types);
01595 return result;
01596 }
01597
01598
01599 static NTSTATUS query_user(struct winbindd_domain *domain,
01600 TALLOC_CTX *mem_ctx,
01601 const DOM_SID *user_sid,
01602 WINBIND_USERINFO *info)
01603 {
01604 struct winbind_cache *cache = get_cache(domain);
01605 struct cache_entry *centry = NULL;
01606 NTSTATUS status;
01607
01608 if (!cache->tdb)
01609 goto do_query;
01610
01611 centry = wcache_fetch(cache, domain, "U/%s", sid_string_static(user_sid));
01612
01613
01614
01615
01616
01617 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
01618 netsamlogon_cache_have(user_sid)) {
01619 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
01620 domain->last_status = NT_STATUS_OK;
01621 centry_free(centry);
01622 goto do_query;
01623 }
01624
01625 if (!centry)
01626 goto do_query;
01627
01628 info->acct_name = centry_string(centry, mem_ctx);
01629 info->full_name = centry_string(centry, mem_ctx);
01630 info->homedir = centry_string(centry, mem_ctx);
01631 info->shell = centry_string(centry, mem_ctx);
01632 info->primary_gid = centry_uint32(centry);
01633 centry_sid(centry, mem_ctx, &info->user_sid);
01634 centry_sid(centry, mem_ctx, &info->group_sid);
01635 status = centry->status;
01636
01637 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
01638 domain->name, nt_errstr(status) ));
01639
01640 centry_free(centry);
01641 return status;
01642
01643 do_query:
01644 ZERO_STRUCTP(info);
01645
01646
01647
01648 if (!NT_STATUS_IS_OK(domain->last_status))
01649 return domain->last_status;
01650
01651 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
01652 domain->name ));
01653
01654 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
01655
01656
01657 refresh_sequence_number(domain, False);
01658 wcache_save_user(domain, status, info);
01659
01660 return status;
01661 }
01662
01663
01664
01665 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
01666 TALLOC_CTX *mem_ctx,
01667 const DOM_SID *user_sid,
01668 uint32 *num_groups, DOM_SID **user_gids)
01669 {
01670 struct winbind_cache *cache = get_cache(domain);
01671 struct cache_entry *centry = NULL;
01672 NTSTATUS status;
01673 unsigned int i;
01674 fstring sid_string;
01675
01676 if (!cache->tdb)
01677 goto do_query;
01678
01679 centry = wcache_fetch(cache, domain, "UG/%s", sid_to_string(sid_string, user_sid));
01680
01681
01682
01683
01684
01685 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
01686 netsamlogon_cache_have(user_sid)) {
01687 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
01688 domain->last_status = NT_STATUS_OK;
01689 centry_free(centry);
01690 goto do_query;
01691 }
01692
01693 if (!centry)
01694 goto do_query;
01695
01696 *num_groups = centry_uint32(centry);
01697
01698 if (*num_groups == 0)
01699 goto do_cached;
01700
01701 (*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
01702 if (! (*user_gids))
01703 smb_panic("lookup_usergroups out of memory");
01704 for (i=0; i<(*num_groups); i++) {
01705 centry_sid(centry, mem_ctx, &(*user_gids)[i]);
01706 }
01707
01708 do_cached:
01709 status = centry->status;
01710
01711 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
01712 domain->name, nt_errstr(status) ));
01713
01714 centry_free(centry);
01715 return status;
01716
01717 do_query:
01718 (*num_groups) = 0;
01719 (*user_gids) = NULL;
01720
01721
01722
01723 if (!NT_STATUS_IS_OK(domain->last_status))
01724 return domain->last_status;
01725
01726 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
01727 domain->name ));
01728
01729 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
01730
01731
01732 refresh_sequence_number(domain, False);
01733 centry = centry_start(domain, status);
01734 if (!centry)
01735 goto skip_save;
01736 centry_put_uint32(centry, *num_groups);
01737 for (i=0; i<(*num_groups); i++) {
01738 centry_put_sid(centry, &(*user_gids)[i]);
01739 }
01740 centry_end(centry, "UG/%s", sid_to_string(sid_string, user_sid));
01741 centry_free(centry);
01742
01743 skip_save:
01744 return status;
01745 }
01746
01747 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
01748 TALLOC_CTX *mem_ctx,
01749 uint32 num_sids, const DOM_SID *sids,
01750 uint32 *num_aliases, uint32 **alias_rids)
01751 {
01752 struct winbind_cache *cache = get_cache(domain);
01753 struct cache_entry *centry = NULL;
01754 NTSTATUS status;
01755 char *sidlist = talloc_strdup(mem_ctx, "");
01756 int i;
01757
01758 if (!cache->tdb)
01759 goto do_query;
01760
01761 if (num_sids == 0) {
01762 *num_aliases = 0;
01763 *alias_rids = NULL;
01764 return NT_STATUS_OK;
01765 }
01766
01767
01768
01769
01770 for (i=0; i<num_sids; i++) {
01771 sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist,
01772 sid_string_static(&sids[i]));
01773 if (sidlist == NULL)
01774 return NT_STATUS_NO_MEMORY;
01775 }
01776
01777 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
01778
01779 if (!centry)
01780 goto do_query;
01781
01782 *num_aliases = centry_uint32(centry);
01783 *alias_rids = NULL;
01784
01785 if (*num_aliases) {
01786 (*alias_rids) = TALLOC_ARRAY(mem_ctx, uint32, *num_aliases);
01787
01788 if ((*alias_rids) == NULL) {
01789 centry_free(centry);
01790 return NT_STATUS_NO_MEMORY;
01791 }
01792 } else {
01793 (*alias_rids) = NULL;
01794 }
01795
01796 for (i=0; i<(*num_aliases); i++)
01797 (*alias_rids)[i] = centry_uint32(centry);
01798
01799 status = centry->status;
01800
01801 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
01802 "status %s\n", domain->name, nt_errstr(status)));
01803
01804 centry_free(centry);
01805 return status;
01806
01807 do_query:
01808 (*num_aliases) = 0;
01809 (*alias_rids) = NULL;
01810
01811 if (!NT_STATUS_IS_OK(domain->last_status))
01812 return domain->last_status;
01813
01814 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
01815 "for domain %s\n", domain->name ));
01816
01817 status = domain->backend->lookup_useraliases(domain, mem_ctx,
01818 num_sids, sids,
01819 num_aliases, alias_rids);
01820
01821
01822 refresh_sequence_number(domain, False);
01823 centry = centry_start(domain, status);
01824 if (!centry)
01825 goto skip_save;
01826 centry_put_uint32(centry, *num_aliases);
01827 for (i=0; i<(*num_aliases); i++)
01828 centry_put_uint32(centry, (*alias_rids)[i]);
01829 centry_end(centry, "UA%s", sidlist);
01830 centry_free(centry);
01831
01832 skip_save:
01833 return status;
01834 }
01835
01836
01837 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
01838 TALLOC_CTX *mem_ctx,
01839 const DOM_SID *group_sid, uint32 *num_names,
01840 DOM_SID **sid_mem, char ***names,
01841 uint32 **name_types)
01842 {
01843 struct winbind_cache *cache = get_cache(domain);
01844 struct cache_entry *centry = NULL;
01845 NTSTATUS status;
01846 unsigned int i;
01847 fstring sid_string;
01848
01849 if (!cache->tdb)
01850 goto do_query;
01851
01852 centry = wcache_fetch(cache, domain, "GM/%s", sid_to_string(sid_string, group_sid));
01853 if (!centry)
01854 goto do_query;
01855
01856 *num_names = centry_uint32(centry);
01857
01858 if (*num_names == 0)
01859 goto do_cached;
01860
01861 (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_names);
01862 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names);
01863 (*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *num_names);
01864
01865 if (! (*sid_mem) || ! (*names) || ! (*name_types)) {
01866 smb_panic("lookup_groupmem out of memory");
01867 }
01868
01869 for (i=0; i<(*num_names); i++) {
01870 centry_sid(centry, mem_ctx, &(*sid_mem)[i]);
01871 (*names)[i] = centry_string(centry, mem_ctx);
01872 (*name_types)[i] = centry_uint32(centry);
01873 }
01874
01875 do_cached:
01876 status = centry->status;
01877
01878 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
01879 domain->name, nt_errstr(status)));
01880
01881 centry_free(centry);
01882 return status;
01883
01884 do_query:
01885 (*num_names) = 0;
01886 (*sid_mem) = NULL;
01887 (*names) = NULL;
01888 (*name_types) = NULL;
01889
01890
01891
01892 if (!NT_STATUS_IS_OK(domain->last_status))
01893 return domain->last_status;
01894
01895 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
01896 domain->name ));
01897
01898 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid, num_names,
01899 sid_mem, names, name_types);
01900
01901
01902 refresh_sequence_number(domain, False);
01903 centry = centry_start(domain, status);
01904 if (!centry)
01905 goto skip_save;
01906 centry_put_uint32(centry, *num_names);
01907 for (i=0; i<(*num_names); i++) {
01908 centry_put_sid(centry, &(*sid_mem)[i]);
01909 centry_put_string(centry, (*names)[i]);
01910 centry_put_uint32(centry, (*name_types)[i]);
01911 }
01912 centry_end(centry, "GM/%s", sid_to_string(sid_string, group_sid));
01913 centry_free(centry);
01914
01915 skip_save:
01916 return status;
01917 }
01918
01919
01920 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
01921 {
01922 refresh_sequence_number(domain, False);
01923
01924 *seq = domain->sequence_number;
01925
01926 return NT_STATUS_OK;
01927 }
01928
01929
01930
01931
01932 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
01933 TALLOC_CTX *mem_ctx,
01934 uint32 *num_domains,
01935 char ***names,
01936 char ***alt_names,
01937 DOM_SID **dom_sids)
01938 {
01939 struct winbind_cache *cache = get_cache(domain);
01940 struct cache_entry *centry = NULL;
01941 NTSTATUS status;
01942 int i;
01943
01944 if (!cache->tdb)
01945 goto do_query;
01946
01947 centry = wcache_fetch(cache, domain, "TRUSTDOMS/%s", domain->name);
01948
01949 if (!centry) {
01950 goto do_query;
01951 }
01952
01953 *num_domains = centry_uint32(centry);
01954
01955 if (*num_domains) {
01956 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
01957 (*alt_names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
01958 (*dom_sids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
01959
01960 if (! (*dom_sids) || ! (*names) || ! (*alt_names)) {
01961 smb_panic("trusted_domains out of memory");
01962 }
01963 } else {
01964 (*names) = NULL;
01965 (*alt_names) = NULL;
01966 (*dom_sids) = NULL;
01967 }
01968
01969 for (i=0; i<(*num_domains); i++) {
01970 (*names)[i] = centry_string(centry, mem_ctx);
01971 (*alt_names)[i] = centry_string(centry, mem_ctx);
01972 centry_sid(centry, mem_ctx, &(*dom_sids)[i]);
01973 }
01974
01975 status = centry->status;
01976
01977 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
01978 domain->name, *num_domains, nt_errstr(status) ));
01979
01980 centry_free(centry);
01981 return status;
01982
01983 do_query:
01984 (*num_domains) = 0;
01985 (*dom_sids) = NULL;
01986 (*names) = NULL;
01987 (*alt_names) = NULL;
01988
01989
01990
01991 if (!NT_STATUS_IS_OK(domain->last_status))
01992 return domain->last_status;
01993
01994 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
01995 domain->name ));
01996
01997 status = domain->backend->trusted_domains(domain, mem_ctx, num_domains,
01998 names, alt_names, dom_sids);
01999
02000
02001
02002
02003
02004 if (!NT_STATUS_IS_ERR(status)) {
02005 status = NT_STATUS_OK;
02006 }
02007
02008
02009 refresh_sequence_number(domain, False);
02010
02011 centry = centry_start(domain, status);
02012 if (!centry)
02013 goto skip_save;
02014
02015 centry_put_uint32(centry, *num_domains);
02016
02017 for (i=0; i<(*num_domains); i++) {
02018 centry_put_string(centry, (*names)[i]);
02019 centry_put_string(centry, (*alt_names)[i]);
02020 centry_put_sid(centry, &(*dom_sids)[i]);
02021 }
02022
02023 centry_end(centry, "TRUSTDOMS/%s", domain->name);
02024
02025 centry_free(centry);
02026
02027 skip_save:
02028 return status;
02029 }
02030
02031
02032 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
02033 TALLOC_CTX *mem_ctx,
02034 SAM_UNK_INFO_12 *policy){
02035 struct winbind_cache *cache = get_cache(domain);
02036 struct cache_entry *centry = NULL;
02037 NTSTATUS status;
02038
02039 if (!cache->tdb)
02040 goto do_query;
02041
02042 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
02043
02044 if (!centry)
02045 goto do_query;
02046
02047 policy->duration = centry_nttime(centry);
02048 policy->reset_count = centry_nttime(centry);
02049 policy->bad_attempt_lockout = centry_uint16(centry);
02050
02051 status = centry->status;
02052
02053 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
02054 domain->name, nt_errstr(status) ));
02055
02056 centry_free(centry);
02057 return status;
02058
02059 do_query:
02060 ZERO_STRUCTP(policy);
02061
02062
02063
02064 if (!NT_STATUS_IS_OK(domain->last_status))
02065 return domain->last_status;
02066
02067 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
02068 domain->name ));
02069
02070 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
02071
02072
02073 refresh_sequence_number(domain, False);
02074 wcache_save_lockout_policy(domain, status, policy);
02075
02076 return status;
02077 }
02078
02079
02080 static NTSTATUS password_policy(struct winbindd_domain *domain,
02081 TALLOC_CTX *mem_ctx,
02082 SAM_UNK_INFO_1 *policy)
02083 {
02084 struct winbind_cache *cache = get_cache(domain);
02085 struct cache_entry *centry = NULL;
02086 NTSTATUS status;
02087
02088 if (!cache->tdb)
02089 goto do_query;
02090
02091 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
02092
02093 if (!centry)
02094 goto do_query;
02095
02096 policy->min_length_password = centry_uint16(centry);
02097 policy->password_history = centry_uint16(centry);
02098 policy->password_properties = centry_uint32(centry);
02099 policy->expire = centry_nttime(centry);
02100 policy->min_passwordage = centry_nttime(centry);
02101
02102 status = centry->status;
02103
02104 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
02105 domain->name, nt_errstr(status) ));
02106
02107 centry_free(centry);
02108 return status;
02109
02110 do_query:
02111 ZERO_STRUCTP(policy);
02112
02113
02114
02115 if (!NT_STATUS_IS_OK(domain->last_status))
02116 return domain->last_status;
02117
02118 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
02119 domain->name ));
02120
02121 status = domain->backend->password_policy(domain, mem_ctx, policy);
02122
02123
02124 refresh_sequence_number(domain, False);
02125 if (NT_STATUS_IS_OK(status)) {
02126 wcache_save_password_policy(domain, status, policy);
02127 }
02128
02129 return status;
02130 }
02131
02132
02133
02134
02135 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
02136 void *state)
02137 {
02138 if (strncmp(kbuf.dptr, "UL/", 3) == 0 ||
02139 strncmp(kbuf.dptr, "GL/", 3) == 0)
02140 tdb_delete(the_tdb, kbuf);
02141
02142 return 0;
02143 }
02144
02145
02146
02147 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
02148 NET_USER_INFO_3 *info3)
02149 {
02150 struct winbind_cache *cache;
02151
02152
02153
02154
02155 if (lp_winbind_offline_logon()) {
02156 return;
02157 }
02158
02159 if (!domain)
02160 return;
02161
02162 cache = get_cache(domain);
02163 netsamlogon_clear_cached_user(cache->tdb, info3);
02164 }
02165
02166 void wcache_invalidate_cache(void)
02167 {
02168 struct winbindd_domain *domain;
02169
02170 for (domain = domain_list(); domain; domain = domain->next) {
02171 struct winbind_cache *cache = get_cache(domain);
02172
02173 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
02174 "entries for %s\n", domain->name));
02175 if (cache)
02176 tdb_traverse(cache->tdb, traverse_fn, NULL);
02177 }
02178 }
02179
02180 static BOOL init_wcache(void)
02181 {
02182 if (wcache == NULL) {
02183 wcache = SMB_XMALLOC_P(struct winbind_cache);
02184 ZERO_STRUCTP(wcache);
02185 }
02186
02187 if (wcache->tdb != NULL)
02188 return True;
02189
02190
02191 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
02192 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
02193 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
02194 O_RDWR|O_CREAT, 0600);
02195
02196 if (wcache->tdb == NULL) {
02197 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
02198 return False;
02199 }
02200
02201 return True;
02202 }
02203
02204
02205
02206
02207
02208
02209
02210 BOOL initialize_winbindd_cache(void)
02211 {
02212 BOOL cache_bad = True;
02213 uint32 vers;
02214
02215 if (!init_wcache()) {
02216 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
02217 return False;
02218 }
02219
02220
02221 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
02222 vers == WINBINDD_CACHE_VERSION) {
02223 cache_bad = False;
02224 }
02225
02226 if (cache_bad) {
02227 DEBUG(0,("initialize_winbindd_cache: clearing cache "
02228 "and re-creating with version number %d\n",
02229 WINBINDD_CACHE_VERSION ));
02230
02231 tdb_close(wcache->tdb);
02232 wcache->tdb = NULL;
02233
02234 if (unlink(lock_path("winbindd_cache.tdb")) == -1) {
02235 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
02236 lock_path("winbindd_cache.tdb"),
02237 strerror(errno) ));
02238 return False;
02239 }
02240 if (!init_wcache()) {
02241 DEBUG(0,("initialize_winbindd_cache: re-initialization "
02242 "init_wcache failed.\n"));
02243 return False;
02244 }
02245
02246
02247 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
02248 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
02249 tdb_errorstr(wcache->tdb) ));
02250 return False;
02251 }
02252 }
02253
02254 tdb_close(wcache->tdb);
02255 wcache->tdb = NULL;
02256 return True;
02257 }
02258
02259 void cache_store_response(pid_t pid, struct winbindd_response *response)
02260 {
02261 fstring key_str;
02262
02263 if (!init_wcache())
02264 return;
02265
02266 DEBUG(10, ("Storing response for pid %d, len %d\n",
02267 pid, response->length));
02268
02269 fstr_sprintf(key_str, "DR/%d", pid);
02270 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
02271 make_tdb_data((const char *)response, sizeof(*response)),
02272 TDB_REPLACE) == -1)
02273 return;
02274
02275 if (response->length == sizeof(*response))
02276 return;
02277
02278
02279
02280 DEBUG(10, ("Storing extra data: len=%d\n",
02281 (int)(response->length - sizeof(*response))));
02282
02283 fstr_sprintf(key_str, "DE/%d", pid);
02284 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
02285 make_tdb_data((const char *)response->extra_data.data,
02286 response->length - sizeof(*response)),
02287 TDB_REPLACE) == 0)
02288 return;
02289
02290
02291
02292
02293 fstr_sprintf(key_str, "DR/%d", pid);
02294 tdb_delete(wcache->tdb, string_tdb_data(key_str));
02295
02296 return;
02297 }
02298
02299 BOOL cache_retrieve_response(pid_t pid, struct winbindd_response * response)
02300 {
02301 TDB_DATA data;
02302 fstring key_str;
02303
02304 if (!init_wcache())
02305 return False;
02306
02307 DEBUG(10, ("Retrieving response for pid %d\n", pid));
02308
02309 fstr_sprintf(key_str, "DR/%d", pid);
02310 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
02311
02312 if (data.dptr == NULL)
02313 return False;
02314
02315 if (data.dsize != sizeof(*response))
02316 return False;
02317
02318 memcpy(response, data.dptr, data.dsize);
02319 SAFE_FREE(data.dptr);
02320
02321 if (response->length == sizeof(*response)) {
02322 response->extra_data.data = NULL;
02323 return True;
02324 }
02325
02326
02327
02328 DEBUG(10, ("Retrieving extra data length=%d\n",
02329 (int)(response->length - sizeof(*response))));
02330
02331 fstr_sprintf(key_str, "DE/%d", pid);
02332 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
02333
02334 if (data.dptr == NULL) {
02335 DEBUG(0, ("Did not find extra data\n"));
02336 return False;
02337 }
02338
02339 if (data.dsize != (response->length - sizeof(*response))) {
02340 DEBUG(0, ("Invalid extra data length: %d\n", (int)data.dsize));
02341 SAFE_FREE(data.dptr);
02342 return False;
02343 }
02344
02345 dump_data(11, data.dptr, data.dsize);
02346
02347 response->extra_data.data = data.dptr;
02348 return True;
02349 }
02350
02351 void cache_cleanup_response(pid_t pid)
02352 {
02353 fstring key_str;
02354
02355 if (!init_wcache())
02356 return;
02357
02358 fstr_sprintf(key_str, "DR/%d", pid);
02359 tdb_delete(wcache->tdb, string_tdb_data(key_str));
02360
02361 fstr_sprintf(key_str, "DE/%d", pid);
02362 tdb_delete(wcache->tdb, string_tdb_data(key_str));
02363
02364 return;
02365 }
02366
02367
02368 BOOL lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
02369 const char **domain_name, const char **name,
02370 enum lsa_SidType *type)
02371 {
02372 struct winbindd_domain *domain;
02373 struct winbind_cache *cache;
02374 struct cache_entry *centry = NULL;
02375 NTSTATUS status;
02376
02377 domain = find_lookup_domain_from_sid(sid);
02378 if (domain == NULL) {
02379 return False;
02380 }
02381
02382 cache = get_cache(domain);
02383
02384 if (cache->tdb == NULL) {
02385 return False;
02386 }
02387
02388 centry = wcache_fetch(cache, domain, "SN/%s", sid_string_static(sid));
02389 if (centry == NULL) {
02390 return False;
02391 }
02392
02393 if (NT_STATUS_IS_OK(centry->status)) {
02394 *type = (enum lsa_SidType)centry_uint32(centry);
02395 *domain_name = centry_string(centry, mem_ctx);
02396 *name = centry_string(centry, mem_ctx);
02397 }
02398
02399 status = centry->status;
02400 centry_free(centry);
02401 return NT_STATUS_IS_OK(status);
02402 }
02403
02404 BOOL lookup_cached_name(TALLOC_CTX *mem_ctx,
02405 const char *domain_name,
02406 const char *name,
02407 DOM_SID *sid,
02408 enum lsa_SidType *type)
02409 {
02410 struct winbindd_domain *domain;
02411 struct winbind_cache *cache;
02412 struct cache_entry *centry = NULL;
02413 NTSTATUS status;
02414 fstring uname;
02415
02416 domain = find_lookup_domain_from_name(domain_name);
02417 if (domain == NULL) {
02418 return False;
02419 }
02420
02421 cache = get_cache(domain);
02422
02423 if (cache->tdb == NULL) {
02424 return False;
02425 }
02426
02427 fstrcpy(uname, name);
02428 strupper_m(uname);
02429
02430 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
02431 if (centry == NULL) {
02432 return False;
02433 }
02434
02435 if (NT_STATUS_IS_OK(centry->status)) {
02436 *type = (enum lsa_SidType)centry_uint32(centry);
02437 centry_sid(centry, mem_ctx, sid);
02438 }
02439
02440 status = centry->status;
02441 centry_free(centry);
02442
02443 return NT_STATUS_IS_OK(status);
02444 }
02445
02446 void cache_name2sid(struct winbindd_domain *domain,
02447 const char *domain_name, const char *name,
02448 enum lsa_SidType type, const DOM_SID *sid)
02449 {
02450 refresh_sequence_number(domain, False);
02451 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
02452 sid, type);
02453 }
02454
02455
02456
02457
02458
02459
02460
02461
02462 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
02463 TDB_DATA dbuf, void *state)
02464 {
02465 struct cache_entry *centry;
02466
02467 if (is_non_centry_key(kbuf)) {
02468 return 0;
02469 }
02470
02471 centry = wcache_fetch_raw(kbuf.dptr);
02472 if (!centry) {
02473 return 0;
02474 }
02475
02476 if (!NT_STATUS_IS_OK(centry->status)) {
02477 DEBUG(10,("deleting centry %s\n", kbuf.dptr));
02478 tdb_delete(the_tdb, kbuf);
02479 }
02480
02481 centry_free(centry);
02482 return 0;
02483 }
02484
02485
02486 void wcache_flush_cache(void)
02487 {
02488 if (!wcache)
02489 return;
02490 if (wcache->tdb) {
02491 tdb_close(wcache->tdb);
02492 wcache->tdb = NULL;
02493 }
02494 if (opt_nocache)
02495 return;
02496
02497
02498 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
02499 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
02500 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
02501 O_RDWR|O_CREAT, 0600);
02502
02503 if (!wcache->tdb) {
02504 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
02505 return;
02506 }
02507
02508 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
02509
02510 DEBUG(10,("wcache_flush_cache success\n"));
02511 }
02512
02513
02514
02515 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
02516 void *state)
02517 {
02518 int *cred_count = (int*)state;
02519
02520 if (strncmp(kbuf.dptr, "CRED/", 5) == 0) {
02521 (*cred_count)++;
02522 }
02523 return 0;
02524 }
02525
02526 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
02527 {
02528 struct winbind_cache *cache = get_cache(domain);
02529
02530 *count = 0;
02531
02532 if (!cache->tdb) {
02533 return NT_STATUS_INTERNAL_DB_ERROR;
02534 }
02535
02536 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
02537
02538 return NT_STATUS_OK;
02539 }
02540
02541 struct cred_list {
02542 struct cred_list *prev, *next;
02543 TDB_DATA key;
02544 fstring name;
02545 time_t created;
02546 };
02547 static struct cred_list *wcache_cred_list;
02548
02549 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
02550 void *state)
02551 {
02552 struct cred_list *cred;
02553
02554 if (strncmp(kbuf.dptr, "CRED/", 5) == 0) {
02555
02556 cred = SMB_MALLOC_P(struct cred_list);
02557 if (cred == NULL) {
02558 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
02559 return -1;
02560 }
02561
02562 ZERO_STRUCTP(cred);
02563
02564
02565
02566 fstrcpy(cred->name, kbuf.dptr);
02567 DLIST_ADD(wcache_cred_list, cred);
02568 }
02569
02570 return 0;
02571 }
02572
02573 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid)
02574 {
02575 struct winbind_cache *cache = get_cache(domain);
02576 NTSTATUS status;
02577 int ret;
02578 struct cred_list *cred, *oldest = NULL;
02579
02580 if (!cache->tdb) {
02581 return NT_STATUS_INTERNAL_DB_ERROR;
02582 }
02583
02584
02585 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
02586
02587 fstring key_str;
02588
02589 DEBUG(11,("we already have an entry, deleting that\n"));
02590
02591 fstr_sprintf(key_str, "CRED/%s", sid_string_static(sid));
02592
02593 tdb_delete(cache->tdb, string_tdb_data(key_str));
02594
02595 return NT_STATUS_OK;
02596 }
02597
02598 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
02599 if (ret == 0) {
02600 return NT_STATUS_OK;
02601 } else if ((ret == -1) || (wcache_cred_list == NULL)) {
02602 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
02603 }
02604
02605 ZERO_STRUCTP(oldest);
02606
02607 for (cred = wcache_cred_list; cred; cred = cred->next) {
02608
02609 TDB_DATA data;
02610 time_t t;
02611
02612 data = tdb_fetch(cache->tdb, make_tdb_data(cred->name, strlen(cred->name)));
02613 if (!data.dptr) {
02614 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
02615 cred->name));
02616 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
02617 goto done;
02618 }
02619
02620 t = IVAL(data.dptr, 0);
02621 SAFE_FREE(data.dptr);
02622
02623 if (!oldest) {
02624 oldest = SMB_MALLOC_P(struct cred_list);
02625 if (oldest == NULL) {
02626 status = NT_STATUS_NO_MEMORY;
02627 goto done;
02628 }
02629
02630 fstrcpy(oldest->name, cred->name);
02631 oldest->created = t;
02632 continue;
02633 }
02634
02635 if (t < oldest->created) {
02636 fstrcpy(oldest->name, cred->name);
02637 oldest->created = t;
02638 }
02639 }
02640
02641 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
02642 status = NT_STATUS_OK;
02643 } else {
02644 status = NT_STATUS_UNSUCCESSFUL;
02645 }
02646 done:
02647 SAFE_FREE(wcache_cred_list);
02648 SAFE_FREE(oldest);
02649
02650 return status;
02651 }
02652
02653
02654 BOOL set_global_winbindd_state_offline(void)
02655 {
02656 TDB_DATA data;
02657
02658 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
02659
02660
02661
02662
02663 if (wcache == NULL || wcache->tdb == NULL) {
02664 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
02665 return False;
02666 }
02667
02668 if (!lp_winbind_offline_logon()) {
02669 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
02670 return False;
02671 }
02672
02673 if (global_winbindd_offline_state) {
02674
02675 return True;
02676 }
02677
02678 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
02679
02680 if (!data.dptr || data.dsize != 4) {
02681 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
02682 SAFE_FREE(data.dptr);
02683 return False;
02684 } else {
02685 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
02686 global_winbindd_offline_state = True;
02687 SAFE_FREE(data.dptr);
02688 return True;
02689 }
02690 }
02691
02692 void set_global_winbindd_state_online(void)
02693 {
02694 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
02695
02696 if (!lp_winbind_offline_logon()) {
02697 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
02698 return;
02699 }
02700
02701 if (!global_winbindd_offline_state) {
02702
02703 return;
02704 }
02705 global_winbindd_offline_state = False;
02706
02707 if (!wcache->tdb) {
02708 return;
02709 }
02710
02711
02712 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
02713 }
02714
02715 BOOL get_global_winbindd_state_offline(void)
02716 {
02717 return global_winbindd_offline_state;
02718 }
02719
02720
02721 struct winbindd_methods cache_methods = {
02722 True,
02723 query_user_list,
02724 enum_dom_groups,
02725 enum_local_groups,
02726 name_to_sid,
02727 sid_to_name,
02728 rids_to_names,
02729 query_user,
02730 lookup_usergroups,
02731 lookup_useraliases,
02732 lookup_groupmem,
02733 sequence_number,
02734 lockout_policy,
02735 password_policy,
02736 trusted_domains
02737 };