• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/netatalk-2.2.5/libatalk/acl/
1/*
2  Copyright (c) 2008,2009 Frank Lahm <franklahm@gmail.com>
3
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  GNU General Public License for more details.
13*/
14
15#ifdef HAVE_CONFIG_H
16#include "config.h"
17#endif /* HAVE_CONFIG_H */
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <time.h>
23#include <errno.h>
24
25#include <atalk/logger.h>
26#include <atalk/afp.h>
27#include <atalk/uuid.h>
28#include "cache.h"
29
30typedef struct cacheduser {
31    unsigned long uid;      /* for future use */
32    uuidtype_t type;
33    uuidp_t uuid;
34    char *name;
35    time_t creationtime;
36    struct cacheduser *prev;
37    struct cacheduser *next;
38} cacheduser_t;
39
40cacheduser_t *namecache[256];   /* indexed by hash of name */
41cacheduser_t *uuidcache[256];   /* indexed by hash of uuid */
42
43/********************************************************
44 * helper function
45 ********************************************************/
46
47void uuidcache_dump(void) {
48    int i;
49    int ret = 0;
50    cacheduser_t *entry;
51    char timestr[200];
52    struct tm *tmp = NULL;
53
54    for ( i=0 ; i<256; i++) {
55        if ((entry = namecache[i]) != NULL) {
56            do {
57                tmp = localtime(&entry->creationtime);
58                if (tmp == NULL)
59                    continue;
60                if (strftime(timestr, 200, "%c", tmp) == 0)
61                    continue;
62                LOG(log_debug, logtype_default,
63                    "namecache{%d}: name:%s, uuid:%s, type%s: %s, cached: %s",
64                    i,
65                    entry->name,
66                    uuid_bin2string(entry->uuid),
67                    (entry->type & UUID_ENOENT) == UUID_ENOENT ? "[negative]" : "",
68                    uuidtype[entry->type & UUIDTYPESTR_MASK],
69                    timestr);
70            } while ((entry = entry->next) != NULL);
71        }
72    }
73
74    for ( i=0; i<256; i++) {
75        if ((entry = uuidcache[i]) != NULL) {
76            do {
77
78                tmp = localtime(&entry->creationtime);
79                if (tmp == NULL)
80                    continue;
81                if (strftime(timestr, 200, "%c", tmp) == 0)
82                    continue;
83                LOG(log_debug, logtype_default,
84                    "uuidcache{%d}: uuid:%s, name:%s, type%s: %s, cached: %s",
85                    i,
86                    uuid_bin2string(entry->uuid),
87                    entry->name,
88                    (entry->type & UUID_ENOENT) == UUID_ENOENT ? "[negative]" : "",
89                    uuidtype[entry->type & UUIDTYPESTR_MASK],
90                    timestr);
91            } while ((entry = entry->next) != NULL);
92        }
93    }
94}
95
96/* hash string it into unsigned char */
97static unsigned char hashstring(unsigned char *str) {
98    unsigned long hash = 5381;
99    unsigned char index;
100    int c;
101    while ((c = *str++) != 0)
102        hash = ((hash << 5) + hash) ^ c; /* (hash * 33) ^ c */
103
104    index = 85 ^ (hash & 0xff);
105    while ((hash = hash >> 8) != 0)
106        index ^= (hash & 0xff);
107
108    return index;
109}
110
111/* hash atalk_uuid_t into unsigned char */
112static unsigned char hashuuid(uuidp_t uuid) {
113    unsigned char index = 83;
114    int i;
115
116    for (i=0; i<16; i++) {
117        index ^= uuid[i];
118        index += uuid[i];
119    }
120    return index;
121}
122
123/********************************************************
124 * Interface
125 ********************************************************/
126
127int add_cachebyname( const char *inname, const uuidp_t inuuid, const uuidtype_t type, const unsigned long uid _U_) {
128    int ret = 0;
129    char *name = NULL;
130    uuidp_t uuid = NULL;
131    cacheduser_t *cacheduser = NULL;
132    unsigned char hash;
133
134    /* allocate mem and copy values */
135    name = malloc(strlen(inname)+1);
136    if (!name) {
137        LOG(log_error, logtype_default, "add_cachebyname: mallor error");
138        ret = -1;
139        goto cleanup;
140    }
141
142    uuid = malloc(UUID_BINSIZE);
143    if (!uuid) {
144        LOG(log_error, logtype_default, "add_cachebyname: mallor error");
145        ret = -1;
146        goto cleanup;
147    }
148
149    cacheduser = malloc(sizeof(cacheduser_t));
150    if (!cacheduser) {
151        LOG(log_error, logtype_default, "add_cachebyname: mallor error");
152        ret = -1;
153        goto cleanup;
154    }
155
156    strcpy(name, inname);
157    memcpy(uuid, inuuid, UUID_BINSIZE);
158
159    /* fill in the cacheduser */
160    cacheduser->name = name;
161    cacheduser->uuid = uuid;
162    cacheduser->type = type;
163    cacheduser->creationtime = time(NULL);
164    cacheduser->prev = NULL;
165    cacheduser->next = NULL;
166
167    /* get hash */
168    hash = hashstring((unsigned char *)name);
169
170    /* insert cache entry into cache array at head of queue */
171    if (namecache[hash] == NULL) {
172        /* this queue is empty */
173        namecache[hash] = cacheduser;
174    } else {
175        cacheduser->next = namecache[hash];
176        namecache[hash]->prev = cacheduser;
177        namecache[hash] = cacheduser;
178    }
179
180cleanup:
181    if (ret != 0) {
182        if (name)
183            free(name);
184        if (uuid)
185            free(uuid);
186        if (cacheduser)
187            free(cacheduser);
188    }
189
190    return ret;
191}
192
193/*!
194 * Search cache by name and uuid type
195 *
196 * @args name     (r)  name to search
197 * @args type     (rw) type (user or group) of name, returns found type here which might
198 *                     mark it as a negative entry
199 * @args uuid     (w)  found uuid is returned here
200 * @returns       0 on sucess, entry found
201 *                -1 no entry found
202 */
203int search_cachebyname(const char *name, uuidtype_t *type, uuidp_t uuid) {
204    int ret;
205    unsigned char hash;
206    cacheduser_t *entry;
207    time_t tim;
208
209    hash = hashstring((unsigned char *)name);
210
211    if (namecache[hash] == NULL)
212        return -1;
213
214    entry = namecache[hash];
215    while (entry) {
216        ret = strcmp(entry->name, name);
217        if (ret == 0 && *type == (entry->type & UUIDTYPESTR_MASK)) {
218            /* found, now check if expired */
219            tim = time(NULL);
220            if ((tim - entry->creationtime) > CACHESECONDS) {
221                LOG(log_debug, logtype_default, "search_cachebyname: expired: name:\"%s\"", entry->name);
222                /* remove item */
223                if (entry->prev) {
224                    /* 2nd to last in queue */
225                    entry->prev->next = entry->next;
226                    if (entry->next)
227                        /* not the last element */
228                        entry->next->prev = entry->prev;
229                } else  {
230                    /* queue head */
231                    if ((namecache[hash] = entry->next) != NULL)
232                        namecache[hash]->prev = NULL;
233                }
234                free(entry->name);
235                free(entry->uuid);
236                free(entry);
237                return -1;
238            } else {
239                memcpy(uuid, entry->uuid, UUID_BINSIZE);
240                *type = entry->type;
241                return 0;
242            }
243        }
244        entry = entry->next;
245    }
246
247    return -1;
248}
249
250/*
251 * Caller must free allocated name
252 */
253int search_cachebyuuid( uuidp_t uuidp, char **name, uuidtype_t *type) {
254    int ret;
255    unsigned char hash;
256    cacheduser_t *entry;
257    time_t tim;
258
259    hash = hashuuid(uuidp);
260
261    if (! uuidcache[hash])
262        return -1;
263
264    entry = uuidcache[hash];
265    while (entry) {
266        ret = memcmp(entry->uuid, uuidp, UUID_BINSIZE);
267        if (ret == 0) {
268            tim = time(NULL);
269            if ((tim - entry->creationtime) > CACHESECONDS) {
270                LOG(log_debug, logtype_default, "search_cachebyuuid: expired: name:\'%s\' in queue {%d}", entry->name, hash);
271                if (entry->prev) {
272                    /* 2nd to last in queue */
273                    entry->prev->next = entry->next;
274                    if (entry->next)
275                        /* not the last element */
276                        entry->next->prev = entry->prev;
277                } else {
278                    /* queue head  */
279                    if ((uuidcache[hash] = entry->next) != NULL)
280                        uuidcache[hash]->prev = NULL;
281                }
282                free(entry->name);
283                free(entry->uuid);
284                free(entry);
285                return -1;
286            } else {
287                *name = malloc(strlen(entry->name)+1);
288                strcpy(*name, entry->name);
289                *type = entry->type;
290                return 0;
291            }
292        }
293        entry = entry->next;
294    }
295
296    return -1;
297}
298
299int add_cachebyuuid( uuidp_t inuuid, const char *inname, uuidtype_t type, const unsigned long uid _U_) {
300    int ret = 0;
301    char *name = NULL;
302    uuidp_t uuid = NULL;
303    cacheduser_t *cacheduser = NULL;
304    cacheduser_t *entry;
305    unsigned char hash;
306
307    /* allocate mem and copy values */
308    name = malloc(strlen(inname)+1);
309    if (!name) {
310        LOG(log_error, logtype_default, "add_cachebyuuid: mallor error");
311        ret = -1;
312        goto cleanup;
313    }
314
315    uuid = malloc(UUID_BINSIZE);
316    if (!uuid) {
317        LOG(log_error, logtype_default, "add_cachebyuuid: mallor error");
318        ret = -1;
319        goto cleanup;
320    }
321
322    cacheduser = malloc(sizeof(cacheduser_t));
323    if (!cacheduser) {
324        LOG(log_error, logtype_default, "add_cachebyuuid: mallor error");
325        ret = -1;
326        goto cleanup;
327    }
328
329    strcpy(name, inname);
330    memcpy(uuid, inuuid, UUID_BINSIZE);
331
332    /* fill in the cacheduser */
333    cacheduser->name = name;
334    cacheduser->type = type;
335    cacheduser->uuid = uuid;
336    cacheduser->creationtime = time(NULL);
337    cacheduser->prev = NULL;
338    cacheduser->next = NULL;
339
340    /* get hash */
341    hash = hashuuid(uuid);
342
343    /* insert cache entry into cache array at head of queue */
344    if (uuidcache[hash] == NULL) {
345        /* this queue is empty */
346        uuidcache[hash] = cacheduser;
347    } else {
348        cacheduser->next = uuidcache[hash];
349        uuidcache[hash]->prev = cacheduser;
350        uuidcache[hash] = cacheduser;
351    }
352
353cleanup:
354    if (ret != 0) {
355        if (name)
356            free(name);
357        if (uuid)
358            free(uuid);
359        if (cacheduser)
360            free(cacheduser);
361    }
362
363    return ret;
364}
365