home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume14 / 3bconnect / server.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-05-08  |  6.0 KB  |  262 lines

  1. /*
  2.  * Copyright (C) 1988 Dave Settle. All rights reserved.
  3.  * Permission is granted to use, copy and modify this software, providing
  4.  * that it is not sold for profit, and that this copyright notice is retained
  5.  * in any copies of the source.
  6.  */
  7. /*
  8.  * server: ethernet server. Accepts requests, and spawns processes to
  9.  * serve remote clients.
  10.  */
  11.  
  12. #include <sys/ni.h>
  13. #include <stdio.h>
  14. #include <sys/signal.h>
  15. #include <sys/errno.h>
  16. extern int errno;
  17. #include <pwd.h>
  18.  
  19. struct passwd *getpwnam();
  20. char *strrchr();
  21.  
  22. #define MAIN
  23. #include "ni.h"
  24.  
  25. int input[2], output[2];        /* pipes for shell */
  26. char cmd[128], program[32];
  27. int reader, sh;                /* pid of child reader process */
  28.  
  29. #define LOG  "/usr/lib/server.log"
  30.  
  31. #define GIGABYTE    2*1024*1024    /* number of blocks in 1 GByte */
  32.  
  33. /*
  34.  * endproc: called when the shell has died (via SIGPIPE) by the writer process
  35.  */
  36. endproc(){
  37.     struct request req;
  38.     skill(reader, SIGTERM);
  39.     sprintf(req.r_data, "your shell died");
  40.     send(&req, strlen(req.r_data), TERMINATE, client);
  41.     exit(0);
  42. }
  43. /*
  44.  * Called when we get a TERMINATE packet from the client.
  45.  */
  46. sigterm(){    
  47.     skill(reader, SIGTERM);
  48.     skill(sh, SIGHUP);
  49.     sleep(1);
  50.     skill(sh, SIGKILL);
  51.     exit(0);
  52. }
  53.  
  54. main()
  55. {
  56.     int in;
  57.     signal(SIGHUP, SIG_IGN);
  58.     signal(SIGINT, SIG_IGN);
  59.     signal(SIGQUIT, SIG_IGN);
  60.     signal(SIGTERM, sigterm);
  61.     ulimit(2, (long) GIGABYTE);
  62. /*
  63.  * This process runs from "init" - it doesn't have ANY file descriptors open
  64.  * Check this, and if necessary, create some dummy fd's.
  65.  */
  66.      if(in = open("/dev/null", 0) == 0) {
  67.          open("/dev/null", 1);
  68.          open("/dev/null", 1);
  69.      }
  70.      else close(in);
  71.     freopen(LOG, "a+", stderr);
  72.     if(configure(server, 2, 0) == -1) exit(1);
  73.      accept();
  74.      return(0);
  75. }
  76. accept(){
  77.     struct request request;
  78.      recv(&request);
  79. /*
  80.  * Fork off child to deal with the request. We die, and are respawned by
  81.  * init.
  82.  */
  83.      if(fork() == 0) exit(serve(&request));
  84. /*
  85.  * parent - exit.
  86.  */
  87.      return(0);
  88. }
  89. /*
  90.  * serve: set up a shell for the remote process, and pass data.
  91.  */
  92. #define RD 0
  93. #define WT 1
  94. serve(r)
  95. register struct request *r;
  96. {
  97.     int pid = getpid(), writer, n, uid, ok;
  98.     int oldnet;
  99.     char user[32];
  100.     struct passwd *pw;
  101.     char home[32], path[128], shell[16], mail[64], term[32], logname[64];
  102. /*
  103.  * Get the user info from the request header, and set our parameters
  104.  */    
  105.     n = sscanf(r->r_data, "%d %s %s", &uid, user, term);
  106.     memcpy(client, r->r_port.srcaddr, ETHERSIZE);
  107.     pw = getpwnam(user);
  108.     if(pw == NULL) {
  109.         n = sprintf(r->r_data, "User '%s' not known here", user);
  110.         send(r, n, TERMINATE, client);
  111.         exit(0);
  112.     }
  113.     if(pw->pw_uid != uid) {
  114.         n = sprintf(r->r_data, "User '%s' and uid '%d' don't match",
  115.             user, uid);
  116.         send(r, n, TERMINATE, client);
  117.         exit(0);
  118.     }
  119. #ifdef SECURE
  120.     if(uid == 0) {
  121.         n = sprintf(r->r_data, "Secure server: root access not allowed");
  122.         send(r, n, TERMINATE, client);
  123.         exit(0);
  124.     }
  125. #endif
  126.     setpgrp();            /* Set up a process group */
  127.     setgid(pw->pw_gid);
  128.     setuid(pw->pw_uid);
  129.     sprintf(mail, "MAIL=/usr/mail/%s", user);
  130.     sprintf(path, "PATH=:/usr/ucb:/bin:/usr/bin");
  131.     sprintf(logname, "LOGNAME=%s", user);
  132.     sprintf(shell, "SHELL=%s", pw->pw_shell);
  133.     sprintf(home, "HOME=%s", pw->pw_dir);
  134.     putenv(home); putenv(path); putenv(shell); 
  135.     putenv(mail); putenv(logname);
  136.     putenv(term);
  137.     chdir(pw->pw_dir);
  138. if(debug) {
  139.     fprintf(stderr, "Server request from %s\n", getenv("LOGNAME"));
  140. }
  141.     server[PIDMSB] = (pid >> 8) & 0xff;
  142.     server[PIDLSB] = pid & 0xff;
  143.     oldnet = ethernet;            /* save old port for a bit */
  144.     if(configure(server, 3, getpid()) == -1) {    /* We are this address */
  145.         ethernet = oldnet;        /* Use old port */
  146.         sprintf(r->r_data, "Can't allocate port");
  147.         send(r, strlen(r->r_data), TERMINATE, client);
  148.         exit(1);
  149.     }
  150.     close(oldnet);                /* OK - use the new port */
  151. /*
  152.  * Inform the client of our new address
  153.  */
  154.     memcpy(r->r_data, mynode, ETHERSIZE);
  155.     send(r, ETHERSIZE, ACCEPT, client);
  156. /*
  157.  * Get the command which the client wishes us to execute
  158.  */
  159.      recv(r);
  160.      memcpy(cmd, r->r_data, r->r_size);
  161. /*
  162.  * Special cases: 
  163.  *    "login" - user wants a real login - use the PC-Interface pttys
  164.  *    "fileserver" - user wants to transfer files.
  165.  */
  166.      if(!strcmp(cmd, "login")) return(dologin(r));
  167.      if(!strcmp(cmd, "fileserver")) return(fileserver(r));
  168. /*
  169.  * Now start off the child process, and collect it's output
  170.  */
  171.      pipe(input);
  172.      pipe(output);
  173.      if(sh = fork()) {
  174.          close(input[WT]);
  175.          close(output[RD]);
  176.          writer = getpid();
  177.          if(reader = fork()) {
  178.              ok = 1;
  179.              signal(SIGPIPE, endproc);
  180.              while(ok) {
  181.                  recv(r);
  182. if(debug) {
  183.                  fprintf(stderr, "server: got [%s] from %s\n",
  184.                      r->r_data, ipaddr(r->r_port.srcaddr));
  185. }
  186.                 ok = passon(r, output[WT]);
  187.              }
  188.             sigterm();
  189.          }
  190.          else {
  191.              signal(SIGTERM, SIG_DFL);
  192.              while((n = read(input[RD], r->r_data, sizeof r->r_data)) != -1) {
  193.                  send(r, n, DATA, client);
  194. if(debug) {
  195.                  fprintf(stderr, "server: %s sent to %s\n",
  196.                      r->r_data, ipaddr(client));
  197. }
  198.              }
  199.              sprintf(r->r_data, "hangup\n");
  200.              send(r, strlen(r->r_data), TERMINATE, client);
  201.              skill(writer, SIGKILL);
  202.              exit(0);
  203.          }
  204.      }
  205.      else doexec(r);        /* exec the child shell */
  206. }    
  207. /*
  208.  * doexec: perform exec of requested procedure
  209.  */
  210. doexec(r)
  211. struct request *r;
  212. {
  213.     char *argv[6];
  214.     split(cmd, argv);
  215.      close(0); close(1); close(2);
  216. /*
  217.  * Duplicate READ side of output as stdin
  218.  */
  219.      if(dup(output[RD]) != 0) perror("dup(input) != 0");
  220. /*
  221.  * Duplicate WRITE side of input as  stdout & stderr
  222.  */
  223.      if(dup(input[WT]) != 1) perror("dup(output) != 1");
  224.      if(dup(input[WT]) != 2) perror("dup(output) != 2");
  225. /*
  226.  * close all the parent's pipes - they're duplicated
  227.  */
  228.     close(input[0]); close(input[1]);
  229.     close(output[0]); close(output[1]);
  230.     close(ethernet);
  231.     signal(SIGINT, SIG_DFL);
  232.     signal(SIGQUIT, SIG_DFL);
  233.     execvp(program, argv);
  234.     sprintf(r->r_data, "Cannot exec %s\n", cmd);
  235.     send(r, strlen(r->r_data), DATA, client);
  236.     exit(1);
  237. }
  238. split(p, argv)
  239. register char *p;
  240. char **argv;
  241. {    
  242.     int n = 1;
  243.     char *f;
  244.     static char name[16];
  245.     argv[0] = p;
  246.     while(*p) {
  247.         if(*p == ' ') {
  248.             *p++ = '\0';
  249.             while(*p == ' ') p++;
  250.             argv[n++] = p;
  251.         }
  252.         else p++;
  253.     }
  254.     strcpy(program, argv[0]);
  255.     if(f = strrchr(argv[0], '/')) f++;
  256.     else f = argv[0];
  257.     sprintf(name, "-%s", f);
  258.     argv[0] = name;
  259.     argv[n++] = NULL;
  260. }
  261.  
  262.