Bug Summary

File:src/usr.bin/telnet/sys_bsd.c
Warning:line 219, column 5
Value stored to 'old' 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 sys_bsd.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/telnet/obj -resource-dir /usr/local/lib/clang/13.0.0 -D KLUDGELINEMODE -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/telnet/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/telnet/sys_bsd.c
1/* $OpenBSD: sys_bsd.c,v 1.35 2019/06/28 13:35:04 deraadt Exp $ */
2/* $NetBSD: sys_bsd.c,v 1.11 1996/02/28 21:04:10 thorpej Exp $ */
3
4/*
5 * Copyright (c) 1988, 1990, 1993
6 * The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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#include "telnet_locl.h"
34
35#include <sys/ioctl.h>
36#include <sys/socket.h>
37#include <arpa/telnet.h>
38#include <errno(*__errno()).h>
39#include <poll.h>
40#include <string.h>
41#include <unistd.h>
42
43/*
44 * The following routines try to encapsulate what is system dependent
45 * (at least between 4.x and dos) which is used in telnet.c.
46 */
47
48int
49 tout, /* Output file descriptor */
50 tin, /* Input file descriptor */
51 net;
52
53#define TELNET_FD_TOUT0 0
54#define TELNET_FD_TIN1 1
55#define TELNET_FD_NET2 2
56#define TELNET_FD_NUM3 3
57
58struct termios old_tc = { 0 };
59
60void
61init_sys(void)
62{
63 tout = fileno(stdout)(!__isthreaded ? (((&__sF[1]))->_file) : (fileno)((&
__sF[1])))
;
64 tin = fileno(stdin)(!__isthreaded ? (((&__sF[0]))->_file) : (fileno)((&
__sF[0])))
;
65
66 errno(*__errno()) = 0;
67}
68
69
70/*
71 * TerminalSpecialChars()
72 *
73 * Look at an input character to see if it is a special character
74 * and decide what to do.
75 *
76 * Output:
77 *
78 * 0 Don't add this character.
79 * 1 Do add this character
80 */
81
82int
83TerminalSpecialChars(int c)
84{
85 if (c == termIntCharnew_tc.c_cc[8]) {
86 intp();
87 return 0;
88 } else if (c == termQuitCharnew_tc.c_cc[9]) {
89#ifdef KLUDGELINEMODE1
90 if (kludgelinemode)
91 sendbrk();
92 else
93#endif
94 sendabort();
95 return 0;
96 } else if (c == termEofCharnew_tc.c_cc[0]) {
97 if (my_want_state_is_will(TELOPT_LINEMODE)(options[34]&0x02)) {
98 sendeof();
99 return 0;
100 }
101 return 1;
102 } else if (c == termSuspCharnew_tc.c_cc[10]) {
103 sendsusp();
104 return(0);
105 } else if (c == termFlushCharnew_tc.c_cc[15]) {
106 xmitAO(); /* Transmit Abort Output */
107 return 0;
108 } else if (!MODE_LOCAL_CHARS(globalmode)((globalmode)&(0x01|0x02))) {
109 if (c == termKillCharnew_tc.c_cc[5]) {
110 xmitEL();
111 return 0;
112 } else if (c == termEraseCharnew_tc.c_cc[3]) {
113 xmitEC(); /* Transmit Erase Character */
114 return 0;
115 }
116 }
117 return 1;
118}
119
120void
121TerminalSaveState(void)
122{
123 tcgetattr(0, &old_tc);
124
125 new_tc = old_tc;
126}
127
128cc_t *
129tcval(int func)
130{
131 switch(func) {
132 case SLC_IP3: return(&termIntCharnew_tc.c_cc[8]);
133 case SLC_ABORT7: return(&termQuitCharnew_tc.c_cc[9]);
134 case SLC_EOF8: return(&termEofCharnew_tc.c_cc[0]);
135 case SLC_EC10: return(&termEraseCharnew_tc.c_cc[3]);
136 case SLC_EL11: return(&termKillCharnew_tc.c_cc[5]);
137 case SLC_XON15: return(&termStartCharnew_tc.c_cc[12]);
138 case SLC_XOFF16: return(&termStopCharnew_tc.c_cc[13]);
139 case SLC_FORW117: return(&termForw1Charnew_tc.c_cc[1]);
140 case SLC_FORW218: return(&termForw2Charnew_tc.c_cc[1]);
141 case SLC_SUSP9: return(&termSuspCharnew_tc.c_cc[10]);
142 case SLC_AO4: return(&termFlushCharnew_tc.c_cc[15]);
143 case SLC_EW12: return(&termWerasCharnew_tc.c_cc[4]);
144 case SLC_RP13: return(&termRprntCharnew_tc.c_cc[6]);
145 case SLC_LNEXT14: return(&termLiteralNextCharnew_tc.c_cc[14]);
146 case SLC_AYT5: return(&termAytCharnew_tc.c_cc[18]);
147 case SLC_SYNCH1:
148 case SLC_BRK2:
149 case SLC_EOR6:
150 default:
151 return(NULL((void *)0));
152 }
153}
154
155void
156TerminalDefaultChars(void)
157{
158 memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
159}
160
161/*
162 * TerminalNewMode - set up terminal to a specific mode.
163 * MODE_ECHO: do local terminal echo
164 * MODE_FLOW: do local flow control
165 * MODE_TRAPSIG: do local mapping to TELNET IAC sequences
166 * MODE_EDIT: do local line editing
167 *
168 * Command mode:
169 * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
170 * local echo
171 * local editing
172 * local xon/xoff
173 * local signal mapping
174 *
175 * Linemode:
176 * local/no editing
177 * Both Linemode and Single Character mode:
178 * local/remote echo
179 * local/no xon/xoff
180 * local/no signal mapping
181 */
182
183static void susp();
184static void ayt();
185
186void
187TerminalNewMode(int f)
188{
189 static int prevmode = 0;
190 struct termios tmp_tc;
191 int onoff;
192 int old;
193 cc_t esc;
194
195 globalmode = f&~MODE_FORCE0x1000;
196 if (prevmode == f)
197 return;
198
199 /*
200 * Write any outstanding data before switching modes
201 * ttyflush() returns 0 only when there is no more data
202 * left to write out, it returns -1 if it couldn't do
203 * anything at all, otherwise it returns 1 + the number
204 * of characters left to write.
205 */
206 old = ttyflush(SYNCHing|flushout);
207 if (old < 0 || old > 1) {
208 tcgetattr(tin, &tmp_tc);
209 do {
210 /*
211 * Wait for data to drain, then flush again.
212 */
213 if (isatty(tin))
214 tcsetattr(tin, TCSADRAIN1, &tmp_tc);
215 old = ttyflush(SYNCHing|flushout);
216 } while (old < 0 || old > 1);
217 }
218
219 old = prevmode;
Value stored to 'old' is never read
220 prevmode = f&~MODE_FORCE0x1000;
221 tmp_tc = new_tc;
222
223 if (f&MODE_ECHO0x0200) {
224 tmp_tc.c_lflag |= ECHO0x00000008;
225 tmp_tc.c_oflag |= ONLCR0x00000002;
226 if (crlf)
227 tmp_tc.c_iflag |= ICRNL0x00000100;
228 } else {
229 tmp_tc.c_lflag &= ~ECHO0x00000008;
230 tmp_tc.c_oflag &= ~ONLCR0x00000002;
231 }
232
233 if ((f&MODE_FLOW0x0100) == 0) {
234 tmp_tc.c_iflag &= ~(IXOFF0x00000400|IXON0x00000200); /* Leave the IXANY bit alone */
235 } else {
236 if (restartany < 0) {
237 tmp_tc.c_iflag |= IXOFF0x00000400|IXON0x00000200; /* Leave the IXANY bit alone */
238 } else if (restartany > 0) {
239 tmp_tc.c_iflag |= IXOFF0x00000400|IXON0x00000200|IXANY0x00000800;
240 } else {
241 tmp_tc.c_iflag |= IXOFF0x00000400|IXON0x00000200;
242 tmp_tc.c_iflag &= ~IXANY0x00000800;
243 }
244 }
245
246 if ((f&MODE_TRAPSIG0x02) == 0) {
247 tmp_tc.c_lflag &= ~ISIG0x00000080;
248 localchars = 0;
249 } else {
250 tmp_tc.c_lflag |= ISIG0x00000080;
251 localchars = 1;
252 }
253
254 if (f&MODE_EDIT0x01) {
255 tmp_tc.c_lflag |= ICANON0x00000100;
256 } else {
257 tmp_tc.c_lflag &= ~ICANON0x00000100;
258 tmp_tc.c_iflag &= ~ICRNL0x00000100;
259 tmp_tc.c_cc[VMIN16] = 1;
260 tmp_tc.c_cc[VTIME17] = 0;
261 }
262
263 if ((f&(MODE_EDIT0x01|MODE_TRAPSIG0x02)) == 0) {
264 tmp_tc.c_lflag &= ~IEXTEN0x00000400;
265 }
266
267 if (f&MODE_SOFT_TAB0x08) {
268# ifdef OXTABS0x00000004
269 tmp_tc.c_oflag |= OXTABS0x00000004;
270# endif
271# ifdef TABDLY
272 tmp_tc.c_oflag &= ~TABDLY;
273 tmp_tc.c_oflag |= TAB3;
274# endif
275 } else {
276# ifdef OXTABS0x00000004
277 tmp_tc.c_oflag &= ~OXTABS0x00000004;
278# endif
279# ifdef TABDLY
280 tmp_tc.c_oflag &= ~TABDLY;
281# endif
282 }
283
284 if (f&MODE_LIT_ECHO0x10) {
285# ifdef ECHOCTL0x00000040
286 tmp_tc.c_lflag &= ~ECHOCTL0x00000040;
287# endif
288 } else {
289# ifdef ECHOCTL0x00000040
290 tmp_tc.c_lflag |= ECHOCTL0x00000040;
291# endif
292 }
293
294 if (f == -1) {
295 onoff = 0;
296 } else {
297 if (f & MODE_INBIN0x0400)
298 tmp_tc.c_iflag &= ~ISTRIP0x00000020;
299 else
300 tmp_tc.c_iflag |= ISTRIP0x00000020;
301 if ((f & MODE_OUTBIN0x0800) || (f & MODE_OUT80x8000)) {
302 tmp_tc.c_cflag &= ~(CSIZE0x00000300|PARENB0x00001000);
303 tmp_tc.c_cflag |= CS80x00000300;
304 if(f & MODE_OUTBIN0x0800)
305 tmp_tc.c_oflag &= ~OPOST0x00000001;
306 else
307 tmp_tc.c_oflag |= OPOST0x00000001;
308
309 } else {
310 tmp_tc.c_cflag &= ~(CSIZE0x00000300|PARENB0x00001000);
311 tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE0x00000300|PARENB0x00001000);
312 tmp_tc.c_oflag |= OPOST0x00000001;
313 }
314 onoff = 1;
315 }
316
317 if (f != -1) {
318 (void) signal(SIGTSTP18, susp);
319 (void) signal(SIGINFO29, ayt);
320#if defined(NOKERNINFO0x02000000)
321 tmp_tc.c_lflag |= NOKERNINFO0x02000000;
322#endif
323 /*
324 * We don't want to process ^Y here. It's just another
325 * character that we'll pass on to the back end. It has
326 * to process it because it will be processed when the
327 * user attempts to read it, not when we send it.
328 */
329# ifdef VDSUSP11
330 tmp_tc.c_cc[VDSUSP11] = (cc_t)(_POSIX_VDISABLE(0377));
331# endif
332 /*
333 * If the VEOL character is already set, then use VEOL2,
334 * otherwise use VEOL.
335 */
336 esc = (rlogin != _POSIX_VDISABLE(0377)) ? rlogin : escape;
337 if ((tmp_tc.c_cc[VEOL1] != esc)
338# ifdef VEOL22
339 && (tmp_tc.c_cc[VEOL22] != esc)
340# endif
341 ) {
342 if (tmp_tc.c_cc[VEOL1] == (cc_t)(_POSIX_VDISABLE(0377)))
343 tmp_tc.c_cc[VEOL1] = esc;
344# ifdef VEOL22
345 else if (tmp_tc.c_cc[VEOL22] == (cc_t)(_POSIX_VDISABLE(0377)))
346 tmp_tc.c_cc[VEOL22] = esc;
347# endif
348 }
349 } else {
350 sigset_t mask;
351 (void) signal(SIGINFO29, ayt_status);
352 (void) signal(SIGTSTP18, SIG_DFL(void (*)(int))0);
353 sigemptyset(&mask);
354 sigaddset(&mask, SIGTSTP18);
355 sigprocmask(SIG_UNBLOCK2, &mask, NULL((void *)0));
356 tmp_tc = old_tc;
357 }
358 if (isatty(tin) && tcsetattr(tin, TCSADRAIN1, &tmp_tc) == -1)
359 tcsetattr(tin, TCSANOW0, &tmp_tc);
360
361 ioctl(tin, FIONBIO((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('f')) << 8) | ((126)))
, &onoff);
362 ioctl(tout, FIONBIO((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('f')) << 8) | ((126)))
, &onoff);
363}
364
365void
366TerminalSpeeds(long *ispeed, long *ospeed)
367{
368 long in, out;
369
370 out = cfgetospeed(&old_tc);
371 in = cfgetispeed(&old_tc);
372 if (in == 0)
373 in = out;
374
375 *ispeed = in;
376 *ospeed = out;
377}
378
379int
380TerminalWindowSize(long *rows, long *cols)
381{
382 struct winsize ws;
383
384 if (ioctl(fileno(stdin)(!__isthreaded ? (((&__sF[0]))->_file) : (fileno)((&
__sF[0])))
, TIOCGWINSZ((unsigned long)0x40000000 | ((sizeof(struct winsize) & 0x1fff
) << 16) | ((('t')) << 8) | ((104)))
, &ws) == 0) {
385 *rows = ws.ws_row;
386 *cols = ws.ws_col;
387 return 1;
388 }
389 return 0;
390}
391
392/*
393 * Various signal handling routines.
394 */
395
396void
397deadpeer(int sig)
398{
399 setcommandmode();
400 longjmp(peerdied, -1);
401}
402
403void
404intr(int sig)
405{
406 if (localchars) {
407 intp();
408 return;
409 }
410 setcommandmode();
411 longjmp(toplevel, -1);
412}
413
414void
415intr2(int sig)
416{
417 if (localchars) {
418#ifdef KLUDGELINEMODE1
419 if (kludgelinemode)
420 sendbrk();
421 else
422#endif
423 sendabort();
424 return;
425 }
426}
427
428void
429susp(int sig)
430{
431 if ((rlogin != _POSIX_VDISABLE(0377)) && rlogin_susp())
432 return;
433 if (localchars)
434 sendsusp();
435}
436
437void
438sendwin(int sig)
439{
440 if (connected) {
441 sendnaws();
442 }
443}
444
445void
446ayt(int sig)
447{
448 if (connected)
449 sendayt();
450 else
451 ayt_status(sig);
452}
453
454
455void
456sys_telnet_init(void)
457{
458 int one = 1;
459
460 (void) signal(SIGINT2, intr);
461 (void) signal(SIGQUIT3, intr2);
462 (void) signal(SIGPIPE13, deadpeer);
463 (void) signal(SIGWINCH28, sendwin);
464 (void) signal(SIGTSTP18, susp);
465 (void) signal(SIGINFO29, ayt);
466
467 setconnmode(0);
468
469 /*
470 * Mark the socket as non-blocking and receive urgent data inline.
471 * (The latter is required for correct telnet operation when a
472 * second urgent is sent before telnet can process the first.)
473 */
474 ioctl(net, FIONBIO((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('f')) << 8) | ((126)))
, &one);
475 if (setsockopt(net, SOL_SOCKET0xffff, SO_OOBINLINE0x0100, &one, sizeof(one)) == -1) {
476 perror("setsockopt");
477 }
478}
479
480/*
481 * Process rings -
482 *
483 * This routine tries to fill up/empty our various rings.
484 *
485 * The parameter specifies whether this is a poll operation,
486 * or a block-until-something-happens operation.
487 *
488 * The return value is 1 if something happened, 0 if not.
489 */
490
491int
492process_rings(int netin, int netout, int netex, int ttyin, int ttyout,
493 int dopoll) /* If 0, then block until something to do */
494{
495 int c;
496 /* One wants to be a bit careful about setting returnValue
497 * to one, since a one implies we did some useful work,
498 * and therefore probably won't be called to block next
499 * time (TN3270 mode only).
500 */
501 int returnValue = 0;
502 struct pollfd pfd[TELNET_FD_NUM3];
503
504 if (ttyout) {
505 pfd[TELNET_FD_TOUT0].fd = tout;
506 pfd[TELNET_FD_TOUT0].events = POLLOUT0x0004;
507 } else {
508 pfd[TELNET_FD_TOUT0].fd = -1;
509 }
510 if (ttyin) {
511 pfd[TELNET_FD_TIN1].fd = tin;
512 pfd[TELNET_FD_TIN1].events = POLLIN0x0001;
513 } else {
514 pfd[TELNET_FD_TIN1].fd = -1;
515 }
516 if (netout || netin || netex) {
517 pfd[TELNET_FD_NET2].fd = net;
518 pfd[TELNET_FD_NET2].events = 0;
519 if (netout)
520 pfd[TELNET_FD_NET2].events |= POLLOUT0x0004;
521 if (netin)
522 pfd[TELNET_FD_NET2].events |= POLLIN0x0001;
523 if (netex)
524 pfd[TELNET_FD_NET2].events |= POLLRDBAND0x0080;
525 } else {
526 pfd[TELNET_FD_NET2].fd = -1;
527 }
528
529 if ((c = poll(pfd, TELNET_FD_NUM3, dopoll ? 0 : INFTIM(-1))) == -1) {
530 return 0;
531 }
532
533 /*
534 * Any urgent data?
535 */
536 if (pfd[TELNET_FD_NET2].revents & POLLRDBAND0x0080) {
537 SYNCHing = 1;
538 (void) ttyflush(1); /* flush already enqueued data */
539 }
540
541 /*
542 * Something to read from the network...
543 */
544 if (pfd[TELNET_FD_NET2].revents & (POLLIN0x0001|POLLHUP0x0010)) {
545 int canread;
546
547 canread = ring_empty_consecutive(&netiring);
548 c = recv(net, netiring.supply, canread, 0);
549 if (c == -1 && errno(*__errno()) == EWOULDBLOCK35) {
550 c = 0;
551 } else if (c <= 0) {
552 return -1;
553 }
554 if (netdata) {
555 Dump('<', netiring.supply, c);
556 }
557 if (c)
558 ring_supplied(&netiring, c);
559 returnValue = 1;
560 }
561
562 /*
563 * Something to read from the tty...
564 */
565 if (pfd[TELNET_FD_TIN1].revents & (POLLIN0x0001|POLLHUP0x0010)) {
566 c = read(tin, ttyiring.supply, ring_empty_consecutive(&ttyiring));
567 if (c == -1 && errno(*__errno()) == EIO5)
568 c = 0;
569 if (c == -1 && errno(*__errno()) == EWOULDBLOCK35) {
570 c = 0;
571 } else {
572 /* EOF detection for line mode!!!! */
573 if ((c == 0) && MODE_LOCAL_CHARS(globalmode)((globalmode)&(0x01|0x02)) && isatty(tin)) {
574 /* must be an EOF... */
575 *ttyiring.supply = termEofCharnew_tc.c_cc[0];
576 c = 1;
577 }
578 if (c <= 0) {
579 return -1;
580 }
581 if (termdata) {
582 Dump('<', ttyiring.supply, c);
583 }
584 ring_supplied(&ttyiring, c);
585 }
586 returnValue = 1; /* did something useful */
587 }
588
589 if (pfd[TELNET_FD_NET2].revents & POLLOUT0x0004) {
590 returnValue |= netflush();
591 }
592 if (pfd[TELNET_FD_TOUT0].revents & POLLOUT0x0004) {
593 returnValue |= (ttyflush(SYNCHing|flushout) > 0);
594 }
595
596 return returnValue;
597}