/** * Create a new update VLC struct * * \param p_this the calling vlc_object * \return pointer to new update_t or NULL */ update_t *update_New( vlc_object_t *p_this ) { update_t *p_update; assert( p_this ); p_update = (update_t *)malloc( sizeof( update_t ) ); if( !p_update ) return NULL; vlc_mutex_init( &p_update->lock ); p_update->p_libvlc = p_this->p_libvlc; p_update->release.psz_url = NULL; p_update->release.psz_desc = NULL; p_update->p_download = NULL; p_update->p_check = NULL; p_update->p_pkey = NULL; vlc_gcrypt_init(); return p_update; }
/** * Probes and initializes. */ static int Open (vlc_object_t *obj) { demux_t *demux = (demux_t *)obj; int tp; /* transport protocol */ if (!strcmp (demux->psz_access, "dccp")) tp = IPPROTO_DCCP; else if (!strcmp (demux->psz_access, "rtptcp")) tp = IPPROTO_TCP; else if (!strcmp (demux->psz_access, "rtp")) tp = IPPROTO_UDP; else if (!strcmp (demux->psz_access, "udplite")) tp = IPPROTO_UDPLITE; else return VLC_EGENERIC; char *tmp = strdup (demux->psz_location); if (tmp == NULL) return VLC_ENOMEM; char *shost; char *dhost = strchr (tmp, '@'); if (dhost != NULL) { *(dhost++) = '\0'; shost = tmp; } else { dhost = tmp; shost = NULL; } /* Parses the port numbers */ int sport = 0, dport = 0; if (shost != NULL) sport = extract_port (&shost); if (dhost != NULL) dport = extract_port (&dhost); if (dport == 0) dport = 5004; /* avt-profile-1 port */ int rtcp_dport = var_CreateGetInteger (obj, "rtcp-port"); /* Try to connect */ int fd = -1, rtcp_fd = -1; switch (tp) { case IPPROTO_UDP: case IPPROTO_UDPLITE: fd = net_OpenDgram (obj, dhost, dport, shost, sport, tp); if (fd == -1) break; if (rtcp_dport > 0) /* XXX: source port is unknown */ rtcp_fd = net_OpenDgram (obj, dhost, rtcp_dport, shost, 0, tp); break; case IPPROTO_DCCP: #ifndef SOCK_DCCP /* provisional API (FIXME) */ # ifdef __linux__ # define SOCK_DCCP 6 # endif #endif #ifdef SOCK_DCCP var_Create (obj, "dccp-service", VLC_VAR_STRING); var_SetString (obj, "dccp-service", "RTPV"); /* FIXME: RTPA? */ fd = net_Connect (obj, dhost, dport, SOCK_DCCP, tp); #else msg_Err (obj, "DCCP support not included"); #endif break; case IPPROTO_TCP: fd = net_Connect (obj, dhost, dport, SOCK_STREAM, tp); break; } free (tmp); if (fd == -1) return VLC_EGENERIC; net_SetCSCov (fd, -1, 12); /* Initializes demux */ demux_sys_t *p_sys = malloc (sizeof (*p_sys)); if (p_sys == NULL) { net_Close (fd); if (rtcp_fd != -1) net_Close (rtcp_fd); return VLC_EGENERIC; } p_sys->chained_demux = NULL; #ifdef HAVE_SRTP p_sys->srtp = NULL; #endif p_sys->fd = fd; p_sys->rtcp_fd = rtcp_fd; p_sys->max_src = var_CreateGetInteger (obj, "rtp-max-src"); p_sys->timeout = var_CreateGetInteger (obj, "rtp-timeout") * CLOCK_FREQ; p_sys->max_dropout = var_CreateGetInteger (obj, "rtp-max-dropout"); p_sys->max_misorder = var_CreateGetInteger (obj, "rtp-max-misorder"); p_sys->thread_ready = false; p_sys->autodetect = true; demux->pf_demux = NULL; demux->pf_control = Control; demux->p_sys = p_sys; p_sys->session = rtp_session_create (demux); if (p_sys->session == NULL) goto error; #ifdef HAVE_SRTP char *key = var_CreateGetNonEmptyString (demux, "srtp-key"); if (key) { vlc_gcrypt_init (); p_sys->srtp = srtp_create (SRTP_ENCR_AES_CM, SRTP_AUTH_HMAC_SHA1, 10, SRTP_PRF_AES_CM, SRTP_RCC_MODE1); if (p_sys->srtp == NULL) { free (key); goto error; } char *salt = var_CreateGetNonEmptyString (demux, "srtp-salt"); int val = srtp_setkeystring (p_sys->srtp, key, salt ? salt : ""); free (salt); free (key); if (val) { msg_Err (obj, "bad SRTP key/salt combination (%s)", vlc_strerror_c(val)); goto error; } } #endif if (vlc_clone (&p_sys->thread, (tp != IPPROTO_TCP) ? rtp_dgram_thread : rtp_stream_thread, demux, VLC_THREAD_PRIORITY_INPUT)) goto error; p_sys->thread_ready = true; return VLC_SUCCESS; error: Close (obj); return VLC_EGENERIC; }
/************************************************************************ * CryptSetup: Initialize encryption ************************************************************************/ static int CryptSetup( sout_access_out_t *p_access, char *key_file ) { sout_access_out_sys_t *p_sys = p_access->p_sys; uint8_t key[16]; char *keyfile = NULL; if( !p_sys->key_uri ) /*No key uri, assume no encryption wanted*/ { msg_Dbg( p_access, "No key uri, no encryption"); return VLC_SUCCESS; } if( key_file ) keyfile = strdup( key_file ); else keyfile = var_InheritString( p_access, SOUT_CFG_PREFIX "key-file" ); if( unlikely(keyfile == NULL) ) { msg_Err( p_access, "No key-file, no encryption" ); return VLC_EGENERIC; } vlc_gcrypt_init(); /*Setup encryption cipher*/ gcry_error_t err = gcry_cipher_open( &p_sys->aes_ctx, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0 ); if( err ) { msg_Err( p_access, "Openin AES Cipher failed: %s", gpg_strerror(err)); free( keyfile ); return VLC_EGENERIC; } int keyfd = vlc_open( keyfile, O_RDONLY | O_NONBLOCK ); if( unlikely( keyfd == -1 ) ) { msg_Err( p_access, "Unable to open keyfile %s: %s", keyfile, vlc_strerror_c(errno) ); free( keyfile ); gcry_cipher_close( p_sys->aes_ctx ); return VLC_EGENERIC; } free( keyfile ); ssize_t keylen = read( keyfd, key, 16 ); vlc_close( keyfd ); if( keylen < 16 ) { msg_Err( p_access, "No key at least 16 octects (you provided %zd), no encryption", keylen ); gcry_cipher_close( p_sys->aes_ctx ); return VLC_EGENERIC; } err = gcry_cipher_setkey( p_sys->aes_ctx, key, 16 ); if(err) { msg_Err(p_access, "Setting AES key failed: %s", gpg_strerror(err)); gcry_cipher_close( p_sys->aes_ctx ); return VLC_EGENERIC; } if( p_sys->b_generate_iv ) vlc_rand_bytes( p_sys->aes_ivs, sizeof(uint8_t)*16); return VLC_SUCCESS; }
/***************************************************************************** * CreateFilter: Create the filter and open the definition file *****************************************************************************/ static int CreateFilter ( vlc_object_t *p_this ) { filter_t *p_filter = (filter_t *)p_this; filter_sys_t *p_sys = malloc( sizeof (*p_sys) ); if( unlikely(p_sys == NULL) ) return VLC_ENOMEM; /* Populating struct */ vlc_mutex_init( &p_sys->lock ); p_sys->b_need_update = false; p_sys->psz_host = var_InheritString( p_this, RMTOSD_CFG "host" ); p_sys->psz_passwd = var_InheritString( p_this, RMTOSD_CFG "password" ); p_sys->i_alpha = var_InheritInteger( p_this, RMTOSD_CFG "alpha" ); p_sys->p_pic = NULL; p_sys->i_socket = -1; memset( p_sys->ar_color_table_yuv, 255, sizeof( p_sys->ar_color_table_yuv ) ); if( p_sys->psz_host == NULL ) { msg_Err( p_filter, "unable to get vnc host" ); goto error; } if( p_sys->psz_passwd == NULL ) { msg_Err( p_filter, "unable to get vnc password" ); goto error; } p_filter->p_sys = p_sys; vlc_gcrypt_init(); /* create the vnc worker thread */ if( vlc_clone( &p_sys->worker_thread, vnc_worker_thread, p_filter, VLC_THREAD_PRIORITY_LOW ) ) { msg_Err( p_filter, "cannot spawn vnc message reader thread" ); goto error; } /* Attach subpicture source callback */ p_filter->pf_sub_source = Filter; es_format_Init( &p_filter->fmt_out, SPU_ES, VLC_CODEC_SPU ); p_filter->fmt_out.i_priority = ES_PRIORITY_SELECTABLE_MIN; if( var_InheritBool( p_this, RMTOSD_CFG "mouse-events" ) ) p_filter->pf_sub_mouse = MouseEvent; p_sys->b_vnc_key_events = var_InheritBool( p_this, RMTOSD_CFG "key-events" ); if( p_sys->b_vnc_key_events ) var_AddCallback( p_filter->p_libvlc, "key-pressed", KeyEvent, p_this ); msg_Dbg( p_filter, "osdvnc filter started" ); return VLC_SUCCESS; error: msg_Err( p_filter, "osdvnc filter discarded" ); vlc_mutex_destroy( &p_sys->lock ); free( p_sys->psz_host ); free( p_sys->psz_passwd ); free( p_sys ); return VLC_EGENERIC; }
/* decrypts the RSA encrypted text read from the XML file, * and saves the AES key and the other needed info * uses libgcrypt for decryption */ int AESKey::decryptRSA( string s_cipher_text_b64 ) { RSAKey rsa_key( this->p_demux ); unsigned char *ps_cipher_text = NULL; unsigned char *ps_plain_text = NULL; gcry_mpi_t cipher_text_mpi = NULL; gcry_sexp_t cipher_text_sexp = NULL; gcry_sexp_t plain_text_sexp = NULL; gcry_mpi_t plain_text_mpi = NULL; gcry_sexp_t tmp_sexp = NULL; gcry_error_t err; size_t length; int i_ret = VLC_EGENERIC; /* get RSA private key file path */ if( rsa_key.setPath() ) goto end; /* read private key from file */ if( rsa_key.readPEM() ) goto end; /* remove spaces and newlines from encoded cipher text * (usually added for indentation in XML files) * */ try { s_cipher_text_b64.erase( remove_if( s_cipher_text_b64.begin(), s_cipher_text_b64.end(), static_cast<int(*)(int)>(isspace) ), s_cipher_text_b64.end() ); } catch( ... ) { msg_Err( this->p_demux, "error while handling string" ); goto end; } /* decode cipher from BASE64 to binary */ if( ! ( length = vlc_b64_decode_binary( &ps_cipher_text, s_cipher_text_b64.c_str() ) ) ) { msg_Err( this->p_demux, "could not decode cipher from Base64" ); goto end; } /* initialize libgcrypt */ vlc_gcrypt_init (); /* create S-expression for ciphertext */ if( ( err = gcry_mpi_scan( &cipher_text_mpi, GCRYMPI_FMT_USG, ps_cipher_text, 256, NULL ) ) ) { msg_Err( this->p_demux, "could not scan MPI from cipher text: %s", gcry_strerror( err ) ); goto end; } if( ( err = gcry_sexp_build( &cipher_text_sexp, NULL, "(enc-val(flags oaep)(rsa(a %m)))", cipher_text_mpi ) ) ) { msg_Err( this->p_demux, "could not build S-expression for cipher text: %s", gcry_strerror( err ) ); goto end; } /* decrypt */ if( ( err = gcry_pk_decrypt( &plain_text_sexp, cipher_text_sexp, rsa_key.priv_key ) ) ) { msg_Err( this->p_demux, "error while decrypting RSA encrypted info: %s", gcry_strerror( err ) ); goto end; } /* extract plain-text from S-expression */ if( ! ( tmp_sexp = gcry_sexp_find_token( plain_text_sexp, "value", 0 ) ) ) /* when using padding flags, the decrypted S-expression is of the form * "(value <plaintext>)", where <plaintext> is an MPI */ { msg_Err( this->p_demux, "decrypted text is in an unexpected form; decryption may have failed" ); goto end; } /* we could have used the gcry_sexp_nth_data to get the data directly, * but as that function is newly introduced (libgcrypt v1.6), * we prefer compatibility, even though that means passing the data through an MPI first */ if( ! ( plain_text_mpi = gcry_sexp_nth_mpi( tmp_sexp, 1, GCRYMPI_FMT_USG ) ) ) { msg_Err( this->p_demux, "could not extract MPI from decrypted S-expression" ); goto end; } if( ( err = gcry_mpi_aprint( GCRYMPI_FMT_USG, &ps_plain_text, &length, plain_text_mpi ) ) ) { msg_Err( this->p_demux, "error while extracting plain text from MPI: %s", gcry_strerror( err ) ); goto end; } /* interpret the plaintext data */ switch( length ) { case 138: /* SMPTE DCP */ if( this->extractInfo( ps_plain_text, true ) ) goto end; break; case 134: /* Interop DCP */ if( this->extractInfo( ps_plain_text, false ) ) goto end; break; case -1: msg_Err( this->p_demux, "could not decrypt" ); goto end; default: msg_Err( this->p_demux, "CipherValue field length does not match SMPTE nor Interop standards" ); goto end; } i_ret = VLC_SUCCESS; end: free( ps_cipher_text ); gcry_mpi_release( cipher_text_mpi ); gcry_sexp_release( cipher_text_sexp ); gcry_sexp_release( plain_text_sexp ); gcry_mpi_release( plain_text_mpi ); gcry_sexp_release( tmp_sexp ); gcry_free( ps_plain_text ); return i_ret; }
/***************************************************************************** * CreateFilter: Create the filter and open the definition file *****************************************************************************/ static int CreateFilter ( vlc_object_t *p_this ) { filter_t *p_filter = (filter_t *)p_this; filter_sys_t *p_sys = NULL; msg_Dbg( p_filter, "Creating vnc osd filter..." ); p_filter->p_sys = p_sys = calloc( 1, sizeof(*p_sys) ); if( !p_filter->p_sys ) return VLC_ENOMEM; /* Populating struct */ vlc_mutex_init( &p_sys->lock ); p_sys->b_continue = true; p_sys->i_socket = -1; p_sys->p_pic = NULL; p_sys->psz_host = var_CreateGetString( p_this, RMTOSD_CFG "host" ); if( EMPTY_STR(p_sys->psz_host) ) { msg_Err( p_filter, "unable to get vnc host" ); goto error; } p_sys->psz_passwd = var_CreateGetString( p_this, RMTOSD_CFG "password" ); if( !p_sys->psz_passwd ) { msg_Err( p_filter, "unable to get vnc password" ); goto error; } p_sys->i_port = var_CreateGetIntegerCommand( p_this, RMTOSD_CFG "port" ); p_sys->i_alpha = var_CreateGetIntegerCommand( p_this, RMTOSD_CFG "alpha" ); /* in milliseconds, 0 disables polling, should not be lower than 100 */ p_sys->i_vnc_poll_interval = var_CreateGetIntegerCommand( p_this, RMTOSD_CFG "update" ); if ( p_sys->i_vnc_poll_interval < 100) { p_sys->i_vnc_poll_interval = 100; } for ( int i = 0; i < 256; i++ ) { p_sys->ar_color_table_yuv[i][0] = 255; p_sys->ar_color_table_yuv[i][1] = 255; p_sys->ar_color_table_yuv[i][2] = 255; p_sys->ar_color_table_yuv[i][3] = 255; } p_sys->b_vnc_poll = var_CreateGetBoolCommand( p_this, RMTOSD_CFG "vnc-polling" ); p_sys->b_vnc_mouse_events = var_CreateGetBoolCommand( p_this, RMTOSD_CFG "mouse-events" ); p_sys->b_vnc_key_events = var_CreateGetBoolCommand( p_this, RMTOSD_CFG "key-events" ); /* Keep track of OSD Events */ p_sys->b_need_update = false; /* Attach subpicture source callback */ p_filter->pf_sub_source = Filter; p_filter->pf_sub_mouse = MouseEvent; var_AddCallback( p_filter->p_libvlc, "key-pressed", KeyEvent, p_this ); es_format_Init( &p_filter->fmt_out, SPU_ES, VLC_CODEC_SPU ); p_filter->fmt_out.i_priority = 0; vlc_gcrypt_init(); /* create the vnc worker thread */ if( vlc_clone( &p_sys->worker_thread, vnc_worker_thread, p_filter, VLC_THREAD_PRIORITY_LOW ) ) { msg_Err( p_filter, "cannot spawn vnc message reader thread" ); goto error; } msg_Dbg( p_filter, "osdvnc filter started" ); return VLC_SUCCESS; error: msg_Err( p_filter, "osdvnc filter discarded" ); stop_osdvnc( p_filter ); vlc_mutex_destroy( &p_sys->lock ); free( p_sys->psz_host ); free( p_sys->psz_passwd ); free( p_sys ); return VLC_EGENERIC; }