Merge branch 'tls-kdh' of https://github.com/arpa2/tlspool into tls-kdh
[tlspool] / tool / get_localid.c
1 /* tool/get_localid.c -- Retrieve local identity credentials
2  *
3  * Provide a config, a NAI and see what types of credentials are available
4  * in localid.db.
5  *
6  * From: Rick van Rein <rick@openfortress.nl>
7  */
8
9
10 #include <stdlib.h>
11 #include <stdint.h>
12 #include <stdio.h>
13 #include <string.h>
14
15 #include <sys/types.h>
16 #include <sys/stat.h>
17
18 #include <unistd.h>
19 #include <fcntl.h>
20 #include <errno.h>
21
22 #include <arpa/inet.h>
23
24 #include <db.h>
25
26 #include <tlspool/internal.h>
27
28
29 const char const *usage =
30 "Usage: %s tlspool.conf [user@]fqdn type [outfile.der]\n"
31 " - tlspool.conf      is the configuration file for the TLS Pool\n"
32 " - user@fqdn or fqdn is a network access identifier\n"
33 " - type              X.509,OpenPGP,Kerberos,valexp,client,server,noP11,chained\n"
34 " - outfile.der       optional output file for binary encoded public data\n"
35 "Since the public data is stored in a binary format, it will never be printed\n"
36 "on stdout; in absense of outfile.der the value is simply not output.\n";
37
38
39 struct typemap_t {
40         char *name;
41         uint32_t bits;
42 };
43
44 struct typemap_t typemap [] = {
45         { "X.509",      1 },
46         { "OpenPGP",    2 },
47         { "Kerberos",   4 },
48         { "krb5",       4 },
49         { "valexp",     5 },
50         { "client",     256 },
51         { "server",     512 },
52         { "noP11",      4096 },
53         { "chained",    8192 },
54         { NULL,         0 }
55 };
56
57
58 /* Setup and tear down management */
59 int setup_management (DB_ENV **dbenv, DB_TXN **txn, DB **dbh) {
60         char *dbenv_dir = cfg_dbenv_dir ();
61         char *dblid_fnm = cfg_db_localid ();
62         if (dbenv_dir == NULL) {
63                 fprintf (stderr, "Please configure database environment directory\n");
64                 return 0;
65         }
66         if (dblid_fnm == NULL) {
67                 fprintf (stderr, "Please configure localid database name\n");
68                 return 0;
69         }
70         if (db_env_create (dbenv, 0) != 0) {
71                 fprintf (stderr, "Failed to create database environment");
72                 return 0;
73         }
74         if ((*dbenv)->open (*dbenv, dbenv_dir, DB_CREATE | DB_RECOVER | DB_INIT_TXN | DB_INIT_LOG | DB_INIT_LOCK | DB_THREAD | DB_INIT_MPOOL, S_IRUSR | S_IWUSR) != 0) {
75                 fprintf (stderr, "Failed to open database environment");
76                 return 0;
77         }
78         if ((*dbenv)->txn_begin (*dbenv, NULL, txn, 0) != 0) {
79                 fprintf (stderr, "Failed to start transaction\n");
80                 exit (1);
81         }
82         if (db_create (dbh, *dbenv, 0) != 0) {
83                 fprintf (stderr, "Failed to create localid database\n");
84                 return 0;
85         }
86         if ((*dbh)->set_flags (*dbh, DB_DUP) != 0) {
87                 fprintf (stderr, "Failed to setup localid database for duplicate entries\n");
88                 return 0;
89         }
90         if ((*dbh)->open (*dbh, *txn, dblid_fnm, NULL, DB_HASH, DB_THREAD | DB_RDONLY, 0) != 0) {
91                 fprintf (stderr, "Failed to open localid database\n");
92                 return 0;
93         }
94         return 1;
95 }
96
97 /* Cleanup maangement structures */
98 void cleanup_management (DB_ENV *dbenv, DB *db) {
99         db->close (db, 0);
100         dbenv->close (dbenv, 0);
101 }
102
103 int main (int argc, char *argv []) {
104         char *localid = NULL;
105         char *partstr = NULL;
106         char *saveptr = NULL;
107         char *p11uri = NULL;
108         uint8_t e_buf [5000];
109         int argi = argc;
110         int filesz = 0;
111         int p11len = 0;
112         struct stat statbuf;
113         uint32_t flags = 0;
114         DB_ENV *dbenv;
115         DB_TXN *txn;
116         DB *dbh;
117         DBC *crs;
118         DBT k_localid;
119         DBT e_value;
120         int nomore;
121         int fd;
122         int outfile = -1;
123         int written = 0;
124         //
125         // Sanity check
126         if ((argc < 4) || (argc > 5)) {
127                 fprintf (stderr, usage, argv [0]);
128                 exit (1);
129         }
130         if (argc == 5) {
131                 outfile = open (argv [4], O_WRONLY | O_CREAT | O_TRUNC, 0644);
132                 if (outfile < 0) {
133                         perror ("Failed to open output file");
134                         exit (1);
135                 }
136         }
137         //
138         // Initialise the modules taken from the src directory
139         parse_cfgfile (argv [1], 0);
140         //
141         // Prepare variables from arguments
142         localid = argv [2];
143         partstr = strtok_r (argv [3], ",", &saveptr);
144         if (partstr == NULL) {
145                 fprintf (stderr, "Flags must not be empty\n");
146                 exit (1);
147         }
148         while (partstr != NULL) {
149                 struct typemap_t *walker = typemap;
150                 while (walker->name != NULL) {
151                         if (strcasecmp (walker->name, partstr) == 0) {
152                                 flags |= walker->bits;
153                                 break;
154                         }
155                         walker++;
156                 }
157                 if (walker->name == NULL) {
158                         fprintf (stderr, "Flag name %s not recognised\n", partstr);
159                         exit (1);
160                 }
161                 partstr = strtok_r (NULL, ",", &saveptr);
162         }
163         //
164         // Now retrieve the matching entries
165         if (!setup_management (&dbenv, &txn, &dbh)) {
166                 exit (1);
167         }
168         if (dbh->cursor (dbh, txn, &crs, 0) != 0) {
169                 fprintf (stderr, "Failed to open cursor on localid.db\n");
170                 goto failure;
171         }
172         memset (&k_localid, 0, sizeof (k_localid));
173         k_localid.data = localid;
174         k_localid.size = strlen (localid);
175         nomore = crs->get (crs, &k_localid, &e_value, DB_SET);
176         while (nomore == 0) {
177                 uint32_t e_flags = 0;
178                 char *e_p11uri = NULL;
179                 uint8_t *e_bindata;
180                 int e_binlen;
181                 if (e_value.size < 4) {
182                         fprintf (stderr, "Found too-short entry?!?\n");
183                         crs->close (crs);
184                         goto failure;
185                 }
186                 e_flags = ntohl (* (uint32_t *) e_value.data);
187                 e_p11uri = (char *) & ((uint32_t *) e_value.data) [1];
188                 e_bindata = e_p11uri + strnlen (e_p11uri, e_value.size - 4) + 1;
189                 e_binlen = e_value.size - 4 - strnlen (e_p11uri, e_value.size - 4) - 1;
190                 if (e_binlen < 0) {
191                         fprintf (stderr, "Error retrieving binary data\n");
192                         crs->close (crs);
193                         goto failure;
194                 }
195                 if ((e_flags & 0xff) == (flags & 0xff)) {
196                         uint32_t todo_flags = e_flags;
197                         struct typemap_t *tm = typemap;
198                         printf ("Flags: 0x%x:", e_flags);
199                         while (tm->name != NULL) {
200                                 if (todo_flags & tm->bits) {
201                                         printf (" %s", tm->name);
202                                         todo_flags = todo_flags & ~tm->bits;
203                                 }
204                                 tm++;
205                         }
206                         if (todo_flags != 0) {
207                                 printf (" UNKNOWN_%d", todo_flags);
208                         }
209                         printf ("\nPrivate: %s\n", e_p11uri);
210                         written = 0;
211                         if (outfile >= 0) {
212                                 if (write (outfile, e_bindata, e_binlen) == e_binlen) {
213 printf ("Written %d bytes\n", e_binlen);
214                                         written = 1;
215                                 }
216                                 close (outfile);
217                                 outfile = -1;   // No more than one binary write
218                         }
219                         printf ("Public: %02x %02x...%02x %02x (length %d)%s\n",
220                                 e_bindata [0], e_bindata [1],
221                                 e_bindata [e_binlen-2], e_bindata [e_binlen-1],
222                                 e_binlen,
223                                 written? " (written)": "");
224                 }
225                 nomore = crs->get (crs, &k_localid, &e_value, DB_NEXT_DUP);
226         }
227         crs->close (crs);
228         if (nomore != DB_NOTFOUND) {
229                 fprintf (stderr, "Database error encountered while iterating\n");
230                 goto failure;
231         }
232         if (txn->commit (txn, 0) != 0) {
233                 fprintf (stderr, "Failed to commit readonly transaction\n");
234                 exit (1);
235         }
236         //
237         // Finish up and report success
238 success:
239         cleanup_management (dbenv, dbh);
240         return 0;
241         //
242         // Handle failure during database interactions
243 failure:
244         fprintf (stderr, "Rolling back transaction\n");
245         txn->abort (txn);
246         cleanup_management (dbenv, dbh);
247         exit (1);
248 }