Пример #1
0
/*PRINTFLIKE4*/
static void
syslog_emit(fmd_hdl_t *hdl, char *buf, size_t len, const char *msgformat, ...)
{
	struct strbuf ctl, dat;
	uint32_t msgid;

	char *format;
	size_t formatlen;
	va_list ap;

	formatlen = strlen(msgformat) + 64; /* +64 for prefix and \0 */
	format = alloca(formatlen);

	STRLOG_MAKE_MSGID(msgformat, msgid);
	(void) snprintf(format, formatlen,
	    "fmd: [ID %u FACILITY_AND_PRIORITY] %s", msgid, msgformat);

	va_start(ap, msgformat);
	(void) vsnprintf(buf, len, format, ap);
	va_end(ap);

	ctl.buf = (void *)&syslog_ctl;
	ctl.len = sizeof (syslog_ctl);

	dat.buf = buf;
	dat.len = strlen(buf) + 1;

	if (syslog_file && putmsg(syslog_logfd, &ctl, &dat, 0) != 0) {
		fmd_hdl_debug(hdl, "putmsg failed: %s\n", strerror(errno));
		syslog_stats.log_err.fmds_value.ui64++;
	}

	dat.buf = strchr(buf, ']');
	dat.len -= (size_t)(dat.buf - buf);

	dat.buf[0] = '\r'; /* overwrite ']' with carriage return */
	dat.buf[1] = '\n'; /* overwrite ' ' with newline */

	if (syslog_cons && write(syslog_msgfd, dat.buf, dat.len) != dat.len) {
		fmd_hdl_debug(hdl, "write failed: %s\n", strerror(errno));
		syslog_stats.msg_err.fmds_value.ui64++;
	}
}
Пример #2
0
void
vsyslog(int pri, const char *fmt, va_list ap)
{
	char *b, *f, *o;
	char c;
	int clen;
	char buf[MAXLINE + 2];
	char outline[MAXLINE + 256];  /* pad to allow date, system name... */
	time_t now;
	pid_t pid;
	struct log_ctl hdr;
	struct strbuf dat;
	struct strbuf ctl;
	char timestr[26];	/* hardwired value 26 due to Posix */
	size_t taglen;
	int olderrno = errno;
	struct stat statbuff;
	int procfd;
	char procfile[32];
	psinfo_t p;
	int showpid;
	uint32_t msgid;
	char *msgid_start, *msgid_end;
	int nowait;

/*
 * Maximum tag length is 256 (the pad in outline) minus the size of the
 * other things that can go in the pad.
 */
#define	MAX_TAG		230

	/* see if we should just throw out this message */
	if (pri < 0 || PRIFAC(pri) >= LOG_NFACILITIES ||
	    (PRIMASK(pri) & LogMask) == 0)
		return;

	if (LogFileInvalid)
		return;

	/*
	 * if openlog() has not been called by the application,
	 * try to get the name of the application and set it
	 * as the ident string for messages. If unable to get
	 * it for any reason, fall back to using the default
	 * of syslog. If we succeed in getting the name, also
	 * turn on LOG_PID, to provide greater detail.
	 */
	showpid = 0;
	if (OpenLogCalled == 0) {
		(void) sprintf(procfile, "/proc/%d/psinfo", (int)getpid());
		if ((procfd = open(procfile, O_RDONLY)) >= 0) {
			if (read(procfd, &p, sizeof (psinfo_t)) >= 0) {
				(void) strncpy(ProcName, p.pr_fname, PRFNSZ);
				LogTag = (const char *) &ProcName;
				showpid = LOG_PID;
			}
			(void) close(procfd);
		}
	}
	if (LogFile < 0)
		openlog(LogTag, LogStat|LOG_NDELAY|showpid, 0);

	if ((fstat(LogFile, &statbuff) != 0) ||
	    (!S_ISCHR(statbuff.st_mode)) || (statbuff.st_rdev != LogDev)) {
		LogFileInvalid = TRUE;
		return;
	}

	/* set default facility if none specified */
	if ((pri & LOG_FACMASK) == 0)
		pri |= LogFacility;

	/* build the header */
	hdr.pri = pri;
	hdr.flags = SL_CONSOLE;
	hdr.level = 0;

	/* build the message */
	/*
	 * To avoid potential security problems, bounds checking is done
	 * on outline and buf.
	 * The following code presumes that the header information will
	 * fit in 250-odd bytes, as was accounted for in the buffer size
	 * allocation.  This is dependent on the assumption that the LogTag
	 * and the string returned by sprintf() for getpid() will return
	 * be less than 230-odd characters combined.
	 */
	o = outline;
	(void) time(&now);
	(void) sprintf(o, "%.15s ", ctime_r(&now, timestr, 26) + 4);
	o += strlen(o);

	if (LogTag) {
		taglen = strlen(LogTag) < MAX_TAG ? strlen(LogTag) : MAX_TAG;
		(void) strncpy(o, LogTag, taglen);
		o[taglen] = '\0';
		o += strlen(o);
	}
	if (LogStat & LOG_PID) {
		(void) sprintf(o, "[%d]", (int)getpid());
		o += strlen(o);
	}
	if (LogTag) {
		(void) strcpy(o, ": ");
		o += 2;
	}

	STRLOG_MAKE_MSGID(fmt, msgid);
	(void) sprintf(o, "[ID %u FACILITY_AND_PRIORITY] ", msgid);
	o += strlen(o);

	b = buf;
	f = (char *)fmt;
	while ((c = *f++) != '\0' && b < &buf[MAXLINE]) {
		char *errmsg;
		if (c != '%') {
			*b++ = c;
			continue;
		}
		if ((c = *f++) != 'm') {
			*b++ = '%';
			*b++ = c;
			continue;
		}
		if ((errmsg = strerror(olderrno)) == NULL)
			(void) snprintf(b, &buf[MAXLINE] - b, "error %d",
			    olderrno);
		else {
			while (*errmsg != '\0' && b < &buf[MAXLINE]) {
				if (*errmsg == '%') {
					(void) strcpy(b, "%%");
					b += 2;
				}
				else
					*b++ = *errmsg;
				errmsg++;
			}
			*b = '\0';
		}
		b += strlen(b);
	}
	if (b > buf && *(b-1) != '\n')	/* ensure at least one newline */
		*b++ = '\n';
	*b = '\0';
	/* LINTED variable format specifier */
	(void) vsnprintf(o, &outline[sizeof (outline)] - o, buf, ap);
	clen  = (int)strlen(outline) + 1;	/* add one for NULL byte */
	if (clen > MAXLINE) {
		clen = MAXLINE;
		outline[MAXLINE-1] = '\0';
	}

	/*
	 * 1136432 points out that the underlying log driver actually
	 * refuses to accept (ERANGE) messages longer than LOG_MAXPS
	 * bytes.  So it really doesn't make much sense to putmsg a
	 * longer message..
	 */
	if (clen > LOG_MAXPS) {
		clen = LOG_MAXPS;
		outline[LOG_MAXPS-1] = '\0';
	}

	/* set up the strbufs */
	ctl.maxlen = sizeof (struct log_ctl);
	ctl.len = sizeof (struct log_ctl);
	ctl.buf = (caddr_t)&hdr;
	dat.maxlen = sizeof (outline);
	dat.len = clen;
	dat.buf = outline;

	/* output the message to the local logger */
	if ((putmsg(LogFile, &ctl, &dat, 0) >= 0) && syslogd_ok())
		return;
	if (!(LogStat & LOG_CONS))
		return;

	/*
	 * Output the message to the console directly.  To reduce visual
	 * clutter, we strip out the message ID.
	 */
	if ((msgid_start = strstr(outline, "[ID ")) != NULL &&
	    (msgid_end = strstr(msgid_start, "] ")) != NULL)
		(void) strcpy(msgid_start, msgid_end + 2);

	clen = strlen(outline) + 1;

	nowait = (LogStat & LOG_NOWAIT);
	pid = forkx(nowait? 0 : (FORK_NOSIGCHLD | FORK_WAITPID));
	if (pid == -1)
		return;

	if (pid == 0) {
		sigset_t sigs;
		int fd;

		(void) sigset(SIGALRM, SIG_DFL);
		(void) sigemptyset(&sigs);
		(void) sigaddset(&sigs, SIGALRM);
		(void) sigprocmask(SIG_UNBLOCK, &sigs, NULL);
		(void) alarm(5);
		if (((fd = open(sysmsg, O_WRONLY)) >= 0) ||
		    (fd = open(ctty, O_WRONLY)) >= 0) {
			(void) alarm(0);
			outline[clen - 1] = '\r';
			(void) write(fd, outline, clen);
			(void) close(fd);
		}
		_exit(0);
	}
	if (!nowait)
		while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
			continue;
}
Пример #3
0
static void pr_vsyslog(int sockfd, int pri, register const char *fmt,
    va_list ap) {
  time_t now;
  static char logbuf[PR_TUNABLE_BUFFER_SIZE] = {'\0'};
  size_t buflen = 0;
  int len = 0, saved_errno = errno;

#ifdef HAVE_DEV_LOG_STREAMS
  struct strbuf ctl, dat;
  struct log_ctl lc;
#else
  char *timestr = NULL;

# ifdef HAVE_TZNAME
  char *saved_tzname[2];
# endif /* HAVE_TZNAME */
#endif

  /* Clear the buffer */
  memset(logbuf, '\0', sizeof(logbuf));

  /* Check for invalid bits. */
  if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
    pri &= LOG_PRIMASK|LOG_FACMASK;
  }

  /* Check priority against setlogmask values. */
  if ((LOG_MASK(pri & LOG_PRIMASK) & log_mask) == 0) {
    return;
  }

  /* Set default facility if none specified. */
  if ((pri & LOG_FACMASK) == 0) {
    pri |= log_facility;
  }

