Hay dos tipos de archivos en macOS que gestionan proceso del sistema: son los launchAgents y los daemons, gestionados por launchd, un sistema unificado de gestión de servicios open source diseñado para iniciar, parar y gestionar daemons, aplicaciones, procesos y scripts. Launchd fue diseñado y escrito por Dave Zarzycki para Apple, y fue introducido por vez primera en Mac OS X 10.4 Tiger además de estar disponible para otros sistemas operativos bajo la licencia Apache. Pero volvamos a los lue aunchAgents y los daemons.

Los launchAgents son dependientes de un usuario. Así, es necesario que macOS inicie una cuenta de usuario para que los launchAgents de ese usuario se pongan en marcha e inicien los procesos a los que hacen referencia. Estos procesos se ejecutan en segundo plano y son capaces de interactuar con el interfaz del sistema, cosa que los daemons no pueden hacer. A los daemons no se les permite conectar con el servidor de ventanas1 y no dependen de un usuario sino que se arrancan con el propio sistema.

Ambos dos, como hemos visto antes, están gestionados por launchd que obliga a ejecutar esos procesos bajo unos parámetros que están almacenados en unos archivos plist en tres ubicaciones del disco duro concretas: una de ellas específica del sistema, una segunda para todos los usuarios del ordenador y una tercera2 por cada usuario que tiene una cuenta en el Mac.

Así nos vamos a encontrar con dos carpetas por cada uno de estos niveles, almacenadas en la correspondiente Biblioteca: éstas carpeta LaunchAgents y LaunchDaemons y están ubicadas en:

  • Para el sistema en /System/Library/
  • Para todos los usuarios en /Library/
  • Para cada usuario en ~/Library/

Por defecto, ninguna aplicación debería poder acceder o instalar ni daemons ni launchAgents en la Librería del Sistema como medida de seguridad. De hecho, los permisos para ambas carpetas para lectura y escritura solo pertenecen al sistema, mientras que wheel y el resto de los usuarios pueden leerlas.

Los archivos plist, por otra parte, no son más que archivos de configuración con una estructura XML concreta, destinada a pasar una serie de parámetros o instrucciones a realizar por aplicaciones. Al ser archivos de texto, es sencillo poder escribir nuestros propios servicios o modificar los existentes3. Lo más importante que debes saber al respecto de estos archivos plist es que hacen referencia a las aplicaciones que van a ejecutar, lo que es muy interesante sobre todo para hacer un seguimiento forense de seguridad.

Cuando inspeccionamos un plist para ambos tipos de carpeta, podemos encontrar un <string> que suele hacer referencia a la aplicación4 que se arrancará al inicio o de una forma puntual  se ejecutará como un proceso más que podemos controlar en el Monitor de Actividad.

Muchas aplicaciones que instalamos crean este tipo de archivos plist, especialmente aquellas que gestionan o sobrepasan servicios del sistema, como por ejemplo drivers para hardware específico5 y cuando desinstalamos éstas aplicaciones, generalmente estos archivos plist se suelen quedar atrás. Adicionalmente, el malware suele utilizar este tipo de archivos para lanzar launchAgents y que las aplicaciones dependientes del malware se ejecuten a plazos regulares para recopilar información y enviarla a los servidores que la recogen o para recibir órdenes de los mismos. Es por esto porque Apple limita el acceso al sistema y a sus partes desde hace algunas versiones de macOS con rootless, para evitar que se instalen este tipo de archivos de forma automática, aunque es factible que puedan instalarse como archivos de usuario, que no del sistema, haciendo su asquerosa labor en segundo plano.

Es, por esto, una buena idea mantener controlados los plist que se instalan en las correspondientes carpetas y adicionalmente, controlar a las aplicaciones a las que referencian en busca no solo de malware, sino de información para la completa desinstalación de un driver o de una aplicación. Especialmente críticas son las propias carpetas de usuario y la librería general para todos los usuarios, que serán posiblemente el destino para esos archivos plist.

También es el caso de que te puedes encontrar en los ítems de arranque con un daemon o aplicación que se ejecuta cada vez que arrancas tu usuario: la retiras utilizando el interfaz pero al volver a arrancar el ordenador o a iniciar sesión vuelve a estar allí, y aparentemente no hay forma de eliminarla: el proceso es buscar el archivo plist correspondiente6, recuperar la ruta para luego poder eliminarla junto con el archivo plist.

