2016-05-19 9 views
0

Ich verwende Perl, um eine Zeichenfolge ($ password) an eine zu interpretierende Systemzeile zu übergeben. Es scheint jedoch nicht korrekt interpretiert zu werden, denn wenn ich das Sparse Bundle anschließe, wird die Authentifizierung fehlgeschlagen. Als Anmerkung funktioniert alles nach der Pfeife gut.Perl Systemaufruf interpretiert Variable nicht korrekt

$password = chomp($password); 

### Create the bash system call to create the sparse bundle with the password 
my $cmd = `echo $password | hdiutil create -size 200g -type SPARSEBUNDLE -encryption -stdinpass -volname \"Encrypted Storage for Matt\" -fs \"Case-sensitive Journaled HFS+\" -verbose ~/Desktop/SparseBundle`; 

Einige Beispielausgabe:

SLC1087-Matt:backups matt$ ./create_sparsebundle.pl 
DIDiskImageCreatorProbe: interface 1, score  1000, CSparseBundleDiskImage 
DIDiskImageCreatorProbe: interface 2, score -1000, CSparseDiskImage 
DIDiskImageCreatorProbe: interface 3, score -1000, CRawDiskImage 
DIDiskImageCreatorProbe: interface 7, score -1000, CWOUDIFDiskImage 
DIDiskImageCreatorProbe: interface 9, score -1000, CCFPlugInDiskImage 
DIDiskImageCreateWithCFURL: CSparseBundleDiskImage 
CBSDBackingStore::createProbe directory, not a valid image file. 
DIBackingStoreCreatorProbe: interface 0, score -1000, CBSDBackingStore 
DIBackingStoreCreatorProbe: interface 1, score  1000, CBundleBackingStore 
DIBackingStoreCreatorProbe: interface 2, score  0, CRAMBackingStore 
DIBackingStoreCreatorProbe: interface 3, score  100, CCarbonBackingStore 
DIBackingStoreCreatorProbe: interface 5, score  -100, CCURLBackingStore 
DIBackingStoreCreateWithCFURL: CBundleBackingStore 
DIFileEncodingCreatorProbe: interface 2, score  1000, CEncryptedEncoding 
DIFileEncodingCreateWithCFURL: CEncryptedEncoding 
DIFileEncodingCreatorProbe: interface 2, score -1000, CEncryptedEncoding 
DIBackingStoreCreatorProbe: interface 0, score  100, CBSDBackingStore 
DIBackingStoreCreatorProbe: interface 1, score -1000, CBundleBackingStore 
DIBackingStoreCreatorProbe: interface 2, score  0, CRAMBackingStore 
DIBackingStoreCreatorProbe: interface 3, score  100, CCarbonBackingStore 
DIBackingStoreCreatorProbe: interface 5, score  -100, CCURLBackingStore 
DIBackingStoreCreateWithCFURL: CBSDBackingStore 
DIBackingStoreCreateWithCFURL: creator returned 0 
DIFileEncodingCreateWithCFURL: creator returned 0 
DIBackingStoreCreateWithCFURL: creator returned 0 
DIDiskImageCreateWithCFURL: creator returned 0 
DI_kextWaitQuiet: about to call IOServiceWaitQuiet... 
DI_kextWaitQuiet: IOServiceWaitQuiet took 0.000003 seconds 
2016-05-18 20:59:09.627 diskimages-helper[68122:1796245] *** -[NSMachPort handlePortMessage:]: dropping incoming DO message because the connection is invalid 
hdiutil: create: returning 0 
SLC1087-Matt:backups matt$ hdiutil attach ~/Desktop/SparseBundle.sparsebundle 
Enter password to access "SparseBundle.sparsebundle": 
hdiutil: attach failed - Authentication error 

Alles scheint gut zu funktionieren, aber das Passwort ist offensichtlich falsch.

+0

