1/* 2 Unix SMB/CIFS implementation. 3 SMB wrapper directory functions 4 Copyright (C) Tim Potter 2000 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19*/ 20 21#include "includes.h" 22 23/* We cache lists of workgroups, lists of servers in workgroups, and lists 24 of shares exported by servers. */ 25 26#define CACHE_TIMEOUT 30 27 28struct name_list { 29 struct name_list *prev, *next; 30 char *name; 31 uint32 stype; 32 char *comment; 33}; 34 35struct cached_names { 36 struct cached_names *prev, *next; 37 char *key; 38 struct name_list *name_list; 39 time_t cache_timeout; 40 int result; 41}; 42 43static struct cached_names *cached_names = NULL; 44 45/* Find a list of cached name for a workgroup, server or share list */ 46 47static struct cached_names *find_cached_names(char *key) 48{ 49 struct cached_names *tmp; 50 51 for (tmp = cached_names; tmp; tmp = tmp->next) { 52 if (strequal(tmp->key, key)) { 53 return tmp; 54 } 55 } 56 57 return NULL; 58} 59 60/* Add a name to a list stored in the state variable */ 61 62static void add_cached_names(const char *name, uint32 stype, 63 const char *comment, void *state) 64{ 65 struct name_list **name_list = (struct name_list **)state; 66 struct name_list *new_name; 67 68 new_name = SMB_MALLOC_P(struct name_list); 69 if (!new_name) return; 70 71 ZERO_STRUCTP(new_name); 72 73 new_name->name = SMB_STRDUP(name); 74 new_name->stype = stype; 75 new_name->comment = SMB_STRDUP(comment); 76 77 DLIST_ADD(*name_list, new_name); 78} 79 80static void free_name_list(struct name_list *name_list) 81{ 82 struct name_list *tmp = name_list; 83 84 while(tmp) { 85 struct name_list *next; 86 87 next = tmp->next; 88 89 SAFE_FREE(tmp->name); 90 SAFE_FREE(tmp->comment); 91 SAFE_FREE(tmp); 92 93 tmp = next; 94 } 95} 96 97/* Wrapper for NetServerEnum function */ 98 99BOOL smbw_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype, 100 void (*fn)(const char *, uint32, const char *, void *), 101 void *state) 102{ 103 struct cached_names *names; 104 struct name_list *tmp; 105 time_t now = time(NULL); 106 char key[PATH_MAX]; 107 BOOL result = True; 108 109 slprintf(key, PATH_MAX - 1, "%s/%s#%s", cli->desthost, 110 workgroup, (stype == SV_TYPE_DOMAIN_ENUM ? "DOM" : "SRV")); 111 112 names = find_cached_names(key); 113 114 if (names == NULL || (now - names->cache_timeout) > CACHE_TIMEOUT) { 115 struct cached_names *new_names = NULL; 116 117 /* No names cached for this workgroup */ 118 119 if (names == NULL) { 120 new_names = SMB_MALLOC_P(struct cached_names); 121 122 ZERO_STRUCTP(new_names); 123 DLIST_ADD(cached_names, new_names); 124 125 } else { 126 127 /* Dispose of out of date name list */ 128 129 free_name_list(names->name_list); 130 names->name_list = NULL; 131 132 new_names = names; 133 } 134 135 result = cli_NetServerEnum(cli, workgroup, stype, 136 add_cached_names, 137 &new_names->name_list); 138 139 new_names->cache_timeout = now; 140 new_names->result = result; 141 new_names->key = SMB_STRDUP(key); 142 143 names = new_names; 144 } 145 146 /* Return names by running callback function. */ 147 148 for (tmp = names->name_list; tmp; tmp = tmp->next) 149 fn(tmp->name, stype, tmp->comment, state); 150 151 return names->result; 152} 153 154/* Wrapper for RNetShareEnum function */ 155 156int smbw_RNetShareEnum(struct cli_state *cli, 157 void (*fn)(const char *, uint32, const char *, void *), 158 void *state) 159{ 160 struct cached_names *names; 161 struct name_list *tmp; 162 time_t now = time(NULL); 163 char key[PATH_MAX]; 164 165 slprintf(key, PATH_MAX - 1, "SHARE/%s", cli->desthost); 166 167 names = find_cached_names(key); 168 169 if (names == NULL || (now - names->cache_timeout) > CACHE_TIMEOUT) { 170 struct cached_names *new_names = NULL; 171 172 /* No names cached for this server */ 173 174 if (names == NULL) { 175 new_names = SMB_MALLOC_P(struct cached_names); 176 177 ZERO_STRUCTP(new_names); 178 DLIST_ADD(cached_names, new_names); 179 180 } else { 181 182 /* Dispose of out of date name list */ 183 184 free_name_list(names->name_list); 185 names->name_list = NULL; 186 187 new_names = names; 188 } 189 190 new_names->result = cli_RNetShareEnum(cli, add_cached_names, 191 &new_names->name_list); 192 193 new_names->cache_timeout = now; 194 new_names->key = SMB_STRDUP(key); 195 196 names = new_names; 197 } 198 199 /* Return names by running callback function. */ 200 201 for (tmp = names->name_list; tmp; tmp = tmp->next) 202 fn(tmp->name, tmp->stype, tmp->comment, state); 203 204 return names->result; 205} 206