Merge from waqas
[prosody.git] / util-src / pposix.c
1 /* Prosody IM v0.3
2 -- Copyright (C) 2008-2009 Matthew Wild
3 -- Copyright (C) 2008-2009 Waqas Hussain
4 -- 
5 -- This project is MIT/X11 licensed. Please see the
6 -- COPYING file in the source package for more information.
7 --
8 */
9
10 /*
11 * pposix.c
12 * POSIX support functions for Lua
13 */
14
15 #define MODULE_VERSION "0.3.0"
16
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <libgen.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23
24 #include <syslog.h>
25 #include <pwd.h>
26
27 #include <string.h>
28 #include <errno.h>
29 #include "lua.h"
30 #include "lauxlib.h"
31
32 /* Daemonization support */
33
34 static int lc_daemonize(lua_State *L)
35 {
36
37         pid_t pid;
38         
39         if ( getppid() == 1 )
40         {
41                 lua_pushboolean(L, 0);
42                 lua_pushstring(L, "already-daemonized");
43                 return 2;
44         }
45         
46         /* Attempt initial fork */
47         if((pid = fork()) < 0)
48         {
49                 /* Forking failed */
50                 lua_pushboolean(L, 0);
51                 lua_pushstring(L, "fork-failed");
52                 return 2;
53         }
54         else if(pid != 0)
55         {
56                 /* We are the parent process */
57                 lua_pushboolean(L, 1);
58                 lua_pushnumber(L, pid);
59                 return 2;
60         }
61         
62         /* and we are the child process */
63         if(setsid() == -1)
64         {
65                 /* We failed to become session leader */
66                 /* (we probably already were) */
67                 lua_pushboolean(L, 0);
68                 lua_pushstring(L, "setsid-failed");
69                 return 2;
70         }
71
72         /* Close stdin, stdout, stderr */
73 /*      close(0);
74         close(1);
75         close(2);
76 */
77         /* Final fork, use it wisely */
78         if(fork())
79                 exit(0);
80
81         /* Show's over, let's continue */
82         lua_pushboolean(L, 1);
83         lua_pushnil(L);
84         return 2;
85 }
86
87 /* Syslog support */
88
89 const char * const facility_strings[] = {
90                                         "auth",
91                                         "authpriv",
92                                         "cron",
93                                         "daemon",
94                                         "ftp",
95                                         "kern",
96                                         "local0",
97                                         "local1",
98                                         "local2",
99                                         "local3",
100                                         "local4",
101                                         "local5",
102                                         "local6",
103                                         "local7",
104                                         "lpr",
105                                         "mail",
106                                         "syslog",
107                                         "user",
108                                         "uucp",
109                                         NULL
110                                 };
111 int facility_constants[] =      {
112                                         LOG_AUTH,
113                                         LOG_AUTHPRIV,
114                                         LOG_CRON,
115                                         LOG_DAEMON,
116                                         LOG_FTP,
117                                         LOG_KERN,
118                                         LOG_LOCAL0,
119                                         LOG_LOCAL1,
120                                         LOG_LOCAL2,
121                                         LOG_LOCAL3,
122                                         LOG_LOCAL4,
123                                         LOG_LOCAL5,
124                                         LOG_LOCAL6,
125                                         LOG_LOCAL7,
126                                         LOG_LPR,
127                                         LOG_MAIL,
128                                         LOG_NEWS,
129                                         LOG_SYSLOG,
130                                         LOG_USER,
131                                         LOG_UUCP,
132                                         -1
133                                 };
134
135 /* "
136        The parameter ident in the call of openlog() is probably stored  as-is.
137        Thus,  if  the  string  it  points  to  is  changed, syslog() may start
138        prepending the changed string, and if the string it points to ceases to
139        exist,  the  results  are  undefined.  Most portable is to use a string
140        constant.
141    " -- syslog manpage
142 */ 
143 char* syslog_ident = NULL;
144
145 int lc_syslog_open(lua_State* L)
146 {
147         int facility = luaL_checkoption(L, 2, "daemon", facility_strings);
148         facility = facility_constants[facility];
149
150         luaL_checkstring(L, 1);
151         
152         if(syslog_ident)
153                 free(syslog_ident);
154         
155         syslog_ident = strdup(lua_tostring(L, 1));
156         
157         openlog(syslog_ident, LOG_PID, facility);
158         return 0;
159 }
160
161 const char * const level_strings[] = {
162                                 "debug",
163                                 "info",
164                                 "notice",
165                                 "warn",
166                                 "error",
167                                 NULL
168                         };
169 int level_constants[] =         {
170                                 LOG_DEBUG,
171                                 LOG_INFO,
172                                 LOG_NOTICE,
173                                 LOG_WARNING,
174                                 LOG_EMERG,
175                                 -1
176                         };
177 int lc_syslog_log(lua_State* L)
178 {
179         int level = luaL_checkoption(L, 1, "notice", level_strings);
180         level = level_constants[level];
181
182         luaL_checkstring(L, 2);
183
184         syslog(level, "%s", lua_tostring(L, 2));
185         return 0;
186 }
187
188 int lc_syslog_close(lua_State* L)
189 {
190         closelog();
191         if(syslog_ident)
192         {
193                 free(syslog_ident);
194                 syslog_ident = NULL;
195         }
196         return 0;
197 }
198
199 int lc_syslog_setmask(lua_State* L)
200 {
201         int level_idx = luaL_checkoption(L, 1, "notice", level_strings);
202         int mask = 0;
203         do
204         {
205                 mask |= LOG_MASK(level_constants[level_idx]);
206         } while (++level_idx<=4);
207
208         setlogmask(mask);
209         return 0;
210 }
211
212 /* getpid */
213
214 int lc_getpid(lua_State* L)
215 {
216         lua_pushinteger(L, getpid());
217         return 1;
218 }
219
220 /* UID/GID functions */
221
222 int lc_getuid(lua_State* L)
223 {
224         lua_pushinteger(L, getuid());
225         return 1;
226 }
227
228 int lc_getgid(lua_State* L)
229 {
230         lua_pushinteger(L, getgid());
231         return 1;
232 }
233
234 int lc_setuid(lua_State* L)
235 {
236         int uid = -1;
237         if(lua_gettop(L) < 1)
238                 return 0;
239         if(!lua_isnumber(L, 1) && lua_tostring(L, 1))
240         {
241                 /* Passed UID is actually a string, so look up the UID */
242                 struct passwd *p;
243                 p = getpwnam(lua_tostring(L, 1));
244                 if(!p)
245                 {
246                         lua_pushboolean(L, 0);
247                         lua_pushstring(L, "no-such-user");
248                         return 2;
249                 }
250                 uid = p->pw_uid;
251         }
252         else
253         {
254                 uid = lua_tonumber(L, 1);
255         }
256         
257         if(uid>-1)
258         {
259                 /* Ok, attempt setuid */
260                 errno = 0;
261                 if(setuid(uid))
262                 {
263                         /* Fail */
264                         lua_pushboolean(L, 0);
265                         switch(errno)
266                         {
267                         case EINVAL:
268                                 lua_pushstring(L, "invalid-uid");
269                                 break;
270                         case EPERM:
271                                 lua_pushstring(L, "permission-denied");
272                                 break;
273                         default:
274                                 lua_pushstring(L, "unknown-error");
275                         }
276                         return 2;
277                 }
278                 else
279                 {
280                         /* Success! */
281                         lua_pushboolean(L, 1);
282                         return 1;
283                 }
284         }
285         
286         /* Seems we couldn't find a valid UID to switch to */
287         lua_pushboolean(L, 0);
288         lua_pushstring(L, "invalid-uid");
289         return 2;
290 }
291
292 /* Register functions */
293
294 int luaopen_util_pposix(lua_State *L)
295 {
296         lua_newtable(L);
297
298         lua_pushcfunction(L, lc_daemonize);
299         lua_setfield(L, -2, "daemonize");
300
301         lua_pushcfunction(L, lc_syslog_open);
302         lua_setfield(L, -2, "syslog_open");
303
304         lua_pushcfunction(L, lc_syslog_close);
305         lua_setfield(L, -2, "syslog_close");
306
307         lua_pushcfunction(L, lc_syslog_log);
308         lua_setfield(L, -2, "syslog_log");
309
310         lua_pushcfunction(L, lc_syslog_setmask);
311         lua_setfield(L, -2, "syslog_setminlevel");
312
313         lua_pushcfunction(L, lc_getpid);
314         lua_setfield(L, -2, "getpid");
315
316         lua_pushcfunction(L, lc_getuid);
317         lua_setfield(L, -2, "getuid");
318
319         lua_pushcfunction(L, lc_setuid);
320         lua_setfield(L, -2, "setuid");
321
322         lua_pushliteral(L, "pposix");
323         lua_setfield(L, -2, "_NAME");
324
325         lua_pushliteral(L, MODULE_VERSION);
326         lua_setfield(L, -2, "_VERSION");
327         
328         return 1;
329 };