#ifndef HAVE_DEV_LOG_STREAMS
  len = snprintf(logbuf, sizeof(logbuf), "<%d>", pri);
  logbuf[sizeof(logbuf)-1] = '\0';
  buflen += len;

# ifdef HAVE_TZNAME
  /* Preserve the old tzname setting. */
  memcpy(saved_tzname, tzname, sizeof(saved_tzname));
# endif /* HAVE_TZNAME */

  time(&now);
  timestr = ctime(&now);

# ifdef HAVE_TZNAME
  /* Restore the old tzname setting, to prevent ctime(3) from inadvertently
   * affecting things, as when we're in a chroot, and ctime(3) loses the
   * timezone info.
   */
  memcpy(tzname, saved_tzname, sizeof(saved_tzname));
# endif /* HAVE_TZNAME */

  /* Remove the trailing newline from the time string returned by ctime(3). */
  timestr[strlen(timestr)-1] = '\0';

  /* Skip past the leading "day of week" prefix. */
  timestr += 4;

  len = snprintf(&(logbuf[buflen]), sizeof(logbuf) - buflen, "%.15s ", timestr);
  logbuf[sizeof(logbuf)-1] = '\0';
  buflen += len;
#endif

  time(&now);

  if (log_ident == NULL) {
#ifdef HAVE___PROGNAME
    log_ident = __progname;
#else
    log_ident = "proftpd";
#endif /* HAVE___PROGNAME */
  }

  if (buflen < sizeof(logbuf) &&
      log_ident != NULL) {
    len = snprintf(&(logbuf[buflen]), sizeof(logbuf) - buflen, "%s", log_ident);
    logbuf[sizeof(logbuf)-1] = '\0';
    buflen += len;
  }

  if (buflen < sizeof(logbuf)-1 &&
      (log_opts & LOG_PID)) {
    len = snprintf(&(logbuf[buflen]), sizeof(logbuf) - buflen, "[%d]",
      (int) getpid());
    logbuf[sizeof(logbuf)-1] = '\0';
    buflen += len;
  }

  if (buflen < sizeof(logbuf)-1 &&
      log_ident != NULL) {
    len = snprintf(&(logbuf[buflen]), sizeof(logbuf) - buflen, ": ");
    logbuf[sizeof(logbuf)-1] = '\0';
    buflen += len;
  }

