2018-10-03 16:33:33 +02:00
package main
import (
"os"
"os/exec"
"os/user"
"path/filepath"
"runtime"
"strconv"
"syscall"
"github.com/jedisct1/dlog"
)
func ( proxy * Proxy ) dropPrivilege ( userStr string , fds [ ] * os . File ) {
currentUser , err := user . Current ( )
2018-10-08 17:48:05 +02:00
if err != nil && currentUser . Uid != "0" {
dlog . Fatal ( "Root privileges are required in order to switch to a different user. Maybe try again with 'sudo'" )
2018-10-03 16:33:33 +02:00
}
2018-10-03 17:57:39 +02:00
userInfo , err := user . Lookup ( userStr )
2018-10-03 16:33:33 +02:00
args := os . Args
if err != nil {
2018-10-03 17:57:39 +02:00
uid , err2 := strconv . Atoi ( userStr )
if err2 != nil || uid <= 0 {
dlog . Fatalf ( "Unable to retrieve any information about user [%s]: [%s] - Remove the user_name directive from the configuration file in order to avoid identity switch" , userStr , err )
}
dlog . Warnf ( "Unable to retrieve any information about user [%s]: [%s] - Switching to user id [%v] with the same group id, as [%v] looks like a user id. But you should remove or fix the user_name directive in the configuration file if possible" , userStr , err , uid , uid )
userInfo = & user . User { Uid : userStr , Gid : userStr }
2018-10-03 16:33:33 +02:00
}
2018-10-03 17:57:39 +02:00
uid , err := strconv . Atoi ( userInfo . Uid )
2018-10-03 16:33:33 +02:00
if err != nil {
dlog . Fatal ( err )
}
2018-10-03 17:57:39 +02:00
gid , err := strconv . Atoi ( userInfo . Gid )
2018-10-03 16:33:33 +02:00
if err != nil {
dlog . Fatal ( err )
}
execPath , err := exec . LookPath ( args [ 0 ] )
if err != nil {
2018-10-03 17:57:39 +02:00
dlog . Fatalf ( "Unable to get the path to the dnscrypt-proxy executable file: [%s]" , err )
2018-10-03 16:33:33 +02:00
}
path , err := filepath . Abs ( execPath )
if err != nil {
dlog . Fatal ( err )
}
ServiceManagerReadyNotify ( )
args = append ( args , "-child" )
dlog . Notice ( "Dropping privileges" )
runtime . LockOSThread ( )
if _ , _ , rcode := syscall . RawSyscall ( syscall . SYS_SETGROUPS , uintptr ( 0 ) , uintptr ( 0 ) , 0 ) ; rcode != 0 {
2018-12-23 18:10:14 +01:00
dlog . Fatalf ( "Unable to drop additional groups: [%s]" , rcode . Error ( ) )
2018-10-03 16:33:33 +02:00
}
if _ , _ , rcode := syscall . RawSyscall ( syscall . SYS_SETGID , uintptr ( gid ) , 0 , 0 ) ; rcode != 0 {
2018-12-23 18:10:14 +01:00
dlog . Fatalf ( "Unable to drop user privileges: [%s]" , rcode . Error ( ) )
2018-10-03 16:33:33 +02:00
}
if _ , _ , rcode := syscall . RawSyscall ( syscall . SYS_SETUID , uintptr ( uid ) , 0 , 0 ) ; rcode != 0 {
2018-12-23 18:10:14 +01:00
dlog . Fatalf ( "Unable to drop user privileges: [%s]" , rcode . Error ( ) )
2018-10-03 16:33:33 +02:00
}
maxfd := uintptr ( 0 )
for _ , fd := range fds {
if fd . Fd ( ) > maxfd {
maxfd = fd . Fd ( )
}
}
fdbase := maxfd + 1
for i , fd := range fds {
if _ , _ , rcode := syscall . RawSyscall ( syscall . SYS_DUP3 , fd . Fd ( ) , fdbase + uintptr ( i ) , 0 ) ; rcode != 0 {
2018-12-23 18:10:14 +01:00
dlog . Fatalf ( "Unable to clone file descriptor: [%s]" , rcode . Error ( ) )
2018-10-03 16:33:33 +02:00
}
if _ , _ , rcode := syscall . RawSyscall ( syscall . SYS_FCNTL , fd . Fd ( ) , syscall . F_SETFD , syscall . FD_CLOEXEC ) ; rcode != 0 {
2018-12-23 18:10:14 +01:00
dlog . Fatalf ( "Unable to set the close on exec flag: [%s]" , rcode . Error ( ) )
2018-10-03 16:33:33 +02:00
}
}
for i := range fds {
if _ , _ , rcode := syscall . RawSyscall ( syscall . SYS_DUP3 , fdbase + uintptr ( i ) , uintptr ( i ) + 3 , 0 ) ; rcode != 0 {
2018-12-23 18:10:14 +01:00
dlog . Fatalf ( "Unable to reassign descriptor: [%s]" , rcode . Error ( ) )
2018-10-03 16:33:33 +02:00
}
}
2018-10-05 01:06:44 +02:00
err = syscall . Exec ( path , args , os . Environ ( ) )
2018-10-05 00:48:17 +02:00
dlog . Fatalf ( "Unable to reexecute [%s]: [%s]" , path , err )
2018-10-03 16:33:33 +02:00
os . Exit ( 1 )
}