1 /* $OpenBSD: syslog_r.c,v 1.7 2015/01/21 19:34:24 deraadt Exp $ */ 2 /* 3 * Copyright (c) 1983, 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the University nor the names of its contributors 15 * may be used to endorse or promote products derived from this software 16 * without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/types.h> 32 #include <sys/syslog.h> 33 #include <sys/uio.h> 34 #include <netdb.h> 35 36 #include <errno.h> 37 #include <fcntl.h> 38 #include <paths.h> 39 #include <stdio.h> 40 #include <string.h> 41 #include <time.h> 42 #include <unistd.h> 43 #include <limits.h> 44 #include <stdarg.h> 45 46 extern char *__progname; /* Program name, from crt0. */ 47 48 int sendsyslog(const char *, size_t); 49 50 void __vsyslog_r(int pri, struct syslog_data *, size_t (*)(char *, size_t), 51 const char *, va_list); 52 53 /* Reentrant version of syslog, i.e. syslog_r() */ 54 55 /* PRINTFLIKE3 */ 56 void 57 syslog_r(int pri, struct syslog_data *data, const char *fmt, ...) 58 { 59 va_list ap; 60 61 va_start(ap, fmt); 62 vsyslog_r(pri, data, fmt, ap); 63 va_end(ap); 64 } 65 66 void 67 vsyslog_r(int pri, struct syslog_data *data, const char *fmt, va_list ap) 68 { 69 const char *ident; 70 71 __vsyslog_r(pri, data, NULL, fmt, ap); 72 73 /* close the socket without losing log_tag */ 74 ident = data->log_tag; 75 closelog_r(data); 76 data->log_tag = ident; 77 } 78 79 /* 80 * This is used by both syslog_r and syslog. The latter supplies 81 * a non-NULL gettime callback for filling in the date, but we also 82 * use the presence of that callback to decide whether it's safe 83 * to call strerror and what the name of the caller is 84 */ 85 void 86 __vsyslog_r(int pri, struct syslog_data *data, 87 size_t (*gettime)(char *, size_t), const char *fmt, va_list ap) 88 { 89 int cnt; 90 char ch, *p, *t; 91 int fd, saved_errno, error; 92 #define TBUF_LEN 2048 93 #define FMT_LEN 1024 94 char *conp = NULL, *stdp = NULL, tbuf[TBUF_LEN], fmt_cpy[FMT_LEN]; 95 int tbuf_left, fmt_left, prlen; 96 97 #define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID 98 /* Check for invalid bits. */ 99 if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) { 100 syslog_r(INTERNALLOG, data, 101 "syslog%s: unknown facility/priority: %x", 102 gettime != NULL ? "" : "_r", pri); 103 pri &= LOG_PRIMASK|LOG_FACMASK; 104 } 105 106 /* Check priority against setlogmask values. */ 107 if (!(LOG_MASK(LOG_PRI(pri)) & data->log_mask)) 108 return; 109 110 saved_errno = errno; 111 112 /* Set default facility if none specified. */ 113 if ((pri & LOG_FACMASK) == 0) 114 pri |= data->log_fac; 115 116 p = tbuf; 117 tbuf_left = TBUF_LEN; 118 119 #define DEC() \ 120 do { \ 121 if (prlen < 0) \ 122 prlen = 0; \ 123 if (prlen >= tbuf_left) \ 124 prlen = tbuf_left - 1; \ 125 p += prlen; \ 126 tbuf_left -= prlen; \ 127 } while (0) 128 129 prlen = snprintf(p, tbuf_left, "<%d>", pri); 130 DEC(); 131 if (data->log_stat & LOG_CONS) 132 conp = p; 133 134 /* 135 * syslogd will expand time automagically for reentrant case, and 136 * for normal case, invoke the callback to do it just do like before 137 */ 138 if (gettime != NULL) { 139 prlen = gettime(p, tbuf_left); 140 DEC(); 141 } 142 143 if (data->log_stat & LOG_PERROR) 144 stdp = p; 145 if (data->log_tag == NULL) 146 data->log_tag = __progname; 147 if (data->log_tag != NULL) { 148 prlen = snprintf(p, tbuf_left, "%.*s", NAME_MAX, data->log_tag); 149 DEC(); 150 } 151 if (data->log_stat & LOG_PID) { 152 prlen = snprintf(p, tbuf_left, "[%ld]", (long)getpid()); 153 DEC(); 154 } 155 if (data->log_tag != NULL) { 156 if (tbuf_left > 1) { 157 *p++ = ':'; 158 tbuf_left--; 159 } 160 if (tbuf_left > 1) { 161 *p++ = ' '; 162 tbuf_left--; 163 } 164 } 165 166 /* strerror() is not reentrant */ 167 168 for (t = fmt_cpy, fmt_left = FMT_LEN; (ch = *fmt); ++fmt) { 169 if (ch == '%' && fmt[1] == 'm') { 170 ++fmt; 171 if (gettime != NULL) { 172 prlen = snprintf(t, fmt_left, "%s", 173 strerror(saved_errno)); 174 } else { 175 prlen = snprintf(t, fmt_left, "Error %d", 176 saved_errno); 177 } 178 if (prlen < 0) 179 prlen = 0; 180 if (prlen >= fmt_left) 181 prlen = fmt_left - 1; 182 t += prlen; 183 fmt_left -= prlen; 184 } else if (ch == '%' && fmt[1] == '%' && fmt_left > 2) { 185 *t++ = '%'; 186 *t++ = '%'; 187 fmt++; 188 fmt_left -= 2; 189 } else { 190 if (fmt_left > 1) { 191 *t++ = ch; 192 fmt_left--; 193 } 194 } 195 } 196 *t = '\0'; 197 198 prlen = vsnprintf(p, tbuf_left, fmt_cpy, ap); 199 DEC(); 200 cnt = p - tbuf; 201 while (cnt > 0 && p[-1] == '\n') { 202 *(--p) = '\0'; 203 --cnt; 204 } 205 206 /* Output to stderr if requested. */ 207 if (data->log_stat & LOG_PERROR) { 208 struct iovec iov[2]; 209 210 iov[0].iov_base = stdp; 211 iov[0].iov_len = cnt > stdp - tbuf ? cnt - (stdp - tbuf) : 0; 212 iov[1].iov_base = "\n"; 213 iov[1].iov_len = 1; 214 (void)writev(STDERR_FILENO, iov, 2); 215 } 216 217 /* 218 * If the sendsyslog() fails, it means that syslogd 219 * is not running. 220 */ 221 error = sendsyslog(tbuf, cnt); 222 223 /* 224 * Output the message to the console; try not to block 225 * as a blocking console should not stop other processes. 226 * Make sure the error reported is the one from the syslogd failure. 227 */ 228 if (error == -1 && (data->log_stat & LOG_CONS) && 229 (fd = open(_PATH_CONSOLE, O_WRONLY|O_NONBLOCK, 0)) >= 0) { 230 struct iovec iov[2]; 231 232 iov[0].iov_base = conp; 233 iov[0].iov_len = cnt > conp - tbuf ? cnt - (conp - tbuf) : 0; 234 iov[1].iov_base = "\r\n"; 235 iov[1].iov_len = 2; 236 (void)writev(fd, iov, 2); 237 (void)close(fd); 238 } 239 } 240 241 void 242 openlog_r(const char *ident, int logstat, int logfac, struct syslog_data *data) 243 { 244 if (ident != NULL) 245 data->log_tag = ident; 246 data->log_stat = logstat; 247 if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0) 248 data->log_fac = logfac; 249 } 250 251 void 252 closelog_r(struct syslog_data *data) 253 { 254 data->log_tag = NULL; 255 } 256 257