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

stefanberger / swtpm / #2835

27 May 2025 04:25PM UTC coverage: 73.372% (+0.03%) from 73.345%
#2835

push

travis-ci

web-flow
Merge a4758d76c into ec7730c70

13 of 29 new or added lines in 5 files covered. (44.83%)

520 existing lines in 8 files now uncovered.

8156 of 11116 relevant lines covered (73.37%)

13441.59 hits per line

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

61.61
/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
        .name = "fsync",
160
        .type = OPT_TYPE_BOOLEAN,
161
    },
162
    END_OPTION_DESC
163
};
164

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

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

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

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

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

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

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

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

330
    if (!options)
1,162✔
331
        return 0;
332

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

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

370
    option_values_free(ovs);
545✔
371

372
    return 0;
545✔
373

UNCOV
374
error:
×
UNCOV
375
    option_values_free(ovs);
×
376

377
    return -1;
×
378
}
379

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

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

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

425
    tmp = option_get_string(ovs, "format", NULL);
137✔
426
    keyformat = key_format_from_string(tmp ? tmp : "hex");
243✔
427
    if (keyformat == KEY_FORMAT_UNKNOWN)
137✔
UNCOV
428
        goto error;
×
429

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

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

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

473
    if (option_get_bool(ovs, "remove", false)) {
137✔
474
        if (keyfile)
31✔
475
            unlink(keyfile);
21✔
476
        if (pwdfile)
31✔
477
            unlink(pwdfile);
10✔
478
    }
479

480
    ret = 0;
481

482
exit:
137✔
483
    option_values_free(ovs);
137✔
484
    if (keyfile_fd >= 0)
137✔
485
        close(keyfile_fd);
7✔
486
    if (pwdfile_fd >= 0)
137✔
487
        close(pwdfile_fd);
7✔
488

489
    return ret;
137✔
490

UNCOV
491
error:
×
UNCOV
492
    ret = -1;
×
UNCOV
493
    free(error);
×
494

495
    goto exit;
×
496
}
497

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

515
    if (!options)
563✔
516
        return 0;
517

518
    if (parse_key_options(options, key, maxkeylen, &keylen, &encmode) < 0) {
107✔
UNCOV
519
        ret = -1;
×
UNCOV
520
        goto error;
×
521
    }
522

523
    if (SWTPM_NVRAM_Set_FileKey(key, keylen, encmode) != TPM_SUCCESS) {
107✔
UNCOV
524
        ret = -1;
×
UNCOV
525
        goto error;
×
526
    }
527

528
error:
107✔
529
    /* Wipe to ensure we don't leave a key on the stack */
530
    memset(key, 0, maxkeylen);
107✔
531
    return ret;
107✔
532
}
533

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

551
    if (!options)
563✔
552
        return 0;
553

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

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

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

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

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

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

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

617
    option_values_free(ovs);
196✔
618

619
    return 0;
196✔
620

UNCOV
621
error:
×
UNCOV
622
    option_values_free(ovs);
×
UNCOV
623
    if (*pidfilefd >= 0)
×
624
        close(*pidfilefd);
×
625
    free(error);
×
626

627
    return -1;
×
628
}
629

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

645
    if (!options)
563✔
646
        return 0;
647

648
    if (parse_pid_options(options, &pidfile, &pidfilefd) < 0)
196✔
649
        return -1;
650

651
    if (pidfile && pidfile_set(pidfile) < 0)
196✔
652
        ret = -1;
653
    else if (pidfile_set_fd(pidfilefd) < 0)
196✔
UNCOV
654
        ret = -1;
×
655

656
    free(pidfile);
196✔
657

658
    return ret;
196✔
659
}
660

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

688
    ovs = options_parse(options, tpmstate_opt_desc, &error);
394✔
689
    if (!ovs) {
394✔
UNCOV
690
        logprintf(STDERR_FILENO, "Error parsing tpmstate options: %s\n",
×
691
                  error);
UNCOV
692
        goto error;
×
693
    }
694

695
    directory = option_get_string(ovs, "dir", NULL);
394✔
696
    backend_uri = option_get_string(ovs, "backend-uri", NULL);
394✔
697
    *make_backup = option_get_bool(ovs, "backup", false);
394✔
698
    *do_fsync = option_get_bool(ovs, "fsync", false);
394✔
699

700
    /* Did user provide mode bits? User can only provide <= 0777 */
701
    *mode = option_get_mode_t(ovs, "mode", 01000);
394✔
702
    *mode_is_default = (*mode == 01000);
394✔
703
    if (*mode_is_default)
394✔
704
        *mode = 0640;
392✔
705

