validator: implement PXE template

This commit is contained in:
nemunaire 2018-02-12 11:39:44 +01:00
parent e9ddee7ef1
commit 24a530b515
5 changed files with 144 additions and 27 deletions

View File

@ -1,29 +1,10 @@
DEFAULT vesamenu.c32 DEFAULT login
MENU RESOLUTION 1024 768
NOESCAPE 1
ALLOWOPTIONS 0
#MENU BACKGROUND splash.png
MENU BACKGROUND #00000000 * *
MENU COLOR TITLE * #FF22BBCC *
#MENU COLOR BORDER * #FFFFFFFF #00000000 none
MENU COLOR SEL * #FFFFFFFF #FF22BBCC *
MENU COLOR HOTSEL 1;7;37;40 #ffffffff #76a1d0ff *
#MENU COLOR TABMSG * #ffffffff #00000000 *
#MENU COLOR HELP 37;40 #ffdddd00 #00000000 *
MENU TABMSG Press ENTER to boot or TAB to edit a menu entry
PROMPT 0
TIMEOUT 1
MENU TITLE Welcome to the EPITA ADvanced LINux administration course!
LABEL login LABEL login
MENU LABEL ^Login MENU LABEL ^Login
KERNEL adlin/login-kernel KERNEL bzImage
INITRD adlin/login-initrd.img INITRD initramfs-login.img
APPEND console=tty0 APPEND console=tty0 quiet
TEXT help TEXT help
You are currently not identified. You are currently not identified.
Please select this menu entry in order to access the tutorial. Please select this menu entry in order to access the tutorial.

48
tftp/pxelinux.cfg/tpl Normal file
View File

@ -0,0 +1,48 @@
default vesamenu.c32
MENU RESOLUTION 1024 768
#menu background splash.png
menu background #00000000 * *
menu color title * #FF22BBCC *
#menu color border * #FFFFFFFF #00000000 none
menu color sel * #FFFFFFFF #FF22BBCC *
menu color hotsel 1;7;37;40 #ffffffff #76a1d0ff *
#menu color tabmsg * #ffffffff #00000000 *
#menu color help 37;40 #ffdddd00 #00000000 *
menu tabmsg Press ENTER to boot or TAB to edit a menu entry
prompt 0
timeout 0
menu title Welcome {{ .username }} to the EPITA ADvanced LINux administration course!
LABEL challenge
MENU LABEL ^Enter Challenge
KERNEL bzImage
INITRD initramfs-challenge.img
APPEND console=tty0 quiet
text help
You are currently identified as {{ .username }}.
Please select this menu entry in order to access the tutorial.
endtext
MENU SEPARATOR
LABEL logout
MENU LABEL Not {{ .username }}? ^logout
KERNEL bzImage
INITRD initramfs-login.img
APPEND console=tty0 quiet
text help
You are currently identified as {{ .username }}.
If this is not you, you should logout right now, using this menu entry!
You'll next be able to login as another user.
endtext
MENU SEPARATOR
LABEL poweroff
MENU LABEL ^Shutdown
KERNEL poweroff.c32

View File

