Seite 1 von 2

string to command

Verfasst: Donnerstag 8. Juni 2006, 21:08
von murph
hi!
wie kann man einen string zu einem python-command amchen?
mir schwebt vor, usersettings in einer datei anzulegen,
die jeder auslesen können soll und auch modifizieren, falls eine fehldiagnose vorliegt.
nun habe ich das problem, dass ich nicht immer fragen will

Code: Alles auswählen

if "string" = string:
    command = string
gibt es dafür eine lösung?

Verfasst: Donnerstag 8. Juni 2006, 21:29
von helmut
Hallo, schau hier mal.
Gruss, Helmut

Re: string to command

Verfasst: Freitag 9. Juni 2006, 09:28
von Joghurt
murph hat geschrieben:wie kann man einen string zu einem python-command amchen?
Mit eval. Denk aber daran, dass ein böser Bub auch sowas wie "import os;os.unlink('Wichtige Datei')" übergeben kann.

Verfasst: Freitag 9. Juni 2006, 09:59
von Mad-Marty
ich würde nicht eval benutzen.

hasattr() und getattr() erscheinen mir in 99 % der Fälle als sinnvoller.

Verfasst: Freitag 9. Juni 2006, 10:36
von Joghurt
Mad-Marty hat geschrieben:hasattr() und getattr() erscheinen mir in 99 % der Fälle als sinnvoller.
Er "will einen String zu einem Pythoncommand machen"

Verfasst: Freitag 9. Juni 2006, 12:10
von Mad-Marty
Joghurt hat geschrieben:
Mad-Marty hat geschrieben:hasattr() und getattr() erscheinen mir in 99 % der Fälle als sinnvoller.
Er "will einen String zu einem Pythoncommand machen"
Das stimmt. Aber gerade bei konfigurationsdateien, wo man wahrscheinlich den optionswert auf ein objekt übertragen wird könnte man die *attr nutzen.

Zumindest lese ich das aus den ersten paar zeilen.

Ist ja auch egal, aber eval(cfg) ist so ziemlich das grösste sicherheitsloch was es gibt ;-)

Und manche sachen gehen dann auch nur mit exec.

Verfasst: Freitag 9. Juni 2006, 12:48
von Rebecca
Mad-Marty hat geschrieben:Das stimmt. Aber gerade bei konfigurationsdateien, wo man wahrscheinlich den optionswert auf ein objekt übertragen wird könnte man die *attr nutzen.
s
Zumindest lese ich das aus den ersten paar zeilen.

Ist ja auch egal, aber eval(cfg) ist so ziemlich das grösste sicherheitsloch was es gibt ;-)
Kommt drauf an, wann man eval benutzt. Wenn ein User in seine Konfigurationsdatei Befehle eintraegt, die dann, wenn er das zugehoerige Programm als eben dieser User startet, mit eval ausgewertet werden -- wo ist das Problem? Er kann dann mittels Konfigurationsdatei das machen, was er auch in einer Shell oder einem Dateimanager anrichten kann.

Hindert mich ja auch keiner dran, in meiner .bashrc rm -r wichtiger_ordner einzutragen, oder in meiner .emacs (delete-direcory wichtiger_ordner), oder in meiner .fvwm2rc Exec exec rm -r wichtiger_ordner...

Problematisch wird's erst, wenn ein Programm mit priviligierten Rechten Eingaben von normalen Usern/Userprogrammen oder von der "Aussenwelt" entgegennimmt, die dann mit eval ausgewertet werden.... Oder wenn schlimme Befehle ausgewertet werden an Stellen, wo eigentlich nur eingeschraenkte, harmlose Eingaben gemacht werden und der User nicht mir rechnet.

Verfasst: Freitag 9. Juni 2006, 13:33
von murph
inwiefern seht ihr eval denn als sicherheitslücke?
und wie funktioniert '*args'?
Das steht in meinem Pythonbuch nicht drin.