706
    if (directory) {
394✔
707
        *tpmstatedir = strdup(directory);
104✔
708
        if (!*tpmstatedir) {
104✔
UNCOV
709
            logprintf(STDERR_FILENO, "Out of memory.");
×
UNCOV
710
            goto error;
×
711
        }
712
    } else if (backend_uri) {
290✔
713
        *tpmbackend_uri = strdup(backend_uri);
290✔
714
        if (!*tpmbackend_uri) {
290✔
715
            logprintf(STDERR_FILENO, "Out of memory.");
×
716
            goto error;
×
717
        }
718
        if (strncmp(*tpmbackend_uri, "file://", 7) == 0)
290✔
719
            lock_default = false;
10✔
720
    } else {
721
        logprintf(STDERR_FILENO,
×
722
                  "The dir or backend-uri parameters is required "
723
                  "for the tpmstate option.\n");
UNCOV
724
        goto error;
×
725
    }
726

727
    *do_locking = option_get_bool(ovs, "lock", lock_default);
394✔
728

729
    option_values_free(ovs);
394✔
730

731
    return 0;
394✔
732

UNCOV
733
error:
×
UNCOV
734
    free(error);
×
UNCOV
735
    option_values_free(ovs);
×
736

UNCOV
737
    return -1;
×
738
}
739

740
/*
741
 * handle_tpmstate_options:
742
 * Parse and act upon the parsed 'tpmstate' options.
743
 *
744
 * @options: the tpmstate options to parse
745
 *
746
 * Returns 0 on success, -1 on failure.
747
 */
748
int
749
handle_tpmstate_options(const char *options)
719✔
750
{
751
    char *tpmstatedir = NULL;
719✔
752
    char *tpmbackend_uri = NULL;
719✔
753
    char *temp_uri = NULL;
719✔
754
    int ret = 0;
719✔
755
    mode_t mode;
719✔
756
    bool mode_is_default = true;
719✔
757
    bool do_locking = false;
719✔
758
    bool make_backup = false;
719✔
759
    bool do_fsync = false;
719✔
760

761
    if (!options)
719✔
762
        return 0;
763

764
    if (parse_tpmstate_options(options, &tpmstatedir, &mode,
394✔
765
                               &mode_is_default, &tpmbackend_uri,
766
                               &do_locking, &make_backup, &do_fsync) < 0) {
UNCOV
767
        ret = -1;
×
UNCOV
768
        goto error;
×
769
    }
770

771
    if (tpmstatedir) {
394✔
772
        /* Default tpmstate store dir backend */
773
        if (asprintf(&temp_uri, "dir://%s", tpmstatedir) < 0) {
104✔
774
            logprintf(STDERR_FILENO,
×
775
                      "Could not asprintf TPM backend uri\n");
UNCOV
776
            ret = -1;
×
UNCOV
777
            temp_uri = NULL;
×
UNCOV
778
            goto error;
×
779
        }
780

781
        if (tpmstate_set_backend_uri(temp_uri) < 0) {
104✔
UNCOV
782
            ret = -1;
×
783
            goto error;
×
784
        }
785
    } else {
786
        if (tpmstate_set_backend_uri(tpmbackend_uri) < 0) {
290✔
UNCOV
787
            ret = -1;
×
UNCOV
788
            goto error;
×
789
        }
790
    }
791

792
    tpmstate_set_mode(mode, mode_is_default);
394✔
793
    tpmstate_set_locking(do_locking);
394✔
794
    tpmstate_set_make_backup(make_backup);
394✔
795
    tpmstate_set_do_fsync(do_fsync);
394✔
796

797
error:
394✔
798
    free(tpmstatedir);
394✔
799
    free(tpmbackend_uri);
394✔
800
    free(temp_uri);
394✔
801

802
    return ret;
394✔
803
}
804

805
/*
806
 * unixio_open_socket: Open a UnixIO socket and return file descriptor
807
 *
808
 * @path: UnixIO socket path
809
 * @perm: UnixIO socket permissions
810
 * @uid: uid to set the ownership of the UnixIO socket path to
811
 * @gid: gid to set the ownership of the UnixIO socket path to
812
 */
813
static int unixio_open_socket(const char *path, mode_t perm,
205✔
814
                              uid_t uid, gid_t gid)