Hay diferentes maneras de mantener controladas estas carpetas, pero para una gestión inmediata de las mismas, es factible utilizar las Acciones de Carpeta para que generen un aviso cuando se añada un nuevo plist a a cada una de ellas. La forma de realizar esto es muy sencilla; navega por la estructura de archivos hasta las correspondientes carpetas de la lista:

  • /Library/LaunchAgents
  • /Library/LaunchDaemons
  • /System/Library/LaunchAgents
  • /System/Library/LaunchDaemons
  • ~/Library/LaunchAgents

Invoca el menú contextual para acceder a los Servicios y selecciona la opción Configuración de Acciones de Carpeta. Añade una acción del tipo “add-new ítem alert.scpt” y así, cuando se añada algún tipo de archivo a esas carpetas (deberás repetir esta acción para cada una de ellas) se te notificará con un cuadro de diálogo en el que se te indica en qué carpeta se ha añadido y si quieres acceder a la misma para verificar el contenido de la carpeta e inspeccionar el archivo.

Construyendo daemons

En ocasiones trabajamos con aplicaciones que son tan críticas que deben estar siempre en marcha en ordenadores no atendidos, pero puede ocurrir que las podemos cerrar por error, o se cierran inesperadamente y hay que volverlas a arrancar manualmente lo que es un problema porque a lo mejor estamos lejos del Mac. Vamos a solucionar este problema. Ten en cuenta que el sistema de daemons está pensado para aplicaciones que se cargan antes de iniciar la sesión de usuario para aplicaciones del sistema que se ejecutan en segundo plano y nosotros vamos a forzar un poco su uso.

La idea es que cuando la aplicación se cierre, sea por la circunstancia que sea, se vuelva a abrir automáticamente y se mantenga activa. Así que para empezar abre TextEdit y crea un documento en modo texto puro (usa ⌘⇧T para saltar entre el modo de texto enriquecido y texto puro) y añade al documento este texto, ya que vamos a crear un daemon para esta tarea. launchd se encargará de lanzar la aplicación7 si por cualquier motivo esta cerrada, aunque hay algunos puntos específicos que trataremos después.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>user.launchkeep.stickies</string>
  <key>KeepAlive</key>
  <true/>
  <key>Program</key>
  <string>/Applications/Stickies.app/Contents/MacOS/Stickies</string>
</dict>
</plist>

Vamos a detallar como se personaliza este .plist que luego activaremos.

Para empezar está el primer storing que hace referencia a user.launchkeep.stickies que realmente es el nombre que le daremos al archivo cuando lo guardemos. En el ejemplo hace referencia a la aplicación Notas adhesivas, pero, por ejemplo, si quisiéramos hacer un daemon para Mail, entonces lo renombraríamos como user.launchkeep.Mail.

El siguiente paso es definir la ruta a la aplicación que se mantendrá siempre abierta. La referencia es a la aplicación ejecutable que está dentro del paquete de la aplicación, no a la app que nosotros visualizamos en el interfaz de OS X. Si te fijas en la ruta del ejemplo es fácil definir la estructura para otra aplicación ya que se mantiene igual para todas las aplicaciones así que para Mail, por ejemplo sería /Applications/Mail.app/Contents/MacOS/Mail.

Ahora ya tienes personalizado el .plist, que guardaremos con el nombre que hemos definido en string. En este caso, el nombre de archivo sería user.launchkeep.Mail.plist.

Este sistema va bien para ciertos tipos de aplicaciones, y Mail es una de ellas, pero no para otros tipos de aplicaciones que necesitan actualizarse con frecuencia, como aplicaciones que has descargado desde la App Store. Lo que ocurre es que cuando tienes que actualizar esa aplicación desde la Mac App Store por ejemplo, es necesario que la aplicación esté cerrada para que pueda actualizarse, pero… ¡ups!, launchd la mantiene viva a través del daemon con lo cual no puedes actualizarla. Lo mismo ocurre al intentar reiniciar el ordenador: launchd reabre la aplicación a través del daemon y se interrumpe el proceso de apagado y por lo tanto, el reinicio. Así que hay que tocar alguna cosa más.

En la mayoría de los casos, una mejor solución es usar KeepAlive junto con SuccessfulExit.

KeepAlive y SuccessfulExit

La idea es crear un plist que permita mantener una aplicación en ejecución todo el tiempo a menos que salga de forma limpia8. Utiliza KeepAlive pero añade una etiqueta al XML llamada SuccessfulExit. Si una aplicación se cierra “con éxito9 entonces la aplicación no se reiniciará automáticamente. Sin embargo, si la aplicación se cuelga10, se reiniciará automáticamente. Aquí está el código relevante del código de lanzamiento:

<key>KeepAlive</key>
 <dict>
 <key>SuccessfulExit</key>
 <false/>
 </dict>

Esto es útil si tienes una aplicación que ocasionalmente se bloquea, especialmente si es una aplicación que se ejecuta en segundo plano o en la barra de menús donde es posible que no te des cuenta inmediatamente.

KeepAlive y NetworkState

Otra opción es KeepAlive y NetworkState, que indica a la aplicación que siga funcionando mientras tengamos una conexión de red.

Aquí está la parte de la lista que trata específicamente de la pregunta que se hará el archivo plist “¿hay conexión a la red?”:

<key>KeepAlive</key>
 <dicto>
 <key>NetworkState</key>
 <true/>
 </dict>

Hay que tener en cuenta dos casos dentro de esta opción:

  • El ejecutable considerará que la “red” está “conectada” si tiene una dirección IP. Sin embargo, es posible que tu red local pueda estar en funcionamiento, pero tu conexión a Internet no funcione. Por ejemplo, en este momento mi ISP está fuera de línea, pero estoy conectado a mi red Wi-Fi local, por lo que en lo que respecta a launchd, la “red” está activa. Recuerda que “La red está arriba” no significa necesariamente “Internet está arriba/accesible”.
  • También es importante recordar que la reapertura de la aplicación no tendrá lugar sólo porque la conexión de red se interrumpa. La única vez que KeepAlive se usaría es si la aplicación se cierra y es vuelta a abrir por launchd, En ese momento, se leerá el plist por parte del sistema y responderá a la pregunta “¿Está lista la red?” y si la respuesta es afirmativa, abrirá la aplicación. Si la respuesta es no, no abrirá la aplicación.

Ahora que he explicado un par de ejemplos, hay que echar un vistazo a la documentación de Apple porque es fascinante. Por ejemplo, en la documentación, hay un ejemplo de creación de una tarea que se ejecuta cada 300 segundos11 y aún más interesante, cómo pasar comandos de Terminal como argumentos de programa. La documentación de Apple, aunque técnica, es relativamente fácil de comprender y abre muchas puertas muy interesantes a la personalización del comportamiento del Mac.

¿Dónde guardar este archivo?

La ruta para guardar este archivo es:

/Library/LaunchAgents

Para todos los usuarios, o en

~/Library/LaunchAgents

solo para nuestro usuario.

¿Por qué en esta ubicación y no en LauchDaemons? Porque los daemons guardados en esta primera ubicación se activan antes de iniciar la sesión de usuario y a nosotros nos interesa que se ejecute después de iniciar la sesión de usuario, así que esa es la ubicación correcta.

Ahora vamos a cargar el daemon, así que abre el Terminal y usa el comando:

launchctl load ~/Library/LaunchAgents/user.launchkeep.Mail.plist

Ahora, si se cierra la aplicación, ya sea manualmente o por un problema, inmediatamente se volverá a abrir. Ten en cuenta que esto va a impedir el reinicio o el apagado del Mac porque cuando se mande una señal para el cierre de todas las aplicaciones, esta se volverá a abrir interrumpiendo el reinicio o el apagado así que para desactivar este comportamiento usaremos previamente:

launchctl remove user.launchkeep.Mail

Este tipo de acciones se utilizan para ordenadores que están permanentemente encendidos y sin atención, de forma que nos aseguramos que ciertas aplicaciones estén siempre activas.

Si buscamos utilizar este tipo de uso en un ordenador de usuario tendremos que automatizar la carga del daemon  en el inicio de sesión de usuario usando una acción de Automator, por ejemplo, y luego crear una miniaplicación también en Automator que desactive el daemon y luego apague o reinicie el Mac.

Notas

  1. por lo que no tienen interfaz
  2. que pueden ser varias
  3. siempre sabiendo lo que tenemos entre manos
  4. que no tiene por qué ser una aplicación “de escritorio” tal como la conocemos
  5. ratones, teclados, servicios de red, aplicaciones que monitorizan el comportamiento de macOS o esperan órdenes del mismo, etc.)
  6. cuyo nombre debería identificar fácilmente el daemon o aplicación al que hace referencia el ítem de arranque dentro del archivo de texto
  7. Revisa cada 10 segundos si una aplicación está activa
  8. es decir, que el usuario haya tomado la decisión de cerrarla
  9. técnicamente, con un código de salida = 0
  10. el código de salida no es igual a 0
  11. 5minutos
In this article


Join the Conversation