2016-04-24 10 views
17

Quando si esegue Files.walk(Paths.get("/var/")).count() come utente non privilegiato, l'esecuzione potrebbe generare un'eccezione in quanto vi sono cartelle all'interno di /var/ che richiedono il permesso di root per essere attraversate.C'è un modo per un'app Java per ottenere i permessi di root?

Sono non alla ricerca di un modo per eseguire un comando bash come root (ad esempio sudo find /var), utilizzando Process, ecc

Voglio solo fare in modo Files.walk(Paths.get("/var/")).count() non significa gettare un AccessDeniedException:

Exception in thread "restartedMain" java.lang.reflect.InvocationTargetException 
    at sun.reflect.NativeMethodAccessorImpl.invoke0 
    at sun.reflect.NativeMethodAccessorImpl.invoke 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke 
    at java.lang.reflect.Method.invoke 
    at org.springframework.boot.devtools.restart.RestartLauncher.run 
Caused by: java.io.UncheckedIOException: java.nio.file.AccessDeniedException: /var/cache/httpd 
    at java.nio.file.FileTreeIterator.fetchNextIfNeeded 
    at java.nio.file.FileTreeIterator.hasNext 
    at java.util.Iterator.forEachRemaining 
    at java.util.Spliterators$IteratorSpliterator.forEachRemaining 
    at java.util.stream.AbstractPipeline.copyInto 
    at java.util.stream.AbstractPipeline.wrapAndCopyInto 
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential 
    at java.util.stream.AbstractPipeline.evaluate 
    at java.util.stream.LongPipeline.reduce 
    at java.util.stream.LongPipeline.sum 
    at java.util.stream.ReferencePipeline.count 
    at com.example.DemoApplication.main 
    ... 5 more 
Caused by: java.nio.file.AccessDeniedException: /var/cache/httpd 
    at sun.nio.fs.UnixException.translateToIOException 
    at sun.nio.fs.UnixException.rethrowAsIOException 
    at sun.nio.fs.UnixException.rethrowAsIOException 
    at sun.nio.fs.UnixFileSystemProvider.newDirectoryStream 
    at java.nio.file.Files.newDirectoryStream 
    at java.nio.file.FileTreeWalker.visit 
    at java.nio.file.FileTreeWalker.next 
    at java.nio.file.FileTreeIterator.fetchNextIfNeeded 

Questo è solo un esempio. Utilizzando filter(...) è possibile aggirare l'eccezione. Ma questo esempio può essere esteso anche ad altri casi d'uso.

Quindi in breve È possibile, per le applicazioni CLI, JavaFX e così via, ottenere le autorizzazioni root dopo che sono state eseguite dalla riga di comando tramite un metodo come java -jar app.jar?

+4

Se fosse possibile, sarebbe un grosso problema di sicurezza ... Immagina che l'app abbia accesso root e 'rm -rf /'. OOOPS. – Tunaki

+7

L'app può visualizzare una finestra di dialogo e chiedere all'utente di immettere la password sudo/root. Molte app native hanno già questa capacità. Per esempio. Software Gnome, Utility Disco, ecc. OOOPS. ;-) – Behrang

+0

I _think_ l'approccio generale è quello di ottenere le informazioni di accesso amministratore/root, e quindi generare un processo separato come tale utente e fare in modo che il processo separato faccia il lavoro. Probabilmente dovresti farlo in modo diverso su ogni piattaforma. Non so se esiste un framework multipiattaforma che lo gestisce per te (e come probabilmente saprai, chiederne uno sarebbe OT su SO). Ad esempio, vedere [qui] (http://stackoverflow.com/q/4662574/1076640) per la risposta di Windows. – yshavit

risposta

3

solo alcune idee completamente testati:

1) eseguire la vostra applicazione con privilegi di root per cominciare:

sudo java -jar myapp.jar

2) Si compia la tua app avviare una lanciatore di classe che richiede le autorizzazioni di root e quindi continua a eseguire il resto della tua app:

java -jar myapp.jar

