Import Upstream version 0.69.0
[hcoop/debian/courier-authlib.git] / authconfigfile.cpp
CommitLineData
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
14extern "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
27courier::auth::config_file::config_file(const char *filenameArg)
28 : filename(filenameArg), loaded(false)
29{
30}
31
32bool 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
56class courier::auth::config_file::isspace {
57
58public:
59
60 bool operator()(char c)
61 {
62 return std::isspace(c);
63 }
64};
65
66class courier::auth::config_file::not_isspace : public isspace {
67
68public:
69
70 bool operator()(char c)
71 {
72 return !isspace::operator()(c);
73 }
74};
75
76
77bool 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
156bool 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
183template<>
184bool 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
192std::string courier::auth::config_file::config(const char *name) const
193{
194 return config(name, 0);
195}
196
197std::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
207std::string
208courier::auth::config_file::expand_string(const std::string &s,
209 const std::map<std::string,
210 std::string> &parameters)
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
247std::string
248courier::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> &parameters)
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}