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

stefanberger / swtpm / #2787

16 Apr 2025 08:30PM UTC coverage: 73.27% (-0.2%) from 73.428%
#2787

push

travis-ci

web-flow
Merge 2415eca70 into 8ad31a72a

8059 of 10999 relevant lines covered (73.27%)

13563.41 hits per line

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

61.27
/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
    END_OPTION_DESC
157
};
158

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

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

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

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

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

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

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

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

324
    if (!options)
1,149✔
325
        return 0;
326

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

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

364
    option_values_free(ovs);
534✔
365

366
    return 0;
534✔
367

368
error:
×
369
    option_values_free(ovs);
×
370

371
    return -1;
×
372
}
373

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

402
    ovs = options_parse(options, key_opt_desc, &error);
135✔
403
    if (!ovs) {
135✔
404
        logprintf(STDERR_FILENO, "Error parsing key options: %s\n",
×
405
                  error);
406
        goto error;
×
407
    }
408

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

419
    tmp = option_get_string(ovs, "format", NULL);
135✔
420
    keyformat = key_format_from_string(tmp ? tmp : "hex");
240✔
421
    if (keyformat == KEY_FORMAT_UNKNOWN)
135✔
422
        goto error;
×
423

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

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

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

467
    if (option_get_bool(ovs, "remove", false)) {
135✔
468
        if (keyfile)
29✔
469
            unlink(keyfile);
20✔
470
        if (pwdfile)
29✔
471
            unlink(pwdfile);
9✔
472
    }
473

474
    ret = 0;
475

476
exit:
135✔
477
    option_values_free(ovs);
135✔
478
    if (keyfile_fd >= 0)
135✔
479
        close(keyfile_fd);
7✔
480
    if (pwdfile_fd >= 0)
135✔
481
        close(pwdfile_fd);
7✔
482

483
    return ret;
135✔
484

485
error:
×
486
    ret = -1;
×
487
    free(error);
×
488

489
    goto exit;
×
490
}
491

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

509
    if (!options)
554✔
510
        return 0;
511

512
    if (parse_key_options(options, key, maxkeylen, &keylen, &encmode) < 0) {
106✔
513
        ret = -1;
×
514
        goto error;
×
515
    }
516

517
    if (SWTPM_NVRAM_Set_FileKey(key, keylen, encmode) != TPM_SUCCESS) {
106✔
518
        ret = -1;
×
519
        goto error;
×
520
    }
521

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

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

545
    if (!options)
554✔
546
        return 0;
547

548
    if (parse_key_options(options, key, maxkeylen, &keylen, &encmode) < 0) {
29✔
549
        ret = -1;
×
550
        goto error;
×
551
    }
552

553
    if (SWTPM_NVRAM_Set_MigrationKey(key, keylen, encmode) != TPM_SUCCESS) {
29✔
554
        ret = -1;
×
555
        goto error;
×
556
    }
557

558
error:
29✔
559
    /* Wipe to ensure we don't leave a key on the stack */
560
    memset(key, 0, maxkeylen);
29✔
561
    return ret;
29✔
562
}
563

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

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

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

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

611
    option_values_free(ovs);
195✔
612

613
    return 0;
195✔
614

615
error:
×
616
    option_values_free(ovs);
×
617
    if (*pidfilefd >= 0)
×
618
        close(*pidfilefd);
×
619
    free(error);
×
620

621
    return -1;
×
622
}
623

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

639
    if (!options)
554✔
640
        return 0;
641

642
    if (parse_pid_options(options, &pidfile, &pidfilefd) < 0)
195✔
643
        return -1;
644

645
    if (pidfile && pidfile_set(pidfile) < 0)
195✔
646
        ret = -1;
647
    else if (pidfile_set_fd(pidfilefd) < 0)
195✔
648
        ret = -1;
×
649

650
    free(pidfile);
195✔
651

652
    return ret;
195✔
653
}
654

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

680
    ovs = options_parse(options, tpmstate_opt_desc, &error);
381✔
681
    if (!ovs) {
381✔
682
        logprintf(STDERR_FILENO, "Error parsing tpmstate options: %s\n",
×
683
                  error);
684
        goto error;
×
685
    }
686

687
    directory = option_get_string(ovs, "dir", NULL);
381✔
688
    backend_uri = option_get_string(ovs, "backend-uri", NULL);
381✔
689

690
    /* Did user provide mode bits? User can only provide <= 0777 */
