(Fix): fixed unsafe.Slice using &r (pointer-to-pointer) as the backing array instead of r (the calloc'd response array), which wrote password bytes into random
This commit is contained in:
@@ -27,6 +27,10 @@ first public release
|
||||
- **utmpx time field portability** — replaced hardcoded `C.__uint32_t` / `C.__int32_t` casts with a C helper function (`auth/utmpx_time.h`) that lets the compiler handle type conversion. fixes build failure on systems where `ut_tv` uses `struct timeval` instead of the 32/64 compat struct
|
||||
- **cgo pointer safety for pam** — replaced `unsafe.Pointer(&h)` (Go stack pointer passed to C) with `storeHandle`/`loadHandle` helpers that keep the `cgo.Handle` in C-heap memory. fixes `cgo argument has Go pointer to unpinned Go pointer` panic on Go 1.22+
|
||||
- **pam conversation callback** — fixed `unsafe.Slice` using `&r` (pointer-to-pointer) as the backing array instead of `r` (the calloc'd response array), which wrote password bytes into random stack memory. also now only responds to `PAM_PROMPT_ECHO_OFF`/`PAM_PROMPT_ECHO_ON` messages — info and error messages get nil. fixes `pam_unix: auth could not identify password`
|
||||
- **cgo handle lifecycle** — moved `cgo.Handle` and its C-heap backing from `Validate` (where they were `defer`-freed on return) into the `Credentials` struct so they stay alive through `OpenSession` and until `CloseSession`. fixes `misuse of an invalid Handle` panic
|
||||
- **session spawning** — replaced the broken `ForkExec` (which relaunched the same binary with made-up flags) with a direct `session.Spawn` call that drops privileges and runs the desktop in-process. fixes `flag provided but not defined: -user`
|
||||
- **renamed extra/ files** — `lemurs.pam` → `latchd.pam`, `lemurs.service` → `latchd.service`
|
||||
- **readme credits** — added a credits section acknowledging lemurs for the `extra/` directory structure and session scanning approach
|
||||
- **makefile `enable` and `update` targets** — `make enable` stops any running DM, disables the aliased display-manager, and enables latchd. `make update` runs uninstall → git pull → reinstall in one command
|
||||
- **missing `extra/` directory** — added `extra/config.toml`, `extra/xsetup.sh`, `extra/lemurs.pam`, and `extra/lemurs.service` so `make install` can find them
|
||||
- **makefile `deps` target** — added `make deps` to automatically install `libpam0g-dev` and `build-essential`, and verify go is present
|
||||
|
||||
@@ -182,3 +182,7 @@ src/
|
||||
## license
|
||||
|
||||
MIT or Apache-2.0
|
||||
|
||||
## credits
|
||||
|
||||
the `extra/` directory structure and the session scanning / pam delegation approach are adapted from [lemurs](https://github.com/coastalwhite/lemurs), a rust display manager.
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
#%PAM-1.0
|
||||
auth include login
|
||||
account include login
|
||||
session include login
|
||||
password include login
|
||||
@@ -1,15 +0,0 @@
|
||||
[Unit]
|
||||
Description=latchd display manager
|
||||
After=systemd-user-sessions.service plymouth-quit-wait.service getty@tty2.service
|
||||
Conflicts=getty@tty2.service
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/latchd
|
||||
StandardInput=tty
|
||||
TTYPath=/dev/tty2
|
||||
TTYReset=yes
|
||||
TTYVHangup=yes
|
||||
Type=idle
|
||||
|
||||
[Install]
|
||||
Alias=display-manager.service
|
||||
@@ -67,6 +67,8 @@ type Credentials struct {
|
||||
HomeDir string
|
||||
Shell string
|
||||
pamHandle *C.pam_handle_t
|
||||
pamData unsafe.Pointer
|
||||
pamCB cgo.Handle
|
||||
}
|
||||
|
||||
//export latchd_pam_conv
|
||||
@@ -110,16 +112,16 @@ func Validate(user, pass, service string) (*Credentials, error) {
|
||||
defer C.free(unsafe.Pointer(cUser))
|
||||
|
||||
h := cgo.NewHandle(pass)
|
||||
defer h.Delete()
|
||||
|
||||
cData := C.storeHandle(C.uintptr_t(h))
|
||||
defer C.free(cData)
|
||||
|
||||
conv := C.makePAMConv(cData)
|
||||
|
||||
var pamh *C.pam_handle_t
|
||||
ret := C.pam_start(cSvc, cUser, &conv, &pamh)
|
||||
if ret != C.PAM_SUCCESS {
|
||||
h.Delete()
|
||||
C.free(cData)
|
||||
return nil, &AuthError{ErrPAMService, fmt.Sprintf("pam_start: %s", pamErr(pamh, ret))}
|
||||
}
|
||||
|
||||
@@ -127,6 +129,8 @@ func Validate(user, pass, service string) (*Credentials, error) {
|
||||
if ret != C.PAM_SUCCESS {
|
||||
msg := fmt.Sprintf("auth failed: %s", pamErr(pamh, ret))
|
||||
C.pam_end(pamh, ret)
|
||||
h.Delete()
|
||||
C.free(cData)
|
||||
return nil, &AuthError{ErrAccountValidation, msg}
|
||||
}
|
||||
|
||||
@@ -134,12 +138,16 @@ func Validate(user, pass, service string) (*Credentials, error) {
|
||||
if ret != C.PAM_SUCCESS {
|
||||
msg := fmt.Sprintf("account: %s", pamErr(pamh, ret))
|
||||
C.pam_end(pamh, ret)
|
||||
h.Delete()
|
||||
C.free(cData)
|
||||
return nil, &AuthError{ErrAccountValidation, msg}
|
||||
}
|
||||
|
||||
u, err := ouser.Lookup(user)
|
||||
if err != nil {
|
||||
C.pam_end(pamh, ret)
|
||||
h.Delete()
|
||||
C.free(cData)
|
||||
return nil, &AuthError{ErrUsernameNotFound, fmt.Sprintf("lookup %s: %v", user, err)}
|
||||
}
|
||||
|
||||
@@ -163,6 +171,8 @@ func Validate(user, pass, service string) (*Credentials, error) {
|
||||
HomeDir: u.HomeDir,
|
||||
Shell: "/bin/sh",
|
||||
pamHandle: pamh,
|
||||
pamData: cData,
|
||||
pamCB: h,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -180,6 +190,11 @@ func (c *Credentials) CloseSession() {
|
||||
C.pam_end(c.pamHandle, 0)
|
||||
c.pamHandle = nil
|
||||
}
|
||||
if c.pamData != nil {
|
||||
C.free(c.pamData)
|
||||
c.pamData = nil
|
||||
}
|
||||
c.pamCB.Delete()
|
||||
}
|
||||
|
||||
func pamErr(h *C.pam_handle_t, e C.int) string {
|
||||
|
||||
Reference in New Issue
Block a user