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 : }