summaryrefslogtreecommitdiffstats
path: root/src/shared/machine-credential.c
blob: c1e76e468e5285f1669ee2b88789578297310da2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/* SPDX-License-Identifier: LGPL-2.1-or-later */

#include "alloc-util.h"
#include "creds-util.h"
#include "escape.h"
#include "extract-word.h"
#include "fileio.h"
#include "macro.h"
#include "memory-util.h"
#include "machine-credential.h"
#include "path-util.h"
#include "string-util-fundamental.h"

static void machine_credential_done(MachineCredential *cred) {
        assert(cred);

        cred->id = mfree(cred->id);
        cred->data = erase_and_free(cred->data);
        cred->size = 0;
}

void machine_credential_context_done(MachineCredentialContext *ctx) {
        assert(ctx);

        FOREACH_ARRAY(cred, ctx->credentials, ctx->n_credentials)
                machine_credential_done(cred);

        free(ctx->credentials);
}

bool machine_credentials_contains(const MachineCredentialContext *ctx, const char *id) {
        assert(ctx);
        assert(id);

        FOREACH_ARRAY(cred, ctx->credentials, ctx->n_credentials)
                if (streq(cred->id, id))
                        return true;

        return false;
}

int machine_credential_set(MachineCredentialContext *ctx, const char *cred_str) {
        _cleanup_(machine_credential_done) MachineCredential cred = {};
        ssize_t l;
        int r;

        assert(ctx);

        const char *p = ASSERT_PTR(cred_str);

        r = extract_first_word(&p, &cred.id, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
        if (r < 0)
                return log_error_errno(r, "Failed to parse --set-credential= parameter: %m");
        if (r == 0 || !p)
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                       "Missing value for --set-credential=: %s", cred_str);

        if (!credential_name_valid(cred.id))
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Credential name is not valid: %s", cred.id);

        if (machine_credentials_contains(ctx, cred.id))
                return log_error_errno(SYNTHETIC_ERRNO(EEXIST), "Duplicate credential '%s', refusing.", cred.id);

        l = cunescape(p, UNESCAPE_ACCEPT_NUL, &cred.data);
        if (l < 0)
                return log_error_errno(l, "Failed to unescape credential data: %s", p);
        cred.size = l;

        if (!GREEDY_REALLOC(ctx->credentials, ctx->n_credentials + 1))
                return log_oom();

        ctx->credentials[ctx->n_credentials++] = TAKE_STRUCT(cred);

        return 0;
}

int machine_credential_load(MachineCredentialContext *ctx, const char *cred_path) {
        _cleanup_(machine_credential_done) MachineCredential cred = {};
        _cleanup_free_ char *path_alloc = NULL;
        ReadFullFileFlags flags = READ_FULL_FILE_SECURE;
        int r;

        assert(ctx);

        const char *p = ASSERT_PTR(cred_path);

        r = extract_first_word(&p, &cred.id, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
        if (r < 0)
                return log_error_errno(r, "Failed to parse --load-credential= parameter: %m");
        if (r == 0 || !p)
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing value for --load-credential=: %s", cred_path);

        if (!credential_name_valid(cred.id))
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Credential name is not valid: %s", cred.id);

        if (machine_credentials_contains(ctx, cred.id))
                return log_error_errno(SYNTHETIC_ERRNO(EEXIST), "Duplicate credential '%s', refusing.", cred.id);

        if (is_path(p) && path_is_valid(p))
                flags |= READ_FULL_FILE_CONNECT_SOCKET;
        else if (credential_name_valid(p)) {
                const char *e;

                r = get_credentials_dir(&e);
                if (r < 0)
                        return log_error_errno(r,
                                               "Credential not available (no credentials passed at all): %s", cred.id);

                path_alloc = path_join(e, p);
                if (!path_alloc)
                        return log_oom();

                p = path_alloc;
        } else
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                       "Credential source appears to be neither a valid path nor a credential name: %s", p);

        r = read_full_file_full(AT_FDCWD, p, UINT64_MAX, SIZE_MAX,
                                flags,
                                NULL,
                                &cred.data, &cred.size);
        if (r < 0)
                return log_error_errno(r, "Failed to read credential '%s': %m", p);

        if (!GREEDY_REALLOC(ctx->credentials, ctx->n_credentials + 1))
                return log_oom();

        ctx->credentials[ctx->n_credentials++] = TAKE_STRUCT(cred);

        return 0;
}