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