| char *cktelv = "Telnet support, 8.0.269, 4 Mar 2004"; |
| #define CKCTEL_C |
| |
| int sstelnet = 0; /* Do server-side Telnet negotiation */ |
| |
| /* C K C T E L -- Telnet support */ |
| |
| /* |
| Authors: |
| Telnet protocol by Frank da Cruz and Jeffrey Altman. |
| Telnet Forward X by Jeffrey Altman |
| Telnet START_TLS support by Jeffrey Altman |
| Telnet AUTH and ENCRYPT support by Jeffrey Altman |
| Telnet COMPORT support by Jeffrey Altman |
| Telnet NEW-ENVIRONMENT support by Jeffrey Altman |
| Telnet NAWS support by Frank da Cruz and Jeffrey Altman |
| Telnet TERMTYPE support by Jeffrey Altman |
| Telnet KERMIT support by Jeffrey Altman |
| Other contributions as indicated in the code. |
| |
| Copyright (C) 1985, 2004, |
| Trustees of Columbia University in the City of New York. |
| All rights reserved. See the C-Kermit COPYING.TXT file or the |
| copyright text in the ckcmai.c module for disclaimer and permissions. |
| */ |
| |
| /* |
| NOTE TO CONTRIBUTORS: This file, and all the other shared (ckc and cku) |
| C-Kermit source files, must be compatible with C preprocessors that support |
| only #ifdef, #else, #endif, #define, and #undef. Please do not use #if, |
| logical operators, or other preprocessor features in this module. Also, |
| don't use any ANSI C constructs except within #ifdef CK_ANSIC..#endif. |
| */ |
| |
| #include "ckcsym.h" |
| #include "ckcdeb.h" |
| |
| #ifdef TNCODE |
| #include "ckcker.h" |
| #define TELCMDS /* to define name array */ |
| #define TELOPTS /* to define name array */ |
| #define SLC_NAMES /* to define name array */ |
| #define ENCRYPT_NAMES |
| #define AUTH_NAMES |
| #define TELOPT_STATES |
| #define TELOPT_MODES |
| #define TNC_NAMES |
| #include "ckcnet.h" |
| #include "ckctel.h" |
| #ifdef CK_AUTHENTICATION |
| #include "ckuath.h" |
| #endif /* CK_AUTHENTICATION */ |
| #ifdef CK_SSL |
| #include "ck_ssl.h" |
| #endif /* CK_SSL */ |
| |
| #ifndef NOTERM |
| #ifdef OS2 /* For terminal type name string */ |
| #include "ckuusr.h" |
| #ifndef NT |
| #include <os2.h> |
| #undef COMMENT |
| #else |
| #define isascii __isascii |
| #endif /* NT */ |
| #include "ckocon.h" |
| extern int tt_type, max_tt; |
| extern struct tt_info_rec tt_info[]; |
| #endif /* OS2 */ |
| #endif /* NOTERM */ |
| |
| #ifdef OS2 |
| #include <assert.h> |
| #ifdef NT |
| #include <setjmpex.h> |
| #else /* NT */ |
| #include <setjmp.h> |
| #endif /* NT */ |
| #include <signal.h> |
| #include "ckcsig.h" |
| #include "ckosyn.h" |
| #endif /* OS2 */ |
| |
| #ifdef CK_NAWS /* Negotiate About Window Size */ |
| #ifdef RLOGCODE |
| _PROTOTYP( int rlog_naws, (void) ); |
| #endif /* RLOGCODE */ |
| #endif /* CK_NAWS */ |
| |
| int tn_init = 0; /* Telnet protocol initialized flag */ |
| int tn_begun = 0; /* Telnet protocol started flag */ |
| static int tn_first = 1; /* First time init flag */ |
| extern int tn_exit; /* Exit on disconnect */ |
| extern int inserver; /* Running as IKSD */ |
| char *tn_term = NULL; /* Terminal type override */ |
| |
| #ifdef CK_SNDLOC |
| char *tn_loc = NULL; /* Location override */ |
| #endif /* CK_SNDLOC */ |
| int tn_nlm = TNL_CRLF; /* Telnet CR -> CR LF mode */ |
| int tn_b_nlm = TNL_CR; /* Telnet Binary CR RAW mode */ |
| int tn_b_meu = 0; /* Telnet Binary ME means U too */ |
| int tn_b_ume = 0; /* Telnet Binary U means ME too */ |
| int tn_wait_flg = 1; /* Telnet Wait for Negotiations */ |
| int tn_infinite = 0; /* Telnet Bug Infinite-Loop-Check */ |
| int tn_rem_echo = 1; /* We will echo if WILL ECHO */ |
| int tn_b_xfer = 0; /* Telnet Binary for Xfers? */ |
| int tn_sb_bug = 1; /* Telnet BUG - SB w/o WILL or DO */ |
| int tn_auth_krb5_des_bug = 1; /* Telnet BUG - AUTH KRB5 DES */ |
| /* truncates long keys */ |
| int tn_no_encrypt_xfer = 0; /* Turn off Telnet Encrypt? */ |
| int tn_delay_sb = 1; /* Delay SBs until safe */ |
| int tn_auth_how = TN_AUTH_HOW_ANY; |
| int tn_auth_enc = TN_AUTH_ENC_ANY; |
| int tn_deb = 0; /* Telnet Debug mode */ |
| int tn_sfu = 0; /* Microsoft SFU compatibility */ |
| #ifdef CK_FORWARD_X |
| char * tn_fwdx_xauthority = NULL; /* Xauthority File */ |
| int fwdx_no_encrypt = 0; /* Forward-X requires encryption */ |
| #endif /* CK_FORWARD_X */ |
| |
| #ifdef OS2 |
| int ttnum = -1; /* Last Telnet Terminal Type sent */ |
| int ttnumend = 0; /* Has end of list been found */ |
| #endif /* OS2 */ |
| |
| char tn_msg[TN_MSG_LEN]; /* Telnet data can be rather long */ |
| char hexbuf[TN_MSG_LEN]; |
| char tn_msg_out[TN_MSG_LEN]; |
| #ifdef CK_FORWARD_X |
| CHAR fwdx_msg_out[TN_MSG_LEN]; |
| #endif /* CK_FORWARD_X */ |
| |
| /* |
| In order to prevent an infinite telnet negotiation loop we maintain a |
| count of the number of times the same telnet negotiation message is |
| sent. When this count hits MAXTNCNT, we do not send any more of the |
| message. The count is stored in the tncnts[][] array. |
| |
| The tncnts[][] array is indexed by negotiation option (SUPPRESS GO AHEAD, |
| TERMINAL TYPE, NAWS, etc. - see the tnopts[] array) and the four |
| negotiation message types (WILL, WONT, DO, DONT). All telnet negotiations |
| are kept track of in this way. |
| |
| The count for a message is zeroed when the "opposite" message is sent. |
| WILL is the opposite of WONT, and DO is the opposite of DONT. |
| For example sending "WILL SGA" increments tncnts[TELOPT_SGA][0] |
| and zeroes tncnts[TELOPT_SGA][1]. |
| |
| The code that does this is in tn_sopt(). |
| |
| rogersh@fsj.co.jp, 18/3/1995 |
| |
| 8/16/1998 - with the recent rewrite of the telnet state machine I don't |
| think this code is necessary anymore. However, it can't do any harm so |
| I am leaving it in. - Jeff |
| |
| 12/28/1998 - all references to tncnts[] must be done with TELOPT_INDEX(opt) |
| because the Telnet option list is no longer contiguous. We also must |
| allocate NTELOPTS + 1 because the TELOPT_INDEX() macro returns NTELOPTS |
| for an invalid option number. |
| */ |
| |
| #define MAXTNCNT 4 /* Permits 4 intermediate telnet firewalls/gateways */ |
| |
| char tncnts[NTELOPTS+1][4]; /* Counts */ |
| char tnopps[4] = { 1,0,3,2 }; /* Opposites */ |
| |
| #ifdef CK_ENVIRONMENT |
| #ifdef CK_FORWARD_X |
| #define TSBUFSIZ 2056 |
| #else /* CK_FORWARD_X */ |
| #define TSBUFSIZ 1024 |
| #endif /* CK_FORWARD_X */ |
| char tn_env_acct[64]; |
| char tn_env_disp[64]; |
| char tn_env_job[64]; |
| char tn_env_prnt[64]; |
| char tn_env_sys[64]; |
| char * tn_env_uservar[8][2]; |
| int tn_env_flg = 1; |
| #else /* CK_ENVIRONMENT */ |
| #define TSBUFSIZ 41 |
| int tn_env_flg = 0; |
| #endif /* CK_ENVIRONMENT */ |
| |
| #ifdef COMMENT |
| /* SIGWINCH handler moved to ckuusx.c */ |
| #ifndef NOSIGWINCH |
| #ifdef CK_NAWS /* Window size business */ |
| #ifdef UNIX |
| #include <signal.h> |
| #endif /* UNIX */ |
| #endif /* CK_NAWS */ |
| #endif /* NOSIGWINCH */ |
| #endif /* COMMENT */ |
| |
| CHAR sb[TSBUFSIZ]; /* Buffer - incoming subnegotiations */ |
| CHAR sb_out[TSBUFSIZ]; /* Buffer - outgoing subnegotiations */ |
| |
| int tn_duplex = 1; /* Local echo */ |
| |
| extern char uidbuf[]; /* User ID buffer */ |
| extern int quiet, ttnet, ttnproto, debses, what, duplex, oldplex, local; |
| extern int seslog, sessft, whyclosed; |
| #ifdef OS2 |
| #ifndef NOTERM |
| extern int tt_rows[], tt_cols[]; |
| extern int tt_status[VNUM]; |
| extern int scrninitialized[]; |
| #endif /* NOTERM */ |
| #else /* OS2 */ |
| extern int tt_rows, tt_cols; /* Everybody has this */ |
| #endif /* OS2 */ |
| extern int cmd_cols, cmd_rows; |
| extern char namecopy[]; |
| extern char myipaddr[]; /* Global copy of my IP address */ |
| |
| #ifndef TELOPT_MACRO |
| int |
| telopt_index(opt) int opt; { |
| if (opt >= 0 && opt <= TELOPT_STDERR) |
| return(opt); |
| else if (opt >= TELOPT_PRAGMA_LOGON && opt <= TELOPT_PRAGMA_HEARTBEAT) |
| return(opt-88); |
| else if (opt == TELOPT_IBM_SAK) |
| return(opt-147); |
| else |
| return(NTELOPTS); |
| } |
| |
| int |
| telopt_ok(opt) int opt; { |
| return((opt >= TELOPT_BINARY && opt <= TELOPT_STDERR) || |
| (opt >= TELOPT_PRAGMA_LOGON && opt <= TELOPT_PRAGMA_HEARTBEAT) || |
| (opt == TELOPT_IBM_SAK)); |
| } |
| |
| CHAR * |
| telopt(opt) int opt; { |
| if (telopt_ok(opt)) |
| return((CHAR *)telopts[telopt_index(opt)]); |
| else |
| return((CHAR *)"UNKNOWN"); |
| } |
| |
| int |
| telopt_mode_ok(opt) int opt; { |
| return((unsigned int)(opt) <= TN_NG_MU); |
| } |
| |
| CHAR * |
| telopt_mode(opt) int opt; { |
| if (telopt_mode_ok(opt)) |
| return((CHAR *)telopt_modes[opt-TN_NG_RF]); |
| else |
| return((CHAR *)"UNKNOWN"); |
| } |
| #endif /* TELOPT_MACRO */ |
| |
| static int |
| tn_outst(notquiet) int notquiet; { |
| int outstanding = 0; |
| int x = 0; |
| #ifdef CK_ENCRYPTION |
| int e = 0; |
| int d = 0; |
| #endif /* CK_ENCRYPTION */ |
| |
| if (tn_wait_flg) { |
| for (x = TELOPT_FIRST; x <= TELOPT_LAST; x++) { |
| if (TELOPT_OK(x)) { |
| if (TELOPT_UNANSWERED_WILL(x)) { |
| if ( notquiet ) |
| printf("?Telnet waiting for response to WILL %s\r\n", |
| TELOPT(x)); |
| debug(F111,"tn_outst","unanswered WILL",x); |
| outstanding = 1; |
| if ( !notquiet ) |
| break; |
| } |
| if (TELOPT_UNANSWERED_DO(x)) { |
| if ( notquiet ) |
| printf("?Telnet waiting for response to DO %s\r\n", |
| TELOPT(x)); |
| debug(F111,"tn_outst","unanswered DO",x); |
| outstanding = 1; |
| if ( !notquiet ) |
| break; |
| } |
| if (TELOPT_UNANSWERED_WONT(x)) { |
| if ( notquiet ) |
| printf("?Telnet waiting for response to WONT %s\r\n", |
| TELOPT(x)); |
| debug(F111,"tn_outst","unanswered WONT",x); |
| outstanding = 1; |
| if ( !notquiet ) |
| break; |
| } |
| if (TELOPT_UNANSWERED_DONT(x)) { |
| if ( notquiet ) |
| printf("?Telnet waiting for response to DONT %s\r\n", |
| TELOPT(x)); |
| debug(F111,"tn_outst","unanswered DONT",x); |
| outstanding = 1; |
| if ( !notquiet ) |
| break; |
| } |
| if (TELOPT_UNANSWERED_SB(x)) { |
| if ( notquiet ) |
| printf("?Telnet waiting for response to SB %s\r\n", |
| TELOPT(x)); |
| debug(F111,"tn_outst","unanswered SB",x); |
| outstanding = 1; |
| if ( !notquiet ) |
| break; |
| } |
| } |
| } |
| #ifdef CK_AUTHENTICATION |
| if (ck_tn_auth_in_progress()) { |
| if (TELOPT_ME(TELOPT_AUTHENTICATION)) { |
| if (notquiet) |
| printf("?Telnet waiting for WILL %s subnegotiation\r\n", |
| TELOPT(TELOPT_AUTHENTICATION)); |
| debug(F111, |
| "tn_outst", |
| "ME authentication in progress", |
| TELOPT_AUTHENTICATION |
| ); |
| outstanding = 1; |
| } else if (TELOPT_U(TELOPT_AUTHENTICATION)) { |
| if (notquiet) |
| printf("?Telnet waiting for DO %s subnegotiation\r\n", |
| TELOPT(TELOPT_AUTHENTICATION)); |
| debug(F111, |
| "tn_outst", |
| "U authentication in progress", |
| TELOPT_AUTHENTICATION |
| ); |
| outstanding = 1; |
| } |
| } |
| #endif /* CK_AUTHENTICATION */ |
| #ifdef CK_ENCRYPTION |
| if (!outstanding) { |
| e = ck_tn_encrypting(); |
| d = ck_tn_decrypting(); |
| if (TELOPT_ME(TELOPT_ENCRYPTION)) { |
| if (TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop && e || |
| !TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop && !e |
| ) { |
| if ( notquiet ) |
| printf("?Telnet waiting for WILL %s subnegotiation\r\n", |
| TELOPT(TELOPT_ENCRYPTION)); |
| debug(F111, |
| "tn_outst", |
| "encryption mode switch", |
| TELOPT_ENCRYPTION |
| ); |
| outstanding = 1; |
| } |
| } |
| if (TELOPT_U(TELOPT_ENCRYPTION)) { |
| if (TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop && d || |
| !TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop && !d |
| ) { |
| if ( notquiet ) |
| printf("?Telnet waiting for DO %s subnegotiation\r\n", |
| TELOPT(TELOPT_ENCRYPTION)); |
| debug(F111, |
| "tn_outst", |
| "decryption mode switch", |
| TELOPT_ENCRYPTION |
| ); |
| outstanding = 1; |
| } |
| } |
| } |
| #endif /* CK_ENCRYPTION */ |
| } /* if (tn_wait_flg) */ |
| |
| #ifdef IKS_OPTION |
| /* Even if we are not waiting for Telnet options we must wait for */ |
| /* Kermit Telnet Subnegotiations if we have sent a request to the */ |
| /* other guy. Otherwise we will get out of sync. */ |
| if (!outstanding) { |
| if (TELOPT_U(TELOPT_KERMIT) && |
| (TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start || |
| TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop || |
| !TELOPT_SB(TELOPT_KERMIT).kermit.sop) |
| ) { |
| if ( notquiet ) |
| printf("?Telnet waiting for SB %s negotiation\r\n", |
| TELOPT(TELOPT_KERMIT)); |
| debug(F111,"tn_outst","U kermit in progress",TELOPT_KERMIT); |
| outstanding = 1; |
| } |
| } |
| #endif /* IKS_OPTION */ |
| |
| #ifdef TN_COMPORT |
| if (!outstanding) { |
| if (TELOPT_ME(TELOPT_COMPORT)) { |
| if (TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb) { |
| if (notquiet) |
| printf("?Telnet waiting for SB %s negotiation\r\n", |
| TELOPT(TELOPT_COMPORT)); |
| debug(F111,"tn_outst","ComPort SB in progress",TELOPT_COMPORT); |
| outstanding = 1; |
| } |
| if (TELOPT_SB(TELOPT_COMPORT).comport.wait_for_ms) { |
| if (notquiet) |
| printf("?Telnet waiting for SB %s MODEM_STATUS negotiation\r\n", |
| TELOPT(TELOPT_COMPORT)); |
| debug(F111,"tn_outst","ComPort SB MS in progress",TELOPT_COMPORT); |
| outstanding = 1; |
| } |
| } |
| } |
| #endif /* TN_COMPORT */ |
| return(outstanding); |
| } |
| |
| int |
| istncomport() { |
| #ifdef TN_COMPORT |
| if (!local) return(0); |
| if (ttnet != NET_TCPB) return(0); |
| if (ttnproto != NP_TELNET) return(0); |
| if (TELOPT_ME(TELOPT_COMPORT)) |
| return(1); |
| else |
| #endif /* TN_COMPORT */ |
| return(0); |
| } |
| |
| /* tn_wait() -- Wait for response to Telnet negotiation. */ |
| /* |
| Wait for up to <timeout> seconds for the response to arrive. |
| Place all non-telnet data into Telnet Wait Buffer. |
| If response does arrive return 1, else return 0. |
| */ |
| #ifndef TN_WAIT_BUF_SZ |
| #define TN_WAIT_BUF_SZ 4096 |
| #endif /* TN_WAIT_BUF_SZ */ |
| static char tn_wait_buf[TN_WAIT_BUF_SZ]; |
| static int tn_wait_idx = 0; |
| #ifndef TN_TIMEOUT |
| #define TN_TIMEOUT 120 |
| #endif /* TN_TIMEOUT */ |
| static int tn_wait_tmo = TN_TIMEOUT; |
| |
| #ifdef CKSPINNER |
| VOID |
| prtwait(state) int state; { |
| switch (state % 4) { |
| case 0: |
| printf("/"); |
| break; |
| case 1: |
| printf("-"); |
| break; |
| case 2: |
| printf("\\"); |
| break; |
| case 3: |
| printf("|"); |
| break; |
| } |
| } |
| #endif /* CKSPINNER */ |
| |
| static int nflag = 0; |
| |
| int |
| #ifdef CK_ANSIC |
| tn_wait(char * where) |
| #else |
| tn_wait(where) char * where; |
| #endif /* CK_ANSIC */ |
| /* tn_wait */ { |
| extern int ckxech, local; |
| int ch = 0, count = 0; |
| #ifndef NOHINTS |
| int nohintgiven = 1; |
| extern int hints; |
| #endif /* NOHINTS */ |
| int outstanding; |
| #ifdef TN_COMPORT |
| int savcarr; |
| extern int ttcarr; |
| #endif /* TN_COMPORT */ |
| |
| rtimer(); |
| |
| debug(F110,"tn_wait waiting for",where,0); |
| tn_wait_tmo = TN_TIMEOUT; |
| debug(F111,"tn_wait","timeout",tn_wait_tmo); |
| outstanding = tn_outst(0); |
| debug(F111,"tn_wait","outstanding",outstanding); |
| debug(F111,"tn_wait","tn_wait_flg",tn_wait_flg); |
| |
| /* The following is meant to be !(||). We only want to return */ |
| /* immediately if both the tn_wait_flg && tn_outst() are false */ |
| if (!(outstanding || tn_wait_flg)) /* If no need to wait */ |
| return(1); /* Don't. */ |
| |
| if (tn_deb || debses) tn_debug("<wait for outstanding negotiations>"); |
| |
| #ifdef CKSPINNER |
| if (!sstelnet && !quiet) |
| prtwait(0); |
| #endif /* CKSPINNER */ |
| |
| /* Wait up to TN_TIMEOUT sec for responses to outstanding telnet negs */ |
| do { |
| #ifdef NTSIG |
| ck_ih(); |
| #endif /* NTSIG */ |
| ch = ttinc(1); |
| if (ch == -1) { /* Timed out */ |
| if (!sstelnet && !quiet) { /* Let user know... */ |
| #ifdef CKSPINNER |
| printf("\b"); |
| prtwait(gtimer()); |
| #else |
| if (nflag == 0) { |
| printf(" Negotiations."); |
| nflag++; |
| } |
| if (nflag > 0) { |
| printf("."); |
| nflag++; |
| fflush(stdout); |
| } |
| #endif /* CKSPINNER */ |
| } |
| } else if (ch < -1) { |
| printf("\r\n?Connection closed by peer.\r\n"); |
| if (tn_deb || debses) tn_debug("<connection closed by peer>"); |
| return(-1); |
| } else |
| switch (ch) { |
| case IAC: |
| #ifdef CKSPINNER |
| if (!sstelnet && !quiet) |
| printf("\b"); |
| #endif /* CKSPINNER */ |
| ch = tn_doop((CHAR)(ch & 0xff),inserver?ckxech:duplex,ttinc); |
| #ifdef CKSPINNER |
| if (!sstelnet && !quiet) { |
| prtwait(gtimer()); |
| } |
| #endif /* CKSPINNER */ |
| debug(F101,"tn_wait tn_doop","",ch); |
| switch (ch) { |
| case 1: |
| duplex = 1; /* Turn on echoing */ |
| if (inserver) |
| ckxech = 1; |
| break; |
| case 2: |
| duplex = 0; /* Turn off echoing */ |
| if (inserver) |
| ckxech = 0; |
| break; |
| case 3: |
| tn_wait_buf[tn_wait_idx++] = IAC; |
| break; |
| case 4: /* IKS event */ |
| case 6: /* Logout */ |
| break; |
| case -1: |
| if (!quiet) |
| printf("?Telnet Option negotiation error.\n"); |
| if (tn_deb || debses) |
| tn_debug("<Telnet Option negotiation error>"); |
| return(-1); |
| case -2: |
| printf("?Connection closed by peer.\n"); |
| if (tn_deb || debses) tn_debug("<Connection closed by peer>"); |
| ttclos(0); |
| return(-2); |
| default: |
| if (ch < 0) { |
| if (tn_deb || debses) tn_debug("<Unknown connection error>"); |
| return(ch); |
| } |
| } /* switch */ |
| break; |
| default: |
| #ifdef CKSPINNER |
| if (!sstelnet && !quiet) { |
| printf("\b"); |
| prtwait(gtimer()); |
| } |
| #endif /* CKSPINNER */ |
| tn_wait_buf[tn_wait_idx++] = (CHAR)(ch & 0xff); |
| } /* switch */ |
| |
| outstanding = tn_outst(0); |
| |
| if ( outstanding && ch != IAC ) { |
| int timer = gtimer(); |
| if ( timer > tn_wait_tmo ) { |
| if (!sstelnet) { |
| printf( |
| "\r\n?Telnet Protocol Timeout - connection closed\r\n"); |
| if (tn_deb || debses) |
| tn_debug( |
| "<telnet protocol timeout - connection closed>"); |
| tn_outst(1); |
| } |
| /* if we do not close the connection, then we will block */ |
| /* the next time we hit a wait. and if we don't we will */ |
| /* do the wrong thing if the host sends 0xFF and does */ |
| /* not intend it to be an IAC. */ |
| ttclos(0); |
| whyclosed = WC_TELOPT; |
| return(-1); |
| } |
| #ifndef NOHINTS |
| else if ( hints && timer > 30 && nohintgiven && !inserver ) { |
| #ifdef CKSPINNER |
| printf("\b"); |
| #else /* CKSPINNER */ |
| printf("\r\n"); |
| #endif /* CKSPINNER */ |
| printf("*************************\r\n"); |
| printf("The Telnet %s is not sending required responses.\r\n\r\n", |
| sstelnet?"client":"server"); |
| tn_outst(1); |
| printf("\nYou can continue to wait or you can cancel with Ctrl-C.\r\n"); |
| printf("In case the Telnet server never responds as required,\r\n"); |
| printf("you can try connecting to this host with TELNET /NOWAIT.\r\n"); |
| printf("Use SET HINTS OFF to suppress further hints.\r\n"); |
| printf("*************************\r\n"); |
| nohintgiven = 0; |
| } |
| #endif /* NOHINTS */ |
| } |
| |
| #ifdef TN_COMPORT |
| /* Must disable carrier detect check if we are using Telnet Comport */ |
| savcarr = ttcarr; |
| ttscarr(CAR_OFF); |
| count = ttchk(); |
| ttscarr(savcarr); |
| #else /* TN_COMPORT */ |
| count = ttchk(); |
| #endif /* TN_COMPORT */ |
| } while ((tn_wait_idx < TN_WAIT_BUF_SZ) && |
| (outstanding && count >= 0)); |
| |
| if (tn_wait_idx == TN_WAIT_BUF_SZ) { |
| if (tn_deb || debses) tn_debug("<Telnet Wait Buffer filled>"); |
| return(0); |
| } |
| |
| if (!sstelnet && !quiet) { |
| #ifdef CKSPINNER |
| printf("\b \b"); |
| #else |
| if (nflag > 0) { |
| printf(" (OK)\n"); |
| nflag = -1; |
| } |
| #endif /* CKSPINNER */ |
| } |
| if (tn_deb || debses) tn_debug("<no outstanding negotiations>"); |
| return(0); |
| } |
| |
| /* Push data from the Telnet Wait Buffer into the I/O Queue */ |
| /* Return 1 on success */ |
| |
| int |
| tn_push() { |
| #ifdef NETLEBUF |
| extern int tt_push_inited; |
| #endif /* NETLEBUF */ |
| if (tn_wait_idx) { |
| hexdump((CHAR *)"tn_push",tn_wait_buf,tn_wait_idx); |
| #ifdef NETLEBUF |
| if (!tt_push_inited) /* Local handling */ |
| le_init(); |
| le_puts((CHAR *)tn_wait_buf,tn_wait_idx); |
| #else /* External handling... */ |
| #ifdef OS2 /* K95 has its own way */ |
| le_puts((CHAR *)tn_wait_buf,tn_wait_idx); |
| #else |
| #ifdef TTLEBUF /* UNIX, etc */ |
| le_puts((CHAR *)tn_wait_buf,tn_wait_idx); |
| #else |
| /* |
| If you see this message in AOS/VS, OS-9, VOS, etc, you need to copy |
| the #ifdef TTLEBUF..#endif code from ckutio.c to the corresponding |
| places in your ck?tio.c module. |
| */ |
| printf("tn_push called but not implemented - data lost.\n"); |
| #endif /* TTLEBUF */ |
| #endif /* OS2 */ |
| #endif /* NETLEBUF */ |
| tn_wait_idx = 0; |
| } |
| tn_wait_tmo = TN_TIMEOUT; /* Reset wait timer stats */ |
| return(1); |
| } |
| |
| /* T N _ S O P T */ |
| /* |
| Sends a telnet option, avoids loops. |
| Returns 1 if command was sent, 0 if not, -1 on error. |
| */ |
| int |
| tn_sopt(cmd,opt) int cmd, opt; { /* TELNET SEND OPTION */ |
| CHAR buf[5]; |
| char msg[128]; |
| int rc; |
| |
| if (ttnet != NET_TCPB) return(-1); /* Must be TCP/IP */ |
| if (ttnproto != NP_TELNET) return(-1); /* Must be telnet protocol */ |
| if (!TELCMD_OK(cmd)) return(-1); |
| if (TELOPT_OK(opt)) { |
| if (cmd == DO && TELOPT_UNANSWERED_DO(opt)) return(0); |
| if (cmd == WILL && TELOPT_UNANSWERED_WILL(opt)) return(0); |
| if (cmd == DONT && TELOPT_UNANSWERED_DONT(opt)) return(0); |
| if (cmd == WONT && TELOPT_UNANSWERED_WONT(opt)) return(0); |
| } |
| #ifdef CK_SSL |
| if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { |
| return(0); |
| } |
| #endif /* CK_SSL */ |
| |
| if (cmd == DO && opt == TELOPT_AUTHENTICATION) |
| buf[0] = 0; |
| |
| if (tn_infinite && TELOPT_OK(opt)) { /* See comment above about */ |
| int index = TELOPT_INDEX(opt); /* preventing infinite loops */ |
| int m = cmd - WILL; |
| |
| if (tncnts[index][m] > MAXTNCNT) { |
| #ifdef DEBUG |
| if (tn_deb || debses || deblog) { |
| ckmakmsg(msg,sizeof(msg), |
| "TELNET negotiation loop ", |
| TELCMD(cmd), " ", |
| TELOPT(opt)); |
| debug(F101,msg,"",opt); |
| if (tn_deb || debses) tn_debug(msg); |
| } |
| #endif /* DEBUG */ |
| return(0); |
| } |
| tncnts[index][m]++; |
| tncnts[index][tnopps[m]] = 0; |
| } |
| buf[0] = (CHAR) IAC; |
| buf[1] = (CHAR) (cmd & 0xff); |
| buf[2] = (CHAR) (opt & 0xff); |
| buf[3] = (CHAR) 0; |
| #ifdef DEBUG |
| if ((tn_deb || debses || deblog) && cmd != SB) |
| ckmakmsg(msg,sizeof(msg),"TELNET SENT ",TELCMD(cmd)," ", |
| TELOPT(opt)); |
| #endif /* DEBUG */ |
| #ifdef OS2 |
| RequestTelnetMutex( SEM_INDEFINITE_WAIT ); |
| #endif |
| debug(F101,msg,"",opt); |
| if ((tn_deb || debses) && cmd != SB) |
| tn_debug(msg); |
| rc = (ttol(buf,3) < 3); |
| #ifdef OS2 |
| ReleaseTelnetMutex(); |
| #endif |
| if (rc) |
| return(-1); |
| |
| |
| if (TELOPT_OK(opt)) { |
| if (cmd == DONT && TELOPT_UNANSWERED_DO(opt)) |
| TELOPT_UNANSWERED_DO(opt) = 0; |
| if (cmd == WONT && TELOPT_UNANSWERED_WILL(opt)) |
| TELOPT_UNANSWERED_WILL(opt) = 0; |
| if (cmd == DO && TELOPT_UNANSWERED_DONT(opt)) |
| TELOPT_UNANSWERED_DONT(opt) = 0; |
| if (cmd == WILL && TELOPT_UNANSWERED_WONT(opt)) |
| TELOPT_UNANSWERED_WONT(opt) = 0; |
| } |
| return(1); |
| } |
| |
| /* Send a telnet sub-option */ |
| /* Returns 1 if command was sent, 0 if not, -1 on error */ |
| |
| int |
| tn_ssbopt(opt,sub,data,len) int opt, sub; CHAR * data; int len; { |
| CHAR buf[256]; |
| int n,m,rc; |
| |
| if (ttnet != NET_TCPB) return(0); /* Must be TCP/IP */ |
| if (ttnproto != NP_TELNET) return(0); /* Must be telnet protocol */ |
| if (!TELOPT_OK(opt)) return(-1); |
| if (len < 0 || len > 250) { |
| debug(F111,"Unable to Send TELNET SB - data too long","len",len); |
| return(-1); /* Data too long */ |
| } |
| #ifdef CK_SSL |
| if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { |
| if (ttchk() < 0) |
| return(-1); |
| else |
| return(1); |
| } |
| #endif /* CK_SSL */ |
| |
| if (!data) len = 0; |
| |
| buf[0] = (CHAR) IAC; |
| buf[1] = (CHAR) (SB & 0xff); |
| buf[2] = (CHAR) (opt & 0xff); |
| buf[3] = (CHAR) (sub & 0xff); |
| if (data && len > 0) { |
| memcpy(&buf[4],data,len); |
| } |
| buf[4+len] = (CHAR) IAC; |
| buf[5+len] = (CHAR) SE; |
| |
| #ifdef DEBUG |
| if (tn_deb || debses || deblog) { |
| if (opt == TELOPT_START_TLS && sub == 1) |
| ckmakmsg(tn_msg_out,TN_MSG_LEN,"TELNET SENT SB ", |
| TELOPT(opt)," FOLLOWS IAC SE",NULL); |
| else if (opt == TELOPT_TTYPE && sub == 1) |
| ckmakmsg(tn_msg_out,TN_MSG_LEN,"TELNET SENT SB ", TELOPT(opt), |
| " SEND IAC SE",NULL); |
| else if (opt == TELOPT_TTYPE && sub == 0) |
| ckmakxmsg(tn_msg_out,TN_MSG_LEN,"TELNET SENT SB ",TELOPT(opt)," IS ", |
| (char *)data," IAC SE",NULL,NULL,NULL,NULL,NULL,NULL,NULL); |
| else if (opt == TELOPT_NEWENVIRON) { |
| int i, quote; |
| ckmakmsg(tn_msg_out,TN_MSG_LEN,"TELNET SENT SB ", |
| TELOPT(TELOPT_NEWENVIRON)," ", |
| sub == TELQUAL_SEND ? "SEND" : |
| sub == TELQUAL_IS ? "IS" : |
| sub == TELQUAL_INFO ?"INFO" : "UNKNOWN" ); |
| for (i = 0, quote = 0; i < len; i++) { |
| if (quote) { |
| sprintf(hexbuf,"%02x",data[i]); /* safe but ugly */ |
| ckstrncat(tn_msg_out,hexbuf,TN_MSG_LEN); |
| quote = 0; |
| } else { |
| switch (data[i]) { |
| case TEL_ENV_USERVAR: |
| ckstrncat(tn_msg_out," USERVAR ",TN_MSG_LEN); |
| break; |
| case TEL_ENV_VAR: |
| ckstrncat(tn_msg_out," VAR ",TN_MSG_LEN); |
| break; |
| case TEL_ENV_VALUE: |
| ckstrncat(tn_msg_out," VALUE ",TN_MSG_LEN); |
| break; |
| case TEL_ENV_ESC: |
| ckstrncat(tn_msg_out," ESC ",TN_MSG_LEN); |
| quote = 1; |
| break; |
| case IAC: |
| ckstrncat(tn_msg_out," IAC ",TN_MSG_LEN); |
| break; |
| default: |
| sprintf(hexbuf,"%c",data[i]); /* safe but ugly */ |
| ckstrncat(tn_msg_out,hexbuf,TN_MSG_LEN); |
| } |
| } |
| } |
| ckstrncat(tn_msg_out," IAC SE",TN_MSG_LEN); |
| } else { |
| sprintf(hexbuf,"%02x",sub); /* safe but ugly */ |
| ckmakxmsg(tn_msg_out,TN_MSG_LEN, |
| "TELNET SENT SB ",TELOPT(opt), |
| " ", |
| hexbuf, |
| " <data> IAC SE", |
| NULL,NULL,NULL,NULL,NULL,NULL,NULL |
| ); |
| } |
| } |
| #endif /* DEBUG */ |
| #ifdef OS2 |
| RequestTelnetMutex( SEM_INDEFINITE_WAIT ); |
| #endif /* OS2 */ |
| #ifdef DEBUG |
| debug(F101,tn_msg_out,"",opt); |
| if (tn_deb || debses) |
| tn_debug(tn_msg_out); |
| #endif /* DEBUG */ |
| rc = (ttol(buf,6+len) < 6+len); |
| #ifdef OS2 |
| ReleaseTelnetMutex(); |
| #endif |
| |
| if (rc) |
| return(-1); |
| return(1); |
| } |
| |
| /* |
| tn_flui() -- Processes all waiting data for Telnet commands. |
| All non-Telnet data is to be stored into the Telnet Wait Buffer. |
| Returns 1 on success. |
| */ |
| int |
| tn_flui() { |
| extern int ckxech; |
| int x = 0; |
| |
| /* Wait up to 5 sec for responses to outstanding telnet negotiations */ |
| while (x >= 0 && ttchk() > 0 && tn_wait_idx < TN_WAIT_BUF_SZ) { |
| x = ttinc(1); |
| switch (x) { |
| case IAC: |
| x = tn_doop((CHAR)(x & 0xff),inserver?ckxech:duplex,ttinc); |
| debug(F101,"tn_flui tn_doop","",x); |
| switch (x) { |
| case 1: /* Turn on echoing */ |
| duplex = 1; |
| if (inserver) |
| ckxech = 1; |
| break; |
| case 2: /* Turn off echoing */ |
| duplex = 0; |
| if (inserver) |
| ckxech = 0; |
| break; |
| case 3: |
| tn_wait_buf[tn_wait_idx++] = IAC; |
| break; |
| case 4: /* IKS event */ |
| case 6: /* Logout */ |
| break; |
| } |
| break; |
| default: |
| if (x >= 0) |
| tn_wait_buf[tn_wait_idx++] = x; |
| } |
| } |
| return(1); |
| } |
| |
| unsigned char * |
| tn_get_display() |
| { |
| char * disp = NULL; |
| static char tmploc[256]; |
| |
| /* Must compute the DISPLAY string we are going to send to the host */ |
| /* If one is not assigned, do not send a string unless the user has */ |
| /* explicitedly requested we try to send one via X-Display Location */ |
| /* But do not send a string at all if FORWARD_X is in use. */ |
| |
| debug(F110,"tn_get_display() myipaddr",myipaddr,0); |
| #ifdef CK_ENVIRONMENT |
| debug(F110,"tn_get_display() tn_env_disp",tn_env_disp,0); |
| if (tn_env_disp[0]) { |
| int colon = ckindex(":",tn_env_disp,0,0,1); |
| if ( !colon ) { |
| ckmakmsg(tmploc,256,myipaddr,":",tn_env_disp,NULL); |
| disp = tmploc; |
| } else if ( ckindex("localhost:",tn_env_disp,0,0,0) || |
| ckindex("unix:",tn_env_disp,0,0,0) || |
| ckindex("127.0.0.1:",tn_env_disp,0,0,0) || |
| !ckstrcmp("0:",tn_env_disp,2,1) || |
| tn_env_disp[0] == ':' ) { |
| ckmakmsg(tmploc,256,myipaddr,":",&tn_env_disp[colon],NULL); |
| disp = tmploc; |
| } else |
| disp = tn_env_disp; |
| } |
| else |
| #endif /* CK_ENVIRONMENT */ |
| if (TELOPT_ME(TELOPT_XDISPLOC) || |
| TELOPT_U(TELOPT_FORWARD_X)) { |
| ckmakmsg(tmploc,256,myipaddr,":0.0",NULL,NULL); |
| disp = tmploc; |
| } |
| debug(F110,"tn_get_display() returns",disp,0); |
| return((CHAR *)disp); |
| } |
| |
| #ifdef CK_FORWARD_X |
| static Xauth fake_xauth = {0,0,NULL,0,NULL,0,NULL,0,NULL}; |
| static Xauth *real_xauth=NULL; |
| |
| /* |
| * Author: Jim Fulton, MIT X Consortium |
| * |
| * fwdx_parse_displayname - |
| * display a display string up into its component parts |
| */ |
| #ifdef UNIX |
| #define UNIX_CONNECTION "unix" |
| #define UNIX_CONNECTION_LENGTH 4 |
| #endif |
| |
| /* |
| * private utility routines |
| */ |
| |
| static int |
| #ifdef CK_ANSIC |
| XmuGetHostname (char *buf, int maxlen) |
| #else |
| XmuGetHostname (buf, maxlen) |
| char *buf; |
| int maxlen; |
| #endif /* CK_ANSIC */ |
| { |
| int len; |
| |
| #ifdef NEED_UTSNAME |
| /* |
| * same host name crock as in server and xinit. |
| */ |
| struct utsname name; |
| |
| uname (&name); |
| len = strlen (name.nodename); |
| if (len >= maxlen) len = maxlen - 1; |
| strncpy (buf, name.nodename, len); |
| buf[len] = '\0'; |
| #else |
| buf[0] = '\0'; |
| (void) gethostname (buf, maxlen); |
| buf [maxlen - 1] = '\0'; |
| len = strlen(buf); |
| #endif /* hpux */ |
| return len; |
| } |
| |
| static char * |
| #ifdef CK_ANSIC |
| copystring (char *src, int len) |
| #else |
| copystring (src, len) |
| char *src; |
| int len; |
| #endif /* CK_ANSIC */ |
| { |
| char *cp; |
| |
| if (!src && len != 0) return NULL; |
| cp = malloc (len + 1); |
| if (cp) { |
| if (src) strncpy (cp, src, len); |
| cp[len] = '\0'; |
| } |
| return cp; |
| } |
| |
| static char * |
| #ifdef CK_ANSIC |
| get_local_hostname (char *buf, int maxlen) |
| #else |
| get_local_hostname (buf, maxlen) |
| char *buf; |
| int maxlen; |
| #endif |
| { |
| buf[0] = '\0'; |
| (void) XmuGetHostname (buf, maxlen); |
| return (buf[0] ? buf : NULL); |
| } |
| |
| #ifndef UNIX |
| static char * |
| copyhostname () |
| { |
| char buf[256]; |
| |
| return (get_local_hostname (buf, sizeof buf) ? |
| copystring (buf, strlen (buf)) : NULL); |
| } |
| #endif |
| |
| |
| int |
| #ifdef CK_ANSIC |
| fwdx_parse_displayname (char *displayname, int *familyp, char **hostp, |
| int *dpynump, int *scrnump, char **restp) |
| #else |
| fwdx_parse_displayname (displayname, familyp, hostp, dpynump, scrnump, restp) |
| char *displayname; |
| int *familyp; /* return */ |
| char **hostp; /* return */ |
| int *dpynump, *scrnump; /* return */ |
| char **restp; /* return */ |
| #endif /* CK_ANSIC */ |
| { |
| char *ptr; /* work variables */ |
| int len; /* work variable */ |
| int family = -1; /* value to be returned */ |
| char *host = NULL; /* must free if set and error return */ |
| int dpynum = -1; /* value to be returned */ |
| int scrnum = 0; /* value to be returned */ |
| char *rest = NULL; /* must free if set and error return */ |
| int dnet = 0; /* if 1 then using DECnet */ |
| |
| /* check the name */ |
| if (!displayname || !displayname[0]) |
| return 0; |
| /* must have at least :number */ |
| ptr = (char *)strchr(displayname, ':'); |
| if (!ptr || !ptr[1]) return 0; |
| if (ptr[1] == ':') { |
| if (ptr[2] == '\0') return 0; |
| dnet = 1; |
| } |
| |
| /* |
| * get the host string; if none is given, use the most effiecient path |
| */ |
| |
| len = (ptr - displayname); /* length of host name */ |
| if (len == 0) { /* choose most efficient path */ |
| #ifdef UNIX |
| host = copystring (UNIX_CONNECTION, UNIX_CONNECTION_LENGTH); |
| family = FamilyLocal; |
| #else |
| if (dnet) { |
| host = copystring ("0", 1); |
| family = FamilyDECnet; |
| } else { |
| host = copyhostname (); |
| family = FamilyInternet; |
| } |
| #endif |
| } else { |
| host = copystring (displayname, len); |
| if (dnet) { |
| family = dnet; |
| } else { |
| #ifdef UNIX |
| if (host && strcmp (host, UNIX_CONNECTION) == 0) |
| family = FamilyLocal; |
| else |
| #endif |
| family = FamilyInternet; |
| } |
| } |
| |
| if (!host) return 0; |
| |
| |
| /* |
| * get the display number; we know that there is something after the |
| * colon (or colons) from above. note that host is now set and must |
| * be freed if there is an error. |
| */ |
| |
| if (dnet) ptr++; /* skip the extra DECnet colon */ |
| ptr++; /* move to start of display num */ |
| { |
| register char *cp; |
| |
| for (cp = ptr; *cp && isascii(*cp) && isdigit(*cp); cp++) ; |
| len = (cp - ptr); |
| /* check present and valid follow */ |
| if (len == 0 || (*cp && *cp != '.')) { |
| free (host); |
| return 0; |
| } |
| |
| dpynum = atoi (ptr); /* it will handle num. as well */ |
| ptr = cp; |
| } |
| |
| /* |
| * now get screen number if given; ptr may point to nul at this point |
| */ |
| if (ptr[0] == '.') { |
| register char *cp; |
| |
| ptr++; |
| for (cp = ptr; *cp && isascii(*cp) && isdigit(*cp); cp++) ; |
| len = (cp - ptr); |
| if (len == 0 || (*cp && *cp != '.')) { /* all prop name */ |
| free (host); |
| return 0; |
| } |
| |
| scrnum = atoi (ptr); /* it will handle num. as well */ |
| ptr = cp; |
| } |
| |
| /* |
| * and finally, get any additional stuff that might be following the |
| * the screen number; ptr must point to a period if there is anything |
| */ |
| |
| if (ptr[0] == '.') { |
| ptr++; |
| len = strlen (ptr); |
| if (len > 0) { |
| rest = copystring (ptr, len); |
| if (!rest) { |
| free (host); |
| return 1; |
| } |
| } |
| } |
| |
| /* |
| * and we are done! |
| */ |
| |
| if ( familyp ) |
| *familyp = family; |
| if ( hostp ) |
| *hostp = host; |
| else |
| free(host); |
| if ( dpynump ) |
| *dpynump = dpynum; |
| if ( scrnump ) |
| *scrnump = scrnum; |
| if ( restp ) |
| *restp = rest; |
| else |
| free(rest); |
| return 1; |
| } |
| |
| |
| int |
| #ifdef CK_ANSIC |
| fwdx_tn_sb( unsigned char * sb, int n ) |
| #else |
| fwdx_tn_sb( sb, n ) unsigned char * sb; int n; |
| #endif /* CK_ANSIC */ |
| { |
| unsigned short hchannel, nchannel; |
| unsigned char * p; |
| int i; |
| int rc = -1; |
| |
| /* check to ensure we have negotiated Forward X */ |
| if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) || |
| !sstelnet && !TELOPT_U(TELOPT_FORWARD_X) ) { |
| debug(F100,"fwdx_tn_sb() not negotiated","",0); |
| return(0); |
| } |
| |
| #ifdef CK_SSL |
| if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { |
| return(0); |
| } |
| #endif /* CK_SSL */ |
| |
| switch (sb[0]) { |
| case FWDX_SCREEN: |
| if (sstelnet && n == 4) |
| rc = fwdx_create_listen_socket(sb[1]); |
| break; |
| case FWDX_OPEN: |
| if ( !sstelnet && n >= 5 ) { |
| p = (unsigned char *) &nchannel; |
| i = 1; |
| /* IAC quoting has been stripped in tn_sb() */ |
| p[0] = sb[i++]; |
| p[1] = sb[i++]; |
| hchannel = ntohs(nchannel); |
| rc = fwdx_open_client_channel(hchannel); |
| if ( rc < 0 ) { |
| /* Failed; Send CLOSE channel */ |
| fwdx_send_close(hchannel); |
| rc = 0; /* Do not consider this to be a telnet error */ |
| } |
| #ifdef NT |
| if ( !TELOPT_SB(TELOPT_FORWARD_X).forward_x.thread_started ) { |
| ckThreadBegin( &fwdx_thread,32655, 0, FALSE, 0 ) ; |
| TELOPT_SB(TELOPT_FORWARD_X).forward_x.thread_started = 1; |
| } |
| #endif /* NT */ |
| } |
| break; |
| case FWDX_CLOSE: |
| p = (unsigned char *) &nchannel; |
| i = 1; |
| /* IAC quoting has been stripped in tn_sb() */ |
| p[0] = sb[i++]; |
| p[1] = sb[i++]; |
| hchannel = ntohs(nchannel); |
| fwdx_close_channel(hchannel); |
| rc = 0; /* no errors when closing */ |
| break; |
| case FWDX_DATA: |
| p = (unsigned char *) &nchannel; |
| i = 1; |
| /* IAC quoting has been stripped in tn_sb() */ |
| p[0] = sb[i++]; |
| p[1] = sb[i++]; |
| hchannel = ntohs(nchannel); |
| rc = fwdx_send_xauth_to_xserver(hchannel,(char *)&sb[3],n-5); |
| if ( rc >= 0 && n-5-rc > 0) { |
| rc = fwdx_write_data_to_channel(hchannel,(char *)&sb[3+rc],n-5-rc); |
| if ( rc < 0 ) { |
| /* Failed; Send CLOSE channel */ |
| rc = fwdx_send_close(hchannel); |
| } |
| } |
| break; |
| case FWDX_OPTIONS: |
| if ( sstelnet ) { |
| #ifndef FWDX_SERVER |
| rc = 0; |
| #else |
| rc = fwdx_server_accept_options((char*)&sb[2],n-3); |
| #endif |
| } else { |
| rc = fwdx_client_reply_options((char *)&sb[2],n-3); |
| if ( rc >= 0 ) { |
| rc = tn_sndfwdx(); |
| } |
| } |
| break; |
| case FWDX_OPT_DATA: |
| switch ( sb[1] ) { |
| default: |
| rc = 0; /* we don't recognize, not an error */ |
| } |
| break; |
| |
| case FWDX_XOFF: |
| case FWDX_XON: |
| if ( !sstelnet ) { |
| p = (unsigned char *) &nchannel; |
| i = 1; |
| /* IAC quoting has been stripped in tn_sb() */ |
| p[0] = sb[i++]; |
| p[1] = sb[i++]; |
| hchannel = ntohs(nchannel); |
| TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[hchannel].suspend = |
| (sb[0] == FWDX_XOFF); |
| rc = 0; |
| } |
| break; |
| } |
| return(rc < 0 ? -1 : 0); |
| } |
| |
| int |
| #ifdef CK_ANSIC |
| fwdx_send_xauth_to_xserver(int channel, unsigned char * data, int len) |
| #else |
| fwdx_send_xauth_to_xserver(channel, data, len) |
| int channel; unsigned char * data; int len; |
| #endif /* CK_ANSIC */ |
| { |
| int name_len, data_len, i; |
| |
| for (i = 0; i < MAXFWDX ; i++) { |
| if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel) |
| break; |
| } |
| if ( i == MAXFWDX ) |
| goto auth_err; |
| |
| if (!TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth) |
| return(0); |
| |
| if (len < 12) |
| goto auth_err; |
| |
| /* Parse the lengths of variable-length fields. */ |
| if (data[0] == 0x42) { /* byte order MSB first. */ |
| /* Xauth packets appear to always have this format */ |
| if ( data[1] != 0x00 || |
| data[2] != 0x00 || |
| data[3] != 0x0B || |
| data[4] != 0x00 || |
| data[5] != 0x00 ) |
| goto auth_err; |
| |
| name_len = (data[6] << 8) + data[7]; |
| data_len = (data[8] << 8) + data[9]; |
| } else if (data[0] == 0x6c) { /* Byte order LSB first. */ |
| /* Xauth packets appear to always have this format */ |
| if ( data[1] != 0x00 || |
| data[2] != 0x0B || |
| data[3] != 0x00 || |
| data[4] != 0x00 || |
| data[5] != 0x00 ) |
| goto auth_err; |
| |
| name_len = data[6] + (data[7] << 8); |
| data_len = data[8] + (data[9] << 8); |
| } else { |
| /* bad byte order byte */ |
| goto auth_err; |
| } |
| |
| /* Check if the whole packet is in buffer. */ |
| if (len < 12 + ((name_len + 3) & ~3) + ((data_len + 3) & ~3)) |
| goto auth_err; |
| /* If the Telnet Server allows a real Xauth message to be sent */ |
| /* Then let the message be processed by the Xserver. */ |
| if (name_len + data_len > 0) { |
| TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0; |
| return(0); |
| } |
| else |
| /* If an empty Xauth message was received. We are going to */ |
| /* send our own Xauth message using the real Xauth data. And */ |
| /* then send any other data in the buffer. */ |
| { |
| int c, err, dpynum, scrnum, family, sb_len; |
| char *display, *host = NULL, *rest = NULL; |
| unsigned char *sb, *p; |
| |
| /* parse the local DISPLAY env var */ |
| display = getenv("DISPLAY"); |
| if ( !display ) |
| display = "127.0.0.1:0.0"; |
| |
| if (fwdx_parse_displayname(display, |
| &family, &host, &dpynum, &scrnum, &rest)) { |
| char * disp_no = ckitoa(dpynum); /* should be unsigned */ |
| if (family == FamilyLocal) { |
| /* call with address = "<local host name>" */ |
| char address[300] = "localhost"; |
| gethostname(address, sizeof(address) - 1); |
| real_xauth = XauGetAuthByAddr(family, |
| strlen(address), |
| address, |
| strlen(disp_no), |
| disp_no, 0, NULL); |
| } |
| else if (family == FamilyInternet) { |
| /* call with address = 4 bytes numeric ip addr (MSB) */ |
| struct hostent *hi; |
| if (hi = gethostbyname(host)) |
| real_xauth = XauGetAuthByAddr(family, 4, |
| hi->h_addr, strlen(disp_no), |
| disp_no, 0, NULL); |
| } |
| } |
| if (host) free(host); |
| if (rest) free(rest); |
| if (!real_xauth) { |
| TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0; |
| return(0); |
| } |
| |
| if (!strncmp(real_xauth->name, |
| "MIT-MAGIC-COOKIE-1", |
| real_xauth->name_length)) { |
| char msg[64]; |
| |
| name_len = real_xauth->name_length; |
| data_len = 16; |
| |
| if ( data[0] == 0x42 ) { |
| msg[0] = 0x42; /* MSB order */ |
| msg[1] = msg[2] = 0; |
| msg[3] = 0x0B; |
| msg[4] = msg[5] = 0; |
| msg[6] = (name_len >> 8); |
| msg[7] = (name_len & 0xFF); |
| msg[8] = (data_len >> 8); |
| msg[9] = (data_len & 0xFF); |
| } else { |
| msg[0] = 0x6c; /* LSB order */ |
| msg[1] = 0; |
| msg[2] = 0x0B; |
| msg[3] = msg[4] = msg[5] = 0; |
| msg[6] = (name_len & 0xFF); |
| msg[7] = (name_len >> 8); |
| msg[8] = (data_len & 0xFF); |
| msg[9] = (data_len >> 8); |
| } |
| msg[10] = msg[11] = 0; |
| memcpy(&msg[12],real_xauth->name,18); |
| msg[30] = msg[31] = 0; |
| memcpy(&msg[32],real_xauth->data,16); |
| |
| if (fwdx_write_data_to_channel(channel,(char *)msg,48) < 0) { |
| TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0; |
| return(-1); |
| } else { |
| TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0; |
| return(12); |
| } |
| } else { |
| TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0; |
| return(0); /* we do not know how to handle this type yet */ |
| } |
| } |
| |
| auth_err: |
| debug(F100,"fwdx_send_xauth_to_xserver error","",0); |
| return(-1); |
| } |
| |
| |
| #ifdef COMMENT |
| int |
| #ifdef CK_ANSIC |
| fwdx_authorize_channel(int channel, unsigned char * data, int len) |
| #else |
| fwdx_authorize_channel(channel, data, len) |
| int channel; unsigned char * data; int len; |
| #endif /* CK_ANSIC */ |
| { |
| /* XXX maybe we should have some retry handling if not the whole first |
| * authorization packet arrives complete |
| */ |
| if ( !TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].authorized ) { |
| int name_len, data_len; |
| |
| if (len < 12) |
| goto auth_err; |
| |
| /* Parse the lengths of variable-length fields. */ |
| if (data[0] == 0x42) { /* byte order MSB first. */ |
| /* Xauth packets appear to always have this format */ |
| if ( data[1] != 0x00 || |
| data[2] != 0x00 || |
| data[3] != 0x0B || |
| data[4] != 0x00 || |
| data[5] != 0x00 ) |
| goto auth_err; |
| |
| name_len = (data[6] << 8) + data[7]; |
| data_len = (data[8] << 8) + data[9]; |
| } else if (data[0] == 0x6c) { /* Byte order LSB first. */ |
| /* Xauth packets appear to always have this format */ |
| if ( data[1] != 0x00 || |
| data[2] != 0x0B || |
| data[3] != 0x00 || |
| data[4] != 0x00 || |
| data[5] != 0x00 ) |
| goto auth_err; |
| |
| name_len = data[6] + (data[7] << 8); |
| data_len = data[8] + (data[9] << 8); |
| } else { |
| /* bad byte order byte */ |
| goto auth_err; |
| } |
| /* Check if authentication protocol matches. */ |
| if (name_len != fake_xauth.name_length || |
| memcmp(data + 12, fake_xauth.name, name_len) != 0) { |
| /* connection uses different authentication protocol */ |
| goto auth_err; |
| } |
| /* Check if authentication data matches our fake data. */ |
| if (data_len != fake_xauth.data_length || |
| memcmp(data + 12 + ((name_len + 3) & ~3), |
| fake_xauth.data, fake_xauth.data_length) != 0) { |
| /* auth data does not match fake data */ |
| goto auth_err; |
| } |
| /* substitute the fake data with real data if we have any */ |
| if (real_xauth && real_xauth->data) |
| memcpy(data + 12 + ((name_len + 3) & ~3), |
| real_xauth->data, data_len); |
| |
| TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].authorized = 1; |
| } |
| return(0); |
| auth_err: |
| return(-1); |
| } |
| #endif /* COMMENT */ |
| |
| int |
| #ifdef CK_ANSIC |
| fwdx_send_close(int channel) |
| #else |
| fwdx_send_close(channel) int channel; |
| #endif /* CK_ANSIC */ |
| { |
| unsigned short nchannel; |
| int i,rc; |
| CHAR * p; |
| |
| #ifdef CK_SSL |
| if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { |
| return(0); |
| } |
| #endif /* CK_SSL */ |
| |
| nchannel = htons(channel); |
| p = (unsigned char *) &nchannel; |
| |
| i = 0; |
| sb_out[i++] = (CHAR) IAC; /* I Am a Command */ |
| sb_out[i++] = (CHAR) SB; /* Subnegotiation */ |
| sb_out[i++] = TELOPT_FORWARD_X; /* Forward X */ |
| sb_out[i++] = FWDX_CLOSE; /* Open */ |
| sb_out[i++] = p[0]; /* First Byte of Channel */ |
| if ( p[0] == IAC ) |
| sb_out[i++] = IAC; |
| sb_out[i++] = p[1]; /* Second Byte of Channel */ |
| if ( p[1] == IAC ) |
| sb_out[i++] = IAC; |
| sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ |
| sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ |
| #ifdef DEBUG |
| if (deblog || tn_deb || debses) { |
| ckmakxmsg(fwdx_msg_out,TN_MSG_LEN,"TELNET SENT SB ", |
| TELOPT(TELOPT_FORWARD_X), |
| " CLOSE CHANNEL=",ckitoa(channel)," IAC SE", |
| NULL,NULL,NULL,NULL,NULL,NULL,NULL |
| ); |
| } |
| #endif /* DEBUG */ |
| #ifdef OS2 |
| RequestTelnetMutex( SEM_INDEFINITE_WAIT ); |
| #endif |
| #ifdef DEBUG |
| debug(F100,fwdx_msg_out,"",0); |
| if (tn_deb || debses) tn_debug(fwdx_msg_out); |
| #endif /* DEBUG */ |
| rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ |
| #ifdef OS2 |
| ReleaseTelnetMutex(); |
| #endif |
| if (rc) |
| return(-1); |
| return(0); |
| } |
| |
| int |
| #ifdef CK_ANSIC |
| fwdx_send_open(int channel) |
| #else /* CK_ANSIC */ |
| fwdx_send_open(channel) int channel; |
| #endif /* CK_ANSIC */ |
| { |
| unsigned short nchannel; |
| int i, rc; |
| CHAR * p; |
| |
| #ifdef CK_SSL |
| if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { |
| return(0); |
| } |
| #endif /* CK_SSL */ |
| |
| nchannel = htons(channel); |
| p = (unsigned char *) &nchannel; |
| |
| i = 0; |
| sb_out[i++] = (CHAR) IAC; /* I Am a Command */ |
| sb_out[i++] = (CHAR) SB; /* Subnegotiation */ |
| sb_out[i++] = TELOPT_FORWARD_X; /* Forward X */ |
| sb_out[i++] = FWDX_OPEN; /* Open */ |
| sb_out[i++] = p[0]; /* First Byte of Channel */ |
| if ( p[0] == IAC ) |
| sb_out[i++] = IAC; |
| sb_out[i++] = p[1]; /* Second Byte of Channel */ |
| if ( p[1] == IAC ) |
| sb_out[i++] = IAC; |
| sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ |
| sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ |
| #ifdef DEBUG |
| if (deblog || tn_deb || debses) { |
| ckmakxmsg(fwdx_msg_out,TN_MSG_LEN,"TELNET SENT SB ", |
| TELOPT(TELOPT_FORWARD_X), |
| " OPEN CHANNEL=",ckitoa(channel)," IAC SE", |
| NULL,NULL,NULL,NULL,NULL,NULL,NULL); |
| } |
| #endif /* DEBUG */ |
| #ifdef OS2 |
| RequestTelnetMutex( SEM_INDEFINITE_WAIT ); |
| #endif |
| #ifdef DEBUG |
| debug(F100,fwdx_msg_out,"",0); |
| if (tn_deb || debses) tn_debug(fwdx_msg_out); |
| #endif /* DEBUG */ |
| rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ |
| #ifdef OS2 |
| ReleaseTelnetMutex(); |
| #endif |
| if (rc) |
| return(-1); |
| return(0); |
| } |
| |
| int |
| #ifdef CK_ANSIC |
| fwdx_client_reply_options(char *opts, int n) |
| #else |
| fwdx_client_reply_options(opts, n) char *opts; int n; |
| #endif /* CK_ANSIC */ |
| { |
| int i,j,rc; |
| |
| #ifdef CK_SSL |
| if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { |
| return(0); |
| } |
| #endif /* CK_SSL */ |
| |
| i = 0; |
| sb_out[i++] = (CHAR) IAC; /* I Am a Command */ |
| sb_out[i++] = (CHAR) SB; /* Subnegotiation */ |
| sb_out[i++] = TELOPT_FORWARD_X; /* Forward X */ |
| sb_out[i++] = FWDX_OPTIONS; /* Options */ |
| |
| /* Look for the options we recognize and will support for this session */ |
| /* and reply with their bytes set */ |
| for (j=0; j<n; j++,i++) { |
| sb_out[i] = FWDX_OPT_NONE; /* Add zero byte - no options */ |
| #ifdef COMMENT |
| /* If we had any options to support, this is how we would do it */ |
| if ( j == 0 ) { |
| if (opts[j] & FWDX_OPT_XXXX) { |
| /* set flag to remember option is in use */ |
| flag = 1; |
| sb_out[i] |= FWDX_OPT_XXXX; |
| } |
| } |
| #endif /* COMMENT */ |
| } |
| sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ |
| sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ |
| #ifdef DEBUG |
| if (deblog || tn_deb || debses) { |
| ckmakxmsg(fwdx_msg_out,TN_MSG_LEN,"TELNET SENT SB ", |
| TELOPT(TELOPT_FORWARD_X), |
| " OPTIONS ",ckctox(sb_out[4],1)," IAC SE", |
| NULL,NULL,NULL,NULL,NULL,NULL,NULL); |
| } |
| #endif /* DEBUG */ |
| #ifdef OS2 |
| RequestTelnetMutex( SEM_INDEFINITE_WAIT ); |
| #endif |
| #ifdef DEBUG |
| debug(F100,fwdx_msg_out,"",0); |
| if (tn_deb || debses) tn_debug(fwdx_msg_out); |
| #endif /* DEBUG */ |
| rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ |
| #ifdef OS2 |
| ReleaseTelnetMutex(); |
| #endif |
| if (rc) |
| return(-1); |
| return(0); |
| } |
| |
| |
| int |
| fwdx_send_options() { |
| int i, rc; |
| |
| #ifdef CK_SSL |
| if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { |
| return(0); |
| } |
| #endif /* CK_SSL */ |
| |
| i = 0; |
| sb_out[i++] = (CHAR) IAC; /* I Am a Command */ |
| sb_out[i++] = (CHAR) SB; /* Subnegotiation */ |
| sb_out[i++] = TELOPT_FORWARD_X; /* Forward X */ |
| sb_out[i++] = FWDX_OPTIONS; /* Options */ |
| sb_out[i] = FWDX_OPT_NONE; |
| /* activate options here */ |
| i++; |
| sb_out[i++] = (CHAR) IAC; /* End of Subnegotiation */ |
| sb_out[i++] = (CHAR) SE; /* marked by IAC SE */ |
| |
| #ifdef DEBUG |
| if (deblog || tn_deb || debses) { |
| ckmakmsg(fwdx_msg_out,TN_MSG_LEN,"TELNET SENT SB ", |
| TELOPT(TELOPT_FORWARD_X), |
| " OPTIONS 00 IAC SE",NULL); |
| } |
| #endif /* DEBUG */ |
| #ifdef OS2 |
| RequestTelnetMutex( SEM_INDEFINITE_WAIT ); |
| #endif |
| #ifdef DEBUG |
| debug(F100,fwdx_msg_out,"",0); |
| if (tn_deb || debses) tn_debug(fwdx_msg_out); |
| #endif /* DEBUG */ |
| rc = (ttol((CHAR *)sb_out,i) < 0); /* Send it. */ |
| #ifdef OS2 |
| ReleaseTelnetMutex(); |
| #endif |
| if (rc) |
| return(-1); |
| return(0); |
| } |
| |
| int |
| #ifdef CK_ANSIC |
| fwdx_send_data_from_channel(int channel, char * data, int len) |
| #else |
| fwdx_send_data_from_channel(channel, data, len) |
| int channel; char * data; int len; |
| #endif |
| { |
| unsigned short nchannel; |
| /* static */ CHAR sb_priv[2048]; |
| CHAR * p; |
| int i, j, j_sav, rc; |
| unsigned int tmp; |
| |
| debug(F111,"fwdx_send_data_from_channel()","channel",channel); |
| |
| #ifdef CK_SSL |
| if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) { |
| return(0); |
| } |
| #endif /* CK_SSL */ |
| |
| nchannel = htons(channel); |
| p = (unsigned char *) &nchannel; |
| |
| j = 0; |
| sb_priv[j++] = (CHAR) IAC; /* I Am a Command */ |
| sb_priv[j++] = (CHAR) SB; /* Subnegotiation */ |
| sb_priv[j++] = TELOPT_FORWARD_X; /* Forward X */ |
| sb_priv[j++] = FWDX_DATA; /* Data */ |
| sb_priv[j++] = p[0]; /* First Byte of Channel */ |
| if ( p[0] == IAC ) |
| sb_priv[j++] = IAC; |
| sb_priv[j++] = p[1]; /* Second Byte of Channel */ |
| if ( p[1] == IAC ) |
| sb_priv[j++] = IAC; |
| j_sav = j; |
| |
| for (i = 0; i < len; i++) { |
| tmp = (unsigned int)data[i]; |
| if ( tmp == IAC ) { |
| sb_priv[j++] = IAC; |
| sb_priv[j++] = IAC; |
| } else { |
| sb_priv[j++] = tmp; |
| } |
| if ( j >= 2045 && (i < len-1) ) { |
| sb_priv[j++] = (CHAR) IAC; /* End of Subnegotiation */ |
| sb_priv[j++] = (CHAR) SE; /* marked by IAC SE */ |
| |
| #ifdef DEBUG |
| if (deblog || tn_deb || debses) { |
| ckmakxmsg( fwdx_msg_out,TN_MSG_LEN,"TELNET SENT SB ", |
| TELOPT(TELOPT_FORWARD_X), |
| " DATA CHANNEL=",ckitoa(channel)," ", |
| NULL,NULL,NULL,NULL,NULL,NULL,NULL ); |
| tn_hex(fwdx_msg_out,TN_MSG_LEN,&sb_priv[j_sav],j-(j_sav+2)); |
| ckstrncat(fwdx_msg_out," IAC SE",TN_MSG_LEN); |
| } |
| #endif /* DEBUG */ |
| #ifdef OS2 |
| RequestTelnetMutex( SEM_INDEFINITE_WAIT ); |
| #endif |
| #ifdef DEBUG |
| debug(F100,fwdx_msg_out,"",0); |
| if (tn_deb || debses) tn_debug(fwdx_msg_out); |
| #endif /* DEBUG */ |
| rc = (ttol(sb_priv,j) < 0); /* Send it. */ |
| #ifdef OS2 |
| ReleaseTelnetMutex(); |
| #endif |
| if (rc) { |
| debug(F110,"fwdx_send_data_from_channel()","ttol() failed",0); |
| return(-1); |
| } |
| |
| j = 0; |
| sb_priv[j++] = (CHAR) IAC; /* I Am a Command */ |
| sb_priv[j++] = (CHAR) SB; /* Subnegotiation */ |
| sb_priv[j++] = TELOPT_FORWARD_X; /* Forward X */ |
| sb_priv[j++] = FWDX_DATA; /* Data */ |
| sb_priv[j++] = p[0]; /* First Byte of Channel */ |
| if ( p[0] == IAC ) |
| sb_priv[j++] = IAC; |
| sb_priv[j++] = p[1]; /* Second Byte of Channel */ |
| if ( p[1] == IAC ) |
| sb_priv[j++] = IAC; |
| } |
| } |
| |
| sb_priv[j++] = (CHAR) IAC; /* End of Subnegotiation */ |
| sb_priv[j++] = (CHAR) SE; /* marked by IAC SE */ |
| |
| #ifdef DEBUG |
| if (deblog || tn_deb || debses) { |
| ckmakxmsg( fwdx_msg_out,TN_MSG_LEN, |
| "TELNET SENT SB ",TELOPT(TELOPT_FORWARD_X), |
| " DATA ",ckctox(p[0],1)," ",ckctox(p[1],1)," ", |
| NULL,NULL,NULL,NULL,NULL); |
| tn_hex(fwdx_msg_out,TN_MSG_LEN,&sb_priv[6],j-8); |
| ckstrncat(fwdx_msg_out," IAC SE",TN_MSG_LEN); |
| } |
| #endif /* DEBUG */ |
| #ifdef OS2 |
| RequestTelnetMutex( SEM_INDEFINITE_WAIT ); |
| #endif |
| #ifdef DEBUG |
| debug(F100,fwdx_msg_out,"",0); |
| if (tn_deb || debses) tn_debug(fwdx_msg_out); |
| #endif /* DEBUG */ |
| rc = (ttol(sb_priv,j) < 0); /* Send it. */ |
| #ifdef OS2 |
| ReleaseTelnetMutex(); |
| #endif |
| if ( rc ) { |
| debug(F110,"fwdx_send_data_from_channel()","ttol() failed",0); |
| return(-1); |
| } |
| |
| |
| return(0); |
| } |
| |
| static unsigned char * |
| #ifdef CK_ANSIC |
| fwdx_add_quoted_twobyte(unsigned char *p, unsigned short twobyte) |
| #else |
| fwdx_add_quoted_twobyte(p, twobyte) |
| unsigned char *p; unsigned short twobyte; |
| #endif /* CK_ANSIC */ |
| /* adds the IAC quoted (MSB) representation of 'channel' at buffer pointer 'p', |
| * returning pointer to new buffer position. NO OVERFLOW CHECK! |
| */ |
| { |
| *p++ = (unsigned char)((twobyte >> 8) & 0xFF); |
| if (*(p - 1) == 0xFF) |
| *p++ = 0xFF; |
| *p++ = (unsigned char)(twobyte & 0xFF); |
| if (*(p - 1) == 0xFF) |
| *p++ = 0xFF; |
| return p; |
| } |
| |
| int |
| #ifdef CK_ANSIC |
| fwdx_create_fake_xauth(char *name, int name_len, int data_len) |
| #else |
| fwdx_create_fake_xauth(name, name_len, data_len) |
| char *name; int name_len; int data_len; |
| #endif /* CK_ANSIC */ |
| { |
| char stackdata[256]; |
| unsigned int c, n; |
| |
| if (!name_len || !data_len) |
| return 1; |
| fake_xauth.name = malloc(name_len); |
| fake_xauth.data = malloc(data_len); |
| if (!fake_xauth.name || !fake_xauth.data) |
| return 2; |
| fake_xauth.name_length = name_len; |
| memcpy(fake_xauth.name, name, name_len); |
| fake_xauth.data_length = data_len; |
| |
| /* try to make a random unsigned int to feed srand() */ |
| c = time(NULL); |
| c *= getpid(); |
| for (n = 0; n < sizeof(stackdata); n++) |
| c += stackdata[n]; |
| srand((unsigned int)c); |
| for (c = 0; c < data_len; c++) |
| fake_xauth.data[c] = (unsigned char)rand(); |
| return 0; |
| } |
| |
| #ifdef COMMENT |
| /* No longer used */ |
| int |
| fwdx_send_xauth(void) |
| { |
| int c, err, dpynum, family, sb_len, rc; |
| char *display, *host = NULL; |
| unsigned char *sb_priv, *p; |
| |
| /* parse the local DISPLAY env var */ |
| if (!(display = tn_get_display())) |
| return (-1); |
| if (fwdx_parse_displayname(display, &family, &host, &dpynum, NULL, NULL)) { |
| char * disp_no = ckitoa(dpynum); |
| if (family == FamilyLocal) { |
| /* call with address = "<local host name>" */ |
| char address[300] = "localhost"; |
| gethostname(address, sizeof(address) - 1); |
| real_xauth = XauGetAuthByAddr(family, |
| strlen(address), |
| address, |
| strlen(disp_no), |
| disp_no, 0, NULL |
| ); |
| } |
| else if (family == FamilyInternet) { |
| /* call with address = 4 bytes numeric ip addr (MSB) */ |
| struct hostent *hi; |
| if (hi = gethostbyname(host)) |
| real_xauth = XauGetAuthByAddr(family, 4, |
| hi->h_addr, |
| strlen(disp_no), |
| disp_no, 0, NULL |
| ); |
| } |
| } |
| if (host) { |
| free(host); |
| host = NULL; |
| } |
| if (real_xauth) |
| err = fwdx_create_fake_xauth(real_xauth->name, |
| real_xauth->name_length, |
| real_xauth->data_length |
| ); |
| else |
| err = fwdx_create_fake_xauth("MIT-MAGIC-COOKIE-1", |
| strlen("MIT-MAGIC-COOKIE-1"), 16); |
| if (err) |
| return(-1); |
| |
| /* allocate memory for the SB block, alloc for worst case */ |
| /* the following sprintf() calls are safe due to length checking */ |
| /* buffer is twice as big as the input just in case every byte was IAC */ |
| sb_len = 5 + 2 + 2 + fake_xauth.name_length + fake_xauth.data_length + 2; |
| if (!(sb_priv = malloc(2 * sb_len))) |
| return(-1); |
| p = sb_priv; |
| sprintf(p, "%c%c%c%c%c", IAC, SB, TELOPT_FORWARD_X, |
| FWDX_OPT_DATA, FWDX_OPT_XAUTH); |
| p += 5; |
| p = fwdx_add_quoted_twobyte(p, fake_xauth.name_length); |
| p = fwdx_add_quoted_twobyte(p, fake_xauth.data_length); |
| for (c = 0; c < fake_xauth.name_length; c++) { |
| *p++ = fake_xauth.name[c]; |
| if ((unsigned char)fake_xauth.name[c] == 0xFF) |
| *p++ = 0xFF; |
| } |
| for (c = 0; c < fake_xauth.data_length; c++) { |
| *p++ = fake_xauth.data[c]; |
| if ((unsigned char)fake_xauth.data[c] == 0xFF) |
| *p++ = 0xFF; |
| } |
| sprintf(p, "%c%c", IAC, SE); |
| p += 2; |
| |
| #ifdef DEBUG |
| if (deblog || tn_deb || debses) { |
| sprintf(fwdx_msg_out,"TELNET SENT SB %s OPTION_DATA XAUTH ", |
| TELOPT(TELOPT_FORWARD_X)); |
| tn_hex(fwdx_msg_out,TN_MSG_LEN,&sb_priv[5],(p-sb_priv)-7); |
| ckstrncat(fwdx_msg_out," IAC SE",TN_MSG_LEN); |
| } |
| #endif /* DEBUG */ |
| |
| /* Add Telnet Debug info here */ |
| #ifdef OS2 |
| RequestTelnetMutex( SEM_INDEFINITE_WAIT ); |
| #endif |
| #ifdef DEBUG |
| debug(F100,fwdx_msg_out,"",0); |
| if (tn_deb || debses) tn_debug(fwdx_msg_out); |
| #endif /* DEBUG */ |
| rc = ( ttol(sb_priv,p-sb_priv) < 0 ); /* Send it. */ |
| #ifdef OS2 |
| ReleaseTelnetMutex(); |
| #endif |
| if (rc) { |
| debug(F110,"fwdx_send_xauth()","ttol() failed",0); |
| return(-1); |
| } |
| |
| |
| free(sb_priv); |
| return(0); |
| } |
| #endif /* COMMENT */ |
| #ifdef FWDX_SERVER |
| /* Only if we ever become a server - not yet ported to Kermit */ |
| /* And even so most of this code does not belong in this module */ |
| |
| int |
| fwdx_write_xauthfile(void) |
| { |
| int dpynum, scrnum, family; |
| char myhost[300], *host, *rest = NULL; |
| FILE *file; |
| struct sockaddr_in saddr; |
| struct hostent *hi; |
| |
| if (!fwdx_display && !fwdx_xauthfile) |
| return 1; |
| if (!parse_displayname(fwdx_display, |
| &family, &host, &dpynum, &scrnum, &rest)) |
| return 2; |
| if (rest) free(rest); |
| if (host) free(host); |
| if (family != FamilyInternet) |
| return 3; /* every thing but FamilyInternet is unexpected */ |
| |
| /* X connections to localhost:1 is actually treated as local unix sockets, |
| * see the 'xauth' man page. |
| */ |
| xauth.family = FamilyLocal; |
| if (gethostname(myhost, sizeof(myhost) - 1)) |
| return 5; |
| xauth.address_length = strlen(myhost); |
| if (!(xauth.address = malloc(xauth.address_length))) |
| return 5; |
| memcpy(xauth.address, myhost, xauth.address_length); |
| |
| /* the display number is written as a string, not numeric */ |
| if (!(xauth.number = malloc(6))) |
| return 6; |
| snprintf(xauth.number, 5, "%u", dpynum); |
| xauth.number_length = strlen(xauth.number); |
| if (!(file = fopen(fwdx_xauthfile, "wb"))) |
| return 7; |
| if (!XauWriteAuth(file, &xauth)) |
| return 8; |
| fclose(file); |
| setenv("XAUTHORITY", fwdx_xauthfile, 1); |
| return 0; |
| } |
| |
| int |
| fwdx_setup_xauth(unsigned char *sp, int len) |
| /* called with 'len' xauth bytes, starting at 'sp' |
| * the data format is: <uint16 name_length> <uint16 data_length> <name> <data> |
| */ |
| { |
| int xauthfd; |
| |
| if (!fwdx_options[FWDX_OPT_XAUTH]) |
| return 1; |
| if (len < 4) |
| return 2; |
| |
| /* setup the xauth struct */ |
| xauth.name_length = (sp[0] << 8) + sp[1]; |
| xauth.data_length = (sp[2] << 8) + sp[3]; |
| if (len != 4 + xauth.name_length + xauth.data_length) |
| return 3; |
| xauth.name = malloc(xauth.name_length); |
| xauth.data = malloc(xauth.data_length); |
| if (!xauth.name || !xauth.data) |
| return 4; |
| memcpy(xauth.name, sp + 4, xauth.name_length); |
| memcpy(xauth.data, sp + 4 + xauth.name_length, xauth.data_length); |
| |
| /* Setup to always have a local .Xauthority. */ |
| fwdx_xauthfile = malloc(MAXPATHLEN+1); |
| snprintf(fwdx_xauthfile, MAXPATHLEN, "/tmp/XauthXXXXXX"); |
| if ((xauthfd = mkstemp(fwdx_xauthfile)) != -1) |
| /* we change file ownership later, when we know who is to be owner! */ |
| close(xauthfd); |
| else { |
| free(fwdx_xauthfile); |
| fwdx_xauthfile = NULL; |
| return 5; |
| } |
| /* Must have the subshell's new DISPLAY env var to write xauth to xauthfile */ |
| if (fwdx_display) |
| if (fwdx_write_xauthfile()) |
| return 6; |
| |
| return 0; |
| } |
| |
| void fwdx_set_xauthfile_owner(int uid) |
| { |
| struct passwd *pwd; |
| |
| if (!fwdx_xauthfile || !(pwd = getpwuid(uid))) |
| return; |
| chown(fwdx_xauthfile, pwd->pw_uid, pwd->pw_gid); |
| } |
| |
| int |
| fwdx_server_accept_options(unsigned char *sp, int len) |
| /* called with 'len' option bytes, starting at 'sp' */ |
| { |
| int c; |
| |
| for (c = 0; c < len-2; c++) { |
| if (c == 0) { |
| if (sp[c] & FWDX_OPT_XAUTH) |
| flag = 1; |
| } |
| } |
| return(0); |
| } |
| #endif /* FWDX_SERVER */ |
| #endif /* CK_FORWARD_X */ |
| |
| #ifdef IKS_OPTION |
| /* |
| iks_wait() -- Wait for an IKS subnegotiation response. |
| sb - is either KERMIT_REQ_START or KERMIT_REQ_STOP depending on the desired |
| state of the peer's Kermit server. |
| flushok - specifies whether it is ok to throw away non-Telnet data |
| if so, then we call ttflui() instead of tn_flui(). |
| Returns: |
| 1 if the desired state is achieved or if it is unknown. |
| 0 if the desired state is not achieved. |
| */ |
| int |
| #ifdef CK_ANSIC |
| iks_wait(int sb, int flushok) |
| #else /* CK_ANSIC */ |
| iks_wait(sb,flushok) int sb; int flushok; |
| #endif /* CK_ANSIC */ |
| { |
| int tn_wait_save = tn_wait_flg; |
| int x; |
| |
| if (TELOPT_U(TELOPT_KERMIT)) { |
| switch (sb) { |
| case KERMIT_REQ_START: |
| debug(F111, |
| "iks_wait KERMIT_REQ_START", |
| "u_start", |
| TELOPT_SB(TELOPT_KERMIT).kermit.u_start |
| ); |
| tn_siks(KERMIT_REQ_START); |
| tn_wait_flg = 1; /* Kermit Option MUST wait */ |
| do { |
| if (flushok) |
| tn_wait_idx = 0; |
| x = tn_wait("iks_wait() me_iks_req_start"); |
| } while (x == 0 && flushok && tn_wait_idx == TN_WAIT_BUF_SZ); |
| tn_wait_flg = tn_wait_save; |
| if (flushok) |
| tn_wait_idx = 0; |
| if (tn_wait_idx == TN_WAIT_BUF_SZ) { |
| /* |
| * We are attempting to start a kermit server on the peer |
| * the most likely reason is because we want to perform a |
| * file transfer. But there is a huge amount of non telnet |
| * negotiation data coming in and so we have not been able |
| * to find the response. So we will lie and assume that |
| * response is 'yes'. The worse that will happen is that |
| * a RESP_STOP is received after we enter protocol mode. |
| * And the protocol operation will be canceled. |
| */ |
| tn_push(); |
| return(1); |
| } else { |
| tn_push(); |
| return(TELOPT_SB(TELOPT_KERMIT).kermit.u_start); |
| } |
| case KERMIT_REQ_STOP: |
| debug(F111, |
| "iks_wait KERMIT_REQ_STOP", |
| "u_start", |
| TELOPT_SB(TELOPT_KERMIT).kermit.u_start |
| ); |
| tn_siks(KERMIT_REQ_STOP); |
| tn_wait_flg = 1; /* Kermit Option MUST wait */ |
| do { |
| if (flushok) |
| tn_wait_idx = 0; |
| x = tn_wait("iks_wait() me_iks_req_stop"); |
| } while (x == 0 && flushok && tn_wait_idx == TN_WAIT_BUF_SZ); |
| tn_wait_flg = tn_wait_save; |
| if (flushok) |
| tn_wait_idx = 0; |
| |
| if (tn_wait_idx == TN_WAIT_BUF_SZ) { |
| /* |
| * We are attempting to stop a kermit server on the peer |
| * the most likely reason being that we want to enter |
| * CONNECT mode. But there is a huge amount of non telnet |
| * negotiation data coming in and so we have not been able |
| * to find the response. So we will lie and assume that |
| * the answer is 'yes' and allow the CONNECT command to |
| * succeed. The worst that happens is that CONNECT mode |
| * swallows the incoming data displaying it to the user |
| * and then it resumes Kermit client mode. |
| */ |
| tn_push(); |
| return(1); |
| } else { |
| tn_push(); |
| return(!TELOPT_SB(TELOPT_KERMIT).kermit.u_start); |
| } |
| } |
| tn_push(); |
| } |
| return(1); |
| } |
| |
| int |
| #ifdef CK_ANSIC |
| iks_tn_sb(CHAR * sb, int n) |
| #else |
| iks_tn_sb(sb, n) CHAR * sb; int n; |
| #endif /* CK_ANSIC */ |
| { |
| extern int server; |
| extern CHAR sstate; |
| #ifdef NOICP |
| extern int autodl; |
| int inautodl = 0, cmdadl = 1; |
| #else |
| #ifdef CK_AUTODL |
| extern int autodl, inautodl, cmdadl; |
| #endif /* CK_AUTODL */ |
| #endif /* NOICP */ |
| switch (sb[0]) { |
| case KERMIT_START: /* START */ |
| TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 1; |
| return(4); |
| |
| case KERMIT_STOP: /* STOP */ |
| TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 0; |
| return(4); |
| |
| case KERMIT_REQ_START: /* REQ-START */ |
| #ifndef NOXFER |
| if (inserver) { |
| #ifdef CK_AUTODL |
| cmdadl = 1; /* Turn on packet detection */ |
| #endif /* CK_AUTODL */ |
| TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 1; |
| tn_siks(KERMIT_RESP_START); |
| } else if (TELOPT_SB(TELOPT_KERMIT).kermit.me_start) { |
| tn_siks(KERMIT_RESP_START); |
| } else { |
| #ifndef IKSDONLY |
| #ifdef CK_AUTODL |
| #ifdef OS2 |
| if (local && (IsConnectMode() && autodl) || |
| (!IsConnectMode() && |
| (inautodl || sstate == 'x' || sstate == 'v')) |
| ) |
| tn_siks(KERMIT_RESP_START); /* START */ |
| else |
| |
| #else /* OS2 */ |
| if ((local && what == W_CONNECT && autodl) || |
| (local && what != W_CONNECT && |
| (inautodl || sstate == 'x' || sstate == 'v') |
| )) |
| tn_siks(KERMIT_RESP_START); /* START */ |
| else |
| #endif /* OS2 */ |
| #endif /* CK_AUTODL */ |
| #endif /* IKSDONLY */ |
| tn_siks(KERMIT_RESP_STOP); |
| } |
| #else /* NOXFER */ |
| tn_siks(KERMIT_RESP_STOP); |
| #endif /* NOXFER */ |
| return(4); |
| |
| case KERMIT_REQ_STOP: /* REQ-STOP */ |
| /* The protocol requires that the request be responded to */ |
| /* either by changing states or by reporting the current */ |
| /* state. */ |
| |
| /* We need to provide the user some way of dictating what */ |
| /* the policies should be. For instance, if we are in */ |
| /* CONNECT mode with autodownload ON and we get a REQ-STOP*/ |
| /* what should the proper response be? */ |
| #ifndef NOXFER |
| if (inserver |
| #ifdef CK_AUTODL |
| || !local && cmdadl |
| #endif /* CK_AUTODL */ |
| ) { |
| #ifdef CK_AUTODL |
| cmdadl = 0; /* Turn off packet detection */ |
| #endif /* CK_AUTODL */ |
| tn_siks(KERMIT_RESP_STOP); |
| } else if (server) { |
| extern int en_fin; |
| if (en_fin) { /* If the server is allowed to stop */ |
| tn_siks(KERMIT_RESP_STOP); |
| } else { /* We are not allowed to stop */ |
| tn_siks(KERMIT_RESP_START); |
| } |
| } |
| #ifndef IKSDONLY |
| #ifdef CK_AUTODL |
| #ifdef OS2 |
| else if (local && (IsConnectMode() && autodl) || |
| (!IsConnectMode() && inautodl) |
| ) { |
| /* If we are a pseudo-server and the other side requests */ |
| /* that we stop, tell then that we have even though we */ |
| /* have not. Otherwise, the other side might refuse to */ |
| /* enter SERVER mode. */ |
| |
| tn_siks(KERMIT_RESP_STOP); /* STOP */ |
| } |
| #else /* OS2 */ |
| else if ((local && what == W_CONNECT && autodl) || |
| (local && what != W_CONNECT && inautodl) |
| ) { |
| /* If we are a pseudo-server and the other side requests */ |
| /* that we stop, tell then that we have even though we */ |
| /* have not. Otherwise, the other side might refuse to */ |
| /* enter SERVER mode. */ |
| |
| tn_siks(KERMIT_RESP_STOP); /* STOP */ |
| } |
| #endif /* OS2 */ |
| #endif /* CK_AUTODL */ |
| #endif /* IKSDONLY */ |
| else |
| #endif /* NOXFER */ |
| { |
| /* If we are not currently in any mode that accepts */ |
| /* Kermit packets then of course report that we are */ |
| /* not being a Kermit server. */ |
| |
| tn_siks(KERMIT_RESP_STOP); /* STOP */ |
| } |
| return(4); |
| |
| case KERMIT_SOP: { /* SOP */ |
| #ifndef NOXFER |
| extern CHAR stchr; /* Incoming SOP character */ |
| stchr = sb[1]; |
| #endif /* NOXFER */ |
| TELOPT_SB(TELOPT_KERMIT).kermit.sop = 1; |
| return(4); |
| } |
| |
| case KERMIT_RESP_START: /* START */ |
| TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 1; |
| if (TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start) { |
| TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start = 0; |
| } else if (TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop) { |
| /* If we have issued a request to stop a Kermit Server */ |
| /* and the response is Start, then we must report this */ |
| /* to the caller. */ |
| TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop = 0; |
| } |
| return(4); |
| |
| case KERMIT_RESP_STOP: /* STOP */ |
| TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 0; |
| if (TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start) { |
| TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start = 0; |
| /* If we have issued a request to start a Kermit Server */ |
| /* and the response is Stop, then we must report this */ |
| /* to the caller. */ |
| } else if (TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop) { |
| TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop = 0; |
| } |
| return(4); |
| |
| default: |
| return(0); |
| |
| } /* switch (sb[0]) */ |
| } |
| #endif /* IKS_OPTION */ |
| |
| /* Initialize telnet settings - set default values for ME and U modes */ |
| int |
| tn_set_modes() { |
| int opt,cmd; |
| #ifdef CK_FORWARD_X |
| int x; |
| #endif /* CK_FORWARD_X */ |
| #ifdef CK_ENVIRONMENT |
| { |
| int i,j; |
| for (i = 0; i < 8; i++) { |
| tn_env_uservar[i][0] = NULL; |
| tn_env_uservar[i][1] = NULL; |
| } |
| } |
| #endif /* CK_ENVIRONMENT */ |
| |
| /* initialize all options to refuse in both directions */ |
| for (opt = 0; opt < NTELOPTS; opt++) { |
| TELOPT_ME(opt) = 0; |
| TELOPT_U(opt) = 0; |
| TELOPT_UNANSWERED_WILL(opt) = 0; |
| TELOPT_UNANSWERED_DO(opt) = 0; |
| TELOPT_UNANSWERED_WONT(opt) = 0; |
| TELOPT_UNANSWERED_DONT(opt) = 0; |
| TELOPT_UNANSWERED_SB(opt) = 0; |
| TELOPT_ME_MODE(opt) = TN_NG_RF; |
| TELOPT_U_MODE(opt) = TN_NG_RF; |
| TELOPT_DEF_S_ME_MODE(opt) = TN_NG_RF; |
| TELOPT_DEF_S_U_MODE(opt) = TN_NG_RF; |
| TELOPT_DEF_C_ME_MODE(opt) = TN_NG_RF; |
| TELOPT_DEF_C_U_MODE(opt) = TN_NG_RF; |
| for (cmd = 0; cmd < 4; cmd ++) |
| tncnts[TELOPT_INDEX(opt)][cmd] = 0; |
| } |
| #ifdef IKS_OPTION |
| TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0; |
| TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 0; |
| TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start = 0; |
| TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop = 0; |
| TELOPT_SB(TELOPT_KERMIT).kermit.sop = 0; |
| #endif /* IKS_OPTION */ |
| |
| #ifdef CK_ENCRYPTION |
| TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop = 0; |
| #endif /* CK_ENCRYPTION */ |
| |
| #ifdef CK_NAWS |
| TELOPT_SB(TELOPT_NAWS).naws.x = 0; |
| TELOPT_SB(TELOPT_NAWS).naws.y = 0; |
| #endif /* CK_NAWS */ |
| |
| #ifdef CK_SSL |
| TELOPT_SB(TELOPT_START_TLS).start_tls.u_follows = 0; |
| TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows = 0; |
| TELOPT_SB(TELOPT_START_TLS).start_tls.auth_request = 0; |
| #endif /* CK_SSL */ |
| |
| /* Now set the ones we want to accept to the proper values */ |
| TELOPT_DEF_S_ME_MODE(TELOPT_SGA) = TN_NG_RQ; |
| TELOPT_DEF_S_U_MODE(TELOPT_SGA) = TN_NG_RQ; |
| TELOPT_DEF_C_ME_MODE(TELOPT_SGA) = TN_NG_AC; |
| TELOPT_DEF_C_U_MODE(TELOPT_SGA) = TN_NG_AC; |
| |
| TELOPT_DEF_S_ME_MODE(TELOPT_BINARY) = TN_NG_AC; |
| TELOPT_DEF_S_U_MODE(TELOPT_BINARY) = TN_NG_AC; |
| TELOPT_DEF_C_ME_MODE(TELOPT_BINARY) = TN_NG_AC; |
| TELOPT_DEF_C_U_MODE(TELOPT_BINARY) = TN_NG_AC; |
| |
| TELOPT_DEF_S_ME_MODE(TELOPT_LOGOUT) = TN_NG_AC; |
| TELOPT_DEF_S_U_MODE(TELOPT_LOGOUT) = TN_NG_AC; |
| TELOPT_DEF_C_ME_MODE(TELOPT_LOGOUT) = TN_NG_AC; |
| TELOPT_DEF_C_U_MODE(TELOPT_LOGOUT) = TN_NG_AC; |
| |
| #ifdef IKS_OPTION |
| TELOPT_DEF_S_ME_MODE(TELOPT_KERMIT) = TN_NG_RQ; |
| TELOPT_DEF_S_U_MODE(TELOPT_KERMIT) = TN_NG_RQ; |
| TELOPT_DEF_C_ME_MODE(TELOPT_KERMIT) = TN_NG_RQ; |
| TELOPT_DEF_C_U_MODE(TELOPT_KERMIT) = TN_NG_RQ; |
| #endif /* IKS_OPTION */ |
| |
| #ifdef CK_ENCRYPTION |
| TELOPT_DEF_S_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ; |
| TELOPT_DEF_S_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ; |
| TELOPT_DEF_C_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ; |
| TELOPT_DEF_C_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RQ; |
| #endif /* CK_ENCRYPTION */ |
| |
| TELOPT_DEF_S_ME_MODE(TELOPT_ECHO) = TN_NG_RQ; |
| #ifdef IKSD |
| if ( !inserver ) |
| #endif /* IKSD */ |
| TELOPT_DEF_S_U_MODE(TELOPT_TTYPE) = TN_NG_RQ; |
| |
| #ifdef CK_ENVIRONMENT |
| TELOPT_DEF_S_U_MODE(TELOPT_NEWENVIRON) = TN_NG_RQ; |
| #endif /* CK_ENVIRONMENT */ |
| |
| #ifdef CK_AUTHENTICATION |
| TELOPT_DEF_S_U_MODE(TELOPT_AUTHENTICATION) = TN_NG_RQ; |
| #endif /* CK_AUTHENTICATION */ |
| |
| #ifdef CK_SSL |
| if (ck_ssleay_is_installed()) { |
| TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RQ; |
| TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_AC; |
| } |
| #endif /* CK_SSL */ |
| |
| #ifdef CK_NAWS |
| TELOPT_DEF_S_U_MODE(TELOPT_NAWS) = TN_NG_RQ; |
| #endif /* CK_NAWS */ |
| |
| TELOPT_DEF_C_U_MODE(TELOPT_ECHO) = TN_NG_AC; |
| TELOPT_DEF_C_ME_MODE(TELOPT_TTYPE) = TN_NG_RQ; |
| |
| #ifdef CK_ENVIRONMENT |
| TELOPT_DEF_C_ME_MODE(TELOPT_NEWENVIRON) = TN_NG_RQ; |
| #endif /* CK_ENVIRONMENT */ |
| |
| #ifdef CK_AUTHENTICATION |
| TELOPT_DEF_C_ME_MODE(TELOPT_AUTHENTICATION) = TN_NG_RQ; |
| #endif /* CK_AUTHENTICATION */ |
| |
| #ifdef CK_NAWS |
| TELOPT_DEF_C_ME_MODE(TELOPT_NAWS) = TN_NG_RQ; |
| #endif /* CK_NAWS */ |
| |
| #ifdef CK_SNDLOC |
| TELOPT_DEF_C_ME_MODE(TELOPT_SNDLOC) = TN_NG_RQ; |
| #endif /* CK_SNDLOC */ |
| |
| #ifdef CK_FORWARD_X |
| TELOPT_DEF_C_U_MODE(TELOPT_FORWARD_X) = TN_NG_AC; |
| TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = -1; |
| for (x = 0; x < MAXFWDX; x++) { |
| TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd = -1; |
| TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id = -1; |
| TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].need_to_send_xauth = 0; |
| TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend = 0; |
| } |
| #endif /* CK_FORWARD_X */ |
| |
| #ifdef TN_COMPORT |
| TELOPT_DEF_C_ME_MODE(TELOPT_COMPORT) = TN_NG_RQ; |
| #endif /* TN_COMPORT */ |
| |
| /* Set the initial values for currently known mode */ |
| for (opt = TELOPT_FIRST; opt <= TELOPT_LAST; opt++) { |
| if (TELOPT_OK(opt)) { |
| TELOPT_ME_MODE(opt) = sstelnet ? |
| TELOPT_DEF_S_ME_MODE(opt) : |
| TELOPT_DEF_C_ME_MODE(opt); |
| TELOPT_U_MODE(opt) = sstelnet ? |
| TELOPT_DEF_S_U_MODE(opt) : |
| TELOPT_DEF_C_U_MODE(opt); |
| } |
| } |
| return(1); |
| } |
| |
| |
| /* Send Delayed Subnegotiations */ |
| |
| VOID |
| tn_sdsb() { |
| if (TELOPT_SB(TELOPT_TTYPE).term.need_to_send) { |
| tn_sttyp(); |
| TELOPT_SB(TELOPT_TTYPE).term.need_to_send = 0; |
| } |
| #ifdef CK_ENVIRONMENT |
| if (TELOPT_SB(TELOPT_NEWENVIRON).env.need_to_send && |
| TELOPT_SB(TELOPT_NEWENVIRON).env.str) { |
| tn_snenv((CHAR *)TELOPT_SB(TELOPT_NEWENVIRON).env.str, |
| TELOPT_SB(TELOPT_NEWENVIRON).env.len); |
| free(TELOPT_SB(TELOPT_NEWENVIRON).env.str); |
| TELOPT_SB(TELOPT_NEWENVIRON).env.str=NULL; |
| TELOPT_SB(TELOPT_NEWENVIRON).env.len=0; |
| TELOPT_SB(TELOPT_NEWENVIRON).env.need_to_send = 0; |
| } |
| #ifdef CK_XDISPLOC |
| if (TELOPT_SB(TELOPT_XDISPLOC).xdisp.need_to_send) { |
| tn_sxdisploc(); |
| TELOPT_SB(TELOPT_XDISPLOC).xdisp.need_to_send = 0; |
| } |
| #endif /* CK_XDISPLOC */ |
| #endif /* CK_ENVIRONMENT */ |
| #ifdef CK_NAWS |
| if (TELOPT_SB(TELOPT_NAWS).naws.need_to_send) { |
| tn_snaws(); |
| TELOPT_SB(TELOPT_NAWS).naws.need_to_send = 0; |
| } |
| #endif /* CK_NAWS */ |
| #ifdef CK_SNDLOC |
| if (TELOPT_SB(TELOPT_SNDLOC).sndloc.need_to_send) { |
| tn_sndloc(); |
| TELOPT_SB(TELOPT_SNDLOC).sndloc.need_to_send = 0; |
| } |
| #endif /* CK_SNDLOC */ |
| #ifdef CK_FORWARD_X |
| if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.need_to_send) { |
| if ( sstelnet ) |
| fwdx_send_options(); |
| TELOPT_SB(TELOPT_FORWARD_X).forward_x.need_to_send = 0; |
| } |
| #endif /* CK_FORWARD_X */ |
| #ifdef TN_COMPORT |
| if (TELOPT_SB(TELOPT_COMPORT).comport.need_to_send) { |
| tn_sndcomport(); |
| TELOPT_SB(TELOPT_COMPORT).comport.need_to_send = 0; |
| } |
| #endif /* TN_COMPORT */ |
| |
| } |
| |
| int |
| tn_reset() { |
| int x,opt,cmd; |
| |
| tn_wait_idx = 0; /* Clear the tn_push() buffer */ |
| tn_wait_tmo = TN_TIMEOUT; /* Reset wait timer stats */ |
| |
| nflag = 0; |
| |
| /* Reset the TELNET OPTIONS counts */ |
| for (opt = TELOPT_FIRST; opt <= TELOPT_LAST; opt++) { |
| if (TELOPT_OK(opt)) { |
| TELOPT_ME(opt) = 0; |
| TELOPT_U(opt) = 0; |
| TELOPT_UNANSWERED_WILL(opt) = 0; |
| TELOPT_UNANSWERED_DO(opt) = 0; |
| TELOPT_UNANSWERED_WONT(opt) = 0; |
| TELOPT_UNANSWERED_DONT(opt) = 0; |
| TELOPT_UNANSWERED_SB(opt) = 0; |
| TELOPT_ME_MODE(opt) = sstelnet ? |
| TELOPT_DEF_S_ME_MODE(opt) : |
| TELOPT_DEF_C_ME_MODE(opt); |
| TELOPT_U_MODE(opt) = sstelnet ? |
| TELOPT_DEF_S_U_MODE(opt) : |
| TELOPT_DEF_C_U_MODE(opt); |
| |
| #ifdef DEBUG |
| if (deblog) { |
| switch (TELOPT_ME_MODE(opt)) { |
| case TN_NG_RF: |
| debug(F110,"tn_ini ME REFUSE ",TELOPT(opt),0); |
| break; |
| case TN_NG_AC: |
| debug(F110,"tn_ini ME ACCEPT ",TELOPT(opt),0); |
| break; |
| case TN_NG_RQ: |
| debug(F110,"tn_ini ME REQUEST",TELOPT(opt),0); |
| break; |
| case TN_NG_MU: |
| debug(F110,"tn_ini ME REQUIRE",TELOPT(opt),0); |
| break; |
| } |
| switch (TELOPT_U_MODE(opt)) { |
| case TN_NG_RF: |
| debug(F110,"tn_ini U REFUSE ",TELOPT(opt),0); |
| break; |
| case TN_NG_AC: |
| debug(F110,"tn_ini U ACCEPT ",TELOPT(opt),0); |
| break; |
| case TN_NG_RQ: |
| debug(F110,"tn_ini U REQUEST",TELOPT(opt),0); |
| break; |
| case TN_NG_MU: |
| debug(F110,"tn_ini U REQUIRE",TELOPT(opt),0); |
| break; |
| } |
| } |
| #endif /* DEBUG */ |
| for (cmd = 0; cmd < 4; cmd ++) |
| tncnts[TELOPT_INDEX(opt)][cmd] = 0; |
| } |
| } |
| #ifdef CK_ENVIRONMENT |
| if (!tn_env_flg) { |
| TELOPT_ME_MODE(TELOPT_NEWENVIRON) = TN_NG_RF; |
| TELOPT_U_MODE(TELOPT_NEWENVIRON) = TN_NG_RF; |
| } |
| #endif /* CK_ENVIRONMENT */ |
| #ifdef CK_SNDLOC |
| if (!tn_loc) |
| TELOPT_DEF_C_ME_MODE(TELOPT_SNDLOC) = TN_NG_RF; |
| #endif /* CK_SNDLOC */ |
| #ifdef IKS_OPTION |
| TELOPT_SB(TELOPT_KERMIT).kermit.me_start = 0; |
| TELOPT_SB(TELOPT_KERMIT).kermit.u_start = 0; |
| TELOPT_SB(TELOPT_KERMIT).kermit.me_req_start = 0; |
| TELOPT_SB(TELOPT_KERMIT).kermit.me_req_stop = 0; |
| TELOPT_SB(TELOPT_KERMIT).kermit.sop = 0; |
| #endif /* IKS_OPTION */ |
| #ifdef CK_ENCRYPTION |
| TELOPT_SB(TELOPT_ENCRYPTION).encrypt.stop = 0; |
| TELOPT_SB(TELOPT_ENCRYPTION).encrypt.need_to_send = 0; |
| #endif /* CK_ENCRYPTION */ |
| #ifdef CK_NAWS |
| TELOPT_SB(TELOPT_NAWS).naws.need_to_send = 0; |
| TELOPT_SB(TELOPT_NAWS).naws.x = 0; |
| TELOPT_SB(TELOPT_NAWS).naws.y = 0; |
| #endif /* CK_NAWS */ |
| TELOPT_SB(TELOPT_TTYPE).term.need_to_send = 0; |
| TELOPT_SB(TELOPT_TTYPE).term.type[0] = '\0'; |
| #ifdef CK_ENVIRONMENT |
| TELOPT_SB(TELOPT_NEWENVIRON).env.need_to_send = 0; |
| if (tn_first) |
| TELOPT_SB(TELOPT_NEWENVIRON).env.str=NULL; |
| else if (TELOPT_SB(TELOPT_NEWENVIRON).env.str) { |
| free(TELOPT_SB(TELOPT_NEWENVIRON).env.str); |
| TELOPT_SB(TELOPT_NEWENVIRON).env.str=NULL; |
| } |
| TELOPT_SB(TELOPT_NEWENVIRON).env.len=0; |
| #ifdef CK_XDISPLOC |
| TELOPT_SB(TELOPT_XDISPLOC).xdisp.need_to_send = 0; |
| #endif /* CK_XDISPLOC */ |
| #endif /* CK_ENVIRONMENT */ |
| #ifdef CK_SNDLOC |
| TELOPT_SB(TELOPT_SNDLOC).sndloc.need_to_send = 0; |
| #endif /* CK_SNDLOC */ |
| #ifdef CK_FORWARD_X |
| TELOPT_SB(TELOPT_FORWARD_X).forward_x.need_to_send = 0; |
| TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = -1; |
| for (x = 0; x < MAXFWDX; x++) { |
| TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd = -1; |
| TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id = -1; |
| TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].need_to_send_xauth = 0; |
| TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend = 0; |
| } |
| /* Reset Xauth data */ |
| if ( real_xauth ) { |
| XauDisposeAuth(real_xauth); |
| real_xauth = NULL; |
| } |
| if ( fake_xauth.name ) |
| free(fake_xauth.name); |
| if ( fake_xauth.data ) |
| free(fake_xauth.data); |
| if ( fake_xauth.address ) |
| free(fake_xauth.address); |
| if ( fake_xauth.number ) |
| free(fake_xauth.number); |
| memset(&fake_xauth,0,sizeof(fake_xauth)); |
| #ifdef NT |
| TELOPT_SB(TELOPT_FORWARD_X).forward_x.thread_started = 0; |
| #endif /* NT */ |
| #endif /* CK_FORWARD_X */ |
| #ifdef CK_SSL |
| if (tls_only_flag || ssl_only_flag) { |
| TELOPT_ME_MODE(TELOPT_START_TLS) = TN_NG_RF; |
| TELOPT_U_MODE(TELOPT_START_TLS) = TN_NG_RF; |
| } |
| TELOPT_SB(TELOPT_START_TLS).start_tls.u_follows = 0; |
| TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows = 0; |
| TELOPT_SB(TELOPT_START_TLS).start_tls.auth_request = 0; |
| #endif /* CK_SSL */ |
| |
| #ifdef CK_ENCRYPTION |
| if (!ck_crypt_is_installed() |
| #ifdef CK_SSL |
| || tls_only_flag || ssl_only_flag |
| #endif /* CK_SSL */ |
| ) { |
| TELOPT_ME_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; |
| TELOPT_U_MODE(TELOPT_ENCRYPTION) = TN_NG_RF; |
| } |
| #endif /* CK_ENCRYPTION */ |
| |
| #ifdef TN_COMPORT |
| TELOPT_SB(TELOPT_COMPORT).comport.need_to_send = 0; |
| TELOPT_SB(TELOPT_COMPORT).comport.wait_for_sb = 0; |
| TELOPT_SB(TELOPT_COMPORT).comport.wait_for_ms = 0; |
| tnc_init(); |
| #endif /* TN_COMPORT */ |
| |
| tn_first = 0; /* No longer the first time init */ |
| |
| #ifdef OS2 |
| ttnum = -1; /* Reset TermType negotiation */ |
| ttnumend = 0; |
| #endif /* OS2 */ |
| |
| return(0); |
| } |
| |
| int |
| tn_start() { |
| int wait, x, opt; |
| |
| if (tn_init && tn_begun) |
| return(0); |
| tn_begun = 1; |
| |
| debug(F111,"tn_start","sstelnet",sstelnet); |
| wait = 0; |
| if (tn_duplex) { |
| oldplex = duplex; /* save old duplex value */ |
| duplex = 1; /* and set to half duplex for telnet */ |
| } |
| #ifdef CK_SSL |
| if (!TELOPT_ME(TELOPT_START_TLS) && |
| TELOPT_ME_MODE(TELOPT_START_TLS) >= TN_NG_RQ) { |
| if (tn_sopt(WILL, TELOPT_START_TLS) < 0) |
| return(-1); |
| TELOPT_UNANSWERED_WILL(TELOPT_START_TLS) = 1; |
| wait = 1; |
| } |
| if (!TELOPT_U(TELOPT_START_TLS) && |
| TELOPT_U_MODE(TELOPT_START_TLS) >= TN_NG_RQ) { |
| if (tn_sopt(DO, TELOPT_START_TLS) < 0) |
| return(-1); |
| TELOPT_UNANSWERED_DO(TELOPT_START_TLS) = 1; |
| wait = 1; |
| } |
| #endif /* CK_SSL */ |
| |
| #ifdef CK_AUTHENTICATION |
| debug(F110,"tn_ini() CK_AUTHENTICATION","",0); |
| if (tn_init) /* tn_ini() might be called recursively */ |
| return(0); |
| if (!TELOPT_ME(TELOPT_AUTHENTICATION) && |
| TELOPT_ME_MODE |