Bug Summary

File:src/usr.sbin/smtpd/smtp/../smtpc.c
Warning:line 181, column 4
Value stored to 'len' is never read

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 smtpc.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/smtp/obj -resource-dir /usr/local/lib/clang/13.0.0 -D IO_TLS -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/smtpd/smtp/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/smtp/../smtpc.c
1/* $OpenBSD: smtpc.c,v 1.19 2021/07/14 13:33:57 kn Exp $ */
2
3/*
4 * Copyright (c) 2018 Eric Faurot <eric@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/socket.h>
20
21#include <event.h>
22#include <netdb.h>
23#include <pwd.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <syslog.h>
28#include <tls.h>
29#include <unistd.h>
30
31#include "smtp.h"
32#include "log.h"
33
34static void parse_server(char *);
35static void parse_message(FILE *);
36static void resume(void);
37
38static int verbose = 1;
39static int done = 0;
40static int noaction = 0;
41static struct addrinfo *res0, *ai;
42static struct smtp_params params;
43static struct smtp_mail mail;
44static const char *servname = NULL((void*)0);
45static struct tls_config *tls_config;
46
47static int nosni = 0;
48static const char *cafile = NULL((void*)0);
49static const char *protocols = NULL((void*)0);
50static const char *ciphers = NULL((void*)0);
51
52static void
53usage(void)
54{
55 extern char *__progname;
56
57 fprintf(stderr(&__sF[2]), "usage: %s [-Chnv] [-a authfile] [-F from] [-H helo] "
58 "[-s server] [-T params] [recipient ...]\n", __progname);
59 exit(1);
60}
61
62static void
63parse_tls_options(char *opt)
64{
65 static char * const tokens[] = {
66#define CAFILE0 0
67 "cafile",
68#define CIPHERS1 1
69 "ciphers",
70#define NOSNI2 2
71 "nosni",
72#define NOVERIFY3 3
73 "noverify",
74#define PROTOCOLS4 4
75 "protocols",
76#define SERVERNAME5 5
77 "servername",
78 NULL((void*)0) };
79 char *value;
80
81 while (*opt) {
82 switch (getsubopt(&opt, tokens, &value)) {
83 case CAFILE0:
84 if (value == NULL((void*)0))
85 fatalx("missing value for cafile");
86 cafile = value;
87 break;
88 case CIPHERS1:
89 if (value == NULL((void*)0))
90 fatalx("missing value for ciphers");
91 ciphers = value;
92 break;
93 case NOSNI2:
94 if (value != NULL((void*)0))
95 fatalx("no value expected for nosni");
96 nosni = 1;
97 break;
98 case NOVERIFY3:
99 if (value != NULL((void*)0))
100 fatalx("no value expected for noverify");
101 params.tls_verify = 0;
102 break;
103 case PROTOCOLS4:
104 if (value == NULL((void*)0))
105 fatalx("missing value for protocols");
106 protocols = value;
107 break;
108 case SERVERNAME5:
109 if (value == NULL((void*)0))
110 fatalx("missing value for servername");
111 servname = value;
112 break;
113 case -1:
114 if (suboptarg)
115 fatalx("invalid TLS option \"%s\"", suboptarg);
116 fatalx("missing TLS option");
117 }
118 }
119}
120
121int
122main(int argc, char **argv)
123{
124 char hostname[256];
125 FILE *authfile;
126 int ch, i;
127 uint32_t protos;
128 char *server = "localhost";
129 char *authstr = NULL((void*)0);
130 size_t alloc = 0;
131 ssize_t len;
132 struct passwd *pw;
133
134 log_init(1, 0);
135
136 if (gethostname(hostname, sizeof(hostname)) == -1)
137 fatal("gethostname");
138
139 if ((pw = getpwuid(getuid())) == NULL((void*)0))
140 fatal("getpwuid");
141
142 memset(&params, 0, sizeof(params));
143
144 params.linemax = 16392;
145 params.ibufmax = 65536;
146 params.obufmax = 65536;
147 params.timeout = 100000;
148 params.helo = hostname;
149
150 params.tls_verify = 1;
151
152 memset(&mail, 0, sizeof(mail));
153 mail.from = pw->pw_name;
154
155 while ((ch = getopt(argc, argv, "CF:H:S:T:a:hns:v")) != -1) {
156 switch (ch) {
157 case 'C':
158 params.tls_verify = 0;
159 break;
160 case 'F':
161 mail.from = optarg;
162 break;
163 case 'H':
164 params.helo = optarg;
165 break;
166 case 'S':
167 servname = optarg;
168 break;
169 case 'T':
170 parse_tls_options(optarg);
171 break;
172 case 'a':
173 if ((authfile = fopen(optarg, "r")) == NULL((void*)0))
174 fatal("%s: open", optarg);
175 if ((len = getline(&authstr, &alloc, authfile)) == -1)
176 fatal("%s: Failed to read username", optarg);
177 if (authstr[len - 1] == '\n')
178 authstr[len - 1] = '\0';
179 params.auth_user = authstr;
180 authstr = NULL((void*)0);
181 len = 0;
Value stored to 'len' is never read
182 if ((len = getline(&authstr, &alloc, authfile)) == -1)
183 fatal("%s: Failed to read password", optarg);
184 if (authstr[len - 1] == '\n')
185 authstr[len - 1] = '\0';
186 params.auth_pass = authstr;
187 fclose(authfile);
188 break;
189 case 'h':
190 usage();
191 break;
192 case 'n':
193 noaction = 1;
194 break;
195 case 's':
196 server = optarg;
197 break;
198 case 'v':
199 verbose++;
200 break;
201 default:
202 usage();
203 }
204 }
205
206 log_setverbose(verbose);
207
208 argc -= optind;
209 argv += optind;
210
211 if (argc) {
212 mail.rcpt = calloc(argc, sizeof(*mail.rcpt));
213 if (mail.rcpt == NULL((void*)0))
214 fatal("calloc");
215 for (i = 0; i < argc; i++)
216 mail.rcpt[i].to = argv[i];
217 mail.rcptcount = argc;
218 }
219
220 event_init();
221
222 tls_config = tls_config_new();
223 if (tls_config == NULL((void*)0))
224 fatal("tls_config_new");
225
226 if (protocols) {
227 if (tls_config_parse_protocols(&protos, protocols) == -1)
228 fatalx("failed to parse protocol '%s'", protocols);
229 if (tls_config_set_protocols(tls_config, protos) == -1)
230 fatalx("tls_config_set_protocols: %s",
231 tls_config_error(tls_config));
232 }
233 if (ciphers && tls_config_set_ciphers(tls_config, ciphers) == -1)
234 fatalx("tls_config_set_ciphers: %s",
235 tls_config_error(tls_config));
236
237 if (cafile == NULL((void*)0))
238 cafile = tls_default_ca_cert_file();
239 if (tls_config_set_ca_file(tls_config, cafile) == -1)
240 fatal("tls_set_ca_file");
241 if (!params.tls_verify) {
242 tls_config_insecure_noverifycert(tls_config);
243 tls_config_insecure_noverifyname(tls_config);
244 tls_config_insecure_noverifytime(tls_config);
245 } else
246 tls_config_verify(tls_config);
247
248 if (pledge("stdio inet dns tmppath", NULL((void*)0)) == -1)
249 fatal("pledge");
250
251 if (!noaction)
252 parse_message(stdin(&__sF[0]));
253
254 if (pledge("stdio inet dns", NULL((void*)0)) == -1)
255 fatal("pledge");
256
257 parse_server(server);
258
259 if (pledge("stdio inet", NULL((void*)0)) == -1)
260 fatal("pledge");
261
262 resume();
263
264 log_debug("done...");
265
266 return 0;
267}
268
269static void
270parse_server(char *server)
271{
272 struct addrinfo hints;
273 char *scheme, *creds, *host, *port, *p, *c;
274 int error;
275
276 creds = NULL((void*)0);
277 host = NULL((void*)0);
278 port = NULL((void*)0);
279 scheme = server;
280
281 p = strstr(server, "://");
282 if (p) {
283 *p = '\0';
284 p += 3;
285 /* check for credentials */
286 c = strrchr(p, '@');
287 if (c) {
288 creds = p;
289 *c = '\0';
290 host = c + 1;
291 } else
292 host = p;
293 } else {
294 /* Assume a simple server name */
295 scheme = "smtp";
296 host = server;
297 }
298
299 if (host[0] == '[') {
300 /* IPV6 address? */
301 p = strchr(host, ']');
302 if (p) {
303 if (p[1] == ':' || p[1] == '\0') {
304 *p++ = '\0'; /* remove ']' */
305 host++; /* skip '[' */
306 if (*p == ':')
307 port = p + 1;
308 }
309 }
310 }
311 else {
312 port = strchr(host, ':');
313 if (port)
314 *port++ = '\0';
315 }
316
317 if (port && port[0] == '\0')
318 port = NULL((void*)0);
319
320 if (creds) {
321 p = strchr(creds, ':');
322 if (p == NULL((void*)0))
323 fatalx("invalid credentials");
324 *p = '\0';
325
326 params.auth_user = creds;
327 params.auth_pass = p + 1;
328 }
329 params.tls_req = TLS_YES1;
330
331 if (!strcmp(scheme, "lmtp")) {
332 params.lmtp = 1;
333 }
334 else if (!strcmp(scheme, "lmtp+tls")) {
335 params.lmtp = 1;
336 params.tls_req = TLS_FORCE2;
337 }
338 else if (!strcmp(scheme, "lmtp+notls")) {
339 params.lmtp = 1;
340 params.tls_req = TLS_NO0;
341 }
342 else if (!strcmp(scheme, "smtps")) {
343 params.tls_req = TLS_SMTPS3;
344 if (port == NULL((void*)0))
345 port = "smtps";
346 }
347 else if (!strcmp(scheme, "smtp")) {
348 }
349 else if (!strcmp(scheme, "smtp+tls")) {
350 params.tls_req = TLS_FORCE2;
351 }
352 else if (!strcmp(scheme, "smtp+notls")) {
353 params.tls_req = TLS_NO0;
354 }
355 else
356 fatalx("invalid url scheme %s", scheme);
357
358 if (port == NULL((void*)0))
359 port = "smtp";
360
361 if (servname == NULL((void*)0))
362 servname = host;
363 if (nosni == 0)
364 params.tls_servname = servname;
365
366 memset(&hints, 0, sizeof(hints));
367 hints.ai_family = AF_UNSPEC0;
368 hints.ai_socktype = SOCK_STREAM1;
369 error = getaddrinfo(host, port, &hints, &res0);
370 if (error)
371 fatalx("%s: %s", host, gai_strerror(error));
372 ai = res0;
373}
374
375void
376parse_message(FILE *ifp)
377{
378 char *line = NULL((void*)0);
379 size_t linesz = 0;
380 ssize_t len;
381
382 if ((mail.fp = tmpfile()) == NULL((void*)0))
383 fatal("tmpfile");
384
385 for (;;) {
386 if ((len = getline(&line, &linesz, ifp)) == -1) {
387 if (feof(ifp)(!__isthreaded ? (((ifp)->_flags & 0x0020) != 0) : (feof
)(ifp))
)
388 break;
389 fatal("getline");
390 }
391
392 if (len >= 2 && line[len - 2] == '\r' && line[len - 1] == '\n')
393 line[--len - 1] = '\n';
394
395 if (fwrite(line, 1, len, mail.fp) != len)
396 fatal("fwrite");
397
398 if (line[len - 1] != '\n' && fputc('\n', mail.fp) == EOF(-1))
399 fatal("fputc");
400 }
401
402 fclose(ifp);
403 rewind(mail.fp);
404}
405
406void
407resume(void)
408{
409 static int started = 0;
410 char host[256];
411 char serv[16];
412
413 if (done) {
414 event_loopexit(NULL((void*)0));
415 return;
416 }
417
418 if (ai == NULL((void*)0))
419 fatalx("no more host");
420
421 getnameinfo(ai->ai_addr, ai->ai_addr->sa_len,
422 host, sizeof(host), serv, sizeof(serv),
423 NI_NUMERICHOST1 | NI_NUMERICSERV2);
424 log_debug("trying host %s port %s...", host, serv);
425
426 params.dst = ai->ai_addr;
427 if (smtp_connect(&params, NULL((void*)0)) == NULL((void*)0))
428 fatal("smtp_connect");
429
430 if (started == 0) {
431 started = 1;
432 event_loop(0);
433 }
434}
435
436void
437log_trace(int lvl, const char *emsg, ...)
438{
439 va_list ap;
440
441 if (verbose > lvl) {
442 va_start(ap, emsg)__builtin_va_start(ap, emsg);
443 vlog(LOG_DEBUG7, emsg, ap);
444 va_end(ap)__builtin_va_end(ap);
445 }
446}
447
448void
449smtp_require_tls(void *tag, struct smtp_client *proto)
450{
451 struct tls *tls;
452
453 tls = tls_client();
454 if (tls == NULL((void*)0))
455 fatal("tls_client");
456
457 if (tls_configure(tls, tls_config) == -1)
458 fatal("tls_configure");
459
460 smtp_set_tls(proto, tls);
461}
462
463void
464smtp_ready(void *tag, struct smtp_client *proto)
465{
466 log_debug("connection ready...");
467
468 if (done || noaction)
469 smtp_quit(proto);
470 else
471 smtp_sendmail(proto, &mail);
472}
473
474void
475smtp_failed(void *tag, struct smtp_client *proto, int failure, const char *detail)
476{
477 switch (failure) {
478 case FAIL_INTERNAL1:
479 log_warnx("internal error: %s", detail);
480 break;
481 case FAIL_CONN2:
482 log_warnx("connection error: %s", detail);
483 break;
484 case FAIL_PROTO3:
485 log_warnx("protocol error: %s", detail);
486 break;
487 case FAIL_IMPL4:
488 log_warnx("missing feature: %s", detail);
489 break;
490 case FAIL_RESP5:
491 log_warnx("rejected by server: %s", detail);
492 break;
493 default:
494 fatalx("unknown failure %d: %s", failure, detail);
495 }
496}
497
498void
499smtp_status(void *tag, struct smtp_client *proto, struct smtp_status *status)
500{
501 log_info("%s: %s: %s", status->rcpt->to, status->cmd, status->status);
502}
503
504void
505smtp_done(void *tag, struct smtp_client *proto, struct smtp_mail *mail)
506{
507 int i;
508
509 log_debug("mail done...");
510
511 if (noaction)
512 return;
513
514 for (i = 0; i < mail->rcptcount; i++)
515 if (!mail->rcpt[i].done)
516 return;
517
518 done = 1;
519}
520
521void
522smtp_closed(void *tag, struct smtp_client *proto)
523{
524 log_debug("connection closed...");
525
526 ai = ai->ai_next;
527 if (noaction && ai == NULL((void*)0))
528 done = 1;
529
530 resume();
531}