Bug Summary

File:src/usr.bin/ftp/main.c
Warning:line 773, 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.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name main.c -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 -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -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/llvm16/lib/clang/16 -internal-isystem /usr/local/llvm16/lib/clang/16/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 -fcf-protection=branch -fno-jump-tables -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/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.bin/ftp/main.c
1/* $OpenBSD: main.c,v 1.146 2023/12/23 23:03:00 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_MAX0x7fffffff, &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");
1
Assuming the environment variable exists
331 if (gateport
1.1
'gateport' is not equal to NULL
== NULL((void *)0) || *gateport == '\0')
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 environment variable does not exist
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");
7
Assuming the environment variable does not exist
378 if (gateserver
7.1
'gateserver' is equal to NULL
== NULL((void *)0))
8
Taking true 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");
11
Assuming the environment variable does not exist
389 dumb_terminal = (cp
11.1
'cp' is equal to NULL
== NULL((void *)0) || *cp == '\0' || !strcmp(cp, "dumb") ||
390 !strcmp(cp, "emacs") || !strcmp(cp, "su"));
391 fromatty = isatty(fileno(stdin)(!__isthreaded ? (((&__sF[0]))->_file) : (fileno)((&
__sF[0])))
);
12
Assuming '__isthreaded' is 0
13
'?' condition is true
392 if (fromatty) {
14
Assuming 'fromatty' is 0
15
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())
16
Assuming '__isthreaded' is 0
17
'?' condition is true
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");
19
Assuming the environment variable does not exist
406 if (tls_config == NULL((void *)0)) {
20
Assuming 'tls_config' is not equal to NULL
21
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 << 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,
22
Assuming the condition is false
23
Loop condition is false. Execution continues on line 580
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_MAX0x7fffffff,
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 pipeout = strcmp(outfile, "-") == 0;
506 ttyout = pipeout ? stderr(&__sF[2]) : stdout(&__sF[1]);
507 break;
508
509 case 'p':
510 passivemode = 1;
511 activefallback = 0;
512 break;
513
514 case 'P':
515 ftpport = optarg;
516 break;
517
518 case 'r':
519 retry_connect = strtonum(optarg, 0, INT_MAX0x7fffffff, &errstr);
520 if (errstr != NULL((void *)0)) {
521 warnx("retry amount is %s: %s", errstr,
522 optarg);
523 usage();
524 }
525 break;
526
527 case 'S':
528#ifndef NOSSL
529 process_ssl_options(optarg);
530#endif /* !NOSSL */
531 break;
532
533 case 's':
534#ifndef SMALL
535 srcaddr = optarg;
536#endif /* !SMALL */
537 break;
538
539#ifndef SMALL
540 case 'T':
541 timestamp = 1;
542 break;
543#endif /* !SMALL */
544 case 't':
545 trace = 1;
546 break;
547
548#ifndef SMALL
549 case 'U':
550 free (httpuseragent);
551 if (strcspn(optarg, "\r\n") != strlen(optarg))
552 errx(1, "Invalid User-Agent: %s.", optarg);
553 if (asprintf(&httpuseragent, "User-Agent: %s",
554 optarg) == -1)
555 errx(1, "Can't allocate memory for HTTP(S) "
556 "User-Agent");
557 break;
558 case 'u':
559 server_timestamps = 0;
560 break;
561#endif /* !SMALL */
562
563 case 'v':
564 verbose = 1;
565 break;
566
567 case 'V':
568 verbose = 0;
569 break;
570
571 case 'w':
572 connect_timeout = strtonum(optarg, 0, 200, &errstr);
573 if (errstr)
574 errx(1, "-w: %s", errstr);
575 break;
576 default:
577 usage();
578 }
579 }
580 argc -= optind;
581 argv += optind;
582
583#ifndef NOSSL
584 cookie_load();
585#endif /* !NOSSL */
586 if (httpuseragent == NULL((void *)0))
24
Assuming 'httpuseragent' is not equal to NULL
25
Taking false branch
587 httpuseragent = HTTP_USER_AGENT"User-Agent: OpenBSD ftp";
588
589 cpend = 0; /* no pending replies */
590 proxy = 0; /* proxy not active */
591 crflag = 1; /* strip c.r. on ascii gets */
592 sendport = -1; /* not using ports */
593 /*
594 * Set up the home directory in case we're globbing.
595 */
596 cp = getlogin();
597 if (cp != NULL((void *)0)) {
26
Assuming 'cp' is equal to NULL
27
Taking false branch
598 pw = getpwnam(cp);
599 }
600 if (pw
27.1
'pw' is equal to NULL
== NULL((void *)0))
28
Taking true branch
601 pw = getpwuid(getuid());
602 if (pw != NULL((void *)0)) {
29
Assuming 'pw' is equal to NULL
30
Taking false branch
603 (void)strlcpy(homedir, pw->pw_dir, sizeof homedir);
604 home = homedir;
605 }
606
607 setttywidth(0);
608 (void)signal(SIGWINCH28, setttywidth);
609
610 if (argc > 0) {
31
Assuming 'argc' is <= 0
32
Taking false branch
611 if (isurl(argv[0])) {
612 if (pipeout) {
613 if (pledge("stdio rpath dns tty inet",
614 NULL((void *)0)) == -1)
615 err(1, "pledge");
616 } else {
617#ifndef SMALL
618 if (outfile == NULL((void *)0)) {
619 if (pledge("stdio rpath wpath cpath dns tty inet proc exec fattr",
620 NULL((void *)0)) == -1)
621 err(1, "pledge");
622 } else
623#endif /* !SMALL */
624 if (pledge("stdio rpath wpath cpath dns tty inet fattr",
625 NULL((void *)0)) == -1)
626 err(1, "pledge");
627 }
628
629 rval = auto_fetch(argc, argv, outfile);
630 /* -1 == connected and cd-ed */
631 if (rval >= 0 || outfile != NULL((void *)0))
632 exit(rval);
633 } else {
634#ifndef SMALL
635 char *xargv[5];
636
637 if (setjmp(toplevel))
638 exit(0);
639 (void)signal(SIGINT2, (sig_t)intr);
640 (void)signal(SIGPIPE13, (sig_t)lostpeer);
641 xargv[0] = __progname;
642 xargv[1] = argv[0];
643 xargv[2] = argv[1];
644 xargv[3] = argv[2];
645 xargv[4] = NULL((void *)0);
646 do {
647 setpeer(argc+1, xargv);
648 if (!retry_connect)
649 break;
650 if (!connected) {
651 macnum = 0;
652 fputs("Retrying...\n", ttyout);
653 sleep(retry_connect);
654 }
655 } while (!connected);
656 retry_connect = 0; /* connected, stop hiding msgs */
657#endif /* !SMALL */
658 }
659 }
660#ifndef SMALL
661 controlediting();
662 top = setjmp(toplevel) == 0;
33
Assuming the condition is false
663 if (top
33.1
'top' is 0
) {
34
Taking false branch
664 (void)signal(SIGINT2, (sig_t)intr);
665 (void)signal(SIGPIPE13, (sig_t)lostpeer);
666 }
667 for (;;) {
35
Loop condition is true. Entering loop body
668 cmdscanner(top);
36
Calling 'cmdscanner'
669 top = 1;
670 }
671#else /* !SMALL */
672 usage();
673#endif /* !SMALL */
674}
675
676void
677intr(void)
678{
679 int save_errno = errno(*__errno());
680
681 write(fileno(ttyout)(!__isthreaded ? ((ttyout)->_file) : (fileno)(ttyout)), "\n\r", 2);
682 alarmtimer(0);
683
684 errno(*__errno()) = save_errno;
685 longjmp(toplevel, 1);
686}
687
688void
689lostpeer(void)
690{
691 int save_errno = errno(*__errno());
692
693 alarmtimer(0);
694 if (connected) {
695 if (cout != NULL((void *)0)) {
696 (void)shutdown(fileno(cout)(!__isthreaded ? ((cout)->_file) : (fileno)(cout)), SHUT_RDWR2);
697 (void)fclose(cout);
698 cout = NULL((void *)0);
699 }
700 if (data >= 0) {
701 (void)shutdown(data, SHUT_RDWR2);
702 (void)close(data);
703 data = -1;
704 }
705 connected = 0;
706 }
707 pswitch(1);
708 if (connected) {
709 if (cout != NULL((void *)0)) {
710 (void)shutdown(fileno(cout)(!__isthreaded ? ((cout)->_file) : (fileno)(cout)), SHUT_RDWR2);
711 (void)fclose(cout);
712 cout = NULL((void *)0);
713 }
714 connected = 0;
715 }
716 proxflag = 0;
717 pswitch(0);
718 errno(*__errno()) = save_errno;
719}
720
721#ifndef SMALL
722/*
723 * Generate a prompt
724 */
725char *
726prompt(void)
727{
728 return ("ftp> ");
729}
730
731/*
732 * Command parser.
733 */
734void
735cmdscanner(int top)
736{
737 struct cmd *c;
738 int num;
739 HistEvent hev;
740
741 if (!top
36.1
'top' is 0
&& !editing)
37
Assuming 'editing' is not equal to 0
38
Taking false branch
742 (void)putc('\n', ttyout)(!__isthreaded ? __sputc('\n', ttyout) : (putc)('\n', ttyout)
)
;
743 for (;;) {
39
Loop condition is true. Entering loop body
744 if (!editing
39.1
'editing' is not equal to 0
) {
40
Taking false branch
745 if (fromatty) {
746 fputs(prompt(), ttyout);
747 (void)fflush(ttyout);
748 }
749 if (fgets(line, sizeof(line), stdin(&__sF[0])) == NULL((void *)0))
750 quit(0, 0);
751 num = strlen(line);
752 if (num == 0)
753 break;
754 if (line[--num] == '\n') {
755 if (num == 0)
756 break;
757 line[num] = '\0';
758 } else if (num == sizeof(line) - 2) {
759 fputs("sorry, input line too long.\n", ttyout);
760 while ((num = getchar()(!__isthreaded ? (--((&__sF[0]))->_r < 0 ? __srget(
(&__sF[0])) : (int)(*((&__sF[0]))->_p++)) : (getc)
((&__sF[0])))
) != '\n' && num != EOF(-1))
761 /* void */;
762 break;
763 } /* else it was a line without a newline */
764 } else {
765 const char *buf;
766 cursor_pos = NULL((void *)0);
767
768 if ((buf = el_gets(el, &num)) == NULL((void *)0) || num == 0) {
41
Value assigned to 'buf'
42
Assuming pointer value is null
769 putc('\n', ttyout)(!__isthreaded ? __sputc('\n', ttyout) : (putc)('\n', ttyout)
)
;
43
Assuming '__isthreaded' is not equal to 0
44
'?' condition is false
770 fflush(ttyout);
771 quit(0, 0);
772 }
773 if (buf[--num] == '\n') {
45
Array access (from variable 'buf') results in a null pointer dereference
774 if (num == 0)
775 break;
776 }
777 if (num >= sizeof(line)) {
778 fputs("sorry, input line too long.\n", ttyout);
779 break;
780 }
781 memcpy(line, buf, (size_t)num);
782 line[num] = '\0';
783 history(hist, &hev, H_ENTER10, buf);
784 }
785
786 makeargv();
787 if (margc == 0)
788 continue;
789 c = getcmd(margv(marg_sl->sl_str)[0]);
790 if (c == (struct cmd *)-1) {
791 fputs("?Ambiguous command.\n", ttyout);
792 continue;
793 }
794 if (c == 0) {
795 /*
796 * Give editline(3) a shot at unknown commands.
797 * XXX - bogus commands with a colon in
798 * them will not elicit an error.
799 */
800 if (editing &&
801 el_parse(el, margc, (const char **)margv(marg_sl->sl_str)) != 0)
802 fputs("?Invalid command.\n", ttyout);
803 continue;
804 }
805 if (c->c_conn && !connected) {
806 fputs("Not connected.\n", ttyout);
807 continue;
808 }
809 confirmrest = 0;
810 (*c->c_handler)(margc, margv(marg_sl->sl_str));
811 if (bell && c->c_bell)
812 (void)putc('\007', ttyout)(!__isthreaded ? __sputc('\007', ttyout) : (putc)('\007', ttyout
))
;
813 if (c->c_handler != help)
814 break;
815 }
816 (void)signal(SIGINT2, (sig_t)intr);
817 (void)signal(SIGPIPE13, (sig_t)lostpeer);
818}
819
820struct cmd *
821getcmd(const char *name)
822{
823 const char *p, *q;
824 struct cmd *c, *found;
825 int nmatches, longest;
826
827 if (name == NULL((void *)0))
828 return (0);
829
830 longest = 0;
831 nmatches = 0;
832 found = 0;
833 for (c = cmdtab; (p = c->c_name) != NULL((void *)0); c++) {
834 for (q = name; *q == *p++; q++)
835 if (*q == 0) /* exact match? */
836 return (c);
837 if (!*q) { /* the name was a prefix */
838 if (q - name > longest) {
839 longest = q - name;
840 nmatches = 1;
841 found = c;
842 } else if (q - name == longest)
843 nmatches++;
844 }
845 }
846 if (nmatches > 1)
847 return ((struct cmd *)-1);
848 return (found);
849}
850
851/*
852 * Slice a string up into argc/argv.
853 */
854
855int slrflag;
856
857void
858makeargv(void)
859{
860 char *argp;
861
862 stringbase = line; /* scan from first of buffer */
863 argbase = argbuf; /* store from first of buffer */
864 slrflag = 0;
865 marg_sl->sl_cur = 0; /* reset to start of marg_sl */
866 for (margc = 0; ; margc++) {
867 argp = slurpstring();
868 sl_add(marg_sl, argp);
869 if (argp == NULL((void *)0))
870 break;
871 }
872 if (cursor_pos == line) {
873 cursor_argc = 0;
874 cursor_argo = 0;
875 } else if (cursor_pos != NULL((void *)0)) {
876 cursor_argc = margc;
877 cursor_argo = strlen(margv(marg_sl->sl_str)[margc-1]);
878 }
879}
880
881#define INC_CHKCURSOR(x){ (x)++ ; if (x == cursor_pos) { cursor_argc = margc; cursor_argo
= ap-argbase; cursor_pos = ((void *)0); } }
{ (x)++ ; \
882 if (x == cursor_pos) { \
883 cursor_argc = margc; \
884 cursor_argo = ap-argbase; \
885 cursor_pos = NULL((void *)0); \
886 } }
887
888/*
889 * Parse string into argbuf;
890 * implemented with FSM to
891 * handle quoting and strings
892 */
893char *
894slurpstring(void)
895{
896 int got_one = 0;
897 char *sb = stringbase;
898 char *ap = argbase;
899 char *tmp = argbase; /* will return this if token found */
900
901 if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */
902 switch (slrflag) { /* and $ as token for macro invoke */
903 case 0:
904 slrflag++;
905 INC_CHKCURSOR(stringbase){ (stringbase)++ ; if (stringbase == cursor_pos) { cursor_argc
= margc; cursor_argo = ap-argbase; cursor_pos = ((void *)0);
} }
;
906 return ((*sb == '!') ? "!" : "$");
907 /* NOTREACHED */
908 case 1:
909 slrflag++;
910 altarg = stringbase;
911 break;
912 default:
913 break;
914 }
915 }
916
917S0:
918 switch (*sb) {
919
920 case '\0':
921 goto OUT;
922
923 case ' ':
924 case '\t':
925 INC_CHKCURSOR(sb){ (sb)++ ; if (sb == cursor_pos) { cursor_argc = margc; cursor_argo
= ap-argbase; cursor_pos = ((void *)0); } }
;
926 goto S0;
927
928 default:
929 switch (slrflag) {
930 case 0:
931 slrflag++;
932 break;
933 case 1:
934 slrflag++;
935 altarg = sb;
936 break;
937 default:
938 break;
939 }
940 goto S1;
941 }
942
943S1:
944 switch (*sb) {
945
946 case ' ':
947 case '\t':
948 case '\0':
949 goto OUT; /* end of token */
950
951 case '\\':
952 INC_CHKCURSOR(sb){ (sb)++ ; if (sb == cursor_pos) { cursor_argc = margc; cursor_argo
= ap-argbase; cursor_pos = ((void *)0); } }
;
953 goto S2; /* slurp next character */
954
955 case '"':
956 INC_CHKCURSOR(sb){ (sb)++ ; if (sb == cursor_pos) { cursor_argc = margc; cursor_argo
= ap-argbase; cursor_pos = ((void *)0); } }
;
957 goto S3; /* slurp quoted string */
958
959 default:
960 *ap = *sb; /* add character to token */
961 ap++;
962 INC_CHKCURSOR(sb){ (sb)++ ; if (sb == cursor_pos) { cursor_argc = margc; cursor_argo
= ap-argbase; cursor_pos = ((void *)0); } }
;
963 got_one = 1;
964 goto S1;
965 }
966
967S2:
968 switch (*sb) {
969
970 case '\0':
971 goto OUT;
972
973 default:
974 *ap = *sb;
975 ap++;
976 INC_CHKCURSOR(sb){ (sb)++ ; if (sb == cursor_pos) { cursor_argc = margc; cursor_argo
= ap-argbase; cursor_pos = ((void *)0); } }
;
977 got_one = 1;
978 goto S1;
979 }
980
981S3:
982 switch (*sb) {
983
984 case '\0':
985 goto OUT;
986
987 case '"':
988 INC_CHKCURSOR(sb){ (sb)++ ; if (sb == cursor_pos) { cursor_argc = margc; cursor_argo
= ap-argbase; cursor_pos = ((void *)0); } }
;
989 goto S1;
990
991 default:
992 *ap = *sb;
993 ap++;
994 INC_CHKCURSOR(sb){ (sb)++ ; if (sb == cursor_pos) { cursor_argc = margc; cursor_argo
= ap-argbase; cursor_pos = ((void *)0); } }
;
995 got_one = 1;
996 goto S3;
997 }
998
999OUT:
1000 if (got_one)
1001 *ap++ = '\0';
1002 argbase = ap; /* update storage pointer */
1003 stringbase = sb; /* update scan pointer */
1004 if (got_one) {
1005 return (tmp);
1006 }
1007 switch (slrflag) {
1008 case 0:
1009 slrflag++;
1010 break;
1011 case 1:
1012 slrflag++;
1013 altarg = (char *) 0;
1014 break;
1015 default:
1016 break;
1017 }
1018 return (NULL((void *)0));
1019}
1020
1021/*
1022 * Help command.
1023 * Call each command handler with argc == 0 and argv[0] == name.
1024 */
1025void
1026help(int argc, char *argv[])
1027{
1028 struct cmd *c;
1029
1030 if (argc == 1) {
1031 StringList *buf;
1032
1033 buf = sl_init();
1034 fprintf(ttyout, "%sommands may be abbreviated. Commands are:\n\n",
1035 proxy ? "Proxy c" : "C");
1036 for (c = cmdtab; c < &cmdtab[NCMDS]; c++)
1037 if (c->c_name && (!proxy || c->c_proxy))
1038 sl_add(buf, c->c_name);
1039 list_vertical(buf);
1040 sl_free(buf, 0);
1041 return;
1042 }
1043
1044#define HELPINDENT((int) sizeof("disconnect")) ((int) sizeof("disconnect"))
1045
1046 while (--argc > 0) {
1047 char *arg;
1048
1049 arg = *++argv;
1050 c = getcmd(arg);
1051 if (c == (struct cmd *)-1)
1052 fprintf(ttyout, "?Ambiguous help command %s\n", arg);
1053 else if (c == NULL((void *)0))
1054 fprintf(ttyout, "?Invalid help command %s\n", arg);
1055 else
1056 fprintf(ttyout, "%-*s\t%s\n", HELPINDENT((int) sizeof("disconnect")),
1057 c->c_name, c->c_help);
1058 }
1059}
1060#endif /* !SMALL */
1061
1062__dead__attribute__((__noreturn__)) void
1063usage(void)
1064{
1065 fprintf(stderr(&__sF[2]), "usage: "
1066#ifndef SMALL
1067 "ftp [-46AadEegiMmnptVv] [-D title] [-k seconds] [-P port] "
1068 "[-r seconds]\n"
1069 " [-s sourceaddr] [host [port]]\n"
1070 " ftp [-C] [-N name] [-o output] [-s sourceaddr]\n"
1071 " ftp://[user:password@]host[:port]/file[/] ...\n"
1072 " ftp [-CTu] [-c cookie] [-N name] [-o output] [-S ssl_options] "
1073 "[-s sourceaddr]\n"
1074 " [-U useragent] [-w seconds] "
1075 "http[s]://[user:password@]host[:port]/file ...\n"
1076 " ftp [-C] [-N name] [-o output] [-s sourceaddr] file:file ...\n"
1077 " ftp [-C] [-N name] [-o output] [-s sourceaddr] host:/file[/] ...\n"
1078#else /* !SMALL */
1079 "ftp [-N name] [-o output] "
1080 "ftp://[user:password@]host[:port]/file[/] ...\n"
1081#ifndef NOSSL
1082 " ftp [-N name] [-o output] [-S ssl_options] [-w seconds] "
1083 "http[s]://[user:password@]host[:port]/file ...\n"
1084#else
1085 " ftp [-N name] [-o output] [-w seconds] http://host[:port]/file ...\n"
1086#endif /* NOSSL */
1087 " ftp [-N name] [-o output] file:file ...\n"
1088 " ftp [-N name] [-o output] host:/file[/] ...\n"
1089#endif /* !SMALL */
1090 );
1091 exit(1);
1092}