¿Cómo iniciar una aplicación GUI en la sesión gráfica de otro usuario?

15

Estoy tratando de descubrir cómo iniciar una aplicación GUI como otro usuario que ha iniciado sesión de forma interactiva, en la sesión gráfica de ese usuario.

Por ejemplo, digamos que tengo dos usuarios, foo y bar. Ambos están conectados, pero el usuario interactivo actual es foo. Me gustaría iniciar Calculator.app como usuario "barra", para que cuando el usuario cambie rápidamente a barra, encuentre que la ventana Calculadora está abierta en la sesión de barra.

Esto es lo que he probado que no funciona:

sudo -u bar /Applications/Calculator.app/Contents/MacOS/Calculator

Esto inicia Calculator.app como barra, pero la ventana se abre en la sesión gráfica de foo.

sudo -u bar osascript -e "tell application \"Calculator\" to activate"

Mismo efecto.

sudo -u bar open "/Applications/Calculator.app"

Inicia Calculator como foo, no bar.

launchctl asuser [uid of bar] [any of the above commands]

Mismo efecto.

¿Hay alguna forma de lograr esto? Estoy dispuesto a entretener todo tipo de soluciones posibles, incluidas las secuencias de comandos bash, AppleScript, escribir un programa Core Foundation o Cocoa, etc. En mi situación, cualquier programa o script podría ejecutarse como cualquier usuario, incluida la raíz.

Nota: Soy consciente de que es posible usar eventos remotos de Apple, pero no puedo usarlo ya que en la situación que estoy tratando de hacer esto no tengo garantía de que "Eventos remotos de Apple" esté habilitado en Compartir preferencias.

Cualquier ayuda sería muy apreciada!

GuyGizmo
fuente
1
¿Intentaste el opencomando usando SSH?
Matthieu Riegler
Por extraño que parezca, el icono del dock de la aplicación aparece en la sesión de foo, pero la ventana de la aplicación aparece en la barra. Eso no parece funcionar, pero es una buena sugerencia. Desafortunadamente, no hay garantía de que el inicio de sesión seguro esté habilitado en la situación en que lo necesito, que es para un instalador.
GuyGizmo
Creo que una pieza de este rompecabezas podría involucrar el argumento de la línea de comandos -psn, que el sistema operativo agrega en algunas situaciones. Me he encontrado con esto en el pasado cuando trabajaba en portar algún código a OS X. Vea esta pregunta y la documentación de Apple a la que hace referencia.
Ashley
a partir de las 10.10, por fin, el bsexec mencionado a continuación funciona perfectamente
Hofi

Respuestas:

7

Lo que quieres lograr es posible pero difícil. Debe iniciar la aplicación dentro de la sesión de usuario adecuada. Por razones de seguridad, cruzar la división de la sesión del usuario es difícil.

Necesita un proceso que ya se esté ejecutando en la sesión del otro usuario para escuchar su solicitud e iniciar la aplicación en su nombre.

bsexec de launchd

Afortunadamente, las versiones recientes de launchdtienen esta capacidad; aunque los ingenieros de Apple no han recomendado su uso general. Use la bsexecopción en launchctl para apuntar a la sesión de usuario adecuada:

 bslist [PID | ..] [-j]
          This prints out Mach bootstrap services and their respective states. While the namespace
          appears flat, it is in fact hierarchical, thus allowing for certain services to be only avail-
          able to a subset of processes. The three states a service can be in are active ("A"), inactive
          ("I") and on-demand ("D").

          If [PID] is specified, print the Mach bootstrap services available to that PID. If [..] is
          specified, print the Mach bootstrap services available in the parent of the current bootstrap.
          Note that in Mac OS X v10.6, the per-user Mach bootstrap namespace is flat, so you will only
          see a different set of services in a per-user bootstrap if you are in an explicitly-created
          bootstrap subset.

          If [-j] is specified, each service name will be followed by the name of the job which regis-
          tered it.

 bsexec PID command [args]
          This executes the given command in the same Mach bootstrap namespace hierachy as the given
          PID.

 bstree [-j]
          This prints a hierarchical view of the entire Mach bootstrap tree. If [-j] is specified, each
          service name will be followed by the name of the job which registered it.  Requires root priv-
          ileges.

El enfoque recomendado es escribir un ticket de trabajo lanzado y reiniciar la Mac, o pedirle al usuario que cierre sesión y vuelva a iniciarla.

Causa de los problemas

Los problemas provienen de que la aplicación está conectada al WindowServerproceso incorrecto . Cada sesión de usuario tiene un WindowServer separado; Este proceso maneja la interfaz de usuario. Sus métodos anteriores colocan la propiedad del proceso con el usuario correcto pero conectado a su propio proceso WindowServer.

Este problema se menciona en la nota técnica de Daemons and Agents de Apple.

Experiencia

Sé esto por experiencia personal. Para Power Manager, escribí pmuser para que exista dentro de cada sesión de usuario. pmuserescucha nuestro demonio y maneja los lanzamientos y comandos por usuario. A pesar de que nuestro demonio tiene autoridad de root, todavía necesitábamos un proceso por usuario para trabajar de manera confiable dentro de las sesiones de usuario.

