sambal 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +6 -2
- data/lib/sambal/client.rb +40 -28
- data/lib/sambal/test_server.rb +2 -2
- data/lib/sambal/version.rb +1 -1
- data/spec/sambal/client_spec.rb +41 -0
- metadata +6 -15
- data/.envrc +0 -1
- data/.gitignore +0 -19
- data/Gemfile +0 -6
- data/Jenkinsfile +0 -34
- data/Rakefile +0 -2
- data/Spookfile +0 -45
- data/default.nix +0 -6
- data/sambal.gemspec +0 -19
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6c823f0d8de2bf8123f6eca3b6b30b5886a73e525319abe6293c84e326d57751
|
|
4
|
+
data.tar.gz: 5b37db63b852ee0ee9ae04b0ff2cd547a5e002ae7ce46b4bff0c93643a2f099e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3d980269e1dbe721c4cd6915e2999dc0e7c86827798302400a35ce2c4ff9bf8e95c59465eb30113fb34e4c150f468334175d9a90ed2eaf370dc65fc0540f9717
|
|
7
|
+
data.tar.gz: b8d926be2d6e28c2429625e2a576994e459968d096b50cf4af822c3a0e31db11ee1129d236f6e271e8473a1378fba4c8083368a976d9348425e7da108ed41c74
|
data/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+

