• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stefanberger / swtpm / #2783

13 Apr 2025 04:06PM UTC coverage: 73.43%. Remained the same
#2783

push

travis-ci

web-flow
Merge 14f849d04 into 8ad31a72a

87 of 102 new or added lines in 5 files covered. (85.29%)

643 existing lines in 9 files now uncovered.

8150 of 11099 relevant lines covered (73.43%)

13458.04 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

61.44
/src/swtpm/common.c
1
/*
2
 * common.c -- Common code for swtpm and swtpm_cuse
3
 *
4
 * (c) Copyright IBM Corporation 2014, 2015, 2019.
5
 *
6
 * Author: Stefan Berger <stefanb@us.ibm.com>
7
 *
8
 * All rights reserved.
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions are
12
 * met:
13
 *
14
 * Redistributions of source code must retain the above copyright notice,
15
 * this list of conditions and the following disclaimer.
16
 *
17
 * Redistributions in binary form must reproduce the above copyright
18
 * notice, this list of conditions and the following disclaimer in the
19
 * documentation and/or other materials provided with the distribution.
20
 *
21
 * Neither the names of the IBM Corporation nor the names of its
22
 * contributors may be used to endorse or promote products derived from
23
 * this software without specific prior written permission.
24
 *
25
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36
 */
37

38
#include "config.h"
39

40
#define _GNU_SOURCE
41
#include <stdio.h>
42
#include <string.h>
43
#include <errno.h>
44
#include <unistd.h>
45
#include <sys/types.h>
46
#include <pwd.h>
47
#include <stdlib.h>
48
#include <sys/stat.h>
49
#include <sys/un.h>
50
#include <netinet/in.h>
51
#include <sys/socket.h>
52
#include <arpa/inet.h>
53
#include <net/if.h>
54

55
#ifdef WITH_SECCOMP
56
# include <seccomp.h>
57
#endif
58

59
#include <libtpms/tpm_error.h>
60

61
#include "common.h"
62
#include "options.h"
63
#include "key.h"
64
#include "locality.h"
65
#include "logging.h"
66
#include "swtpm_nvstore.h"
67
#include "pidfile.h"
68
#include "tpmstate.h"
69
#include "ctrlchannel.h"
70
#include "server.h"
71
#include "seccomp_profile.h"
72
#include "tpmlib.h"
73
#include "mainloop.h"
74
#include "profile.h"
75
#include "swtpm_utils.h"
76
#include "utils.h"
77

78
/* --log %s */
79
static const OptionDesc logging_opt_desc[] = {
80
    {
81
        .name = "file",
82
        .type = OPT_TYPE_STRING,
83
    }, {
84
        .name = "fd",
85
        .type = OPT_TYPE_INT,
86
    }, {
87
        .name = "level",
88
        .type = OPT_TYPE_UINT,
89
    }, {
90
        .name = "prefix",
91
        .type = OPT_TYPE_STRING,
92
    }, {
93
        .name = "truncate",
94
        .type = OPT_TYPE_BOOLEAN,
95
    },
96
    END_OPTION_DESC
97
};
98

99
/* --key %s */
100
static const OptionDesc key_opt_desc[] = {
101
    {
102
        .name = "file",
103
        .type = OPT_TYPE_STRING,
104
    }, {
105
        .name = "mode",
106
        .type = OPT_TYPE_STRING,
107
    }, {
108
        .name = "format",
109
        .type = OPT_TYPE_STRING,
110
    }, {
111
        .name = "remove",
112
        .type = OPT_TYPE_BOOLEAN,
113
    }, {
114
        .name = "pwdfile",
115
        .type = OPT_TYPE_STRING,
116
    }, {
117
        .name = "kdf",
118
        .type = OPT_TYPE_STRING,
119
    }, {
120
        .name = "fd",
121
        .type = OPT_TYPE_INT,
122
    }, {
123
        .name = "pwdfd",
124
        .type = OPT_TYPE_INT,
125
    },
126
    END_OPTION_DESC
127
};
128

129
/* --pid %s */
130
static const OptionDesc pid_opt_desc[] = {
131
    {
132
        .name = "file",
133
        .type = OPT_TYPE_STRING,
134
    }, {
135
        .name = "fd",
136
        .type = OPT_TYPE_INT,
137
    },
138
    END_OPTION_DESC
139
};
140

141
/* --state %s */
142
static const OptionDesc tpmstate_opt_desc[] = {
143
    {
144
        .name = "dir",
145
        .type = OPT_TYPE_STRING,
146
    }, {
147
        .name = "mode",
148
        .type = OPT_TYPE_MODE_T,
149
    }, {
150
        .name = "backend-uri",
151
        .type = OPT_TYPE_STRING,
152
    }, {
153
        .name = "lock",
154
        .type = OPT_TYPE_BOOLEAN,
155
    }, {
156
        .name = "backup",
157
        .type = OPT_TYPE_BOOLEAN,
158
    },
159
    END_OPTION_DESC
160
};
161

162
static const OptionDesc ctrl_opt_desc[] = {
163
    {
164
        .name = "type",
165
        .type = OPT_TYPE_STRING,
166
    }, {
167
        .name = "path",
168
        .type = OPT_TYPE_STRING,
169
    }, {
170
        .name = "port",
171
        .type = OPT_TYPE_INT,
172
    }, {
173
        .name = "bindaddr",
174
        .type = OPT_TYPE_STRING,
175
    }, {
176
        .name = "ifname",
177
        .type = OPT_TYPE_STRING,
178
    }, {
179
        .name = "fd",
180
        .type = OPT_TYPE_INT,
181
    }, {
182
        .name = "clientfd",
183
        .type = OPT_TYPE_INT,
184
    }, {
185
        .name = "mode",
186
        .type = OPT_TYPE_MODE_T,
187
    }, {
188
        .name = "uid",
189
        .type = OPT_TYPE_UID_T,
190
    }, {
191
        .name = "gid",
192
        .type = OPT_TYPE_GID_T,
193
    }, {
194
        .name = "terminate",
195
        .type = OPT_TYPE_BOOLEAN,
196
    },
197
    END_OPTION_DESC
198
};
199

200
static const OptionDesc server_opt_desc[] = {
201
    {
202
        .name = "type",
203
        .type = OPT_TYPE_STRING,
204
    }, {
205
        .name = "path",
206
        .type = OPT_TYPE_STRING,
207
    }, {
208
        .name = "port",
209
        .type = OPT_TYPE_INT,
210
    }, {
211
        .name = "bindaddr",
212
        .type = OPT_TYPE_STRING,
213
    }, {
214
        .name = "ifname",
215
        .type = OPT_TYPE_STRING,
216
    }, {
217
        .name = "fd",
218
        .type = OPT_TYPE_INT,
219
    }, {
220
        .name = "disconnect",
221
        .type = OPT_TYPE_BOOLEAN,
222
    }, {
223
        .name = "mode",
224
        .type = OPT_TYPE_MODE_T,
225
    }, {
226
        .name = "uid",
227
        .type = OPT_TYPE_UID_T,
228
    }, {
229
        .name = "gid",
230
        .type = OPT_TYPE_GID_T,
231
    },
232
    END_OPTION_DESC
233
};
234

235
static const OptionDesc locality_opt_desc[] = {
236
    {
237
        .name = "reject-locality-4",
238
        .type = OPT_TYPE_BOOLEAN,
239
    }, {
240
        .name = "allow-set-locality",
241
        .type = OPT_TYPE_BOOLEAN,
242
    },
243
    END_OPTION_DESC
244
};
245

