Bug Summary

File:src/usr.sbin/smtpd/smtpctl/../table.c
Warning:line 652, column 7
Null pointer passed as 2nd argument to string comparison function

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name table.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/smtpd/smtpctl/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/smtpd/smtpctl/.. -D NO_IO -D CONFIG_MINIMUM -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/smtpd/smtpctl/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/smtpd/smtpctl/../table.c
1/* $OpenBSD: table.c,v 1.50 2021/06/14 17:58:16 eric Exp $ */
2
3/*
4 * Copyright (c) 2013 Eric Faurot <eric@openbsd.org>
5 * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include <sys/stat.h>
21
22#include <net/if.h>
23
24#include <arpa/inet.h>
25#include <errno(*__errno()).h>
26#include <regex.h>
27#include <stdlib.h>
28#include <string.h>
29
30#include "smtpd.h"
31#include "log.h"
32
33struct table_backend *table_backend_lookup(const char *);
34
35extern struct table_backend table_backend_static;
36extern struct table_backend table_backend_db;
37extern struct table_backend table_backend_getpwnam;
38extern struct table_backend table_backend_proc;
39
40static const char * table_service_name(enum table_service);
41static int table_parse_lookup(enum table_service, const char *, const char *,
42 union lookup *);
43static int parse_sockaddr(struct sockaddr *, int, const char *);
44
45static unsigned int last_table_id = 0;
46
47static struct table_backend *backends[] = {
48 &table_backend_static,
49 &table_backend_db,
50 &table_backend_getpwnam,
51 &table_backend_proc,
52 NULL((void *)0)
53};
54
55struct table_backend *
56table_backend_lookup(const char *backend)
57{
58 int i;
59
60 if (!strcmp(backend, "file"))
61 backend = "static";
62
63 for (i = 0; backends[i]; i++)
64 if (!strcmp(backends[i]->name, backend))
65 return (backends[i]);
66
67 return NULL((void *)0);
68}
69
70static const char *
71table_service_name(enum table_service s)
72{
73 switch (s) {
74 case K_NONE: return "NONE";
75 case K_ALIAS: return "ALIAS";
76 case K_DOMAIN: return "DOMAIN";
77 case K_CREDENTIALS: return "CREDENTIALS";
78 case K_NETADDR: return "NETADDR";
79 case K_USERINFO: return "USERINFO";
80 case K_SOURCE: return "SOURCE";
81 case K_MAILADDR: return "MAILADDR";
82 case K_ADDRNAME: return "ADDRNAME";
83 case K_MAILADDRMAP: return "MAILADDRMAP";
84 case K_RELAYHOST: return "RELAYHOST";
85 case K_STRING: return "STRING";
86 case K_REGEX: return "REGEX";
87 }
88 return "???";
89}
90
91struct table *
92table_find(struct smtpd *conf, const char *name)
93{
94 return dict_get(conf->sc_tables_dict, name);
95}
96
97int
98table_match(struct table *table, enum table_service kind, const char *key)
99{
100 return table_lookup(table, kind, key, NULL((void *)0));
101}
102
103int
104table_lookup(struct table *table, enum table_service kind, const char *key,
105 union lookup *lk)
106{
107 char lkey[1024], *buf = NULL((void *)0);
108 int r;
109
110 r = -1;
111 if (table->t_backend->lookup == NULL((void *)0))
112 errno(*__errno()) = ENOTSUP91;
113 else if (!lowercase(lkey, key, sizeof lkey)) {
114 log_warnx("warn: lookup key too long: %s", key);
115 errno(*__errno()) = EINVAL22;
116 }
117 else
118 r = table->t_backend->lookup(table, kind, lkey, lk ? &buf : NULL((void *)0));
119
120 if (r == 1) {
121 log_trace(TRACE_LOOKUP, "lookup: %s \"%s\" as %s in table %s:%s -> %s%s%s",do { if (tracing & (0x0100)) log_trace0("lookup: %s \"%s\" as %s in table %s:%s -> %s%s%s"
, lk ? "lookup" : "match", key, table_service_name(kind), table
->t_backend->name, table->t_name, lk ? "\"" : "", lk
? buf : "true", lk ? "\"" : ""); } while (0)
122 lk ? "lookup" : "match",do { if (tracing & (0x0100)) log_trace0("lookup: %s \"%s\" as %s in table %s:%s -> %s%s%s"
, lk ? "lookup" : "match", key, table_service_name(kind), table
->t_backend->name, table->t_name, lk ? "\"" : "", lk
? buf : "true", lk ? "\"" : ""); } while (0)
123 key,do { if (tracing & (0x0100)) log_trace0("lookup: %s \"%s\" as %s in table %s:%s -> %s%s%s"
, lk ? "lookup" : "match", key, table_service_name(kind), table
->t_backend->name, table->t_name, lk ? "\"" : "", lk
? buf : "true", lk ? "\"" : ""); } while (0)
124 table_service_name(kind),do { if (tracing & (0x0100)) log_trace0("lookup: %s \"%s\" as %s in table %s:%s -> %s%s%s"
, lk ? "lookup" : "match", key, table_service_name(kind), table
->t_backend->name, table->t_name, lk ? "\"" : "", lk
? buf : "true", lk ? "\"" : ""); } while (0)
125 table->t_backend->name,do { if (tracing & (0x0100)) log_trace0("lookup: %s \"%s\" as %s in table %s:%s -> %s%s%s"
, lk ? "lookup" : "match", key, table_service_name(kind), table
->t_backend->name, table->t_name, lk ? "\"" : "", lk
? buf : "true", lk ? "\"" : ""); } while (0)
126 table->t_name,do { if (tracing & (0x0100)) log_trace0("lookup: %s \"%s\" as %s in table %s:%s -> %s%s%s"
, lk ? "lookup" : "match", key, table_service_name(kind), table
->t_backend->name, table->t_name, lk ? "\"" : "", lk
? buf : "true", lk ? "\"" : ""); } while (0)
127 lk ? "\"" : "",do { if (tracing & (0x0100)) log_trace0("lookup: %s \"%s\" as %s in table %s:%s -> %s%s%s"
, lk ? "lookup" : "match", key, table_service_name(kind), table
->t_backend->name, table->t_name, lk ? "\"" : "", lk
? buf : "true", lk ? "\"" : ""); } while (0)
128 lk ? buf : "true",do { if (tracing & (0x0100)) log_trace0("lookup: %s \"%s\" as %s in table %s:%s -> %s%s%s"
, lk ? "lookup" : "match", key, table_service_name(kind), table
->t_backend->name, table->t_name, lk ? "\"" : "", lk
? buf : "true", lk ? "\"" : ""); } while (0)
129 lk ? "\"" : "")do { if (tracing & (0x0100)) log_trace0("lookup: %s \"%s\" as %s in table %s:%s -> %s%s%s"
, lk ? "lookup" : "match", key, table_service_name(kind), table
->t_backend->name, table->t_name, lk ? "\"" : "", lk
? buf : "true", lk ? "\"" : ""); } while (0)
;
130 if (buf)
131 r = table_parse_lookup(kind, lkey, buf, lk);
132 }
133 else
134 log_trace(TRACE_LOOKUP, "lookup: %s \"%s\" as %s in table %s:%s -> %s%s",do { if (tracing & (0x0100)) log_trace0("lookup: %s \"%s\" as %s in table %s:%s -> %s%s"
, lk ? "lookup" : "match", key, table_service_name(kind), table
->t_backend->name, table->t_name, (r == -1) ? "error: "
: (lk ? "none" : "false"), (r == -1) ? strerror((*__errno())
) : ""); } while (0)
135 lk ? "lookup" : "match",do { if (tracing & (0x0100)) log_trace0("lookup: %s \"%s\" as %s in table %s:%s -> %s%s"
, lk ? "lookup" : "match", key, table_service_name(kind), table
->t_backend->name, table->t_name, (r == -1) ? "error: "
: (lk ? "none" : "false"), (r == -1) ? strerror((*__errno())
) : ""); } while (0)
136 key,do { if (tracing & (0x0100)) log_trace0("lookup: %s \"%s\" as %s in table %s:%s -> %s%s"
, lk ? "lookup" : "match", key, table_service_name(kind), table
->t_backend->name, table->t_name, (r == -1) ? "error: "
: (lk ? "none" : "false"), (r == -1) ? strerror((*__errno())
) : ""); } while (0)
137 table_service_name(kind),do { if (tracing & (0x0100)) log_trace0("lookup: %s \"%s\" as %s in table %s:%s -> %s%s"
, lk ? "lookup" : "match", key, table_service_name(kind), table
->t_backend->name, table->t_name, (r == -1) ? "error: "
: (lk ? "none" : "false"), (r == -1) ? strerror((*__errno())
) : ""); } while (0)
138 table->t_backend->name,do { if (tracing & (0x0100)) log_trace0("lookup: %s \"%s\" as %s in table %s:%s -> %s%s"
, lk ? "lookup" : "match", key, table_service_name(kind), table
->t_backend->name, table->t_name, (r == -1) ? "error: "
: (lk ? "none" : "false"), (r == -1) ? strerror((*__errno())
) : ""); } while (0)
139 table->t_name,do { if (tracing & (0x0100)) log_trace0("lookup: %s \"%s\" as %s in table %s:%s -> %s%s"
, lk ? "lookup" : "match", key, table_service_name(kind), table
->t_backend->name, table->t_name, (r == -1) ? "error: "
: (lk ? "none" : "false"), (r == -1) ? strerror((*__errno())
) : ""); } while (0)
140 (r == -1) ? "error: " : (lk ? "none" : "false"),do { if (tracing & (0x0100)) log_trace0("lookup: %s \"%s\" as %s in table %s:%s -> %s%s"
, lk ? "lookup" : "match", key, table_service_name(kind), table
->t_backend->name, table->t_name, (r == -1) ? "error: "
: (lk ? "none" : "false"), (r == -1) ? strerror((*__errno())
) : ""); } while (0)
141 (r == -1) ? strerror(errno) : "")do { if (tracing & (0x0100)) log_trace0("lookup: %s \"%s\" as %s in table %s:%s -> %s%s"
, lk ? "lookup" : "match", key, table_service_name(kind), table
->t_backend->name, table->t_name, (r == -1) ? "error: "
: (lk ? "none" : "false"), (r == -1) ? strerror((*__errno())
) : ""); } while (0)
;
142
143 free(buf);
144
145 return (r);
146}
147
148int
149table_fetch(struct table *table, enum table_service kind, union lookup *lk)
150{
151 char *buf = NULL((void *)0);
152 int r;
153
154 r = -1;
155 if (table->t_backend->fetch == NULL((void *)0))
1
Assuming field 'fetch' is not equal to NULL
2
Taking false branch
156 errno(*__errno()) = ENOTSUP91;
157 else
158 r = table->t_backend->fetch(table, kind, &buf);
159
160 if (r == 1) {
3
Assuming 'r' is equal to 1
4
Taking true branch
161 log_trace(TRACE_LOOKUP, "lookup: fetch %s from table %s:%s -> \"%s\"",do { if (tracing & (0x0100)) log_trace0("lookup: fetch %s from table %s:%s -> \"%s\""
, table_service_name(kind), table->t_backend->name, table
->t_name, buf); } while (0)
5
Assuming the condition is false
6
Taking false branch
7
Loop condition is false. Exiting loop
162 table_service_name(kind),do { if (tracing & (0x0100)) log_trace0("lookup: fetch %s from table %s:%s -> \"%s\""
, table_service_name(kind), table->t_backend->name, table
->t_name, buf); } while (0)
163 table->t_backend->name,do { if (tracing & (0x0100)) log_trace0("lookup: fetch %s from table %s:%s -> \"%s\""
, table_service_name(kind), table->t_backend->name, table
->t_name, buf); } while (0)
164 table->t_name,do { if (tracing & (0x0100)) log_trace0("lookup: fetch %s from table %s:%s -> \"%s\""
, table_service_name(kind), table->t_backend->name, table
->t_name, buf); } while (0)
165 buf)do { if (tracing & (0x0100)) log_trace0("lookup: fetch %s from table %s:%s -> \"%s\""
, table_service_name(kind), table->t_backend->name, table
->t_name, buf); } while (0)
;
166 r = table_parse_lookup(kind, NULL((void *)0), buf, lk);
8
Passing null pointer value via 2nd parameter 'key'
9
Calling 'table_parse_lookup'
167 }
168 else
169 log_trace(TRACE_LOOKUP, "lookup: fetch %s from table %s:%s -> %s%s",do { if (tracing & (0x0100)) log_trace0("lookup: fetch %s from table %s:%s -> %s%s"
, table_service_name(kind), table->t_backend->name, table
->t_name, (r == -1) ? "error: " : "none", (r == -1) ? strerror
((*__errno())) : ""); } while (0)
170 table_service_name(kind),do { if (tracing & (0x0100)) log_trace0("lookup: fetch %s from table %s:%s -> %s%s"
, table_service_name(kind), table->t_backend->name, table
->t_name, (r == -1) ? "error: " : "none", (r == -1) ? strerror
((*__errno())) : ""); } while (0)
171 table->t_backend->name,do { if (tracing & (0x0100)) log_trace0("lookup: fetch %s from table %s:%s -> %s%s"
, table_service_name(kind), table->t_backend->name, table
->t_name, (r == -1) ? "error: " : "none", (r == -1) ? strerror
((*__errno())) : ""); } while (0)
172 table->t_name,do { if (tracing & (0x0100)) log_trace0("lookup: fetch %s from table %s:%s -> %s%s"
, table_service_name(kind), table->t_backend->name, table
->t_name, (r == -1) ? "error: " : "none", (r == -1) ? strerror
((*__errno())) : ""); } while (0)
173 (r == -1) ? "error: " : "none",do { if (tracing & (0x0100)) log_trace0("lookup: fetch %s from table %s:%s -> %s%s"
, table_service_name(kind), table->t_backend->name, table
->t_name, (r == -1) ? "error: " : "none", (r == -1) ? strerror
((*__errno())) : ""); } while (0)
174 (r == -1) ? strerror(errno) : "")do { if (tracing & (0x0100)) log_trace0("lookup: fetch %s from table %s:%s -> %s%s"
, table_service_name(kind), table->t_backend->name, table
->t_name, (r == -1) ? "error: " : "none", (r == -1) ? strerror
((*__errno())) : ""); } while (0)
;
175
176 free(buf);
177
178 return (r);
179}
180
181struct table *
182table_create(struct smtpd *conf, const char *backend, const char *name,
183 const char *config)
184{
185 struct table *t;
186 struct table_backend *tb;
187 char path[LINE_MAX2048];
188 size_t n;
189 struct stat sb;
190
191 if (name && table_find(conf, name))
192 fatalx("table_create: table \"%s\" already defined", name);
193
194 if ((tb = table_backend_lookup(backend)) == NULL((void *)0)) {
195 if ((size_t)snprintf(path, sizeof(path), PATH_LIBEXEC"/usr/local/libexec/smtpd""/table-%s",
196 backend) >= sizeof(path)) {
197 fatalx("table_create: path too long \""
198 PATH_LIBEXEC"/usr/local/libexec/smtpd""/table-%s\"", backend);
199 }
200 if (stat(path, &sb) == 0) {
201 tb = table_backend_lookup("proc");
202 (void)strlcpy(path, backend, sizeof(path));
203 if (config) {
204 (void)strlcat(path, ":", sizeof(path));
205 if (strlcat(path, config, sizeof(path))
206 >= sizeof(path))
207 fatalx("table_create: config file path too long");
208 }
209 config = path;
210 }
211 }
212
213 if (tb == NULL((void *)0))
214 fatalx("table_create: backend \"%s\" does not exist", backend);
215
216 t = xcalloc(1, sizeof(*t));
217 t->t_backend = tb;
218
219 if (config) {
220 if (strlcpy(t->t_config, config, sizeof t->t_config)
221 >= sizeof t->t_config)
222 fatalx("table_create: table config \"%s\" too large",
223 t->t_config);
224 }
225
226 if (strcmp(tb->name, "static") != 0)
227 t->t_type = T_DYNAMIC;
228
229 if (name == NULL((void *)0))
230 (void)snprintf(t->t_name, sizeof(t->t_name), "<dynamic:%u>",
231 last_table_id++);
232 else {
233 n = strlcpy(t->t_name, name, sizeof(t->t_name));
234 if (n >= sizeof(t->t_name))
235 fatalx("table_create: table name too long");
236 }
237
238 dict_set(conf->sc_tables_dict, t->t_name, t);
239
240 return (t);
241}
242
243void
244table_destroy(struct smtpd *conf, struct table *t)
245{
246 dict_xpop(conf->sc_tables_dict, t->t_name);
247 free(t);
248}
249
250int
251table_config(struct table *t)
252{
253 if (t->t_backend->config == NULL((void *)0))
254 return (1);
255 return (t->t_backend->config(t));
256}
257
258void
259table_add(struct table *t, const char *key, const char *val)
260{
261 if (t->t_backend->add == NULL((void *)0))
262 fatalx("table_add: cannot add to table");
263
264 if (t->t_backend->add(t, key, val) == 0)
265 log_warnx("warn: failed to add \"%s\" in table \"%s\"", key, t->t_name);
266}
267
268void
269table_dump(struct table *t)
270{
271 const char *type;
272 char buf[LINE_MAX2048];
273
274 switch(t->t_type) {
275 case T_NONE:
276 type = "NONE";
277 break;
278 case T_DYNAMIC:
279 type = "DYNAMIC";
280 break;
281 case T_LIST:
282 type = "LIST";
283 break;
284 case T_HASH:
285 type = "HASH";
286 break;
287 default:
288 type = "???";
289 break;
290 }
291
292 if (t->t_config[0])
293 snprintf(buf, sizeof(buf), " config=\"%s\"", t->t_config);
294 else
295 buf[0] = '\0';
296
297 log_debug("TABLE \"%s\" backend=%s type=%s%s", t->t_name,
298 t->t_backend->name, type, buf);
299
300 if (t->t_backend->dump)
301 t->t_backend->dump(t);
302}
303
304int
305table_check_type(struct table *t, uint32_t mask)
306{
307 return t->t_type & mask;
308}
309
310int
311table_check_service(struct table *t, uint32_t mask)
312{
313 return t->t_backend->services & mask;
314}
315
316int
317table_check_use(struct table *t, uint32_t tmask, uint32_t smask)
318{
319 return table_check_type(t, tmask) && table_check_service(t, smask);
320}
321
322int
323table_open(struct table *t)
324{
325 if (t->t_backend->open == NULL((void *)0))
326 return (1);
327 return (t->t_backend->open(t));
328}
329
330void
331table_close(struct table *t)
332{
333 if (t->t_backend->close)
334 t->t_backend->close(t);
335}
336
337int
338table_update(struct table *t)
339{
340 if (t->t_backend->update == NULL((void *)0))
341 return (1);
342 return (t->t_backend->update(t));
343}
344
345
346/*
347 * quick reminder:
348 * in *_match() s1 comes from session, s2 comes from table
349 */
350
351int
352table_domain_match(const char *s1, const char *s2)
353{
354 return hostname_match(s1, s2);
355}
356
357int
358table_mailaddr_match(const char *s1, const char *s2)
359{
360 struct mailaddr m1;
361 struct mailaddr m2;
362
363 if (!text_to_mailaddr(&m1, s1))
364 return 0;
365 if (!text_to_mailaddr(&m2, s2))
366 return 0;
367 return mailaddr_match(&m1, &m2);
368}
369
370static int table_match_mask(struct sockaddr_storage *, struct netaddr *);
371static int table_inet4_match(struct sockaddr_in *, struct netaddr *);
372static int table_inet6_match(struct sockaddr_in6 *, struct netaddr *);
373
374int
375table_netaddr_match(const char *s1, const char *s2)
376{
377 struct netaddr n1;
378 struct netaddr n2;
379
380 if (strcasecmp(s1, s2) == 0)
381 return 1;
382 if (!text_to_netaddr(&n1, s1))
383 return 0;
384 if (!text_to_netaddr(&n2, s2))
385 return 0;
386 if (n1.ss.ss_family != n2.ss.ss_family)
387 return 0;
388 if (n1.ss.ss_len != n2.ss.ss_len)
389 return 0;
390 return table_match_mask(&n1.ss, &n2);
391}
392
393static int
394table_match_mask(struct sockaddr_storage *ss, struct netaddr *ssmask)
395{
396 if (ss->ss_family == AF_INET2)
397 return table_inet4_match((struct sockaddr_in *)ss, ssmask);
398
399 if (ss->ss_family == AF_INET624)
400 return table_inet6_match((struct sockaddr_in6 *)ss, ssmask);
401
402 return (0);
403}
404
405static int
406table_inet4_match(struct sockaddr_in *ss, struct netaddr *ssmask)
407{
408 in_addr_t mask;
409 int i;
410
411 /* a.b.c.d/8 -> htonl(0xff000000) */
412 mask = 0;
413 for (i = 0; i < ssmask->bits; ++i)
414 mask = (mask >> 1) | 0x80000000;
415 mask = htonl(mask)(__uint32_t)(__builtin_constant_p(mask) ? (__uint32_t)(((__uint32_t
)(mask) & 0xff) << 24 | ((__uint32_t)(mask) & 0xff00
) << 8 | ((__uint32_t)(mask) & 0xff0000) >> 8
| ((__uint32_t)(mask) & 0xff000000) >> 24) : __swap32md
(mask))
;
416
417 /* (addr & mask) == (net & mask) */
418 if ((ss->sin_addr.s_addr & mask) ==
419 (((struct sockaddr_in *)ssmask)->sin_addr.s_addr & mask))
420 return 1;
421
422 return 0;
423}
424
425static int
426table_inet6_match(struct sockaddr_in6 *ss, struct netaddr *ssmask)
427{
428 struct in6_addr *in;
429 struct in6_addr *inmask;
430 struct in6_addr mask;
431 int i;
432
433 memset(&mask, 0, sizeof(mask));
434 for (i = 0; i < ssmask->bits / 8; i++)
435 mask.s6_addr__u6_addr.__u6_addr8[i] = 0xff;
436 i = ssmask->bits % 8;
437 if (i)
438 mask.s6_addr__u6_addr.__u6_addr8[ssmask->bits / 8] = 0xff00 >> i;
439
440 in = &ss->sin6_addr;
441 inmask = &((struct sockaddr_in6 *)&ssmask->ss)->sin6_addr;
442
443 for (i = 0; i < 16; i++) {
444 if ((in->s6_addr__u6_addr.__u6_addr8[i] & mask.s6_addr__u6_addr.__u6_addr8[i]) !=
445 (inmask->s6_addr__u6_addr.__u6_addr8[i] & mask.s6_addr__u6_addr.__u6_addr8[i]))
446 return (0);
447 }
448
449 return (1);
450}
451
452int
453table_regex_match(const char *string, const char *pattern)
454{
455 regex_t preg;
456 int cflags = REG_EXTENDED0001|REG_NOSUB0004;
457 int ret;
458
459 if (strncmp(pattern, "(?i)", 4) == 0) {
460 cflags |= REG_ICASE0002;
461 pattern += 4;
462 }
463
464 if (regcomp(&preg, pattern, cflags) != 0)
465 return (0);
466
467 ret = regexec(&preg, string, 0, NULL((void *)0), 0);
468
469 regfree(&preg);
470
471 if (ret != 0)
472 return (0);
473
474 return (1);
475}
476
477void
478table_dump_all(struct smtpd *conf)
479{
480 struct table *t;
481 void *iter;
482
483 iter = NULL((void *)0);
484 while (dict_iter(conf->sc_tables_dict, &iter, NULL((void *)0), (void **)&t))
485 table_dump(t);
486}
487
488void
489table_open_all(struct smtpd *conf)
490{
491 struct table *t;
492 void *iter;
493
494 iter = NULL((void *)0);
495 while (dict_iter(conf->sc_tables_dict, &iter, NULL((void *)0), (void **)&t))
496 if (!table_open(t))
497 fatalx("failed to open table %s", t->t_name);
498}
499
500void
501table_close_all(struct smtpd *conf)
502{
503 struct table *t;
504 void *iter;
505
506 iter = NULL((void *)0);
507 while (dict_iter(conf->sc_tables_dict, &iter, NULL((void *)0), (void **)&t))
508 table_close(t);
509}
510
511static int
512table_parse_lookup(enum table_service service, const char *key,
513 const char *line, union lookup *lk)
514{
515 char buffer[LINE_MAX2048], *p;
516 size_t len;
517
518 len = strlen(line);
519
520 switch (service) {
10
Control jumps to 'case K_ADDRNAME:' at line 604
521 case K_ALIAS:
522 lk->expand = calloc(1, sizeof(*lk->expand));
523 if (lk->expand == NULL((void *)0))
524 return (-1);
525 if (!expand_line(lk->expand, line, 1)) {
526 expand_free(lk->expand);
527 return (-1);
528 }
529 return (1);
530
531 case K_DOMAIN:
532 if (strlcpy(lk->domain.name, line, sizeof(lk->domain.name))
533 >= sizeof(lk->domain.name))
534 return (-1);
535 return (1);
536
537 case K_CREDENTIALS:
538
539 /* credentials are stored as user:password */
540 if (len < 3)
541 return (-1);
542
543 /* too big to fit in a smtp session line */
544 if (len >= LINE_MAX2048)
545 return (-1);
546
547 p = strchr(line, ':');
548 if (p == NULL((void *)0)) {
549 if (strlcpy(lk->creds.username, key, sizeof (lk->creds.username))
550 >= sizeof (lk->creds.username))
551 return (-1);
552 if (strlcpy(lk->creds.password, line, sizeof(lk->creds.password))
553 >= sizeof(lk->creds.password))
554 return (-1);
555 return (1);
556 }
557
558 if (p == line || p == line + len - 1)
559 return (-1);
560
561 memmove(lk->creds.username, line, p - line);
562 lk->creds.username[p - line] = '\0';
563
564 if (strlcpy(lk->creds.password, p+1, sizeof(lk->creds.password))
565 >= sizeof(lk->creds.password))
566 return (-1);
567
568 return (1);
569
570 case K_NETADDR:
571 if (!text_to_netaddr(&lk->netaddr, line))
572 return (-1);
573 return (1);
574
575 case K_USERINFO:
576 if (!bsnprintf(buffer, sizeof(buffer), "%s:%s", key, line))
577 return (-1);
578 if (!text_to_userinfo(&lk->userinfo, buffer))
579 return (-1);
580 return (1);
581
582 case K_SOURCE:
583 if (parse_sockaddr((struct sockaddr *)&lk->source.addr,
584 PF_UNSPEC0, line) == -1)
585 return (-1);
586 return (1);
587
588 case K_MAILADDR:
589 if (!text_to_mailaddr(&lk->mailaddr, line))
590 return (-1);
591 return (1);
592
593 case K_MAILADDRMAP:
594 lk->maddrmap = calloc(1, sizeof(*lk->maddrmap));
595 if (lk->maddrmap == NULL((void *)0))
596 return (-1);
597 maddrmap_init(lk->maddrmap);
598 if (!mailaddr_line(lk->maddrmap, line)) {
599 maddrmap_free(lk->maddrmap);
600 return (-1);
601 }
602 return (1);
603
604 case K_ADDRNAME:
605 if (parse_sockaddr((struct sockaddr *)&lk->addrname.addr,
12
Calling 'parse_sockaddr'
606 PF_UNSPEC0, key) == -1)
11
Passing null pointer value via 3rd parameter 'str'
607 return (-1);
608 if (strlcpy(lk->addrname.name, line, sizeof(lk->addrname.name))
609 >= sizeof(lk->addrname.name))
610 return (-1);
611 return (1);
612
613 case K_RELAYHOST:
614 if (strlcpy(lk->relayhost, line, sizeof(lk->relayhost))
615 >= sizeof(lk->relayhost))
616 return (-1);
617 return (1);
618
619 default:
620 return (-1);
621 }
622}
623
624static int
625parse_sockaddr(struct sockaddr *sa, int family, const char *str)
626{
627 struct in_addr ina;
628 struct in6_addr in6a;
629 struct sockaddr_in *sin;
630 struct sockaddr_in6 *sin6;
631 char *cp, *str2;
632 const char *errstr;
633
634 switch (family) {
13
Control jumps to 'case 0:' at line 635
17
Control jumps to 'case 24:' at line 651
635 case PF_UNSPEC0:
636 if (parse_sockaddr(sa, PF_INET2, str) == 0)
14
Taking false branch
637 return (0);
638 return parse_sockaddr(sa, PF_INET624, str);
15
Passing null pointer value via 3rd parameter 'str'
16
Calling 'parse_sockaddr'
639
640 case PF_INET2:
641 if (inet_pton(PF_INET2, str, &ina) != 1)
642 return (-1);
643
644 sin = (struct sockaddr_in *)sa;
645 memset(sin, 0, sizeof *sin);
646 sin->sin_len = sizeof(struct sockaddr_in);
647 sin->sin_family = PF_INET2;
648 sin->sin_addr.s_addr = ina.s_addr;
649 return (0);
650
651 case PF_INET624:
652 if (strncasecmp("ipv6:", str, 5) == 0)
18
Null pointer passed as 2nd argument to string comparison function
653 str += 5;
654 cp = strchr(str, SCOPE_DELIMITER'%');
655 if (cp) {
656 str2 = strdup(str);
657 if (str2 == NULL((void *)0))
658 return (-1);
659 str2[cp - str] = '\0';
660 if (inet_pton(PF_INET624, str2, &in6a) != 1) {
661 free(str2);
662 return (-1);
663 }
664 cp++;
665 free(str2);
666 } else if (inet_pton(PF_INET624, str, &in6a) != 1)
667 return (-1);
668
669 sin6 = (struct sockaddr_in6 *)sa;
670 memset(sin6, 0, sizeof *sin6);
671 sin6->sin6_len = sizeof(struct sockaddr_in6);
672 sin6->sin6_family = PF_INET624;
673 sin6->sin6_addr = in6a;
674
675 if (cp == NULL((void *)0))
676 return (0);
677
678 if (IN6_IS_ADDR_LINKLOCAL(&in6a)(((&in6a)->__u6_addr.__u6_addr8[0] == 0xfe) &&
(((&in6a)->__u6_addr.__u6_addr8[1] & 0xc0) == 0x80
))
||
679 IN6_IS_ADDR_MC_LINKLOCAL(&in6a)(((&in6a)->__u6_addr.__u6_addr8[0] == 0xff) &&
(((&in6a)->__u6_addr.__u6_addr8[1] & 0x0f) == 0x02
))
||
680 IN6_IS_ADDR_MC_INTFACELOCAL(&in6a)(((&in6a)->__u6_addr.__u6_addr8[0] == 0xff) &&
(((&in6a)->__u6_addr.__u6_addr8[1] & 0x0f) == 0x01
))
)
681 if ((sin6->sin6_scope_id = if_nametoindex(cp)))
682 return (0);
683
684 sin6->sin6_scope_id = strtonum(cp, 0, UINT32_MAX0xffffffffU, &errstr);
685 if (errstr)
686 return (-1);
687 return (0);
688
689 default:
690 break;
691 }
692
693 return (-1);
694}