void authenticate_client(void) { u_char secretlen; u_short userid; if (read(compat_sock, (char *)&userid, sizeof(userid)) != sizeof(userid)) efatal("server read"); userid = ntohs(userid); if (debug) diag("read userid %d", userid); if (read(compat_sock, &secretlen, sizeof(secretlen)) != sizeof(secretlen)) efatal("server read"); if (debug) diag("read secretlen %d", secretlen); if (secretlen != 0) efatal("non-zero secretlen"); if (read(compat_sock, &secretlen, sizeof(secretlen)) != sizeof(secretlen)) efatal("server read"); if (secretlen <= 0 || secretlen >= ANAME_SZ) fatal("bad local name length"); if (read(compat_sock, lname, secretlen) != secretlen) efatal("server read??"); if (debug) diag("local name %s", lname); }
void setup_control(void) { char buf2[BUFSIZ]; int pid; int pv[2]; long ready, readfrom; char sig; int i; (void) signal(SIGINT, SIG_DFL); (void) signal(SIGQUIT, SIG_DFL); (void) signal(SIGTERM, SIG_DFL); if (pipe(pv) < 0) efatal("pipe failed"); pid = fork(); if (pid == -1) efatal("fork failed"); if (pid == 0) { (void) setsid(); (void) close(sigsock); (void) close(pv[0]); dup2(pv[1], 2); (void) close(pv[1]); return; } (void) close(0); (void) close(1); (void) close(2); (void) close(pv[1]); readfrom = (1L<<sigsock) | (1L<<pv[0]); i = 1; ioctl(pv[0], FIONBIO, (char *)&i); do { ready = readfrom; if (select(16, (fd_set *)&ready, (fd_set *)0, (fd_set *)0, (struct timeval *)0) < 0) break; if (ready & (1L<<sigsock)) { if (read(sigsock, &sig, 1) <= 0) readfrom &= ~(1L<<sigsock); else #ifdef NO_KILLPG kill(pid, sig); #else killpg(pid, sig); #endif } if (ready & (1L<<pv[0])) { i = read(pv[0], buf2, sizeof (buf2)); if (i <= 0) { shutdown(sigsock, 1+1); readfrom &= ~(1L<<pv[0]); } else (void) write(sigsock, buf2, i); } } while (readfrom); exit(0); }
void read_config_info (void) { u_char len; if (read(datasock, &len, sizeof(len)) != sizeof(len)) efatal("server read"); if (read(datasock, uniq_str, len) != len) efatal("server read??"); } /* end read_config_info */
str *str_new(void) { str *ret = malloc(sizeof(str)); if (!ret) efatal("malloc"); ret->pos = ret->buf = NULL; ret->size = ret->space = 0; return ret; }
static void ensure_total_space(str *s, size_t space) { //debug("ensure total: %d", space); size_t before = s->space; if (!s->space) s->space = space < 5 ? 5 : space; while (s->space < space) s->space *= ALLOC_FACTOR; if (s->space != before) { if (!(s->buf = realloc(s->buf, s->space))) efatal("realloc"); s->pos = s->buf + s->size; } }
void put_buffer ( char * buffer, int len, int * len2, int fd ) { int error; if ((*len2 = write(datasock, buffer, len)) != len) { error = errno; (void) close(fd); (void) unlink(tempfile); (void) rmdir(tempdir); errno = error; efatal("write", error); } }
void get_buffer ( char * buffer, int * len, int readsize, int fd ) { int error; if ((*len = read(datasock, buffer, readsize)) <= 0) { error = errno; (void) close(fd); (void) unlink(tempfile); (void) rmdir(tempdir); if (len == 0) fatal("premature EOF"); errno = error; efatal("server read", error); } }
/*VARARGS1*/ void diag(const char * fmt, ... ) { char buf[BUFSIZ]; char *ptr; va_list vargs; struct timeval tv; if (gettimeofday(&tv, (struct timezone *)0) < 0) efatal("gettimeofday failed"); (void) sprintf(buf, "%d.%d: ", tv.tv_sec, tv.tv_usec); ptr = buf + strlen(buf); va_start(vargs,fmt); ptr += vsprintf(ptr, fmt, vargs); va_end(vargs); *ptr++ = '\n'; (void) write(errdesc, buf, ptr-buf); }
void transmit_status(void) { unsigned int status; int op; if (debug) diag("sending status %d", exit_status); if ( batch ) { (*header).count = 0; (*header).status = htonl (exit_status); op=1; setsockopt(datasock, IPPROTO_TCP, TCP_NODELAY, (char *)&op , sizeof(op) ); write ( datasock, buf, sizeof(*header) ); op=0; setsockopt(datasock, IPPROTO_TCP, TCP_NODELAY, (char *)&op , sizeof(op) ); } else { status = htonl((unsigned int)exit_status); if (write(datasock, (char *)&status, sizeof(status)) != sizeof(status)) efatal("write failed"); } /* if */ }
void transmit_data(void) { unsigned int count; u_short perm; char *buffer; int bufsize; int fd; struct stat st; int len, len2; int error; char exists; if (debug) diag("sending data"); if ((tempmode&WANT_BACK) == 0) { (void) unlink(tempfile); if (debug) diag("not wanted back"); return; } if (lstat(tempfile, &st) < 0) { if (errno != ENOENT) { error = errno; (void) unlink(tempfile); (void) rmdir(tempdir); errno = error; efatal("lstat", error); } exists = 0; } else { if ((st.st_mode&S_IFMT) != S_IFREG) { (void) unlink(tempfile); (void) rmdir(tempdir); fatal("tempfile no longer a regular file"); } exists = 1; } if (debug) diag("exists %d", exists); if ( ! put_exists ( &exists ) ) { (void) unlink(tempfile); (void) rmdir(tempdir); efatal("write failed"); } if (!exists) { (void) unlink(tempfile); return; } perm = st.st_mode&0777; if (debug) diag("perm %#o", perm); if ( ! put_perm ( &perm ) ) { (void) unlink(tempfile); (void) rmdir(tempdir); efatal("write failed"); } count = st.st_size; if (debug) diag("count %d", count); if ( ! put_count ( &count ) ) { (void) unlink(tempfile); (void) rmdir(tempdir); efatal("write failed"); } count = st.st_size; if (count == 0) { (void) unlink(tempfile); #ifdef notdef (void) rmdir(tempdir); #endif return; } if ((fd = open(tempfile, O_RDONLY, 0)) < 0) { (void) unlink(tempfile); (void) rmdir(tempdir); efatal("open failed"); } if ((bufsize = count) > 10*1024) buffer = (char *) malloc(bufsize = 10*1024); else buffer = (char *) malloc(bufsize); if (buffer == NULL) { (void) unlink(tempfile); (void) rmdir(tempdir); fatal("malloc failed"); } if (debug) diag("bufsize %d", bufsize); while (count != 0) { if (debug) diag("loop count %d", count); if ((len = read(fd, buffer, bufsize)) <= 0) { error = errno; (void) close(fd); (void) unlink(tempfile); (void) rmdir(tempdir); if (len == 0) fatal("1 premature EOF"); errno = error; efatal("server read", error); } if (debug) diag("read %d bytes", len); put_buffer ( buffer, len, &len2, fd ); if (debug) diag("wrote %d bytes", len2); count -= len; if (count < bufsize) bufsize = count; } if (close(fd) < 0) { error = errno; (void) unlink(tempfile); (void) rmdir(tempdir); errno = error; efatal("close"); } (void) free(buffer); (void) unlink(tempfile); if (debug) diag("transfer complete"); }
void receive_data (void) { unsigned int count; u_short perm; char *buffer; int bufsize; int fd; int len, len2; int error; char exists; int readsize; if (debug) diag("receiving data"); if ((tempmode&SEND_OVER) == 0) exists = 0; else if ( ! get_exists ( &exists ) ) efatal("server read failed"); if (debug) diag("exists %d", exists); if (exists) { if ( ! get_perm ( &perm ) ) efatal("server read failed"); if ( ! get_count ( &count ) ) efatal("server read failed"); } else { perm = 0600; count = 0; } concat ( temppath, sizeof(temppath), tempdir, "/", tempfile, NULL ); tempfile = temppath; if (debug) { diag("perm %#o, count %d", perm, count); diag("d: %s f: %s p: %s", tempdir, tempfile, temppath ); } fd = open ( tempfile, O_CREAT | O_RDWR, 0600 ); if (debug) diag("tempfile %s", tempfile); if (fchmod(fd, (mode_t) (perm & ( S_IRWXU | S_IRWXG | S_IRWXO ) ) ) < 0) efatal("fchmod failed"); if (!exists) (void) unlink(tempfile); if (count == 0) { (void) close(fd); return; } /* * should check for space on disk, but could be expensive and unreliable */ if ((bufsize = count) > 10*1024) buffer = (char *) malloc(bufsize = 10*1024); else buffer = (char *) malloc(bufsize); if (buffer == NULL) fatal("malloc failed"); while (count != 0) { if (debug) diag("loop count %d", count); if ( count > bufsize ) readsize = bufsize; else readsize = count; /* if */ get_buffer ( buffer, &len, readsize, fd ); if ((len2 = write(fd, buffer, len)) != len) { error = errno; (void) close(fd); (void) unlink(tempfile); (void) rmdir(tempdir); errno = error; efatal("write", error); } count -= len; if (count < bufsize) bufsize = count; } if (close(fd) < 0) { error = errno; (void) unlink(tempfile); (void) rmdir(tempdir); errno = error; efatal("close"); } (void) free(buffer); if (debug) diag("transfer complete"); } /* end receive_data */
void check_config(void) { char buf[BUFSIZ]; char aclfile[MAXPATHLEN]; char *tools_dir=NULL; char *tree_owner=NULL; char *map_file=NULL; char *cmd; char *p; char *q=(char *)""; FILE *fp; int cmdfound; char *uniq_str_arg; struct stat st; struct passwd *pw; char * bufptr; BOOLEAN matched; int i; char * dummy; if (debug) diag("checking config"); if ( !batch ) { tree_base = *arglist++; tree_owner = *arglist++; } /* if */ cmd = *arglist; if (debug) diag("command: %s", cmd ); if ( strcmp ( cmd, "odexm_begin") == 0 ) { start_batch = 1; return; } /* if */ if ( strcmp ( cmd, "odexm_end") == 0 ) { end_batch = 1; return; } /* if */ if ( first ) { first = FALSE; if ((fp = fopen( conf_file, "r")) == NULL) efatal("fopen %s", conf_file); matched = FALSE; while ( fgets( buf, sizeof(buf), fp ) != NULL) { rm_newline ( buf ); bufptr = (char *) buf; uniq_str_arg = strdup ( nxtarg ( &bufptr, " \t" ) ); if ( strcmp ( uniq_str_arg, uniq_str ) != 0 ) continue; /* if */ matched = TRUE; if ( batch ) tree_base = strdup ( nxtarg ( &bufptr, " \t" ) ); else /* Skip over argument */ dummy = nxtarg ( &bufptr, " \t" ); /* if */ tools_dir = strdup ( nxtarg ( &bufptr, " \t" ) ); if ( batch ) tree_owner = strdup ( nxtarg ( &bufptr, " \t" ) ); else /* Skip over argument */ dummy = nxtarg ( &bufptr, " \t" ); /* if */ map_file = strdup ( nxtarg ( &bufptr, " \t" ) ); break; } /* while */ fclose ( fp ); if ( ! matched ) { sprintf (buf, "No match for unique string %s\nin configuration file %s.\n", uniq_str, conf_file ); fatal (buf); } if (debug) diag("map file %s", map_file ); if (lstat(map_file, &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG) { sprintf(buf, "Invalid odexm map file: %s\n", map_file); fatal(buf); } if (debug) diag("map file mode ok"); if ((pw = getpwnam(tree_owner)) == NULL) fatal("Owner of directory not found"); if (pw -> pw_uid == 0) fatal("Cannot run as root"); if (setgid(pw->pw_gid) < 0) efatal("setgid"); if (setuid(pw->pw_uid) < 0) efatal("setuid"); if (chdir(tree_base) < 0) efatal("chdir"); if (debug) diag("setuid/chdir ok"); (void) concat ( exec_path, sizeof (exec_path), tools_dir, ":/bin:/usr/bin:/usr/ucb", NULL ); if ((fp = fopen(map_file, "r")) == NULL) efatal("map file fopen"); i = 0; while ((p = fgets(buf, sizeof(buf), fp)) != NULL) { if ((q = strrchr (p, '\n')) != NULL) *q = '\0'; q = nxtarg(&p, " \t"); strcpy ( map_data [i].cmd, q ); q = nxtarg(&p, " \t"); strcpy ( map_data [i].bin, q ); q = nxtarg(&p, " \t"); strcpy ( map_data [i].acl, q ); i++; } map_entries = i; (void) fclose(fp); } /* if */ if ( tempslot != 0 && !made_temp_dir ) { made_temp_dir = TRUE; concat ( tempdir, sizeof(tempdir), tree_base, "/#odexmXXXXXX", NULL); if ( opentemp(tempdir, tempdir ) < 0) { efatal("opentemp %s failed", tree_base); } } /* if */ cmdfound = FALSE; if ( strcmp ( cmd, "odexm_cp" ) != 0 ) { for ( i = 0; i < map_entries; i++ ) { if (strcmp( map_data [i].cmd, cmd) == 0) { cmdfound = TRUE; (void) strcpy(aclfile, q); strcpy ( cmdbuf, map_data [i].bin ); } /* if */ } /* for */ if (!cmdfound) { sprintf (buf, "No match for command %s in map file %s.\n", cmd, map_file ); fatal("%s", buf); } if (debug) diag("command %s acl %s temp %s", cmdbuf, aclfile, tempdir); /* if */ } /* if */ if ( !batch ) authenticate_client (); /* if */ }
void read_arglist(void) { int i; u_char byte; u_short count; u_short length; char *sp; char *ep; unsigned int checksum; if (read(compat_sock, &byte, sizeof(byte)) != sizeof(byte)) efatal("read needsecret failed"); if (byte) efatal("request for secret"); if (debug) diag("reading arglist"); if (read(compat_sock, (char *)&count, sizeof(count)) != sizeof(count)) efatal("server read"); count = ntohs(count); if (debug) diag("arglist count %d", count); if ( ( batch && count < 1) || ( !batch && count < 3 ) || count > MAXARGC - 1) fatal("Invalid arg count"); if (read(compat_sock, (char *)&length, sizeof(length)) != sizeof(length)) efatal("server read"); length = ntohs(length); if (debug) diag("arglist length %d", length); if ((int)length > NCARGS) fatal("Arglist too long"); if (read(compat_sock, (char *)&tempslot, sizeof(tempslot)) != sizeof(tempslot)) efatal("server read"); tempslot = ntohs(tempslot); if (debug) diag("tempslot %d", tempslot); if ( ( batch && tempslot >= count) || (!batch && tempslot >= count - 2 ) ) fatal("Invalid temp file index"); if (tempslot != 0) { if (read(compat_sock, (char *)&tempmode, sizeof(tempmode)) != sizeof(tempmode)) efatal("server read"); if (debug) diag("tempmode %d", tempmode); } if (read(compat_sock, (char *)&checksum, sizeof(checksum)) != sizeof(checksum)) efatal("server read"); checksum = ntohl(checksum); if (debug) diag("checksum %x", checksum); memset (args, 0, sizeof(args)); sp = args; ep = args + length; while (ep > sp) { i = ep - sp; i = read(compat_sock, sp, i); if (i < 0) efatal("server read"); else if (i == 0) fatal("read (eof)"); sp += i; } check_arglist ( count, ep, sp, checksum); }
void setup_connections(void) { int i; struct linger linger; struct sockaddr_in s_in; u_short port; u_short sigport; u_short dataport; header = (odexm_header *) buf; /* * setup file descriptors */ for (;;) { errno = 0; i = dup(0); if (i == -1) { efatal("dup failed"); } if (i > 2) break; } errdesc = i; if (dup2(i, 0) < 0) efatal("dup2 #0 failed"); if (dup2(i, 1) < 0) efatal("dup2 #1 failed"); if (dup2(i, 2) < 0) efatal("dup2 #2 failed"); (void) close(i); errdesc = 2; /* * setup main (command) connection */ i = 1; if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, sizeof(i)) < 0) ewarn("setsockopt (SO_KEEPALIVE)"); #ifdef DONT_SO_LINGER if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&i, sizeof(i)) < 0 ) #else linger.l_onoff = 1; linger.l_linger = 60; if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger, sizeof(linger)) < 0) #endif ewarn("setsockopt (SO_LINGER)"); i = sizeof(peername); if (getpeername(0, (struct sockaddr *)&peername, &i) < 0) efatal("getpeername"); i = sizeof(sockname); if (getsockname(0, (struct sockaddr *)&sockname, &i) < 0) efatal("getsockname"); if (debug) diag("connection from %s (%d)", inet_ntoa(peername.sin_addr), ntohs(peername.sin_port)); /* * get flags */ if (read(0, &flags, sizeof(flags)) != sizeof(flags)) efatal("server read"); if ( flags == 1 || flags == 3 ) debug = 1; /* if */ if ( flags > 1 ) batch = 1; /* if */ /* * setup control (signal) connection */ if (read(0, (char *)&sigport, sizeof(sigport)) != sizeof(sigport)) efatal("server read"); sigsock = socket(AF_INET, SOCK_STREAM, 0); if (sigsock < 0) efatal("socket"); memcpy (&s_in, &sockname, sizeof(s_in)); s_in.sin_port = 0; if (bind(sigsock, (struct sockaddr *)&s_in, sizeof(s_in)) < 0) efatal("bind"); i = sizeof(s_in); if (getsockname(sigsock, (struct sockaddr *)&s_in, &i) < 0) efatal("getsockname"); port = s_in.sin_port; if (write(1, (char *)&port, sizeof(port)) != sizeof(port)) efatal("write"); memcpy(&s_in, &peername, sizeof(s_in)); s_in.sin_port = sigport; if (connect(sigsock, (struct sockaddr *)&s_in, sizeof(s_in)) < 0) efatal("connect"); /* * start control process (actually parent) */ setup_control(); /* * safe now for debugging */ /* * setup data transfer connection */ if (debug) diag("reading data port"); if (read(0, (char *)&dataport, sizeof(dataport)) != sizeof(dataport)) efatal("server read"); if (debug) diag("data port %d", ntohs(dataport)); datasock = socket(AF_INET, SOCK_STREAM, 0); if (datasock < 0) efatal("socket"); memcpy(&s_in, &sockname, sizeof(s_in)); s_in.sin_port = 0; if (bind(datasock, (struct sockaddr *)&s_in, sizeof(s_in)) < 0) efatal("bind"); i = sizeof(s_in); if (getsockname(datasock, (struct sockaddr *)&s_in, &i) < 0) efatal("getsockname"); port = s_in.sin_port; if (debug) diag("sending data port %d", ntohs(port)); if (write(1, (char *)&port, sizeof(port)) != sizeof(port)) efatal("write"); memcpy(&s_in, &peername, sizeof(s_in)); s_in.sin_port = dataport; if (connect(datasock, (struct sockaddr *)&s_in, sizeof(s_in)) < 0) efatal("connect"); if (debug) diag("connected to dataport"); if ( batch ) compat_sock = datasock; else compat_sock = 0; /* if */ }
int main(int argc,char **argv) { int i,srv_sock,j,retval,ptype; struct sockaddr_in srv_sa; int clientfds[MAX_CLIENTS]; char *clientsas[MAX_CLIENTS]; int client_cnt = 0; int block_size = 1024; int maxfd = 0; int c; char *srvhost = NULL; short srvport = DEF_SRV_PORT; int proto = DEF_PROTO; int debug = 0; char *buf = NULL; fd_set rfds; fd_set static_rfds; /* grab some quick args, hostname, port, tcp, udp... */ while ((c = getopt(argc,argv,"h:p:tudb:")) != -1) { switch(c) { case 'h': srvhost = optarg; break; case 'p': srvport = atoi(optarg); break; case 't': proto = SOCK_STREAM; break; case 'u': proto = SOCK_DGRAM; fatal("no udp support yet!"); break; case 'd': ++debug; break; case 'b': block_size = atoi(optarg); break; default: break; } } if ((buf = (char *)malloc(sizeof(char)*block_size)) == NULL) { efatal("no memory for data buf"); } if ((retval = fill_sockaddr(srvhost,srvport,&srv_sa)) != 0) { if (retval == -1) { fatal("bad port"); } else { efatal("host lookup failed"); } } /* startup server... */ if ((srv_sock = socket(AF_INET,proto,0)) == -1) { efatal("could not get socket"); } if (bind(srv_sock, (struct sockaddr *)&srv_sa, sizeof(struct sockaddr_in) ) < 0) { efatal("could not bind"); } if (proto == PROTO_TCP) { if (listen(srv_sock,8) < 0) { efatal("could not listen"); } } /* daemonize... */ if (!debug) { daemon(0,0); } for (i = 0; i < MAX_CLIENTS; ++i) { clientfds[i] = -1; clientsas[i] = (char *)malloc(MAX_NAME_LEN + 1); } FD_ZERO(&static_rfds); FD_SET(srv_sock,&static_rfds); maxfd = srv_sock; /* listen and read forever */ while (1) { /* reset fdsets */ memcpy(&rfds,&static_rfds,sizeof(static_rfds)); retval = select(maxfd+1,&rfds,NULL,NULL,NULL); if (retval > 0) { if (FD_ISSET(srv_sock,&rfds)) { struct sockaddr_in client_sin; socklen_t slen; int client_fd; slen = sizeof(client_sin); if ((client_fd = accept(srv_sock, (struct sockaddr *)&client_sin, &slen)) < 0) { warn("accept failed"); } else if (client_cnt >= MAX_CLIENTS) { warn("already at max clients"); } else { /* add new client... */ for (i = 0; i < MAX_CLIENTS; ++i) { if (clientfds[i] == -1) { break; } } clientfds[i] = client_fd; if (client_fd > maxfd) { maxfd = client_fd; } FD_SET(client_fd,&static_rfds); if (debug) { fprintf(stdout, "connect from %s:%d\n", inet_ntoa(client_sin.sin_addr), ntohs(client_sin.sin_port)); } char *addr = inet_ntoa(client_sin.sin_addr); int addrlen = strlen(addr); strncpy(clientsas[i], addr, (addrlen > MAX_NAME_LEN)?MAX_NAME_LEN:addrlen); /* null term if strncpy couldn't */ if (addrlen > MAX_NAME_LEN) { clientsas[i][MAX_NAME_LEN] = '\0'; } ++client_cnt; } } else { for (i = 0; i < MAX_CLIENTS; ++i) { if (clientfds[i] > -1) { if (FD_ISSET(clientfds[i],&rfds)) { /* read a block, or as much as possible */ retval = read(clientfds[i],buf,block_size); /* dead client, pretty much */ if (retval <= 0) { if (debug) { fprintf(stdout, "disconnect from %s\n", clientsas[i]); } close(clientfds[i]); FD_CLR(clientfds[i],&static_rfds); clientfds[i] = -1; --client_cnt; } else if (debug > 2 ) { fprintf(stdout, "DEBUG: read %d bytes from %s\n", retval, clientsas[i]); } } } } } } else if (retval < 0) { /* error... */ ewarn("error in select"); } } return -1; }