246
static const OptionDesc flags_opt_desc[] = {
247
    {
248
        .name = "not-need-init",
249
        .type = OPT_TYPE_BOOLEAN,
250
    }, {
251
        .name = "startup-none",
252
        .type = OPT_TYPE_BOOLEAN,
253
    }, {
254
        .name = "startup-clear",
255
        .type = OPT_TYPE_BOOLEAN,
256
    }, {
257
        .name = "startup-state",
258
        .type = OPT_TYPE_BOOLEAN,
259
    }, {
260
        .name = "startup-deactivated",
261
        .type = OPT_TYPE_BOOLEAN,
262
    }, {
263
        .name = "disable-auto-shutdown",
264
        .type = OPT_TYPE_BOOLEAN,
265
    },
266
    END_OPTION_DESC
267
};
268

269
#ifdef WITH_SECCOMP
270
static const OptionDesc seccomp_opt_desc[] = {
271
    {
272
        .name = "action",
273
        .type = OPT_TYPE_STRING,
274
    },
275
    END_OPTION_DESC
276
};
277
#endif
278

279
static const OptionDesc migration_opt_desc[] = {
280
    {
281
        .name = "incoming",
282
        .type = OPT_TYPE_BOOLEAN,
283
    }, {
284
        .name = "release-lock-outgoing",
285
        .type = OPT_TYPE_BOOLEAN,
286
    },
287
    END_OPTION_DESC
288
};
289

290
static const OptionDesc profile_opt_desc[] = {
291
    {
292
        .name = "name",
293
        .type = OPT_TYPE_STRING,
294
    }, {
295
        .name = "profile",
296
        .type = OPT_TYPE_STRING,
297
    }, {
298
        .name = "file",
299
        .type = OPT_TYPE_STRING,
300
    }, {
301
        .name = "fd",
302
        .type = OPT_TYPE_INT,
303
    }, {
304
        .name = "remove-disabled",
305
        .type = OPT_TYPE_STRING,
306
    },
307
    END_OPTION_DESC
308
};
309

310
/*
311
 * handle_log_options:
312
 * Parse and act upon the parsed log options. Initialize the logging.
313
 * @options: the log options
314
 *
315
 * Returns 0 on success, -1 on failure.
316
 */
317
int
318
handle_log_options(const char *options)
1,153✔
319
{
320
    char *error = NULL;
1,153✔
321
    const char *logfile = NULL, *logprefix = NULL;
1,153✔
322
    int logfd;
1,153✔
323
    unsigned int loglevel;
1,153✔
324
    bool logtruncate;
1,153✔
325
    OptionValues *ovs = NULL;
1,153✔
326

327
    if (!options)
1,153✔
328
        return 0;
329

330
    ovs = options_parse(options, logging_opt_desc, &error);
538✔
331
    if (!ovs) {
538✔
UNCOV
332
        logprintf(STDERR_FILENO, "Error parsing logging options: %s\n",
×
333
                  error);
UNCOV
334
        free(error);
×
335
        return -1;
×
336
    }
337
    logfile = option_get_string(ovs, "file", NULL);
538✔
338
    logfd = option_get_int(ovs, "fd", -1);
538✔
339
    loglevel = option_get_uint(ovs, "level", 0);
538✔
340
    logprefix = option_get_string(ovs, "prefix", NULL);
538✔
341
    logtruncate = option_get_bool(ovs, "truncate", false);
538✔
342
    if (logfile && (log_init(logfile, logtruncate) < 0)) {
538✔
UNCOV
343
        logprintf(STDERR_FILENO,
×
344
                  "Could not open logfile for writing: %s\n",
UNCOV
345
                  strerror(errno));
×
346
        goto error;
×
347
    } else if (logfd >= 0 && (log_init_fd(logfd) < 0)) {
538✔
348
        logprintf(STDERR_FILENO,
×
349
                  "Could not access logfile using fd %d: %s\n",
UNCOV
350
                  logfd, strerror(errno));
×
351
        goto error;
×
352
    }
353
    if ((logfile || logfd) && !loglevel)
538✔
354
        loglevel = 1;
355

356
    if (log_set_prefix(logprefix) < 0) {
538✔
UNCOV
357
        logprintf(STDERR_FILENO,
×
358
                  "Could not set logging prefix. Out of memory?\n");
UNCOV
359
        goto error;
×
360
    }
361
    if (log_set_level(loglevel) < 0) {
538✔
362
        logprintf(STDERR_FILENO,
×
363
                  "Could not set log level. Out of memory?");
UNCOV
364
        goto error;
×
365
    }
366

367
    option_values_free(ovs);
538✔
368

369
    return 0;
538✔
370

UNCOV
371
error:
×
UNCOV
372
    option_values_free(ovs);
×
373

374
    return -1;
×
375
}
376

377
/*
378
 * parse_key_options:
379
 * Parse and act upon the parsed key options.
380
 *
381
 * @options: the key options to parse
382
 * @key: buffer to hold the key
383
 * @maxkeylen: size of the buffer (= max. size the key can have)
384
 * @keylen: the length of the parsed key
385
 * @encmode: the encryption mode as determined from the options
386
 *
387
 * Returns 0 on success, -1 on failure.
388
 */
389
static int
390
parse_key_options(const char *options, unsigned char *key, size_t maxkeylen,
136✔
391
                  size_t *keylen, enum encryption_mode *encmode)
392
{
393
    OptionValues *ovs = NULL;
136✔
394
    char *error = NULL;
136✔
395
    const char *keyfile = NULL;
136✔
396
    const char *pwdfile = NULL;
136✔
397
    const char *tmp;
136✔
398
    enum key_format keyformat;
136✔
399
    enum kdf_identifier kdfid;
136✔
400
    size_t mode_keylength;
136✔
401
    int ret;
136✔
402
    int keyfile_fd = -1;
136✔
403
    int pwdfile_fd = -1;
136✔
404

405
    ovs = options_parse(options, key_opt_desc, &error);
136✔
406
    if (!ovs) {
136✔
UNCOV
407
        logprintf(STDERR_FILENO, "Error parsing key options: %s\n",
×
408
                  error);
UNCOV
409
        goto error;
×
410
    }
411

412
    keyfile = option_get_string(ovs, "file", NULL);
136✔
413
    keyfile_fd = option_get_int(ovs, "fd", -1);
136✔
414
    pwdfile = option_get_string(ovs, "pwdfile", NULL);
136✔
415
    pwdfile_fd = option_get_int(ovs, "pwdfd", -1);
136✔
416
    if (!keyfile && keyfile_fd == -1 && !pwdfile && pwdfile_fd == -1) {
136✔
UNCOV
417
        logprintf(STDERR_FILENO,
×
418
                  "Either file=, fd=, pwdfile=, or pwdfd= is required for key option\n");
UNCOV
419
        goto error;
×
420
    }
421

422
    tmp = option_get_string(ovs, "format", NULL);
136✔
423
    keyformat = key_format_from_string(tmp ? tmp : "hex");
242✔
424
    if (keyformat == KEY_FORMAT_UNKNOWN)
136✔
UNCOV
425
        goto error;
×
426

427
    tmp = option_get_string(ovs, "mode", NULL);
136✔
428
    *encmode = encryption_mode_from_string(tmp ? tmp : "aes-128-cbc",
192✔
429
                                           &mode_keylength);
430
    if (*encmode == ENCRYPTION_MODE_UNKNOWN) {
136✔
UNCOV
431
        logprintf(STDERR_FILENO, "Unknown encryption mode '%s'.\n", tmp);
×
UNCOV
432
        goto error;
×
433
    }
434

435
    if (mode_keylength > maxkeylen) {
136✔
436
        /* program error ... */
UNCOV
437
        logprintf(STDERR_FILENO,
×
438
                  "Requested key size %zu larger than supported size %zu.\n",
439
                  mode_keylength, maxkeylen);
440
        goto error;
×
441
    }
442

443
    if (keyfile != NULL) {
136✔
444
        if (key_load_key(keyfile, keyformat,
36✔
445
                         key, keylen, mode_keylength) < 0)
UNCOV
446
            goto error;
×
447
    } else if (keyfile_fd >= 0) {
100✔
448
        if (key_load_key_fd(keyfile_fd, keyformat,
7✔
449
                            key, keylen, mode_keylength) < 0)
UNCOV
450
            goto error;
×
451
    } else {
452
        tmp = option_get_string(ovs, "kdf", "pbkdf2");
93✔
453
        kdfid = kdf_identifier_from_string(tmp);
93✔
454
        if (kdfid == KDF_IDENTIFIER_UNKNOWN) {
93✔
UNCOV
455
            logprintf(STDERR_FILENO, "Unknown kdf '%s'.\n", tmp);
×
UNCOV
456
            goto error;
×
457
        }
458
        /* no key file, so must be pwdfile or pwdfile_fd */
459
        if (pwdfile) {
93✔
460
            if (key_from_pwdfile(pwdfile, key, keylen,
86✔
461
                                 mode_keylength, kdfid) < 0)
UNCOV
462
                goto error;
×
463
        } else {
464
            if (key_from_pwdfile_fd(pwdfile_fd, key, keylen,
7✔
465
                                    mode_keylength, kdfid) < 0)
UNCOV
466
                goto error;
×
467
        }
468
    }
469

470
    if (option_get_bool(ovs, "remove", false)) {
136✔
471
        if (keyfile)
30✔
472
            unlink(keyfile);
20✔
473
        if (pwdfile)
30✔
474
            unlink(pwdfile);
10✔
475
    }
476

477
    ret = 0;
478

479
exit:
136✔
480
    option_values_free(ovs);
136✔
481
    if (keyfile_fd >= 0)
136✔
482
        close(keyfile_fd);
7✔
483
    if (pwdfile_fd >= 0)
136✔
484
        close(pwdfile_fd);
7✔
485

486
    return ret;
136✔
487

UNCOV
488
error:
×
UNCOV
489
    ret = -1;
×
UNCOV
490
    free(error);
×
491

492
    goto exit;
×
493
}
494

495
/*
496
 * handle_key_options:
497
 * Parse and act upon the parsed key options. Set global values related
498
 * to the options found.
499
 * @options: the key options to parse
500
 *
501
 * Returns 0 on success, -1 on failure.
502
 */
503
int
504
handle_key_options(const char *options)
558✔
505
{
506
    enum encryption_mode encmode = ENCRYPTION_MODE_UNKNOWN;
558✔
507
    unsigned char key[256/8];
558✔
508
    size_t maxkeylen = sizeof(key);
558✔
509
    size_t keylen;
558✔
510
    int ret = 0;
558✔
511

512
    if (!options)
558✔
513
        return 0;
514

515
    if (parse_key_options(options, key, maxkeylen, &keylen, &encmode) < 0) {
106✔
UNCOV
516
        ret = -1;
×
UNCOV
517
        goto error;
×
518
    }
519

520
    if (SWTPM_NVRAM_Set_FileKey(key, keylen, encmode) != TPM_SUCCESS) {
106✔
UNCOV
521
        ret = -1;
×
UNCOV
522
        goto error;
×
523
    }
524

525
error:
106✔
526
    /* Wipe to ensure we don't leave a key on the stack */
527
    memset(key, 0, maxkeylen);
106✔
528
    return ret;
106✔
529
}
530

531
/*
532
 * handle_migration_key_options:
533
 * Parse and act upon the parsed key options. Set global values related
534
 * to the options found.
535
 * @options: the key options to parse
536
 *
537
 * Returns 0 on success, -1 on failure.
538
 */
539
int
540
handle_migration_key_options(const char *options)
558✔
541
{
542
    enum encryption_mode encmode = ENCRYPTION_MODE_UNKNOWN;
558✔
543
    unsigned char key[256/8];
558✔
544
    size_t maxkeylen = sizeof(key);
558✔
545
    size_t keylen;
558✔
546
    int ret = 0;
558✔
547

548
    if (!options)
558✔
549
        return 0;
550

551
    if (parse_key_options(options, key, maxkeylen, &keylen, &encmode) < 0) {
30✔
UNCOV
552
        ret = -1;
×
UNCOV
553
        goto error;
×
554
    }
555

556
    if (SWTPM_NVRAM_Set_MigrationKey(key, keylen, encmode) != TPM_SUCCESS) {
30✔
UNCOV
557
        ret = -1;
×
UNCOV
558
        goto error;
×
559
    }
560

561
error:
30✔
562
    /* Wipe to ensure we don't leave a key on the stack */
563
    memset(key, 0, maxkeylen);
30✔
564
    return ret;
30✔
565
}
566

567
/*
568
 * parse_pid_options:
569
 * Parse and act upon the parsed 'pid' options.
570
 *
571
 * @options: the 'pid' options to parse
572
 * @pidfile: Point to pointer for pidfile
573
 * @pidfilefd: Pointer to file descriptor for pidfile
574
 *
575
 * Returns 0 on success, -1 on failure.
576
 */
577
static int
578
parse_pid_options(const char *options, char **pidfile, int *pidfilefd)
195✔
579
{
580
    OptionValues *ovs = NULL;
195✔
581
    char *error = NULL;
195✔
582
    const char *filename = NULL;
195✔
583
    struct stat stat;
195✔
584

585
    ovs = options_parse(options, pid_opt_desc, &error);
195✔
586
    if (!ovs) {
195✔
UNCOV
587
        logprintf(STDERR_FILENO, "Error parsing pid options: %s\n",
×
588
                  error);
UNCOV
589
        goto error;
×
590
    }
591

592
    filename = option_get_string(ovs, "file", NULL);
195✔
593
    *pidfilefd = option_get_int(ovs, "fd", -1);
195✔
594
    if (!filename && *pidfilefd < 0) {
195✔
UNCOV
595
        logprintf(STDERR_FILENO,
×
596
                  "The file or fd parameter is required for the pid option.\n");
UNCOV
597
        goto error;
×
598
    }
599

600
    if (filename) {
195✔
601
        *pidfile = strdup(filename);
195✔
602
        if (!*pidfile) {
195✔
UNCOV
603
            logprintf(STDERR_FILENO, "Out of memory.");
×
UNCOV
604
            goto error;
×
605
        }
606
    } else {
607
        if (fstat(*pidfilefd, &stat) < 0 || !S_ISREG(stat.st_mode)) {
×
UNCOV
608
            logprintf(STDERR_FILENO,
×
609
                      "Bad filedescriptor %d for pid file\n", *pidfilefd);
610
            goto error;
×
611
        }
612
    }
613

614
    option_values_free(ovs);
195✔
615

616
    return 0;
195✔
617

UNCOV
618
error:
×
UNCOV
619
    option_values_free(ovs);
×
UNCOV
620
    if (*pidfilefd >= 0)
×
621
        close(*pidfilefd);
×
622
    free(error);
×
623

624
    return -1;
×
625
}
626

627
/*
628
 * handle_pidfile_options:
629
 * Parse and act upon the parse pidfile options.
630
 *
631
 * @options: the pidfile options to parse
632
 *
633
 * Returns 0 on success, -1 on failure.
634
 */
635
int
636
handle_pid_options(const char *options)
558✔
637
{
638
    char *pidfile = NULL;
558✔
639
    int pidfilefd = -1;
558✔
640
    int ret = 0;
558✔
641

642
    if (!options)
558✔
643
        return 0;
644

645
    if (parse_pid_options(options, &pidfile, &pidfilefd) < 0)
195✔
646
        return -1;
647

648
    if (pidfile && pidfile_set(pidfile) < 0)
195✔
649
        ret = -1;
650
    else if (pidfile_set_fd(pidfilefd) < 0)
195✔
UNCOV
651
        ret = -1;
×
652

653
    free(pidfile);
195✔
654

655
    return ret;
195✔
656
}
657

