2018-02-09 18:42:18 +03:00
# -*- coding: utf-8 -*-
# Unix SMB/CIFS implementation. Tests for smb manipulation
# Copyright (C) David Mulder <dmulder@suse.com> 2018
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2018-07-30 09:21:38 +03:00
import samba
import os
import random
import sys
2018-12-03 01:15:14 +03:00
from samba import NTSTATUSError
2018-12-06 06:16:36 +03:00
from samba . ntstatus import ( NT_STATUS_OBJECT_NAME_NOT_FOUND ,
NT_STATUS_OBJECT_PATH_NOT_FOUND )
2018-12-13 02:32:17 +03:00
from samba . samba3 import libsmb
2018-12-03 00:50:19 +03:00
from samba . samba3 import param as s3param
2018-02-09 18:42:18 +03:00
PY3 = sys . version_info [ 0 ] == 3
2018-12-12 00:04:09 +03:00
realm = os . environ . get ( ' REALM ' )
domain_dir = realm . lower ( ) + ' / '
2018-07-30 09:18:25 +03:00
test_contents = ' abcd ' * 256
utf_contents = u ' Süßigkeiten Äpfel ' * 128
test_literal_bytes_embed_nulls = b ' \xff \xfe \x14 \x61 \x00 \x00 \x62 \x63 \x64 ' * 256
2018-02-09 18:42:18 +03:00
binary_contents = b ' \xff \xfe '
2018-07-30 09:18:25 +03:00
binary_contents = binary_contents + " Hello cruel world of python3 " . encode ( ' utf8 ' ) * 128
2018-12-12 00:04:09 +03:00
test_dir = os . path . join ( domain_dir , ' testing_ %d ' % random . randint ( 0 , 0xFFFF ) )
2018-02-09 18:42:18 +03:00
test_file = os . path . join ( test_dir , ' testing ' ) . replace ( ' / ' , ' \\ ' )
2018-07-30 09:20:39 +03:00
2018-02-09 18:42:18 +03:00
class SMBTests ( samba . tests . TestCase ) :
def setUp ( self ) :
super ( SMBTests , self ) . setUp ( )
self . server = os . environ [ " SERVER " ]
creds = self . insta_creds ( template = self . get_credentials ( ) )
2018-12-03 00:50:19 +03:00
2018-12-12 04:42:30 +03:00
# create an SMB connection to the server
2018-12-03 00:50:19 +03:00
lp = s3param . get_context ( )
lp . load ( os . getenv ( " SMB_CONF_PATH " ) )
2018-12-13 02:32:17 +03:00
self . smb_conn = libsmb . Conn ( self . server , " sysvol " , lp , creds )
2018-12-03 00:50:19 +03:00
2018-12-03 06:27:07 +03:00
self . smb_conn . mkdir ( test_dir )
2018-02-09 18:42:18 +03:00
def tearDown ( self ) :
super ( SMBTests , self ) . tearDown ( )
try :
2018-12-12 03:45:46 +03:00
self . smb_conn . deltree ( test_dir )
2018-02-09 18:42:18 +03:00
except :
pass
def test_list ( self ) :
2018-12-03 07:22:43 +03:00
# check a basic listing returns the items we expect
2018-12-12 00:04:09 +03:00
ls = [ f [ ' name ' ] for f in self . smb_conn . list ( domain_dir ) ]
2018-02-09 18:42:18 +03:00
self . assertIn ( ' scripts ' , ls ,
2018-07-30 09:16:12 +03:00
msg = ' " scripts " directory not found in sysvol ' )
2018-07-30 09:19:05 +03:00
self . assertIn ( ' Policies ' , ls ,
2018-07-30 09:16:12 +03:00
msg = ' " Policies " directory not found in sysvol ' )
2018-12-03 07:22:43 +03:00
self . assertNotIn ( ' .. ' , ls ,
msg = ' Parent (..) found in directory listing ' )
self . assertNotIn ( ' . ' , ls ,
msg = ' Current dir (.) found in directory listing ' )
# using a '*' mask should be the same as using no mask
2018-12-12 00:04:09 +03:00
ls_wildcard = [ f [ ' name ' ] for f in self . smb_conn . list ( domain_dir , " * " ) ]
2018-12-03 07:22:43 +03:00
self . assertEqual ( ls , ls_wildcard )
# applying a mask should only return items that match that mask
2018-12-12 00:04:09 +03:00
ls_pol = [ f [ ' name ' ] for f in self . smb_conn . list ( domain_dir , " Pol* " ) ]
2018-12-03 07:22:43 +03:00
expected = [ " Policies " ]
self . assertEqual ( ls_pol , expected )
# each item in the listing is a has with expected keys
expected_keys = [ ' attrib ' , ' mtime ' , ' name ' , ' short_name ' , ' size ' ]
2018-12-12 00:04:09 +03:00
for item in self . smb_conn . list ( domain_dir ) :
2018-12-03 07:22:43 +03:00
for key in expected_keys :
self . assertIn ( key , item ,
msg = " Key ' %s ' not in listing ' %s ' " % ( key , item ) )
2018-12-06 06:16:36 +03:00
def test_deltree ( self ) :
""" The smb.deltree API should delete files and sub-dirs """
# create some test sub-dirs
dirpaths = [ ]
empty_dirs = [ ]
cur_dir = test_dir
2018-12-12 03:45:46 +03:00
2018-12-06 06:16:36 +03:00
for subdir in [ " subdir-X " , " subdir-Y " , " subdir-Z " ] :
path = self . make_sysvol_path ( cur_dir , subdir )
2018-12-03 06:27:07 +03:00
self . smb_conn . mkdir ( path )
2018-12-06 06:16:36 +03:00
dirpaths . append ( path )
cur_dir = path
# create another empty dir just for kicks
path = self . make_sysvol_path ( cur_dir , " another " )
2018-12-03 06:27:07 +03:00
self . smb_conn . mkdir ( path )
2018-12-06 06:16:36 +03:00
empty_dirs . append ( path )
# create some files in these directories
filepaths = [ ]
for subdir in dirpaths :
for i in range ( 1 , 4 ) :
contents = " I ' m file {0} in dir {1} ! " . format ( i , subdir )
path = self . make_sysvol_path ( subdir , " file- {0} .txt " . format ( i ) )
2018-12-10 23:34:42 +03:00
self . smb_conn . savefile ( path , test_contents . encode ( ' utf8 ' ) )
2018-12-06 06:16:36 +03:00
filepaths . append ( path )
# sanity-check these dirs/files exist
for subdir in dirpaths + empty_dirs :
2018-12-03 06:33:19 +03:00
self . assertTrue ( self . smb_conn . chkpath ( subdir ) ,
2018-12-06 06:16:36 +03:00
" Failed to create {0} " . format ( subdir ) )
for path in filepaths :
self . assertTrue ( self . file_exists ( path ) ,
" Failed to create {0} " . format ( path ) )
# try using deltree to remove a single empty directory
path = empty_dirs . pop ( 0 )
2018-12-12 03:45:46 +03:00
self . smb_conn . deltree ( path )
2018-12-03 06:33:19 +03:00
self . assertFalse ( self . smb_conn . chkpath ( path ) ,
2018-12-06 06:16:36 +03:00
" Failed to delete {0} " . format ( path ) )
# try using deltree to remove a single file
path = filepaths . pop ( 0 )
2018-12-12 03:45:46 +03:00
self . smb_conn . deltree ( path )
2018-12-06 06:16:36 +03:00
self . assertFalse ( self . file_exists ( path ) ,
" Failed to delete {0} " . format ( path ) )
# delete the top-level dir
2018-12-12 03:45:46 +03:00
self . smb_conn . deltree ( test_dir )
2018-12-06 06:16:36 +03:00
# now check that all the dirs/files are no longer there
for subdir in dirpaths + empty_dirs :
2018-12-03 06:33:19 +03:00
self . assertFalse ( self . smb_conn . chkpath ( subdir ) ,
2018-12-06 06:16:36 +03:00
" Failed to delete {0} " . format ( subdir ) )
for path in filepaths :
self . assertFalse ( self . file_exists ( path ) ,
" Failed to delete {0} " . format ( path ) )
2018-02-09 18:42:18 +03:00
2018-12-03 01:15:14 +03:00
def file_exists ( self , filepath ) :
""" Returns whether a regular file exists (by trying to open it) """
try :
2018-12-05 05:08:09 +03:00
self . smb_conn . loadfile ( filepath )
2018-12-03 01:15:14 +03:00
exists = True ;
except NTSTATUSError as err :
2018-12-06 06:16:36 +03:00
if ( err . args [ 0 ] == NT_STATUS_OBJECT_NAME_NOT_FOUND or
err . args [ 0 ] == NT_STATUS_OBJECT_PATH_NOT_FOUND ) :
2018-12-03 01:15:14 +03:00
exists = False
else :
raise err
return exists
2018-06-13 01:39:57 +03:00
def test_unlink ( self ) :
"""
The smb . unlink API should delete file
"""
2018-12-03 01:15:14 +03:00
# create the test file
self . assertFalse ( self . file_exists ( test_file ) )
2018-12-10 23:34:42 +03:00
self . smb_conn . savefile ( test_file , binary_contents )
2018-12-03 01:15:14 +03:00
self . assertTrue ( self . file_exists ( test_file ) )
# delete it and check that it's gone
2018-12-03 00:50:19 +03:00
self . smb_conn . unlink ( test_file )
2018-12-03 01:15:14 +03:00
self . assertFalse ( self . file_exists ( test_file ) )
2018-06-13 01:39:57 +03:00
2018-12-03 01:01:14 +03:00
def test_chkpath ( self ) :
""" Tests .chkpath determines whether or not a directory exists """
2018-12-03 06:33:19 +03:00
self . assertTrue ( self . smb_conn . chkpath ( test_dir ) )
2018-12-03 01:01:14 +03:00
# should return False for a non-existent directory
bad_dir = self . make_sysvol_path ( test_dir , ' dont_exist ' )
2018-12-03 06:33:19 +03:00
self . assertFalse ( self . smb_conn . chkpath ( bad_dir ) )
2018-12-03 01:01:14 +03:00
# should return False for files (because they're not directories)
2018-12-10 23:34:42 +03:00
self . smb_conn . savefile ( test_file , binary_contents )
2018-12-03 06:33:19 +03:00
self . assertFalse ( self . smb_conn . chkpath ( test_file ) )
2018-12-03 01:01:14 +03:00
# check correct result after creating and then deleting a new dir
new_dir = self . make_sysvol_path ( test_dir , ' test-new ' )
2018-12-03 06:27:07 +03:00
self . smb_conn . mkdir ( new_dir )
2018-12-03 06:33:19 +03:00
self . assertTrue ( self . smb_conn . chkpath ( new_dir ) )
2018-12-03 06:27:07 +03:00
self . smb_conn . rmdir ( new_dir )
2018-12-03 06:33:19 +03:00
self . assertFalse ( self . smb_conn . chkpath ( new_dir ) )
2018-12-03 01:01:14 +03:00
2018-02-09 18:42:18 +03:00
def test_save_load_text ( self ) :
2018-12-10 23:34:42 +03:00
self . smb_conn . savefile ( test_file , test_contents . encode ( ' utf8 ' ) )
2018-02-09 18:42:18 +03:00
2018-12-05 05:08:09 +03:00
contents = self . smb_conn . loadfile ( test_file )
2018-02-09 18:42:18 +03:00
self . assertEquals ( contents . decode ( ' utf8 ' ) , test_contents ,
2018-07-30 09:16:12 +03:00
msg = ' contents of test file did not match what was written ' )
2018-02-09 18:42:18 +03:00
2018-12-05 02:51:22 +03:00
# check we can overwrite the file with new contents
new_contents = ' wxyz ' * 128
2018-12-10 23:34:42 +03:00
self . smb_conn . savefile ( test_file , new_contents . encode ( ' utf8 ' ) )
2018-12-05 05:08:09 +03:00
contents = self . smb_conn . loadfile ( test_file )
2018-12-05 02:51:22 +03:00
self . assertEquals ( contents . decode ( ' utf8 ' ) , new_contents ,
msg = ' contents of test file did not match what was written ' )
2018-02-09 18:42:18 +03:00
# with python2 this will save/load str type (with embedded nulls)
# with python3 this will save/load bytes type
def test_save_load_string_bytes ( self ) :
2018-12-10 23:34:42 +03:00
self . smb_conn . savefile ( test_file , test_literal_bytes_embed_nulls )
2018-02-09 18:42:18 +03:00
2018-12-05 05:08:09 +03:00
contents = self . smb_conn . loadfile ( test_file )
2018-02-09 18:42:18 +03:00
self . assertEquals ( contents , test_literal_bytes_embed_nulls ,
2018-07-30 09:16:12 +03:00
msg = ' contents of test file did not match what was written ' )
2018-02-09 18:42:18 +03:00
# python3 only this will save/load unicode
def test_save_load_utfcontents ( self ) :
if PY3 :
2018-12-10 23:34:42 +03:00
self . smb_conn . savefile ( test_file , utf_contents . encode ( ' utf8 ' ) )
2018-02-09 18:42:18 +03:00
2018-12-05 05:08:09 +03:00
contents = self . smb_conn . loadfile ( test_file )
2018-02-09 18:42:18 +03:00
self . assertEquals ( contents . decode ( ' utf8 ' ) , utf_contents ,
2018-07-30 09:16:12 +03:00
msg = ' contents of test file did not match what was written ' )
2018-02-09 18:42:18 +03:00
# with python2 this will save/load str type
# with python3 this will save/load bytes type
def test_save_binary_contents ( self ) :
2018-12-10 23:34:42 +03:00
self . smb_conn . savefile ( test_file , binary_contents )
2018-02-09 18:42:18 +03:00
2018-12-05 05:08:09 +03:00
contents = self . smb_conn . loadfile ( test_file )
2018-02-09 18:42:18 +03:00
self . assertEquals ( contents , binary_contents ,
2018-07-30 09:16:12 +03:00
msg = ' contents of test file did not match what was written ' )
2018-12-03 01:01:14 +03:00
def make_sysvol_path ( self , dirpath , filename ) :
# return the dir + filename as a sysvol path
return os . path . join ( dirpath , filename ) . replace ( ' / ' , ' \\ ' )