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)
249 if(strcmp(user, "none") == 0){
255 if((ch = auth_challenge("proto=p9cr role=server user=%q", user)) == nil)
257 snprint(nchall, sizeof nchall, "challenge: %s\r\nresponse", ch->chal);
258 prompt(nchall, response, sizeof response, 0);
260 ch->nresp = strlen(response);
261 ai = auth_response(ch);
264 rerrstr(response, sizeof response);
265 print("!%s\n", response);
268 if(auth_chuid(ai, nil) < 0)
273 * use the in the clear apop password to change user id
276 noworldlogin(char *user)
280 prompt("password", password, sizeof(password), 1);
281 if(login(user, password, "/lib/namespace.noworld") < 0)
283 rfork(RFNOMNT); /* sandbox */
291 prompt("user", user, Maxuser, 0);
293 return noworldlogin(user);
296 return challuser(user);
301 * Process some input from the child, add protocol if needed. If
302 * the input buffer goes empty, return.
305 fromchild(char *bp, int len)
310 for(start = bp; bp-start < len-1; ){
318 if(cons->raw == 0 && c == '\n')
321 if(Bbuffered(&childib) == 0)
328 * Read from the network up to a '\n' or some other break.
330 * If in binary mode, buffer characters but don't
332 * The following characters are special:
333 * '\r\n's and '\r's get turned into '\n's.
334 * ^H erases the last character buffered.
335 * ^U kills the whole line buffered.
336 * ^W erases the last word
337 * ^D causes a 0-length line to be returned.
338 * Intr causes an "interrupt" note to be sent to the children.
340 #define ECHO(c) { *ebp++ = (c); }
342 fromnet(char *bp, int len)
352 /* simulate an EOF as a 0 length input */
358 for(ebp = echobuf,start = bp; bp-start < len && ebp-echobuf < sizeof(echobuf); ){
367 /* telnet protocol only */
369 /* protocol messages */
382 /* \r\n or \n\r become \n */
383 if(c == '\r' || c == '\n'){
384 if(crnl && crnl != c){
388 if(cons->raw == 0 && opt[Echo].local){
401 /* raw processing (each character terminates */
407 /* in binary mode, there are no control characters */
408 if(opt[Binary].local){
415 /* cooked processing */
418 if(noproto) /* telnet ignores nulls */
444 if (opt[Echo].local) {
445 while (--bp >= start && !alnum(*bp))
447 while (bp >= start && alnum(*bp)) {
456 write(notefd, "interrupt", 9);
466 write(1, echobuf, ebp-echobuf);
471 write(1, echobuf, ebp-echobuf);
476 termchange(Biobuf *bp, int cmd)
484 /* ask other side to send term type info */
487 *p++ = opt[Term].code;
491 return iwrite(Bfildes(bp), buf, p-buf);
495 termsub(Biobuf *bp, uchar *sub, int n)
500 if(n-- < 1 || sub[0] != 0)
504 strncpy(term, (char*)sub, n);
505 putenv("TERM", term);
510 xlocchange(Biobuf *bp, int cmd)
518 /* ask other side to send x display info */
521 *p++ = opt[Xloc].code;
525 return iwrite(Bfildes(bp), buf, p-buf);
529 xlocsub(Biobuf *bp, uchar *sub, int n)
534 if(n-- < 1 || sub[0] != 0)
538 strncpy(xloc, (char*)sub, n);
539 putenv("DISPLAY", xloc);
544 * create a shared segment. Make is start 2 meg higher than the current
545 * end of process memory.
553 if(vastart == (void*)-1)
555 vastart += 2*1024*1024;
557 if(segattach(0, "shared", vastart, len) == (void*)-1)
564 * bind a pipe onto consctl and keep reading it to
565 * get changes to console state.
576 /* a pipe to simulate the /dev/cons */
577 if(bind("#|", "/mnt/cons", MREPL) < 0)
578 fatal("/dev/cons1", 0, 0);
579 if(bind("/mnt/cons/data1", "/dev/cons", MREPL) < 0)
580 fatal("/dev/cons2", 0, 0);
582 /* a pipe to simulate consctl */
583 if(bind("#|", "/mnt/consctl", MBEFORE) < 0
584 || bind("/mnt/consctl/data1", "/dev/consctl", MREPL) < 0)
585 fatal("/dev/consctl", 0, 0);
587 /* a process to read /dev/consctl and set the state in cons */
590 fatal("forking", 0, 0);
594 return open("/mnt/cons/data", ORDWR);
597 for(tries = 0; tries < 100; tries++){
600 fd = open("/mnt/consctl/data", OREAD);
605 n = read(fd, buf, sizeof(buf)-1);
609 n = getfields(buf, field, 10, 1, " ");
610 for(i = 0; i < n; i++){
611 if(strcmp(field[i], "rawon") == 0) {
612 if(debug) fprint(2, "raw = 1\n");
614 } else if(strcmp(field[i], "rawoff") == 0) {
615 if(debug) fprint(2, "raw = 0\n");
617 } else if(strcmp(field[i], "holdon") == 0) {
619 if(debug) fprint(2, "raw = 1\n");
620 } else if(strcmp(field[i], "holdoff") == 0) {
622 if(debug) fprint(2, "raw = 0\n");
636 * Hard to get absolutely right. Use what we know about ASCII
637 * and assume anything above the Latin control characters is
638 * potentially an alphanumeric.
642 if(0x7F<=c && c<=0xA0)
644 if(strchr("!\"#$%&'()*+,-./:;<=>?@`[\\]^{|}~", c))