Cómo ejecutar un script usando cron o launchd para la cuenta de usuario Invitado en El Capitán

1

No pude encontrar una manera de ejecutar un script para la cuenta de Invitado durante el inicio de sesión que se ejecuta cada minuto. Dicen que el uso del cron daemon está obsoleto, por lo que parece que estaré usando launchd con archivos .plist.

Escenario: Tengo un iMac público. Quiero permitir que el público en general use la cuenta de invitado y haga que cierre la sesión cada media hora. Escribí un script de ruby para verificar el tiempo de inicio de sesión y averiguar el tiempo restante. Puedo hacer que muestre una notificación de banner cada 10 minutos usando osascript y luego hacer que cierre la sesión de mi cuenta. El problema es que cuando intento implementarlo para la cuenta de invitado no funciona.

El problema es cuando coloco el archivo .plist dentro de / Library / LaunchDaemons ya que se ejecuta después del inicio de sesión y también se ejecuta como root. Ejecutar como root es importante ya que puedo tener el privilegio de cerrar procesos cuando se agote el tiempo. Lo necesito para ejecutar una vez cada minuto. Este es el archivo plist actual que funciona cuando inicio mi sesión como mi propio nombre de usuario "propietario" pero no como invitado. Usando org.user.plist

Mi archivo .plist original se parecía en algo a esto

<?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>org.user</string> 
    <key>Program</key> 
        <string>/usr/local/bin/notify-custom</string> 
    <key>RunAtLoad</key> 
        <true/> 
</dict> 
</plist>

Actualización 1 (todavía no es una solución) .plist que se ejecuta cada 10 segundos tanto para el invitado como para mi nombre de usuario

<?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>org.user</string>
    <key>ProgramArguments</key>
        <string>/usr/local/bin/notify-custom</string>
    <key>WatchPaths</key>
        <array>        
            <string>/Users/Guest/Library</string>
            <string>/Users/owner/Library</string>
        <array>
    </integer>
</dict>
</plist>

Como prueba para asegurarse de que aparezca el banner de notificación de osascript, tengo este código dentro de / usr / local / bin / notify-custom

#/bin/bash

#Using whoami would have shown me logged in as root under LaunchDaemon .plist
loggedinUser='finger | awk 'NR==3{print $1}''
#I need to manually run terminal and type sudo as guest for nextline to work
sudo -u $loggedinUser /usr/bin/osascript -e 'display notification "Test" with title "Banner Notification"'

La solución está abajo.

    
pregunta Mickey D 11.08.2016 - 03:12

2 respuestas

0

Resuelto. He estado trabajando en esto por un tiempo. Mi solución finalmente hace lo que necesito y es que se inicia durante el inicio de sesión para el usuario Invitado (y, como opción, también la tengo iniciada por mi mismo usuario iMac1 solo para mostrar el tiempo de inicio de sesión). No vi una forma sencilla de colocar el archivo org.user.plist en / Users / Guest / Library / LaunchAgents que, en teoría, lo habría iniciado cuando el Guest inició sesión y la razón por la que renuncié a esa situación es desde esa carpeta no se crea hasta el inicio de sesión.

Lo que hice fue poner mi archivo .plist en / Library / LaunchAgents / que se ejecuta para cada usuario. Eso está bien, ya que mi código distinguirá al usuario invitado y tomará medidas (en este caso, cierre la sesión después de un tiempo establecido).

El archivo .plist final:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
        <string>org.user</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/bin/notify-custom</string>
    </array>
    <key>RunAtLoad</key>
        <true/>
    <key>StartInterval</key>
        <integer>60</integer>
</dict>
</plist>

Note que agregué una clave RunAtLoad ya que sin ella el script se ejecutó pero esperé un minuto para disparar su primer evento. Si, por el contrario, usé la clave WatchPaths como @klanomath señaló en su comentario, entonces el script se ejecutaría cada 10 segundos, ya que su actividad debe estar ocurriendo en esa carpeta con regularidad. Solo quería que funcionara cada 60 segundos por ahora. Podría cambiar ese temporizador más adelante cuando limpie todo el procedimiento con algunos diálogos de advertencia más coloridos escritos en Python.

Aquí está el código ruby dentro de / usr / local / bin / notify-custom que se ejecuta para cada inicio de sesión de usuario:

#!/usr/bin/ruby -w

require 'time'
require 'FileUtils'

loggedinUser='finger|awk 'END{print $1}''.strip
getloginTime='finger|awk 'END{print}'|cut -c49-53'
getnowTime='date|awk 'NR==1{print $4}''[0..4]
loginTime=(Time.parse(getloginTime).to_i)
nowTime=(Time.parse(getnowTime).to_i)
diffSec=(nowTime-loginTime)
diffMin=(diffSec/60)
timeRemain=30-diffMin

