129 lines
3.7 KiB
Go
129 lines
3.7 KiB
Go
package main
|
|
|
|
import (
|
|
"compress/gzip"
|
|
"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
|
|
}
|
|
log.Printf("%s \"%s %s\" [%s]\n", r.RemoteAddr, r.Method, r.URL.Path, r.UserAgent())
|
|
|
|
w.Header().Set("Content-Type", "text/plain")
|
|
|
|
// Check request type and size
|
|
if r.Method != "POST" {
|
|
http.Error(w,
|
|
"Invalid request",
|
|
http.StatusBadRequest)
|
|
return
|
|
} else if r.ContentLength < 0 || r.ContentLength > 655360 {
|
|
http.Error(w,
|
|
"Request entity too large",
|
|
http.StatusRequestEntityTooLarge)
|
|
return
|
|
}
|
|
|
|
// Authenticate the request
|
|
|
|
// Retrieve the file
|
|
file, header, err := r.FormFile("shadow")
|
|
if err != nil {
|
|
log.Println("Error when retrieving shadow file from", r.RemoteAddr, err.Error())
|
|
http.Error(w, "Unable to read your passwd file: something is wrong in your request", http.StatusBadRequest)
|
|
return
|
|
}
|
|
defer file.Close()
|
|
|
|
// Save the file
|
|
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)
|
|
return
|
|
}
|
|
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
|
|
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
|
|
}
|
|
|
|
// Append the new cpio archive
|
|
wfd := io.MultiWriter(fd, fd2)
|
|
zw := gzip.NewWriter(wfd)
|
|
wcpio := cpio.NewWriter(zw)
|
|
|
|
hdr := &cpio.Header{
|
|
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())
|
|
http.Error(w, "Unable to treat your passwd file, please try again later", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
body, err := io.ReadAll(file)
|
|
if err != nil {
|
|
log.Println("Error when writing cpio body from", r.RemoteAddr, err.Error())
|
|
http.Error(w, "Unable to treat your passwd file, please try again later", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
if _, err := wcpio.Write(body); err != nil {
|
|
log.Println("Error when writing cpio file from", r.RemoteAddr, err.Error())
|
|
http.Error(w, "Unable to treat your passwd file, please try again later", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if err := wcpio.Close(); err != nil {
|
|
log.Println("Error when closing cpio file from", r.RemoteAddr, err.Error())
|
|
http.Error(w, "Unable to treat your passwd file, please try again later", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if err := zw.Close(); err != nil {
|
|
log.Println("Error when closing gzip file from", r.RemoteAddr, err.Error())
|
|
http.Error(w, "Unable to treat your passwd file, please try again later", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
log.Println("Registered shadow for", r.RemoteAddr)
|
|
http.Error(w, "Success", http.StatusOK)
|
|
}
|