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

stefanberger / swtpm / 621325588

05 May 2024 09:04PM UTC coverage: 73.542% (+0.2%) from 73.324%
621325588

push

travis-ci

web-flow
Merge defd1f468 into bfd6b8270

7163 of 9740 relevant lines covered (73.54%)

14121.07 hits per line

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

85.6
/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

25
#include "swtpm_utils.h"
26

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

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

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

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

53
    if (logfile == NULL)
747✔
54
        fprintf(stream, "%s", str);
626✔
55
    else
56
        append_to_file(logfile, str);
121✔
57

58
    free(str);
747✔
59
}
60

61
void logit(const char *logfile, const char *fmt, ...)
733✔
62
{
63
    va_list ap;
733✔
64

65
    va_start(ap, fmt);
733✔
66
    alog(stdout, logfile, fmt, ap);
733✔
67
    va_end(ap);
733✔
68
}
733✔
69

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

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

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

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

109
    for (i = 0; arr1 != NULL && arr1[i]; i++)
19,334✔
110
        n++;
16,811✔
111
    for (i = 0; arr2 != NULL && arr2[i]; i++)
8,434✔
112
        n++;
5,911✔
113

114
    res = g_malloc0(sizeof(char *) * (n + 1));
2,523✔
115
    for (i = 0, n = 0; arr1 != NULL && arr1[i]; i++)
21,857✔
116
        res[n++] = arr1[i];
16,811✔
117
    for (i = 0; arr2 != NULL && arr2[i]; i++)
8,434✔
118
        res[n++] = arr2[i];
5,911✔
119

120
    if (free_arr1 && arr1)
2,523✔
121
        g_free(arr1);
1,827✔
122

123
    return res;
2,523✔
124
}
125

126
/* Concatenate buffers into a given buffer of a given length 'buflen' */
127
ssize_t concat(unsigned char *buffer, size_t buflen, ...)
206✔
128
{
129
    va_list ap;
206✔
130
    ssize_t offset = 0;
206✔
131

132
    va_start(ap, buflen);
206✔
133

134
    while (1) {
762✔
135
        size_t len;
484✔
136
        unsigned char *i = va_arg(ap, unsigned char *);
484✔
137

138
        if (i == NULL)
484✔
139
            break;
140

141
        len = va_arg(ap, size_t);
278✔
142
        if (offset + len > buflen) {
278✔
143
            offset = -(offset + len);
×
144
            break;
×
145
        }
146

147
        memcpy(&buffer[offset], i, len);
278✔
148
        offset += len;
278✔
149
   }
150
   va_end(ap);
206✔
151

152
   return offset;
206✔
153
}
154

155
/* Concatenate buffers and allocate a new buffer and return its size */
156
ssize_t memconcat(unsigned char **buffer, ...)
837✔
157
{
158
    va_list ap;
837✔
159
    ssize_t offset = 0;
837✔
160
    size_t allocated = 128;
837✔
161
    unsigned char *p;
837✔
162

163
    *buffer = g_malloc(allocated);
837✔
164
    p = *buffer;
837✔
165

166
    va_start(ap, buffer);
837✔
167

168
    while (1) {
7,641✔
169
        size_t len;
4,239✔
170
        unsigned char *i = va_arg(ap, unsigned char *);
4,239✔
171

172
        if (i == NULL)
4,239✔
173
            break;
174

175
        len = va_arg(ap, size_t);
3,402✔
176
        if (offset + len > allocated) {
3,402✔
177
            allocated += offset + len;
88✔
178
            *buffer = g_realloc(*buffer, allocated);
88✔
179
            p = *buffer;
88✔
180
        }
181

182
        memcpy(&p[offset], i, len);
3,402✔
183
        offset += len;
3,402✔
184
   }
185
   va_end(ap);
837✔
186

187
   return offset;
837✔
188
}
189

190
/* Print an input buffer as hex number */
191
gchar *print_as_hex(const unsigned char *input, size_t input_len)
125✔
192
{
193
    gchar *out = g_malloc(input_len * 2 + 1);
125✔
194
    size_t i;
125✔
195

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

199
    return out;
125✔
200
}
201

202
/* Split a command line and remove all trailing and leading spaces from all entries and remove
203
 * 0-length strings entirely.
204
 */