Graham Miln
fuente
¿Podría proporcionar un script simple, como en la respuesta de TJ allí, pero que funcione? ¿O es demasiado complejo para tal cosa?
cregox
La solución correcta es demasiado compleja para un script corto. Idealmente, se requiere un proceso separado similar a un trampolín en la sesión de usuario objetivo. Esto es lo que teníamos que hacer para Power Manager: dssw.co.uk/powermanager ¿Qué espera lograr?
Graham Miln
Con la esperanza de lograr exactamente lo que dice el título: inicie una aplicación GUI en la sesión de otro usuario . "Puntos de bonificación" si el otro usuario no necesita iniciar sesión o si puede iniciar sesión mediante programación. En concreto, quiero múltiples unidades de Google. Funciona si simplemente inicio sesión manualmente y está debajo de los Elementos de inicio de sesión de ese usuario en las Preferencias del sistema. Un proceso de trampolín no traería los puntos de bonificación, pero si esa es la única forma, ¿cuál es precisamente la recomendación de los ingenieros de Apple en contra? ¡Pensé que sería precisamente por hacer scripts de pirateo tan simples! : P
cregox
@Cawas, haga esto como una nueva pregunta y concéntrese en el objetivo de querer varias unidades de Google, en lugar de cómo se podría lograr. El cambio de enfoque ayudará a que la pregunta no se marque como un duplicado.
Graham Miln
Bastante justo y listo .
cregox
7

Ninguna de las respuestas de bsexec anteriores funciona en El Capitan (10.11), debido a que la Protección de integración del sistema (SIP) cierra los puertos. "launchctl asuser" funciona, pero debe ejecutarse como root. El siguiente comando funciona en El Capitan (y los sistemas operativos más recientes):

sudo launchctl asuser 501 open /Applications/Calculator.app

Tenga en cuenta que 501 es el ID de usuario para mi otro usuario.

Boris Vidolov
fuente
Este es mi resultado:, bruno.medeiros@brunojcm-macbook:~ $ sudo launchctl asuser 501 open /Applications/Firefox.appy obtuveLSOpenURLsWithRole() failed with error -600 for the file /Applications/Firefox.app
BrunoJCM
@BrunoJCM ¿está seguro de que 501 es el código de identificación de usuario para el usuario con el que desea abrirlo? Es un poco más claro si el comando es algo así como: sudo launchctl asuser $(id -u <user_id_name>) <app>. Dicho esto, me sale un error diferente de posix_spawn(): 13: Permission deniedincluso si me encuentro con el mismo ID de usuario que estoy conectado con (y es propietaria de la sesión) parasudo launchctl asuser $(id -u mtylutki) /Applications/Calculator.app
Marcus
2

Como finalmente 10.10 proporciona una implementación correcta "launchctl bsexec" que puede usar:

sudo /bin/launchctl bsexec PID chroot -u UID -g GID / open /Applications/TextWrangler.app

el hombre dice

Esto ejecuta el comando dado en un contexto de ejecución lo más similar posible al PID de destino.

Entonces, como parámetro PID, puede usar el pid del proceso de ventana de inicio de sesión apropiado . El UID es la identificación de usuario del usuario que posee esa ventana de inicio de sesión y el GID es su grupo primario.

Esto funciona bien para cualquier comando y, por supuesto, para los trabajos de lanzamiento (por ejemplo, lanzadores) también, por fin, como:

/bin/launchctl bsexec 104 chroot -u 501 -g 20 / /bin/launchctl load -S Aqua /Library/LaunchAgents/com.youragent.plist 2>&1
Hofi
fuente
No estoy seguro si esto es cierto para otros, pero task_for_pid(): 0x5ahora recibo un error para esto, donde he verificado que el PID es correcto.
Marcus
1

Puede usar el Finder como el host para los permisos correctos osascript -e "tell application \"Finder\" to open (\"${app}\" as POSIX file as alias)". De esa manera, se lanzará a través del contexto GUI lanzado Finder.

Atishay Jain
fuente
0

Esto funciona a través de ssh:

#!/bin/bash

PID=$(ps auxwww | egrep "^bar" |\
fgrep /System/Library/CoreServices/loginwindow.app/Contents/MacOS/loginwindow |\
awk '{print $2}')

sudo launchctl bsexec "$PID" open -a TextEdit

pero si lo prueba a través de Terminal.app, abre TextEdit en la GUI del usuario actual.

Si no está seguro de que sshesté habilitado, quizás pueda habilitarlo temporalmente

sudo launchctl load -w /System/Library/LaunchDaemons/ssh.plist

y deshabilitarlo nuevamente si es necesario?

De lo contrario estoy perplejo.

Probado en 10.9.

TJ Luoma
fuente
Abre la aplicación como usted dice, pero la abre en la sesión del usuario actual y no en la sesión del otro usuario como se le solicitó.
cregox
-1

Sencillo

sudo su name_of_user

luego ejecute los comandos normalmente.

Software PandB
fuente
Los comandos se ejecutarían bar, pero aún se ejecutarían en foola sesión gráfica.
John N
Lo siento, sí, estoy confundido acerca de la pregunta, no se ejecuta en una sesión gráfica foo.
PandB Software