Bug Summary

File:src/usr.bin/telnet/sys_bsd.c
Warning:line 529, column 10
Although the value stored to 'c' is used in the enclosing expression, the value is never actually read from 'c'

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;
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) {
Although the value stored to 'c' is used in the enclosing expression, the value is never actually read from 'c'
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}