2 * Copyright (c) 2003 the Netatalk Team
3 * Copyright (c) 2003 Rafal Lewczuk <rlewczuk@pronet.pl>
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.
15 #endif /* HAVE_CONFIG_H */
17 #include <sys/types.h>
20 #include <sys/param.h>
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>
35 /* List of all registered modules. */
36 static struct list_head modules = ATALK_LIST_HEAD_INIT(modules);
38 static sigset_t sigblockset;
39 static const struct itimerval none = {{0, 0}, {0, 0}};
41 /* Registers new CNID backend module. */
43 /* Once module has been registered, it cannot be unregistered. */
44 void cnid_register(struct _cnid_module *module)
46 struct list_head *ptr;
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);
55 LOG(log_info, logtype_afpd, "Registering CNID module [%s]", module->name);
56 ptr = &(module->db_list);
57 list_add_tail(ptr, &modules);
61 static int cnid_dir(const char *dir, mode_t mask)
66 if (stat(dir, &st) < 0) {
69 if (ad_stat( dir, &st) < 0)
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));
78 if (mkdir(dir, 0777 & ~mask) < 0)
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 */
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));
94 /* Opens CNID database using particular back-end */
95 struct _cnid_db *cnid_open(struct vol *vol, char *type, int flags)
98 cnid_module *mod = NULL;
99 struct list_head *ptr;
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);
111 LOG(log_error, logtype_afpd, "Cannot find module named [%s] in registered module list!", type);
115 if ((mod->flags & CNID_FLAG_SETUID) && !(flags & CNID_FLAG_MEMORY)) {
119 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
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));
131 struct cnid_open_args args = {
132 .cnid_args_flags = flags,
136 db = mod->cnid_open(&args);
138 if ((mod->flags & CNID_FLAG_SETUID) && !(flags & CNID_FLAG_MEMORY)) {
140 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
141 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
147 LOG(log_error, logtype_afpd, "Cannot open CNID db at [%s].", vol->v_path);
151 db->cnid_db_flags |= mod->flags;
152 if (flags & CNID_FLAG_NODEV)
153 db->cnid_db_flags |= CNID_FLAG_NODEV;
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);
167 /* ------------------- */
168 static void block_signal(uint32_t flags)
170 if ((flags & CNID_FLAG_BLOCK)) {
171 pthread_sigmask(SIG_BLOCK, &sigblockset, NULL);
175 /* ------------------- */
176 static void unblock_signal(uint32_t flags)
178 if ((flags & CNID_FLAG_BLOCK)) {
179 pthread_sigmask(SIG_UNBLOCK, &sigblockset, NULL);
183 /* -------------------
184 protect against bogus value from the DB.
185 adddir really doesn't like 2
187 static cnid_t valide(cnid_t id)
189 if (id == CNID_INVALID)
192 if (id < CNID_START) {
196 LOG(log_error, logtype_afpd, "Error: Invalid cnid, corrupted DB?");
203 /* Closes CNID database. Currently it's just a wrapper around db->cnid_close(). */
204 void cnid_close(struct _cnid_db *db)
209 LOG(log_error, logtype_afpd, "Error: cnid_close called with NULL argument !");
212 /* cnid_close free db */
213 flags = db->cnid_db_flags;
216 unblock_signal(flags);
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)
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);
234 /* --------------- */
235 int cnid_delete(struct _cnid_db *cdb, cnid_t id)
239 block_signal(cdb->cnid_db_flags);
240 ret = cdb->cnid_delete(cdb, id);
241 unblock_signal(cdb->cnid_db_flags);
246 /* --------------- */
247 cnid_t cnid_get(struct _cnid_db *cdb, const cnid_t did, char *name,const size_t len)
251 block_signal(cdb->cnid_db_flags);
252 ret = valide(cdb->cnid_get(cdb, did, name, len));
253 unblock_signal(cdb->cnid_db_flags);
257 /* --------------- */
258 int cnid_getstamp(struct _cnid_db *cdb, void *buffer, const size_t len)
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))
269 memcpy(buffer, &t, sizeof(time_t));
272 block_signal(cdb->cnid_db_flags);
273 ret = cdb->cnid_getstamp(cdb, buffer, len);
274 unblock_signal(cdb->cnid_db_flags);
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)
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);
290 /* --------------- */
291 int cnid_find(struct _cnid_db *cdb, const char *name, size_t namelen, void *buffer, size_t buflen)
295 if (cdb->cnid_find == NULL) {
296 LOG(log_error, logtype_cnid, "cnid_find not supported by CNID backend");
300 block_signal(cdb->cnid_db_flags);
301 ret = cdb->cnid_find(cdb, name, namelen, buffer, buflen);
302 unblock_signal(cdb->cnid_db_flags);
306 /* --------------- */
307 char *cnid_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, size_t len)
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? ");
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)
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);
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)
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);
345 /* --------------- */
346 int cnid_wipe(struct _cnid_db *cdb)
350 block_signal(cdb->cnid_db_flags);
352 ret = cdb->cnid_wipe(cdb);
353 unblock_signal(cdb->cnid_db_flags);