1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <sys/types.h>
33 #include <cx/hash_map.h>
34 #include <cx/utils.h>
35 #include <errno.h>
36 #include <libxml/tree.h>
37
38 #include "config.h"
39 #include "system.h"
40
41 #include <libidav/utils.h>
42 #include <libidav/config.h>
43
44 #define xstreq(a,b) xmlStrEqual(
BAD_CAST a,
BAD_CAST b)
45 #define xstrEQ(a,b) !xmlStrcasecmp(
BAD_CAST a,
BAD_CAST b)
46
47 #define print_error(lineno, ...) \
48 do {\
49 fprintf(stderr,
"Error (config.xml line %u): ", lineno); \
50 fprintf(stderr,
__VA_ARGS__); \
51 fprintf(stderr,
"Abort.\n"); \
52 }
while(
0);
53 #define print_warning(lineno, ...) \
54 do {\
55 fprintf(stderr,
"Warning (config.xml line %u): ", lineno); \
56 fprintf(stderr,
__VA_ARGS__); \
57 }
while(
0);
58
59 #ifdef _WIN32
60 #define ENV_HOME getenv(
"USERPROFILE")
61 #else
62 #define ENV_HOME getenv(
"HOME")
63 #endif
64
65 static CxMap *repos;
66 static CxMap *keys;
67
68 static DavConfig *davconfig;
69 static PwdStore *pstore;
70
71 static char *secretstore_unlock_cmd;
72 static char *secretstore_lock_cmd;
73
74 int check_config_dir(
void) {
75 char *file = util_concat_path(
ENV_HOME,
".dav");
76 int ret =
0;
77 if(util_mkdir(file,
S_IRWXU)) {
78 if(errno !=
EEXIST) {
79 ret =
1;
80 }
81 }
82 free(file);
83 return ret;
84 }
85
86 static DavContext *context;
87
88 void create_default_config(
char *file) {
89 xmlDoc *doc = xmlNewDoc(
BAD_CAST "1.0");
90 xmlNode *root = xmlNewNode(
NULL,
BAD_CAST "configuration");
91 xmlDocSetRootElement(doc, root);
92 xmlSaveFormatFileEnc(file, doc,
"UTF-8",
1);
93 xmlFreeDoc(doc);
94 }
95
96 char* config_file_path(
char *name) {
97 char *davd = util_concat_path(
ENV_HOME,
".dav");
98 if(!davd) {
99 return NULL;
100 }
101 char *path = util_concat_path(davd, name);
102 free(davd);
103 return path;
104 }
105
106 cxmutstr config_load_file(
const char *path) {
107 FILE *file = sys_fopen(path,
"r");
108 if(!file) {
109 return (cxmutstr){
NULL,
0};
110 }
111
112 CxBuffer buf;
113 cxBufferInit(&buf,
NULL,
1024, cxDefaultAllocator,
CX_BUFFER_AUTO_EXTEND);
114 cx_stream_copy(file, &buf, (cx_read_func)fread, (cx_write_func)cxBufferWrite);
115 fclose(file);
116
117 return cx_mutstrn(buf.space, buf.size);
118 }
119
120 int load_config(DavContext *ctx) {
121 context = ctx;
122
123 repos = cxHashMapCreate(cxDefaultAllocator,
CX_STORE_POINTERS,
16);
124 keys = cxHashMapCreate(cxDefaultAllocator,
CX_STORE_POINTERS,
16);
125
126 char *pwfile = util_concat_path(
ENV_HOME,
".dav/secrets.crypt");
127 pstore = pwdstore_open(pwfile);
128 free(pwfile);
129
130 char *file = util_concat_path(
ENV_HOME,
".dav/config.xml");
131
132 struct stat s;
133 if(stat(file, &s)) {
134 switch(errno) {
135 case ENOENT: {
136 davconfig = dav_config_new(
NULL);
137 return 0;
138 }
139 default: {
140 perror(
"Cannot load config.xml");
141 }
142 }
143 return 1;
144 }
145
146 cxmutstr config_content = config_load_file(file);
147 int config_error;
148 davconfig = dav_config_load(config_content, &config_error);
149 free(config_content.ptr);
150 free(file);
151
152 if(!davconfig) {
153 fprintf(stderr,
"Cannot load config.xml\n");
154 return 1;
155 }
156
157 if(dav_config_register_namespaces(davconfig, ctx)) {
158 return 1;
159 }
160
161 return dav_config_register_keys(davconfig, ctx, load_key_file);
162 }
163
164 DavConfig* load_config_file(
void) {
165 char *file = util_concat_path(
ENV_HOME,
".dav/config.xml");
166
167 struct stat s;
168 if(stat(file, &s)) {
169 switch(errno) {
170 case ENOENT: {
171 davconfig = dav_config_new(
NULL);
172 return NULL;
173 }
174 default: {
175 perror(
"Cannot load config.xml");
176 }
177 }
178 return NULL;
179 }
180
181 cxmutstr config_content = config_load_file(file);
182 int config_error;
183 DavConfig *cfg = dav_config_load(config_content, &config_error);
184 free(config_content.ptr);
185 free(file);
186 return cfg;
187 }
188
189
190 void set_config(DavConfig *cfg) {
191 if(davconfig) {
192 dav_config_free(davconfig);
193 }
194 davconfig = cfg;
195 }
196
197 DavConfig* get_config(
void) {
198 return davconfig;
199 }
200
201 int store_config(
void) {
202 if(check_config_dir()) {
203 return 1;
204 }
205
206 CxBuffer *buf = dav_config2buf(davconfig);
207 if(!buf) {
208 return 1;
209 }
210
211 char *file = util_concat_path(
ENV_HOME,
".dav/config.xml");
212 FILE *cout = sys_fopen(file,
"w");
213 if(!cout) {
214 cxBufferFree(buf);
215 return 1;
216 }
217
218
219
220
221
222 fwrite(buf->space, buf->size,
1, cout);
223
224 cxBufferFree(buf);
225 fclose(cout);
226
227 return 0;
228 }
229
230 void free_config(
void) {
231 if(davconfig) {
232 dav_config_free(davconfig);
233 }
234 }
235
236 cxmutstr load_key_file(
const char *filename) {
237 cxmutstr k;
238 k.ptr =
NULL;
239 k.length =
0;
240
241 FILE *file =
NULL;
242 if(filename[
0] ==
'/') {
243 file = sys_fopen(filename,
"r");
244 }
else {
245 char *path = util_concat_path(
ENV_HOME,
".dav/");
246 char *p2 = util_concat_path(path, filename);
247 file = sys_fopen(p2,
"r");
248 free(path);
249 free(p2);
250 }
251
252 if(!file) {
253 fprintf(stderr,
"Error: cannot load keyfile %s\n", filename);
254 return k;
255 }
256
257 char *data = malloc(
256);
258 size_t r = fread(data,
1,
256, file);
259 k.ptr = data;
260 k.length = r;
261
262 fclose(file);
263 return k;
264 }
265
266 PwdStore* get_pwdstore(
void) {
267 return pstore;
268 }
269
270 void set_pwdstore(PwdStore *newstore) {
271 if(pstore) {
272
273 }
274 pstore = newstore;
275 }
276
277 int pwdstore_save(PwdStore *pwdstore) {
278 if(check_config_dir()) {
279 return 1;
280 }
281
282 char *pwfile = util_concat_path(
ENV_HOME,
".dav/secrets.crypt");
283 int ret = pwdstore_store(pwdstore, pwfile);
284 free(pwfile);
285 return ret;
286 }
287
288 typedef struct CredLocation {
289 char *id;
290 char *location;
291 } CredLocation;
292
293 static int cmp_url_cred_entry(CredLocation *e1, CredLocation *e2,
void *n) {
294 return strcmp(e2->location, e1->location);
295 }
296
297 static void free_cred_location(CredLocation *c) {
298
299 free(c->location);
300 free(c);
301 }
302
303 int get_stored_credentials(
const char *credid,
char **user,
char **password) {
304 if(!credid) {
305 return 0;
306 }
307
308 PwdStore *secrets = get_pwdstore();
309 if(!secrets) {
310 fprintf(stderr,
"Error: no secrets store available\n");
311 return 0;
312 }
313
314 if(pwdstore_has_id(secrets, credid)) {
315 if(!secrets->isdecrypted) {
316 if(pwdstore_decrypt_secrets(secrets)) {
317 return 0;
318 }
319 }
320
321 PwdEntry *s_cred = pwdstore_get(secrets, credid);
322 if(s_cred) {
323 *user = s_cred->user;
324 *password = s_cred->password;
325 return 1;
326 }
327 }
else {
328 fprintf(stderr,
"Error: credentials id ''%s'' not found\n", credid);
329 }
330
331 return 0;
332 }
333
334
335 const char* get_location_credentials(DavCfgRepository *repo,
const char *path) {
336 PwdStore *secrets = get_pwdstore();
337 if(!secrets) {
338 return NULL;
339 }
340
341
342
343
344
345 CxList *locations = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)cmp_url_cred_entry,
CX_STORE_POINTERS);
346 cxDefineDestructor(locations, free_cred_location);
347 CxIterator i = cxListIterator(secrets->locations);
348 cx_foreach(PwdIndexEntry*, e, i) {
349 CxIterator entry_iter = cxListIterator(e->locations);
350 cx_foreach(
char *, loc, entry_iter) {
351 cxmutstr rpath;
352 DavCfgRepository *r = dav_config_url2repo_s(davconfig, cx_str(loc), &rpath);
353 CredLocation *urlentry = calloc(
1,
sizeof(CredLocation));
354 urlentry->id = e->id;
355 urlentry->location = util_concat_path_s(cx_strcast(r->url.value), cx_strcast(rpath)).ptr;
356 cxListAdd(locations, urlentry);
357 free(rpath.ptr);
358 }
359 }
360
361 cxListSort(locations);
362
363
364 cxmutstr req_url_proto = util_concat_path_s(cx_strcast(repo->url.value), cx_str(path));
365 cxstring req_url = cx_strcast(req_url_proto);
366 if(cx_strprefix(req_url,
CX_STR(
"http://"))) {
367 req_url = cx_strsubs(req_url,
7);
368 }
else if(cx_strprefix(req_url,
CX_STR(
"https://"))) {
369 req_url = cx_strsubs(req_url,
8);
370 }
371
372
373
374 const char *id =
NULL;
375 i = cxListIterator(locations);
376 cx_foreach(CredLocation*, cred, i) {
377 cxstring cred_url = cx_str(cred->location);
378
379
380 if(cx_strprefix(cred_url,
CX_STR(
"http://"))) {
381 cred_url = cx_strsubs(cred_url,
7);
382 }
else if(cx_strprefix(cred_url,
CX_STR(
"https://"))) {
383 cred_url = cx_strsubs(cred_url,
8);
384 }
385
386 if(cx_strprefix(req_url, cred_url)) {
387 id = cred->id;
388 break;
389 }
390 }
391
392 free(req_url_proto.ptr);
393 cxListDestroy(locations);
394
395 return id;
396 }
397