658
/*
659
 * parse_tpmstate_options:
660
 * Parse and act upon the parsed 'tpmstate' options.
661
 *
662
 * @options: the 'pid' options to parse
663
 * @tpmstatedir: Point to pointer for tpmstatedir
664
 * @mode: the mode of the TPM's state files
665
 * @mode_is_default: true if user did not provide mode bits but using default
666
 * @tpmbackend_uri: Point to pointer for backend URI
667
 * @do_locking: whether the backend should file-lock the storage
668
 *
669
 * Returns 0 on success, -1 on failure.
670
 */
671
static int
672
parse_tpmstate_options(const char *options, char **tpmstatedir, mode_t *mode,
389✔
673
                       bool *mode_is_default, char **tpmbackend_uri,
674
                       bool *do_locking, bool *make_backup)
675
{
676
    OptionValues *ovs = NULL;
389✔
677
    char *error = NULL;
389✔
678
    const char *directory = NULL;
389✔
679
    const char *backend_uri = NULL;
389✔
680
    /* historically dir backend always locked, file backend did not */
681
    bool lock_default = true;
389✔
682

683
    ovs = options_parse(options, tpmstate_opt_desc, &error);
389✔
684
    if (!ovs) {
389✔
UNCOV
685
        logprintf(STDERR_FILENO, "Error parsing tpmstate options: %s\n",
×
686
                  error);
UNCOV
687
        goto error;
×
688
    }
689

690
    directory = option_get_string(ovs, "dir", NULL);
389✔
691
    backend_uri = option_get_string(ovs, "backend-uri", NULL);
389✔
692
    *make_backup = option_get_bool(ovs, "backup", false);
389✔
693

694
    /* Did user provide mode bits? User can only provide <= 0777 */
695
    *mode = option_get_mode_t(ovs, "mode", 01000);
389✔
696
    *mode_is_default = (*mode == 01000);
389✔
697
    if (*mode_is_default)
389✔
698
        *mode = 0640;
387✔
699

700
    if (directory) {
389✔
701
        *tpmstatedir = strdup(directory);
101✔
702
        if (!*tpmstatedir) {
101✔
UNCOV
703
            logprintf(STDERR_FILENO, "Out of memory.");
×
UNCOV
704
            goto error;
×
705
        }
706
    } else if (backend_uri) {
288✔
707
        *tpmbackend_uri = strdup(backend_uri);
288✔
708
        if (!*tpmbackend_uri) {
288✔
UNCOV
709
            logprintf(STDERR_FILENO, "Out of memory.");
×
UNCOV
710
            goto error;
×
711
        }
712
        if (strncmp(*tpmbackend_uri, "file://", 7) == 0)
288✔
713
            lock_default = false;
10✔
714
    } else {
UNCOV
715
        logprintf(STDERR_FILENO,
×
716
                  "The dir or backend-uri parameters is required "
717
                  "for the tpmstate option.\n");
UNCOV
718
        goto error;
×
719
    }
720

721
    *do_locking = option_get_bool(ovs, "lock", lock_default);
389✔
722

723
    option_values_free(ovs);
389✔
724

725
    return 0;
389✔
726

UNCOV
727
error:
×
UNCOV
728
    free(error);
×
UNCOV
729
    option_values_free(ovs);
×
730

731
    return -1;
×
732
}
733

734
/*
735
 * handle_tpmstate_options:
736
 * Parse and act upon the parsed 'tpmstate' options.
737
 *
738
 * @options: the tpmstate options to parse
739
 *
740
 * Returns 0 on success, -1 on failure.
741
 */
742
int
743
handle_tpmstate_options(const char *options)
713✔
744
{
745
    char *tpmstatedir = NULL;
713✔
746
    char *tpmbackend_uri = NULL;
713✔
747
    char *temp_uri = NULL;
713✔
748
    int ret = 0;
713✔
749
    mode_t mode;
713✔
750
    bool mode_is_default = true;
713✔
751
    bool do_locking = false;
713✔
752
    bool make_backup = false;
713✔
753

754
    if (!options)
713✔
755
        return 0;
756

757
    if (parse_tpmstate_options(options, &tpmstatedir, &mode,
389✔
758
                               &mode_is_default, &tpmbackend_uri,
759
                               &do_locking, &make_backup) < 0) {
UNCOV
760
        ret = -1;
×
UNCOV
761
        goto error;
×
762
    }
763

764
    if (tpmstatedir) {
389✔
765
        /* Default tpmstate store dir backend */
766
        if (asprintf(&temp_uri, "dir://%s", tpmstatedir) < 0) {
101✔
UNCOV
767
            logprintf(STDERR_FILENO,
×
768
                      "Could not asprintf TPM backend uri\n");
UNCOV
769
            ret = -1;
×
UNCOV
770
            temp_uri = NULL;
×
UNCOV
771
            goto error;
×
772
        }
773

774
        if (tpmstate_set_backend_uri(temp_uri) < 0) {
101✔
775
            ret = -1;
×
776
            goto error;
×
777
        }
778
    } else {
779
        if (tpmstate_set_backend_uri(tpmbackend_uri) < 0) {
288✔
780
            ret = -1;
×
781
            goto error;
×
782
        }
783
    }
784

785
    tpmstate_set_mode(mode, mode_is_default);
389✔
786
    tpmstate_set_locking(do_locking);
389✔
787
    tpmstate_set_make_backup(make_backup);
389✔
788

789
error:
389✔
790
    free(tpmstatedir);
389✔
791
    free(tpmbackend_uri);
389✔
792
    free(temp_uri);
389✔
793

794
    return ret;
389✔
795
}
796

797
/*
798
 * unixio_open_socket: Open a UnixIO socket and return file descriptor
799
 *
800
 * @path: UnixIO socket path
801
 * @perm: UnixIO socket permissions
802
 * @uid: uid to set the ownership of the UnixIO socket path to
803
 * @gid: gid to set the ownership of the UnixIO socket path to
804
 */
805
static int unixio_open_socket(const char *path, mode_t perm,
205✔
806
                              uid_t uid, gid_t gid)
807
{
808
    struct sockaddr_un su;
205✔
809
    int fd = -1, n;
205✔
810
    size_t len;
205✔
811

812
    su.sun_family = AF_UNIX;
205✔
813
    len = sizeof(su.sun_path);
205✔
814
    n = snprintf(su.sun_path, len, "%s", path);
205✔
815
    if (n < 0) {
205✔
UNCOV
816
        logprintf(STDERR_FILENO, "Could not nsprintf path to UnixIO socket\n");
×
UNCOV
817
        return -1;
×
818
    }
819
    if (n >= (int)len) {
205✔
UNCOV
820
        logprintf(STDERR_FILENO, "Path for UnioIO socket is too long\n");
×
UNCOV
821
        return -1;
×
822
    }
823

824
    unlink(su.sun_path);
205✔
825

826
    fd = socket(AF_UNIX, SOCK_STREAM, 0);
205✔
827
    if (fd < 0) {
205✔
UNCOV
828
        logprintf(STDERR_FILENO, "Could not open UnixIO socket\n");
×
UNCOV
829
        return -1;
×
830
    }
831

832
    len = strlen(su.sun_path) + sizeof(su.sun_family) + 1;
205✔
833
    n = bind(fd, (struct sockaddr *)&su, len);
205✔
834
    if (n < 0) {
205✔
835
        logprintf(STDERR_FILENO, "Could not open UnixIO socket: %s\n",
×
UNCOV
836
                  strerror(errno));
×
UNCOV
837
        goto error;
×
838
    }
839

840
    if (chmod(su.sun_path, perm) < 0) {
205✔
841
        logprintf(STDERR_FILENO,
×
842
                  "Could not change permissions on UnixIO socket: %s\n",
843
                  strerror(errno));
×
UNCOV
844
        goto error;
×
845
    }
846

847
    if ((uid != (uid_t)-1 || gid != (gid_t)-1) &&
206✔
848
        chown(su.sun_path, uid, gid) < 0) {
1✔
849
        logprintf(STDERR_FILENO,
×
850
                  "Could not change ownership of UnixIO socket to "
UNCOV
851
                  "%u:%u %s\n", uid, gid, strerror(errno));
×
UNCOV
852
        goto error;
×
853
    }
854

855
    n = listen(fd, 1);
205✔
856
    if (n < 0) {
205✔
857
        logprintf(STDERR_FILENO, "Cannot listen on UnixIO socket: %s\n",
×
858
                  strerror(errno));
×
UNCOV
859
        goto error;
×
860
    }
861

862
    return fd;
863

864
error:
×
865
    close(fd);
×
866

UNCOV
867
    return -1;
×
868
}
869

