Bug Summary

File:src/usr.bin/ftp/main.c
Warning:line 783, column 8
Array access (from variable 'buf') results in a null pointer dereference

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 main.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.bin/ftp/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/ftp/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.bin/ftp/main.c
1/* $OpenBSD: main.c,v 1.138 2021/07/14 13:33:57 kn Exp $ */
2/* $NetBSD: main.c,v 1.24 1997/08/18 10:20:26 lukem Exp $ */
3
4/*
5 * Copyright (C) 1997 and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33/*
34 * Copyright (c) 1985, 1989, 1993, 1994
35 * The Regents of the University of California. All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 */
61
62/*
63 * FTP User Program -- Command Interface.
64 */
65#include <sys/types.h>
66#include <sys/socket.h>
67
68#include <ctype.h>
69#include <err.h>
70#include <fcntl.h>
71#include <netdb.h>
72#include <pwd.h>
73#include <stdio.h>
74#include <errno(*__errno()).h>
75#include <stdlib.h>
76#include <string.h>
77#include <unistd.h>
78
79#include <tls.h>
80
81#include "cmds.h"
82#include "ftp_var.h"
83
84int trace;
85int hash;
86int mark;
87int sendport;
88int verbose;
89int connected;
90int fromatty;
91int interactive;
92#ifndef SMALL
93int confirmrest;
94int debug;
95int bell;
96char *altarg;
97#endif /* !SMALL */
98int doglob;
99int autologin;
100int proxy;
101int proxflag;
102int gatemode;
103char *gateserver;
104int sunique;
105int runique;
106int mcase;
107int ntflag;
108int mapflag;
109int preserve;
110int progress;
111int code;
112int crflag;
113char pasv[BUFSIZ1024];
114int passivemode;
115int activefallback;
116char ntin[17];
117char ntout[17];
118char mapin[PATH_MAX1024];
119char mapout[PATH_MAX1024];
120char typename[32];
121int type;
122int curtype;
123char structname[32];
124int stru;
125char formname[32];
126int form;
127char modename[32];
128int mode;
129char bytename[32];
130int bytesize;
131int anonftp;
132int dirchange;
133unsigned int retry_connect;
134int ttywidth;
135int epsv4;
136int epsv4bad;
137
138#ifndef SMALL
139int editing;
140EditLine *el;
141History *hist;
142char *cursor_pos;
143size_t cursor_argc;
144size_t cursor_argo;
145int resume;
146char *srcaddr;
147int timestamp;
148#endif /* !SMALL */
149
150char *cookiefile;
151
152off_t bytes;
153off_t filesize;
154char *direction;
155
156char *hostname;
157int unix_server;
158int unix_proxy;
159
160char *ftpport;
161char *httpport;
162#ifndef NOSSL
163char *httpsport;
164#endif /* !SMALL */
165char *httpuseragent;
166char *gateport;
167
168jmp_buf toplevel;
169
170#ifndef SMALL
171char line[FTPBUFLEN1024 + 200];
172char *argbase;
173char *stringbase;
174char argbuf[FTPBUFLEN1024 + 200];
175StringList *marg_sl;
176int margc;
177int options;
178#endif /* !SMALL */
179
180int cpend;
181int mflag;
182
183#ifndef SMALL
184int macnum;
185struct macel macros[16];
186char macbuf[4096];
187#endif /* !SMALL */
188
189FILE *ttyout;
190
191int connect_timeout;
192
193#ifndef SMALL
194/* enable using server timestamps by default */
195int server_timestamps = 1;
196#endif
197
198#ifndef NOSSL
199char * const ssl_verify_opts[] = {
200#define SSL_CAFILE0 0
201 "cafile",
202#define SSL_CAPATH1 1
203 "capath",
204#define SSL_CIPHERS2 2
205 "ciphers",
206#define SSL_DONTVERIFY3 3
207 "dont",
208#define SSL_DOVERIFY4 4
209 "do",
210#define SSL_VERIFYDEPTH5 5
211 "depth",
212#define SSL_MUSTSTAPLE6 6
213 "muststaple",
214#define SSL_NOVERIFYTIME7 7
215 "noverifytime",
216#define SSL_SESSION8 8
217 "session",
218#define SSL_PROTOCOLS9 9
219 "protocols",
220 NULL((void*)0)
221};
222
223struct tls_config *tls_config;
224int tls_session_fd = -1;
225
226static void
227process_ssl_options(char *cp)
228{
229 const char *errstr;
230 char *str;
231 int depth;
232 uint32_t protocols;
233
234 while (*cp) {
235 switch (getsubopt(&cp, ssl_verify_opts, &str)) {
236 case SSL_CAFILE0:
237 if (str == NULL((void*)0))
238 errx(1, "missing CA file");
239 if (tls_config_set_ca_file(tls_config, str) != 0)
240 errx(1, "tls ca file failed: %s",
241 tls_config_error(tls_config));
242 break;
243 case SSL_CAPATH1:
244 if (str == NULL((void*)0))
245 errx(1, "missing CA directory path");
246 if (tls_config_set_ca_path(tls_config, str) != 0)
247 errx(1, "tls ca path failed: %s",
248 tls_config_error(tls_config));
249 break;
250 case SSL_CIPHERS2:
251 if (str == NULL((void*)0))
252 errx(1, "missing cipher list");
253 if (tls_config_set_ciphers(tls_config, str) != 0)
254 errx(1, "tls ciphers failed: %s",
255 tls_config_error(tls_config));
256 break;
257 case SSL_DONTVERIFY3:
258 tls_config_insecure_noverifycert(tls_config);
259 tls_config_insecure_noverifyname(tls_config);
260 break;
261 case SSL_DOVERIFY4:
262 tls_config_verify(tls_config);
263 break;
264 case SSL_VERIFYDEPTH5:
265 if (str == NULL((void*)0))
266 errx(1, "missing depth");
267 depth = strtonum(str, 0, INT_MAX2147483647, &errstr);
268 if (errstr)
269 errx(1, "certificate validation depth is %s",
270 errstr);
271 tls_config_set_verify_depth(tls_config, depth);
272 break;
273 case SSL_MUSTSTAPLE6:
274 tls_config_ocsp_require_stapling(tls_config);
275 break;
276 case SSL_NOVERIFYTIME7:
277 tls_config_insecure_noverifytime(tls_config);
278 break;
279 case SSL_SESSION8:
280 if (str == NULL((void*)0))
281 errx(1, "missing session file");
282 if ((tls_session_fd = open(str, O_RDWR0x0002|O_CREAT0x0200,
283 0600)) == -1)
284 err(1, "failed to open or create session file "
285 "'%s'", str);
286 if (tls_config_set_session_fd(tls_config,
287 tls_session_fd) == -1)
288 errx(1, "failed to set session: %s",
289 tls_config_error(tls_config));
290 break;
291 case SSL_PROTOCOLS9:
292 if (str == NULL((void*)0))
293 errx(1, "missing protocol name");
294 if (tls_config_parse_protocols(&protocols, str) != 0)
295 errx(1, "failed to parse TLS protocols");
296 if (tls_config_set_protocols(tls_config, protocols) != 0)
297 errx(1, "failed to set TLS protocols: %s",
298 tls_config_error(tls_config));
299 break;
300 default:
301 errx(1, "unknown -S suboption `%s'",
302 suboptarg ? suboptarg : "");
303 /* NOTREACHED */
304 }
305 }
306}
307#endif /* !NOSSL */
308
309int family = PF_UNSPEC0;
310int pipeout;
311
312int
313main(volatile int argc, char *argv[])
314{
315 int ch, rval;
316#ifndef SMALL
317 int top;
318#endif
319 struct passwd *pw = NULL((void*)0);
320 char *cp, homedir[PATH_MAX1024];
321 char *outfile = NULL((void*)0);
322 const char *errstr;
323 int dumb_terminal = 0;
324
325 ftpport = "ftp";
326 httpport = "http";
327#ifndef NOSSL
328 httpsport = "https";
329#endif /* !NOSSL */
330 gateport = getenv("FTPSERVERPORT");
331 if (gateport == NULL((void*)0) || *gateport == '\0')
1
Assuming 'gateport' is not equal to NULL
2
Assuming the condition is false
3
Taking false branch
332 gateport = "ftpgate";
333 doglob = 1;
334 interactive = 1;
335 autologin = 1;
336 passivemode = 1;
337 activefallback = 1;
338 preserve = 1;
339 verbose = 0;
340 progress = 0;
341 gatemode = 0;
342#ifndef NOSSL
343 cookiefile = NULL((void*)0);
344#endif /* NOSSL */
345#ifndef SMALL
346 editing = 0;
347 el = NULL((void*)0);
348 hist = NULL((void*)0);
349 resume = 0;
350 timestamp = 0;
351 srcaddr = NULL((void*)0);
352 marg_sl = sl_init();
353#endif /* !SMALL */
354 mark = HASHBYTES1024;
355 epsv4 = 1;
356 epsv4bad = 0;
357
358 /* Set default operation mode based on FTPMODE environment variable */
359 if ((cp = getenv("FTPMODE")) != NULL((void*)0) && *cp != '\0') {
4
Assuming the condition is false
360 if (strcmp(cp, "passive") == 0) {
361 passivemode = 1;
362 activefallback = 0;
363 } else if (strcmp(cp, "active") == 0) {
364 passivemode = 0;
365 activefallback = 0;
366 } else if (strcmp(cp, "gate") == 0) {
367 gatemode = 1;
368 } else if (strcmp(cp, "auto") == 0) {
369 passivemode = 1;
370 activefallback = 1;
371 } else
372 warnx("unknown FTPMODE: %s. Using defaults", cp);
373 }
374
375 if (strcmp(__progname, "gate-ftp") == 0)
5
Assuming the condition is false
6
Taking false branch
376 gatemode = 1;
377 gateserver = getenv("FTPSERVER");
378 if (gateserver == NULL((void*)0))
7
Assuming 'gateserver' is not equal to NULL
8
Taking false branch
379 gateserver = "";
380 if (gatemode) {
9
Assuming 'gatemode' is 0
10
Taking false branch
381 if (*gateserver == '\0') {
382 warnx(
383"Neither $FTPSERVER nor $GATE_SERVER is defined; disabling gate-ftp");
384 gatemode = 0;
385 }
386 }
387
388 cp = getenv("TERM");
389 dumb_terminal = (cp == NULL((void*)0) || *cp == '\0' || !strcmp(cp, "dumb") ||
11
Assuming 'cp' is not equal to NULL
12
Assuming the condition is true
390 !strcmp(cp, "emacs") || !strcmp(cp, "su"));
391 fromatty = isatty(fileno(stdin)(!__isthreaded ? (((&__sF[0]))->_file) : (fileno)((&
__sF[0])))
);
13
Assuming '__isthreaded' is not equal to 0
14
'?' condition is false
392 if (fromatty) {
15
Assuming 'fromatty' is 0
16
Taking false branch
393 verbose = 1; /* verbose if from a tty */
394#ifndef SMALL
395 if (!dumb_terminal)
396 editing = 1; /* editing mode on if tty is usable */
397#endif /* !SMALL */
398 }
399
400 ttyout = stdout(&__sF[1]);
401 if (isatty(fileno(ttyout)(!__isthreaded ? ((ttyout)->_file) : (fileno)(ttyout))) && !dumb_terminal && foregroundproc())
17
'?' condition is false
18
Assuming the condition is false
402 progress = 1; /* progress bar on if tty is usable */
403
404#ifndef NOSSL
405 cookiefile = getenv("http_cookies");
406 if (tls_config == NULL((void*)0)) {
19
Assuming 'tls_config' is not equal to NULL
20
Taking false branch
407 tls_config = tls_config_new();
408 if (tls_config == NULL((void*)0))
409 errx(1, "tls config failed");
410 if (tls_config_set_protocols(tls_config,
411 TLS_PROTOCOLS_ALL((1 << 1)|(1 << 2)| (1 << 3)|(1 << 4)
)
) != 0)
412 errx(1, "tls set protocols failed: %s",
413 tls_config_error(tls_config));
414 if (tls_config_set_ciphers(tls_config, "legacy") != 0)
415 errx(1, "tls set ciphers failed: %s",
416 tls_config_error(tls_config));
417 }
418#endif /* !NOSSL */
419
420 httpuseragent = NULL((void*)0);
421
422 while ((ch = getopt(argc, argv,
21
Assuming the condition is false
22
Loop condition is false. Execution continues on line 586
423 "46AaCc:dD:EeN:gik:Mmno:pP:r:S:s:TtU:uvVw:")) != -1) {
424 switch (ch) {
425 case '4':
426 family = PF_INET2;
427 break;
428 case '6':
429 family = PF_INET624;
430 break;
431 case 'A':
432 activefallback = 0;
433 passivemode = 0;
434 break;
435
436 case 'N':
437 setprogname(optarg);
438 break;
439 case 'a':
440 anonftp = 1;
441 break;
442
443 case 'C':
444#ifndef SMALL
445 resume = 1;
446#endif /* !SMALL */
447 break;
448
449 case 'c':
450#ifndef SMALL
451 cookiefile = optarg;
452#endif /* !SMALL */
453 break;
454
455 case 'D':
456 action = optarg;
457 break;
458 case 'd':
459#ifndef SMALL
460 options |= SO_DEBUG0x0001;
461 debug++;
462#endif /* !SMALL */
463 break;
464
465 case 'E':
466 epsv4 = 0;
467 break;
468
469 case 'e':
470#ifndef SMALL
471 editing = 0;
472#endif /* !SMALL */
473 break;
474
475 case 'g':
476 doglob = 0;
477 break;
478
479 case 'i':
480 interactive = 0;
481 break;
482
483 case 'k':
484 keep_alive_timeout = strtonum(optarg, 0, INT_MAX2147483647,
485 &errstr);
486 if (errstr != NULL((void*)0)) {
487 warnx("keep alive amount is %s: %s", errstr,
488 optarg);
489 usage();
490 }
491 break;
492 case 'M':
493 progress = 0;
494 break;
495 case 'm':
496 progress = -1;
497 break;
498
499 case 'n':
500 autologin = 0;
501 break;
502
503 case 'o':
504 outfile = optarg;
505 if (*outfile == '\0') {
506 pipeout = 0;
507 outfile = NULL((void*)0);
508 ttyout = stdout(&__sF[1]);
509 } else {
510 pipeout = strcmp(outfile, "-") == 0;
511 ttyout = pipeout ? stderr(&__sF[2]) : stdout(&__sF[1]);
512 }
513 break;
514
515 case 'p':
516 passivemode = 1;
517 activefallback = 0;
518 break;
519
520 case 'P':
521 ftpport = optarg;
522 break;
523
524 case 'r':
525 retry_connect = strtonum(optarg, 0, INT_MAX2147483647, &errstr);
526 if (errstr != NULL((void*)0)) {
527 warnx("retry amount is %s: %s", errstr,
528 optarg);
529 usage();
530 }
531 break;
532
533 case 'S':
534#ifndef NOSSL
535 process_ssl_options(optarg);
536#endif /* !NOSSL */
537 break;
538
539 case 's':
540#ifndef SMALL
541 srcaddr = optarg;
542#endif /* !SMALL */
543 break;
544
545#ifndef SMALL
546 case 'T':
547 timestamp = 1;
548 break;
549#endif /* !SMALL */
550 case 't':
551 trace = 1;
552 break;
553
554#ifndef SMALL
555 case 'U':
556 free (httpuseragent);
557 if (strcspn(optarg, "\r\n") != strlen(optarg))
558 errx(1, "Invalid User-Agent: %s.", optarg);
559 if (asprintf(&httpuseragent, "User-Agent: %s",
560 optarg) == -1)
561 errx(1, "Can't allocate memory for HTTP(S) "
562 "User-Agent");
563 break;
564 case 'u':
565 server_timestamps = 0;
566 break;
567#endif /* !SMALL */
568
569 case 'v':
570 verbose = 1;
571 break;
572
573 case 'V':
574 verbose = 0;
575 break;
576
577 case 'w':
578 connect_timeout = strtonum(optarg, 0, 200, &errstr);
579 if (errstr)
580 errx(1, "-w: %s", errstr);
581 break;
582 default:
583 usage();
584 }
585 }
586 argc -= optind;
587 argv += optind;
588
589#ifndef NOSSL
590 cookie_load();
591#endif /* !NOSSL */
592 if (httpuseragent == NULL((void*)0))
23
Assuming 'httpuseragent' is not equal to NULL
24
Taking false branch
593 httpuseragent = HTTP_USER_AGENT"User-Agent: OpenBSD ftp";
594
595 cpend = 0; /* no pending replies */
596 proxy = 0; /* proxy not active */
597 crflag = 1; /* strip c.r. on ascii gets */
598 sendport = -1; /* not using ports */
599 /*
600 * Set up the home directory in case we're globbing.
601 */
602 cp = getlogin();
603 if (cp != NULL((void*)0)) {
25
Assuming 'cp' is equal to NULL
26
Taking false branch
604 pw = getpwnam(cp);
605 }
606 if (pw
26.1
'pw' is equal to NULL
== NULL((void*)0))
27
Taking true branch
607 pw = getpwuid(getuid());
608 if (pw != NULL((void*)0)) {
28
Assuming 'pw' is equal to NULL
29
Taking false branch
609 (void)strlcpy(homedir, pw->pw_dir, sizeof homedir);
610 home = homedir;
611 }
612
613 setttywidth(0);
614 (void)signal(SIGWINCH28, setttywidth);
615
616 if (argc > 0) {
30
Assuming 'argc' is <= 0
31
Taking false branch
617 if (isurl(argv[0])) {
618 if (pipeout) {
619#ifndef SMALL
620 if (pledge("stdio rpath dns tty inet proc exec fattr",
621 NULL((void*)0)) == -1)
622 err(1, "pledge");
623#else
624 if (pledge("stdio rpath dns tty inet fattr",
625 NULL((void*)0)) == -1)
626 err(1, "pledge");
627#endif
628 } else {
629#ifndef SMALL
630 if (pledge("stdio rpath wpath cpath dns tty inet proc exec fattr",
631 NULL((void*)0)) == -1)
632 err(1, "pledge");
633#else
634 if (pledge("stdio rpath wpath cpath dns tty inet fattr",
635 NULL((void*)0)) == -1)
636 err(1, "pledge");
637#endif
638 }
639
640 rval = auto_fetch(argc, argv, outfile);
641 if (rval >= 0) /* -1 == connected and cd-ed */
642 exit(rval);
643 } else {
644#ifndef SMALL
645 char *xargv[5];
646
647 if (setjmp(toplevel))
648 exit(0);
649 (void)signal(SIGINT2, (sig_t)intr);
650 (void)signal(SIGPIPE13, (sig_t)lostpeer);
651 xargv[0] = __progname;
652 xargv[1] = argv[0];
653 xargv[2] = argv[1];
654 xargv[3] = argv[2];
655 xargv[4] = NULL((void*)0);
656 do {
657 setpeer(argc+1, xargv);
658 if (!retry_connect)
659 break;
660 if (!connected) {
661 macnum = 0;
662 fputs("Retrying...\n", ttyout);
663 sleep(retry_connect);
664 }
665 } while (!connected);
666 retry_connect = 0; /* connected, stop hiding msgs */
667#endif /* !SMALL */
668 }
669 }
670#ifndef SMALL
671 controlediting();
672 top = setjmp(toplevel) == 0;
32
Assuming the condition is false
673 if (top
32.1
'top' is 0
) {
33
Taking false branch
674 (void)signal(SIGINT2, (sig_t)intr);
675 (void)signal(SIGPIPE13, (sig_t)lostpeer);
676 }
677 for (;;) {
34
Loop condition is true. Entering loop body
678 cmdscanner(top);
35
Calling 'cmdscanner'
679 top = 1;
680 }
681#else /* !SMALL */
682 usage();
683#endif /* !SMALL */
684}
685
686void
687intr(void)
688{
689 int save_errno = errno(*__errno());
690
691 write(fileno(ttyout)(!__isthreaded ? ((ttyout)->_file) : (fileno)(ttyout)), "\n\r", 2);
692 alarmtimer(0);
693
694 errno(*__errno()) = save_errno;
695 longjmp(toplevel, 1);
696}
697
698void
699lostpeer(void)
700{
701 int save_errno = errno(*__errno());
702
703 alarmtimer(0);
704 if (connected) {
705 if (cout != NULL((void*)0)) {
706 (void)shutdown(fileno(cout)(!__isthreaded ? ((cout)->_file) : (fileno)(cout)), SHUT_RDWR2);
707 (void)fclose(cout);
708 cout = NULL((void*)0);
709 }
710 if (data >= 0) {
711 (void)shutdown(data, SHUT_RDWR2);
712 (void)close(data);
713 data = -1;
714 }
715 connected = 0;
716 }
717 pswitch(1);
718 if (connected) {
719 if (cout != NULL((void*)0)) {
720 (void)shutdown(fileno(cout)(!__isthreaded ? ((cout)->_file) : (fileno)(cout)), SHUT_RDWR2);
721 (void)fclose(cout);
722 cout = NULL((void*)0);
723 }
724 connected = 0;
725 }
726 proxflag = 0;
727 pswitch(0);
728 errno(*__errno()) = save_errno;
729}
730
731#ifndef SMALL
732/*
733 * Generate a prompt
734 */
735char *
736prompt(void)
737{
738 return ("ftp> ");
739}
740
741/*
742 * Command parser.
743 */
744void
745cmdscanner(int top)
746{
747 struct cmd *c;
748 int num;
749 HistEvent hev;
750
751 if (!top
35.1
'top' is 0
&& !editing)
36
Assuming 'editing' is not equal to 0
37
Taking false branch
752 (void)putc('\n', ttyout)(!__isthreaded ? __sputc('\n', ttyout) : (putc)('\n', ttyout)
)
;
753 for (;;) {
38
Loop condition is true. Entering loop body
754 if (!editing
38.1
'editing' is not equal to 0
) {
39
Taking false branch
755 if (fromatty) {
756 fputs(prompt(), ttyout);
757 (void)fflush(ttyout);
758 }
759 if (fgets(line, sizeof(line), stdin(&__sF[0])) == NULL((void*)0))
760 quit(0, 0);
761 num = strlen(line);
762 if (num == 0)
763 break;
764 if (line[--num] == '\n') {
765 if (num == 0)
766 break;
767 line[num] = '\0';
768 } else if (num == sizeof(line) - 2) {
769 fputs("sorry, input line too long.\n", ttyout);
770 while ((num = getchar()(!__isthreaded ? (--((&__sF[0]))->_r < 0 ? __srget(
(&__sF[0])) : (int)(*((&__sF[0]))->_p++)) : (getc)
((&__sF[0])))
) != '\n' && num != EOF(-1))
771 /* void */;
772 break;
773 } /* else it was a line without a newline */
774 } else {
775 const char *buf;
776 cursor_pos = NULL((void*)0);
777
778 if ((buf = el_gets(el, &num)) == NULL((void*)0) || num == 0) {
40
Value assigned to 'buf'
41
Assuming pointer value is null
779 putc('\n', ttyout)(!__isthreaded ? __sputc('\n', ttyout) : (putc)('\n', ttyout)
)
;
42
'?' condition is false
780 fflush(ttyout);
781 quit(0, 0);
782 }
783 if (buf[--num] == '\n') {
43
Array access (from variable 'buf') results in a null pointer dereference
784 if (num == 0)
785 break;
786 }
787 if (num >= sizeof(line)) {
788 fputs("sorry, input line too long.\n", ttyout);
789 break;
790 }
791 memcpy(line, buf, (size_t)num);
792 line[num] = '\0';
793 history(hist, &hev, H_ENTER10, buf);
794 }
795
796 makeargv();
797 if (margc == 0)
798 continue;
799 c = getcmd(margv(marg_sl->sl_str)[0]);
800 if (c == (struct cmd *)-1) {
801 fputs("?Ambiguous command.\n", ttyout);
802 continue;
803 }
804 if (c == 0) {
805 /*
806 * Give editline(3) a shot at unknown commands.
807 * XXX - bogus commands with a colon in
808 * them will not elicit an error.
809 */
810 if (editing &&
811 el_parse(el, margc, (const char **)margv(marg_sl->sl_str)) != 0)
812 fputs("?Invalid command.\n", ttyout);
813 continue;
814 }
815 if (c->c_conn && !connected) {
816 fputs("Not connected.\n", ttyout);
817 continue;
818 }
819 confirmrest = 0;
820 (*c->c_handler)(margc, margv(marg_sl->sl_str));
821 if (bell && c->c_bell)
822 (void)putc('\007', ttyout)(!__isthreaded ? __sputc('\007', ttyout) : (putc)('\007', ttyout
))
;
823 if (c->c_handler != help)
824 break;
825 }
826 (void)signal(SIGINT2, (sig_t)intr);
827 (void)signal(SIGPIPE13, (sig_t)lostpeer);
828}
829
830struct cmd *
831getcmd(const char *name)
832{
833 const char *p, *q;
834 struct cmd *c, *found;
835 int nmatches, longest;
836
837 if (name == NULL((void*)0))
838 return (0);
839
840 longest = 0;
841 nmatches = 0;
842 found = 0;
843 for (c = cmdtab; (p = c->c_name) != NULL((void*)0); c++) {
844 for (q = name; *q == *p++; q++)
845 if (*q == 0) /* exact match? */
846 return (c);
847 if (!*q) { /* the name was a prefix */
848 if (q - name > longest) {
849 longest = q - name;
850 nmatches = 1;
851 found = c;
852 } else if (q - name == longest)
853 nmatches++;
854 }
855 }
856 if (nmatches > 1)
857 return ((struct cmd *)-1);
858 return (found);
859}
860
861/*
862 * Slice a string up into argc/argv.
863 */
864
865int slrflag;
866
867void
868makeargv(void)
869{
870 char *argp;
871
872 stringbase = line; /* scan from first of buffer */
873 argbase = argbuf; /* store from first of buffer */
874 slrflag = 0;
875 marg_sl->sl_cur = 0; /* reset to start of marg_sl */
876 for (margc = 0; ; margc++) {
877 argp = slurpstring();
878 sl_add(marg_sl, argp);
879 if (argp == NULL((void*)0))
880 break;
881 }
882 if (cursor_pos == line) {
883 cursor_argc = 0;
884 cursor_argo = 0;
885 } else if (cursor_pos != NULL((void*)0)) {
886 cursor_argc = margc;
887 cursor_argo = strlen(margv(marg_sl->sl_str)[margc-1]);
888 }
889}
890
891#define INC_CHKCURSOR(x){ (x)++ ; if (x == cursor_pos) { cursor_argc = margc; cursor_argo
= ap-argbase; cursor_pos = ((void*)0); } }
{ (x)++ ; \
892 if (x == cursor_pos) { \
893 cursor_argc = margc; \
894 cursor_argo = ap-argbase; \
895 cursor_pos = NULL((void*)0); \
896 } }
897
898/*
899 * Parse string into argbuf;
900 * implemented with FSM to
901 * handle quoting and strings
902 */
903char *
904slurpstring(void)
905{
906 int got_one = 0;
907 char *sb = stringbase;
908 char *ap = argbase;
909 char *tmp = argbase; /* will return this if token found */
910
911 if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */
912 switch (slrflag) { /* and $ as token for macro invoke */
913 case 0:
914 slrflag++;
915 INC_CHKCURSOR(stringbase){ (stringbase)++ ; if (stringbase == cursor_pos) { cursor_argc
= margc; cursor_argo = ap-argbase; cursor_pos = ((void*)0); }
}
;
916 return ((*sb == '!') ? "!" : "$");
917 /* NOTREACHED */
918 case 1:
919 slrflag++;
920 altarg = stringbase;
921 break;
922 default:
923 break;
924 }
925 }
926
927S0:
928 switch (*sb) {
929
930 case '\0':
931 goto OUT;
932
933 case ' ':
934 case '\t':
935 INC_CHKCURSOR(sb){ (sb)++ ; if (sb == cursor_pos) { cursor_argc = margc; cursor_argo
= ap-argbase; cursor_pos = ((void*)0); } }
;
936 goto S0;
937
938 default:
939 switch (slrflag) {
940 case 0:
941 slrflag++;
942 break;
943 case 1:
944 slrflag++;
945 altarg = sb;
946 break;
947 default:
948 break;
949 }
950 goto S1;
951 }
952
953S1:
954 switch (*sb) {
955
956 case ' ':
957 case '\t':
958 case '\0':
959 goto OUT; /* end of token */
960
961 case '\\':
962 INC_CHKCURSOR(sb){ (sb)++ ; if (sb == cursor_pos) { cursor_argc = margc; cursor_argo
= ap-argbase; cursor_pos = ((void*)0); } }
;
963 goto S2; /* slurp next character */
964
965 case '"':
966 INC_CHKCURSOR(sb){ (sb)++ ; if (sb == cursor_pos) { cursor_argc = margc; cursor_argo
= ap-argbase; cursor_pos = ((void*)0); } }
;
967 goto S3; /* slurp quoted string */
968
969 default:
970 *ap = *sb; /* add character to token */
971 ap++;
972 INC_CHKCURSOR(sb){ (sb)++ ; if (sb == cursor_pos) { cursor_argc = margc; cursor_argo
= ap-argbase; cursor_pos = ((void*)0); } }
;
973 got_one = 1;
974 goto S1;
975 }
976
977S2:
978 switch (*sb) {
979
980 case '\0':
981 goto OUT;
982
983 default:
984 *ap = *sb;
985 ap++;
986 INC_CHKCURSOR(sb){ (sb)++ ; if (sb == cursor_pos) { cursor_argc = margc; cursor_argo
= ap-argbase; cursor_pos = ((void*)0); } }
;
987 got_one = 1;
988 goto S1;
989 }
990
991S3:
992 switch (*sb) {
993
994 case '\0':
995 goto OUT;
996
997 case '"':
998 INC_CHKCURSOR(sb){ (sb)++ ; if (sb == cursor_pos) { cursor_argc = margc; cursor_argo
= ap-argbase; cursor_pos = ((void*)0); } }
;
999 goto S1;
1000
1001 default:
1002 *ap = *sb;
1003 ap++;
1004 INC_CHKCURSOR(sb){ (sb)++ ; if (sb == cursor_pos) { cursor_argc = margc; cursor_argo
= ap-argbase; cursor_pos = ((void*)0); } }
;
1005 got_one = 1;
1006 goto S3;
1007 }
1008
1009OUT:
1010 if (got_one)
1011 *ap++ = '\0';
1012 argbase = ap; /* update storage pointer */
1013 stringbase = sb; /* update scan pointer */
1014 if (got_one) {
1015 return (tmp);
1016 }
1017 switch (slrflag) {
1018 case 0:
1019 slrflag++;
1020 break;
1021 case 1:
1022 slrflag++;
1023 altarg = (char *) 0;
1024 break;
1025 default:
1026 break;
1027 }
1028 return (NULL((void*)0));
1029}
1030
1031/*
1032 * Help command.
1033 * Call each command handler with argc == 0 and argv[0] == name.
1034 */
1035void
1036help(int argc, char *argv[])
1037{
1038 struct cmd *c;
1039
1040 if (argc == 1) {
1041 StringList *buf;
1042
1043 buf = sl_init();
1044 fprintf(ttyout, "%sommands may be abbreviated. Commands are:\n\n",
1045 proxy ? "Proxy c" : "C");
1046 for (c = cmdtab; c < &cmdtab[NCMDS]; c++)
1047 if (c->c_name && (!proxy || c->c_proxy))
1048 sl_add(buf, c->c_name);
1049 list_vertical(buf);
1050 sl_free(buf, 0);
1051 return;
1052 }
1053
1054#define HELPINDENT((int) sizeof("disconnect")) ((int) sizeof("disconnect"))
1055
1056 while (--argc > 0) {
1057 char *arg;
1058
1059 arg = *++argv;
1060 c = getcmd(arg);
1061 if (c == (struct cmd *)-1)
1062 fprintf(ttyout, "?Ambiguous help command %s\n", arg);
1063 else if (c == NULL((void*)0))
1064 fprintf(ttyout, "?Invalid help command %s\n", arg);
1065 else
1066 fprintf(ttyout, "%-*s\t%s\n", HELPINDENT((int) sizeof("disconnect")),
1067 c->c_name, c->c_help);
1068 }
1069}
1070#endif /* !SMALL */
1071
1072__dead__attribute__((__noreturn__)) void
1073usage(void)
1074{
1075 fprintf(stderr(&__sF[2]), "usage: "
1076#ifndef SMALL
1077 "ftp [-46AadEegiMmnptVv] [-D title] [-k seconds] [-P port] "
1078 "[-r seconds]\n"
1079 " [-s sourceaddr] [host [port]]\n"
1080 " ftp [-C] [-N name] [-o output] [-s sourceaddr]\n"
1081 " ftp://[user:password@]host[:port]/file[/] ...\n"
1082 " ftp [-CTu] [-c cookie] [-N name] [-o output] [-S ssl_options] "
1083 "[-s sourceaddr]\n"
1084 " [-U useragent] [-w seconds] "
1085 "http[s]://[user:password@]host[:port]/file ...\n"
1086 " ftp [-C] [-N name] [-o output] [-s sourceaddr] file:file ...\n"
1087 " ftp [-C] [-N name] [-o output] [-s sourceaddr] host:/file[/] ...\n"
1088#else /* !SMALL */
1089 "ftp [-N name] [-o output] "
1090 "ftp://[user:password@]host[:port]/file[/] ...\n"
1091#ifndef NOSSL
1092 " ftp [-N name] [-o output] [-S ssl_options] [-w seconds] "
1093 "http[s]://[user:password@]host[:port]/file ...\n"
1094#else
1095 " ftp [-N name] [-o output] [-w seconds] http://host[:port]/file ...\n"
1096#endif /* NOSSL */
1097 " ftp [-N name] [-o output] file:file ...\n"
1098 " ftp [-N name] [-o output] host:/file[/] ...\n"
1099#endif /* !SMALL */
1100 );
1101 exit(1);
1102}