|
|
1.1 root 1: /*
2: * Copyright (c) 1988 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted
6: * provided that the above copyright notice and this paragraph are
7: * duplicated in all such forms and that any documentation,
8: * advertising materials, and other materials related to such
9: * distribution and use acknowledge that the software was developed
10: * by the University of California, Berkeley. The name of the
11: * University may not be used to endorse or promote products derived
12: * from this software without specific prior written permission.
13: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16: */
17:
18: #ifndef lint
19: static char sccsid[] = "@(#)system.c 4.3 (Berkeley) 9/2/89";
20: #endif /* not lint */
21:
22: #include <sys/types.h>
23:
24: #if defined(pyr)
25: #define fd_set fdset_t
26: #endif /* defined(pyr) */
27:
28: /*
29: * Wouldn't it be nice if these REALLY were in <sys/inode.h>? Or,
30: * equivalently, if <sys/inode.h> REALLY existed?
31: */
32: #define IREAD 00400
33: #define IWRITE 00200
34:
35: #include <sys/file.h>
36: #include <sys/time.h>
37: #include <sys/socket.h>
38: #include <netinet/in.h>
39: #include <sys/wait.h>
40:
41: #include <errno.h>
42: extern int errno;
43:
44: #include <netdb.h>
45: #include <signal.h>
46: #include <stdio.h>
47: #include <pwd.h>
48:
49: #include "../general/general.h"
50: #include "../ctlr/api.h"
51: #include "../api/api_exch.h"
52:
53: #include "../general/globals.h"
54:
55: #ifndef FD_SETSIZE
56: /*
57: * The following is defined just in case someone should want to run
58: * this telnet on a 4.2 system.
59: *
60: */
61:
62: #define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n)))
63: #define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1<<(n)))
64: #define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n)))
65: #define FD_ZERO(p) ((p)->fds_bits[0] = 0)
66:
67: #endif
68:
69: static int shell_pid = 0;
70: static char key[50]; /* Actual key */
71: static char *keyname; /* Name of file with key in it */
72:
73: static char *ourENVlist[200]; /* Lots of room */
74:
75: static int
76: sock = -1, /* Connected socket */
77: serversock; /* Server (listening) socket */
78:
79: static enum { DEAD, UNCONNECTED, CONNECTED } state;
80:
81: static long
82: storage_location; /* Address we have */
83: static short
84: storage_length = 0; /* Length we have */
85: static int
86: storage_must_send = 0, /* Storage belongs on other side of wire */
87: storage_accessed = 0; /* The storage is accessed (so leave alone)! */
88:
89: static long storage[1000];
90:
91: static union REGS inputRegs;
92: static struct SREGS inputSregs;
93:
94: extern int apitrace;
95:
96: static void
97: kill_connection()
98: {
99: state = UNCONNECTED;
100: if (sock != -1) {
101: (void) close(sock);
102: sock = -1;
103: }
104: }
105:
106:
107: static int
108: nextstore()
109: {
110: struct storage_descriptor sd;
111:
112: if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
113: storage_length = 0;
114: return -1;
115: }
116: storage_length = sd.length;
117: storage_location = sd.location;
118: if (storage_length > sizeof storage) {
119: fprintf(stderr, "API client tried to send too much storage (%d).\n",
120: storage_length);
121: storage_length = 0;
122: return -1;
123: }
124: if (api_exch_intype(EXCH_TYPE_BYTES, storage_length, (char *)storage)
125: == -1) {
126: storage_length = 0;
127: return -1;
128: }
129: return 0;
130: }
131:
132:
133: static int
134: doreject(message)
135: char *message;
136: {
137: struct storage_descriptor sd;
138: int length = strlen(message);
139:
140: if (api_exch_outcommand(EXCH_CMD_REJECTED) == -1) {
141: return -1;
142: }
143: sd.length = length;
144: if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
145: return -1;
146: }
147: if (api_exch_outtype(EXCH_TYPE_BYTES, length, message) == -1) {
148: return -1;
149: }
150: return 0;
151: }
152:
153:
154: /*
155: * doassociate()
156: *
157: * Negotiate with the other side and try to do something.
158: *
159: * Returns:
160: *
161: * -1: Error in processing
162: * 0: Invalid password entered
163: * 1: Association OK
164: */
165:
166: static int
167: doassociate()
168: {
169: struct passwd *pwent;
170: char
171: promptbuf[100],
172: buffer[200];
173: struct storage_descriptor sd;
174: extern char *crypt();
175:
176: if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
177: return -1;
178: }
179: sd.length = sd.length;
180: if (sd.length > sizeof buffer) {
181: doreject("(internal error) Authentication key too long");
182: return -1;
183: }
184: if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) {
185: return -1;
186: }
187: buffer[sd.length] = 0;
188:
189: if (strcmp(buffer, key) != 0) {
190: #if (!defined(sun)) || defined(BSD) && (BSD >= 43)
191: extern uid_t geteuid();
192: #endif /* (!defined(sun)) || defined(BSD) && (BSD >= 43) */
193:
194: if ((pwent = getpwuid((int)geteuid())) == 0) {
195: return -1;
196: }
197: sprintf(promptbuf, "Enter password for user %s:", pwent->pw_name);
198: if (api_exch_outcommand(EXCH_CMD_SEND_AUTH) == -1) {
199: return -1;
200: }
201: sd.length = strlen(promptbuf);
202: if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd)
203: == -1) {
204: return -1;
205: }
206: if (api_exch_outtype(EXCH_TYPE_BYTES, strlen(promptbuf), promptbuf)
207: == -1) {
208: return -1;
209: }
210: sd.length = strlen(pwent->pw_name);
211: if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd)
212: == -1) {
213: return -1;
214: }
215: if (api_exch_outtype(EXCH_TYPE_BYTES,
216: strlen(pwent->pw_name), pwent->pw_name) == -1) {
217: return -1;
218: }
219: if (api_exch_incommand(EXCH_CMD_AUTH) == -1) {
220: return -1;
221: }
222: if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd)
223: == -1) {
224: return -1;
225: }
226: sd.length = sd.length;
227: if (sd.length > sizeof buffer) {
228: doreject("Password entered was too long");
229: return -1;
230: }
231: if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) {
232: return -1;
233: }
234: buffer[sd.length] = 0;
235:
236: /* Is this the correct password? */
237: if (strlen(pwent->pw_name)) {
238: char *ptr;
239: int i;
240:
241: ptr = pwent->pw_name;
242: i = 0;
243: while (i < sd.length) {
244: buffer[i++] ^= *ptr++;
245: if (*ptr == 0) {
246: ptr = pwent->pw_name;
247: }
248: }
249: }
250: if (strcmp(crypt(buffer, pwent->pw_passwd), pwent->pw_passwd) != 0) {
251: doreject("Invalid password");
252: sleep(10); /* Don't let us do too many of these */
253: return 0;
254: }
255: }
256: if (api_exch_outcommand(EXCH_CMD_ASSOCIATED) == -1) {
257: return -1;
258: } else {
259: return 1;
260: }
261: }
262:
263:
264: void
265: freestorage()
266: {
267: struct storage_descriptor sd;
268:
269: if (storage_accessed) {
270: fprintf(stderr, "Internal error - attempt to free accessed storage.\n");
271: fprintf(stderr, "(Encountered in file %s at line %d.)\n",
272: __FILE__, __LINE__);
273: quit();
274: }
275: if (storage_must_send == 0) {
276: return;
277: }
278: storage_must_send = 0;
279: if (api_exch_outcommand(EXCH_CMD_HEREIS) == -1) {
280: kill_connection();
281: return;
282: }
283: sd.length = storage_length;
284: sd.location = storage_location;
285: if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) {
286: kill_connection();
287: return;
288: }
289: if (api_exch_outtype(EXCH_TYPE_BYTES, storage_length, (char *)storage)
290: == -1) {
291: kill_connection();
292: return;
293: }
294: }
295:
296:
297: static int
298: getstorage(address, length, copyin)
299: long
300: address;
301: int
302: length,
303: copyin;
304: {
305: struct storage_descriptor sd;
306:
307: freestorage();
308: if (storage_accessed) {
309: fprintf(stderr,
310: "Internal error - attempt to get while storage accessed.\n");
311: fprintf(stderr, "(Encountered in file %s at line %d.)\n",
312: __FILE__, __LINE__);
313: quit();
314: }
315: storage_must_send = 0;
316: if (api_exch_outcommand(EXCH_CMD_GIMME) == -1) {
317: kill_connection();
318: return -1;
319: }
320: storage_location = address;
321: storage_length = length;
322: if (copyin) {
323: sd.location = (long)storage_location;
324: sd.length = storage_length;
325: if (api_exch_outtype(EXCH_TYPE_STORE_DESC,
326: sizeof sd, (char *)&sd) == -1) {
327: kill_connection();
328: return -1;
329: }
330: if (api_exch_incommand(EXCH_CMD_HEREIS) == -1) {
331: fprintf(stderr, "Bad data from other side.\n");
332: fprintf(stderr, "(Encountered at %s, %d.)\n", __FILE__, __LINE__);
333: return -1;
334: }
335: if (nextstore() == -1) {
336: kill_connection();
337: return -1;
338: }
339: }
340: return 0;
341: }
342:
343: /*ARGSUSED*/
344: void
345: movetous(local, es, di, length)
346: char
347: *local;
348: unsigned int
349: es,
350: di;
351: int
352: length;
353: {
354: long where = SEG_OFF_BACK(es, di);
355:
356: if (length > sizeof storage) {
357: fprintf(stderr, "Internal API error - movetous() length too long.\n");
358: fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__);
359: quit();
360: } else if (length == 0) {
361: return;
362: }
363: getstorage(where, length, 1);
364: memcpy(local, (char *)(storage+((where-storage_location))), length);
365: if (apitrace) {
366: Dump('(', local, length);
367: }
368: }
369:
370: /*ARGSUSED*/
371: void
372: movetothem(es, di, local, length)
373: unsigned int
374: es,
375: di;
376: char
377: *local;
378: int
379: length;
380: {
381: long where = SEG_OFF_BACK(es, di);
382:
383: if (length > sizeof storage) {
384: fprintf(stderr, "Internal API error - movetothem() length too long.\n");
385: fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__);
386: quit();
387: } else if (length == 0) {
388: return;
389: }
390: freestorage();
391: memcpy((char *)storage, local, length);
392: if (apitrace) {
393: Dump(')', local, length);
394: }
395: storage_length = length;
396: storage_location = where;
397: storage_must_send = 1;
398: }
399:
400:
401: char *
402: access_api(location, length, copyin)
403: char *
404: location;
405: int
406: length,
407: copyin; /* Do we need to copy in initially? */
408: {
409: if (storage_accessed) {
410: fprintf(stderr, "Internal error - storage accessed twice\n");
411: fprintf(stderr, "(Encountered in file %s, line %d.)\n",
412: __FILE__, __LINE__);
413: quit();
414: } else if (length != 0) {
415: freestorage();
416: getstorage((long)location, length, copyin);
417: storage_accessed = 1;
418: }
419: return (char *) storage;
420: }
421:
422: /*ARGSUSED*/
423: void
424: unaccess_api(location, local, length, copyout)
425: char *location;
426: char *local;
427: int length;
428: int copyout;
429: {
430: if (storage_accessed == 0) {
431: fprintf(stderr, "Internal error - unnecessary unaccess_api call.\n");
432: fprintf(stderr, "(Encountered in file %s, line %d.)\n",
433: __FILE__, __LINE__);
434: quit();
435: }
436: storage_accessed = 0;
437: storage_must_send = copyout; /* if needs to go back */
438: }
439:
440: /*
441: * Accept a connection from an API client, aborting if the child dies.
442: */
443:
444: static int
445: doconnect()
446: {
447: fd_set fdset;
448: int i;
449:
450: sock = -1;
451: FD_ZERO(&fdset);
452: while (shell_active && (sock == -1)) {
453: FD_SET(serversock, &fdset);
454: if ((i = select(serversock+1, &fdset,
455: (fd_set *)0, (fd_set *)0, (struct timeval *)0)) < 0) {
456: if (errno = EINTR) {
457: continue;
458: } else {
459: perror("in select waiting for API connection");
460: return -1;
461: }
462: } else {
463: i = accept(serversock, (struct sockaddr *)0, (int *)0);
464: if (i == -1) {
465: perror("accepting API connection");
466: return -1;
467: }
468: sock = i;
469: }
470: }
471: /* If the process has already exited, we may need to close */
472: if ((shell_active == 0) && (sock != -1)) {
473: extern void setcommandmode();
474:
475: (void) close(sock);
476: sock = -1;
477: setcommandmode(); /* In case child_died sneaked in */
478: }
479: return 0;
480: }
481:
482: /*
483: * shell_continue() actually runs the command, and looks for API
484: * requests coming back in.
485: *
486: * We are called from the main loop in telnet.c.
487: */
488:
489: int
490: shell_continue()
491: {
492: int i;
493:
494: switch (state) {
495: case DEAD:
496: pause(); /* Nothing to do */
497: break;
498: case UNCONNECTED:
499: if (doconnect() == -1) {
500: kill_connection();
501: return -1;
502: }
503: /* At this point, it is possible that we've gone away */
504: if (shell_active == 0) {
505: kill_connection();
506: return -1;
507: }
508: if (api_exch_init(sock, "server") == -1) {
509: return -1;
510: }
511: while (state == UNCONNECTED) {
512: if (api_exch_incommand(EXCH_CMD_ASSOCIATE) == -1) {
513: kill_connection();
514: return -1;
515: } else {
516: switch (doassociate()) {
517: case -1:
518: kill_connection();
519: return -1;
520: case 0:
521: break;
522: case 1:
523: state = CONNECTED;
524: }
525: }
526: }
527: break;
528: case CONNECTED:
529: switch (i = api_exch_nextcommand()) {
530: case EXCH_CMD_REQUEST:
531: if (api_exch_intype(EXCH_TYPE_REGS, sizeof inputRegs,
532: (char *)&inputRegs) == -1) {
533: kill_connection();
534: } else if (api_exch_intype(EXCH_TYPE_SREGS, sizeof inputSregs,
535: (char *)&inputSregs) == -1) {
536: kill_connection();
537: } else if (nextstore() == -1) {
538: kill_connection();
539: } else {
540: handle_api(&inputRegs, &inputSregs);
541: freestorage(); /* Send any storage back */
542: if (api_exch_outcommand(EXCH_CMD_REPLY) == -1) {
543: kill_connection();
544: } else if (api_exch_outtype(EXCH_TYPE_REGS, sizeof inputRegs,
545: (char *)&inputRegs) == -1) {
546: kill_connection();
547: } else if (api_exch_outtype(EXCH_TYPE_SREGS, sizeof inputSregs,
548: (char *)&inputSregs) == -1) {
549: kill_connection();
550: }
551: /* Done, and it all worked! */
552: }
553: break;
554: case EXCH_CMD_DISASSOCIATE:
555: kill_connection();
556: break;
557: default:
558: if (i != -1) {
559: fprintf(stderr,
560: "Looking for a REQUEST or DISASSOCIATE command\n");
561: fprintf(stderr, "\treceived 0x%02x.\n", i);
562: }
563: kill_connection();
564: break;
565: }
566: }
567: return shell_active;
568: }
569:
570:
571: static int
572: child_died()
573: {
574: union wait status;
575: register int pid;
576:
577: while ((pid = wait3(&status, WNOHANG, (struct rusage *)0)) > 0) {
578: if (pid == shell_pid) {
579: char inputbuffer[100];
580: extern void setconnmode();
581: extern void ConnectScreen();
582:
583: shell_active = 0;
584: if (sock != -1) {
585: (void) close(sock);
586: sock = -1;
587: }
588: printf("[Hit return to continue]");
589: fflush(stdout);
590: (void) gets(inputbuffer);
591: setconnmode();
592: ConnectScreen(); /* Turn screen on (if need be) */
593: (void) close(serversock);
594: (void) unlink(keyname);
595: }
596: }
597: signal(SIGCHLD, child_died);
598: }
599:
600:
601: /*
602: * Called from telnet.c to fork a lower command.com. We
603: * use the spint... routines so that we can pick up
604: * interrupts generated by application programs.
605: */
606:
607:
608: int
609: shell(argc,argv)
610: int argc;
611: char *argv[];
612: {
613: int length;
614: struct sockaddr_in server;
615: char sockNAME[100];
616: static char **whereAPI = 0;
617: int fd;
618: struct timeval tv;
619: long ikey;
620: extern long random();
621: extern char *mktemp();
622: extern char *strcpy();
623:
624: /* First, create verification file. */
625: do {
626: keyname = mktemp("/tmp/apiXXXXXX");
627: fd = open(keyname, O_RDWR|O_CREAT|O_EXCL, IREAD|IWRITE);
628: } while ((fd == -1) && (errno == EEXIST));
629:
630: if (fd == -1) {
631: perror("open");
632: return 0;
633: }
634:
635: /* Now, get seed for random */
636:
637: if (gettimeofday(&tv, (struct timezone *)0) == -1) {
638: perror("gettimeofday");
639: return 0;
640: }
641: srandom(tv.tv_usec); /* seed random number generator */
642: do {
643: ikey = random();
644: } while (ikey == 0);
645: sprintf(key, "%lu\n", (unsigned long) ikey);
646: if (write(fd, key, strlen(key)) != strlen(key)) {
647: perror("write");
648: return 0;
649: }
650: key[strlen(key)-1] = 0; /* Get rid of newline */
651:
652: if (close(fd) == -1) {
653: perror("close");
654: return 0;
655: }
656:
657: /* Next, create the socket which will be connected to */
658: serversock = socket(AF_INET, SOCK_STREAM, 0);
659: if (serversock < 0) {
660: perror("opening API socket");
661: return 0;
662: }
663: server.sin_family = AF_INET;
664: server.sin_addr.s_addr = INADDR_ANY;
665: server.sin_port = 0;
666: if (bind(serversock, (struct sockaddr *)&server, sizeof server) < 0) {
667: perror("binding API socket");
668: return 0;
669: }
670: length = sizeof server;
671: if (getsockname(serversock, (struct sockaddr *)&server, &length) < 0) {
672: perror("getting API socket name");
673: (void) close(serversock);
674: }
675: listen(serversock, 1);
676: /* Get name to advertise in address list */
677: strcpy(sockNAME, "API3270=");
678: gethostname(sockNAME+strlen(sockNAME), sizeof sockNAME-strlen(sockNAME));
679: if (strlen(sockNAME) > (sizeof sockNAME-(10+strlen(keyname)))) {
680: fprintf(stderr, "Local hostname too large; using 'localhost'.\n");
681: strcpy(sockNAME, "localhost");
682: }
683: sprintf(sockNAME+strlen(sockNAME), ":%u", ntohs(server.sin_port));
684: sprintf(sockNAME+strlen(sockNAME), ":%s", keyname);
685:
686: if (whereAPI == 0) {
687: char **ptr, **nextenv;
688: extern char **environ;
689:
690: ptr = environ;
691: nextenv = ourENVlist;
692: while (*ptr) {
693: if (nextenv >= &ourENVlist[highestof(ourENVlist)-1]) {
694: fprintf(stderr, "Too many environmental variables\n");
695: break;
696: }
697: *nextenv++ = *ptr++;
698: }
699: whereAPI = nextenv++;
700: *nextenv++ = 0;
701: environ = ourENVlist; /* New environment */
702: }
703: *whereAPI = sockNAME;
704:
705: child_died(); /* Start up signal handler */
706: shell_active = 1; /* We are running down below */
707: if (shell_pid = vfork()) {
708: if (shell_pid == -1) {
709: perror("vfork");
710: (void) close(serversock);
711: } else {
712: state = UNCONNECTED;
713: }
714: } else { /* New process */
715: register int i;
716:
717: for (i = 3; i < 30; i++) {
718: (void) close(i);
719: }
720: if (argc == 1) { /* Just get a shell */
721: char *cmdname;
722: extern char *getenv();
723:
724: cmdname = getenv("SHELL");
725: execlp(cmdname, cmdname, 0);
726: perror("Exec'ing new shell...\n");
727: exit(1);
728: } else {
729: execvp(argv[1], &argv[1]);
730: perror("Exec'ing command.\n");
731: exit(1);
732: }
733: /*NOTREACHED*/
734: }
735: return shell_active; /* Go back to main loop */
736: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.