Create process as user in ruby - windows

The following code is in a file called run.rb, the idea is to run ruby as a different user so I can do some testing.
require 'rubygems'
require 'win32/process'
domain = 'WORLDWIDE'
user_name = 'user'
password = 'password'
rubyScript = 'ruby test.rb'
Process.create(:command_line => rubyScript, :domain => domain, :with_logon => user_name, :password => password, :close_handles => false)
the contents of test.rb is:
require 'rubygems'
require 'watir'
browser = Watir::IE.new
browser.goto('http://localhost:44001/Users/List')
puts browser.text
when I run 'ruby run.rb' a command shell opens and then closes straight away.
Any ideas what I am doing wrong here?

Reviving a dead question, but in Windows NT, other users can't interact with your desktop. So if you're logged on as DOMAIN\user1 and spawn a process as DOMAIN\user2, the DOMAIN\user2 process cannot interact with DOMAIN\user1's desktop. An exception to this is if the process is running as a service and has the "Can interact with desktop" box checked in the service properties (but I think that requires that it run as SYSTEM).
It is possible to use the Local Security Policy (secpol.msc) to assign user rights to that user that permits that user to interact with everyone's desktops, but that would be unsafe to do if the user is granted the right to logon interactively.

It's probably running your command just fine, opening a new command window (since it's a new windows Process), then closing that window when it completes. Try throwing a "sleep 1000" at the end of test.rb. If I'm correct, that should keep the window around so that you can view the output.

Related

Execute basic windows commands

I would like to achieve this using win32ole only and not any other way to execute shell commands in ruby.
require 'win32ole'
shell = WIN32OLE.new('Shell.Application')
my_username = shell.ShellExecute('cmd.exe', 'username', '', 'open', 0)
puts my_username
#Current output => nil
Just want to print my username but generally would like to execute any commands and get its output. I know we have ENV['user'] or echo %username% gives me what I want but want this using win32ole only.
Thanks a lot in advance.
You should try with whoami instead of username:
require 'win32ole'
shell = WIN32OLE.new('Shell.Application')
my_username = shell.ShellExecute('cmd.exe', 'whoami', '', 'open', 0)
puts my_username
You can't use ShellExecute() because it doesn't let you access the output of the command your run which is what you want. See Using ShellExecuteEx and capturing standard in/out/err for more informations about that point.
I would simply use puts ENV['USERNAME'] which works like a charm. (Or any command given by Ilia Aptsiauri in his answer)
If you just want to execute Windows CLI commands you need to take little bit different approach.
Instead of whoami you can put any command you want
system("whoami")
`whoami` (these are backticks)
spawn("whoami")
The difference between those are the following
system waits until "The command" has finished and outputs everything
to $stdout. Then it returns true or false depending on the exitstatus.
The backticks wait as well, but return the output made by the program.
spawn doesn't wait, but rather returns the PID of the subprocess. Note
that this requires Ruby 1.9 on Windows to work.
There is one more option check Open3 library it get's little bit more information during the output.

Unix commands work on server but not in ruby ssh session

