• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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