在我正在创建的应用程序中,我需要以root身份运行以下命令(如果用户真的想要提示用户,他们将被要求卸载他们的驱动器):
/bin/rm -rf /
#Yes, really
问题是仅仅使用替换用户Do(sudo
)不起作用,因为用户需要输入密码到不可用的stdin。我想在用户点击Preferences.app中的锁时向用户显示相同的窗口,这样(希望密码更短):
screenshot http://www.quickpwn.com/wp-content/uploads/2009/08/snow-leopard-enter-password.png
任何人都可以帮我吗?感谢。
答案 0 :(得分:9)
查看STPrivilegedTask,一个围绕AuthorizationExecuteWithPrivileges()的Objective-C包装类,带有类似NSTask的接口。
答案 1 :(得分:6)
这是在Mac OS X上正确完成的最难的任务之一。
指导如何执行此操作的指南是Authorization Services Programming Guide。有多种可能性,像往常一样,最安全的是最难实施的。
我开始编写一个使用launchd守护程序(最安全的方法)的工具code is available on google code。因此,如果您愿意,可以复制该代码。
答案 2 :(得分:4)
我想我现在可以回答这个问题了,感谢一些谷歌搜索和this SO question中的一个很好的发现。这是非常轻微的hacky,但恕我直言是一个令人满意的解决方案。
我写了这个通用实现,它应该达到你想要的效果:
- (BOOL) runProcessAsAdministrator:(NSString*)scriptPath
withArguments:(NSArray *)arguments
output:(NSString **)output
errorDescription:(NSString **)errorDescription {
NSString * allArgs = [arguments componentsJoinedByString:@" "];
NSString * fullScript = [NSString stringWithFormat:@"%@ %@", scriptPath, allArgs];
NSDictionary *errorInfo = [NSDictionary new];
NSString *script = [NSString stringWithFormat:@"do shell script \"%@\" with administrator privileges", fullScript];
NSAppleScript *appleScript = [[NSAppleScript new] initWithSource:script];
NSAppleEventDescriptor * eventResult = [appleScript executeAndReturnError:&errorInfo];
// Check errorInfo
if (! eventResult)
{
// Describe common errors
*errorDescription = nil;
if ([errorInfo valueForKey:NSAppleScriptErrorNumber])
{
NSNumber * errorNumber = (NSNumber *)[errorInfo valueForKey:NSAppleScriptErrorNumber];
if ([errorNumber intValue] == -128)
*errorDescription = @"The administrator password is required to do this.";
}
// Set error message from provided message
if (*errorDescription == nil)
{
if ([errorInfo valueForKey:NSAppleScriptErrorMessage])
*errorDescription = (NSString *)[errorInfo valueForKey:NSAppleScriptErrorMessage];
}
return NO;
}
else
{
// Set output to the AppleScript's output
*output = [eventResult stringValue];
return YES;
}
}
用法示例:
NSString * output = nil;
NSString * processErrorDescription = nil;
BOOL success = [self runProcessAsAdministrator:@"/usr/bin/id"
withArguments:[NSArray arrayWithObjects:@"-un", nil]
output:&output
errorDescription:&processErrorDescription
asAdministrator:YES];
if (!success) // Process failed to run
{
// ...look at errorDescription
}
else
{
// ...process output
}
答案 3 :(得分:-1)
好吧,所以我在搜索如何正确执行此操作时遇到了这个...我知道它可能是完成任务的最不安全的方法,但可能是最简单的,我没有在任何地方看到过这个答案。我为我创建的应用程序想出了这个用于我自己的目的,并作为user142019描述的任务类型的临时授权例程。我不认为Apple会批准。这只是一个片段,不包含UI输入表单或任何捕获标准输出的方法,但是还有很多其他资源可以提供这些文件。
创建一个名为“script.sh”的空白文件,并将其添加到项目的支持文件中。
将其添加到头文件中:
// set this from IBOutlets or encrypted file
@property (strong, nonatomic) NSString * password;
@property (strong, nonatomic) NSString * command;
实现:
@synthesize password;
@synthesize command;
(IBAction)buttonExecute:(id)sender {
NSString *scriptPath = [[NSBundle mainBundle]pathForResource:@"script" ofType:@"sh"];
NSString *scriptText = [[NSString alloc]initWithFormat:@"#! usr/sh/echo\n%@ | sudo -S %@",password,command];
[scriptText writeToFile:scriptPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
NSTask * task = [[NSTask alloc]init];
[task setLaunchPath:@"/bin/sh"];
NSArray * args = [NSArray arrayWithObjects:scriptPath, nil];
[task setArguments:args];
[task launch];
NSString * blank = @" ";
[blank writeToFile:scriptPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
}
最后一步是因为您的捆绑包中没有明文管理员密码。我建议确保以某种方式对方法之外的任何内容进行模糊处理。
答案 4 :(得分:-2)
在我的一个案例中,这是不正确的:
> 问题是简单地使用替换用户Do(sudo)不起作用,因为用户需要输入密码 >
我只是编辑/ etc / sudoers以允许所需的用户启动任何.sh脚本而不提示输入密码。因此,您将执行一个shell脚本,其中包含一个命令行,如sudo sed [/] /etc/printers.conf,以修改printers.conf文件,而/ etc / sudoers文件将包含此行
myLocalUser ALL =(ALL)NOPASSWD:ALL
但我当然正在寻找一个更好的解决方案,它正确地提示用户键入管理员密码以允许脚本或NSTask执行。感谢使用AppleScript调用来提示和执行任务/ shell脚本的代码。