205
gchar **split_cmdline(const gchar *cmdline) {
84✔
206
    gchar **result = g_strsplit(cmdline, " ", -1);
84✔
207
    size_t i, j;
84✔
208

209
    for (i = 0, j = 0; result[i] != NULL; i++) {
415✔
210
        gchar *chomped = g_strchomp(result[i]);
247✔
211

212
        if (strlen(chomped) == 0) {
247✔
213
            g_free(chomped);
79✔
214
            result[i] = NULL;
79✔
215
        } else {
216
            result[i] = NULL;
168✔
217
            result[j++] = chomped;
168✔
218
        }
219
    }
220
    return result;
84✔
221
}
222

223
/* resolve environment variables in a string */
224
gchar *resolve_string(const gchar *inp) {
250✔
225
    char *pe;
250✔
226
    gchar *result = NULL;
250✔
227
    gchar *new_res, *tmp;
250✔
228
    size_t sidx = 0;
250✔
229
    const gchar *envval;
264✔
230

231
    while (1) {
278✔
232
        gchar *ps = g_strstr_len(&inp[sidx], -1, "${");
264✔
233
        if (ps == NULL) {
264✔
234
            if (sidx == 0) {
250✔
235
                g_free(result); /* coverity */
236✔
236
                return g_strdup(inp);
236✔
237
            }
238
            new_res = g_strconcat(result ? result : "", &inp[sidx], NULL);
14✔
239
            g_free(result);
14✔
240
            return new_res;
14✔
241
        }
242

243
        tmp = g_strndup(&inp[sidx], ps - &inp[sidx]);
14✔
244
        new_res = g_strconcat(result ? result : "", tmp, NULL);
28✔
245
        g_free(tmp);
14✔
246
        g_free(result);
14✔
247
        result = new_res;
14✔
248

249
        pe = g_strstr_len(&ps[2], -1, "}");
14✔
250
        if (pe == NULL) {
14✔
251
            new_res = g_strconcat(result ? result : "", ps, NULL);
×
252
            g_free(result);
×
253
            return new_res;
×
254
        }
255

256
        /* name of environment variable */
257
        tmp = g_strndup(&ps[2], pe - &ps[2]);
14✔
258

259
        envval = g_getenv(tmp);
14✔
260
        new_res = g_strconcat(result ? result : "",
14✔
261
                              envval ? envval : "",
262
                              NULL);
263
        g_free(tmp);
14✔
264
        g_free(result);
14✔
265
        result = new_res;
14✔
266
        sidx = &pe[1] - inp;
14✔
267
    }
268
}
269

270
/* Read an entire file */
271
int read_file(const gchar *filename, gchar **buffer, gsize *buffer_len)
342✔
272
{
273
    GError *error = NULL;
342✔
274

275
    if (!g_file_get_contents(filename, buffer, buffer_len, &error)) {
342✔
276
        logerr(gl_LOGFILE, "%s\n", error->message);
×
277
        g_error_free(error);
×
278
        return 1;
×
279
    }
280
    return 0;
281
}
282

283
/* Read a file and convert its lines into a NULL-termianted array */
284
int read_file_lines(const char *filename, gchar ***config_file_lines)
199✔
285
{
286
    g_autofree gchar *buffer = NULL;
398✔
287
    gsize buffer_len;
199✔
288
    size_t start = 0;
199✔
289
    gchar **array;
199✔
290
    gsize array_len = 1; /* null-terminated array */
199✔
291

292
    if (read_file(filename, &buffer, &buffer_len) != 0)
199✔
293
        return 1;
294

295
    array = g_malloc0(sizeof(char *) * array_len);
199✔
296

297
    while (start < buffer_len) {
905✔
298
        size_t off = start;
299

300
        /* search for end-of-string or next newline */
301
        while (off < buffer_len && buffer[off] != '\n')
29,284✔
302
            off++;
28,578✔
303

304
        if (off > start) {
706✔
305
            /* non-empty line */
306
            array = g_realloc(array, sizeof(char *) * (array_len + 1));
706✔
307
            array[array_len - 1] = g_strndup(&buffer[start], off - start);
706✔
308
            array_len++;
706✔
309
        }
310
        start = off + 1;
706✔
311
    }
312
    array[array_len - 1] = NULL;
199✔
313
    *config_file_lines = array;
199✔
314

315
    return 0;
199✔
316
}
317

