#ifndef lint static char sccsid[] = "@(#)efsd.c 4.2 10/10/82"; #endif #include #include #include #include #include #include #include #include #include #include #include #include #define EXIT (1) #define NO_EXIT (2) #define dprintf if(debug) printf2("efsd: "); \ if(debug) printf2 #define efserror(f, exit) {efssenderror(f, exit); break;} extern errno; char *raddr(); int options = SO_ACCEPTCONN|SO_KEEPALIVE|SO_DONTLINGER; struct sockaddr_in sin = { AF_INET, IPPORT_EFSSERVER }; int debug = 0; main(argc, argv) int argc; char **argv; { union wait status; int f; struct sockaddr_in from; #ifndef DEBUG if (fork()) exit(0); for (f = 0; f < 10; f++) (void) close(f); (void) open("/", 0); (void) dup2(0, 1); (void) dup2(0, 2); { int tt = open("/dev/tty", 2); if (tt > 0) { ioctl(tt, TIOCNOTTY, 0); close(tt); } } #endif #if vax sin.sin_port = htons(sin.sin_port); #endif argc--, argv++; if (argc > 0 && !strcmp(argv[0], "-d")) { options |= SO_DEBUG; debug = 1; } nice(-4); /* give it some help */ for (;;) { f = socket(SOCK_STREAM, 0, &sin, options); if (f < 0) { perror("socket"); sleep(5); continue; } if (accept(f, &from) < 0) { perror("accept"); if(close(f) < 0) perror("close"); sleep(1); continue; } if (fork() == 0) doit(f, &from); if(close(f) < 0) perror("close"); while (wait3(status, WNOHANG, 0) > 0) continue; } } char bigbuffer[32*1024]; /* is this big enough? */ extern errno; struct efs_controlblock cb, retcb; char *getpath(); doit(f, fromp) int f; struct sockaddr_in *fromp; { char *rhost; short int mode, uid, gid, cmask; short int owner, group; register int i; long int offset, count, size, len; char *path; int fd; struct stat statb; #if vax fromp->sin_port = htons(fromp->sin_port); #endif rhost = raddr(fromp->sin_addr.s_addr); if (fromp->sin_family != AF_INET || /* fromp->sin_port >= IPPORT_RESERVED || NOT FOR NOW */ rhost == 0) abort("connection invalid"); for(;;) { if(read(f, &cb, sizeof cb) != sizeof cb) abort("efsd: read1"); dprintf("\ncmd: %d\n", cb.efs_cmd); switch(cb.efs_cmd) { case EFS_OPEN: case EFS_CREAT: mode = ntohs(cb.efs_mode); uid = ntohs(cb.efs_uid); gid = ntohs(cb.efs_gid); for(i = 0; i < (sizeof cb.efs_grps)/(sizeof(int)); i++) cb.efs_grps[i] = ntohl(cb.efs_grps); cmask = ntohs(cb.efs_cmask); path = getpath(f); if(path == NULL || strlen(path) <= 0) { errno = ENOENT; efserror(f, EXIT); } dprintf("O/C mode=%o,uid=%d,gid=%d,cmask=%o,path=%s\n", mode, uid, gid, cmask, path); umask(cmask); setgid(gid); setgrp(cb.efs_grps, 0); setuid(uid); if(cb.efs_cmd == EFS_OPEN) { if((fd = open(path, mode)) < 0) efserror(f, EXIT); } else if((fd = creat(path, mode)) < 0) efserror(f, EXIT); size = lseek(fd, 0L, 2); /* pass size back */ dprintf("O/C succeeded. size=%d\n", size); retcb.efs_size = htonl(size); retcb.efs_cmd = EFS_OK; efswrite(f, &retcb, sizeof retcb); break; case EFS_CLOSE: if(close(fd) < 0) { efserror(f, NO_EXIT); } else { retcb.efs_cmd = EFS_OK; efswrite(f, &retcb, sizeof retcb); } exit(0); case EFS_READ: offset = ntohl(cb.efs_offset); count = ntohl(cb.efs_count); if(count > sizeof bigbuffer) abort("EFS_READ: buffer too small"); if(lseek(fd, offset, 0) < 0) { dprintf("efs_read, lseek to %d failed\n", offset); efserror(f, NO_EXIT); } if((len = read(fd, bigbuffer, count)) < 0) { dprintf("efs_read, read %d failed\n", count); efserror(f, NO_EXIT); } dprintf("read returns %d\n", len); retcb.efs_size = htonl(len); retcb.efs_cmd = EFS_OK; efswrite(f, &retcb, sizeof retcb); efswrite(f, bigbuffer, len); break; case EFS_WRITE: offset = ntohl(cb.efs_offset); count = ntohl(cb.efs_count); if(count > sizeof bigbuffer) abort("EFS_WRITE: buffer too small"); if(lseek(fd, offset, 0) < 0) efserror(f, NO_EXIT); if(read(f, bigbuffer, count) != count) abort("efsd: read2"); if((len = write(fd, bigbuffer, count)) < 0) efserror(f, NO_EXIT); retcb.efs_cmd = EFS_OK; retcb.efs_size = htonl(len); efswrite(f, &retcb, sizeof retcb); break; case EFS_IOCTL: if(ioctl(fd, FIONREAD, &size) < 0) efserror(f, NO_EXIT); retcb.efs_cmd = EFS_OK; retcb.efs_size = htonl(size); efswrite(f, &retcb, sizeof retcb); break; case EFS_FSTAT: if(fstat(fd, &statb) < 0) efserror(f, NO_EXIT); retcb.efs_cmd = EFS_OK; efswrite(f, &retcb, sizeof retcb); /* THIS IS NOT PORTABLE -- SHOULD htonl EACH FIELD */ efswrite(f, &statb, sizeof statb); break; case EFS_STAT: case EFS_LSTAT: uid = ntohs(cb.efs_uid); gid = ntohs(cb.efs_gid); for(i = 0; i < (sizeof cb.efs_grps)/(sizeof(int)); i++) cb.efs_grps[i] = ntohl(cb.efs_grps); path = getpath(f); if(path == NULL || strlen(path) <= 0) { errno = ENOENT; efserror(f, EXIT); } setgid(gid); setgrp(cb.efs_grps, 0); setuid(uid); if(cb.efs_cmd == EFS_STAT) { if(stat(path, &statb) < 0) efserror(f, EXIT); } else if(lstat(path, &statb) < 0) efserror(f, EXIT); retcb.efs_cmd = EFS_OK; efswrite(f, &retcb, sizeof retcb); /* THIS IS NOT PORTABLE -- SHOULD htonl EACH FIELD */ efswrite(f, &statb, sizeof statb); exit(0); /* once only function */ case EFS_UNLINK: uid = ntohs(cb.efs_uid); gid = ntohs(cb.efs_gid); for(i = 0; i < (sizeof cb.efs_grps)/(sizeof(int)); i++) cb.efs_grps[i] = ntohl(cb.efs_grps); path = getpath(f); if(path == NULL || strlen(path) <= 0) { errno = ENOENT; efserror(f, EXIT); } setgid(gid); setgrp(cb.efs_grps, 0); setuid(uid); if(unlink(path) < 0) efserror(f, EXIT); retcb.efs_cmd = EFS_OK; efswrite(f, &retcb, sizeof retcb); exit(0); /* once only function */ case EFS_READLINK: uid = ntohs(cb.efs_uid); gid = ntohs(cb.efs_gid); for(i = 0; i < (sizeof cb.efs_grps)/(sizeof(int)); i++) cb.efs_grps[i] = ntohl(cb.efs_grps); path = getpath(f); if(path == NULL || strlen(path) <= 0) { errno = ENOENT; efserror(f, EXIT); } setgid(gid); setgrp(cb.efs_grps, 0); setuid(uid); if((len = readlink(path, bigbuffer, sizeof bigbuffer)) < 0) efserror(f, EXIT); retcb.efs_cmd = EFS_OK; retcb.efs_size = htonl(len); efswrite(f, &retcb, sizeof retcb); efswrite(f, bigbuffer, len); exit(0); /* once only function */ case EFS_CHMOD: uid = ntohs(cb.efs_uid); gid = ntohs(cb.efs_gid); for(i = 0; i < (sizeof cb.efs_grps)/(sizeof(int)); i++) cb.efs_grps[i] = ntohl(cb.efs_grps); mode = ntohs(cb.efs_mode); path = getpath(f); if(path == NULL || strlen(path) <= 0) { errno = ENOENT; efserror(f, EXIT); } setgid(gid); setgrp(cb.efs_grps, 0); setuid(uid); if(chmod(path, mode) < 0) efserror(f, EXIT); retcb.efs_cmd = EFS_OK; efswrite(f, &retcb, sizeof retcb); exit(0); /* once only function */ case EFS_CHOWN: uid = ntohs(cb.efs_uid); gid = ntohs(cb.efs_gid); for(i = 0; i < (sizeof cb.efs_grps)/(sizeof(int)); i++) cb.efs_grps[i] = ntohl(cb.efs_grps); owner = ntohs(cb.efs_owner); group = ntohs(cb.efs_group); path = getpath(f); if(path == NULL || strlen(path) <= 0) { errno = ENOENT; efserror(f, EXIT); } setgid(gid); setgrp(cb.efs_grps, 0); setuid(uid); if(chown(path, owner, group) < 0) efserror(f, EXIT); retcb.efs_cmd = EFS_OK; efswrite(f, &retcb, sizeof retcb); exit(0); /* once only function */ case EFS_ACCESS: uid = ntohs(cb.efs_uid); gid = ntohs(cb.efs_gid); for(i = 0; i < (sizeof cb.efs_grps)/(sizeof(int)); i++) cb.efs_grps[i] = ntohl(cb.efs_grps); mode = ntohs(cb.efs_mode); path = getpath(f); if(path == NULL || strlen(path) <= 0) { errno = ENOENT; efserror(f, EXIT); } setgid(gid); setgrp(cb.efs_grps, 0); setuid(uid); if(access(path, mode) < 0) efserror(f, EXIT); retcb.efs_cmd = EFS_OK; efswrite(f, &retcb, sizeof retcb); exit(0); /* once only function */ case EFS_UTIME: uid = ntohs(cb.efs_uid); gid = ntohs(cb.efs_gid); for(i = 0; i < (sizeof cb.efs_grps)/(sizeof(int)); i++) cb.efs_grps[i] = ntohl(cb.efs_grps); cb.efs_time[0] = ntohl(cb.efs_time[0]); cb.efs_time[1] = ntohl(cb.efs_time[1]); path = getpath(f); if(path == NULL || strlen(path) <= 0) { errno = ENOENT; efserror(f, EXIT); } setgid(gid); setgrp(cb.efs_grps, 0); setuid(uid); if(utime(path, cb.efs_time) < 0) efserror(f, EXIT); retcb.efs_cmd = EFS_OK; efswrite(f, &retcb, sizeof retcb); exit(0); /* once only function */ } } } char pathbuf[MAXPATHLEN]; char *getpath(f) int f; { register char *cp; char c; for(cp = pathbuf; cp < &pathbuf[MAXPATHLEN]; cp++) { if(read(f, &c, 1) < 0) abort("getpath: read1"); *cp = c; if(c == '\0') return(pathbuf); } abort("getpath: file name too long"); } efswrite(f, addr, size) int f; char *addr; int size; { dprintf("efswrite: size=%d\n", size); if(write(f, addr, size) != size) abort("efswrite"); dprintf("\twrite done\n"); } efssenderror(f, exitflag) int f, exitflag; { dprintf("efssenderror: errno=%d\n", errno); retcb.efs_cmd = EFS_ERROR; retcb.efs_error = errno; efswrite(f, &retcb, sizeof retcb); if(exitflag == EXIT) exit(0); } abort(str) char *str; { perror(str); exit(1); } printf2(s, a, b, c, d, e, f, g, h) char *s; { fprintf(stderr, s, a, b, c, d, e, f, g, h); }