2010-05-10 9 views
45

मेरे पास एक पाइथन लिपि है जो बहुत सी चीजें कर रही है जिसके लिए रूट-स्तरीय विशेषाधिकारों की आवश्यकता होगी, जैसे/etc में फ़ाइलों को ले जाना, एपीटी-गेट के साथ इंस्टॉल करना आदि। मेरे पास वर्तमान में है:किसी स्क्रिप्ट के उपयोगकर्ता के पास रूट-जैसे विशेषाधिकार हैं या नहीं, यह जांचने का सबसे अच्छा तरीका क्या है?

if os.geteuid() != 0: 
    exit("You need to have root privileges to run this script.\nPlease try again, this time using 'sudo'. Exiting.") 

क्या यह जांच करने का सबसे अच्छा तरीका है? क्या अन्य सर्वोत्तम प्रथाएं हैं?

उत्तर

26

"आसान अनुमति से माफी पूछो करने के लिए" सिद्धांत के तहत:

try: 
    os.rename('/etc/foo', '/etc/bar') 
except IOError as e: 
    if (e[0] == errno.EPERM): 
     print >> sys.stderr, "You need root permissions to do this, laterz!" 
     sys.exit(1) 

आप के बारे में चिंतित हैं, तो! os.geteuid() की गैर-पोर्टेबिलिटी आपको शायद /etc के साथ मिलकर नहीं मिलना चाहिए।

+0

यह सबसे पोर्टेबल तरीका है और यहां तक ​​कि कुछ और अधिक विदेशी परिस्थितियों में काम करता है, जैसे SELinux रूट विशेषाधिकारों को सीमित करता है। –

+3

यह स्थिति के आधार पर वास्तव में खराब हो सकता है। हम्म लेकिन फ्लोरियन का एक बिंदु है। –

+0

@ लोंगपोक - क्या आप उस परिस्थिति का जिक्र कर रहे हैं जहां उपयोगकर्ता के पास/etc में अनुमतियों का नाम बदल सकता है - लेकिन उस पथ से फ़ाइल को हटाने की क्षमता कम है? यदि आपका यही मतलब है, तो यह निर्धारित करने की कोशिश कर रहा है कि उपयोगकर्ता पहले से कौन सी क्षमताओं को पहले से ही करता है वह मूर्खतापूर्ण है। "लेनदेन" अर्थशास्त्र के लिए अपने कोड को बेहतर बनाने के लिए बेहतर है जहां सी विफल होने पर ए और बी को लुढ़काया जा सकता है। – msw

48

os.geteuid प्रभावी उपयोगकर्ता आईडी प्राप्त करता है, जो वास्तव में आप चाहते हैं, इसलिए मैं इस तरह के चेक करने के किसी भी बेहतर तरीके से नहीं सोच सकता। एक बिट जो अनिश्चित है वह शीर्षक में "रूट-जैसा 'है: आपका कोड के लिए बिल्कुलroot, इसके बारे में" पसंद "नहीं है, और वास्तव में मुझे नहीं पता कि" रूट की तरह लेकिन रूट नहीं "का क्या अर्थ होगा - हां, अगर आप कुछ "वास्तव में रूट" की तुलना में अलग मतलब है, शायद आप स्पष्ट कर सकते हैं, धन्यवाद

+2

मैं यह सोचते हैं हूँ पॉल प्रशासकों के लिए अलग UIDs का उपयोग कर विभिन्न प्रणालियों के बारे में चिंतित है। आम तौर पर आईडी (रूट) == 0, लेकिन यह जरूरी नहीं है और कुछ प्रणालियों पर यह वास्तव में बराबर नहीं है। – Stan

+0

@Stan: तो ईएएफपी वास्तव में बेहतर होगा – msw

+8

धारणा है कि प्रभावी यूआईडी == 0 का अर्थ है "रूट" यूनिक्स कोड में बहुत गहराई से शामिल है (अधिकांश यूनिक्स जैसे कर्नेल स्रोतों सहित)। लिनक्स के तहत तकनीकी रूप से धारणा है कि धारणा जरूरी नहीं है। लिनक्स "क्षमताओं" मॉडल सिस्टम को प्रोसेस विरासत (लैप 2 रैपर) या संभावित रूप से विस्तारित फाइल सिस्टम विशेषताओं के माध्यम से सौंपे गए अधिक सुगंधित नियंत्रणों के साथ चलाने की अनुमति देता है। इसके अलावा SELinux सुविधाएं ऐसी धारणाओं के साथ विनाश खेल सकती हैं। वहां 99% सिस्टम के लिए, geteuid() == 0 पर्याप्त है; बाकी के लिए प्रयास करें: ... को छोड़कर: आपका दोस्त है। –

