1. 程式人生 > >如何在unix系統中用別的用戶運行一個程序?

如何在unix系統中用別的用戶運行一個程序?

獲取 程序 eight idt code 如何 不用 hold 結構

1、問題的緣由

實際開發系統的時候,經常需要用別的用戶運行一個程序。比如,有些系統為保證系統安全,不允許使用root來運行。這裏,我們總結了unix系統下如何解決這個問題的一些方法。同時,我們還討論如何在python腳本裏實現。

2、unix系統的方法

2.1、runuser

runuser允許使用替代用戶和組ID來運行命令。如果選項-u沒有給出,則回退到su兼容的語義和shell被執行。

  • runuser和su命令之間的區別在於runuser不要求輸入密碼(因為它可能僅由root用戶執行),它使用不同的PAM配置。命令runuser不必與suid權限一起安裝。
  • 當沒有參數調用時,runuser默認以root用戶身份運行交互式shell。
  • 為了向後兼容,runuser默認不更改當前目錄並僅設置環境變量HOME和SHELL(加上USER和LOG- 如果目標用戶不是root用戶,則為NAME)。此版本的runuser使用PAM進行會話管理

用法:

runuser [options] -u <USER> COMMAND
runuser [options] [-] [USER [arg]...]

案例:

runuser -l elastic -c "ls /var/opt/elastic"

如果當前用戶不是root:

runuser: may not be used by non-root users

2.2、su

su允許使用替代用戶和組ID來運行命令。

  • 當沒有參數的情況下調用su時默認以root身份運行交互式shell。
  • 為了向後兼容,su默認不更改當前目錄並僅設置環境變量HOME和SHELL(如果目標用戶不是root的話,加上USER和LOGNAME)。
  • 建議始終使用--login選項(而不是快捷方式-),以避免混合環境導致的副作用,
  • su使用PAM進行認證,帳戶和會話管理。在其他su實現中有一些配置選項,例如 必須通過PAM配置wheel組的支持。

案例:

$ su -l elastic
Password:*****

$ whoami
elastic

2.3、sudo

sudo允許允許的用戶按照安全策略的規定,以超級用戶或其他用戶的身份執行命令。

  • sudo支持安全策略和輸入/輸出日誌記錄的插件體系結構。第三方可以開發和分發自己的策略和I / O日誌插件與sudo前端無縫協作。
  • 默認安全策略是sudoers,通過/ etc / sudoers文件或通過LDAP配置。看PLUGINS部分獲取更多信息。
  • 安全策略確定用戶必須運行sudo的權限(如果有的話)。該政策可能要求用戶使用密碼或另一種認證機制驗證自己身份。如果需要驗證,如果用戶的密碼未在可配置的時間限制內輸入,則sudo將退出。sudoers安全策略的默認密碼提示超時為5分鐘。安全策略可以支持憑證緩存,以允許用戶在不需要認證的情況下再次運行sudo一段時間。 sudoers 安全策略的緩存憑證5分鐘,除非在sudoers(5)中覆蓋。通過使用-v選項運行sudo,用戶無需更新緩存的憑據 運行一個命令。當作為sudoedit被調用時,隱含-e選項。安全策略可能會記錄成功和失敗的嘗試使用sudo。如果配置了I / O插件,則記錄運行命令的輸入和輸出。

案例:

sudo -u jim -g audio vi ~jim/sound.txt

2.4、總結

命令

root到用戶

用戶到root

任何用戶間

身份驗證

系統支持

日誌

解釋

runuser

Y

N

N

不需要

Linux:是

Solaris:不

MacOS:是

N/A

不用身份驗證,效率較高

su

Y

Y

Y

目標用戶的密碼

Linux:是

Solaris:是

MacOS:是

/var/log/auth.log

/var/log/secure

必須提供用戶密碼

sudo

Y

Y

Y

用戶需要驗證本人身份

Linux:是

Solaris:不

MacOS:是

/var/log/auth.log

/var/log/secure

用戶必須是wheel組的成員,可以執行管理員的工作

3、python腳本的方法

在實際工作中,越來越多需要用python來自動化任務、集成不同的部件、處理數據。很多時候會碰到同樣問題:如何在python腳本中調用不同用戶來運行程序。

  • 定義一個函數來設置正在運行的進程的gid和uid。
  • 將此函數作為preexec_fn參數傳遞給subprocess.Popen

subprocess.Popen將使用fork / exec模型來使用preexec_fn。這等同於按順序調用

  • os.fork(),
  • preexec_fn()(在子進程中),
  • os.exec()(在子進程中)

必須註意,由於os.setuid,os.setgid和preexec_fn僅在Unix上受支持,因此此解決方案僅支持unix及相關系統。

import os, pwd, subprocess, sys

# set gid and uid
def demote(user_uid, user_gid):
    def result():
        os.setgid(user_gid)
        os.setuid(user_uid)
    return result

# run a command under a new user
def run_command(cmd, user_name, cwd):
    pw_record = pwd.getpwnam(user_name)
    user_name      = pw_record.pw_name
    user_uid       = pw_record.pw_uid
    user_gid       = pw_record.pw_gid

    # get env variable
    env = os.environ.copy()
    env[ HOME     ]  = pw_record.pw_dir
    env[ LOGNAME  ]  = user_name
    env[ PWD      ]  = cwd
    env[ USER     ]  = user_name
    proc = subprocess.Popen(cmd, 
                          preexec_fn=demote(user_uid, user_gid), 
                          cwd=cwd, env=env )
    return proc.communicate()

如何在unix系統中用別的用戶運行一個程序?