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