Coverage Report

Created: 2026-08-13 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwebsockets/lib/system/policy.c
Line
Count
Source
1
/*
2
 * libwebsockets - small server side websockets and web server implementation
3
 *
4
 * Copyright (C) 2010 - 2026 Andy Green <andy@warmcat.com>
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to
8
 * deal in the Software without restriction, including without limitation the
9
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10
 * sell copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22
 * IN THE SOFTWARE.
23
 */
24
25
#include <private-lib-core.h>
26
27
#if defined(LWS_WITH_NETWORK)
28
#if defined(LWS_WITH_FILE_OPS)
29
/*
30
 * lws_system_parse_policy() parses a JSON policy file and so depends on the
31
 * LEJP JSON parser.  Only build the real implementation when LEJP is enabled;
32
 * otherwise provide a stub (in the #else below) that reports "no policy", so
33
 * callers that reference it without gating on LWS_WITH_LEJP (eg, the ACME /
34
 * versioned-cert path in tls.c) still link without pulling in lejp.
35
 */
36
#if defined(LWS_WITH_LEJP)
37
38
static const char * const policy_paths[] = {
39
  "dns_base_dir",
40
  "seeds[]",
41
};
42
43
enum lejp_policy_paths {
44
  LEJP_PLCY_DNS_BASE_DIR,
45
  LEJP_PLCY_SEEDS,
46
};
47
48
struct policy_parse_ctx {
49
  lws_system_policy_t *p;
50
};
51
52
static signed char
53
policy_cb(struct lejp_ctx *ctx, char reason)
54
0
{
55
0
  struct policy_parse_ctx *pctx = (struct policy_parse_ctx *)ctx->user;
56
0
  lws_system_seed_t *s;
57
58
0
  if (reason == LEJPCB_VAL_STR_END) {
59
0
        int match = ctx->path_match - 1;
60
0
        if (match < 0) {
61
0
            if (!strcmp(ctx->path, "dns_base_dir")) match = LEJP_PLCY_DNS_BASE_DIR;
62
0
            else if (!strcmp(ctx->path, "seeds[]")) match = LEJP_PLCY_SEEDS;
63
0
        }
64
65
0
    switch (match) {
66
0
    case LEJP_PLCY_DNS_BASE_DIR:
67
0
      lws_strncpy(pctx->p->dns_base_dir, ctx->buf, sizeof(pctx->p->dns_base_dir));
68
0
      break;
69
0
    case LEJP_PLCY_SEEDS:
70
0
      s = lws_zalloc(sizeof(*s), "policy seed");
71
0
      if (!s)
72
0
        return -1;
73
0
      lws_strncpy(s->hostname, ctx->buf, sizeof(s->hostname));
74
0
      lws_dll2_add_tail(&s->list, &pctx->p->seeds);
75
0
      break;
76
0
    }
77
0
  }
78
79
0
  return 0;
80
0
}
81
82
83
static const char *default_policy =
84
  "{\n"
85
  "    \"dns_base_dir\": \"/var/dnssec\",\n"
86
  "    \"seeds\": [ \"selfdns.org\", \"uk1.selfdns.org\", \"asia1.selfdns.org\" ]\n"
87
  "}\n";
88
89
int
90
lws_system_parse_policy(struct lws_context *cx, const char *filepath, lws_system_policy_t **_policy)
91
0
{
92
0
  struct policy_parse_ctx pctx;
93
0
  struct lejp_ctx ctx;
94
0
  lws_system_policy_t *p;
95
0
  int fd, n, m;
96
0
  uint8_t buf[256];
97
98
0
  *_policy = NULL;
99
100
0
  fd = lws_open(filepath, O_RDONLY);
101
0
  if (fd < 0) {
102
0
#if !defined(_WIN32)
103
0
    const char *pt = strrchr(filepath, '/');
104
0
    if (pt) {
105
0
      char dir[256];
106
0
      lws_strncpy(dir, filepath, sizeof(dir));
107
0
      dir[pt - filepath] = '\0';
108
0
      if (mkdir(dir, 0750) < 0)
109
0
        lwsl_debug("%s: mkdir %s failed (may exist)\n", __func__, dir);
110
0
    }
111
0
#endif
112
0
    fd = lws_open(filepath, O_CREAT | O_WRONLY | O_TRUNC, 0644);
113
0
    if (fd >= 0) {
114
0
      n = (int)write(fd, default_policy, LWS_POSIX_LENGTH_CAST(strlen(default_policy)));
115
0
      close(fd);
116
0
      fd = -1;
117
0
      if (n == (int)strlen(default_policy))
118
0
        fd = lws_open(filepath, O_RDONLY);
119
0
    }
120
0
  }
121
122
0
  p = lws_zalloc(sizeof(*p), "policy");
123
0
  if (!p) {
124
0
    if (fd >= 0)
125
0
      close(fd);
126
0
    return 1;
127
0
  }
128
129
0
  pctx.p = p;
130
0
  lejp_construct(&ctx, policy_cb, &pctx, policy_paths, LWS_ARRAY_SIZE(policy_paths));
131
132
0
  if (fd < 0) {
133
    /* Fallback: parse from memory if we failed to open and failed to create */
134
0
    m = lejp_parse(&ctx, (uint8_t *)default_policy, (int)strlen(default_policy));
135
0
    if (m < 0 && m != LEJP_CONTINUE)
136
0
      goto bail;
137
0
    goto done;
138
0
  }
139
140
0
  do {
141
0
    n = (int)read(fd, buf, sizeof(buf));
142
0
    if (n == 0)
143
0
      break;
144
0
    if (n < 0)
145
0
      goto bail;
146
147
0
    m = lejp_parse(&ctx, buf, n);
148
0
    if (m < 0 && m != LEJP_CONTINUE)
149
0
      goto bail;
150
151
0
  } while (1);
152
153
0
done:
154
0
  if (fd >= 0)
155
0
    close(fd);
156
0
  lejp_destruct(&ctx);
157
158
0
  *_policy = p;
159
0
  return 0;
160
161
0
bail:
162
0
  if (fd >= 0)
163
0
    close(fd);
164
0
  lejp_destruct(&ctx);
165
0
  lws_system_policy_free(p);
166
0
  return 1;
167
0
}
168
169
#else /* !LWS_WITH_LEJP */
170
171
int
172
lws_system_parse_policy(struct lws_context *cx, const char *filepath,
173
      lws_system_policy_t **_policy)
174
{
175
  *_policy = NULL;
176
  return 1; /* no JSON parser available without LEJP */
177
}
178
179
#endif /* LWS_WITH_LEJP */
180
#endif /* LWS_WITH_FILE_OPS */
181
182
void
183
lws_system_policy_free(lws_system_policy_t *policy)
184
0
{
185
0
  if (!policy)
186
0
    return;
187
188
0
  lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
189
0
           lws_dll2_get_head(&policy->seeds)) {
190
0
    lws_system_seed_t *s = lws_container_of(d, lws_system_seed_t, list);
191
192
0
    lws_dll2_remove(d);
193
0
    lws_free(s);
194
0
  } lws_end_foreach_dll_safe(d, d1);
195
196
0
  lws_free(policy);
197
0
}
198
199
#endif