Skocz do zawartości

[pygtk] Pierwszy Projekt Sudog.py


borzole

Rekomendowane odpowiedzi

Witam,

udało mi się wreszcie napisać "coś" w pythonie i to z gtk (jupi!), no ale to wszystko wyglądało tak magicznie, że miałbym prośbę, potrzebuję:

* chętnych do przetestowania, czy jakieś głupoty nie wyskakują tam gdzie nie potrzeba

* chętnych do przejrzenia kodu (miernik WTF 'mile' widziany)

skrypt: sudog.py

sudo-simple-alfa.png

Jak testować:

* na początku skryptu zmienić w klasie SudoSimple tę linię:

sudoers='/home/lucas/project/python/sudo/sudoers'

na ścieżkę absolutną do kopi pliku /etc/sudoers

* proszę pamiętać o prawach dostępu i właścicielu (chmod,chown)

 

Tak na marginesie:

Dla roota nawet pliki tylko do odczytu, są zapisywalne ! Czy to normalne?

Odnośnik do komentarza
Udostępnij na innych stronach

Później zerknę dokładniej na kod, ale najpierw:

* na początku skryptu zmienić w klasie SudoSimple tę linię:

sudoers='/home/lucas/project/python/sudo/sudoers'

na ścieżkę absolutną do kopi pliku /etc/sudoers

* proszę pamiętać o prawach dostępu i właścicielu (chmod,chown)

Jeśli chodzi o pierwszy punkt to może wygodniej byłoby zrobić jakiegoś file choosera albo dać to do configa?

Co do drugiego, proponuję zrobić obsługę wyjątków i zgłoszenie odpowiedniego komunikatu, gdy któregoś z uprawnień brakuje.

 

[edit]

Ok, spojrzałem w kod i mam takie uwagi:

  • rozbijanie tego wyrażenia regularnego na szereg dodatkowych zmiennych IMO znacznie obniża jego czytelność i zwiększa podatność na błędy (których się nie ustrzegłeś). Można to zrobić np. tak:

    passwd="^\s*%s\s+ALL\s*=\s*\(\s*ALL\s*\)\s*ALL\s*$"

    i potem korzystając z operatora % podstawiać tam nazwę usera, przykład:

    In [41]: passwd="^\s*%s\s+ALL\s*=\s*\(\s*ALL\s*\)\s*ALL\s*$"
    
    In [42]: print passwd % 'ecik'
    ^\s*ecik\s+ALL\s*=\s*\(\s*ALL\s*\)\s*ALL\s*$

    Zrobić też trzeba oczywiście podobne wyrażenie dla NOPASSWD - choć tak naprawdę wystarczy zrobić jedno wyrażenia dla obu typów, a potem z pomocą grup będzie się dało rozróżnić które wyrażenie zostało zastosowany - służę pomocą, jakby co :)

    A jeśli uważasz, że tamto wyrażenie regularne jest nieczytelne to można je ładnie "uczytelnić" korzystając z flagi verbose (x), którą można zapodać w wyrażeniu. Wtedy wyrażenie mogłoby wyglądać np. tak:

    passwd = r"""
              (?x)          # ustawiamy flagę VERBOSE
              ^\s*          # początek stringu i dowolna ilość białych znaków
              %s            # tu zostanie podstawiona nazwa usera
              \s+ ALL       # co najmniej jeden biały znak i słówko 'ALL'
              \s*=\s*       # znak '=' z otoczeniem
              \(\s* ALL \s*\)
              \s* ALL \s*
              $             # koniec linii
              """

    Polecam poczytać helpa do re - daje naprawdę olbrzymie możliwości ;)

  • if re.search(passwd,  line) != None:

    Jak sprawdzasz czy dany obiekt jest typu None to właściwie powinieneś używać operatora is. Zaś najlepiej, w ogóle do niczego tutaj nie porównać wyniku searcha tylko zrobić tak:

    if re.search(passwd, line):

    Polecam poczytać w dokumentacji jakie wyrażenia są rozpoznawane jako prawdziwe, a jakie jako fałszywe.

  • #@TODO: czy można edytować plik 'w locie', bez dwukrotnego otwarcia?

    Można, przy otwieraniu pliku trzeba podać r+ jako flagi, ale nie osiągniesz w ten sposób tego co chcesz. Można też użyć modułu fileinput, używając przy tworzeniu obiektu parametru inplace. Podanie tego parametru powoduje, że sys.stdout jest przekierowywany na plik i wywołanie print zapisuje do pliku. Np. poniższy kodzik powoduje usunięcie z pliku tekstowego wszystkich linii zaczynających się literą 'a':

    import fileinput
    
    file = fileinput.input('test', inplace=1)
    
    
    for line in file:
            if not line.startswith('a'):
                    print line,

    Zwracam uwagę na przecinek na końcu linii z print. Powoduje on, że print nie dopisuje nowej linii (co jest pożądane gdyż "\n" jest uwzględniany w line).