I am trying to learn how to use the net-ssh gem for ruby. I want to execute the commands below, after I login to the directory - /home/james.
cd /
pwd
ls
When I do this with putty, it works and i can see a list of directories. But, when I do it with ruby code, it does not give me the the same output.
require 'rubygems'
require 'net/ssh'
host = 'server'
user = 'james'
pass = 'password123'
def get_ssh(host, user, pass)
ssh = nil
begin
ssh = Net::SSH.start(host, user, :password => pass)
puts "conn successful!"
rescue
puts "error - cannot connect to host"
end
return ssh
end
conn = get_ssh(host, user, pass)
def exec(linux_code, conn)
puts linux_code
result = conn.exec!(linux_code)
puts result
end
exec('cd /', conn)
exec('pwd', conn)
exec('ls', conn)
conn.close
Output -
conn successful!
cd /
nil
pwd
/home/james
ls
nil
I was expecting pwd to give me / instead of /home/james. That is how it works in putty. What is the mistake in the ruby code?
It seems like every command runs on it's own environment, so the current directory is not carried over exec to exec. You can verify this if you do:
exec('cd / && pwd', conn)
It will print /. It is not clear from the documentation how to make all the commands execute on the same environment or if this is even possible at all.
This is because net/ssh is stateless, so it opens a new connection with each command execution.
You can use the rye gem that implements a work around for this. but I do not know if it works with ruby > 2, since its development is not that active.
Another way is to use a pty process, in which you'll open a pseudo terminal with the ssh command, than use the input and output files to write commands for the terminal and read the results. To read the results you need to use the select method of the IO class. But you need to learn how to use those utilities since its not that obvious for a non experienced programmer.
And, Yey, I found how to do that, and in fact it is so simple. I think I did not get to this solution last time, because I was a little new to this thing of net-ssh, pty terminal. But yey, I found it finally, and here and example.
require 'net/ssh'
shell = {} #this will save the open channel so that we can use it accross threads
threads = []
# the shell thread
threads << Thread.new do
# Connect to the server
Net::SSH.start('localhost', 'your_user_name', password: 'your_password') do |session|
# Open an ssh channel
session.open_channel do |channel|
# send a shell request, this will open an interactive shell to the server
channel.send_channel_request "shell" do |ch, success|
if success
# Save the channel to be used in the other thread to send commands
shell[:ch] = ch
# Register a data event
# this will be triggered whenever there is data(output) from the server
ch.on_data do |ch, data|
puts data
end
end
end
end
end
end
# the commands thread
threads << Thread.new do
loop do
# This will prompt for a command in the terminal
print ">"
cmd = gets
# Here you've to make sure that cmd ends with '\n'
# since in this example the cmd is got from the user it ends with
#a trailing eol
shell[:ch].send_data cmd
# exit if the user enters the exit command
break if cmd == "exit\n"
end
end
threads.each(&:join)
and here we are, an interactive terminal using net-ssh ruby gem.
For more info look here its for the previous version 1, but it is so useful for you to understand how every piece works. And here

How to enter a password into another process prompt from Ruby

I am writing an application that needs to run command on a remote Raspberry PI using a revssh script. revssh is a custom script that implements to some level the Revssh protocol concepts. it uses ssh reverse tunneling to send commands from the server to the clients.
I am using Ruby 2.1, I tried to do this using IO.popen but it does not work, so I tried the following:
# revssh (short for reverse ssh ) enables the execution of remote commands
# from the server on connected clients, like the 'psu_pi_analytics' here. but it requires
# to enter a root password each time you want to run a command using 'revssh -c'
IO.popen('revssh -c psu_pi_analytics uname -a', 'w+') do|io|
io.puts 'password' # enter the password when prompted
puts io.gets
end
this code work if the command to execute run on the local machine, but not in my case.
So any thoughts, or suggestions.
What important here is how to deal with the new connection created by the revssh script using ssh, which is managed in the terminal if the script is run directly from the terminal.
Edit:
By not work I mean it still prompts for the password, even if I puts the password to the io.
You can use an Expect-like library (e.g. RExpect, Expect4r) for interacting with other processes.
Another question related to this: Is there an Expect equivalent gem for Ruby?

Automating SSH to windows with Ruby

I have a 13 windows servers running Jenkins Slaves. For some reason (windows updates?), the Jenkins slaves periodically quit working and the Jenkins Slave service needs to be restarted. If I manually SSH to the machines (cygwin ssh server is running) I simply type:
net stop "Jenkins Slave"
net start "Jenkins Slave"
and this (almost) always solves the problem.
So I wrote a Ruby script to automate this.
Here is is:
#!/usr/bin/env ruby
require 'rubygems'
require 'net/ssh'
USER = 'Administrator'
PASS = 'PASSWORD'
hosts = [:breckenridge, :carbondale, :crestone, :denali, :gunnison, :sneffels, "mammoth", "whitney", "snowmass", "firestone", "avon", :grizzly, :silverton]
hosts.each {|host|
puts "SSHing #{host} ..."
Net::SSH.start( HOST, USER, :password => PASS ) do |ssh|
puts ssh.exec!('net stop "Jenkins Slave"')
puts ssh.exec!('net start "Jenkins Slave"')
puts "Logging out..."
end
}
The script executes on all machines, I see output that the service has started. However, this never works. When I ssh back to the machine, the service hasn't started.
Sadly, I can't use Linux - I'm not in control of these machines.
Any ideas on why a manually executed SSH works, but the script doesn't?
Thanks
phil
I tried it out in Pry and found two issues:
HOST is undefined, it should be host as this is the variable being passed into the block.
SSH.start expects the parameters to be STRING class, so add the .to_s as indicated below.
Also, I switched it to the idiomatic Ruby pattern of using do...end when a block extends past 1 line.
hosts.each do |host|
puts "SSHing #{host} ..."
Net::SSH.start( host.to_s, USER, :password => PASS ) do |ssh|
puts ssh.exec!('date')
puts "Logging out..."
end
end
I tested this in Pry and it's now working. I hope this helps.

