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