870
/*
871
 * tcp_open_socket: Open a TCP port and return the file descriptor
872
 *
873
 * @port: port number
874
 * @bindadddr: the address to bind the socket to
875
 */
876
static int tcp_open_socket(unsigned short port, const char *bindaddr,
341✔
877
                           const char *ifname)
878
{
879
    int fd = -1, n, af, opt;
341✔
880
    struct sockaddr_in si;
341✔
881
    struct sockaddr_in6 si6;
341✔
882
    struct sockaddr *sa;
341✔
883
    socklen_t sa_len;
341✔
884
    void *dst;
341✔
885

886
    if (index(bindaddr, ':')) {
341✔
887
        af = AF_INET6;
1✔
888

889
        memset(&si6, 0, sizeof(si6));
1✔
890
        si6.sin6_family = af;
1✔
891
        si6.sin6_port = htons(port);
1✔
892

893
        dst = &si6.sin6_addr.s6_addr;
1✔
894
        sa = (struct sockaddr *)&si6;
1✔
895
        sa_len = sizeof(si6);
1✔
896
    } else {
897
        af = AF_INET;
340✔
898

899
        si.sin_family = af;
340✔
900
        si.sin_port = htons(port);
340✔
901
        memset(&si.sin_zero, 0, sizeof(si.sin_zero));
340✔
902

903
        dst = &si.sin_addr.s_addr;
340✔
904
        sa = (struct sockaddr *)&si;
340✔
905
        sa_len = sizeof(si);
340✔
906
    }
907

908
    n = inet_pton(af, bindaddr, dst);
341✔
909
    if (n <= 0) {
341✔
UNCOV
910
        logprintf(STDERR_FILENO, "Could not parse the bind address '%s'\n",
×
911
                  bindaddr);
UNCOV
912
        return -1;
×
913
    }
914

915
    if (af == AF_INET6) {
341✔
916
        if (IN6_IS_ADDR_LINKLOCAL(&si6.sin6_addr)) {
1✔
UNCOV
917
            if (!ifname) {
×
918
                logprintf(STDERR_FILENO,
×
919
                          "Missing interface name for link local address\n");
UNCOV
920
                return -1;
×
921
            }
UNCOV
922
            n = if_nametoindex(ifname);
×
923
            if (!n) {
×
924
                logprintf(STDERR_FILENO,
×
925
                          "Could not convert interface name '%s' to "
926
                          "index: %s\n",
UNCOV
927
                          ifname, strerror(errno));
×
928
                return -1;
×
929
            }
930
            si6.sin6_scope_id = n;
×
931
        }
932
    }
933

934
    fd = socket(af, SOCK_STREAM, 0);
341✔
935
    if (fd < 0) {
341✔
936
        logprintf(STDERR_FILENO, "Could not open TCP socket\n");
×
UNCOV
937
        return -1;
×
938
    }
939

940
    opt = 1;
341✔
941
    n = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
341✔
942
    if (n < 0) {
341✔
943
        logprintf(STDERR_FILENO,
×
944
                  "Could not set socket option SO_REUSEADDR: %s\n",
UNCOV
945
                  strerror(errno));
×
UNCOV
946
        goto error;
×
947
    }
948

949
    n = bind(fd, sa, sa_len);
341✔
950
    if (n < 0) {
341✔
951
        logprintf(STDERR_FILENO, "Could not open TCP socket: %s\n",
×
952
                  strerror(errno));
×
UNCOV
953
        goto error;
×
954
    }
955

956
    n = listen(fd, 1);
341✔
957
    if (n < 0) {
341✔
958
        logprintf(STDERR_FILENO, "Cannot listen on TCP socket: %s\n",
×
959
                  strerror(errno));
×
UNCOV
960
        goto error;
×
961
    }
962

963
    return fd;
964

965
error:
×
966
    close(fd);
×
967

UNCOV
968
    return -1;
×
969
}
970

971
/*
972
 * parse_ctrlchannel_options:
973
 * Parse the 'ctrl' (control channel) options.
974
 *
975
 * @options: the control channel options to parse
976
 * @cc: pointer for pointer to allocated ctrlchannel struct
977
 * @mainloop_flags: pointer to mainloop flags to add a flag to
978
 *
979
 * Returns 0 on success, -1 on failure.
980
 */
981
static int parse_ctrlchannel_options(const char *options,
416✔
982
                                     struct ctrlchannel **cc,
983
                                     uint32_t *mainloop_flags)
984
{
985
    OptionValues *ovs = NULL;
416✔
986
    char *error = NULL;
416✔
987
    const char *type, *path, *bindaddr, *ifname;
416✔
988
    int fd, clientfd, port;
416✔
989
    struct stat stat;
416✔
990
    mode_t mode;
416✔
991
    uid_t uid;
416✔
992
    gid_t gid;
416✔
993

994
    ovs = options_parse(options, ctrl_opt_desc, &error);
416✔
995
    if (!ovs) {
416✔
UNCOV
996
        logprintf(STDERR_FILENO, "Error parsing ctrl options: %s\n", error);
×
UNCOV
997
        goto error;
×
998
    }
999

1000
    type = option_get_string(ovs, "type", NULL);
416✔
1001
    if (!type) {
416✔
1002
        logprintf(STDERR_FILENO,
×
1003
                  "Missing type parameter for control channel\n");
UNCOV
1004
        goto error;
×
1005
    }
1006

1007
    if (!strcmp(type, "unixio")) {
416✔
1008
        path = option_get_string(ovs, "path", NULL);
285✔
1009
        fd = option_get_int(ovs, "fd", -1);
285✔
1010
        clientfd = option_get_int(ovs, "clientfd", -1);
285✔
1011
        mode = option_get_mode_t(ovs, "mode", 0770);
285✔
1012
        uid = option_get_uid_t(ovs, "uid", -1);
285✔
1013
        gid = option_get_gid_t(ovs, "gid", -1);
285✔
1014
        if (fd >= 0) {
285✔
UNCOV
1015
            if (fstat(fd, &stat) < 0 || !S_ISSOCK(stat.st_mode)) {
×
UNCOV
1016
               logprintf(STDERR_FILENO,
×
1017
                         "Bad filedescriptor %d for UnixIO control channel\n",
1018
                         fd);
UNCOV
1019
               goto error;
×
1020
            }
1021

1022
            *cc = ctrlchannel_new(fd, false, NULL);
×
1023
        } else if (clientfd >= 0) {
285✔
1024
            if (fstat(clientfd, &stat) < 0 || !S_ISSOCK(stat.st_mode)) {
142✔
1025
               logprintf(STDERR_FILENO,
×
1026
                         "Bad filedescriptor %d for UnixIO client control"
1027
                         " channel\n", clientfd);
1028
               goto error;
×
1029
            }
1030

1031
            *cc = ctrlchannel_new(clientfd, true, NULL);
142✔
1032
        } else if (path) {
143✔
1033
            fd = unixio_open_socket(path, mode, uid, gid);
143✔
1034
            if (fd < 0)
143✔
UNCOV
1035
                goto error;
×
1036

1037
            *cc = ctrlchannel_new(fd, false, path);
143✔
1038
        } else {
UNCOV
1039
            logprintf(STDERR_FILENO,
×
1040
                      "Missing path and fd options for UnixIO "
1041
                      "control channel\n");
UNCOV
1042
            goto error;
×
1043
        }
1044
    } else if (!strcmp(type, "tcp")) {
131✔
1045
        port = option_get_int(ovs, "port", -1);
131✔
1046
        fd = option_get_int(ovs, "fd", -1);
131✔
1047
        if (fd >= 0) {
131✔
1048
            if (fstat(fd, &stat) < 0 || !S_ISSOCK(stat.st_mode)) {
×
UNCOV
1049
               logprintf(STDERR_FILENO,
×
1050
                         "Bad filedescriptor %d for TCP control channel\n", fd);
UNCOV
1051
               goto error;
×
1052
            }
1053

1054
            *cc = ctrlchannel_new(fd, false, NULL);
×
1055
        } else if (port >= 0) {
131✔
1056
            if (port >= 0x10000) {
131✔
1057
                logprintf(STDERR_FILENO,
×
1058
                          "TCP control channel port outside valid range\n");
UNCOV
1059
                goto error;
×
1060
            }
1061

1062
            bindaddr = option_get_string(ovs, "bindaddr", "127.0.0.1");
131✔
1063
            ifname = option_get_string(ovs, "ifname", NULL);
131✔
1064

1065
            fd = tcp_open_socket(port, bindaddr, ifname);
131✔
1066
            if (fd < 0)
131✔
UNCOV
1067
                goto error;
×
1068

1069
            *cc = ctrlchannel_new(fd, false, NULL);
131✔
1070
        } else {
UNCOV
1071
            logprintf(STDERR_FILENO,
×
1072
                      "Missing port and fd options for TCP control channel\n");
1073
            goto error;
×
1074
        }
1075
    } else {
UNCOV
1076
        logprintf(STDERR_FILENO, "Unsupported control channel type: %s\n", type);
×
1077
        goto error;
×
1078
    }
1079

1080
    if (*cc == NULL)
416✔
UNCOV
1081
        goto error;
×
1082

1083
    if (option_get_bool(ovs, "terminate", false))
416✔
1084
        *mainloop_flags |= MAIN_LOOP_FLAG_CTRL_END_ON_HUP;
4✔
1085

1086
    option_values_free(ovs);
416✔
1087

1088
    return 0;
416✔
1089

UNCOV
1090
error:
×
UNCOV
1091
    free(error);
×
UNCOV
1092
    option_values_free(ovs);
×
1093

UNCOV
1094
    return -1;
×
1095
}
1096

