Branch data Line data Source code
1 : : /***********************************************************
2 : : Copyright 1994 by Lance Ellinghouse,
3 : : Cathedral City, California Republic, United States of America.
4 : :
5 : : All Rights Reserved
6 : :
7 : : Permission to use, copy, modify, and distribute this software and its
8 : : documentation for any purpose and without fee is hereby granted,
9 : : provided that the above copyright notice appear in all copies and that
10 : : both that copyright notice and this permission notice appear in
11 : : supporting documentation, and that the name of Lance Ellinghouse
12 : : not be used in advertising or publicity pertaining to distribution
13 : : of the software without specific, written prior permission.
14 : :
15 : : LANCE ELLINGHOUSE DISCLAIMS ALL WARRANTIES WITH REGARD TO
16 : : THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 : : FITNESS, IN NO EVENT SHALL LANCE ELLINGHOUSE BE LIABLE FOR ANY SPECIAL,
18 : : INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
19 : : FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20 : : NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
21 : : WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 : :
23 : : ******************************************************************/
24 : :
25 : : /******************************************************************
26 : :
27 : : Revision history:
28 : :
29 : : 2010/04/20 (Sean Reifschneider)
30 : : - Use basename(sys.argv[0]) for the default "ident".
31 : : - Arguments to openlog() are now keyword args and are all optional.
32 : : - syslog() calls openlog() if it hasn't already been called.
33 : :
34 : : 1998/04/28 (Sean Reifschneider)
35 : : - When facility not specified to syslog() method, use default from openlog()
36 : : (This is how it was claimed to work in the documentation)
37 : : - Potential resource leak of o_ident, now cleaned up in closelog()
38 : : - Minor comment accuracy fix.
39 : :
40 : : 95/06/29 (Steve Clift)
41 : : - Changed arg parsing to use PyArg_ParseTuple.
42 : : - Added PyErr_Clear() call(s) where needed.
43 : : - Fix core dumps if user message contains format specifiers.
44 : : - Change openlog arg defaults to match normal syslog behavior.
45 : : - Plug memory leak in openlog().
46 : : - Fix setlogmask() to return previous mask value.
47 : :
48 : : ******************************************************************/
49 : :
50 : : /* syslog module */
51 : :
52 : : #include "Python.h"
53 : : #include "osdefs.h" // SEP
54 : :
55 : : #include <syslog.h>
56 : :
57 : : /*[clinic input]
58 : : module syslog
59 : : [clinic start generated code]*/
60 : : /*[clinic end generated code: output=da39a3ee5e6b4b0d input=478f4ac94a1d4cae]*/
61 : :
62 : : #include "clinic/syslogmodule.c.h"
63 : :
64 : : /* only one instance, only one syslog, so globals should be ok,
65 : : * these fields are writable from the main interpreter only. */
66 : : static PyObject *S_ident_o = NULL; // identifier, held by openlog()
67 : : static char S_log_open = 0;
68 : :
69 : : static inline int
70 : 0 : is_main_interpreter(void)
71 : : {
72 : 0 : return (PyInterpreterState_Get() == PyInterpreterState_Main());
73 : : }
74 : :
75 : : static PyObject *
76 : 0 : syslog_get_argv(void)
77 : : {
78 : : /* Figure out what to use for as the program "ident" for openlog().
79 : : * This swallows exceptions and continues rather than failing out,
80 : : * because the syslog module can still be used because openlog(3)
81 : : * is optional.
82 : : */
83 : :
84 : : Py_ssize_t argv_len, scriptlen;
85 : : PyObject *scriptobj;
86 : : Py_ssize_t slash;
87 : 0 : PyObject *argv = PySys_GetObject("argv");
88 : :
89 [ # # ]: 0 : if (argv == NULL) {
90 : 0 : return(NULL);
91 : : }
92 : :
93 : 0 : argv_len = PyList_Size(argv);
94 [ # # ]: 0 : if (argv_len == -1) {
95 : 0 : PyErr_Clear();
96 : 0 : return(NULL);
97 : : }
98 [ # # ]: 0 : if (argv_len == 0) {
99 : 0 : return(NULL);
100 : : }
101 : :
102 : 0 : scriptobj = PyList_GetItem(argv, 0);
103 [ # # ]: 0 : if (scriptobj == NULL) {
104 : 0 : PyErr_Clear();
105 : 0 : return NULL;
106 : : }
107 [ # # ]: 0 : if (!PyUnicode_Check(scriptobj)) {
108 : 0 : return(NULL);
109 : : }
110 : 0 : scriptlen = PyUnicode_GET_LENGTH(scriptobj);
111 [ # # ]: 0 : if (scriptlen == 0) {
112 : 0 : return(NULL);
113 : : }
114 : :
115 : 0 : slash = PyUnicode_FindChar(scriptobj, SEP, 0, scriptlen, -1);
116 [ # # ]: 0 : if (slash == -2) {
117 : 0 : PyErr_Clear();
118 : 0 : return NULL;
119 : : }
120 [ # # ]: 0 : if (slash != -1) {
121 : 0 : return PyUnicode_Substring(scriptobj, slash + 1, scriptlen);
122 : : } else {
123 : 0 : Py_INCREF(scriptobj);
124 : 0 : return(scriptobj);
125 : : }
126 : : }
127 : :
128 : :
129 : : /*[clinic input]
130 : : syslog.openlog
131 : :
132 : : ident: unicode = NULL
133 : : logoption as logopt: long = 0
134 : : facility: long(c_default="LOG_USER") = LOG_USER
135 : :
136 : : Set logging options of subsequent syslog() calls.
137 : : [clinic start generated code]*/
138 : :
139 : : static PyObject *
140 : 0 : syslog_openlog_impl(PyObject *module, PyObject *ident, long logopt,
141 : : long facility)
142 : : /*[clinic end generated code: output=5476c12829b6eb75 input=8a987a96a586eee7]*/
143 : : {
144 : : // Since the sys.openlog changes the process level state of syslog library,
145 : : // this operation is only allowed for the main interpreter.
146 [ # # ]: 0 : if (!is_main_interpreter()) {
147 : 0 : PyErr_SetString(PyExc_RuntimeError, "subinterpreter can't use syslog.openlog()");
148 : 0 : return NULL;
149 : : }
150 : :
151 : 0 : const char *ident_str = NULL;
152 : :
153 [ # # ]: 0 : if (ident) {
154 : 0 : Py_INCREF(ident);
155 : : }
156 : : else {
157 : : /* get sys.argv[0] or NULL if we can't for some reason */
158 : 0 : ident = syslog_get_argv();
159 : : }
160 : :
161 : : /* At this point, ident should be INCREF()ed. openlog(3) does not
162 : : * make a copy, and syslog(3) later uses it. We can't garbagecollect it.
163 : : * If NULL, just let openlog figure it out (probably using C argv[0]).
164 : : */
165 [ # # ]: 0 : if (ident) {
166 : 0 : ident_str = PyUnicode_AsUTF8(ident);
167 [ # # ]: 0 : if (ident_str == NULL) {
168 : 0 : Py_DECREF(ident);
169 : 0 : return NULL;
170 : : }
171 : : }
172 [ # # # # ]: 0 : if (PySys_Audit("syslog.openlog", "Oll", ident ? ident : Py_None, logopt, facility) < 0) {
173 : 0 : Py_DECREF(ident);
174 : 0 : return NULL;
175 : : }
176 : :
177 : 0 : openlog(ident_str, logopt, facility);
178 : 0 : S_log_open = 1;
179 : 0 : Py_XSETREF(S_ident_o, ident);
180 : :
181 : 0 : Py_RETURN_NONE;
182 : : }
183 : :
184 : :
185 : :
186 : : /*[clinic input]
187 : : syslog.syslog
188 : :
189 : : [
190 : : priority: int(c_default="LOG_INFO") = LOG_INFO
191 : : ]
192 : :
193 : : message: str
194 : :
195 : : /
196 : :
197 : : Send the string message to the system logger.
198 : : [clinic start generated code]*/
199 : :
200 : : static PyObject *
201 : 0 : syslog_syslog_impl(PyObject *module, int group_left_1, int priority,
202 : : const char *message)
203 : : /*[clinic end generated code: output=c3dbc73445a0e078 input=ac83d92b12ea3d4e]*/
204 : : {
205 [ # # ]: 0 : if (PySys_Audit("syslog.syslog", "is", priority, message) < 0) {
206 : 0 : return NULL;
207 : : }
208 : :
209 : : /* if log is not opened, open it now */
210 [ # # ]: 0 : if (!S_log_open) {
211 [ # # ]: 0 : if (!is_main_interpreter()) {
212 : 0 : PyErr_SetString(PyExc_RuntimeError, "subinterpreter can't use syslog.syslog() "
213 : : "until the syslog is opened by the main interpreter");
214 : 0 : return NULL;
215 : : }
216 : 0 : PyObject *openlog_ret = syslog_openlog_impl(module, NULL, 0, LOG_USER);
217 [ # # ]: 0 : if (openlog_ret == NULL) {
218 : 0 : return NULL;
219 : : }
220 : 0 : Py_DECREF(openlog_ret);
221 : : }
222 : :
223 : : /* Incref ident, because it can be decrefed if syslog.openlog() is
224 : : * called when the GIL is released.
225 : : */
226 : 0 : PyObject *ident = Py_XNewRef(S_ident_o);
227 : : #ifdef __APPLE__
228 : : // gh-98178: On macOS, libc syslog() is not thread-safe
229 : : syslog(priority, "%s", message);
230 : : #else
231 : 0 : Py_BEGIN_ALLOW_THREADS;
232 : 0 : syslog(priority, "%s", message);
233 : 0 : Py_END_ALLOW_THREADS;
234 : : #endif
235 : 0 : Py_XDECREF(ident);
236 : 0 : Py_RETURN_NONE;
237 : : }
238 : :
239 : :
240 : : /*[clinic input]
241 : : syslog.closelog
242 : :
243 : : Reset the syslog module values and call the system library closelog().
244 : : [clinic start generated code]*/
245 : :
246 : : static PyObject *
247 : 0 : syslog_closelog_impl(PyObject *module)
248 : : /*[clinic end generated code: output=97890a80a24b1b84 input=fb77a54d447acf07]*/
249 : : {
250 : : // Since the sys.closelog changes the process level state of syslog library,
251 : : // this operation is only allowed for the main interpreter.
252 [ # # ]: 0 : if (!is_main_interpreter()) {
253 : 0 : PyErr_SetString(PyExc_RuntimeError, "sunbinterpreter can't use syslog.closelog()");
254 : 0 : return NULL;
255 : : }
256 : :
257 [ # # ]: 0 : if (PySys_Audit("syslog.closelog", NULL) < 0) {
258 : 0 : return NULL;
259 : : }
260 [ # # ]: 0 : if (S_log_open) {
261 : 0 : closelog();
262 [ # # ]: 0 : Py_CLEAR(S_ident_o);
263 : 0 : S_log_open = 0;
264 : : }
265 : 0 : Py_RETURN_NONE;
266 : : }
267 : :
268 : : /*[clinic input]
269 : : syslog.setlogmask -> long
270 : :
271 : : maskpri: long
272 : : /
273 : :
274 : : Set the priority mask to maskpri and return the previous mask value.
275 : : [clinic start generated code]*/
276 : :
277 : : static long
278 : 0 : syslog_setlogmask_impl(PyObject *module, long maskpri)
279 : : /*[clinic end generated code: output=d6ed163917b434bf input=adff2c2b76c7629c]*/
280 : : {
281 [ # # ]: 0 : if (PySys_Audit("syslog.setlogmask", "l", maskpri) < 0) {
282 : 0 : return -1;
283 : : }
284 : :
285 : 0 : return setlogmask(maskpri);
286 : : }
287 : :
288 : : /*[clinic input]
289 : : syslog.LOG_MASK -> long
290 : :
291 : : pri: long
292 : : /
293 : :
294 : : Calculates the mask for the individual priority pri.
295 : : [clinic start generated code]*/
296 : :
297 : : static long
298 : 0 : syslog_LOG_MASK_impl(PyObject *module, long pri)
299 : : /*[clinic end generated code: output=c4a5bbfcc74c7c94 input=534829cb7fb5f7d2]*/
300 : : {
301 : 0 : return LOG_MASK(pri);
302 : : }
303 : :
304 : : /*[clinic input]
305 : : syslog.LOG_UPTO -> long
306 : :
307 : : pri: long
308 : : /
309 : :
310 : : Calculates the mask for all priorities up to and including pri.
311 : : [clinic start generated code]*/
312 : :
313 : : static long
314 : 0 : syslog_LOG_UPTO_impl(PyObject *module, long pri)
315 : : /*[clinic end generated code: output=9eab083c90601d7e input=5e906d6c406b7458]*/
316 : : {
317 : 0 : return LOG_UPTO(pri);
318 : : }
319 : :
320 : : /* List of functions defined in the module */
321 : :
322 : : static PyMethodDef syslog_methods[] = {
323 : : SYSLOG_OPENLOG_METHODDEF
324 : : SYSLOG_CLOSELOG_METHODDEF
325 : : SYSLOG_SYSLOG_METHODDEF
326 : : SYSLOG_SETLOGMASK_METHODDEF
327 : : SYSLOG_LOG_MASK_METHODDEF
328 : : SYSLOG_LOG_UPTO_METHODDEF
329 : : {NULL, NULL, 0}
330 : : };
331 : :
332 : :
333 : : static int
334 : 1 : syslog_exec(PyObject *module)
335 : : {
336 : : #define ADD_INT_MACRO(module, macro) \
337 : : do { \
338 : : if (PyModule_AddIntConstant(module, #macro, macro) < 0) { \
339 : : return -1; \
340 : : } \
341 : : } while (0)
342 : : /* Priorities */
343 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_EMERG);
344 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_ALERT);
345 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_CRIT);
346 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_ERR);
347 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_WARNING);
348 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_NOTICE);
349 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_INFO);
350 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_DEBUG);
351 : :
352 : : /* openlog() option flags */
353 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_PID);
354 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_CONS);
355 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_NDELAY);
356 : : #ifdef LOG_ODELAY
357 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_ODELAY);
358 : : #endif
359 : : #ifdef LOG_NOWAIT
360 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_NOWAIT);
361 : : #endif
362 : : #ifdef LOG_PERROR
363 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_PERROR);
364 : : #endif
365 : :
366 : : /* Facilities */
367 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_KERN);
368 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_USER);
369 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_MAIL);
370 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_DAEMON);
371 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_AUTH);
372 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_LPR);
373 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_LOCAL0);
374 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_LOCAL1);
375 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_LOCAL2);
376 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_LOCAL3);
377 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_LOCAL4);
378 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_LOCAL5);
379 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_LOCAL6);
380 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_LOCAL7);
381 : :
382 : : #ifndef LOG_SYSLOG
383 : : #define LOG_SYSLOG LOG_DAEMON
384 : : #endif
385 : : #ifndef LOG_NEWS
386 : : #define LOG_NEWS LOG_MAIL
387 : : #endif
388 : : #ifndef LOG_UUCP
389 : : #define LOG_UUCP LOG_MAIL
390 : : #endif
391 : : #ifndef LOG_CRON
392 : : #define LOG_CRON LOG_DAEMON
393 : : #endif
394 : :
395 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_SYSLOG);
396 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_CRON);
397 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_UUCP);
398 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_NEWS);
399 : :
400 : : #ifdef LOG_AUTHPRIV
401 [ - + ]: 1 : ADD_INT_MACRO(module, LOG_AUTHPRIV);
402 : : #endif
403 : :
404 : 1 : return 0;
405 : : }
406 : :
407 : : static PyModuleDef_Slot syslog_slots[] = {
408 : : {Py_mod_exec, syslog_exec},
409 : : {0, NULL}
410 : : };
411 : :
412 : : /* Initialization function for the module */
413 : :
414 : : static struct PyModuleDef syslogmodule = {
415 : : PyModuleDef_HEAD_INIT,
416 : : .m_name = "syslog",
417 : : .m_size = 0,
418 : : .m_methods = syslog_methods,
419 : : .m_slots = syslog_slots,
420 : : };
421 : :
422 : : PyMODINIT_FUNC
423 : 1 : PyInit_syslog(void)
424 : : {
425 : 1 : return PyModuleDef_Init(&syslogmodule);
426 : : }
|