Verfasst: Freitag 9. Juni 2006, 13:52
von Rebecca
Stell dir mal vor, Lisa und Sebastian spielen ein Spiel uebers Netz. Ihre beiden Programme muessen miteinander kommunizieren, z.B. werden Strings ueber Sockets ausgetauscht. Nun ist Lisas Programm ganz boese und schickt einen gemeinen String an Sebastians Program ("import os;os.unlink('Wichtige Datei')"), um mal Joghurts Beispiel aufzugreifen.

Wenn jetzt Sebastians Programm ein eval drauf anwendet, weil es weniger boese Sachen erwartet, wird diese wichtige Datei auf Sebastians Computer geloescht, was der wahrscheinlich nicht will. Und das wichtige: Lisa selbst oder Lisas Programm haetten das gar nicht gedurft, weil sie nicht Rechte auf Sebastians Rechner haben, um Sebastians wichtige Datei zu loeschen, aber Lisas Programm hat quasi Sebastians eigenes Programm mit dessen eigenen Rechten missbraucht.

Aber wie ich schon sagte, kommt halt auf den Zusammenhang an.

Verfasst: Freitag 9. Juni 2006, 14:14
von murph
ich bin grade dabei, was für sqlite zu machen.
ich weiß, dass es da schon was gibt, wollte mich aber mal in den klassen austoben und dachte mir, dass man da mal was schreiben könnte.
aber ich will dem nutzer kein modul vorschreiben, deshalb soll geprüft werden, was für ein sqlite-modul installiert ist um das dann zu importieren.
weil ich aber nicht immer wieder alles testen will, soll das in eine textdatei.
+nun habe ich das problem, dass bei import keine variablen akzeptiert werden.
die *args habe ich im forum gefunden...

Verfasst: Freitag 9. Juni 2006, 15:20
von murph
ich habe nun damit ein problem.
exec funktioniert nur eingeschränkt...hier der code(ausschnitssweise):

Code: Alles auswählen

def Importer():
    getter = UserSettings()
    module = getter.get_module()
    exec("import %s as sqlite_module") % module
[....]
class main:
    def greeting(self):
        self.conn_var = raw_input("Please enter the Path to the SQLite-Database: \n")
        Importer()
        self.conn = sqlite_module.connect(self.conn_var)
        self.cur = self.conn.cursor
    def cmdgetter():
        cmd = raw_input("§§§")
        self.cur.execute(cmd)
        self.cur.commit()      
        try:
            TELL(self.cur.fetchall())
        except:
            TELL("Things were commited!")
        main().cmdgetter()
nun meint der aber, das 'sqlite_module' nicht belegt wäre, obwohl ich mit exec dieses getan habe. was tun?

Verfasst: Freitag 9. Juni 2006, 19:32
von murph
ich werde konkreter:

Code: Alles auswählen

#!/usr/bin/env python
exec("import sqlite as sqlite_module")
conn = sqlite_module.connect("test.db")
cur = conn.cursor()
cur.execute("SELECT * from t1")
print cur.fetchall()
Das Funktioniert!!!!!
aber das oben geschickte beispiel nicht, er denkt, das sqlite_module sei ein attribut, soll aber die importierte datenbank ansprechen (import sth as sth)

Verfasst: Freitag 9. Juni 2006, 20:01
von gerold
murph hat geschrieben:ich werde konkreter:

Code: Alles auswählen

#!/usr/bin/env python
exec("import sqlite as sqlite_module")
Hi murph!

Das importieren von vorher nicht bekannten Modulen funktioniert mit __import__(): http://docs.python.org/lib/built-in-funcs.html#l2h-6

mfg
Gerold
:-)

Re: string to command

Verfasst: Freitag 9. Juni 2006, 20:07
von gerold
murph hat geschrieben:mir schwebt vor, usersettings in einer datei anzulegen,
die jeder auslesen können soll und auch modifizieren,
Hi murph!

Das ist eine gute Idee. Dafür gibt es auch schon ein Modul, das ideal dafür geeignet ist, Einstellungen auszulagern -- den ConfigParser: http://docs.python.org/lib/module-ConfigParser.html

Andere Formate empfehle ich erst dann, wenn es wichtig ist, auch verschachtelte Einstellungen in eine Config-Datei zu schreiben.

mfg
Gerold
:-)

Re: string to command

