• 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/cnid/
1/*
2 * Copyright (c) 2003 the Netatalk Team
3 * Copyright (c) 2003 Rafal Lewczuk <rlewczuk@pronet.pl>
4 *
5 * This program is free software; you can redistribute and/or modify
6 * it under the terms of the GNU General Public License as published
7 * by the Free Software Foundation version 2 of the License or later
8 * version if explicitly stated by any of above copyright holders.
9 *
10 */
11#define USE_LIST
12
13#ifdef HAVE_CONFIG_H
14#include "config.h"
15#endif /* HAVE_CONFIG_H */
16
17#include <sys/types.h>
18#include <sys/stat.h>
19#include <sys/time.h>
20#include <sys/param.h>
21#include <stdlib.h>
22#include <string.h>
23#include <time.h>
24#include <signal.h>
25#include <unistd.h>
26#include <errno.h>
27
28#include <atalk/cnid.h>
29#include <atalk/list.h>
30#include <atalk/logger.h>
31#include <atalk/util.h>
32
33/* List of all registered modules. */
34static struct list_head modules = ATALK_LIST_HEAD_INIT(modules);
35
36static sigset_t sigblockset;
37static const struct itimerval none = {{0, 0}, {0, 0}};
38
39/* Registers new CNID backend module. */
40
41/* Once module has been registered, it cannot be unregistered. */
42void cnid_register(struct _cnid_module *module)
43{
44    struct list_head *ptr;
45
46    /* Check if our module is already registered. */
47    list_for_each(ptr, &modules)
48        if (0 == strcmp(list_entry(ptr, cnid_module, db_list)->name, module->name)) {
49        LOG(log_error, logtype_afpd, "Module with name [%s] is already registered !", module->name);
50        return;
51    }
52
53    LOG(log_info, logtype_afpd, "Registering CNID module [%s]", module->name);
54    ptr = &(module->db_list);
55    list_add_tail(ptr, &modules);
56}
57
58/* --------------- */
59static int cnid_dir(const char *dir, mode_t mask)
60{
61   struct stat st, st1;
62   char tmp[MAXPATHLEN];
63
64   if (stat(dir, &st) < 0) {
65       if (errno != ENOENT)
66           return -1;
67       if (ad_stat( dir, &st) < 0)
68          return -1;
69
70       LOG(log_info, logtype_cnid, "Setting uid/gid to %d/%d", st.st_uid, st.st_gid);
71       if (setegid(st.st_gid) < 0 || seteuid(st.st_uid) < 0) {
72           LOG(log_error, logtype_cnid, "uid/gid: %s", strerror(errno));
73           return -1;
74       }
75
76       if (mkdir(dir, 0777 & ~mask) < 0)
77           return -1;
78   } else {
79       strlcpy(tmp, dir, sizeof(tmp));
80       strlcat(tmp, "/.AppleDB", sizeof(tmp));
81       if (stat(tmp, &st1) < 0) /* use .AppleDB owner, if folder already exists */
82           st1 = st;
83       LOG(log_info, logtype_cnid, "Setting uid/gid to %d/%d", st1.st_uid, st1.st_gid);
84       if (setegid(st1.st_gid) < 0 || seteuid(st1.st_uid) < 0) {
85           LOG(log_error, logtype_cnid, "uid/gid: %s", strerror(errno));
86           return -1;
87       }
88   }
89   return 0;
90}
91
92/* Opens CNID database using particular back-end */
93struct _cnid_db *cnid_open(const char *volpath, mode_t mask, char *type, int flags,
94                           const char *cnidsrv, const char *cnidport)
95{
96    struct _cnid_db *db;
97    cnid_module *mod = NULL;
98    struct list_head *ptr;
99    uid_t uid = -1;
100    gid_t gid = -1;
101
102    list_for_each(ptr, &modules) {
103        if (0 == strcmp(list_entry(ptr, cnid_module, db_list)->name, type)) {
104	    mod = list_entry(ptr, cnid_module, db_list);
105        break;
106        }
107    }
108
109    if (NULL == mod) {
110        LOG(log_error, logtype_afpd, "Cannot find module named [%s] in registered module list!", type);
111        return NULL;
112    }
113
114    if ((mod->flags & CNID_FLAG_SETUID) && !(flags & CNID_FLAG_MEMORY)) {
115        uid = geteuid();
116        gid = getegid();
117        if (seteuid(0)) {
118            LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
119            return NULL;
120        }
121        if (cnid_dir(volpath, mask) < 0) {
122            if ( setegid(gid) < 0 || seteuid(uid) < 0) {
123                LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
124                exit(EXITERR_SYS);
125            }
126            return NULL;
127        }
128    }
129
130    struct cnid_open_args args = {volpath, mask, flags, cnidsrv, cnidport};
131    db = mod->cnid_open(&args);
132
133    if ((mod->flags & CNID_FLAG_SETUID) && !(flags & CNID_FLAG_MEMORY)) {
134        seteuid(0);
135        if ( setegid(gid) < 0 || seteuid(uid) < 0) {
136            LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
137            exit(EXITERR_SYS);
138        }
139    }
140
141    if (NULL == db) {
142        LOG(log_error, logtype_afpd, "Cannot open CNID db at [%s].", volpath);
143        return NULL;
144    }
145    /* FIXME should module know about it ? */
146    if ((flags & CNID_FLAG_NODEV)) {
147        db->flags |= CNID_FLAG_NODEV;
148    }
149    db->flags |= mod->flags;
150
151    if ((db->flags & CNID_FLAG_BLOCK)) {
152        sigemptyset(&sigblockset);
153        sigaddset(&sigblockset, SIGTERM);
154        sigaddset(&sigblockset, SIGHUP);
155        sigaddset(&sigblockset, SIGUSR1);
156        sigaddset(&sigblockset, SIGUSR2);
157        sigaddset(&sigblockset, SIGALRM);
158    }
159
160    return db;
161}
162
163/* ------------------- */
164static void block_signal( u_int32_t flags)
165{
166    if ((flags & CNID_FLAG_BLOCK)) {
167        pthread_sigmask(SIG_BLOCK, &sigblockset, NULL);
168    }
169}
170
171/* ------------------- */
172static void unblock_signal(u_int32_t flags)
173{
174    if ((flags & CNID_FLAG_BLOCK)) {
175        pthread_sigmask(SIG_UNBLOCK, &sigblockset, NULL);
176    }
177}
178
179/* -------------------
180  protect against bogus value from the DB.
181  adddir really doesn't like 2
182*/
183static cnid_t valide(cnid_t id)
184{
185  if (id == CNID_INVALID)
186      return id;
187
188  if (id < CNID_START) {
189    static int err = 0;
190    if (!err) {
191        err = 1;
192        LOG(log_error, logtype_afpd, "Error: Invalid cnid, corrupted DB?");
193    }
194    return CNID_INVALID;
195  }
196  return id;
197}
198
199/* Closes CNID database. Currently it's just a wrapper around db->cnid_close(). */
200void cnid_close(struct _cnid_db *db)
201{
202u_int32_t flags;
203
204    if (NULL == db) {
205        LOG(log_error, logtype_afpd, "Error: cnid_close called with NULL argument !");
206        return;
207    }
208    /* cnid_close free db */
209    flags = db->flags;
210    block_signal(flags);
211    db->cnid_close(db);
212    unblock_signal(flags);
213}
214
215/* --------------- */
216cnid_t cnid_add(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
217                const char *name, const size_t len, cnid_t hint)
218{
219    cnid_t ret;
220
221    if (len == 0)
222        return CNID_INVALID;
223
224    block_signal(cdb->flags);
225    ret = valide(cdb->cnid_add(cdb, st, did, name, len, hint));
226    unblock_signal(cdb->flags);
227    return ret;
228}
229
230/* --------------- */
231int cnid_delete(struct _cnid_db *cdb, cnid_t id)
232{
233int ret;
234
235    block_signal(cdb->flags);
236    ret = cdb->cnid_delete(cdb, id);
237    unblock_signal(cdb->flags);
238    return ret;
239}
240
241
242/* --------------- */
243cnid_t cnid_get(struct _cnid_db *cdb, const cnid_t did, char *name,const size_t len)
244{
245cnid_t ret;
246
247    block_signal(cdb->flags);
248    ret = valide(cdb->cnid_get(cdb, did, name, len));
249    unblock_signal(cdb->flags);
250    return ret;
251}
252
253/* --------------- */
254int cnid_getstamp(struct _cnid_db *cdb,  void *buffer, const size_t len)
255{
256cnid_t ret;
257time_t t;
258
259    if (!cdb->cnid_getstamp) {
260        memset(buffer, 0, len);
261    	/* return the current time. it will invalide cache */
262    	if (len < sizeof(time_t))
263    	    return -1;
264    	t = time(NULL);
265    	memcpy(buffer, &t, sizeof(time_t));
266        return 0;
267    }
268    block_signal(cdb->flags);
269    ret = cdb->cnid_getstamp(cdb, buffer, len);
270    unblock_signal(cdb->flags);
271    return ret;
272}
273
274/* --------------- */
275cnid_t cnid_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
276                   char *name, const size_t len)
277{
278    cnid_t ret;
279
280    block_signal(cdb->flags);
281    ret = valide(cdb->cnid_lookup(cdb, st, did, name, len));
282    unblock_signal(cdb->flags);
283    return ret;
284}
285
286/* --------------- */
287int cnid_find(struct _cnid_db *cdb, const char *name, size_t namelen, void *buffer, size_t buflen)
288{
289    int ret;
290
291    if (cdb->cnid_find == NULL) {
292        LOG(log_error, logtype_cnid, "cnid_find not supported by CNID backend");
293        return -1;
294    }
295
296    block_signal(cdb->flags);
297    ret = cdb->cnid_find(cdb, name, namelen, buffer, buflen);
298    unblock_signal(cdb->flags);
299    return ret;
300}
301
302/* --------------- */
303char *cnid_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, size_t len)
304{
305char *ret;
306
307    block_signal(cdb->flags);
308    ret = cdb->cnid_resolve(cdb, id, buffer, len);
309    unblock_signal(cdb->flags);
310    if (ret && !strcmp(ret, "..")) {
311        LOG(log_error, logtype_afpd, "cnid_resolve: name is '..', corrupted db? ");
312        ret = NULL;
313    }
314    return ret;
315}
316
317/* --------------- */
318int cnid_update   (struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
319			const cnid_t did, char *name, const size_t len)
320{
321int ret;
322
323    block_signal(cdb->flags);
324    ret = cdb->cnid_update(cdb, id, st, did, name, len);
325    unblock_signal(cdb->flags);
326    return ret;
327}
328
329/* --------------- */
330cnid_t cnid_rebuild_add(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
331                       char *name, const size_t len, cnid_t hint)
332{
333cnid_t ret;
334
335    block_signal(cdb->flags);
336    ret = cdb->cnid_rebuild_add(cdb, st, did, name, len, hint);
337    unblock_signal(cdb->flags);
338    return ret;
339}
340