Jak uruchomić aplikację GUI w sesji graficznej innego użytkownika?

15

Próbuję wymyślić, jak uruchomić aplikację GUI jako inny użytkownik zalogowany interaktywnie, w sesji graficznej tego użytkownika.

Powiedzmy, że mam dwóch użytkowników, foo i bar. Oba są zalogowane, ale obecny użytkownik interaktywny to foo. Chciałbym uruchomić Calculator.app jako „pasek” użytkownika, aby po szybkim przełączeniu użytkownika na pasek znajdowałem okno kalkulatora w sesji paska.

Oto, co próbowałem, to nie działa:

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

To uruchamia Calculator.app jako pasek, ale okno otwiera się w sesji graficznej foo.

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

Ten sam efekt.

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

Uruchamia kalkulator jako foo, a nie pasek.

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

Ten sam efekt.

Czy jest jakiś sposób na osiągnięcie tego? Jestem gotów zająć się wszelkimi możliwymi rozwiązaniami, w tym skryptami bash, AppleScript, pisaniem programu Core Foundation lub Cocoa i tak dalej. W mojej sytuacji każdy program lub skrypt może być uruchamiany jak każdy użytkownik, w tym root.

Uwaga: Zdaję sobie sprawę, że jest to możliwe przy użyciu zdalnych zdarzeń Apple, ale nie mogę tego użyć, ponieważ w tej sytuacji próbuję to zrobić, nie mam gwarancji, że „Zdalne zdarzenia Apple” zostaną włączone w preferencjach udostępniania.

Każda pomoc byłaby bardzo mile widziana!

GuyGizmo
źródło
1
Czy próbowałeś użyć openpolecenia SSH?
Matthieu Riegler,
Co dziwne, ikona dokowania aplikacji pojawia się w sesji foo, ale okno aplikacji pojawia się w pasku. Więc to nie działa, ale dobra sugestia. Niestety, nie ma gwarancji, że bezpieczne logowanie jest włączone w sytuacji, gdy potrzebuję tego, co jest dla instalatora.
GuyGizmo
Myślę, że jedna część tej układanki może zawierać argument wiersza polecenia -psn, który system operacyjny dodaje w niektórych sytuacjach. Zetknąłem się z tym w przeszłości podczas pracy nad portowaniem jakiegoś kodu do OS X. Zobacz to pytanie i dokumentację Apple, do której się odwołuje.
Ashley
od 10.10 w końcu wspomniany bsexec działa doskonale
Hofi

Odpowiedzi:

7

To, co chcesz osiągnąć, jest możliwe, ale trudne. Musisz uruchomić aplikację w ramach odpowiedniej sesji użytkownika. Ze względów bezpieczeństwa przekroczenie podziału sesji użytkownika jest trudne.

Potrzebujesz procesu już uruchomionego w sesji innego użytkownika, aby wysłuchać twojego żądania i uruchomić aplikację w Twoim imieniu.

Wystartował bsexec

Na szczęście najnowsze wersje launchdmają tę zdolność; chociaż inżynierowie Apple nie zalecili jego ogólnego zastosowania. Użyj bsexecopcji w launchctl, aby wybrać odpowiednią sesję użytkownika:

 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.

Zalecanym podejściem jest napisanie uruchomionego biletu zadania i zrestartowanie komputera Mac - lub poproszenie użytkownika o wylogowanie i ponowne zalogowanie.

Przyczyna problemów

Problemy wynikają z połączenia aplikacji z niewłaściwym WindowServerprocesem. Każda sesja użytkownika ma osobny WindowServer; ten proces obsługuje interfejs użytkownika. Wcześniejsze metody przypisują własność procesu właściwemu użytkownikowi, ale są połączone z własnym procesem WindowServer.

Ten problem jest wymieniony w nocie technicznej Daemons and Agents od Apple.

Doświadczenie

Wiem to z własnego doświadczenia. Dla Power Managera napisałem pmuser, aby istniał w każdej sesji użytkownika. pmusernasłuchuje naszego demona i obsługuje uruchomienia i polecenia dla poszczególnych użytkowników. Pomimo tego, że nasz demon ma uprawnienia administratora, nadal potrzebowaliśmy procesu na użytkownika, aby działać niezawodnie w sesjach użytkowników.