691
    *mode = option_get_mode_t(ovs, "mode", 01000);
381✔
692
    *mode_is_default = (*mode == 01000);
381✔
693
    if (*mode_is_default)
381✔
694
        *mode = 0640;
379✔
695

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

717
    *do_locking = option_get_bool(ovs, "lock", lock_default);
381✔
718

719
    option_values_free(ovs);
381✔
720

721
    return 0;
381✔
722

723
error:
×
724
    free(error);
×
725
    option_values_free(ovs);
×
726

727
    return -1;
×
728
}
729

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

749
    if (!options)
709✔
750
        return 0;
751

752
    if (parse_tpmstate_options(options, &tpmstatedir, &mode,
381✔
753
                               &mode_is_default, &tpmbackend_uri,
754
                               &do_locking) < 0) {
755
        ret = -1;
×
756
        goto error;
×
757
    }
758

759
    if (tpmstatedir) {
381✔
760
        /* Default tpmstate store dir backend */
761
        if (asprintf(&temp_uri, "dir://%s", tpmstatedir) < 0) {
93✔
762
            logprintf(STDERR_FILENO,
×
763
                      "Could not asprintf TPM backend uri\n");
764
            ret = -1;
×
765
            temp_uri = NULL;
×
766
            goto error;
×
767
        }
768

769
        if (tpmstate_set_backend_uri(temp_uri) < 0) {
93✔
770
            ret = -1;
×
771
            goto error;
×
772
        }
773
    } else {
774
        if (tpmstate_set_backend_uri(tpmbackend_uri) < 0) {
288✔
775
            ret = -1;
×
776
            goto error;
×
777
        }
778
    }
779

780
    tpmstate_set_mode(mode, mode_is_default);
381✔
781
    tpmstate_set_locking(do_locking);
381✔
782

783
error:
381✔
784
    free(tpmstatedir);
381✔
785
    free(tpmbackend_uri);
381✔
786
    free(temp_uri);
381✔
787

788
    return ret;
381✔
789
}
790

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

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

818
    unlink(su.sun_path);
205✔
819

820
    fd = socket(AF_UNIX, SOCK_STREAM, 0);
205✔
821
    if (fd < 0) {
205✔
822
        logprintf(STDERR_FILENO, "Could not open UnixIO socket\n");
×
823
        return -1;
×
824
    }
825

826
    len = strlen(su.sun_path) + sizeof(su.sun_family) + 1;
205✔
827
    n = bind(fd, (struct sockaddr *)&su, len);
205✔
828
    if (n < 0) {
205✔
829
        logprintf(STDERR_FILENO, "Could not open UnixIO socket: %s\n",
×
830
                  strerror(errno));
×
831
        goto error;
×
832
    }
833

834
    if (chmod(su.sun_path, perm) < 0) {
205✔
835
        logprintf(STDERR_FILENO,
×
836
                  "Could not change permissions on UnixIO socket: %s\n",
837
                  strerror(errno));
×
838
        goto error;
×
839
    }
840

841
    if ((uid != (uid_t)-1 || gid != (gid_t)-1) &&
206✔
842
        chown(su.sun_path, uid, gid) < 0) {
1✔
843
        logprintf(STDERR_FILENO,
×
844
                  "Could not change ownership of UnixIO socket to "
845
                  "%u:%u %s\n", uid, gid, strerror(errno));
×
846
        goto error;
×
847
    }
848

849
    n = listen(fd, 1);
205✔
850
    if (n < 0) {
205✔
851
        logprintf(STDERR_FILENO, "Cannot listen on UnixIO socket: %s\n",
×
852
                  strerror(errno));
×
853
        goto error;
×
854
    }
855

856
    return fd;
857

858
error:
×
859
    close(fd);
×
860

861
    return -1;
×
862
}
863

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

880
    if (index(bindaddr, ':')) {
335✔
881
        af = AF_INET6;
1✔
882

883
        memset(&si6, 0, sizeof(si6));
1✔
884
        si6.sin6_family = af;
1✔
885
        si6.sin6_port = htons(port);
1✔
886

887
        dst = &si6.sin6_addr.s6_addr;
1✔
888
        sa = (struct sockaddr *)&si6;
1✔
889
        sa_len = sizeof(si6);
1✔
890
    } else {
891
        af = AF_INET;
334✔
892

893
        si.sin_family = af;
334✔
894
        si.sin_port = htons(port);
334✔
895
        memset(&si.sin_zero, 0, sizeof(si.sin_zero));
334✔
896

897
        dst = &si.sin_addr.s_addr;
334✔
898
        sa = (struct sockaddr *)&si;
334✔
899
        sa_len = sizeof(si);
334✔
900
    }
