root/source3/winbindd/winbindd_cache.c

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

DEFINITIONS

This source file includes following definitions.
  1. is_non_centry_key
  2. winbindd_check_cache_size
  3. get_cache
  4. centry_free
  5. centry_check_bytes
  6. centry_uint32
  7. centry_uint16
  8. centry_uint8
  9. centry_nttime
  10. centry_time
  11. centry_string
  12. centry_hash16
  13. centry_sid
  14. centry_ntstatus
  15. wcache_server_down
  16. fetch_cache_seqnum
  17. store_cache_seqnum
  18. refresh_sequence_number
  19. centry_expired
  20. wcache_fetch_raw
  21. wcache_fetch
  22. wcache_delete
  23. centry_expand
  24. centry_put_uint32
  25. centry_put_uint16
  26. centry_put_uint8
  27. centry_put_string
  28. centry_put_hash16
  29. centry_put_sid
  30. centry_put_ntstatus
  31. centry_put_nttime
  32. centry_put_time
  33. centry_start
  34. centry_end
  35. wcache_save_name_to_sid
  36. wcache_save_sid_to_name
  37. wcache_save_user
  38. wcache_save_lockout_policy
  39. wcache_save_password_policy
  40. wcache_save_username_alias
  41. wcache_save_alias_username
  42. resolve_username_to_alias
  43. resolve_alias_to_username
  44. wcache_cached_creds_exist
  45. wcache_get_creds
  46. wcache_save_creds
  47. query_user_list
  48. enum_dom_groups
  49. enum_local_groups
  50. name_to_sid
  51. sid_to_name
  52. rids_to_names
  53. query_user
  54. lookup_usergroups
  55. lookup_useraliases
  56. lookup_groupmem
  57. sequence_number
  58. trusted_domains
  59. lockout_policy
  60. password_policy
  61. traverse_fn
  62. wcache_invalidate_samlogon
  63. wcache_invalidate_cache
  64. wcache_invalidate_cache_noinit
  65. init_wcache
  66. initialize_winbindd_cache
  67. close_winbindd_cache
  68. cache_store_response
  69. cache_retrieve_response
  70. cache_cleanup_response
  71. lookup_cached_sid
  72. lookup_cached_name
  73. cache_name2sid
  74. traverse_fn_cleanup
  75. wcache_flush_cache
  76. traverse_fn_cached_creds
  77. wcache_count_cached_creds
  78. traverse_fn_get_credlist
  79. wcache_remove_oldest_cached_creds
  80. set_global_winbindd_state_offline
  81. set_global_winbindd_state_online
  82. get_global_winbindd_state_offline
  83. create_centry_validate
  84. validate_seqnum
  85. validate_ns
  86. validate_sn
  87. validate_u
  88. validate_loc_pol
  89. validate_pwd_pol
  90. validate_cred
  91. validate_ul
  92. validate_gl
  93. validate_ug
  94. validate_ua
  95. validate_gm
  96. validate_dr
  97. validate_de
  98. validate_pwinfo
  99. validate_nss_an
  100. validate_nss_na
  101. validate_trustdoms
  102. validate_trustdomcache
  103. validate_offline
  104. validate_cache_version
  105. cache_traverse_validate_fn
  106. validate_panic
  107. winbindd_validate_cache
  108. winbindd_validate_cache_nobackup
  109. winbindd_cache_validate_and_initialize
  110. add_wbdomain_to_tdc_array
  111. make_tdc_key
  112. pack_tdc_domains
  113. unpack_tdc_domains
  114. wcache_tdc_store_list
  115. wcache_tdc_fetch_list
  116. wcache_tdc_add_domain
  117. wcache_tdc_fetch_domain
  118. wcache_tdc_clear
  119. wcache_save_user_pwinfo
  120. nss_get_info_cached

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    Winbind cache backend functions
   5 
   6    Copyright (C) Andrew Tridgell 2001
   7    Copyright (C) Gerald Carter   2003-2007
   8    Copyright (C) Volker Lendecke 2005
   9    Copyright (C) Guenther Deschner 2005
  10    Copyright (C) Michael Adam    2007
  11 
  12    This program is free software; you can redistribute it and/or modify
  13    it under the terms of the GNU General Public License as published by
  14    the Free Software Foundation; either version 3 of the License, or
  15    (at your option) any later version.
  16    
  17    This program is distributed in the hope that it will be useful,
  18    but WITHOUT ANY WARRANTY; without even the implied warranty of
  19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20    GNU General Public License for more details.
  21    
  22    You should have received a copy of the GNU General Public License
  23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  24 */
  25 
  26 #include "includes.h"
  27 #include "winbindd.h"
  28 #include "tdb_validate.h"
  29 
  30 #undef DBGC_CLASS
  31 #define DBGC_CLASS DBGC_WINBIND
  32 
  33 #define WINBINDD_CACHE_VERSION 1
  34 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
  35 
  36 extern struct winbindd_methods reconnect_methods;
  37 #ifdef HAVE_ADS
  38 extern struct winbindd_methods ads_methods;
  39 #endif
  40 extern struct winbindd_methods builtin_passdb_methods;
  41 
  42 /*
  43  * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
  44  * Here are the list of entry types that are *not* stored
  45  * as form struct cache_entry in the cache.
  46  */
  47 
  48 static const char *non_centry_keys[] = {
  49         "SEQNUM/",
  50         "DR/",
  51         "DE/",
  52         "WINBINDD_OFFLINE",
  53         WINBINDD_CACHE_VERSION_KEYSTR,
  54         NULL
  55 };
  56 
  57 /************************************************************************
  58  Is this key a non-centry type ?
  59 ************************************************************************/
  60 
  61 static bool is_non_centry_key(TDB_DATA kbuf)
     /* [<][>][^][v][top][bottom][index][help] */
  62 {
  63         int i;
  64 
  65         if (kbuf.dptr == NULL || kbuf.dsize == 0) {
  66                 return false;
  67         }
  68         for (i = 0; non_centry_keys[i] != NULL; i++) {
  69                 size_t namelen = strlen(non_centry_keys[i]);
  70                 if (kbuf.dsize < namelen) {
  71                         continue;
  72                 }
  73                 if (strncmp(non_centry_keys[i], (const char *)kbuf.dptr, namelen) == 0) {
  74                         return true;
  75                 }
  76         }
  77         return false;
  78 }
  79 
  80 /* Global online/offline state - False when online. winbindd starts up online
  81    and sets this to true if the first query fails and there's an entry in
  82    the cache tdb telling us to stay offline. */
  83 
  84 static bool global_winbindd_offline_state;
  85 
  86 struct winbind_cache {
  87         TDB_CONTEXT *tdb;
  88 };
  89 
  90 struct cache_entry {
  91         NTSTATUS status;
  92         uint32 sequence_number;
  93         uint8 *data;
  94         uint32 len, ofs;
  95 };
  96 
  97 void (*smb_panic_fn)(const char *const why) = smb_panic;
  98 
  99 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
 100 
 101 static struct winbind_cache *wcache;
 102 
 103 void winbindd_check_cache_size(time_t t)
     /* [<][>][^][v][top][bottom][index][help] */
 104 {
 105         static time_t last_check_time;
 106         struct stat st;
 107 
 108         if (last_check_time == (time_t)0)
 109                 last_check_time = t;
 110 
 111         if (t - last_check_time < 60 && t - last_check_time > 0)
 112                 return;
 113 
 114         if (wcache == NULL || wcache->tdb == NULL) {
 115                 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
 116                 return;
 117         }
 118 
 119         if (fstat(tdb_fd(wcache->tdb), &st) == -1) {
 120                 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno) ));
 121                 return;
 122         }
 123 
 124         if (st.st_size > WINBINDD_MAX_CACHE_SIZE) {
 125                 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
 126                         (unsigned long)st.st_size,
 127                         (unsigned long)WINBINDD_MAX_CACHE_SIZE));
 128                 wcache_flush_cache();
 129         }
 130 }
 131 
 132 /* get the winbind_cache structure */
 133 static struct winbind_cache *get_cache(struct winbindd_domain *domain)
     /* [<][>][^][v][top][bottom][index][help] */
 134 {
 135         struct winbind_cache *ret = wcache;
 136 
 137         /* We have to know what type of domain we are dealing with first. */
 138 
 139         if (domain->internal) {
 140                 domain->backend = &builtin_passdb_methods;
 141                 domain->initialized = True;
 142         }
 143         if ( !domain->initialized ) {
 144                 init_dc_connection( domain );
 145         }
 146 
 147         /* 
 148            OK.  listen up becasue I'm only going to say this once.
 149            We have the following scenarios to consider
 150            (a) trusted AD domains on a Samba DC,
 151            (b) trusted AD domains and we are joined to a non-kerberos domain
 152            (c) trusted AD domains and we are joined to a kerberos (AD) domain
 153 
 154            For (a) we can always contact the trusted domain using krb5 
 155            since we have the domain trust account password
 156 
 157            For (b) we can only use RPC since we have no way of 
 158            getting a krb5 ticket in our own domain
 159 
 160            For (c) we can always use krb5 since we have a kerberos trust
 161 
 162            --jerry
 163          */
 164 
 165         if (!domain->backend) {
 166 #ifdef HAVE_ADS
 167                 struct winbindd_domain *our_domain = domain;
 168 
 169                 /* find our domain first so we can figure out if we 
 170                    are joined to a kerberized domain */
 171 
 172                 if ( !domain->primary )
 173                         our_domain = find_our_domain();
 174 
 175                 if ((our_domain->active_directory || IS_DC)
 176                     && domain->active_directory
 177                     && !lp_winbind_rpc_only()) {
 178                         DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain->name));
 179                         domain->backend = &ads_methods;
 180                 } else {
 181 #endif  /* HAVE_ADS */
 182                         DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain->name));
 183                         domain->backend = &reconnect_methods;
 184 #ifdef HAVE_ADS
 185                 }
 186 #endif  /* HAVE_ADS */
 187         }
 188 
 189         if (ret)
 190                 return ret;
 191         
 192         ret = SMB_XMALLOC_P(struct winbind_cache);
 193         ZERO_STRUCTP(ret);
 194 
 195         wcache = ret;
 196         wcache_flush_cache();
 197 
 198         return ret;
 199 }
 200 
 201 /*
 202   free a centry structure
 203 */
 204 static void centry_free(struct cache_entry *centry)
     /* [<][>][^][v][top][bottom][index][help] */
 205 {
 206         if (!centry)
 207                 return;
 208         SAFE_FREE(centry->data);
 209         free(centry);
 210 }
 211 
 212 static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes)
     /* [<][>][^][v][top][bottom][index][help] */
 213 {
 214         if (centry->len - centry->ofs < nbytes) {
 215                 DEBUG(0,("centry corruption? needed %u bytes, have %d\n", 
 216                          (unsigned int)nbytes,
 217                          centry->len - centry->ofs));
 218                 return false;
 219         }
 220         return true;
 221 }
 222 
 223 /*
 224   pull a uint32 from a cache entry 
 225 */
 226 static uint32 centry_uint32(struct cache_entry *centry)
     /* [<][>][^][v][top][bottom][index][help] */
 227 {
 228         uint32 ret;
 229 
 230         if (!centry_check_bytes(centry, 4)) {
 231                 smb_panic_fn("centry_uint32");
 232         }
 233         ret = IVAL(centry->data, centry->ofs);
 234         centry->ofs += 4;
 235         return ret;
 236 }
 237 
 238 /*
 239   pull a uint16 from a cache entry 
 240 */
 241 static uint16 centry_uint16(struct cache_entry *centry)
     /* [<][>][^][v][top][bottom][index][help] */
 242 {
 243         uint16 ret;
 244         if (!centry_check_bytes(centry, 2)) {
 245                 smb_panic_fn("centry_uint16");
 246         }
 247         ret = CVAL(centry->data, centry->ofs);
 248         centry->ofs += 2;
 249         return ret;
 250 }
 251 
 252 /*
 253   pull a uint8 from a cache entry 
 254 */
 255 static uint8 centry_uint8(struct cache_entry *centry)
     /* [<][>][^][v][top][bottom][index][help] */
 256 {
 257         uint8 ret;
 258         if (!centry_check_bytes(centry, 1)) {
 259                 smb_panic_fn("centry_uint8");
 260         }
 261         ret = CVAL(centry->data, centry->ofs);
 262         centry->ofs += 1;
 263         return ret;
 264 }
 265 
 266 /*
 267   pull a NTTIME from a cache entry 
 268 */
 269 static NTTIME centry_nttime(struct cache_entry *centry)
     /* [<][>][^][v][top][bottom][index][help] */
 270 {
 271         NTTIME ret;
 272         if (!centry_check_bytes(centry, 8)) {
 273                 smb_panic_fn("centry_nttime");
 274         }
 275         ret = IVAL(centry->data, centry->ofs);
 276         centry->ofs += 4;
 277         ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
 278         centry->ofs += 4;
 279         return ret;
 280 }
 281 
 282 /*
 283   pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
 284 */
 285 static time_t centry_time(struct cache_entry *centry)
     /* [<][>][^][v][top][bottom][index][help] */
 286 {
 287         return (time_t)centry_nttime(centry);
 288 }
 289 
 290 /* pull a string from a cache entry, using the supplied
 291    talloc context 
 292 */
 293 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 294 {
 295         uint32 len;
 296         char *ret;
 297 
 298         len = centry_uint8(centry);
 299 
 300         if (len == 0xFF) {
 301                 /* a deliberate NULL string */
 302                 return NULL;
 303         }
 304 
 305         if (!centry_check_bytes(centry, (size_t)len)) {
 306                 smb_panic_fn("centry_string");
 307         }
 308 
 309         ret = TALLOC_ARRAY(mem_ctx, char, len+1);
 310         if (!ret) {
 311                 smb_panic_fn("centry_string out of memory\n");
 312         }
 313         memcpy(ret,centry->data + centry->ofs, len);
 314         ret[len] = 0;
 315         centry->ofs += len;
 316         return ret;
 317 }
 318 
 319 /* pull a hash16 from a cache entry, using the supplied
 320    talloc context 
 321 */
 322 static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 323 {
 324         uint32 len;
 325         char *ret;
 326 
 327         len = centry_uint8(centry);
 328 
 329         if (len != 16) {
 330                 DEBUG(0,("centry corruption? hash len (%u) != 16\n", 
 331                         len ));
 332                 return NULL;
 333         }
 334 
 335         if (!centry_check_bytes(centry, 16)) {
 336                 return NULL;
 337         }
 338 
 339         ret = TALLOC_ARRAY(mem_ctx, char, 16);
 340         if (!ret) {
 341                 smb_panic_fn("centry_hash out of memory\n");
 342         }
 343         memcpy(ret,centry->data + centry->ofs, 16);
 344         centry->ofs += 16;
 345         return ret;
 346 }
 347 
 348 /* pull a sid from a cache entry, using the supplied
 349    talloc context 
 350 */
 351 static bool centry_sid(struct cache_entry *centry, TALLOC_CTX *mem_ctx, DOM_SID *sid)
     /* [<][>][^][v][top][bottom][index][help] */
 352 {
 353         char *sid_string;
 354         sid_string = centry_string(centry, mem_ctx);
 355         if ((sid_string == NULL) || (!string_to_sid(sid, sid_string))) {
 356                 return false;
 357         }
 358         return true;
 359 }
 360 
 361 
 362 /*
 363   pull a NTSTATUS from a cache entry
 364 */
 365 static NTSTATUS centry_ntstatus(struct cache_entry *centry)
     /* [<][>][^][v][top][bottom][index][help] */
 366 {
 367         NTSTATUS status;
 368 
 369         status = NT_STATUS(centry_uint32(centry));
 370         return status;
 371 }
 372 
 373 
 374 /* the server is considered down if it can't give us a sequence number */
 375 static bool wcache_server_down(struct winbindd_domain *domain)
     /* [<][>][^][v][top][bottom][index][help] */
 376 {
 377         bool ret;
 378 
 379         if (!wcache->tdb)
 380                 return false;
 381 
 382         ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
 383 
 384         if (ret)
 385                 DEBUG(10,("wcache_server_down: server for Domain %s down\n", 
 386                         domain->name ));
 387         return ret;
 388 }
 389 
 390 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
     /* [<][>][^][v][top][bottom][index][help] */
 391 {
 392         TDB_DATA data;
 393         fstring key;
 394         uint32 time_diff;
 395         
 396         if (!wcache->tdb) {
 397                 DEBUG(10,("fetch_cache_seqnum: tdb == NULL\n"));
 398                 return NT_STATUS_UNSUCCESSFUL;
 399         }
 400                 
 401         fstr_sprintf( key, "SEQNUM/%s", domain->name );
 402         
 403         data = tdb_fetch_bystring( wcache->tdb, key );
 404         if ( !data.dptr || data.dsize!=8 ) {
 405                 DEBUG(10,("fetch_cache_seqnum: invalid data size key [%s]\n", key ));
 406                 return NT_STATUS_UNSUCCESSFUL;
 407         }
 408         
 409         domain->sequence_number = IVAL(data.dptr, 0);
 410         domain->last_seq_check  = IVAL(data.dptr, 4);
 411         
 412         SAFE_FREE(data.dptr);
 413 
 414         /* have we expired? */
 415         
 416         time_diff = now - domain->last_seq_check;
 417         if ( time_diff > lp_winbind_cache_time() ) {
 418                 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
 419                         domain->name, domain->sequence_number,
 420                         (uint32)domain->last_seq_check));
 421                 return NT_STATUS_UNSUCCESSFUL;
 422         }
 423 
 424         DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n", 
 425                 domain->name, domain->sequence_number, 
 426                 (uint32)domain->last_seq_check));
 427 
 428         return NT_STATUS_OK;
 429 }
 430 
 431 static NTSTATUS store_cache_seqnum( struct winbindd_domain *domain )
     /* [<][>][^][v][top][bottom][index][help] */
 432 {
 433         TDB_DATA data;
 434         fstring key_str;
 435         uint8 buf[8];
 436         
 437         if (!wcache->tdb) {
 438                 DEBUG(10,("store_cache_seqnum: tdb == NULL\n"));
 439                 return NT_STATUS_UNSUCCESSFUL;
 440         }
 441                 
 442         fstr_sprintf( key_str, "SEQNUM/%s", domain->name );
 443         
 444         SIVAL(buf, 0, domain->sequence_number);
 445         SIVAL(buf, 4, domain->last_seq_check);
 446         data.dptr = buf;
 447         data.dsize = 8;
 448         
 449         if ( tdb_store_bystring( wcache->tdb, key_str, data, TDB_REPLACE) == -1 ) {
 450                 DEBUG(10,("store_cache_seqnum: tdb_store fail key [%s]\n", key_str ));
 451                 return NT_STATUS_UNSUCCESSFUL;
 452         }
 453 
 454         DEBUG(10,("store_cache_seqnum: success [%s][%u @ %u]\n", 
 455                 domain->name, domain->sequence_number, 
 456                 (uint32)domain->last_seq_check));
 457         
 458         return NT_STATUS_OK;
 459 }
 460 
 461 /*
 462   refresh the domain sequence number. If force is true
 463   then always refresh it, no matter how recently we fetched it
 464 */
 465 
 466 static void refresh_sequence_number(struct winbindd_domain *domain, bool force)
     /* [<][>][^][v][top][bottom][index][help] */
 467 {
 468         NTSTATUS status;
 469         unsigned time_diff;
 470         time_t t = time(NULL);
 471         unsigned cache_time = lp_winbind_cache_time();
 472 
 473         if ( IS_DOMAIN_OFFLINE(domain) ) {
 474                 return;
 475         }
 476         
 477         get_cache( domain );
 478 
 479 #if 0   /* JERRY -- disable as the default cache time is now 5 minutes */
 480         /* trying to reconnect is expensive, don't do it too often */
 481         if (domain->sequence_number == DOM_SEQUENCE_NONE) {
 482                 cache_time *= 8;
 483         }
 484 #endif
 485 
 486         time_diff = t - domain->last_seq_check;
 487 
 488         /* see if we have to refetch the domain sequence number */
 489         if (!force && (time_diff < cache_time) &&
 490                         (domain->sequence_number != DOM_SEQUENCE_NONE) &&
 491                         NT_STATUS_IS_OK(domain->last_status)) {
 492                 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
 493                 goto done;
 494         }
 495         
 496         /* try to get the sequence number from the tdb cache first */
 497         /* this will update the timestamp as well */
 498         
 499         status = fetch_cache_seqnum( domain, t );
 500         if (NT_STATUS_IS_OK(status) &&
 501                         (domain->sequence_number != DOM_SEQUENCE_NONE) &&
 502                         NT_STATUS_IS_OK(domain->last_status)) {
 503                 goto done;
 504         }
 505 
 506         /* important! make sure that we know if this is a native 
 507            mode domain or not.  And that we can contact it. */
 508 
 509         if ( winbindd_can_contact_domain( domain ) ) {          
 510                 status = domain->backend->sequence_number(domain, 
 511                                                           &domain->sequence_number);
 512         } else {
 513                 /* just use the current time */
 514                 status = NT_STATUS_OK;
 515                 domain->sequence_number = time(NULL);
 516         }
 517 
 518 
 519         /* the above call could have set our domain->backend to NULL when
 520          * coming from offline to online mode, make sure to reinitialize the
 521          * backend - Guenther */
 522         get_cache( domain );
 523 
 524         if (!NT_STATUS_IS_OK(status)) {
 525                 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status)));
 526                 domain->sequence_number = DOM_SEQUENCE_NONE;
 527         }
 528         
 529         domain->last_status = status;
 530         domain->last_seq_check = time(NULL);
 531         
 532         /* save the new sequence number in the cache */
 533         store_cache_seqnum( domain );
 534 
 535 done:
 536         DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n", 
 537                    domain->name, domain->sequence_number));
 538 
 539         return;
 540 }
 541 
 542 /*
 543   decide if a cache entry has expired
 544 */
 545 static bool centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
     /* [<][>][^][v][top][bottom][index][help] */
 546 {
 547         /* If we've been told to be offline - stay in that state... */
 548         if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
 549                 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
 550                         keystr, domain->name ));
 551                 return false;
 552         }
 553 
 554         /* when the domain is offline return the cached entry.
 555          * This deals with transient offline states... */
 556 
 557         if (!domain->online) {
 558                 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
 559                         keystr, domain->name ));
 560                 return false;
 561         }
 562 
 563         /* if the server is OK and our cache entry came from when it was down then
 564            the entry is invalid */
 565         if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&  
 566             (centry->sequence_number == DOM_SEQUENCE_NONE)) {
 567                 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
 568                         keystr, domain->name ));
 569                 return true;
 570         }
 571 
 572         /* if the server is down or the cache entry is not older than the
 573            current sequence number then it is OK */
 574         if (wcache_server_down(domain) || 
 575             centry->sequence_number == domain->sequence_number) {
 576                 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
 577                         keystr, domain->name ));
 578                 return false;
 579         }
 580 
 581         DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
 582                 keystr, domain->name ));
 583 
 584         /* it's expired */
 585         return true;
 586 }
 587 
 588 static struct cache_entry *wcache_fetch_raw(char *kstr)
     /* [<][>][^][v][top][bottom][index][help] */
 589 {
 590         TDB_DATA data;
 591         struct cache_entry *centry;
 592         TDB_DATA key;
 593 
 594         key = string_tdb_data(kstr);
 595         data = tdb_fetch(wcache->tdb, key);
 596         if (!data.dptr) {
 597                 /* a cache miss */
 598                 return NULL;
 599         }
 600 
 601         centry = SMB_XMALLOC_P(struct cache_entry);
 602         centry->data = (unsigned char *)data.dptr;
 603         centry->len = data.dsize;
 604         centry->ofs = 0;
 605 
 606         if (centry->len < 8) {
 607                 /* huh? corrupt cache? */
 608                 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr));
 609                 centry_free(centry);
 610                 return NULL;
 611         }
 612         
 613         centry->status = centry_ntstatus(centry);
 614         centry->sequence_number = centry_uint32(centry);
 615 
 616         return centry;
 617 }
 618 
 619 /*
 620   fetch an entry from the cache, with a varargs key. auto-fetch the sequence
 621   number and return status
 622 */
 623 static struct cache_entry *wcache_fetch(struct winbind_cache *cache, 
     /* [<][>][^][v][top][bottom][index][help] */
 624                                         struct winbindd_domain *domain,
 625                                         const char *format, ...) PRINTF_ATTRIBUTE(3,4);
 626 static struct cache_entry *wcache_fetch(struct winbind_cache *cache, 
 627                                         struct winbindd_domain *domain,
 628                                         const char *format, ...)
 629 {
 630         va_list ap;
 631         char *kstr;
 632         struct cache_entry *centry;
 633 
 634         if (!winbindd_use_cache()) {
 635                 return NULL;
 636         }
 637 
 638         refresh_sequence_number(domain, false);
 639 
 640         va_start(ap, format);
 641         smb_xvasprintf(&kstr, format, ap);
 642         va_end(ap);
 643 
 644         centry = wcache_fetch_raw(kstr);
 645         if (centry == NULL) {
 646                 free(kstr);
 647                 return NULL;
 648         }
 649 
 650         if (centry_expired(domain, kstr, centry)) {
 651 
 652                 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
 653                          kstr, domain->name ));
 654 
 655                 centry_free(centry);
 656                 free(kstr);
 657                 return NULL;
 658         }
 659 
 660         DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
 661                  kstr, domain->name ));
 662 
 663         free(kstr);
 664         return centry;
 665 }
 666 
 667 static void wcache_delete(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
     /* [<][>][^][v][top][bottom][index][help] */
 668 static void wcache_delete(const char *format, ...)
 669 {
 670         va_list ap;
 671         char *kstr;
 672         TDB_DATA key;
 673 
 674         va_start(ap, format);
 675         smb_xvasprintf(&kstr, format, ap);
 676         va_end(ap);
 677 
 678         key = string_tdb_data(kstr);
 679 
 680         tdb_delete(wcache->tdb, key);
 681         free(kstr);
 682 }
 683 
 684 /*
 685   make sure we have at least len bytes available in a centry 
 686 */
 687 static void centry_expand(struct cache_entry *centry, uint32 len)
     /* [<][>][^][v][top][bottom][index][help] */
 688 {
 689         if (centry->len - centry->ofs >= len)
 690                 return;
 691         centry->len *= 2;
 692         centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
 693                                          centry->len);
 694         if (!centry->data) {
 695                 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
 696                 smb_panic_fn("out of memory in centry_expand");
 697         }
 698 }
 699 
 700 /*
 701   push a uint32 into a centry 
 702 */
 703 static void centry_put_uint32(struct cache_entry *centry, uint32 v)
     /* [<][>][^][v][top][bottom][index][help] */
 704 {
 705         centry_expand(centry, 4);
 706         SIVAL(centry->data, centry->ofs, v);
 707         centry->ofs += 4;
 708 }
 709 
 710 /*
 711   push a uint16 into a centry 
 712 */
 713 static void centry_put_uint16(struct cache_entry *centry, uint16 v)
     /* [<][>][^][v][top][bottom][index][help] */
 714 {
 715         centry_expand(centry, 2);
 716         SIVAL(centry->data, centry->ofs, v);
 717         centry->ofs += 2;
 718 }
 719 
 720 /*
 721   push a uint8 into a centry 
 722 */
 723 static void centry_put_uint8(struct cache_entry *centry, uint8 v)
     /* [<][>][^][v][top][bottom][index][help] */
 724 {
 725         centry_expand(centry, 1);
 726         SCVAL(centry->data, centry->ofs, v);
 727         centry->ofs += 1;
 728 }
 729 
 730 /* 
 731    push a string into a centry 
 732  */
 733 static void centry_put_string(struct cache_entry *centry, const char *s)
     /* [<][>][^][v][top][bottom][index][help] */
 734 {
 735         int len;
 736 
 737         if (!s) {
 738                 /* null strings are marked as len 0xFFFF */
 739                 centry_put_uint8(centry, 0xFF);
 740                 return;
 741         }
 742 
 743         len = strlen(s);
 744         /* can't handle more than 254 char strings. Truncating is probably best */
 745         if (len > 254) {
 746                 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
 747                 len = 254;
 748         }
 749         centry_put_uint8(centry, len);
 750         centry_expand(centry, len);
 751         memcpy(centry->data + centry->ofs, s, len);
 752         centry->ofs += len;
 753 }
 754 
 755 /* 
 756    push a 16 byte hash into a centry - treat as 16 byte string.
 757  */
 758 static void centry_put_hash16(struct cache_entry *centry, const uint8 val[16])
     /* [<][>][^][v][top][bottom][index][help] */
 759 {
 760         centry_put_uint8(centry, 16);
 761         centry_expand(centry, 16);
 762         memcpy(centry->data + centry->ofs, val, 16);
 763         centry->ofs += 16;
 764 }
 765 
 766 static void centry_put_sid(struct cache_entry *centry, const DOM_SID *sid) 
     /* [<][>][^][v][top][bottom][index][help] */
 767 {
 768         fstring sid_string;
 769         centry_put_string(centry, sid_to_fstring(sid_string, sid));
 770 }
 771 
 772 
 773 /*
 774   put NTSTATUS into a centry
 775 */
 776 static void centry_put_ntstatus(struct cache_entry *centry, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 777 {
 778         uint32 status_value = NT_STATUS_V(status);
 779         centry_put_uint32(centry, status_value);
 780 }
 781 
 782 
 783 /*
 784   push a NTTIME into a centry 
 785 */
 786 static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
     /* [<][>][^][v][top][bottom][index][help] */
 787 {
 788         centry_expand(centry, 8);
 789         SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
 790         centry->ofs += 4;
 791         SIVAL(centry->data, centry->ofs, nt >> 32);
 792         centry->ofs += 4;
 793 }
 794 
 795 /*
 796   push a time_t into a centry - use a 64 bit size.
 797   NTTIME here is being used as a convenient 64-bit size.
 798 */
 799 static void centry_put_time(struct cache_entry *centry, time_t t)
     /* [<][>][^][v][top][bottom][index][help] */
 800 {
 801         NTTIME nt = (NTTIME)t;
 802         centry_put_nttime(centry, nt);
 803 }
 804 
 805 /*
 806   start a centry for output. When finished, call centry_end()
 807 */
 808 struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 809 {
 810         struct cache_entry *centry;
 811 
 812         if (!wcache->tdb)
 813                 return NULL;
 814 
 815         centry = SMB_XMALLOC_P(struct cache_entry);
 816 
 817         centry->len = 8192; /* reasonable default */
 818         centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);
 819         centry->ofs = 0;
 820         centry->sequence_number = domain->sequence_number;
 821         centry_put_ntstatus(centry, status);
 822         centry_put_uint32(centry, centry->sequence_number);
 823         return centry;
 824 }
 825 
 826 /*
 827   finish a centry and write it to the tdb
 828 */
 829 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
     /* [<][>][^][v][top][bottom][index][help] */
 830 static void centry_end(struct cache_entry *centry, const char *format, ...)
 831 {
 832         va_list ap;
 833         char *kstr;
 834         TDB_DATA key, data;
 835 
 836         if (!winbindd_use_cache()) {
 837                 return;
 838         }
 839 
 840         va_start(ap, format);
 841         smb_xvasprintf(&kstr, format, ap);
 842         va_end(ap);
 843 
 844         key = string_tdb_data(kstr);
 845         data.dptr = centry->data;
 846         data.dsize = centry->ofs;
 847 
 848         tdb_store(wcache->tdb, key, data, TDB_REPLACE);
 849         free(kstr);
 850 }
 851 
 852 static void wcache_save_name_to_sid(struct winbindd_domain *domain, 
     /* [<][>][^][v][top][bottom][index][help] */
 853                                     NTSTATUS status, const char *domain_name,
 854                                     const char *name, const DOM_SID *sid, 
 855                                     enum lsa_SidType type)
 856 {
 857         struct cache_entry *centry;
 858         fstring uname;
 859 
 860         centry = centry_start(domain, status);
 861         if (!centry)
 862                 return;
 863         centry_put_uint32(centry, type);
 864         centry_put_sid(centry, sid);
 865         fstrcpy(uname, name);
 866         strupper_m(uname);
 867         centry_end(centry, "NS/%s/%s", domain_name, uname);
 868         DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name,
 869                   uname, sid_string_dbg(sid), nt_errstr(status)));
 870         centry_free(centry);
 871 }
 872 
 873 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status, 
     /* [<][>][^][v][top][bottom][index][help] */
 874                                     const DOM_SID *sid, const char *domain_name, const char *name, enum lsa_SidType type)
 875 {
 876         struct cache_entry *centry;
 877         fstring sid_string;
 878 
 879         centry = centry_start(domain, status);
 880         if (!centry)
 881                 return;
 882 
 883         if (NT_STATUS_IS_OK(status)) {
 884                 centry_put_uint32(centry, type);
 885                 centry_put_string(centry, domain_name);
 886                 centry_put_string(centry, name);
 887         }
 888 
 889         centry_end(centry, "SN/%s", sid_to_fstring(sid_string, sid));
 890         DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string, 
 891                   name, nt_errstr(status)));
 892         centry_free(centry);
 893 }
 894 
 895 
 896 static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WINBIND_USERINFO *info)
     /* [<][>][^][v][top][bottom][index][help] */
 897 {
 898         struct cache_entry *centry;
 899         fstring sid_string;
 900 
 901         if (is_null_sid(&info->user_sid)) {
 902                 return;
 903         }
 904 
 905         centry = centry_start(domain, status);
 906         if (!centry)
 907                 return;
 908         centry_put_string(centry, info->acct_name);
 909         centry_put_string(centry, info->full_name);
 910         centry_put_string(centry, info->homedir);
 911         centry_put_string(centry, info->shell);
 912         centry_put_uint32(centry, info->primary_gid);
 913         centry_put_sid(centry, &info->user_sid);
 914         centry_put_sid(centry, &info->group_sid);
 915         centry_end(centry, "U/%s", sid_to_fstring(sid_string,
 916                                                   &info->user_sid));
 917         DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
 918         centry_free(centry);
 919 }
 920 
 921 static void wcache_save_lockout_policy(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
 922                                        NTSTATUS status,
 923                                        struct samr_DomInfo12 *lockout_policy)
 924 {
 925         struct cache_entry *centry;
 926 
 927         centry = centry_start(domain, status);
 928         if (!centry)
 929                 return;
 930 
 931         centry_put_nttime(centry, lockout_policy->lockout_duration);
 932         centry_put_nttime(centry, lockout_policy->lockout_window);
 933         centry_put_uint16(centry, lockout_policy->lockout_threshold);
 934 
 935         centry_end(centry, "LOC_POL/%s", domain->name);
 936 
 937         DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
 938 
 939         centry_free(centry);
 940 }
 941 
 942 
 943 
 944 static void wcache_save_password_policy(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
 945                                         NTSTATUS status,
 946                                         struct samr_DomInfo1 *policy)
 947 {
 948         struct cache_entry *centry;
 949 
 950         centry = centry_start(domain, status);
 951         if (!centry)
 952                 return;
 953 
 954         centry_put_uint16(centry, policy->min_password_length);
 955         centry_put_uint16(centry, policy->password_history_length);
 956         centry_put_uint32(centry, policy->password_properties);
 957         centry_put_nttime(centry, policy->max_password_age);
 958         centry_put_nttime(centry, policy->min_password_age);
 959 
 960         centry_end(centry, "PWD_POL/%s", domain->name);
 961 
 962         DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
 963 
 964         centry_free(centry);
 965 }
 966 
 967 /***************************************************************************
 968  ***************************************************************************/
 969 
 970 static void wcache_save_username_alias(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
 971                                        NTSTATUS status,
 972                                        const char *name, const char *alias)
 973 {
 974         struct cache_entry *centry;
 975         fstring uname;
 976 
 977         if ( (centry = centry_start(domain, status)) == NULL )
 978                 return;
 979 
 980         centry_put_string( centry, alias );
 981 
 982         fstrcpy(uname, name);
 983         strupper_m(uname);
 984         centry_end(centry, "NSS/NA/%s", uname);
 985 
 986         DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name, alias ));
 987 
 988         centry_free(centry);
 989 }
 990 
 991 static void wcache_save_alias_username(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
 992                                        NTSTATUS status,
 993                                        const char *alias, const char *name)
 994 {
 995         struct cache_entry *centry;
 996         fstring uname;
 997 
 998         if ( (centry = centry_start(domain, status)) == NULL )
 999                 return;
1000 
1001         centry_put_string( centry, name );
1002 
1003         fstrcpy(uname, alias);
1004         strupper_m(uname);
1005         centry_end(centry, "NSS/AN/%s", uname);
1006 
1007         DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias, name ));
1008 
1009         centry_free(centry);
1010 }
1011 
1012 /***************************************************************************
1013  ***************************************************************************/
1014 
1015 NTSTATUS resolve_username_to_alias( TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1016                                     struct winbindd_domain *domain,
1017                                     const char *name, char **alias )
1018 {
1019         struct winbind_cache *cache = get_cache(domain);
1020         struct cache_entry *centry = NULL;
1021         NTSTATUS status;
1022         char *upper_name;
1023 
1024         if ( domain->internal )
1025                 return NT_STATUS_NOT_SUPPORTED;
1026 
1027         if (!cache->tdb)
1028                 goto do_query;
1029 
1030         if ( (upper_name = SMB_STRDUP(name)) == NULL )
1031                 return NT_STATUS_NO_MEMORY;
1032         strupper_m(upper_name);
1033 
1034         centry = wcache_fetch(cache, domain, "NSS/NA/%s", upper_name);
1035 
1036         SAFE_FREE( upper_name );
1037 
1038         if (!centry)
1039                 goto do_query;
1040 
1041         status = centry->status;
1042 
1043         if (!NT_STATUS_IS_OK(status)) {
1044                 centry_free(centry);
1045                 return status;
1046         }
1047 
1048         *alias = centry_string( centry, mem_ctx );
1049 
1050         centry_free(centry);
1051 
1052         DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1053                   name, *alias ? *alias : "(none)"));
1054 
1055         return (*alias) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1056 
1057 do_query:
1058 
1059         /* If its not in cache and we are offline, then fail */
1060 
1061         if ( get_global_winbindd_state_offline() || !domain->online ) {
1062                 DEBUG(8,("resolve_username_to_alias: rejecting query "
1063                          "in offline mode\n"));
1064                 return NT_STATUS_NOT_FOUND;
1065         }
1066 
1067         status = nss_map_to_alias( mem_ctx, domain->name, name, alias );
1068 
1069         if ( NT_STATUS_IS_OK( status ) ) {
1070                 wcache_save_username_alias(domain, status, name, *alias);
1071         }
1072 
1073         if ( NT_STATUS_EQUAL( status, NT_STATUS_NONE_MAPPED ) ) {
1074                 wcache_save_username_alias(domain, status, name, "(NULL)");
1075         }
1076 
1077         DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1078                  nt_errstr(status)));
1079 
1080         if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1081                 set_domain_offline( domain );
1082         }
1083 
1084         return status;
1085 }
1086 
1087 /***************************************************************************
1088  ***************************************************************************/
1089 
1090 NTSTATUS resolve_alias_to_username( TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1091                                     struct winbindd_domain *domain,
1092                                     const char *alias, char **name )
1093 {
1094         struct winbind_cache *cache = get_cache(domain);
1095         struct cache_entry *centry = NULL;
1096         NTSTATUS status;
1097         char *upper_name;
1098 
1099         if ( domain->internal )
1100                 return  NT_STATUS_NOT_SUPPORTED;
1101 
1102         if (!cache->tdb)
1103                 goto do_query;
1104 
1105         if ( (upper_name = SMB_STRDUP(alias)) == NULL )
1106                 return NT_STATUS_NO_MEMORY;
1107         strupper_m(upper_name);
1108 
1109         centry = wcache_fetch(cache, domain, "NSS/AN/%s", upper_name);
1110 
1111         SAFE_FREE( upper_name );
1112 
1113         if (!centry)
1114                 goto do_query;
1115 
1116         status = centry->status;
1117 
1118         if (!NT_STATUS_IS_OK(status)) {
1119                 centry_free(centry);
1120                 return status;
1121         }
1122 
1123         *name = centry_string( centry, mem_ctx );
1124 
1125         centry_free(centry);
1126 
1127         DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1128                   alias, *name ? *name : "(none)"));
1129 
1130         return (*name) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1131 
1132 do_query:
1133 
1134         /* If its not in cache and we are offline, then fail */
1135 
1136         if ( get_global_winbindd_state_offline() || !domain->online ) {
1137                 DEBUG(8,("resolve_alias_to_username: rejecting query "
1138                          "in offline mode\n"));
1139                 return NT_STATUS_NOT_FOUND;
1140         }
1141 
1142         /* an alias cannot contain a domain prefix or '@' */
1143 
1144         if (strchr(alias, '\\') || strchr(alias, '@')) {
1145                 DEBUG(10,("resolve_alias_to_username: skipping fully "
1146                           "qualified name %s\n", alias));
1147                 return NT_STATUS_OBJECT_NAME_INVALID;
1148         }
1149 
1150         status = nss_map_from_alias( mem_ctx, domain->name, alias, name );
1151 
1152         if ( NT_STATUS_IS_OK( status ) ) {
1153                 wcache_save_alias_username( domain, status, alias, *name );
1154         }
1155 
1156         if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1157                 wcache_save_alias_username(domain, status, alias, "(NULL)");
1158         }
1159 
1160         DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1161                  nt_errstr(status)));
1162 
1163         if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1164                 set_domain_offline( domain );
1165         }
1166 
1167         return status;
1168 }
1169 
1170 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const DOM_SID *sid)
     /* [<][>][^][v][top][bottom][index][help] */