@ -54,9 +54,48 @@ func (l loginChecker) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} }
if !canContinue { if !canContinue {
log.Println("Login not found:", lu.Username, "at", r.RemoteAddr)
http.Error(w, "Login not found in whitelist.", http.StatusUnauthorized) http.Error(w, "Login not found in whitelist.", http.StatusUnauthorized)
return return
} }
if err := l.lateLoginAction(lu.Username, r.RemoteAddr); err != nil {
log.Println("Error on late login action:", err)
http.Error(w, "Internal server error. Please retry in a few minutes", http.StatusInternalServerError)
return
}
log.Println("Successful login of", lu.Username, "at", r.RemoteAddr)
http.Error(w, "Success", http.StatusOK) http.Error(w, "Success", http.StatusOK)
} }
func (l loginChecker) lateLoginAction(username, remoteAddr string) error {
// Find corresponding MAC
var fname string
spl := strings.SplitN(remoteAddr, ":", 2)
if ip := net.ParseIP(spl[0]); ip == nil {
return errors.New("Unable to parse given IPv4: " + spl[0])
} else if arptable, err := ARPAnalyze(); err != nil {
return err
} else if arpent := ARPContainsIP(arptable, ip); arpent == nil {
return errors.New("Unable to find MAC in ARP table")
} else {
fname = fmt.Sprintf("%02x-%02x-%02x-%02x-%02x-%02x-%02x", arpent.HWType, arpent.HWAddress[0], arpent.HWAddress[1], arpent.HWAddress[2], arpent.HWAddress[3], arpent.HWAddress[4], arpent.HWAddress[5])
}
if tpl, err := ioutil.ReadFile(path.Join(tftpDir, "pxelinux.cfg", "tpl")); err != nil {
log.Println("Unable to open tpl: ", err)
} else if file, err := os.OpenFile(path.Join(tftpDir, "pxelinux.cfg", fname), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0644)); err != nil {
log.Println("Unable to open destination file: ", err)
} else {
defer file.Close()
if configTmpl, err := template.New("pxelinux.cfg").Parse(string(tpl)); err != nil {
log.Println("Cannot create template: ", err)
} else if err := configTmpl.Execute(file, map[string]string{"username": username, "remoteAddr": remoteAddr, "fname": fname}); err != nil {
log.Println("An error occurs during template execution: ", err)
}
}
return nil
}

View File

@ -7,22 +7,22 @@ import (
"path/filepath" "path/filepath"
) )
var tftpDir string
func main() { func main() {
var staticDir string
var studentsFile string var studentsFile string
var bind = flag.String("bind", ":8081", "Bind port/socket") var bind = flag.String("bind", ":8081", "Bind port/socket")
flag.StringVar(&studentsFile, "students", "./students.csv", "Path to a CSV file containing students list") flag.StringVar(&studentsFile, "students", "./students.csv", "Path to a CSV file containing students list")
flag.StringVar(&staticDir, "static", "./static/", "Directory containing static files")
flag.StringVar(&ARPTable, "arp", ARPTable, "Path to ARP table") flag.StringVar(&ARPTable, "arp", ARPTable, "Path to ARP table")
//var tftpdLogs = flag.String("tftpd", "/var/logs/tftpd.log", "Path to TFTPd logs") flag.StringVar(&tftpDir, "tftpdir", "/var/tftp/", "Path to TFTPd directory")
flag.Parse() flag.Parse()
var err error var err error
// Sanitize options // Sanitize options
log.Println("Checking paths...") log.Println("Checking paths...")
if staticDir, err = filepath.Abs(staticDir); err != nil { if tftpDir, err = filepath.Abs(tftpDir); err != nil {
log.Fatal(err) log.Fatal(err)
} }

49
validator/pxetpl.go Normal file
View File

@ -0,0 +1,49 @@
package main
import (
"errors"
"fmt"
"io/ioutil"
"log"
"net"
"os"
"path"
"text/template"
)
const pxeUserTplPath = "pxelinux.cfg/tpl"
const pxeUserPath = "pxelinux.cfg"
func RegisterUserMAC(ip net.IP, username string) error {
if tab, err := ARPAnalyze(); err != nil {
return err
} else if ent := ARPContainsIP(tab, ip); ent == nil {
return errors.New(fmt.Sprintf("Unable to find MAC address for given IP (%s)", ip))
} else {
return registerUser(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)
}
}
func RegisterUserIP(ip net.IP, username string) error {
return registerUser(fmt.Sprintf("%02X%02X%02X%02X", ip.To4()[0], ip.To4()[1], ip.To4()[2], ip.To4()[3]), username)
}
func registerUser(filename string, username string) error {
if pxeTplCnt, err := ioutil.ReadFile(path.Join(tftpDir, pxeUserTplPath)); err != nil {
return err
} else if userfd, err := os.OpenFile(path.Join(tftpDir, pxeUserPath, filename), os.O_RDWR|os.O_CREATE, 0644); err != nil {
return err
} else {
defer userfd.Close()
if pxeTmpl, err := template.New("pxeUser").Parse(string(pxeTplCnt)); err != nil {
return err
} else if err := pxeTmpl.Execute(userfd, map[string]string{"username": username}); err != nil {
return err
}
}
return nil
}
func init() {
log.Println(RegisterUserMAC(net.IPv4(192, 168, 23, 21), "mercie_d"))
}