7 #include "../ip/telnet.h"
9 /* console state (for consctl) */
10 typedef struct Consstate Consstate;
17 int notefd; /* for sending notes to the child */
18 int noproto; /* true if we shouldn't be using the telnet protocol */
19 int trusted; /* true if we need not authenticate - current user
21 int nonone = 1; /* don't allow none logins */
22 int noworldonly; /* only noworld accounts */
31 /* input and output buffers for network connection */
34 char remotesys[Maxpath]; /* name of remote system */
38 int fromchild(char*, int);
39 int fromnet(char*, int);
40 int termchange(Biobuf*, int);
41 int termsub(Biobuf*, uchar*, int);
42 int xlocchange(Biobuf*, int);
43 int xlocsub(Biobuf*, uchar*, int);
45 int noworldlogin(char*);
49 #define TELNETLOG "telnet"
58 vseprint(buf, buf + sizeof(buf) / sizeof(*buf), fmt, arg);
60 syslog(0, TELNETLOG, "(%s) %s", remotesys, buf);
67 char remfile[Maxpath];
69 sprint(remfile, "%s/remote", dir);
70 fd = open(remfile, OREAD);
72 strcpy(remotesys, "unknown2");
73 n = read(fd, remotesys, sizeof(remotesys)-1);
77 strcpy(remotesys, remfile);
82 main(int argc, char *argv[])
91 memset(user, 0, sizeof(user));
105 strncpy(user, getuser(), sizeof(user)-1);
108 strncpy(user, ARGF(), sizeof(user)-1);
119 getremote(argv[argc-1]);
121 strcpy(remotesys, "unknown");
123 /* options we need routines for */
124 opt[Term].change = termchange;
125 opt[Term].sub = termsub;
126 opt[Xloc].sub = xlocsub;
128 /* setup default telnet options */
130 send3(1, Iac, Will, opt[Echo].code);
131 send3(1, Iac, Do, opt[Term].code);
132 send3(1, Iac, Do, opt[Xloc].code);
135 /* shared data for console state */
136 cons = share(sizeof(Consstate));
138 fatal("shared memory", 0, 0);
140 /* authenticate and create new name space */
141 Binit(&netib, 0, OREAD);
143 while(doauth(user) < 0)
145 logit("failed as %s: %r", user);
146 print("authentication failure:%r\r\n");
147 exits("authentication");
150 logit("logged in as %s", user);
151 putenv("service", "con");
153 /* simulate /dev/consctl and /dev/cons using pipes */
156 fatal("simulating", 0, 0);
157 Binit(&childib, fd, OREAD);
159 /* start a shell in a different process group */
160 switch(childpid = rfork(RFPROC|RFNAMEG|RFFDG|RFNOTEG)){
165 fd = open("/dev/cons", OREAD);
168 fd = open("/dev/cons", OWRITE);
173 execl("/bin/rc", "rc", "-il", nil);
174 fatal("/bin/rc", 0, 0);
176 sprint(buf, "/proc/%d/notepg", childpid);
177 notefd = open(buf, OWRITE);
181 /* two processes to shuttle bytes twixt children and network */
188 n = fromchild(buf, sizeof(buf));
195 if(write(1, buf, n) != n)
200 while((n = fromnet(buf, sizeof(buf))) >= 0)
201 if(write(fd, buf, n) != n)
206 /* kill off all server processes */
207 sprint(buf, "/proc/%d/notepg", getpid());
208 fd = open(buf, OWRITE);
214 prompt(char *p, char *b, int n, int raw)
220 echo = opt[Echo].local;
224 for(e = b+n; b < e;){
227 exits("fromnet: hungup");
229 if(*(b-1) == '\n' || *(b-1) == '\r'){
235 opt[Echo].local = echo;
242 challuser(char *user)
250 if(strcmp(user, "none") == 0){
256 if((ch = auth_challenge("proto=p9cr role=server user=%q", user)) == nil)
258 snprint(nchall, sizeof nchall, "challenge: %s\r\nresponse", ch->chal);
259 prompt(nchall, response, sizeof response, 0);
261 ch->nresp = strlen(response);
262 ai = auth_response(ch);
264 if(ai == nil || auth_chuid(ai, nil) < 0){
265 rerrstr(response, sizeof response);
266 print("!%s\n", response);
271 /* chown network connection */
281 * use the in the clear apop password to change user id
284 noworldlogin(char *user)
288 prompt("password", password, sizeof(password), 1);
289 if(login(user, password, "/lib/namespace.noworld") < 0)
291 rfork(RFNOMNT); /* sandbox */
299 prompt("user", user, Maxuser, 0);
301 return noworldlogin(user);
304 return challuser(user);
309 * Process some input from the child, add protocol if needed. If
310 * the input buffer goes empty, return.
313 fromchild(char *bp, int len)
318 for(start = bp; bp-start < len-1; ){
326 if(cons->raw == 0 && c == '\n')
329 if(Bbuffered(&childib) == 0)
336 * Read from the network up to a '\n' or some other break.
338 * If in binary mode, buffer characters but don't
340 * The following characters are special:
341 * '\r\n's and '\r's get turned into '\n's.
342 * ^H erases the last character buffered.
343 * ^U kills the whole line buffered.
344 * ^W erases the last word
345 * ^D causes a 0-length line to be returned.
346 * Intr causes an "interrupt" note to be sent to the children.
348 #define ECHO(c) { *ebp++ = (c); }
350 fromnet(char *bp, int len)
360 /* simulate an EOF as a 0 length input */
366 for(ebp = echobuf,start = bp; bp-start < len && ebp-echobuf < sizeof(echobuf); ){
375 /* telnet protocol only */
377 /* protocol messages */
390 /* \r\n or \n\r become \n */
391 if(c == '\r' || c == '\n'){
392 if(crnl && crnl != c){
396 if(cons->raw == 0 && opt[Echo].local){
409 /* raw processing (each character terminates */
415 /* in binary mode, there are no control characters */
416 if(opt[Binary].local){
423 /* cooked processing */
426 if(noproto) /* telnet ignores nulls */
452 if (opt[Echo].local) {
453 while (--bp >= start && !alnum(*bp))
455 while (bp >= start && alnum(*bp)) {
464 write(notefd, "interrupt", 9);
474 write(1, echobuf, ebp-echobuf);
479 write(1, echobuf, ebp-echobuf);
484 termchange(Biobuf *bp, int cmd)
492 /* ask other side to send term type info */
495 *p++ = opt[Term].code;
499 return iwrite(Bfildes(bp), buf, p-buf);
503 termsub(Biobuf *bp, uchar *sub, int n)
508 if(n-- < 1 || sub[0] != 0)
512 strncpy(term, (char*)sub, n);
513 putenv("TERM", term);
518 xlocchange(Biobuf *bp, int cmd)
526 /* ask other side to send x display info */
529 *p++ = opt[Xloc].code;
533 return iwrite(Bfildes(bp), buf, p-buf);
537 xlocsub(Biobuf *bp, uchar *sub, int n)
542 if(n-- < 1 || sub[0] != 0)
546 strncpy(xloc, (char*)sub, n);
547 putenv("DISPLAY", xloc);
552 * create a shared segment.
559 v = segattach(0, "shared", 0, len);
566 * bind a pipe onto consctl and keep reading it to
567 * get changes to console state.
578 /* a pipe to simulate the /dev/cons */
579 if(bind("#|", "/mnt/cons", MREPL) == -1)
580 fatal("/dev/cons1", 0, 0);
581 if(bind("/mnt/cons/data1", "/dev/cons", MREPL) == -1)
582 fatal("/dev/cons2", 0, 0);
584 /* a pipe to simulate consctl */
585 if(bind("#|", "/mnt/consctl", MBEFORE) == -1
586 || bind("/mnt/consctl/data1", "/dev/consctl", MREPL) == -1)
587 fatal("/dev/consctl", 0, 0);
589 /* a process to read /dev/consctl and set the state in cons */
592 fatal("forking", 0, 0);
596 return open("/mnt/cons/data", ORDWR);
599 for(tries = 0; tries < 100; tries++){
602 fd = open("/mnt/consctl/data", OREAD);
607 n = read(fd, buf, sizeof(buf)-1);
611 n = getfields(buf, field, 10, 1, " ");
612 for(i = 0; i < n; i++){
613 if(strcmp(field[i], "rawon") == 0) {
614 if(debug) fprint(2, "raw = 1\n");
616 } else if(strcmp(field[i], "rawoff") == 0) {
617 if(debug) fprint(2, "raw = 0\n");
619 } else if(strcmp(field[i], "holdon") == 0) {
621 if(debug) fprint(2, "raw = 1\n");
622 } else if(strcmp(field[i], "holdoff") == 0) {
624 if(debug) fprint(2, "raw = 0\n");
638 * Hard to get absolutely right. Use what we know about ASCII
639 * and assume anything above the Latin control characters is
640 * potentially an alphanumeric.
644 if(0x7F<=c && c<=0xA0)
646 if(strchr("!\"#$%&'()*+,-./:;<=>?@`[\\]^{|}~", c))