我使用Perl将字符串($ password)传递给要解释的系统行。它似乎没有被正确解释,因为当我去附加稀疏捆绑时,它说认证失败了。作为一个注释,管道后的一切工作正常。
$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`;
一些示例输出:
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
一切似乎都运行良好,但密码显然是错误的。
答案 0 :(得分:6)
了解chomp
返回的内容。您的代码至少会使用可能为$password
或0
的整数重写1
变量。这引起了我的注意。
chomp
返回从其所有参数中删除的字符总数。
答案 1 :(得分:1)
hdiutil
实用程序需要以空值终止的密码。
也就是说,"mypass"
还不够好。它需要查看"mypass\0"
,因为密码允许包含有趣的字符,如嵌入的换行符。
所以,它看到的是"mypass\n"
而不是"mypass\0"
你可以试试这个,因为它可以在linux下运行:
echo -n -e "mypass\x00" | hdiutil ...
但...... AFAICT,回声的OSX版本没有-e
,因此您可能需要进行试验。
如果所有其他方法都失败了,请将echo
替换为:
echo "mypass" | perl -e '$_ = <STDIN>; chomp ; print $_,"\x00"'
可能有更简单的方法来表达/表达这一点。您可以创建第二个perl脚本(称之为passme
):
#!/usr/bin/perl
print $ARGV[0],"\x00";
然后将echo
替换为passme
。我将在参数周围加上双引号。
<强>更新强>
我非常确定,因为stdpass必须将printf传送到命令。我不知道我是否完全正确。
echo
和printf
将通过管道输入命令。但是,还有更多方法可以做到这一点,我会推荐这些方法。
正如其他人所说,最干净的方法可能是使用IPC::Run3
。这是一站式购物。
但是,默认情况下可能不会在您的系统[或其他OSX系统]上安装它。说不上 - 因人而异。您可能需要对此进行调查。所以,你可能必须自己安装它[来自CPAN,我推测(?)]
如果您的脚本仅供您自己使用,则上述情况可能没问题。但是,如果您要创建供其他人使用的脚本,它可能最终会出现在没有Run3的系统上,并且sysadm不会安装它。
所以,你必须平衡易用性和无处不在。那将是你的选择。
Run3在stdin
命令上设置 stdout
和hdiutil
,这是您需要的,因为您要为其提供密码和捕获其输出。
如果你只需要一个,你可以在&#34; pipe&#34;中使用perl的open
功能。模式。有关详细信息,请参阅man perlipc
。它使用起来非常简单。我有一个例子 - 见下文。
或者,你可以自己推动自己的&#34;使用perl的内在run3
调用等同于pipe
所做的事情。您需要两个管道。这是一项工作,所以也许是未来的事情。
echo
,printf
,[和passme
]方法的最大问题是[正如其他人所指出的],是因为他们使用argv来获取密码,他们& #34;流血&#34;它简要地说到其他过程。
所以,我们希望有一种安全的方法[例如Run3将是]。这就是为什么hdiutil
在stdin
而不是命令行参数上获取密码的原因。
(1)实际上,最简单的方法可能是将密码转储到临时文件:
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)如果您不想将密码写入临时文件,无论它有多么短暂,都有另一种方式。它类似于上面的passme
脚本方法,除了它将密码作为环境变量传递下去。这样可以避免通过命令行参数泄露密码。
这是passme
变体:
#!/usr/bin/perl
print($ENV{"PASSME"},"\x00");
这也可以通过内联来完成:
perl -e 'print($ENV{"PASSME"},"\x00")'
然后,您的脚本变为:
my $password = "whatever";
$ENV{"PASSME"} = $password;
my $cmd = `passme | hdiutil ...`;
delete($ENV{"PASSME"});
(3)另一种方法是在管道模式下使用perl的open
[上述]。将其设置为hdiutil
的输入管道,并将输出转移到临时文件,该文件在执行命令后读回。
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);