📄 serv_p4.c
字号:
#include "p4.h"#include "p4_sys.h"/****#include <stdio.h>#include <ctype.h>#include <pwd.h>#include <errno.h>#include <signal.h>#include <netdb.h>#include <sys/socket.h>#include <sys/types.h>#include <netinet/in.h>#include <arpa/inet.h>#include <time.h>****/#include <sys/stat.h>#include <sys/file.h>#include <sys/ioctl.h>#ifdef _AIX#include <sys/wait.h>#endifextern char *inet_ntoa ( struct in_addr ); /* from <arpa/inet.h> */#ifdef FOO/* These are in p4_sys.h, done better */#ifdef P4BSD#include <strings.h>#endif#ifdef P4SYSV#include <string.h>#endif#endif#if defined(SYMMETRY)#define NEED_GETOPT#endif#ifdef NEED_GETOPT/* This is from the released BSD sources lib/libc/getopt.c *//* * get option letter from argument vector */int opterr = 1, /* if error message should be printed */ optind = 1, /* index into parent argv vector */ optopt; /* character checked for validity */char *optarg; /* argument associated with option */#elseextern char *optarg;#endif#define MAXARGS 256#ifndef LOGFILE#define LOGFILE "/usr/adm/serv_p4.log"#endif#define notice2(a,b) {sprintf(tmpbuf, a, b); notice(tmpbuf);}#define notice3(a,b,c) {sprintf(tmpbuf, a, b,c); notice(tmpbuf);}#define failure2(a,b) {sprintf(tmpbuf, a, b); failure(tmpbuf);}/* extern char *crypt ( const char *, const char * ); */extern char *crypt();#ifndef HAVE_STRERRORextern char *sys_errlist[];#define strerror(n) sys_errlist[n]#endifextern int errno;char tmpbuf[1024];char *fromhost;char logfile[1024];FILE *logfile_fp;int logfile_fd;#define DEFAULT_PORT 753int daemon_mode;int daemon_port;int daemon_pid; /* pid of parent */int stdfd_closed = 0;int debug = 0;char *this_username;int this_uid;void doit (int);void execute ( char *, char *, int, int, struct hostent * );int getline ( char *, int );void failure ( char * );void notice ( char * );int net_accept ( int );void net_setup_listener ( int, int, int * );void net_setup_anon_listener ( int, int *, int *);void error_check ( int, char * );char *timestamp ( void );char *save_string ( char * );static int connect_to_listener ( struct hostent *, int );void reaper ( int );int main ( int, char ** );/* * Notes on the use of file descriptors (fds) * * This code uses the <stdio> routines to read/write data to the * connected socket. This simplifies much of the code. However, * using stdin/out/err is a problem, since in various modes we may * close those units (for example, in order to start the server with * rsh but have the rsh return when the server starts, it is necessary * to close stdin/out/err). * * Thus, instead of relying on particular * unit numbers for stdin/out/err, we set (change) these values. */int stdin_fd = 0;FILE *stdin_fp = 0; /* = stdin; */int stdout_fd = 1;FILE *stdout_fp = 0; /* = stdout; */int stderr_fd = 2;FILE *stderr_fp = 0; /* = stderr; */void reaper(sigval)int sigval;{ int i; /* For systems where signal does not work (signals one-shot), we need to reinstall the handler. This isn't reliable, since there is a race condition, but it is a small exposure Later versions will use sigaction where available. */ signal(SIGCHLD, reaper); wait(&i);}int main(argc, argv)int argc;char **argv;{ int c; struct sockaddr_in name; int namelen; int pid; /* Initialize the FILE handles */ stdin_fp = stdin; stdout_fp = stdout; stderr_fp = stderr; daemon_pid = getpid(); if (getuid() == 0) { strcpy(logfile, LOGFILE); daemon_port = DEFAULT_PORT; } else { sprintf(logfile, "P4Server.Log.%d", (int)getpid()); daemon_port = 0; debug = 1; } namelen = sizeof(name); if (getpeername(0, (struct sockaddr *) &name, &namelen) < 0) daemon_mode = 1; else daemon_mode = 0; while ((c = getopt(argc, argv, "Ddop:l:")) != EOF) { switch (c) { case 'D': debug++; break; case 'd': daemon_mode++; break; case 'o': /* Orphan mode; I'd use -detach, but old-fashioned getopt wants single letter names */ daemon_mode++; close(0); close(1); close(2); stdfd_closed = 1; pid = fork(); if (pid < 0) { /* We've closed stderr! */ exit(1); } else if (pid > 0) exit(0); /* We're the child, so we continue on */ daemon_pid = getpid(); break; case 'p': daemon_port = atoi(optarg); break; case 'l': strcpy(logfile, optarg); break; case '?': default: fprintf(stderr, "\Usage: %s [-d] [-D] [-p port] [-l logfile] [-o]\n",argv[0]); exit(1); } } if ((logfile_fp = fopen(logfile, "a")) == NULL) { if (getuid() != 0) { fprintf( stdout_fp, "Cannot open logfile, disabling logging\n"); logfile_fp = fopen("/dev/null", "w"); } else { fprintf( stderr, "Cannot open logfile %s: %s\n", logfile, strerror(errno)); exit(1); } } else { if (!stdfd_closed) fprintf( stdout_fp, "Logging to %s\n", logfile); } logfile_fd = fileno( logfile_fp ); setbuf(logfile_fp, NULL); fprintf( logfile_fp, "%s pid=%d starting at %s, logfile fd is %d\n", argv[0], (int)getpid(), timestamp(), logfile_fd ); fflush( logfile_fp ); if (stdfd_closed) { /* redirect stdout and stderr to logfile */ dup2( logfile_fd, 1 ); dup2( logfile_fd, 2 ); } if (daemon_mode) { int lfd, /* lfd is listener fd */ fd, /* fd is accepted connection fd */ pid; /* pid of child when forking a process to handle connection */ signal(SIGCHLD, reaper); if (daemon_port == 0) { net_setup_anon_listener(2, &daemon_port, &lfd); } else { net_setup_listener(2, daemon_port, &lfd); } fprintf( logfile_fp, "Listening on port %d\n", daemon_port ); if ((debug || daemon_port != DEFAULT_PORT) && !stdfd_closed) fprintf( stdout_fp, "Listening on %d\n", daemon_port); if (!debug) { /* Create an orphan process and exit. This is for root use only (debug set to 1 if getuid() != 0) NOTE: Since changes in handling of fd's, this code may no longer work. */ if (fork()) exit(0); for (fd = 0; fd < 10; fd++) if (fd != lfd && fd != logfile_fd) close(fd); #ifdef P4SYSV fd = open ("/dev/console", O_RDWR); if (fd < 0) fd = open ("/dev/tty", O_RDWR); if (fd < 0) fd = open ("/dev/null", O_RDWR);# if defined(CRAY) (void) dup2(0, 1); (void) dup2(0, 2);# else (void) dup2(STDIN_FILENO, STDOUT_FILENO); (void) dup2(STDIN_FILENO, STDERR_FILENO);# endif /* If your system says "too few arguments to function setpgrp" then you do NOT have the SYSV version of this function (that version takes no arguments) */ (void) setpgrp();#else (void) open("/", 0); (void) dup2(0, 1); (void) dup2(0, 2); fd = open("/dev/tty", O_RDWR); if (fd >= 0) { ioctl(fd, TIOCNOTTY, 0); (void) close(fd); }#endif } while (1) { /* Wait for a new connection attempt */ fd = net_accept(lfd); pid = fork(); if (pid < 0) { fprintf( logfile_fp, "Fork failed: %s\n", strerror(errno)); exit(pid); } if (pid == 0) { fprintf( logfile_fp, "Started subprocess for connection at %s with pid %d\n", timestamp(), (int)getpid() );#if defined(HP) (void) setpgrp();#else { int ttyfd = open("/dev/tty",O_RDWR); if (ttyfd >= 0) {# if !defined(CRAY) ioctl(ttyfd, TIOCNOTTY, 0);# endif close(ttyfd); } }#endif /* Make stdin/stdout refer to fd */ if (stdfd_closed) { stdin_fp = fdopen( fd, "r" ); stdout_fp = fdopen( fd, "a" ); stderr_fp = logfile_fp; if (stdin_fp == NULL || stdout_fp == NULL) { fprintf( logfile_fp, "Could not fdopen stdin or out\n" ); exit(1); } close(lfd); doit(fd); } else { close(0); dup2(fd, 0); close(1); dup2(fd, 1); close(2); dup2( logfile_fd, 2); close(lfd); doit(0); } exit(0); } /* We can't close the new fd until we're sure that the fork has successfully started */ /* What we REALLY want to do is close the fd when the child exits */ /* sleep(2); */ close(fd); } } else { doit(0); } }/* This is called (possibly in a subprocess) to process create p4-process * requests. */void doit(fd)int fd;{ struct sockaddr_in name; int namelen; struct hostent *hp; struct passwd *pw; char client_user[80], server_user[80]; char pgm[1024], pgm_args[1024]; char *user_home; int superuser; int valid; FILE *fp; int stdout_port; char stdout_port_str[16]; char filename[1024], progline[1024]; struct stat statbuf, statbuf_pgm, statbuf_apps_entry; this_uid = getuid(); pw = getpwuid(this_uid); if (pw == NULL) { fprintf( logfile_fp, "Cannot get pw entry for user %d\n", this_uid); exit(1); } this_username = save_string(pw->pw_name); if (this_uid != 0) fprintf( logfile_fp, "WARNING: Not run as root\n"); setbuf(stdout_fp, NULL); fprintf( logfile_fp, "Got connection at %s", timestamp()); namelen = sizeof(name); if (getpeername(fd, (struct sockaddr *) &name, &namelen) != 0) { fprintf( logfile_fp, "getpeername failed: %s\n", strerror(errno)); exit(1); } fromhost = inet_ntoa(name.sin_addr); hp = gethostbyaddr((char *) &name.sin_addr, sizeof(name.sin_addr), (int) name.sin_family); if (hp == NULL) failure2("Cannot get remote address for %s", fromhost); fromhost = hp->h_name; if (!getline(client_user, sizeof(client_user))) failure("No client user"); if (!getline(server_user, sizeof(server_user))) failure("No server user"); pw = getpwnam(server_user); if (pw == NULL) failure2("No such user: %s\n", server_user); if (this_uid != 0 && this_uid != pw->pw_uid) failure2("Server is not running as root. Only %s can start processes\n", this_username); user_home = pw->pw_dir; superuser = (pw->pw_uid == 0); fprintf( logfile_fp, "Starting ruserok at %s\n", timestamp() ); valid = ruserok(fromhost, superuser, client_user, server_user); fprintf( logfile_fp, "Completed ruserok at %s\n", timestamp() ); if (valid != 0) { char user_pw[80]; char *xpw; fprintf( stdout_fp, "Password\n"); if (!getline(user_pw, sizeof(user_pw))) failure("No server user"); xpw = crypt(user_pw, pw->pw_passwd); if (strcmp(pw->pw_passwd, xpw) != 0) failure("Invalid password"); fprintf( stdout_fp, "Proceed\n"); } else fprintf( stdout_fp, "Proceed\n"); /* Make sure that the proceed message is delivered */ fflush( stdout_fp ); sprintf(tmpbuf, "authenticated client_id=%s server_id=%s\n", client_user, server_user); notice(tmpbuf); /* At this point, we have an authenticated user. We could accept additional commands beyond just "start program". For example, we could accept "exit", which would allow simpler management of the servers. (Note that we'd have to kill the parent, since we're probably just a forked child). */ /* Get the program to execute */ if (!getline(pgm, sizeof(pgm))) failure("No pgm"); /* Check for key words: %id (give id) %run (run program) %exit (exit) */ if (strcmp( pgm, "%id" ) == 0) { fprintf( stdout_fp, "Port %d for client %s and server user %s\n", daemon_port, client_user, server_user ); exit(0); } else if (strcmp( pgm, "%run" ) == 0) { /* Just get the program */ if (!getline(pgm, sizeof(pgm))) failure("No pgm"); } else if (strcmp( pgm, "%exit" ) == 0) { kill( daemon_pid, SIGINT ); sleep(1); kill( daemon_pid, SIGQUIT ); exit(1); } if (!getline(pgm_args, sizeof(pgm_args))) failure("No pgm args"); notice2("got args %s", pgm_args); if (pgm[0] != '/') failure2("%s is not a full pathname", pgm); if (this_uid == 0) {#if defined(HP) && !defined(SUN_SOLARIS) if (setresuid(-1, pw->pw_uid, -1) != 0) failure2("setresuid failed: %s", strerror(errno));#else#ifndef _AIX if (seteuid(pw->pw_uid) != 0) failure2("seteuid failed: %s", strerror(errno));#endif#endif } #define P4_APP_TEST#ifdef P4_APP_TEST sprintf(filename, "%s/.p4apps", user_home); valid = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -