2010-10-29 11 views
9

En una aplicación que estoy haciendo lo que necesito para ejecutar el siguiente comando como root (usuario se le pedirá dos por tres si realmente quieren, y se le pedirá que desmontar sus unidades) utilizando NSTask:¿Cómo se usa NSTask como raíz?

/bin/rm -rf/
#Yes, really 

El problema es que simplemente el uso del usuario sustituto no (sudo) no funciona, ya que el usuario necesita ingresar la contraseña para el código no disponible. Prefiero gustaría mostrar al usuario la misma ventana que te gustaría ver al hacer clic en el candado en Preferences.app, como este (esperemos que con una contraseña más corta):

screenshot http://www.quickpwn.com/wp-content/uploads/2009/08/snow-leopard-enter-password.png


Puede Alguien me ayude con esto? Gracias.

Respuesta

6

Esa es una de las tareas más difíciles de hacer correctamente en Mac OS X.

La guía de documentación de cómo hacer esto es la Authorization Services Programming Guide. Hay múltiples posibilidades, como de costumbre, la más segura es la más difícil de implementar.

He empezado a escribir una herramienta que utiliza un demonio launchd (la forma más segura), la code is available on google code. Entonces, si lo desea, puede copiar ese código.

8

Consulte STPrivilegedTask, una clase de contenedor Objective-C alrededor de AuthorizationExecuteWithPrivileges() con una interfaz similar a NSTask.

+1

Gracias: solución simple, de trabajo y simplemente elegante! – MeIr

+0

Si quiero ejecutar alguna tarea como root, ¿me pedirá la contraseña del usuario? Intenté esto y funcioné pero el usuario tiene que ingresar su contraseña. –

4

creo que ahora puedo responder a esto, gracias a algunas google y una agradable encontrar en this SO question. Es muy ligeramente hacky, pero en mi humilde opinión es una solución satisfactoria.

Escribí esta aplicación genérica que debe lograr lo que quiere: ejemplo

- (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; 
    } 
} 

Uso:

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 
    } 
+0

Es posible que desee ser un poco cuidadoso con lo que alimenta en esta función, sin embargo. Si la ruta de su script contiene espacios o caracteres de comillas (por ejemplo, porque la aplicación se colocó en una carpeta con ese nombre), o necesita pasar las rutas de archivos citadas, esto le dará un error de sintaxis de AppleScript en el mejor de los casos. En el peor de los casos, alguien puede inyectar código en su aplicación, p. Ej.nombrando un archivo 'rm -rf /" con privilegios de administrador --' (que ejecutará rm -rf con privilegios de administrador y luego comentará el resto de la línea con su código legítimo. – uliwitness

-2

En uno de mis casos esto no es correcto:

> El problema es que el simple hecho de utilizar el usuario sustituto do (sudo) no funciona ya que el usuario necesita ingresar la contraseña >

simplemente/etc/sudoers editado para permitir que el usuario deseado para iniciar cualquier script .sh sin solicitar la contraseña. Entonces, ejecutaría un script de shell que contiene una línea de comando como sudo sed [...] /etc/printers.conf para modificar el archivo impresoras.conf, y el archivo/etc/sudoers contendría esta línea

myLocalUser ALL = (ALL) NOPASSWD: ALL

Pero, por supuesto, estoy buscando una solución mejor que indique correctamente al usuario que escriba una contraseña de administrador para permitir la ejecución de la secuencia de comandos o NSTask. Gracias por el código que utiliza una llamada AppleScript para solicitar y ejecutar el script tarea/shell.

+1

Este es un riesgo de seguridad horrible, tener un usuario que puede ejecutar cualquier código de sudo sin ingresar una contraseña. – uliwitness

-1

Bien, así que me encontré con esto mientras buscaba cómo hacer esto correctamente ... Sé que es probablemente el método menos seguro para realizar la tarea, pero probablemente sea el más fácil y no he visto esta respuesta en ningún lado.Se me ocurrió esto para que las aplicaciones que creo se ejecuten para mis propios fines y como una rutina de autorización temporal para el tipo de tarea que describe el usuario142019. No creo que Apple lo apruebe. Esto es solo un fragmento y no incluye un formulario de entrada UI ni ninguna forma de capturar stdout, pero hay muchos otros recursos que pueden proporcionar esas piezas.

Cree un archivo en blanco llamado "script.sh" y agréguelo a los archivos auxiliares de su proyecto.

Añadir esta a la cabecera del archivo:

// set this from IBOutlets or encrypted file
@property (strong, nonatomic) NSString * password;
@property (strong, nonatomic) NSString * command;

aplicación:

@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];
}

El último paso es sólo por lo que no tiene una contraseña de administrador sin cifrar sentado en su paquete. Recomiendo asegurarse de que algo más allá del método se ofusque de alguna manera.

+0

Esto es horrible y no funcionará en muchos casos: en primer lugar, la mayoría de los usuarios no tiene permiso para cambiar el paquete de la aplicación actual, por lo que obtendrá un error al intentar escribir scriptText en el paquete de aplicaciones. En segundo lugar, incluso si funcionó para todos los usuarios, podría encontrarse en condiciones de carrera si dos usuarios en una máquina están utilizando la misma aplicación, o la aplicación se inicia desde un servidor compartido. En tercer lugar, USTED ESTÁ ESCRIBIENDO ¡UNA CONTRASEÑA DE USUARIO EN DISCO NO CIFRADO! Por lo menos, debe intentar conectar el texto del script al shell en lugar de guardarlo en el disco. – uliwitness