901

902
    n = inet_pton(af, bindaddr, dst);
335✔
903
    if (n <= 0) {
335✔
904
        logprintf(STDERR_FILENO, "Could not parse the bind address '%s'\n",
×
905
                  bindaddr);
906
        return -1;
×
907
    }
908

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

928
    fd = socket(af, SOCK_STREAM, 0);
335✔
929
    if (fd < 0) {
335✔
930
        logprintf(STDERR_FILENO, "Could not open TCP socket\n");
×
931
        return -1;
×
932
    }
933

934
    opt = 1;
335✔
935
    n = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
335✔
936
    if (n < 0) {
335✔
937
        logprintf(STDERR_FILENO,
×
938
                  "Could not set socket option SO_REUSEADDR: %s\n",
939
                  strerror(errno));
×
940
        goto error;
×
941
    }
942

943
    n = bind(fd, sa, sa_len);
335✔
944
    if (n < 0) {
335✔
945
        logprintf(STDERR_FILENO, "Could not open TCP socket: %s\n",
×
946
                  strerror(errno));
×
947
        goto error;
×
948
    }
949

950
    n = listen(fd, 1);
335✔
951
    if (n < 0) {
335✔
952
        logprintf(STDERR_FILENO, "Cannot listen on TCP socket: %s\n",
×
953
                  strerror(errno));
×
954
        goto error;
×
955
    }
956

957
    return fd;
958

959
error:
×
960
    close(fd);
×
961

962
    return -1;
×
963
}
964

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

988
    ovs = options_parse(options, ctrl_opt_desc, &error);
413✔
989
    if (!ovs) {
413✔
990
        logprintf(STDERR_FILENO, "Error parsing ctrl options: %s\n", error);
×
991
        goto error;
×
992
    }
993

994
    type = option_get_string(ovs, "type", NULL);
413✔
995
    if (!type) {
413✔
996
        logprintf(STDERR_FILENO,
×
997
                  "Missing type parameter for control channel\n");
998
        goto error;
×
999
    }
1000

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

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

1025
            *cc = ctrlchannel_new(clientfd, true, NULL);
142✔
1026
        } else if (path) {
143✔
1027
            fd = unixio_open_socket(path, mode, uid, gid);
143✔
1028
            if (fd < 0)
143✔
1029
                goto error;
×
1030

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

1048
            *cc = ctrlchannel_new(fd, false, NULL);
×
1049
        } else if (port >= 0) {
128✔
1050
            if (port >= 0x10000) {
128✔
1051
                logprintf(STDERR_FILENO,
×
1052
                          "TCP control channel port outside valid range\n");
1053
                goto error;
×
1054
            }
1055

1056
            bindaddr = option_get_string(ovs, "bindaddr", "127.0.0.1");
128✔
1057
            ifname = option_get_string(ovs, "ifname", NULL);
128✔
1058

1059
            fd = tcp_open_socket(port, bindaddr, ifname);
128✔
1060
            if (fd < 0)
128✔
1061
                goto error;
×
1062

1063
            *cc = ctrlchannel_new(fd, false, NULL);
128✔
1064
        } else {
1065
            logprintf(STDERR_FILENO,
×
1066
                      "Missing port and fd options for TCP control channel\n");
1067
            goto error;
×
1068
        }
1069
    } else {
1070
        logprintf(STDERR_FILENO, "Unsupported control channel type: %s\n", type);
×
1071
        goto error;
×
1072
    }
1073

1074
    if (*cc == NULL)
413✔
1075
        goto error;
×
1076

1077
    if (option_get_bool(ovs, "terminate", false))
413✔
1078
        *mainloop_flags |= MAIN_LOOP_FLAG_CTRL_END_ON_HUP;
4✔
1079

1080
    option_values_free(ovs);
413✔
1081

1082
    return 0;
413✔
1083

1084
error:
×
1085
    free(error);
×
1086
    option_values_free(ovs);
×
1087

1088
    return -1;
×
1089
}
1090

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

1107
    if (parse_ctrlchannel_options(options, cc, mainloop_flag) < 0)
413✔
1108
        return -1;
×
1109

1110
    return 0;
1111
}
1112

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

1134
    *c = NULL;