1097
/*
1098
 * handle_ctrlchannel_options:
1099
 * Parse and act upon the parsed 'ctrl' (control channel) options.
1100
 *
1101
 * @options: the control channel options to parse
1102
 * @cc: pointer for pointer to allocated ctrlchannel struct
1103
 * @mainloop_flags: pointer to mainloop flags to add a flag to
1104
 *
1105
 * Returns 0 on success, -1 on failure.
1106
 */
1107
int handle_ctrlchannel_options(const char *options, struct ctrlchannel **cc,
597✔
1108
                               uint32_t *mainloop_flag)
1109
{
1110
    if (!options)
597✔
1111
        return 0;
1112

1113
    if (parse_ctrlchannel_options(options, cc, mainloop_flag) < 0)
416✔
UNCOV
1114
        return -1;
×
1115

1116
    return 0;
1117
}
1118

1119
/*
1120
 * parse_server_options:
1121
 * Parse the 'server' options.
1122
 *
1123
 * @options: the server options to parse
1124
 *
1125
 * Returns 0 on success, -1 on failure.
1126
 */
1127
static int parse_server_options(const char *options, struct server **c)
413✔
1128
{
1129
    OptionValues *ovs = NULL;
413✔
1130
    char *error = NULL;
413✔
1131
    const char *bindaddr, *ifname;
413✔
1132
    const char *type, *path;
413✔
1133
    int fd, port;
413✔
1134
    struct stat stat;
413✔
1135
    unsigned int flags = 0;
413✔
1136
    mode_t mode;
413✔
1137
    uid_t uid;
413✔
1138
    gid_t gid;
413✔
1139

1140
    *c = NULL;
413✔
1141

1142
    ovs = options_parse(options, server_opt_desc, &error);
413✔
1143
    if (!ovs) {
413✔
UNCOV
1144
        logprintf(STDERR_FILENO, "Error parsing server options: %s\n", error);
×
UNCOV
1145
        goto error;
×
1146
    }
1147

1148
    type = option_get_string(ovs, "type", "tcp");
413✔
1149

1150
    if (option_get_bool(ovs, "disconnect", false))
413✔
1151
        flags |= SERVER_FLAG_DISCONNECT;
181✔
1152

1153
    if (!strcmp(type, "unixio")) {
413✔
1154
        path = option_get_string(ovs, "path", NULL);
62✔
1155
        fd = option_get_int(ovs, "fd", -1);
62✔
1156
        mode = option_get_mode_t(ovs, "mode", 0770);
62✔
1157
        uid = option_get_uid_t(ovs, "uid", -1);
62✔
1158
        gid = option_get_gid_t(ovs, "gid", -1);
62✔
1159
        if (fd >= 0) {
62✔
UNCOV
1160
            if (fstat(fd, &stat) < 0 || !S_ISSOCK(stat.st_mode)) {
×
UNCOV
1161
               logprintf(STDERR_FILENO,
×
1162
                         "Bad filedescriptor %d for UnixIO control channel\n",
1163
                         fd);
UNCOV
1164
               goto error;
×
1165
            }
1166

1167
            *c = server_new(fd, flags, NULL);
×
1168
        } else if (path) {
62✔
1169
            fd = unixio_open_socket(path, mode, uid, gid);
62✔
1170
            if (fd < 0)
62✔
UNCOV
1171
                goto error;
×
1172

1173
            *c = server_new(fd, flags, path);
62✔
1174
        } else {
UNCOV
1175
            logprintf(STDERR_FILENO,
×
1176
                      "Missing path and file descriptor option for UnixIO "
1177
                      "socket\n");
UNCOV
1178
            goto error;
×
1179
        }
1180
    } else if (!strcmp(type, "tcp")) {
351✔
1181
        fd = option_get_int(ovs, "fd", -1);
351✔
1182
        if (fd >= 0) {
351✔
1183
            if (fstat(fd, &stat) < 0 || !S_ISSOCK(stat.st_mode)) {
141✔
1184
               logprintf(STDERR_FILENO,
×
1185
                         "Bad filedescriptor %d for TCP socket\n", fd);
UNCOV
1186
               goto error;
×
1187
            }
1188

1189
            flags |= SERVER_FLAG_FD_GIVEN;
141✔
1190

1191
            *c = server_new(fd, flags, NULL);
141✔
1192
        } else {
1193
            port = option_get_int(ovs, "port", -1);
210✔
1194
            if (port == -1) {
210✔
1195
                const char *port_str = getenv("TPM_PORT");
3✔
1196
                if (!port_str || sscanf(port_str, "%d", &port) == -1)
3✔
UNCOV
1197
                    port = -1;
×
1198
            }
1199
            if (port < 0) {
210✔
UNCOV
1200
                logprintf(STDERR_FILENO,
×
1201
                      "No valid port number provided for TCP socket.\n");
UNCOV
1202
                goto error;
×
1203
            }
1204
            if (port >= 0x10000) {
210✔
UNCOV
1205
                logprintf(STDERR_FILENO,
×
1206
                          "TCP socket port outside valid range\n");
UNCOV
1207
                goto error;
×
1208
            }
1209

1210
            bindaddr = option_get_string(ovs, "bindaddr", "127.0.0.1");
210✔
1211
            ifname = option_get_string(ovs, "ifname", NULL);
210✔
1212

1213
            fd = tcp_open_socket(port, bindaddr, ifname);
210✔
1214
            if (fd < 0)
210✔
UNCOV
1215
                goto error;
×
1216

1217
            *c = server_new(fd, flags, NULL);
210✔
1218
        }
1219
    } else {
UNCOV
1220
        logprintf(STDERR_FILENO, "Unsupported socket type: %s\n", type);
×
1221
        goto error;
×
1222
    }
1223

1224
    if (*c == NULL)
413✔
UNCOV
1225
        goto error;
×
1226

1227
    option_values_free(ovs);
413✔
1228

1229
    return 0;
413✔
1230

1231
error:
×
UNCOV
1232
    if (*c) {
×
UNCOV
1233
        server_free(*c);
×
UNCOV
1234
        *c = NULL;
×
1235
    }
UNCOV
1236
    option_values_free(ovs);
×
1237
    free(error);
×
1238

1239
    return -1;
×
1240
}
1241

