]> arthur.barton.de Git - netatalk.git/blob - libatalk/cnid/cnid.c
big merge for db frontend and unicode.
[netatalk.git] / libatalk / cnid / cnid.c
1 /* 
2  * $Id: cnid.c,v 1.1.4.1 2003-09-09 16:42:21 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 <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
32 /* List of all registered modules. */
33 static struct list_head modules = LIST_HEAD_INIT(modules);
34
35 static sigset_t sigblockset;
36 static const struct itimerval none = {{0, 0}, {0, 0}};
37 static struct itimerval savetimer;
38
39 /* Registers new CNID backend module. */
40
41 /* Once module has been registered, it cannot be unregistered. */
42 void 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 /* --------------- */
59 static int cnid_dir(const char *dir, mode_t mask)
60 {
61    struct stat st; 
62
63    if (stat(dir, &st) < 0) {
64        if (errno != ENOENT) 
65            return -1;
66        if (ad_stat( dir, &st) < 0)
67           return -1;
68
69        LOG(log_info, logtype_cnid, "Setting uid/gid to %d/%d", st.st_uid, st.st_gid);
70        if (setegid(st.st_gid) < 0 || seteuid(st.st_uid) < 0) {
71            LOG(log_error, logtype_cnid, "uid/gid: %s", strerror(errno));
72            return -1;
73        }
74
75        if (mkdir(dir, 0777 & ~mask) < 0)
76            return -1;
77    } else {
78        LOG(log_info, logtype_cnid, "Setting uid/gid to %d/%d", st.st_uid, st.st_gid);
79        if (setegid(st.st_gid) < 0 || seteuid(st.st_uid) < 0) {
80            LOG(log_error, logtype_cnid, "uid/gid: %s", strerror(errno));
81            return -1;
82        }
83    }
84    return 0;
85 }
86
87 /* Opens CNID database using particular back-end */
88 struct _cnid_db *cnid_open(const char *volpath, mode_t mask, char *type)
89 {
90     struct _cnid_db *db;
91     cnid_module *mod = NULL;
92     struct list_head *ptr;
93     uid_t uid;
94     gid_t gid;
95     
96     list_for_each(ptr, &modules) {
97         if (0 == strcmp(list_entry(ptr, cnid_module, db_list)->name, type)) {
98             mod = list_entry(ptr, cnid_module, db_list);
99         break;
100         }
101     }
102
103     if (NULL == mod) {
104         LOG(log_error, logtype_afpd, "Cannot find module named [%s] in registered module list!", type);
105         return NULL;
106     }
107     if ((mod->flags & CNID_FLAG_SETUID)) {
108         uid = geteuid();
109         gid = getegid();
110         if (seteuid(0)) {
111             LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
112             return NULL;
113         }
114         if (cnid_dir(volpath, mask) < 0) {
115             if ( setegid(gid) < 0 || seteuid(uid) < 0) {
116                 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
117                 exit(1);
118             }
119             return NULL;
120         }
121     }
122
123     db = mod->cnid_open(volpath, mask);
124
125     if ((mod->flags & CNID_FLAG_SETUID)) {
126         seteuid(0);
127         if ( setegid(gid) < 0 || seteuid(uid) < 0) {
128             LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
129             exit(1);
130         }
131     }
132
133     if (NULL == db) {
134         LOG(log_error, logtype_afpd, "Cannot open CNID db at [%s].", volpath);
135         return NULL;
136     }
137     db->flags |= mod->flags;
138
139     if (db->flags |= CNID_FLAG_BLOCK) {
140         sigemptyset(&sigblockset);
141         sigaddset(&sigblockset, SIGTERM);
142         sigaddset(&sigblockset, SIGHUP);
143         sigaddset(&sigblockset, SIGUSR1);
144         sigaddset(&sigblockset, SIGALRM);
145     }
146
147     return db;
148 }
149
150 /* ------------------- */
151 static void block_signal(struct _cnid_db *db)
152 {
153     if ((db->flags & CNID_FLAG_BLOCK)) {
154         sigprocmask(SIG_BLOCK, &sigblockset, NULL);
155         setitimer(ITIMER_REAL, &none, &savetimer);
156     }
157 }
158
159 /* ------------------- */
160 static void unblock_signal(struct _cnid_db *db)
161 {
162     if ((db->flags & CNID_FLAG_BLOCK)) {
163         setitimer(ITIMER_REAL, &savetimer, NULL);
164         sigprocmask(SIG_UNBLOCK, &sigblockset, NULL);
165     }
166 }
167
168 /* Closes CNID database. Currently it's just a wrapper around db->cnid_close(). */
169 void cnid_close(struct _cnid_db *db)
170 {
171     if (NULL == db) {
172         LOG(log_error, logtype_afpd, "Error: cnid_close called with NULL argument !");
173         return;
174     }
175     block_signal(db);
176     db->cnid_close(db);
177     unblock_signal(db);
178 }
179
180 /* --------------- */
181 cnid_t cnid_add(struct _cnid_db *cdb, const struct stat *st, const cnid_t did, 
182                         const char *name, const int len, cnid_t hint)
183 {
184 cnid_t ret;
185
186     block_signal(cdb);
187     ret = cdb->cnid_add(cdb, st, did, name, len, hint);
188     unblock_signal(cdb);
189     return ret;
190 }
191
192 /* --------------- */
193 int cnid_delete(struct _cnid_db *cdb, cnid_t id)
194 {
195 int ret;
196
197     block_signal(cdb);
198     ret = cdb->cnid_delete(cdb, id);
199     unblock_signal(cdb);
200     return ret;
201 }
202
203
204 /* --------------- */
205 cnid_t cnid_get(struct _cnid_db *cdb, const cnid_t did, const char *name,const int len)
206 {
207 cnid_t ret;
208
209     block_signal(cdb);
210     ret = cdb->cnid_get(cdb, did, name, len);
211     unblock_signal(cdb);
212     return ret;
213 }
214
215 /* --------------- */
216 cnid_t cnid_getstamp(struct _cnid_db *cdb,  void *buffer, const int len)
217 {
218 cnid_t ret;
219
220     if (!cdb->cnid_getstamp) {
221         return -1;
222     }
223     block_signal(cdb);
224     ret = cdb->cnid_getstamp(cdb, buffer, len);
225     unblock_signal(cdb);
226     return ret;
227 }
228
229 /* --------------- */
230 cnid_t cnid_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
231                         const char *name, const int len)
232 {
233 cnid_t ret;
234
235     block_signal(cdb);
236     ret = cdb->cnid_lookup(cdb, st, did, name, len);
237     unblock_signal(cdb);
238     return ret;
239 }
240
241 /* --------------- */
242 char *cnid_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, u_int32_t len)
243 {
244 char *ret;
245
246     block_signal(cdb);
247     ret = cdb->cnid_resolve(cdb, id, buffer, len);
248     unblock_signal(cdb);
249     return ret;
250 }
251
252 /* --------------- */
253 int cnid_update   (struct _cnid_db *cdb, const cnid_t id, const struct stat *st, 
254                         const cnid_t did, const char *name, const int len)
255 {
256 int ret;
257
258     block_signal(cdb);
259     ret = cdb->cnid_update(cdb, id, st, did, name, len);
260     unblock_signal(cdb);
261     return ret;
262 }
263                         
264