Esempio n. 1
0
struct chirp_file *chirp_global_open(const char *host, const char *path, INT64_T flags, INT64_T mode, time_t stoptime)
{
	if(is_multi_path(host)) {
		char mhost[CHIRP_PATH_MAX];
		char mpath[CHIRP_PATH_MAX];
		parse_multi_path(path, mhost, mpath);
		return chirp_multi_open(mhost, mpath, flags, mode, stoptime);
	} else if(not_empty(path)) {
		return chirp_reli_open(host, path, flags, mode, stoptime);
	} else if(not_empty(host)) {
		if(server_lookup(host, stoptime)) {
			errno = EISDIR;
			return 0;
		} else {
			if(flags & O_CREAT) {
				errno = EACCES;
			} else {
				errno = ENOENT;
			}
			return 0;
		}
	} else {
		errno = EISDIR;
		return 0;
	}
}
Esempio n. 2
0
File: child.c Progetto: aosm/xinetd
/*
 * This function is invoked when a SIGCLD is received
 */
void child_exit(void)
{
   const char *func = "child_exit" ;

   for ( ;; )         /* Find all children that exited */
   {
      int status ;
      pid_t pid ;
      struct server *serp ;
      
#ifdef HAVE_WAITPID
      pid = waitpid( -1, &status, WNOHANG ) ;
#else
#if defined( sun ) && defined( lint )
      pid = wait3( (union wait *)&status, WNOHANG, RUSAGE_NULL ) ;
#else
      pid = wait3( &status, WNOHANG, RUSAGE_NULL ) ;
#endif
#endif

      if ( debug.on )
#ifdef HAVE_WAITPID
         msg( LOG_DEBUG, func, "waitpid returned = %d", pid ) ;
#else
         msg( LOG_DEBUG, func, "wait3 returned = %d", pid ) ;
#endif
      
      if ( pid == -1 ) {
         if ( errno == EINTR )
            continue ;
         else
            break ;
      }

      if ( pid == 0 )
         break ;
      
      if ( ( serp = server_lookup( pid ) ) != NULL )
      {
         serp->svr_exit_status = status ;
         server_end( serp ) ;
      }
      else
         msg( LOG_NOTICE, func, "unknown child process %d %s", pid,
            PROC_STOPPED( status ) ? "stopped" : "died" ) ;
   }
}
Esempio n. 3
0
/*
 * Get address client connected to, by doing a DIOCNATLOOK call.
 * Uses server_lookup code from ftp-proxy.
 */
