r16945: Sync trunk -> 3.0 for 3.0.24 code. Still need
[tprouty/samba.git] / source / libsmb / libsmb_cache.c
1
2 /* 
3    Unix SMB/CIFS implementation.
4    SMB client library implementation (server cache)
5    Copyright (C) Andrew Tridgell 1998
6    Copyright (C) Richard Sharpe 2000
7    Copyright (C) John Terpstra 2000
8    Copyright (C) Tom Jansen (Ninja ISD) 2002 
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26
27 #include "include/libsmbclient.h"
28 #include "../include/libsmb_internal.h"
29 /*
30  * Structure we use if internal caching mechanism is used 
31  * nothing fancy here.
32  */
33 struct smbc_server_cache {
34         char *server_name;
35         char *share_name;
36         char *workgroup;
37         char *username;
38         SMBCSRV *server;
39         
40         struct smbc_server_cache *next, *prev;
41 };
42         
43
44
45 /*
46  * Add a new connection to the server cache.
47  * This function is only used if the external cache is not enabled 
48  */
49 static int smbc_add_cached_server(SMBCCTX * context, SMBCSRV * newsrv,
50                                   const char * server, const char * share, 
51                                   const char * workgroup, const char * username)
52 {
53         struct smbc_server_cache * srvcache = NULL;
54
55         if (!(srvcache = SMB_MALLOC_P(struct smbc_server_cache))) {
56                 errno = ENOMEM;
57                 DEBUG(3, ("Not enough space for server cache allocation\n"));
58                 return 1;
59         }
60        
61         ZERO_STRUCTP(srvcache);
62
63         srvcache->server = newsrv;
64
65         srvcache->server_name = SMB_STRDUP(server);
66         if (!srvcache->server_name) {
67                 errno = ENOMEM;
68                 goto failed;
69         }
70
71         srvcache->share_name = SMB_STRDUP(share);
72         if (!srvcache->share_name) {
73                 errno = ENOMEM;
74                 goto failed;
75         }
76
77         srvcache->workgroup = SMB_STRDUP(workgroup);
78         if (!srvcache->workgroup) {
79                 errno = ENOMEM;
80                 goto failed;
81         }
82
83         srvcache->username = SMB_STRDUP(username);
84         if (!srvcache->username) {
85                 errno = ENOMEM;
86                 goto failed;
87         }
88
89         DLIST_ADD((context->server_cache), srvcache);
90         return 0;
91
92  failed:
93         SAFE_FREE(srvcache->server_name);
94         SAFE_FREE(srvcache->share_name);
95         SAFE_FREE(srvcache->workgroup);
96         SAFE_FREE(srvcache->username);
97         SAFE_FREE(srvcache);
98         
99         return 1;
100 }
101
102
103
104 /*
105  * Search the server cache for a server 
106  * returns server handle on success, NULL on error (not found)
107  * This function is only used if the external cache is not enabled 
108  */
109 static SMBCSRV * smbc_get_cached_server(SMBCCTX * context, const char * server, 
110                                   const char * share, const char * workgroup, const char * user)
111 {
112         struct smbc_server_cache * srv = NULL;
113         
114         /* Search the cache lines */
115         for (srv=((struct smbc_server_cache *)context->server_cache);srv;srv=srv->next) {
116
117                 if (strcmp(server,srv->server_name)  == 0 &&
118                     strcmp(workgroup,srv->workgroup) == 0 &&
119                     strcmp(user, srv->username)  == 0) {
120
121                         /* If the share name matches, we're cool */
122                         if (strcmp(share, srv->share_name) == 0) {
123                                 return srv->server;
124                         }
125
126                         /*
127                          * We only return an empty share name or the attribute
128                          * server on an exact match (which would have been
129                          * caught above).
130                          */
131                         if (*share == '\0' || strcmp(share, "*IPC$") == 0)
132                                 continue;
133
134                         /*
135                          * Never return an empty share name or the attribute
136                          * server if it wasn't what was requested.
137                          */
138                         if (*srv->share_name == '\0' ||
139                             strcmp(srv->share_name, "*IPC$") == 0)
140                                 continue;
141
142                         /*
143                          * If we're only allowing one share per server, then
144                          * a connection to the server (other than the
145                          * attribute server connection) is cool.
146                          */
147                         if (context->options.one_share_per_server) {
148                                 /*
149                                  * The currently connected share name
150                                  * doesn't match the requested share, so
151                                  * disconnect from the current share.
152                                  */
153                                 if (! cli_tdis(srv->server->cli)) {
154                                         /* Sigh. Couldn't disconnect. */
155                                         cli_shutdown(srv->server->cli);
156                                         srv->server->cli = NULL;
157                                         context->callbacks.remove_cached_srv_fn(context, srv->server);
158                                         continue;
159                                 }
160
161                                 /*
162                                  * Save the new share name.  We've
163                                  * disconnected from the old share, and are
164                                  * about to connect to the new one.
165                                  */
166                                 SAFE_FREE(srv->share_name);
167                                 srv->share_name = SMB_STRDUP(share);
168                                 if (!srv->share_name) {
169                                         /* Out of memory. */
170                                         cli_shutdown(srv->server->cli);
171                                         srv->server->cli = NULL;
172                                         context->callbacks.remove_cached_srv_fn(context, srv->server);
173                                         continue;
174                                 }
175
176
177                                 return srv->server;
178                         }
179                 }
180         }
181
182         return NULL;
183 }
184
185
186 /* 
187  * Search the server cache for a server and remove it
188  * returns 0 on success
189  * This function is only used if the external cache is not enabled 
190  */
191 static int smbc_remove_cached_server(SMBCCTX * context, SMBCSRV * server)
192 {
193         struct smbc_server_cache * srv = NULL;
194         
195         for (srv=((struct smbc_server_cache *)context->server_cache);srv;srv=srv->next) {
196                 if (server == srv->server) { 
197
198                         /* remove this sucker */
199                         DLIST_REMOVE(context->server_cache, srv);
200                         SAFE_FREE(srv->server_name);
201                         SAFE_FREE(srv->share_name);
202                         SAFE_FREE(srv->workgroup);
203                         SAFE_FREE(srv->username);
204                         SAFE_FREE(srv);
205                         return 0;
206                 }
207         }
208         /* server not found */
209         return 1;
210 }
211
212
213 /*
214  * Try to remove all the servers in cache
215  * returns 1 on failure and 0 if all servers could be removed.
216  */
217 static int smbc_purge_cached(SMBCCTX * context)
218 {
219         struct smbc_server_cache * srv;
220         struct smbc_server_cache * next;
221         int could_not_purge_all = 0;
222
223         for (srv = ((struct smbc_server_cache *) context->server_cache),
224                  next = (srv ? srv->next :NULL);
225              srv;
226              srv = next, next = (srv ? srv->next : NULL)) {
227
228                 if (smbc_remove_unused_server(context, srv->server)) {
229                         /* could not be removed */
230                         could_not_purge_all = 1;
231                 }
232         }
233         return could_not_purge_all;
234 }
235
236
237
238 /*
239  * This functions initializes all server-cache related functions 
240  * to the default (internal) system.
241  *
242  * We use this to make the rest of the cache system static.
243  */
244
245 int smbc_default_cache_functions(SMBCCTX * context)
246 {
247         context->callbacks.add_cached_srv_fn    = smbc_add_cached_server;
248         context->callbacks.get_cached_srv_fn    = smbc_get_cached_server;
249         context->callbacks.remove_cached_srv_fn = smbc_remove_cached_server;
250         context->callbacks.purge_cached_fn      = smbc_purge_cached;
251
252         return 0;
253 }