Commit | Line | Data |
---|---|---|
0e333c05 CE |
1 | /* |
2 | ** Copyright 2016 Double Precision, Inc. See COPYING for | |
3 | ** distribution information. | |
4 | */ | |
5 | ||
6 | #if HAVE_CONFIG_H | |
7 | #include "courier_auth_config.h" | |
8 | #endif | |
9 | ||
10 | #if HAVE_SYS_STAT_H | |
11 | #include <sys/stat.h> | |
12 | #endif | |
13 | ||
14 | extern "C" { | |
15 | #include "authldap.h" | |
16 | #include "auth.h" | |
17 | #include "authldaprc.h" | |
18 | #include "courierauthdebug.h" | |
19 | }; | |
20 | ||
21 | #include <algorithm> | |
22 | #include <fstream> | |
23 | #include <sstream> | |
24 | ||
25 | #include "authconfigfile.h" | |
26 | ||
27 | courier::auth::config_file::config_file(const char *filenameArg) | |
28 | : filename(filenameArg), loaded(false) | |
29 | { | |
30 | } | |
31 | ||
32 | bool courier::auth::config_file::load(bool reload) | |
33 | { | |
34 | struct stat stat_buf; | |
35 | ||
36 | if (stat(filename, &stat_buf) < 0) | |
37 | { | |
38 | courier_auth_err("stat(%s) failed", filename); | |
39 | return false; | |
40 | } | |
41 | ||
42 | if (loaded) | |
43 | { | |
44 | if (stat_buf.st_mtime != config_timestamp) | |
45 | do_reload(); | |
46 | return true; | |
47 | } | |
48 | ||
49 | loaded=open_and_load_file(reload); | |
50 | ||
51 | if (loaded) | |
52 | config_timestamp=stat_buf.st_mtime; | |
53 | return loaded; | |
54 | } | |
55 | ||
56 | class courier::auth::config_file::isspace { | |
57 | ||
58 | public: | |
59 | ||
60 | bool operator()(char c) | |
61 | { | |
62 | return std::isspace(c); | |
63 | } | |
64 | }; | |
65 | ||
66 | class courier::auth::config_file::not_isspace : public isspace { | |
67 | ||
68 | public: | |
69 | ||
70 | bool operator()(char c) | |
71 | { | |
72 | return !isspace::operator()(c); | |
73 | } | |
74 | }; | |
75 | ||
76 | ||
77 | bool courier::auth::config_file::open_and_load_file(bool reload) | |
78 | { | |
79 | std::ifstream f(filename); | |
80 | ||
81 | if (!f.is_open()) | |
82 | { | |
83 | courier_auth_err("Cannot open %s", filename); | |
84 | ||
85 | return false; | |
86 | } | |
87 | ||
88 | std::string s; | |
89 | ||
90 | bool seen_marker=false; | |
91 | ||
92 | while (s.clear(), !std::getline(f, s).eof() || !s.empty()) | |
93 | { | |
94 | std::string::iterator e=s.end(); | |
95 | ||
96 | std::string::iterator p= | |
97 | std::find_if(s.begin(), e, not_isspace()); | |
98 | ||
99 | if (p == s.end() || *p == '#') | |
100 | { | |
101 | static const char marker[]="##NAME: MARKER:"; | |
102 | ||
103 | if (s.substr(0, sizeof(marker)-1) == marker) | |
104 | seen_marker=true; | |
105 | continue; | |
106 | } | |
107 | ||
108 | std::string::iterator q=std::find_if(p, e, isspace()); | |
109 | ||
110 | std::string name(p, q); | |
111 | std::string setting; | |
112 | ||
113 | while (1) | |
114 | { | |
115 | q=std::find_if(q, e, not_isspace()); | |
116 | ||
117 | while (q != e && isspace()(e[-1])) | |
118 | --e; | |
119 | ||
120 | if (q == e) | |
121 | break; | |
122 | ||
123 | bool continuing=false; | |
124 | ||
125 | if (e[-1] == '\\') | |
126 | { | |
127 | continuing=true; | |
128 | e[-1]=' '; | |
129 | } | |
130 | ||
131 | setting.insert(setting.end(), q, e); | |
132 | ||
133 | if (!continuing) | |
134 | break; | |
135 | ||
136 | std::getline(f, s); | |
137 | ||
138 | q=s.begin(); | |
139 | e=s.end(); | |
140 | } | |
141 | ||
142 | parsed_config.insert(std::make_pair(name, setting)); | |
143 | } | |
144 | ||
145 | if (!seen_marker) | |
146 | { | |
147 | courier_auth_err((reload | |
148 | ? "marker line not found in %s will try again later" | |
149 | : "marker line not found in %s (probably forgot to run sysconftool after an upgrade)"), filename); | |
150 | return false; | |
151 | } | |
152 | ||
153 | return do_load(); | |
154 | } | |
155 | ||
156 | bool courier::auth::config_file::getconfig(const char *name, | |
157 | std::string &value, | |
158 | bool required, | |
159 | const char *default_value) const | |
160 | { | |
161 | std::map<std::string, std::string>::const_iterator | |
162 | iter=parsed_config.find(name); | |
163 | ||
164 | if (iter != parsed_config.end()) | |
165 | { | |
166 | value=iter->second; | |
167 | return true; | |
168 | } | |
169 | ||
170 | if (required) | |
171 | { | |
172 | courier_auth_err("%s not found in %s", | |
173 | name, filename); | |
174 | return false; | |
175 | } | |
176 | ||
177 | value.clear(); | |
178 | if (default_value) | |
179 | value=default_value; | |
180 | return true; | |
181 | } | |
182 | ||
183 | template<> | |
184 | bool courier::auth::config_file::config(const char *name, | |
185 | std::string &value, | |
186 | bool required, | |
187 | const char *default_value) const | |
188 | { | |
189 | return getconfig(name, value, required, default_value); | |
190 | } | |
191 | ||
192 | std::string courier::auth::config_file::config(const char *name) const | |
193 | { | |
194 | return config(name, 0); | |
195 | } | |
196 | ||
197 | std::string courier::auth::config_file::config(const char *name, | |
198 | const char *default_value) const | |
199 | { | |
200 | std::string retval; | |
201 | ||
202 | config(name, retval, false, default_value); | |
203 | ||
204 | return retval; | |
205 | } | |
206 | ||
207 | std::string | |
208 | courier::auth::config_file::expand_string(const std::string &s, | |
209 | const std::map<std::string, | |
210 | std::string> ¶meters) | |
211 | { | |
212 | std::ostringstream o; | |
213 | ||
214 | std::string::const_iterator b=s.begin(), e=s.end(), p; | |
215 | std::map<std::string, std::string>::const_iterator p_iter; | |
216 | ||
217 | while (b != e) | |
218 | { | |
219 | p=std::find(b, e, '$'); | |
220 | ||
221 | o << std::string(b, p); | |
222 | ||
223 | b=p; | |
224 | ||
225 | if (b == e) | |
226 | continue; | |
227 | ||
228 | if (*++b != '(') | |
229 | { | |
230 | o << '$'; | |
231 | continue; | |
232 | } | |
233 | ||
234 | p=std::find(++b, e, ')'); | |
235 | ||
236 | p_iter=parameters.find(std::string(b, p)); | |
237 | b=p; | |
238 | if (b != e) | |
239 | ++b; | |
240 | ||
241 | if (p_iter != parameters.end()) | |
242 | o << p_iter->second; | |
243 | } | |
244 | return o.str(); | |
245 | } | |
246 | ||
247 | std::string | |
248 | courier::auth::config_file::parse_custom_query(const std::string &s, | |
249 | const std::string &login, | |
250 | const std::string &defdomain, | |
251 | std::map<std::string, | |
252 | std::string> ¶meters) | |
253 | { | |
254 | ||
255 | std::string::const_iterator b=login.begin(), | |
256 | e=login.end(), | |
257 | p=std::find(b, e, '@'); | |
258 | ||
259 | parameters["local_part"]=std::string(b, p); | |
260 | parameters["domain"]=p == e ? defdomain:std::string(p+1, e); | |
261 | ||
262 | return expand_string(s, parameters); | |
263 | } |