#if defined(SOLARIS2_9) || defined(SOLARIS2_10)
  /* Add in the (IMHO stupid and nonportable) syslog "header" that was added
   * to the Solaris 9/10 libc syslog(3) function.  Some sites apparently
   * think that trying to use this header to generate reports of logging
   * is a Good Idea; I'll have the last laugh when those sites try to move
   * to a different platform with different syslog logging.
   *
   * The header to be added looks like:
   *
   *  "[ID %lu %s.%s]"
   *
   * where the ID is generated using STRLOG_MAKE_MSGID(), a macro defined
   * in <sys/strlog.h>, and the following two strings are the syslog
   * facility and level, respectively.
   */

  if (buflen < sizeof(logbuf)) {
    register unsigned int i;
    uint32_t msgid;
    const char *facility_name = "unknown", *level_name = "unknown";

    STRLOG_MAKE_MSGID(fmt, msgid);

    for (i = 0; syslog_facility_names[i].name; i++) {
      if (syslog_facility_names[i].facility == log_facility) {
        facility_name = syslog_facility_names[i].name;
        break;
      }
    }

    for (i = 0; syslog_level_names[i].name; i++) {
      if (syslog_level_names[i].level == (pri & LOG_PRIMASK)) {
        level_name = syslog_level_names[i].name;
        break;
      }
    }

    len = snprintf(&(logbuf[buflen]), sizeof(logbuf) - buflen,
      "[ID %lu %s.%s] ", (unsigned long) msgid, facility_name, level_name);
    logbuf[sizeof(logbuf)-1] = '\0';
    buflen += len;
  }