void
getcaddr(struct con *cp) {
	struct sockaddr_storage spamd_end;
	struct sockaddr *sep = (struct sockaddr *) &spamd_end;
	struct sockaddr_storage original_destination;
	struct sockaddr *odp = (struct sockaddr *) &original_destination;
	socklen_t len = sizeof(struct sockaddr_storage);
	int error;

	cp->caddr[0] = '\0';
	if (getsockname(cp->fd, sep, &len) == -1)
		return;
	if (server_lookup((struct sockaddr *)&cp->ss, sep, odp) != 0)
		return;
	error = getnameinfo(odp, odp->sa_len, cp->caddr, sizeof(cp->caddr),
	    NULL, 0, NI_NUMERICHOST);
	if (error)
		cp->caddr[0] = '\0';
}
Esempio n. 4
0
INT64_T chirp_global_access(const char *host, const char *path, INT64_T mode, time_t stoptime)
{
	if(is_multi_path(host)) {
		char mhost[CHIRP_PATH_MAX];
		char mpath[CHIRP_PATH_MAX];
		parse_multi_path(path, mhost, mpath);
		return chirp_multi_access(mhost, mpath, mode, stoptime);
	} else if(not_empty(path)) {
		return chirp_reli_access(host, path, mode, stoptime);
	} else if(not_empty(host)) {
		if(server_lookup(host, stoptime)) {
			return 0;
		} else {
			return chirp_reli_access(host, path, mode, stoptime);
		}
	} else {
		return 0;
	}
}
Esempio n. 5
0
INT64_T chirp_global_setxattr(const char *host, const char *path, const char *name, const void *data, size_t size, int flags, time_t stoptime)
{
	if(is_multi_path(host)) {
		errno = EACCES;
		return -1;
	} else if(not_empty(path)) {
		return chirp_reli_setxattr(host, path, name, data, size, flags, stoptime);
	} else if(not_empty(host)) {
		if(server_lookup(host, stoptime)) {
			errno = EACCES;
			return -1;
		} else {
			errno = ENOENT;
			return -1;
		}
	} else {
		errno = EACCES;
		return -1;
	}
}
Esempio n. 6
0
INT64_T chirp_global_llistxattr(const char *host, const char *path, char *list, size_t size, time_t stoptime)
{
	if(is_multi_path(host)) {
		errno = EACCES;
		return -1;
	} else if(not_empty(path)) {
		return chirp_reli_llistxattr(host, path, list, size, stoptime);
	} else if(not_empty(host)) {
		if(server_lookup(host, stoptime)) {
			errno = EACCES;
			return -1;
		} else {
			errno = ENOENT;
			return -1;
		}
	} else {
		errno = EACCES;
		return -1;
	}
}
Esempio n. 7
0
INT64_T chirp_global_rmall(const char *host, const char *path, time_t stoptime)
{
	if(is_multi_path(host)) {
		errno = ENOSYS;
		return -1;
	} else if(not_empty(path)) {
		return chirp_reli_rmall(host, path, stoptime);
	} else if(not_empty(host)) {
		if(server_lookup(host, stoptime)) {
			errno = EACCES;
			return -1;
		} else {
			errno = ENOENT;
			return -1;
		}
	} else {
		errno = EACCES;
		return -1;
	}
}
Esempio n. 8
0
INT64_T chirp_global_utime(const char *host, const char *path, time_t actime, time_t modtime, time_t stoptime)
{
	if(is_multi_path(host)) {
		char mhost[CHIRP_PATH_MAX];
		char mpath[CHIRP_PATH_MAX];
		parse_multi_path(path, mhost, mpath);
		return chirp_multi_utime(mhost, mpath, actime, modtime, stoptime);
	} else if(not_empty(path)) {
		return chirp_reli_utime(host, path, actime, modtime, stoptime);
	} else if(not_empty(host)) {
		if(server_lookup(host, stoptime)) {
			errno = EISDIR;
			return -1;
		} else {
			errno = ENOENT;
			return -1;
		}
	} else {
		errno = EISDIR;
		return -1;
	}
}
Esempio n. 9
0
INT64_T chirp_global_lchown(const char *host, const char *path, INT64_T uid, INT64_T gid, time_t stoptime)
{
	if(is_multi_path(host)) {
		char mhost[CHIRP_PATH_MAX];
		char mpath[CHIRP_PATH_MAX];
		parse_multi_path(path, mhost, mpath);
		return chirp_multi_lchown(mhost, mpath, uid, gid, stoptime);
	} else if(not_empty(path)) {
		return chirp_reli_lchown(host, path, uid, gid, stoptime);
	} else if(not_empty(host)) {
		if(server_lookup(host, stoptime)) {
			errno = EACCES;
			return -1;
		} else {
			errno = ENOENT;
			return -1;
		}
	} else {
		errno = EACCES;
		return -1;
	}
}
Esempio n. 10
0
INT64_T chirp_global_lstat(const char *host, const char *path, struct chirp_stat * buf, time_t stoptime)
{
	if(is_multi_path(host)) {
		char mhost[CHIRP_PATH_MAX];
		char mpath[CHIRP_PATH_MAX];
		parse_multi_path(path, mhost, mpath);
		return chirp_multi_lstat(mhost, mpath, buf, stoptime);
	} else if(not_empty(path)) {
		return chirp_reli_lstat(host, path, buf, stoptime);
	} else if(not_empty(host)) {
		struct jx *j = server_lookup(host, stoptime);
		if(j) {
			chirp_jx_to_stat(j, buf);
			return 0;
		} else {
			return chirp_reli_lstat(host, "/", buf, stoptime);
		}
	} else {
		chirp_blank_stat(buf);
		return 0;
	}
}
Esempio n. 11
0
INT64_T chirp_global_readlink(const char *host, const char *path, char *buf, INT64_T length, time_t stoptime)
{
	if(is_multi_path(host)) {
		char mhost[CHIRP_PATH_MAX];
		char mpath[CHIRP_PATH_MAX];
		parse_multi_path(path, mhost, mpath);
		return chirp_multi_readlink(mhost, mpath, buf, length, stoptime);
	} else if(not_empty(path)) {
		return chirp_reli_readlink(host, path, buf, length, stoptime);
	} else if(not_empty(host)) {
		if(server_lookup(host, stoptime)) {
			errno = EINVAL;
			return -1;
		} else {
			errno = ENOENT;
			return -1;
		}
	} else {
		errno = EINVAL;
		return -1;
	}
}
Esempio n. 12
0
INT64_T chirp_global_putfile_buffer(const char *host, const char *path, const char *buffer, INT64_T mode, INT64_T length, time_t stoptime)
{
	if(is_multi_path(host)) {
		char mhost[CHIRP_PATH_MAX];
		char mpath[CHIRP_PATH_MAX];
		parse_multi_path(path, mhost, mpath);
		return chirp_multi_putfile_buffer(mhost, mpath, buffer, mode, length, stoptime);
	} else if(not_empty(path)) {
		return chirp_reli_putfile_buffer(host, path, buffer, mode, length, stoptime);
	} else if(not_empty(host)) {
		if(server_lookup(host, stoptime)) {
			errno = EISDIR;
			return -1;
		} else {
			errno = EACCES;
			return -1;
		}
	} else {
		errno = EACCES;
		return -1;
	}
}
Esempio n. 13
0
INT64_T chirp_global_getfile(const char *host, const char *path, FILE * stream, time_t stoptime)
{
	if(is_multi_path(host)) {
		char mhost[CHIRP_PATH_MAX];
		char mpath[CHIRP_PATH_MAX];
		parse_multi_path(path, mhost, mpath);
		return chirp_multi_getfile(mhost, mpath, stream, stoptime);
	} else if(not_empty(path)) {
		return chirp_reli_getfile(host, path, stream, stoptime);
	} else if(not_empty(host)) {
		if(server_lookup(host, stoptime)) {
			errno = EISDIR;
			return -1;
		} else {
			errno = EACCES;
			return -1;
		}
	} else {
		errno = EACCES;
		return -1;
	}
}
Esempio n. 14
0
int
main(int argc, char *argv[])
{
	int c, fd = 0, on = 1, out_fd = 0, peer, reqsize = 0;
	int transwait = DEFTRANSWAIT;
	char *p;
	struct tftphdr *tp;
	struct passwd *pw;
	size_t cbuflen;
	char *cbuf;
	char req[PKTSIZE];
	struct cmsghdr *cmsg;
	struct msghdr msg;
	struct iovec iov;

	struct sockaddr_storage from, proxy, server, proxy_to_server, s_in;
	struct sockaddr_in sock_out;
	socklen_t j;
	in_port_t bindport;

	openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);

	while ((c = getopt(argc, argv, "vw:")) != -1)
		switch (c) {
		case 'v':
			verbose++;
			break;
		case 'w':
			transwait = strtoll(optarg, &p, 10);
			if (transwait < 1) {
				syslog(LOG_ERR, "invalid -w value");
				exit(1);
			}
			break;
		default:
			usage();
			break;
		}

	/* open /dev/pf */
	init_filter(NULL, verbose);

	tzset();

	pw = getpwnam(NOPRIV_USER);
	if (!pw) {
		syslog(LOG_ERR, "no such user %s: %m", NOPRIV_USER);
		exit(1);
	}
	if (chroot(CHROOT_DIR) || chdir("/")) {
		syslog(LOG_ERR, "chroot %s: %m", CHROOT_DIR);
		exit(1);
	}