1171 {
1172         struct winbind_cache *cache = get_cache(domain);
1173         TDB_DATA data;
1174         fstring key_str, tmp;
1175         uint32 rid;
1176 
1177         if (!cache->tdb) {
1178                 return NT_STATUS_INTERNAL_DB_ERROR;
1179         }
1180 
1181         if (is_null_sid(sid)) {
1182                 return NT_STATUS_INVALID_SID;
1183         }
1184 
1185         if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1186                 return NT_STATUS_INVALID_SID;
1187         }
1188 
1189         fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
1190 
1191         data = tdb_fetch(cache->tdb, string_tdb_data(key_str));
1192         if (!data.dptr) {
1193                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1194         }
1195 
1196         SAFE_FREE(data.dptr);
1197         return NT_STATUS_OK;
1198 }
1199 
1200 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1201    as new salted ones. */
1202 
1203 NTSTATUS wcache_get_creds(struct winbindd_domain *domain, 
     /* [<][>][^][v][top][bottom][index][help] */
1204                           TALLOC_CTX *mem_ctx, 
1205                           const DOM_SID *sid,
1206                           const uint8 **cached_nt_pass,
1207                           const uint8 **cached_salt)
1208 {
1209         struct winbind_cache *cache = get_cache(domain);
1210         struct cache_entry *centry = NULL;
1211         NTSTATUS status;
1212         time_t t;
1213         uint32 rid;
1214         fstring tmp;
1215 
1216         if (!cache->tdb) {
1217                 return NT_STATUS_INTERNAL_DB_ERROR;
1218         }
1219 
1220         if (is_null_sid(sid)) {
1221                 return NT_STATUS_INVALID_SID;
1222         }
1223 
1224         if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1225                 return NT_STATUS_INVALID_SID;
1226         }
1227 
1228         /* Try and get a salted cred first. If we can't
1229            fall back to an unsalted cred. */
1230 
1231         centry = wcache_fetch(cache, domain, "CRED/%s",
1232                               sid_to_fstring(tmp, sid));
1233         if (!centry) {
1234                 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n", 
1235                           sid_string_dbg(sid)));
1236                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1237         }
1238 
1239         t = centry_time(centry);
1240 
1241         /* In the salted case this isn't actually the nt_hash itself,
1242            but the MD5 of the salt + nt_hash. Let the caller
1243            sort this out. It can tell as we only return the cached_salt
1244            if we are returning a salted cred. */
1245 
1246         *cached_nt_pass = (const uint8 *)centry_hash16(centry, mem_ctx);
1247         if (*cached_nt_pass == NULL) {
1248                 fstring sidstr;
1249 
1250                 sid_to_fstring(sidstr, sid);
1251 
1252                 /* Bad (old) cred cache. Delete and pretend we
1253                    don't have it. */
1254                 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n", 
1255                                 sidstr));
1256                 wcache_delete("CRED/%s", sidstr);
1257                 centry_free(centry);
1258                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1259         }
1260 
1261         /* We only have 17 bytes more data in the salted cred case. */
1262         if (centry->len - centry->ofs == 17) {
1263                 *cached_salt = (const uint8 *)centry_hash16(centry, mem_ctx);
1264         } else {
1265                 *cached_salt = NULL;
1266         }
1267 
1268         dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
1269         if (*cached_salt) {
1270                 dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
1271         }
1272 
1273         status = centry->status;
1274 
1275         DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1276                   sid_string_dbg(sid), nt_errstr(status) ));
1277 
1278         centry_free(centry);
1279         return status;
1280 }
1281 
1282 /* Store creds for a SID - only writes out new salted ones. */
1283 
1284 NTSTATUS wcache_save_creds(struct winbindd_domain *domain, 
     /* [<][>][^][v][top][bottom][index][help] */
1285                            TALLOC_CTX *mem_ctx, 
1286                            const DOM_SID *sid, 
1287                            const uint8 nt_pass[NT_HASH_LEN])
1288 {
1289         struct cache_entry *centry;
1290         fstring sid_string;
1291         uint32 rid;
1292         uint8 cred_salt[NT_HASH_LEN];
1293         uint8 salted_hash[NT_HASH_LEN];
1294 
1295         if (is_null_sid(sid)) {
1296                 return NT_STATUS_INVALID_SID;
1297         }
1298 
1299         if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1300                 return NT_STATUS_INVALID_SID;
1301         }
1302 
1303         centry = centry_start(domain, NT_STATUS_OK);
1304         if (!centry) {
1305                 return NT_STATUS_INTERNAL_DB_ERROR;
1306         }
1307 
1308         dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1309 
1310         centry_put_time(centry, time(NULL));
1311 
1312         /* Create a salt and then salt the hash. */
1313         generate_random_buffer(cred_salt, NT_HASH_LEN);
1314         E_md5hash(cred_salt, nt_pass, salted_hash);
1315 
1316         centry_put_hash16(centry, salted_hash);
1317         centry_put_hash16(centry, cred_salt);
1318         centry_end(centry, "CRED/%s", sid_to_fstring(sid_string, sid));
1319 
1320         DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1321 
1322         centry_free(centry);
1323 
1324         return NT_STATUS_OK;
1325 }
1326 
1327 
1328 /* Query display info. This is the basic user list fn */
1329 static NTSTATUS query_user_list(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
1330                                 TALLOC_CTX *mem_ctx,
1331                                 uint32 *num_entries, 
1332                                 WINBIND_USERINFO **info)
1333 {
1334         struct winbind_cache *cache = get_cache(domain);
1335         struct cache_entry *centry = NULL;
1336         NTSTATUS status;
1337         unsigned int i, retry;
1338 
1339         if (!cache->tdb)
1340                 goto do_query;
1341 
1342         centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1343         if (!centry)
1344                 goto do_query;
1345 
1346         *num_entries = centry_uint32(centry);
1347         
1348         if (*num_entries == 0)
1349                 goto do_cached;
1350 
1351         (*info) = TALLOC_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
1352         if (! (*info)) {
1353                 smb_panic_fn("query_user_list out of memory");
1354         }
1355         for (i=0; i<(*num_entries); i++) {
1356                 (*info)[i].acct_name = centry_string(centry, mem_ctx);
1357                 (*info)[i].full_name = centry_string(centry, mem_ctx);
1358                 (*info)[i].homedir = centry_string(centry, mem_ctx);
1359                 (*info)[i].shell = centry_string(centry, mem_ctx);
1360                 centry_sid(centry, mem_ctx, &(*info)[i].user_sid);
1361                 centry_sid(centry, mem_ctx, &(*info)[i].group_sid);
1362         }
1363 
1364 do_cached:      
1365         status = centry->status;
1366 
1367         DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1368                 domain->name, nt_errstr(status) ));
1369 
1370         centry_free(centry);
1371         return status;
1372 
1373 do_query:
1374         *num_entries = 0;
1375         *info = NULL;
1376 
1377         /* Return status value returned by seq number check */
1378 
1379         if (!NT_STATUS_IS_OK(domain->last_status))
1380                 return domain->last_status;
1381 
1382         /* Put the query_user_list() in a retry loop.  There appears to be
1383          * some bug either with Windows 2000 or Samba's handling of large
1384          * rpc replies.  This manifests itself as sudden disconnection
1385          * at a random point in the enumeration of a large (60k) user list.
1386          * The retry loop simply tries the operation again. )-:  It's not
1387          * pretty but an acceptable workaround until we work out what the
1388          * real problem is. */
1389 
1390         retry = 0;
1391         do {
1392 
1393                 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1394                         domain->name ));
1395 
1396                 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
1397                 if (!NT_STATUS_IS_OK(status)) {
1398                         DEBUG(3, ("query_user_list: returned 0x%08x, "
1399                                   "retrying\n", NT_STATUS_V(status)));
1400                 }
1401                 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1402                         DEBUG(3, ("query_user_list: flushing "
1403                                   "connection cache\n"));
1404                         invalidate_cm_connection(&domain->conn);
1405                 }
1406 
1407         } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) && 
1408                  (retry++ < 5));
1409 
1410         /* and save it */
1411         refresh_sequence_number(domain, false);
1412         centry = centry_start(domain, status);
1413         if (!centry)
1414                 goto skip_save;
1415         centry_put_uint32(centry, *num_entries);
1416         for (i=0; i<(*num_entries); i++) {
1417                 centry_put_string(centry, (*info)[i].acct_name);
1418                 centry_put_string(centry, (*info)[i].full_name);
1419                 centry_put_string(centry, (*info)[i].homedir);
1420                 centry_put_string(centry, (*info)[i].shell);
1421                 centry_put_sid(centry, &(*info)[i].user_sid);
1422                 centry_put_sid(centry, &(*info)[i].group_sid);
1423                 if (domain->backend && domain->backend->consistent) {
1424                         /* when the backend is consistent we can pre-prime some mappings */
1425                         wcache_save_name_to_sid(domain, NT_STATUS_OK, 
1426                                                 domain->name,
1427                                                 (*info)[i].acct_name, 
1428                                                 &(*info)[i].user_sid,
1429                                                 SID_NAME_USER);
1430                         wcache_save_sid_to_name(domain, NT_STATUS_OK, 
1431                                                 &(*info)[i].user_sid,
1432                                                 domain->name,
1433                                                 (*info)[i].acct_name, 
1434                                                 SID_NAME_USER);
1435                         wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
1436                 }
1437         }       
1438         centry_end(centry, "UL/%s", domain->name);
1439         centry_free(centry);
1440 
1441 skip_save:
1442         return status;
1443 }
1444 
1445 /* list all domain groups */
1446 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
1447                                 TALLOC_CTX *mem_ctx,
1448                                 uint32 *num_entries, 
1449                                 struct acct_info **info)
1450 {
1451         struct winbind_cache *cache = get_cache(domain);
1452         struct cache_entry *centry = NULL;
1453         NTSTATUS status;
1454         unsigned int i;
1455 
1456         if (!cache->tdb)
1457                 goto do_query;
1458 
1459         centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1460         if (!centry)
1461                 goto do_query;
1462 
1463         *num_entries = centry_uint32(centry);
1464         
1465         if (*num_entries == 0)
1466                 goto do_cached;
1467 
1468         (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1469         if (! (*info)) {
1470                 smb_panic_fn("enum_dom_groups out of memory");
1471         }
1472         for (i=0; i<(*num_entries); i++) {
1473                 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1474                 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1475                 (*info)[i].rid = centry_uint32(centry);
1476         }
1477 
1478 do_cached:      
1479         status = centry->status;
1480 
1481         DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1482                 domain->name, nt_errstr(status) ));
1483 
1484         centry_free(centry);
1485         return status;
1486 
1487 do_query:
1488         *num_entries = 0;
1489         *info = NULL;
1490 
1491         /* Return status value returned by seq number check */
1492 
1493         if (!NT_STATUS_IS_OK(domain->last_status))
1494                 return domain->last_status;
1495 
1496         DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1497                 domain->name ));
1498 
1499         status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1500 
1501         /* and save it */
1502         refresh_sequence_number(domain, false);
1503         centry = centry_start(domain, status);
1504         if (!centry)
1505                 goto skip_save;
1506         centry_put_uint32(centry, *num_entries);
1507         for (i=0; i<(*num_entries); i++) {
1508                 centry_put_string(centry, (*info)[i].acct_name);
1509                 centry_put_string(centry, (*info)[i].acct_desc);
1510                 centry_put_uint32(centry, (*info)[i].rid);
1511         }       
1512         centry_end(centry, "GL/%s/domain", domain->name);
1513         centry_free(centry);
1514 
1515 skip_save:
1516         return status;
1517 }
1518 
1519 /* list all domain groups */
1520 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
1521                                 TALLOC_CTX *mem_ctx,
1522                                 uint32 *num_entries, 
1523                                 struct acct_info **info)
1524 {
1525         struct winbind_cache *cache = get_cache(domain);
1526         struct cache_entry *centry = NULL;
1527         NTSTATUS status;
1528         unsigned int i;
1529 
1530         if (!cache->tdb)
1531                 goto do_query;
1532 
1533         centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1534         if (!centry)
1535                 goto do_query;
1536 
1537         *num_entries = centry_uint32(centry);
1538         
1539         if (*num_entries == 0)
1540                 goto do_cached;
1541 
1542         (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1543         if (! (*info)) {
1544                 smb_panic_fn("enum_dom_groups out of memory");
1545         }
1546         for (i=0; i<(*num_entries); i++) {
1547                 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1548                 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1549                 (*info)[i].rid = centry_uint32(centry);
1550         }
1551 
1552 do_cached:      
1553 
1554         /* If we are returning cached data and the domain controller
1555            is down then we don't know whether the data is up to date
1556            or not.  Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1557            indicate this. */
1558 
1559         if (wcache_server_down(domain)) {
1560                 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1561                 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1562         } else
1563                 status = centry->status;
1564 
1565         DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1566                 domain->name, nt_errstr(status) ));
1567 
1568         centry_free(centry);
1569         return status;
1570 
1571 do_query:
1572         *num_entries = 0;
1573         *info = NULL;
1574 
1575         /* Return status value returned by seq number check */
1576 
1577         if (!NT_STATUS_IS_OK(domain->last_status))
1578                 return domain->last_status;
1579 
1580         DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1581                 domain->name ));
1582 
1583         status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1584 
1585         /* and save it */
1586         refresh_sequence_number(domain, false);
1587         centry = centry_start(domain, status);
1588         if (!centry)
1589                 goto skip_save;
1590         centry_put_uint32(centry, *num_entries);
1591         for (i=0; i<(*num_entries); i++) {
1592                 centry_put_string(centry, (*info)[i].acct_name);
1593                 centry_put_string(centry, (*info)[i].acct_desc);
1594                 centry_put_uint32(centry, (*info)[i].rid);
1595         }
1596         centry_end(centry, "GL/%s/local", domain->name);
1597         centry_free(centry);
1598 
1599 skip_save:
1600         return status;
1601 }
1602 
1603 /* convert a single name to a sid in a domain */
1604 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
1605                             TALLOC_CTX *mem_ctx,
1606                             enum winbindd_cmd orig_cmd,
1607                             const char *domain_name,
1608                             const char *name,
1609                             DOM_SID *sid,
1610                             enum lsa_SidType *type)
1611 {
1612         struct winbind_cache *cache = get_cache(domain);
1613         struct cache_entry *centry = NULL;
1614         NTSTATUS status;
1615         fstring uname;
1616 
1617         if (!cache->tdb)
1618                 goto do_query;
1619 
1620         fstrcpy(uname, name);
1621         strupper_m(uname);
1622         centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1623         if (!centry)
1624                 goto do_query;
1625 
1626         status = centry->status;
1627         if (NT_STATUS_IS_OK(status)) {
1628                 *type = (enum lsa_SidType)centry_uint32(centry);
1629                 centry_sid(centry, mem_ctx, sid);
1630         }
1631 
1632         DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n",
1633                 domain->name, nt_errstr(status) ));
1634 
1635         centry_free(centry);
1636         return status;
1637 
1638 do_query:
1639         ZERO_STRUCTP(sid);
1640 
1641         /* If the seq number check indicated that there is a problem
1642          * with this DC, then return that status... except for
1643          * access_denied.  This is special because the dc may be in
1644          * "restrict anonymous = 1" mode, in which case it will deny
1645          * most unauthenticated operations, but *will* allow the LSA
1646          * name-to-sid that we try as a fallback. */
1647 
1648         if (!(NT_STATUS_IS_OK(domain->last_status)
1649               || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1650                 return domain->last_status;
1651 
1652         DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1653                 domain->name ));
1654 
1655         status = domain->backend->name_to_sid(domain, mem_ctx, orig_cmd, 
1656                                               domain_name, name, sid, type);
1657 
1658         /* and save it */
1659         refresh_sequence_number(domain, false);
1660 
1661         if (domain->online &&
1662             (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1663                 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1664 
1665                 /* Only save the reverse mapping if this was not a UPN */
1666                 if (!strchr(name, '@')) {
1667                         strupper_m(CONST_DISCARD(char *,domain_name));
1668                         strlower_m(CONST_DISCARD(char *,name));
1669                         wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1670                 }
1671         }
1672         
1673         return status;
1674 }
1675 
1676 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1677    given */
1678 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
1679                             TALLOC_CTX *mem_ctx,
1680                             const DOM_SID *sid,
1681                             char **domain_name,
1682                             char **name,
1683                             enum lsa_SidType *type)
1684 {
1685         struct winbind_cache *cache = get_cache(domain);
1686         struct cache_entry *centry = NULL;
1687         NTSTATUS status;
1688         fstring sid_string;
1689 
1690         if (!cache->tdb)
1691                 goto do_query;
1692 
1693         centry = wcache_fetch(cache, domain, "SN/%s",
1694                               sid_to_fstring(sid_string, sid));
1695         if (!centry)
1696                 goto do_query;
1697 
1698         status = centry->status;
1699         if (NT_STATUS_IS_OK(status)) {
1700                 *type = (enum lsa_SidType)centry_uint32(centry);
1701                 *domain_name = centry_string(centry, mem_ctx);
1702                 *name = centry_string(centry, mem_ctx);
1703         }
1704 
1705         DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: %s\n",
1706                 domain->name, nt_errstr(status) ));
1707 
1708         centry_free(centry);
1709         return status;
1710 
1711 do_query:
1712         *name = NULL;
1713         *domain_name = NULL;
1714 
1715         /* If the seq number check indicated that there is a problem
1716          * with this DC, then return that status... except for
1717          * access_denied.  This is special because the dc may be in
1718          * "restrict anonymous = 1" mode, in which case it will deny
1719          * most unauthenticated operations, but *will* allow the LSA
1720          * sid-to-name that we try as a fallback. */
1721 
1722         if (!(NT_STATUS_IS_OK(domain->last_status)
1723               || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1724                 return domain->last_status;
1725 
1726         DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1727                 domain->name ));
1728 
1729         status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1730 
1731         /* and save it */
1732         refresh_sequence_number(domain, false);
1733         wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1734 
1735         /* We can't save the name to sid mapping here, as with sid history a
1736          * later name2sid would give the wrong sid. */
1737 
1738         return status;
1739 }
1740 
1741 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
1742                               TALLOC_CTX *mem_ctx,
1743                               const DOM_SID *domain_sid,
1744                               uint32 *rids,
1745                               size_t num_rids,
1746                               char **domain_name,
1747                               char ***names,
1748                               enum lsa_SidType **types)
1749 {
1750         struct winbind_cache *cache = get_cache(domain);
1751         size_t i;
1752         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1753         bool have_mapped;
1754         bool have_unmapped;
1755 
1756         *domain_name = NULL;
1757         *names = NULL;
1758         *types = NULL;
1759 
1760         if (!cache->tdb) {
1761                 goto do_query;
1762         }
1763 
1764         if (num_rids == 0) {
1765                 return NT_STATUS_OK;
1766         }
1767 
1768         *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
1769         *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
1770 
1771         if ((*names == NULL) || (*types == NULL)) {
1772                 result = NT_STATUS_NO_MEMORY;
1773                 goto error;
1774         }
1775 
1776         have_mapped = have_unmapped = false;
1777 
1778         for (i=0; i<num_rids; i++) {
1779                 DOM_SID sid;
1780                 struct cache_entry *centry;
1781                 fstring tmp;
1782 
1783                 if (!sid_compose(&sid, domain_sid, rids[i])) {
1784                         result = NT_STATUS_INTERNAL_ERROR;
1785                         goto error;
1786                 }
1787 
1788                 centry = wcache_fetch(cache, domain, "SN/%s",
1789                                       sid_to_fstring(tmp, &sid));
1790                 if (!centry) {
1791                         goto do_query;
1792                 }
1793 
1794                 (*types)[i] = SID_NAME_UNKNOWN;
1795                 (*names)[i] = talloc_strdup(*names, "");
1796 
1797                 if (NT_STATUS_IS_OK(centry->status)) {
1798                         char *dom;
1799                         have_mapped = true;
1800                         (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
1801 
1802                         dom = centry_string(centry, mem_ctx);
1803                         if (*domain_name == NULL) {
1804                                 *domain_name = dom;
1805                         } else {
1806                                 talloc_free(dom);
1807                         }
1808 
1809                         (*names)[i] = centry_string(centry, *names);
1810 
1811                 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
1812                         have_unmapped = true;
1813 
1814                 } else {
1815                         /* something's definitely wrong */
1816                         result = centry->status;
1817                         goto error;
1818                 }
1819 
1820                 centry_free(centry);
1821         }
1822 
1823         if (!have_mapped) {
1824                 return NT_STATUS_NONE_MAPPED;
1825         }
1826         if (!have_unmapped) {
1827                 return NT_STATUS_OK;
1828         }
1829         return STATUS_SOME_UNMAPPED;
1830 
1831  do_query:
1832 
1833         TALLOC_FREE(*names);
1834         TALLOC_FREE(*types);
1835 
1836         result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
1837                                                 rids, num_rids, domain_name,
1838                                                 names, types);
1839 
1840         /*
1841           None of the queried rids has been found so save all negative entries
1842         */
1843         if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
1844                 for (i = 0; i < num_rids; i++) {
1845                         DOM_SID sid;
1846                         const char *name = "";
1847                         const enum lsa_SidType type = SID_NAME_UNKNOWN;
1848                         NTSTATUS status = NT_STATUS_NONE_MAPPED;
1849                         
1850                         if (!sid_compose(&sid, domain_sid, rids[i])) {
1851                                 return NT_STATUS_INTERNAL_ERROR;
1852                         }
1853 
1854                         wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1855                                                 name, type);
1856                 }
1857 
1858                 return result;
1859         }
1860 
1861         /*
1862           Some or all of the queried rids have been found.
1863         */
1864         if (!NT_STATUS_IS_OK(result) &&
1865             !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
1866                 return result;
1867         }
1868 
1869         refresh_sequence_number(domain, false);
1870 
1871         for (i=0; i<num_rids; i++) {
1872                 DOM_SID sid;
1873                 NTSTATUS status;
1874 
1875                 if (!sid_compose(&sid, domain_sid, rids[i])) {
1876                         result = NT_STATUS_INTERNAL_ERROR;
1877                         goto error;
1878                 }
1879 
1880                 status = (*types)[i] == SID_NAME_UNKNOWN ?
1881                         NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
1882 
1883                 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1884                                         (*names)[i], (*types)[i]);
1885         }
1886 
1887         return result;
1888 
1889  error:
1890         
1891         TALLOC_FREE(*names);
1892         TALLOC_FREE(*types);
1893         return result;
1894 }
1895 
1896 /* Lookup user information from a rid */
1897 static NTSTATUS query_user(struct winbindd_domain *domain, 
     /* [<][>][^][v][top][bottom][index][help] */
1898                            TALLOC_CTX *mem_ctx, 
1899                            const DOM_SID *user_sid, 
1900                            WINBIND_USERINFO *info)
1901 {
1902         struct winbind_cache *cache = get_cache(domain);
1903         struct cache_entry *centry = NULL;
1904         NTSTATUS status;
1905         fstring tmp;
1906 
1907         if (!cache->tdb)
1908                 goto do_query;
1909 
1910         centry = wcache_fetch(cache, domain, "U/%s",
1911                               sid_to_fstring(tmp, user_sid));
1912         
1913         /* If we have an access denied cache entry and a cached info3 in the
1914            samlogon cache then do a query.  This will force the rpc back end
1915            to return the info3 data. */
1916 
1917         if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1918             netsamlogon_cache_have(user_sid)) {
1919                 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1920                 domain->last_status = NT_STATUS_OK;
1921                 centry_free(centry);
1922                 goto do_query;
1923         }
1924         
1925         if (!centry)
1926                 goto do_query;
1927         
1928         /* if status is not ok then this is a negative hit
1929            and the rest of the data doesn't matter */
1930         status = centry->status;
1931         if (NT_STATUS_IS_OK(status)) {
1932                 info->acct_name = centry_string(centry, mem_ctx);
1933                 info->full_name = centry_string(centry, mem_ctx);
1934                 info->homedir = centry_string(centry, mem_ctx);
1935                 info->shell = centry_string(centry, mem_ctx);
1936                 info->primary_gid = centry_uint32(centry);
1937                 centry_sid(centry, mem_ctx, &info->user_sid);
1938                 centry_sid(centry, mem_ctx, &info->group_sid);
1939         }
1940 
1941         DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
1942                 domain->name, nt_errstr(status) ));
1943 
1944         centry_free(centry);
1945         return status;
1946 
1947 do_query:
1948         ZERO_STRUCTP(info);
1949 
1950         /* Return status value returned by seq number check */
1951 
1952         if (!NT_STATUS_IS_OK(domain->last_status))
1953                 return domain->last_status;
1954         
1955         DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
1956                 domain->name ));
1957 
1958         status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
1959 
1960         /* and save it */
1961         refresh_sequence_number(domain, false);
1962         wcache_save_user(domain, status, info);
1963 
1964         return status;
1965 }
1966 
1967 
1968 /* Lookup groups a user is a member of. */
1969 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
1970                                   TALLOC_CTX *mem_ctx,
1971                                   const DOM_SID *user_sid, 
1972                                   uint32 *num_groups, DOM_SID **user_gids)
1973 {
1974         struct winbind_cache *cache = get_cache(domain);
1975         struct cache_entry *centry = NULL;
1976         NTSTATUS status;
1977         unsigned int i;
1978         fstring sid_string;
1979 
1980         if (!cache->tdb)
1981                 goto do_query;
1982 
1983         centry = wcache_fetch(cache, domain, "UG/%s",
1984                               sid_to_fstring(sid_string, user_sid));
1985         
1986         /* If we have an access denied cache entry and a cached info3 in the
1987            samlogon cache then do a query.  This will force the rpc back end
1988            to return the info3 data. */
1989 
1990         if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1991             netsamlogon_cache_have(user_sid)) {
1992                 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
1993                 domain->last_status = NT_STATUS_OK;
1994                 centry_free(centry);
1995                 goto do_query;
1996         }
1997         
1998         if (!centry)
1999                 goto do_query;
2000 
2001         *num_groups = centry_uint32(centry);
2002         
2003         if (*num_groups == 0)
2004                 goto do_cached;
2005 
2006         (*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
2007         if (! (*user_gids)) {
2008                 smb_panic_fn("lookup_usergroups out of memory");
2009         }
2010         for (i=0; i<(*num_groups); i++) {
2011                 centry_sid(centry, mem_ctx, &(*user_gids)[i]);
2012         }
2013 
2014 do_cached:      
2015         status = centry->status;
2016 
2017         DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
2018                 domain->name, nt_errstr(status) ));
2019 
2020         centry_free(centry);
2021         return status;
2022 
2023 do_query:
2024         (*num_groups) = 0;
2025         (*user_gids) = NULL;
2026 
2027         /* Return status value returned by seq number check */
2028 
2029         if (!NT_STATUS_IS_OK(domain->last_status))
2030                 return domain->last_status;
2031 
2032         DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2033                 domain->name ));
2034 
2035         status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
2036 
2037         if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
2038                 goto skip_save;
2039         
2040         /* and save it */
2041         refresh_sequence_number(domain, false);
2042         centry = centry_start(domain, status);
2043         if (!centry)
2044                 goto skip_save;
2045 
2046         centry_put_uint32(centry, *num_groups);
2047         for (i=0; i<(*num_groups); i++) {
2048                 centry_put_sid(centry, &(*user_gids)[i]);
2049         }       
2050 
2051         centry_end(centry, "UG/%s", sid_to_fstring(sid_string, user_sid));
2052         centry_free(centry);
2053 
2054 skip_save:
2055         return status;
2056 }
2057 
2058 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
2059                                    TALLOC_CTX *mem_ctx,
2060                                    uint32 num_sids, const DOM_SID *sids,
2061                                    uint32 *num_aliases, uint32 **alias_rids)
2062 {
2063         struct winbind_cache *cache = get_cache(domain);
2064         struct cache_entry *centry = NULL;
2065         NTSTATUS status;
2066         char *sidlist = talloc_strdup(mem_ctx, "");
2067         int i;
2068 
2069         if (!cache->tdb)
2070                 goto do_query;
2071 
2072         if (num_sids == 0) {
2073                 *num_aliases = 0;
2074                 *alias_rids = NULL;
2075                 return NT_STATUS_OK;
2076         }
2077 
2078         /* We need to cache indexed by the whole list of SIDs, the aliases
2079          * resulting might come from any of the SIDs. */
2080 
2081         for (i=0; i<num_sids; i++) {
2082                 fstring tmp;
2083                 sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist,
2084                                           sid_to_fstring(tmp, &sids[i]));
2085                 if (sidlist == NULL)
2086                         return NT_STATUS_NO_MEMORY;
2087         }
2088 
2089         centry = wcache_fetch(cache, domain, "UA%s", sidlist);
2090 
2091         if (!centry)
2092                 goto do_query;
2093 
2094         *num_aliases = centry_uint32(centry);
2095         *alias_rids = NULL;
2096 
2097         if (*num_aliases) {
2098                 (*alias_rids) = TALLOC_ARRAY(mem_ctx, uint32, *num_aliases);
2099 
2100                 if ((*alias_rids) == NULL) {
2101                         centry_free(centry);
2102                         return NT_STATUS_NO_MEMORY;
2103                 }
2104         } else {
2105                 (*alias_rids) = NULL;
2106         }
2107 
2108         for (i=0; i<(*num_aliases); i++)
2109                 (*alias_rids)[i] = centry_uint32(centry);
2110 
2111         status = centry->status;
2112 
2113         DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2114                   "status %s\n", domain->name, nt_errstr(status)));
2115 
2116         centry_free(centry);
2117         return status;
2118 
2119  do_query:
2120         (*num_aliases) = 0;
2121         (*alias_rids) = NULL;
2122 
2123         if (!NT_STATUS_IS_OK(domain->last_status))
2124                 return domain->last_status;
2125 
2126         DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2127                   "for domain %s\n", domain->name ));
2128 
2129         status = domain->backend->lookup_useraliases(domain, mem_ctx,
2130                                                      num_sids, sids,
2131                                                      num_aliases, alias_rids);
2132 
2133         /* and save it */
2134         refresh_sequence_number(domain, false);
2135         centry = centry_start(domain, status);
2136         if (!centry)
2137                 goto skip_save;
2138         centry_put_uint32(centry, *num_aliases);
2139         for (i=0; i<(*num_aliases); i++)
2140                 centry_put_uint32(centry, (*alias_rids)[i]);
2141         centry_end(centry, "UA%s", sidlist);
2142         centry_free(centry);
2143 
2144  skip_save:
2145         return status;
2146 }
2147 
2148 
2149 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
2150                                 TALLOC_CTX *mem_ctx,
2151                                 const DOM_SID *group_sid, uint32 *num_names, 
2152                                 DOM_SID **sid_mem, char ***names, 
2153                                 uint32 **name_types)
2154 {
2155         struct winbind_cache *cache = get_cache(domain);
2156         struct cache_entry *centry = NULL;
2157         NTSTATUS status;
2158         unsigned int i;
2159         fstring sid_string;
2160 
2161         if (!cache->tdb)
2162                 goto do_query;
2163 
2164         centry = wcache_fetch(cache, domain, "GM/%s",
2165                               sid_to_fstring(sid_string, group_sid));
2166         if (!centry)
2167                 goto do_query;
2168 
2169         *num_names = centry_uint32(centry);
2170         
2171         if (*num_names == 0)
2172                 goto do_cached;
2173 
2174         (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_names);
2175         (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names);
2176         (*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *num_names);
2177 
2178         if (! (*sid_mem) || ! (*names) || ! (*name_types)) {
2179                 smb_panic_fn("lookup_groupmem out of memory");
2180         }
2181 
2182         for (i=0; i<(*num_names); i++) {
2183                 centry_sid(centry, mem_ctx, &(*sid_mem)[i]);
2184                 (*names)[i] = centry_string(centry, mem_ctx);
2185                 (*name_types)[i] = centry_uint32(centry);
2186         }
2187 
2188 do_cached:      
2189         status = centry->status;
2190 
2191         DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
2192                 domain->name, nt_errstr(status)));
2193 
2194         centry_free(centry);
2195         return status;
2196 
2197 do_query:
2198         (*num_names) = 0;
2199         (*sid_mem) = NULL;
2200         (*names) = NULL;
2201         (*name_types) = NULL;
2202         
2203         /* Return status value returned by seq number check */
2204 
2205         if (!NT_STATUS_IS_OK(domain->last_status))
2206                 return domain->last_status;
2207 
2208         DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2209                 domain->name ));
2210 
2211         status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid, num_names, 
2212                                                   sid_mem, names, name_types);
2213 
2214         /* and save it */
2215         refresh_sequence_number(domain, false);
2216         centry = centry_start(domain, status);
2217         if (!centry)
2218                 goto skip_save;
2219         centry_put_uint32(centry, *num_names);
2220         for (i=0; i<(*num_names); i++) {
2221                 centry_put_sid(centry, &(*sid_mem)[i]);
2222                 centry_put_string(centry, (*names)[i]);
2223                 centry_put_uint32(centry, (*name_types)[i]);
2224         }       
2225         centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
2226         centry_free(centry);
2227 
2228 skip_save:
2229         return status;
2230 }
2231 
2232 /* find the sequence number for a domain */
2233 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
     /* [<][>][^][v][top][bottom][index][help] */
