First delivery of the validation framework
[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,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         { "valexp",     5 },
48         { "client",     256 },
49         { "server",     512 },
50         { "noP11",      4096 },
51         { "chained",    8192 },
52         { NULL,         0 }
53 };
54
55
56 /* Setup and tear down management */
57 int setup_management (DB_ENV **dbenv, DB_TXN **txn, DB **dbh) {
58         char *dbenv_dir = cfg_dbenv_dir ();
59         char *dblid_fnm = cfg_db_localid ();
60         if (dbenv_dir == NULL) {
61                 fprintf (stderr, "Please configure database environment directory\n");
62                 return 0;
63         }
64         if (dblid_fnm == NULL) {
65                 fprintf (stderr, "Please configure localid database name\n");
66                 return 0;
67         }
68         if (db_env_create (dbenv, 0) != 0) {
69                 fprintf (stderr, "Failed to create database environment");
70                 return 0;
71         }
72         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) {
73                 fprintf (stderr, "Failed to open database environment");
74                 return 0;
75         }
76         if ((*dbenv)->txn_begin (*dbenv, NULL, txn, 0) != 0) {
77                 fprintf (stderr, "Failed to start transaction\n");
78                 exit (1);
79         }
80         if (db_create (dbh, *dbenv, 0) != 0) {
81                 fprintf (stderr, "Failed to create localid database\n");
82                 return 0;
83         }
84         if ((*dbh)->set_flags (*dbh, DB_DUP) != 0) {
85                 fprintf (stderr, "Failed to setup localid database for duplicate entries\n");
86                 return 0;
87         }
88         if ((*dbh)->open (*dbh, *txn, dblid_fnm, NULL, DB_HASH, DB_THREAD | DB_RDONLY, 0) != 0) {
89                 fprintf (stderr, "Failed to open localid database\n");
90                 return 0;
91         }
92         return 1;
93 }
94
95 /* Cleanup maangement structures */
96 void cleanup_management (DB_ENV *dbenv, DB *db) {
97         db->close (db, 0);
98         dbenv->close (dbenv, 0);
99 }
100
101 int main (int argc, char *argv []) {
102         char *localid = NULL;
103         char *partstr = NULL;
104         char *saveptr = NULL;
105         char *p11uri = NULL;
106         uint8_t e_buf [5000];
107         int argi = argc;
108         int filesz = 0;
109         int p11len = 0;
110         struct stat statbuf;
111         uint32_t flags = 0;
112         DB_ENV *dbenv;
113         DB_TXN *txn;
114         DB *dbh;
115         DBC *crs;
116         DBT k_localid;
117         DBT e_value;
118         int nomore;
119         int fd;
120         int outfile = -1;
121         int written = 0;
122         //
123         // Sanity check
124         if ((argc < 4) || (argc > 5)) {
125                 fprintf (stderr, usage, argv [0]);
126                 exit (1);
127         }
128         if (argc == 5) {
129                 outfile = open (argv [4], O_WRONLY | O_CREAT | O_TRUNC, 0644);
130                 if (outfile < 0) {
131                         perror ("Failed to open output file");
132                         exit (1);
133                 }
134         }
135         //
136         // Initialise the modules taken from the src directory
137         parse_cfgfile (argv [1], 0);
138         //
139         // Prepare variables from arguments
140         localid = argv [2];
141         partstr = strtok_r (argv [3], ",", &saveptr);
142         if (partstr == NULL) {
143                 fprintf (stderr, "Flags must not be empty\n");
144                 exit (1);
145         }
146         while (partstr != NULL) {
147                 struct typemap_t *walker = typemap;
148                 while (walker->name != NULL) {
149                         if (strcasecmp (walker->name, partstr) == 0) {
150                                 flags |= walker->bits;
151                                 break;
152                         }
153                         walker++;
154                 }
155                 if (walker->name == NULL) {
156                         fprintf (stderr, "Flag name %s not recognised\n", partstr);
157                         exit (1);
158                 }
159                 partstr = strtok_r (NULL, ",", &saveptr);
160         }
161         //
162         // Now retrieve the matching entries
163         if (!setup_management (&dbenv, &txn, &dbh)) {
164                 exit (1);
165         }
166         if (dbh->cursor (dbh, txn, &crs, 0) != 0) {
167                 fprintf (stderr, "Failed to open cursor on localid.db\n");
168                 goto failure;
169         }
170         memset (&k_localid, 0, sizeof (k_localid));
171         k_localid.data = localid;
172         k_localid.size = strlen (localid);
173         nomore = crs->get (crs, &k_localid, &e_value, DB_SET);
174         while (nomore == 0) {
175                 uint32_t e_flags = 0;
176                 char *e_p11uri = NULL;
177                 uint8_t *e_bindata;
178                 int e_binlen;
179                 if (e_value.size < 4) {
180                         fprintf (stderr, "Found too-short entry?!?\n");
181                         crs->close (crs);
182                         goto failure;
183                 }
184                 e_flags = ntohl (* (uint32_t *) e_value.data);
185                 e_p11uri = (char *) & ((uint32_t *) e_value.data) [1];
186                 e_bindata = e_p11uri + strnlen (e_p11uri, e_value.size - 4) + 1;
187                 e_binlen = e_value.size - 4 - strnlen (e_p11uri, e_value.size - 4) - 1;
188                 if (e_binlen < 0) {
189                         fprintf (stderr, "Error retrieving binary data\n");
190                         crs->close (crs);
191                         goto failure;
192                 }
193                 if ((e_flags & 0xff) == (flags & 0xff)) {
194                         uint32_t todo_flags = e_flags;
195                         struct typemap_t *tm = typemap;
196                         printf ("Flags: 0x%x:", e_flags);
197                         while (tm->name != NULL) {
198                                 if (todo_flags & tm->bits) {
199                                         printf (" %s", tm->name);
200                                         todo_flags = todo_flags & ~tm->bits;
201                                 }
202                                 tm++;
203                         }
204                         if (todo_flags != 0) {
205                                 printf (" UNKNOWN_%d", todo_flags);
206                         }
207                         printf ("\nPrivate: %s\n", e_p11uri);
208                         written = 0;
209                         if (outfile >= 0) {
210                                 if (write (outfile, e_bindata, e_binlen) == e_binlen) {
211 printf ("Written %d bytes\n", e_binlen);
212                                         written = 1;
213                                 }
214                                 close (outfile);
215                                 outfile = -1;   // No more than one binary write
216                         }
217                         printf ("Public: %02x %02x...%02x %02x (length %d)%s\n",
218                                 e_bindata [0], e_bindata [1],
219                                 e_bindata [e_binlen-2], e_bindata [e_binlen-1],
220                                 e_binlen,
221                                 written? " (written)": "");
222                 }
223                 nomore = crs->get (crs, &k_localid, &e_value, DB_NEXT_DUP);
224         }
225         crs->close (crs);
226         if (nomore != DB_NOTFOUND) {
227                 fprintf (stderr, "Database error encountered while iterating\n");
228                 goto failure;
229         }
230         if (txn->commit (txn, 0) != 0) {
231                 txn->abort (txn);
232                 fprintf (stderr, "Failed to commit readonly transaction\n");
233                 exit (1);
234         }
235         //
236         // Finish up and report success
237 success:
238         cleanup_management (dbenv, dbh);
239         return 0;
240         //
241         // Handle failure during database interactions
242 failure:
243         fprintf (stderr, "Rolling back transaction\n");
244         txn->abort (txn);
245         cleanup_management (dbenv, dbh);
246         exit (1);
247 }