]> git.sesse.net Git - vlc/blob - modules/lua/intf.c
lua: remove MD5 functions before someone uses them
[vlc] / modules / lua / intf.c
1 /*****************************************************************************
2  * intf.c: Generic lua interface functions
3  *****************************************************************************
4  * Copyright (C) 2007-2008 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Antoine Cellerier <dionoea at videolan tod org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifndef  _GNU_SOURCE
28 #   define  _GNU_SOURCE
29 #endif
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <vlc_common.h>
36 #include <vlc_interface.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <assert.h>
40
41 #include <lua.h>        /* Low level lua C API */
42 #include <lauxlib.h>    /* Higher level C API */
43 #include <lualib.h>     /* Lua libs */
44
45 #include "vlc.h"
46 #include "libs.h"
47
48 /*****************************************************************************
49  * Prototypes
50  *****************************************************************************/
51 static void *Run( void * );
52
53 static const char * const ppsz_intf_options[] = { "intf", "config", NULL };
54
55 /*****************************************************************************
56  *
57  *****************************************************************************/
58 static inline void luaL_register_submodule( lua_State *L, const char *psz_name,
59                                             const luaL_Reg *l )
60 {
61     lua_newtable( L );
62     luaL_register( L, NULL, l );
63     lua_setfield( L, -2, psz_name );
64 }
65
66 static char *StripPasswords( const char *psz_config )
67 {
68     unsigned n = 0;
69     const char *p = psz_config;
70     while ((p = strstr(p, "password=")) != NULL)
71     {
72         n++;
73         p++;
74     }
75     if (n == 0)
76         return strdup(psz_config);
77  
78     char *psz_log = malloc(strlen(psz_config) + n * strlen("******") + 1);
79     if (psz_log == NULL)
80         return NULL;
81     psz_log[0] = '\0';
82
83     for (p = psz_config; ; )
84     {
85         const char *pwd = strstr(p, "password=");
86         if (pwd == NULL)
87         {
88             /* Copy the last, ending bit */
89             strcat(psz_log, p);
90             break;
91         }
92         pwd += strlen("password=");
93
94         char delim[3] = ",}";
95         if (*pwd == '\'' || *pwd == '"')
96         {
97             delim[0] = *pwd++;
98             delim[1] = '\0';
99         }
100
101         strncat(psz_log, p, pwd - p);
102         strcat(psz_log, "******");
103
104         /* Advance to the delimiter at the end of the password */
105         p = pwd - 1;
106         do
107         {
108             p = strpbrk(p + 1, delim);
109             if (p == NULL)
110                 /* Oops, unbalanced quotes or brackets */
111                 return psz_log;
112         }
113         while (*(p - 1) == '\\');
114     }
115     return psz_log;
116 }
117
118 static const luaL_Reg p_reg[] = { { NULL, NULL } };
119
120 static int Start_LuaIntf( vlc_object_t *p_this, const char *name )
121 {
122     intf_thread_t *p_intf = (intf_thread_t*)p_this;
123     intf_sys_t *p_sys;
124     lua_State *L;
125
126     assert( name != NULL );
127     config_ChainParse( p_intf, "lua-", ppsz_intf_options, p_intf->p_cfg );
128
129     char *psz_config;
130     bool b_config_set = false;
131
132     p_intf->p_sys = (intf_sys_t*)malloc( sizeof(intf_sys_t) );
133     if( !p_intf->p_sys )
134         return VLC_ENOMEM;
135     p_sys = p_intf->p_sys;
136     p_sys->psz_filename = vlclua_find_file( p_this, "intf", name );
137     if( !p_sys->psz_filename )
138     {
139         msg_Err( p_intf, "Couldn't find lua interface script \"%s\".",
140                  name );
141         goto error;
142     }
143     msg_Dbg( p_intf, "Found lua interface script: %s", p_sys->psz_filename );
144
145     L = luaL_newstate();
146     if( !L )
147     {
148         msg_Err( p_intf, "Could not create new Lua State" );
149         goto error;
150     }
151
152     vlclua_set_this( L, p_intf );
153     vlclua_set_intf( L, p_sys );
154
155     luaL_openlibs( L );
156
157     /* register our functions */
158     luaL_register( L, "vlc", p_reg );
159
160     /* register submodules */
161     luaopen_acl( L );
162     luaopen_config( L );
163     luaopen_volume( L );
164     luaopen_httpd( L );
165     luaopen_input( L );
166     luaopen_msg( L );
167     luaopen_misc( L );
168     luaopen_net( L );
169     luaopen_object( L );
170     luaopen_osd( L );
171     luaopen_playlist( L );
172     luaopen_sd( L );
173     luaopen_stream( L );
174     luaopen_strings( L );
175     luaopen_variables( L );
176     luaopen_video( L );
177     luaopen_vlm( L );
178     luaopen_volume( L );
179     luaopen_gettext( L );
180     luaopen_xml( L );
181     luaopen_equalizer( L );
182
183     /* clean up */
184     lua_pop( L, 1 );
185
186     /* Setup the module search path */
187     if( vlclua_add_modules_path( p_intf, L, p_sys->psz_filename ) )
188     {
189         msg_Warn( p_intf, "Error while setting the module search path for %s",
190                   p_sys->psz_filename );
191         lua_close( L );
192         goto error;
193     }
194
195     /*
196      * Get the lua-config string.
197      * If the string is empty, try with the old http-* or telnet-* options
198      * and build the right configuration line
199      */
200     psz_config = var_CreateGetNonEmptyString( p_intf, "lua-config" );
201     if( !psz_config )
202     {
203         if( !strcmp( name, "http" ) )
204         {
205             char *psz_http_src = var_CreateGetNonEmptyString( p_intf, "http-src" );
206             bool b_http_index = var_CreateGetBool( p_intf, "http-index" );
207             if( psz_http_src )
208             {
209                 char *psz_esc = config_StringEscape( psz_http_src );
210                 if( psz_config )
211                 {
212                     char *psz_tmp;
213                     asprintf( &psz_tmp, "%s,dir='%s'", psz_config, psz_esc );
214                     free( psz_config );
215                     psz_config = psz_tmp;
216                 }
217                 else
218                     asprintf( &psz_config, "http={dir='%s'", psz_esc );
219                 free( psz_esc );
220                 free( psz_http_src );
221             }
222             if( psz_config )
223             {
224                 char *psz_tmp;
225                 asprintf( &psz_tmp, "%s,no_index=%s}", psz_config, b_http_index ? "true" : "false" );
226                 free( psz_config );
227                 psz_config = psz_tmp;
228             }
229             else
230                 asprintf( &psz_config, "http={no_index=%s}", b_http_index ? "true" : "false" );
231         }
232         else if( !strcmp( name, "telnet" ) )
233         {
234             char *psz_telnet_host = var_CreateGetString( p_intf, "telnet-host" );
235             if( !strcmp( psz_telnet_host, "*console" ) )
236                 ;
237             else
238             {
239                 vlc_url_t url;
240                 vlc_UrlParse( &url, psz_telnet_host, 0 );
241                 int i_telnet_port = var_CreateGetInteger( p_intf, "telnet-port" );
242                 if ( url.i_port != 0 )
243                 {
244                     if ( i_telnet_port == TELNETPORT_DEFAULT )
245                         i_telnet_port = url.i_port;
246                     else if ( url.i_port != i_telnet_port )
247                         msg_Warn( p_intf, "ignoring port %d (using %d)", url.i_port, i_telnet_port );
248                 }
249
250                 char *psz_esc_host = config_StringEscape( url.psz_host );
251                 free( psz_telnet_host );
252                 vlc_UrlClean( &url );
253
254                 asprintf( &psz_telnet_host, "telnet://%s:%d", psz_esc_host ? psz_esc_host : "", i_telnet_port );
255                 free( psz_esc_host );
256             }
257
258             char *psz_telnet_passwd = var_CreateGetString( p_intf, "telnet-password" );
259
260             char *psz_esc_passwd = config_StringEscape( psz_telnet_passwd );
261
262             asprintf( &psz_config, "telnet={host='%s',password='%s'}", psz_telnet_host, psz_esc_passwd );
263
264             free( psz_esc_passwd );
265             free( psz_telnet_passwd );
266             free( psz_telnet_host );
267         }
268         else if( !strcmp( name, "cli" ) )
269         {
270             char *psz_rc_host = var_CreateGetNonEmptyString( p_intf, "rc-host" );
271             if( !psz_rc_host )
272                 psz_rc_host = var_CreateGetNonEmptyString( p_intf, "cli-host" );
273             if( psz_rc_host )
274             {
275                 char *psz_esc_host = config_StringEscape( psz_rc_host );
276                 asprintf( &psz_config, "cli={host='%s'}", psz_esc_host );
277
278                 free( psz_esc_host );
279                 free( psz_rc_host );
280             }
281         }
282     }
283
284     if( psz_config )
285     {
286         char *psz_buffer;
287         if( asprintf( &psz_buffer, "config={%s}", psz_config ) != -1 )
288         {
289             char *psz_log = StripPasswords( psz_buffer );
290             if( psz_log != NULL )
291             {
292                 msg_Dbg( p_intf, "Setting config variable: %s", psz_log );
293                 free( psz_log );
294             }
295
296             if( luaL_dostring( L, psz_buffer ) == 1 )
297                 msg_Err( p_intf, "Error while parsing \"lua-config\"." );
298             free( psz_buffer );
299             lua_getglobal( L, "config" );
300             if( lua_istable( L, -1 ) )
301             {
302                 if( !strcmp( name, "cli" ) )
303                 {
304                     lua_getfield( L, -1, "rc" );
305                     if( lua_istable( L, -1 ) )
306                     {
307                         /* msg_Warn( p_intf, "The `rc' lua interface script "
308                                           "was renamed `cli', please update "
309                                           "your configuration!" ); */
310                         lua_setfield( L, -2, "cli" );
311                     }
312                     else
313                         lua_pop( L, 1 );
314                 }
315                 lua_getfield( L, -1, name );
316                 if( lua_istable( L, -1 ) )
317                 {
318                     lua_setglobal( L, "config" );
319                     b_config_set = true;
320                 }
321             }
322         }
323         free( psz_config );
324     }
325
326     if( !b_config_set )
327     {
328         lua_newtable( L );
329         lua_setglobal( L, "config" );
330     }
331
332     /* Wrapper for legacy telnet config */
333     if ( !strcmp( name, "telnet" ) )
334     {
335         /* msg_Warn( p_intf, "The `telnet' lua interface script was replaced "
336                           "by `cli', please update your configuration!" ); */
337
338         char *wrapped_file = vlclua_find_file( p_this, "intf", "cli" );
339         if( !wrapped_file )
340         {
341             msg_Err( p_intf, "Couldn't find lua interface script \"cli\", "
342                              "needed by telnet wrapper" );
343             lua_close( p_sys->L );
344             goto error;
345         }
346         lua_pushstring( L, wrapped_file );
347         lua_setglobal( L, "wrapped_file" );
348         free( wrapped_file );
349     }
350
351     p_sys->L = L;
352
353     /* Cleaned up by vlc_object_release() */
354     p_intf->psz_header = strdup( name );
355
356     vlc_mutex_init( &p_sys->lock );
357     vlc_cond_init( &p_sys->wait );
358     p_sys->exiting = false;
359
360     if( vlc_clone( &p_sys->thread, Run, p_intf, VLC_THREAD_PRIORITY_LOW ) )
361     {
362         free( p_intf->psz_header );
363         p_intf->psz_header = NULL;
364         vlc_cond_destroy( &p_sys->wait );
365         vlc_mutex_destroy( &p_sys->lock );
366         lua_close( p_sys->L );
367         goto error;
368     }
369
370     return VLC_SUCCESS;
371 error:
372     free( p_sys->psz_filename );
373     free( p_sys );
374     return VLC_EGENERIC;
375 }
376
377 void Close_LuaIntf( vlc_object_t *p_this )
378 {
379     intf_thread_t *p_intf = (intf_thread_t*)p_this;
380     intf_sys_t *p_sys = p_intf->p_sys;
381
382     vlc_cancel( p_sys->thread );
383
384     vlc_mutex_lock( &p_sys->lock );
385     p_sys->exiting = true;
386     vlc_cond_signal( &p_sys->wait );
387     vlc_mutex_unlock( &p_sys->lock );
388     vlc_join( p_sys->thread, NULL );
389     vlc_cond_destroy( &p_sys->wait );
390     vlc_mutex_destroy( &p_sys->lock );
391
392     lua_close( p_sys->L );
393
394     free( p_sys->psz_filename );
395     free( p_sys );
396 }
397
398 static void *Run( void *data )
399 {
400     intf_thread_t *p_intf = data;
401     intf_sys_t *p_sys = p_intf->p_sys;
402     lua_State *L = p_sys->L;
403
404     if( luaL_dofile( L, p_sys->psz_filename ) )
405     {
406         msg_Err( p_intf, "Error loading script %s: %s", p_sys->psz_filename,
407                  lua_tostring( L, lua_gettop( L ) ) );
408         lua_pop( L, 1 );
409     }
410     return NULL;
411 }
412
413 int Open_LuaIntf( vlc_object_t *p_this )
414 {
415     char *name = var_InheritString( p_this, "lua-intf" );
416     if( unlikely(name == NULL) )
417         return VLC_EGENERIC;
418
419     int ret = Start_LuaIntf( p_this, name );
420     free( name );
421     return ret;
422 }
423
424 int Open_LuaHTTP( vlc_object_t *p_this )
425 {
426     return Start_LuaIntf( p_this, "http" );
427 }
428
429 int Open_LuaCLI( vlc_object_t *p_this )
430 {
431     return Start_LuaIntf( p_this, "cli" );
432 }
433
434 int Open_LuaTelnet( vlc_object_t *p_this )
435 {
436     return Start_LuaIntf( p_this, "telnet" );
437 }