2234 {
2235         refresh_sequence_number(domain, false);
2236 
2237         *seq = domain->sequence_number;
2238 
2239         return NT_STATUS_OK;
2240 }
2241 
2242 /* enumerate trusted domains 
2243  * (we need to have the list of trustdoms in the cache when we go offline) -
2244  * Guenther */
2245 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
2246                                 TALLOC_CTX *mem_ctx,
2247                                 uint32 *num_domains,
2248                                 char ***names,
2249                                 char ***alt_names,
2250                                 DOM_SID **dom_sids)
2251 {
2252         struct winbind_cache *cache = get_cache(domain);
2253         struct cache_entry *centry = NULL;
2254         NTSTATUS status;
2255         int i;
2256  
2257         if (!cache->tdb)
2258                 goto do_query;
2259  
2260         centry = wcache_fetch(cache, domain, "TRUSTDOMS/%s", domain->name);
2261         
2262         if (!centry) {
2263                 goto do_query;
2264         }
2265  
2266         *num_domains = centry_uint32(centry);
2267         
2268         if (*num_domains) {
2269                 (*names)        = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2270                 (*alt_names)    = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2271                 (*dom_sids)     = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
2272  
2273                 if (! (*dom_sids) || ! (*names) || ! (*alt_names)) {
2274                         smb_panic_fn("trusted_domains out of memory");
2275                 }
2276         } else {
2277                 (*names) = NULL;
2278                 (*alt_names) = NULL;
2279                 (*dom_sids) = NULL;
2280         }
2281  
2282         for (i=0; i<(*num_domains); i++) {
2283                 (*names)[i] = centry_string(centry, mem_ctx);
2284                 (*alt_names)[i] = centry_string(centry, mem_ctx);
2285                 if (!centry_sid(centry, mem_ctx, &(*dom_sids)[i])) {
2286                         sid_copy(&(*dom_sids)[i], &global_sid_NULL);
2287                 }
2288         }
2289 
2290         status = centry->status;
2291  
2292         DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
2293                 domain->name, *num_domains, nt_errstr(status) ));
2294  
2295         centry_free(centry);
2296         return status;
2297  
2298 do_query:
2299         (*num_domains) = 0;
2300         (*dom_sids) = NULL;
2301         (*names) = NULL;
2302         (*alt_names) = NULL;
2303  
2304         /* Return status value returned by seq number check */
2305 
2306         if (!NT_STATUS_IS_OK(domain->last_status))
2307                 return domain->last_status;
2308         
2309         DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2310                 domain->name ));
2311  
2312         status = domain->backend->trusted_domains(domain, mem_ctx, num_domains,
2313                                                 names, alt_names, dom_sids);
2314 
2315         /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2316          * so that the generic centry handling still applies correctly -
2317          * Guenther*/
2318 
2319         if (!NT_STATUS_IS_ERR(status)) {
2320                 status = NT_STATUS_OK;
2321         }
2322 
2323 
2324 #if 0    /* Disabled as we want the trust dom list to be managed by
2325             the main parent and always to make the query.  --jerry */
2326 
2327         /* and save it */
2328         refresh_sequence_number(domain, false);
2329  
2330         centry = centry_start(domain, status);
2331         if (!centry)
2332                 goto skip_save;
2333 
2334         centry_put_uint32(centry, *num_domains);
2335 
2336         for (i=0; i<(*num_domains); i++) {
2337                 centry_put_string(centry, (*names)[i]);
2338                 centry_put_string(centry, (*alt_names)[i]);
2339                 centry_put_sid(centry, &(*dom_sids)[i]);
2340         }
2341         
2342         centry_end(centry, "TRUSTDOMS/%s", domain->name);
2343  
2344         centry_free(centry);
2345  
2346 skip_save:
2347 #endif
2348 
2349         return status;
2350 }       
2351 
2352 /* get lockout policy */
2353 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
2354                                TALLOC_CTX *mem_ctx,
2355                                struct samr_DomInfo12 *policy)
2356 {
2357         struct winbind_cache *cache = get_cache(domain);
2358         struct cache_entry *centry = NULL;
2359         NTSTATUS status;
2360 
2361         if (!cache->tdb)
2362                 goto do_query;
2363 
2364         centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2365 
2366         if (!centry)
2367                 goto do_query;
2368 
2369         policy->lockout_duration = centry_nttime(centry);
2370         policy->lockout_window = centry_nttime(centry);
2371         policy->lockout_threshold = centry_uint16(centry);
2372 
2373         status = centry->status;
2374 
2375         DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2376                 domain->name, nt_errstr(status) ));
2377 
2378         centry_free(centry);
2379         return status;
2380 
2381 do_query:
2382         ZERO_STRUCTP(policy);
2383 
2384         /* Return status value returned by seq number check */
2385 
2386         if (!NT_STATUS_IS_OK(domain->last_status))
2387                 return domain->last_status;
2388 
2389         DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2390                 domain->name ));
2391 
2392         status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2393 
2394         /* and save it */
2395         refresh_sequence_number(domain, false);
2396         wcache_save_lockout_policy(domain, status, policy);
2397 
2398         return status;
2399 }
2400 
2401 /* get password policy */
2402 static NTSTATUS password_policy(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
2403                                 TALLOC_CTX *mem_ctx,
2404                                 struct samr_DomInfo1 *policy)
2405 {
2406         struct winbind_cache *cache = get_cache(domain);
2407         struct cache_entry *centry = NULL;
2408         NTSTATUS status;
2409 
2410         if (!cache->tdb)
2411                 goto do_query;
2412 
2413         centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2414 
2415         if (!centry)
2416                 goto do_query;
2417 
2418         policy->min_password_length = centry_uint16(centry);
2419         policy->password_history_length = centry_uint16(centry);
2420         policy->password_properties = centry_uint32(centry);
2421         policy->max_password_age = centry_nttime(centry);
2422         policy->min_password_age = centry_nttime(centry);
2423 
2424         status = centry->status;
2425 
2426         DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2427                 domain->name, nt_errstr(status) ));
2428 
2429         centry_free(centry);
2430         return status;
2431 
2432 do_query:
2433         ZERO_STRUCTP(policy);
2434 
2435         /* Return status value returned by seq number check */
2436 
2437         if (!NT_STATUS_IS_OK(domain->last_status))
2438                 return domain->last_status;
2439 
2440         DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2441                 domain->name ));
2442 
2443         status = domain->backend->password_policy(domain, mem_ctx, policy);
2444 
2445         /* and save it */
2446         refresh_sequence_number(domain, false);
2447         if (NT_STATUS_IS_OK(status)) {
2448                 wcache_save_password_policy(domain, status, policy);
2449         }
2450 
2451         return status;
2452 }
2453 
2454 
2455 /* Invalidate cached user and group lists coherently */
2456 
2457 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, 
     /* [<][>][^][v][top][bottom][index][help] */