Verfasst: Freitag 9. Juni 2006, 20:22
von gerold
Joghurt hat geschrieben:Mit eval. Denk aber daran, dass ein böser Bub auch sowas wie "import os;os.unlink('Wichtige Datei')" übergeben kann.
Hi Joghurt!

eval ist eher abgespeckt. Man kann damit einen Python-Ausdruck (1+1 oder 'hallo'*2) ausführen lassen, aber kein Programm. Es lassen sich nicht alle Kommandos ausführen. Ein Import ist nicht möglich. Allerdings kann man meistens davon ausgehen, dass zumindest os, os.path und sys bereits importiert sind. Dann sind solche Konstrukte wie "os.remove(sys.executable)" sehrwohl möglich. Bitte nicht ausprobieren. :lol:

mfg
Gerold
:-)

Verfasst: Freitag 9. Juni 2006, 20:41
von murph
aber wie übergebe ich dem __import__ ein 'as'?
ich will ja später nur noch eine variable nutzen, damit man diesen code mit allen sqlite-wrappern nutzen kann, die die standardfunktionen haben.

Verfasst: Freitag 9. Juni 2006, 20:55
von gerold
murph hat geschrieben:aber wie übergebe ich dem __import__ ein 'as'?
Hi murph!

Code: Alles auswählen

ver = __import__("sys").version
print ver
mfg
Gerold
:-)

Verfasst: Freitag 9. Juni 2006, 21:07
von gerold

Code: Alles auswählen

sqlite_module = __import__("sqlite")
conn = sqlite_module.connect(":memory:")
...

Verfasst: Freitag 9. Juni 2006, 22:17
von murph
das will er nicht!
gleiche fehlermeldung!
Traceback (most recent call last):
File "./sqlite-manager.py", line 103, in ?
starter()
File "./sqlite-manager.py", line 85, in starter
executer.greeting()
File "./sqlite-manager.py", line 91, in greeting
self.conn = sqlite_module.connect(self.conn_var)
NameError: global name 'sqlite_module' is not defined
der code (nicht, dass ich was übersehen habe trotz gründlichen suchens)

Code: Alles auswählen

def Importer():
    getter = UserSettings()
    module = getter.get_module()
    sqlite_module = __import__(module)
class main:
    def greeting(self):
        Importer()
        self.conn_var = raw_input("Please enter the Path to the SQLite-Database: \n")
        self.conn = sqlite_module.connect(self.conn_var)
        self.cur = self.conn.cursor
also meiner ansicht nach sollte das klappen, die variablen sind problemlos vergeben. ich verstehe nicht,warum, wenn gerolds ansatz doch klappen sollte, das nicht funktioniert!

Verfasst: Freitag 9. Juni 2006, 22:46
von gerold
murph hat geschrieben:NameError: global name 'sqlite_module' is not defined
Hi murph!

Zwei Sachen:
1. Verwende keine Bindestriche in Modulnamen, da ein Bindestrich für Python ein "Minus" darstellt.
2. Variablen, die du in einer Funktion erstellst -- egal wie -- sind in deren Gültigkeit auf den lokalen Namensraum dieser Funktion beschränkt. Entweder du setzt vor der Verwendung die Variable mit "global" in den globalen Namensraum oder du importierst nicht in einer Funktion.

mfg
Gerold
:-)

PS: Klassennamen sollten mit einem Großbuchstaben beginnen und Funktions-/Methodennamen sollten mit einem Kleinbuchstaben beginnen.

Code: Alles auswählen

class HalloWelt:
    def say_yes(self):
        print "Yes!"
h = HalloWelt() # Sofort als Instanzierung einer Klasse erkennbar
h.say_yes()
Dadurch lassen sich Fehler vermeiden, da man sofort weiß, ob man gerade eben eine Klasse instanziert oder eine Funktion ausführt.
Meines Erachtens, wäre "import_modules()" ein guter Name für die Funktion "Importer()", da er ausdrückt was getan wird. "Importer()" sieht aus wie eine Klasse und hat auch den Namen eines Objektes. Dass keine Klasseninstanz zurück gegeben wird -- verwirrt. :?