Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

gdp / apps / gdp-create.c @ master

History | View | Annotate | Download (11.4 KB)

1 c6293003 Eric Allman
/* vim: set ai sw=4 sts=4 ts=4 : */
2
3 055d3009 Eric Allman
/*
4
**  LOG-CREATE --- create a new log
5
**
6
**                This is a temporary interface.  Ultimately we need a log
7
**                creation service that does reasonable log placement rather
8
**                than having to name a specific log server.
9
**
10
**        ----- BEGIN LICENSE BLOCK -----
11
**        Applications for the Global Data Plane
12
**        From the Ubiquitous Swarm Lab, 490 Cory Hall, U.C. Berkeley.
13
**
14 c87dd166 Eric Allman
**        Copyright (c) 2015-2019, Regents of the University of California.
15 6bd5476b Eric Allman
**        All rights reserved.
16 055d3009 Eric Allman
**
17 6bd5476b Eric Allman
**        Permission is hereby granted, without written agreement and without
18
**        license or royalty fees, to use, copy, modify, and distribute this
19
**        software and its documentation for any purpose, provided that the above
20
**        copyright notice and the following two paragraphs appear in all copies
21
**        of this software.
22 055d3009 Eric Allman
**
23 6bd5476b Eric Allman
**        IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
24
**        SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
25
**        PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
26
**        EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 055d3009 Eric Allman
**
28 6bd5476b Eric Allman
**        REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
29 055d3009 Eric Allman
**        LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
30 6bd5476b Eric Allman
**        FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION,
31
**        IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO
32
**        OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
33
**        OR MODIFICATIONS.
34 055d3009 Eric Allman
**        ----- END LICENSE BLOCK -----
35
*/
36
37 c6293003 Eric Allman
#include <ep/ep.h>
38
#include <ep/ep_app.h>
39 80da996e Eric Allman
//#include <ep/ep_crypto.h>
40 c6293003 Eric Allman
#include <ep/ep_dbg.h>
41 80da996e Eric Allman
//#include <ep/ep_string.h>
42 c6293003 Eric Allman
#include <gdp/gdp.h>
43
44 ffa61df3 Eric Allman
#include <errno.h>
45 c6293003 Eric Allman
#include <string.h>
46
#include <sysexits.h>
47 1173b91e Eric Allman
#include <sys/stat.h>
48 c6293003 Eric Allman
49 8223a9f1 Eric Allman
50 298273b2 Eric Allman
//static EP_DBG        Dbg = EP_DBG_INIT("gdp-create", "Create new log");
51 b84971ef Eric Allman
52
53 78dfc436 Eric Allman
// command line options
54 80da996e Eric Allman
#define OPTIONS                "b:c:C:D:e:G:h:k:K:qs:SwW:"
55 78dfc436 Eric Allman
56 c6293003 Eric Allman
void
57
usage(void)
58
{
59 2a942e9a Eric Allman
        fprintf(stderr, "Usage: %s [-C creator] [-D dbgspec] [-e key_enc_alg]\n"
60 64259fd2 Eric Allman
                        "\t[-G gdpd_addr] [-q] [-s logd_name] [-S]\n"
61 80da996e Eric Allman
                        "\t[-h] [-k keytype] [-K owner_keyfile] [-w] [-W writer_keyfile]\n"
62
                        "\t[-b keybits] [-c curve] [<mdid>=<metadata>...] [log_name]\n"
63 2a942e9a Eric Allman
                        "    -C  set name of log creator (owner; for metadata)\n"
64 84b021ab Eric Allman
                        "    -D  set debugging flags\n"
65 25e66e4f Eric Allman
                        "    -e  set secret key encryption algorithm\n"
66 84b021ab Eric Allman
                        "    -G  IP host to contact for GDP router\n"
67 2a942e9a Eric Allman
                        "    -q  don't give error if log already exists\n"
68 80da996e Eric Allman
                        "    -s  set creation service name\n"
69 64259fd2 Eric Allman
                        "    -S  skip the test to see if log already exists (for debugging)\n"
70 25e66e4f Eric Allman
                        "    -h  set the hash (message digest) algorithm (defaults to sha256)\n"
71 bf192036 Eric Allman
                        "    -k  type of key; valid key types are \"rsa\", \"dsa\", and \"ec\"\n"
72
                        "\t(defaults to ec); \"none\" turns off key generation\n"
73 80da996e Eric Allman
                        "    -K  use indicated key/place to write secret owner key\n"
74
                        "    -w  create separate writer key\n"
75
                        "    -W  use indicated key/place to write secret writer key\n"
76
                        "\tIf -K or -W specify a directory, a .pem file is written there\n"
77 84b021ab Eric Allman
                        "\twith the name of the GCL (defaults to \"KEYS\" or \".\")\n"
78 b0136566 Eric Allman
                        "    -b  set size of key in bits (RSA and DSA only)\n"
79
                        "    -c  set curve name (EC only)\n"
80 2a942e9a Eric Allman
                        "    creator is the id of the creator, formatted as an email address\n"
81 84b021ab Eric Allman
                        "    logd_name is the name of the log server to host this log\n"
82 2a942e9a Eric Allman
                        "    metadata ids are (by convention) four letters or digits\n"
83 eae1d3ec Eric Allman
                        "    log_name is the name of the log to create\n",
84 c6293003 Eric Allman
                        ep_app_getprogname());
85
        exit(EX_USAGE);
86
}
87
88
89
int
90
main(int argc, char **argv)
91
{
92 eae1d3ec Eric Allman
        const char *gobxname = NULL;        // external name of GCL
93 b84971ef Eric Allman
        const char *logdxname = NULL;        // external name of log daemon
94 2a942e9a Eric Allman
        const char *cname = NULL;                // creator/owner name (for metadata)
95 eae1d3ec Eric Allman
        gdp_gin_t *gin = NULL;
96 80da996e Eric Allman
        gdp_create_info_t *gci = NULL;
97 c6293003 Eric Allman
        int opt;
98
        EP_STAT estat;
99
        char *gdpd_addr = NULL;
100
        bool show_usage = false;
101 11e67a2d Eric Allman
        bool quiet = false;
102 64259fd2 Eric Allman
        bool skip_existence_test = false;
103 ed3149f0 Eric Allman
        const char *dig_alg_name = "def";
104
        const char *key_alg_name = "def";
105 80da996e Eric Allman
        int key_bits = 0;
106
        const char *key_curve = NULL;
107
        const char *owner_keyfile = NULL;
108
        const char *writer_keyfile = NULL;
109 ed3149f0 Eric Allman
        const char *key_enc_alg_name = "def";
110 80da996e Eric Allman
        bool separate_writer_key = false;
111
        const char *phase = NULL;
112 c6293003 Eric Allman
113 78dfc436 Eric Allman
        // quick pass so debugging is on for initialization
114
        while ((opt = getopt(argc, argv, OPTIONS)) > 0)
115
        {
116
                if (opt == 'D')
117
                        ep_dbg_set(optarg);
118
        }
119 6a095f87 Eric Allman
        optind = 1;
120
#if EP_OSCF_NEED_OPTRESET
121
        optreset = 1;
122
#endif
123 78dfc436 Eric Allman
124 b8591e8b Eric Allman
        // preinit library (must be early due to crypto code in arg processing)
125 a87ede3e Eric Allman
        ep_crypto_init(0);
126 d18b013a Eric Allman
127 c6293003 Eric Allman
        // collect command-line arguments
128 78dfc436 Eric Allman
        while ((opt = getopt(argc, argv, OPTIONS)) > 0)
129 c6293003 Eric Allman
        {
130
                switch (opt)
131
                {
132 2a64fc09 Eric Allman
                 case 'b':
133 80da996e Eric Allman
                        key_bits = atoi(optarg);
134 2a64fc09 Eric Allman
                        break;
135
136 b0136566 Eric Allman
                 case 'c':
137 80da996e Eric Allman
                        key_curve = optarg;
138 b0136566 Eric Allman
                        break;
139
140 2a942e9a Eric Allman
                 case 'C':
141
                        cname = optarg;
142
                        break;
143
144 c6293003 Eric Allman
                 case 'D':
145 78dfc436 Eric Allman
                        // already done
146 c6293003 Eric Allman
                        break;
147
148 d18b013a Eric Allman
                 case 'e':
149 80da996e Eric Allman
                        if (ep_crypto_keyenc_byname(optarg) < 0)
150 d18b013a Eric Allman
                        {
151
                                ep_app_error("unknown key encryption algorithm %s", optarg);
152
                                show_usage = true;
153
                        }
154 80da996e Eric Allman
                        key_enc_alg_name = optarg;
155 d18b013a Eric Allman
                        break;
156
157 c6293003 Eric Allman
                 case 'G':
158
                        gdpd_addr = optarg;
159
                        break;
160
161 2a64fc09 Eric Allman
                 case 'h':
162 80da996e Eric Allman
                        if (ep_crypto_md_alg_byname(optarg) < 0)
163 e57b2ceb Eric Allman
                        {
164 2a64fc09 Eric Allman
                                ep_app_error("unknown digest hash algorithm %s", optarg);
165
                                show_usage = true;
166 e57b2ceb Eric Allman
                        }
167 80da996e Eric Allman
                        dig_alg_name = optarg;
168 c6293003 Eric Allman
                        break;
169
170 2a64fc09 Eric Allman
                 case 'k':
171 80da996e Eric Allman
                        if (ep_crypto_keytype_byname(optarg) == EP_CRYPTO_KEYTYPE_UNKNOWN)
172 2a64fc09 Eric Allman
                        {
173
                                ep_app_error("unknown key type %s", optarg);
174
                                show_usage = true;
175
                        }
176 80da996e Eric Allman
                        key_alg_name = optarg;
177 2a64fc09 Eric Allman
                        break;
178
179 bf192036 Eric Allman
                 case 'K':
180 80da996e Eric Allman
                        owner_keyfile = optarg;
181 bf192036 Eric Allman
                        break;
182
183 11e67a2d Eric Allman
                 case 'q':
184
                        quiet = true;
185
                        break;
186
187 b84971ef Eric Allman
                 case 's':
188
                        logdxname = optarg;
189
                        break;
190
191 64259fd2 Eric Allman
                 case 'S':
192
                        skip_existence_test = true;
193
                        break;
194
195 80da996e Eric Allman
                 case 'w':
196
                        separate_writer_key = true;
197
                        break;
198
199
                 case 'W':
200
                        writer_keyfile = optarg;
201
                        separate_writer_key = true;
202
                        break;
203
204 c6293003 Eric Allman
                 default:
205
                        show_usage = true;
206
                        break;
207
                }
208
        }
209
        argc -= optind;
210
        argv += optind;
211
212 b84971ef Eric Allman
        if (show_usage || argc < 0)
213 c6293003 Eric Allman
                usage();
214
215 80da996e Eric Allman
        // initialize the GDP library
216
        phase = "initializing GDP";
217
        estat = gdp_init(gdpd_addr);
218
        if (!EP_STAT_ISOK(estat))
219
                goto fail0;
220
221
        // allow thread to settle to avoid interspersed debug output
222
        ep_time_nanosleep(INT64_C(100000000));
223
224
        gci = gdp_create_info_new();
225
226
        // collect any metadata and external name
227
        while (argc > 0)
228 c6293003 Eric Allman
        {
229 80da996e Eric Allman
                char *p;
230
                if ((p = strchr(argv[0], '=')) != NULL)
231
                {
232
                        gdp_md_id_t mdid = 0;
233
                        int i;
234
235
                        p++;
236
                        for (i = 0; i < 4; i++)
237
                        {
238
                                if (argv[0][i] == '=')
239
                                        break;
240
                                mdid = (mdid << 8) | (unsigned) argv[0][i];
241
                        }
242 feb6c5a2 Eric Allman
                        if (argv[0][i] != '=')
243
                                ep_app_warn("metadata id %.*s truncated to 4 characters",
244
                                                (int) (p - argv[0] - 1), argv[0]);
245 c6293003 Eric Allman
246 80da996e Eric Allman
                        gdp_create_info_add_metadata(gci, mdid, strlen(p), p);
247
                }
248
                else if (gobxname == NULL)
249 c6293003 Eric Allman
                {
250 80da996e Eric Allman
                        gobxname = *argv;
251
                }
252
                else
253
                {
254
                        usage();
255 c6293003 Eric Allman
                }
256
257
                argc--;
258
                argv++;
259
        }
260
261
        // name is optional ; if omitted one will be created
262
        if (argc-- > 0)
263 eae1d3ec Eric Allman
                gobxname = *argv++;
264 c39a16b1 Eric Allman
        if (gobxname != NULL && gobxname[0] == '0')
265
                gobxname = NULL;
266 c6293003 Eric Allman
267
        if (show_usage || argc > 0)
268
                usage();
269
270 eae1d3ec Eric Allman
        if (gobxname != NULL)
271 11e67a2d Eric Allman
        {
272 c39a16b1 Eric Allman
                // check validity of the name
273
                gdp_name_t gobiname;
274
                if (EP_STAT_ISOK(gdp_internal_name(gobxname, gobiname)))
275
                {
276
                        // this is a valid base64-encooded log name: not appropriate
277
                        estat = GDP_STAT_GDP_NAME_INVALID;
278
                        if (!quiet)
279
                        {
280
                                ep_app_error("Cannot choose internal GDPname (%s)",
281
                                                gobxname);
282
                                exit(EX_CANTCREAT);
283
                        }
284
                }
285 64259fd2 Eric Allman
                if (!skip_existence_test)
286 11e67a2d Eric Allman
                {
287 c39a16b1 Eric Allman
                        /*
288
                        **  If the external name is already known in the
289
                        **  Human-Oriented Name to GDPname directory, OR if the
290
                        **  hashed (old-style) internal name can be found,
291
                        **  then there is a conflict.
292
                        */
293
294 80da996e Eric Allman
                        gin = NULL;
295 c39a16b1 Eric Allman
                        estat = gdp_name_parse(gobxname, gobiname, NULL);
296
                        if (EP_STAT_ISWARN(estat))
297 64259fd2 Eric Allman
                        {
298 c39a16b1 Eric Allman
                                // iname used is the SHA256 of the xname
299
                                estat = gdp_gin_open(gobiname, GDP_MODE_RO, NULL, &gin);
300
                        }
301
                        if (EP_STAT_ISOK(estat))
302
                        {
303
                                // oops, we shouldn't be able to parse or open it
304 80da996e Eric Allman
                                if (gin != NULL)
305
                                        (void) gdp_gin_close(gin);
306 64259fd2 Eric Allman
                                if (!quiet)
307 eae1d3ec Eric Allman
                                        ep_app_error("Cannot create %s: already exists", gobxname);
308 64259fd2 Eric Allman
                                exit(EX_CANTCREAT);
309
                        }
310 11e67a2d Eric Allman
                }
311
        }
312
313 034d97fd Eric Allman
        /**************************************************************
314
        **  Set up other automatic metadata
315
        */
316
317 80da996e Eric Allman
        if (cname != NULL)
318 034d97fd Eric Allman
        {
319 80da996e Eric Allman
                phase = "setting creator";
320
                estat = gdp_create_info_set_creator(gci, cname, NULL);
321
                EP_STAT_CHECK(estat, goto fail1);
322 034d97fd Eric Allman
        }
323
324 80da996e Eric Allman
        if (logdxname != NULL)
325 2a942e9a Eric Allman
        {
326 80da996e Eric Allman
                phase = "setting creation service";
327
                estat = gdp_create_info_set_creation_service(gci, logdxname);
328 c39a16b1 Eric Allman
                // OK if iname is hash of xname, which presents as a warning
329
                if (EP_STAT_ISFAIL(estat))
330
                        goto fail1;
331 2a942e9a Eric Allman
        }
332 034d97fd Eric Allman
333 80da996e Eric Allman
        if (owner_keyfile != NULL)
334 d18b013a Eric Allman
        {
335 1173b91e Eric Allman
                // could be an existing file or a directory
336 80da996e Eric Allman
                phase = "setting owner key";
337 1173b91e Eric Allman
                struct stat st;
338
                int istat = stat(owner_keyfile, &st);
339
340
                if (istat < 0)
341
                {
342
                        // non-existent file: error
343
                        ep_app_error("%s must exist", owner_keyfile);
344
                        estat = ep_stat_from_errno(ENOENT);
345
                }
346
                else if ((st.st_mode & S_IFMT) == S_IFDIR)
347
                {
348
                        // arrange for key to be written to this directory
349
                        phase = "creating owner key";
350
                        ep_adm_setparam("swarm.gdp.crypto.key.dir", owner_keyfile);
351
                        estat = gdp_create_info_new_owner_key(gci, dig_alg_name,
352
                                                        key_alg_name, key_bits, key_curve,
353
                                                        key_enc_alg_name);
354
                }
355
                else
356
                {
357
                        // existing key file --- use it instead of creating new key
358
                        EP_CRYPTO_KEY *key = NULL;
359
                        key = ep_crypto_key_read_file(owner_keyfile,
360
                                                                EP_CRYPTO_KEYFORM_UNKNOWN, EP_CRYPTO_F_SECRET);
361
                        estat = gdp_create_info_set_owner_key(gci, key, dig_alg_name);
362
                }
363 d18b013a Eric Allman
        }
364 1173b91e Eric Allman
        else
365 2a64fc09 Eric Allman
        {
366 80da996e Eric Allman
                phase = "creating owner key";
367
                estat = gdp_create_info_new_owner_key(gci, dig_alg_name, key_alg_name,
368
                                                key_bits, key_curve, key_enc_alg_name);
369 e57b2ceb Eric Allman
        }
370 80da996e Eric Allman
        EP_STAT_CHECK(estat, goto fail1);
371 e57b2ceb Eric Allman
372 80da996e Eric Allman
        if (writer_keyfile != NULL)
373 c6293003 Eric Allman
        {
374 80da996e Eric Allman
                phase = "setting writer key";
375 8e138989 Eric Allman
                EP_CRYPTO_KEY *key;
376
                key = ep_crypto_key_read_file(writer_keyfile, 0, EP_CRYPTO_F_SECRET);
377 80da996e Eric Allman
                estat = gdp_create_info_set_writer_key(gci, key, dig_alg_name);
378 c6293003 Eric Allman
        }
379 80da996e Eric Allman
        else if (separate_writer_key)
380 c6293003 Eric Allman
        {
381 80da996e Eric Allman
                phase = "creating writer key";
382
                estat = gdp_create_info_new_writer_key(gci, dig_alg_name, key_alg_name,
383
                                                key_bits, key_curve, key_enc_alg_name);
384 c6293003 Eric Allman
        }
385 80da996e Eric Allman
        EP_STAT_CHECK(estat, goto fail1);
386 c6293003 Eric Allman
387 c39a16b1 Eric Allman
        // if the user specified an unqualified name and we have a root name,
388
        // use the extended name.
389
        const char *root = gdp_name_root_get();
390
        char xnamebuf[GDP_HUMAN_NAME_MAX + 1];
391
        if (gobxname != NULL && strchr(gobxname, '.') == NULL && root != NULL)
392
        {
393
                snprintf(xnamebuf, sizeof xnamebuf, "%s.%s", root, gobxname);
394
                gobxname = xnamebuf;
395
        }
396
397 d18b013a Eric Allman
        /*
398
        **  Hello sailor, this is where the actual creation happens
399
        */
400 034d97fd Eric Allman
401 80da996e Eric Allman
        phase = "creating GDP object";
402
        estat = gdp_gin_create(gci, gobxname, &gin);
403 c6293003 Eric Allman
        EP_STAT_CHECK(estat, goto fail1);
404
405 d18b013a Eric Allman
        // just for a lark, let the user know the (internal) name
406 11e67a2d Eric Allman
        if (!quiet)
407 d18b013a Eric Allman
        {
408
                gdp_pname_t pname;
409 c6293003 Eric Allman
410 71f57d41 Eric Allman
                // this output gets parsed by gdp-rest --- don't change it!
411 80da996e Eric Allman
                printf("Created new GCL %s\n",
412
                                gdp_printable_name(*gdp_gin_getname(gin), pname));
413 c6293003 Eric Allman
        }
414
415 eae1d3ec Eric Allman
        gdp_gin_close(gin);
416 7fcb8dfd Eric Allman
417 c6293003 Eric Allman
fail1:
418 80da996e Eric Allman
        // free creation information
419
        gdp_create_info_free(&gci);
420
421
fail0:
422
        if (!EP_STAT_ISOK(estat))
423 1a2e6f40 Rick Pratt
        {
424 80da996e Eric Allman
                char ebuf[100];
425
                ep_app_error("Creation failed while %s: %s",
426
                                phase, ep_stat_tostr(estat, ebuf, sizeof ebuf));
427 1a2e6f40 Rick Pratt
        }
428 c6293003 Eric Allman
429 2dba893f Eric Allman
        int exitstat;
430
        if (EP_STAT_ISOK(estat))
431
                exitstat = EX_OK;
432 a4ca7afc Eric Allman
        else if (EP_STAT_IS_SAME(estat, GDP_STAT_NAK_NOROUTE))
433 2dba893f Eric Allman
                exitstat = EX_NOHOST;
434 4964758b Eric Allman
        else if (EP_STAT_IS_SAME(estat, GDP_STAT_NAK_CONFLICT))
435
                exitstat = EX_CANTCREAT;
436 a4ca7afc Eric Allman
        else if (EP_STAT_ISABORT(estat))
437 2dba893f Eric Allman
                exitstat = EX_SOFTWARE;
438
        else
439
                exitstat = EX_UNAVAILABLE;
440
441 c6293003 Eric Allman
        // OK status can have values; hide that from the user
442
        if (EP_STAT_ISOK(estat))
443
                estat = EP_STAT_OK;
444 2dba893f Eric Allman
445
        if (!EP_STAT_ISOK(estat))
446 9829d4ae Eric Allman
                ep_app_message(estat, "exiting with status");
447 2dba893f Eric Allman
        else if (!quiet)
448
                fprintf(stderr, "Exiting with status OK\n");
449 cb98e88e Eric Allman
450
        return exitstat;
451 c6293003 Eric Allman
}