From 66e4e2d3cbbcfac1c2a9750e8355c22a4fbbca59 Mon Sep 17 00:00:00 2001 From: lgromero Date: Fri, 2 Feb 2024 14:56:01 +0100 Subject: [PATCH] refs #198 Adds tftpboot service and pxe protocol --- installer/ogboot_installer.sh | 130 ++++++++++++++++++ server/tftpboot/NetbootPXE.es.txt | 77 +++++++++++ server/tftpboot/grldr | Bin 0 -> 273039 bytes server/tftpboot/grldr-0.4.4 | Bin 0 -> 220049 bytes server/tftpboot/grub/default | 74 ++++++++++ server/tftpboot/grub/examples/refind | 4 + server/tftpboot/grub/grub.cfg | 9 ++ server/tftpboot/grub/templates/00unknown | 77 +++++++++++ server/tftpboot/grub/templates/10 | 4 + server/tftpboot/grub/templates/11 | 4 + server/tftpboot/grub/templates/12 | 4 + server/tftpboot/grub/templates/13 | 4 + server/tftpboot/grub/templates/19pxeADMIN | 22 +++ server/tftpboot/grub/templates/pxe | 37 +++++ server/tftpboot/menu.lst/default | 8 ++ server/tftpboot/menu.lst/examples/default | 25 ++++ .../examples/defaultHOTREBOOT_WindowsXP | 36 +++++ server/tftpboot/menu.lst/templates/00unknown | 6 + server/tftpboot/menu.lst/templates/10 | 8 ++ server/tftpboot/menu.lst/templates/11 | 8 ++ server/tftpboot/menu.lst/templates/12 | 6 + server/tftpboot/menu.lst/templates/13 | 8 ++ server/tftpboot/menu.lst/templates/19pxeADMIN | 20 +++ server/tftpboot/menu.lst/templates/pxe | 38 +++++ 24 files changed, 609 insertions(+) create mode 100644 installer/ogboot_installer.sh create mode 100644 server/tftpboot/NetbootPXE.es.txt create mode 100644 server/tftpboot/grldr create mode 100644 server/tftpboot/grldr-0.4.4 create mode 100644 server/tftpboot/grub/default create mode 100644 server/tftpboot/grub/examples/refind create mode 100644 server/tftpboot/grub/grub.cfg create mode 100644 server/tftpboot/grub/templates/00unknown create mode 100644 server/tftpboot/grub/templates/10 create mode 100644 server/tftpboot/grub/templates/11 create mode 100644 server/tftpboot/grub/templates/12 create mode 100644 server/tftpboot/grub/templates/13 create mode 100644 server/tftpboot/grub/templates/19pxeADMIN create mode 100644 server/tftpboot/grub/templates/pxe create mode 100644 server/tftpboot/menu.lst/default create mode 100644 server/tftpboot/menu.lst/examples/default create mode 100644 server/tftpboot/menu.lst/examples/defaultHOTREBOOT_WindowsXP create mode 100644 server/tftpboot/menu.lst/templates/00unknown create mode 100644 server/tftpboot/menu.lst/templates/10 create mode 100644 server/tftpboot/menu.lst/templates/11 create mode 100644 server/tftpboot/menu.lst/templates/12 create mode 100644 server/tftpboot/menu.lst/templates/13 create mode 100644 server/tftpboot/menu.lst/templates/19pxeADMIN create mode 100644 server/tftpboot/menu.lst/templates/pxe diff --git a/installer/ogboot_installer.sh b/installer/ogboot_installer.sh new file mode 100644 index 0000000..09bf971 --- /dev/null +++ b/installer/ogboot_installer.sh @@ -0,0 +1,130 @@ + +TFTPSERV=tftp +TFTPCFGDIR=/var/lib/tftpboot + +function createDirs() +{ + if [ $# -ne 1 ]; then + errorAndLog "${FUNCNAME}(): invalid number of parameters" + exit 1 + fi + + local path_ogboot_base="$1" + + # Crear estructura de directorios. + echoAndLog "${FUNCNAME}(): creating directory paths in $path_ogboot_base" + mkdir -p $path_ogboot_base + mkdir -p $path_ogboot_base/bin + mkdir -p $path_ogboot_base/client/{cache,images,log} + mkdir -p $path_ogboot_base/doc + mkdir -p $path_ogboot_base/etc + mkdir -p $path_ogboot_base/lib + mkdir -p $path_ogboot_base/log/clients + ln -fs $path_ogboot_base/log /var/log/ogboot + + mkdir -p $TFTPCFGDIR + ln -fs $TFTPCFGDIR $path_ogboot_base/tftpboot + mkdir -p $path_ogboot_base/tftpboot/{menu.lst,grub} + if [ $? -ne 0 ]; then + errorAndLog "${FUNCNAME}(): error while creating dirs. Do you have write permissions?" + return 1 + fi + + # Crear usuario ficticio. + if id -u $OPENGNSYS_CLIENT_USER &>/dev/null; then + echoAndLog "${FUNCNAME}(): user \"$OPENGNSYS_CLIENT_USER\" is already created" + else + echoAndLog "${FUNCNAME}(): creating OpenGnsys user" + useradd $OPENGNSYS_CLIENT_USER 2>/dev/null + if [ $? -ne 0 ]; then + errorAndLog "${FUNCNAME}(): error creating OpenGnsys user" + return 1 + fi + fi + + # Mover el fichero de registro de instalación al directorio de logs. + echoAndLog "${FUNCNAME}(): moving installation log file" + mv $LOG_FILE $OGLOGFILE && LOG_FILE=$OGLOGFILE + chmod 600 $LOG_FILE + + echoAndLog "${FUNCNAME}(): directory paths created" + return 0 +} + +# Copia ficheros de configuración y ejecutables genéricos del servidor. +function copyServerFiles () +{ + if [ $# -ne 1 ]; then + errorAndLog "${FUNCNAME}(): invalid number of parameters" + exit 1 + fi + + local path_ogboot_base="$1" + + # Lista de ficheros y directorios origen y de directorios destino. + local SOURCES=( server/tftpboot \ + /usr/lib/shim/shimx64.efi.signed \ + /usr/lib/grub/x86_64-efi-signed/grubnetx64.efi.signed \ + ) + local TARGETS=( tftpboot \ + tftpboot \ + tftpboot/grubx64.efi \ +) + + if [ ${#SOURCES[@]} != ${#TARGETS[@]} ]; then + errorAndLog "${FUNCNAME}(): inconsistent number of array items" + exit 1 + fi + + # Copiar ficheros. + echoAndLog "${FUNCNAME}(): copying files to server directories" + + pushd $WORKDIR/ogboot + local i + for (( i = 0; i < ${#SOURCES[@]}; i++ )); do + if [ -f "${SOURCES[$i]}" ]; then + echoAndLog "Copying ${SOURCES[$i]} to $path_ogboot_base/${TARGETS[$i]}" + cp -a "${SOURCES[$i]}" "${path_ogboot_base}/${TARGETS[$i]}" + elif [ -d "${SOURCES[$i]}" ]; then + echoAndLog "Copying content of ${SOURCES[$i]} to $path_ogboot_base/${TARGETS[$i]}" + cp -a "${SOURCES[$i]}"/* "${path_ogboot_base}/${TARGETS[$i]}" + else + warningAndLog "Unable to copy ${SOURCES[$i]} to $path_ogboot_base/${TARGETS[$i]}" + fi + done + + popd +} +############################################################ +### Esqueleto para el Servicio pxe y contenedor tftpboot ### +############################################################ + + +function tftpConfigure() +{ + echoAndLog "${FUNCNAME}(): Configuring TFTP service." + # Habilitar TFTP y reiniciar Inetd. + if [ -n "$TFTPSERV" ]; then + if [ -f $INETDCFGDIR/$TFTPSERV ]; then + perl -pi -e 's/disable.*/disable = no/' $INETDCFGDIR/$TFTPSERV + else + service=$TFTPSERV + $ENABLESERVICE; $STARTSERVICE + fi + fi + service=$INETDSERV + $ENABLESERVICE; $STARTSERVICE + + # comprobamos el servicio tftp + sleep 1 + testPxe +} + +# Comprueba que haya conexión al servicio TFTP/PXE. +function testPxe () +{ + echoAndLog "${FUNCNAME}(): Checking TFTP service... please wait." + echo "test" >$TFTPCFGDIR/testpxe + tftp -v 127.0.0.1 -c get testpxe /tmp/testpxe && echoAndLog "TFTP service is OK." || errorAndLog "TFTP service is down." + rm -f $TFTPCFGDIR/testpxe /tmp/testpxe +} \ No newline at end of file diff --git a/server/tftpboot/NetbootPXE.es.txt b/server/tftpboot/NetbootPXE.es.txt new file mode 100644 index 0000000..a1c7c8a --- /dev/null +++ b/server/tftpboot/NetbootPXE.es.txt @@ -0,0 +1,77 @@ + +Notas sobre arranque remoto de los clientes +=========================================== + +Desde la versión OpenGnsys 1.0.2 se utiliza Grub4Dos como gestor de arranque en sustitución de PXELinux. + +El instalador de OpenGnsys configura por defecto el servicio DHCP para usar el fichero "grldr" como gestor PXE, incluyendo la siguiente cláusula que debe ser común a todos los equipos afectados: + + filename "grldr"; + +En algunos equipos, puede aparecer el siguiente mensaje de error al finalizar la carga de los ficheros de arranque: +llll PXE unload fails: 1 +ln este caso, debe sustituirse el fichero por defecto "grldr" por "grldr-0.4.5b", que incluye una versión más actualizado de Grub4Dos, quedando la línea de configuración de DHCP como sigue: + + filename "grldr-0.4.5b"; + +Si se dispone distinto hardware compatible solo con uno de estos ficheros, deberá editarse el fichero de configuracińo de DHCP usando declaraciones para grupos de equipos: + + group { + filename "grldr"; + host ... + ... + } + group { + filename "grldr-0.4.5b"; + host ... + ... + } + +No olvidar reiniciar el servicio DHCP tras cada modificación de su fichero de configuración. + + + +Como cambiar el arranque en red PXELinux por Grub4DOS +===================================================== + +NOTA: la siguiente información está anticuada y es válido solo para versiones anteriores a OpenGnsys 1.0.2. + + +OpenGnsys 1.0.1 usa como gestor PXE el binario pxelinux.0, sin embargo, la actulización a OpenGnsys 1.0.2 sustituye automáticamente dicho gestor por Grub4Dos. + + +Realizar los siguientes pasos para sutituir "a mano" PXELinux por Grub4Dos como gestor de arranque sin usar el proceso de actualización de OpenGnsys. + + +Activar el grldr del grub4dos +1) modificar el dhcp, donde aparezca filename "pxelinux.0" por "grldr" + filename "grldr"; +2) Reiniciamos el servicio dhcp + /etc/init.d/dhcpd restart +3) Renombrar cambiar el gestor de arranque de la web, para que use grldr. + cp /opt/opengnsys/www/principal/boot.php /opt/opengnsys/www/principal/boot.pxelinux.php + cp /opt/opengnsys/www/principal/boot.grub4dos.php /opt/opengnsys/www/principal/boot.php + + cp /opt/opengnsys/www/gestores/gestor_pxe.php /opt/opengnsys/www/gestores/gestor_pxe.pxelinux.php + cp /opt/opengnsys/www/gestores/gestor_pxe_grub4dos.php /opt/opengnsys/www/gestores/gestor_pxe.php + +4) +En la funcion ogBoot, de la libreria Boot.lib descomentar los comentarios del if de las líneas 71 a 85, para que quede + #FIXME: activar seguimiento inicio sesion XP con grub4dos + if `ogGetOsVersion $1 $2 | grep "Windows" > /dev/null` + then + dd if=/dev/zero of=${MNTDIR}/ogboot.me bs=1024 count=3 + dd if=/dev/zero of=${MNTDIR}/ogboot.firstboot bs=1024 count=3 + dd if=/dev/zero of=${MNTDIR}/ogboot.secondboot bs=1024 count=3 + ogLoadHiveWindows $1 $2 + ogHiveNTRunMachine "cmd /c del c:\ogboot.* " ogcleanboot + ogUpdateHiveWindows + reboot + else + cp $OGLIB/grub4dos/* $MNTDIR # */ (Comentario Doxygen) + ##kexec -l $MNTDIR/grub.exe --append=--config-file="find --set-root /$LOADER; chainloader /$LOADER; tpm --init" + kexec -l $MNTDIR/grub.exe --append=--config-file="root (hd$[$1-1],$[$2-1]); chainloader (hd$[$1-1],$[$2-1])/$LOADER; tpm --init" + fi + + + diff --git a/server/tftpboot/grldr b/server/tftpboot/grldr new file mode 100644 index 0000000000000000000000000000000000000000..50e25d53ac1363486d49914f13f5d52bcbafe429 GIT binary patch literal 273039 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