Mono DllImport libsmbclient не аутентифицируется
Мне нужно иметь доступ к общему ресурсу Samba/Cifs из Mono, используя определенные учетные данные.
Лучший вариант, который я нашел, - это использовать libsmbclient. К сожалению, я не могу получить его для проверки подлинности. Чтобы исключить брандмауэр / безопасность / и т.д., я попытался использовать smbclient
исполняемый файл, который можно подключить без проблем.
Низкоуровневая библиотека DLLImport и некоторые жестко запрограммированные кредиты для тестирования...
public static void Initialise() {
log.Trace("Initialising libsmbclient wrapper");
try {
smbc_init(callbackAuth, 1);
} catch (Exception e) {
log.Trace(String.Format("{0}: {1}", e.GetType().Name, e.ToString()));
throw;
}
}
public static void callbackAuth(
[MarshalAs(UnmanagedType.LPStr)]String server,
[MarshalAs(UnmanagedType.LPStr)]String share,
[MarshalAs(UnmanagedType.LPStr)]String workgroup, int workgroupMaxLen,
[MarshalAs(UnmanagedType.LPStr)]String username, int usernameMaxLen,
[MarshalAs(UnmanagedType.LPStr)]String password, int passwordMaxLen) {
server = "targetserver";
share = "Public";
username = "Management.Service";
password = @"{SomeComplexPassword}";
workgroup = "targetserver";
usernameMaxLen = username.Length;
passwordMaxLen = password.Length;
workgroupMaxLen = workgroup.Length;
}
[DllImport("libsmbclient.so", SetLastError = true)]
extern internal static int smbc_init(smbCGetAuthDataFn callBackAuth, int debug);
[DllImport("libsmbclient.so", SetLastError = true)]
extern internal static int smbc_opendir([MarshalAs(UnmanagedType.LPStr)]String durl);
Я пытаюсь использовать это так...
public bool DirectoryExists(string path) {
log.Trace("Checking directory exists {0}", path);
int handle;
string fullpath = @"smb:" + parseUNCPath(path);
handle = SambaWrapper.smbc_opendir(fullpath);
if (handle < 0) {
var error = Stdlib.GetLastError().ToString();
if (error == "ENOENT"
|error == "EINVAL")
return false;
else
throw new Exception(error);
} else {
WrapperSambaClient.smbc_close(fd);
return true;
}
}
Initialise()
вызов успешно, но когда DirectoryExists
звонки SambaWrapper.smbc_opendir(fullpath)
Я получаю отрицательную ручку и выбрасываю следующее исключение...
Slurpy.Exceptions.FetchException: исключение: не удалось получить: EACCES > (файл:////targetserver/Public/ValidSubfolder) ---> System.Exception: EACCES
Что я делаю неправильно? Есть ли способ отладить это?
Редактировать: Кажется, проблема в том, что значения из обратного вызова auth не имеют никакого эффекта (но обратный вызов определенно вызывается, поскольку там обрабатывается оператор журнала). Мне интересно, это как-то связано с неизменяемостью строк и созданием нового экземпляра строки с новыми значениями, а не с перезаписью старых?
Редактировать: удалена полная отладочная информация от libsmbclient, пытающегося подключиться. Вы можете увидеть это в истории редактирования, если требуется.
По запросу, определение метода из заголовков...
/**@ingroup misc
* Initialize the samba client library.
*
* Must be called before using any of the smbclient API function
*
* @param fn The function that will be called to obtaion
* authentication credentials.
*
* @param debug Allows caller to set the debug level. Can be
* changed in smb.conf file. Allows caller to set
* debugging if no smb.conf.
*
* @return 0 on success, < 0 on error with errno set:
* - ENOMEM Out of memory
* - ENOENT The smb.conf file would not load
*
*/
int smbc_init(smbc_get_auth_data_fn fn, int debug);
/**@ingroup callback
* Authentication callback function type (traditional method)
*
* Type for the the authentication function called by the library to
* obtain authentication credentals
*
* For kerberos support the function should just be called without
* prompting the user for credentials. Which means a simple 'return'
* should work. Take a look at examples/libsmbclient/get_auth_data_fn.h
* and examples/libsmbclient/testbrowse.c.
*
* @param srv Server being authenticated to
*
* @param shr Share being authenticated to
*
* @param wg Pointer to buffer containing a "hint" for the
* workgroup to be authenticated. Should be filled in
* with the correct workgroup if the hint is wrong.
*
* @param wglen The size of the workgroup buffer in bytes
*
* @param un Pointer to buffer containing a "hint" for the
* user name to be use for authentication. Should be
* filled in with the correct workgroup if the hint is
* wrong.
*
* @param unlen The size of the username buffer in bytes
*
* @param pw Pointer to buffer containing to which password
* copied
*
* @param pwlen The size of the password buffer in bytes
*
*/
typedef void (*smbc_get_auth_data_fn)(const char *srv,
const char *shr,
char *wg, int wglen,
char *un, int unlen,
char *pw, int pwlen);
1 ответ
Ваш обратный вызов вызывается libsmbclient, и он передает буфер и его длину из неуправляемого кода, ожидая, что вы заполните имя пользователя и пароль. Поскольку эта выделенная память контролируется вызывающей стороной, вы не можете использовать строку или строитель строк. Я предлагаю использовать IntPtr и заполнять буфер на минимально возможном уровне.
(С другой стороны, server и share являются строками только для чтения, и не ожидается, что они изменятся, поэтому мы можем сохранить их в виде строки).
public static void callbackAuth(
[MarshalAs(UnmanagedType.LPStr)]String server,
[MarshalAs(UnmanagedType.LPStr)]String share,
IntPtr workgroup, int workgroupMaxLen,
IntPtr username, int usernameMaxLen,
IntPtr password, int passwordMaxLen)
{
//server = "targetserver";
//share = "Public";
// should not be assigned -
// you must provide credentials for specified server
SetString(username, "Management.Service", username.Length);
SetString(password, @"{SomeComplexPassword}", password.Length);
SetString(workgroup, "targetserver", workgroup.Length);
}
private void SetString(IntPtr dest, string str, int maxLen)
{
// include null string terminator
byte[] buffer = Encoding.ASCII.GetBytes(str + "\0");
if (buffer.Length >= maxLen) return; // buffer is not big enough
Marshal.Copy(buffer, 0, dest, buffer.Length);
}