telnetd.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <bio.h>
  12. #include <auth.h>
  13. #include <mp.h>
  14. #include <libsec.h>
  15. #include "../ip/telnet.h"
  16. /* console state (for consctl) */
  17. typedef struct Consstate Consstate;
  18. struct Consstate{
  19. int raw;
  20. int hold;
  21. };
  22. Consstate *cons;
  23. int notefd; /* for sending notes to the child */
  24. int noproto; /* true if we shouldn't be using the telnet protocol */
  25. int trusted; /* true if we need not authenticate - current user
  26. is ok */
  27. int nonone = 1; /* don't allow none logins */
  28. int noworldonly; /* only noworld accounts */
  29. enum
  30. {
  31. Maxpath= 256,
  32. Maxuser= 64,
  33. Maxvar= 32,
  34. };
  35. /* input and output buffers for network connection */
  36. Biobuf netib;
  37. Biobuf childib;
  38. char remotesys[Maxpath]; /* name of remote system */
  39. int alnum(int);
  40. int conssim(void);
  41. int fromchild(char*, int);
  42. int fromnet(char*, int);
  43. int termchange(Biobuf*, int);
  44. int termsub(Biobuf*, uint8_t*, int);
  45. int xlocchange(Biobuf*, int);
  46. int xlocsub(Biobuf*, uint8_t*, int);
  47. int challuser(char*);
  48. int noworldlogin(char*);
  49. void* share(uint32_t);
  50. int doauth(char*);
  51. #define TELNETLOG "telnet"
  52. void
  53. logit(char *fmt, ...)
  54. {
  55. va_list arg;
  56. char buf[8192];
  57. va_start(arg, fmt);
  58. vseprint(buf, buf + sizeof(buf) / sizeof(*buf), fmt, arg);
  59. va_end(arg);
  60. syslog(0, TELNETLOG, "(%s) %s", remotesys, buf);
  61. }
  62. void
  63. getremote(char *dir)
  64. {
  65. int fd, n;
  66. char remfile[Maxpath];
  67. sprint(remfile, "%s/remote", dir);
  68. fd = open(remfile, OREAD);
  69. if(fd < 0)
  70. strcpy(remotesys, "unknown2");
  71. n = read(fd, remotesys, sizeof(remotesys)-1);
  72. if(n>0)
  73. remotesys[n-1] = 0;
  74. else
  75. strcpy(remotesys, remfile);
  76. close(fd);
  77. }
  78. void
  79. main(int argc, char *argv[])
  80. {
  81. char buf[1024];
  82. int fd;
  83. char user[Maxuser];
  84. int tries = 0;
  85. int childpid;
  86. int n, eofs;
  87. memset(user, 0, sizeof(user));
  88. ARGBEGIN {
  89. case 'n':
  90. opt[Echo].local = 1;
  91. noproto = 1;
  92. break;
  93. case 'p':
  94. noproto = 1;
  95. break;
  96. case 'a':
  97. nonone = 0;
  98. break;
  99. case 't':
  100. trusted = 1;
  101. strncpy(user, getuser(), sizeof(user)-1);
  102. break;
  103. case 'u':
  104. strncpy(user, ARGF(), sizeof(user)-1);
  105. break;
  106. case 'd':
  107. debug = 1;
  108. break;
  109. case 'N':
  110. noworldonly = 1;
  111. break;
  112. } ARGEND
  113. if(argc)
  114. getremote(argv[argc-1]);
  115. else
  116. strcpy(remotesys, "unknown");
  117. /* options we need routines for */
  118. opt[Term].change = termchange;
  119. opt[Term].sub = termsub;
  120. opt[Xloc].sub = xlocsub;
  121. /* setup default telnet options */
  122. if(!noproto){
  123. send3(1, Iac, Will, opt[Echo].code);
  124. send3(1, Iac, Do, opt[Term].code);
  125. send3(1, Iac, Do, opt[Xloc].code);
  126. }
  127. /* shared data for console state */
  128. cons = share(sizeof(Consstate));
  129. if(cons == 0)
  130. fatal("shared memory", 0, 0);
  131. /* authenticate and create new name space */
  132. Binit(&netib, 0, OREAD);
  133. if (!trusted){
  134. while(doauth(user) < 0)
  135. if(++tries == 5){
  136. logit("failed as %s: %r", user);
  137. print("authentication failure:%r\r\n");
  138. exits("authentication");
  139. }
  140. }
  141. logit("logged in as %s", user);
  142. putenv("service", "con");
  143. /* simulate /dev/consctl and /dev/cons using pipes */
  144. fd = conssim();
  145. if(fd < 0)
  146. fatal("simulating", 0, 0);
  147. Binit(&childib, fd, OREAD);
  148. /* start a shell in a different process group */
  149. switch(childpid = rfork(RFPROC|RFNAMEG|RFFDG|RFNOTEG)){
  150. case -1:
  151. fatal("fork", 0, 0);
  152. case 0:
  153. close(fd);
  154. fd = open("/dev/cons", OREAD);
  155. dup(fd, 0);
  156. close(fd);
  157. fd = open("/dev/cons", OWRITE);
  158. dup(fd, 1);
  159. dup(fd, 2);
  160. close(fd);
  161. segdetach(cons);
  162. execl("/bin/rc", "rc", "-il", nil);
  163. fatal("/bin/rc", 0, 0);
  164. default:
  165. sprint(buf, "/proc/%d/notepg", childpid);
  166. notefd = open(buf, OWRITE);
  167. break;
  168. }
  169. /* two processes to shuttle bytes twixt children and network */
  170. switch(fork()){
  171. case -1:
  172. fatal("fork", 0, 0);
  173. case 0:
  174. eofs = 0;
  175. for(;;){
  176. n = fromchild(buf, sizeof(buf));
  177. if(n <= 0){
  178. if(eofs++ > 2)
  179. break;
  180. continue;
  181. }
  182. eofs = 0;
  183. if(write(1, buf, n) != n)
  184. break;
  185. }
  186. break;
  187. default:
  188. while((n = fromnet(buf, sizeof(buf))) >= 0)
  189. if(write(fd, buf, n) != n)
  190. break;
  191. break;
  192. }
  193. /* kill off all server processes */
  194. sprint(buf, "/proc/%d/notepg", getpid());
  195. fd = open(buf, OWRITE);
  196. write(fd, "die", 3);
  197. exits(0);
  198. }
  199. void
  200. prompt(char *p, char *b, int n, int raw)
  201. {
  202. char *e;
  203. int i;
  204. int echo;
  205. echo = opt[Echo].local;
  206. if(raw)
  207. opt[Echo].local = 0;
  208. print("%s: ", p);
  209. for(e = b+n; b < e;){
  210. i = fromnet(b, e-b);
  211. if(i <= 0)
  212. exits("fromnet: hungup");
  213. b += i;
  214. if(*(b-1) == '\n' || *(b-1) == '\r'){
  215. *(b-1) = 0;
  216. break;
  217. }
  218. }
  219. if(raw)
  220. opt[Echo].local = echo;
  221. }
  222. /*
  223. * challenge user
  224. */
  225. int
  226. challuser(char *user)
  227. {
  228. char nchall[64];
  229. char response[64];
  230. Chalstate *ch;
  231. AuthInfo *ai;
  232. if(strcmp(user, "none") == 0){
  233. if(nonone)
  234. return -1;
  235. newns("none", nil);
  236. return 0;
  237. }
  238. if((ch = auth_challenge("proto=p9cr role=server user=%q", user)) == nil)
  239. return -1;
  240. snprint(nchall, sizeof nchall, "challenge: %s\r\nresponse", ch->chal);
  241. prompt(nchall, response, sizeof response, 0);
  242. ch->resp = response;
  243. ch->nresp = strlen(response);
  244. ai = auth_response(ch);
  245. auth_freechal(ch);
  246. if(ai == nil){
  247. rerrstr(response, sizeof response);
  248. print("!%s\n", response);
  249. return -1;
  250. }
  251. if(auth_chuid(ai, nil) < 0)
  252. return -1;
  253. return 0;
  254. }
  255. /*
  256. * use the in the clear apop password to change user id
  257. */
  258. int
  259. noworldlogin(char *user)
  260. {
  261. char password[256];
  262. prompt("password", password, sizeof(password), 1);
  263. if(login(user, password, "/lib/namespace.noworld") < 0)
  264. return -1;
  265. rfork(RFNOMNT); /* sandbox */
  266. return 0;
  267. }
  268. int
  269. doauth(char *user)
  270. {
  271. if(*user == 0)
  272. prompt("user", user, Maxuser, 0);
  273. if(noworld(user))
  274. return noworldlogin(user);
  275. if(noworldonly)
  276. return -1;
  277. return challuser(user);
  278. }
  279. /*
  280. * Process some input from the child, add protocol if needed. If
  281. * the input buffer goes empty, return.
  282. */
  283. int
  284. fromchild(char *bp, int len)
  285. {
  286. int c;
  287. char *start;
  288. for(start = bp; bp-start < len-1; ){
  289. c = Bgetc(&childib);
  290. if(c < 0){
  291. if(bp == start)
  292. return -1;
  293. else
  294. break;
  295. }
  296. if(cons->raw == 0 && c == '\n')
  297. *bp++ = '\r';
  298. *bp++ = c;
  299. if(Bbuffered(&childib) == 0)
  300. break;
  301. }
  302. return bp-start;
  303. }
  304. /*
  305. * Read from the network up to a '\n' or some other break.
  306. *
  307. * If in binary mode, buffer characters but don't
  308. *
  309. * The following characters are special:
  310. * '\r\n's and '\r's get turned into '\n's.
  311. * ^H erases the last character buffered.
  312. * ^U kills the whole line buffered.
  313. * ^W erases the last word
  314. * ^D causes a 0-length line to be returned.
  315. * Intr causes an "interrupt" note to be sent to the children.
  316. */
  317. #define ECHO(c) { *ebp++ = (c); }
  318. int
  319. fromnet(char *bp, int len)
  320. {
  321. int c;
  322. char echobuf[1024];
  323. char *ebp;
  324. char *start;
  325. static int crnl;
  326. static int doeof;
  327. /* simulate an EOF as a 0 length input */
  328. if(doeof){
  329. doeof = 0;
  330. return 0;
  331. }
  332. for(ebp = echobuf,start = bp; bp-start < len && ebp-echobuf < sizeof(echobuf); ){
  333. c = Bgetc(&netib);
  334. if(c < 0){
  335. if(bp == start)
  336. return -1;
  337. else
  338. break;
  339. }
  340. /* telnet protocol only */
  341. if(!noproto){
  342. /* protocol messages */
  343. switch(c){
  344. case Iac:
  345. crnl = 0;
  346. c = Bgetc(&netib);
  347. if(c == Iac)
  348. break;
  349. control(&netib, c);
  350. continue;
  351. }
  352. }
  353. /* \r\n or \n\r become \n */
  354. if(c == '\r' || c == '\n'){
  355. if(crnl && crnl != c){
  356. crnl = 0;
  357. continue;
  358. }
  359. if(cons->raw == 0 && opt[Echo].local){
  360. ECHO('\r');
  361. ECHO('\n');
  362. }
  363. crnl = c;
  364. if(cons->raw == 0)
  365. *bp++ = '\n';
  366. else
  367. *bp++ = c;
  368. break;
  369. } else
  370. crnl = 0;
  371. /* raw processing (each character terminates */
  372. if(cons->raw){
  373. *bp++ = c;
  374. break;
  375. }
  376. /* in binary mode, there are no control characters */
  377. if(opt[Binary].local){
  378. if(opt[Echo].local)
  379. ECHO(c);
  380. *bp++ = c;
  381. continue;
  382. }
  383. /* cooked processing */
  384. switch(c){
  385. case 0x00:
  386. if(noproto) /* telnet ignores nulls */
  387. *bp++ = c;
  388. continue;
  389. case 0x04:
  390. if(bp != start)
  391. doeof = 1;
  392. goto out;
  393. case 0x08: /* ^H */
  394. if(start < bp)
  395. bp--;
  396. if(opt[Echo].local)
  397. ECHO(c);
  398. break;
  399. case 0x15: /* ^U */
  400. bp = start;
  401. if(opt[Echo].local){
  402. ECHO('^');
  403. ECHO('U');
  404. ECHO('\r');
  405. ECHO('\n');
  406. }
  407. break;
  408. case 0x17: /* ^W */
  409. if (opt[Echo].local) {
  410. while (--bp >= start && !alnum(*bp))
  411. ECHO('\b');
  412. while (bp >= start && alnum(*bp)) {
  413. ECHO('\b');
  414. bp--;
  415. }
  416. bp++;
  417. }
  418. break;
  419. case 0x7f: /* Del */
  420. write(notefd, "interrupt", 9);
  421. bp = start;
  422. break;
  423. default:
  424. if(opt[Echo].local)
  425. ECHO(c);
  426. *bp++ = c;
  427. }
  428. if(ebp != echobuf)
  429. write(1, echobuf, ebp-echobuf);
  430. ebp = echobuf;
  431. }
  432. out:
  433. if(ebp != echobuf)
  434. write(1, echobuf, ebp-echobuf);
  435. return bp - start;
  436. }
  437. int
  438. termchange(Biobuf *bp, int cmd)
  439. {
  440. unsigned char buf[8];
  441. unsigned char *p = buf;
  442. if(cmd != Will)
  443. return 0;
  444. /* ask other side to send term type info */
  445. *p++ = Iac;
  446. *p++ = Sb;
  447. *p++ = opt[Term].code;
  448. *p++ = 1;
  449. *p++ = Iac;
  450. *p++ = Se;
  451. return iwrite(Bfildes(bp), buf, p-buf);
  452. }
  453. int
  454. termsub(Biobuf *bp, uint8_t *sub, int n)
  455. {
  456. char term[Maxvar];
  457. USED(bp);
  458. if(n-- < 1 || sub[0] != 0)
  459. return 0;
  460. if(n >= sizeof term)
  461. n = sizeof term;
  462. strncpy(term, (char*)sub, n);
  463. putenv("TERM", term);
  464. return 0;
  465. }
  466. int
  467. xlocchange(Biobuf *bp, int cmd)
  468. {
  469. unsigned char buf[8];
  470. unsigned char *p = buf;
  471. if(cmd != Will)
  472. return 0;
  473. /* ask other side to send x display info */
  474. *p++ = Iac;
  475. *p++ = Sb;
  476. *p++ = opt[Xloc].code;
  477. *p++ = 1;
  478. *p++ = Iac;
  479. *p++ = Se;
  480. return iwrite(Bfildes(bp), buf, p-buf);
  481. }
  482. int
  483. xlocsub(Biobuf *bp, uint8_t *sub, int n)
  484. {
  485. char xloc[Maxvar];
  486. USED(bp);
  487. if(n-- < 1 || sub[0] != 0)
  488. return 0;
  489. if(n >= sizeof xloc)
  490. n = sizeof xloc;
  491. strncpy(xloc, (char*)sub, n);
  492. putenv("DISPLAY", xloc);
  493. return 0;
  494. }
  495. /*
  496. * create a shared segment. Make is start 2 meg higher than the current
  497. * end of process memory.
  498. */
  499. void*
  500. share(uint32_t len)
  501. {
  502. uint8_t *vastart;
  503. vastart = sbrk(0);
  504. if(vastart == (void*)-1)
  505. return 0;
  506. vastart += 2*1024*1024;
  507. if(segattach(0, "shared", vastart, len) == (void*)-1)
  508. return 0;
  509. return vastart;
  510. }
  511. /*
  512. * bind a pipe onto consctl and keep reading it to
  513. * get changes to console state.
  514. */
  515. int
  516. conssim(void)
  517. {
  518. int i, n;
  519. int fd;
  520. int tries;
  521. char buf[128];
  522. char *field[10];
  523. /* a pipe to simulate the /dev/cons */
  524. if(bind("#|", "/mnt/cons/cons", MREPL) < 0)
  525. fatal("/dev/cons1", 0, 0);
  526. if(bind("/mnt/cons/cons/data1", "/dev/cons", MREPL) < 0)
  527. fatal("/dev/cons2", 0, 0);
  528. /* a pipe to simulate consctl */
  529. if(bind("#|", "/mnt/cons/consctl", MBEFORE) < 0
  530. || bind("/mnt/cons/consctl/data1", "/dev/consctl", MREPL) < 0)
  531. fatal("/dev/consctl", 0, 0);
  532. /* a process to read /dev/consctl and set the state in cons */
  533. switch(fork()){
  534. case -1:
  535. fatal("forking", 0, 0);
  536. case 0:
  537. break;
  538. default:
  539. return open("/mnt/cons/cons/data", ORDWR);
  540. }
  541. for(tries = 0; tries < 100; tries++){
  542. cons->raw = 0;
  543. cons->hold = 0;
  544. fd = open("/mnt/cons/consctl/data", OREAD);
  545. if(fd < 0)
  546. continue;
  547. tries = 0;
  548. for(;;){
  549. n = read(fd, buf, sizeof(buf)-1);
  550. if(n <= 0)
  551. break;
  552. buf[n] = 0;
  553. n = getfields(buf, field, 10, 1, " ");
  554. for(i = 0; i < n; i++){
  555. if(strcmp(field[i], "rawon") == 0) {
  556. if(debug) fprint(2, "raw = 1\n");
  557. cons->raw = 1;
  558. } else if(strcmp(field[i], "rawoff") == 0) {
  559. if(debug) fprint(2, "raw = 0\n");
  560. cons->raw = 0;
  561. } else if(strcmp(field[i], "holdon") == 0) {
  562. cons->hold = 1;
  563. if(debug) fprint(2, "raw = 1\n");
  564. } else if(strcmp(field[i], "holdoff") == 0) {
  565. cons->hold = 0;
  566. if(debug) fprint(2, "raw = 0\n");
  567. }
  568. }
  569. }
  570. close(fd);
  571. }
  572. exits(0);
  573. return -1;
  574. }
  575. int
  576. alnum(int c)
  577. {
  578. /*
  579. * Hard to get absolutely right. Use what we know about ASCII
  580. * and assume anything above the Latin control characters is
  581. * potentially an alphanumeric.
  582. */
  583. if(c <= ' ')
  584. return 0;
  585. if(0x7F<=c && c<=0xA0)
  586. return 0;
  587. if(strchr("!\"#$%&'()*+,-./:;<=>?@`[\\]^{|}~", c))
  588. return 0;
  589. return 1;
  590. }