]> arthur.barton.de Git - netatalk.git/blob - libatalk/cnid/cnid.c
Check if we can get a DB stamp sucessfully in afs_openvol and fail
[netatalk.git] / libatalk / cnid / cnid.c
1 /* 
2  * $Id: cnid.c,v 1.1.4.8 2004-01-14 23:15:19 lenneis Exp $
3  *
4  * Copyright (c) 2003 the Netatalk Team
5  * Copyright (c) 2003 Rafal Lewczuk <rlewczuk@pronet.pl>
6  * 
7  * This program is free software; you can redistribute and/or modify
8  * it under the terms of the GNU General Public License as published
9  * by the Free Software Foundation version 2 of the License or later
10  * version if explicitly stated by any of above copyright holders.
11  *
12  */
13 #define USE_LIST
14
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif /* HAVE_CONFIG_H */
18
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/time.h>
22 #include <signal.h>
23 #include <unistd.h>
24 #include <errno.h>
25
26 #include <atalk/cnid.h>
27 #include <atalk/list.h>
28 #include <atalk/logger.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <time.h>
32
33 /* List of all registered modules. */
34 static struct list_head modules = ATALK_LIST_HEAD_INIT(modules);
35
36 static sigset_t sigblockset;
37 static const struct itimerval none = {{0, 0}, {0, 0}};
38 static struct itimerval savetimer;
39
40 /* Registers new CNID backend module. */
41
42 /* Once module has been registered, it cannot be unregistered. */
43 void cnid_register(struct _cnid_module *module)
44 {
45     struct list_head *ptr;
46
47     /* Check if our module is already registered. */
48     list_for_each(ptr, &modules)
49         if (0 == strcmp(list_entry(ptr, cnid_module, db_list)->name, module->name)) {
50         LOG(log_error, logtype_afpd, "Module with name [%s] is already registered !", module->name);
51         return;
52     }
53
54     LOG(log_info, logtype_afpd, "Registering CNID module [%s]", module->name);
55     ptr = &(module->db_list);
56     list_add_tail(ptr, &modules);
57 }
58
59 /* --------------- */
60 static int cnid_dir(const char *dir, mode_t mask)
61 {
62    struct stat st; 
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        LOG(log_info, logtype_cnid, "Setting uid/gid to %d/%d", st.st_uid, st.st_gid);
80        if (setegid(st.st_gid) < 0 || seteuid(st.st_uid) < 0) {
81            LOG(log_error, logtype_cnid, "uid/gid: %s", strerror(errno));
82            return -1;
83        }
84    }
85    return 0;
86 }
87
88 /* Opens CNID database using particular back-end */
89 struct _cnid_db *cnid_open(const char *volpath, mode_t mask, char *type, int flags)
90 {
91     struct _cnid_db *db;
92     cnid_module *mod = NULL;
93     struct list_head *ptr;
94     uid_t uid;
95     gid_t gid;
96     
97     list_for_each(ptr, &modules) {
98         if (0 == strcmp(list_entry(ptr, cnid_module, db_list)->name, type)) {
99             mod = list_entry(ptr, cnid_module, db_list);
100         break;
101         }
102     }
103
104     if (NULL == mod) {
105         LOG(log_error, logtype_afpd, "Cannot find module named [%s] in registered module list!", type);
106         return NULL;
107     }
108
109     if ((mod->flags & CNID_FLAG_SETUID)) {
110         uid = geteuid();
111         gid = getegid();
112         if (seteuid(0)) {
113             LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
114             return NULL;
115         }
116         if (cnid_dir(volpath, mask) < 0) {
117             if ( setegid(gid) < 0 || seteuid(uid) < 0) {
118                 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
119                 exit(1);
120             }
121             return NULL;
122         }
123     }
124
125     db = mod->cnid_open(volpath, mask);
126     /* FIXME should module know about it ? */
127     if (flags) {
128         db->flags |= CNID_FLAG_NODEV;
129     }
130
131     if ((mod->flags & CNID_FLAG_SETUID)) {
132         seteuid(0);
133         if ( setegid(gid) < 0 || seteuid(uid) < 0) {
134             LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
135             exit(1);
136         }
137     }
138
139     if (NULL == db) {
140         LOG(log_error, logtype_afpd, "Cannot open CNID db at [%s].", volpath);
141         return NULL;
142     }
143     db->flags |= mod->flags;
144
145     if ((db->flags & CNID_FLAG_BLOCK)) {
146         sigemptyset(&sigblockset);
147         sigaddset(&sigblockset, SIGTERM);
148         sigaddset(&sigblockset, SIGHUP);
149         sigaddset(&sigblockset, SIGUSR1);
150         sigaddset(&sigblockset, SIGALRM);
151     }
152
153     return db;
154 }
155
156 /* ------------------- */
157 static void block_signal( u_int32_t flags)
158 {
159     if ((flags & CNID_FLAG_BLOCK)) {
160         sigprocmask(SIG_BLOCK, &sigblockset, NULL);
161         setitimer(ITIMER_REAL, &none, &savetimer);
162     }
163 }
164
165 /* ------------------- */
166 static void unblock_signal(u_int32_t flags)
167 {
168     if ((flags & CNID_FLAG_BLOCK)) {
169         setitimer(ITIMER_REAL, &savetimer, NULL);
170         sigprocmask(SIG_UNBLOCK, &sigblockset, NULL);
171     }
172 }
173
174 /* Closes CNID database. Currently it's just a wrapper around db->cnid_close(). */
175 void cnid_close(struct _cnid_db *db)
176 {
177 u_int32_t flags;
178
179     if (NULL == db) {
180         LOG(log_error, logtype_afpd, "Error: cnid_close called with NULL argument !");
181         return;
182     }
183     /* cnid_close free db */
184     flags = db->flags;
185     block_signal(flags);
186     db->cnid_close(db);
187     unblock_signal(flags);
188 }
189
190 /* --------------- */
191 cnid_t cnid_add(struct _cnid_db *cdb, const struct stat *st, const cnid_t did, 
192                         const char *name, const int len, cnid_t hint)
193 {
194 cnid_t ret;
195
196     block_signal(cdb->flags);
197     ret = cdb->cnid_add(cdb, st, did, name, len, hint);
198     unblock_signal(cdb->flags);
199     return ret;
200 }
201
202 /* --------------- */
203 int cnid_delete(struct _cnid_db *cdb, cnid_t id)
204 {
205 int ret;
206
207     block_signal(cdb->flags);
208     ret = cdb->cnid_delete(cdb, id);
209     unblock_signal(cdb->flags);
210     return ret;
211 }
212
213
214 /* --------------- */
215 cnid_t cnid_get(struct _cnid_db *cdb, const cnid_t did, const char *name,const int len)
216 {
217 cnid_t ret;
218
219     block_signal(cdb->flags);
220     ret = cdb->cnid_get(cdb, did, name, len);
221     unblock_signal(cdb->flags);
222     return ret;
223 }
224
225 /* --------------- */
226 int cnid_getstamp(struct _cnid_db *cdb,  void *buffer, const int len)
227 {
228 cnid_t ret;
229
230     if (!cdb->cnid_getstamp) {
231         memset(buffer, 0, len);
232         /* return the current time. it will invalide cache */
233         if (len < sizeof(time_t))
234             return -1;
235         time(buffer);
236         return 0;
237     }
238     block_signal(cdb->flags);
239     ret = cdb->cnid_getstamp(cdb, buffer, len);
240     unblock_signal(cdb->flags);
241     return ret;
242 }
243
244 /* --------------- */
245 cnid_t cnid_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
246                         const char *name, const int len)
247 {
248 cnid_t ret;
249
250     block_signal(cdb->flags);
251     ret = cdb->cnid_lookup(cdb, st, did, name, len);
252     unblock_signal(cdb->flags);
253     return ret;
254 }
255
256 /* --------------- */
257 char *cnid_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, u_int32_t len)
258 {
259 char *ret;
260
261     block_signal(cdb->flags);
262     ret = cdb->cnid_resolve(cdb, id, buffer, len);
263     unblock_signal(cdb->flags);
264     return ret;
265 }
266
267 /* --------------- */
268 int cnid_update   (struct _cnid_db *cdb, const cnid_t id, const struct stat *st, 
269                         const cnid_t did, const char *name, const int len)
270 {
271 int ret;
272
273     block_signal(cdb->flags);
274     ret = cdb->cnid_update(cdb, id, st, did, name, len);
275     unblock_signal(cdb->flags);
276     return ret;
277 }
278                         
279