telopt_server.c 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169
  1. /******************************************************************************
  2. * This file is part of TinTin++ *
  3. * *
  4. * Copyright 2001-2019 Igor van den Hoven *
  5. * *
  6. * TinTin++ is free software; you can redistribute it and/or modify *
  7. * it under the terms of the GNU General Public License as published by *
  8. * the Free Software Foundation; either version 3 of the License, or *
  9. * (at your option) any later version. *
  10. * *
  11. * This program is distributed in the hope that it will be useful, *
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  14. * GNU General Public License for more details. *
  15. * *
  16. * *
  17. * You should have received a copy of the GNU General Public License *
  18. * along with TinTin++. If not, see https://www.gnu.org/licenses. *
  19. ******************************************************************************/
  20. /******************************************************************************
  21. * (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t *
  22. * *
  23. * coded by Igor van den Hoven 2009 *
  24. ******************************************************************************/
  25. #include "tintin.h"
  26. #include "telnet.h"
  27. void unannounce_support(struct session *ses, struct port_data *buddy);
  28. void telopt_debug(struct session *ses, char *format, ...);
  29. void debug_telopts(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen);
  30. void send_echo_off(struct session *ses, struct port_data *buddy);
  31. void send_echo_on(struct session *ses, struct port_data *buddy);
  32. void send_eor(struct session *ses, struct port_data *buddy);
  33. int process_do_eor(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen );
  34. int process_will_ttype(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen );
  35. int process_sb_ttype_is(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen );
  36. int process_sb_naws(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen );
  37. int process_will_new_environ(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen );
  38. int process_sb_new_environ(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen );
  39. int process_do_charset(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen );
  40. int process_sb_charset(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen );
  41. int process_do_msdp(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen );
  42. int process_sb_msdp(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen );
  43. int process_do_gmcp(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen );
  44. int process_sb_gmcp(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen );
  45. int process_do_mssp(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen );
  46. int start_mccp2(struct session *ses, struct port_data *buddy);
  47. void process_mccp2(struct session *ses, struct port_data *buddy);
  48. int process_do_mccp2(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen );
  49. int process_dont_mccp2(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen );
  50. int process_do_mccp3(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen );
  51. int process_sb_mccp3(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen );
  52. int skip_sb(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen );
  53. #define TELOPT_DEBUG 1
  54. struct iac_type
  55. {
  56. int size;
  57. unsigned char * code;
  58. int (* func) (struct session *ses, struct port_data *buddy, unsigned char *src, int srclen );
  59. };
  60. struct iac_type iac_server_table [] =
  61. {
  62. { 3, (unsigned char []) { IAC, DO, TELOPT_EOR, 0 }, &process_do_eor},
  63. { 3, (unsigned char []) { IAC, WILL, TELOPT_TTYPE, 0 }, &process_will_ttype},
  64. { 4, (unsigned char []) { IAC, SB, TELOPT_TTYPE, ENV_IS, 0 }, &process_sb_ttype_is},
  65. { 3, (unsigned char []) { IAC, SB, TELOPT_NAWS, 0 }, &process_sb_naws},
  66. { 3, (unsigned char []) { IAC, WILL, TELOPT_NEW_ENVIRON, 0 }, &process_will_new_environ},
  67. { 3, (unsigned char []) { IAC, SB, TELOPT_NEW_ENVIRON, 0 }, &process_sb_new_environ},
  68. { 3, (unsigned char []) { IAC, DO, TELOPT_CHARSET, 0 }, &process_do_charset},
  69. { 3, (unsigned char []) { IAC, SB, TELOPT_CHARSET, 0 }, &process_sb_charset},
  70. { 3, (unsigned char []) { IAC, DO, TELOPT_MSSP, 0 }, &process_do_mssp},
  71. { 3, (unsigned char []) { IAC, DO, TELOPT_MSDP, 0 }, &process_do_msdp},
  72. { 3, (unsigned char []) { IAC, SB, TELOPT_MSDP, 0 }, &process_sb_msdp},
  73. { 3, (unsigned char []) { IAC, DO, TELOPT_GMCP, 0 }, &process_do_gmcp},
  74. { 3, (unsigned char []) { IAC, SB, TELOPT_GMCP, 0 }, &process_sb_gmcp},
  75. { 3, (unsigned char []) { IAC, DO, TELOPT_MCCP2, 0 }, &process_do_mccp2},
  76. { 3, (unsigned char []) { IAC, DONT, TELOPT_MCCP2, 0 }, &process_dont_mccp2},
  77. { 3, (unsigned char []) { IAC, DO, TELOPT_MCCP3, 0 }, &process_do_mccp3},
  78. { 5, (unsigned char []) { IAC, SB, TELOPT_MCCP3, IAC, SE, 0 }, &process_sb_mccp3},
  79. { 0, NULL, NULL}
  80. };
  81. /*
  82. Call this to announce support for telopts marked as such in tables.c
  83. */
  84. void announce_support(struct session *ses, struct port_data *buddy)
  85. {
  86. int i;
  87. push_call("announce_support(%p,%p)",ses,buddy);
  88. for (i = 0 ; i < 255 ; i++)
  89. {
  90. if (telopt_table[i].flags)
  91. {
  92. if (HAS_BIT(telopt_table[i].flags, ANNOUNCE_WILL))
  93. {
  94. port_telnet_printf(ses, buddy, 3, "%c%c%c", IAC, WILL, i);
  95. }
  96. if (HAS_BIT(telopt_table[i].flags, ANNOUNCE_DO))
  97. {
  98. port_telnet_printf(ses, buddy, 3, "%c%c%c", IAC, DO, i);
  99. }
  100. }
  101. }
  102. pop_call();
  103. return;
  104. }
  105. /*
  106. Call this right before a copyover to reset the telnet state
  107. */
  108. void unannounce_support(struct session *ses, struct port_data *buddy)
  109. {
  110. int i;
  111. for (i = 0 ; i < 255 ; i++)
  112. {
  113. if (telopt_table[i].flags)
  114. {
  115. if (HAS_BIT(telopt_table[i].flags, ANNOUNCE_WILL))
  116. {
  117. port_telnet_printf(ses, buddy, 3, "%c%c%c", IAC, WONT, i);
  118. }
  119. if (HAS_BIT(telopt_table[i].flags, ANNOUNCE_DO))
  120. {
  121. port_telnet_printf(ses, buddy, 3, "%c%c%c", IAC, DONT, i);
  122. }
  123. }
  124. }
  125. }
  126. /*
  127. This is the main routine that strips out and handles telopt negotiations.
  128. It also deals with \r and \0 so commands are separated by a single \n.
  129. */
  130. int server_translate_telopts(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen, unsigned char *out, int outlen)
  131. {
  132. int cnt, skip;
  133. unsigned char *pti, *pto;
  134. push_call("server_translate_telopts(%p,%p,%p,%d,%p,%d)",ses,buddy,src,srclen,out,outlen);
  135. pti = src;
  136. pto = out + outlen;
  137. if (srclen > 0 && buddy->mccp3)
  138. {
  139. buddy->mccp3->next_in = pti;
  140. buddy->mccp3->avail_in = srclen;
  141. buddy->mccp3->next_out = gtd->mccp_buf;
  142. buddy->mccp3->avail_out = gtd->mccp_len;
  143. inflate:
  144. switch (inflate(buddy->mccp3, Z_SYNC_FLUSH))
  145. {
  146. case Z_BUF_ERROR:
  147. if (buddy->mccp3->avail_out == 0)
  148. {
  149. gtd->mccp_len *= 2;
  150. gtd->mccp_buf = (unsigned char *) realloc(gtd->mccp_buf, gtd->mccp_len);
  151. buddy->mccp3->avail_out = gtd->mccp_len / 2;
  152. buddy->mccp3->next_out = gtd->mccp_buf + gtd->mccp_len / 2;
  153. goto inflate;
  154. }
  155. else
  156. {
  157. port_socket_printf(ses, buddy, "%c%c%c", IAC, DONT, TELOPT_MCCP3);
  158. inflateEnd(buddy->mccp3);
  159. free(buddy->mccp3);
  160. buddy->mccp3 = NULL;
  161. srclen = 0;
  162. }
  163. break;
  164. case Z_OK:
  165. if (buddy->mccp3->avail_out == 0)
  166. {
  167. gtd->mccp_len *= 2;
  168. gtd->mccp_buf = (unsigned char *) realloc(gtd->mccp_buf, gtd->mccp_len);
  169. buddy->mccp3->avail_out = gtd->mccp_len / 2;
  170. buddy->mccp3->next_out = gtd->mccp_buf + gtd->mccp_len / 2;
  171. goto inflate;
  172. }
  173. srclen = buddy->mccp3->next_out - gtd->mccp_buf;
  174. pti = gtd->mccp_buf;
  175. if (srclen + outlen > BUFFER_SIZE)
  176. {
  177. srclen = BUFFER_SIZE - outlen - 1;
  178. }
  179. break;
  180. case Z_STREAM_END:
  181. port_log_printf(ses, buddy, "MCCP3: Compression end, disabling MCCP3.");
  182. skip = buddy->mccp3->next_out - gtd->mccp_buf;
  183. pti += (srclen - buddy->mccp3->avail_in);
  184. srclen = buddy->mccp3->avail_in;
  185. inflateEnd(buddy->mccp3);
  186. free(buddy->mccp3);
  187. buddy->mccp3 = NULL;
  188. while (skip + srclen + 1 > gtd->mccp_len)
  189. {
  190. gtd->mccp_len *= 2;
  191. gtd->mccp_buf = (unsigned char *) realloc(gtd->mccp_buf, gtd->mccp_len);
  192. }
  193. memcpy(gtd->mccp_buf + skip, pti, srclen);
  194. pti = gtd->mccp_buf;
  195. srclen += skip;
  196. break;
  197. default:
  198. port_log_printf(ses, buddy, "MCCP3: Compression error, disabling MCCP3.");
  199. syserr_printf(ses, "server_translate_telopts: inflate:");
  200. port_socket_printf(ses, buddy, "%c%c%c", IAC, DONT, TELOPT_MCCP3);
  201. inflateEnd(buddy->mccp3);
  202. free(buddy->mccp3);
  203. buddy->mccp3 = NULL;
  204. srclen = 0;
  205. break;
  206. }
  207. }
  208. // packet patching
  209. if (buddy->teltop)
  210. {
  211. if (buddy->teltop + srclen + 1 < BUFFER_SIZE)
  212. {
  213. memcpy(buddy->telbuf + buddy->teltop, pti, srclen);
  214. srclen += buddy->teltop;
  215. pti = (unsigned char *) buddy->telbuf;
  216. }
  217. else
  218. {
  219. port_log_printf(ses, buddy, "server_translate_telopts: buffer overflow.");
  220. }
  221. buddy->teltop = 0;
  222. }
  223. while (srclen > 0)
  224. {
  225. switch (*pti)
  226. {
  227. case IAC:
  228. skip = 2;
  229. debug_telopts(ses, buddy, pti, srclen);
  230. for (cnt = 0 ; iac_server_table[cnt].code ; cnt++)
  231. {
  232. if (srclen < iac_server_table[cnt].size)
  233. {
  234. if (!memcmp(pti, iac_server_table[cnt].code, srclen))
  235. {
  236. skip = iac_server_table[cnt].size;
  237. break;
  238. }
  239. }
  240. else
  241. {
  242. if (!memcmp(pti, iac_server_table[cnt].code, iac_server_table[cnt].size))
  243. {
  244. skip = iac_server_table[cnt].func(ses, buddy, pti, srclen);
  245. if (iac_server_table[cnt].func == process_sb_mccp3)
  246. {
  247. pop_call();
  248. return server_translate_telopts(ses, buddy, pti + skip, srclen - skip, out, pto - out);
  249. }
  250. break;
  251. }
  252. }
  253. }
  254. if (iac_server_table[cnt].code == NULL && srclen > 1)
  255. {
  256. switch (pti[1])
  257. {
  258. case WILL:
  259. case DO:
  260. case WONT:
  261. case DONT:
  262. skip = 3;
  263. break;
  264. case SB:
  265. skip = skip_sb(ses, buddy, pti, srclen);
  266. break;
  267. case IAC:
  268. *pto++ = *pti++;
  269. srclen--;
  270. skip = 1;
  271. break;
  272. default:
  273. if (TELCMD_OK(pti[1]))
  274. {
  275. skip = 2;
  276. }
  277. else
  278. {
  279. skip = 1;
  280. }
  281. break;
  282. }
  283. }
  284. if (skip <= srclen)
  285. {
  286. pti += skip;
  287. srclen -= skip;
  288. }
  289. else
  290. {
  291. memcpy(buddy->telbuf, pti, srclen);
  292. buddy->teltop = srclen;
  293. *pto = 0;
  294. pop_call();
  295. return strlen((char *) out);
  296. }
  297. break;
  298. case '\r':
  299. if (srclen > 1 && pti[1] == '\0')
  300. {
  301. *pto++ = '\n';
  302. }
  303. pti++;
  304. srclen--;
  305. break;
  306. case '\0':
  307. pti++;
  308. srclen--;
  309. break;
  310. default:
  311. *pto++ = *pti++;
  312. srclen--;
  313. break;
  314. }
  315. }
  316. *pto = 0;
  317. pop_call();
  318. return strlen((char *) out);
  319. }
  320. void telopt_debug(struct session *ses, char *format, ...)
  321. {
  322. char buf[BUFFER_SIZE];
  323. va_list args;
  324. if (HAS_BIT(ses->telopts, TELOPT_FLAG_DEBUG))
  325. {
  326. va_start(args, format);
  327. vsprintf(buf, format, args);
  328. va_end(args);
  329. tintin_puts(ses, buf);
  330. }
  331. }
  332. void debug_telopts(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen)
  333. {
  334. if (srclen > 1 && TELOPT_DEBUG)
  335. {
  336. switch(src[1])
  337. {
  338. case IAC:
  339. tintin_printf2(ses, "RCVD IAC IAC");
  340. break;
  341. case DO:
  342. case DONT:
  343. case WILL:
  344. case WONT:
  345. case SB:
  346. if (srclen > 2)
  347. {
  348. if (src[1] == SB)
  349. {
  350. if (skip_sb(ses, buddy, src, srclen) == srclen + 1)
  351. {
  352. tintin_printf2(ses, "RCVD IAC SB %s ?", TELOPT(src[2]));
  353. }
  354. else
  355. {
  356. tintin_printf2(ses, "RCVD IAC SB %s IAC SE", TELOPT(src[2]));
  357. }
  358. }
  359. else
  360. {
  361. tintin_printf2(ses, "RCVD IAC %s %s", TELCMD(src[1]), TELOPT(src[2]));
  362. }
  363. }
  364. else
  365. {
  366. tintin_printf2(ses, "RCVD IAC %s ?", TELCMD(src[1]));
  367. }
  368. break;
  369. default:
  370. if (TELCMD_OK(src[1]))
  371. {
  372. tintin_printf2(ses, "RCVD IAC %s", TELCMD(src[1]));
  373. }
  374. else
  375. {
  376. tintin_printf2(ses, "RCVD IAC %d", src[1]);
  377. }
  378. break;
  379. }
  380. }
  381. else
  382. {
  383. tintin_printf2(ses, "RCVD IAC ?");
  384. }
  385. }
  386. /*
  387. Send to client to have it disable local echo
  388. */
  389. void send_echo_off(struct session *ses, struct port_data *buddy)
  390. {
  391. SET_BIT(buddy->comm_flags, COMM_FLAG_PASSWORD);
  392. port_socket_printf(ses, buddy, "%c%c%c", IAC, WILL, TELOPT_ECHO);
  393. }
  394. /*
  395. Send to client to have it enable local echo
  396. */
  397. void send_echo_on(struct session *ses, struct port_data *buddy)
  398. {
  399. DEL_BIT(buddy->comm_flags, COMM_FLAG_PASSWORD);
  400. port_socket_printf(ses, buddy, "%c%c%c", IAC, WONT, TELOPT_ECHO);
  401. }
  402. /*
  403. Send right after the prompt to mark it as such.
  404. */
  405. void send_eor(struct session *ses, struct port_data *buddy)
  406. {
  407. if (HAS_BIT(buddy->comm_flags, COMM_FLAG_EOR))
  408. {
  409. port_socket_printf(ses, buddy, "%c%c", IAC, EOR);
  410. }
  411. }
  412. /*
  413. End Of Record negotiation - not enabled by default in tables.c
  414. */
  415. int process_do_eor(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen )
  416. {
  417. SET_BIT(buddy->comm_flags, COMM_FLAG_EOR);
  418. return 3;
  419. }
  420. /*
  421. Terminal Type negotiation - make sure buddy->ttype is initialized.
  422. */
  423. int process_will_ttype(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen )
  424. {
  425. if (*buddy->ttype == 0)
  426. {
  427. // Request the first three terminal types to see if MTTS is supported, next reset to default.
  428. port_socket_printf(ses, buddy, "%c%c%c%c%c%c", IAC, SB, TELOPT_TTYPE, ENV_SEND, IAC, SE);
  429. port_socket_printf(ses, buddy, "%c%c%c%c%c%c", IAC, SB, TELOPT_TTYPE, ENV_SEND, IAC, SE);
  430. port_socket_printf(ses, buddy, "%c%c%c%c%c%c", IAC, SB, TELOPT_TTYPE, ENV_SEND, IAC, SE);
  431. port_socket_printf(ses, buddy, "%c%c%c", IAC, DONT, TELOPT_TTYPE);
  432. }
  433. return 3;
  434. }
  435. int process_sb_ttype_is(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen )
  436. {
  437. char val[BUFFER_SIZE];
  438. char *pto;
  439. int i;
  440. if (skip_sb(ses, buddy, src, srclen) > srclen)
  441. {
  442. return srclen + 1;
  443. }
  444. pto = val;
  445. for (i = 4 ; i < srclen && src[i] != SE ; i++)
  446. {
  447. switch (src[i])
  448. {
  449. default:
  450. *pto++ = src[i];
  451. break;
  452. case IAC:
  453. *pto = 0;
  454. if (TELOPT_DEBUG)
  455. {
  456. tintin_printf2(ses, "INFO IAC SB TTYPE RCVD VAL %s.", val);
  457. }
  458. if (*buddy->ttype == 0)
  459. {
  460. RESTRING(buddy->ttype, val);
  461. }
  462. else
  463. {
  464. if (sscanf(val, "MTTS %lld", &buddy->mtts_flags) == 1)
  465. {
  466. if (HAS_BIT(buddy->mtts_flags, MTTS_FLAG_256COLORS))
  467. {
  468. SET_BIT(buddy->comm_flags, COMM_FLAG_256COLORS);
  469. }
  470. if (HAS_BIT(buddy->mtts_flags, MTTS_FLAG_UTF8))
  471. {
  472. SET_BIT(buddy->comm_flags, COMM_FLAG_UTF8);
  473. }
  474. }
  475. if (strstr(val, "-256color") || strstr(val, "-256COLOR") || strcasecmp(val, "xterm"))
  476. {
  477. SET_BIT(buddy->comm_flags, COMM_FLAG_256COLORS);
  478. }
  479. }
  480. break;
  481. }
  482. }
  483. return i + 1;
  484. }
  485. /*
  486. NAWS: Negotiate About Window Size
  487. */
  488. int process_sb_naws(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen )
  489. {
  490. int i, j;
  491. buddy->cols = buddy->rows = 0;
  492. if (skip_sb(ses, buddy, src, srclen) > srclen)
  493. {
  494. return srclen + 1;
  495. }
  496. for (i = 3, j = 0 ; i < srclen && j < 4 ; i++, j++)
  497. {
  498. switch (j)
  499. {
  500. case 0:
  501. buddy->cols += (src[i] == IAC) ? src[i++] * 256 : src[i] * 256;
  502. break;
  503. case 1:
  504. buddy->cols += (src[i] == IAC) ? src[i++] : src[i];
  505. break;
  506. case 2:
  507. buddy->rows += (src[i] == IAC) ? src[i++] * 256 : src[i] * 256;
  508. break;
  509. case 3:
  510. buddy->rows += (src[i] == IAC) ? src[i++] : src[i];
  511. break;
  512. }
  513. }
  514. if (TELOPT_DEBUG)
  515. {
  516. tintin_printf2(ses, "INFO IAC SB NAWS RCVD ROWS %d COLS %d", buddy->rows, buddy->cols);
  517. }
  518. return skip_sb(ses, buddy, src, srclen);
  519. }
  520. /*
  521. NEW ENVIRON, used here to discover Windows telnet.
  522. */
  523. int process_will_new_environ(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen )
  524. {
  525. port_socket_printf(ses, buddy, "%c%c%c%c%c%s%c%c", IAC, SB, TELOPT_NEW_ENVIRON, ENV_SEND, ENV_VAR, "SYSTEMTYPE", IAC, SE);
  526. return 3;
  527. }
  528. int process_sb_new_environ(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen )
  529. {
  530. char var[BUFFER_SIZE], val[BUFFER_SIZE];
  531. char *pto;
  532. int i;
  533. if (skip_sb(ses, buddy, src, srclen) > srclen)
  534. {
  535. return srclen + 1;
  536. }
  537. var[0] = val[0] = 0;
  538. i = 4;
  539. while (i < srclen && src[i] != SE)
  540. {
  541. switch (src[i])
  542. {
  543. case ENV_VAR:
  544. case ENV_USR:
  545. i++;
  546. pto = var;
  547. while (i < srclen && src[i] >= 32 && src[i] != IAC)
  548. {
  549. *pto++ = src[i++];
  550. }
  551. *pto = 0;
  552. if (src[i] != ENV_VAL)
  553. {
  554. tintin_printf2(ses, "INFO IAC SB NEW-ENVIRON RCVD %d VAR %s", src[3], var);
  555. }
  556. break;
  557. case ENV_VAL:
  558. i++;
  559. pto = val;
  560. while (i < srclen && src[i] >= 32 && src[i] != IAC)
  561. {
  562. *pto++ = src[i++];
  563. }
  564. *pto = 0;
  565. if (TELOPT_DEBUG)
  566. {
  567. tintin_printf2(ses, "INFO IAC SB NEW-ENVIRON RCVD %d VAR %s VAL %s", src[3], var, val);
  568. }
  569. if (src[3] == ENV_IS)
  570. {
  571. // Detect Windows telnet and enable remote echo.
  572. if (!strcasecmp(var, "SYSTEMTYPE") && !strcasecmp(val, "WIN32"))
  573. {
  574. if (!strcasecmp(buddy->ttype, "ANSI"))
  575. {
  576. SET_BIT(buddy->comm_flags, COMM_FLAG_REMOTEECHO);
  577. RESTRING(buddy->ttype, "WINDOWS TELNET");
  578. }
  579. }
  580. // Get the real IP address when connecting to mudportal and other MTTS compliant proxies.
  581. if (!strcasecmp(var, "IPADDRESS"))
  582. {
  583. RESTRING(buddy->proxy, val);
  584. }
  585. }
  586. break;
  587. default:
  588. i++;
  589. break;
  590. }
  591. }
  592. return i + 1;
  593. }
  594. /*
  595. CHARSET, used to detect UTF-8 support
  596. */
  597. int process_do_charset(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen )
  598. {
  599. port_socket_printf(ses, buddy, "%c%c%c%c%c%s%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_REQUEST, ' ', "UTF-8", IAC, SE);
  600. return 3;
  601. }
  602. int process_sb_charset(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen )
  603. {
  604. char val[BUFFER_SIZE];
  605. char *pto;
  606. int i;
  607. if (skip_sb(ses, buddy, src, srclen) > srclen)
  608. {
  609. return srclen + 1;
  610. }
  611. val[0] = 0;
  612. i = 5;
  613. while (i < srclen && src[i] != SE && src[i] != src[4])
  614. {
  615. pto = val;
  616. while (i < srclen && src[i] != src[4] && src[i] != IAC)
  617. {
  618. *pto++ = src[i++];
  619. }
  620. *pto = 0;
  621. if (TELOPT_DEBUG)
  622. {
  623. tintin_printf2(ses, "INFO IAC SB CHARSET RCVD %d VAL %s", src[3], val);
  624. }
  625. if (src[3] == CHARSET_ACCEPTED)
  626. {
  627. if (!strcasecmp(val, "UTF-8"))
  628. {
  629. SET_BIT(buddy->comm_flags, COMM_FLAG_UTF8);
  630. }
  631. }
  632. else if (src[3] == CHARSET_REJECTED)
  633. {
  634. if (!strcasecmp(val, "UTF-8"))
  635. {
  636. DEL_BIT(buddy->comm_flags, COMM_FLAG_UTF8);
  637. }
  638. }
  639. i++;
  640. }
  641. return i + 1;
  642. }
  643. /*
  644. MSDP: Mud Server Data Protocol
  645. http://tintin.sourceforge.net/msdp
  646. */
  647. int process_do_msdp(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen )
  648. {
  649. int index;
  650. if (buddy->msdp_data)
  651. {
  652. return 3;
  653. }
  654. buddy->msdp_data = (struct msdp_data **) calloc(gtd->msdp_table_size, sizeof(struct msdp_data *));
  655. for (index = 0 ; index < gtd->msdp_table_size ; index++)
  656. {
  657. buddy->msdp_data[index] = (struct msdp_data *) calloc(1, sizeof(struct msdp_data *));
  658. buddy->msdp_data[index]->flags = msdp_table[index].flags;
  659. buddy->msdp_data[index]->value = strdup("");
  660. }
  661. tintin_printf2(ses, "INFO MSDP INITIALIZED");
  662. // Easiest to handle variable initialization here.
  663. msdp_update_var(ses, buddy, "SPECIFICATION", "http://tintin.sourceforge.net/msdp");
  664. msdp_update_varf(ses, buddy, "SCREEN_ROWS", "%d", gtd->screen->rows);
  665. msdp_update_varf(ses, buddy, "SCREEN_COLS", "%d", gtd->screen->cols);
  666. msdp_update_varf(ses, buddy, "SCREEN_HEIGHT", "%d", gtd->screen->height);
  667. msdp_update_varf(ses, buddy, "SCREEN_WIDTH", "%d", gtd->screen->width);
  668. msdp_update_varf(ses, buddy, "SCREEN_POSITION_HEIGHT", "%d", gtd->screen->pos_height);
  669. msdp_update_varf(ses, buddy, "SCREEN_POSITION_WIDTH", "%d", gtd->screen->pos_width);
  670. msdp_update_varf(ses, buddy, "SCREEN_FOCUS", "%d", gtd->screen->focus);
  671. msdp_update_varf(ses, buddy, "SCREEN_MINIMIZED", "%d", gtd->screen->minimized);
  672. return 3;
  673. }
  674. int process_sb_msdp(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen )
  675. {
  676. char var[BUFFER_SIZE], val[BUFFER_SIZE];
  677. char *pto;
  678. int i, nest;
  679. if (skip_sb(ses, buddy, src, srclen) > srclen)
  680. {
  681. return srclen + 1;
  682. }
  683. var[0] = val[0] = 0;
  684. i = 3;
  685. nest = 0;
  686. while (i < srclen && src[i] != SE)
  687. {
  688. switch (src[i])
  689. {
  690. case MSDP_VAR:
  691. i++;
  692. pto = var;
  693. while (i < srclen && src[i] != MSDP_VAL && src[i] != IAC)
  694. {
  695. *pto++ = src[i++];
  696. }
  697. *pto = 0;
  698. break;
  699. case MSDP_VAL:
  700. i++;
  701. pto = val;
  702. while (i < srclen && src[i] != IAC)
  703. {
  704. if (src[i] == MSDP_TABLE_OPEN || src[i] == MSDP_ARRAY_OPEN)
  705. {
  706. nest++;
  707. }
  708. else if (src[i] == MSDP_TABLE_CLOSE || src[i] == MSDP_ARRAY_CLOSE)
  709. {
  710. nest--;
  711. }
  712. else if (nest == 0 && (src[i] == MSDP_VAR || src[i] == MSDP_VAL))
  713. {
  714. break;
  715. }
  716. *pto++ = src[i++];
  717. }
  718. *pto = 0;
  719. if (nest == 0)
  720. {
  721. if (buddy->msdp_data)
  722. {
  723. process_msdp_varval(ses, buddy, var, val);
  724. }
  725. }
  726. break;
  727. default:
  728. i++;
  729. break;
  730. }
  731. }
  732. return i + 1;
  733. }
  734. // MSDP over GMCP
  735. int process_do_gmcp(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen )
  736. {
  737. if (buddy->msdp_data)
  738. {
  739. return 3;
  740. }
  741. tintin_printf2(ses, "INFO MSDP OVER GMCP INITIALIZED");
  742. SET_BIT(buddy->comm_flags, COMM_FLAG_GMCP);
  743. return process_do_msdp(ses, buddy, src, srclen);
  744. }
  745. int process_sb_gmcp(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen )
  746. {
  747. char out[BUFFER_SIZE];
  748. int outlen, skiplen;
  749. skiplen = skip_sb(ses, buddy, src, srclen);
  750. if (skiplen > srclen)
  751. {
  752. return srclen + 1;
  753. }
  754. outlen = json2msdp(src, srclen, out);
  755. process_sb_msdp(ses, buddy, (unsigned char *) out, outlen);
  756. return skiplen;
  757. }
  758. /*
  759. MSSP: Mud Server Status Protocol
  760. http://tintin.sourceforge.net/mssp
  761. Uncomment and update as needed
  762. */
  763. int process_do_mssp(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen )
  764. {
  765. char buffer[BUFFER_SIZE] = { 0 };
  766. cat_sprintf(buffer, "%c%s%c%s", MSSP_VAR, "NAME", MSSP_VAL, "TINTIN COMMANDER");
  767. cat_sprintf(buffer, "%c%s%c%d", MSSP_VAR, "PLAYERS", MSSP_VAL, ses->port->total);
  768. cat_sprintf(buffer, "%c%s%c%d", MSSP_VAR, "UPTIME", MSSP_VAL, ses->created);
  769. // cat_sprintf(buffer, "%c%s%c%s", MSSP_VAR, "HOSTNAME", MSSP_VAL, "example.com");
  770. cat_sprintf(buffer, "%c%s%c%d", MSSP_VAR, "PORT", MSSP_VAL, ses->port->port);
  771. cat_sprintf(buffer, "%c%s%c%s", MSSP_VAR, "CODEBASE", MSSP_VAL, CLIENT_NAME);
  772. // cat_sprintf(buffer, "%c%s%c%s", MSSP_VAR, "CONTACT", MSSP_VAL, "mud@example.com");
  773. // cat_sprintf(buffer, "%c%s%c%s", MSSP_VAR, "LANGUAGE", MSSP_VAL, "English");
  774. // cat_sprintf(buffer, "%c%s%c%s", MSSP_VAR, "MINIMUM AGE", MSSP_VAL, "13");
  775. cat_sprintf(buffer, "%c%s%c%s", MSSP_VAR, "WEBSITE", MSSP_VAL, "https://tintin.sourceforge.io");
  776. cat_sprintf(buffer, "%c%s%c%s", MSSP_VAR, "FAMILY", MSSP_VAL, "TINTIN");
  777. cat_sprintf(buffer, "%c%s%c%s", MSSP_VAR, "INTERMUD", MSSP_VAL, "Arachnos");
  778. cat_sprintf(buffer, "%c%s%c%d", MSSP_VAR, "ANSI", MSSP_VAL, 1);
  779. cat_sprintf(buffer, "%c%s%c%d", MSSP_VAR, "MCCP", MSSP_VAL, 1);
  780. cat_sprintf(buffer, "%c%s%c%d", MSSP_VAR, "MSDP", MSSP_VAL, 1);
  781. // cat_sprintf(buffer, "%c%s%c%d", MSSP_VAR, "MSP", MSSP_VAL, 0);
  782. cat_sprintf(buffer, "%c%s%c%d", MSSP_VAR, "UTF-8", MSSP_VAL, 1);
  783. cat_sprintf(buffer, "%c%s%c%d", MSSP_VAR, "VT100", MSSP_VAL, 1);
  784. cat_sprintf(buffer, "%c%s%c%d", MSSP_VAR, "XTERM 256 COLORS", MSSP_VAL, 1);
  785. port_socket_printf(ses, buddy, "%c%c%c%s%c%c", IAC, SB, TELOPT_MSSP, buffer, IAC, SE);
  786. return 3;
  787. }
  788. /*
  789. MCCP: Mud Client Compression Protocol
  790. */
  791. int start_mccp2(struct session *ses, struct port_data *buddy)
  792. {
  793. z_stream *stream;
  794. if (buddy->mccp2)
  795. {
  796. return TRUE;
  797. }
  798. stream = calloc(1, sizeof(z_stream));
  799. stream->next_in = NULL;
  800. stream->avail_in = 0;
  801. stream->next_out = gtd->mccp_buf;
  802. stream->avail_out = gtd->mccp_len;
  803. stream->data_type = Z_ASCII;
  804. stream->zalloc = zlib_alloc;
  805. stream->zfree = zlib_free;
  806. stream->opaque = Z_NULL;
  807. /*
  808. 12, 5 = 32K of memory, more than enough
  809. */
  810. if (deflateInit2(stream, Z_BEST_COMPRESSION, Z_DEFLATED, 12, 5, Z_DEFAULT_STRATEGY) != Z_OK)
  811. {
  812. tintin_printf2(ses, "start_mccp2: failed deflateInit2");
  813. free(stream);
  814. return FALSE;
  815. }
  816. port_socket_printf(ses, buddy, "%c%c%c%c%c", IAC, SB, TELOPT_MCCP2, IAC, SE);
  817. /*
  818. The above call must send all pending output to the descriptor, since from now on we'll be compressing.
  819. */
  820. buddy->mccp2 = stream;
  821. return TRUE;
  822. }
  823. void end_mccp2(struct session *ses, struct port_data *buddy)
  824. {
  825. if (buddy->mccp2 == NULL)
  826. {
  827. return;
  828. }
  829. buddy->mccp2->next_in = NULL;
  830. buddy->mccp2->avail_in = 0;
  831. buddy->mccp2->next_out = gtd->mccp_buf;
  832. buddy->mccp2->avail_out = gtd->mccp_len;
  833. if (deflate(buddy->mccp2, Z_FINISH) != Z_STREAM_END)
  834. {
  835. tintin_printf2(ses, "end_mccp2: failed to deflate");
  836. }
  837. if (!HAS_BIT(buddy->comm_flags, COMM_FLAG_DISCONNECT))
  838. {
  839. process_mccp2(ses, buddy);
  840. }
  841. if (deflateEnd(buddy->mccp2) != Z_OK)
  842. {
  843. tintin_printf2(ses, "end_mccp2: failed to deflateEnd");
  844. }
  845. free(buddy->mccp2);
  846. buddy->mccp2 = NULL;
  847. tintin_printf2(ses, "MCCP2: COMPRESSION END");
  848. return;
  849. }
  850. void write_mccp2(struct session *ses, struct port_data *buddy, char *txt, int length)
  851. {
  852. buddy->mccp2->next_in = (unsigned char *) txt;
  853. buddy->mccp2->avail_in = length;
  854. buddy->mccp2->next_out = (unsigned char *) gtd->mccp_buf;
  855. buddy->mccp2->avail_out = gtd->mccp_len;
  856. if (deflate(buddy->mccp2, Z_SYNC_FLUSH) != Z_OK)
  857. {
  858. return;
  859. }
  860. process_mccp2(ses, buddy);
  861. return;
  862. }
  863. void process_mccp2(struct session *ses, struct port_data *buddy)
  864. {
  865. if (HAS_BIT(buddy->flags, PORT_FLAG_LINKLOST))
  866. {
  867. return;
  868. }
  869. if (write(buddy->fd, gtd->mccp_buf, gtd->mccp_len - buddy->mccp2->avail_out) < 1)
  870. {
  871. syserr_printf(ses, "process_mccp2: write");
  872. SET_BIT(buddy->comm_flags, COMM_FLAG_DISCONNECT);
  873. }
  874. }
  875. int process_do_mccp2(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen )
  876. {
  877. start_mccp2(ses, buddy);
  878. return 3;
  879. }
  880. int process_dont_mccp2(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen )
  881. {
  882. end_mccp2(ses, buddy);
  883. return 3;
  884. }
  885. // MCCP3
  886. int process_do_mccp3(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen )
  887. {
  888. return 3;
  889. }
  890. int process_sb_mccp3(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen )
  891. {
  892. if (buddy->mccp3)
  893. {
  894. tintin_printf2(ses, "\e[1;31mERROR: MCCP3 ALREADY INITIALIZED");
  895. return 5;
  896. }
  897. buddy->mccp3 = (z_stream *) calloc(1, sizeof(z_stream));
  898. buddy->mccp3->data_type = Z_ASCII;
  899. buddy->mccp3->zalloc = zlib_alloc;
  900. buddy->mccp3->zfree = zlib_free;
  901. buddy->mccp3->opaque = NULL;
  902. if (inflateInit(buddy->mccp3) != Z_OK)
  903. {
  904. tintin_printf2(ses, "INFO IAC SB MCCP3 FAILED TO INITIALIZE");
  905. port_socket_printf(ses, buddy, "%c%c%c", IAC, WONT, TELOPT_MCCP3);
  906. free(buddy->mccp3);
  907. buddy->mccp3 = NULL;
  908. }
  909. else
  910. {
  911. tintin_printf2(ses, "INFO IAC SB MCCP3 INITIALIZED");
  912. }
  913. return 5;
  914. }
  915. void end_mccp3(struct session *ses, struct port_data *buddy)
  916. {
  917. if (buddy->mccp3)
  918. {
  919. tintin_printf2(ses, "MCCP3: COMPRESSION END");
  920. inflateEnd(buddy->mccp3);
  921. free(buddy->mccp3);
  922. buddy->mccp3 = NULL;
  923. }
  924. }
  925. int skip_sb(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen )
  926. {
  927. int i;
  928. for (i = 1 ; i < srclen ; i++)
  929. {
  930. if (src[i] == SE && src[i-1] == IAC)
  931. {
  932. return i + 1;
  933. }
  934. }
  935. return srclen + 1;
  936. }