#endif /* Solaris 9 or 10 */

  /* Restore errno for %m format.  */
  errno = saved_errno;

  /* We have the header.  Print the user's format into the buffer.  */
  if (buflen < sizeof(logbuf)) {
    len = vsnprintf(&(logbuf[buflen]), sizeof(logbuf) - buflen, fmt, ap);
    logbuf[sizeof(logbuf)-1] = '\0';
    buflen += len;
  }

  /* Always make sure the buffer is NUL-terminated
   */
  logbuf[sizeof(logbuf)-1] = '\0';

  /* If we have a SOCK_STREAM connection, also send ASCII NUL as a record
   * terminator.
   */
  if (sock_type == SOCK_STREAM) {
    ++buflen;
  }

  /* If we have exceeded the capacity of the buffer, we're done here. */
  if (buflen >= sizeof(logbuf)) {
    return;
  }

#ifndef HAVE_DEV_LOG_STREAMS
  if (sockfd >= 0 &&
      send(sockfd, logbuf, buflen, 0) < 0) {
    fprintf(stderr, "error sending log message '%s' to socket fd %d: %s\n",
      logbuf, sockfd, strerror(errno));
  }
#else

  /* Prepare the structs for use by putmsg(). As /dev/log (or /dev/conslog)
   * is a STREAMS device on Solaris (and possibly other platforms?), putmsg() is
   * used so that syslog facility and level are properly honored; write()
   * does not seem to work as desired.
   */
  ctl.len = ctl.maxlen = sizeof(lc);
  ctl.buf = (char *) &lc;
  dat.len = dat.maxlen = buflen;
  dat.buf = logbuf;
  lc.level = 0;
  lc.flags = SL_CONSOLE;
  lc.pri = pri;

  putmsg(sockfd, &ctl, &dat, 0);
