1 /*-
2  * Copyright (c) 2017 Mariusz Zaborski <oshogbo@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/dnv.h>
31 #include <sys/nv.h>
32 
33 #include <assert.h>
34 #include <errno.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <syslog.h>
40 
41 #include <libcasper.h>
42 #include <libcasper_service.h>
43 
44 #include "cap_syslog.h"
45 
46 #define	CAP_SYSLOG_LIMIT	2048
47 
48 void
49 cap_syslog(cap_channel_t *chan, int pri, const char *fmt, ...)
50 {
51 	va_list ap;
52 
53 	va_start(ap, fmt);
54 	cap_vsyslog(chan, pri, fmt, ap);
55 	va_end(ap);
56 }
57 
58 void
59 cap_vsyslog(cap_channel_t *chan, int priority, const char *fmt, va_list ap)
60 {
61 	nvlist_t *nvl;
62 	char message[CAP_SYSLOG_LIMIT];
63 
64 	(void)vsnprintf(message, sizeof(message), fmt, ap);
65 
66 	nvl = nvlist_create(0);
67 	nvlist_add_string(nvl, "cmd", "vsyslog");
68 	nvlist_add_number(nvl, "priority", priority);
69 	nvlist_add_string(nvl, "message", message);
70 	nvl = cap_xfer_nvlist(chan, nvl, 0);
71 	if (nvl == NULL) {
72 		return;
73 	}
74 	nvlist_destroy(nvl);
75 }
76 
77 void
78 cap_openlog(cap_channel_t *chan, const char *ident, int logopt, int facility)
79 {
80 	nvlist_t *nvl;
81 
82 	nvl = nvlist_create(0);
83 	nvlist_add_string(nvl, "cmd", "openlog");
84 	if (ident != NULL) {
85 		nvlist_add_string(nvl, "ident", ident);
86 	}
87 	nvlist_add_number(nvl, "logopt", logopt);
88 	nvlist_add_number(nvl, "facility", facility);
89 	nvl = cap_xfer_nvlist(chan, nvl, 0);
90 	if (nvl == NULL) {
91 		return;
92 	}
93 	nvlist_destroy(nvl);
94 }
95 
96 void
97 cap_closelog(cap_channel_t *chan)
98 {
99 	nvlist_t *nvl;
100 
101 	nvl = nvlist_create(0);
102 	nvlist_add_string(nvl, "cmd", "closelog");
103 	nvl = cap_xfer_nvlist(chan, nvl, 0);
104 	if (nvl == NULL) {
105 		return;
106 	}
107 	nvlist_destroy(nvl);
108 }
109 
110 int
111 cap_setlogmask(cap_channel_t *chan, int maskpri)
112 {
113 	nvlist_t *nvl;
114 	int omask;
115 
116 	nvl = nvlist_create(0);
117 	nvlist_add_string(nvl, "cmd", "setlogmask");
118 	nvlist_add_number(nvl, "maskpri", maskpri);
119 	nvl = cap_xfer_nvlist(chan, nvl, 0);
120 	omask = nvlist_get_number(nvl, "omask");
121 
122 	nvlist_destroy(nvl);
123 
124 	return (omask);
125 }
126 
127 /*
128  * Service functions.
129  */
130 
131 static char *LogTag;
132 
133 static void
134 slog_vsyslog(const nvlist_t *limits __unused, const nvlist_t *nvlin,
135     nvlist_t *nvlout __unused)
136 {
137 
138 	syslog(nvlist_get_number(nvlin, "priority"), "%s",
139 	    nvlist_get_string(nvlin, "message"));
140 }
141 
142 static void
143 slog_openlog(const nvlist_t *limits __unused, const nvlist_t *nvlin,
144     nvlist_t *nvlout __unused)
145 {
146 	const char *ident;
147 
148 	ident = dnvlist_get_string(nvlin, "ident", NULL);
149 	if (ident != NULL) {
150 		free(LogTag);
151 		LogTag = strdup(ident);
152 	}
153 
154 	openlog(LogTag, nvlist_get_number(nvlin, "logopt"),
155 	    nvlist_get_number(nvlin, "facility"));
156 }
157 
158 static void
159 slog_closelog(const nvlist_t *limits __unused, const nvlist_t *nvlin __unused,
160     nvlist_t *nvlout __unused)
161 {
162 
163 	closelog();
164 
165 	free(LogTag);
166 	LogTag = NULL;
167 }
168 
169 static void
170 slog_setlogmask(const nvlist_t *limits __unused, const nvlist_t *nvlin,
171     nvlist_t *nvlout)
172 {
173 	int omask;
174 
175 	omask = setlogmask(nvlist_get_number(nvlin, "maskpri"));
176 	nvlist_add_number(nvlout, "omask", omask);
177 }
178 
179 static int
180 syslog_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
181     nvlist_t *nvlout)
182 {
183 
184 	if (strcmp(cmd, "vsyslog") == 0) {
185 		slog_vsyslog(limits, nvlin, nvlout);
186 	} else if (strcmp(cmd, "openlog") == 0) {
187 		slog_openlog(limits, nvlin, nvlout);
188 	} else if (strcmp(cmd, "closelog") == 0) {
189 		slog_closelog(limits, nvlin, nvlout);
190 	} else if (strcmp(cmd, "setlogmask") == 0) {
191 		slog_setlogmask(limits, nvlin, nvlout);
192 	} else {
193 		return (EINVAL);
194 	}
195 
196 	return (0);
197 }
198 
199 CREATE_SERVICE("system.syslog", NULL, syslog_command, 0);
200