1242
/*
1243
 * handle_server_options:
1244
 * Parse and act upon the parsed 'server' options.
1245
 *
1246
 * @options: the server options to parse
1247
 *
1248
 * Returns 0 on success, -1 on failure.
1249
 */
1250
int handle_server_options(const char *options, struct server **c)
594✔
1251
{
1252
    if (!options)
594✔
1253
        return 0;
1254

1255
    if (parse_server_options(options, c) < 0)
413✔
UNCOV
1256
        return -1;
×
1257

1258
    return 0;
1259
}
1260

1261
static int parse_locality_options(const char *options, uint32_t *flags)
1262
{
UNCOV
1263
    OptionValues *ovs = NULL;
×
UNCOV
1264
    char *error = NULL;
×
1265

UNCOV
1266
    ovs = options_parse(options, locality_opt_desc, &error);
×
UNCOV
1267
    if (!ovs) {
×
UNCOV
1268
        logprintf(STDERR_FILENO, "Error parsing locality options: %s\n", error);
×
1269
        goto error;
×
1270
    }
1271

1272
    if (option_get_bool(ovs, "reject-locality-4", false))
×
1273
        *flags |= LOCALITY_FLAG_REJECT_LOCALITY_4;
×
1274
    if (option_get_bool(ovs, "allow-set-locality", false))
×
1275
        *flags |= LOCALITY_FLAG_ALLOW_SETLOCALITY;
×
1276

UNCOV
1277
    option_values_free(ovs);
×
1278

1279
    return 0;
×
1280

1281
error:
×
UNCOV
1282
    option_values_free(ovs);
×
1283
    free(error);
×
1284

1285
    return -1;
×
1286
}
1287

1288
/*
1289
 * handle_locality_options:
1290
 * Parse the 'locality' options.
1291
 *
1292
 * @options: the locality options to parse
1293
 *
1294
 * Returns 0 on success, -1 on failure.
1295
 */
1296
int handle_locality_options(const char *options, uint32_t *flags)
561✔
1297
{
1298
    *flags = 0;
561✔
1299

1300
    if (!options)
561✔
1301
        return 0;
1302

UNCOV
1303
    if (parse_locality_options(options, flags) < 0)
×
UNCOV
1304
        return -1;
×
1305

1306
    return 0;
1307
}
1308

1309
static int parse_flags_options(const char *options, bool *need_init_cmd,
228✔
1310
                               uint16_t *startupType, bool *disable_auto_shutdown)
1311
{
1312
    OptionValues *ovs = NULL;
228✔
1313
    char *error = NULL;
228✔
1314

1315
    ovs = options_parse(options, flags_opt_desc, &error);
228✔
1316
    if (!ovs) {
228✔
UNCOV
1317
        logprintf(STDERR_FILENO, "Error parsing flags options: %s\n", error);
×
UNCOV
1318
        goto error;
×
1319
    }
1320

1321
    if (option_get_bool(ovs, "not-need-init", false))
228✔
1322
        *need_init_cmd = false;
227✔
1323
    if (option_get_bool(ovs, "disable-auto-shutdown", false))
228✔
1324
        *disable_auto_shutdown = true;
1✔
1325

1326
    if (option_get_bool(ovs, "startup-clear", false))
228✔
1327
        *startupType = TPM_ST_CLEAR;
209✔
1328
    else if (option_get_bool(ovs, "startup-state", false))
19✔
UNCOV
1329
        *startupType = TPM_ST_STATE;
×
1330
    else if (option_get_bool(ovs, "startup-deactivated", false))
19✔
UNCOV
1331
        *startupType = TPM_ST_DEACTIVATED;
×
1332
    else if (option_get_bool(ovs, "startup-none", false))
19✔
UNCOV
1333
        *startupType = _TPM_ST_NONE;
×
1334

1335
    if (*startupType != _TPM_ST_NONE)
228✔
1336
        *need_init_cmd = false;
209✔
1337

1338
    option_values_free(ovs);
228✔
1339

1340
    return 0;
228✔
1341

UNCOV
1342
error:
×
UNCOV
1343
    option_values_free(ovs);
×
UNCOV
1344
    free(error);
×
1345

UNCOV
1346
    return -1;
×
1347
}
1348

1349
/*
1350
 * handle_flags_options:
1351
 * Parse the 'flags' options.
1352
 *
1353
 * @options: the flags options to parse
1354
 *
1355
 * Returns 0 on success, -1 on failure.
1356
 */
1357
int handle_flags_options(const char *options, bool *need_init_cmd,
558✔
1358
                         uint16_t *startupType, bool *disable_auto_shutdown)
1359
{
1360
    if (!options)
558✔
1361
        return 0;
1362

1363
    if (parse_flags_options(options, need_init_cmd, startupType,
228✔
1364
                            disable_auto_shutdown) < 0)
UNCOV
1365
        return -1;
×
1366

1367
    return 0;
1368
}
1369

1370
#ifdef WITH_SECCOMP
1371
static int parse_seccomp_options(const char *options, unsigned int *seccomp_action)
10✔
1372
{
1373
    OptionValues *ovs = NULL;
10✔
1374
    char *error = NULL;
10✔
1375
    const char *action;
10✔
1376

1377
    ovs = options_parse(options, seccomp_opt_desc, &error);
10✔
1378
    if (!ovs) {
10✔
UNCOV
1379
        logprintf(STDERR_FILENO, "Error parsing seccomp options: %s\n", error);
×
UNCOV
1380
        goto error;
×
1381
    }
1382

1383
    action = option_get_string(ovs, "action", "kill");
10✔
1384
    if (!strcmp(action, "kill")) {
10✔
1385
        *seccomp_action = SWTPM_SECCOMP_ACTION_KILL;
×
1386
#ifdef SCMP_ACT_LOG
1387
    } else if (!strcmp(action, "log")) {
10✔
UNCOV
1388
        *seccomp_action = SWTPM_SECCOMP_ACTION_LOG;
×
1389
#endif
1390
    } else if (!strcmp(action, "none")) {
10✔
1391
        *seccomp_action = SWTPM_SECCOMP_ACTION_NONE;
10✔
1392
    } else {
UNCOV
1393
        logprintf(STDERR_FILENO,
×
1394
                  "Unsupported seccomp log action %s\n", action);
UNCOV
1395
        goto error;
×
1396
    }
1397

1398
    option_values_free(ovs);
10✔
1399

1400
    return 0;
10✔
1401

UNCOV
1402
error:
×
UNCOV
1403
    option_values_free(ovs);
×
UNCOV
1404
    free(error);
×
1405

UNCOV
1406
    return -1;
×
1407
}
1408

1409
/*
1410
 * handle_seccomp_options:
1411
 * Parse the 'seccomp' options.
1412
 *
1413
 * @options: the flags options to parse
1414
 * @seccomp_action: the action to take when 
1415
 *
1416
 * Returns 0 on success, -1 on failure.
1417
 */
