0%

【Linux技术分享】简单处理wine下smb无法使用问题

wine下目前不支持smb下拷贝,目前遇到wine下某应用启动后升级需要拷贝目标smb文件至指定文件夹中

问题概述

启动升级失败,现象如下图
图2

升级流程

  1. 与应用厂商沟通发现该应用升级首先调用WNetAddConnection2A函数

  2. wine启动增加mpr日志通道,日志输出如下,发现该函数调用三次
    图3

  3. WNetAddConnection2: 函数与网络资源建立连接,并且可以将本地设备重定向到网络资源。在该流程中此函数是建立与smb的服务器连接,从而访问服务器文件。

  4. 学习wine下源码,发现该函数在if (!providerTable || providerTable->numProviders == 0)判断时已返回,而providerTable是在wnetInit函数中进行初始化,源码大致如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    HKEY hKey;

    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\NetworkProvider\\Order",
    0, KEY_READ, &hKey) == ERROR_SUCCESS)
    {
    DWORD size = 0;

    RegQueryValueExW(hKey, L"ProviderOrder", NULL, NULL, NULL, &size);
    if (size)
    {
    ......
    providerTable =
    HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
    sizeof(WNetProviderTable)
    + (numToAllocate - 1) * sizeof(WNetProvider));
    ......
    }
  5. 打开wine下注册表发现System\\CurrentControlSet\\Control\\NetworkProvider\\Order\\NetworkProvider缺失,从window下注册表发现该项中LanmanWorkstation这项存在,

    • LanmanWorkstation 是 Windows 操作系统中的一个服务,正式名称为 ​Workstation 服务。它的主要功能是管理客户端与网络资源(如文件共享和打印机共享)的连接。具体来说,Workstation 服务负责处理与 SMB(Server Message Block)协议相关的操作,使客户端能够访问远程服务器上的共享资源。
      图4
  6. 将该注册表与相关dll导入至wine容器中,发现无法启动报错。

  7. 调研开发原生的wine下smb服务实现时间较长,不符合现场项目速度要求,所以尝试其他快速平替方案,暂时将该函数不返回错误码,代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @@ -2183,6 +2183,9 @@ DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, NETRESOURCEA *resource,
    TRACE( "(%p, %p, %p, %s, 0x%08lX, %p, %p, %p)\n", hwndOwner, resource, password, debugstr_a(userid), flags,
    accessname, buffer_size, result );

    + if(userid && !strcmp(userid, "ZEMR_USER")){
    + return 0;
    + }
    netresource_a_to_w(resource, &resourceW);

    ctxt.hwndOwner = hwndOwner;
  8. 在wine启动时增加file日志通道,发现升级时访问路径\\192.0.1.80\\nurse.update时,在wine中替换为UNC\\192.0.1.80\\nurse.update路径

    • 在 Windows 系统中,​UNC(Universal Naming Convention,通用命名约定)​ 是一种用于标识网络资源的标准化路径格式。UNC 路径通常用于访问网络共享资源,例如文件共享或打印机。
    • UNC 路径的基本格式如下:\ServerName\ShareName\Path

图5

具体方案

  1. 根据上述流程分析可以暂定一个方案,可以在系统开机时将目标服务器文件挂载至容器中,在wine中代码将UNC+服务器地址路径转换为本地路径中,细节交互图如下:
    图6

  2. 由于mount必须提权才可挂载,所以需要使用自启动的server文件,才能对智业smb服务器下文件进行访问,该服务器需要在系统的smbd服务启动后才可启动,细节如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    [Unit]
    Description=mount zhiye smb file
    After=smbd.service network.target
    Requires=smbd.service

    [Service]
    ExecStart=/usr/sbin/mount_zhiyesmb.sh
    Restart=on-failure
    User=root
    RestartSec=5s

    [Install]
    WantedBy=multi-user.target
  3. 对于wine下代码修改如下,当检测到192.0.1.80路径时替换至容器路径,将开机字自启动的挂载目录软连接到容器中即可成功访问

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @@ -272,8 +274,12 @@ NTSTATUS WINAPI RtlDosPathNameToNtPathName_U_WithStatus(const WCHAR *dos_path, U
    switch (RtlDetermineDosPathNameType_U(ptr))
    {
    case UNC_PATH: /* \\foo */
    - offset = 2;
    + offset = 2;
    + if(wcsstr(ptr,L"192.0.1.80")) {
    + wcscat(ntpath->Buffer, L"C:\\");
    + }else {
    wcscat(ntpath->Buffer, L"UNC\\");
    + }
    break;
    case DEVICE_PATH: /* \\.\foo */
    offset = 4;
    --

验证

修改后启动后升级效果图如下:
图6

其他方案

  • 方案1:完成wine下的​Workstation服务,让其支持容器下的smb连接
    • 优点:能够完整的符合window逻辑,实现smb服务的启动与访问。
    • 缺点:难度较大,实现时间较长。
  • 方案2:在wine下访问unc路径时,使用C实现SMB下的文件夹访问/读取/拷贝
    • 优点:难度中等,属于方案1的平替方案,可以间接补充wine下smb文件访问的代码,完成后有一定的代码通用性。
    • 缺点:与window下的smb服务逻辑有出入,未实现window下的smb服务启动。