]> arthur.barton.de Git - netatalk.git/blob - libatalk/cnid/cnid.c
remove gcc warnings and cleanup inline mess
[netatalk.git] / libatalk / cnid / cnid.c
1 /* 
2  * $Id: cnid.c,v 1.1.4.11.2.4 2008-11-25 15:16:34 didg 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 <sys/param.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
26 #include <signal.h>
27 #include <unistd.h>
28 #include <errno.h>
29
30 #include <atalk/cnid.h>
31 #include <atalk/list.h>
32 #include <atalk/logger.h>
33 #include <atalk/util.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 static struct itimerval savetimer;
41
42 /* Registers new CNID backend module. */
43
44 /* Once module has been registered, it cannot be unregistered. */
45 void cnid_register(struct _cnid_module *module)
46 {
47     struct list_head *ptr;
48
49     /* Check if our module is already registered. */
50     list_for_each(ptr, &modules)
51         if (0 == strcmp(list_entry(ptr, cnid_module, db_list)->name, module->name)) {
52         LOG(log_error, logtype_afpd, "Module with name [%s] is already registered !", module->name);
53         return;
54     }
55
56     LOG(log_info, logtype_afpd, "Registering CNID module [%s]", module->name);
57     ptr = &(module->db_list);
58     list_add_tail(ptr, &modules);
59 }
60
61 /* --------------- */
62 static int cnid_dir(const char *dir, mode_t mask)
63 {
64    struct stat st, st1; 
65    char tmp[MAXPATHLEN];
66
67    if (stat(dir, &st) < 0) {
68        if (errno != ENOENT) 
69            return -1;
70        if (ad_stat( dir, &st) < 0)
71           return -1;
72
73        LOG(log_info, logtype_cnid, "Setting uid/gid to %d/%d", st.st_uid, st.st_gid);
74        if (setegid(st.st_gid) < 0 || seteuid(st.st_uid) < 0) {
75            LOG(log_error, logtype_cnid, "uid/gid: %s", strerror(errno));
76            return -1;
77        }
78
79        if (mkdir(dir, 0777 & ~mask) < 0)
80            return -1;
81    } else {
82        strlcpy(tmp, dir, sizeof(tmp));
83        strlcat(tmp, "/.AppleDB", sizeof(tmp));
84        if (stat(tmp, &st1) < 0) /* use .AppleDB owner, if folder already exists */
85            st1 = st; 
86        LOG(log_info, logtype_cnid, "Setting uid/gid to %d/%d", st1.st_uid, st1.st_gid);
87        if (setegid(st1.st_gid) < 0 || seteuid(st1.st_uid) < 0) {
88            LOG(log_error, logtype_cnid, "uid/gid: %s", strerror(errno));
89            return -1;
90        }
91    }
92    return 0;
93 }
94
95 /* Opens CNID database using particular back-end */
96 struct _cnid_db *cnid_open(const char *volpath, mode_t mask, char *type, int flags)
97 {
98     struct _cnid_db *db;
99     cnid_module *mod = NULL;
100     struct list_head *ptr;
101     uid_t uid = -1;  
102     gid_t gid = -1;
103     
104     list_for_each(ptr, &modules) {
105         if (0 == strcmp(list_entry(ptr, cnid_module, db_list)->name, type)) {
106             mod = list_entry(ptr, cnid_module, db_list);
107         break;
108         }
109     }
110
111     if (NULL == mod) {
112         LOG(log_error, logtype_afpd, "Cannot find module named [%s] in registered module list!", type);
113         return NULL;
114     }
115
116     if ((mod->flags & CNID_FLAG_SETUID)) {
117         uid = geteuid();
118         gid = getegid();
119         if (seteuid(0)) {
120             LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
121             return NULL;
122         }
123         if (cnid_dir(volpath, mask) < 0) {
124             if ( setegid(gid) < 0 || seteuid(uid) < 0) {
125                 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
126                 exit(EXITERR_SYS);
127             }
128             return NULL;
129         }
130     }
131
132     db = mod->cnid_open(volpath, mask);
133
134     if ((mod->flags & CNID_FLAG_SETUID)) {
135         seteuid(0);
136         if ( setegid(gid) < 0 || seteuid(uid) < 0) {
137             LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
138             exit(EXITERR_SYS);
139         }
140     }
141
142     if (NULL == db) {
143         LOG(log_error, logtype_afpd, "Cannot open CNID db at [%s].", volpath);
144         return NULL;
145     }
146     /* FIXME should module know about it ? */
147     if (flags) {
148         db->flags |= CNID_FLAG_NODEV;
149     }
150     db->flags |= mod->flags;
151
152     if ((db->flags & CNID_FLAG_BLOCK)) {
153         sigemptyset(&sigblockset);
154         sigaddset(&sigblockset, SIGTERM);
155         sigaddset(&sigblockset, SIGHUP);
156         sigaddset(&sigblockset, SIGUSR1);
157         sigaddset(&sigblockset, SIGALRM);
158     }
159
160     return db;
161 }
162
163 /* ------------------- */
164 static void block_signal( u_int32_t flags)
165 {
166     if ((flags & CNID_FLAG_BLOCK)) {
167         sigprocmask(SIG_BLOCK, &sigblockset, NULL);
168         setitimer(ITIMER_REAL, &none, &savetimer);
169     }
170 }
171
172 /* ------------------- */
173 static void unblock_signal(u_int32_t flags)
174 {
175     if ((flags & CNID_FLAG_BLOCK)) {
176         setitimer(ITIMER_REAL, &savetimer, NULL);
177         sigprocmask(SIG_UNBLOCK, &sigblockset, NULL);
178     }
179 }
180
181 /* Closes CNID database. Currently it's just a wrapper around db->cnid_close(). */
182 void cnid_close(struct _cnid_db *db)
183 {
184 u_int32_t flags;
185
186     if (NULL == db) {
187         LOG(log_error, logtype_afpd, "Error: cnid_close called with NULL argument !");
188         return;
189     }
190     /* cnid_close free db */
191     flags = db->flags;
192     block_signal(flags);
193     db->cnid_close(db);
194     unblock_signal(flags);
195 }
196
197 /* --------------- */
198 cnid_t cnid_add(struct _cnid_db *cdb, const struct stat *st, const cnid_t did, 
199                         char *name, const size_t len, cnid_t hint)
200 {
201 cnid_t ret;
202
203     block_signal(cdb->flags);
204     ret = cdb->cnid_add(cdb, st, did, name, len, hint);
205     unblock_signal(cdb->flags);
206     return ret;
207 }
208
209 /* --------------- */
210 int cnid_delete(struct _cnid_db *cdb, cnid_t id)
211 {
212 int ret;
213
214     block_signal(cdb->flags);
215     ret = cdb->cnid_delete(cdb, id);
216     unblock_signal(cdb->flags);
217     return ret;
218 }
219
220
221 /* --------------- */
222 cnid_t cnid_get(struct _cnid_db *cdb, const cnid_t did, char *name,const size_t len)
223 {
224 cnid_t ret;
225
226     block_signal(cdb->flags);
227     ret = cdb->cnid_get(cdb, did, name, len);
228     unblock_signal(cdb->flags);
229     return ret;
230 }
231
232 /* --------------- */
233 int cnid_getstamp(struct _cnid_db *cdb,  void *buffer, const size_t len)
234 {
235 cnid_t ret;
236 time_t t;
237
238     if (!cdb->cnid_getstamp) {
239         memset(buffer, 0, len);
240         /* return the current time. it will invalide cache */
241         if (len < sizeof(time_t))
242             return -1;
243         t = time(NULL);
244         memcpy(buffer, &t, sizeof(time_t));
245         return 0;
246     }
247     block_signal(cdb->flags);
248     ret = cdb->cnid_getstamp(cdb, buffer, len);
249     unblock_signal(cdb->flags);
250     return ret;
251 }
252
253 /* --------------- */
254 cnid_t cnid_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
255                         char *name, const size_t len)
256 {
257 cnid_t ret;
258
259     block_signal(cdb->flags);
260     ret = cdb->cnid_lookup(cdb, st, did, name, len);
261     unblock_signal(cdb->flags);
262     return ret;
263 }
264
265 /* --------------- */
266 char *cnid_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, size_t len)
267 {
268 char *ret;
269
270     block_signal(cdb->flags);
271     ret = cdb->cnid_resolve(cdb, id, buffer, len);
272     unblock_signal(cdb->flags);
273     return ret;
274 }
275
276 /* --------------- */
277 int cnid_update   (struct _cnid_db *cdb, const cnid_t id, const struct stat *st, 
278                         const cnid_t did, char *name, const size_t len)
279 {
280 int ret;
281
282     block_signal(cdb->flags);
283     ret = cdb->cnid_update(cdb, id, st, did, name, len);
284     unblock_signal(cdb->flags);
285     return ret;
286 }
287                         
288