1 /*
2 Copyright 2021 Northern.tech AS
3
4 This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; version 3.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18
19 To the extent this program is licensed as part of the Enterprise
20 versions of CFEngine, the applicable Commercial Open Source License
21 (COSL) may apply to this file if you as a licensee so wish it. See
22 included file COSL.txt.
23 */
24
25 #include <syslog_client.h>
26 #include <printsize.h>
27
28 #include <cf3.defs.h>
29
30 /*
31 * Set by cf-agent/cf-serverd from body agent/server control.
32 */
33 static char SYSLOG_HOST[MAXHOSTNAMELEN] = "localhost";
34 /*
35 * Set by cf-agent/cf-serverd from body agent/server control.
36 */
37 static uint16_t SYSLOG_PORT = 514;
38 /*
39 * Set by cf-agent/cf-serverd/cf-execd from body agent/exec/server control.
40 */
41 static int SYSLOG_FACILITY = LOG_USER;
42
43
SetSyslogFacility(int facility)44 void SetSyslogFacility(int facility)
45 {
46 SYSLOG_FACILITY = facility;
47 }
48
GetSyslogFacility()49 int GetSyslogFacility()
50 {
51 return SYSLOG_FACILITY;
52 }
53
SetSyslogHost(const char * host)54 bool SetSyslogHost(const char *host)
55 {
56 if (strlen(host) < sizeof(SYSLOG_HOST))
57 {
58 strcpy(SYSLOG_HOST, host);
59 return true;
60 }
61 else
62 {
63 return false;
64 }
65 }
66
SetSyslogPort(uint16_t port)67 void SetSyslogPort(uint16_t port)
68 {
69 SYSLOG_PORT = port;
70 }
71
RemoteSysLog(int log_priority,const char * log_string)72 void RemoteSysLog(int log_priority, const char *log_string)
73 {
74 time_t now = time(NULL);
75
76 struct addrinfo query = { 0 }, *response = NULL;
77 char strport[PRINTSIZE(unsigned)];
78 xsnprintf(strport, sizeof(strport), "%u", (unsigned) SYSLOG_PORT);
79
80 query.ai_family = AF_UNSPEC;
81 query.ai_socktype = SOCK_DGRAM;
82
83 int err = getaddrinfo(SYSLOG_HOST, strport, &query, &response);
84 if (err != 0)
85 {
86 Log(LOG_LEVEL_INFO,
87 "Unable to find syslog_host or service: (%s/%s) %s",
88 SYSLOG_HOST, strport, gai_strerror(err));
89 if (response != NULL)
90 {
91 freeaddrinfo(response);
92 }
93 return;
94 }
95
96 for (const struct addrinfo *ap = response; ap != NULL; ap = ap->ai_next)
97 {
98 /* No DNS lookup, just convert IP address to string. */
99 char txtaddr[CF_MAX_IP_LEN] = "";
100 getnameinfo(ap->ai_addr, ap->ai_addrlen,
101 txtaddr, sizeof(txtaddr),
102 NULL, 0, NI_NUMERICHOST);
103 Log(LOG_LEVEL_VERBOSE,
104 "Connect to syslog '%s' = '%s' on port '%s'",
105 SYSLOG_HOST, txtaddr, strport);
106
107 int sd = socket(ap->ai_family, ap->ai_socktype, IPPROTO_UDP);
108 if (sd == -1)
109 {
110 Log(LOG_LEVEL_INFO, "Couldn't open a socket. (socket: %s)", GetErrorStr());
111 continue;
112 }
113 else
114 {
115 const size_t rfc3164_len = 1024;
116 char message[rfc3164_len];
117 char timebuffer[26];
118 pid_t pid = getpid();
119
120 snprintf(
121 message,
122 sizeof(message),
123 "<%i>%.15s %s %s[%ld]: %s",
124 (log_priority | SYSLOG_FACILITY),
125 (cf_strtimestamp_local(now, timebuffer) + 4), // Skips day str
126 VFQNAME,
127 VPREFIX,
128 (long) pid,
129 log_string);
130 err = sendto(sd, message, strlen(message),
131 0, ap->ai_addr, ap->ai_addrlen);
132 if (err == -1)
133 {
134 Log(LOG_LEVEL_VERBOSE, "Couldn't send '%s' to syslog server '%s'. (sendto: %s)",
135 message, SYSLOG_HOST, GetErrorStr());
136 }
137 else
138 {
139 Log(LOG_LEVEL_VERBOSE, "Syslog message: '%s' to server '%s'", message, SYSLOG_HOST);
140 }
141 close(sd);
142 }
143 }
144
145 freeaddrinfo(response);
146 }
147