How do you prompt for a sudo password using Ruby?

Often I find myself needing to write scripts that have to execute some portions as a normal user and other portions as a super user. I am aware of one similar question on SO where the answer was to run the same script twice and execute it as sudo, however that is not sufficient for me. Some times I need to revert to being a normal user after a sudo operation.
I have written the following in Ruby to do this
#!/usr/bin/ruby
require 'rubygems'
require 'highline/import'
require 'pty'
require 'expect'
def sudorun(command, password)
`sudo -k`
PTY.spawn("sleep 1; sudo -u root #{command} 2>&1") { | stdin, stdout, pid |
begin
stdin.expect(/password/) {
stdout.write("#{password}\n")
puts stdin.read.lstrip
}
rescue Errno::EIO
end
}
end
Unfortunately, using that code if the user enters the wrong password the script crashes. Ideally it should give the user 3 tries to get the sudo password right. How do I fix this?
I am running this on Linux Ubuntu BTW.
In my opinion, running a script that does stuff internally with sudo is wrong. A better approach is to have the user run the whole script with sudo, and have the script fork lesser-privileged children to do stuff:
# Drops privileges to that of the specified user
def drop_priv user
Process.initgroups(user.username, user.gid)
Process::Sys.setegid(user.gid)
Process::Sys.setgid(user.gid)
Process::Sys.setuid(user.uid)
end
# Execute the provided block in a child process as the specified user
# The parent blocks until the child finishes.
def do_as_user user
unless pid = fork
drop_priv(user)
yield if block_given?
exit! 0 # prevent remainder of script from running in the child process
end
puts "Child running as PID #{pid} with reduced privs"
Process.wait(pid)
end
at_exit { puts 'Script finished.' }
User = Struct.new(:username, :uid, :gid)
user = User.new('nobody', 65534, 65534)
do_as_user(user) do
sleep 1 # do something more useful here
exit! 2 # optionally provide an exit code
end
puts "Child exited with status #{$?.exitstatus}"
puts 'Running stuff as root'
sleep 1
do_as_user(user) do
puts 'Doing stuff as a user'
sleep 1
end
This example script has two helper methods. #drop_priv takes an object with username, uid, and gid defined and properly reduces the permissions of the executing process. The #do_as_user method calls #drop_priv in a child process before yielding to the provided block. Note the use of #exit! to prevent the child from running any part of the script outside of the block while avoiding the at_exit hook.
Often overlooked security concerns to think about:
Inheritance of open file descriptors
Environment variable filtering
Run children in a chroot?
Depending on what the script is doing, any of these may need to be addressed. #drop_priv is an ideal place to handle all of them.
If it is possible, you could move the stuff you want executed as root to a seperate file and use the system() function to run it as sudo, including the sudo prompt etc:
system("sudo ruby stufftorunasroot.rb")
The system() function is blocking, so the flow of your program doesn't need to be changed.
I do not know if this is what you want or need, but have you tried sudo -A (search the web or the man page for SUDO_ASKPASS which might have a value like /usr/lib/openssh/gnome-ssh-askpass or similar)? This is what I use when I need to present a graphical password dialogue to users in GUI environments.
Sorry if this is the wrong answer, maybe you really want to remain on the console.
#!/usr/bin/ruby
# ... blabla, other code
# part which requires sudo:
system "sudo -p 'sudo password: ' #{command}"
# other stuff
# sudo again
system "sudo -p 'sudo password: ' #{command}"
# usually sudo 'remembers' that you just authenticated yourself successfuly and doesn't ask for the PW again...
# some more code...

Resources