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