From bf383acf3b852b0ebe11252461817b8e636ad779 Mon Sep 17 00:00:00 2001 From: smorlat Date: Fri, 13 Feb 2009 22:19:13 +0000 Subject: [PATCH] linphonecsh and linphonec use a unix socket by default, for security reasons git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@259 3f6dc0c8-ddfe-455d-9043-3cd528dc4637 --- linphone/NEWS | 1 + linphone/console/commands.c | 4 +- linphone/console/linphonec.c | 124 ++++++++++++++++++++++++----------- linphone/console/shell.c | 103 +++++++++++++++++++++++------ 4 files changed, 173 insertions(+), 59 deletions(-) diff --git a/linphone/NEWS b/linphone/NEWS index 036cf1134..dac6ea015 100644 --- a/linphone/NEWS +++ b/linphone/NEWS @@ -6,6 +6,7 @@ linphone-3.1.0 -- January 19, 2009 * set a user friendly gtk theme by default on windows * linphonec can compile and work without libreadline * enable translations on windows + * enable lookups of SRV records * bugfixing as usual linphone-3.0.0 -- October 13, 2008 diff --git a/linphone/console/commands.c b/linphone/console/commands.c index 57af71117..2966e8376 100644 --- a/linphone/console/commands.c +++ b/linphone/console/commands.c @@ -1243,7 +1243,7 @@ static int lpc_cmd_status(LinphoneCore *lc, char *args){ if (strstr(args,"register")){ if (cfg){ if (linphone_proxy_config_is_registered(cfg)){ - linphonec_out("identity=%s duration=%i\n", + linphonec_out("registered, identity=%s duration=%i\n", linphone_proxy_config_get_identity(cfg), linphone_proxy_config_get_expires(cfg)); }else if (linphone_proxy_config_register_enabled(cfg)){ @@ -1268,7 +1268,7 @@ static int lpc_cmd_status(LinphoneCore *lc, char *args){ linphonec_out("hook=offhook\n"); break; case GSTATE_CALL_OUT_CONNECTED: - linphonec_out("hook=%s duration=%i\n", linphonec_get_callee(), + linphonec_out("Call out, hook=%s duration=%i\n", linphonec_get_callee(), linphone_core_get_current_call_duration(lc)); break; case GSTATE_CALL_IN_CONNECTED: diff --git a/linphone/console/linphonec.c b/linphone/console/linphonec.c index adf168c49..777c598da 100644 --- a/linphone/console/linphonec.c +++ b/linphone/console/linphonec.c @@ -47,6 +47,8 @@ #else #include #include +#include +#include #endif @@ -130,6 +132,7 @@ static bool_t vcap_enabled=FALSE; static bool_t display_enabled=FALSE; static bool_t preview_enabled=FALSE; static bool_t show_general_state=FALSE; +static bool_t unix_socket=FALSE; static int tcp_port=0; /* see --tcp: tcp port to listen for commands */ LPC_AUTH_STACK auth_stack; static int trace_level = 0; @@ -138,6 +141,10 @@ static char configfile_name[PATH_MAX]; static char *sipAddr = NULL; /* for autocall */ static ortp_socket_t client_sock=-1; char prompt[PROMPT_MAX_LEN]; +char sock_unix_path[128]={0}; +static ortp_thread_t net_reader_th; +static bool_t net_reader_run=FALSE; +static ortp_socket_t server_sock; LinphoneCoreVTable linphonec_vtable = { show:(ShowInterfaceCb) stub, @@ -366,43 +373,60 @@ static void start_prompt_reader(void){ } static ortp_socket_t create_server_socket(int port){ - ortp_socket_t server_sock; - char service[12]; - int tmp,err; - /*setup the server socket */ - struct addrinfo *ai=NULL; - struct addrinfo hints; - memset(&hints,0,sizeof(hints)); - hints.ai_family=AF_INET; - snprintf(service,sizeof(service),"%i",port); - - getaddrinfo("127.0.0.1",service,&hints,&ai); - if (ai==NULL){ - fprintf(stderr,"getaddrinfo failed on port %s",service); - exit(-1); + ortp_socket_t sock; + if (!unix_socket){ + char service[12]; + /*setup the server socket */ + struct addrinfo *ai=NULL; + struct addrinfo hints; + memset(&hints,0,sizeof(hints)); + hints.ai_family=AF_INET; + snprintf(service,sizeof(service),"%i",port); + + getaddrinfo("127.0.0.1",service,&hints,&ai); + if (ai==NULL){ + fprintf(stderr,"getaddrinfo failed on port %s",service); + exit(-1); + } + sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP); + if (bind(sock,ai->ai_addr,ai->ai_addrlen)!=0){ + fprintf(stderr,"Failed to bind command socket.\n"); + exit(-1); + } + listen(sock,1); + }else{ +#ifndef WIN32 + struct sockaddr_un sa; + sock=socket(AF_UNIX,SOCK_STREAM,0); + sa.sun_family=AF_UNIX; + snprintf(sock_unix_path,sizeof(sock_unix_path)-1,"/tmp/linphonec-%i",getuid()); + strncpy(sa.sun_path,sock_unix_path,sizeof(sa.sun_path)-1); + unlink(sock_unix_path);/*in case we didn't finished properly previous time */ + fchmod(sock,S_IRUSR|S_IWUSR); + if (bind(sock,(struct sockaddr*)&sa,sizeof(sa))!=0){ + fprintf(stderr,"Failed to bind command unix socket.\n"); + exit(-1); + } + listen(sock,1); + printf("Listening from unix socket %s\n",sock_unix_path); +#else + fprintf(stderr,"Window pipe implementation not written yet.\n"); +#endif } - server_sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP); - tmp=1; - err=setsockopt(server_sock,SOL_SOCKET,SO_REUSEADDR,(void*)&tmp,sizeof(tmp)); - if (err<0) fprintf(stderr,"Error in setsockopt(): %s\n",getSocketError()); - if (bind(server_sock,ai->ai_addr,ai->ai_addrlen)!=0){ - fprintf(stderr,"Failed to bind command socket."); - exit(-1); - } - listen(server_sock,1); - return server_sock; + return sock; } -static void *tcp_thread(void*p){ +static void *net_thread(void*p){ char tmp[250]; - ortp_socket_t server_sock; struct sockaddr_storage ss; +#ifndef WIN32 + struct sockaddr_un su; +#endif socklen_t ssize; - bool_t run=TRUE; server_sock=create_server_socket(tcp_port); if (server_sock==-1) return NULL; - while(run){ + while(net_reader_run){ while(client_sock!=-1){ /*sleep until the last command is finished*/ #ifndef WIN32 usleep(20000); @@ -410,15 +434,20 @@ static void *tcp_thread(void*p){ Sleep(20); #endif } - ssize=sizeof(ss); - if ((client_sock=accept(server_sock,(struct sockaddr*)&ss,&ssize))!=-1){ + if (!unix_socket){ + ssize=sizeof(ss); + client_sock=accept(server_sock,(struct sockaddr*)&ss,&ssize); + }else{ + ssize=sizeof(su); + client_sock=accept(server_sock,(struct sockaddr*)&su,&ssize); + } + if (client_sock!=-1){ int len; /*now read from the client */ if ((len=recv(client_sock,tmp,sizeof(tmp)-1,0))>0){ ortp_mutex_lock(&prompt_mutex); tmp[len]='\0'; strcpy(received_prompt,tmp); - if (strcmp(received_prompt,"quit")==0) run=FALSE; printf("Receiving command '%s'\n",received_prompt);fflush(stdout); have_prompt=TRUE; ortp_mutex_unlock(&prompt_mutex); @@ -428,15 +457,27 @@ static void *tcp_thread(void*p){ client_sock=-1; } + }else{ + if (net_reader_run) fprintf(stderr,"accept() failed: %s\n",getSocketError()); } } + return NULL; } -static void start_tcp_reader(void){ - ortp_thread_t th; +static void start_net_reader(void){ ms_mutex_init(&prompt_mutex,NULL); - ortp_thread_create(&th,NULL,tcp_thread,NULL); + net_reader_run=TRUE; + ortp_thread_create(&net_reader_th,NULL,net_thread,NULL); +} + +static void stop_net_reader(void){ + net_reader_run=FALSE; + close(server_sock); + if (sock_unix_path[0]!=0){ + unlink(sock_unix_path); + } + /*ortp_thread_join(net_reader_th,NULL);*/ } #endif @@ -446,14 +487,14 @@ char *linphonec_readline(char *prompt){ return readline(prompt); #else static bool_t prompt_reader_started=FALSE; - static bool_t tcp_reader_started=FALSE; + static bool_t net_reader_started=FALSE; if (!prompt_reader_started){ start_prompt_reader(); prompt_reader_started=TRUE; } - if (tcp_port>0 && !tcp_reader_started){ - start_tcp_reader(); - tcp_reader_started=TRUE; + if ((tcp_port>0 || unix_socket) && !net_reader_started){ + start_net_reader(); + net_reader_started=TRUE; } fprintf(stdout,"%s",prompt); fflush(stdout); @@ -632,6 +673,9 @@ linphonec_finish(int exit_status) #ifdef HAVE_READLINE linphonec_finish_readline(); #endif + + if (net_reader_run) + stop_net_reader(); linphone_core_uninit (&linphonec); if (mylogfile != NULL && mylogfile != stdout) @@ -1006,6 +1050,10 @@ linphonec_parse_cmdline(int argc, char **argv) } if (tcp_port==0) tcp_port=DEFAULT_TCP_PORT; } + else if (strncmp ("--pipe", argv[arg_num], 6) == 0) + { + unix_socket=1; + } else if (old_arg_num == arg_num) { fprintf (stderr, "ERROR: bad arguments\n"); diff --git a/linphone/console/shell.c b/linphone/console/shell.c index 1543c8a86..9e6ad4163 100644 --- a/linphone/console/shell.c +++ b/linphone/console/shell.c @@ -29,6 +29,8 @@ #else #include #include +#include + #endif #include "ortp/ortp.h" @@ -36,27 +38,77 @@ #define DEFAULT_TCP_PORT "32333" #define DEFAULT_REPLY_SIZE 4096 +#define STATUS_REGISTERED (1<<0) +#define STATUS_REGISTERING (1<<1) +#define STATUS_DIALING (1<<2) +#define STATUS_AUTOANSWER (1<<3) +#define STATUS_IN_CONNECTED (1<<4) /* incoming call accepted */ +#define STATUS_OUT_CONNECTED (1<<5) /*outgoing call accepted */ + +static int tcp=0; + +static int make_status_value(const char *status_string){ + int ret=0; + if (strstr(status_string,"registered, identity=")){ + ret|=STATUS_REGISTERED; + } + if (strstr(status_string,"registered=-1")){ + ret|=STATUS_REGISTERING; + } + if (strstr(status_string,"autoanswer=1")){ + ret|=STATUS_AUTOANSWER; + } + if (strstr(status_string,"dialing")){ + ret|=STATUS_DIALING; + } + if (strstr(status_string,"Call out")){ + ret|=STATUS_OUT_CONNECTED; + } + if (strstr(status_string,"hook=answered")){ + ret|=STATUS_IN_CONNECTED; + } + return ret; +} + static int send_command(const char *command, const char * port, char *reply, int reply_len, int print_errors){ ortp_socket_t sock; - struct addrinfo *ai=NULL; - struct addrinfo hints; - int err; int i; - memset(&hints,0,sizeof(hints)); - hints.ai_family=AF_INET; - hints.ai_socktype=SOCK_STREAM; - err=getaddrinfo("127.0.0.1",port,&hints,&ai); - if (err!=0){ - if (print_errors) fprintf(stderr,"ERROR: getaddrinfo failed: error %i\n", err); - return -1; - } - sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP); - if (connect(sock,ai->ai_addr,ai->ai_addrlen)!=0){ - if (print_errors) fprintf(stderr,"ERROR: Failed to connect socket.\n"); + int err; + if (tcp){ + struct addrinfo *ai=NULL; + struct addrinfo hints; + memset(&hints,0,sizeof(hints)); + hints.ai_family=AF_INET; + hints.ai_socktype=SOCK_STREAM; + err=getaddrinfo("127.0.0.1",port,&hints,&ai); + if (err!=0){ + if (print_errors) fprintf(stderr,"ERROR: getaddrinfo failed: error %i\n", err); + return -1; + } + sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP); + if (connect(sock,ai->ai_addr,ai->ai_addrlen)!=0){ + if (print_errors) fprintf(stderr,"ERROR: Failed to connect socket.\n"); + freeaddrinfo(ai); + return -1; + } freeaddrinfo(ai); + }else{ +#ifndef WIN32 + struct sockaddr_un sa; + char path[128]; + sock=socket(AF_UNIX,SOCK_STREAM,0); + sa.sun_family=AF_UNIX; + snprintf(path,sizeof(path)-1,"/tmp/linphonec-%i",getuid()); + strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1); + if (connect(sock,(struct sockaddr*)&sa,sizeof(sa))!=0){ + if (print_errors) fprintf(stderr,"ERROR: Failed to connect socket: %s\n",getSocketError()); + return -1; + } +#else + fprintf(stderr,"ERROR: windows pipes communication not yet implemented.\n"); return -1; +#endif } - freeaddrinfo(ai); if (send(sock,command,strlen(command),0)<0){ if (print_errors) fprintf(stderr,"ERROR: Fail to send command to remote linphonec\n"); close_socket(sock); @@ -96,8 +148,10 @@ static void spawn_linphonec(int argc, char *argv[]){ pid_t pid; j=0; args[j++]="linphonec"; - args[j++]="--tcp"; - args[j++]=DEFAULT_TCP_PORT; + if (tcp){ + args[j++]="--tcp"; + args[j++]=DEFAULT_TCP_PORT; + }else args[j++]="--pipe"; args[j++]="-c"; args[j++]="/dev/null"; for(i=0;i