login-validator: Save shadow file by IP

This commit is contained in:
nemunaire 2022-02-26 22:21:31 +01:00
parent 59abc217d1
commit 26c162f319
6 changed files with 82 additions and 23 deletions

View File

@ -169,5 +169,5 @@ func (l loginChecker) registerUser(username, remoteAddr string, ent ARPEntry) (n
} }
func (l loginChecker) lateLoginAction(username, remoteAddr string, mac ARPEntry, ip net.IP) error { func (l loginChecker) lateLoginAction(username, remoteAddr string, mac ARPEntry, ip net.IP) error {
return RegisterUserMAC(mac, ip, username) return RegisterUserMAC(mac, ip, username, remoteAddr)
} }

View File

@ -2,16 +2,27 @@ package main
import ( import (
"compress/gzip" "compress/gzip"
"fmt"
"io" "io"
"log" "log"
"net/http" "net/http"
"os" "os"
"path" "path"
"time"
"github.com/cavaliergopher/cpio" "github.com/cavaliergopher/cpio"
) )
func copy_challenge(fd io.Writer) error {
fdchal, err := os.Open(path.Join(tftpDir, "challenge-initrd.img"))
if err != nil {
return err
}
defer fdchal.Close()
_, err = io.Copy(fd, fdchal)
return err
}
func passwd(w http.ResponseWriter, r *http.Request) { func passwd(w http.ResponseWriter, r *http.Request) {
if addr := r.Header.Get("X-Forwarded-For"); addr != "" { if addr := r.Header.Get("X-Forwarded-For"); addr != "" {
r.RemoteAddr = addr r.RemoteAddr = addr
@ -45,7 +56,10 @@ func passwd(w http.ResponseWriter, r *http.Request) {
defer file.Close() defer file.Close()
// Save the file // Save the file
fd, err := os.Create(path.Join(tftpDir, "shadows", fmt.Sprintf("%s.img", initrd_name(r.RemoteAddr)))) initrd := initrd_name(r.RemoteAddr)
os.MkdirAll(path.Join(tftpDir, "shadows", initrd), 0755)
fd, err := os.Create(path.Join(tftpDir, "shadows", initrd, "challenge-initrd.img"))
if err != nil { if err != nil {
log.Println("Error when creating shadow file from", r.RemoteAddr, err.Error()) log.Println("Error when creating shadow file from", r.RemoteAddr, err.Error())
http.Error(w, "Unable to treat your passwd file, please try again later", http.StatusInternalServerError) http.Error(w, "Unable to treat your passwd file, please try again later", http.StatusInternalServerError)
@ -53,25 +67,32 @@ func passwd(w http.ResponseWriter, r *http.Request) {
} }
defer fd.Close() defer fd.Close()
fd2, err := os.Create(path.Join(tftpDir, "shadows", initrd, "shadow"))
if err != nil {
log.Println("Error when creating shadow file from", r.RemoteAddr, err.Error())
http.Error(w, "Unable to treat your passwd file, please try again later", http.StatusInternalServerError)
return
}
defer fd2.Close()
// Copy the original challenge // Copy the original challenge
fdchal, err := os.Open(path.Join(tftpDir, "challenge-initrd.img")) err = copy_challenge(fd)
if err != nil { if err != nil {
log.Println(r.RemoteAddr, "Error when opening original challenge initramfs:", err.Error()) log.Println(r.RemoteAddr, "Error when opening original challenge initramfs:", err.Error())
http.Error(w, "Unable to treat your passwd file, please try again later", http.StatusInternalServerError) http.Error(w, "Unable to treat your passwd file, please try again later", http.StatusInternalServerError)
return return
} }
defer fdchal.Close()
io.Copy(fd, fdchal)
// Append the new cpio archive // Append the new cpio archive
zw := gzip.NewWriter(fd) wfd := io.MultiWriter(fd, fd2)
zw := gzip.NewWriter(wfd)
wcpio := cpio.NewWriter(zw) wcpio := cpio.NewWriter(zw)
hdr := &cpio.Header{ hdr := &cpio.Header{
Name: "etc/shadow", Name: "etc/shadow_",
Mode: 0640, Mode: 0640,
Size: header.Size, ModTime: time.Now(),
Size: header.Size,
} }
if err := wcpio.WriteHeader(hdr); err != nil { if err := wcpio.WriteHeader(hdr); err != nil {
log.Println("Error when writing cpio header from", r.RemoteAddr, err.Error()) log.Println("Error when writing cpio header from", r.RemoteAddr, err.Error())

View File

@ -6,6 +6,7 @@ import (
"crypto/sha512" "crypto/sha512"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log"
"net" "net"
"os" "os"
"path" "path"
@ -16,25 +17,22 @@ const pxeUserTplPath = "pxelinux.cfg/tpl"
const ipxeUserTplPath = "pxelinux.cfg/tpl.ipxe" const ipxeUserTplPath = "pxelinux.cfg/tpl.ipxe"
const pxeUserPath = "pxelinux.cfg" const pxeUserPath = "pxelinux.cfg"
func RegisterUserMAC(ent ARPEntry, ip net.IP, username string) error { func RegisterUserMAC(ent ARPEntry, ip net.IP, username, remoteAddr string) error {
if err := registerUser(ipxeUserTplPath, fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x.ipxe", ent.HWAddress[0], ent.HWAddress[1], ent.HWAddress[2], ent.HWAddress[3], ent.HWAddress[4], ent.HWAddress[5]), username, ip); err != nil { if err := registerUser(ipxeUserTplPath, remoteAddr, fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x.ipxe", ent.HWAddress[0], ent.HWAddress[1], ent.HWAddress[2], ent.HWAddress[3], ent.HWAddress[4], ent.HWAddress[5]), username, ip); err != nil {
return err return err
} else { } else {
return registerUser(pxeUserTplPath, fmt.Sprintf("%02x-%02x-%02x-%02x-%02x-%02x-%02x", ent.HWType, ent.HWAddress[0], ent.HWAddress[1], ent.HWAddress[2], ent.HWAddress[3], ent.HWAddress[4], ent.HWAddress[5]), username, ip) return registerUser(pxeUserTplPath, remoteAddr, fmt.Sprintf("%02x-%02x-%02x-%02x-%02x-%02x-%02x", ent.HWType, ent.HWAddress[0], ent.HWAddress[1], ent.HWAddress[2], ent.HWAddress[3], ent.HWAddress[4], ent.HWAddress[5]), username, ip)
} }
} }
func RegisterUserIP(ip net.IP, username string) error {
return registerUser(pxeUserTplPath, fmt.Sprintf("%02X%02X%02X%02X", ip.To4()[0], ip.To4()[1], ip.To4()[2], ip.To4()[3]), username, ip)
}
func initrd_name(remote string) string { func initrd_name(remote string) string {
log.Println("initrd_name:", remote)
initrd := hmac.New(md5.New, []byte(loginSalt)) initrd := hmac.New(md5.New, []byte(loginSalt))
initrd.Write([]byte(remote)) initrd.Write([]byte(remote))
return fmt.Sprintf("%x", initrd.Sum(nil)) return fmt.Sprintf("%x", initrd.Sum(nil))
} }
func registerUser(tplPath string, filename string, username string, ip net.IP) error { func registerUser(tplPath, remoteAddr string, filename string, username string, ip net.IP) error {
if pxeTplCnt, err := ioutil.ReadFile(path.Join(tftpDir, tplPath)); err != nil { if pxeTplCnt, err := ioutil.ReadFile(path.Join(tftpDir, tplPath)); err != nil {
return err return err
} else if userfd, err := os.OpenFile(path.Join(tftpDir, pxeUserPath, filename), os.O_RDWR|os.O_CREATE, 0644); err != nil { } else if userfd, err := os.OpenFile(path.Join(tftpDir, pxeUserPath, filename), os.O_RDWR|os.O_CREATE, 0644); err != nil {
@ -42,6 +40,24 @@ func registerUser(tplPath string, filename string, username string, ip net.IP) e
} else { } else {
defer userfd.Close() defer userfd.Close()
initrd := initrd_name(remoteAddr)
err := os.MkdirAll(path.Join(tftpDir, "shadows", initrd), 0755)
if err != nil {
return err
}
fd, err := os.Create(path.Join(tftpDir, "shadows", initrd, "challenge-initrd.img"))
if err != nil {
return err
}
defer fd.Close()
err = copy_challenge(fd)
if err != nil {
return err
}
pkey := hmac.New(sha512.New512_224, []byte(loginSalt)) pkey := hmac.New(sha512.New512_224, []byte(loginSalt))
pkey.Write([]byte(username)) pkey.Write([]byte(username))
@ -53,7 +69,7 @@ func registerUser(tplPath string, filename string, username string, ip net.IP) e
return err return err
} else if err := pxeTmpl.Execute(userfd, map[string]string{ } else if err := pxeTmpl.Execute(userfd, map[string]string{
"username": username, "username": username,
"initrd": initrd_name(ip.String()), "initrd": initrd,
"pkey": fmt.Sprintf("%x", pkey.Sum(nil)), "pkey": fmt.Sprintf("%x", pkey.Sum(nil)),
"ip": ip.String(), "ip": ip.String(),
}); err != nil { }); err != nil {

View File

@ -143,6 +143,7 @@ services:
- /srv/tftp:/srv/tftp:ro - /srv/tftp:/srv/tftp:ro
- /var/lib/adlin/pxelinux.cfg:/srv/tftp/bios/pxelinux.cfg - /var/lib/adlin/pxelinux.cfg:/srv/tftp/bios/pxelinux.cfg
- /var/lib/adlin/pxelinux.cfg:/srv/tftp/pxelinux.cfg - /var/lib/adlin/pxelinux.cfg:/srv/tftp/pxelinux.cfg
- /var/lib/adlin/shadows:/srv/tftp/s
- name: arp-spoofer - name: arp-spoofer
image: nemunaire/adlin-arp-spoofer:9cfd4b106e4a70281fad33fb36df1a189f846cb6 image: nemunaire/adlin-arp-spoofer:9cfd4b106e4a70281fad33fb36df1a189f846cb6
@ -159,6 +160,8 @@ services:
- /etc/resolv.conf:/etc/resolv.conf:ro - /etc/resolv.conf:/etc/resolv.conf:ro
- /var/lib/adlin/students.csv:/students.csv:ro - /var/lib/adlin/students.csv:/students.csv:ro
- /var/lib/adlin/pxelinux.cfg:/var/tftp/pxelinux.cfg - /var/lib/adlin/pxelinux.cfg:/var/tftp/pxelinux.cfg
- /var/lib/adlin/shadows:/var/tftp/shadows
- /srv/tftp/challenge-initrd.img:/var/tftp/challenge-initrd.img:ro
- /etc/ssl/certs:/etc/ssl/certs:ro - /etc/ssl/certs:/etc/ssl/certs:ro
- /usr/share/ca-certificates:/usr/share/ca-certificates:ro - /usr/share/ca-certificates:/usr/share/ca-certificates:ro
- name: nginx-login - name: nginx-login
@ -276,6 +279,7 @@ files:
- path: etc/init.d/011-copy-to-var - path: etc/init.d/011-copy-to-var
contents: | contents: |
#!/bin/sh #!/bin/sh
mkdir -p /var/lib/adlin/shadows
cp -r /srv/tftp/pxelinux.cfg /var/lib/adlin/ cp -r /srv/tftp/pxelinux.cfg /var/lib/adlin/
touch /var/lib/adlin/dhcp/dhcpd.leases touch /var/lib/adlin/dhcp/dhcpd.leases
@ -287,6 +291,17 @@ files:
/usr/sbin/crond /usr/sbin/crond
mode: "0755" mode: "0755"
- path: etc/init.d/032-update-std-initrd
contents: |
#!/bin/sh
for IRD in /var/lib/adlin/shadows/*/challenge-initrd.img
do
cat "/srv/tftp/challenge-initrd.img" > "${IRD}"
[ -f "${IRD%/challenge-initrd.img}/shadow" ] && cat "${IRD%/challenge-initrd.img}/shadow" >> "${IRD}"
done
mode: "0755"
- path: etc/init.d/021-nameserver - path: etc/init.d/021-nameserver
contents: | contents: |
#!/bin/sh #!/bin/sh
@ -539,6 +554,10 @@ files:
proxy_pass http://localhost:8081; proxy_pass http://localhost:8081;
proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-For $remote_addr;
} }
location /passwd {
proxy_pass http://localhost:8081;
proxy_set_header X-Forwarded-For $remote_addr;
}
location /logout { location /logout {
proxy_pass http://localhost:8081; proxy_pass http://localhost:8081;
proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-For $remote_addr;
@ -844,6 +863,9 @@ files:
- path: srv/tftp - path: srv/tftp
directory: true directory: true
mode: "0755" mode: "0755"
- path: srv/tftp/s
directory: true
mode: "0755"
- path: srv/tftp/bios/ldlinux.c32 - path: srv/tftp/bios/ldlinux.c32
source: /usr/share/syslinux/ldlinux.c32 source: /usr/share/syslinux/ldlinux.c32
@ -892,7 +914,7 @@ files:
source: /var/tftp/adlin/bzImage source: /var/tftp/adlin/bzImage
mode: "0644" mode: "0644"
- path: srv/tftp/login-initrd.img - path: srv/tftp/login-initrd.img
source: tftp/login-initrd.img source: login-initrd.img
mode: "0644" mode: "0644"
- path: srv/tftp/challenge-initrd.img - path: srv/tftp/challenge-initrd.img
source: challenge-initrd.img source: challenge-initrd.img

View File

@ -20,7 +20,7 @@ menu title Welcome {{ .username }} to the EPITA ADvanced LINux administration co
LABEL challenge LABEL challenge
MENU LABEL ^Enter Challenge MENU LABEL ^Enter Challenge
KERNEL ../bzImage KERNEL ../bzImage
INITRD ../s/{{ .initrd }}.img INITRD ../s/{{ .initrd }}/challenge-initrd.img
APPEND console=tty0 adlin.login={{ .username }} adlin.key={{ .pkey }} adlin.ip={{ .ip }} quiet APPEND console=tty0 adlin.login={{ .username }} adlin.key={{ .pkey }} adlin.ip={{ .ip }} quiet
text help text help
You are currently identified as {{ .username }}. You are currently identified as {{ .username }}.

View File

@ -30,7 +30,7 @@ echo -n Kernel command line: ${}
read cmdline || goto start read cmdline || goto start
kernel tftp://${next-server}/bzImage ${cmdline} adlin.login={{ .username }} adlin.key={{ .pkey }} adlin.ip={{ .ip }} kernel tftp://${next-server}/bzImage ${cmdline} adlin.login={{ .username }} adlin.key={{ .pkey }} adlin.ip={{ .ip }}
initrd tftp://${next-server}/s/{{ .initrd }}.img initrd tftp://${next-server}/s/{{ .initrd }}/challenge-initrd.img
boot || goto failed boot || goto failed
goto start goto start