815
{
816
    struct sockaddr_un su;
205✔
817
    int fd = -1, n;
205✔
818
    size_t len;
205✔
819

820
    su.sun_family = AF_UNIX;
205✔
821
    len = sizeof(su.sun_path);
205✔
822
    n = snprintf(su.sun_path, len, "%s", path);
205✔
823
    if (n < 0) {
205✔
UNCOV
824
        logprintf(STDERR_FILENO, "Could not nsprintf path to UnixIO socket\n");
×
UNCOV
825
        return -1;
×
826
    }
827
    if (n >= (int)len) {
205✔
UNCOV
828
        logprintf(STDERR_FILENO, "Path for UnioIO socket is too long\n");
×
UNCOV
829
        return -1;
×
830
    }
831

832
    unlink(su.sun_path);
205✔
833

834
    fd = socket(AF_UNIX, SOCK_STREAM, 0);
205✔
835
    if (fd < 0) {
205✔
836
        logprintf(STDERR_FILENO, "Could not open UnixIO socket\n");
×
837
        return -1;
×
838
    }
839

840
    len = strlen(su.sun_path) + sizeof(su.sun_family) + 1;
205✔
841
    n = bind(fd, (struct sockaddr *)&su, len);
205✔
842
    if (n < 0) {
205✔
UNCOV
843
        logprintf(STDERR_FILENO, "Could not open UnixIO socket: %s\n",
×
844
                  strerror(errno));
×
845
        goto error;
×
846
    }
847

848
    if (chmod(su.sun_path, perm) < 0) {
205✔
UNCOV
849
        logprintf(STDERR_FILENO,
×
850
                  "Could not change permissions on UnixIO socket: %s\n",
851
                  strerror(errno));
×
852
        goto error;
×
853
    }
854

855
    if ((uid != (uid_t)-1 || gid != (gid_t)-1) &&
206✔
856
        chown(su.sun_path, uid, gid) < 0) {
1✔
857
        logprintf(STDERR_FILENO,
×
858
                  "Could not change ownership of UnixIO socket to "
859
                  "%u:%u %s\n", uid, gid, strerror(errno));
×
860
        goto error;
×
861
    }
862

863
    n = listen(fd, 1);
205✔
864
    if (n < 0) {
205✔
865
        logprintf(STDERR_FILENO, "Cannot listen on UnixIO socket: %s\n",
×
UNCOV
866
                  strerror(errno));
×
867
        goto error;
×
868
    }
869

870
    return fd;
871

UNCOV
872
error:
×
873
    close(fd);
×
874

875
    return -1;
×
876
}
877

878
/*
879
 * tcp_open_socket: Open a TCP port and return the file descriptor
880
 *
881
 * @port: port number
882
 * @bindadddr: the address to bind the socket to
883
 */
884
static int tcp_open_socket(unsigned short port, const char *bindaddr,
347✔
885
                           const char *ifname)
886
{
887
    int fd = -1, n, af, opt;
347✔
888
    struct sockaddr_in si;
347✔
889
    struct sockaddr_in6 si6;
347✔
890
    struct sockaddr *sa;
347✔
891
    socklen_t sa_len;
347✔
892
    void *dst;
347✔
893

894
    if (index(bindaddr, ':')) {
347✔
895
        af = AF_INET6;
1✔
896

897
        memset(&si6, 0, sizeof(si6));
1✔
898
        si6.sin6_family = af;
1✔
899
        si6.sin6_port = htons(port);
1✔
900

901
        dst = &si6.sin6_addr.s6_addr;
1✔
902
        sa = (struct sockaddr *)&si6;
1✔
903
        sa_len = sizeof(si6);
1✔
904
    } else {
905
        af = AF_INET;
346✔
906

907
        si.sin_family = af;
346✔
908
        si.sin_port = htons(port);
346✔
909
        memset(&si.sin_zero, 0, sizeof(si.sin_zero));
346✔
910

911
        dst = &si.sin_addr.s_addr;
346✔
912
        sa = (struct sockaddr *)&si;
346✔
913
        sa_len = sizeof(si);
346✔
914
    }
915

916
    n = inet_pton(af, bindaddr, dst);
347✔
917
    if (n <= 0) {
347✔
UNCOV
918
        logprintf(STDERR_FILENO, "Could not parse the bind address '%s'\n",
×
919
                  bindaddr);
UNCOV
920
        return -1;
×
921
    }
922

923
    if (af == AF_INET6) {
347✔
924
        if (IN6_IS_ADDR_LINKLOCAL(&si6.sin6_addr)) {
1✔
UNCOV
925
            if (!ifname) {
×
926
                logprintf(STDERR_FILENO,
×
927
                          "Missing interface name for link local address\n");
928
                return -1;
×
929
            }
UNCOV
930
            n = if_nametoindex(ifname);
×
UNCOV
931
            if (!n) {
×
UNCOV
932
                logprintf(STDERR_FILENO,
×
933
                          "Could not convert interface name '%s' to "
934
                          "index: %s\n",
UNCOV
935
                          ifname, strerror(errno));
×
936
                return -1;
×
937
            }
938
            si6.sin6_scope_id = n;
×
939
        }
940
    }
941

942
    fd = socket(af, SOCK_STREAM, 0);
347✔
943
    if (fd < 0) {
347✔
944
        logprintf(STDERR_FILENO, "Could not open TCP socket\n");
×
UNCOV
945
        return -1;
×
946
    }
947

948
    opt = 1;
347✔
949
    n = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
347✔
950
    if (n < 0) {
347✔
UNCOV
951
        logprintf(STDERR_FILENO,
×
952
                  "Could not set socket option SO_REUSEADDR: %s\n",
953
                  strerror(errno));
×
UNCOV
954
        goto error;
×
955
    }
956

957
    n = bind(fd, sa, sa_len);
347✔
958
    if (n < 0) {
347✔
959
        logprintf(STDERR_FILENO, "Could not open TCP socket: %s\n",
×
UNCOV
960
                  strerror(errno));
×
961
        goto error;
×
962
    }
963

964
    n = listen(fd, 1);
347✔
965
    if (n < 0) {
347✔
UNCOV
966
        logprintf(STDERR_FILENO, "Cannot listen on TCP socket: %s\n",
×
967
                  strerror(errno));
×
968
        goto error;
×
969
    }
970

971
    return fd;
972

UNCOV
973
error:
×
974
    close(fd);
×
975

976
    return -1;
×
977
}
978

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

1002
    ovs = options_parse(options, ctrl_opt_desc, &error);
420✔
1003
    if (!ovs) {
420✔
UNCOV
1004
        logprintf(STDERR_FILENO, "Error parsing ctrl options: %s\n", error);
×
UNCOV
1005
        goto error;
×
1006
    }
1007

1008
    type = option_get_string(ovs, "type", NULL);
420✔
1009
    if (!type) {
420✔
UNCOV
1010
        logprintf(STDERR_FILENO,
×
1011
                  "Missing type parameter for control channel\n");
1012
        goto error;
×
1013
    }
1014

1015
    if (!strcmp(type, "unixio")) {
420✔
1016
        path = option_get_string(ovs, "path", NULL);
286✔
1017
        fd = option_get_int(ovs, "fd", -1);
286✔
1018
        clientfd = option_get_int(ovs, "clientfd", -1);
286✔
1019
        mode = option_get_mode_t(ovs, "mode", 0770);
286✔
1020
        uid = option_get_uid_t(ovs, "uid", -1);
286✔
1021
        gid = option_get_gid_t(ovs, "gid", -1);
286✔
1022
        if (fd >= 0) {
286✔
UNCOV
1023
            if (fstat(fd, &stat) < 0 || !S_ISSOCK(stat.st_mode)) {
×
UNCOV
1024
               logprintf(STDERR_FILENO,
×
1025
                         "Bad filedescriptor %d for UnixIO control channel\n",
1026
                         fd);
UNCOV
1027
               goto error;
×
1028
            }
1029

UNCOV
1030
            *cc = ctrlchannel_new(fd, false, NULL);
×
1031
        } else if (clientfd >= 0) {
286✔
1032
            if (fstat(clientfd, &stat) < 0 || !S_ISSOCK(stat.st_mode)) {
143✔
UNCOV
1033
               logprintf(STDERR_FILENO,
×
1034
                         "Bad filedescriptor %d for UnixIO client control"
1035
                         " channel\n", clientfd);
UNCOV
1036
               goto error;
×
1037
            }
1038

1039
            *cc = ctrlchannel_new(clientfd, true, NULL);
143✔
1040
        } else if (path) {
143✔
1041
            fd = unixio_open_socket(path, mode, uid, gid);
143✔
1042
            if (fd < 0)
143✔
UNCOV
1043
                goto error;
×
1044

1045
            *cc = ctrlchannel_new(fd, false, path);
143✔
1046
        } else {
UNCOV
1047
            logprintf(STDERR_FILENO,
×
1048
                      "Missing path and fd options for UnixIO "
1049
                      "control channel\n");
UNCOV
1050
            goto error;
×
1051
        }
1052
    } else if (!strcmp(type, "tcp")) {
134✔
1053
        port = option_get_int(ovs, "port", -1);
134✔
1054
        fd = option_get_int(ovs, "fd", -1);
134✔
1055
        if (fd >= 0) {
134✔
UNCOV
1056
            if (fstat(fd, &stat) < 0 || !S_ISSOCK(stat.st_mode)) {
×
UNCOV
1057
               logprintf(STDERR_FILENO,
×
1058
                         "Bad filedescriptor %d for TCP control channel\n", fd);
UNCOV
1059
               goto error;
×
1060
            }
1061

UNCOV
1062
            *cc = ctrlchannel_new(fd, false, NULL);
×
1063
        } else if (port >= 0) {
134✔
1064
            if (port >= 0x10000) {
134✔
1065
                logprintf(STDERR_FILENO,
×
1066
                          "TCP control channel port outside valid range\n");
1067
                goto error;
×
1068
            }
1069

1070
            bindaddr = option_get_string(ovs, "bindaddr", "127.0.0.1");
134✔
1071
            ifname = option_get_string(ovs, "ifname", NULL);
134✔
1072

1073
            fd = tcp_open_socket(port, bindaddr, ifname);
134✔
1074
            if (fd < 0)
134✔
1075
                goto error;
×
1076

1077
            *cc = ctrlchannel_new(fd, false, NULL);
134✔
1078
        } else {
UNCOV
1079
            logprintf(STDERR_FILENO,
×
1080
                      "Missing port and fd options for TCP control channel\n");
UNCOV
1081
            goto error;
×
1082
        }
1083
    } else {
UNCOV
1084
        logprintf(STDERR_FILENO, "Unsupported control channel type: %s\n", type);
×
UNCOV
1085
        goto error;
×
1086
    }
1087

1088
    if (*cc == NULL)
420✔
1089
        goto error;
×
1090

1091
    if (option_get_bool(ovs, "terminate", false))
420✔
1092
        *mainloop_flags |= MAIN_LOOP_FLAG_CTRL_END_ON_HUP;
4✔
1093

1094
    option_values_free(ovs);
420✔
1095

1096
    return 0;
420✔
1097

UNCOV
1098
error:
×
UNCOV
1099
    free(error);
×
UNCOV
1100
    option_values_free(ovs);
×
1101

UNCOV
1102
    return -1;
×
1103
}
1104

1105
/*
1106
 * handle_ctrlchannel_options:
1107
 * Parse and act upon the parsed 'ctrl' (control channel) options.
1108
 *
1109
 * @options: the control channel options to parse
1110
 * @cc: pointer for pointer to allocated ctrlchannel struct
1111
 * @mainloop_flags: pointer to mainloop flags to add a flag to
1112
 *
1113
 * Returns 0 on success, -1 on failure.
1114
 */
1115
int handle_ctrlchannel_options(const char *options, struct ctrlchannel **cc,
603✔
1116
                               uint32_t *mainloop_flag)
1117
{
1118
    if (!options)
603✔
1119
        return 0;
1120

1121
    if (parse_ctrlchannel_options(options, cc, mainloop_flag) < 0)
420✔
UNCOV
1122
        return -1;
×
1123

1124
    return 0;
1125
}
1126

1127
/*
1128
 * parse_server_options:
1129
 * Parse the 'server' options.
1130
 *
1131
 * @options: the server options to parse
1132
 *
1133
 * Returns 0 on success, -1 on failure.
1134
 */
1135
static int parse_server_options(const char *options, struct server **c)
417✔
1136
{
1137
    OptionValues *ovs = NULL;
417✔
1138
    char *error = NULL;
417✔
1139
    const char *bindaddr, *ifname;
417✔
1140
    const char *type, *path;
417✔
1141
    int fd, port;
417✔
1142
    struct stat stat;
417✔
1143
    unsigned int flags = 0;
417✔
1144
    mode_t mode;
417✔
1145
    uid_t uid;
417✔
1146
    gid_t gid;
417✔
1147

1148
    *c = NULL;
417✔
1149

1150
    ovs = options_parse(options, server_opt_desc, &error);
417✔
1151
    if (!ovs) {
417✔
UNCOV
1152
        logprintf(STDERR_FILENO, "Error parsing server options: %s\n", error);
×
UNCOV
1153
        goto error;
×
1154
    }
1155

1156
    type = option_get_string(ovs, "type", "tcp");
417✔
1157

1158
    if (option_get_bool(ovs, "disconnect", false))
417✔
1159
        flags |= SERVER_FLAG_DISCONNECT;
183✔
1160

1161
    if (!strcmp(type, "unixio")) {
417✔
1162
        path = option_get_string(ovs, "path", NULL);
62✔
1163
        fd = option_get_int(ovs, "fd", -1);
62✔
1164
        mode = option_get_mode_t(ovs, "mode", 0770);
62✔
1165
        uid = option_get_uid_t(ovs, "uid", -1);
62✔
1166
        gid = option_get_gid_t(ovs, "gid", -1);
62✔
1167
        if (fd >= 0) {
62✔
UNCOV
1168
            if (fstat(fd, &stat) < 0 || !S_ISSOCK(stat.st_mode)) {
×
UNCOV
1169
               logprintf(STDERR_FILENO,
×
1170
                         "Bad filedescriptor %d for UnixIO control channel\n",
1171
                         fd);
UNCOV
1172
               goto error;
×
1173
            }
1174

UNCOV
1175
            *c = server_new(fd, flags, NULL);
×
1176
        } else if (path) {
62✔
1177
            fd = unixio_open_socket(path, mode, uid, gid);
62✔
1178
            if (fd < 0)
62✔
UNCOV
1179
                goto error;
×
1180

1181
            *c = server_new(fd, flags, path);
62✔
1182
        } else {
1183
            logprintf(STDERR_FILENO,
×
1184
                      "Missing path and file descriptor option for UnixIO "
1185
                      "socket\n");
UNCOV
1186
            goto error;
×
1187
        }
1188
    } else if (!strcmp(type, "tcp")) {
355✔
1189
        fd = option_get_int(ovs, "fd", -1);
355✔
1190
        if (fd >= 0) {
355✔
1191
            if (fstat(fd, &stat) < 0 || !S_ISSOCK(stat.st_mode)) {
142✔
UNCOV
1192
               logprintf(STDERR_FILENO,
×
1193
                         "Bad filedescriptor %d for TCP socket\n", fd);
1194
               goto error;
×
1195
            }
1196

1197
            flags |= SERVER_FLAG_FD_GIVEN;
142✔
1198

1199
            *c = server_new(fd, flags, NULL);
142✔
1200
        } else {
1201
            port = option_get_int(ovs, "port", -1);
213✔
1202
            if (port == -1) {
213✔
1203
                const char *port_str = getenv("TPM_PORT");
3✔
1204
                if (!port_str || sscanf(port_str, "%d", &port) == -1)
3✔
UNCOV
1205
                    port = -1;
×
1206
            }
1207
            if (port < 0) {
213✔
UNCOV
1208
                logprintf(STDERR_FILENO,
×
1209
                      "No valid port number provided for TCP socket.\n");
UNCOV
1210
                goto error;
×
1211
            }
1212
            if (port >= 0x10000) {
213✔
1213
                logprintf(STDERR_FILENO,
×
1214
                          "TCP socket port outside valid range\n");
UNCOV
1215
                goto error;
×
1216
            }
1217

1218
            bindaddr = option_get_string(ovs, "bindaddr", "127.0.0.1");
213✔
1219
            ifname = option_get_string(ovs, "ifname", NULL);
213✔
1220

1221
            fd = tcp_open_socket(port, bindaddr, ifname);
213✔
1222
            if (fd < 0)
213✔
1223
                goto error;
×
1224

1225
            *c = server_new(fd, flags, NULL);
213✔
1226
        }
1227
    } else {
UNCOV
1228
        logprintf(STDERR_FILENO, "Unsupported socket type: %s\n", type);
×
UNCOV
1229
        goto error;
×
1230
    }
1231

1232
    if (*c == NULL)
417✔
UNCOV
1233
        goto error;
×
1234

1235
    option_values_free(ovs);
417✔
1236

1237
    return 0;
417✔
1238

UNCOV
1239
error:
×
UNCOV
1240
    if (*c) {
×
1241
        server_free(*c);
×
UNCOV
1242
        *c = NULL;
×
1243
    }
UNCOV
1244
    option_values_free(ovs);
×
UNCOV
1245
    free(error);
×
1246

1247
    return -1;
×
1248
}
1249

1250
/*
1251
 * handle_server_options:
1252
 * Parse and act upon the parsed 'server' options.
1253
 *
1254
 * @options: the server options to parse
1255
 *
1256
 * Returns 0 on success, -1 on failure.
1257
 */
1258
int handle_server_options(const char *options, struct server **c)
600✔
1259
{
1260
    if (!options)
600✔
1261
        return 0;
1262

1263
    if (parse_server_options(options, c) < 0)
417✔
UNCOV
1264
        return -1;
×
1265

1266
    return 0;
1267
}
1268

1269
static int parse_locality_options(const char *options, uint32_t *flags)
1270
{
UNCOV
1271
    OptionValues *ovs = NULL;
×
1272
    char *error = NULL;
×
1273

UNCOV
1274
    ovs = options_parse(options, locality_opt_desc, &error);
×
UNCOV
1275
    if (!ovs) {
×
UNCOV
1276
        logprintf(STDERR_FILENO, "Error parsing locality options: %s\n", error);
×
UNCOV
1277
        goto error;
×
1278
    }
1279

1280
    if (option_get_bool(ovs, "reject-locality-4", false))
×
UNCOV
1281
        *flags |= LOCALITY_FLAG_REJECT_LOCALITY_4;
×
1282
    if (option_get_bool(ovs, "allow-set-locality", false))
×
1283
        *flags |= LOCALITY_FLAG_ALLOW_SETLOCALITY;
×
1284

1285
    option_values_free(ovs);
×
1286

UNCOV
1287
    return 0;
×
1288

1289
error:
×
1290
    option_values_free(ovs);
×
1291
    free(error);
×
1292

1293
    return -1;
×
1294
}
1295

1296
/*
1297
 * handle_locality_options:
1298
 * Parse the 'locality' options.
1299
 *
1300
 * @options: the locality options to parse
1301
 *
1302
 * Returns 0 on success, -1 on failure.
1303
 */
1304
int handle_locality_options(const char *options, uint32_t *flags)
566✔
1305
{
1306
    *flags = 0;
566✔
1307

1308
    if (!options)
566✔
1309
        return 0;
1310

UNCOV
1311
    if (parse_locality_options(options, flags) < 0)
×
UNCOV
1312
        return -1;
×
1313

1314
    return 0;
1315
}
1316

1317
static int parse_flags_options(const char *options, bool *need_init_cmd,
231✔
1318
                               uint16_t *startupType, bool *disable_auto_shutdown)
1319
{
1320
    OptionValues *ovs = NULL;
231✔
1321
    char *error = NULL;
231✔
1322

1323
    ovs = options_parse(options, flags_opt_desc, &error);
231✔
1324
    if (!ovs) {
231✔
UNCOV
1325
        logprintf(STDERR_FILENO, "Error parsing flags options: %s\n", error);
×
UNCOV
1326
        goto error;
×
1327
    }
1328

1329
    if (option_get_bool(ovs, "not-need-init", false))
231✔
1330
        *need_init_cmd = false;
230✔
1331
    if (option_get_bool(ovs, "disable-auto-shutdown", false))
231✔
1332
        *disable_auto_shutdown = true;
1✔
1333

1334
    if (option_get_bool(ovs, "startup-clear", false))
231✔
1335
        *startupType = TPM_ST_CLEAR;
211✔
1336
    else if (option_get_bool(ovs, "startup-state", false))
20✔
UNCOV
1337
        *startupType = TPM_ST_STATE;
×
1338
    else if (option_get_bool(ovs, "startup-deactivated", false))
20✔
UNCOV
1339
        *startupType = TPM_ST_DEACTIVATED;
×
1340
    else if (option_get_bool(ovs, "startup-none", false))
20✔
UNCOV
1341
        *startupType = _TPM_ST_NONE;
×
1342

1343
    if (*startupType != _TPM_ST_NONE)
231✔
1344
        *need_init_cmd = false;
211✔
1345

1346
    option_values_free(ovs);
231✔
1347

1348
    return 0;
231✔
1349

UNCOV
1350
error:
×
UNCOV
1351
    option_values_free(ovs);
×
UNCOV
1352
    free(error);
×
1353

UNCOV
1354
    return -1;
×
1355
}
1356

1357
/*
1358
 * handle_flags_options:
1359
 * Parse the 'flags' options.
1360
 *
1361
 * @options: the flags options to parse
1362
 *
1363
 * Returns 0 on success, -1 on failure.
1364
 */
1365
int handle_flags_options(const char *options, bool *need_init_cmd,
563✔
1366
                         uint16_t *startupType, bool *disable_auto_shutdown)
1367
{
1368
    if (!options)
563✔
1369
        return 0;
1370

1371
    if (parse_flags_options(options, need_init_cmd, startupType,
231✔
1372
                            disable_auto_shutdown) < 0)
UNCOV
1373
        return -1;
×
1374

1375
    return 0;
1376
}
1377

1378
#ifdef WITH_SECCOMP
1379
static int parse_seccomp_options(const char *options, unsigned int *seccomp_action)
10✔
1380
{
1381
    OptionValues *ovs = NULL;
10✔
1382
    char *error = NULL;
10✔
1383
    const char *action;
10✔
1384

1385
    ovs = options_parse(options, seccomp_opt_desc, &error);
10✔
1386
    if (!ovs) {
10✔
UNCOV
1387
        logprintf(STDERR_FILENO, "Error parsing seccomp options: %s\n", error);
×
UNCOV
1388
        goto error;
×
1389
    }
1390

1391
    action = option_get_string(ovs, "action", "kill");
10✔
1392
    if (!strcmp(action, "kill")) {
10✔
UNCOV
1393
        *seccomp_action = SWTPM_SECCOMP_ACTION_KILL;
×
1394
#ifdef SCMP_ACT_LOG
1395
    } else if (!strcmp(action, "log")) {
10✔
1396
        *seccomp_action = SWTPM_SECCOMP_ACTION_LOG;
×
1397
#endif
1398
    } else if (!strcmp(action, "none")) {
10✔
1399
        *seccomp_action = SWTPM_SECCOMP_ACTION_NONE;
10✔
1400
    } else {
1401
        logprintf(STDERR_FILENO,
×
1402
                  "Unsupported seccomp log action %s\n", action);
UNCOV
1403
        goto error;
×
1404
    }
1405

1406
    option_values_free(ovs);
10✔
1407

1408
    return 0;
10✔
1409

UNCOV
1410
error:
×
1411
    option_values_free(ovs);
×
UNCOV
1412
    free(error);
×
1413

UNCOV
1414
    return -1;
×
1415
}
1416

1417
/*
1418
 * handle_seccomp_options:
1419
 * Parse the 'seccomp' options.
1420
 *
1421
 * @options: the flags options to parse
1422
 * @seccomp_action: the action to take when 
1423
 *
1424
 * Returns 0 on success, -1 on failure.
1425
 */
1426
int handle_seccomp_options(const char *options, unsigned int *seccomp_action)
563✔
1427
{
1428
    *seccomp_action = SWTPM_SECCOMP_ACTION_KILL;
563✔
1429

1430
    if (!options)
563✔
1431
        return 0;
1432

1433
    if (parse_seccomp_options(options, seccomp_action) < 0)
10✔
UNCOV
1434
        return -1;
×
1435

1436
    return 0;
1437
}
1438
#endif /* WITH_SECCOMP */
1439

1440
static int parse_migration_options(const char *options, bool *incoming_migration,
10✔
1441
                                   bool *release_lock_outgoing)
