1 /* zxcot.c  -  CoT (Circle-of-Trust) management tool: list CoT, add metadata to CoT
2  * Copyright (c) 2012 Synergetics SA (sampo@synergetics.be), All Rights Reserved.
3  * Copyright (c) 2009-2011 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
4  * This is confidential unpublished proprietary source code of the author.
5  * NO WARRANTY, not even implied warranties. Contains trade secrets.
6  * Distribution prohibited unless authorized in writing.
7  * Licensed under Apache License 2.0, see file COPYING.
8  * $Id: zxcot.c,v 1.5 2009-11-29 12:23:06 sampo Exp $
9  *
10  * 27.8.2009, created --Sampo
11  * 24.4.2012, obsoleted PATH=/var/zxid/idp. From now on, just use /var/zxid/ or VPATH --Sampo
12  */
13 
14 #include "platform.h"  /* for dirent.h */
15 
16 #include <string.h>
17 #include <stdio.h>
18 #include <fcntl.h>
19 #include <errno.h>
20 #include <sys/stat.h>  /* for mkdir(2) */
21 
22 #include "errmac.h"
23 #include "zx.h"
24 #include "zxid.h"
25 #include "zxidutil.h"
26 #include "zxidconf.h"
27 #include "c/zxidvers.h"
28 #include "c/zx-const.h"
29 #include "c/zx-ns.h"
30 #include "c/zx-data.h"
31 
32 char* help =
33 "zxcot  -  Circle-of-Trust and metadata management tool R" ZXID_REL "\n\
34 Copyright (c) 2012-2013 Synergetics SA (sampo@synergetics.be), All Rights Reserved.\n\
35 Copyright (c) 2009-2011 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.\n\
36 NO WARRANTY, not even implied warranties. Licensed under Apache License v2.0\n\
37 See http://www.apache.org/licenses/LICENSE-2.0\n\
38 Send well researched bug reports to the author. Home: http://zxid.org\n\
39 \n\
40 Usage: zxcot [options] [cotdir]         # Gives listing of metadata\n\
41        zxcot -c CPATH=/var/zxid/ -dirs  # Creates directory hierarchy\n\
42        zxcot -a [options] [cotdir] <meta.xml  # Import metadata\n\
43        zxcot -b [options] [dimddir] <epr.xml  # Register EPR\n\
44        curl https://site.com/metadata.xml | zxcot -a [options] [cotdir]\n\
45        zxcot -g https://site.com/metadata.xml [options] [cotdir]\n\
46        zxcot -m [options] >meta.xml     # Generate our own metadata\n\
47        zxcot -p https://site.com/metadata.xml\n\
48   [dir]            CoT directory. Default /var/zxid/cot\n\
49   -c CONF          Optional configuration string (default -c CPATH=/var/zxid/)\n\
50                    Most of the configuration is read from " ZXID_CONF_PATH "\n\
51                    N.B. If VURL and/or VPATH are used, you should set\n\
52                    environment variables that affect virtualization, e.g.\n\
53                      HTTP_HOST=example.com:8443 SERVER_PORT=8443 SCRIPT_NAME=zxidhlo zxcot -m\n\
54   -ci              IdP conf, synonym for -c IDP_ENA=1\n\
55   -dirs            Create configuration directory hierarchy\n\
56   -a               Add (someone else's) metadata from stdin\n\
57   -b               Register Web Service, add Service EPR from stdin\n\
58   -bs              Register Web Service and Bootstrap, add Service EPR from stdin\n\
59   -e endpoint abstract entid servicetype   Construct and dump EPR to stdout.\n\
60   -g URL           Do HTTP(S) GET to URL (aka WKL) and add as metadata (if compiled w/libcurl)\n\
61   -sign            Sign imported metadata (used with -a or -g). Used for Metadata Authority.\n\
62   -n               Dryrun. Do not actually add the metadata. Instead print it to stdout.\n\
63   -s               Swap columns, for easier sorting by URL\n\
64   -m               Output metadata of this installation (our own metadata). Caveat: If your\n\
65                    own code, or virtual hosting, sets options like URL, you need to supply\n\
66                    them with appropriate -c CONF option. zxcot is not able to guess them!\n\
67   -p ENTID         Print sha1 name corresponding to an entity ID.\n\
68   -v               Verbose messages.\n\
69   -q               Be extra quiet.\n\
70   -d               Turn on debugging.\n\
71   -dc              Dump configuration.\n\
72   -h               This help message\n\
73   --               End of options\n\
74 \n\
75 HTTP_HOST=idp.cloud-identity.eu SCRIPT_NAME=/idp e2etacot -c 'CPATH=/d/relifex/e2eta/' -m\n\
76 zxcot -e http://idp.tas3.pt:8081/zxididp?o=S 'TAS3 Default Discovery Service (ID-WSF 2.0)' http://idp.tas3.pt:8081/zxididp?o=B urn:liberty:disco:2006-08 | zxcot -b\n\
77 \n";
78 
79 #define ZXID_MAX_MD (256*1024)
80 
81 int sign_md = 0;
82 int swap = 0;
83 int addmd = 0;
84 int regsvc = 0;
85 int regbs = 0;
86 int genmd = 0;
87 int dryrun = 0;
88 int inflate_flag = 2;  /* Auto */
89 int verbose = 1;
90 char buf[ZXID_MAX_MD+1] = "PATH=/var/zxid/";
91 char* mdurl = 0;
92 char* entid = 0;
93 char* cotdir;
94 char* dimddir;
95 char* uiddir;
96 zxid_conf* cf = 0;
97 
98 static void zx_mkdirs();
99 
100 /* Called by:  main x8, zxbusd_main, zxbuslist_main, zxbustailf_main, zxcall_main, zxcot_main, zxdecode_main */
opt(int * argc,char *** argv,char *** env)101 static void opt(int* argc, char*** argv, char*** env)
102 {
103   int len;
104   struct zx_str* ss;
105 
106   if (*argc <= 1) goto path_to_dir;
107 
108   while (1) {
109     ++(*argv); --(*argc);
110 
111     if (!(*argc) || ((*argv)[0][0] != '-')) break;  /* normal exit from options loop */
112 
113     switch ((*argv)[0][1]) {
114     case '-': if ((*argv)[0][2]) break;
115       ++(*argv); --(*argc);
116       DD("End of options by --");
117       return;  /* -- ends the options */
118 
119     case 'a':
120       switch ((*argv)[0][2]) {
121       case '\0':
122 	++addmd;
123 	continue;
124       }
125       break;
126 
127     case 'b':
128       switch ((*argv)[0][2]) {
129       case 's':
130 	++regsvc;
131 	++regbs;
132 	continue;
133       case '\0':
134 	++regsvc;
135 	continue;
136       }
137       break;
138 
139     case 'c':
140       switch ((*argv)[0][2]) {
141       case 'i':
142 	switch ((*argv)[0][3]) {
143 	case '\0':
144 	  cf->idp_ena = 1;
145 	  zxid_parse_conf(cf, buf); /* buf was statically initialised to "PATH=/var/zxid/" */
146 	  continue;
147 	}
148 	break;
149       case '\0':
150 	++(*argv); --(*argc);
151 	if ((*argc) < 1) break;
152 	zxid_parse_conf(cf, (*argv)[0]);
153 	continue;
154       }
155       break;
156 
157     case 'e':
158       switch ((*argv)[0][2]) {
159       case '\0':
160 	if ((*argc) < 4) break;
161 	printf(
162 "<a:EndpointReference xmlns:a=\"http://www.w3.org/2005/08/addressing\" "
163 "xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" "
164     "notOnOrAfter=\"2037-01-05T23:03:59.001Z\" "
165     "wsu:Id=\"EPRID92lFPo3ZNEt_3rHtJFoU\">"
166   "<a:Address>%s</a:Address>"
167   "<a:Metadata>"
168     "<sbf:Framework xmlns:sbf=\"urn:liberty:sb\" version=\"2.0\"></sbf:Framework>"
169     "<di:Abstract xmlns:di=\"urn:liberty:disco:2006-08\">%s</di:Abstract>"
170     "<di:ProviderID xmlns:di=\"urn:liberty:disco:2006-08\">%s</di:ProviderID>"
171     "<di:ServiceType xmlns:di=\"urn:liberty:disco:2006-08\">%s</di:ServiceType>"
172   "</a:Metadata>"
173 "</a:EndpointReference>", (*argv)[1], (*argv)[2], (*argv)[3], (*argv)[4]);
174 	exit(0);
175       }
176       break;
177 
178     case 'g':
179       switch ((*argv)[0][2]) {
180       case '\0':
181 	++(*argv); --(*argc);
182 	if ((*argc) < 1) break;
183 	mdurl = (*argv)[0];
184 	++addmd;
185 	continue;
186       }
187       break;
188 
189     case 'd':
190       switch ((*argv)[0][2]) {
191       case '\0':
192 	++errmac_debug;
193 	continue;
194       case 'c':
195 	ss = zxid_show_conf(cf);
196 	fprintf(stderr, "\n======== CONF ========\n%.*s\n^^^^^^^^ CONF ^^^^^^^^\n",ss->len,ss->s);
197 	continue;
198       }
199       if (!strcmp((*argv)[0],"-dirs")) {
200 	zx_mkdirs();
201 	exit(0);
202       }
203       break;
204 
205     case 's':
206       switch ((*argv)[0][2]) {
207       case '\0':
208 	++swap;
209 	continue;
210       case 'i':
211 	if (!strcmp((*argv)[0],"-sign")) {
212 	  sign_md = 1;
213 	  continue;
214 	}
215 	break;
216       }
217       break;
218 
219     case 'p':
220       switch ((*argv)[0][2]) {
221       case '\0':
222 	++(*argv); --(*argc);
223 	if ((*argc) < 1) break;
224 	entid = (*argv)[0];
225 	continue;
226       }
227       break;
228 
229     case 'm':
230       switch ((*argv)[0][2]) {
231       case '\0':
232 	++genmd;
233 	continue;
234       }
235       break;
236 
237     case 'n':
238       switch ((*argv)[0][2]) {
239       case '\0':
240 	++dryrun;
241 	continue;
242       }
243       break;
244 
245 #if 0
246     case 'l':
247       switch ((*argv)[0][2]) {
248       case 'i':
249 	if (!strcmp((*argv)[0],"-license")) {
250 	  extern char* license;
251 	  fprintf(stderr, license);
252 	  exit(0);
253 	}
254 	break;
255       }
256       break;
257 #endif
258 
259     case 'q':
260       switch ((*argv)[0][2]) {
261       case '\0':
262 	verbose = 0;
263 	continue;
264       }
265       break;
266 
267     case 'v':
268       switch ((*argv)[0][2]) {
269       case '\0':
270 	++verbose;
271 	continue;
272       }
273       break;
274 
275     }
276     /* fall thru means unrecognized flag */
277     if (*argc)
278       fprintf(stderr, "Unrecognized flag `%s'\n", (*argv)[0]);
279     if (verbose>1) {
280       printf("%s", help);
281       exit(0);
282     }
283     fprintf(stderr, "%s", help);
284     /*fprintf(stderr, "version=0x%06x rel(%s)\n", zxid_version(), zxid_version_str());*/
285     exit(3);
286   }
287   if (*argc) {
288     uiddir = dimddir = cotdir = (*argv)[0];
289     len = strlen(cotdir);
290     if (cotdir[len-1] != '/') {  /* Append slash as that is required */
291       cotdir = malloc(len+1);
292       strcpy(cotdir, (*argv)[0]);
293       cotdir[len] = '/';
294       cotdir[++len] = 0;
295       uiddir = dimddir = cotdir;
296     }
297     if (!strcmp(uiddir+len-sizeof("/dimd/")+1, "/dimd/")) {
298       uiddir = strdup(uiddir);
299       strcpy(uiddir+len-sizeof("/dimd/")+1, "/uid/");
300     }
301   } else {
302 path_to_dir:
303     len = strlen(cf->cpath);
304     cotdir = malloc(len+sizeof(ZXID_COT_DIR));
305     strcpy(cotdir, cf->cpath);
306     strcpy(cotdir+len, ZXID_COT_DIR);
307 
308     dimddir = malloc(len+sizeof(ZXID_DIMD_DIR));
309     strcpy(dimddir, cf->cpath);
310     strcpy(dimddir+len, ZXID_DIMD_DIR);
311 
312     uiddir = malloc(len+sizeof(ZXID_UID_DIR));
313     strcpy(uiddir, cf->cpath);
314     strcpy(uiddir+len, ZXID_UID_DIR);
315   }
316 }
317 
318 /* --------- Make zxid config directories --------- */
319 
320 static const char* mkdirs_list[] = {
321 "ses",
322 "user",
323 "uid",
324 "nid",
325 "log",
326 "log/rely",
327 "log/issue",
328 "pem",
329 "cot",
330 "inv",
331 "dimd",
332 "dcr",
333 "rsr",
334 "uid/.all",
335 "uid/.all/.bs",
336 "tmp",
337 "ch",
338 "ch/default",
339 "ch/default/.ack",
340 "ch/default/.del"
341 };
342 
343 /* Called by:  opt */
zx_mkdirs()344 static void zx_mkdirs()
345 {
346   char path[ZXID_MAX_BUF];
347   char* p;
348   const char** dir;
349   int len;
350   struct stat st;
351 
352 #define ZXID_PATH_LENGTH_MARGIN (sizeof("ch/default/.del")+10) /* Accommodate longest subdir */
353   len = snprintf(path, sizeof(path)-ZXID_PATH_LENGTH_MARGIN, "%s", cf->cpath);
354   if (len > sizeof(path)-ZXID_PATH_LENGTH_MARGIN) {
355     ERR("CPATH %s too long. len=%d, space=%d", cf->cpath, len, (int)(sizeof(path)-ZXID_PATH_LENGTH_MARGIN));
356     exit(1);
357   }
358 
359   for (p = path+len-1; p > path && *p != '/'; --p) ;  /* Handle CPATH=/var/zxid/idp */
360 
361   if (MKDIR(path, 02770) < 0) {
362     if (errno == EEXIST) {
363       INFO("Directory %s already exists. Will still try to create hierarchy under it.", path);
364     } else {
365       ERR("Failed to create directory hierarchy at %s: %d (%s) (perhaps nonexistent parent directory or permissions problem)", path, errno, STRERROR(errno));
366       exit(1);
367     }
368   } else {
369     D("Created %s", path);
370   }
371 
372   for (dir = mkdirs_list; *dir; ++dir) {
373     len = snprintf(path, sizeof(path)-ZXID_PATH_LENGTH_MARGIN, "%s%s", cf->cpath, *dir);
374     if (MKDIR(path, 02770) < 0) {
375       ERR("Failed to create directory %s: %d (%s)", path, errno, STRERROR(errno));
376     } else {
377       D("Created %s", path);
378     }
379   }
380 
381   len = snprintf(path, sizeof(path)-ZXID_PATH_LENGTH_MARGIN, "%s" ZXID_CONF_FILE, cf->cpath);
382   if (stat(path, &st)) {  /* error return from stat means file does not exist, create example */
383     write_all_path_fmt("-dirs", sizeof(path), path, "%s%s", cf->cpath, ZXID_CONF_FILE,
384 "# This is example configuration file %s" ZXID_CONF_FILE "\n"
385 "# You should edit the values to suit your situation.\n"
386 "BURL=https://yourhost.example.com:8443/protected/saml\n"
387 "NICE_NAME=Configuration NICE_NAME: Set this to describe your site to humans, see %s" ZXID_CONF_FILE "\n"
388 "BUTTON_URL=https://example.com/YOUR_BRAND_saml2_icon_150x60.png\n"
389 "ORG_NAME=Unspecified ORG_NAME conf variable\n"
390 "LOCALITY=Lisboa\n"
391 "STATE=Lisboa\n"
392 "COUNTRY=PT\n"
393 "CONTACT_ORG=Your organization\n"
394 "CONTACT_NAME=Your Name\n"
395 "CONTACT_EMAIL=your@email.com\n"
396 "CONTACT_TEL=+351918731007\n", cf->cpath, cf->cpath);
397   }
398 
399   INFO("Created directories. You should inspect their ownership and permissions to ensure the webserver can read and write them, yet outsiders can not access them. You may want to run  chown -R www-data %s", cf->cpath);
400 }
401 
402 /* --------------- reg_svc --------------- */
403 
404 /*() IdP and Discovery. Register service metadata to /var/zxid/idpdimd/XX,
405  * and possibly boostrap to /var/zxid/idpuid/.all/.bs/YY
406  *
407  * bs_reg:: Register-also-as-bootstrap flag
408  * dry_run:: nonzero: do not write anything
409  * ddimd:: Discovery metadata directory, such as /var/zxid/idpdimd/
410  * duid:: uid dir such as  /var/zxid/idpuid/
411  * returns:: 0 on success, nonzero on error. */
412 
413 /* Called by:  zxcot_main */
zxid_reg_svc(zxid_conf * cf,int bs_reg,int dry_run,const char * ddimd,const char * duid)414 static int zxid_reg_svc(zxid_conf* cf, int bs_reg, int dry_run, const char* ddimd, const char* duid)
415 {
416   char sha1_name[28];
417   char path[ZXID_MAX_BUF];
418   int got;
419   fdtype fd;
420   struct zx_root_s* r;
421   zxid_epr* epr;
422   struct zx_str* ss;
423   struct zx_str* tt;
424 
425   read_all_fd(fdstdin, buf, sizeof(buf)-1, &got);  /* Read EPR */
426   buf[got] = 0;
427 
428   r = zx_dec_zx_root(cf->ctx, got, buf, "cot reg_svc");
429   if (!r || !r->EndpointReference) {
430     ERR("Failed to parse <EndpointReference> buf(%.*s)", got, buf);
431     return 1;
432   }
433   epr = r->EndpointReference;
434   if (!ZX_SIMPLE_ELEM_CHK(epr->Address)) {
435     ERR("<EndpointReference> MUST have <Address> element buf(%.*s)", got, buf);
436     return 1;
437   }
438   if (!epr->Metadata) {
439     ERR("<EndpointReference> MUST have <Metadata> element buf(%.*s)", got, buf);
440     return 1;
441   }
442   if (!ZX_SIMPLE_ELEM_CHK(epr->Metadata->ProviderID)) {
443     ERR("<EndpointReference> MUST have <Metadata> with <ProviderID> element buf(%.*s)", got, buf);
444     return 1;
445   }
446   if (!epr->Metadata->ServiceType) {
447     ERR("<EndpointReference> MUST have <ServiceType> element buf(%.*s)", got, buf);
448     return 1;
449   }
450 
451   /* *** possibly add something here and double check the required fields are available. */
452 
453   ss = zx_easy_enc_elem_opt(cf, &epr->gg);
454   if (!ss)
455     return 2;
456 
457 #if 0
458   // *** wrong
459   tt = ZX_GET_CONTENT(epr->Metadata->ProviderID);
460 #else
461   tt = ZX_GET_CONTENT(epr->Metadata->ServiceType);
462 #endif
463   got = MIN(tt->len, sizeof(path)-1);
464   memcpy(path, tt?tt->s:"", got);
465   path[got] = 0;
466   zxid_fold_svc(path, got);
467 
468   sha1_safe_base64(sha1_name, ss->len, ss->s);
469   sha1_name[27] = 0;
470 
471   if (verbose)
472     fprintf(stderr, "Registering metadata in %s%s,%s\n", ddimd, path, sha1_name);
473 
474   if (dry_run) {
475     if (verbose)
476       fprintf(stderr, "Register EPR dry run. Would have written to path(%s%s,%s). "
477 	      "You may also want to\n"
478 	      "  touch %s.all/.bs/%s,%s\n\n", ddimd, path, sha1_name, uiddir, path, sha1_name);
479     fflush(stdin);
480     write_all_fd(fdstdout, ss->s, ss->len);
481     zx_str_free(cf->ctx, ss);
482     return 0;
483   }
484 
485   D("Register EPR path(%s%s,%s) in discovery metadata.", ddimd, path, sha1_name);
486   fd = open_fd_from_path(O_CREAT | O_WRONLY | O_TRUNC, 0666, "zxcot -b", 1,
487 			 "%s%s,%s", ddimd, path, sha1_name);
488   if (fd == BADFD) {
489     perror("open epr for registering");
490     ERR("Failed to open file for writing: sha1_name(%s,%s) to service registration", path, sha1_name);
491     zx_str_free(cf->ctx, ss);
492     return 1;
493   }
494 
495   write_all_fd(fd, ss->s, ss->len);
496   zx_str_free(cf->ctx, ss);
497   close_file(fd, (const char*)__FUNCTION__);
498 
499   if (bs_reg) {
500     if (verbose)
501       fprintf(stderr, "Activating bootstrap %s.all/.bs/%s,%s", duid, path, sha1_name);
502 
503     if (!dryrun) {
504       fd = open_fd_from_path(O_CREAT | O_WRONLY | O_TRUNC, 0666, "zxcot -bs", 1,
505 			     "%s.all/.bs/%s,%s", duid, path, sha1_name);
506       if (fd == BADFD) {
507 	perror("open epr for bootstrap activation");
508 	ERR("Failed to open file for writing: sha1_name(%s,%s) to bootstrap activation", path, sha1_name);
509 	return 1;
510       }
511 
512       write_all_fd(fd, "", 0);
513       close_file(fd, (const char*)__FUNCTION__);
514     }
515   } else {
516     D("You may also want to activate bootstrap by\n  touch %s.all/.bs/%s,%s", duid, path, sha1_name);
517   }
518   return 0;
519 }
520 
521 /* --------------- addmd --------------- */
522 
523 /*() Add metadata of a partner to the Circle-of-Trust, represented by the CoT dir */
524 
525 /* Called by:  zxcot_main */
zxid_addmd(zxid_conf * cf,char * mdurl,int dry_run,const char * dcot)526 static int zxid_addmd(zxid_conf* cf, char* mdurl, int dry_run, const char* dcot)
527 {
528   int got;
529   fdtype fd;
530   char* p;
531   zxid_entity* ent;
532   struct zx_str* ss;
533 
534   if (mdurl) {
535     ent = zxid_get_meta(cf, mdurl);
536   } else {
537     read_all_fd(fdstdin, buf, sizeof(buf)-1, &got);
538     buf[got] = 0;
539     p = buf;
540     ent = zxid_parse_meta(cf, &p, buf+got);
541   }
542 
543   if (!ent) {
544     ERR("***** Parsing metadata failed %d", 0);
545     return 1;
546   }
547 
548   for (; ent; ent = ent->n) {
549     ss = zx_easy_enc_elem_opt(cf, &ent->ed->gg);
550     if (!ss)
551       return 2;
552 
553     if (dry_run) {
554       write_all_fd(fdstdout, ss->s, ss->len);
555       zx_str_free(cf->ctx, ss);
556       if (verbose>1)
557 	printf("\n\nDry run ent(%s) to %s%s\n", ent->eid, dcot, ent->sha1_name);
558       continue;
559     }
560     if (verbose)
561       printf("Writing ent(%s) to %s%s\n", ent->eid, dcot, ent->sha1_name);
562 
563     fd = open_fd_from_path(O_CREAT | O_WRONLY | O_TRUNC, 0666, "zxcot -a", 1,
564 			   "%s%s", dcot, ent->sha1_name);
565     if (fd == BADFD) {
566       perror("open metadata for writing metadata to cache");
567       ERR("Failed to open file for writing: sha1_name(%s) to metadata cache", ent->sha1_name);
568       zx_str_free(cf->ctx, ss);
569       return 1;
570     }
571 
572     write_all_fd(fd, ss->s, ss->len);
573     zx_str_free(cf->ctx, ss);
574     close_file(fd, (const char*)__FUNCTION__);
575   }
576   return 0;
577 }
578 
579 /* --------------- genmd --------------- */
580 
581 /*() Generate our own metadata */
582 
583 /* Called by:  zxcot_main */
zxid_genmd(zxid_conf * cf,int dry_run,const char * dcot)584 static int zxid_genmd(zxid_conf* cf, int dry_run, const char* dcot)
585 {
586   zxid_cgi cgi;
587   struct zx_str* meta = zxid_sp_meta(cf, &cgi);
588   ZERO(&cgi, sizeof(cgi));
589   printf("%.*s", meta->len, meta->s);
590   return 0;
591 }
592 
593 /* --------------- lscot --------------- */
594 
595 /*() Print a line of Circle-of-Trust listing */
596 
597 /* Called by:  zxid_lscot x2 */
zxid_lscot_line(zxid_conf * cf,int col_swap,const char * dcot,const char * den)598 static int zxid_lscot_line(zxid_conf* cf, int col_swap, const char* dcot, const char* den)
599 {
600   zxid_entity* ent;
601   char* p;
602   int got = read_all(ZXID_MAX_MD, buf, "zxcot line", 1, "%s%s", dcot, den);
603   if (!got) {
604     ERR("Zero data in file(%s%s). If cot directory does not exist consider running zxcot -dirs", dcot, den);
605     return 1;
606   }
607   p = buf;
608   ent = zxid_parse_meta(cf, &p, buf+got);
609   if (!ent) {
610     ERR("***** Parsing metadata failed for(%s%s)", dcot, den);
611     return 2;
612   }
613   while (ent) {
614     switch (col_swap) {
615     case 1:  printf("%-50s %s%s %s\n", ent->eid, dcot, den, STRNULLCHKD(ent->dpy_name)); break;
616     case 2:  printf("%s\n",       ent->eid); break;
617     default: printf("%s%s %-50s %s\n", dcot, den, ent->eid, STRNULLCHKD(ent->dpy_name));
618     }
619     if (strcmp(*den?den:dcot, ent->sha1_name))
620       fprintf(stderr, "Filename(%s) does not match sha1_name(%s)\n", *den?den:dcot, ent->sha1_name);
621     ent = ent->n;
622   }
623   return 0;
624 }
625 
626 /*() List the contents of the Circle-of-Trust, represented by the CoT directory,
627  * in various formats. */
628 
629 /* Called by:  zxcot_main */
zxid_lscot(zxid_conf * cf,int col_swap,const char * dcot)630 static int zxid_lscot(zxid_conf* cf, int col_swap, const char* dcot)
631 {
632   int got, ret;
633   char* p;
634   DIR* dir;
635   struct dirent* de;
636 
637   dir = opendir(dcot);
638   if (!dir) {
639     perror("opendir for /var/zxid/cot (or other if configured) for loading cot cache");
640     D("failed path(%s)", dcot);
641 
642     got = strlen(dcot);
643     p = ZX_ALLOC(cf->ctx, got+1);
644     memcpy(p, dcot, got-1);
645     p[got-1] = 0;  /* chop off / */
646     got = zxid_lscot_line(cf, col_swap, p, "");
647     ZX_FREE(cf->ctx, p);
648     return got;
649   }
650 
651   while (de = readdir(dir)) {
652     if (de->d_name[0] == '.' || de->d_name[strlen(de->d_name)-1] == '~')
653       continue;
654     ret = zxid_lscot_line(cf, col_swap, dcot, de->d_name);
655     if (!ONE_OF_2(ret, 0, 2))
656       return ret;
657   }
658   return 0;
659 }
660 
661 /* ============== MAIN ============ */
662 
663 #ifndef zxcot_main
664 #define zxcot_main main
665 #endif
666 extern int zxid_suppress_vpath_warning;
667 
668 /*() Circle of Trust management tool */
669 
670 /* Called by: */
zxcot_main(int argc,char ** argv,char ** env)671 int zxcot_main(int argc, char** argv, char** env)
672 {
673   strncpy(errmac_instance, "cot", sizeof(errmac_instance));
674   zxid_suppress_vpath_warning = 1;
675   cf = zxid_new_conf_to_cf(0);
676 
677   opt(&argc, &argv, &env);
678 
679   if (entid) {
680     char sha1_name[28];
681     sha1_safe_base64(sha1_name, strlen(entid), entid);
682     sha1_name[27] = 0;
683     printf("%s\n", sha1_name);
684     return 0;
685   }
686 
687   if (addmd)
688     return zxid_addmd(cf, mdurl, dryrun, cotdir);
689 
690   if (regsvc)
691     return zxid_reg_svc(cf, regbs, dryrun, dimddir, uiddir);
692 
693   if (genmd)
694     return zxid_genmd(cf, dryrun, cotdir);
695 
696   return zxid_lscot(cf, swap, cotdir);
697 }
698 
699 /* EOF  --  zxcot.c */
700