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 // clinic/syslogmodule.c.h uses internal pycore_modsupport.h API
53 #ifndef Py_BUILD_CORE_BUILTIN
54 # define Py_BUILD_CORE_MODULE 1
55 #endif
56
57 #include "Python.h"
58 #include "osdefs.h" // SEP
59
60 #include <syslog.h>
61
62 /*[clinic input]
63 module syslog
64 [clinic start generated code]*/
65 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=478f4ac94a1d4cae]*/
66
67 #include "clinic/syslogmodule.c.h"
68
69 /* only one instance, only one syslog, so globals should be ok,
70 * these fields are writable from the main interpreter only. */
71 static PyObject *S_ident_o = NULL; // identifier, held by openlog()
72 static char S_log_open = 0;
73
74 static inline int
is_main_interpreter(void)75 is_main_interpreter(void)
76 {
77 return (PyInterpreterState_Get() == PyInterpreterState_Main());
78 }
79
80 static PyObject *
syslog_get_argv(void)81 syslog_get_argv(void)
82 {
83 /* Figure out what to use for as the program "ident" for openlog().
84 * This swallows exceptions and continues rather than failing out,
85 * because the syslog module can still be used because openlog(3)
86 * is optional.
87 */
88
89 Py_ssize_t argv_len, scriptlen;
90 PyObject *scriptobj;
91 Py_ssize_t slash;
92 PyObject *argv = PySys_GetObject("argv");
93
94 if (argv == NULL) {
95 return(NULL);
96 }
97
98 argv_len = PyList_Size(argv);
99 if (argv_len == -1) {
100 PyErr_Clear();
101 return(NULL);
102 }
103 if (argv_len == 0) {
104 return(NULL);
105 }
106
107 scriptobj = PyList_GetItem(argv, 0);
108 if (scriptobj == NULL) {
109 PyErr_Clear();
110 return NULL;
111 }
112 if (!PyUnicode_Check(scriptobj)) {
113 return(NULL);
114 }
115 scriptlen = PyUnicode_GET_LENGTH(scriptobj);
116 if (scriptlen == 0) {
117 return(NULL);
118 }
119
120 slash = PyUnicode_FindChar(scriptobj, SEP, 0, scriptlen, -1);
121 if (slash == -2) {
122 PyErr_Clear();
123 return NULL;
124 }
125 if (slash != -1) {
126 return PyUnicode_Substring(scriptobj, slash + 1, scriptlen);
127 } else {
128 Py_INCREF(scriptobj);
129 return(scriptobj);
130 }
131 }
132
133
134 /*[clinic input]
135 @critical_section
136 syslog.openlog
137
138 ident: unicode = NULL
139 logoption as logopt: long = 0
140 facility: long(c_default="LOG_USER") = LOG_USER
141
142 Set logging options of subsequent syslog() calls.
143 [clinic start generated code]*/
144
145 static PyObject *
syslog_openlog_impl(PyObject * module,PyObject * ident,long logopt,long facility)146 syslog_openlog_impl(PyObject *module, PyObject *ident, long logopt,
147 long facility)
148 /*[clinic end generated code: output=5476c12829b6eb75 input=ee700b8786f81c23]*/
149 {
150 // Since the sys.openlog changes the process level state of syslog library,
151 // this operation is only allowed for the main interpreter.
152 if (!is_main_interpreter()) {
153 PyErr_SetString(PyExc_RuntimeError, "subinterpreter can't use syslog.openlog()");
154 return NULL;
155 }
156
157 const char *ident_str = NULL;
158
159 if (ident) {
160 Py_INCREF(ident);
161 }
162 else {
163 /* get sys.argv[0] or NULL if we can't for some reason */
164 ident = syslog_get_argv();
165 }
166
167 /* At this point, ident should be INCREF()ed. openlog(3) does not
168 * make a copy, and syslog(3) later uses it. We can't garbagecollect it.
169 * If NULL, just let openlog figure it out (probably using C argv[0]).
170 */
171 if (ident) {
172 ident_str = PyUnicode_AsUTF8(ident);
173 if (ident_str == NULL) {
174 Py_DECREF(ident);
175 return NULL;
176 }
177 }
178 if (PySys_Audit("syslog.openlog", "Oll", ident ? ident : Py_None, logopt, facility) < 0) {
179 Py_DECREF(ident);
180 return NULL;
181 }
182
183 openlog(ident_str, logopt, facility);
184 S_log_open = 1;
185 Py_XSETREF(S_ident_o, ident);
186
187 Py_RETURN_NONE;
188 }
189
190
191
192 /*[clinic input]
193 @critical_section
194 syslog.syslog
195
196 [
197 priority: int(c_default="LOG_INFO") = LOG_INFO
198 ]
199
200 message: str
201
202 /
203
204 Send the string message to the system logger.
205 [clinic start generated code]*/
206
207 static PyObject *
syslog_syslog_impl(PyObject * module,int group_left_1,int priority,const char * message)208 syslog_syslog_impl(PyObject *module, int group_left_1, int priority,
209 const char *message)
210 /*[clinic end generated code: output=c3dbc73445a0e078 input=6588ddb0b113af8e]*/
211 {
212 if (PySys_Audit("syslog.syslog", "is", priority, message) < 0) {
213 return NULL;
214 }
215
216 /* if log is not opened, open it now */
217 if (!S_log_open) {
218 if (!is_main_interpreter()) {
219 PyErr_SetString(PyExc_RuntimeError, "subinterpreter can't use syslog.syslog() "
220 "until the syslog is opened by the main interpreter");
221 return NULL;
222 }
223 PyObject *openlog_ret = syslog_openlog_impl(module, NULL, 0, LOG_USER);
224 if (openlog_ret == NULL) {
225 return NULL;
226 }
227 Py_DECREF(openlog_ret);
228 }
229
230 /* Incref ident, because it can be decrefed if syslog.openlog() is
231 * called when the GIL is released.
232 */
233 PyObject *ident = Py_XNewRef(S_ident_o);
234 #ifdef __APPLE__
235 // gh-98178: On macOS, libc syslog() is not thread-safe
236 syslog(priority, "%s", message);
237 #else
238 Py_BEGIN_ALLOW_THREADS;
239 syslog(priority, "%s", message);
240 Py_END_ALLOW_THREADS;
241 #endif
242 Py_XDECREF(ident);
243 Py_RETURN_NONE;
244 }
245
246
247 /*[clinic input]
248 @critical_section
249 syslog.closelog
250
251 Reset the syslog module values and call the system library closelog().
252 [clinic start generated code]*/
253
254 static PyObject *
syslog_closelog_impl(PyObject * module)255 syslog_closelog_impl(PyObject *module)
256 /*[clinic end generated code: output=97890a80a24b1b84 input=167f489868bd5a72]*/
257 {
258 // Since the sys.closelog changes the process level state of syslog library,
259 // this operation is only allowed for the main interpreter.
260 if (!is_main_interpreter()) {
261 PyErr_SetString(PyExc_RuntimeError, "sunbinterpreter can't use syslog.closelog()");
262 return NULL;
263 }
264
265 if (PySys_Audit("syslog.closelog", NULL) < 0) {
266 return NULL;
267 }
268 if (S_log_open) {
269 closelog();
270 Py_CLEAR(S_ident_o);
271 S_log_open = 0;
272 }
273 Py_RETURN_NONE;
274 }
275
276 /*[clinic input]
277 syslog.setlogmask -> long
278
279 maskpri: long
280 /
281
282 Set the priority mask to maskpri and return the previous mask value.
283 [clinic start generated code]*/
284
285 static long
syslog_setlogmask_impl(PyObject * module,long maskpri)286 syslog_setlogmask_impl(PyObject *module, long maskpri)
287 /*[clinic end generated code: output=d6ed163917b434bf input=adff2c2b76c7629c]*/
288 {
289 if (PySys_Audit("syslog.setlogmask", "l", maskpri) < 0) {
290 return -1;
291 }
292
293 return setlogmask(maskpri);
294 }
295
296 /*[clinic input]
297 syslog.LOG_MASK -> long
298
299 pri: long
300 /
301
302 Calculates the mask for the individual priority pri.
303 [clinic start generated code]*/
304
305 static long
syslog_LOG_MASK_impl(PyObject * module,long pri)306 syslog_LOG_MASK_impl(PyObject *module, long pri)
307 /*[clinic end generated code: output=c4a5bbfcc74c7c94 input=534829cb7fb5f7d2]*/
308 {
309 return LOG_MASK(pri);
310 }
311
312 /*[clinic input]
313 syslog.LOG_UPTO -> long
314
315 pri: long
316 /
317
318 Calculates the mask for all priorities up to and including pri.
319 [clinic start generated code]*/
320
321 static long
syslog_LOG_UPTO_impl(PyObject * module,long pri)322 syslog_LOG_UPTO_impl(PyObject *module, long pri)
323 /*[clinic end generated code: output=9eab083c90601d7e input=5e906d6c406b7458]*/
324 {
325 return LOG_UPTO(pri);
326 }
327
328 /* List of functions defined in the module */
329
330 static PyMethodDef syslog_methods[] = {
331 SYSLOG_OPENLOG_METHODDEF
332 SYSLOG_CLOSELOG_METHODDEF
333 SYSLOG_SYSLOG_METHODDEF
334 SYSLOG_SETLOGMASK_METHODDEF
335 SYSLOG_LOG_MASK_METHODDEF
336 SYSLOG_LOG_UPTO_METHODDEF
337 {NULL, NULL, 0}
338 };
339
340
341 static int
syslog_exec(PyObject * module)342 syslog_exec(PyObject *module)
343 {
344 #define ADD_INT_MACRO(module, macro) \
345 do { \
346 if (PyModule_AddIntConstant(module, #macro, macro) < 0) { \
347 return -1; \
348 } \
349 } while (0)
350 /* Priorities */
351 ADD_INT_MACRO(module, LOG_EMERG);
352 ADD_INT_MACRO(module, LOG_ALERT);
353 ADD_INT_MACRO(module, LOG_CRIT);
354 ADD_INT_MACRO(module, LOG_ERR);
355 ADD_INT_MACRO(module, LOG_WARNING);
356 ADD_INT_MACRO(module, LOG_NOTICE);
357 ADD_INT_MACRO(module, LOG_INFO);
358 ADD_INT_MACRO(module, LOG_DEBUG);
359
360 /* openlog() option flags */
361 ADD_INT_MACRO(module, LOG_PID);
362 ADD_INT_MACRO(module, LOG_CONS);
363 ADD_INT_MACRO(module, LOG_NDELAY);
364 #ifdef LOG_ODELAY
365 ADD_INT_MACRO(module, LOG_ODELAY);
366 #endif
367 #ifdef LOG_NOWAIT
368 ADD_INT_MACRO(module, LOG_NOWAIT);
369 #endif
370 #ifdef LOG_PERROR
371 ADD_INT_MACRO(module, LOG_PERROR);
372 #endif
373
374 /* Facilities */
375 ADD_INT_MACRO(module, LOG_KERN);
376 ADD_INT_MACRO(module, LOG_USER);
377 ADD_INT_MACRO(module, LOG_MAIL);
378 ADD_INT_MACRO(module, LOG_DAEMON);
379 ADD_INT_MACRO(module, LOG_AUTH);
380 ADD_INT_MACRO(module, LOG_LPR);
381 ADD_INT_MACRO(module, LOG_LOCAL0);
382 ADD_INT_MACRO(module, LOG_LOCAL1);
383 ADD_INT_MACRO(module, LOG_LOCAL2);
384 ADD_INT_MACRO(module, LOG_LOCAL3);
385 ADD_INT_MACRO(module, LOG_LOCAL4);
386 ADD_INT_MACRO(module, LOG_LOCAL5);
387 ADD_INT_MACRO(module, LOG_LOCAL6);
388 ADD_INT_MACRO(module, LOG_LOCAL7);
389
390 #ifndef LOG_SYSLOG
391 #define LOG_SYSLOG LOG_DAEMON
392 #endif
393 #ifndef LOG_NEWS
394 #define LOG_NEWS LOG_MAIL
395 #endif
396 #ifndef LOG_UUCP
397 #define LOG_UUCP LOG_MAIL
398 #endif
399 #ifndef LOG_CRON
400 #define LOG_CRON LOG_DAEMON
401 #endif
402
403 ADD_INT_MACRO(module, LOG_SYSLOG);
404 ADD_INT_MACRO(module, LOG_CRON);
405 ADD_INT_MACRO(module, LOG_UUCP);
406 ADD_INT_MACRO(module, LOG_NEWS);
407
408 #ifdef LOG_AUTHPRIV
409 ADD_INT_MACRO(module, LOG_AUTHPRIV);
410 #endif
411
412 #ifdef LOG_FTP
413 ADD_INT_MACRO(module, LOG_FTP);
414 #endif
415
416 #ifdef LOG_NETINFO
417 ADD_INT_MACRO(module, LOG_NETINFO);
418 #endif
419
420 #ifdef LOG_REMOTEAUTH
421 ADD_INT_MACRO(module, LOG_REMOTEAUTH);
422 #endif
423
424 #ifdef LOG_INSTALL
425 ADD_INT_MACRO(module, LOG_INSTALL);
426 #endif
427
428 #ifdef LOG_RAS
429 ADD_INT_MACRO(module, LOG_RAS);
430 #endif
431
432 #ifdef LOG_LAUNCHD
433 ADD_INT_MACRO(module, LOG_LAUNCHD);
434 #endif
435
436 return 0;
437 }
438
439 static PyModuleDef_Slot syslog_slots[] = {
440 {Py_mod_exec, syslog_exec},
441 {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
442 {Py_mod_gil, Py_MOD_GIL_NOT_USED},
443 {0, NULL}
444 };
445
446 /* Initialization function for the module */
447
448 static struct PyModuleDef syslogmodule = {
449 PyModuleDef_HEAD_INIT,
450 .m_name = "syslog",
451 .m_size = 0,
452 .m_methods = syslog_methods,
453 .m_slots = syslog_slots,
454 };
455
456 PyMODINIT_FUNC
PyInit_syslog(void)457 PyInit_syslog(void)
458 {
459 return PyModuleDef_Init(&syslogmodule);
460 }
461