1418
int handle_seccomp_options(const char *options, unsigned int *seccomp_action)
558✔
1419
{
1420
    *seccomp_action = SWTPM_SECCOMP_ACTION_KILL;
558✔
1421

1422
    if (!options)
558✔
1423
        return 0;
1424

1425
    if (parse_seccomp_options(options, seccomp_action) < 0)
10✔
UNCOV
1426
        return -1;
×
1427

1428
    return 0;
1429
}
1430
#endif /* WITH_SECCOMP */
1431

1432
static int parse_migration_options(const char *options, bool *incoming_migration,
10✔
1433
                                   bool *release_lock_outgoing)
1434
{
1435
    OptionValues *ovs = NULL;
10✔
1436
    char *error = NULL;
10✔
1437

1438
    ovs = options_parse(options, migration_opt_desc, &error);
10✔
1439
    if (!ovs) {
10✔
UNCOV
1440
        logprintf(STDERR_FILENO, "Error parsing migration options: %s\n", error);
×
UNCOV
1441
        goto error;
×
1442
    }
1443

1444
    *incoming_migration = option_get_bool(ovs, "incoming", false);
10✔
1445
    *release_lock_outgoing = option_get_bool(ovs, "release-lock-outgoing",
10✔
1446
                                             false);
1447

1448
    option_values_free(ovs);
10✔
1449

1450
    return 0;
10✔
1451

UNCOV
1452
error:
×
UNCOV
1453
    option_values_free(ovs);
×
UNCOV
1454
    free(error);
×
1455

UNCOV
1456
    return -1;
×
1457
}
1458

1459
static int parse_profile_options(const char *options, char **json_profile)
106✔
1460
{
1461
    g_autofree gchar *buffer = NULL;
212✔
1462
    const char *remove_disabled;
106✔
1463
    OptionValues *ovs = NULL;
106✔
1464
    gboolean force = false;
106✔
1465
    GError *gerror = NULL;
106✔
1466
    const char *filename;
106✔
1467
    const char *profile;
106✔
1468
    char *error = NULL;
106✔
1469
    int profilefd = -1;
106✔
1470
    gsize buffer_len;
106✔
1471
    const char *name;
106✔
1472

1473
    ovs = options_parse(options, profile_opt_desc, &error);
106✔
1474
    if (!ovs) {
106✔
UNCOV
1475
        logprintf(STDERR_FILENO, "Error parsing profile options: %s\n", error);
×
UNCOV
1476
        goto error;
×
1477
    }
1478

1479
    profile = option_get_string(ovs, "profile", NULL);
106✔
1480
    name = option_get_string(ovs, "name", NULL);
106✔
1481
    filename = option_get_string(ovs, "file", NULL);
106✔
1482
    profilefd = option_get_int(ovs, "fd", -1);
106✔
1483

1484
    if ((profile != NULL) + (name != NULL) + (filename != NULL) > 1 + (profilefd >= 0)) {
181✔
UNCOV
1485
        logprintf(STDERR_FILENO, "Only one profile option parameter of 'profile', 'name', 'fd', or 'file' may be provided\n");
×
UNCOV
1486
        goto error;
×
1487
    }
1488
    if (profile) {
106✔
1489
        *json_profile = strdup(profile);
75✔
1490
        if (!*json_profile)
75✔
1491
            goto oom_error;
×
1492
    } else if (name) {
31✔
UNCOV
1493
        if (asprintf(json_profile, "{\"Name\":\"%s\"}", name) < 0) {
×
UNCOV
1494
            logprintf(STDERR_FILENO, "Out of memory.\n");
×
UNCOV
1495
            goto oom_error;
×
1496
        }
1497
    } else if (filename) {
31✔
UNCOV
1498
        if (!g_file_get_contents(filename, &buffer, &buffer_len, &gerror)) {
×
1499
            logprintf(STDERR_FILENO, "%s\n", gerror->message);
×
1500
            goto error;
×
1501
        }
UNCOV
1502
        *json_profile = strndup(buffer, buffer_len);
×
1503
    } else if (profilefd >= 0) {
31✔
1504
        buffer_len = 10 * 1024;
31✔
1505
        buffer = g_malloc(buffer_len);
31✔
1506
        buffer_len = read_eintr(profilefd, buffer, buffer_len - 1);
31✔
1507
        if ((ssize_t)buffer_len < 0) {
31✔
1508
            logprintf(STDERR_FILENO, "Unable to read profile: %s\n",
×
UNCOV
1509
                      strerror(errno));
×
UNCOV
1510
            goto error;
×
1511
        }
1512
        SWTPM_CLOSE(profilefd);
31✔
1513
        buffer[buffer_len] = 0;
31✔
1514
        *json_profile = g_steal_pointer(&buffer);
31✔
1515
    } else {
1516
        logprintf(STDERR_FILENO,
×
1517
                  "No profile option parameter given to get a profile\n");
UNCOV
1518
        goto error;
×
1519
    }
1520
    /* remove leading and trailing whitespaces */
1521
    g_strstrip(*json_profile);
106✔
1522

1523
    remove_disabled = option_get_string(ovs, "remove-disabled", NULL);
106✔
1524
    if (remove_disabled) {
106✔
1525
        if (!strcmp(remove_disabled, "check")) {
5✔
1526
            force = false;
1527
        } else if (!strcmp(remove_disabled, "fips-host")) {
5✔
1528
            force = true;
1529
        } else {
UNCOV
1530
            logprintf(STDERR_FILENO, "Invalid option parameter '%s' for 'remove-disabled'\n",
×
1531
                      remove_disabled);
UNCOV
1532
            goto error;
×
1533
        }
1534
        if (profile_remove_fips_disabled_algorithms(json_profile, force) == -1)
5✔
UNCOV
1535
            goto error;
×
1536
    }
1537

1538
    option_values_free(ovs);
106✔
1539

1540
    return 0;
106✔
1541

UNCOV
1542
oom_error:
×
UNCOV
1543
    logprintf(STDERR_FILENO,
×
1544
              "Out of memory to create JSON profile\n");
1545

UNCOV
1546
error:
×
UNCOV
1547
    if (profilefd >= 0)
×
1548
        close(profilefd);
×
1549
    if (gerror)
×
UNCOV
1550
        g_error_free(gerror);
×
UNCOV
1551
    SWTPM_G_FREE(*json_profile);
×
1552
    option_values_free(ovs);
×
1553
    free(error);
×
1554

1555
    return -1;
×
1556
}
1557

1558
/*
1559
 * handle_migration_options:
1560
 * Parse the 'migration' options.
1561
 *
1562
 * @options: the migration options to parse
1563
 * @incoming_migration: whether there's an incoming migration
1564
 * @release_lock_outgoing: whether to release NVRAM lock on outgoing migration
1565
 *
1566
 * Return 0 on success, -1 on failure.
1567
 */
1568
int handle_migration_options(const char *options, bool *incoming_migration,
558✔
1569
                             bool *release_lock_outgoing)
1570
{
1571
    *incoming_migration = false;
558✔
1572

1573
    if (!options)
558✔
1574
        return 0;
1575

1576
    if (parse_migration_options(options, incoming_migration,
10✔
1577
                                release_lock_outgoing) < 0)
UNCOV
1578
        return -1;
×
1579

1580
    return 0;
1581
}
1582

1583
/*
1584
 * handle_profile_options:
1585
 * Parse the 'profile' options.
1586
 *
1587
 * @options: the porfile options to parse
1588
 * @json_profile: pointer to a buffer for the profile rules to pass to libtpms
1589
 *
1590
 * Returns 0 on success, -1 on failure.
1591
 */
1592
int handle_profile_options(const char *options, char **json_profile)
558✔
1593
{
1594
    *json_profile = NULL;
558✔
1595

1596
    if (!options)
558✔
1597
        return 0;
1598

1599
    if (parse_profile_options(options, json_profile) < 0)
106✔
UNCOV
1600
        return -1;
×
1601

1602
    return 0;
1603
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc