@@ -3,8 +3,15 @@ package smb
3
3
import (
4
4
"fmt"
5
5
"strings"
6
+ "syscall"
6
7
8
+ "github.com/kubernetes-csi/csi-proxy/pkg/cim"
7
9
"github.com/kubernetes-csi/csi-proxy/pkg/utils"
10
+ "golang.org/x/sys/windows"
11
+ )
12
+
13
+ const (
14
+ credentialDelimiter = ":"
8
15
)
9
16
10
17
type API interface {
@@ -26,18 +33,52 @@ func New(requirePrivacy bool) *SmbAPI {
26
33
}
27
34
}
28
35
36
+ func remotePathForQuery (remotePath string ) string {
37
+ return strings .ReplaceAll (remotePath , "\\ " , "\\ \\ " )
38
+ }
39
+
40
+ func escapeUserName (userName string ) string {
41
+ // refer to https://github.com/PowerShell/PowerShell/blob/9303de597da55963a6e26a8fe164d0b256ca3d4d/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimConverter.cs#L169-L170
42
+ escaped := strings .ReplaceAll (userName , "\\ " , "\\ \\ " )
43
+ escaped = strings .ReplaceAll (escaped , credentialDelimiter , "\\ " + credentialDelimiter )
44
+ return escaped
45
+ }
46
+
47
+ func createSymlink (link , target string , isDir bool ) error {
48
+ linkPtr , err := syscall .UTF16PtrFromString (link )
49
+ if err != nil {
50
+ return err
51
+ }
52
+ targetPtr , err := syscall .UTF16PtrFromString (target )
53
+ if err != nil {
54
+ return err
55
+ }
56
+
57
+ var flags uint32
58
+ if isDir {
59
+ flags = windows .SYMBOLIC_LINK_FLAG_DIRECTORY
60
+ }
61
+
62
+ err = windows .CreateSymbolicLink (
63
+ linkPtr ,
64
+ targetPtr ,
65
+ flags ,
66
+ )
67
+ return err
68
+ }
69
+
29
70
func (* SmbAPI ) IsSmbMapped (remotePath string ) (bool , error ) {
30
- cmdLine := `$(Get-SmbGlobalMapping -RemotePath $Env:smbremotepath -ErrorAction Stop).Status `
31
- cmdEnv := fmt .Sprintf ("smbremotepath=%s" , remotePath )
32
- out , err := utils .RunPowershellCmd (cmdLine , cmdEnv )
71
+ inst , err := cim .QuerySmbGlobalMappingByRemotePath (remotePathForQuery (remotePath ))
33
72
if err != nil {
34
- return false , fmt . Errorf ( "error checking smb mapping. cmd %s, output: %s, err: %v" , remotePath , string ( out ), err )
73
+ return false , cim . IgnoreNotFound ( err )
35
74
}
36
75
37
- if len (out ) == 0 || ! strings .EqualFold (strings .TrimSpace (string (out )), "OK" ) {
38
- return false , nil
76
+ status , err := inst .GetProperty ("Status" )
77
+ if err != nil {
78
+ return false , err
39
79
}
40
- return true , nil
80
+
81
+ return status .(int32 ) == cim .SmbMappingStatusOK , nil
41
82
}
42
83
43
84
// NewSmbLink - creates a directory symbolic link to the remote share.
@@ -48,42 +89,46 @@ func (*SmbAPI) IsSmbMapped(remotePath string) (bool, error) {
48
89
// alpha to merge the paths.
49
90
// TODO (for beta release): Merge the link paths - os.Symlink and Powershell link path.
50
91
func (* SmbAPI ) NewSmbLink (remotePath , localPath string ) error {
51
-
52
92
if ! strings .HasSuffix (remotePath , "\\ " ) {
53
93
// Golang has issues resolving paths mapped to file shares if they do not end in a trailing \
54
94
// so add one if needed.
55
95
remotePath = remotePath + "\\ "
56
96
}
97
+ longRemotePath := utils .EnsureLongPath (remotePath )
98
+ longLocalPath := utils .EnsureLongPath (localPath )
57
99
58
- cmdLine := `New-Item -ItemType SymbolicLink $Env:smblocalPath -Target $Env:smbremotepath`
59
- output , err := utils .RunPowershellCmd (cmdLine , fmt .Sprintf ("smbremotepath=%s" , remotePath ), fmt .Sprintf ("smblocalpath=%s" , localPath ))
100
+ err := createSymlink (longLocalPath , longRemotePath , true )
60
101
if err != nil {
61
- return fmt .Errorf ("error linking %s to %s. output: %s, err: %v" , remotePath , localPath , string ( output ) , err )
102
+ return fmt .Errorf ("error linking %s to %s. err: %v" , remotePath , localPath , err )
62
103
}
63
104
64
105
return nil
65
106
}
66
107
67
108
func (api * SmbAPI ) NewSmbGlobalMapping (remotePath , username , password string ) error {
68
- // use PowerShell Environment Variables to store user input string to prevent command line injection
69
- // https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment_variables?view=powershell-5.1
70
- cmdLine := fmt .Sprintf (`$PWord = ConvertTo-SecureString -String $Env:smbpassword -AsPlainText -Force` +
71
- `;$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Env:smbuser, $PWord` +
72
- `;New-SmbGlobalMapping -RemotePath $Env:smbremotepath -Credential $Credential -RequirePrivacy $%t` , api .RequirePrivacy )
73
-
74
- if output , err := utils .RunPowershellCmd (cmdLine ,
75
- fmt .Sprintf ("smbuser=%s" , username ),
76
- fmt .Sprintf ("smbpassword=%s" , password ),
77
- fmt .Sprintf ("smbremotepath=%s" , remotePath )); err != nil {
78
- return fmt .Errorf ("NewSmbGlobalMapping failed. output: %q, err: %v" , string (output ), err )
109
+ params := map [string ]interface {}{
110
+ "RemotePath" : remotePath ,
111
+ "RequirePrivacy" : api .RequirePrivacy ,
112
+ }
113
+ if username != "" {
114
+ // refer to https://github.com/PowerShell/PowerShell/blob/9303de597da55963a6e26a8fe164d0b256ca3d4d/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimConverter.cs#L166-L178
115
+ // on how SMB credential is handled in PowerShell
116
+ params ["Credential" ] = escapeUserName (username ) + credentialDelimiter + password
79
117
}
118
+
119
+ result , _ , err := cim .InvokeCimMethod (cim .WMINamespaceSmb , "MSFT_SmbGlobalMapping" , "Create" , params )
120
+ if err != nil {
121
+ return fmt .Errorf ("NewSmbGlobalMapping failed. result: %d, err: %v" , result , err )
122
+ }
123
+
80
124
return nil
81
125
}
82
126
83
127
func (* SmbAPI ) RemoveSmbGlobalMapping (remotePath string ) error {
84
- cmd := `Remove-SmbGlobalMapping -RemotePath $Env:smbremotepath -Force`
85
- if output , err := utils . RunPowershellCmd ( cmd , fmt . Sprintf ( "smbremotepath=%s" , remotePath )); err != nil {
86
- return fmt .Errorf ("UnmountSmbShare failed. output: %q, err: %v" , string ( output ) , err )
128
+ err := cim . RemoveSmbGlobalMappingByRemotePath ( remotePathForQuery ( remotePath ))
129
+ if err != nil {
130
+ return fmt .Errorf ("error remove smb mapping '%s'. err: %v" , remotePath , err )
87
131
}
132
+
88
133
return nil
89
134
}
0 commit comments