2458                        void *state)
2459 {
2460         if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
2461             strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
2462                 tdb_delete(the_tdb, kbuf);
2463 
2464         return 0;
2465 }
2466 
2467 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2468 
2469 void wcache_invalidate_samlogon(struct winbindd_domain *domain, 
     /* [<][>][^][v][top][bottom][index][help] */
2470                                 struct netr_SamInfo3 *info3)
2471 {
2472         DOM_SID sid;
2473         fstring key_str, sid_string;
2474         struct winbind_cache *cache;
2475 
2476         /* dont clear cached U/SID and UG/SID entries when we want to logon
2477          * offline - gd */
2478 
2479         if (lp_winbind_offline_logon()) {
2480                 return;
2481         }
2482 
2483         if (!domain)
2484                 return;
2485 
2486         cache = get_cache(domain);
2487 
2488         if (!cache->tdb) {
2489                 return;
2490         }
2491 
2492         sid_copy(&sid, info3->base.domain_sid);
2493         sid_append_rid(&sid, info3->base.rid);
2494 
2495         /* Clear U/SID cache entry */
2496         fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, &sid));
2497         DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
2498         tdb_delete(cache->tdb, string_tdb_data(key_str));
2499 
2500         /* Clear UG/SID cache entry */
2501         fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, &sid));
2502         DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
2503         tdb_delete(cache->tdb, string_tdb_data(key_str));
2504 
2505         /* Samba/winbindd never needs this. */
2506         netsamlogon_clear_cached_user(info3);
2507 }
2508 
2509 bool wcache_invalidate_cache(void)
     /* [<][>][^][v][top][bottom][index][help] */