410✔
1135

1136
    ovs = options_parse(options, server_opt_desc, &error);
410✔
1137
    if (!ovs) {
410✔
1138
        logprintf(STDERR_FILENO, "Error parsing server options: %s\n", error);
×
1139
        goto error;
×
1140
    }
1141

1142
    type = option_get_string(ovs, "type", "tcp");
410✔
1143

1144
    if (option_get_bool(ovs, "disconnect", false))
410✔
1145
        flags |= SERVER_FLAG_DISCONNECT;
181✔
1146

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

1161
            *c = server_new(fd, flags, NULL);
×
1162
        } else if (path) {
62✔
1163
            fd = unixio_open_socket(path, mode, uid, gid);
62✔
1164
            if (fd < 0)
62✔
1165
                goto error;
×
1166

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

1183
            flags |= SERVER_FLAG_FD_GIVEN;
141✔
1184

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

1204
            bindaddr = option_get_string(ovs, "bindaddr", "127.0.0.1");
207✔
1205
            ifname = option_get_string(ovs, "ifname", NULL);
207✔
1206

1207
            fd = tcp_open_socket(port, bindaddr, ifname);
207✔
1208
            if (fd < 0)
207✔
1209
                goto error;
×
1210

1211
            *c = server_new(fd, flags, NULL);
207✔
1212
        }
1213
    } else {
1214
        logprintf(STDERR_FILENO, "Unsupported socket type: %s\n", type);
×
1215
        goto error;
×
1216
    }
1217

1218
    if (*c == NULL)
410✔
1219
        goto error;
×
1220

1221
    option_values_free(ovs);
410✔
1222

1223
    return 0;
410✔
1224

1225
error:
×
1226
    if (*c) {
×
1227
        server_free(*c);
×
1228
        *c = NULL;
×
1229
    }
1230
    option_values_free(ovs);
×
1231
    free(error);
×
1232

1233
    return -1;
×
1234
}
1235

1236
/*
1237
 * handle_server_options:
1238
 * Parse and act upon the parsed 'server' options.
1239
 *
1240
 * @options: the server options to parse
1241
 *
1242
 * Returns 0 on success, -1 on failure.
1243
 */
1244
int handle_server_options(const char *options, struct server **c)
591✔
1245
{
1246
    if (!options)
591✔
1247
        return 0;
1248

1249
    if (parse_server_options(options, c) < 0)
410✔
1250
        return -1;
×
1251

1252
    return 0;
1253
}
1254

1255
static int parse_locality_options(const char *options, uint32_t *flags)
1256
{
1257
    OptionValues *ovs = NULL;
×
1258
    char *error = NULL;
×
1259

1260
    ovs = options_parse(options, locality_opt_desc, &error);
×
1261
    if (!ovs) {
×
1262
        logprintf(STDERR_FILENO, "Error parsing locality options: %s\n", error);
×
1263
        goto error;
×
1264
    }
1265

1266
    if (option_get_bool(ovs, "reject-locality-4", false))
×
1267
        *flags |= LOCALITY_FLAG_REJECT_LOCALITY_4;
×
1268
    if (option_get_bool(ovs, "allow-set-locality", false))
×
1269
        *flags |= LOCALITY_FLAG_ALLOW_SETLOCALITY;
×
1270

1271
    option_values_free(ovs);
×
1272

1273
    return 0;
×
1274

1275
error:
×
1276
    option_values_free(ovs);
×
1277
    free(error);
×
1278

1279
    return -1;
×
1280
}
1281

1282
/*
1283
 * handle_locality_options:
1284
 * Parse the 'locality' options.
1285
 *
1286
 * @options: the locality options to parse
1287
 *
1288
 * Returns 0 on success, -1 on failure.
1289
 */
1290
int handle_locality_options(const char *options, uint32_t *flags)
557✔
1291
{
1292
    *flags = 0;
557✔
1293

1294
    if (!options)
557✔
1295
        return 0;
1296

1297
    if (parse_locality_options(options, flags) < 0)
×
1298
        return -1;
×
1299

1300
    return 0;
1301
}
1302

1303
static int parse_flags_options(const char *options, bool *need_init_cmd,
225✔
1304
                               uint16_t *startupType, bool *disable_auto_shutdown)
