From ed9a1f3e8fc3f8ccc6fd824dd11e28afb3582e76 Mon Sep 17 00:00:00 2001 From: nagai Date: Fri, 18 Nov 2005 08:39:29 +0000 Subject: * ext/tk/lib/multi-tk.rb: add restriction to access the entried command table and manipulate other IPs (for reason of security). Now, a IP object can be controlled by only its master IP or the default IP. * ext/tk/lib/remote-tk.rb: add restriction to manipulate. * ext/tk/tcltklib.c (ip_is_slave_of_p): add TclTkIp#slave_of?(ip) to check manipulability. * ext/tk/lib/tk.rb: bug fix on handling of Tcl's namespaces. * ext/tk/lib/tk/namespace.rb: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9562 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/tk/lib/multi-tk.rb | 217 +++++++++++++++++++++++++++++++++++++++++---- ext/tk/lib/remote-tk.rb | 38 ++++++++ ext/tk/lib/tk.rb | 62 ++++++++++++- ext/tk/lib/tk/namespace.rb | 56 ++++++++++-- 4 files changed, 350 insertions(+), 23 deletions(-) (limited to 'ext/tk/lib') diff --git a/ext/tk/lib/multi-tk.rb b/ext/tk/lib/multi-tk.rb index d10e304a3d..b5ef77c14d 100644 --- a/ext/tk/lib/multi-tk.rb +++ b/ext/tk/lib/multi-tk.rb @@ -63,7 +63,82 @@ class MultiTkIp @@TK_TABLE_LIST = [].taint unless defined?(@@TK_TABLE_LIST) - @@TK_CMD_TBL = {}.taint unless defined?(@@TK_CMD_TBL) + unless defined?(@@TK_CMD_TBL) + @@TK_CMD_TBL = Object.new.taint + + @@TK_CMD_TBL.instance_variable_set('@tbl', {}.taint) + + class << @@TK_CMD_TBL + allow = [ + '__send__', '__id__', 'freeze', 'inspect', 'kind_of?', + '[]', '[]=', 'delete', 'each', 'has_key?' + ] + instance_methods.each{|m| undef_method(m) unless allow.index(m)} + + def kind_of?(klass) + @tbl.kind_of?(klass) + end + + def inspect + if Thread.current.group == ThreadGroup::Default + @tbl.inspect + else + ip = MultiTkIp.__getip + @tbl.reject{|idx, ent| ent.respond_to?(:ip) && ent.ip != ip}.inspect + end + end + + def [](idx) + return unless (ent = @tbl[idx]) + if Thread.current.group == ThreadGroup::Default + ent + elsif ent.respond_to?(:ip) + (ent.ip == MultiTkIp.__getip)? ent: nil + else + ent + end + end + + def []=(idx,val) + if self.has_key?(idx) && Thread.current.group != ThreadGroup::Default + fail SecurityError,"cannot change the entried command" + end + @tbl[idx] = val + end + + def delete(idx, &blk) + # if gets an entry, is permited to delete + if self[idx] + @tbl.delete(idx) + elsif blk + blk.call(idx) + else + nil + end + end + + def each(&blk) + if Thread.current.group == ThreadGroup::Default + @tbl.each(&blk) + else + ip = MultiTkIp.__getip + @tbl.each{|idx, ent| + blk.call(idx, ent) unless ent.respond_to?(:ip) && ent.ip != ip + } + end + self + end + + def has_key?(k) + @tbl.has_key?(k) + end + alias include? has_key? + alias key? has_key? + alias member? has_key? + end + + @@TK_CMD_TBL.freeze + end ###################################### @@ -876,6 +951,8 @@ class MultiTkIp private :__create_safetk_frame def __create_safe_slave_obj(safe_opts, app_name, tk_opts) + raise SecurityError, "no permission to manipulate" unless self.manipulable? + # safe interpreter ip_name = _create_slave_ip_name slave_ip = @interp.create_slave(ip_name, true) @@ -917,6 +994,8 @@ class MultiTkIp end def __create_trusted_slave_obj(name, keys) + raise SecurityError, "no permission to manipulate" unless self.manipulable? + ip_name = _create_slave_ip_name slave_ip = @interp.create_slave(ip_name, false) slave_ip._invoke('set', 'argv0', name) if name.kind_of?(String) @@ -929,6 +1008,8 @@ class MultiTkIp ###################################### def _create_slave_object(keys={}) + raise SecurityError, "no permission to manipulate" unless self.manipulable? + ip = MultiTkIp.new_slave(self, keys={}) @slave_ip_tbl[ip.name] = ip end @@ -1056,6 +1137,7 @@ class MultiTkIp ###################################### def _default_delete_hook(slave) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @slave_ip_tbl.delete(slave) top = @slave_ip_top.delete(slave) if top.kind_of?(String) @@ -1090,6 +1172,7 @@ class MultiTkIp __getip._ip_id_ end def _ip_id_ + # for RemoteTkIp '' end @@ -1192,19 +1275,21 @@ end class MultiTkIp def inspect s = self.to_s.chop! - if master? - if @interp.deleted? - s << ':deleted-master' - else - s << ':master' - end - else - if @interp.deleted? - s << ':deleted-slave' - elsif @interp.safe? - s << ':safe-slave' + if self.manipulable? + if master? + if @interp.deleted? + s << ':deleted-master' + else + s << ':master' + end else - s << ':trusted-slave' + if @interp.deleted? + s << ':deleted-slave' + elsif @interp.safe? + s << ':safe-slave' + else + s << ':trusted-slave' + end end end s << '>' @@ -1229,6 +1314,7 @@ class MultiTkIp end def alive? + raise SecurityError, "no permission to manipulate" unless self.manipulable? begin return false unless @cmd_receiver.alive? return false if @interp.deleted? @@ -1262,6 +1348,7 @@ class MultiTkIp end def slaves(all = false) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp','slaves').split.map!{|name| if @slave_ip_tbl.key?(name) @slave_ip_tbl[name] @@ -1275,6 +1362,20 @@ class MultiTkIp def self.slaves(all = false) __getip.slaves(all) end + + def manipulable? + return true if (Thread.current.group == ThreadGroup::Default) + ip = MultiTkIp.__getip + (ip == self) || ip._is_master_of?(@interp) + end + def self.manipulable? + true + end + + def _is_master_of?(tcltkip_obj) + tcltkip_obj.slave_of?(@interp) + end + protected :_is_master_of? end @@ -1403,6 +1504,7 @@ class MultiTkIp # instance method def eval_proc_core(req_val, cmd, *args) # check + raise SecurityError, "no permission to manipulate" unless self.manipulable? unless cmd.kind_of?(Proc) || cmd.kind_of?(Method) raise RuntimeError, "A Proc/Method object is expected for the 'cmd' argument" end @@ -1870,6 +1972,7 @@ end # depend on TclTkIp class MultiTkIp def mainloop(check_root = true, restart_on_dead = true) + raise SecurityError, "no permission to manipulate" unless self.manipulable? #return self if self.slave? #return self if self != @@DEFAULT_MASTER if self != @@DEFAULT_MASTER @@ -1978,26 +2081,32 @@ class MultiTkIp end def make_safe + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.make_safe end def safe? + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.safe? end def safe_base? + raise SecurityError, "no permission to manipulate" unless self.manipulable? @safe_base end def allow_ruby_exit? + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.allow_ruby_exit? end def allow_ruby_exit= (mode) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.allow_ruby_exit = mode end def delete + raise SecurityError, "no permission to manipulate" unless self.manipulable? @slave_ip_tbl.each{|name, subip| _destroy_slaves_of_slaveIP(subip) =begin @@ -2060,19 +2169,23 @@ class MultiTkIp end def deleted? + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.deleted? end def has_mainwindow? + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.has_mainwindow? end def invalid_namespace? + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.invalid_namespace? end def abort(msg = nil) - if master? + raise SecurityError, "no permission to manipulate" unless self.manipulable? + if master? && !safe? && allow_ruby_exit? if msg Kernel.abort(msg) else @@ -2086,7 +2199,8 @@ class MultiTkIp end def exit(st = true) - if master? + raise SecurityError, "no permission to manipulate" unless self.manipulable? + if master? && !safe? && allow_ruby_exit? Kernel.exit(st) else delete @@ -2095,6 +2209,7 @@ class MultiTkIp end def exit!(st = false) + raise SecurityError, "no permission to manipulate" unless self.manipulable? if master? && !safe? && allow_ruby_exit? Kernel.exit!(st) else @@ -2104,6 +2219,8 @@ class MultiTkIp end def restart(app_name = nil, keys = {}) + raise SecurityError, "no permission to manipulate" unless self.manipulable? + _init_ip_internal(@@INIT_IP_ENV, @@ADD_TK_PROCS) @interp._invoke('set', 'argv0', app_name) if app_name @@ -2115,102 +2232,130 @@ class MultiTkIp end def __eval(str) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.__eval(str) end def __invoke(*args) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.__invoke(*args) end def _eval(str) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._eval(str) end def _invoke(*args) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke(*args) end def _eval_without_enc(str) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._eval_without_enc(str) end def _invoke_without_enc(*args) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke_without_enc(*args) end def _eval_with_enc(str) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._eval_with_enc(str) end def _invoke_with_enc(*args) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke_with_enc(*args) end def _toUTF8(str, encoding=nil) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._toUTF8(str, encoding) end def _fromUTF8(str, encoding=nil) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._fromUTF8(str, encoding) end def _thread_vwait(var) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._thread_vwait(var) end def _thread_tkwait(mode, target) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._thread_tkwait(mode, target) end def _return_value + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._return_value end def _get_variable(var, flag) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._get_variable(var, flag) end def _get_variable2(var, idx, flag) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._get_variable2(var, idx, flag) end def _set_variable(var, value, flag) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._set_variable(var, value, flag) end def _set_variable2(var, idx, value, flag) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._set_variable2(var, idx, value, flag) end def _unset_variable(var, flag) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._unset_variable(var, flag) end def _unset_variable2(var, idx, flag) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._unset_variable2(var, idx, flag) end def _get_global_var(var) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._get_global_var(var) end def _get_global_var2(var, idx) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._get_global_var2(var, idx) end def _set_global_var(var, value) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._set_global_var(var, value) end def _set_global_var2(var, idx, value) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._set_global_var2(var, idx, value) end def _unset_global_var(var) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._unset_global_var(var) end def _unset_global_var2(var, idx) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._unset_global_var2(var, idx) end def _split_tklist(str) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._split_tklist(str) end def _merge_tklist(*args) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._merge_tklist(*args) end def _conv_listelement(arg) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._conv_listelement(arg) end end @@ -2261,6 +2406,7 @@ class MultiTkIp private :_slavearg def alias_info(slave, cmd_name) + raise SecurityError, "no permission to manipulate" unless self.manipulable? _lst2ary(@interp._invoke('interp', 'alias', _slavearg(slave), cmd_name)) end def self.alias_info(slave, cmd_name) @@ -2268,6 +2414,7 @@ class MultiTkIp end def alias_delete(slave, cmd_name) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'alias', _slavearg(slave), cmd_name, '') self end @@ -2277,6 +2424,7 @@ class MultiTkIp end def def_alias(slave, new_cmd, org_cmd, *args) + raise SecurityError, "no permission to manipulate" unless self.manipulable? ret = @interp._invoke('interp', 'alias', _slavearg(slave), new_cmd, '', org_cmd, *args) (ret == new_cmd)? self: nil @@ -2287,6 +2435,7 @@ class MultiTkIp end def aliases(slave = '') + raise SecurityError, "no permission to manipulate" unless self.manipulable? _lst2ary(@interp._invoke('interp', 'aliases', _slavearg(slave))) end def self.aliases(slave = '') @@ -2294,6 +2443,7 @@ class MultiTkIp end def delete_slaves(*args) + raise SecurityError, "no permission to manipulate" unless self.manipulable? slaves = args.collect{|s| _slavearg(s)} @interp._invoke('interp', 'delete', *slaves) if slaves.size > 0 self @@ -2304,6 +2454,7 @@ class MultiTkIp end def exist?(slave = '') + raise SecurityError, "no permission to manipulate" unless self.manipulable? ret = @interp._invoke('interp', 'exists', _slavearg(slave)) (ret == '1')? true: false end @@ -2312,6 +2463,7 @@ class MultiTkIp end def delete_cmd(slave, cmd) + raise SecurityError, "no permission to manipulate" unless self.manipulable? slave_invoke = @interp._invoke('list', 'rename', cmd, '') @interp._invoke('interp', 'eval', _slavearg(slave), slave_invoke) self @@ -2322,6 +2474,7 @@ class MultiTkIp end def expose_cmd(slave, cmd, aliasname = nil) + raise SecurityError, "no permission to manipulate" unless self.manipulable? if aliasname @interp._invoke('interp', 'expose', _slavearg(slave), cmd, aliasname) else @@ -2335,6 +2488,7 @@ class MultiTkIp end def hide_cmd(slave, cmd, aliasname = nil) + raise SecurityError, "no permission to manipulate" unless self.manipulable? if aliasname @interp._invoke('interp', 'hide', _slavearg(slave), cmd, aliasname) else @@ -2348,6 +2502,7 @@ class MultiTkIp end def hidden_cmds(slave = '') + raise SecurityError, "no permission to manipulate" unless self.manipulable? _lst2ary(@interp._invoke('interp', 'hidden', _slavearg(slave))) end def self.hidden_cmds(slave = '') @@ -2355,6 +2510,7 @@ class MultiTkIp end def invoke_hidden(slave, cmd, *args) + raise SecurityError, "no permission to manipulate" unless self.manipulable? if args[-1].kind_of?(Hash) keys = _symbolkey2str(args.pop) else @@ -2374,6 +2530,7 @@ class MultiTkIp end def invoke_hidden_on_global(slave, cmd, *args) + raise SecurityError, "no permission to manipulate" unless self.manipulable? if args[-1].kind_of?(Hash) keys = _symbolkey2str(args.pop) else @@ -2395,6 +2552,7 @@ class MultiTkIp def invoke_hidden_on_namespace(slave, ns, cmd, *args) # for Tcl8.5 or later + raise SecurityError, "no permission to manipulate" unless self.manipulable? if args[-1].kind_of?(Hash) keys = _symbolkey2str(args.pop) else @@ -2411,6 +2569,7 @@ class MultiTkIp end def mark_trusted(slave = '') + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'marktrusted', _slavearg(slave)) self end @@ -2420,6 +2579,8 @@ class MultiTkIp end def set_bgerror_handler(cmd = Proc.new, slave = nil, &b) + raise SecurityError, "no permission to manipulate" unless self.manipulable? + unless TkComm._callback_entry?(cmd) if !slave && b slave = cmd @@ -2435,6 +2596,7 @@ class MultiTkIp end def get_bgerror_handler(slave = '') + raise SecurityError, "no permission to manipulate" unless self.manipulable? procedure(@interp._invoke('interp', 'bgerror', _slavearg(slave))) end def self.bgerror(slave = '') @@ -2442,6 +2604,7 @@ class MultiTkIp end def set_limit(limit_type, slave = '', opts = {}) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'limit', _slavearg(slave), limit_type, opts) end def self.set_limit(limit_type, slave = '', opts = {}) @@ -2449,6 +2612,8 @@ class MultiTkIp end def get_limit(limit_type, slave = '', slot = nil) + raise SecurityError, "no permission to manipulate" unless self.manipulable? + if slot num_or_str(@interp._invoke('interp', 'limit', _slavearg(slave), limit_type, slot)) @@ -2472,6 +2637,7 @@ class MultiTkIp end def recursion_limit(slave = '', limit = None) + raise SecurityError, "no permission to manipulate" unless self.manipulable? number(@interp._invoke('interp', 'recursionlimit', _slavearg(slave), limit)) end @@ -2480,6 +2646,7 @@ class MultiTkIp end def alias_target(aliascmd, slave = '') + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'target', _slavearg(slave), aliascmd) end def self.alias_target(aliascmd, slave = '') @@ -2487,6 +2654,7 @@ class MultiTkIp end def share_stdin(dist, src = '') + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'share', src, 'stdin', dist) self end @@ -2496,6 +2664,7 @@ class MultiTkIp end def share_stdout(dist, src = '') + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'share', src, 'stdout', dist) self end @@ -2505,6 +2674,7 @@ class MultiTkIp end def share_stderr(dist, src = '') + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'share', src, 'stderr', dist) self end @@ -2514,6 +2684,7 @@ class MultiTkIp end def transfer_stdin(dist, src = '') + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'transfer', src, 'stdin', dist) self end @@ -2523,6 +2694,7 @@ class MultiTkIp end def transfer_stdout(dist, src = '') + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'transfer', src, 'stdout', dist) self end @@ -2532,6 +2704,7 @@ class MultiTkIp end def transfer_stderr(dist, src = '') + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'transfer', src, 'stderr', dist) self end @@ -2541,6 +2714,7 @@ class MultiTkIp end def share_stdio(dist, src = '') + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'share', src, 'stdin', dist) @interp._invoke('interp', 'share', src, 'stdout', dist) @interp._invoke('interp', 'share', src, 'stderr', dist) @@ -2552,6 +2726,7 @@ class MultiTkIp end def transfer_stdio(dist, src = '') + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._invoke('interp', 'transfer', src, 'stdin', dist) @interp._invoke('interp', 'transfer', src, 'stdout', dist) @interp._invoke('interp', 'transfer', src, 'stderr', dist) @@ -2586,8 +2761,12 @@ class MultiTkIp conf = _lst2ary(ip._eval("::safe::interpConfigure " + @ip_name + " -#{slot}")) if conf[0] == '-deleteHook' +=begin if conf[1] =~ /^rb_out\S* (c(_\d+_)?\d+)/ ret[conf[0][1..-1]] = MultiTkIp._tk_cmd_tbl[$1] +=end + if conf[1] =~ /rb_out\S*(?:\s+(::\S*|[{](::.*)[}]|["](::.*)["]))? (c(_\d+_)?(\d+))/ + ret[conf[0][1..-1]] = MultiTkIp._tk_cmd_tbl[$4] else ret[conf[0][1..-1]] = conf[1] end @@ -2598,8 +2777,12 @@ class MultiTkIp Hash[*_lst2ary(ip._eval("::safe::interpConfigure " + @ip_name))].each{|k, v| if k == '-deleteHook' +=begin if v =~ /^rb_out\S* (c(_\d+_)?\d+)/ ret[k[1..-1]] = MultiTkIp._tk_cmd_tbl[$1] +=end + if v =~ /rb_out\S*(?:\s+(::\S*|[{](::.*)[}]|["](::.*)["]))? (c(_\d+_)?(\d+))/ + ret[k[1..-1]] = MultiTkIp._tk_cmd_tbl[$4] else ret[k[1..-1]] = v end @@ -2636,18 +2819,22 @@ end # encoding convert class MultiTkIp def encoding + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.encoding end def encoding=(enc) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.encoding = enc end def encoding_convertfrom(str, enc=None) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.encoding_convertfrom(str, enc) end alias encoding_convert_from encoding_convertfrom def encoding_convertto(str, enc=None) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp.encoding_convertto(str, enc) end alias encoding_convert_to encoding_convertto diff --git a/ext/tk/lib/remote-tk.rb b/ext/tk/lib/remote-tk.rb index 6e64a1ca2d..70115a60aa 100644 --- a/ext/tk/lib/remote-tk.rb +++ b/ext/tk/lib/remote-tk.rb @@ -66,6 +66,11 @@ class RemoteTkIp end @interp = MultiTkIp.__getip + if @interp.safe? + fail SecurityError, "safe-IP cannot create RemoteTkIp" + end + + @interp.allow_ruby_exit = false @appname = @interp._invoke('tk', 'appname') @remote = remote_ip.to_s.dup.freeze @@ -127,11 +132,26 @@ class RemoteTkIp self.freeze # defend against modification end + def manipulable? + return true if (Thread.current.group == ThreadGroup::Default) + MultiTkIp.__getip == @interp && ! @interp.safe? + end + def self.manipulable? + true + end + + def _is_master_of?(tcltkip_obj) + tcltkip_obj == @interp + end + protected :_is_master_of? + def _ip_id_ @ip_id end def _available_check(timeout = 5) + raise SecurityError, "no permission to manipulate" unless self.manipulable? + return nil if timeout < 1 @ret_val.value = '' @interp._invoke('send', '-async', @remote, @@ -150,6 +170,8 @@ class RemoteTkIp private :_available_check def _create_connection + raise SecurityError, "no permission to manipulate" unless self.manipulable? + ip_id = '_' + @interp._invoke('send', @remote, <<-'EOS') + '_' if {[catch {set _rubytk_control_ip_id_} ret] != 0} { set _rubytk_control_ip_id_ 0 @@ -170,6 +192,8 @@ class RemoteTkIp private :_create_connection def _appsend(enc_mode, async, *cmds) + raise SecurityError, "no permission to manipulate" unless self.manipulable? + p ['_appsend', [@remote, @displayof], enc_mode, async, cmds] if $DEBUG if $SAFE >= 4 fail SecurityError, "cannot send commands at level 4" @@ -210,6 +234,8 @@ class RemoteTkIp end def appsend(async, *args) + raise SecurityError, "no permission to manipulate" unless self.manipulable? + if async != true && async != false && async != nil args.unshift(async) async = false @@ -222,6 +248,8 @@ class RemoteTkIp end def rb_appsend(async, *args) + raise SecurityError, "no permission to manipulate" unless self.manipulable? + if async != true && async != false && async != nil args.unshift(async) async = false @@ -267,6 +295,8 @@ class RemoteTkIp end def deleted? + raise SecurityError, "no permission to manipulate" unless self.manipulable? + if @displayof lst = @interp._invoke_without_enc('winfo', 'interps', '-displayof', @displayof) @@ -282,6 +312,8 @@ class RemoteTkIp end def has_mainwindow? + raise SecurityError, "no permission to manipulate" unless self.manipulable? + begin inf = @interp._invoke_without_enc('info', 'command', '.') rescue Exception @@ -333,10 +365,12 @@ class RemoteTkIp end def _toUTF8(str, encoding=nil) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._toUTF8(str, encoding) end def _fromUTF8(str, encoding=nil) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._fromUTF8(str, encoding) end @@ -349,6 +383,7 @@ class RemoteTkIp end def _return_value + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._return_value end @@ -401,14 +436,17 @@ class RemoteTkIp end def _split_tklist(str) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._split_tklist(str) end def _merge_tklist(*args) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._merge_tklist(*args) end def _conv_listelement(str) + raise SecurityError, "no permission to manipulate" unless self.manipulable? @interp._conv_listelement(str) end diff --git a/ext/tk/lib/tk.rb b/ext/tk/lib/tk.rb index 7e501753e2..3e6c0c0a04 100644 --- a/ext/tk/lib/tk.rb +++ b/ext/tk/lib/tk.rb @@ -16,6 +16,7 @@ class TclTkIp alias _invoke_without_enc _invoke def _ip_id_ + # for RemoteTkIp '' end end @@ -189,6 +190,7 @@ module TkComm module_function :_at def tk_tcl2ruby(val, enc_mode = false, listobj = true) +=begin if val =~ /^rb_out\S* (c(_\d+_)?\d+)/ #return Tk_CMDTBL[$1] return TkCore::INTERP.tk_cmd_tbl[$1] @@ -199,6 +201,10 @@ module TkComm # cmd_obj.cmd #end end +=end + if val =~ /rb_out\S*(?:\s+(::\S*|[{](::.*)[}]|["](::.*)["]))? (c(_\d+_)?(\d+))/ + return TkCore::INTERP.tk_cmd_tbl[$4] + end #if val.include? ?\s # return val.split.collect{|v| tk_tcl2ruby(v)} #end @@ -601,10 +607,14 @@ end end end def procedure(val) +=begin if val =~ /^rb_out\S* (c(_\d+_)?\d+)/ #Tk_CMDTBL[$1] #TkCore::INTERP.tk_cmd_tbl[$1] TkCore::INTERP.tk_cmd_tbl[$1].cmd +=end + if val =~ /rb_out\S*(?:\s+(::\S*|[{](::.*)[}]|["](::.*)["]))? (c(_\d+_)?(\d+))/ + return TkCore::INTERP.tk_cmd_tbl[$4].cmd else #nil val @@ -783,6 +793,13 @@ end def install_cmd(cmd) return '' if cmd == '' + begin + ns = TkCore::INTERP._invoke_without_enc('namespace', 'current') + ns = nil if ns == '::' # for backward compatibility + rescue + # probably, Tcl7.6 + ns = nil + end id = _next_cmd_id #Tk_CMDTBL[id] = cmd if cmd.kind_of?(TkCallbackEntry) @@ -794,10 +811,15 @@ end @cmdtbl.taint unless @cmdtbl.tainted? @cmdtbl.push id #return Kernel.format("rb_out %s", id); - return 'rb_out' + TkCore::INTERP._ip_id_ + ' ' + id + if ns + 'rb_out' << TkCore::INTERP._ip_id_ << ' ' << ns << ' ' << id + else + 'rb_out' << TkCore::INTERP._ip_id_ << ' ' << id + end end def uninstall_cmd(id) - id = $1 if /rb_out\S* (c(_\d+_)?\d+)/ =~ id + #id = $1 if /rb_out\S* (c(_\d+_)?\d+)/ =~ id + id = $4 if id =~ /rb_out\S*(?:\s+(::\S*|[{](::.*)[}]|["](::.*)["]))? (c(_\d+_)?(\d+))/ #Tk_CMDTBL.delete(id) TkCore::INTERP.tk_cmd_tbl.delete(id) end @@ -915,9 +937,13 @@ module TkComm def _bindinfo(what, context=nil) if context tk_call_without_enc(*what+["<#{tk_event_sequence(context)}>"]) .collect {|cmdline| +=begin if cmdline =~ /^rb_out\S* (c(?:_\d+_)?\d+)\s+(.*)$/ #[Tk_CMDTBL[$1], $2] [TkCore::INTERP.tk_cmd_tbl[$1], $2] +=end + if cmdline =~ /rb_out\S*(?:\s+(::\S*|[{](::.*)[}]|["](::.*)["]))? (c(_\d+_)?(\d+))/ + [TkCore::INTERP.tk_cmd_tbl[$4], $5] else cmdline end @@ -1081,6 +1107,13 @@ module TkCore INTERP.instance_eval{ @tk_cmd_tbl = {}.taint + def @tk_cmd_tbl.[]=(idx,val) + if self.has_key?(idx) && Thread.current.group != ThreadGroup::Default + fail SecurityError,"cannot change the entried command" + end + super(idx,val) + end + @tk_windows = {}.taint @tk_table_list = [].taint @@ -1190,6 +1223,28 @@ module TkCore INTERP.add_tk_procs(TclTkLib::FINALIZE_PROC_NAME, '', "bind all <#{WIDGET_DESTROY_HOOK}> {}") + INTERP.add_tk_procs('rb_out', 'ns args', <<-'EOL') + if [regexp {^::} $ns] { + set cmd {namespace eval $ns {ruby_cmd TkCore callback} $args} + } else { + set cmd {eval {ruby_cmd TkCore callback} $ns $args} + } + if {[set st [catch $cmd ret]] != 0} { + #return -code $st $ret + set idx [string first "\n\n" $ret] + if {$idx > 0} { + return -code $st \ + -errorinfo [string range $ret [expr $idx + 2] \ + [string length $ret]] \ + [string range $ret 0 [expr $idx - 1]] + } else { + return -code $st $ret + } + } else { + return $ret + } + EOL +=begin INTERP.add_tk_procs('rb_out', 'args', <<-'EOL') if {[set st [catch {eval {ruby_cmd TkCore callback} $args} ret]] != 0} { #return -code $st $ret @@ -1206,6 +1261,7 @@ module TkCore return $ret } EOL +=end =begin INTERP.add_tk_procs('rb_out', 'args', <<-'EOL') #regsub -all {\\} $args {\\\\} args @@ -4443,7 +4499,7 @@ end #Tk.freeze module Tk - RELEASE_DATE = '2005-10-24'.freeze + RELEASE_DATE = '2005-11-18'.freeze autoload :AUTO_PATH, 'tk/variable' autoload :TCL_PACKAGE_PATH, 'tk/variable' diff --git a/ext/tk/lib/tk/namespace.rb b/ext/tk/lib/tk/namespace.rb index 85a94372b9..7634527724 100644 --- a/ext/tk/lib/tk/namespace.rb +++ b/ext/tk/lib/tk/namespace.rb @@ -14,6 +14,14 @@ class TkNamespace < TkObject Tk_Namespace_ID_TBL = TkCore::INTERP.create_table Tk_Namespace_ID = ["ns".freeze, "00000".taint].freeze + TkCore::INTERP.init_ip_env{ Tk_Namespace_ID_TBL.clear } + + def TkNamespace.id2obj(id) + Tk_Namespace_ID_TBL[id]? Tk_Namespace_ID_TBL[id]: id + end + + ##################################### + class Ensemble < TkObject def __cget_cmd ['namespace', 'ensemble', 'configure', self.path] @@ -107,6 +115,8 @@ class TkNamespace < TkObject end end + ##################################### + class ScopeArgs < Array include Tk @@ -139,6 +149,8 @@ class TkNamespace < TkObject end end + ##################################### + class NsCode < TkObject def initialize(scope) @scope = scope + ' ' @@ -154,6 +166,18 @@ class TkNamespace < TkObject end end + ##################################### + + def install_cmd(cmd) + lst = tk_split_simplelist(super(cmd), false, false) + if lst[1] =~ /^::/ + lst[1] = @fullname + else + lst.insert(1, @fullname) + end + TkCore::INTERP._merge_tklist(*lst) + end + alias __tk_call tk_call alias __tk_call_without_enc tk_call_without_enc alias __tk_call_with_enc tk_call_with_enc @@ -252,17 +276,37 @@ class TkNamespace < TkObject _get_eval_string(cmd, false))) end - def self.current + def self.current_path tk_call('namespace', 'current') end + def current_path + @fullname + end + + def self.current + ns = self.current_path + if Tk_Namespace_ID_TBL.key?(ns) + Tk_Namespace_ID_TBL[ns] + else + ns + end + end def current_namespace # ns_tk_call('namespace', 'current') - @fullname + # @fullname + self end alias current current_namespace def self.delete(*ns_list) tk_call('namespace', 'delete', *ns_list) + ns_list.each{|ns| + if ns.kind_of?(TkNamespace) + Tk_Namespace_ID_TBL.delete(ns.path) + else + Tk_Namespace_ID_TBL.delete(ns.to_s) + end + } end def delete TkNamespece.delete(@fullname) @@ -302,14 +346,14 @@ class TkNamespace < TkObject ret = code_obj.call(*args) # uninstall_cmd(TkCore::INTERP._split_tklist(code_obj.path)[-1]) uninstall_cmd(_fromUTF8(TkCore::INTERP._split_tklist(_toUTF8(code_obj.path))[-1])) - ret + tk_tcl2ruby(ret) end def self.exist?(ns) bool(tk_call('namespace', 'exists', ns)) end def exist? - TkNamespece.delete(@fullname) + TkNamespece.exist?(@fullname) end def self.export(*patterns) @@ -349,7 +393,7 @@ class TkNamespace < TkObject tk_call('namespace', 'inscope', namespace, script, *args) end def inscope(script, *args) - TkNamespace(@fullname, script, *args) + TkNamespace.inscope(@fullname, script, *args) end def self.origin(cmd) @@ -396,3 +440,5 @@ class TkNamespace < TkObject tk_call('namespace', 'which', '-variable', name) end end + +TkNamespace::Global = TkNamespace.new('::') -- cgit v1.2.3