telnetd.c 12 KB

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