(module privdrop mzscheme
(require "ffi-utils.ss"
(all-except (lib "contract.ss") ->)
(rename (lib "contract.ss") => ->)
(lib "foreign.ss")) (unsafe!)
(provide privdrop)
(default-_string-type _string*/utf-8)
(define _uid_t _uint32)
(define _gid_t _uint32)
(define _time_t _uint32)
(define _cbool
(make-ctype _int32
#f
(lambda (val)
(not (= val -1)))))
(define-cstruct _passwd
([pw_name _string]
[pw_passwd _string]
[pw_uid _uid_t]
[pw_gid _gid_t]
[pw_change _time_t]
[pw_class _string]
[pw_gecos _string]
[pw_dir _string]
[pw_shell _string]
[pw_expire _time_t]
[pw_fields _int]))
(define libc (ffi-lib #f))
(define-syntax unix-only-ffi
(syntax-rules ()
([_ promise function lib type]
(define promise
(delay
(get-ffi-obj function
lib
type))))))
(unix-only-ffi getpwnam-promise
"getpwnam"
libc
(_fun _string -> (_ptr o _passwd)))
(unix-only-ffi setgid-promise
"setgid"
libc
(_fun _gid_t -> _cbool))
(unix-only-ffi setuid-promise
"setuid"
libc
(_fun _uid_t -> _cbool))
(define (privdrop user)
(case (system-type)
[(unix)
(let ([pw ((force getpwnam-promise) user)])
(and pw
((force setgid-promise) (passwd-pw_gid pw))
((force setuid-promise) (passwd-pw_uid pw))))]
[(windows) #f]))
)