1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * This module implements the "fast path" processing for the telnet protocol.
31 * Since it only knows a very small number of the telnet protocol options,
32 * the daemon is required to assist this module. This module must be run
33 * underneath logindmux, which handles switching messages between the
34 * daemon and the pty master stream appropriately. When an unknown telnet
35 * option is received it is handled as a stop-and-wait operation. The
36 * module refuses to forward data in either direction, and waits for the
37 * daemon to deal with the option, and forward any unprocessed data back
38 * to the daemon.
39 */
40
41 #include <sys/types.h>
42 #include <sys/param.h>
43 #include <sys/stream.h>
44 #include <sys/stropts.h>
45 #include <sys/strsun.h>
46 #include <sys/kmem.h>
47 #include <sys/errno.h>
48 #include <sys/ddi.h>
49 #include <sys/sunddi.h>
50 #include <sys/tihdr.h>
51 #include <sys/ptem.h>
52 #include <sys/logindmux.h>
53 #include <sys/telioctl.h>
54 #include <sys/termios.h>
55 #include <sys/debug.h>
56 #include <sys/conf.h>
57 #include <sys/modctl.h>
58 #include <sys/cmn_err.h>
59 #include <sys/cryptmod.h>
60
61 #define IAC 255
62
63 extern struct streamtab telmodinfo;
64
65 #define TELMOD_ID 105
66 #define SIMWAIT (1*hz)
67
68 /*
69 * Module state flags
70 */
71 #define TEL_IOCPASSTHRU 0x100
72 #define TEL_STOPPED 0x80
73 #define TEL_CRRCV 0x40
74 #define TEL_CRSND 0x20
75 #define TEL_GETBLK 0x10
76
77 /*
78 * NOTE: values TEL_BINARY_IN and TEL_BINARY_OUT are defined in
79 * telioctl.h, passed in the TEL_IOC_MODE ioctl and stored (bitwise)
80 * in the module state flag. So those values are not available
81 * even though they are not defined here.
82 */
83
84
85
86 /*
87 * Per queue instances are single-threaded since the q_ptr
88 * field of queues need to be shared among threads.
89 */
90 static struct fmodsw fsw = {
91 "telmod",
92 &telmodinfo,
93 D_MTQPAIR | D_MP
94 };
95
96 /*
97 * Module linkage information for the kernel.
98 */
99
100 static struct modlstrmod modlstrmod = {
101 &mod_strmodops,
102 "telnet module",
103 &fsw
104 };
105
106 static struct modlinkage modlinkage = {
107 MODREV_1, &modlstrmod, NULL
108 };
109
110 int
_init()111 _init()
112 {
113 return (mod_install(&modlinkage));
114 }
115
116 int
_fini()117 _fini()
118 {
119 return (mod_remove(&modlinkage));
120 }
121
122 int
_info(struct modinfo * modinfop)123 _info(struct modinfo *modinfop)
124 {
125 return (mod_info(&modlinkage, modinfop));
126 }
127
128 static int telmodopen(queue_t *, dev_t *, int, int, cred_t *);
129 static int telmodclose(queue_t *, int, cred_t *);
130 static void telmodrput(queue_t *, mblk_t *);
131 static void telmodrsrv(queue_t *);
132 static void telmodwput(queue_t *, mblk_t *);
133 static void telmodwsrv(queue_t *);
134 static int rcv_parse(queue_t *q, mblk_t *mp);
135 static int snd_parse(queue_t *q, mblk_t *mp);
136 static void telmod_timer(void *);
137 static void telmod_buffer(void *);
138 static void recover(queue_t *, mblk_t *, size_t);
139
140 static struct module_info telmodoinfo = {
141 TELMOD_ID, /* module id number */
142 "telmod", /* module name */
143 0, /* minimum packet size */
144 INFPSZ, /* maximum packet size */
145 512, /* hi-water mark */
146 256 /* lo-water mark */
147 };
148
149 static struct qinit telmodrinit = {
150 (int (*)())telmodrput,
151 (int (*)())telmodrsrv,
152 telmodopen,
153 telmodclose,
154 nulldev,
155 &telmodoinfo,
156 NULL
157 };
158
159 static struct qinit telmodwinit = {
160 (int (*)())telmodwput,
161 (int (*)())telmodwsrv,
162 NULL,
163 NULL,
164 nulldev,
165 &telmodoinfo,
166 NULL
167 };
168
169 struct streamtab telmodinfo = {
170 &telmodrinit,
171 &telmodwinit,
172 NULL,
173 NULL
174 };
175
176 /*
177 * Per-instance state struct for the telnet module.
178 */
179 struct telmod_info {
180 int flags;
181 bufcall_id_t wbufcid;
182 bufcall_id_t rbufcid;
183 timeout_id_t wtimoutid;
184 timeout_id_t rtimoutid;
185 mblk_t *unbind_mp;
186
187 };
188
189 /*ARGSUSED*/
190 static void
dummy_callback(void * arg)191 dummy_callback(void *arg)
192 {}
193
194 /*
195 * telmodopen -
196 * A variety of telnet options can never really be processed in the
197 * kernel. For example, TELOPT_TTYPE, must be based in the TERM
198 * environment variable to the login process. Also, data may already
199 * have reached the stream head before telmod was pushed on the stream.
200 * So when telmod is opened, it begins in stopped state, preventing
201 * further data passing either direction through it. It sends a
202 * T_DATA_REQ messages up toward the daemon. This is so the daemon
203 * can be sure that all data which was not processed by telmod
204 * (because it wasn't yet pushed) has been received at the stream head.
205 */
206 /*ARGSUSED*/
207 static int
telmodopen(queue_t * q,dev_t * devp,int oflag,int sflag,cred_t * credp)208 telmodopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *credp)
209 {
210 struct telmod_info *tmip;
211 mblk_t *bp;
212 union T_primitives *tp;
213 int error;
214
215 if (sflag != MODOPEN)
216 return (EINVAL);
217
218 if (q->q_ptr != NULL) {
219 /* It's already attached. */
220 return (0);
221 }
222 /*
223 * Allocate state structure.
224 */
225 tmip = kmem_zalloc(sizeof (*tmip), KM_SLEEP);
226
227 /*
228 * Cross-link.
229 */
230 q->q_ptr = tmip;
231 WR(q)->q_ptr = tmip;
232
233 noenable(q);
234 tmip->flags |= TEL_STOPPED;
235 qprocson(q);
236
237 /*
238 * Since TCP operates in the TLI-inspired brain-dead fashion,
239 * the connection will revert to bound state if the connection
240 * is reset by the client. We must send a T_UNBIND_REQ in
241 * that case so the port doesn't get "wedged" (preventing
242 * inetd from being able to restart the listener). Allocate
243 * it here, so that we don't need to worry about allocb()
244 * failures later.
245 */
246 while ((tmip->unbind_mp = allocb(sizeof (union T_primitives),
247 BPRI_HI)) == NULL) {
248 bufcall_id_t id = qbufcall(q, sizeof (union T_primitives),
249 BPRI_HI, dummy_callback, NULL);
250 if (!qwait_sig(q)) {
251 qunbufcall(q, id);
252 error = EINTR;
253 goto fail;
254 }
255 qunbufcall(q, id);
256 }
257 tmip->unbind_mp->b_wptr = tmip->unbind_mp->b_rptr +
258 sizeof (struct T_unbind_req);
259 tmip->unbind_mp->b_datap->db_type = M_PROTO;
260 tp = (union T_primitives *)tmip->unbind_mp->b_rptr;
261 tp->type = T_UNBIND_REQ;
262 /*
263 * Send a M_PROTO msg of type T_DATA_REQ (this is unique for
264 * read queue since only write queue can get T_DATA_REQ).
265 * Readstream routine in telnet daemon will do a getmsg() till
266 * it receives this proto message
267 */
268 while ((bp = allocb(sizeof (union T_primitives), BPRI_HI)) == NULL) {
269 bufcall_id_t id = qbufcall(q, sizeof (union T_primitives),
270 BPRI_HI, dummy_callback, NULL);
271 if (!qwait_sig(q)) {
272 qunbufcall(q, id);
273 error = EINTR;
274 goto fail;
275 }
276 qunbufcall(q, id);
277 }
278 bp->b_datap->db_type = M_PROTO;
279 bp->b_wptr = bp->b_rptr + sizeof (union T_primitives);
280 tp = (union T_primitives *)bp->b_rptr;
281 tp->type = T_DATA_REQ;
282 tp->data_req.MORE_flag = 0;
283
284 putnext(q, bp);
285 return (0);
286
287 fail:
288 qprocsoff(q);
289 if (tmip->unbind_mp != NULL) {
290 freemsg(tmip->unbind_mp);
291 }
292 kmem_free(tmip, sizeof (struct telmod_info));
293 q->q_ptr = NULL;
294 WR(q)->q_ptr = NULL;
295 return (error);
296 }
297
298
299 /*
300 * telmodclose - just the normal streams clean-up is required.
301 */
302
303 /*ARGSUSED*/
304 static int
telmodclose(queue_t * q,int flag,cred_t * credp)305 telmodclose(queue_t *q, int flag, cred_t *credp)
306 {
307 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr;
308 mblk_t *mp;
309
310 /*
311 * Flush any write-side data downstream. Ignoring flow
312 * control at this point is known to be safe because the
313 * M_HANGUP below poisons the stream such that no modules can
314 * be pushed again.
315 */
316 while (mp = getq(WR(q)))
317 putnext(WR(q), mp);
318
319 /* Poison the stream head so that we can't be pushed again. */
320 (void) putnextctl(q, M_HANGUP);
321
322 qprocsoff(q);
323 if (tmip->wbufcid) {
324 qunbufcall(q, tmip->wbufcid);
325 tmip->wbufcid = 0;
326 }
327 if (tmip->rbufcid) {
328 qunbufcall(q, tmip->rbufcid);
329 tmip->rbufcid = 0;
330 }
331 if (tmip->wtimoutid) {
332 (void) quntimeout(q, tmip->wtimoutid);
333 tmip->wtimoutid = 0;
334 }
335 if (tmip->rtimoutid) {
336 (void) quntimeout(q, tmip->rtimoutid);
337 tmip->rtimoutid = 0;
338 }
339 if (tmip->unbind_mp != NULL) {
340 freemsg(tmip->unbind_mp);
341 }
342
343 kmem_free(q->q_ptr, sizeof (struct telmod_info));
344 q->q_ptr = WR(q)->q_ptr = NULL;
345 return (0);
346 }
347
348 /*
349 * telmodrput:
350 * Be sure to preserve data order. If the daemon is waiting for additional
351 * data (TEL_GETBLK state) forward new data. Otherwise, apply normal
352 * telnet protocol processing to M_DATA. Take notice of TLI messages
353 * indicating connection tear-down, and change them into M_HANGUP's.
354 */
355 static void
telmodrput(queue_t * q,mblk_t * mp)356 telmodrput(queue_t *q, mblk_t *mp)
357 {
358 mblk_t *newmp;
359 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr;
360 union T_primitives *tip;
361
362 if ((mp->b_datap->db_type < QPCTL) &&
363 ((q->q_first) || ((tmip->flags & TEL_STOPPED) &&
364 !(tmip->flags & TEL_GETBLK)) || !canputnext(q))) {
365 (void) putq(q, mp);
366 return;
367 }
368
369 switch (mp->b_datap->db_type) {
370 case M_DATA:
371
372 /*
373 * If the user level daemon requests for 1 more
374 * block of data (needs more data for protocol processing)
375 * create a M_CTL message block with the mp.
376 */
377 is_mdata:
378 if (tmip->flags & TEL_GETBLK) {
379 if ((newmp = allocb(sizeof (char), BPRI_MED)) == NULL) {
380 recover(q, mp, msgdsize(mp));
381 return;
382 }
383 newmp->b_datap->db_type = M_CTL;
384 newmp->b_wptr = newmp->b_rptr + 1;
385 *(newmp->b_rptr) = M_CTL_MAGIC_NUMBER;
386 newmp->b_cont = mp;
387 tmip->flags &= ~TEL_GETBLK;
388 noenable(q);
389 tmip->flags |= TEL_STOPPED;
390
391 putnext(q, newmp);
392
393 break;
394 }
395 /*
396 * call the protocol parsing routine which processes
397 * the data part of the message block first. Then it
398 * handles protocol and CR/LF processing.
399 * If an error is found inside allocb/dupb, recover
400 * routines inside rcv_parse will queue up the
401 * original message block in its service queue.
402 */
403 (void) rcv_parse(q, mp);
404 break;
405
406 case M_FLUSH:
407 /*
408 * Since M_FLUSH came from TCP, we mark it bound for
409 * daemon, not tty. This only happens when TCP expects
410 * to do a connection reset.
411 */
412 mp->b_flag |= MSGMARK;
413 if (*mp->b_rptr & FLUSHR)
414 flushq(q, FLUSHALL);
415 putnext(q, mp);
416 break;
417
418 case M_PCSIG:
419 case M_ERROR:
420 if (tmip->flags & TEL_GETBLK)
421 tmip->flags &= ~TEL_GETBLK;
422 /* FALLTHRU */
423 case M_IOCACK:
424 case M_IOCNAK:
425 case M_SETOPTS:
426 putnext(q, mp);
427 break;
428
429 case M_PROTO:
430 case M_PCPROTO:
431 if (tmip->flags & TEL_GETBLK)
432 tmip->flags &= ~TEL_GETBLK;
433
434 tip = (union T_primitives *)mp->b_rptr;
435 switch (tip->type) {
436
437 case T_ORDREL_IND:
438 case T_DISCON_IND:
439 /* Make into M_HANGUP and putnext */
440 ASSERT(mp->b_cont == NULL);
441 mp->b_datap->db_type = M_HANGUP;
442 mp->b_wptr = mp->b_rptr;
443 if (mp->b_cont) {
444 freemsg(mp->b_cont);
445 mp->b_cont = NULL;
446 }
447 /*
448 * If we haven't already, send T_UNBIND_REQ to prevent
449 * TCP from going into "BOUND" state and locking up the
450 * port.
451 */
452 if (tip->type == T_DISCON_IND && tmip->unbind_mp !=
453 NULL) {
454 putnext(q, mp);
455 qreply(q, tmip->unbind_mp);
456 tmip->unbind_mp = NULL;
457 } else {
458 putnext(q, mp);
459 }
460 break;
461
462 case T_EXDATA_IND:
463 case T_DATA_IND: /* conform to TPI, but never happens */
464 newmp = mp->b_cont;
465 freeb(mp);
466 mp = newmp;
467 if (mp) {
468 ASSERT(mp->b_datap->db_type == M_DATA);
469 if (msgdsize(mp) != 0) {
470 goto is_mdata;
471 }
472 freemsg(mp);
473 }
474 break;
475
476 /*
477 * We only get T_OK_ACK when we issue the unbind, and it can
478 * be ignored safely.
479 */
480 case T_OK_ACK:
481 ASSERT(tmip->unbind_mp == NULL);
482 freemsg(mp);
483 break;
484
485 default:
486 #ifdef DEBUG
487 cmn_err(CE_NOTE,
488 "telmodrput: unexpected TLI primitive msg "
489 "type 0x%x", tip->type);
490 #endif
491 freemsg(mp);
492 }
493 break;
494
495 default:
496 #ifdef DEBUG
497 cmn_err(CE_NOTE,
498 "telmodrput: unexpected msg type 0x%x",
499 mp->b_datap->db_type);
500 #endif
501 freemsg(mp);
502 }
503 }
504
505 /*
506 * telmodrsrv:
507 * Mostly we end up here because of M_DATA processing delayed due to flow
508 * control or lack of memory. XXX.sparker: TLI primitives here?
509 */
510 static void
telmodrsrv(queue_t * q)511 telmodrsrv(queue_t *q)
512 {
513 mblk_t *mp, *newmp;
514 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr;
515 union T_primitives *tip;
516
517 while ((mp = getq(q)) != NULL) {
518 if (((tmip->flags & TEL_STOPPED) &&
519 !(tmip->flags & TEL_GETBLK)) || !canputnext(q)) {
520 (void) putbq(q, mp);
521 return;
522 }
523 switch (mp->b_datap->db_type) {
524
525 case M_DATA:
526 is_mdata:
527 if (tmip->flags & TEL_GETBLK) {
528 if ((newmp = allocb(sizeof (char),
529 BPRI_MED)) == NULL) {
530 recover(q, mp, msgdsize(mp));
531 return;
532 }
533 newmp->b_datap->db_type = M_CTL;
534 newmp->b_wptr = newmp->b_rptr + 1;
535 *(newmp->b_rptr) = M_CTL_MAGIC_NUMBER;
536 newmp->b_cont = mp;
537 tmip->flags &= ~TEL_GETBLK;
538 noenable(q);
539 tmip->flags |= TEL_STOPPED;
540
541 putnext(q, newmp);
542
543 break;
544 }
545 if (!rcv_parse(q, mp)) {
546 return;
547 }
548 break;
549
550 case M_PROTO:
551
552 tip = (union T_primitives *)mp->b_rptr;
553
554 /*
555 * Unless the M_PROTO message indicates data, clear
556 * TEL_GETBLK so that we stop passing our messages
557 * up to the telnet daemon.
558 */
559 if (tip->type != T_DATA_IND &&
560 tip->type != T_EXDATA_IND)
561 tmip->flags &= ~TEL_GETBLK;
562
563 switch (tip->type) {
564 case T_ORDREL_IND:
565 case T_DISCON_IND:
566 /* Make into M_HANGUP and putnext */
567 ASSERT(mp->b_cont == NULL);
568 mp->b_datap->db_type = M_HANGUP;
569 mp->b_wptr = mp->b_rptr;
570 if (mp->b_cont) {
571 freemsg(mp->b_cont);
572 mp->b_cont = NULL;
573 }
574 /*
575 * If we haven't already, send T_UNBIND_REQ
576 * to prevent TCP from going into "BOUND"
577 * state and locking up the port.
578 */
579 if (tip->type == T_DISCON_IND &&
580 tmip->unbind_mp != NULL) {
581 putnext(q, mp);
582 qreply(q, tmip->unbind_mp);
583 tmip->unbind_mp = NULL;
584 } else {
585 putnext(q, mp);
586 }
587 break;
588
589 case T_DATA_IND: /* conform to TPI, but never happens */
590 case T_EXDATA_IND:
591 newmp = mp->b_cont;
592 freeb(mp);
593 mp = newmp;
594 if (mp) {
595 ASSERT(mp->b_datap->db_type == M_DATA);
596 if (msgdsize(mp) != 0) {
597 goto is_mdata;
598 }
599 freemsg(mp);
600 }
601 break;
602
603 /*
604 * We only get T_OK_ACK when we issue the unbind, and
605 * it can be ignored safely.
606 */
607 case T_OK_ACK:
608 ASSERT(tmip->unbind_mp == NULL);
609 freemsg(mp);
610 break;
611
612 default:
613 #ifdef DEBUG
614 cmn_err(CE_NOTE,
615 "telmodrsrv: unexpected TLI primitive "
616 "msg type 0x%x", tip->type);
617 #endif
618 freemsg(mp);
619 }
620 break;
621
622 case M_SETOPTS:
623 putnext(q, mp);
624 break;
625
626 default:
627 #ifdef DEBUG
628 cmn_err(CE_NOTE,
629 "telmodrsrv: unexpected msg type 0x%x",
630 mp->b_datap->db_type);
631 #endif
632 freemsg(mp);
633 }
634 }
635 }
636
637 /*
638 * telmodwput:
639 * M_DATA is processed and forwarded if we aren't stopped awaiting the daemon
640 * to process something. M_CTL's are data from the daemon bound for the
641 * network. We forward them immediately. There are two classes of ioctl's
642 * we must handle here also. One is ioctl's forwarded by ptem which we
643 * ignore. The other is ioctl's issued by the daemon to control us.
644 * Process them appropriately. M_PROTO's we pass along, figuring they are
645 * are TPI operations for TCP. M_FLUSH requires careful processing, since
646 * telnet cannot tolerate flushing its protocol requests. Also the flushes
647 * can be running either daemon<->TCP or application<->telmod. We must
648 * carefully deal with this.
649 */
650 static void
telmodwput(queue_t * q,mblk_t * mp)651 telmodwput(
652 queue_t *q, /* Pointer to the read queue */
653 mblk_t *mp) /* Pointer to current message block */
654 {
655 struct telmod_info *tmip;
656 struct iocblk *ioc;
657 mblk_t *savemp;
658 int rw;
659 int error;
660
661 tmip = (struct telmod_info *)q->q_ptr;
662
663 switch (mp->b_datap->db_type) {
664 case M_DATA:
665 if (!canputnext(q) || (tmip->flags & TEL_STOPPED) ||
666 (q->q_first)) {
667 noenable(q);
668 (void) putq(q, mp);
669 break;
670 }
671 /*
672 * This routine parses data generating from ptm side.
673 * Insert a null character if carraige return
674 * is not followed by line feed unless we are in binary mode.
675 * Also, duplicate IAC if found in the data.
676 */
677 (void) snd_parse(q, mp);
678 break;
679
680 case M_CTL:
681 if (((mp->b_wptr - mp->b_rptr) == 1) &&
682 (*(mp->b_rptr) == M_CTL_MAGIC_NUMBER)) {
683 savemp = mp->b_cont;
684 freeb(mp);
685 mp = savemp;
686 }
687 putnext(q, mp);
688 break;
689
690 case M_IOCTL:
691 ioc = (struct iocblk *)mp->b_rptr;
692 switch (ioc->ioc_cmd) {
693
694 /*
695 * This ioctl is issued by user level daemon to
696 * request one more message block to process protocol
697 */
698 case TEL_IOC_GETBLK:
699 if (!(tmip->flags & TEL_STOPPED)) {
700 miocnak(q, mp, 0, EINVAL);
701 break;
702 }
703 tmip->flags |= TEL_GETBLK;
704 qenable(RD(q));
705 enableok(RD(q));
706
707 miocack(q, mp, 0, 0);
708 break;
709
710 /*
711 * This ioctl is issued by user level daemon to reenable the
712 * read and write queues. This is issued during startup time
713 * after setting up the mux links and also after processing
714 * the protocol. It is also issued after each time an
715 * an unrecognized telnet option is forwarded to the daemon.
716 */
717 case TEL_IOC_ENABLE:
718
719 /*
720 * Send negative ack if TEL_STOPPED flag is not set
721 */
722 if (!(tmip->flags & TEL_STOPPED)) {
723 miocnak(q, mp, 0, EINVAL);
724 break;
725 }
726 tmip->flags &= ~TEL_STOPPED;
727 if (mp->b_cont) {
728 (void) putbq(RD(q), mp->b_cont);
729 mp->b_cont = 0;
730 }
731
732 qenable(RD(q));
733 enableok(RD(q));
734 qenable(q);
735 enableok(q);
736
737 miocack(q, mp, 0, 0);
738 break;
739
740 /*
741 * Set binary/normal mode for input and output
742 * according to the instructions from the daemon.
743 */
744 case TEL_IOC_MODE:
745 error = miocpullup(mp, sizeof (uchar_t));
746 if (error != 0) {
747 miocnak(q, mp, 0, error);
748 break;
749 }
750 tmip->flags |= *(mp->b_cont->b_rptr) &
751 (TEL_BINARY_IN|TEL_BINARY_OUT);
752 miocack(q, mp, 0, 0);
753 break;
754
755 #ifdef DEBUG
756 case TCSETAF:
757 case TCSETSF:
758 case TCSETA:
759 case TCSETAW:
760 case TCSETS:
761 case TCSETSW:
762 case TCSBRK:
763 case TIOCSTI:
764 case TIOCSWINSZ:
765 miocnak(q, mp, 0, EINVAL);
766 break;
767 #endif
768 case CRYPTPASSTHRU:
769 error = miocpullup(mp, sizeof (uchar_t));
770 if (error != 0) {
771 miocnak(q, mp, 0, error);
772 break;
773 }
774 if (*(mp->b_cont->b_rptr) == 0x01)
775 tmip->flags |= TEL_IOCPASSTHRU;
776 else
777 tmip->flags &= ~TEL_IOCPASSTHRU;
778
779 miocack(q, mp, 0, 0);
780 break;
781
782 default:
783 if (tmip->flags & TEL_IOCPASSTHRU) {
784 putnext(q, mp);
785 } else {
786 #ifdef DEBUG
787 cmn_err(CE_NOTE,
788 "telmodwput: unexpected ioctl type 0x%x",
789 ioc->ioc_cmd);
790 #endif
791 miocnak(q, mp, 0, EINVAL);
792 }
793 break;
794 }
795 break;
796
797 case M_FLUSH:
798 /*
799 * Flushing is tricky: We try to flush all we can, but certain
800 * data cannot be flushed. Telnet protocol sequences cannot
801 * be flushed. So, TCP's queues cannot be flushed since we
802 * cannot tell what might be telnet protocol data. Then we
803 * must take care to create and forward out-of-band data
804 * indicating the flush to the far side.
805 */
806 rw = *mp->b_rptr;
807 if (rw & FLUSHR) {
808 /*
809 * We cannot flush our read queue, since there may
810 * be telnet protocol bits in the queue, awaiting
811 * processing. However, once it leaves this module
812 * it's guaranteed that all protocol data is in
813 * M_CTL, so we do flush read data beyond us, expecting
814 * them (actually logindmux) to do FLUSHDATAs also.
815 */
816 *mp->b_rptr = rw & ~FLUSHW;
817 qreply(q, mp);
818 } else {
819 freemsg(mp);
820 }
821 if (rw & FLUSHW) {
822 /*
823 * Since all telnet protocol data comes from the
824 * daemon, stored as M_CTL messages, flushq will
825 * do exactly what's needed: Flush bytes which do
826 * not have telnet protocol data.
827 */
828 flushq(q, FLUSHDATA);
829 }
830 break;
831
832 case M_PCPROTO:
833 putnext(q, mp);
834 break;
835
836 case M_PROTO:
837 /* We may receive T_DISCON_REQ from the mux */
838 if (!canputnext(q) || q->q_first != NULL)
839 (void) putq(q, mp);
840 else
841 putnext(q, mp);
842 break;
843
844 default:
845 #ifdef DEBUG
846 cmn_err(CE_NOTE,
847 "telmodwput: unexpected msg type 0x%x",
848 mp->b_datap->db_type);
849 #endif
850 freemsg(mp);
851 break;
852 }
853 }
854
855 /*
856 * telmodwsrv - module write service procedure
857 */
858 static void
telmodwsrv(queue_t * q)859 telmodwsrv(queue_t *q)
860 {
861 mblk_t *mp, *savemp;
862
863 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr;
864
865 while ((mp = getq(q)) != NULL) {
866 if (!canputnext(q)) {
867 ASSERT(mp->b_datap->db_type < QPCTL);
868 (void) putbq(q, mp);
869 return;
870 }
871 switch (mp->b_datap->db_type) {
872
873 case M_DATA:
874 if (tmip->flags & TEL_STOPPED) {
875 (void) putbq(q, mp);
876 return;
877 }
878 /*
879 * Insert a null character if carraige return
880 * is not followed by line feed
881 */
882 if (!snd_parse(q, mp)) {
883 return;
884 }
885 break;
886
887 case M_CTL:
888 if (((mp->b_wptr - mp->b_rptr) == 1) &&
889 (*(mp->b_rptr) == M_CTL_MAGIC_NUMBER)) {
890 savemp = mp->b_cont;
891 freeb(mp);
892 mp = savemp;
893 }
894 putnext(q, mp);
895 break;
896
897 case M_PROTO:
898 putnext(q, mp);
899 break;
900
901 default:
902 #ifdef DEBUG
903 cmn_err(CE_NOTE,
904 "telmodwsrv: unexpected msg type 0x%x",
905 mp->b_datap->db_type);
906 #endif
907 freemsg(mp);
908 }
909
910 }
911 }
912
913 /*
914 * This routine is called from read put/service procedure and parses
915 * message block to check for telnet protocol by detecting an IAC.
916 * The routine processes the data part of the message block first and
917 * then sends protocol followed after IAC to the telnet daemon. The
918 * routine also processes CR/LF by eliminating LF/NULL followed after CR.
919 *
920 * Since the code to do this with streams mblks is complicated, some
921 * explanations are in order. If an IAC is found, a dupb() is done,
922 * and the pointers are adjusted to create two streams message. The
923 * (possibly empty) first message contains preceeding data, and the
924 * second begins with the IAC and contains the rest of the streams
925 * message.
926 *
927 * The variables:
928 * datamp: Points to the head of a chain of mblks containing data
929 * which requires no expansion, and can be forwarded directly
930 * to the pty.
931 * prevmp: Points to the last mblk on the datamp chain, used to add
932 * to the chain headed by datamp.
933 * newmp: When an M_CTL header is required, this pointer references
934 * that "header" mblk.
935 * protomp: When an IAC is discovered, a dupb() is done on the first mblk
936 * containing an IAC. protomp points to this dup'ed mblk.
937 * This mblk is eventually forwarded to the daemon.
938 */
939 static int
rcv_parse(queue_t * q,mblk_t * mp)940 rcv_parse(queue_t *q, mblk_t *mp)
941 {
942 mblk_t *protomp, *newmp, *datamp, *prevmp;
943 unsigned char *tmp;
944 size_t msgsize;
945
946 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr;
947
948 datamp = mp;
949 prevmp = protomp = 0;
950
951 while (mp) {
952 /*
953 * If the mblk is empty, just continue scanning.
954 */
955 if (mp->b_rptr == mp->b_wptr) {
956 prevmp = mp;
957 mp = mp->b_cont;
958 continue;
959 }
960 /*
961 * First check to see if we have received CR and are checking
962 * for a following LF/NULL. If so, do what's necessary to
963 * trim the LF/NULL. This case is for when the LF/NULL is
964 * at the beginning of a subsequent mblk.
965 */
966 if (!(tmip->flags & TEL_BINARY_IN) &&
967 (tmip->flags & TEL_CRRCV)) {
968 if ((*mp->b_rptr == '\n') || (*mp->b_rptr == NULL)) {
969 if (mp->b_wptr == (mp->b_rptr + 1)) {
970 tmip->flags &= ~TEL_CRRCV;
971 if (prevmp) {
972 prevmp->b_cont = mp->b_cont;
973 freeb(mp);
974 mp = prevmp->b_cont;
975 continue;
976 } else {
977 datamp = mp->b_cont;
978 freeb(mp);
979 if (datamp == NULL) {
980 /*
981 * Message contained
982 * only a '\0' after
983 * a '\r' in a previous
984 * message, so we can
985 * read more, even
986 * though we have
987 * nothing to putnext.
988 */
989 return (1);
990 } else {
991 mp = datamp;
992 continue;
993 }
994 }
995 }
996 mp->b_rptr += 1;
997 }
998 tmip->flags &= ~TEL_CRRCV;
999 }
1000 tmp = mp->b_rptr;
1001 /*
1002 * Now scan through the entire message block, for IACs
1003 * and CR characters, which need processing.
1004 */
1005 while (tmp < mp->b_wptr) {
1006
1007 if (tmp[0] == IAC) {
1008 /*
1009 * Telnet protocol - parse it now
1010 * process data part of mblk
1011 * before sending the protocol.
1012 */
1013 if (tmp > mp->b_rptr) {
1014 if ((protomp = dupb(mp)) == NULL) {
1015 msgsize = msgdsize(datamp);
1016 recover(q, datamp, msgsize);
1017 return (0);
1018 }
1019 ASSERT(tmp >= mp->b_datap->db_base);
1020 ASSERT(tmp <= mp->b_datap->db_lim);
1021 ASSERT(tmp >=
1022 protomp->b_datap->db_base);
1023 ASSERT(tmp <= protomp->b_datap->db_lim);
1024 mp->b_wptr = tmp;
1025 protomp->b_rptr = tmp;
1026 protomp->b_cont = mp->b_cont;
1027 mp->b_cont = 0;
1028
1029 if (prevmp)
1030 prevmp->b_cont = mp;
1031
1032 } else {
1033 protomp = mp;
1034
1035 if (prevmp)
1036 prevmp->b_cont = 0;
1037 else
1038 datamp = 0;
1039 }
1040 if (datamp) {
1041 putnext(q, datamp);
1042 }
1043 /*
1044 * create a 1 byte M_CTL message block with
1045 * protomp and send it down.
1046 */
1047
1048 if ((newmp = allocb(sizeof (char),
1049 BPRI_MED)) == NULL) {
1050 /*
1051 * Save the dup'ed mp containing
1052 * the protocol information which
1053 * we couldn't get an M_CTL header
1054 * for.
1055 */
1056 msgsize = msgdsize(protomp);
1057 recover(q, protomp, msgsize);
1058 return (0);
1059 }
1060 newmp->b_datap->db_type = M_CTL;
1061 newmp->b_wptr = newmp->b_rptr + 1;
1062 *(newmp->b_rptr) = M_CTL_MAGIC_NUMBER;
1063 newmp->b_cont = protomp;
1064 noenable(q);
1065 tmip->flags |= TEL_STOPPED;
1066 putnext(q, newmp);
1067
1068 return (0);
1069 }
1070 if (!(tmip->flags & TEL_BINARY_IN)) {
1071 /*
1072 * Set TEL_CRRCV flag if last character is CR
1073 */
1074 if ((tmp == (mp->b_wptr - 1)) &&
1075 (tmp[0] == '\r')) {
1076 tmip->flags |= TEL_CRRCV;
1077 break;
1078 }
1079
1080 /*
1081 * If CR is followed by LF/NULL, get rid of
1082 * LF/NULL and realign the message block.
1083 */
1084 if ((tmp[0] == '\r') && ((tmp[1] == '\n') ||
1085 (tmp[1] == NULL))) {
1086 /*
1087 * If CR is in the middle of a block,
1088 * we need to get rid of LF and join
1089 * the two pieces together.
1090 */
1091 if (mp->b_wptr > (tmp + 2)) {
1092 bcopy(tmp + 2, tmp + 1,
1093 (mp->b_wptr - tmp - 2));
1094 mp->b_wptr -= 1;
1095 } else {
1096 mp->b_wptr = tmp + 1;
1097 }
1098
1099 if (prevmp)
1100 prevmp->b_cont = mp;
1101 }
1102 }
1103 tmp++;
1104 }
1105 prevmp = mp;
1106 mp = mp->b_cont;
1107 }
1108 putnext(q, datamp);
1109
1110 return (1);
1111 }
1112
1113 /*
1114 * This routine is called from write put/service procedures and processes
1115 * CR-LF. If CR is not followed by LF, it inserts a NULL character if we are
1116 * in non binary mode. Also, duplicate IAC(0xFF) if found in the mblk.
1117 * This routine is pessimistic: It pre-allocates a buffer twice the size
1118 * of the incoming message, which is the maximum size a message can become
1119 * after IAC expansion.
1120 *
1121 * savemp: Points at the original message, so it can be freed when
1122 * processing is complete.
1123 * mp: The current point of scanning the message.
1124 * newmp: New message being created with the processed output.
1125 */
1126 static int
snd_parse(queue_t * q,mblk_t * mp)1127 snd_parse(queue_t *q, mblk_t *mp)
1128 {
1129 unsigned char *tmp, *tmp1;
1130 mblk_t *newmp, *savemp;
1131 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr;
1132 size_t size = msgdsize(mp);
1133
1134 savemp = mp;
1135
1136 if (size == 0) {
1137 putnext(q, mp);
1138 return (1);
1139 }
1140
1141 /*
1142 * Extra byte to allocb() takes care of the case when there was
1143 * a '\r' at the end of the previous message and there's a '\r'
1144 * at the beginning of the current message.
1145 */
1146 if ((newmp = allocb((2 * size)+1, BPRI_MED)) == NULL) {
1147 recover(q, mp, (2 * size)+1);
1148 return (0);
1149 }
1150 newmp->b_datap->db_type = M_DATA;
1151
1152 tmp1 = newmp->b_rptr;
1153 while (mp) {
1154 if (!(tmip->flags & TEL_BINARY_OUT) &&
1155 (tmip->flags & TEL_CRSND)) {
1156 if (*(mp->b_rptr) != '\n')
1157 *tmp1++ = NULL;
1158 tmip->flags &= ~TEL_CRSND;
1159 }
1160 tmp = mp->b_rptr;
1161 while (tmp < mp->b_wptr) {
1162 if (!(tmip->flags & TEL_BINARY_OUT)) {
1163 *tmp1++ = *tmp;
1164 if ((tmp == (mp->b_wptr - 1)) &&
1165 (tmp[0] == '\r')) {
1166 tmip->flags |= TEL_CRSND;
1167 break;
1168 }
1169 if ((tmp[0] == '\r') &&
1170 (tmp1 == newmp->b_wptr)) {
1171 /* XXX.sparker: can't happen */
1172 tmip->flags |= TEL_CRSND;
1173 break;
1174 }
1175 if ((tmp[0] == '\r') && (tmp[1] != '\n')) {
1176 *tmp1++ = NULL;
1177 }
1178 } else
1179 *tmp1++ = *tmp;
1180
1181 if (tmp[0] == IAC) {
1182 *tmp1++ = IAC;
1183 }
1184 tmp++;
1185 }
1186 mp = mp->b_cont;
1187 }
1188
1189 newmp->b_wptr = tmp1;
1190
1191 putnext(q, newmp);
1192 freemsg(savemp);
1193 return (1);
1194 }
1195
1196 static void
telmod_timer(void * arg)1197 telmod_timer(void *arg)
1198 {
1199 queue_t *q = arg;
1200 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr;
1201
1202 ASSERT(tmip);
1203
1204 if (q->q_flag & QREADR) {
1205 ASSERT(tmip->rtimoutid);
1206 tmip->rtimoutid = 0;
1207 } else {
1208 ASSERT(tmip->wtimoutid);
1209 tmip->wtimoutid = 0;
1210 }
1211 enableok(q);
1212 qenable(q);
1213 }
1214
1215 static void
telmod_buffer(void * arg)1216 telmod_buffer(void *arg)
1217 {
1218 queue_t *q = arg;
1219 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr;
1220
1221 ASSERT(tmip);
1222
1223 if (q->q_flag & QREADR) {
1224 ASSERT(tmip->rbufcid);
1225 tmip->rbufcid = 0;
1226 } else {
1227 ASSERT(tmip->wbufcid);
1228 tmip->wbufcid = 0;
1229 }
1230 enableok(q);
1231 qenable(q);
1232 }
1233
1234 static void
recover(queue_t * q,mblk_t * mp,size_t size)1235 recover(queue_t *q, mblk_t *mp, size_t size)
1236 {
1237 bufcall_id_t bid;
1238 timeout_id_t tid;
1239 struct telmod_info *tmip = (struct telmod_info *)q->q_ptr;
1240
1241 ASSERT(mp->b_datap->db_type < QPCTL);
1242 noenable(q);
1243 (void) putbq(q, mp);
1244
1245 /*
1246 * Make sure there is at most one outstanding request per queue.
1247 */
1248 if (q->q_flag & QREADR) {
1249 if (tmip->rtimoutid || tmip->rbufcid) {
1250 return;
1251 }
1252 } else {
1253 if (tmip->wtimoutid || tmip->wbufcid) {
1254 return;
1255 }
1256 }
1257 if (!(bid = qbufcall(RD(q), size, BPRI_MED, telmod_buffer, q))) {
1258 tid = qtimeout(RD(q), telmod_timer, q, SIMWAIT);
1259 if (q->q_flag & QREADR)
1260 tmip->rtimoutid = tid;
1261 else
1262 tmip->wtimoutid = tid;
1263 } else {
1264 if (q->q_flag & QREADR)
1265 tmip->rbufcid = bid;
1266 else
1267 tmip->wbufcid = bid;
1268 }
1269 }
1270