usuario sesion por permisos mac iniciar entrar desde defecto dar crear contraseña como cambiar administrador c++ root elevated-privileges

c++ - sesion - ¿Cómo ganar programáticamente privilegios de root?



entrar como administrador en terminal mac (7)

Estoy escribiendo un software (en C ++, para Linux / Mac OSX) que se ejecuta como un usuario sin privilegios, pero necesita privilegios de administrador en algún momento (para crear un nuevo dispositivo virtual).

Ejecutar este programa como root no es una opción (principalmente para problemas de seguridad) y necesito conocer la identidad (uid) del usuario "real".

¿Hay alguna manera de imitar el comportamiento del comando "sudo" (solicitar la contraseña del usuario) para obtener privilegios de root temporalmente y realizar la tarea en particular? Si es así, ¿qué funciones usaría?

Muchas gracias por su ayuda !


En OS X, puede usar la función AuthorizationExecuteWithPrivileges . La página sobre Tareas de los Servicios de Autorización contiene una discusión elaborada de esta (y relacionada) funciones.

Aquí hay un poco de código C ++ para ejecutar un programa con privilegios de administrador:

static bool execute(const std::string &program, const std::vector<std::string> &arguments) { AuthorizationRef ref; if (AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &ref) != errAuthorizationSuccess) { return false; } AuthorizationItem item = { kAuthorizationRightExecute, 0, 0, 0 }; AuthorizationRights rights = { 1, &item }; const AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights; if (AuthorizationCopyRights(ref, &rights, kAuthorizationEmptyEnvironment, flags, 0) != errAuthorizationSuccess) { AuthorizationFree(ref, kAuthorizationFlagDestroyRights); return false; } std::vector<char*> args; for (std::vector<std::string>::const_iterator it = arguments.begin(); it != arguments.end(); ++it) { args.push_back(it->c_str()); } args.push_back(0); OSStatus status = AuthorizationExecuteWithPrivileges(ref, program.c_str(), kAuthorizationFlagDefaults, &args[0], 0); AuthorizationFree(ref, kAuthorizationFlagDestroyRights); return status == errAuthorizationSuccess; }


Es posible que desee echar un vistazo a estas API:

setuid, seteuid, setgid, setegid, ...

Están definidos en el encabezado <unistd.h> en sistemas Linux (no sé mucho sobre MAC, pero también debería tener un encabezado similar).

Un problema que puedo ver es que el proceso debe tener suficientes privilegios para cambiar sus ID de usuario / grupo. De lo contrario, las llamadas a las funciones anteriores darán como resultado un error con errorno establecido en EPERM .

Le sugiero que ejecute su programa como el usuario root , cambie la identificación de usuario efectiva (usando seteuid ) a un usuario desfavorecido desde el principio. Luego, cada vez que necesite elevar los permisos, seteuid una contraseña y luego use seteuid nuevamente para volver al usuario root .


No puede obtener privilegios de root, debe comenzar con ellos y reducir sus privilegios según sea necesario. La forma habitual de hacerlo es instalar el programa con el conjunto de bits "setuid": esto ejecuta el programa con el ID de usuario efectivo del propietario del archivo. Si ejecuta ls -l en sudo , verá que está instalado de esa manera:

-rwsr-xr-x 2 root root 123504 2010-02-25 18:22 /usr/bin/sudo

Mientras su programa se ejecuta con privilegios de administrador, puede llamar a la llamada del sistema setuid(2) para cambiar su userid efectivo a algún usuario no privilegiado. Creo (pero no lo he intentado) que puede instalar su programa como root con el bit de setuid activado, reducir inmediatamente el privilegio y restaurar el privilegio según sea necesario (sin embargo, es posible que una vez que disminuya su privilegio no lo haga). ser capaz de restaurarlo).

Una mejor solución es dividir la parte de su programa que necesita ejecutarse como raíz, e instalarlo con el bit de setuid activado. Por supuesto, deberá tomar precauciones razonables para que no pueda invocarse fuera de su programa maestro.


Normalmente esto se hace haciendo que su raíz suid binaria.

Una forma de gestionar esto para que los ataques contra su programa sean difíciles es minimizar el código que se ejecuta como root así:

int privileged_server(int argc, char **argv); int unprivileged_client(int argc, char **argv, int comlink); int main(int argc, char **argv) { int sockets[2]; pid_t child; socketpair(AF_INET, SOCK_STREAM, 0); /* or is it AF_UNIX? */ child = fork(); if (child < 0) { perror("fork"); exit(3); } elseif (child == 0) { close(sockets[0]); dup2(sockets[1], 0); close(sockets[1]); dup2(0, 1); dup2(0, 2); /* or not */ _exit(privileged_server(argc, argv)); } else { close(sockets[1]); int rtn; setuid(getuid()); rtn = unprivileged_client(argc, argv, sockets[0]); wait(child); return rtn; } }

Ahora el código sin privilegios se comunica con el código privilegiado a través del comunicador fd (que es un socket conectado). El código privilegiado correspondiente utiliza stdin / stdout como su extremo del comlink.

El código privilegiado necesita verificar la seguridad de cada operación que necesita hacer, pero como este código es pequeño en comparación con el código sin privilegios, esto debería ser razonablemente fácil.


Puede intentar ejecutar el comando para crear el dispositivo virtual (incluido sudo) a través de un shell de fondo. Pida la contraseña de los usuarios en un cuadro de diálogo propio y canalícela al shell cuando sudo lo solicite. Existen otras soluciones, como el uso de gksu, pero no está garantizado que estén disponibles en todas las máquinas.

No ejecuta todo el programa como root, sino solo la parte pequeña que necesita root. Debe generar un proceso separado para eso y sudo puede ser de ayuda para usted.


Si necesita privilegios de administrador cada vez, lo mejor es iniciar su programa como root y soltarlos (en un subproceso) con setuid y setgid . Eso es lo que hace Apache cuando necesita vincularse al puerto restringido 80.

Si obtener derechos de root es la excepción en lugar de la regla y el programa se ejecuta de forma interactiva, otra forma es escribir un programa add_interface y ejecutar

sudo add_interface args

y deje que sudo maneje la autenticación por usted. En lugar de sudo, puede usar una interfaz gráfica como gksu, gksudo, kdesu o kdesudo. No trataría de implementar la contraseña segura de entrada yo mismo; puede ser un problema difícil y probablemente dejará huecos de seguridad y problemas de funcionalidad (¿Admite lectores de huellas digitales?).

Otra alternativa es polkit , anteriormente llamado PolicyKit.


Respuesta original

Puede considerar el interruptor setuid en el ejecutable mismo. Wikipedia tiene un article que incluso muestra la diferencia entre geteuid() y getuid() bastante efectiva, siendo el primero para descubrir a quién "emulas" y el último para quién "eres". El proceso sudo, por ejemplo, geteuid debe devolver 0 (raíz) y obtener la ID de su usuario, sin embargo, sus subprocesos realmente se ejecutan como root (puede verificar esto con sudo id -u -r ).

No creo que haya una forma de obtener fácilmente acceso a la raíz mediante programación, después de todo, aplicando el principio de privilegio mínimo, ¿por qué lo necesitarías? La práctica común es ejecutar solo partes limitadas de código con privilegios elevados. Muchos daemons, etc., también se configuran en sistemas modernos para que se ejecuten como sus propios usuarios con la mayoría de los privilegios que necesitan. Es solo para operaciones muy específicas (montaje, etc.) que los privilegios de root son realmente necesarios.

Actualización 2013

Mi respuesta original se encuentra (aunque mi versión 2013 podría hacer un mejor trabajo que la de 2010), pero si está diseñando una aplicación que requiere acceso raíz, es posible que desee considerar exactamente qué tipo de acceso raíz se necesita y considerar el uso de Capacidades POSIX (página man) . Estos son diferentes a la seguridad basada en la capacidad tal como se implementa en L4 et al. Las capacidades de POSIX permiten que su aplicación tenga un subconjunto de poderes de raíz. Por ejemplo, CAP_SYS_MODULE le permitirá insertar módulos de kernel, pero no le dará ningún otro poder de raíz. Esto está en uso en las distribuciones, por ejemplo, Fedora tiene una función para eliminar por completo binarios setuid con acceso raíz indiscriminado.

Esto es importante porque como programador, ¡su código es obviamente perfecto! Pero, las bibliotecas de las que dependes (suspira, ¡si tan solo las hubieras escrito!) Podrían tener vulnerabilidades en ellas. Mediante el uso de capacidades, puede limitar el uso de este exploit y salvarse a sí mismo y a su empresa del escrutinio relacionado con la seguridad. Esto hace que todos sean más felices.