home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1988 Dave Settle. All rights reserved.
- * Permission is granted to use, copy and modify this software, providing
- * that it is not sold for profit, and that this copyright notice is retained
- * in any copies of the source.
- */
- /*
- * server: ethernet server. Accepts requests, and spawns processes to
- * serve remote clients.
- */
-
- #include <sys/ni.h>
- #include <stdio.h>
- #include <sys/signal.h>
- #include <sys/errno.h>
- extern int errno;
- #include <pwd.h>
-
- struct passwd *getpwnam();
- char *strrchr();
-
- #define MAIN
- #include "ni.h"
-
- int input[2], output[2]; /* pipes for shell */
- char cmd[128], program[32];
- int reader, sh; /* pid of child reader process */
-
- #define LOG "/usr/lib/server.log"
-
- #define GIGABYTE 2*1024*1024 /* number of blocks in 1 GByte */
-
- /*
- * endproc: called when the shell has died (via SIGPIPE) by the writer process
- */
- endproc(){
- struct request req;
- skill(reader, SIGTERM);
- sprintf(req.r_data, "your shell died");
- send(&req, strlen(req.r_data), TERMINATE, client);
- exit(0);
- }
- /*
- * Called when we get a TERMINATE packet from the client.
- */
- sigterm(){
- skill(reader, SIGTERM);
- skill(sh, SIGHUP);
- sleep(1);
- skill(sh, SIGKILL);
- exit(0);
- }
-
- main()
- {
- int in;
- signal(SIGHUP, SIG_IGN);
- signal(SIGINT, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
- signal(SIGTERM, sigterm);
- ulimit(2, (long) GIGABYTE);
- /*
- * This process runs from "init" - it doesn't have ANY file descriptors open
- * Check this, and if necessary, create some dummy fd's.
- */
- if(in = open("/dev/null", 0) == 0) {
- open("/dev/null", 1);
- open("/dev/null", 1);
- }
- else close(in);
- freopen(LOG, "a+", stderr);
- if(configure(server, 2, 0) == -1) exit(1);
- accept();
- return(0);
- }
- accept(){
- struct request request;
- recv(&request);
- /*
- * Fork off child to deal with the request. We die, and are respawned by
- * init.
- */
- if(fork() == 0) exit(serve(&request));
- /*
- * parent - exit.
- */
- return(0);
- }
- /*
- * serve: set up a shell for the remote process, and pass data.
- */
- #define RD 0
- #define WT 1
- serve(r)
- register struct request *r;
- {
- int pid = getpid(), writer, n, uid, ok;
- int oldnet;
- char user[32];
- struct passwd *pw;
- char home[32], path[128], shell[16], mail[64], term[32], logname[64];
- /*
- * Get the user info from the request header, and set our parameters
- */
- n = sscanf(r->r_data, "%d %s %s", &uid, user, term);
- memcpy(client, r->r_port.srcaddr, ETHERSIZE);
- pw = getpwnam(user);
- if(pw == NULL) {
- n = sprintf(r->r_data, "User '%s' not known here", user);
- send(r, n, TERMINATE, client);
- exit(0);
- }
- if(pw->pw_uid != uid) {
- n = sprintf(r->r_data, "User '%s' and uid '%d' don't match",
- user, uid);
- send(r, n, TERMINATE, client);
- exit(0);
- }
- #ifdef SECURE
- if(uid == 0) {
- n = sprintf(r->r_data, "Secure server: root access not allowed");
- send(r, n, TERMINATE, client);
- exit(0);
- }
- #endif
- setpgrp(); /* Set up a process group */
- setgid(pw->pw_gid);
- setuid(pw->pw_uid);
- sprintf(mail, "MAIL=/usr/mail/%s", user);
- sprintf(path, "PATH=:/usr/ucb:/bin:/usr/bin");
- sprintf(logname, "LOGNAME=%s", user);
- sprintf(shell, "SHELL=%s", pw->pw_shell);
- sprintf(home, "HOME=%s", pw->pw_dir);
- putenv(home); putenv(path); putenv(shell);
- putenv(mail); putenv(logname);
- putenv(term);
- chdir(pw->pw_dir);
- if(debug) {
- fprintf(stderr, "Server request from %s\n", getenv("LOGNAME"));
- }
- server[PIDMSB] = (pid >> 8) & 0xff;
- server[PIDLSB] = pid & 0xff;
- oldnet = ethernet; /* save old port for a bit */
- if(configure(server, 3, getpid()) == -1) { /* We are this address */
- ethernet = oldnet; /* Use old port */
- sprintf(r->r_data, "Can't allocate port");
- send(r, strlen(r->r_data), TERMINATE, client);
- exit(1);
- }
- close(oldnet); /* OK - use the new port */
- /*
- * Inform the client of our new address
- */
- memcpy(r->r_data, mynode, ETHERSIZE);
- send(r, ETHERSIZE, ACCEPT, client);
- /*
- * Get the command which the client wishes us to execute
- */
- recv(r);
- memcpy(cmd, r->r_data, r->r_size);
- /*
- * Special cases:
- * "login" - user wants a real login - use the PC-Interface pttys
- * "fileserver" - user wants to transfer files.
- */
- if(!strcmp(cmd, "login")) return(dologin(r));
- if(!strcmp(cmd, "fileserver")) return(fileserver(r));
- /*
- * Now start off the child process, and collect it's output
- */
- pipe(input);
- pipe(output);
- if(sh = fork()) {
- close(input[WT]);
- close(output[RD]);
- writer = getpid();
- if(reader = fork()) {
- ok = 1;
- signal(SIGPIPE, endproc);
- while(ok) {
- recv(r);
- if(debug) {
- fprintf(stderr, "server: got [%s] from %s\n",
- r->r_data, ipaddr(r->r_port.srcaddr));
- }
- ok = passon(r, output[WT]);
- }
- sigterm();
- }
- else {
- signal(SIGTERM, SIG_DFL);
- while((n = read(input[RD], r->r_data, sizeof r->r_data)) != -1) {
- send(r, n, DATA, client);
- if(debug) {
- fprintf(stderr, "server: %s sent to %s\n",
- r->r_data, ipaddr(client));
- }
- }
- sprintf(r->r_data, "hangup\n");
- send(r, strlen(r->r_data), TERMINATE, client);
- skill(writer, SIGKILL);
- exit(0);
- }
- }
- else doexec(r); /* exec the child shell */
- }
- /*
- * doexec: perform exec of requested procedure
- */
- doexec(r)
- struct request *r;
- {
- char *argv[6];
- split(cmd, argv);
- close(0); close(1); close(2);
- /*
- * Duplicate READ side of output as stdin
- */
- if(dup(output[RD]) != 0) perror("dup(input) != 0");
- /*
- * Duplicate WRITE side of input as stdout & stderr
- */
- if(dup(input[WT]) != 1) perror("dup(output) != 1");
- if(dup(input[WT]) != 2) perror("dup(output) != 2");
- /*
- * close all the parent's pipes - they're duplicated
- */
- close(input[0]); close(input[1]);
- close(output[0]); close(output[1]);
- close(ethernet);
- signal(SIGINT, SIG_DFL);
- signal(SIGQUIT, SIG_DFL);
- execvp(program, argv);
- sprintf(r->r_data, "Cannot exec %s\n", cmd);
- send(r, strlen(r->r_data), DATA, client);
- exit(1);
- }
- split(p, argv)
- register char *p;
- char **argv;
- {
- int n = 1;
- char *f;
- static char name[16];
- argv[0] = p;
- while(*p) {
- if(*p == ' ') {
- *p++ = '\0';
- while(*p == ' ') p++;
- argv[n++] = p;
- }
- else p++;
- }
- strcpy(program, argv[0]);
- if(f = strrchr(argv[0], '/')) f++;
- else f = argv[0];
- sprintf(name, "-%s", f);
- argv[0] = name;
- argv[n++] = NULL;
- }
-
-