sambal 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0a50e0a519bdbc0ab8cccb0116250c2b073e5e305a906d9f46fac5012dc11814
4
- data.tar.gz: 71ac3f8493eae53b548a0e58a207e38034615af0f0d915956d50ab338b5bc16e
3
+ metadata.gz: 9fc6edc1f7ee1557e9bb47fa9af736415cfa7c43fbe9a0869a81cc63f738d7ab
4
+ data.tar.gz: 7664aaf2c58023cbe3f7e5eb3d486a6340ce650def28ca32a311024611bdece5
5
5
  SHA512:
6
- metadata.gz: 5e14f217b9d83deceae6bd11a17d94ce17ca59800850031a0d57d416fe5f1f1431a0de3b8c9d9e8a3f4b4695f9d4e16b15fa2e2cbb808cf16ba409ad60dc67d3
7
- data.tar.gz: ba2eb773c39c1dccfd4b71dbe2b184f453b17cf02690124d010d30d18d3456e4976a7d33f5b11bacda7c192882d1336b686f859ca0147a736ac0a9ff8191ede4
6
+ metadata.gz: '0901a04a4fe2f864ac3e457cae9d0a238fcde13213745644d49127b2565d32830f4b90b768c864fec1381bd8665152fd651c8a5a7016c70877f8b7eef81bec8e'
7
+ data.tar.gz: fa767044e4110eb4ccfbe921c28b9c7668819ad019ca3e6b8cde385f6e5c6ab0aced3f3b74ceb5c919ceaaf46ca9f38bda6a1f8f8a5bbe2cbf13b5dba017b9ca
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,15 +34,15 @@ module Sambal
33
34
 
34
35
  password =
35
36
  if options[:authfile]
36
- "--authentication-file #{options[:authfile]}"
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]} smbclient \"//#{options[:host]}/#{options[:share]}\" #{password}"
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("#{command} #{option_flags(options)}")
45
+ @output, @input, @pid = PTY.spawn(command[0], *command[1..-1])
45
46
 
46
47
  res = @output.expect(/(.*\n)?smb:.*\\>/, @timeout)[0] rescue nil
47
48
  @connected = case res
@@ -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('') =~ /NT_STATUS_OBJECT_NAME_NOT_FOUND/
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)
@@ -253,7 +254,13 @@ module Sambal
253
254
 
254
255
  def ask(cmd)
255
256
  @input.print("#{cmd}\n")
256
- response = @output.expect(/^smb:.*\\>/,@timeout)[0] rescue nil
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 << "--workgroup \"#{options[:domain]}\"" if options[:domain] && !options[:authfile]
309
- flags << "--user \"#{options[:user]}\"" if options[:user] && !options[:authfile]
310
- flags << "--ip-address #{options[:ip_address]}" if options[:ip_address]
311
- flags << "--send-buffer #{options[:buffer_size]}" if options[:buffer_size]
312
- flags << "--debuglevel #{options[:debug_level]}" if options[:debug_level]
313
- flags << '--encrypt' if options[:encrypt]
314
- flags << "--max-protocol #{options[:max_protocol]}" if options[:max_protocol]
315
- flags << '--use-ccache' if options[:use_ccache]
316
- flags << "--socket-options #{options[:socket_options]}" if options[:socket_options]
317
- flags << "--port #{options[:port]}" if options[:port]
318
- flags << "--name-resolve #{options[:name_resolve]}" if options[:name_resolve]
319
- flags << (options[:configfile] ? "--configfile #{options[:configfile]}" : '--configfile /dev/null')
320
- flags.join(' ')
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
@@ -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 -S -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`
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 -S -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"
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
@@ -1,5 +1,5 @@
1
1
  # coding: UTF-8
2
2
 
3
3
  module Sambal
4
- VERSION = "0.2.2"
4
+ VERSION = "0.2.3"
5
5
  end
@@ -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.2
4
+ version: 0.2.3
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: 2018-09-22 00:00:00.000000000 Z
11
+ date: 2022-01-26 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
- rubyforge_project:
71
- rubygems_version: 2.7.7
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
@@ -1,19 +0,0 @@
1
- *.gem
2
- *.rbc
3
- .bundle
4
- .config
5
- .yardoc
6
- Gemfile.lock
7
- InstalledFiles
8
- _yardoc
9
- coverage
10
- doc/
11
- lib/bundler/man
12
- pkg
13
- rdoc
14
- spec/reports
15
- spec/sambashare
16
- spec/smb.conf
17
- test/tmp
18
- test/version_tmp
19
- tmp
data/Gemfile DELETED
@@ -1,6 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in sambal.gemspec
4
- gemspec
5
-
6
- gem 'rspec_junit_formatter', '0.2.2'
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
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env rake
2
- require "bundler/gem_tasks"
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
@@ -1,6 +0,0 @@
1
- with import <nixpkgs> {};
2
-
3
- stdenv.mkDerivation {
4
- name = "sambal";
5
- buildInputs = [ ruby rake samba ];
6
- }
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