Was passiert, wenn Sie nur das Passwort ausdrucken? 'system (" echo $ passwort ")'? – Robert

+0

Haben Sie verifiziert, dass dies tatsächlich in bash funktioniert? - d. h. ohne Perl. Einige Apps, auf die ich gestoßen bin, tun etwas, das mit Passwörtern funky ist und nichts mit diesem Format aufnimmt. Also öffne bash und führe einfach 'echo TheRealPassword | hdiutil create -size 200g -type SPARSEBUNDLE -cryption -stdinpass -volname \ "Verschlüsselter Speicher für Matt \" -fs \ "Groß- und Kleinschreibung Journaled HFS + \" -verbose ~/Desktop/SparseBundle' – GregHNZ

+0

@GregHNZ, Warum? Das ist nicht das, was er mit Perl an die Shell weitergibt. – ikegami

Antwort

1

Das Dienstprogramm hdiutil erfordert ein Null-terminiertes Kennwort.

Das heißt, "mypass" ist nicht gut genug. Es muss "mypass\0" angezeigt werden, da das Kennwort lustige Zeichen wie eingebettete Zeilenumbrüche enthalten darf.

Also, was es ist zu sehen, "mypass\n" statt "mypass\0"

Sie könnte dies versuchen, wie es unter Linux arbeiten:

echo -n -e "mypass\x00" | hdiutil ... 

Aber ... AFAICT, die OSX Version von Echo doesn Haben Sie -e, so müssen Sie vielleicht experimentieren.

Wenn alles andere fehlschlägt, ersetzen die echo mit:

echo "mypass" | perl -e '$_ = <STDIN>; chomp ; print $_,"\x00"' 

Es einfachere Möglichkeiten sein kann, dies zu tun/auszudrücken. Sie könnten ein zweites Perl-Skript (nennen wir es passme) erstellen:

#!/usr/bin/perl 
print $ARGV[0],"\x00"; 

dann die echo mit passme ersetzen. I würde doppelte Anführungszeichen um das Argument setzen.


UPDATE:

Ich bin ziemlich sicher, weil der stdinpass, dass der printf auf den Befehl geleitet werden muss. Ich weiß nicht, ob ich genau richtig liege.

echo und printf werden an den Befehl weitergeleitet. Aber es gibt noch mehr Möglichkeiten, dies zu tun, die ich Ihnen empfehlen werde.

Wie andere bereits erwähnt haben, könnte der sauberste Weg die Verwendung von IPC::Run3 sein. Es ist One-Stop-Shopping.

Es kann jedoch nicht standardmäßig auf Ihrem System [oder anderen OSX-Systemen] installiert werden. Weiß nicht - YMMV. Möglicherweise müssen Sie dies untersuchen. Also, Sie müssen es möglicherweise selbst installieren [von CPAN, ich nehme an (?)]

Wenn Ihr Skript ist nur für Ihren eigenen Gebrauch, kann das oben in Ordnung sein.Wenn Sie jedoch ein Skript erstellen, das von anderen verwendet wird, kann es auf einem System landen, auf dem Run3 nicht ausgeführt wird, und sysadm installiert es nicht.

Also, Sie müssen Benutzerfreundlichkeit gegen Ubiquität ausgleichen. Das wird Ihre Wahl sein.

Run3 setzt bis beidestdin und stdout auf dem hdiutil Befehl, das, was Sie brauchen, weil Sie ihm das Passwort und erfassen seinen Ausgang geben wollen.

Wenn Sie nur eine benötigen, können Sie die Funktion open perl im "pipe" -Modus verwenden. Einzelheiten finden Sie unter man perlipc. Es ist ziemlich einfach zu benutzen. Ich habe ein Beispiel dafür - siehe unten.

Oder Sie könnten "rollen Sie Ihre eigenen" Äquivalent von dem, was run3 tut, indem Sie perl intrinsischen pipe Aufruf verwenden. Sie würden zwei Rohre benötigen. Es ist ein bisschen Arbeit, also vielleicht etwas für die Zukunft.

Das größte Problem mit dem echo, printf, [und passme] Ansätze ist [wie andere darauf hingewiesen,], das ist, weil sie argv verwenden Sie das Passwort zu erhalten, sie „bluten“, um es anderen Prozessen [kurz].

Wir hätten also gerne eine sichere Methode [z. Run3 wäre]. Deshalb nimmt hdiutil ein Passwort auf stdin anstelle eines Befehlszeilenarguments.


(1) Eigentlich kann das Passwort in eine temporäre Datei dump die einfachste Art und Weise:

use Fcntl; 

my $fd; 
my $tmp = "/tmp/pwfile"; 

my $password = "whatever"; 

# NOTE: by using sysopen and setting the 600 permission atomically, we avoid a 
# race condition that may allow another user to open this file 
unlink($tmp); 
sysopen($fd,$tmp,O_WRONLY | O_CREAT | O_EXCL,0600) or 
    die("unable to open '$tmp' -- $!\n"); 
syswrite($fd,$password . "\x00"); 
close($fd) 

my $cmd = `hdiutil ... < $tmp`; 
unlink($tmp); 

(2) Wenn Sie das Passwort nicht schreiben wollen eine temporäre Datei, egal wie kurz sie sich noch herumspielt, gibt es noch einen anderen Weg. Es ähnelt dem passme Script-Ansatz oben, , außer. Es übergibt das Passwort als Umgebungsvariable. Dies verhindert, dass das Passwort über Befehlszeilenargumente angezeigt wird.

Hier ist die passme Variante:

perl -e 'print($ENV{"PASSME"},"\x00")' 

Dann Ihr Skript wird:

my $password = "whatever"; 

$ENV{"PASSME"} = $password; 
my $cmd = `passme | hdiutil ...`; 
delete($ENV{"PASSME"}); 

(3

#!/usr/bin/perl 
print($ENV{"PASSME"},"\x00"); 

Dies auch mit einem Inline getan werden könnte,) Noch ein anderer Weg ist die Verwendung [der oben genannten] Verwendung von Perl open im Pipe-Modus. Stellen Sie es als eine Eingangsleitung auf hdiutil ein und leiten Sie die Ausgabe in eine temporäre Datei um, die Sie nach der Ausführung des Befehls zurücklesen.

my $fdout; 
my $fdin; 
my $tmp = "/tmp/results"; 
my $buf; 

my $password = "whatever"; 

open($fdout,"| hdiutil ... > $tmp") || 
    die("unable to open hdiutil pope -- $!\n"); 
print($fdout $password,"\x00"); 
close($fdout); 

open($fdin,"<$tmp") || 
    die("unable to open '$tmp' -- $!\n"); 
while ($buf = <$fdin>) { 
    chomp($buf); 
    # do whatever ... 
} 
close($fdin); 
+0

Es kann auch ohne die drei externen Prozesse und ohne das Passwort für alle auf dem Rechner mit 'usage IPC :: Run3 qw (run3); run3 (['hdutil', ...], \ "$ password \ 0", \ my $ stdout); ' – ikegami

+0

Nein, was es sieht ist' "1 \ n" 'weil er' $ password' zugewiesen hat der Rückgabewert von 'chomp'. –

+0

Für die Portabilität: Verwenden Sie 'printf' anstelle von' echo -e' – oals

6

Lesen Sie über das, was die chomp zurückkehrt. Ihr Code schreibt mindestens die Variable $password mit einer Ganzzahl, vermutlich 0 oder 1, um. Das ist mir aufgefallen.


Die chomp gibt die Gesamtzahl der von allen seinen Argumenten entfernt Zeichen.

+0

Ich habe 'chomp' entfernt und bekomme immer noch Probleme. Ich werde aktualisieren, was ich oben zeige. –

Verwandte Themen