Odnośnik do komentarza
Udostępnij na innych stronach

Dzięki za odpowiedź.

* Plik jest jeden: /etc/sudoers więc nie ma sensu go wybierać z programu ;) natomiast sprawdzania praw dostępu na razie mi się nie chciało robić, potem pomyślę.

* Dzięki za wskazówki do re. Nie wiedziałem, że można tam jakieś parametry i komentarze wrzucać. Natomiast wytłumacz mi co masz na myśli mówiąc "grupy". Zrobiłem to teraz tak, że przeniosłem do funkcji:

    def rex(self,name,data=None):
        sudo = r"""
            (?x)            # ustawiamy flagę VERBOSE
                            # borzole ALL=(ALL) ALL
                            # lucas ALL=(ALL) NOPASSWD:ALL
            ^\s*            # początek stringu i dowolna ilość białych znaków
            %s                # tu zostanie podstawiona nazwa usera
            \s+ ALL            # co najmniej jeden biały znak i słówko 'ALL'
            \s*=\s*            # znak '=' z otoczeniem
            \(\s* ALL \s*\)    #
            %s                # podstawić \s*NOPASSWD\s*:\s*
            \s* ALL \s*        #
            $                # koniec linii
            """
        if data :
            return sudo % (name,"\s*NOPASSWD\s*:\s*")
        else:
            return sudo % (name,"")

i odwołanie jest tak:

    def get(self,name):
        passwd   = self.rex(name)
        nopasswd   = self.rex(name,True) # nie tyle 'True' co właściwie cokolwiek

ale oczywiście, chciałbym zobaczyć Twoją propozycję.

 

Zaktualizowałem skrypt pod tym samym linkiem, jakbyś miał ochotę to drąż dalej.

Odnośnik do komentarza
Udostępnij na innych stronach

* Dzięki za wskazówki do re. Nie wiedziałem, że można tam jakieś parametry i komentarze wrzucać. Natomiast wytłumacz mi co masz na myśli mówiąc "grupy". Zrobiłem to teraz tak, że przeniosłem do funkcji:

Grupy to fragment wyrażenia regularnego, który umieszczasz w nawiasach i później możesz wyciągnąć jego zawartość. Wcześniej dużo tworzyłeś skryptów bashowych to na pewno wiesz o co chodzi ;)

Przykład:

In [26]: regex = ('^(\w+)\s*=\s*(\d+)$')

In [27]: re.search (regex, 'sdd =427').groups()
Out[27]: ('sdd', '427')

In [28]: re.search (regex, 'sdd =427').group(1)
Out[28]: 'sdd'

 

Groups wyciąga wszystkie grupy, group - jedną konkretną. Można przerobić to wyrażenie regularne z sudog do takiej postaci:

sudo = r"""
            (?x)            # ustawiamy flagę VERBOSE
                            # borzole ALL=(ALL) ALL
                            # lucas ALL=(ALL) NOPASSWD:ALL
            ^\s*            # początek stringu i dowolna ilość białych znaków
            %s                # tu zostanie podstawiona nazwa usera
            \s+ ALL            # co najmniej jeden biały znak i słówko 'ALL'
            \s*=\s*            # znak '=' z otoczeniem
            \(\s* ALL \s*\)    #
            (\s*NOPASSWD\s*:)? # NOPASSWD co najwyżej jeden raz
            \s* ALL \s*        #
            $                # koniec linii
            """

i taki przykładowy kod funkcji do pobierania typu:

def get_type(user, line):
    sudore = re.compile(sudo % user)
    m = sudore.match(line)
    if m:
        if m.group(1) is not None: # czyli zawiera ciąg NOPASSWD
            return 'nopasswd'
        else:
            return 'passwd'
    else:
        return None

 

I później taki kod

    print get_type('borzole', 'borzole ALL=(ALL) ALL')
    print get_type('borzole', 'borzole ALL=(ALL) NOPASSWD:ALL')
    print get_type('borzole', 'borzole ALL=(ALL) NOPASWD:ALL')

zwróci:

passwd
nopasswd
None

 

Dzięki temu jest tylko jedno wyrażenie regularne, które spróbuje dopasować linię, a potem z jego wykorzystaniem można sprawdzić czy była to linia z NOPASSWD czy bez tego :)

Odnośnik do komentarza
Udostępnij na innych stronach

  • 2 weeks later...

Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto

Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.

Zarejestruj nowe konto

Załóż nowe konto. To bardzo proste!

Zarejestruj się

Zaloguj się

Posiadasz już konto? Zaloguj się poniżej.

Zaloguj się
×
×
  • Dodaj nową pozycję...