* Handle the work of transmitting the syslog message */
| 165 | * Handle the work of transmitting the syslog message |
| 166 | */ |
| 167 | static void |
| 168 | xo_send_syslog (char *full_msg, char *v0_hdr, |
| 169 | char *text_only) |
| 170 | { |
| 171 | if (xo_syslog_send) { |
| 172 | xo_syslog_send(full_msg, v0_hdr, text_only); |
| 173 | return; |
| 174 | } |
| 175 | |
| 176 | int fd; |
| 177 | int full_len = strlen(full_msg); |
| 178 | |
| 179 | /* Output to stderr if requested, then we've been passed a v0 header */ |
| 180 | if (v0_hdr) { |
| 181 | struct iovec iov[3]; |
| 182 | struct iovec *v = iov; |
| 183 | char newline[] = "\n"; |
| 184 | |
| 185 | v->iov_base = v0_hdr; |
| 186 | v->iov_len = strlen(v0_hdr); |
| 187 | v += 1; |
| 188 | v->iov_base = text_only; |
| 189 | v->iov_len = strlen(text_only); |
| 190 | v += 1; |
| 191 | v->iov_base = newline; |
| 192 | v->iov_len = 1; |
| 193 | v += 1; |
| 194 | REAL_VOID(writev(STDERR_FILENO, iov, 3)); |
| 195 | } |
| 196 | |
| 197 | /* Get connected, output the message to the local logger. */ |
| 198 | if (!xo_opened) |
| 199 | xo_open_log_unlocked(xo_logtag, xo_logstat | LOG_NDELAY, 0); |
| 200 | xo_connect_log(); |
| 201 | |
| 202 | /* |
| 203 | * If the send() fails, there are two likely scenarios: |
| 204 | * 1) syslogd was restarted |
| 205 | * 2) /var/run/log is out of socket buffer space, which |
| 206 | * in most cases means local DoS. |
| 207 | * If the error does not indicate a full buffer, we address |
| 208 | * case #1 by attempting to reconnect to /var/run/log[priv] |
| 209 | * and resending the message once. |
| 210 | * |
| 211 | * If we are working with a privileged socket, the retry |
| 212 | * attempts end there, because we don't want to freeze a |
| 213 | * critical application like su(1) or sshd(8). |
| 214 | * |
| 215 | * Otherwise, we address case #2 by repeatedly retrying the |
| 216 | * send() to give syslogd a chance to empty its socket buffer. |
| 217 | */ |
| 218 | |
| 219 | if (send(xo_logfile, full_msg, full_len, 0) < 0) { |
| 220 | if (errno != ENOBUFS) { |
| 221 | /* |
| 222 | * Scenario 1: syslogd was restarted |
| 223 | * reconnect and resend once |
| 224 | */ |
no test coverage detected