Questo a sua volta fa eseguire un comando di shell, ma solo un xterm che richiede la password di root, e poi continua a eseguire un programma Java con i permessi di root:

xterm -e "sudo sh -c 'java -jar /tmp/myrootapp.jar'"

o forse usare qualcosa nicer- guardando usando gksudo. Attenti allo ' e allo ".

Forse lo myapp.jar si estrae in un temporary directory. myapp.jar contiene myrootapp.jar e quindi può avviarlo come descritto sopra. /tmp dovrebbe ovviamente essere recuperato da java e preferibilmente essere una directory con un nome casuale a cui solo l'utente che esegue myapp.jar ha accesso per impedire l'iniezione di myrootapp.jar.

multipiattaforma

Lei ha parlato di /var/ te stesso, così ho pensato che eri su una sorta di Linux. Se questo dovrebbe funzionare su più piattaforme, ad es. anche su Macintosh o Microsoft Windows, è necessario prima eseguire una sorta di identificazione del sistema. Quindi è possibile applicare StrategyPattern in codice per gestire i vari modi di consentire a myrootapp.jar di ottenere le autorizzazioni root o di amministratore.

+2

Tuttavia, a seconda della tua applicazione, tieni presente che l'esecuzione della tua app con privilegi di root può introdurre ulteriori vulnerabilità dannose. Ad esempio, quando si utilizza il motore di Rhino, esistono vulnerabilità di iniezione, che consentono a un utente malintenzionato di inserire codice Java arbitrario tramite il motore. In questo caso, ovviamente, questo codice iniettato viene eseguito con i privilegi di root. – Max

9

Se quello che vuoi è effettivamente saltare i percorsi in cui non avete accesso, avete due approcci:

Streams

In the answer to this question si spiega come ottenere il flusso di tutti i file di un sottoalbero puoi accedere.

Ma questo esempio può essere esteso anche ad altri casi di utilizzo.

FileVisitor

Utilizzando un FileVisitor aggiunge un sacco di codice, ma concede molto più flessibilità quando si cammina alberi di directory. Per risolvere lo stesso problema si può sostituire con Files.walk():

Files.walkFileTree(Path start, FileVisitor<? super Path> visitor); 

estende SimpleFileVisitor (per contare i file) e l'override alcuni metodi.

È possibile:

  1. l'override del metodo visitFileFailed, per gestire il caso non è possibile accedere a un file per qualche motivo; (Consiglio di Lukasz_Plawny)
  2. (facoltativo) Sostituisci il metodo preVisitDirectory, controllando le autorizzazioni prima di accedere alla directory: se non riesci ad accedervi, puoi semplicemente saltare il suo sottoalbero (tieni presente che potresti essere in grado di accedere a una directory , ma non tutti i suoi file);

ad es. 1

@Override 
public FileVisitResult visitFileFailed(Path file, IOException exc) { 
    // you can log the exception 'exc' 
    return FileVisitResult.SKIP_SUBTREE; 
} 

ad es. 2

@Override 
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { 

    if(!Files.isReadable(dir)) 
     return FileVisitResult.SKIP_SUBTREE; 

    return FileVisitResult.CONTINUE; 

} 

FileVisitor docs

FileVisitor tutorial

Speranza che aiuta.

+2

Il mio suggerimento è di implementare il metodo 'visitFileFailed' da un' FileVisitor', che viene richiamato quando un file non può essere visitato. Quando aggiungi 'return FileVisitResult.SKIP_SUBTREE;' a questo metodo, quindi AccessDeniedException non verrà lanciato. –

+0

Hai ragione! Aggiornerò la risposta al più presto. – Linuslabo

1

Non esiste un modo semplice per modificare le autorizzazioni. Java non è adatto a queste attività. Ci sono solo alcuni trucchi come controllare le autorizzazioni all'avvio e provare a cambiare i permessi tramite su/sudo, quindi riavviare l'applicazione o utilizzare Java-gnome. Si prega di leggere un po 'di più qui: Java: Ask root privileges on Ubuntu

Problemi correlati