1 /*****************************************************************************
2 * samba.c: Samba / libsmbclient input module
3 *****************************************************************************
4 * Copyright (C) 2001-2015 VLC authors and VideoLAN
6 * Authors: Gildas Bazin <gbazin@videolan.org>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
29 #include <libsmbclient.h>
31 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_access.h>
35 #include <vlc_input_item.h>
37 #include <vlc_keystore.h>
39 #include "smb_common.h"
49 * smb://[[[domain;]user[:password@]]server[/share[/path[/file]]]] */
50 static char *smb_get_uri(
51 const char *psz_domain
,
52 const char *psz_user
, const char *psz_pwd
,
53 const char *psz_server
, const char *psz_share_path
,
59 #define PSZ_SHARE_PATH_OR_NULL psz_share_path ? psz_share_path : ""
60 #define PSZ_NAME_OR_NULL psz_name ? "/" : "", psz_name ? psz_name : ""
62 ? asprintf( &uri
, "smb://%s%s%s%s%s@%s%s%s%s",
63 psz_domain
? psz_domain
: "", psz_domain
? ";" : "",
64 psz_user
, psz_pwd
? ":" : "",
65 psz_pwd
? psz_pwd
: "", psz_server
,
66 PSZ_SHARE_PATH_OR_NULL
, PSZ_NAME_OR_NULL
)
67 : asprintf( &uri
, "smb://%s%s%s%s", psz_server
,
68 PSZ_SHARE_PATH_OR_NULL
, PSZ_NAME_OR_NULL
)) == -1 )
73 /*****************************************************************************
74 * Seek: try to go at the right place
75 *****************************************************************************/
76 static int Seek( stream_t
*p_access
, uint64_t i_pos
)
78 access_sys_t
*p_sys
= p_access
->p_sys
;
81 if( i_pos
>= INT64_MAX
)
84 msg_Dbg( p_access
, "seeking to %"PRId64
, i_pos
);
86 i_ret
= smbc_lseek( p_sys
->i_smb
, i_pos
, SEEK_SET
);
89 msg_Err( p_access
, "seek failed (%s)", vlc_strerror_c(errno
) );
96 /*****************************************************************************
98 *****************************************************************************/
99 static ssize_t
Read( stream_t
*p_access
, void *p_buffer
, size_t i_len
)
101 access_sys_t
*p_sys
= p_access
->p_sys
;
104 i_read
= smbc_read( p_sys
->i_smb
, p_buffer
, i_len
);
107 msg_Err( p_access
, "read failed (%s)", vlc_strerror_c(errno
) );
114 /*****************************************************************************
116 *****************************************************************************/
117 static int DirRead (stream_t
*p_access
, input_item_node_t
*p_node
)
119 access_sys_t
*p_sys
= p_access
->p_sys
;
120 int i_ret
= VLC_SUCCESS
;
122 struct vlc_readdir_helper rdh
;
123 vlc_readdir_helper_init( &rdh
, p_access
, p_node
);
125 struct smbc_dirent
*p_entry
;
127 while( i_ret
== VLC_SUCCESS
&& ( p_entry
= smbc_readdir( p_sys
->i_smb
) ) )
129 const char *psz_server
= p_sys
->url
.psz_host
;
130 const char *psz_path
= p_sys
->url
.psz_path
;
131 const char *psz_name
= p_entry
->name
;
134 switch( p_entry
->smbc_type
)
138 psz_server
= p_sys
->url
.psz_host
;
142 case SMBC_FILE_SHARE
:
144 i_type
= ITEM_TYPE_DIRECTORY
;
147 i_type
= ITEM_TYPE_FILE
;
150 case SMBC_PRINTER_SHARE
:
151 case SMBC_COMMS_SHARE
:
157 char *psz_encoded_name
= NULL
;
159 && ( psz_encoded_name
= vlc_uri_encode( psz_name
) ) == NULL
)
165 char *uri
= smb_get_uri(NULL
, NULL
, NULL
,
166 psz_server
, psz_path
, psz_encoded_name
);
168 free(psz_encoded_name
);
172 free(psz_encoded_name
);
173 i_ret
= vlc_readdir_helper_additem(&rdh
, uri
, NULL
, p_entry
->name
,
178 vlc_readdir_helper_finish( &rdh
, i_ret
== VLC_SUCCESS
);
183 /*****************************************************************************
185 *****************************************************************************/
186 static int Control( stream_t
*p_access
, int i_query
, va_list args
)
188 access_sys_t
*sys
= p_access
->p_sys
;
192 case STREAM_CAN_SEEK
:
193 case STREAM_CAN_PAUSE
:
194 case STREAM_CAN_CONTROL_PACE
:
195 *va_arg( args
, bool* ) = true;
198 case STREAM_CAN_FASTSEEK
:
199 *va_arg( args
, bool* ) = false;
202 case STREAM_GET_SIZE
:
203 if( p_access
->pf_readdir
!= NULL
)
205 *va_arg( args
, uint64_t * ) = sys
->size
;
208 case STREAM_GET_PTS_DELAY
:
209 *va_arg( args
, vlc_tick_t
* ) = VLC_TICK_FROM_MS(
210 var_InheritInteger( p_access
, "network-caching" ) );
213 case STREAM_SET_PAUSE_STATE
:
224 static void smb_auth(const char *srv
, const char *shr
, char *wg
, int wglen
,
225 char *un
, int unlen
, char *pw
, int pwlen
)
235 //wglen = unlen = pwlen = 0;
238 static int Open(vlc_object_t
*obj
)
240 stream_t
*access
= (stream_t
*)obj
;
242 vlc_credential credential
;
243 char *psz_decoded_path
= NULL
, *uri
, *psz_var_domain
= NULL
;
248 if (smbc_init(smb_auth
, 0))
251 if (vlc_UrlParseFixup(&url
, access
->psz_url
) != 0)
257 if (url
.psz_path
!= NULL
)
259 psz_decoded_path
= vlc_uri_decode_duplicate(url
.psz_path
);
260 if (psz_decoded_path
== NULL
)
267 vlc_credential_init(&credential
, &url
);
268 psz_var_domain
= var_InheritString(access
, "smb-domain");
269 credential
.psz_realm
= psz_var_domain
;
270 vlc_credential_get(&credential
, access
, "smb-user", "smb-pwd", NULL
, NULL
);
276 uri
= smb_get_uri(credential
.psz_realm
, credential
.psz_username
,
277 credential
.psz_password
, url
.psz_host
,
278 psz_decoded_path
, NULL
);
281 vlc_credential_clean(&credential
);
282 free(psz_var_domain
);
283 free(psz_decoded_path
);
288 if (smbc_stat(uri
, &st
) == 0)
290 is_dir
= S_ISDIR(st
.st_mode
) != 0;
295 /* smbc_stat() fails with servers or shares. Assume directory. */
303 if (!vlc_credential_get(&credential
, access
, "smb-user",
304 "smb-pwd", SMB_LOGIN_DIALOG_TITLE
,
305 SMB_LOGIN_DIALOG_TEXT
, url
.psz_host
))
309 vlc_credential_store(&credential
, access
);
310 vlc_credential_clean(&credential
);
311 free(psz_var_domain
);
312 free(psz_decoded_path
);
315 access_sys_t
*sys
= vlc_obj_calloc(obj
, 1, sizeof (*sys
));
316 if (unlikely(sys
== NULL
))
328 access
->pf_readdir
= DirRead
;
329 access
->pf_control
= access_vaDirectoryControlHelper
;
330 fd
= smbc_opendir(uri
);
332 vlc_UrlClean(&sys
->url
);
336 access
->pf_read
= Read
;
337 access
->pf_control
= Control
;
338 access
->pf_seek
= Seek
;
339 fd
= smbc_open(uri
, O_RDONLY
, 0);
346 msg_Err(obj
, "cannot open %s: %s",
347 access
->psz_location
, vlc_strerror_c(errno
));
357 static void Close(vlc_object_t
*obj
)
359 stream_t
*access
= (stream_t
*)obj
;
360 access_sys_t
*sys
= access
->p_sys
;
362 vlc_UrlClean(&sys
->url
);
364 if (access
->pf_readdir
!= NULL
)
365 smbc_closedir(sys
->i_smb
);
367 smbc_close(sys
->i_smb
);
372 set_description(N_("SMB input"))
373 set_help(N_("Samba (Windows network shares) input"))
374 set_capability("access", 0)
375 set_category(CAT_INPUT
)
376 set_subcategory(SUBCAT_INPUT_ACCESS
)
377 add_string("smb-user", NULL
, SMB_USER_TEXT
, SMB_USER_LONGTEXT
, false)
378 add_password("smb-pwd", NULL
, SMB_PASS_TEXT
, SMB_PASS_LONGTEXT
)
379 add_string("smb-domain", NULL
, SMB_DOMAIN_TEXT
, SMB_DOMAIN_LONGTEXT
, false)
381 set_callbacks(Open
, Close
)