Cannot access file on Samba server via Python

Grant Bartel picture Grant Bartel · Aug 7, 2017 · Viewed 9.2k times · Source

I'm trying to access a file on our Samba server using Python. I found out I need to use a Samba client for this, so I started using PySmbClient. Even though there are many examples online of how to do this, mine just does not want to work. See below.

smb = smbclient.SambaClient(server="192.168.0.320", share="DATA", domain="WORKGROUP",username="admin", password="abc123")
f = smb.open('test.json', 'r')

This produces the following error:

OSError: [Errno 2] No such file or directory

with the following trace:

Traceback (most recent call last):
  File "create_dataset.py", line 35, in <module>
    f = smb.open('serverSaver.txt', 'r')
  File "/home/grant/Development/create_dataset/env/local/lib/python2.7/site-packages/smbclient.py", line 408, in open
    f = _SambaFile(self, path, mode)
  File "/home/grant/Development/create_dataset/env/local/lib/python2.7/site-packages/smbclient.py", line 448, in __init__
    connection.download(remote_name, self._tmp_name)
  File "/home/grant/Development/create_dataset/env/local/lib/python2.7/site-packages/smbclient.py", line 393, in download
    result = self._runcmd('get', remote_path, local_path)
  File "/home/grant/Development/create_dataset/env/local/lib/python2.7/site-packages/smbclient.py", line 184, in _runcmd
    return self._raw_runcmd(fullcmd)
  File "/home/grant/Development/create_dataset/env/local/lib/python2.7/site-packages/smbclient.py", line 168, in _raw_runcmd
    stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  File "/usr/lib/python2.7/subprocess.py", line 711, in __init__
    errread, errwrite)
  File "/usr/lib/python2.7/subprocess.py", line 1343, in _execute_child
    raise child_exception

I've read and implemented many "solutions", but so far nothing has worked for me. I can access the Samba server with the given credentials through my file manager just fine, so I know those values should be fine. I even spoke to our sys admin and he doesn't know what could be wrong.

It must be more than the simple code I wrote. Do you think there's an issue on the server side of things? Something with the values I input into SambaClient? At this point I'm pretty much open to anything that leads to a solution.

Answer

AS Mackay picture AS Mackay · Aug 8, 2017

Here's some code that works for me, transferring a file from a Linux Samba share to my Windows laptop. It's also known to work fine in the other direction (Linux client, Windows server).

I'm using the pysmb library version 1.1.19 (the latest) and Python 2.7.1.

See the pysmb site for the pysmb package; I actually downloaded and installed it directly from its tarball and setup.py, as pip was throwing an error.

The pysmb package is less user-friendly but it does work well for Windows clients.

I set up a share called "my_share" on the Linux machine for user "edwards" using the following entry in smb.conf:

[my_share]
path = /home/edwards
valid_users = edwards
read only = no
guest ok = yes
browseable = yes

And then used the following code to list the files on the share, and download a file called "rti_license.dat" to my laptop:

import tempfile
import smb
import shutil

from smb.SMBConnection import SMBConnection

share_name          = "my_share"
user_name           = "edwards"
password            = "######"             # secret :-)
local_machine_name  = "laptop"             # arbitrary
server_machine_name = "edwards-Yocto"      # MUST match correctly
server_IP           = "192.162.2.1"        # as must this            

# create and establish connection
conn = SMBConnection(user_name, password, local_machine_name, server_machine_name, use_ntlm_v2 = True)

assert conn.connect(server_IP, 139)

# print list of files at the root of the share
files = conn.listPath(share_name, "/") 
for item in files:
    print item.filename

# check if the file we want is there
sf = conn.getAttributes(share_name, "rti_license.dat")
print sf.file_size
print sf.filename

# create a temporary file for the transfer
file_obj = tempfile.NamedTemporaryFile(mode='w+t', delete=False)
file_name = file_obj.name
file_attributes, copysize = conn.retrieveFile(share_name, "rti_license.dat", file_obj)
print copysize
file_obj.close()

# copy temporary file 
shutil.copy(file_name, "rti_license.dat")

# close connection
conn.close()

Note that the server name must be correct or the connection won't work (from a Linux machine it's the output of the hostname command)

Hope this may be useful.