318
static ssize_t write_to_fd(int fd, const unsigned char *data, size_t data_len)
63✔
319
{
320
    ssize_t n;
63✔
321

322
    n = write(fd, data, data_len);
63✔
323
    if (n < 0) {
63✔
324
        logerr(gl_LOGFILE, "Could not write to file: %s\n", strerror(errno));
×
325
    } else if ((size_t)n != data_len) {
63✔
326
        logerr(gl_LOGFILE, "Could not write all bytes to the file.\n");
×
327
        n = -1;
×
328
    }
329
    return n;
63✔
330
}
331

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

344
    n = write_to_fd(fd, data, data_len);
33✔
345
    close(fd);
33✔
346
    if (n < 0)
33✔
347
        return 1;
×
348

349
    return 0;
350
}
351

352
int write_to_tempfile(gchar **filename, const unsigned char *data, size_t data_len)
30✔
353
{
354
    GError *error = NULL;
30✔
355
    int fd = g_file_open_tmp("XXXXXX", filename, &error);
30✔
356
    ssize_t n;
30✔
357

358
    if (error) {
30✔
359
        logerr(gl_LOGFILE, "Could not create temporary file: %s\n", error->message);
×
360
        g_error_free(error);
×
361
        return 1;
×
362
    }
363

364
    n = write_to_fd(fd, data, data_len);
30✔
365
    if (n < 0)
30✔
366
        goto error;
×
367

368
    n = lseek(fd, 0, SEEK_SET);
30✔
369
    if (n < 0) {
30✔
370
        logerr(gl_LOGFILE, "Could not seek(0) on file '%s': %s\n", filename, strerror(errno));
×
371
        goto error;
×
372
    }
373
    return fd;
374

375
error:
×
376
    close(fd);
×
377
    return -1;
×
378
}
379

380
/* replace occurrences of 'torep' with 'rep' in a string 'in' */
381
gchar *str_replace(const char *in, const char *torep, const char *rep)
4✔
382
{
383
    char *res;
4✔
384
    const char *s, *b;
4✔
385
    size_t torep_len;
4✔
386
    size_t rep_len;
4✔
387
    size_t ctr = 0;
4✔
388
    size_t off = 0;
4✔
389

390
    if (in == NULL || torep == NULL || rep == NULL)
4✔
391
        return NULL;
392

393
    torep_len = strlen(torep);
4✔
394
    if (torep_len == 0)
4✔
395
        return NULL;
396

397
    rep_len = strlen(rep);
4✔
398

399
    s = in;
4✔
400
    while ((s = strstr(s, torep)) != NULL) {
28✔
401
        s += torep_len;
24✔
402
        ctr++;
24✔
403
    }
404

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

407
    b = s = in;
4✔
408
    while ((s = strstr(s, torep)) != NULL) {
28✔
409
        strncpy(&res[off], b, s - b);
24✔
410
        off += (s - b);
24✔
411
        s += torep_len;
24✔
412
        b = s;
24✔
413
        strcpy(&res[off], rep);
24✔
414
        off += rep_len;
24✔
415
    }
416
    strcpy(&res[off], b);
4✔
417

418
    return res;
4✔
419
}
420

421
int check_directory_access(const gchar *directory, int mode, const struct passwd *curr_user)
80✔
422
{
423
    struct stat statbuf;
80✔
424

425
    if (stat(directory, &statbuf) != 0 || (statbuf.st_mode & S_IFMT) != S_IFDIR) {
80✔
426
        logerr(gl_LOGFILE,
×
427
               "User %s cannot access directory %s. Make sure it exists and is a directory.\n",
428
               curr_user ? curr_user->pw_name : "<unknown>", directory);
429
        return 1;
×
430
    }
431
    if ((mode & R_OK) && access(directory, R_OK) != 0) {
80✔
432
        logerr(gl_LOGFILE, "Need read rights on directory %s for user %s.\n",
×
433
               directory, curr_user ? curr_user->pw_name : "<unknown>");
434
        return 1;
×
435
    }
436
    if ((mode & W_OK) && access(directory, W_OK) != 0) {
80✔
437
        logerr(gl_LOGFILE, "Need write rights on directory %s for user %s.\n",
×
438
               directory, curr_user ? curr_user->pw_name : "<unknown>");
439
        return 1;
×
440
    }
441
    return 0;
442
}
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