#endif
}
Пример #4
0
/*
 * Ideally we would just use syslog(3C) for outputting our messages, but our
 * messaging standard defines a nice multi-line format and syslogd(1M) is very
 * inflexible and stupid when it comes to multi-line messages.  It pulls data
 * out of log(7D) and splits it up by \n, printing each line to the console
 * with its usual prefix of date and sender; it uses the same behavior for the
 * messages file as well.  Further, syslog(3C) provides no CE_CONT equivalent
 * for userland callers (which at least works around repeated file prefixing).
 * So with a multi-line message format, your file and console end up like this:
 *
 * Dec 02 18:08:40 hostname this is my nicely formatted
 * Dec 02 18:08:40 hostname message designed for 80 cols
 * ...
 *
 * To resolve these issues, we use our own syslog_emit() wrapper to emit
 * messages and some knowledge of how the Solaris log drivers work.  We first
 * construct an enlarged format string containing the appropriate msgid(1).
 * We then format the caller's message using the provided format and buffer.
 * We send this message to log(7D) using putmsg() with SL_CONSOLE | SL_LOGONLY
 * set in the log_ctl_t.  The log driver allows us to set SL_LOGONLY when we
 * construct messages ourself, indicating that syslogd should only emit the
 * message to /var/adm/messages and any remote hosts, and skip the console.
 * Then we emit the message a second time, without the special prefix, to the
 * sysmsg(7D) device, which handles console redirection and also permits us
 * to output any characters we like to the console, including \n and \r.
 */
static void
syslog_emit(fmd_hdl_t *hdl, const char *msg)
{
	struct strbuf ctl, dat;
	uint32_t msgid;

	char *buf;
	size_t buflen;

	const char *format = "fmd: [ID %u FACILITY_AND_PRIORITY] %s";
	STRLOG_MAKE_MSGID(format, msgid);

	buflen = snprintf(NULL, 0, format, msgid, msg);
	buf = alloca(buflen + 1);
	(void) snprintf(buf, buflen + 1, format, msgid, msg);

	ctl.buf = (void *)&syslog_ctl;
	ctl.len = sizeof (syslog_ctl);

	dat.buf = buf;
	dat.len = buflen + 1;

	/*
	 * The underlying log driver won't accept messages longer than
	 * LOG_MAXPS bytes.  Therefore, messages which exceed this limit will
	 * be truncated and appended with a pointer to the full message.
	 */
	if (dat.len > LOG_MAXPS) {
		char *syslog_pointer, *p;
		size_t plen;

		if ((syslog_pointer = fmd_msg_gettext_id(syslog_msghdl, NULL,
		    SYSLOG_POINTER)) == NULL) {
			/*
			 * This shouldn't happen, but if it does we'll just
			 * truncate the message.
			 */
			buf[LOG_MAXPS - 1] = '\0';
			dat.len = LOG_MAXPS;
		} else {
			plen = strlen(syslog_pointer) + 1;
			buf[LOG_MAXPS - plen] = '\0';
			/*
			 * If possible, the pointer is appended after a newline
			 */
			if ((p = strrchr(buf, '\n')) == NULL)
				p = &buf[LOG_MAXPS - plen];

			(void) strcpy(p, syslog_pointer);
			free(syslog_pointer);
			dat.len = strlen(buf) + 1;
		}
	}
	if (syslog_file && putmsg(syslog_logfd, &ctl, &dat, 0) != 0) {
		fmd_hdl_debug(hdl, "putmsg failed: %s\n", strerror(errno));
		syslog_stats.log_err.fmds_value.ui64++;
	}

	dat.buf = strchr(buf, ']');
	dat.len -= (size_t)(dat.buf - buf);

	dat.buf[0] = '\r'; /* overwrite ']' with carriage return */
	dat.buf[1] = '\n'; /* overwrite ' ' with newline */

	if (syslog_cons && write(syslog_msgfd, dat.buf, dat.len) != dat.len) {
		fmd_hdl_debug(hdl, "write failed: %s\n", strerror(errno));
		syslog_stats.msg_err.fmds_value.ui64++;
	}
}