home changes contents help options

213:ユーザID・グループIDを切り替える

スーパーユーザから一般ユーザに切り替える

スーパーユーザが一時的に一般ユーザとなって作業を行うには os.seteuid を用います。 元の値を保持しておいて、再度設定することでスーパーユーザに戻ることができます。 永続的に一般ユーザになるには os.setuid を用います。 引数にはユーザ ID を与えます。 ID の確認方法は 212:ユーザやグループに関する情報を得る を参照してください。

>>> import os
>>> ruid = os.geteuid()
>>> os.seteuid(1000)
>>>
>>> os.setuid(ruid)

グループ ID を切り替える

一時的にグループを変更し os.setegid を、永続的に行うには os.setgid を用います。

>>> import os
>>> rgid = os.getegid()
>>> os.setegid(1000)
>>>
>>> os.setegid(rgid)

一時的にユーザー・グループに切り替えて、確実に元に戻すには

try, finally を用います。

ruid = os.geteuid()
os.seteuid(1000)
try:
    print os.geteuid() # 一般ユーザー権限で行う処理
finally:
    os.seteuid(ruid)

次の SwitchEuid? のようなコンテキストマネージャを用いる方法もあります (Python 2.5 以降限定。 Python 2.5 の場合、さらに from future import with_statement が必要)。

import os

class SwitchEuid():
    def __init__(self, id):
        self.id = id

    def __enter__(self):
        self.ruid = os.geteuid()
        os.seteuid(self.id)
        
    def __exit__(self, exc_type, exc_value, traceback):
        os.seteuid(self.ruid)
        if exc_type:
            return False
        return True

これは with 文にて次のように用います。

print os.geteuid()
with SwitchEuid(1000):
    print os.geteuid()
print os.geteuid()

関数単位の処理ならば次の switch_euid のようなデコレータを用いるという方法もあります(Python 2.4 以降限定)。

import os
import functools

def switch_euid(euid):
    def wrapper(func):
        @functools.wraps(func)
        def _(*args, **kwargs):
            ruid = os.geteuid()
            os.seteuid(euid)
            try:
                return func(*args, **kwargs)
            finally:
                os.seteuid(ruid)
        return _
    return wrapper

デコレータは次のように使います。

@switch_euid(1000)
def test():
    print os.geteuid()

def main():
    print os.geteuid()
    test()
    print os.geteuid()
    
if __name__ == '__main__':
    main()

参考