#To see some console output while debugging
puts "getloginTime      =#{getloginTime}"
puts "getnowTime        =#{getnowTime}"
puts "loginTime=#{loginTime}"
puts "nowTime  =#{nowTime}"
puts "timeRemain=#{timeRemain}"

if loggedinUser == "Guest"
        open("/Users/#{loggedinUser}/Desktop/30 Minutes Max Use Per Day",'a'){|f| f.puts "With this new iMac, you are limited to a maximum of 1/2 hour use per day"}
        if timeRemain < 0
            '/usr/bin/osascript -e 'tell application "Finder" to set desktop picture to POSIX file "/Library/Desktop Pictures/Earth Horizon.jpg"''
            '/usr/bin/osascript -e 'display notification "SHUTTING DOWN! Now= #{getnowTime}   LoggedInAt=#{getloginTime}   TimeRemain=#{timeRemain}" with title "Guest SHUTTING DOWN" sound name "Glass"''
            '/usr/bin/osascript -e 'tell app "Terminal" to do script "sudo shutdown -h now"''
        else
            '/usr/bin/osascript -e 'display notification "Now= #{getnowTime}     TimeRemain=#{timeRemain}" with title "#{loggedinUser} TIME LOGGED IN= #{getloginTime}" subtitle "User= #{loggedinUser}"''
        end
else
        '/usr/bin/osascript -e 'display notification "Now= #{getnowTime}     TimeRemain=#{timeRemain}" with title "#{loggedinUser} TIME LOGGED IN= #{getloginTime}" subtitle "User= #{loggedinUser}"''
end

Nuevamente, tenga en cuenta que si utiliza los LaunchDaemons en su lugar, se ejecutan bajo la cuenta raíz del sistema mientras que los agentes se ejecutan en la cuenta de los usuarios registrados. Usando la segunda opción, tuve que dar permiso al usuario invitado para ejecutar sudo shutdown como @klanomath se menciona a continuación. Esto se hizo ejecutando el comando: $ sudo visudo y agregando lo siguiente al final del archivo:

Guest ALL=NOPASSWD: /sbin/shutdown

También quería mostrar solo la cuenta de Invitado en la página de inicio de sesión, así que oculté mi cuenta de esa pantalla con este comando:

sudo dscl . create /Users/hiddenuser IsHidden 1

y si cambias de opinión, puedes recuperarlo con:

sudo dscl . create /Users/hiddenuser IsHidden 0

Gracias @klanomath y @ user3439894

    
respondido por el Mickey D 18.08.2016 - 17:51
1

En mi opinión, lo siguiente debería funcionar. ¡Lo hace en mi VM! - lanzado como /Library/LaunchDaemons/org.user.plist:

<?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>org.user</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/touch</string>
        <string>-f</string>
        <string>/Users/Guest/Desktop/test.txt</string>
    </array>
    <key>UserName</key>
    <string>Guest</string>
    <key>GroupName</key>
    <string>_guest</string>
    <key>InitGroups</key>
    <true/>
    <key>WatchPaths</key>
    <array>
        <string>/Users/Guest/Library</string>
    </array>
</dict>
</plist>

Como tarea de ejemplo, uso /usr/bin/touch -f /Users/Guest/Desktop/test.txt .

El truco aquí es que el contenido completo de la carpeta Invitado se elimina después de cerrar sesión. Después de un nuevo Invitado, los registros en todo el contenido se recrean desde cero. Tan pronto como se crea la carpeta / Users / Guest / Library, se inicia la tarea de ejemplo ( touch ... ) debido a la clave WatchPaths.

Dado que la tarea / script / aplicación debe ejecutarse como invitado, no puede usar los agentes de inicio porque la ruta / Users / Guest / Library / LaunchAgents / simplemente no existe.

En su lugar, use un demonio de lanzamiento y ejecútelo como Guest / _guest . ¿Su script ruby / usr / local / bin / notification-custom tiene que ser legible / ejecutable en todo el mundo? por supuesto.

También intenté ejecutar la tarea cada 60 segundos, lo que funciona correctamente pero produce algunos errores después de el cierre de sesión del invitado. Probablemente es mejor implementar todo en el script ruby. Sin embargo, dependiendo de su guión, su kilometraje puede variar.

Si tiene dos tareas diferentes que ejecutar (por ejemplo, mostrar un banner cada 10 minutos con Ruby y un temporizador para forzar el cierre de sesión después de 30 minutos) probablemente sea mejor crear dos demonios de lanzamiento diferentes.

    
respondido por el klanomath 11.08.2016 - 05:40

Lea otras preguntas en las etiquetas