Graham Miln
źródło
Czy możesz podać prosty skrypt, taki jak w odpowiedzi TJ, ale taki, który działa? Czy może jest to po prostu zbyt skomplikowane?
cregox,
Prawidłowe rozwiązanie jest zbyt skomplikowane, aby można je było napisać krótko. Idealnie, osobny proces podobny do trampoliny jest wymagany w sesji użytkownika docelowego. Oto, co musieliśmy zrobić dla Power Managera: dssw.co.uk/powermanager Co masz nadzieję osiągnąć?
Graham Miln,
Mając nadzieję osiągnąć dokładnie to, co mówi tytuł: uruchom aplikację GUI w sesji innego użytkownika . „Punkty bonusowe”, jeśli drugi użytkownik nie musi być zalogowany lub może zostać zalogowany programowo. W szczególności chcę wielu dysków Google. Działa, jeśli po prostu loguję się ręcznie i znajduje się w elementach logowania tego użytkownika w Preferencjach systemowych. Proces trampoliny nie przyniósłby punktów bonusowych, ale jeśli to jedyny sposób, jakie jest dokładnie zalecenie inżynierów Apple? Myślałem, że to właśnie do robienia tak prostych skryptów hakerskich! : P
cregox
@Cawas, zadaj to pytanie jako nowe pytanie i skup się na celu, jakim jest uzyskanie wielu Dysków Google, a nie na tym, jak można to osiągnąć. Zmiana fokusu sprawi, że pytanie nie będzie oznaczone jako duplikat.
Graham Miln,
Wystarczająco uczciwe i gotowe .
cregox
7

Żadna z powyższych odpowiedzi bsesek nie działa na El Capitan (10.11), ze względu na zamknięcie portów przez System Integration Protection (SIP). „launchctl asuser” działa, ale wymaga uruchomienia jako root. Poniższe polecenie działa w El Capitan (i najnowszych systemach operacyjnych):

sudo launchctl asuser 501 open /Applications/Calculator.app

Zauważ, że 501 jest identyfikatorem użytkownika dla mojego innego użytkownika.

Boris Vidolov
źródło
To jest mój wynik: bruno.medeiros@brunojcm-macbook:~ $ sudo launchctl asuser 501 open /Applications/Firefox.appi dostałemLSOpenURLsWithRole() failed with error -600 for the file /Applications/Firefox.app
BrunoJCM 17.10.16
@BrunoJCM czy jesteś pewien, że 501 to kod ID użytkownika, z którym chcesz go otworzyć? Jest nieco bardziej jasne, czy polecenie jest coś takiego: sudo launchctl asuser $(id -u <user_id_name>) <app>. To powiedziawszy, otrzymuję inny błąd, posix_spawn(): 13: Permission deniednawet jeśli uruchamiam z tym samym identyfikatorem użytkownika, z którym jestem zalogowany (i jestem właścicielem sesji) dlasudo launchctl asuser $(id -u mtylutki) /Applications/Calculator.app
Marcus
2

Ponieważ ostatecznie 10.10 zapewnia poprawną implementację „launchctl bsexec”, możesz użyć:

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

człowiek mówi

Spowoduje to wykonanie podanego polecenia w możliwie najbardziej zbliżonym kontekście wykonania do docelowego PID.

Tak więc jako parametr PID możesz użyć pid odpowiedniego procesu logowania do okna . UID to identyfikator użytkownika posiadającego loginwindow, a GID to jego podstawowa grupa.

Działa to dobrze dla każdego polecenia i oczywiście dla uruchomionych zadań (np. Launchagents), w końcu także:

/bin/launchctl bsexec 104 chroot -u 501 -g 20 / /bin/launchctl load -S Aqua /Library/LaunchAgents/com.youragent.plist 2>&1
Hofi
źródło
Nie jestem pewien, czy dotyczy to innych, ale teraz pojawia się task_for_pid(): 0x5błąd, w którym sprawdziłem, czy PID jest poprawny.
Marcus
1

Możesz użyć Findera jako hosta dla odpowiednich uprawnień osascript -e "tell application \"Finder\" to open (\"${app}\" as POSIX file as alias)". W ten sposób uruchomi się za pomocą dowolnego kontekstu GUI uruchomionego Findera.

Atishay Jain
źródło
0

Działa to przez 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

ale jeśli spróbujesz za pośrednictwem Terminal.app, to otworzy TextEdit w GUI bieżącego użytkownika.

Jeśli nie masz pewności, czy sshjest włączona, być może możesz ją tymczasowo włączyć

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

i wyłącz go później, jeśli to konieczne?

W przeciwnym razie jestem zakłopotany.

Testowane na 10.9.

TJ Luoma
źródło
Otwiera aplikację tak, jak mówisz, ale otwiera ją w bieżącej sesji użytkownika, a nie w sesji innego użytkownika, zgodnie z pytaniem.
cregox
-1

Prosty

sudo su nazwa_użytkownika

następnie wykonuj polecenia normalnie.

Oprogramowanie PandB
źródło
Polecenia byłyby uruchamiane bar, ale nadal działałyby w foosesji graficznej.
John N
Przepraszam, tak, mylę się co do pytania, nie jest wykonywane w sesji graficznej foo.
PandB Software,