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