2510 {
2511         struct winbindd_domain *domain;
2512 
2513         for (domain = domain_list(); domain; domain = domain->next) {
2514                 struct winbind_cache *cache = get_cache(domain);
2515 
2516                 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2517                            "entries for %s\n", domain->name));
2518                 if (cache) {
2519                         if (cache->tdb) {
2520                                 tdb_traverse(cache->tdb, traverse_fn, NULL);
2521                         } else {
2522                                 return false;
2523                         }
2524                 }
2525         }
2526         return true;
2527 }
2528 
2529 bool wcache_invalidate_cache_noinit(void)
     /* [<][>][^][v][top][bottom][index][help] */
2530 {
2531         struct winbindd_domain *domain;
2532 
2533         for (domain = domain_list(); domain; domain = domain->next) {
2534                 struct winbind_cache *cache;
2535 
2536                 /* Skip uninitialized domains. */
2537                 if (!domain->initialized && !domain->internal) {
2538                         continue;
2539                 }
2540 
2541                 cache = get_cache(domain);
2542 
2543                 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2544                            "entries for %s\n", domain->name));
2545                 if (cache) {
2546                         if (cache->tdb) {
2547                                 tdb_traverse(cache->tdb, traverse_fn, NULL);
2548                         } else {
2549                                 return false;
2550                         }
2551                 }
2552         }
2553         return true;
2554 }
2555 
2556 bool init_wcache(void)
     /* [<][>][^][v][top][bottom][index][help] */
