Como iniciar um aplicativo GUI na sessão gráfica de outro usuário?

15

Estou tentando descobrir como iniciar um aplicativo GUI como outro usuário conectado interativamente, na sessão gráfica do usuário.

Por exemplo, digamos que eu tenha dois usuários, foo e bar. Ambos estão conectados, mas o usuário interativo atual é foo. Gostaria de iniciar o Calculator.app como usuário "bar", para que, quando eu mudo rapidamente para o bar, descubro que a janela Calculadora está aberta na sessão do bar.

Aqui está o que eu tentei que não funciona:

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

Isso inicia o Calculator.app como barra, mas a janela é aberta na sessão gráfica do foo.

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

O mesmo efeito.

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

Inicia a Calculadora como foo, não como barra.

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

O mesmo efeito.

Existe alguma maneira de conseguir isso? Estou disposto a oferecer todo tipo de solução possível, incluindo scripts de bash, AppleScript, criação de um programa Core Foundation ou Cocoa e assim por diante. Na minha situação, qualquer programa ou script pode ser executado como qualquer usuário, incluindo o root.

Nota: Estou ciente de que é possível usar o Apple Events remoto, mas não posso usá-lo, pois, na situação em que estou tentando fazer isso, não tenho garantia de que o "Apple Remote Events" será ativado nas preferências de compartilhamento.

Qualquer ajuda seria muito apreciada!

GuyGizmo
fonte
1
Você tentou o opencomando usando SSH?
Matthieu Riegler
Curiosamente, o ícone de encaixe do aplicativo aparece na sessão do foo, mas a janela do aplicativo aparece na barra. Portanto, isso não parece funcionar, mas uma boa sugestão. Infelizmente, não há garantia de que o login seguro esteja ativado na situação em que preciso disso, que é para um instalador.
precisa saber é o seguinte
Acho que uma parte desse quebra-cabeça pode envolver o argumento da linha de comando -psn, que o sistema operacional adiciona em algumas situações. Eu encontrei isso no passado ao trabalhar na portabilidade de algum código para o OS X. Consulte esta pergunta e a documentação da Apple que ele faz referência.
Ashley
a partir das 10h10, finalmente, o abaixo mencionado bsexec funciona perfeitamente
Hofi

Respostas:

7

O que você deseja alcançar é possível, mas difícil. Você precisa iniciar o aplicativo dentro da sessão de usuário apropriada. Por motivos de segurança, é difícil atravessar a divisão da sessão do usuário.

Você precisa de um processo já em execução na sessão do outro usuário para ouvir sua solicitação e iniciar o aplicativo em seu nome.

bsexec do launchd

Felizmente, versões recentes de launchdtêm essa capacidade; embora os engenheiros da Apple não tenham recomendado seu uso geral. Use a bsexecopção no launchctl para direcionar a sessão de usuário apropriada:

 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.

A abordagem recomendada é escrever um tíquete de trabalho iniciado e reiniciar o Mac - ou solicitar ao usuário que efetue logout e logon novamente.

Causa dos problemas

Os problemas decorrem da conexão do aplicativo ao WindowServerprocesso errado . Cada sessão do usuário possui um WindowServer separado; esse processo lida com a interface do usuário. Seus métodos anteriores colocam a propriedade do processo com o usuário certo, mas conectado ao seu próprio processo WindowServer.

Esse problema é mencionado na nota técnica de Daemons and Agents da Apple.

Experiência

Sei disso por experiência pessoal. Para o Power Manager, escrevi pmuser para existir em cada sessão do usuário. pmuserouve nosso daemon e lida com os lançamentos e comandos por usuário. Apesar de nosso daemon ter autoridade root, ainda precisamos de um processo por usuário para trabalhar de maneira confiável nas sessões do usuário.