1442
{
1443
    OptionValues *ovs = NULL;
10✔
1444
    char *error = NULL;
10✔
1445

1446
    ovs = options_parse(options, migration_opt_desc, &error);
10✔
1447
    if (!ovs) {
10✔
UNCOV
1448
        logprintf(STDERR_FILENO, "Error parsing migration options: %s\n", error);
×
UNCOV
1449
        goto error;
×
1450
    }
1451

1452
    *incoming_migration = option_get_bool(ovs, "incoming", false);
10✔
1453
    *release_lock_outgoing = option_get_bool(ovs, "release-lock-outgoing",
10✔
1454
                                             false);
1455

1456
    option_values_free(ovs);
10✔
1457

1458
    return 0;
10✔
1459

UNCOV
1460
error:
×
UNCOV
1461
    option_values_free(ovs);
×
UNCOV
1462
    free(error);
×
1463

UNCOV
1464
    return -1;
×
1465
}
1466

1467
static int parse_profile_options(const char *options, char **json_profile)
107✔
1468
{
1469
    g_autofree gchar *buffer = NULL;
214✔
1470
    const char *remove_disabled;
107✔
1471
    OptionValues *ovs = NULL;
107✔
1472
    gboolean force = false;
107✔
1473
    GError *gerror = NULL;
107✔
1474
    const char *filename;
107✔
1475
    const char *profile;
107✔
1476
    char *error = NULL;
107✔
1477
    int profilefd = -1;
107✔
1478
    gsize buffer_len;
107✔
1479
    const char *name;
107✔
1480

1481
    ovs = options_parse(options, profile_opt_desc, &error);
107✔
1482
    if (!ovs) {
107✔
UNCOV
1483
        logprintf(STDERR_FILENO, "Error parsing profile options: %s\n", error);
×
UNCOV
1484
        goto error;
×
1485
    }
1486

1487
    profile = option_get_string(ovs, "profile", NULL);
107✔
1488
    name = option_get_string(ovs, "name", NULL);
107✔
1489
    filename = option_get_string(ovs, "file", NULL);
107✔
1490
    profilefd = option_get_int(ovs, "fd", -1);
107✔
1491

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

1531
    remove_disabled = option_get_string(ovs, "remove-disabled", NULL);
107✔
1532
    if (remove_disabled) {
107✔
1533
        if (!strcmp(remove_disabled, "check")) {
5✔
1534
            force = false;
1535
        } else if (!strcmp(remove_disabled, "fips-host")) {
5✔
1536
            force = true;
1537
        } else {
UNCOV
1538
            logprintf(STDERR_FILENO, "Invalid option parameter '%s' for 'remove-disabled'\n",
×
1539
                      remove_disabled);
UNCOV
1540
            goto error;
×
1541
        }
1542
        if (profile_remove_fips_disabled_algorithms(json_profile, force) == -1)
5✔
UNCOV
1543
            goto error;
×
1544
    }
1545

1546
    option_values_free(ovs);
107✔
1547

1548
    return 0;
107✔
1549

UNCOV
1550
oom_error:
×
1551
    logprintf(STDERR_FILENO,
×
1552
              "Out of memory to create JSON profile\n");
1553

UNCOV
1554
error:
×
UNCOV
1555
    if (profilefd >= 0)
×
UNCOV
1556
        close(profilefd);
×
UNCOV
1557
    if (gerror)
×
1558
        g_error_free(gerror);
×
1559
    SWTPM_G_FREE(*json_profile);
×
UNCOV
1560
    option_values_free(ovs);
×
UNCOV
1561
    free(error);
×
1562

1563
    return -1;
×
1564
}
1565

1566
/*
1567
 * handle_migration_options:
1568
 * Parse the 'migration' options.
1569
 *
1570
 * @options: the migration options to parse
1571
 * @incoming_migration: whether there's an incoming migration
1572
 * @release_lock_outgoing: whether to release NVRAM lock on outgoing migration
1573
 *
1574
 * Return 0 on success, -1 on failure.
1575
 */
1576
int handle_migration_options(const char *options, bool *incoming_migration,
563✔
1577
                             bool *release_lock_outgoing)
1578
{
1579
    *incoming_migration = false;
563✔
1580

1581
    if (!options)
563✔
1582
        return 0;
1583

1584
    if (parse_migration_options(options, incoming_migration,
10✔
1585
                                release_lock_outgoing) < 0)
UNCOV
1586
        return -1;
×
1587

1588
    return 0;
1589
}
1590

1591
/*
1592
 * handle_profile_options:
1593
 * Parse the 'profile' options.
1594
 *
1595
 * @options: the porfile options to parse
1596
 * @json_profile: pointer to a buffer for the profile rules to pass to libtpms
1597
 *
1598
 * Returns 0 on success, -1 on failure.
1599
 */
1600
int handle_profile_options(const char *options, char **json_profile)
563✔
1601
{
1602
    *json_profile = NULL;
563✔
1603

1604
    if (!options)
563✔
1605
        return 0;
1606

1607
    if (parse_profile_options(options, json_profile) < 0)
107✔
UNCOV
1608
        return -1;
×
1609

1610
    return 0;
1611
}
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