1 /* qmail-domains.c - qmail locals/virtualdomains lookup routines
2 * Copyright (C) 2010 Bruce Guenter <bruce@untroubled.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 #include <bglibs/sysdeps.h>
19 #include <errno.h>
20 #include <sys/stat.h>
21
22 #include <bglibs/dict.h>
23 #include <bglibs/dict.h>
24 #include <bglibs/str.h>
25
26 #include "qmail.h"
27
28 static dict vdomains;
29 static struct stat vdomains_stat;
30 static str vdomains_path;
31
32 static dict locals;
33 static struct stat locals_stat;
34 static str locals_path;
35
36 static int assume_local = 0;
37
map_lower(str * s)38 static int map_lower(str* s)
39 {
40 str_lower(s);
41 return 1;
42 }
43
stat_changed(const char * path,const struct stat * orig,struct stat * curr)44 static int stat_changed(const char* path, const struct stat* orig,
45 struct stat* curr)
46 {
47 if (stat(path, curr) != 0)
48 return -1;
49 if (orig->st_mtime != curr->st_mtime
50 || orig->st_ino != curr->st_ino
51 || orig->st_size != curr->st_size)
52 return 1;
53 return 0;
54 }
55
load_dict(const char * path,struct stat * oldstat,dict * dictp,void (* free_fn)(void *),int (* load_fn)(void))56 static int load_dict(const char* path, struct stat* oldstat,
57 dict* dictp, void (*free_fn)(void*),
58 int (*load_fn)(void))
59 {
60 struct stat s;
61 switch (stat_changed(path, oldstat, &s)) {
62 case -1:
63 if (errno != ENOENT)
64 return 0;
65 oldstat->st_mtime = 0;
66 oldstat->st_ino = 0;
67 oldstat->st_size = 0;
68 dict_free(dictp, free_fn);
69 return 1;
70 case 0:
71 return 1;
72 }
73 // FIXME: obuf_putsflush(&errbuf, "Reloading *path*\n");
74 *oldstat = s;
75 dict_free(dictp, free_fn);
76 return load_fn();
77 }
78
_load_vdomains(void)79 static int _load_vdomains(void)
80 {
81 return dict_load_map(&vdomains, vdomains_path.s, 0, ':', map_lower, 0);
82 }
83
load_vdomains(void)84 static int load_vdomains(void)
85 {
86 return load_dict(vdomains_path.s, &vdomains_stat, &vdomains, dict_str_free, _load_vdomains);
87 }
88
_load_locals(void)89 static int _load_locals(void)
90 {
91 return dict_load_list(&locals, locals_path.s, 0, map_lower);
92 }
93
load_locals(void)94 static int load_locals(void)
95 {
96 return load_dict(locals_path.s, &locals_stat, &locals, 0, _load_locals);
97 }
98
qmail_domains_reinit(void)99 int qmail_domains_reinit(void)
100 {
101 if (!load_locals()
102 || !load_vdomains())
103 return -1;
104
105 return 0;
106 }
107
qmail_domains_init(void)108 int qmail_domains_init(void)
109 {
110 assume_local = getenv("CVM_QMAIL_ASSUME_LOCAL") != 0;
111
112 if (!str_copy2s(&vdomains_path, qmail_root, "/control/virtualdomains")
113 || !str_copy2s(&locals_path, qmail_root, "/control/locals"))
114 return -1;
115
116 if (!load_locals()
117 || !load_vdomains())
118 return -1;
119
120 return 0;
121 }
122
qmail_domains_lookup(const str * d,str * domain,str * prefix)123 int qmail_domains_lookup(const str* d, str* domain, str* prefix)
124 {
125 dict_entry* e;
126
127 if (!str_copy(domain, d))
128 return -1;
129 str_lower(domain);
130
131 if ((e = dict_get(&locals, domain)) != 0)
132 return str_copys(prefix, "") ? 1 : -1;
133
134 if ((e = dict_get(&vdomains, domain)) == 0) {
135 unsigned i;
136 while ((i = str_findnext(domain, '.', 1)) != (unsigned)-1) {
137 str_lcut(domain, i);
138 if ((e = dict_get(&vdomains, domain)) != 0)
139 break;
140 }
141 }
142 if (e == 0) {
143 if (assume_local) {
144 if (!str_copys(prefix, "")) return -1;
145 if (!str_copy(domain, d)) return -1;
146 str_lower(domain);
147 return 1;
148 }
149 return 0;
150 }
151 if (!str_copy(prefix, (str*)e->data))
152 return -1;
153 return 1;
154 }
155