1 /*===========================================================================
2 *
3 *                            PUBLIC DOMAIN NOTICE
4 *               National Center for Biotechnology Information
5 *
6 *  This software/database is a "United States Government Work" under the
7 *  terms of the United States Copyright Act.  It was written as part of
8 *  the author's official duties as a United States Government employee and
9 *  thus cannot be copyrighted.  This software/database is freely available
10 *  to the public for use. The National Library of Medicine and the U.S.
11 *  Government have not placed any restriction on its use or reproduction.
12 *
13 *  Although all reasonable efforts have been taken to ensure the accuracy
14 *  and reliability of the software and data, the NLM and the U.S.
15 *  Government do not and cannot warrant the performance or results that
16 *  may be obtained by using this software or data. The NLM and the U.S.
17 *  Government disclaim all warranties, express or implied, including
18 *  warranties of performance, merchantability or fitness for any particular
19 *  purpose.
20 *
21 *  Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26 
27 #include <kfg/extern.h>
28 
29 #include <kfg/config.h>
30 #include <kfg/repository.h> /* KRepositoryMgr */
31 #include <kfg/kfg-priv.h>
32 
33 #include <klib/namelist.h> /* KNamelistRelease */
34 #include <klib/out.h> /* OUTMSG */
35 #include <klib/klib-priv.h>
36 #include <klib/rc.h>
37 
38 #include <kfs/directory.h>
39 #include <kfs/dyload.h> /* KDyld */
40 #include <kfs/file.h> /* KFileRead */
41 #include <kfs/nullfile.h> /* KFileMakeNullUpdate */
42 #include <kfs/md5.h> /* KMD5SumFmt */
43 
44 #include <sysalloc.h>
45 
46 #include <stdarg.h> /* va_start */
47 #include <stdio.h> /* sprintf */
48 #include <stdlib.h> /* malloc */
49 #include <string.h> /* memset */
50 #include <limits.h> /* PATH_MAX */
51 #include <assert.h>
52 
53 #ifndef PATH_MAX
54 #define PATH_MAX 4096
55 #endif
56 
57 #define RELEASE(type, obj) do { rc_t rc2 = type##Release(obj); \
58     if (rc2 && !rc) { rc = rc2; } obj = NULL; } while (false)
59 
60 /*
61  * An unrecoverable error happened.
62  * We can help to solve it
63  * by reporting information about known application execution environment.
64  */
65 
66 #define report ( * f -> report )
67 #define reportData ( * f -> reportData )
68 #define reportData1 ( * f -> reportData1 )
69 #define reportOpen ( * f -> reportOpen )
70 #define reportOpen1 ( * f -> reportOpen1 )
71 #define reportClose ( * f -> reportClose )
72 #define reportClose1 ( * f -> reportClose1 )
73 #define reportError ( * f -> reportError )
74 #define reportErrorStr ( * f -> reportErrorStr )
75 #define reportErrorStrImpl ( * f -> reportErrorStrImpl )
76 #define reportErrorStrInt ( * f -> reportErrorStrInt )
77 #define reportError3Str ( * f -> reportError3Str )
78 
ReportKfgFiles(const ReportFuncs * f,int indent,const KConfig * cfg)79 static rc_t ReportKfgFiles(const ReportFuncs *f,
80     int indent, const KConfig* cfg)
81 {
82     rc_t rc = 0;
83 
84     uint32_t count = 0;
85     KNamelist* names = NULL;
86 
87     rc = KConfigListIncluded(cfg, &names);
88 
89     if (rc != 0) {
90         reportOpen(indent, "Files", 0);
91         reportError(indent + 1, rc, "KConfigListIncluded");
92     }
93     else {
94         rc = KNamelistCount(names, &count);
95         if (rc != 0) {
96             reportOpen(indent, "Files", 0);
97             reportErrorStr(indent + 1,
98                 rc, "KNamelistCount", "origin", "KConfigListIncluded");
99         }
100         else {
101             uint32_t i = 0;
102             reportOpen(indent, "Files", 1, "count", 'd', count);
103             for (i = 0; i < count && rc == 0; ++i) {
104                 const char* name = NULL;
105                 rc = KNamelistGet(names, i, &name);
106                 if (rc != 0) {
107                     reportErrorStrInt(indent + 1, rc, "KNamelistGet",
108                         "origin", "KConfigListIncluded", "idx", i);
109                 }
110                 else
111                 {   report(indent + 1, "File", 1, "name", 's', name); }
112             }
113         }
114     }
115     reportClose(indent, "Files");
116 
117     RELEASE(KNamelist, names);
118 
119     return rc;
120 }
121 
122 static
sKConfigNode_Read(const KConfigNode * node,char * buffer,size_t buf_sz,char ** overflow_buf,bool * cant_allocate)123 rc_t sKConfigNode_Read(const KConfigNode* node, char* buffer, size_t buf_sz,
124     char** overflow_buf, bool* cant_allocate)
125 {
126     rc_t rc = 0;
127     size_t num_read = 0;
128     size_t remaining = 0;
129     assert(overflow_buf && cant_allocate);
130     *cant_allocate = false;
131     *overflow_buf = NULL;
132     rc = KConfigNodeRead(node, 0, buffer, buf_sz, &num_read, &remaining);
133     if (rc != 0)
134     {   return rc; }
135     if (num_read < buf_sz)
136     {   buffer[num_read] = '\0'; }
137     else {
138         size_t new_buf_sz = num_read + remaining + 1;
139         char* overflow = malloc(new_buf_sz);
140         if (overflow == NULL) {
141             int i = 0;
142             for (i = 2; i < 5 && buf_sz - i > 0; ++i)
143             {   buffer[buf_sz - i] = '.'; }
144             buffer[buf_sz - 1] = '\0';
145             *cant_allocate = true;
146         }
147         else {
148             buffer = *overflow_buf = overflow;
149             buf_sz =
150             rc = KConfigNodeRead
151                 (node, 0, buffer, new_buf_sz, &num_read, &remaining);
152             if (rc != 0)
153             {   return rc; }
154             assert(num_read < new_buf_sz && remaining == 0);
155             buffer[num_read] = '\0';
156         }
157     }
158     return rc;
159 }
160 
161 static rc_t ReportChildNode(const ReportFuncs *f, int indent,
162     const KNamelist* names, const KConfigNode* node, const char* root, uint32_t idx);
163 
164 static
ReportConfigNodeChildren(const ReportFuncs * f,int indent,const KConfigNode * node,const char * nodeName)165 rc_t ReportConfigNodeChildren(const ReportFuncs *f, int indent,
166     const KConfigNode* node, const char* nodeName)
167 {
168     KNamelist* names = NULL;
169     rc_t rc = KConfigNodeListChild(node, &names);
170     if (rc != 0) {
171         reportErrorStrImpl(indent,
172             rc, "KConfigNodeListChild", "node", nodeName, false);
173     }
174     else {
175         uint32_t count = 0;
176         rc = KNamelistCount(names, &count);
177         if (rc != 0) {
178             reportErrorStrImpl
179                 (indent, rc, "KNamelistCount", "node", nodeName, false);
180         }
181         else {
182             if (count) {
183                 uint32_t i = 0;
184                 int j;
185                 OUTMSG(("\n"));
186                 for (i = 0; i < count && rc == 0; ++i) {
187                     rc = ReportChildNode
188                         (f, indent + 1, names, node, nodeName, i);
189                 }
190                 for (j = 0; j < indent; ++j)
191                 {   OUTMSG((" ")); }
192             }
193         }
194     }
195     RELEASE(KNamelist, names);
196     return rc;
197 }
198 
ReportConfigNode(const ReportFuncs * f,int indent,const char * root,const char * name,const KConfigNode * node,const char * node_name)199 static rc_t ReportConfigNode(const ReportFuncs *f, int indent, const char* root,
200     const char* name, const KConfigNode* node, const char* node_name)
201 {
202     rc_t rc = 0;
203 
204     char local[PATH_MAX + 1] = "";
205     const char* nodeName = node_name ? node_name : name;
206     char* overflow = NULL;
207     bool cantallocate = false;
208 
209     reportOpen1(indent, nodeName);
210     rc = sKConfigNode_Read(node, local, sizeof local, &overflow, &cantallocate);
211     if (rc == 0) {
212         char* buf = overflow ? overflow : local;
213         rc = reportData1(buf);
214         free(overflow);
215         overflow = NULL;
216         if (rc == 0)
217         {   rc = ReportConfigNodeChildren(f, indent, node, nodeName); }
218     }
219     else {
220         reportError3Str
221             (indent + 1, rc, "KConfigNodeRead", "node", root, "/", name, false);
222     }
223     reportClose1(nodeName);
224 
225     return rc;
226 }
227 
ReportConfigNode_File(const ReportFuncs * f,int indent,const char * root,const char * name,const KConfigNode * node,const char * node_name)228 static rc_t ReportConfigNode_File(const ReportFuncs *f, int indent,
229     const char* root,
230     const char* name, const KConfigNode* node, const char* node_name)
231 {
232     rc_t rc = 0;
233     char local[PATH_MAX + 1] = "";
234     const char* nodeName = node_name ? node_name : name;
235     char* overflow = NULL;
236     bool cantallocate = false;
237     rc = sKConfigNode_Read(node, local, sizeof local, &overflow, &cantallocate);
238     if (rc) {
239         reportError3Str
240             (indent, rc, "KConfigNodeRead", "node", root, "/", name, false);
241     }
242     else {
243         const char* buf = overflow ? overflow : local;
244         KPathType file_type = kptNotFound;
245         const char* type = NULL;
246         if (!cantallocate) {
247             KDirectory* dir = NULL;
248             rc = KDirectoryNativeDir(&dir);
249             if (rc == 0) {
250                 file_type = KDirectoryPathType(dir, "%s", buf);
251                 file_type &= ~kptAlias;
252                 type = file_type == kptFile ? "exists" :
253                           file_type == kptNotFound ? "not found" : "unexpected";
254             }
255             RELEASE(KDirectory, dir);
256         }
257         else
258         {   type = "noo long"; }
259         if (rc == 0)
260         {   reportData(indent, nodeName, buf, 1, "file", 's', type); }
261     }
262     free(overflow);
263     overflow = NULL;
264     return rc;
265 }
266 
ReportChildNode(const ReportFuncs * f,int indent,const KNamelist * names,const KConfigNode * node,const char * root,uint32_t idx)267 static rc_t ReportChildNode(const ReportFuncs *f, int indent,
268     const KNamelist* names,
269     const KConfigNode* node, const char* root, uint32_t idx)
270 {
271     rc_t rc = 0;
272 
273     const char* name = NULL;
274     rc = KNamelistGet(names, idx, &name);
275     if (rc != 0) {
276         reportErrorStrInt
277             (indent + 1, rc, "KNamelistGet", "node", root, "idx", idx);
278     }
279     else {
280         const KConfigNode* child = NULL;
281 
282         rc = KConfigNodeOpenNodeRead(node, &child, "%s", name);
283         if (rc != 0) {
284             reportOpen(indent, name, 0);
285             reportError3Str(indent + 1, rc, "KConfigNodeOpenNodeRead",
286                 "node", root, "/", name, true);
287             reportClose(indent, name);
288         }
289         else {
290             rc = ReportConfigNode(f, indent, root, name, child, NULL);
291         }
292 
293         RELEASE(KConfigNode, child);
294     }
295 
296     return rc;
297 }
298 
299 static
ReportRefseq(const ReportFuncs * f,int indent,const KConfig * cfg)300 rc_t ReportRefseq(const ReportFuncs *f, int indent, const KConfig* cfg)
301 {
302     rc_t rc = 0;
303 
304     const char root[] = "refseq";
305 
306     const KConfigNode* node = NULL;
307     rc = KConfigOpenNodeRead(cfg, &node, "%s", root);
308     if (rc != 0) {
309         if (GetRCState(rc) == rcNotFound) {
310             report(indent, root, 1, "state", 's', "not found");
311             rc = 0;
312         }
313         else
314         {   reportErrorStr(indent, rc, "KConfigOpenNodeRead", "node", root); }
315     }
316     else {
317         KNamelist* names = NULL;
318         rc = KConfigNodeListChild(node, &names);
319         if (rc != 0)
320         {   reportErrorStr(indent, rc, "KConfigNodeListChild", "node", root); }
321         else {
322             uint32_t count = 0;
323             rc = KNamelistCount(names, &count);
324             if (rc != 0)
325             {   reportErrorStr(indent, rc, "KNamelistCount", "node", root); }
326             else {
327                 uint32_t i = 0;
328                 reportOpen(indent, root, 0);
329                 for (i = 0; i < count && rc == 0; ++i)
330                 {   rc = ReportChildNode(f, indent + 1, names, node, root, i); }
331                 reportClose(indent, root);
332             }
333         }
334         RELEASE(KNamelist, names);
335     }
336 
337     RELEASE(KConfigNode, node);
338 
339     return rc;
340 }
341 
342 static
ReportSra(const ReportFuncs * f,int indent,const KConfig * cfg)343 rc_t ReportSra(const ReportFuncs *f, int indent, const KConfig* cfg)
344 {
345     rc_t rc = 0;
346     const char root[] = "sra";
347     const KConfigNode* node = NULL;
348     assert(cfg);
349     rc = KConfigOpenNodeRead(cfg, &node, "%s", root);
350     if (rc != 0) {
351         if (GetRCState(rc) == rcNotFound) {
352             report(indent, root, 1, "state", 's', "not found");
353             rc = 0;
354         }
355         else
356         {   reportErrorStr(indent, rc, "KConfigOpenNodeRead", "node", root); }
357     }
358     else {
359         KNamelist* names = NULL;
360         rc = KConfigNodeListChild(node, &names);
361         if (rc != 0)
362         {   reportErrorStr(indent, rc, "KConfigNodeListChild", "node", root); }
363         else {
364             uint32_t count = 0;
365             rc = KNamelistCount(names, &count);
366             if (rc != 0)
367             {   reportErrorStr(indent, rc, "KNamelistCount", "node", root); }
368             else {
369                 uint32_t i = 0;
370                 reportOpen(indent, root, 0);
371                 for (i = 0; i < count && rc == 0; ++i)
372                 {   rc = ReportChildNode(f, indent + 1, names, node, root, i); }
373                 reportClose(indent, root);
374             }
375         }
376         RELEASE(KNamelist, names);
377     }
378     RELEASE(KConfigNode, node);
379     return rc;
380 }
381 
382 static
ReportKrypto(const ReportFuncs * f,int indent,const KConfig * cfg)383 rc_t ReportKrypto(const ReportFuncs *f, int indent, const KConfig* cfg)
384 {
385     rc_t rc = 0;
386 
387     const char root[] = KFG_KRYPTO_PWFILE;
388     const char name[] = "krypto";
389 
390     const KConfigNode* node = NULL;
391     rc = KConfigOpenNodeRead(cfg, &node, "%s", root);
392     if (rc != 0) {
393         if (GetRCState(rc) == rcNotFound) {
394             report(indent, name, 1, "state", 's', "pwfile: not found");
395             rc = 0;
396         }
397         else
398         {   reportErrorStr(indent, rc, "KConfigOpenNodeRead", "node", root); }
399     }
400     else {
401         rc = ReportConfigNode_File(f, indent, "krypto", "pwfile", node, "krypto");
402     }
403 
404     RELEASE(KConfigNode, node);
405 
406     return rc;
407 }
408 
ReportRemoteAccess(const ReportFuncs * f,int indent,const KRepositoryMgr * mgr)409 static rc_t ReportRemoteAccess(const ReportFuncs *f,
410     int indent, const KRepositoryMgr *mgr)
411 {
412     const char root[] = "RemoteAccess";
413 
414     bool available = KRepositoryMgrHasRemoteAccess(mgr);
415     report(indent, root, 1, "available", 's', available ? "true" : "false");
416 
417     return 0;
418 }
419 
ReportCrntRepository(const ReportFuncs * f,int indent,const KRepositoryMgr * mgr)420 static rc_t ReportCrntRepository(const ReportFuncs *f,
421     int indent, const KRepositoryMgr *mgr)
422 {
423     rc_t rc = 0;
424 
425     const KRepository *protectd = NULL;
426 
427     const char root[] = "CurrentProtectedRepository";
428     bool open = false;
429 
430     if (rc == 0) {
431         rc = KRepositoryMgrCurrentProtectedRepository(mgr, &protectd);
432         if (rc != 0) {
433             if (rc == SILENT_RC(
434                 rcKFG, rcMgr, rcAccessing, rcNode, rcNotFound))
435             {
436                 report(indent, root, 1, "found", 's', "false");
437             }
438             else {
439                 reportOpen(indent, root, 0);
440                 open = true;
441                 reportErrorStr(indent + 1, rc,
442                     "KRepositoryMgrCurrentProtectedRepository", NULL, NULL);
443             }
444         }
445     }
446     if (rc == 0) {
447         char buffer[256];
448         size_t name_size = 0;
449         reportOpen(indent, root, 1, "found", 's', "true");
450         open = true;
451         rc = KRepositoryName(protectd, buffer, sizeof buffer, &name_size);
452         if (rc != 0) {
453             reportErrorStr(indent + 1, rc, "KRepositoryName",
454                 "origin", "KRepositoryMgrCurrentProtectedRepository");
455         }
456         else {
457             reportData(indent + 1, "name", buffer, 0);
458         }
459     }
460     if (open) {
461         reportClose(indent, root);
462     }
463 
464     RELEASE(KRepository, protectd);
465 
466     return rc;
467 }
468 
ReportKfg(const ReportFuncs * f,uint32_t indent,uint32_t skipCount,va_list args)469 rc_t ReportKfg
470     ( const ReportFuncs *f, uint32_t indent, uint32_t skipCount, va_list args )
471 {
472     rc_t rc = 0;
473 
474     KConfig *cfg = NULL;
475     const KRepositoryMgr *mgr = NULL;
476 
477     const char tag[] = "Configuration";
478 
479     reportOpen(indent, tag, 0);
480 
481     rc = KConfigMake(&cfg, NULL);
482     if (rc != 0) {
483         reportError(indent + 1, rc, "KConfigMake");
484     }
485     else if ((rc = KConfigMakeRepositoryMgrRead(cfg, &mgr)) != 0) {
486         reportError(indent + 1, rc, "KConfigMakeRepositoryMgrRead");
487     }
488     else {
489         {
490             rc_t rc2 = ReportKfgFiles(f, indent + 1, cfg);
491             if (rc == 0 && rc2 != 0)
492             {   rc = rc2; }
493         }
494         {
495             rc_t rc2 = ReportRefseq(f, indent + 1, cfg);
496             if (rc == 0 && rc2 != 0)
497             {   rc = rc2; }
498         }
499         {
500             rc_t rc2 = ReportKrypto(f, indent + 1, cfg);
501             if (rc == 0 && rc2 != 0)
502             {   rc = rc2; }
503         }
504         {
505             rc_t rc2 = ReportSra(f, indent + 1, cfg);
506             if (rc == 0 && rc2 != 0)
507             {   rc = rc2; }
508         }
509         {
510             rc_t rc2 = KConfigPrintPartial(cfg, indent, skipCount, args);
511             if (rc == 0 && rc2 != 0)
512             {   rc = rc2; }
513         }
514         {
515             rc_t rc2 = ReportRemoteAccess(f, indent + 1, mgr);
516             if (rc == 0 && rc2 != 0)
517             {   rc = rc2; }
518         }
519         {
520             rc_t rc2 = ReportCrntRepository(f, indent + 1, mgr);
521             if (rc == 0 && rc2 != 0)
522             {   rc = rc2; }
523         }
524     }
525 
526     reportClose(indent, tag);
527 
528     RELEASE(KRepositoryMgr, mgr);
529     RELEASE(KConfig, cfg);
530 
531     return rc;
532 }
533