How do you prompt for a sudo password using Ruby?

前端 未结 4 1998
栀梦
栀梦 2020-12-19 06:52

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

相关标签:
4条回答
  • 2020-12-19 06:53

    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.

    0 讨论(0)
  • 2020-12-19 07:02
    #!/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...
    
    0 讨论(0)
  • 2020-12-19 07:04

    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.

    0 讨论(0)
  • 2020-12-19 07:15

    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.

    0 讨论(0)
提交回复
热议问题