Dopo l'aggiornamento a Mojave, il mio script di backup basato su rsync eseguito tramite un launch agent in ~ / Library / LaunchAgents, non poteva più leggere alcune directory in ~ / Library.
Dopo l'aggiornamento a Mojave, il mio script di backup basato su rsync eseguito tramite un launch agent in ~ / Library / LaunchAgents, non poteva più leggere alcune directory in ~ / Library.
Ho trascorso alcune settimane a cercare di risolvere questo problema. Sono d'accordo sul fatto che la risposta attualmente accettata non sia realmente una soluzione: non è molto meglio che disabilitare completamente SIP.
La mia soluzione è una soluzione totalmente hacky, ma non richiede il whitelist% di% co_de interamente. Aggiornamento: soluzione alternativa meno invasiva qui sotto.
bash
ma non utilizzando direttamente l'eseguibile archiviato in ad esempio open /path/to/MyApp.app
) Per il Passaggio 1, puoi facilmente impacchettare il tuo script come un'app utilizzando gli strumenti incorporati in MacOS come Automator.app o Script Editor o Platypus funziona anche.
I contenuti di esempio di questa app potrebbero essere un semplice AppleScript (in Script Editor) come:
on run
do shell script "/usr/local/bin/bash /path/to/myscript.sh"
end run
Da Script Editor, utilizza il menu a discesa nel menu Salva per salvare come applicazione, quindi CHIUDI SCRIPT EDITOR .
Aggiungi questa app a Accesso completo al disco tramite MyApp.app/Contents/Resources/
- > System Preferences
.
NB: se non hai salvato e chiuso Script Editor prima di aggiungere alla FDA come da istruzioni, sembra che qualche tipo di processo invisibile (salva sfondo automatizzato?) cambierà qualcosa (qualche tipo di timestamp o hash?) necessario per l'accesso completo al disco, che può causare errori intermittenti che sono stati un grosso mal di testa da capire. Quindi, se non l'hai fatto, rimuovi la tua app dalla FDA, salva e chiudi Script Editor, quindi aggiungi di nuovo all'FDA.
Per il tuo LaunchAgent, usa qualcosa come:
<string>/usr/bin/open</string>
<string>/path/to/MyApp.app</string>
Se il tuo script di backup ha bisogno di un accesso root (ad esempio per eseguire il backup dei file 0600 di proprietà di root), ti troverai per un altro set di soluzioni alternative, dal momento che Security & Privacy
non sembra eseguire nulla come root (anche se tu specifica la chiave /usr/bin/open
in un% di proprietà di root% co_de. (Sarei felice di aprirlo come una domanda separata se appropriato, dal momento che penso che la soluzione alternativa qui sotto lascia molto a desiderare.)
Un'opzione per questo è aggiungere UserName
nel tuo AppleScript, ma ciò richiede la digitazione manuale della password, vanificando lo scopo del backup automatico. La mia soluzione attuale è:
/Library/LaunchDaemons/
e concedo al mio utente non privilegiato la possibilità di eseguire il mio script di backup come sudo con NOPASSWD: (Ho anche specificato l'hash dello script per migliorare la sicurezza, ad esempio with administrator privileges
) sudo visudo
myuser ALL=(ALL) NOPASSWD: sha256:hashgoeshere /path/to/myscript.sh
(4 quindi può ancora essere aggiunto a VCS) sudo chown root myscript.sh
e salva nuovamente come MyApp.app Ulteriori letture / dettagli:
Dopo alcuni test preliminari, sembra che una soluzione leggermente meno hacky sia quella di compilare un binario (usando un linguaggio compilato) che chiama il tuo script bash. Aggiungi quel binario alla FDA e sembra funzionare. Aggiungi al% di proprietà di root% co_de e hai un modo per chiamarlo da sudo chmod 0740 myscript.sh
senza tutta la pazzia di cui sopra.
Esempio di script in Vai:
// Runrestic provides a binary to run my restic backup script in MacOS Mojave with Full Disk Access
package main
import (
"log"
"os"
"os/exec"
"path/filepath"
)
func main() {
ex, err := os.Executable()
if err != nil {
log.Fatal(err)
}
dir := filepath.Dir(ex)
script := filepath.Join(dir, "restic-backup.sh")
cmd := exec.Command("/usr/local/bin/bash", script)
if err := cmd.Run(); err != nil {
log.Fatal(err)
}
}
Per sicurezza, I do shell script "sudo -n /path/to/myscript.sh"
e /Library/LaunchDaemons
il binario risultante prima di aggiungere a root
(anche se ammettiamo che un utente malintenzionato potrebbe semplicemente cambiare lo script bash che chiama se non fosse protetto).
Ho risolto questo come segue:
L'errore che ho fatto è che l'agente di lancio ha eseguito lo script in questo modo:
<key>ProgramArguments</key>
<array>
<string>/Users/channing/bin/backup.sh</string>
</array>
Fai questo invece
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>/Users/channing/bin/backup.sh</string>
</array>
Riavvia il tuo agente:
launchctl unload ~/Library/LaunchAgents/backup.plist
launchctl load ~/Library/LaunchAgents/backup.plist
Rallegratevi.
Ho fatto ancora un po 'di test e non riesco più a dare a nessun normale accesso al disco completo del programma †. Ho scritto uno script di shell minimale [1], un binario minimo che chiama lo script di shell [2] e un binario che tenta di accedere a una posizione protetta [3]. Ho quindi fornito tutti questi script / eseguibili Accesso completo al disco e anche a /bin/sh
per buona misura.
Chiamare qualsiasi di questi direttamente tramite la shell mi dà un errore.
Poi sono incappato in una discussione sui forum di Apple dev su Regole per l'accesso completo al disco . Sembra che tu abbia bisogno di un pacchetto di app per fornire le autorizzazioni di Accesso completo al disco , il che spiega perché la concessione dell'accesso completo a un'app terminale consente a tale app di chiamare correttamente ls ~/Library/Mail
.
Tuttavia, not spiega perché puoi concedere l'accesso a /bin/bash
e quindi utilizzarlo nel tuo file launchd.plist
per avere accesso completo al disco nello script della shell.
† semplice binario, non un pacchetto di app che vive in /Applications
[1] /Users/me/access-test.sh
:
#!/bin/sh
ls /Users/me/Library/Mail
[2] /Users/me/access-test.c
:
#include <unistd.h>
int main(int argc, char *const argv[]) {
const char *file = "/Users/me/access-test.sh";
return execvp(file, argv);
}
[3] /Users/me/access-test-2.c
:
#include <stdio.h>
#include <dirent.h>
int main(void) {
DIR *dp;
struct dirent *ep;
dp = opendir("/Users/me/Library/Mail");
if (dp == NULL) {
perror("Couldn't open directory");
return 1;
} else {
while ((ep = readdir(dp))) {
puts(ep->d_name);
}
closedir (dp);
}
}
Consenti allo script di backup l'accesso completo al disco.
Vai a Preferenze di sistema → Sicurezza e amp; Privacy → Privacy → Accesso completo al disco . Quindi fai clic sul lucchetto
Sto riscontrando lo stesso problema con alcune copie attivate tramite launchd che usano idem. Provando anche alcuni test, vedo cosa posso minimamente aggiungere a Full Disk Access per farlo funzionare. Per gli script di bash mi chiedo se potresti essere in grado di creare un'applicazione AppleScript e usarla per concedere l'accesso e chiamare lo script. Potrebbe darti un modo per concedere l'accesso a quella specifica applicazione ed evitare di concedere l'accesso a tutto ciò che potresti eseguire attraverso bash