nsswitch/winbindd_cache.c

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

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