1/***********************************************************
2Copyright 1994 by Lance Ellinghouse,
3Cathedral City, California Republic, United States of America.
4
5 All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the name of Lance Ellinghouse
12not be used in advertising or publicity pertaining to distribution
13of the software without specific, written prior permission.
14
15LANCE ELLINGHOUSE DISCLAIMS ALL WARRANTIES WITH REGARD TO
16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17FITNESS, IN NO EVENT SHALL LANCE ELLINGHOUSE BE LIABLE FOR ANY SPECIAL,
18INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
19FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
21WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23******************************************************************/
24
25/******************************************************************
26
27Revision history:
28
292010/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
341998/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
4095/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/* only one instance, only one syslog, so globals should be ok */
58static PyObject *S_ident_o = NULL; /* identifier, held by openlog() */
59static char S_log_open = 0;
60
61
62static PyObject *
63syslog_get_argv(void)
64{
65 /* Figure out what to use for as the program "ident" for openlog().
66 * This swallows exceptions and continues rather than failing out,
67 * because the syslog module can still be used because openlog(3)
68 * is optional.
69 */
70
71 Py_ssize_t argv_len, scriptlen;
72 PyObject *scriptobj;
73 Py_ssize_t slash;
74 PyObject *argv = PySys_GetObject("argv");
75
76 if (argv == NULL) {
77 return(NULL);
78 }
79
80 argv_len = PyList_Size(argv);
81 if (argv_len == -1) {
82 PyErr_Clear();
83 return(NULL);
84 }
85 if (argv_len == 0) {
86 return(NULL);
87 }
88
89 scriptobj = PyList_GetItem(argv, 0);
90 if (!PyUnicode_Check(scriptobj)) {
91 return(NULL);
92 }
93 scriptlen = PyUnicode_GET_LENGTH(scriptobj);
94 if (scriptlen == 0) {
95 return(NULL);
96 }
97
98 slash = PyUnicode_FindChar(scriptobj, SEP, 0, scriptlen, -1);
99 if (slash == -2)
100 return NULL;
101 if (slash != -1) {
102 return PyUnicode_Substring(scriptobj, slash + 1, scriptlen);
103 } else {
104 Py_INCREF(scriptobj);
105 return(scriptobj);
106 }
107
108 return(NULL);
109}
110
111
112static PyObject *
113syslog_openlog(PyObject * self, PyObject * args, PyObject *kwds)
114{
115 long logopt = 0;
116 long facility = LOG_USER;
117 PyObject *new_S_ident_o = NULL;
118 static char *keywords[] = {"ident", "logoption", "facility", 0};
119 const char *ident = NULL;
120
121 if (!PyArg_ParseTupleAndKeywords(args, kwds,
122 "|Ull:openlog", keywords, &new_S_ident_o, &logopt, &facility))
123 return NULL;
124
125 if (new_S_ident_o) {
126 Py_INCREF(new_S_ident_o);
127 }
128
129 /* get sys.argv[0] or NULL if we can't for some reason */
130 if (!new_S_ident_o) {
131 new_S_ident_o = syslog_get_argv();
132 }
133
134 Py_XDECREF(S_ident_o);
135 S_ident_o = new_S_ident_o;
136
137 /* At this point, S_ident_o should be INCREF()ed. openlog(3) does not
138 * make a copy, and syslog(3) later uses it. We can't garbagecollect it
139 * If NULL, just let openlog figure it out (probably using C argv[0]).
140 */
141 if (S_ident_o) {
142 ident = PyUnicode_AsUTF8(S_ident_o);
143 if (ident == NULL)
144 return NULL;
145 }
146
147 if (PySys_Audit("syslog.openlog", "sll", ident, logopt, facility) < 0) {
148 return NULL;
149 }
150
151 openlog(ident, logopt, facility);
152 S_log_open = 1;
153
154 Py_RETURN_NONE;
155}
156
157
158static PyObject *
159syslog_syslog(PyObject * self, PyObject * args)
160{
161 PyObject *message_object;
162 const char *message;
163 int priority = LOG_INFO;
164
165 if (!PyArg_ParseTuple(args, "iU;[priority,] message string",
166 &priority, &message_object)) {
167 PyErr_Clear();
168 if (!PyArg_ParseTuple(args, "U;[priority,] message string",
169 &message_object))
170 return NULL;
171 }
172
173 message = PyUnicode_AsUTF8(message_object);
174 if (message == NULL)
175 return NULL;
176
177 if (PySys_Audit("syslog.syslog", "is", priority, message) < 0) {
178 return NULL;
179 }
180
181 /* if log is not opened, open it now */
182 if (!S_log_open) {
183 PyObject *openargs;
184
185 /* Continue even if PyTuple_New fails, because openlog(3) is optional.
186 * So, we can still do logging in the unlikely event things are so hosed
187 * that we can't do this tuple.
188 */
189 if ((openargs = PyTuple_New(0))) {
190 PyObject *openlog_ret = syslog_openlog(self, openargs, NULL);
191 Py_XDECREF(openlog_ret);
192 Py_DECREF(openargs);
193 }
194 }
195
196 Py_BEGIN_ALLOW_THREADS;
197 syslog(priority, "%s", message);
198 Py_END_ALLOW_THREADS;
199 Py_RETURN_NONE;
200}
201
202static PyObject *
203syslog_closelog(PyObject *self, PyObject *unused)
204{
205 if (PySys_Audit("syslog.closelog", NULL) < 0) {
206 return NULL;
207 }
208 if (S_log_open) {
209 closelog();
210 Py_CLEAR(S_ident_o);
211 S_log_open = 0;
212 }
213 Py_RETURN_NONE;
214}
215
216static PyObject *
217syslog_setlogmask(PyObject *self, PyObject *args)
218{
219 long maskpri, omaskpri;
220
221 if (!PyArg_ParseTuple(args, "l;mask for priority", &maskpri))
222 return NULL;
223 if (PySys_Audit("syslog.setlogmask", "(O)", args ? args : Py_None) < 0) {
224 return NULL;
225 }
226 omaskpri = setlogmask(maskpri);
227 return PyLong_FromLong(omaskpri);
228}
229
230static PyObject *
231syslog_log_mask(PyObject *self, PyObject *args)
232{
233 long mask;
234 long pri;
235 if (!PyArg_ParseTuple(args, "l:LOG_MASK", &pri))
236 return NULL;
237 mask = LOG_MASK(pri);
238 return PyLong_FromLong(mask);
239}
240
241static PyObject *
242syslog_log_upto(PyObject *self, PyObject *args)
243{
244 long mask;
245 long pri;
246 if (!PyArg_ParseTuple(args, "l:LOG_UPTO", &pri))
247 return NULL;
248 mask = LOG_UPTO(pri);
249 return PyLong_FromLong(mask);
250}
251
252/* List of functions defined in the module */
253
254static PyMethodDef syslog_methods[] = {
255 {"openlog", (PyCFunction)(void(*)(void)) syslog_openlog, METH_VARARGS | METH_KEYWORDS},
256 {"closelog", syslog_closelog, METH_NOARGS},
257 {"syslog", syslog_syslog, METH_VARARGS},
258 {"setlogmask", syslog_setlogmask, METH_VARARGS},
259 {"LOG_MASK", syslog_log_mask, METH_VARARGS},
260 {"LOG_UPTO", syslog_log_upto, METH_VARARGS},
261 {NULL, NULL, 0}
262};
263
264
265static int
266syslog_exec(PyObject *module)
267{
268#define ADD_INT_MACRO(module, macro) \
269 do { \
270 if (PyModule_AddIntConstant(module, #macro, macro) < 0) { \
271 return -1; \
272 } \
273 } while (0)
274 /* Priorities */
275 ADD_INT_MACRO(module, LOG_EMERG);
276 ADD_INT_MACRO(module, LOG_ALERT);
277 ADD_INT_MACRO(module, LOG_CRIT);
278 ADD_INT_MACRO(module, LOG_ERR);
279 ADD_INT_MACRO(module, LOG_WARNING);
280 ADD_INT_MACRO(module, LOG_NOTICE);
281 ADD_INT_MACRO(module, LOG_INFO);
282 ADD_INT_MACRO(module, LOG_DEBUG);
283
284 /* openlog() option flags */
285 ADD_INT_MACRO(module, LOG_PID);
286 ADD_INT_MACRO(module, LOG_CONS);
287 ADD_INT_MACRO(module, LOG_NDELAY);
288#ifdef LOG_ODELAY
289 ADD_INT_MACRO(module, LOG_ODELAY);
290#endif
291#ifdef LOG_NOWAIT
292 ADD_INT_MACRO(module, LOG_NOWAIT);
293#endif
294#ifdef LOG_PERROR
295 ADD_INT_MACRO(module, LOG_PERROR);
296#endif
297
298 /* Facilities */
299 ADD_INT_MACRO(module, LOG_KERN);
300 ADD_INT_MACRO(module, LOG_USER);
301 ADD_INT_MACRO(module, LOG_MAIL);
302 ADD_INT_MACRO(module, LOG_DAEMON);
303 ADD_INT_MACRO(module, LOG_AUTH);
304 ADD_INT_MACRO(module, LOG_LPR);
305 ADD_INT_MACRO(module, LOG_LOCAL0);
306 ADD_INT_MACRO(module, LOG_LOCAL1);
307 ADD_INT_MACRO(module, LOG_LOCAL2);
308 ADD_INT_MACRO(module, LOG_LOCAL3);
309 ADD_INT_MACRO(module, LOG_LOCAL4);
310 ADD_INT_MACRO(module, LOG_LOCAL5);
311 ADD_INT_MACRO(module, LOG_LOCAL6);
312 ADD_INT_MACRO(module, LOG_LOCAL7);
313
314#ifndef LOG_SYSLOG
315#define LOG_SYSLOG LOG_DAEMON
316#endif
317#ifndef LOG_NEWS
318#define LOG_NEWS LOG_MAIL
319#endif
320#ifndef LOG_UUCP
321#define LOG_UUCP LOG_MAIL
322#endif
323#ifndef LOG_CRON
324#define LOG_CRON LOG_DAEMON
325#endif
326
327 ADD_INT_MACRO(module, LOG_SYSLOG);
328 ADD_INT_MACRO(module, LOG_CRON);
329 ADD_INT_MACRO(module, LOG_UUCP);
330 ADD_INT_MACRO(module, LOG_NEWS);
331
332#ifdef LOG_AUTHPRIV
333 ADD_INT_MACRO(module, LOG_AUTHPRIV);
334#endif
335
336 return 0;
337}
338
339static PyModuleDef_Slot syslog_slots[] = {
340 {Py_mod_exec, syslog_exec},
341 {0, NULL}
342};
343
344/* Initialization function for the module */
345
346static struct PyModuleDef syslogmodule = {
347 PyModuleDef_HEAD_INIT,
348 .m_name = "syslog",
349 .m_size = 0,
350 .m_methods = syslog_methods,
351 .m_slots = syslog_slots,
352};
353
354PyMODINIT_FUNC
355PyInit_syslog(void)
356{
357 return PyModuleDef_Init(&syslogmodule);
358}