Graham Miln
fonte
Você poderia fornecer um script simples, como na resposta de TJ, mas que funciona? Ou é muito complexo para uma coisa dessas?
cregox
A solução correta é muito complexa para um script curto. Idealmente, é necessário um processo separado do tipo trampolim na sessão do usuário de destino. Isto é o que tínhamos que fazer com o Power Manager: dssw.co.uk/powermanager O que você espera alcançar?
Graham Miln
Na esperança de alcançar exatamente o que diz o título: inicie um aplicativo GUI na sessão de outro usuário . "Pontos de bônus" se o outro usuário não precisar fazer login ou se puder fazer login programaticamente. Especificamente, quero vários Google Drive. Funciona se eu simplesmente efetuar login manualmente e estiver nos itens de login desse usuário nas Preferências do sistema. Um processo de trampolim não traria os pontos de bônus, mas se esse é o único caminho, qual é precisamente a recomendação dos engenheiros da Apple contra isso? Eu pensei que seria precisamente por fazer scripts de hack tão simples! : P
cregox
@Cawas, faça isso como uma nova pergunta e concentre-se no objetivo de querer vários Google Drives, e não em como isso pode ser alcançado. A mudança de foco ajudará a questão a não ser marcada como duplicada.
Graham Miln
Justo e pronto .
cregox
7

Nenhuma das respostas bsexec acima funciona no El Capitan (10.11), devido ao SIP (System Integration Protection) fechar as portas. O "launchctl asuser" funciona, mas precisa ser executado como root. O comando abaixo funciona no El Capitan (e nos SO mais recentes):

sudo launchctl asuser 501 open /Applications/Calculator.app

Observe que 501 é o ID do usuário para meu outro usuário.

Boris Vidolov
fonte
Este é o meu resultado bruno.medeiros@brunojcm-macbook:~ $ sudo launchctl asuser 501 open /Applications/Firefox.appLSOpenURLsWithRole() failed with error -600 for the file /Applications/Firefox.app
:,
@BrunoJCM tem certeza de que 501 é o código de identificação do usuário com o qual você deseja abri-lo? É um pouco mais claro se o comando é algo como: sudo launchctl asuser $(id -u <user_id_name>) <app>. Dito isto, eu recebo um erro diferente do posix_spawn(): 13: Permission deniedmesmo se eu correr com o mesmo ID de usuário que eu estou logado com (e possui a sessão) parasudo launchctl asuser $(id -u mtylutki) /Applications/Calculator.app
Marcus
2

Como finalmente a 10.10 fornece uma implementação "launchctl bsexec" correta, você pode usar:

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

homem diz

Isso executa o comando fornecido em um contexto de execução o mais semelhante possível ao PID de destino.

Portanto, como parâmetro PID, você pode usar o pid do processo de janela de login apropriado . O UID é o ID do usuário que possui a janela de login e o GID é o grupo principal.

Isso funciona bem para qualquer comando e, é claro, para tarefas launchd (fe launchchagents), também como finalmente:

/bin/launchctl bsexec 104 chroot -u 501 -g 20 / /bin/launchctl load -S Aqua /Library/LaunchAgents/com.youragent.plist 2>&1
Hofi
fonte
Não tenho certeza se isso é verdade para outras pessoas, mas agora recebo um task_for_pid(): 0x5erro para isso, onde verifiquei se o PID está correto.
Marcus
1

Você pode usar o Finder como host para as permissões corretas osascript -e "tell application \"Finder\" to open (\"${app}\" as POSIX file as alias)". Dessa forma, ele será iniciado por qualquer contexto da GUI que lançou o Finder.

Atishay Jain
fonte
0

Isso funciona via 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

mas se tentar pelo Terminal.app, ele abrirá o TextEdit na GUI do usuário atual.

Se não tiver certeza de que sshestá ativado, talvez você possa habilitá-lo temporariamente

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

e desativá-lo novamente depois, se necessário?

Caso contrário, estou perplexo.

Testado em 10.9.

TJ Luoma
fonte
Ele abre o aplicativo como você diz, mas o abre na sessão atual do usuário, e não na sessão do outro usuário, conforme solicitado.
cregox
-1

Simples

sudo su name_of_user

depois execute os comandos normalmente.

PandB Software
fonte
Os comandos seriam executados bar, mas ainda seriam executados na foosessão gráfica da sessão.
John N
Desculpe, sim, estou confuso com a pergunta, não é executado em uma sessão gráfica.
PandB Software