1305
{
1306
    OptionValues *ovs = NULL;
225✔
1307
    char *error = NULL;
225✔
1308

1309
    ovs = options_parse(options, flags_opt_desc, &error);
225✔
1310
    if (!ovs) {
225✔
1311
        logprintf(STDERR_FILENO, "Error parsing flags options: %s\n", error);
×
1312
        goto error;
×
1313
    }
1314

1315
    if (option_get_bool(ovs, "not-need-init", false))
225✔
1316
        *need_init_cmd = false;
224✔
1317
    if (option_get_bool(ovs, "disable-auto-shutdown", false))
225✔
1318
        *disable_auto_shutdown = true;
1✔
1319

1320
    if (option_get_bool(ovs, "startup-clear", false))
225✔
1321
        *startupType = TPM_ST_CLEAR;
209✔
1322
    else if (option_get_bool(ovs, "startup-state", false))
16✔
1323
        *startupType = TPM_ST_STATE;
×
1324
    else if (option_get_bool(ovs, "startup-deactivated", false))
16✔
1325
        *startupType = TPM_ST_DEACTIVATED;
×
1326
    else if (option_get_bool(ovs, "startup-none", false))
16✔
1327
        *startupType = _TPM_ST_NONE;
×
1328

1329
    if (*startupType != _TPM_ST_NONE)
225✔
1330
        *need_init_cmd = false;
209✔
1331

1332
    option_values_free(ovs);
225✔
1333

1334
    return 0;
225✔
1335

1336
error:
×
1337
    option_values_free(ovs);
×
1338
    free(error);
×
1339

1340
    return -1;
×
1341
}
1342

1343
/*
1344
 * handle_flags_options:
1345
 * Parse the 'flags' options.
1346
 *
1347
 * @options: the flags options to parse
1348
 *
1349
 * Returns 0 on success, -1 on failure.
1350
 */
1351
int handle_flags_options(const char *options, bool *need_init_cmd,
554✔
1352
                         uint16_t *startupType, bool *disable_auto_shutdown)
1353
{
1354
    if (!options)
554✔
1355
        return 0;
1356

1357
    if (parse_flags_options(options, need_init_cmd, startupType,
225✔
1358
                            disable_auto_shutdown) < 0)
1359
        return -1;
×
1360

1361
    return 0;
1362
}
1363

1364
#ifdef WITH_SECCOMP
1365
static int parse_seccomp_options(const char *options, unsigned int *seccomp_action)
10✔
1366
{
1367
    OptionValues *ovs = NULL;
10✔
1368
    char *error = NULL;
10✔
1369
    const char *action;
10✔
1370

1371
    ovs = options_parse(options, seccomp_opt_desc, &error);
10✔
1372
    if (!ovs) {
10✔
1373
        logprintf(STDERR_FILENO, "Error parsing seccomp options: %s\n", error);
×
1374
        goto error;
×
1375
    }
1376

1377
    action = option_get_string(ovs, "action", "kill");
10✔
1378
    if (!strcmp(action, "kill")) {
10✔
1379
        *seccomp_action = SWTPM_SECCOMP_ACTION_KILL;
×
1380
#ifdef SCMP_ACT_LOG
1381
    } else if (!strcmp(action, "log")) {
10✔
1382
        *seccomp_action = SWTPM_SECCOMP_ACTION_LOG;
×
1383
#endif
1384
    } else if (!strcmp(action, "none")) {
10✔
1385
        *seccomp_action = SWTPM_SECCOMP_ACTION_NONE;
10✔
1386
    } else {
1387
        logprintf(STDERR_FILENO,
×
1388
                  "Unsupported seccomp log action %s\n", action);
1389
        goto error;
×
1390
    }
1391

1392
    option_values_free(ovs);
10✔
1393

1394
    return 0;
10✔
1395

1396
error:
×
1397
    option_values_free(ovs);
×
1398
    free(error);
×
1399

1400
    return -1;
×
1401
}
1402

1403
/*
1404
 * handle_seccomp_options:
1405
 * Parse the 'seccomp' options.
1406
 *
1407
 * @options: the flags options to parse
1408
 * @seccomp_action: the action to take when 
1409
 *
1410
 * Returns 0 on success, -1 on failure.
1411
 */
1412
int handle_seccomp_options(const char *options, unsigned int *seccomp_action)
554✔
1413
{
1414
    *seccomp_action = SWTPM_SECCOMP_ACTION_KILL;
554✔
1415

1416
    if (!options)
554✔
1417
        return 0;
1418

1419
    if (parse_seccomp_options(options, seccomp_action) < 0)
10✔
1420
        return -1;
×
1421

1422
    return 0;
1423
}
1424
#endif /* WITH_SECCOMP */
1425

