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

stefanberger / swtpm / #2780

11 Apr 2025 10:02PM UTC coverage: 73.298% (+0.1%) from 73.203%
#2780

push

travis-ci

web-flow
Merge a4c50fc32 into 738d9e13c

8062 of 10999 relevant lines covered (73.3%)

13564.54 hits per line

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

85.35
/src/utils/swtpm_utils.c
1
/* SPDX-License-Identifier: BSD-3-Clause */
2
/*
3
 * swtpm_setup_utils.c: Utility functions for swtpm_setup et al.
4
 *
5
 * Author: Stefan Berger, stefanb@linux.ibm.com
6
 *
7
 * Copyright (c) IBM Corporation, 2021
8
 */
9

10
#include "config.h"
11

12
#define _GNU_SOURCE
13
#include <sys/types.h>
14
#include <sys/stat.h>
15
#include <errno.h>
16
#include <fcntl.h>
17
#include <stdarg.h>
18
#include <stdio.h>
19
#include <stdlib.h>
20
#include <string.h>
21
#include <unistd.h>
22

23
#include <glib.h>
24
#include <json-glib/json-glib.h>
25

26
#include "swtpm_utils.h"
27

28
void append_to_file(const char *pathname, const char *str)
540✔
29
{
30
    size_t n, len;
540✔
31
    int fd = open(pathname, O_WRONLY|O_APPEND|O_CREAT|O_NOFOLLOW, S_IRUSR|S_IWUSR|S_IRGRP);
540✔
32

33
    if (fd >= 0) {
540✔
34
        len = strlen(str);
540✔
35
        n = write(fd, str, len);
540✔
36
        if (n != len) {
540✔
37
            fprintf(stderr, "Error writing to %s: %s\n", pathname, strerror(errno));
×
38
        }
39
        close(fd);
540✔
40
    } else {
41
        fprintf(stderr, "Error opening file %s: %s\n", pathname, strerror(errno));
×
42
    }
43
}
540✔
44

45
static void alog(FILE *stream, const char *logfile, const char *fmt, va_list ap)
1,209✔
46
{
47
    char *str = NULL;
1,209✔
48
    int n;
1,209✔
49

50
    n = vasprintf(&str, fmt, ap);
1,209✔
51
    if (n < 0)
1,209✔
52
        return;
×
53

54
    if (logfile == NULL)
1,209✔
55
        fprintf(stream, "%s", str);
669✔
56
    else
57
        append_to_file(logfile, str);
540✔
58

59
    free(str);
1,209✔
60
}
61

62
void logit(const char *logfile, const char *fmt, ...)
1,165✔
63
{
64
    va_list ap;
1,165✔
65

66
    va_start(ap, fmt);
1,165✔
67
    alog(stdout, logfile, fmt, ap);
1,165✔
68
    va_end(ap);
1,165✔
69
}
1,165✔
70

71
void logerr(const char *logfile, const char *fmt, ...)
44✔
72
{
73
    va_list ap;
44✔
74

75
    va_start(ap, fmt);
44✔
76
    alog(stderr, logfile, fmt, ap);
44✔
77
    va_end(ap);
44✔
78
}
44✔
79

80
/* Join paths of up to 3 parts into a pre-allocated buffer. The last part is optional */
81
char *pathjoin(char *buffer, size_t bufferlen, const char *p1, const char *p2, const char *p3)
144✔
82
{
83
    char *res = NULL;
144✔
84
    int n = snprintf(buffer, bufferlen, "%s%s%s%s%s",
288✔
85
                     p1,
86
                     G_DIR_SEPARATOR_S,
87
                     p2,
88
                     p3 ? G_DIR_SEPARATOR_S : "",
89
                     p3 ? p3 : "");
90
    if (n < 0) {
144✔
91
        logerr(gl_LOGFILE, "Error: Could not print into buffer.\n");
×
92
    } else if ((size_t)n >= bufferlen) {
144✔
93
        logerr(gl_LOGFILE, "Error: Buffer for path is too small.\n");
×
94
    } else {
95
        res = buffer;
96
    }
97
    return res;
144✔
98
}
99

