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

stefanberger / swtpm / 4301

pending completion
4301

cron

travis-ci-com

stefanberger
utils: Implement find_program() to try BINDIR path before PATH

To support install paths that are not covered by $PATH, and still allow
swtpm_setup and swtpm_localca to find swtpm and swtpm_cert executables,
implement find_program() to prepend the install path if only the program
name is given and otherwise fall back to g_find_program_in_path().

Update the man page stating that swtpm from the installation directory
(BINDIR) is tried to be used before one is attempted to be found in
the PATH.

Resolves: https://github.com/stefanberger/swtpm/issues/795
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>

10 of 10 new or added lines in 3 files covered. (100.0%)

7075 of 9649 relevant lines covered (73.32%)

13737.06 hits per line

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

86.06
/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_conf.h"
26
#include "swtpm_utils.h"
27

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

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

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

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

54
    if (logfile == NULL)
736✔
55
        fprintf(stream, "%s", str);
615✔
56
    else
57
        append_to_file(logfile, str);
121✔
58

59
    free(str);
736✔
60
}
61

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

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

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

75
    va_start(ap, fmt);
3✔
76
    alog(stderr, logfile, fmt, ap);
3✔
77
    va_end(ap);
3✔
78
}
3✔
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)
75✔
82
{
83
    char *res = NULL;
75✔
84
    int n = snprintf(buffer, bufferlen, "%s%s%s%s%s",
150✔
85
                     p1,
86
                     G_DIR_SEPARATOR_S,
87
                     p2,
88
                     p3 ? G_DIR_SEPARATOR_S : "",
89
                     p3 ? p3 : "");
90
    if (n < 0) {
75✔
91
        logerr(gl_LOGFILE, "Error: Could not print into buffer.\n");
×
92
    } else if ((size_t)n >= bufferlen) {
75✔
93
        logerr(gl_LOGFILE, "Error: Buffer for path is too small.\n");
×
94
    } else {
95
        res = buffer;
96
    }
97
    return res;
75✔
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
gchar **concat_arrays(char **arr1, char **arr2, gboolean free_arr1)
2,523✔
105
{
106
    size_t n = 0;
2,523✔
107
    gchar **res;
2,523✔
108
    size_t i;
2,523✔
109

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

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

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

124
    return res;
2,523✔
125
}
126

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

133
    va_start(ap, buflen);
206✔
134

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

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

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

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

153
   return offset;
206✔
154
}
155

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

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

167
    va_start(ap, buffer);
837✔
168

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

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

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

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

188
   return offset;
837✔
189
}
190

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

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

200
    return out;
125✔
201
}
202

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

316
    return 0;
199✔
317
}
318

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

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

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

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

350
    return 0;
351
}
352

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

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

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

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

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

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

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

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

398
    rep_len = strlen(rep);
4✔
399

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

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

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

419
    return res;
4✔
420
}
421

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

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

445
/* A program that is only described by the name of the executable is searched
446
 * for in the BINDIR path and only then in $PATH
447
 */
448
gchar *find_program(const gchar *program)
113✔
449
{
450
    g_autofree gchar *dirname = g_path_get_dirname(program);
113✔
451
    gchar *path;
113✔
452

453
    if (g_strcmp0(".", dirname) == 0) {
113✔
454
        path = g_strdup_printf(BINDIR "/%s", program);
113✔
455
        if (g_file_test(path, G_FILE_TEST_IS_EXECUTABLE))
113✔
456
            return path;
457

458
        g_free(path);
113✔
459
    }
460

461
    return g_find_program_in_path(program);
113✔
462
}
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