1426
static int parse_migration_options(const char *options, bool *incoming_migration,
10✔
1427
                                   bool *release_lock_outgoing)
1428
{
1429
    OptionValues *ovs = NULL;
10✔
1430
    char *error = NULL;
10✔
1431

1432
    ovs = options_parse(options, migration_opt_desc, &error);
10✔
1433
    if (!ovs) {
10✔
1434
        logprintf(STDERR_FILENO, "Error parsing migration options: %s\n", error);
×
1435
        goto error;
×
1436
    }
1437

1438
    *incoming_migration = option_get_bool(ovs, "incoming", false);
10✔
1439
    *release_lock_outgoing = option_get_bool(ovs, "release-lock-outgoing",
10✔
1440
                                             false);
1441

1442
    option_values_free(ovs);
10✔
1443

1444
    return 0;
10✔
1445

1446
error:
×
1447
    option_values_free(ovs);
×
1448
    free(error);
×
1449

1450
    return -1;
×
1451
}
1452

1453
static int parse_profile_options(const char *options, char **json_profile)
106✔
1454
{
1455
    g_autofree gchar *buffer = NULL;
212✔
1456
    const char *remove_disabled;
106✔
1457
    OptionValues *ovs = NULL;
106✔
1458
    gboolean force = false;
106✔
1459
    GError *gerror = NULL;
106✔
1460
    const char *filename;
106✔
1461
    const char *profile;
106✔
1462
    char *error = NULL;
106✔
1463
    int profilefd = -1;
106✔
1464
    gsize buffer_len;
106✔
1465
    const char *name;
106✔
1466

1467
    ovs = options_parse(options, profile_opt_desc, &error);
106✔
1468
    if (!ovs) {
106✔
1469
        logprintf(STDERR_FILENO, "Error parsing profile options: %s\n", error);
×
1470
        goto error;
×
1471
    }
1472

1473
    profile = option_get_string(ovs, "profile", NULL);
106✔
1474
    name = option_get_string(ovs, "name", NULL);
106✔
1475
    filename = option_get_string(ovs, "file", NULL);
106✔
1476
    profilefd = option_get_int(ovs, "fd", -1);
106✔
1477

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

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

1532
    option_values_free(ovs);
106✔
1533

1534
    return 0;
106✔
1535

1536
oom_error:
×
1537
    logprintf(STDERR_FILENO,
×
1538
              "Out of memory to create JSON profile\n");
1539

1540
error:
×
1541
    if (profilefd >= 0)
×
1542
        close(profilefd);
×
1543
    if (gerror)
×
1544
        g_error_free(gerror);
×
1545
    SWTPM_G_FREE(*json_profile);
×
1546
    option_values_free(ovs);
×
1547
    free(error);
×
1548

1549
    return -1;
×
1550
}
1551

1552
/*
1553
 * handle_migration_options:
1554
 * Parse the 'migration' options.
1555
 *
1556
 * @options: the migration options to parse
1557
 * @incoming_migration: whether there's an incoming migration
1558
 * @release_lock_outgoing: whether to release NVRAM lock on outgoing migration
1559
 *
1560
 * Return 0 on success, -1 on failure.
1561
 */
1562
int handle_migration_options(const char *options, bool *incoming_migration,
554✔
1563
                             bool *release_lock_outgoing)
1564
{
1565
    *incoming_migration = false;
554✔
1566

1567
    if (!options)
554✔
1568
        return 0;
1569

1570
    if (parse_migration_options(options, incoming_migration,
10✔
1571
                                release_lock_outgoing) < 0)
1572
        return -1;
×
1573

1574
    return 0;
1575
}
1576

1577
/*
1578
 * handle_profile_options:
1579
 * Parse the 'profile' options.
1580
 *
1581
 * @options: the porfile options to parse
1582
 * @json_profile: pointer to a buffer for the profile rules to pass to libtpms
1583
 *
1584
 * Returns 0 on success, -1 on failure.
1585
 */
1586
int handle_profile_options(const char *options, char **json_profile)
554✔
1587
{
1588
    *json_profile = NULL;
554✔
1589

1590
    if (!options)
554✔
1591
        return 0;
1592

1593
    if (parse_profile_options(options, json_profile) < 0)
106✔
1594
        return -1;
×
1595

1596
    return 0;
1597
}
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