2557 {
2558         if (wcache == NULL) {
2559                 wcache = SMB_XMALLOC_P(struct winbind_cache);
2560                 ZERO_STRUCTP(wcache);
2561         }
2562 
2563         if (wcache->tdb != NULL)
2564                 return true;
2565 
2566         /* when working offline we must not clear the cache on restart */
2567         wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
2568                                 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE, 
2569                                 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST), 
2570                                 O_RDWR|O_CREAT, 0600);
2571 
2572         if (wcache->tdb == NULL) {
2573                 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2574                 return false;
2575         }
2576 
2577         return true;
2578 }
2579 
2580 /************************************************************************
2581  This is called by the parent to initialize the cache file.
2582  We don't need sophisticated locking here as we know we're the
2583  only opener.
2584 ************************************************************************/
2585 
2586 bool initialize_winbindd_cache(void)
     /* [<][>][^][v][top][bottom][index][help] */
2587 {
2588         bool cache_bad = true;
2589         uint32 vers;
2590 
2591         if (!init_wcache()) {
2592                 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
2593                 return false;
2594         }
2595 
2596         /* Check version number. */
2597         if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
2598                         vers == WINBINDD_CACHE_VERSION) {
2599                 cache_bad = false;
2600         }
2601 
2602         if (cache_bad) {
2603                 DEBUG(0,("initialize_winbindd_cache: clearing cache "
2604                         "and re-creating with version number %d\n",
2605                         WINBINDD_CACHE_VERSION ));
2606 
2607                 tdb_close(wcache->tdb);
2608                 wcache->tdb = NULL;
2609 
2610                 if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
2611                         DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
2612                                 cache_path("winbindd_cache.tdb"),
2613                                 strerror(errno) ));
2614                         return false;
2615                 }
2616                 if (!init_wcache()) {
2617                         DEBUG(0,("initialize_winbindd_cache: re-initialization "
2618                                         "init_wcache failed.\n"));
2619                         return false;
2620                 }
2621 
2622                 /* Write the version. */
2623                 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
2624                         DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
2625                                 tdb_errorstr(wcache->tdb) ));
2626                         return false;
2627                 }
2628         }
2629 
2630         tdb_close(wcache->tdb);
2631         wcache->tdb = NULL;
2632         return true;
2633 }
2634 
2635 void close_winbindd_cache(void)
     /* [<][>][^][v][top][bottom][index][help] */
2636 {
2637         if (!wcache) {
2638                 return;
2639         }
2640         if (wcache->tdb) {
2641                 tdb_close(wcache->tdb);
2642                 wcache->tdb = NULL;
2643         }
2644 }
2645 
2646 void cache_store_response(pid_t pid, struct winbindd_response *response)
     /* [<][>][^][v][top][bottom][index][help] */
2647 {
2648         fstring key_str;
2649 
2650         if (!init_wcache())
2651                 return;
2652 
2653         DEBUG(10, ("Storing response for pid %d, len %d\n",
2654                    (int)pid, response->length));
2655 
2656         fstr_sprintf(key_str, "DR/%d", (int)pid);
2657         if (tdb_store(wcache->tdb, string_tdb_data(key_str), 
2658                       make_tdb_data((uint8 *)response, sizeof(*response)),
2659                       TDB_REPLACE) == -1)
2660                 return;
2661 
2662         if (response->length == sizeof(*response))
2663                 return;
2664 
2665         /* There's extra data */
2666 
2667         DEBUG(10, ("Storing extra data: len=%d\n",
2668                    (int)(response->length - sizeof(*response))));
2669 
2670         fstr_sprintf(key_str, "DE/%d", (int)pid);
2671         if (tdb_store(wcache->tdb, string_tdb_data(key_str),
2672                       make_tdb_data((uint8 *)response->extra_data.data,
2673                                     response->length - sizeof(*response)),
2674                       TDB_REPLACE) == 0)
2675                 return;
2676 
2677         /* We could not store the extra data, make sure the tdb does not
2678          * contain a main record with wrong dangling extra data */
2679 
2680         fstr_sprintf(key_str, "DR/%d", (int)pid);
2681         tdb_delete(wcache->tdb, string_tdb_data(key_str));
2682 
2683         return;
2684 }
2685 
2686 bool cache_retrieve_response(pid_t pid, struct winbindd_response * response)
     /* [<][>][^][v][top][bottom][index][help] */
2687 {
2688         TDB_DATA data;
2689         fstring key_str;
2690 
2691         if (!init_wcache())
2692                 return false;
2693 
2694         DEBUG(10, ("Retrieving response for pid %d\n", (int)pid));
2695 
2696         fstr_sprintf(key_str, "DR/%d", (int)pid);
2697         data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
2698 
2699         if (data.dptr == NULL)
2700                 return false;
2701 
2702         if (data.dsize != sizeof(*response))
2703                 return false;
2704 
2705         memcpy(response, data.dptr, data.dsize);
2706         SAFE_FREE(data.dptr);
2707 
2708         if (response->length == sizeof(*response)) {
2709                 response->extra_data.data = NULL;
2710                 return true;
2711         }
2712 
2713         /* There's extra data */
2714 
2715         DEBUG(10, ("Retrieving extra data length=%d\n",
2716                    (int)(response->length - sizeof(*response))));
2717 
2718         fstr_sprintf(key_str, "DE/%d", (int)pid);
2719         data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
2720 
2721         if (data.dptr == NULL) {
2722                 DEBUG(0, ("Did not find extra data\n"));
2723                 return false;
2724         }
2725 
2726         if (data.dsize != (response->length - sizeof(*response))) {
2727                 DEBUG(0, ("Invalid extra data length: %d\n", (int)data.dsize));
2728                 SAFE_FREE(data.dptr);
2729                 return false;
2730         }
2731 
2732         dump_data(11, (uint8 *)data.dptr, data.dsize);
2733 
2734         response->extra_data.data = data.dptr;
2735         return true;
2736 }
2737 
2738 void cache_cleanup_response(pid_t pid)
     /* [<][>][^][v][top][bottom][index][help] */
2739 {
2740         fstring key_str;
2741 
2742         if (!init_wcache())
2743                 return;
2744 
2745         fstr_sprintf(key_str, "DR/%d", (int)pid);
2746         tdb_delete(wcache->tdb, string_tdb_data(key_str));
2747 
2748         fstr_sprintf(key_str, "DE/%d", (int)pid);
2749         tdb_delete(wcache->tdb, string_tdb_data(key_str));
2750 
2751         return;
2752 }
2753 
2754 
2755 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
     /* [<][>][^][v][top][bottom][index][help] */
2756                        char **domain_name, char **name,
2757                        enum lsa_SidType *type)
2758 {
2759         struct winbindd_domain *domain;
2760         struct winbind_cache *cache;
2761         struct cache_entry *centry = NULL;
2762         NTSTATUS status;
2763         fstring tmp;
2764 
2765         domain = find_lookup_domain_from_sid(sid);
2766         if (domain == NULL) {
2767                 return false;
2768         }
2769 
2770         cache = get_cache(domain);
2771 
2772         if (cache->tdb == NULL) {
2773                 return false;
2774         }
2775 
2776         centry = wcache_fetch(cache, domain, "SN/%s",
2777                               sid_to_fstring(tmp, sid));
2778         if (centry == NULL) {
2779                 return false;
2780         }
2781 
2782         if (NT_STATUS_IS_OK(centry->status)) {
2783                 *type = (enum lsa_SidType)centry_uint32(centry);
2784                 *domain_name = centry_string(centry, mem_ctx);
2785                 *name = centry_string(centry, mem_ctx);
2786         }
2787 
2788         status = centry->status;
2789         centry_free(centry);
2790         return NT_STATUS_IS_OK(status);
2791 }
2792 
2793 bool lookup_cached_name(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
2794                         const char *domain_name,
2795                         const char *name,
2796                         DOM_SID *sid,
2797                         enum lsa_SidType *type)
2798 {
2799         struct winbindd_domain *domain;
2800         struct winbind_cache *cache;
2801         struct cache_entry *centry = NULL;
2802         NTSTATUS status;
2803         fstring uname;
2804         bool original_online_state;     
2805 
2806         domain = find_lookup_domain_from_name(domain_name);
2807         if (domain == NULL) {
2808                 return false;
2809         }
2810 
2811         cache = get_cache(domain);
2812 
2813         if (cache->tdb == NULL) {
2814                 return false;
2815         }
2816 
2817         fstrcpy(uname, name);
2818         strupper_m(uname);
2819         
2820         /* If we are doing a cached logon, temporarily set the domain
2821            offline so the cache won't expire the entry */
2822         
2823         original_online_state = domain->online;
2824         domain->online = false;
2825         centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
2826         domain->online = original_online_state;
2827         
2828         if (centry == NULL) {
2829                 return false;
2830         }
2831 
2832         if (NT_STATUS_IS_OK(centry->status)) {
2833                 *type = (enum lsa_SidType)centry_uint32(centry);
2834                 centry_sid(centry, mem_ctx, sid);
2835         }
2836 
2837         status = centry->status;
2838         centry_free(centry);
2839         
2840         return NT_STATUS_IS_OK(status);
2841 }
2842 
2843 void cache_name2sid(struct winbindd_domain *domain, 
     /* [<][>][^][v][top][bottom][index][help] */
2844                     const char *domain_name, const char *name,
2845                     enum lsa_SidType type, const DOM_SID *sid)
2846 {
2847         refresh_sequence_number(domain, false);
2848         wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
2849                                 sid, type);
2850 }
2851 
2852 /*
2853  * The original idea that this cache only contains centries has
2854  * been blurred - now other stuff gets put in here. Ensure we
2855  * ignore these things on cleanup.
2856  */
2857 
2858 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, 
     /* [<][>][^][v][top][bottom][index][help] */
2859                                TDB_DATA dbuf, void *state)
2860 {
2861         struct cache_entry *centry;
2862 
2863         if (is_non_centry_key(kbuf)) {
2864                 return 0;
2865         }
2866 
2867         centry = wcache_fetch_raw((char *)kbuf.dptr);
2868         if (!centry) {
2869                 return 0;
2870         }
2871 
2872         if (!NT_STATUS_IS_OK(centry->status)) {
2873                 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
2874                 tdb_delete(the_tdb, kbuf);
2875         }
2876 
2877         centry_free(centry);
2878         return 0;
2879 }
2880 
2881 /* flush the cache */
2882 void wcache_flush_cache(void)
     /* [<][>][^][v][top][bottom][index][help] */
2883 {
2884         if (!wcache)
2885                 return;
2886         if (wcache->tdb) {
2887                 tdb_close(wcache->tdb);
2888                 wcache->tdb = NULL;
2889         }
2890         if (!winbindd_use_cache()) {
2891                 return;
2892         }
2893 
2894         /* when working offline we must not clear the cache on restart */
2895         wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
2896                                 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE, 
2897                                 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST), 
2898                                 O_RDWR|O_CREAT, 0600);
2899 
2900         if (!wcache->tdb) {
2901                 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2902                 return;
2903         }
2904 
2905         tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
2906 
2907         DEBUG(10,("wcache_flush_cache success\n"));
2908 }
2909 
2910 /* Count cached creds */
2911 
2912 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, 
     /* [<][>][^][v][top][bottom][index][help] */
2913                                     void *state)
2914 {
2915         int *cred_count = (int*)state;
2916  
2917         if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2918                 (*cred_count)++;
2919         }
2920         return 0;
2921 }
2922 
2923 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
     /* [<][>][^][v][top][bottom][index][help] */
2924 {
2925         struct winbind_cache *cache = get_cache(domain);
2926 
2927         *count = 0;
2928 
2929         if (!cache->tdb) {
2930                 return NT_STATUS_INTERNAL_DB_ERROR;
2931         }
2932  
2933         tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
2934 
2935         return NT_STATUS_OK;
2936 }
2937 
2938 struct cred_list {
2939         struct cred_list *prev, *next;
2940         TDB_DATA key;
2941         fstring name;
2942         time_t created;
2943 };
2944 static struct cred_list *wcache_cred_list;
2945 
2946 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, 
     /* [<][>][^][v][top][bottom][index][help] */
2947                                     void *state)
2948 {
2949         struct cred_list *cred;
2950 
2951         if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2952 
2953                 cred = SMB_MALLOC_P(struct cred_list);
2954                 if (cred == NULL) {
2955                         DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2956                         return -1;
2957                 }
2958 
2959                 ZERO_STRUCTP(cred);
2960                 
2961                 /* save a copy of the key */
2962                 
2963                 fstrcpy(cred->name, (const char *)kbuf.dptr);           
2964                 DLIST_ADD(wcache_cred_list, cred);
2965         }
2966         
2967         return 0;
2968 }
2969 
2970 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid) 
     /* [<][>][^][v][top][bottom][index][help] */
2971 {
2972         struct winbind_cache *cache = get_cache(domain);
2973         NTSTATUS status;
2974         int ret;
2975         struct cred_list *cred, *oldest = NULL;
2976 
2977         if (!cache->tdb) {
2978                 return NT_STATUS_INTERNAL_DB_ERROR;
2979         }
2980 
2981         /* we possibly already have an entry */
2982         if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
2983         
2984                 fstring key_str, tmp;
2985 
2986                 DEBUG(11,("we already have an entry, deleting that\n"));
2987 
2988                 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
2989 
2990                 tdb_delete(cache->tdb, string_tdb_data(key_str));
2991 
2992                 return NT_STATUS_OK;
2993         }
2994 
2995         ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
2996         if (ret == 0) {
2997                 return NT_STATUS_OK;
2998         } else if ((ret == -1) || (wcache_cred_list == NULL)) {
2999                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3000         }
3001 
3002         ZERO_STRUCTP(oldest);
3003 
3004         for (cred = wcache_cred_list; cred; cred = cred->next) {
3005 
3006                 TDB_DATA data;
3007                 time_t t;
3008 
3009                 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
3010                 if (!data.dptr) {
3011                         DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n", 
3012                                 cred->name));
3013                         status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
3014                         goto done;
3015                 }
3016         
3017                 t = IVAL(data.dptr, 0);
3018                 SAFE_FREE(data.dptr);
3019 
3020                 if (!oldest) {
3021                         oldest = SMB_MALLOC_P(struct cred_list);
3022                         if (oldest == NULL) {
3023                                 status = NT_STATUS_NO_MEMORY;
3024                                 goto done;
3025                         }
3026 
3027                         fstrcpy(oldest->name, cred->name);
3028                         oldest->created = t;
3029                         continue;
3030                 }
3031 
3032                 if (t < oldest->created) {
3033                         fstrcpy(oldest->name, cred->name);
3034                         oldest->created = t;
3035                 }
3036         }
3037 
3038         if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
3039                 status = NT_STATUS_OK;
3040         } else {
3041                 status = NT_STATUS_UNSUCCESSFUL;
3042         }
3043 done:
3044         SAFE_FREE(wcache_cred_list);
3045         SAFE_FREE(oldest);
3046         
3047         return status;
3048 }
3049 
3050 /* Change the global online/offline state. */
3051 bool set_global_winbindd_state_offline(void)
     /* [<][>][^][v][top][bottom][index][help] */
3052 {
3053         TDB_DATA data;
3054 
3055         DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3056 
3057         /* Only go offline if someone has created
3058            the key "WINBINDD_OFFLINE" in the cache tdb. */
3059 
3060         if (wcache == NULL || wcache->tdb == NULL) {
3061                 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3062                 return false;
3063         }
3064 
3065         if (!lp_winbind_offline_logon()) {
3066                 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3067                 return false;
3068         }
3069 
3070         if (global_winbindd_offline_state) {
3071                 /* Already offline. */
3072                 return true;
3073         }
3074 
3075         data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
3076 
3077         if (!data.dptr || data.dsize != 4) {
3078                 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3079                 SAFE_FREE(data.dptr);
3080                 return false;
3081         } else {
3082                 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3083                 global_winbindd_offline_state = true;
3084                 SAFE_FREE(data.dptr);
3085                 return true;
3086         }
3087 }
3088 
3089 void set_global_winbindd_state_online(void)
     /* [<][>][^][v][top][bottom][index][help] */
3090 {
3091         DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3092 
3093         if (!lp_winbind_offline_logon()) {
3094                 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3095                 return;
3096         }
3097 
3098         if (!global_winbindd_offline_state) {
3099                 /* Already online. */
3100                 return;
3101         }
3102         global_winbindd_offline_state = false;
3103 
3104         if (!wcache->tdb) {
3105                 return;
3106         }
3107 
3108         /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3109         tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
3110 }
3111 
3112 bool get_global_winbindd_state_offline(void)
     /* [<][>][^][v][top][bottom][index][help] */
3113 {
3114         return global_winbindd_offline_state;
3115 }
3116 
3117 /***********************************************************************
3118  Validate functions for all possible cache tdb keys.
3119 ***********************************************************************/
3120 
3121 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data, 
     /* [<][>][^][v][top][bottom][index][help] */
3122                                                   struct tdb_validation_status *state)
3123 {
3124         struct cache_entry *centry;
3125 
3126         centry = SMB_XMALLOC_P(struct cache_entry);
3127         centry->data = (unsigned char *)memdup(data.dptr, data.dsize);
3128         if (!centry->data) {
3129                 SAFE_FREE(centry);
3130                 return NULL;
3131         }
3132         centry->len = data.dsize;
3133         centry->ofs = 0;
3134 
3135         if (centry->len < 8) {
3136                 /* huh? corrupt cache? */
3137                 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
3138                 centry_free(centry);
3139                 state->bad_entry = true;
3140                 state->success = false;
3141                 return NULL;
3142         }
3143 
3144         centry->status = NT_STATUS(centry_uint32(centry));
3145         centry->sequence_number = centry_uint32(centry);
3146         return centry;
3147 }
3148 
3149 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
     /* [<][>][^][v][top][bottom][index][help] */
3150                            struct tdb_validation_status *state)
3151 {
3152         if (dbuf.dsize != 8) {
3153                 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3154                                 keystr, (unsigned int)dbuf.dsize ));
3155                 state->bad_entry = true;
3156                 return 1;
3157         }
3158         return 0;
3159 }
3160 
3161 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
     /* [<][>][^][v][top][bottom][index][help] */
3162                        struct tdb_validation_status *state)
3163 {
3164         struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3165         if (!centry) {
3166                 return 1;
3167         }
3168 
3169         (void)centry_uint32(centry);
3170         if (NT_STATUS_IS_OK(centry->status)) {
3171                 DOM_SID sid;
3172                 (void)centry_sid(centry, mem_ctx, &sid);
3173         }
3174 
3175         centry_free(centry);
3176 
3177         if (!(state->success)) {
3178                 return 1;
3179         }
3180         DEBUG(10,("validate_ns: %s ok\n", keystr));
3181         return 0;
3182 }
3183 
3184 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
     /* [<][>][^][v][top][bottom][index][help] */
3185                        struct tdb_validation_status *state)
3186 {
3187         struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3188         if (!centry) {
3189                 return 1;
3190         }
3191 
3192         if (NT_STATUS_IS_OK(centry->status)) {
3193                 (void)centry_uint32(centry);
3194                 (void)centry_string(centry, mem_ctx);
3195                 (void)centry_string(centry, mem_ctx);
3196         }
3197 
3198         centry_free(centry);
3199 
3200         if (!(state->success)) {
3201                 return 1;
3202         }
3203         DEBUG(10,("validate_sn: %s ok\n", keystr));
3204         return 0;
3205 }
3206 
3207 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
     /* [<][>][^][v][top][bottom][index][help] */
3208                       struct tdb_validation_status *state)
3209 {
3210         struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3211         DOM_SID sid;
3212 
3213         if (!centry) {
3214                 return 1;
3215         }
3216 
3217         (void)centry_string(centry, mem_ctx);
3218         (void)centry_string(centry, mem_ctx);
3219         (void)centry_string(centry, mem_ctx);
3220         (void)centry_string(centry, mem_ctx);
3221         (void)centry_uint32(centry);
3222         (void)centry_sid(centry, mem_ctx, &sid);
3223         (void)centry_sid(centry, mem_ctx, &sid);
3224 
3225         centry_free(centry);
3226 
3227         if (!(state->success)) {
3228                 return 1;
3229         }
3230         DEBUG(10,("validate_u: %s ok\n", keystr));
3231         return 0;
3232 }
3233 
3234 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
     /* [<][>][^][v][top][bottom][index][help] */
3235                             struct tdb_validation_status *state)
3236 {
3237         struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3238 
3239         if (!centry) {
3240                 return 1;
3241         }
3242 
3243         (void)centry_nttime(centry);
3244         (void)centry_nttime(centry);
3245         (void)centry_uint16(centry);
3246 
3247         centry_free(centry);
3248 
3249         if (!(state->success)) {
3250                 return 1;
3251         }
3252         DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
3253         return 0;
3254 }
3255 
3256 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
     /* [<][>][^][v][top][bottom][index][help] */
3257                             struct tdb_validation_status *state)
3258 {
3259         struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3260 
3261         if (!centry) {
3262                 return 1;
3263         }
3264 
3265         (void)centry_uint16(centry);
3266         (void)centry_uint16(centry);
3267         (void)centry_uint32(centry);
3268         (void)centry_nttime(centry);
3269         (void)centry_nttime(centry);
3270 
3271         centry_free(centry);
3272 
3273         if (!(state->success)) {
3274                 return 1;
3275         }
3276         DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
3277         return 0;
3278 }
3279 
3280 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
     /* [<][>][^][v][top][bottom][index][help] */
3281                          struct tdb_validation_status *state)
3282 {
3283         struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3284 
3285         if (!centry) {
3286                 return 1;
3287         }
3288 
3289         (void)centry_time(centry);
3290         (void)centry_hash16(centry, mem_ctx);
3291 
3292         /* We only have 17 bytes more data in the salted cred case. */
3293         if (centry->len - centry->ofs == 17) {
3294                 (void)centry_hash16(centry, mem_ctx);
3295         }
3296 
3297         centry_free(centry);
3298 
3299         if (!(state->success)) {
3300                 return 1;
3301         }
3302         DEBUG(10,("validate_cred: %s ok\n", keystr));
3303         return 0;
3304 }
3305 
3306 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
     /* [<][>][^][v][top][bottom][index][help] */
3307                        struct tdb_validation_status *state)
3308 {
3309         struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3310         int32 num_entries, i;
3311 
3312         if (!centry) {
3313                 return 1;
3314         }
3315 
3316         num_entries = (int32)centry_uint32(centry);
3317 
3318         for (i=0; i< num_entries; i++) {
3319                 DOM_SID sid;
3320                 (void)centry_string(centry, mem_ctx);
3321                 (void)centry_string(centry, mem_ctx);
3322                 (void)centry_string(centry, mem_ctx);
3323                 (void)centry_string(centry, mem_ctx);
3324                 (void)centry_sid(centry, mem_ctx, &sid);
3325                 (void)centry_sid(centry, mem_ctx, &sid);
3326         }
3327 
3328         centry_free(centry);
3329 
3330         if (!(state->success)) {
3331                 return 1;
3332         }
3333         DEBUG(10,("validate_ul: %s ok\n", keystr));
3334         return 0;
3335 }
3336 
3337 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
     /* [<][>][^][v][top][bottom][index][help] */
3338                        struct tdb_validation_status *state)
3339 {
3340         struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3341         int32 num_entries, i;
3342 
3343         if (!centry) {
3344                 return 1;
3345         }
3346 
3347         num_entries = centry_uint32(centry);
3348         
3349         for (i=0; i< num_entries; i++) {
3350                 (void)centry_string(centry, mem_ctx);
3351                 (void)centry_string(centry, mem_ctx);
3352                 (void)centry_uint32(centry);
3353         }
3354 
3355         centry_free(centry);
3356 
3357         if (!(state->success)) {
3358                 return 1;
3359         }
3360         DEBUG(10,("validate_gl: %s ok\n", keystr));
3361         return 0;
3362 }
3363 
3364 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
     /* [<][>][^][v][top][bottom][index][help] */
3365                        struct tdb_validation_status *state)
3366 {
3367         struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3368         int32 num_groups, i;
3369 
3370         if (!centry) {
3371                 return 1;
3372         }
3373 
3374         num_groups = centry_uint32(centry);
3375 
3376         for (i=0; i< num_groups; i++) {
3377                 DOM_SID sid;
3378                 centry_sid(centry, mem_ctx, &sid);
3379         }
3380 
3381         centry_free(centry);
3382 
3383         if (!(state->success)) {
3384                 return 1;
3385         }
3386         DEBUG(10,("validate_ug: %s ok\n", keystr));
3387         return 0;
3388 }
3389 
3390 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
     /* [<][>][^][v][top][bottom][index][help] */
3391                        struct tdb_validation_status *state)
3392 {
3393         struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3394         int32 num_aliases, i;
3395 
3396         if (!centry) {
3397                 return 1;
3398         }
3399 
3400         num_aliases = centry_uint32(centry);
3401 
3402         for (i=0; i < num_aliases; i++) {
3403                 (void)centry_uint32(centry);
3404         }
3405 
3406         centry_free(centry);
3407 
3408         if (!(state->success)) {
3409                 return 1;
3410         }
3411         DEBUG(10,("validate_ua: %s ok\n", keystr));
3412         return 0;
3413 }
3414 
3415 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
     /* [<][>][^][v][top][bottom][index][help] */
3416                        struct tdb_validation_status *state)
3417 {
3418         struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3419         int32 num_names, i;
3420 
3421         if (!centry) {
3422                 return 1;
3423         }
3424 
3425         num_names = centry_uint32(centry);
3426 
3427         for (i=0; i< num_names; i++) {
3428                 DOM_SID sid;
3429                 centry_sid(centry, mem_ctx, &sid);
3430                 (void)centry_string(centry, mem_ctx);
3431                 (void)centry_uint32(centry);
3432         }
3433 
3434         centry_free(centry);
3435 
3436         if (!(state->success)) {
3437                 return 1;
3438         }
3439         DEBUG(10,("validate_gm: %s ok\n", keystr));
3440         return 0;
3441 }
3442 
3443 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
     /* [<][>][^][v][top][bottom][index][help] */
3444                        struct tdb_validation_status *state)
3445 {
3446         /* Can't say anything about this other than must be nonzero. */
3447         if (dbuf.dsize == 0) {
3448                 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3449                                 keystr));
3450                 state->bad_entry = true;
3451                 state->success = false;
3452                 return 1;
3453         }
3454 
3455         DEBUG(10,("validate_dr: %s ok\n", keystr));
3456         return 0;
3457 }
3458 
3459 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
     /* [<][>][^][v][top][bottom][index][help] */
3460                        struct tdb_validation_status *state)
3461 {
3462         /* Can't say anything about this other than must be nonzero. */
3463         if (dbuf.dsize == 0) {
3464                 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3465                                 keystr));
3466                 state->bad_entry = true;
3467                 state->success = false;
3468                 return 1;
3469         }
3470 
3471         DEBUG(10,("validate_de: %s ok\n", keystr));
3472         return 0;
3473 }
3474 
3475 static int validate_pwinfo(TALLOC_CTX *mem_ctx, const char *keystr,
     /* [<][>][^][v][top][bottom][index][help] */
3476                            TDB_DATA dbuf, struct tdb_validation_status *state)
3477 {
3478         struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3479 
3480         if (!centry) {
3481                 return 1;
3482         }
3483 
3484         (void)centry_string(centry, mem_ctx);
3485         (void)centry_string(centry, mem_ctx);
3486         (void)centry_string(centry, mem_ctx);
3487         (void)centry_uint32(centry);
3488 
3489         centry_free(centry);
3490 
3491         if (!(state->success)) {
3492                 return 1;
3493         }
3494         DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3495         return 0;
3496 }
3497 
3498 static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
     /* [<][>][^][v][top][bottom][index][help] */
3499                            TDB_DATA dbuf,
3500                            struct tdb_validation_status *state)
3501 {
3502         struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3503 
3504         if (!centry) {
3505                 return 1;
3506         }
3507 
3508         (void)centry_string( centry, mem_ctx );
3509 
3510         centry_free(centry);
3511 
3512         if (!(state->success)) {
3513                 return 1;
3514         }
3515         DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3516         return 0;
3517 }
3518 
3519 static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
     /* [<][>][^][v][top][bottom][index][help] */
3520                            TDB_DATA dbuf,
3521                            struct tdb_validation_status *state)
3522 {
3523         struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3524 
3525         if (!centry) {
3526                 return 1;
3527         }
3528 
3529         (void)centry_string( centry, mem_ctx );
3530 
3531         centry_free(centry);
3532 
3533         if (!(state->success)) {
3534                 return 1;
3535         }
3536         DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3537         return 0;
3538 }
3539 
3540 static int validate_trustdoms(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
     /* [<][>][^][v][top][bottom][index][help] */
3541                               struct tdb_validation_status *state)
3542 {
3543         struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3544         int32 num_domains, i;
3545 
3546         if (!centry) {
3547                 return 1;
3548         }
3549 
3550         num_domains = centry_uint32(centry);
3551         
3552         for (i=0; i< num_domains; i++) {
3553                 DOM_SID sid;
3554                 (void)centry_string(centry, mem_ctx);
3555                 (void)centry_string(centry, mem_ctx);
3556                 (void)centry_sid(centry, mem_ctx, &sid);
3557         }
3558 
3559         centry_free(centry);
3560 
3561         if (!(state->success)) {
3562                 return 1;
3563         }
3564         DEBUG(10,("validate_trustdoms: %s ok\n", keystr));
3565         return 0;
3566 }
3567 
3568 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr, 
     /* [<][>][^][v][top][bottom][index][help] */
3569                                   TDB_DATA dbuf,
3570                                   struct tdb_validation_status *state)
3571 {
3572         if (dbuf.dsize == 0) {
3573                 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3574                           "key %s (len ==0) ?\n", keystr));
3575                 state->bad_entry = true;
3576                 state->success = false;
3577                 return 1;
3578         }
3579 
3580         DEBUG(10,    ("validate_trustdomcache: %s ok\n", keystr));
3581         DEBUGADD(10, ("  Don't trust me, I am a DUMMY!\n"));
3582         return 0;
3583 }
3584 
3585 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
     /* [<][>][^][v][top][bottom][index][help] */
3586                             struct tdb_validation_status *state)
3587 {
3588         if (dbuf.dsize != 4) {
3589                 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3590                                 keystr, (unsigned int)dbuf.dsize ));
3591                 state->bad_entry = true;
3592                 state->success = false;
3593                 return 1;
3594         }
3595         DEBUG(10,("validate_offline: %s ok\n", keystr));
3596         return 0;
3597 }
3598 
3599 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
     /* [<][>][^][v][top][bottom][index][help] */
3600                                   struct tdb_validation_status *state)
3601 {
3602         if (dbuf.dsize != 4) {
3603                 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3604                           "key %s (len %u != 4) ?\n", 
3605                           keystr, (unsigned int)dbuf.dsize));
3606                 state->bad_entry = true;
3607                 state->success = false;
3608                 return 1;
3609         }
3610 
3611         DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
3612         return 0;
3613 }
3614 
3615 /***********************************************************************
3616  A list of all possible cache tdb keys with associated validation
3617  functions.
3618 ***********************************************************************/
3619 
3620 struct key_val_struct {
3621         const char *keyname;
3622         int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
3623 } key_val[] = {
3624         {"SEQNUM/", validate_seqnum},
3625         {"NS/", validate_ns},
3626         {"SN/", validate_sn},
3627         {"U/", validate_u},
3628         {"LOC_POL/", validate_loc_pol},
3629         {"PWD_POL/", validate_pwd_pol},
3630         {"CRED/", validate_cred},
3631         {"UL/", validate_ul},
3632         {"GL/", validate_gl},
3633         {"UG/", validate_ug},
3634         {"UA", validate_ua},
3635         {"GM/", validate_gm},
3636         {"DR/", validate_dr},
3637         {"DE/", validate_de},
3638         {"NSS/PWINFO/", validate_pwinfo},
3639         {"TRUSTDOMS/", validate_trustdoms},
3640         {"TRUSTDOMCACHE/", validate_trustdomcache},
3641         {"NSS/NA/", validate_nss_na},
3642         {"NSS/AN/", validate_nss_an},
3643         {"WINBINDD_OFFLINE", validate_offline},
3644         {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
3645         {NULL, NULL}
3646 };
3647 
3648 /***********************************************************************
3649  Function to look at every entry in the tdb and validate it as far as
3650  possible.
3651 ***********************************************************************/
3652 
3653 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
     /* [<][>][^][v][top][bottom][index][help] */
3654 {
3655         int i;
3656         unsigned int max_key_len = 1024;
3657         struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
3658 
3659         /* Paranoia check. */
3660         if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0) {
3661                 max_key_len = 1024 * 1024;
3662         }
3663         if (kbuf.dsize > max_key_len) {
3664                 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
3665                           "(%u) > (%u)\n\n",
3666                           (unsigned int)kbuf.dsize, (unsigned int)max_key_len));
3667                 return 1;
3668         }
3669 
3670         for (i = 0; key_val[i].keyname; i++) {
3671                 size_t namelen = strlen(key_val[i].keyname);
3672                 if (kbuf.dsize >= namelen && (
3673                                 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
3674                         TALLOC_CTX *mem_ctx;
3675                         char *keystr;
3676                         int ret;
3677 
3678                         keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
3679                         if (!keystr) {
3680                                 return 1;
3681                         }
3682                         memcpy(keystr, kbuf.dptr, kbuf.dsize);
3683                         keystr[kbuf.dsize] = '\0';
3684 
3685                         mem_ctx = talloc_init("validate_ctx");
3686                         if (!mem_ctx) {
3687                                 SAFE_FREE(keystr);
3688                                 return 1;
3689                         }
3690 
3691                         ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf, 
3692                                                           v_state);
3693 
3694                         SAFE_FREE(keystr);
3695                         talloc_destroy(mem_ctx);
3696                         return ret;
3697                 }
3698         }
3699 
3700         DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
3701         dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize);
3702         DEBUG(0,("data :\n"));
3703         dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize);
3704         v_state->unknown_key = true;
3705         v_state->success = false;
3706         return 1; /* terminate. */
3707 }
3708 
3709 static void validate_panic(const char *const why)
     /* [<][>][^][v][top][bottom][index][help] */
3710 {
3711         DEBUG(0,("validating cache: would panic %s\n", why ));
3712         DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
3713         exit(47);
3714 }
3715 
3716 /***********************************************************************
3717  Try and validate every entry in the winbindd cache. If we fail here,
3718  delete the cache tdb and return non-zero.
3719 ***********************************************************************/
3720 
3721 int winbindd_validate_cache(void)
     /* [<][>][^][v][top][bottom][index][help] */
3722 {
3723         int ret = -1;
3724         const char *tdb_path = cache_path("winbindd_cache.tdb");
3725         TDB_CONTEXT *tdb = NULL;
3726 
3727         DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3728         smb_panic_fn = validate_panic;
3729 
3730 
3731         tdb = tdb_open_log(tdb_path, 
3732                            WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3733                            ( lp_winbind_offline_logon() 
3734                              ? TDB_DEFAULT 
3735                              : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
3736                            O_RDWR|O_CREAT, 
3737                            0600);
3738         if (!tdb) {
3739                 DEBUG(0, ("winbindd_validate_cache: "
3740                           "error opening/initializing tdb\n"));
3741                 goto done;
3742         }
3743         tdb_close(tdb);
3744 
3745         ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
3746 
3747         if (ret != 0) {
3748                 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
3749                 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
3750                 unlink(tdb_path);
3751         }
3752 
3753 done:
3754         DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
3755         smb_panic_fn = smb_panic;
3756         return ret;
3757 }
3758 
3759 /***********************************************************************
3760  Try and validate every entry in the winbindd cache.
3761 ***********************************************************************/
3762 
3763 int winbindd_validate_cache_nobackup(void)
     /* [<][>][^][v][top][bottom][index][help] */
3764 {
3765         int ret = -1;
3766         const char *tdb_path = cache_path("winbindd_cache.tdb");
3767 
3768         DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3769         smb_panic_fn = validate_panic;
3770 
3771 
3772         if (wcache == NULL || wcache->tdb == NULL) {
3773                 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
3774         } else {
3775                 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
3776         }
3777 
3778         if (ret != 0) {
3779                 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
3780                            "successful.\n"));
3781         }
3782 
3783         DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
3784                    "function\n"));
3785         smb_panic_fn = smb_panic;
3786         return ret;
3787 }
3788 
3789 bool winbindd_cache_validate_and_initialize(void)
     /* [<][>][^][v][top][bottom][index][help] */
3790 {
3791         close_winbindd_cache();
3792 
3793         if (lp_winbind_offline_logon()) {
3794                 if (winbindd_validate_cache() < 0) {
3795                         DEBUG(0, ("winbindd cache tdb corrupt and no backup "
3796                                   "could be restored.\n"));
3797                 }
3798         }
3799 
3800         return initialize_winbindd_cache();
3801 }
3802 
3803 /*********************************************************************
3804  ********************************************************************/
3805 
3806 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
     /* [<][>][^][v][top][bottom][index][help] */
3807                                        struct winbindd_tdc_domain **domains, 
3808                                        size_t *num_domains )
3809 {
3810         struct winbindd_tdc_domain *list = NULL;
3811         size_t idx;
3812         int i;
3813         bool set_only = false;
3814         
3815         /* don't allow duplicates */
3816 
3817         idx = *num_domains;
3818         list = *domains;
3819         
3820         for ( i=0; i< (*num_domains); i++ ) {
3821                 if ( strequal( new_dom->name, list[i].domain_name ) ) {
3822                         DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
3823                                   new_dom->name));
3824                         idx = i;
3825                         set_only = true;
3826                         
3827                         break;
3828                 }
3829         }
3830 
3831         if ( !set_only ) {
3832                 if ( !*domains ) {
3833                         list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 );
3834                         idx = 0;
3835                 } else {
3836                         list = TALLOC_REALLOC_ARRAY( *domains, *domains, 
3837                                                      struct winbindd_tdc_domain,  
3838                                                      (*num_domains)+1);
3839                         idx = *num_domains;             
3840                 }
3841 
3842                 ZERO_STRUCT( list[idx] );
3843         }
3844 
3845         if ( !list )
3846                 return false;
3847 
3848         list[idx].domain_name = talloc_strdup( list, new_dom->name );
3849         list[idx].dns_name = talloc_strdup( list, new_dom->alt_name );
3850 
3851         if ( !is_null_sid( &new_dom->sid ) ) {
3852                 sid_copy( &list[idx].sid, &new_dom->sid );
3853         } else {
3854                 sid_copy(&list[idx].sid, &global_sid_NULL);
3855         }
3856 
3857         if ( new_dom->domain_flags != 0x0 )
3858                 list[idx].trust_flags = new_dom->domain_flags;  
3859 
3860         if ( new_dom->domain_type != 0x0 )
3861                 list[idx].trust_type = new_dom->domain_type;
3862 
3863         if ( new_dom->domain_trust_attribs != 0x0 )
3864                 list[idx].trust_attribs = new_dom->domain_trust_attribs;
3865         
3866         if ( !set_only ) {
3867                 *domains = list;
3868                 *num_domains = idx + 1; 
3869         }
3870 
3871         return true;
3872 }
3873 
3874 /*********************************************************************
3875  ********************************************************************/
3876 
3877 static TDB_DATA make_tdc_key( const char *domain_name )
     /* [<][>][^][v][top][bottom][index][help] */
3878 {
3879         char *keystr = NULL;
3880         TDB_DATA key = { NULL, 0 };
3881         
3882         if ( !domain_name ) {
3883                 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
3884                 return key;
3885         }
3886                
3887                 
3888         if (asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ) == -1) {
3889                 return key;
3890         }
3891         key = string_term_tdb_data(keystr);
3892         
3893         return key;     
3894 }
3895 
3896 /*********************************************************************
3897  ********************************************************************/
3898 
3899 static int pack_tdc_domains( struct winbindd_tdc_domain *domains, 
     /* [<][>][^][v][top][bottom][index][help] */
3900                              size_t num_domains,
3901                              unsigned char **buf )
3902 {
3903         unsigned char *buffer = NULL;
3904         int len = 0;
3905         int buflen = 0;
3906         int i = 0;
3907 
3908         DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
3909                   (int)num_domains));
3910         
3911         buflen = 0;
3912         
3913  again: 
3914         len = 0;
3915         
3916         /* Store the number of array items first */
3917         len += tdb_pack( buffer+len, buflen-len, "d", 
3918                          num_domains );
3919 
3920         /* now pack each domain trust record */
3921         for ( i=0; i<num_domains; i++ ) {
3922 
3923                 fstring tmp;
3924 
3925                 if ( buflen > 0 ) {
3926                         DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
3927                                   domains[i].domain_name,
3928                                   domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
3929                 }
3930                 
3931                 len += tdb_pack( buffer+len, buflen-len, "fffddd",
3932                                  domains[i].domain_name,
3933                                  domains[i].dns_name,
3934                                  sid_to_fstring(tmp, &domains[i].sid),
3935                                  domains[i].trust_flags,
3936                                  domains[i].trust_attribs,
3937                                  domains[i].trust_type );
3938         }
3939 
3940         if ( buflen < len ) {
3941                 SAFE_FREE(buffer);
3942                 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
3943                         DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
3944                         buflen = -1;
3945                         goto done;
3946                 }
3947                 buflen = len;
3948                 goto again;
3949         }
3950 
3951         *buf = buffer;  
3952         
3953  done:  
3954         return buflen;  
3955 }
3956 
3957 /*********************************************************************
3958  ********************************************************************/
3959 
3960 static size_t unpack_tdc_domains( unsigned char *buf, int buflen, 
     /* [<][>][^][v][top][bottom][index][help] */
3961                                   struct winbindd_tdc_domain **domains )
3962 {
3963         fstring domain_name, dns_name, sid_string;      
3964         uint32 type, attribs, flags;
3965         int num_domains;
3966         int len = 0;
3967         int i;
3968         struct winbindd_tdc_domain *list = NULL;
3969 
3970         /* get the number of domains */
3971         len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
3972         if ( len == -1 ) {
3973                 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));               
3974                 return 0;
3975         }
3976 
3977         list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains );
3978         if ( !list ) {
3979                 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
3980                 return 0;               
3981         }
3982         
3983         for ( i=0; i<num_domains; i++ ) {
3984                 len += tdb_unpack( buf+len, buflen-len, "fffddd",
3985                                    domain_name,
3986                                    dns_name,
3987                                    sid_string,
3988                                    &flags,
3989                                    &attribs,
3990                                    &type );
3991 
3992                 if ( len == -1 ) {
3993                         DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3994                         TALLOC_FREE( list );                    
3995                         return 0;
3996                 }
3997 
3998                 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
3999                           "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4000                           domain_name, dns_name, sid_string,
4001                           flags, attribs, type));
4002                 
4003                 list[i].domain_name = talloc_strdup( list, domain_name );
4004                 list[i].dns_name = talloc_strdup( list, dns_name );
4005                 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {                   
4006                         DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4007                                   domain_name));
4008                 }
4009                 list[i].trust_flags = flags;
4010                 list[i].trust_attribs = attribs;
4011                 list[i].trust_type = type;
4012         }
4013 
4014         *domains = list;
4015         
4016         return num_domains;
4017 }
4018 
4019 /*********************************************************************
4020  ********************************************************************/
4021 
4022 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
     /* [<][>][^][v][top][bottom][index][help] */
4023 {
4024         TDB_DATA key = make_tdc_key( lp_workgroup() );   
4025         TDB_DATA data = { NULL, 0 };
4026         int ret;
4027         
4028         if ( !key.dptr )
4029                 return false;
4030         
4031         /* See if we were asked to delete the cache entry */
4032 
4033         if ( !domains ) {
4034                 ret = tdb_delete( wcache->tdb, key );
4035                 goto done;
4036         }
4037         
4038         data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
4039         
4040         if ( !data.dptr ) {
4041                 ret = -1;
4042                 goto done;
4043         }
4044                 
4045         ret = tdb_store( wcache->tdb, key, data, 0 );
4046 
4047  done:
4048         SAFE_FREE( data.dptr );
4049         SAFE_FREE( key.dptr );
4050         
4051         return ( ret != -1 );   
4052 }
4053 
4054 /*********************************************************************
4055  ********************************************************************/
4056 
4057 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
     /* [<][>][^][v][top][bottom][index][help] */
4058 {
4059         TDB_DATA key = make_tdc_key( lp_workgroup() );
4060         TDB_DATA data = { NULL, 0 };
4061 
4062         *domains = NULL;        
4063         *num_domains = 0;       
4064 
4065         if ( !key.dptr )
4066                 return false;
4067         
4068         data = tdb_fetch( wcache->tdb, key );
4069 
4070         SAFE_FREE( key.dptr );
4071         
4072         if ( !data.dptr ) 
4073                 return false;
4074         
4075         *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
4076 
4077         SAFE_FREE( data.dptr );
4078         
4079         if ( !*domains )
4080                 return false;
4081 
4082         return true;
4083 }
4084 
4085 /*********************************************************************
4086  ********************************************************************/
4087 
4088 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
     /* [<][>][^][v][top][bottom][index][help] */
4089 {
4090         struct winbindd_tdc_domain *dom_list = NULL;
4091         size_t num_domains = 0;
4092         bool ret = false;
4093 
4094         DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4095                   "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4096                   domain->name, domain->alt_name, 
4097                   sid_string_dbg(&domain->sid),
4098                   domain->domain_flags,
4099                   domain->domain_trust_attribs,
4100                   domain->domain_type));        
4101         
4102         if ( !init_wcache() ) {
4103                 return false;
4104         }
4105         
4106         /* fetch the list */
4107 
4108         wcache_tdc_fetch_list( &dom_list, &num_domains );
4109         
4110         /* add the new domain */
4111 
4112         if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
4113                 goto done;              
4114         }       
4115 
4116         /* pack the domain */
4117 
4118         if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
4119                 goto done;              
4120         }
4121         
4122         /* Success */
4123 
4124         ret = true;
4125  done:
4126         TALLOC_FREE( dom_list );
4127         
4128         return ret;     
4129 }
4130 
4131 /*********************************************************************
4132  ********************************************************************/
4133 
4134 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
     /* [<][>][^][v][top][bottom][index][help] */
4135 {
4136         struct winbindd_tdc_domain *dom_list = NULL;
4137         size_t num_domains = 0;
4138         int i;
4139         struct winbindd_tdc_domain *d = NULL;   
4140 
4141         DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
4142 
4143         if ( !init_wcache() ) {
4144                 return false;
4145         }
4146         
4147         /* fetch the list */
4148 
4149         wcache_tdc_fetch_list( &dom_list, &num_domains );
4150         
4151         for ( i=0; i<num_domains; i++ ) {
4152                 if ( strequal(name, dom_list[i].domain_name) ||
4153                      strequal(name, dom_list[i].dns_name) )
4154                 {
4155                         DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4156                                   name));
4157                         
4158                         d = TALLOC_P( ctx, struct winbindd_tdc_domain );
4159                         if ( !d )
4160                                 break;                  
4161                         
4162                         d->domain_name = talloc_strdup( d, dom_list[i].domain_name );
4163                         d->dns_name = talloc_strdup( d, dom_list[i].dns_name );
4164                         sid_copy( &d->sid, &dom_list[i].sid );
4165                         d->trust_flags   = dom_list[i].trust_flags;
4166                         d->trust_type    = dom_list[i].trust_type;
4167                         d->trust_attribs = dom_list[i].trust_attribs;
4168 
4169                         break;
4170                 }
4171         }
4172 
4173         TALLOC_FREE( dom_list );
4174         
4175         return d;       
4176 }
4177 
4178 
4179 /*********************************************************************
4180  ********************************************************************/
4181 
4182 void wcache_tdc_clear( void )
     /* [<][>][^][v][top][bottom][index][help] */
4183 {
4184         if ( !init_wcache() )
4185                 return;
4186 
4187         wcache_tdc_store_list( NULL, 0 );
4188         
4189         return; 
4190 }
4191 
4192 
4193 /*********************************************************************
4194  ********************************************************************/
4195 
4196 static void wcache_save_user_pwinfo(struct winbindd_domain *domain, 
     /* [<][>][^][v][top][bottom][index][help] */
4197                                     NTSTATUS status,
4198                                     const DOM_SID *user_sid,
4199                                     const char *homedir,
4200                                     const char *shell,
4201                                     const char *gecos,
4202                                     uint32 gid)
4203 {
4204         struct cache_entry *centry;
4205         fstring tmp;
4206 
4207         if ( (centry = centry_start(domain, status)) == NULL )
4208                 return;
4209 
4210         centry_put_string( centry, homedir );
4211         centry_put_string( centry, shell );
4212         centry_put_string( centry, gecos );
4213         centry_put_uint32( centry, gid );
4214         
4215         centry_end(centry, "NSS/PWINFO/%s", sid_to_fstring(tmp, user_sid) );
4216 
4217         DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid) ));
4218 
4219         centry_free(centry);
4220 }
4221 
4222 NTSTATUS nss_get_info_cached( struct winbindd_domain *domain, 
     /* [<][>][^][v][top][bottom][index][help] */
4223                               const DOM_SID *user_sid,
4224                               TALLOC_CTX *ctx,
4225                               ADS_STRUCT *ads, LDAPMessage *msg,
4226                               char **homedir, char **shell, char **gecos,
4227                               gid_t *p_gid)
4228 {
4229         struct winbind_cache *cache = get_cache(domain);
4230         struct cache_entry *centry = NULL;
4231         NTSTATUS nt_status;
4232         fstring tmp;
4233 
4234         if (!cache->tdb)
4235                 goto do_query;
4236 
4237         centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s",
4238                               sid_to_fstring(tmp, user_sid));
4239         
4240         if (!centry)
4241                 goto do_query;
4242 
4243         *homedir = centry_string( centry, ctx );
4244         *shell   = centry_string( centry, ctx );
4245         *gecos   = centry_string( centry, ctx );
4246         *p_gid   = centry_uint32( centry );     
4247 
4248         centry_free(centry);
4249 
4250         DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4251                   sid_string_dbg(user_sid)));
4252 
4253         return NT_STATUS_OK;
4254 
4255 do_query:
4256         
4257         nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg, 
4258                                   homedir, shell, gecos, p_gid );
4259 
4260         DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status)));
4261 
4262         if ( NT_STATUS_IS_OK(nt_status) ) {
4263                 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir));
4264                 DEBUGADD(10, ("\tshell = '%s'\n", *shell));
4265                 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos));
4266                 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid));
4267 
4268                 wcache_save_user_pwinfo( domain, nt_status, user_sid,
4269                                          *homedir, *shell, *gecos, *p_gid );
4270         }       
4271 
4272         if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
4273                 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4274                          domain->name ));
4275                 set_domain_offline( domain );
4276         }
4277 
4278         return nt_status;       
4279 }
4280 
4281 
4282 /* the cache backend methods are exposed via this structure */
4283 struct winbindd_methods cache_methods = {
4284         true,
4285         query_user_list,
4286         enum_dom_groups,
4287         enum_local_groups,
4288         name_to_sid,
4289         sid_to_name,
4290         rids_to_names,
4291         query_user,
4292         lookup_usergroups,
4293         lookup_useraliases,
4294         lookup_groupmem,
4295         sequence_number,
4296         lockout_policy,
4297         password_policy,
4298         trusted_domains
4299 };

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