Example #1
0
int tube_write_msg(struct tube* tube, uint8_t* buf, uint32_t len, 
        int nonblock)
{
	ssize_t r, d;
	int fd = tube->sw;

	/* test */
	if(nonblock) {
		r = write(fd, &len, sizeof(len));
		if(r == -1) {
			if(errno==EINTR || errno==EAGAIN)
				return -1;
			log_err("tube msg write failed: %s", strerror(errno));
			return -1; /* can still continue, perhaps */
		}
	} else r = 0;
	if(!fd_set_block(fd))
		return 0;
	/* write remainder */
	d = r;
	while(d != (ssize_t)sizeof(len)) {
		if((r=write(fd, ((char*)&len)+d, sizeof(len)-d)) == -1) {
			if(errno == EAGAIN)
				continue; /* temporarily unavail: try again*/
			log_err("tube msg write failed: %s", strerror(errno));
			(void)fd_set_nonblock(fd);
			return 0;
		}
		d += r;
	}
	d = 0;
	while(d != (ssize_t)len) {
		if((r=write(fd, buf+d, len-d)) == -1) {
			if(errno == EAGAIN)
				continue; /* temporarily unavail: try again*/
			log_err("tube msg write failed: %s", strerror(errno));
			(void)fd_set_nonblock(fd);
			return 0;
		}
		d += r;
	}
	if(!fd_set_nonblock(fd))
		return 0;
	return 1;
}
Example #2
0
int pr_log_openfile(const char *log_file, int *log_fd, mode_t log_mode) {
  int res;
  pool *tmp_pool = NULL;
  char *tmp = NULL, *lf;
  unsigned char have_stat = FALSE, *allow_log_symlinks = NULL;
  struct stat st;

  /* Sanity check */
  if (!log_file || !log_fd) {
    errno = EINVAL;
    return -1;
  }

  /* Make a temporary copy of log_file in case it's a constant */
  tmp_pool = make_sub_pool(permanent_pool);
  pr_pool_tag(tmp_pool, "log_openfile() tmp pool");
  lf = pstrdup(tmp_pool, log_file);

  tmp = strrchr(lf, '/');
  if (tmp == NULL) {
    pr_log_debug(DEBUG0, "inappropriate log file: %s", lf);
    destroy_pool(tmp_pool);

    errno = EINVAL;
    return -1;
  }

  /* Set the path separator to zero, in order to obtain the directory
   * name, so that checks of the directory may be made.
   */
  *tmp = '\0';

  if (stat(lf, &st) < 0) {
    int xerrno = errno;
    pr_log_debug(DEBUG0, "error: unable to stat() %s: %s", lf,
      strerror(errno));
    destroy_pool(tmp_pool);

    errno = xerrno;
    return -1;
  }

  /* The path must be in a valid directory */
  if (!S_ISDIR(st.st_mode)) {
    pr_log_debug(DEBUG0, "error: %s is not a directory", lf);
    destroy_pool(tmp_pool);

    errno = ENOTDIR;
    return -1;
  }

  /* Do not log to world-writable directories */
  if (st.st_mode & S_IWOTH) {
    pr_log_pri(PR_LOG_NOTICE, "error: %s is a world-writable directory", lf);
    destroy_pool(tmp_pool);
    return PR_LOG_WRITABLE_DIR;
  }

  /* Restore the path separator so that checks on the file itself may be
   * done.
   */
  *tmp = '/';

  allow_log_symlinks = get_param_ptr(main_server->conf, "AllowLogSymlinks",
    FALSE);

  if (allow_log_symlinks == NULL ||
      *allow_log_symlinks == FALSE) {
    int flags = O_APPEND|O_CREAT|O_WRONLY;

#ifdef PR_USE_NONBLOCKING_LOG_OPEN
    /* Use the O_NONBLOCK flag when opening log files, as they might be
     * FIFOs whose other end is not currently running; we do not want to
     * block indefinitely in such cases.
     */
    flags |= O_NONBLOCK;
#endif /* PR_USE_NONBLOCKING_LOG_OPEN */

#ifdef O_NOFOLLOW
    /* On systems that support the O_NOFOLLOW flag (e.g. Linux and FreeBSD),
     * use it so that the path being opened, if it is a symlink, is not
     * followed.
     */
    flags |= O_NOFOLLOW;

#elif defined(SOLARIS2)
    /* Solaris doesn't support the O_NOFOLLOW flag.  Instead, in their
     * wisdom (hah!), Solaris decided that if the given path is a symlink
     * and the flags O_CREAT and O_EXCL are set, the link is not followed.
     * Right.  The problem here is the case where the path is not a symlink;
     * using O_CREAT|O_EXCL will then cause the open() to fail if the
     * file already exists.
     */
    flags |= O_EXCL;
#endif /* O_NOFOLLOW or SOLARIS2 */

    *log_fd = open(lf, flags, log_mode);
    if (*log_fd < 0) {

      if (errno != EEXIST) {
        destroy_pool(tmp_pool);

        /* More portability fun: Linux likes to report ELOOP if O_NOFOLLOW
         * is used to open a symlink file; FreeBSD likes to return EMLINK.
         * Both would lead to rather misleading error messages being
         * logged.  Catch these errnos, and return the value that properly
         * informs the caller that the given path was an illegal symlink.
         */

        switch (errno) {
#ifdef ELOOP
          case ELOOP:
            return PR_LOG_SYMLINK;
#endif /* ELOOP */

#ifdef EMLINK
          case EMLINK:
            return PR_LOG_SYMLINK;
#endif /* EMLINK */
        }

        return -1;

      } else {
#if defined(SOLARIS2)
        /* On Solaris, because of the stupid multiplexing of O_CREAT and
         * O_EXCL to get open() not to follow a symlink, it's possible that
         * the path already exists.  Now, we'll try to open() without
         * O_EXCL, then lstat() the path to see if this pre-existing file is
         * a symlink or a regular file.
         *
         * Note that because this check cannot be done atomically on Solaris,
         * the possibility of a race condition/symlink attack still exists.
         * Solaris doesn't provide a good way around this situation.
         */
        flags &= ~O_EXCL;

        *log_fd = open(lf, flags, log_mode);
        if (*log_fd < 0) {
          destroy_pool(tmp_pool);
          return -1;
        }

        /* The race condition on Solaris is here, between the open() call
         * above and the lstat() call below...
         */

        if (lstat(lf, &st) != -1)
          have_stat = TRUE;
#else
        destroy_pool(tmp_pool);
        return -1;
#endif /* SOLARIS2 */
      }
    }

    /* Stat the file using the descriptor, not the path */
    if (!have_stat &&
        fstat(*log_fd, &st) != -1)
      have_stat = TRUE;

    if (!have_stat ||
        S_ISLNK(st.st_mode)) {
      pr_log_debug(DEBUG0, !have_stat ? "error: unable to stat %s" :
        "error: %s is a symbolic link", lf);

      close(*log_fd);
      *log_fd = -1;
      destroy_pool(tmp_pool);
      return PR_LOG_SYMLINK;
    }

  } else {
    int flags = O_CREAT|O_APPEND|O_WRONLY;

#ifdef PR_USE_NONBLOCKING_LOG_OPEN
    /* Use the O_NONBLOCK flag when opening log files, as they might be
     * FIFOs whose other end is not currently running; we do not want to
     * block indefinitely in such cases.
     */
    flags |= O_NONBLOCK;
#endif /* PR_USE_NONBLOCKING_LOG_OPEN */

    *log_fd = open(lf, flags, log_mode);
    if (*log_fd < 0) {
      destroy_pool(tmp_pool);
      return -1;
    }
  }

  /* Find a usable fd for the just-opened log fd. */
  if (*log_fd <= STDERR_FILENO) {
    res = pr_fs_get_usable_fd(*log_fd);
    if (res < 0) {
      pr_log_debug(DEBUG0, "warning: unable to find good fd for logfd %d: %s",
        *log_fd, strerror(errno));

    } else {
      close(*log_fd);
      *log_fd = res;
    }
  }

  if (fcntl(*log_fd, F_SETFD, FD_CLOEXEC) < 0) {
    pr_log_pri(PR_LOG_WARNING, "unable to set CLO_EXEC on log fd %d: %s",
      *log_fd, strerror(errno));
  }

#ifdef PR_USE_NONBLOCKING_LOG_OPEN
  /* Return the fd to blocking mode. */
  (void) fd_set_block(*log_fd);
#endif /* PR_USE_NONBLOCKING_LOG_OPEN */

  destroy_pool(tmp_pool);
  return 0;
}
Example #3
0
int tube_read_msg(struct tube* tube, uint8_t** buf, uint32_t* len, 
        int nonblock)
{
	ssize_t r, d;
	int fd = tube->sr;

	/* test */
	*len = 0;
	if(nonblock) {
		r = read(fd, len, sizeof(*len));
		if(r == -1) {
			if(errno==EINTR || errno==EAGAIN)
				return -1;
			log_err("tube msg read failed: %s", strerror(errno));
			return -1; /* we can still continue, perhaps */
		}
		if(r == 0) /* EOF */
			return 0;
	} else r = 0;
	if(!fd_set_block(fd))
		return 0;
	/* read remainder */
	d = r;
	while(d != (ssize_t)sizeof(*len)) {
		if((r=read(fd, ((char*)len)+d, sizeof(*len)-d)) == -1) {
			log_err("tube msg read failed: %s", strerror(errno));
			(void)fd_set_nonblock(fd);
			return 0;
		}
		if(r == 0) /* EOF */ {
			(void)fd_set_nonblock(fd);
			return 0;
		}
		d += r;
	}
	log_assert(*len < 65536*2);
	*buf = (uint8_t*)malloc(*len);
	if(!*buf) {
		log_err("tube read out of memory");
		(void)fd_set_nonblock(fd);
		return 0;
	}
	d = 0;
	while(d < (ssize_t)*len) {
		if((r=read(fd, (*buf)+d, (size_t)((ssize_t)*len)-d)) == -1) {
			log_err("tube msg read failed: %s", strerror(errno));
			(void)fd_set_nonblock(fd);
			free(*buf);
			return 0;
		}
		if(r == 0) { /* EOF */
			(void)fd_set_nonblock(fd);
			free(*buf);
			return 0;
		}
		d += r;
	}
	if(!fd_set_nonblock(fd)) {
		free(*buf);
		return 0;
	}
	return 1;
}