1 /*
2    Bacula(R) - The Network Backup Solution
3 
4    Copyright (C) 2000-2020 Kern Sibbald
5 
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8 
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13 
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16 
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 
20 #include "config-storage.h"
21 #include <android/log.h>
22 #include <iostream>
23 #include <fstream>
24 #include "resmodel.h"
25 
26 extern URES res_all;
27 extern char *configfile;        // defined in tray-monitor.cpp
28 
29 /* Check for \ at the end */
is_str_valid(POOLMEM ** buf,const char * p)30 static char *is_str_valid(POOLMEM **buf, const char *p)
31 {
32    char *p1;
33    if (!p || !*p) {
34       return NULL;
35    }
36    p1 = *buf = check_pool_memory_size(*buf, (strlen(p) + 1));
37    for (; *p ; p++) {
38       if (*p == '\\') {
39          *p1++ = '/';
40 
41       } else if (*p == '"') {
42          return NULL;
43 
44       } else {
45          *p1++ = *p;
46       }
47    }
48    *p1 = 0;
49    return *buf;
50 }
51 
reloadResources()52 bool ConfigStorage::reloadResources()
53 {
54    reloadResources(false);
55 }
56 
reloadResources(bool encodePwd)57 bool ConfigStorage::reloadResources(bool encodePwd)
58 {
59    bool ret;
60    config = New(CONFIG());
61    config->encode_password(encodePwd);
62    config->init(configfile, NULL, M_ERROR, (void *)&res_all, res_all_size,
63                 r_first, r_last, resources, &rhead);
64    ret = config->parse_config();
65    return ret;
66 }
67 
68 
getMonitor()69 MONITOR *ConfigStorage::getMonitor() {
70     MONITOR *mon = NULL;
71     mon = (MONITOR *) GetNextRes(rhead, R_MONITOR, NULL);
72     return mon;
73 }
74 
saveMonitor(const char * deviceId)75 const char *ConfigStorage::saveMonitor(const char *deviceId) {
76     MONITOR mon;
77     POOLMEM *monName = get_pool_memory(PM_FNAME);
78     Mmsg(monName, "%s-mon", deviceId);
79     mon.hdr.name = monName;
80     const char *err_msg = saveMonitor(&mon);
81     free_and_null_pool_memory(monName);
82     return err_msg;
83 }
84 
saveMonitor(MONITOR * mon)85 const char *ConfigStorage::saveMonitor(MONITOR *mon)
86 {
87     const char *error_msg = NULL;
88     POOL_MEM tmp_fname;
89     Mmsg(tmp_fname, "%s.temp", configfile);
90     FILE *fp = fopen(tmp_fname.c_str(), "w");
91 
92     if(!fp) {
93         return "Error - unable to open configuration file";
94     }
95 
96     writeMonitor(fp, mon);
97 
98     QList<RESMON *> *resources = getAllResources();
99     for(RESMON *res : *resources)  {
100         writeResource(fp, res, res->code);
101     }
102 
103     fclose(fp);
104     unlink(configfile);
105 
106     int result = rename(tmp_fname.c_str(), configfile);
107 
108     if (result != 0) {
109         error_msg = "Error - unable to write to the configuration file";
110     }
111 
112     if(error_msg == NULL) {
113       reloadResources();
114       dump_storage();
115     }
116 
117     return error_msg;
118 }
119 
getResourceByName(rescode resCode,const char * resName)120 RESMON *ConfigStorage::getResourceByName(rescode resCode, const char* resName) {
121    RESMON *res = NULL;
122    QList<RESMON *> *resources = getResources(resCode);
123 
124    for(RESMON *r : *resources)  {
125        if(strcmp(r->hdr.name, resName) == 0) {
126             res = r;
127        }
128    }
129 
130    return res;
131 }
132 
getResources(rescode resCode)133 QList<RESMON *> *ConfigStorage::getResources(rescode resCode) {
134     QList<RESMON *> *resources = new QList<RESMON *>();
135     RESMON *res;
136 
137     for(res=NULL; (res=(RESMON *)GetNextRes(rhead, resCode, (RES*)res));) {
138         res->code = resCode;
139         resources->push_back(res);
140     }
141 
142     return resources;
143 }
144 
getAllResources()145 QList<RESMON *> *ConfigStorage::getAllResources() {
146     QList<RESMON *> *resources = new QList<RESMON *>();
147     RESMON *res;
148 
149     for(res=NULL; (res=(RESMON *)GetNextRes(rhead, R_CLIENT, (RES*)res));) {
150         res->code = R_CLIENT;
151         resources->push_back(res);
152     }
153 
154     for(res=NULL; (res=(RESMON *)GetNextRes(rhead, R_DIRECTOR, (RES*)res));) {
155         res->code = R_DIRECTOR;
156         resources->push_back(res);
157     }
158 
159     for(res=NULL; (res=(RESMON *)GetNextRes(rhead, R_STORAGE, (RES*)res));) {
160         res->code = R_STORAGE;
161         resources->push_back(res);
162     }
163 
164     return resources;
165 }
166 
saveResources(QList<QObject * > * clients,QList<QObject * > * directors,QList<QObject * > * storages)167 const char *ConfigStorage::saveResources(
168         QList<QObject *> *clients,
169         QList<QObject *> *directors,
170         QList<QObject *> *storages
171         )
172 {
173     const char *error_msg = NULL;
174 
175     POOL_MEM tmp_fname;
176     Mmsg(tmp_fname, "%s.temp", configfile);
177     FILE *fp = fopen(tmp_fname.c_str(), "w");
178 
179     if(!fp) {
180         return "Unable to open configuration file";
181     }
182 
183     MONITOR *mon = getMonitor();
184     writeMonitor(fp, mon);
185 
186     for(QObject *obj : *clients)  {
187         ResourceModel *model = (ResourceModel *) obj;
188         RESMON *res = model->resource();
189         writeResource(fp, res, R_CLIENT);
190     }
191 
192     for(QObject *obj : *directors)  {
193         ResourceModel *model = (ResourceModel *) obj;
194         RESMON *res = model->resource();
195         writeResource(fp, res, R_DIRECTOR);
196     }
197 
198     for(QObject *obj : *storages)  {
199         ResourceModel *model = (ResourceModel *) obj;
200         RESMON *res = model->resource();
201         writeResource(fp, res, R_STORAGE);
202     }
203 
204     fclose(fp);
205     unlink(configfile);
206     int result = rename(tmp_fname.c_str(), configfile);
207 
208     if (result != 0) {
209         error_msg = "Unable to write to the configuration file";
210     }
211 
212     reloadResources();
213     return error_msg;
214 }
215 
writeMonitor(FILE * fp,MONITOR * mon)216 void ConfigStorage::writeMonitor(FILE *fp, MONITOR *mon) {
217     fprintf(fp, "Monitor {\n Name = \"%s\"\n", mon->hdr.name);
218     fprintf(fp, " Refresh Interval = %d\n", 120);
219     fprintf(fp, "}\n");
220 }
221 
222 
addResource(const char * resName,rescode code)223 const char *ConfigStorage::addResource(const char *resName, rescode code) {
224     return addResource(resName, code, false);
225 }
226 
addResource(const char * resName,rescode code,bool managed)227 const char *ConfigStorage::addResource(const char *resName, rescode code, bool managed) {
228     RESMON res;
229     res.address = "localhost";
230     res.password = (char *) AndroidFD::devicePwd().toUtf8().constData();
231     res.managed = managed;
232     POOLMEM *pm_resName = get_pool_memory(PM_FNAME);
233 
234     switch (code) {
235     case R_CLIENT:
236         Mmsg(pm_resName, "%s-fd", resName);
237         res.port = 9102;
238         res.use_remote = false;
239         break;
240     case R_DIRECTOR:
241         Mmsg(pm_resName, "%s-dir", resName);
242         res.port = 9101;
243         break;
244     case R_STORAGE:
245         Mmsg(pm_resName, "%s-sd", resName);
246         res.port = 9103;
247         break;
248     default:
249         return NULL;
250     }
251 
252     res.hdr.name = pm_resName;
253     const char *err_msg = addResource(&res, code);
254     free_and_null_pool_memory(pm_resName);
255     return err_msg;
256 }
257 
addResource(RESMON * newRes,rescode code)258 const char *ConfigStorage::addResource(RESMON *newRes, rescode code) {
259     const char *error_msg = validateResource(newRes);
260 
261     if(error_msg != NULL) {
262         return error_msg;
263     }
264 
265     FILE *fp = fopen(configfile, "a");
266 
267     if(!fp) {
268         return "Unable to open configuration file";
269     }
270 
271     writeResource(fp, newRes, code);
272     fclose(fp);
273     reloadResources();
274     return error_msg;
275 }
276 
editResource(RESMON * oldRes,RESMON * newRes,rescode resCode)277 const char *ConfigStorage::editResource(RESMON *oldRes, RESMON *newRes, rescode resCode) {
278     const char *error_msg = validateResource(newRes);
279 
280     if(error_msg != NULL) {
281         return error_msg;
282     }
283 
284     POOL_MEM tmp_fname;
285     Mmsg(tmp_fname, "%s.temp", configfile);
286     FILE *fp = fopen(tmp_fname.c_str(), "w");
287 
288     if(!fp) {
289         return "Unable to open configuration file";
290     }
291 
292     MONITOR *mon = getMonitor();
293     writeMonitor(fp, mon);
294 
295     QList<RESMON *> *resources = getAllResources();
296     for(RESMON *res : *resources)  {
297         if(strcmp(res->hdr.name, oldRes->hdr.name) == 0) {
298             writeResource(fp, newRes, resCode);
299         }
300         else {
301             writeResource(fp, res, res->code);
302         }
303     }
304 
305     fclose(fp);
306     unlink(configfile);
307     int result = rename(tmp_fname.c_str(), configfile);
308 
309     if (result != 0) {
310         error_msg = "Unable to write to the configuration file";
311     }
312 
313     if(error_msg == NULL) {
314       reloadResources();
315       dump_storage();
316     }
317 
318     return error_msg;
319 }
320 
validateResource(RESMON * res)321 const char *ConfigStorage::validateResource(RESMON *res) {
322     POOLMEM *buf1 = get_pool_memory(PM_FNAME);
323     POOLMEM *buf2 = get_pool_memory(PM_FNAME);
324     POOLMEM *buf3 = get_pool_memory(PM_FNAME);
325 
326     res->hdr.name = is_str_valid(&buf1, res->hdr.name);
327 
328     if(!res->hdr.name) {
329         return "The name of the Resource should be set";
330     }
331 
332     res->address = is_str_valid(&buf2, res->address);
333 
334     if(!res->address) {
335         return "The address of the Resource should be set";
336     }
337 
338     res->password = is_str_valid(&buf3, res->password);
339 
340     if(!res->password) {
341         return "The password of the Resource should be set";
342     }
343 
344     return NULL;
345 }
346 
writeResource(FILE * fp,RESMON * res,rescode code)347 void ConfigStorage::writeResource(FILE *fp, RESMON *res, rescode code) {
348     const char *resType;
349 
350     switch (code) {
351     case R_CLIENT:
352         resType = "Client";
353         break;
354     case R_DIRECTOR:
355         resType = "Director";
356         break;
357     case R_STORAGE:
358         resType = "Storage";
359         break;
360     default:
361         return;
362     }
363 
364     fprintf(fp, "%s {\n Name = \"%s\"\n Address = \"%s\"\n", resType, res->hdr.name, res->address);
365     fprintf(fp, " Password = \"%s\"\n", res->password);
366     fprintf(fp, " Port = %d\n", res->port);
367     fprintf(fp, " Connect Timeout = %d\n", 10);
368 
369     if (res->use_remote) {
370        fprintf(fp, " Remote = yes\n");
371     }
372 
373     if (res->managed) {
374        fprintf(fp, " Managed = yes\n");
375     }
376 
377     fprintf(fp, "}\n");
378 }
379 
380 
dump_storage()381 void ConfigStorage::dump_storage() {
382     __android_log_write(ANDROID_LOG_DEBUG, "Configuration File:", configfile);
383     std::string line;
384     std::ifstream myfile(configfile);
385     if (myfile.is_open())
386     {
387         __android_log_write(ANDROID_LOG_DEBUG, "Success!", "File was opened");
388       while ( getline (myfile, line) )
389       {
390           __android_log_write(ANDROID_LOG_DEBUG, "Line:", line.c_str());
391       }
392       myfile.close();
393     } else {
394         __android_log_write(ANDROID_LOG_DEBUG, "Error!", "Unable to open file");
395     }
396 }
397 
398 
399 
400