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 "libsmbclient.h" 25#include "libsmb_internal.h" 26 27/* 28 * Structure we use if internal caching mechanism is used 29 * nothing fancy here. 30 */ 31struct smbc_server_cache { 32 char *server_name; 33 char *share_name; 34 char *workgroup; 35 char *username; 36 SMBCSRV *server; 37 38 struct smbc_server_cache *next, *prev; 39}; 40 41 42 43/* 44 * Add a new connection to the server cache. 45 * This function is only used if the external cache is not enabled 46 */ 47int 48SMBC_add_cached_server(SMBCCTX * context, 49 SMBCSRV * newsrv, 50 const char * server, 51 const char * share, 52 const char * workgroup, 53 const char * username) 54{ 55 struct smbc_server_cache * srvcache = NULL; 56 57 if (!(srvcache = SMB_MALLOC_P(struct smbc_server_cache))) { 58 errno = ENOMEM; 59 DEBUG(3, ("Not enough space for server cache allocation\n")); 60 return 1; 61 } 62 63 ZERO_STRUCTP(srvcache); 64 65 srvcache->server = newsrv; 66 67 srvcache->server_name = SMB_STRDUP(server); 68 if (!srvcache->server_name) { 69 errno = ENOMEM; 70 goto failed; 71 } 72 73 srvcache->share_name = SMB_STRDUP(share); 74 if (!srvcache->share_name) { 75 errno = ENOMEM; 76 goto failed; 77 } 78 79 srvcache->workgroup = SMB_STRDUP(workgroup); 80 if (!srvcache->workgroup) { 81 errno = ENOMEM; 82 goto failed; 83 } 84 85 srvcache->username = SMB_STRDUP(username); 86 if (!srvcache->username) { 87 errno = ENOMEM; 88 goto failed; 89 } 90 91 DLIST_ADD(context->internal->server_cache, srvcache); 92 return 0; 93 94failed: 95 SAFE_FREE(srvcache->server_name); 96 SAFE_FREE(srvcache->share_name); 97 SAFE_FREE(srvcache->workgroup); 98 SAFE_FREE(srvcache->username); 99 SAFE_FREE(srvcache); 100 101 return 1; 102} 103 104 105 106/* 107 * Search the server cache for a server 108 * returns server handle on success, NULL on error (not found) 109 * This function is only used if the external cache is not enabled 110 */ 111SMBCSRV * 112SMBC_get_cached_server(SMBCCTX * context, 113 const char * server, 114 const char * share, 115 const char * workgroup, 116 const char * user) 117{ 118 struct smbc_server_cache * srv = NULL; 119 120 /* Search the cache lines */ 121 for (srv = context->internal->server_cache; srv; srv = srv->next) { 122 123 if (strcmp(server,srv->server_name) == 0 && 124 strcmp(workgroup,srv->workgroup) == 0 && 125 strcmp(user, srv->username) == 0) { 126 127 /* If the share name matches, we're cool */ 128 if (strcmp(share, srv->share_name) == 0) { 129 return srv->server; 130 } 131 132 /* 133 * We only return an empty share name or the attribute 134 * server on an exact match (which would have been 135 * caught above). 136 */ 137 if (*share == '\0' || strcmp(share, "*IPC$") == 0) 138 continue; 139 140 /* 141 * Never return an empty share name or the attribute 142 * server if it wasn't what was requested. 143 */ 144 if (*srv->share_name == '\0' || 145 strcmp(srv->share_name, "*IPC$") == 0) 146 continue; 147 148 /* 149 * If we're only allowing one share per server, then 150 * a connection to the server (other than the 151 * attribute server connection) is cool. 152 */ 153 if (smbc_getOptionOneSharePerServer(context)) { 154 /* 155 * The currently connected share name 156 * doesn't match the requested share, so 157 * disconnect from the current share. 158 */ 159 if (! cli_tdis(srv->server->cli)) { 160 /* Sigh. Couldn't disconnect. */ 161 cli_shutdown(srv->server->cli); 162 srv->server->cli = NULL; 163 smbc_getFunctionRemoveCachedServer(context)(context, srv->server); 164 continue; 165 } 166 167 /* 168 * Save the new share name. We've 169 * disconnected from the old share, and are 170 * about to connect to the new one. 171 */ 172 SAFE_FREE(srv->share_name); 173 srv->share_name = SMB_STRDUP(share); 174 if (!srv->share_name) { 175 /* Out of memory. */ 176 cli_shutdown(srv->server->cli); 177 srv->server->cli = NULL; 178 smbc_getFunctionRemoveCachedServer(context)(context, srv->server); 179 continue; 180 } 181 182 183 return srv->server; 184 } 185 } 186 } 187 188 return NULL; 189} 190 191 192/* 193 * Search the server cache for a server and remove it 194 * returns 0 on success 195 * This function is only used if the external cache is not enabled 196 */ 197int 198SMBC_remove_cached_server(SMBCCTX * context, 199 SMBCSRV * server) 200{ 201 struct smbc_server_cache * srv = NULL; 202 203 for (srv = context->internal->server_cache; srv; srv = srv->next) { 204 if (server == srv->server) { 205 206 /* remove this sucker */ 207 DLIST_REMOVE(context->internal->server_cache, srv); 208 SAFE_FREE(srv->server_name); 209 SAFE_FREE(srv->share_name); 210 SAFE_FREE(srv->workgroup); 211 SAFE_FREE(srv->username); 212 SAFE_FREE(srv); 213 return 0; 214 } 215 } 216 /* server not found */ 217 return 1; 218} 219 220 221/* 222 * Try to remove all the servers in cache 223 * returns 1 on failure and 0 if all servers could be removed. 224 */ 225int 226SMBC_purge_cached_servers(SMBCCTX * context) 227{ 228 struct smbc_server_cache * srv; 229 struct smbc_server_cache * next; 230 int could_not_purge_all = 0; 231 232 for (srv = context->internal->server_cache, 233 next = (srv ? srv->next :NULL); 234 srv; 235 srv = next, 236 next = (srv ? srv->next : NULL)) { 237 238 if (SMBC_remove_unused_server(context, srv->server)) { 239 /* could not be removed */ 240 could_not_purge_all = 1; 241 } 242 } 243 return could_not_purge_all; 244} 245