xttn.c
上传用户:duobangkj
上传日期:2007-01-07
资源大小:70k
文件大小:12k
源码类别:

Telnet客户端

开发平台:

Unix_Linux

  1. /* xttn.c -- telnet module for XT
  2. This file uses 4-character tabstops
  3. */
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <netdb.h>
  7. #include <sys/types.h>
  8. #include <sys/socket.h>
  9. #include <netinet/in.h>
  10. #include <arpa/telnet.h>
  11. #include <sys/time.h>
  12. #include <sys/select.h>
  13. #include <unistd.h>
  14. #include <signal.h>
  15. #include <setjmp.h>
  16. #include <errno.h>
  17. #include "xt.h"
  18. FILE *cfp, /* capture file pointer */
  19. *fp; /* file to transmit */
  20. int sfd = -1; /* socket file descriptor */
  21. char captfile[SM_BUFF] = CAPTFILE, /* capture file's name */
  22. proto[8];
  23. extern short autoflag, cismode, nl2cr;
  24. extern char hostname[];
  25. extern jmp_buf erret;
  26. short capture = FALSE;
  27. static jmp_buf stop;
  28. static RETSIGTYPE (*oldvec)();
  29. #define SB_IAC 256 /* This is not a TELNET code - it is used to indicated
  30.   that an IAC has been received during an SB sequence. */
  31. #define CAN_WILL (1 << 0) /* Can WILL this protocol. */
  32. #define CAN_DO (1 << 1) /* Can DO this protocol. */ 
  33. #define DONE_WILL (1 << 2) /* WILL done. */
  34. #define DONE_DO (1 << 3) /* DO done. */
  35. #define REC_WILL (1 << 4) /* Received a WILL. */
  36. #define REC_DO (1 << 5) /* Received a DO. */
  37. /* Attach standard input and output to the socket. This only gets called
  38. after a fork by the child process, which then exec's a program that uses
  39. standard i/o for some data transfer protocol.
  40. */
  41. void
  42. sattach()
  43. {
  44. dup2(sfd, 0); /* close local stdin and connect to socket */
  45. dup2(sfd, 1); /* close local stdout and connect to socket */
  46. close(sfd); /* close the old socket descriptor */
  47. }
  48. static
  49. userdatum(c)
  50. unsigned c;
  51. {
  52. static int state=0;
  53. switch(state){
  54. case 0:
  55. case 'r':
  56. {
  57. if(c != IAC){ /* Output character, but suppress a NUL byte after a
  58. carriage return character, because it is put in by
  59. the other end to meet protocol requirements. */
  60. if(state != 'r' || c != 0)
  61. return (SUCCESS);
  62. /* Set the new state to 'r' if a 'r' was 
  63. received and we're not in binary mode. */
  64. state = 
  65.   !(proto[TELOPT_BINARY] & REC_WILL) && c == 'r'
  66.   ? 'r'
  67.   : 0;
  68. }
  69. else
  70. state = IAC;
  71. break;
  72. }
  73. case IAC:
  74. {
  75. switch(c) {
  76. case SE:
  77. case NOP:
  78. case DM:
  79. case BREAK:
  80. case IP:
  81. case AO:
  82. case AYT:
  83. case EC:
  84. case EL:
  85. case GA:
  86. state = 0;
  87. break;
  88. case SB:
  89. state = SB;
  90. break;
  91. case IAC:
  92. state = 0;
  93. return (SUCCESS);
  94. case WILL:
  95. state = WILL;
  96. break;
  97. case WONT:
  98. state = WONT;
  99. break;
  100. case DO:
  101. state = DO;
  102. break;
  103. case DONT:
  104. state = DONT;
  105. break;
  106. default:
  107. state = 0;
  108. }
  109. break;
  110. }
  111. case SB:
  112. case SB_IAC:
  113. {
  114. if(state == SB_IAC) {
  115. if(c == IAC)
  116. state = SB;
  117. else if(c == SE)
  118. state = 0;
  119. } else if(c == IAC)
  120. state = SB_IAC;
  121. break;
  122. }
  123. case WILL:
  124. {
  125. unsigned char rbuf[3];
  126. rbuf[1] = 0;
  127. if(c < sizeof(proto) && proto[c] & CAN_DO) {
  128. proto[c] |= REC_WILL;
  129. if(!(proto[c] & DONE_DO)) {
  130. rbuf[1] = DO;
  131. proto[c] |= DONE_DO;
  132. }
  133. } else
  134. rbuf[1] = DONT;
  135. if(rbuf[1]) {
  136. rbuf[0] = (unsigned char) IAC;
  137. rbuf[2] = (unsigned char) c;
  138. send_string(rbuf, sizeof(rbuf));
  139. }
  140. state = 0;
  141. break;
  142. }
  143. case DO:
  144. {
  145. unsigned char rbuf[3];
  146. rbuf[1] = 0;
  147. if(c < sizeof(proto) && proto[c] & CAN_WILL) {
  148. proto[c] |= REC_DO;
  149. if(!(proto[c] & DONE_WILL)) {
  150. rbuf[1] = WILL;
  151. proto[c] |= DONE_WILL;
  152. }
  153. }
  154. else rbuf[1] = WONT;
  155. if(rbuf[1]) {
  156. rbuf[0] = (unsigned char) IAC;
  157. rbuf[2] = (unsigned char) c;
  158. send_string(rbuf, sizeof(rbuf));
  159. }
  160. state = 0;
  161. break;
  162. }
  163. case WONT:
  164. if(c < sizeof(proto))
  165. proto[c] &= ~(REC_WILL | DONE_DO);
  166. state = 0;
  167. break;
  168. case DONT:
  169. if(c < sizeof(proto))
  170. proto[c] &= ~(REC_DO | DONE_WILL);
  171. state = 0;
  172. break;
  173. }
  174. return (FAILURE);
  175. }
  176. static void
  177. alrm(junk)
  178. int junk;
  179. { /* do nothing */
  180. }
  181. /*  Get a byte from the socket within 'seconds' or return -1.
  182.     All data read from the socket are input through this routine.
  183. */
  184. readbyte(seconds)
  185. unsigned seconds;
  186. {
  187.     static int count = 0;
  188.     static char *p, rxbuf[LG_BUFF];
  189.     unsigned alarm();
  190.     if (count-- > 0){
  191. return(*p++ & 0xff);
  192.     }
  193.     if (seconds){
  194.         signal(SIGALRM, alrm);
  195.         alarm(seconds);
  196.     }
  197.     if ((count = read(sfd, p = rxbuf, LG_BUFF)) < 1)
  198.         return(-1);
  199.     if (seconds)
  200.         alarm(0);
  201.     if (count-- > 0){
  202. return(*p++ & 0xff);
  203.     }
  204. }
  205. void
  206. sendbyte(ch)
  207. int ch;
  208. {
  209.     char c = ch & 0xff;
  210. send_string(&c, 1);
  211. }
  212. /* Write data to the remote host. If an error (other than EPIPE) occurs, then
  213.    abort, and don't return. EPIPE errors are ignored. */
  214. void
  215. send_string(data, len)
  216. char *data;
  217. int len;
  218. {
  219. if(write(sfd, data, len) < 0 && errno != EPIPE){
  220. S1("Cannot write to host");
  221. s_exit();
  222. }
  223. }
  224. /*  start capturing */
  225. static void
  226. capt_on()
  227. {
  228. if (capture)
  229. sprintf(Msg,"Already capturing to "%s"",captfile);
  230. else {
  231. if (!(cfp = fopen(captfile, "a")))
  232. sprintf(Msg,"Can't open "%s" for capturing",captfile);
  233. else
  234. capture = TRUE,
  235.     sprintf(Msg,"Capturing to "%s"",captfile),
  236.     setbuf(cfp, NIL(char));
  237. }
  238. S2(Msg);
  239. }
  240. /*  stop capturing */
  241. static RETSIGTYPE 
  242. capt_off()
  243. {
  244. if (!capture)
  245. sprintf(Msg,"Sorry, we haven't been capturing lately");
  246. else
  247. fclose(cfp),
  248.     capture = FALSE,
  249.     sprintf(Msg,""%s" closed for capturing",captfile);
  250. S2(Msg);
  251. }
  252. /* cleanup, flush and exit */
  253. static RETSIGTYPE 
  254. cleanup()
  255. {
  256. if (capture)
  257. fclose(cfp),
  258.     sprintf(Msg,""%s" closed for capturing",captfile),
  259.     S2(Msg);
  260. capture = FALSE;
  261. }
  262. static void 
  263. end_divert(junk)
  264. int junk;
  265. {
  266. show_abort();
  267. fclose(fp);
  268. signal(SIGINT, oldvec);
  269. longjmp(stop,1);
  270. }
  271. /* Divert file into input stream */
  272. void 
  273. divert(script)
  274. short script;
  275. {
  276. int c;
  277. if (!script)
  278. fputc('r',tfp),
  279. fputc('n',tfp),
  280. show(-1,"File?"),
  281. getline(),
  282. getword();
  283. if (word[0] == '')
  284. return;
  285. if (!(fp = fopen(word, "r"))){
  286. sprintf(Msg,"Can't access '%s'",word);
  287. S2(Msg);
  288. return;
  289. }
  290. oldvec = signal(SIGINT,end_divert);
  291. if (setjmp(stop))
  292. return;
  293. while ((c = getc(fp)) != EOF){
  294. if (c != 'n')
  295. sendbyte(c);
  296. else
  297. sendbyte(nl2cr ? 'r' : 'n');
  298. }
  299. fclose(fp);
  300. signal(SIGINT,oldvec);
  301. }
  302. xttn()
  303. {
  304. /* Request string for a binary path. */
  305. static char req_bin[] = {
  306. (char) IAC, (char) DO, (char) TELOPT_BINARY,
  307. (char) IAC, (char) WILL, (char) TELOPT_BINARY
  308. };
  309. /* Request string for ECHO and Suppress GA. */
  310. static char req_opt[] = {
  311. (char) IAC, (char) DO, (char) TELOPT_ECHO,
  312. (char) IAC, (char) DO, (char) TELOPT_SGA
  313. };
  314. int i, port;
  315. long netnum;
  316. struct hostent *n;
  317. struct sockaddr_in in;
  318. if (sfd > 0)
  319. close (sfd);
  320. sfd = -1;
  321. port = 23; /* Default TELNET port. */
  322. netnum = inet_addr(hostname);
  323. if(netnum == -1) {
  324. n = gethostbyname(hostname);
  325. if(!n) {
  326. sprintf(Msg,"Host %s is not known",hostname);
  327. S;
  328. return(FALSE);
  329. }
  330. for(i = 0; n->h_addr_list[i]; i++){
  331. sfd = socket(AF_INET, SOCK_STREAM, 0);
  332. if(sfd < 0){
  333. S1("Cannot create a socket");
  334. s_exit();
  335. }
  336. memcpy(&netnum, n->h_addr_list[i], sizeof(netnum));
  337. memset(&in, 0, sizeof(in));
  338. in.sin_family = AF_INET;
  339. in.sin_port = htons(port);
  340. in.sin_addr.s_addr = netnum;
  341. sprintf(Msg,"Trying %s...",inet_ntoa(in.sin_addr));
  342. S;
  343. if(connect(sfd, &in, sizeof(in)) >= 0)
  344. break;
  345. close(sfd);
  346. }
  347. if(!n->h_addr_list[i])
  348. s_exit();
  349. } else {
  350. sfd = socket(AF_INET, SOCK_STREAM, 0);
  351. if(sfd < 0){
  352. S1("Cannot create a socket");
  353. s_exit();
  354. }
  355. memset(&in, 0, sizeof(in));
  356. in.sin_family = AF_INET;
  357. in.sin_port = htons(port);
  358. in.sin_addr.s_addr = netnum;
  359. sprintf(Msg,"Trying %s...",hostname);
  360. S;
  361. if(connect(sfd, &in, sizeof(in)) < 0)
  362. s_exit();
  363. }
  364. /* Ignore broken pipes on writing, we'll spot the eof on input instead. */
  365. signal(SIGPIPE, SIG_IGN);
  366. memset(proto, 0, sizeof(proto));
  367. /* Request remote echo and suppress GA. */
  368. proto[TELOPT_ECHO] = DONE_DO | CAN_DO;
  369. proto[TELOPT_SGA] = DONE_DO | CAN_DO;
  370. send_string(req_opt, sizeof(req_opt));
  371. /* Request binary link */
  372. proto[TELOPT_BINARY] = DONE_DO | DONE_WILL | CAN_DO | CAN_WILL;
  373. send_string(req_bin, sizeof(req_bin));
  374. return(tninit());
  375. }
  376. tnterm()
  377. {
  378. int res, i, rdy_kbd, rdy_host;
  379. fd_set readfds, writefds, exceptfds;
  380. struct timeval select_timout = {0L,0L};
  381. unsigned cu;
  382. if (sfd < 0)
  383. return(FAILURE);
  384. if (autoflag)
  385. capt_on();
  386. FD_ZERO(&readfds);
  387. FD_ZERO(&writefds);
  388. FD_ZERO(&exceptfds);
  389. mode(NEWMODE);
  390. while (1) {
  391. FD_SET(0,   &readfds);
  392. FD_SET(sfd, &readfds);
  393. FD_SET(0, &exceptfds);
  394. FD_SET(sfd, &exceptfds);
  395. select_timout.tv_sec = 600L;
  396. res = select(sfd+1, &readfds, &writefds, &exceptfds, &select_timout);
  397. if(res == 0) {
  398. if(FD_ISSET(0, &exceptfds) || FD_ISSET(sfd, &exceptfds))
  399. res = -1; /* Exception raisied */
  400. }
  401. rdy_kbd  = FD_ISSET(0,   &readfds);
  402. rdy_host = FD_ISSET(sfd, &readfds);
  403. if(res < 0){
  404. S1("Error on Telnet");
  405. longjmp(erret,1);
  406. }
  407. if(rdy_host){ /* Data available from the host, so read some. */
  408. char buf[LG_BUFF];
  409. res = read(sfd, buf, sizeof(buf));
  410. if(res == 0)
  411. break;
  412. if(res < 0){
  413. S1("Error on socket read");
  414. s_exit();
  415. }
  416. for (i=0;i<res;i++){
  417. cu = (unchar)buf[i];
  418. if (cismode && cu == ENQ) {
  419. cleanup();
  420. cismode = 2;
  421. return(SUCCESS);
  422. }
  423. fputc(cu,tfp);
  424. if (capture && cu != 'r')
  425. fputc(cu,cfp);
  426. }
  427. }
  428. if(rdy_kbd) {
  429. char buf[LG_BUFF / 2];
  430. char obuf[LG_BUFF];
  431. binding_t *ptr;
  432. extern binding_t *first_binding;
  433. int lc, xcape, olen = 0;
  434. res = read(0, buf, sizeof(buf));
  435. if(res < 0){
  436. S1("Error on stdin read");
  437. s_exit();
  438. }
  439. if(res == 0)
  440. /* End of file on input - so just exit. */
  441. s_exit();
  442. for (i=0;i<res;i++){
  443. cu = (int) buf[i] & 0xff;
  444. if (! xcape && cu == my_escape){
  445. xcape++;
  446. continue;
  447. }
  448. if (xcape){
  449. xcape=0;
  450. lc = tolower(cu);
  451. for (ptr = first_binding; ptr; ptr = ptr->bs_next){
  452. if (ptr->bs_c == lc){
  453. switch (ptr->bs_function){
  454. case CAPTYES:
  455. capt_on();
  456. cu = 0;
  457. break;
  458. case CAPTEND:
  459. capt_off();
  460. cu = 0;
  461. break;
  462. case DIVCHAR:
  463. mode(SIGMODE);
  464. divert(FALSE);
  465. mode(NEWMODE);
  466. cu = 0;
  467. break;
  468. case HLPCHAR:
  469. show_bindings();
  470. cu = 0;
  471. break;
  472. case ENDCHAR:
  473. cleanup();
  474. return(FALSE);
  475. case QUITCHR:
  476. cleanup();
  477. s_exit();
  478. default: /* just use the next character */
  479. ;
  480. }
  481. }
  482. }
  483. }
  484. if(cu)
  485. obuf[olen++] = (char) cu;
  486. if(cu == IAC) { /* Force the IAC escape character. */
  487. obuf[olen++] = (char) IAC;
  488. } else if(cu == 'r' && !(proto[TELOPT_BINARY] & REC_DO)) {
  489. /* Always insert a NUL byte after a carriage return. 
  490.    Strictly speaking this is necessary only if a line
  491.    feed does not follow. Don't do this in binary mode/ */
  492. obuf[olen++] = 0;
  493. }
  494. }
  495. if(olen)
  496. send_string(obuf, olen);
  497. }
  498. }
  499. S2("Connection closed by remote host.");
  500. *hostname = '';
  501. close (sfd);
  502. sfd = -1;
  503. return(FALSE);
  504. }
  505. tninit()
  506. {
  507. int res, i, rdy;
  508. fd_set readfds, writefds, exceptfds;
  509. struct timeval select_timout= {0L,0L};
  510. unsigned cu;
  511. if (sfd < 0)
  512. return(FAILURE);
  513. FD_ZERO(&readfds);
  514. FD_ZERO(&writefds);
  515. FD_ZERO(&exceptfds);
  516. FD_SET(sfd, &readfds);
  517. FD_SET(sfd, &exceptfds);
  518. while (1) {
  519. select_timout.tv_sec = 200L;
  520. res = select(sfd+1, &readfds, &writefds, &exceptfds, &select_timout);
  521. if(res == 0) {
  522. if(FD_ISSET(sfd, &exceptfds))
  523. res = -1; /* Exception raisied */
  524. }
  525. rdy = FD_ISSET(sfd, &readfds);
  526. if(res < 0){
  527. S1("Error on Telnet");
  528. s_exit();
  529. }
  530. if(rdy) {
  531. /* Data available from the host, so read some. */
  532. char buf[LG_BUFF];
  533. res = read(sfd, buf, 1);
  534. if(res == 0)
  535. break;
  536. if(res < 0){
  537. S1("Error on socket read");
  538. s_exit();
  539. }
  540. for (i=0;i<res;i++){
  541. cu = (unchar)buf[i];
  542. if (userdatum(cu))
  543. return(SUCCESS);
  544. }
  545. }
  546. }
  547. return(SUCCESS);
  548. }