#ifdef __NetBSD__
	if (setgroups(1, &pw->pw_gid) ||
	    setgid(pw->pw_gid) ||
	    setuid(pw->pw_uid)) {
		syslog(LOG_ERR, "can't revoke privs: %m");
		exit(1);
	}
#else
	if (setgroups(1, &pw->pw_gid) ||
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) {
		syslog(LOG_ERR, "can't revoke privs: %m");
		exit(1);
	}
#endif /* !__NetBSD__ */

	/* non-blocking io */
	if (ioctl(fd, FIONBIO, &on) < 0) {
		syslog(LOG_ERR, "ioctl(FIONBIO): %m");
		exit(1);
	}

	if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on)) == -1) {
		syslog(LOG_ERR, "setsockopt(IP_RECVDSTADDR): %m");
		exit(1);
	}

	j = sizeof(s_in);
	if (getsockname(fd, (struct sockaddr *)&s_in, &j) == -1) {
		syslog(LOG_ERR, "getsockname: %m");
		exit(1);
	}

	bindport = ((struct sockaddr_in *)&s_in)->sin_port;

	/* req will be pushed back out at the end, unchanged */
	j = sizeof(from);
	if ((reqsize = recvfrom(fd, req, sizeof(req), MSG_PEEK,
	    (struct sockaddr *)&from, &j)) < 0) {
		syslog(LOG_ERR, "recvfrom: %m");
		exit(1);
	}

	bzero(&msg, sizeof(msg));
	iov.iov_base = req;
	iov.iov_len = sizeof(req);
	msg.msg_name = &from;
	msg.msg_namelen = sizeof(from);
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;

	cbuflen = CMSG_SPACE(sizeof(struct sockaddr_storage));
	if ((cbuf = malloc(cbuflen)) == NULL) {
		syslog(LOG_ERR, "malloc: %m");
		exit(1);
	}

	msg.msg_control = cbuf;
	msg.msg_controllen = cbuflen;

	if (recvmsg(fd, &msg, 0) < 0) {
		syslog(LOG_ERR, "recvmsg: %m");
		exit(1);
	}

	close(fd);
	close(1);

	peer = socket(from.ss_family, SOCK_DGRAM, 0);
	if (peer < 0) {
		syslog(LOG_ERR, "socket: %m");
		exit(1);
	}
	memset(&s_in, 0, sizeof(s_in));
	s_in.ss_family = from.ss_family;
	s_in.ss_len = from.ss_len;

	/* get local address if possible */
	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
		if (cmsg->cmsg_level == IPPROTO_IP &&
		    cmsg->cmsg_type == IP_RECVDSTADDR) {
			memcpy(&((struct sockaddr_in *)&s_in)->sin_addr,
			    CMSG_DATA(cmsg), sizeof(struct in_addr));
			break;
		}
	}

	if (bind(peer, (struct sockaddr *)&s_in, s_in.ss_len) < 0) {
		syslog(LOG_ERR, "bind: %m");
		exit(1);
	}
	if (connect(peer, (struct sockaddr *)&from, from.ss_len) < 0) {
		syslog(LOG_ERR, "connect: %m");
		exit(1);
	}

	tp = (struct tftphdr *)req;
	if (!(ntohs(tp->th_opcode) == RRQ || ntohs(tp->th_opcode) == WRQ)) {
		/* not a tftp request, bail */
		if (verbose) {
			syslog(LOG_WARNING, "not a valid tftp request");
			exit(1);
		} else
			/* exit 0 so inetd doesn't log anything */
			exit(0);
	}

	j = sizeof(struct sockaddr_storage);
	if (getsockname(fd, (struct sockaddr *)&proxy, &j) == -1) {
		syslog(LOG_ERR, "getsockname: %m");
		exit(1);
	}

	((struct sockaddr_in *)&proxy)->sin_port = bindport;

	/* find the un-rdr'd server and port the client wanted */
	if (server_lookup((struct sockaddr *)&from,
	    (struct sockaddr *)&proxy, (struct sockaddr *)&server,
	    IPPROTO_UDP) != 0) {
		syslog(LOG_ERR, "pf connection lookup failed (no rdr?)");
		exit(1);
	}

	/* establish a new outbound connection to the remote server */
	if ((out_fd = socket(((struct sockaddr *)&from)->sa_family,
	    SOCK_DGRAM, IPPROTO_UDP)) < 0) {
		syslog(LOG_ERR, "couldn't create new socket");
		exit(1);
	}

	bzero((char *)&sock_out, sizeof(sock_out));
	sock_out.sin_family = from.ss_family;
	sock_out.sin_port = htons(pick_proxy_port());
	if (bind(out_fd, (struct sockaddr *)&sock_out, sizeof(sock_out)) < 0) {
		syslog(LOG_ERR, "couldn't bind to new socket: %m");
		exit(1);
	}

	if (connect(out_fd, (struct sockaddr *)&server,
	    ((struct sockaddr *)&server)->sa_len) < 0 && errno != EINPROGRESS) {
		syslog(LOG_ERR, "couldn't connect to remote server: %m");
		exit(1);
	}

	j = sizeof(struct sockaddr_storage);
	if ((getsockname(out_fd, (struct sockaddr *)&proxy_to_server,
	    &j)) < 0) {
		syslog(LOG_ERR, "getsockname: %m");
		exit(1);
	}

	if (verbose)
		syslog(LOG_INFO, "%s:%d -> %s:%d/%s:%d -> %s:%d \"%s %s\"",
			sock_ntop((struct sockaddr *)&from),
			ntohs(((struct sockaddr_in *)&from)->sin_port),
			sock_ntop((struct sockaddr *)&proxy),
			ntohs(((struct sockaddr_in *)&proxy)->sin_port),
			sock_ntop((struct sockaddr *)&proxy_to_server),
			ntohs(((struct sockaddr_in *)&proxy_to_server)->sin_port),
			sock_ntop((struct sockaddr *)&server),
			ntohs(((struct sockaddr_in *)&server)->sin_port),
			opcode(ntohs(tp->th_opcode)),
			tp->th_stuff);

	/* get ready to add rdr and pass rules */
	if (prepare_commit(1) == -1) {
		syslog(LOG_ERR, "couldn't prepare pf commit");
		exit(1);
	}

	/* rdr from server to us on our random port -> client on its port */
	if (add_rdr(1, (struct sockaddr *)&server,
	    (struct sockaddr *)&proxy_to_server, ntohs(sock_out.sin_port),
	    (struct sockaddr *)&from,
	    ntohs(((struct sockaddr_in *)&from)->sin_port),
	    IPPROTO_UDP) == -1) {
		syslog(LOG_ERR, "couldn't add rdr");
		exit(1);
	}

	/* explicitly allow the packets to return back to the client (which pf
	 * will see post-rdr) */
	if (add_filter(1, PF_IN, (struct sockaddr *)&server,
	    (struct sockaddr *)&from,
	    ntohs(((struct sockaddr_in *)&from)->sin_port),
	    IPPROTO_UDP) == -1) {
		syslog(LOG_ERR, "couldn't add pass in");
		exit(1);
	}
	if (add_filter(1, PF_OUT, (struct sockaddr *)&server,
	    (struct sockaddr *)&from,
	    ntohs(((struct sockaddr_in *)&from)->sin_port),
	    IPPROTO_UDP) == -1) {
		syslog(LOG_ERR, "couldn't add pass out");
		exit(1);
	}

	/* and just in case, to pass out from us to the server */
	if (add_filter(1, PF_OUT, (struct sockaddr *)&proxy_to_server,
	    (struct sockaddr *)&server,
	    ntohs(((struct sockaddr_in *)&server)->sin_port),
	    IPPROTO_UDP) == -1) {
		syslog(LOG_ERR, "couldn't add pass out");
		exit(1);
	}

	if (do_commit() == -1) {
		syslog(LOG_ERR, "couldn't commit pf rules");
		exit(1);
	}

	/* forward the initial tftp request and start the insanity */
	if (send(out_fd, tp, reqsize, 0) < 0) {
		syslog(LOG_ERR, "couldn't forward tftp packet: %m");
		exit(1);
	}

	/* allow the transfer to start to establish a state */
	sleep(transwait);

	/* delete our rdr rule and clean up */
	prepare_commit(1);
	do_commit();

	return(0);
}