Initial import
[samba] / 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         
98         return 1;
99 }
100
101
102
103 /*
104  * Search the server cache for a server 
105  * returns server handle on success, NULL on error (not found)
106  * This function is only used if the external cache is not enabled 
107  */
108 static SMBCSRV * smbc_get_cached_server(SMBCCTX * context, const char * server, 
109                                   const char * share, const char * workgroup, const char * user)
110 {
111         struct smbc_server_cache * srv = NULL;
112         
113         /* Search the cache lines */
114         for (srv=((struct smbc_server_cache *)context->server_cache);srv;srv=srv->next) {
115
116                 if (strcmp(server,srv->server_name)  == 0 &&
117                     strcmp(workgroup,srv->workgroup) == 0 &&
118                     strcmp(user, srv->username)  == 0) {
119
120                         /* If the share name matches, we're cool */
121                         if (strcmp(share, srv->share_name) == 0) {
122                                 return srv->server;
123                         }
124
125                         /*
126                          * We only return an empty share name or the attribute
127                          * server on an exact match (which would have been
128                          * caught above).
129                          */
130                         if (*share == '\0' || strcmp(share, "*IPC$") == 0)
131                                 continue;
132
133                         /*
134                          * Never return an empty share name or the attribute
135                          * server if it wasn't what was requested.
136                          */
137                         if (*srv->share_name == '\0' ||
138                             strcmp(srv->share_name, "*IPC$") == 0)
139                                 continue;
140
141                         /*
142                          * If we're only allowing one share per server, then
143                          * a connection to the server (other than the
144                          * attribute server connection) is cool.
145                          */
146                         if (context->options.one_share_per_server) {
147                                 /*
148                                  * The currently connected share name
149                                  * doesn't match the requested share, so
150                                  * disconnect from the current share.
151                                  */
152                                 if (! cli_tdis(&srv->server->cli)) {
153                                         /* Sigh. Couldn't disconnect. */
154                                         cli_shutdown(&srv->server->cli);
155                                         context->callbacks.remove_cached_srv_fn(context, srv->server);
156                                         continue;
157                                 }
158
159                                 return srv->server;
160                         }
161                 }
162         }
163
164         return NULL;
165 }
166
167
168 /* 
169  * Search the server cache for a server and remove it
170  * returns 0 on success
171  * This function is only used if the external cache is not enabled 
172  */
173 static int smbc_remove_cached_server(SMBCCTX * context, SMBCSRV * server)
174 {
175         struct smbc_server_cache * srv = NULL;
176         
177         for (srv=((struct smbc_server_cache *)context->server_cache);srv;srv=srv->next) {
178                 if (server == srv->server) { 
179
180                         /* remove this sucker */
181                         DLIST_REMOVE(context->server_cache, srv);
182                         SAFE_FREE(srv->server_name);
183                         SAFE_FREE(srv->share_name);
184                         SAFE_FREE(srv->workgroup);
185                         SAFE_FREE(srv->username);
186                         SAFE_FREE(srv);
187                         return 0;
188                 }
189         }
190         /* server not found */
191         return 1;
192 }
193
194
195 /*
196  * Try to remove all the servers in cache
197  * returns 1 on failure and 0 if all servers could be removed.
198  */
199 static int smbc_purge_cached(SMBCCTX * context)
200 {
201         struct smbc_server_cache * srv;
202         struct smbc_server_cache * next;
203         int could_not_purge_all = 0;
204
205         for (srv = ((struct smbc_server_cache *) context->server_cache),
206                  next = (srv ? srv->next :NULL);
207              srv;
208              srv = next, next = (srv ? srv->next : NULL)) {
209
210                 if (smbc_remove_unused_server(context, srv->server)) {
211                         /* could not be removed */
212                         could_not_purge_all = 1;
213                 }
214         }
215         return could_not_purge_all;
216 }
217
218
219
220 /*
221  * This functions initializes all server-cache related functions 
222  * to the default (internal) system.
223  *
224  * We use this to make the rest of the cache system static.
225  */
226
227 int smbc_default_cache_functions(SMBCCTX * context)
228 {
229         context->callbacks.add_cached_srv_fn    = smbc_add_cached_server;
230         context->callbacks.get_cached_srv_fn    = smbc_get_cached_server;
231         context->callbacks.remove_cached_srv_fn = smbc_remove_cached_server;
232         context->callbacks.purge_cached_fn      = smbc_purge_cached;
233
234         return 0;
235 }