home *** CD-ROM | disk | FTP | other *** search
- /* Public domain. */
-
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/file.h>
- #include <signal.h>
- #include <fcntl.h>
- #include "dupdup.h"
- #include "malloc.h"
- #include "errno.h"
- #include "username.h"
- #include "env.h"
- #include "getopt.h"
- #include "numfiles.h"
-
- #ifndef F_LOCK
- #define F_LOCK 1
- #endif
- #ifndef O_RDONLY
- #define O_RDONLY 0
- #endif
- #ifndef O_WRONLY
- #define O_WRONLY 1
- #endif
- #ifndef O_RDWR
- #define O_RDWR 2
- #endif
-
- static int flagverbose = 1;
-
- static char errbuf[500];
- void die(n,s) int n; char *s;
- { if (flagverbose) fprintf(stderr,"npipeclient: fatal: %s\n",s); exit(n); }
- void dies(n,s,t) int n; char *s; char *t;
- { if (flagverbose) fprintf(stderr,"npipeclient: fatal: %s%s\n",s,t); exit(n); }
- void diep(n,s) int n; char *s;
- { if (flagverbose) sprintf(errbuf,"npipeclient: fatal: %s",s); perror(errbuf); exit(n); }
- void warnp(s) char *s;
- { if (flagverbose) sprintf(errbuf,"npipeclient: warning: %s",s); perror(errbuf); }
- void warnsp(s,t) char *s; char *t;
- { if (flagverbose) sprintf(errbuf,"npipeclient: warning: %s%s",s,t); perror(errbuf); }
-
- main(argc,argv,envp)
- int argc;
- char *argv[];
- char *envp[];
- {
- int *d;
- int numfiles;
- int arguid;
- int uid;
- int i;
- static char npipelocal[200];
- static char npiperemote[300];
- int fdserv;
- int fdlock;
- int fds2c;
- int fdc2s;
- char fnlock[200];
- char fns2c[200];
- char fnc2s[200];
- char fnserv[200];
- int m;
- int n;
- int r;
- char buf[100];
- char *uname;
- int pid;
- int opt;
-
- pid = getpid();
-
- while ((opt = getopt(argc,argv,"qQ")) != EOF)
- switch(opt)
- {
- case 'q':
- flagverbose = 0; break;
- case 'Q':
- flagverbose = 1; break;
- case '?':
- break; /*XXX*/
- default:
- break; /*XXX*/
- }
- argc -= optind; argv += optind;
-
- if (argc < 3)
- die(1,"need at least three arguments");
-
- uid = getuid();
- if (username2uid(argv[0],&arguid) == -1)
- dies(2,"cannot figure out username ",argv[0]);
- /* XXX: any permission checks? */
-
- for (i = 0;argv[0][i];++i)
- if ((argv[0][i] == '/') || (argv[0][i] == ':') || (argv[0][i] == '.') || (argv[0][i] == '\n'))
- dies(4,"illegal characters in username ",argv[0]);
-
- for (i = 0;argv[1][i];++i)
- if ((argv[1][i] == '/') || (argv[1][i] == '.') || (argv[0][i] == '\n'))
- dies(5,"illegal characters in service ",argv[1]);
-
- close(6);
- close(7); /* XXX: these have implications that should be documented */
-
- signal(SIGPIPE,SIG_IGN);
-
- if (uid2username(uid,&uname) == -1) /* will never happen */
- die(2,"cannot figure out my own username");
-
- numfiles = NUMFILES;
- d = (int *) malloc(numfiles * sizeof(int));
- if (!d)
- die(6,"cannot malloc");
- for (i = 0;i < numfiles;++i)
- d[i] = -1;
-
- if (strlen(NPIPEDIR) + strlen(argv[0]) + strlen(argv[1]) + 1 > 90) /*XXX*/
- die(8,"server filenames too long");
- sprintf(fnserv,"%s/%ds%s",NPIPEDIR,arguid,argv[1]);
- sprintf(fnlock,"%s/%dl%s",NPIPEDIR,arguid,argv[1]);
- sprintf(fns2c,"%s/s2c.%d",NPIPEDIR,pid);
- sprintf(fnc2s,"%s/c2s.%d",NPIPEDIR,pid);
- sprintf(buf,"%d",pid);
- n = strlen(buf);
- if (n + strlen(uname) + 10 > sizeof(buf))
- die(8,"username too long");
- strcpy(buf + n + 1,uname);
- n += strlen(uname) + 2;
-
- if (env_init() == -1)
- die(11,"cannot init environment");
- if (env_put("PROTO=NPIPE") == -1)
- die(11,"out of memory putting PROTO into environment");
- sprintf(npipelocal,"NPIPELOCAL=%s",uname);
- if (env_put(npipelocal) == -1)
- die(11,"out of memory putting NPIPELOCAL into environment");
- sprintf(npiperemote,"NPIPEREMOTE=%s:%s",argv[0],argv[1]);
- if (env_put(npiperemote) == -1)
- die(11,"out of memory putting NPIPEREMOTE into environment");
-
- /* XXX: fork? not necessary here */
-
- /* Action! */
-
- fdlock = open(fnlock,O_RDWR,0);
- if (fdlock == -1)
- diep(1,"cannot open lock file");
- /* Here's the tricky bit: file locking. :-( */
- /* XXX: We assume that anyone with named pipes also has lockf(). */
- if (lockf(fdlock,F_LOCK,1) == -1)
- diep(1,"cannot wait for lock on lock file");
-
- fdserv = open(fnserv,O_WRONLY,0);
- if (fdserv == -1)
- diep(1,"cannot open server's named pipe");
-
- if (mknod(fns2c,010600,0) == -1)
- diep(1,"cannot create server-to-client pipe");
- if (mknod(fnc2s,010600,0) == -1)
- {
- unlink(fns2c);
- diep(1,"cannot create client-to-server pipe");
- }
-
- m = 0;
- r = 0;
- while ((m < n) && ((r = write(fdserv,buf + m,n - m)) > 0))
- m += r;
- if (r <= 0)
- {
- unlink(fnc2s);
- unlink(fns2c);
- die(1,"cannot write pid and username to server");
- }
- close(fdserv); /*XXX*/
-
- fds2c = open(fns2c,O_RDONLY,0); /* blocks */
- unlink(fns2c);
- if (fds2c == -1)
- {
- unlink(fnc2s);
- die(1,"cannot open server-to-client pipe");
- }
- fdc2s = open(fnc2s,O_WRONLY,0); /* blocks */
- unlink(fnc2s);
- if (fdc2s == -1)
- die(1,"cannot open client-to-server pipe");
-
- if (read(fds2c,buf,1) < 1)
- diep(1,"cannot read from server-to-client pipe");
-
- close(fdlock);
-
- /* Now put fds2c into descriptor 6 and fdc2s into descriptor 7. */
- /* XXX: should check that fdc2s and fds2c are small enough */
- d[fds2c] = 6;
- d[fdc2s] = 7;
- if (dupdup(d,numfiles) == -1)
- diep(10,"cannot dup connection to server");
-
- if (setreuid(uid,uid) == -1)
- diep(1,"cannot setreuid"); /* will never happen */
- signal(SIGPIPE,SIG_DFL);
- execvp(argv[2],argv + 2);
- warnsp("cannot exec ",argv[2]);
- exit(1);
- }
-