100
/* Concatenate two NULL-terminated arrays creating one new one;
101
 * This function does not duplicate the memory for the elements.
102
 * Either one of the arrays may be NULL. The first array can be freed.
103
 */
104
const gchar **concat_arrays(const gchar **arr1, const gchar **arr2, gboolean free_arr1)
3,605✔
105
{
106
    size_t n = 0;
3,605✔
107
    const gchar **res;
3,605✔
108
    size_t i;
3,605✔
109

110
    for (i = 0; arr1 != NULL && arr1[i]; i++)
25,778✔
111
        n++;
22,173✔
112
    for (i = 0; arr2 != NULL && arr2[i]; i++)
12,017✔
113
        n++;
8,412✔
114

115
    res = g_malloc0(sizeof(char *) * (n + 1));
3,605✔
116
    for (i = 0, n = 0; arr1 != NULL && arr1[i]; i++)
29,383✔
117
        res[n++] = arr1[i];
22,173✔
118
    for (i = 0; arr2 != NULL && arr2[i]; i++)
12,017✔
119
        res[n++] = arr2[i];
8,412✔
120

121
    if (free_arr1 && arr1)
3,605✔
122
        g_free(arr1);
2,479✔
123

124
    return res;
3,605✔
125
}
126

127
gchar **concat_varrays(gchar **arr1, gchar **arr2, gboolean free_arr1)
1,008✔
128
{
129
    return (gchar **)concat_arrays((const char **)arr1,
1,008✔
130
                                   (const char **)arr2,
131
                                   free_arr1);
132
}
133

134
/* Concatenate buffers into a given buffer of a given length 'buflen' */
135
ssize_t concat(unsigned char *buffer, size_t buflen, ...)
398✔
136
{
137
    va_list ap;
398✔
138
    ssize_t offset = 0;
398✔
139

140
    va_start(ap, buflen);
398✔
141

142
    while (1) {
1,338✔
143
        size_t len;
868✔
144
        unsigned char *i = va_arg(ap, unsigned char *);
868✔
145

146
        if (i == NULL)
868✔
147
            break;
148

149
        len = va_arg(ap, size_t);
470✔
150
        if (offset + len > buflen) {
470✔
151
            offset = -(offset + len);
×
152
            break;
×
153
        }
154

155
        memcpy(&buffer[offset], i, len);
470✔
156
        offset += len;
470✔
157
   }
158
   va_end(ap);
398✔
159

160
   return offset;
398✔
161
}
162

163
/* Concatenate buffers and allocate a new buffer and return its size */
164
ssize_t memconcat(unsigned char **buffer, ...)
958✔
165
{
166
    va_list ap;
958✔
167
    ssize_t offset = 0;
958✔
168
    size_t allocated = 128;
958✔
169
    unsigned char *p;
958✔
170

171
    *buffer = g_malloc(allocated);
958✔
172
    p = *buffer;
958✔
173

174
    va_start(ap, buffer);
958✔
175

176
    while (1) {
8,606✔
177
        size_t len;
4,782✔
178
        unsigned char *i = va_arg(ap, unsigned char *);
4,782✔
179

180
        if (i == NULL)
4,782✔
181
            break;
182

183
        len = va_arg(ap, size_t);
3,824✔
184
        if (offset + len > allocated) {
3,824✔
185
            allocated += offset + len;
88✔
186
            *buffer = g_realloc(*buffer, allocated);
88✔
187
            p = *buffer;
88✔
188
        }
189

190
        memcpy(&p[offset], i, len);
3,824✔
191
        offset += len;
3,824✔
192
   }
193
   va_end(ap);
958✔
194

195
   return offset;
958✔
196
}
197

198
/* Print an input buffer as hex number */
199
gchar *print_as_hex(const unsigned char *input, size_t input_len)
125✔
200
{
201
    gchar *out = g_malloc(input_len * 2 + 1);
125✔
202
    size_t i;
125✔
203

204
    for (i = 0; i < input_len; i++)
17,562✔
205
        g_snprintf(&out[i * 2], 3, "%02x", input[i]);
17,312✔
206

207
    return out;
125✔
208
}
209

210
/* Split a command line and remove all trailing and leading spaces from all entries and remove
211
 * 0-length strings entirely.
212
 */
213
gchar **split_cmdline(const gchar *cmdline) {
156✔
214
    gchar **result = g_strsplit(cmdline, " ", -1);
156✔
215
    size_t i, j;
156✔
216

217
    for (i = 0, j = 0; result[i] != NULL; i++) {
775✔
218
        gchar *chomped = g_strchomp(result[i]);
463✔
219

220
        if (strlen(chomped) == 0) {
463✔
221
            g_free(chomped);
151✔
222
            result[i] = NULL;
151✔
223
        } else {
224
            result[i] = NULL;
312✔
225
            result[j++] = chomped;
312✔
226
        }
227
    }
228
    return result;
156✔
229
}
230

231
/* resolve environment variables in a string */
232
gchar *resolve_string(const gchar *inp) {
296✔
233
    char *pe;
296✔
234
    gchar *result = NULL;
296✔
235
    gchar *new_res, *tmp;
296✔
236
    size_t sidx = 0;
296✔
237
    const gchar *envval;
310✔
238

239
    while (1) {
324✔
240
        gchar *ps = g_strstr_len(&inp[sidx], -1, "${");
310✔
241
        if (ps == NULL) {
310✔
242
            if (sidx == 0) {
296✔
243
                g_free(result); /* coverity */
282✔
244
                return g_strdup(inp);
282✔
245
            }
246
            new_res = g_strconcat(result ? result : "", &inp[sidx], NULL);
14✔
247
            g_free(result);
14✔
248
            return new_res;
14✔
249
        }
250

251
        tmp = g_strndup(&inp[sidx], ps - &inp[sidx]);
14✔
252
        new_res = g_strconcat(result ? result : "", tmp, NULL);
28✔
253
        g_free(tmp);
14✔
254
        g_free(result);
14✔
255
        result = new_res;
14✔
256

257
        pe = g_strstr_len(&ps[2], -1, "}");
14✔
258
        if (pe == NULL) {
14✔
259
            new_res = g_strconcat(result ? result : "", ps, NULL);
×
260
            g_free(result);
×
261
            return new_res;
×
262
        }
263

264
        /* name of environment variable */
265
        tmp = g_strndup(&ps[2], pe - &ps[2]);
14✔
266

267
        envval = g_getenv(tmp);
14✔
268
        new_res = g_strconcat(result ? result : "",
14✔
269
                              envval ? envval : "",
270
                              NULL);
271
        g_free(tmp);
14✔
272
        g_free(result);
14✔
273
        result = new_res;
14✔
274
        sidx = &pe[1] - inp;
14✔
275
    }
276
}
277

278
/* Read an entire file */
279
int read_file(const gchar *filename, gchar **buffer, gsize *buffer_len)
420✔
280
{
281
    GError *error = NULL;
420✔
282

283
    if (!g_file_get_contents(filename, buffer, buffer_len, &error)) {
420✔
284
        logerr(gl_LOGFILE, "%s\n", error->message);
×
285
        g_error_free(error);
×
286
        return 1;
×
287
    }
288
    return 0;
289
}
290

291
/* Read a file and convert its lines into a NULL-termianted array */
292
int read_file_lines(const char *filename, gchar ***config_file_lines)
277✔
293
{
294
    g_autofree gchar *buffer = NULL;
554✔
295
    gsize buffer_len;
277✔
296
    size_t start = 0;
277✔
297
    gchar **array;
277✔
298
    gsize array_len = 1; /* null-terminated array */
277✔
299

300
    if (read_file(filename, &buffer, &buffer_len) != 0)
277✔
301
        return 1;
302

303
    array = g_malloc0(sizeof(char *) * array_len);
277✔
304

305
    while (start < buffer_len) {
1,351✔
306
        size_t off = start;
307

308
        /* search for end-of-string or next newline */
309
        while (off < buffer_len && buffer[off] != '\n')
46,500✔
310
            off++;
45,426✔
311

312
        if (off > start) {
1,074✔
313
            /* non-empty line */
314
            array = g_realloc(array, sizeof(char *) * (array_len + 1));
1,074✔
315
            array[array_len - 1] = g_strndup(&buffer[start], off - start);
1,074✔
316
            array_len++;
1,074✔
317
        }
318
        start = off + 1;
1,074✔
319
    }
320
    array[array_len - 1] = NULL;
277✔
321
    *config_file_lines = array;
277✔
322

323
    return 0;
277✔
324
}
325

326
static ssize_t write_to_fd(int fd, const unsigned char *data, size_t data_len)
63✔
327
{
328
    ssize_t n;
63✔
329

330
    n = write(fd, data, data_len);
63✔
331
    if (n < 0) {
63✔
332
        logerr(gl_LOGFILE, "Could not write to file: %s\n", strerror(errno));
×
333
    } else if ((size_t)n != data_len) {
63✔
334
        logerr(gl_LOGFILE, "Could not write all bytes to the file.\n");
×
335
        n = -1;
×
336
    }
337
    return n;
63✔
338
}
339

340
/* Write to a file with the given name */
341
int write_file(const gchar *filename, const unsigned char *data, size_t data_len)
33✔
342
{
343
    ssize_t n;
33✔
344
    int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC,
33✔
345
                  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH );
346
    if (fd < 0) {
33✔
347
        logerr(gl_LOGFILE, "Could not open file %s for writing: %s\n",
×
348
               filename, strerror(errno));
×
349
        return 1;
×
350
    }
351

352
    n = write_to_fd(fd, data, data_len);
33✔
353
    close(fd);
33✔
354
    if (n < 0)
33✔
355
        return 1;
×
356

357
    return 0;
358
}
359

360
int write_to_tempfile(gchar **filename, const unsigned char *data, size_t data_len)
30✔
361
{
362
    GError *error = NULL;
30✔
363
    int fd = g_file_open_tmp("XXXXXX", filename, &error);
30✔
364
    ssize_t n;
30✔
365

366
    if (error) {
30✔
367
        logerr(gl_LOGFILE, "Could not create temporary file: %s\n", error->message);
×
368
        g_error_free(error);
×
369
        return 1;
×
370
    }
371

372
    n = write_to_fd(fd, data, data_len);
30✔
373
    if (n < 0)
30✔
374
        goto error;
×
375

376
    n = lseek(fd, 0, SEEK_SET);
30✔
377
    if (n < 0) {
30✔
378
        logerr(gl_LOGFILE, "Could not seek(0) on file '%s': %s\n", filename, strerror(errno));
×
379
        goto error;
×
380
    }
381
    return fd;
382

383
error:
×
384
    close(fd);
×
385
    return -1;
×
386
}
387

388
/* replace occurrences of 'torep' with 'rep' in a string 'in' */
389
gchar *str_replace(const char *in, const char *torep, const char *rep)
4✔
390
{
391
    char *res;
4✔
392
    const char *s, *b;
4✔
393
    size_t torep_len;
4✔
394
    size_t rep_len;
4✔
395
    size_t ctr = 0;
4✔
396
    size_t off = 0;
4✔
397

398
    if (in == NULL || torep == NULL || rep == NULL)
4✔
399
        return NULL;
400

401
    torep_len = strlen(torep);
4✔
402
    if (torep_len == 0)
4✔
403
        return NULL;
404

405
    rep_len = strlen(rep);
4✔
406

407
    s = in;
4✔
408
    while ((s = strstr(s, torep)) != NULL) {
28✔
409
        s += torep_len;
24✔
410
        ctr++;
24✔
411
    }
412

413
    res = g_malloc(strlen(in) - ctr * torep_len + ctr * rep_len + 1);
4✔
414

415
    b = s = in;
4✔
416
    while ((s = strstr(s, torep)) != NULL) {
28✔
417
        strncpy(&res[off], b, s - b);
24✔
418
        off += (s - b);
24✔
419
        s += torep_len;
24✔
420
        b = s;
24✔
421
        strcpy(&res[off], rep);
24✔
422
        off += rep_len;
24✔
423
    }
424
    strcpy(&res[off], b);
4✔
425

426
    return res;
4✔
427
}
428

429
int check_directory_access(const gchar *directory, int mode, const struct passwd *curr_user)
149✔
430
{
431
    struct stat statbuf;
149✔
432

433
    if (stat(directory, &statbuf) != 0 || (statbuf.st_mode & S_IFMT) != S_IFDIR) {
149✔
434
        logerr(gl_LOGFILE,
×
435
               "User %s cannot access directory %s. Make sure it exists and is a directory.\n",
436
               curr_user ? curr_user->pw_name : "<unknown>", directory);
437
        return 1;
×
438
    }
439
    if ((mode & R_OK) && access(directory, R_OK) != 0) {
149✔
440
        logerr(gl_LOGFILE, "Need read rights on directory %s for user %s.\n",
×
441
               directory, curr_user ? curr_user->pw_name : "<unknown>");
442
        return 1;
×
443
    }
444
    if ((mode & W_OK) && access(directory, W_OK) != 0) {
149✔
445
        logerr(gl_LOGFILE, "Need write rights on directory %s for user %s.\n",
×
446
               directory, curr_user ? curr_user->pw_name : "<unknown>");
447
        return 1;
×
448
    }
449
    return 0;
450
}
451

452
int json_get_map_value(const char *json_input, const char *field_name,
75✔
453
                       gchar **value)
454
{
455
    g_autoptr(GError) error = NULL;
150✔
456
    JsonParser *jp = NULL;
75✔
457
    JsonReader *jr = NULL;
75✔
458
    JsonNode *root;
75✔
459
    int ret = -1;
75✔
460

461
    jp = json_parser_new();
75✔
462
    if (!json_parser_load_from_data(jp, json_input, -1, &error)) {
75✔
463
        logerr(gl_LOGFILE,
×
464
               "Could not parse JSON '%s': %s\n", json_input, error->message);
×
465
        goto error_unref_jp;
×
466
    }
467

468
    root = json_parser_get_root(jp);
75✔
469
    jr = json_reader_new(root);
75✔
470

471
    if (!json_reader_read_member(jr, field_name)) {
75✔
472
        logerr(gl_LOGFILE, "Missing '%s' field in '%s'\n",
×
473
               field_name, json_input);
474
        goto error_unref_jr;
×
475
    }
476
    *value = g_strdup(json_reader_get_string_value(jr));
75✔
477
    /* caller should handle *value == NULL */
478

479
    ret = 0;
75✔
480

481
error_unref_jr:
75✔
482
    g_object_unref(jr);
75✔
483

484
error_unref_jp:
75✔
485
    g_object_unref(jp);
75✔
486

487
    return ret;
75✔
488
}
489

490
int strv_strcmp(gchar *const*str_array, const gchar *s)
52✔
491
{
492
    size_t i;
52✔
493

494
    for (i = 0; str_array[i]; i++) {
121✔
495
        if (strcmp(str_array[i], s) == 0)
120✔
496
            return (int)i;
51✔
497
    }
498
    return -1;
499
}
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