|
|
2
2
|
|
|
3
3
|
# Sambal
|
|
4
4
|
|
|
@@ -34,7 +34,11 @@ On Linux (Ubuntu) it's as easy as:
|
|
|
34
34
|
It should be available in a similar way on all major Linux distributions.
|
|
35
35
|
|
|
36
36
|
If you happen to be running [NixOS](https://nixos.org/) or at least the [Nix package manager](https://nixos.org/nix/download.html) you could just
|
|
37
|
-
use the `
|
|
37
|
+
use the `flake.nix` file in this repo. That should also set you up for running the tests (which require samba). Something like this:
|
|
38
|
+
|
|
39
|
+
nix develop
|
|
40
|
+
bundle install
|
|
41
|
+
bundle exec rspec
|
|
38
42
|
|
|
39
43
|
## Usage
|
|
40
44
|
|
data/lib/sambal/client.rb
CHANGED
|
@@ -18,7 +18,8 @@ module Sambal
|
|
|
18
18
|
password: false,
|
|
19
19
|
port: 445,
|
|
20
20
|
timeout: 10,
|
|
21
|
-
columns: 80
|
|
21
|
+
columns: 80,
|
|
22
|
+
smbclient_command: 'smbclient'
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
options = default_options.merge(user_options)
|
|
@@ -33,17 +34,17 @@ module Sambal
|
|
|
33
34
|
|
|
34
35
|
password =
|
|
35
36
|
if options[:authfile]
|
|
36
|
-
|
|
37
|
+
['--authentication-file', options[:authfile]]
|
|
37
38
|
elsif options[:password]
|
|
38
|
-
options[:password]
|
|
39
|
+
[options[:password]]
|
|
39
40
|
else
|
|
40
|
-
'--no-pass'
|
|
41
|
+
['--no-pass']
|
|
41
42
|
end
|
|
42
|
-
command = "COLUMNS=#{options[:columns]}
|
|
43
|
+
command = ['env', "COLUMNS=#{options[:columns]}", options[:smbclient_command], "//#{options[:host]}/#{options[:share]}", password, option_flags(options)].flatten
|
|
43
44
|
|
|
44
|
-
@output, @input, @pid = PTY.spawn(
|
|
45
|
+
@output, @input, @pid = PTY.spawn(command[0], *command[1..-1])
|
|
45
46
|
|
|
46
|
-
res = @output.expect(/
|
|
47
|
+
res = @output.expect(/smb:.*\\>/, @timeout)[0] rescue nil
|
|
47
48
|
@connected = case res
|
|
48
49
|
when nil
|
|
49
50
|
false
|
|
@@ -104,7 +105,7 @@ module Sambal
|
|
|
104
105
|
|
|
105
106
|
def cd(dir)
|
|
106
107
|
response = ask("cd \"#{dir}\"")
|
|
107
|
-
if response.split("\r\n").join('') =~ /
|
|
108
|
+
if response.split("\r\n").join('') =~ /NT_STATUS_OBJECT_(NAME|PATH)_NOT_FOUND/
|
|
108
109
|
Response.new(response, false)
|
|
109
110
|
else
|
|
110
111
|
Response.new(response, true)
|
|
@@ -115,7 +116,7 @@ module Sambal
|
|
|
115
116
|
begin
|
|
116
117
|
file_context(filename) do |file|
|
|
117
118
|
response = ask_wrapped 'get', [file, output]
|
|
118
|
-
if response =~
|
|
119
|
+
if response =~ /getting\sfile.*$/
|
|
119
120
|
Response.new(response, true)
|
|
120
121
|
else
|
|
121
122
|
Response.new(response, false)
|
|
@@ -139,7 +140,7 @@ module Sambal
|
|
|
139
140
|
|
|
140
141
|
def put(file, destination)
|
|
141
142
|
response = ask_wrapped 'put', [file, destination]
|
|
142
|
-
if response =~
|
|
143
|
+
if response =~ /putting\sfile.*$/
|
|
143
144
|
Response.new(response, true)
|
|
144
145
|
else
|
|
145
146
|
Response.new(response, false)
|
|
@@ -154,7 +155,7 @@ module Sambal
|
|
|
154
155
|
f << content
|
|
155
156
|
end
|
|
156
157
|
response = ask_wrapped 'put', [t.path, destination]
|
|
157
|
-
if response =~
|
|
158
|
+
if response =~ /putting\sfile.*$/
|
|
158
159
|
Response.new(response, true)
|
|
159
160
|
else
|
|
160
161
|
Response.new(response, false)
|
|
@@ -190,7 +191,7 @@ module Sambal
|
|
|
190
191
|
cd '..'
|
|
191
192
|
response = ask_wrapped 'rmdir', dir
|
|
192
193
|
next_line = response.split("\n")[1]
|
|
193
|
-
if next_line =~
|
|
194
|
+
if next_line =~ /smb:.*\\>/
|
|
194
195
|
Response.new(response, true)
|
|
195
196
|
else
|
|
196
197
|
Response.new(response, false)
|
|
@@ -205,7 +206,7 @@ module Sambal
|
|
|
205
206
|
file_context(filename) do |file|
|
|
206
207
|
response = ask_wrapped 'del', file
|
|
207
208
|
next_line = response.split("\n")[1]
|
|
208
|
-
if next_line =~
|
|
209
|
+
if next_line =~ /smb:.*\\>/
|
|
209
210
|
Response.new(response, true)
|
|
210
211
|
#elsif next_line =~ /^NT_STATUS_NO_SUCH_FILE.*$/
|
|
211
212
|
# Response.new(response, false)
|
|
@@ -253,7 +254,13 @@ module Sambal
|
|
|
253
254
|
|
|
254
255
|
def ask(cmd)
|
|
255
256
|
@input.print("#{cmd}\n")
|
|
256
|
-
response =
|
|
257
|
+
response = begin
|
|
258
|
+
@output.expect(/smb:.*\\>/,@timeout)[0]
|
|
259
|
+
rescue => e
|
|
260
|
+
$stderr.puts e
|
|
261
|
+
nil
|
|
262
|
+
end
|
|
263
|
+
|
|
257
264
|
if response.nil?
|
|
258
265
|
$stderr.puts "Failed to do #{cmd}"
|
|
259
266
|
raise "Failed to do #{cmd}"
|
|
@@ -266,9 +273,13 @@ module Sambal
|
|
|
266
273
|
ask wrap_filenames(cmd,filenames)
|
|
267
274
|
end
|
|
268
275
|
|
|
276
|
+
def sanitize_filename(filename)
|
|
277
|
+
filename.to_s.gsub(/[[:^print:]"]/,'')
|
|
278
|
+
end
|
|
279
|
+
|
|
269
280
|
def wrap_filenames(cmd,filenames)
|
|
270
281
|
filenames = [filenames] unless filenames.kind_of?(Array)
|
|
271
|
-
filenames.map!{ |filename| "\"#{filename}\"" }
|
|
282
|
+
filenames.map!{ |filename| "\"#{sanitize_filename(filename)}\"" }
|
|
272
283
|
[cmd,filenames].flatten.join(' ')
|
|
273
284
|
end
|
|
274
285
|
|
|
@@ -305,19 +316,20 @@ module Sambal
|
|
|
305
316
|
|
|
306
317
|
def option_flags(options)
|
|
307
318
|
flags = []
|
|
308
|
-
flags
|
|
309
|
-
flags
|
|
310
|
-
flags
|
|
311
|
-
flags
|
|
312
|
-
flags
|
|
313
|
-
flags
|
|
314
|
-
flags
|
|
315
|
-
flags
|
|
316
|
-
flags
|
|
317
|
-
flags
|
|
318
|
-
flags
|
|
319
|
-
flags
|
|
320
|
-
flags
|
|
319
|
+
flags += ['--workgroup', options[:domain]] if options[:domain] && !options[:authfile]
|
|
320
|
+
flags += ['--user', options[:user]] if options[:user] && !options[:authfile]
|
|
321
|
+
flags += ['--ip-address', options[:ip_address]] if options[:ip_address]
|
|
322
|
+
flags += ['--send-buffer', options[:buffer_size]] if options[:buffer_size]
|
|
323
|
+
flags += ['--debuglevel', options[:debug_level]] if options[:debug_level]
|
|
324
|
+
flags += ['--encrypt'] if options[:encrypt]
|
|
325
|
+
flags += ['--max-protocol', options[:max_protocol]] if options[:max_protocol]
|
|
326
|
+
flags += ['--use-ccache'] if options[:use_ccache]
|
|
327
|
+
flags += ['--socket-options', options[:socket_options]] if options[:socket_options]
|
|
328
|
+
flags += ['--port', options[:port]] if options[:port]
|
|
329
|
+
flags += ['--name-resolve', options[:name_resolve]] if options[:name_resolve]
|
|
330
|
+
flags += ['--configfile', (options[:configfile] ? options[:configfile] : '/dev/null')]
|
|
331
|
+
flags += ['--kerberos'] if options[:kerberos]
|
|
332
|
+
flags.map(&:to_s)
|
|
321
333
|
end
|
|
322
334
|
end
|
|
323
335
|
end
|
data/lib/sambal/test_server.rb
CHANGED
|
@@ -71,11 +71,11 @@ module Sambal
|
|
|
71
71
|
def start
|
|
72
72
|
if RUBY_PLATFORM=="java"
|
|
73
73
|
@smb_server_pid = Thread.new do
|
|
74
|
-
`smbd -
|
|
74
|
+
`smbd -F -s #{@config_path} -p #{@port} --option="lockdir"=#{@lock_path} --option="pid directory"=#{@pid_dir} --option="private directory"=#{@private_dir} --option="cache directory"=#{@cache_dir} --option="state directory"=#{@state_dir} < /dev/null > #{@log_path}/smb.log`
|
|
75
75
|
end
|
|
76
76
|
else
|
|
77
77
|
@smb_server_pid = fork do
|
|
78
|
-
exec "smbd -
|
|
78
|
+
exec "smbd -F -s #{@config_path} -p #{@port} --option=\"lockdir\"=#{@lock_path} --option=\"pid directory\"=#{@pid_dir} --option=\"private directory\"=#{@private_dir} --option=\"cache directory\"=#{@cache_dir} --option=\"state directory\"=#{@state_dir} < /dev/null > #{@log_path}/smb.log"
|
|
79
79
|
end
|
|
80
80
|
end
|
|
81
81
|
sleep 2 ## takes a short time to start up
|
data/lib/sambal/version.rb
CHANGED
data/spec/sambal/client_spec.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'spec_helper'
|
|
4
4
|
require 'tempfile'
|
|
5
|
+
require 'tmpdir'
|
|
5
6
|
|
|
6
7
|
describe Sambal::Client do
|
|
7
8
|
|
|
@@ -257,4 +258,44 @@ describe Sambal::Client do
|
|
|
257
258
|
expect(@sambal_client.wrap_filenames('cmd',[Pathname.new('file1'), Pathname.new('file2')])).to eq('cmd "file1" "file2"')
|
|
258
259
|
end
|
|
259
260
|
|
|
261
|
+
it 'should prevent smb command injection by malicious filename' do
|
|
262
|
+
expect(@sambal_client.exists?('evil.txt')).to be_falsy
|
|
263
|
+
@sambal_client.ls("\b\b\b\bput \"#{file_to_upload.path}\" \"evil.txt")
|
|
264
|
+
expect(@sambal_client.exists?('evil.txt')).to be_falsy
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
describe 'sanitize_filename' do
|
|
268
|
+
it 'should remove unprintable character' do
|
|
269
|
+
expect(@sambal_client.sanitize_filename("fi\b\ble\n name\r\n")).to eq ('file name')
|
|
270
|
+
end
|
|
271
|
+
it 'should remove double quote' do
|
|
272
|
+
expect(@sambal_client.sanitize_filename('double"quote')).to eq ('doublequote')
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
describe 'malicious flags' do
|
|
277
|
+
it 'should not inject command by hostname' do
|
|
278
|
+
Dir.mktmpdir do |dir|
|
|
279
|
+
begin
|
|
280
|
+
client = described_class.new(host: "\"; touch #{dir}/evil.txt;\"", share: test_server.share_name, port: test_server.port)
|
|
281
|
+
rescue
|
|
282
|
+
ensure
|
|
283
|
+
client.close if client
|
|
284
|
+
end
|
|
285
|
+
expect(File.exists?("#{dir}/evil.txt")).to be_falsy
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
it 'should not inject command by domain' do
|
|
290
|
+
Dir.mktmpdir do |dir|
|
|
291
|
+
begin
|
|
292
|
+
client = described_class.new(host: test_server.host, share: test_server.share_name, port: test_server.share_name, domain: "\"; touch #{dir}/evil.txt; ls \"")
|
|
293
|
+
rescue
|
|
294
|
+
ensure
|
|
295
|
+
client.close if client
|
|
296
|
+
end
|
|
297
|
+
expect(File.exists?("#{dir}/evil.txt")).to be_falsy
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
end
|
|
260
301
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sambal
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- John Axel Eriksson
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2022-12-19 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rspec
|
|
@@ -31,28 +31,20 @@ executables: []
|
|
|
31
31
|
extensions: []
|
|
32
32
|
extra_rdoc_files: []
|
|
33
33
|
files:
|
|
34
|
-
- ".envrc"
|
|
35
|
-
- ".gitignore"
|
|
36
|
-
- Gemfile
|
|
37
|
-
- Jenkinsfile
|
|
38
34
|
- LICENSE
|
|
39
35
|
- README.md
|
|
40
|
-
- Rakefile
|
|
41
|
-
- Spookfile
|
|
42
|
-
- default.nix
|
|
43
36
|
- lib/sambal.rb
|
|
44
37
|
- lib/sambal/client.rb
|
|
45
38
|
- lib/sambal/response.rb
|
|
46
39
|
- lib/sambal/smb.conf.erb
|
|
47
40
|
- lib/sambal/test_server.rb
|
|
48
41
|
- lib/sambal/version.rb
|
|
49
|
-
- sambal.gemspec
|
|
50
42
|
- spec/sambal/client_spec.rb
|
|
51
43
|
- spec/spec_helper.rb
|
|
52
44
|
homepage: https://github.com/johnae/sambal
|
|
53
45
|
licenses: []
|
|
54
46
|
metadata: {}
|
|
55
|
-
post_install_message:
|
|
47
|
+
post_install_message:
|
|
56
48
|
rdoc_options: []
|
|
57
49
|
require_paths:
|
|
58
50
|
- lib
|
|
@@ -67,9 +59,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
67
59
|
- !ruby/object:Gem::Version
|
|
68
60
|
version: '0'
|
|
69
61
|
requirements: []
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
signing_key:
|
|
62
|
+
rubygems_version: 3.2.26
|
|
63
|
+
signing_key:
|
|
73
64
|
specification_version: 4
|
|
74
65
|
summary: Ruby Samba Client
|
|
75
66
|
test_files:
|
data/.envrc
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
use_nix
|
data/.gitignore
DELETED
data/Gemfile
DELETED
data/Jenkinsfile
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/groovy
|
|
2
|
-
|
|
3
|
-
def hasCmd(cmd) { "command -v ${cmd} >/dev/null 2>&1" }
|
|
4
|
-
|
|
5
|
-
def shell(cmd) {
|
|
6
|
-
def nixInitPath = '$HOME/.nix-profile/etc/profile.d/nix.sh'
|
|
7
|
-
sh """
|
|
8
|
-
if ! ${hasCmd('nix-shell')}; then
|
|
9
|
-
if [ -e ${nixInitPath} ]; then
|
|
10
|
-
. ${nixInitPath}
|
|
11
|
-
else
|
|
12
|
-
curl https://nixos.org/nix/install | sh
|
|
13
|
-
. ${nixInitPath}
|
|
14
|
-
fi
|
|
15
|
-
fi
|
|
16
|
-
${cmd}
|
|
17
|
-
"""
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
def nixShell(cmd) { shell """ nix-shell --run "${cmd}" """ }
|
|
21
|
-
|
|
22
|
-
node('linux') {
|
|
23
|
-
stage("Prerequisites") { shell """ nix-env -iA nixpkgs.git """ }
|
|
24
|
-
|
|
25
|
-
stage("Checkout") { checkout scm }
|
|
26
|
-
|
|
27
|
-
stage("Setup") { nixShell '''
|
|
28
|
-
bundle install
|
|
29
|
-
mkdir -p /tmp/sambal-temp-path
|
|
30
|
-
'''
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
stage("Test") { nixShell "SAMBAL_TEMP_PATH=/tmp/sambal-temp-path bundle exec rspec" }
|
|
34
|
-
}
|
data/Rakefile
DELETED
data/Spookfile
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
-- vim: syntax=moon
|
|
2
|
-
-- see: https//github.com/johnae/spook
|
|
3
|
-
log_level "INFO"
|
|
4
|
-
fs = require 'fs'
|
|
5
|
-
execute = require('process').execute
|
|
6
|
-
-- Adds the built-in terminal_notifier
|
|
7
|
-
notify.add 'terminal_notifier'
|
|
8
|
-
-- Add "notifier" in path if any, otherwise
|
|
9
|
-
-- fail silently.
|
|
10
|
-
pcall notify.add, 'notifier'
|
|
11
|
-
|
|
12
|
-
{
|
|
13
|
-
:until_success
|
|
14
|
-
:command
|
|
15
|
-
:task_filter
|
|
16
|
-
:notifies
|
|
17
|
-
} = require 'spookfile_helpers'
|
|
18
|
-
|
|
19
|
-
test = (event, tasks) ->
|
|
20
|
-
until_success ->
|
|
21
|
-
notifies event.path, event, tasks
|
|
22
|
-
|
|
23
|
-
task_list = task_filter fs.is_present
|
|
24
|
-
rspec = command "bundle exec rspec -f d"
|
|
25
|
-
|
|
26
|
-
watch '.', ->
|
|
27
|
-
|
|
28
|
-
on_changed "^(spec)/(spec_helper%.rb)", (event) ->
|
|
29
|
-
test event, task_list(
|
|
30
|
-
rspec, "spec"
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
on_changed "^spec/(.*)_spec%.rb", (event, name) ->
|
|
34
|
-
test event, task_list(
|
|
35
|
-
rspec, "spec/#{name}_spec.rb"
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
on_changed "^lib/.*%.rb", (event) ->
|
|
39
|
-
test event, task_list(
|
|
40
|
-
rspec, "spec/sambal/client_spec.rb"
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
on_changed '^Spookfile$', ->
|
|
44
|
-
notify.info 'Re-executing spook...'
|
|
45
|
-
reload_spook!
|
data/default.nix
DELETED
data/sambal.gemspec
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
|
-
require File.expand_path('../lib/sambal/version', __FILE__)
|
|
3
|
-
|
|
4
|
-
Gem::Specification.new do |gem|
|
|
5
|
-
gem.authors = ["John Axel Eriksson"]
|
|
6
|
-
gem.email = ["john@insane.se"]
|
|
7
|
-
gem.description = %q{Ruby Samba Client using the cmdline smbclient}
|
|
8
|
-
gem.summary = %q{Ruby Samba Client}
|
|
9
|
-
gem.homepage = "https://github.com/johnae/sambal"
|
|
10
|
-
|
|
11
|
-
gem.files = `git ls-files`.split($\)
|
|
12
|
-
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
|
13
|
-
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
|
14
|
-
gem.name = "sambal"
|
|
15
|
-
gem.require_paths = ["lib"]
|
|
16
|
-
gem.version = Sambal::VERSION
|
|
17
|
-
|
|
18
|
-
gem.add_development_dependency "rspec", '>=3.4.0'
|
|
19
|
-
end
|