0

यह सब निर्भर करता है कि आप पोर्टेबल कैसे चाहते हैं कि आप ऐप बनें। यदि आपका मतलब उदारता है, तो हमें यह मानना ​​होगा कि व्यवस्थापक खाता हमेशा 0 के बराबर नहीं होता है। इसका मतलब है कि ईयूआईडी 0 की जांच पर्याप्त नहीं है। समस्या यह है कि ऐसी स्थितियां हैं जहां एक कमांड व्यवहार करेगा जैसे कि आप रूट हैं और अगली अनुमति के साथ विफल हो जाएगी (SELinux & सह।) को अस्वीकार कर दिया गया है। इसलिए यह वास्तव में विफल होने के लिए वास्तव में बेहतर है और जब भी उचित हो तो EPERM errno की जांच करें।

7

यदि आप वास्तव में लिनक्स कॉन्फ़िगरेशन की एक विस्तृत विविधता में अपने कोड को मजबूत करना चाहते हैं तो मैं सुझाव दूंगा कि आप कोने के मामलों पर विचार करें जहां कोई SELinux, या फाइल सिस्टम एसीएल, या "क्षमताओं" सुविधाओं का उपयोग कर रहा है वी। 2.2 या उसके बाद से लिनक्स कर्नेल में। आपकी प्रक्रिया कुछ रैपर के तहत चल रही हो सकती है जिसने SELinux, या कुछ लिनक्स क्षमताओं लाइब्रेरी का उपयोग किया है, जैसे कि libcap2libcap-ng, या fscaps या elfcap नील्स प्रोवोस की अद्भुत और दुखद रूप से सराहना की गई systrace प्रणाली जैसी कुछ विदेशी चीज़ों के माध्यम से।

ये सभी तरीके हैं कि आप कोड गैर-रूट के रूप में चल रहे हैं और फिर भी आपकी प्रक्रिया को EUID == 0 के बिना अपना काम करने के लिए आवश्यक पहुंच सौंपी गई हो सकती है।

तो मैं सुझाव दूंगा कि आप अपने कोड को और अधिक पाइथनिक रूप से लिखने पर विचार करें, जो अनुमतियों को लपेटकर या अपवाद हैंडलिंग कोड के साथ अन्य मुद्दों के कारण विफल हो सकते हैं। यदि आप विभिन्न संचालन करने के लिए बाहर निकल रहे हैं (उदाहरण के लिए subprocess मॉड्यूल का उपयोग करके) आप sudo (उदाहरण के लिए कमांड लाइन, पर्यावरण, या .rc फ़ाइल विकल्प के रूप में) के साथ ऐसी सभी कॉल को उपसर्ग करने की पेशकश कर सकते हैं। यदि यह अंतःक्रियात्मक रूप से चलाया जा रहा है तो आप sudo का उपयोग कर अनुमतियों से संबंधित अपवादों को बढ़ाने के लिए किसी भी आदेश को फिर से निष्पादित करने की पेशकश कर सकते हैं (वैकल्पिक रूप से केवल तभी जब आप sudo os.environ ['पथ'] पर पाते हैं)।

कुल मिलाकर यह सच है कि अधिकांश लिनक्स और यूनिक्स सिस्टमों में अभी भी उनके अधिकांश प्रशासन को 'रूट' विशेषाधिकार प्राप्त उपयोगकर्ता द्वारा किया जाता है। हालांकि, यह पुराना स्कूल है और हम प्रोग्रामर के रूप में, नए मॉडल का समर्थन करने की कोशिश करनी चाहिए। अपने परिचालनों को आज़माकर और अपवाद हैंडलिंग करने की अनुमति देना, यह काम आपके कोड को किसी भी प्रणाली के तहत काम करने की अनुमति देता है जो आपको आवश्यक संचालनों की पारदर्शी अनुमति देता है, और sudo का उपयोग करने के लिए तैयार और तैयार होने के लिए एक अच्छा स्पर्श है (जैसा कि, अब तक, सबसे अधिक है सिस्टम विशेषाधिकारों के नियंत्रित प्रतिनिधिमंडल के लिए व्यापक उपकरण)।

3

प्रश्न के दूसरे भाग के लिए उत्तर

(खेद टिप्पणी बॉक्स था बहुत छोटा)

