From 26c162f3197efd58b18b8c52d042158b420930ac Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Sat, 26 Feb 2022 22:21:31 +0100 Subject: [PATCH] login-validator: Save shadow file by IP --- pkg/login-validator/cmd/login.go | 2 +- pkg/login-validator/cmd/passwd.go | 41 +++++++++++++++++++++++-------- pkg/login-validator/cmd/pxetpl.go | 34 ++++++++++++++++++------- server.yml | 24 +++++++++++++++++- tftp/pxelinux.cfg/tpl | 2 +- tftp/pxelinux.cfg/tpl.ipxe | 2 +- 6 files changed, 82 insertions(+), 23 deletions(-) diff --git a/pkg/login-validator/cmd/login.go b/pkg/login-validator/cmd/login.go index 9126b51..298c337 100644 --- a/pkg/login-validator/cmd/login.go +++ b/pkg/login-validator/cmd/login.go @@ -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 { - return RegisterUserMAC(mac, ip, username) + return RegisterUserMAC(mac, ip, username, remoteAddr) } diff --git a/pkg/login-validator/cmd/passwd.go b/pkg/login-validator/cmd/passwd.go index e2603ab..f64ef31 100644 --- a/pkg/login-validator/cmd/passwd.go +++ b/pkg/login-validator/cmd/passwd.go @@ -2,16 +2,27 @@ package main import ( "compress/gzip" - "fmt" "io" "log" "net/http" "os" "path" + "time" "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) { if addr := r.Header.Get("X-Forwarded-For"); addr != "" { r.RemoteAddr = addr @@ -45,7 +56,10 @@ func passwd(w http.ResponseWriter, r *http.Request) { defer file.Close() // 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 { 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) @@ -53,25 +67,32 @@ func passwd(w http.ResponseWriter, r *http.Request) { } 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 - fdchal, err := os.Open(path.Join(tftpDir, "challenge-initrd.img")) + err = copy_challenge(fd) if err != nil { 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) return } - defer fdchal.Close() - - io.Copy(fd, fdchal) // Append the new cpio archive - zw := gzip.NewWriter(fd) + wfd := io.MultiWriter(fd, fd2) + zw := gzip.NewWriter(wfd) wcpio := cpio.NewWriter(zw) hdr := &cpio.Header{ - Name: "etc/shadow", - Mode: 0640, - Size: header.Size, + Name: "etc/shadow_", + Mode: 0640, + ModTime: time.Now(), + Size: header.Size, } if err := wcpio.WriteHeader(hdr); err != nil { log.Println("Error when writing cpio header from", r.RemoteAddr, err.Error()) diff --git a/pkg/login-validator/cmd/pxetpl.go b/pkg/login-validator/cmd/pxetpl.go index b0659b8..61ee39e 100644 --- a/pkg/login-validator/cmd/pxetpl.go +++ b/pkg/login-validator/cmd/pxetpl.go @@ -6,6 +6,7 @@ import ( "crypto/sha512" "fmt" "io/ioutil" + "log" "net" "os" "path" @@ -16,25 +17,22 @@ const pxeUserTplPath = "pxelinux.cfg/tpl" const ipxeUserTplPath = "pxelinux.cfg/tpl.ipxe" const pxeUserPath = "pxelinux.cfg" -func RegisterUserMAC(ent ARPEntry, ip net.IP, username 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 { +func RegisterUserMAC(ent ARPEntry, ip net.IP, username, remoteAddr string) error { + 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 } 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 { + log.Println("initrd_name:", remote) initrd := hmac.New(md5.New, []byte(loginSalt)) initrd.Write([]byte(remote)) 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 { return err } 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 { 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.Write([]byte(username)) @@ -53,7 +69,7 @@ func registerUser(tplPath string, filename string, username string, ip net.IP) e return err } else if err := pxeTmpl.Execute(userfd, map[string]string{ "username": username, - "initrd": initrd_name(ip.String()), + "initrd": initrd, "pkey": fmt.Sprintf("%x", pkey.Sum(nil)), "ip": ip.String(), }); err != nil { diff --git a/server.yml b/server.yml index 709a056..dd5dfb5 100644 --- a/server.yml +++ b/server.yml @@ -143,6 +143,7 @@ services: - /srv/tftp:/srv/tftp:ro - /var/lib/adlin/pxelinux.cfg:/srv/tftp/bios/pxelinux.cfg - /var/lib/adlin/pxelinux.cfg:/srv/tftp/pxelinux.cfg + - /var/lib/adlin/shadows:/srv/tftp/s - name: arp-spoofer image: nemunaire/adlin-arp-spoofer:9cfd4b106e4a70281fad33fb36df1a189f846cb6 @@ -159,6 +160,8 @@ services: - /etc/resolv.conf:/etc/resolv.conf:ro - /var/lib/adlin/students.csv:/students.csv:ro - /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 - /usr/share/ca-certificates:/usr/share/ca-certificates:ro - name: nginx-login @@ -276,6 +279,7 @@ files: - path: etc/init.d/011-copy-to-var contents: | #!/bin/sh + mkdir -p /var/lib/adlin/shadows cp -r /srv/tftp/pxelinux.cfg /var/lib/adlin/ touch /var/lib/adlin/dhcp/dhcpd.leases @@ -287,6 +291,17 @@ files: /usr/sbin/crond 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 contents: | #!/bin/sh @@ -539,6 +554,10 @@ files: proxy_pass http://localhost:8081; 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 { proxy_pass http://localhost:8081; proxy_set_header X-Forwarded-For $remote_addr; @@ -844,6 +863,9 @@ files: - path: srv/tftp directory: true mode: "0755" + - path: srv/tftp/s + directory: true + mode: "0755" - path: srv/tftp/bios/ldlinux.c32 source: /usr/share/syslinux/ldlinux.c32 @@ -892,7 +914,7 @@ files: source: /var/tftp/adlin/bzImage mode: "0644" - path: srv/tftp/login-initrd.img - source: tftp/login-initrd.img + source: login-initrd.img mode: "0644" - path: srv/tftp/challenge-initrd.img source: challenge-initrd.img diff --git a/tftp/pxelinux.cfg/tpl b/tftp/pxelinux.cfg/tpl index 3441eda..60ea108 100644 --- a/tftp/pxelinux.cfg/tpl +++ b/tftp/pxelinux.cfg/tpl @@ -20,7 +20,7 @@ menu title Welcome {{ .username }} to the EPITA ADvanced LINux administration co LABEL challenge MENU LABEL ^Enter Challenge 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 text help You are currently identified as {{ .username }}. diff --git a/tftp/pxelinux.cfg/tpl.ipxe b/tftp/pxelinux.cfg/tpl.ipxe index 4d1234e..371cfd0 100644 --- a/tftp/pxelinux.cfg/tpl.ipxe +++ b/tftp/pxelinux.cfg/tpl.ipxe @@ -30,7 +30,7 @@ echo -n Kernel command line: ${} read cmdline || goto start 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 goto start