पॉल हॉफमैन, आप सही, मैं सिर्फ अपने प्रश्न intrinsics से निपटने का एक हिस्सा संबोधित कर रहे हैं, लेकिन यह यदि यह apt-get को संभाल नहीं सकता है तो यह एक योग्य स्क्रिप्टिंग भाषा नहीं होगी। वरीय पुस्तकालय एक बालक वर्बोज़ है, लेकिन यह काम करता है:

>>> apt_get = ['/usr/bin/apt-get', 'install', 'python'] 
>>> p = subprocess.Popen(apt_get, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
>>> p.wait() 
100     # Houston, we have a problem. 
>>> p.stderr.read() 
'E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied)' 
'E: Unable to lock the administration directory (/var/lib/dpkg/), are you root?\n' 

लेकिन Popen एक सामान्यीकृत उपकरण है और सुविधा के लिए लपेटा जा सकता है:

$ cat apt.py 
import errno 
import subprocess 

def get_install(package): 
    cmd = '/usr/bin/apt-get install'.split() 
    cmd.append(package) 
    output_kw = {'stdout': subprocess.PIPE, 'stderr': subprocess.PIPE} 
    p = subprocess.Popen(cmd, **output_kw) 
    status = p.wait() 
    error = p.stderr.read().lower() 
    if status and 'permission denied' in error: 
     raise OSError(errno.EACCES, 'Permission denied running apt-get') 
    # other conditions here as you require 
$ python 
>>> import apt 
>>> apt.get_install('python') 
Traceback ... 
OSError: [Errno 13] Permission denied running apt-get 

और अब हम वापस अपवाद संचालन करने के लिए कर रहे हैं। मैं उप-प्रोसेस मॉड्यूल की जावा-जैसी अति-सामान्यता पर टिप्पणी करने से इनकार कर दूंगा।

+1

क्या इसे आपके अन्य उत्तर में संपादित करने के लिए और अधिक समझदारी नहीं होगी? – jpmc26

1

मैं पर्यावरण चर में sudo के लिए जाँच करना चाहते:

 
if not 'SUDO_UID' in os.environ.keys(): 
    print "this program requires super user priv." 
    sys.exit(1) 
5

आप sudo पहुँच के लिए उपयोगकर्ता का संकेत दे सकता:

import os, subprocess 

def prompt_sudo(): 
    ret = 0 
    if os.geteuid() != 0: 
     msg = "[sudo] password for %u:" 
     ret = subprocess.check_call("sudo -v -p '%s'" % msg, shell=True) 
    return ret 

if prompt_sudo() != 0: 
    # the user wasn't authenticated as a sudoer, exit? 

sudo -v स्विच अद्यतन उपयोगकर्ता के कैश किए गए क्रेडेंशियल्स (man sudo देखें) ।

2

मेरा ऐप इस कोड के साथ काम करता है:

import os 
user = os.getenv("SUDO_USER") 
if user is None: 
    print "This program need 'sudo'" 
    exit() 
+0

खराब कोड। यहां फेंक दिया गया त्रुटि 'TypeError' है, क्योंकि यदि आप रूट के रूप में नहीं चल रहे हैं,' os.getenv ("SUDO_USER") 'वापसी' कोई नहीं 'जो कि' noneType 'प्रकार का है, और आप 'str' और' NoneType'। यदि आप समस्या को हल करने के लिए 'os.getenv (" SUDO_USER ")' का उपयोग करना चाहते हैं, तो आपको इसे ऐसा करना चाहिए: 'o ogetgetenv (" SUDO_USER ") == कोई नहीं: प्रिंट करें" इस प्रोग्राम की आवश्यकता है " sudo ' "; बाहर निकलें() ' –

+2

मैंने अपना उत्तर – Guillaume

+1

संपादित करने के लिए धन्यवाद संपादित किया है, यह कोड केवल सूड का परीक्षण करेगा, न कि रूट पहुंच। चूंकि यह रूट की जांच नहीं करता है, अगर आप रूट के रूप में लॉग इन करते हैं (या आपने मेरे जैसे क्रोनबॉब लिखा है) तो आपको अभी भी स्क्रिप्ट के साथ स्क्रिप्ट को कॉल करने की आवश्यकता है, क्योंकि सूडो रूट पर पासवर्ड नहीं पूछता है, मैं अपने cronjob को ठीक करने में सक्षम था सूडो के साथ मेरी पायथन लिपि को बुलाकर। – Cediddi