Inhaltsverzeichnis

Folgende Problemstellung: In einem Büro hat man des öfteren Kunden, welche gerne einen Internetzugang hätten, um auf ihr Firmennetz zuzugreifen oder Mails zu checken. Natürlich kann und will man das nicht über sein eigenes Firmennetzwerk machen (ok, das ginge schon unter bestimmten Voraussetzungen, aber nicht ohne erheblichen bürokratischem und finanziellen Aufwand – zumindest bei großen Firmen).

Es ist jedoch ein zusätzlicher DSL-Anschluss vorhanden, an dem bereits ein Speedport W920V hängt. Natürlich hat dieser auch WLAN und so wurden dem Kunden einfach mal der WPA-Key gegeben, damit er ins Internet konnte. Diese Vorgehensweise ist vielleicht pragmatisch, aber weder sicher, noch sonderlich professionell. Es muss also ein GastWLAN her. Eins sei gleich gesagt, alle Fritz!Boxen dieser Welt, die eine solche „Funktion“ integriert haben, sind für so einen Zweck völlig unbrauchbar. Diese WLAN Gastzugänge haben nämlich ausschließlich den Zweck, den Gast und „sein“ WLAN vom restlichen LAN und WLAN zu trennen. Nicht mehr und nicht weniger. Der administrative Aufwand, dem Kunden/Gast einen WPA-Schlüssel zu geben und diesen auch nach festen Zeiträumen zu wechseln bleibt bestehen. Immerhin will man ja nicht, dass der Gast auch noch in einem Jahr von der Straße aus in das WLAN einloggen kann ;-)

Nachdem ich genau jenen Speedport auch daheim im Einsatz habe, habe ich eine entsprechende Testumgebung aufgebaut.

Folgende Rahmenbedingungen habe ich für unseren WLAN Gastzugang definiert:

  1. Ein Gast soll einen zeitlich begrenzten Zugang mit eindeutigem Usernamen und Passwort bekommen. Login wie in Hotels über eine Startseite.
  2. Bedienerfreundliches Anlegen und Verwalten der User über eine Web-Oberfläche.
  3. Automatische Generierung der Zugangsdaten und Export als PDF für den Kunden.
  4. Zeitbeschränkung des Zugangs, Speicherung der Daten für einen bestimmten Zeitraum und automatisches Löschen der Userdaten nach dieser Zeitspanne.

Hört sich im ersten Moment nach einer nicht allzu schweren Aufgabe an. Immerhin gibt es diverse Dienstleister, die solche Lösungen anbieten. Jedoch wollte ich erstens diese Lösung selbst umsetzen und zweitens hatte ich einen sehr begrenzten finanziellen Rahmen. Immerhin wusste ich, dass der Gastzugang nur hin und wieder gefordert wird und darüber hinaus natürlich völlig unkommerziell sein sollte.  Was liegt also näher sich im OpenSource-Lager nach einer Lösung umzusehen?

Und genau dort gibt es Ansätze die sehr interessant sind. So fand ich nach ein paar Google-Recherchen heraus, dass man zum einen eine Hotspot-Software braucht, die auf einem Router läuft und zum anderen einen Server benötigt, der die Userauthentifizierung übernimmt.

Folgende Komponenten werden bei meiner Lösung eingesetzt:

Beim Einrichten der Komponenten hat mir die Anleitung auf zeroathome.de sehr gut geholfen. Allerdings musste ich einige abweichenden Einstellungen vornehmen und auch den Funktionsumfang erweitern, da sich die Anleitung in erster Linie mit einer groben, aber lauffähigen, Installation beschäftigt.

 

Gesamtkonfiguration

 

Um die Gesamtkonfiguration des Netzwerkes verständlicher zu machen, will ich es anhand des obigen Bildes erläutern:

  • Der Speedport stellt die Verbindung zum Internet her und hat die interne IP-Adresse 192.168.2.1
  • Der Ubuntu-Server (im Bild als Radius-Server wiedergegeben) hängt direkt am Speedport und hat eine IP-Adresse des selben Subnetzes, also in unserem Fall 192.168.2.2. So ist der Server auch von außen erreichbar, was wir benötigen, damit User über das Webinterface erstellt werden können.
  • Der Linksys-Router, welcher mit der DD-WRT Firmware geflasht wurde, hängt ebenfalls am Speedport, jedoch über den WAN-Anschluss. Das WAN-Interface benutzen wir als Gateway um in das Subnetz des Speedports zu kommen, da der Linksys-Router ein eigenes Subnetz bekommt: 192.168.1.1. Bucht sich nun ein Client in das Gast-WLAN ein, wird er beim Aufruf einer beliebigen Homepage auf die Login-Seite umgeleitet, die auf dem Ubuntu-Server liegt. Die Benutzerauthentifizierung läuft dann über das Zusammenspiel zwischen Chillispot auf dem Linksys-Router und dem Radius-Server auf dem Ubuntu-Server.
  • Die Gast-Clients verbinden sich mit dem Linksys-Router und bekommen von Chillispot eine IP aus einem weiteren Subnetz zugewiesen 192.168.182.X.

Mit dieser Methode erreicht man eine klare Abgrenzung der Netze.

Und hier nochmal der Ablauf bzw. die Funktionsweise anhand eines Diagramms:

 

Ubuntu Server installieren und einrichten

 

Als erstes müssen wir den Server installieren und einrichten. Auf die Details einer Ubuntu-Installation will ich hier nicht eingehen, dazu gibt es im Internet massenweise gute Seiten, wie z.b. ubuntuusers.de

Bei der Installation des Ubuntu Servers sollte man bereits openSSH (für die Serververwaltung über Konsole/Fernzugriff) und LAMP (Linux Apache MySQL PHP) auswählen.

Nach der abgeschlossenen Installation des Grundsystem holen wir uns noch die Pakete für freeradius:

sudo apt-get install freeradius freeradius-mysql freeradius-common

Wir weisen dem Server noch seine statische IP-Adresse über die Datei /etc/network/interfaces zu, womit die Serverinstallation im wesentlichen abgeschlossen wäre.

 

hotspotlogin.cgi für Chillispot vorbereiten

 

Als nächstes konfigurieren wir die Login-Seite von Chillispot. Chillispot an sich läuft ja auch dem Linksys-Router als Bestandteil der DD-WRT Firmware, allerdings erfolgt der Login über eine Seite auf dem Ubuntu-Server.

Wir installieren uns vorübergehend Chillispot auf dem Server mit:

sudo apt-get install chillispot

Aus dieser Installation wollen wir lediglich an das hotspotlogin.cgi Skript:

sudo zcat /usr/share/doc/chillispot/hotspotlogin.cgi.gz > /usr/lib/cgi-bin/hotspotlogin.cgi
sudo chmod 755 /usr/lib/cgi-bin/hotspotlogin.cgi

Nun haben wir die Voraussetzung getroffen, die hotspotlogin.cgi entsprechend unserer Konfiguration einzurichten. Dafür öffnen wir die Datei und passen die nachfolgenden Punkte  an.

  • Wir benutzen keine verschlüsselte Verbindung, da bei selbst erzeugten Zertifikaten nur Fehlermeldungen und Warnungen auftauchen (nicht verifizierte Zertifikate). Dazu kommentiert man die nachfolgenden Zeilen aus:
    # If she did not use https tell her that it was wrong.
    #if (!($ENV{HTTPS} =~ /^on$/)) {
    #    print "Content-type: text/html\n\n
    #<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">
    #<html>
    #<head>
    #  <title>ChilliSpot Login Failed</title>
    #  <meta http-equiv=\"Cache-control\" content=\"no-cache\">
    #  <meta http-equiv=\"Pragma\" content=\"no-cache\">
    #</head>
    #<body bgColor = '#c0d8f4'>
    # <h1 style=\"text-align: center;\">ChilliSpot Login Failed</h1>
    #  <center>
    #    Login must use encrypted connection.
    #  </center>
    #</body>
    #<!--
    #<?xml version=\"1.0\" encoding=\"UTF-8\"?>
    #<WISPAccessGatewayParam
    #  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
    #  xsi:noNamespaceSchemaLocation=\"http://www.acmewisp.com/WISPAccessGatewayParam.xsd\">
    #<AuthenticationReply>
    #<MessageType>120</MessageType>
    #<ResponseCode>102</ResponseCode>
    #<ReplyMessage>Login must use encrypted connection</ReplyMessage>
    #</AuthenticationReply>
    #</WISPAccessGatewayParam>
    #-->
    #</html>
    #";
    #    exit(0);
    #}
  • In der Zeile $uamsecret=„sicheres_passwort“ tragen wir ein sicheres Passwort ein, mit dem sich der Chillispot mit der hotspotlogin.cgi verbindet. Dieses Passwort unbedingt für das spätere Einrichten des Chillispots notieren.
  • Wir starten den Apache-Server neu:
sudo /etc/init.d/apache2 force-reload

 

Freeradius konfigurieren

 

Als nächstes konfigurieren wir freeradius, damit eine Kommunikation zwischen Chillispot und freeradius für die Userauthentifizierung möglich wird.

  • Nachdem freeradius unter Ubuntu zum Editieren der Konfigurationsdateien Superuserrechte verlangt, loggen wir uns als Superuser um:
sudo su
  • Nun öffnen wir mit einem Editor die Datei clients.conf unter /etc/freeradius/
  • Wir passen gleich den ersten Block an unsere Einstellungen an:
    client RadiusNASID {
    ipaddr = 192.168.2.2
    secret = sicheres_passwort
    nastype = other
    }
  • In den obrigen Zeilen legen wir den Clientnamen fest, den wir für die Chillispotkonfiguration (Feld: Radius NAS ID) benötigen. Dieser Clientname ist frei wählbar, z.B. wlanhotspot.
  • Die IP-Adresse entspricht der IP des Linux-Servers (siehe Übersichtsbild).
  • Das secret entspricht unserem uamsecret.
  • nastype lassen wir auf other.

 

Konfiguration des DD-WRT Routers und des Chillispots

 

Nachdem wir unseren DD-WRT fähigen Router mit der aktuellen Firmware geflasht haben, können wir ihn über das Webmenü entsprechend konfigurieren. Bevor wir allerdings an die Chillispot-Konfiguration gehen, müssen wir grundlegende Einstellungen treffen, damit der DD-WRT-Router über den zweiten Router (Speedport) ins Internet gelangt.

Als erstes wechseln wir in den Einstellungsdialog Setup -> Basic Setup und editieren den Block WAN Setup:

  • Als Connection Type wählen wir Static IP
  • Die WAN IP Address muss eine verfügbare Adresse im Subnetz des Internet-Gateways sein, also in unserem Fall eine IP im Subnetz des Speedport, z.B. 192.168.2.10
  • Die Subnet Mask lautet 255.255.255.0
  • Das Gateway ist unser Speedport und ist mit der IP-Adresse 192.168.2.1 einzutragen.
  • Static DNS 1 ist ebenfalls unser Speedport mit der IP 192.168.2.1
  • STP setzen wir auf Disable

WAN Setup

Danach treffen wir natürlich auch die grundlegenden Routereinstellungen im Block Network Setup:

  • Local IP Address ist die IP-Adresse des DD-WRT Routers, in unserem Fall bekommt dieser die IP 192.168.1.1 Diese IP tragen wir ebenfalls unter Gateway und Local DNS ein.
  • Die Subnet Mask ist wiederum 255.255.255.0

Das wären die wichtigsten Einstellungen für den Router, natürlich kann man auch noch DHCP-Server aktivieren, was wir hier auch gemacht haben, damit ein mit Kabel verbundener Client auch eine IP-Adresse zugewiesen bekommt (unabhängig vom Chillispot!).

 

Network Setup

Damit der DD-WRT Router auch ins Internet kommt, muss eine statische Route zum Speedport eingerichtet werden, andernfalls werden Anfragen nicht richtig weitergeleitet. Diese Einstellung nehmen wir im Untermenü Setup -> Advanced Routing vor.

  • Als Operation Mode wählen wir Gateway
  • Unter Route Name tragen wir einen Namen ein, der diese Route identifiziert.
  • Destination LAN NET ist das Netz in das wir routen wollen, in unserem Fall ist dies das Netz des Speedports, als tragen wir die IP-Adresse 192.168.2.0 ein.
  • Subnet Mask ist wieder 255.255.255.0
  • Das Gateway hat die IP-Adresse des Speedports mit 192.168.2.1. Die Route erfolgt über das Interface WAN. Dabei ist zu beachten, dass der DD-WRT wirklich über den WAN-Port mit dem Speedport verbunden ist!

 

Advanced Routing

 

Zu guter Letzt richten wir noch den Chillispot ein. Dies erfolgt unter dem Menüpunkt Services -> Chillispot. Nun brauchen wir auch die Einstellungen, die wir in der hotspotlogin.cgi und in der clients.conf des freeradius getroffen haben.

  • Als erstes setzen wir Chillispot auf Enable
  • Danach wählen wir auch für Seperate Wifi from the LAN Bridge die Option Enable
  • Das Interface, das die IP zuweisen soll (DHCP Interface) muss folgerichtig das WLAN-Interface des Routers sein, in unserem Fall ist dies ath0.
  • Die Einstellungen für Remote Network lassen wir wie sie sind auf 192.168.182.0/24. Alle Gast-Clients bekommen mit dieser Einstellung eine IP des Subnetzes 182 zugewiesen.
  • Primary Radius Server IP/DNS ist die IP-Adresse unseres Radius-Servers, also die 192.168.2.2. Gleiches setzen wir für den Backup Radius Server IP/DNS da wir nur einen Radius-Server betreiben.
  • Die DNS IP entspricht unserem Router, der uns ins Internet befördert und die DNS Anfragen beantwortet, also die des Speedport: 192.168.2.1
  • Die Redirect URL ist die URL auf die ein Client umgeleitet wird, wenn er eine Internetseite aufruft. Diese URL verweist also auf die hotspotlogin.cgi auf unsrem Server: http://192.168.2.2/cgi-bin/hotspotlogin.cgi
  • Der Shared Key entspricht unserem secret, das wir in der clients.conf festgelegt haben: sicheres_passwort
  • Die Radius NAS ID ist der in der clients.conf des freeradius festgelegte Client Name. Wir haben das Beispiel wlanhotspot benutzt.
  • Das UAM Secret entspricht dem uamsecret in der hotspotlogin.cgi: sicheres_passwort
  • Die restlichen Einstellungen bleiben unverändert.

Chillispot

 

Freeradius an MySQL anbinden

 

Als nächstes legen wir uns eine MySQL Datenbank an, aus der sich freeradius die benötigten Daten holt. Entsprechende Datensätze für die Benutzer werden in dieser Datenbank angelegt, welche wiederum von freeradius für die Zugangskontrolle nutzt.

  • Anmelden an MySQL mit dem Befehl:
mysql -u root -p
  • Anlegen einer neuen Datenbank „radius“:
CREATE DATABASE radius;
  • Verlassen von MySQL mit dem Befehl:
quit
  • Erneutes Anmelden, aber dieses mal direkt an die Datenbank „radius“:
mysql -u root -p radius
  • Dem Benutzer „radius“ werden alle Rechte zum Bearbeiten der Datenbank „radius“ zugewiesen:
    GRANT ALL PRIVILEGES ON radius.* TO 'radius'@'localhost' IDENTIFIED BY 'sicherespasswort';
    FLUSH PRIVILEGES;
  • Verlassen von MySQL mit dem Befehl:
quit
  • Die Tabellen für freeradius werden über die mitgelieferten Vorlagen importiert:
    mysql -u root -p radius < /etc/freeradius/sql/mysql/schema.sql
    mysql -u root -p radius < /etc/freeradius/sql/mysql/nas.sql

 

Freeradius für MySQL konfigurieren

 

Damit freeradius auch mit MySQL und der gerade angelegten Datenbank zusammenarbeitet, müssen wir die nachfolgenden Konfigurationsdateien auf unsere Bedürfnisse anpassen.

  • Anmelden als Superuser:
sudo su
  • Öffnen der Datei /etc/freeradius/radiusd.conf
  • Den Kommentar in der Zeile $INCLUDE sql.conf entfernen. Dies aktiviert die Nutzung der MySQL-Datenbank durch freeradius.
  • Den Kommentar in der Zeile $INCLUDE sql/mysql/counter.conf entfernen. Dieser Eintrag ermöglicht es uns MySQL die zeitbasierten Zugänge verwalten zu lassen. Im Konzept beschrieben, wollen wir dem User nur für eine bestimmte Zeit Zugang zu unserem WLAN geben. Diese Option werden wir später genauer definieren.
  • Als nächstes editieren wir die Datei /etc/freeradius/sql.conf. Hier müssen wir freeradius die Zugangsdaten zur radius-Datenbank mitteilen.
    server = "localhost"
    login = "radius"
    password = "passwort_der_datenbank"
  • Als letztes öffnen wir die Datei /etc/freeradius/sites-available/default zum Editieren. In der Sektion ‚authorize‘ kommentieren wir ‚files‘ aus und entfernen dafür den Kommentar bei ’sql‘.
    authorize {
    
            preprocess
    
            chap
    
            mschap
    
            digest
    
            suffix
    	eap {
                    ok = return
            }
    	#files
            sql
    
            expiration
            logintime
    
            pap
    
    noresetcounter  #Für zeitlich begrenzte Zugänge
    dailycounter    #Tageslimits, werden jeden Tag zurückgesetzt
    monthlycounter  #Monatslimits, werden jeden Monat zurückgesetzt
    expire_on_login #Rücksetzen nach einer vorgegebenen Zeit nach Login <- wird von uns benutzt
    }
  • Zusätzlich müssen noch die Zeilen mit ’sql‘ unter der Sektion ‚accounting‘ sowie ’session‘ einkommentiert bzw. von den Kommentarzeichen befreit werden!
  • Wie oben zu sehen haben wir am Ende noch die Zählervarianten definiert. Die Zeiträume nach denen der Zugang zurückgesetzt wird, sind in den Kommentaren beschrieben. Der von uns eingesetzte Counter ist der als letztes aufgeführte ‚expire_on_login‘. Dieser Counter setzt den Zugang des Benutzers (nach dem initialen Login) nach einer definierten Zeit zurück.
  • Der ‚expire_on_login‘ Counter befindet sich nicht wie die anderen aufgeführten Counter in der Datei /etc/freeradius/sql/mysql/counter.conf, sondern in der Datei /etc/freeradius/modules/sqlcounter_expire_on_login
sqlcounter expire_on_login {
        counter-name = Expire-After-Initial-Login
        check-name = Expire-After
        counter-attribute = Acct-Status-Type
        sqlmod-inst = sql
        key = User-Name
        reset = never
        query = "SELECT TIME_TO_SEC(TIMEDIFF(NOW(), acctstarttime)) FROM radacct WHERE UserName='%{%k}' ORDER BY acctstarttime LIMIT 1;"
}
  • Abschließend starten wir den freeradius-server neu, die wesentliche Konfiguration des Hotspots ist damit abgeschlossen:
sudo /etc/init.d/freeradius restart

 

Erste Tests des freeradius

 

Damit wir feststellen können, ob freeradius richtig konfiguriert wurde, starten wir den freeradius-server mit dem Befehl:

sudo freeradius -XXX

Startet der freeradius Server richtig, bekommen wir nachfolgende Meldung, welche wir mit einem STRG-C quittieren.

Info: Ready to process requests.

Danach wollen wir den freeradius neustarten. Sollte dieser Neustart des freeradius eine Fehlermeldung bringen, läuft der obige Prozess noch und sollte „gekillt“ werden:

sudo killall freeradius

Danach kann der freeradius Server erneut gestartet werden.

sudo freeradius start

Konnten wir diesen freeradius-Test erfolgreich durchführen, gehen wir dazu über das komplette Hotspotsystem einem ersten Test zu unterziehen.

 

Test des Hotspotsystems

 

Für einen ersten Test am kompletten Hotspotsystem brauchen wir einen Benutzer. Für diesen ersten Test benutzen wir den ’noresetcounter‘, da dieser sofort nach dem Anlagen des Benutzers zum Ablaufen beginnt.

Wir wollen also einen User Anlagen, dessen Daten wie folgt sind:

  • Benutzername: User001
  • Passwort: passwort
  • Zeitspanne, nachdem der User automatisch ausgeloggt wird: 5 Minuten = 300 Sekunden

Diese Rahmenbedingungen sollen es uns ermöglichen, dass wir uns mit den obigen Benutzerdaten im Gast-WLAN einloggen können und 5 Minuten nach Anlagen des Benutzers sehen, ob wir wirklich automatisch ausgeloggt werden.

Den Benutzer müssen wir in der Datenbank anlegen, dies kann entweder über eine Weboberfläche wie phpmyadmin oder per Konsole erfolgen. Da wir sowieso an unserem Linux-Server sitzen nehmen wir für den ersten Test die Konsole, ein Anlegen geht damit denkbar schnell:

mysql -u root -p radius
INSERT INTO radcheck VALUES ('','User001','Password',':=','passwort');
INSERT INTO radcheck VALUES ('','User001','Max-All-Session',':=','300');

Zum Anlegen des Benutzers schreiben wir in die Tabelle ‚radcheck‘ der Radius-Datenbank. Wie beschreiben dabei die Felder, die in der Klammer folgen. Diese Spalten haben in der Tabelle folgende Namen:

  • id –> Wird automatisch eingetragen und hochgezählt
  • username –> Der Benutzername für den User, in unserem Fall User001
  • attribute –> Die freeradius-Option, die wir benutzen wollen, im Fall der ersten Zeile ist dies Password, in der zweiten Zeile Max-All-Sessions
  • op –> Zuweisungs-Operator :=, der dem attribute eine Wert übergibt
  • value –> Der Wert, der dem attribute zugewiesen wird. In der ersten Zeile ist die passwort und in der zweiten Zeile die Sekunden nachdem der Logout stattfindet, also 300.

Mit diesem Wissen kann man bereits wunderbar testen und die verschiedenen Szenarien durchspielen, an der Zeit drehen, mehrere Benutzer anlegen etc.

 

Erweiterung des Hotspotsystems um eine Userverwaltung

 

OK, das ganze ist nichts wesentlich Neues und wird bereits seit geraumer Zeit wunderbar auf zeroathome.de beschrieben. Allerdings ist dieses Hotspotsystem etwas umständlich, wenn man Benutzer anlegen will. Viel schlimmer wird es, wenn jemand einen Benutzer anlegen soll, der keine Ahnung von Linux, MySQL und Co. hat. Wie dies wahrscheinlich fast überall der Fall ist, wo Hotspots zum Einsatz kommen. Oder würdet ihr erwarten, dass die nette Dame im Hotel sagt: „Moment, da muss ich erst einen User in MySQL anlegen, das hatten wir erst in der letzten Linuxschulung“? ;-)

Einen Webserver haben wir ja sowieso schon am Laufen, also liegt es nahe ein Webmenü zu erstellen, mit dem man die User verwalten kann. Als Skriptsprache für MySQL-Operationen bietet sich PHP 5 an. Für die Umsetzung unserer Ideen benutzen wir in erster Linie PHP5 und HTML. Ein bißchen JavaScript ist auch noch enthalten ;-)

Nachfolgend unsere Zielsetzung für unsere Userverwaltung über den Webbrowser:

  • Eingabe von Vorname, Name und Firma.
  • Festlegen einer Gültigkeitsdauer von bis zu 5 Tagen.
  • Automatisches Generieren eines Benutzernamens und eines Passworts
  • Automatisches Generieren einer PDF-Datei mit allen Informationen, die dem Benutzer ausgedruckt werden kann.
  • Angelegte Benutzer verwalten: Einzelne Benutzer löschen, erzeugtes PDF neu aufrufen.
  • Automatisches Löschen von Benutzerdaten älter als 3 Monate.

Nachdem wir mehr Informationen speichern wollen, als von freeradius vorgesehen wird, erweitern wir die Datenbank ‚radius‘ um eine Tabelle, in der wir alle zusätzlichen Einträge machen (entweder manuell erstellen oder per phpmyadmin anlegen, ich werde hier nicht mehr im Detail auf die MySQL-Befehle eingehen). Wir nennen diese Tabelle ‚firma‘. Diese Tabelle könnte natürlich ganz anders heissen, genau wie deren Inhalt. Freeradius benötigt für eine Authetifizierung diese Tabelle nicht, sie dient uns rein für eine bessere Benutzerverwaltung.

Unsere Tabelle ‚firma‘ besitzt also folgende Spalten:

  1. firma_id (Typ = int(7), AUTO_INCREMENT)
  2. name (Typ = varchar(50))
  3. vorname (Typ = varchar(50))
  4. firma (Typ = varchar(50))
  5. datum (Typ = date)
  6. gueltig_bis (Typ = date)
  7. id (Typ = int(7), Wert muss unsigned sein!)

Der nachfolgende Screenshot zeigt, wie sich die Tabelle bei mir in phpMyAdmin darstellt:

phpMyAdmin_firma_db

Mit einem Fremdschlüssel auf die ID der Benutzernamen in der Tabelle ‚radcheck‘ verknüpfen wir die Tabllen ‚radcheck‘ und ‚firma‘ miteinander. Nachdem die beiden Tabellen bereits existieren, muss der Fremdschlüssel nachträglich mit nachfolgendem SQL-Befehl angelegt werden.

ALTER TABLE firma
ADD FOREIGN KEY (id)
REFERENCES radcheck(id);

 

Web-Formular für die Eingabe der Daten

 

Auf der Webseite müssen entsprechende Formularfelder vorhanden sein, deren Inhalt wir mit der „Post“-Methode an den Webserver übermitteln. PHP verarbeitet diese Daten weiter und trägt sie in die MySQL-Datenbank ein. Nachfolgend ein Screenshot, wie eine solche einfache, aber sehr effektive Webseite aussehen kann.

WebformularDer Code für die obige Startseite ist nachfolgend aufgeführt und durch Kommentare hinlänglich erläutert. Auf die einzelnen Punkte möchte ich im Detail nicht eingehen, das würde diesen Blog-Beitrag sprängen. Bitte stellt mir einfach eure Fragen als Kommentar, ich versuche diese dann zu beantworten.

Quellcode   
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Benutzer f&uuml;r GastWLAN anlegen</title>
 
<script type="text/javascript">
function chkFormular () {
  if (document.Formular.firma.value == "") {
    alert("Bitte die Firma eingeben!");
    document.Formular.firma.focus();
    return false;
  }
  if (document.Formular.name.value == "") {
    alert("Bitte Ihren Namen eingeben!");
    document.Formular.name.focus();
    return false;
  }
  if (document.Formular.vorname.value == "") {
    alert("Bitte den Vornamen eingeben!");
    document.Formular.vorname.focus();
    return false;
  }
  if (document.Formular.zeit.selectedIndex == "") {
    alert(unescape("Bitte Gueltigkeitsdauer eingeben!"));
    document.Formular.zeit.focus();
    return false;
  }
}
</script>
</head>
<span style="font-family:'Helvetica'">
<body>
 
<form name="Formular" action= "create_user.php"
  method="post" onsubmit="return chkFormular()">
 
<pre>
 
<div align="center" style="font-family:'helvetica'; font-size:150%" >Login f&uuml;r GastWLAN anlegen</div><br />
<hr />
<!--<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post" name="formular" id="formular">-->
<span style="font-family:Helvetica">
<center>
<table border="0">
  <tr>
    <td> Firma:  </td>
    <td> <input type="text" name="firma" id="firma" />  </td>
  </tr>
  <tr>
    <td> Name:  </td>
    <td> <input type="text" name="name" id="name" />  </td>
  </tr>
  <tr>
        <td> Vorname: </td>
        <td> <input type="text" name="vorname" id="vorname" /> </td>
  </tr>
  <tr>
        <td> G&uuml;ltigkeit:  </td>
        <td> <select name="zeit"><option></option><option>1</option> <option>2</option> <option>3</option> <option>4</option> <option>5</option></select> Tage</td>
  </tr>
        </table> <br />
 <!--<input type="text" name="zeit" id="zeit" /><br />-->
<input type="submit" name="eintragen" id="eintragen" value="User anlegen/PDF generieren" /><br />
<!--<input type="submit" name="list" id="list" onclick="window.open('Auslesen_DB.php')" />-->
<button name="list" type="button" onclick="window.open('Admin_dir/Admin_Auslesen_DB.php')">Liste aller Accounts
</button>
</center>
</span>
</pre>
<!--</form>-->
 
</body>
</span>
</html>

Das im obigen Code enthaltene JavaScript dient dazu, zu prüfen, ob auch alle Felder ausgefüllt wurden. Wurde ein Feld nicht ausgefüllt erscheint ein Fenster, das den Administrator darauf hinweist, welches Feld noch befüllt werden muss.

 

Generieren, Abschicken und Eintragen der Daten

 

Bei einem Klick auf den Button User anlegen/PDF generieren werden Benutzername und Passwort generiert, bevor die Formulardaten sowie Benutzername und Passwort an den Server übertragen und in die MySQL-Datenbank ‚radius‘ eingetragen werden.

Nachdem das PHP-Skript die Daten in die Datenbank eingetragen hat wird ein PDF generiert und geöffnet.

Zuerst müssen aber noch der Benutzername und das dazugehörige Passwort generiert werden. Diese Daten werden mit einem Zufallsgenerator erzeugt und sind für jeden Benutzer eindeutig. Der erzeugte Benutzername und das Passwort haben eine relativ kurze Länge, damit die Eingabe nicht übermäßig erschwert wird. Der Generator erzeugt ein Array aus Zeichen, die anschließend durchgemischt werden.

Das Array für den Benutzernamen beschränken wir auf eine Zeichenlänge von 5 Zeichen und benutzen dafür Zahlen von 0 bis 9 und Kleinbuchstaben von a bis z.

Quellcode   
// User-Generator
function user_create()
{
 $zeichen = 5;
 $chars = array_merge(
        range(0, 9),
        range('a', 'z')
        //range('A', 'Z')
    );
    shuffle($chars);
    $user_gen = implode('', array_slice($chars, 0, $zeichen));
        $user_ret = $user_gen;
        return $user_ret;
}

Das Passwort soll eine Länge von 8 Zeichen haben und Großbuchstaben von A bis Z, Kleinbuchstaben von a bis z und Ziffern von 0 bis 9 enthalten.

Quellcode   
// Passwort-Generator
function passwort_create()
{
 $zeichen = 8;
 $chars = array_merge(
        range(0, 9),
        range('a', 'z'),
        range('A', 'Z')
    );
    shuffle($chars);
    $passwort_gen = implode('', array_slice($chars, 0, $zeichen));
        $password_ret = $passwort_gen;
        return $password_ret;
}

Die Komplexität des Benutzernamens und des Passwort kann natürlich mit obigem Generator beliebig erweitert bzw. verändert werden.

Nach dem Generieren der Daten müssen die Felder, die Strings enthalten unschädlich gemacht werden, um eine MySQL-Injection mit Schadcode zu verhindern. Für diesen Zweck stellt PHP die Funktion mysql_real_escape_string($string) zur Verfügung. Nachdem die Strings entsprechend geprüft wurden, werden die Anweisungen durch Stringkonkatenationen zusammengesetzt und mit mysql_query($query) ausgeführt.

Quellcode   
if (isset( $_POST['eintragen'] ))
{
    // Maskierende Slashes aus POST entfernen
    $_POST = get_magic_quotes_gpc() ? array_map( 'stripslashes', $_POST ) : $_POST;
 
    // Inhalte der Felder aus POST holen bzw. festlegen
    $id ="''";
        $username = user_create();
    $attribute1 = "'Password'";
        $attribute2 = "'Expire-After'";
        $op = "':='";
        $value1 = passwort_create();
        $value2 = $_POST['zeit'];
    $firma = $_POST['firma'];
        $name   = $_POST['name'];
        $vorname = $_POST['vorname'];
        $date_act = date("Y-m-d",time());
 
    /* ************************************************************************************************ */
    /* *** Hier sollten und MUESSEN die Benutzereingaben geprueft werden um Schadcode abzufangen!!! *** */
    /* ************************************************************************************************ */
 
 // Hier wird das Ablaufdatum des Accounts berechnet
 
        $date_exp1 = (time() + 86400*$value2);
        $date_exp2 = date("Y-m-d",$date_exp1);
 
    // Sind alle Eingaben durch die Validierung gekommen werden sie in die DB geschrieben
    // Verbindung oeffnen und Datenbank ausweahlen
    $conID = mysql_connect( $db_host, $db_user, $db_pass ) or die( "Die Datenbank konnte nicht erreicht werden!" );
    if ($conID)
    {
        mysql_select_db( $db_name, $conID );
    }
 
        // Auf doppelten Eintrag in der Datenbank pruefen
        $_query_double = "Select * from firma where name = '" .$name. "' and vorname = '" .$vorname. "' and gueltig_bis >= '" .$date_act. "' and firma = '" .
$firma. "'";
        If (mysql_num_rows(mysql_query($_query_double)))
                { echo "<html>
                                <head>
                                <title>Eintrag vorhanden</title>
                                </head>
                                <br/><br/><br/>
                                <center><div><font face=\"helvetica\" size='5'><b> Es besteht bereits ein noch g&uuml;ltiger Eintrag</b></font> </div></center><br/>
                                <body>
                                <center>
                                <button name=\"back\" type=\"button\" onclick = \"history.back()\">zur Anmeldung</button>
                                </center>
                                </body>
                                </html>
                                ";}
        else
        {
// Anfrage zusammenstellen, die an die DB geschickt werden soll
    $sql1 = "INSERT INTO `radcheck`
                (`id`, `username`, `attribute`, `op`, `value`)
            VALUES(
                " .$id. ",
                                '" .mysql_real_escape_string( $username ). "',
                                " .$attribute1. ",
                                " .$op. ",
                '" .mysql_real_escape_string( $value1 ). "'
                )";
 
        mysql_query( $sql1 );
        //Speicherung der Id, des Eintrags, der neu angelegt wurde
 
    $rad_id_firm = mysql_query("select max(id) from radcheck");
    $result = mysql_fetch_array ( $rad_id_firm );
 
        // Anfrage zusammenstellen, die an die DB geschickt werden soll
    $sql2 = "INSERT INTO `radcheck`
                (`id`, `username`, `attribute`, `op`, `value`)
            VALUES(
                " .$id. ",
                                '" .mysql_real_escape_string( $username ). "',
                                " .$attribute2. ",
                                " .$op. ",
                '" .mysql_real_escape_string( 86400*$value2 ). "'
                )";
 // Anfrage zusammenstellen, die an die DB geschickt werden soll
        $sql3 = "INSERT INTO `firma`
                (`firma_id`, `name`, `vorname`, `firma`, `datum`, `gueltig_bis`, `id`)
            VALUES(
                " .$id. ",
                                '" .mysql_real_escape_string( $name ). "',
                                '" .mysql_real_escape_string( $vorname ). "',
                                '" .mysql_real_escape_string( $firma ). "','
                                " .$date_act. "',
                                '" .$date_exp2. "',
                                " .$result[0]. "
                )";
 
   // Schickt die Anfrage an die DB und schreibt die Daten in die Tabelle
 
        mysql_query( $sql2 );
        mysql_query( $sql3 );

 

PDF mit Userdaten erzeugen

 

Wir haben jetzt also einen User mit Passwort und sämtlichen dazugehörigen Daten erzeugt. Damit unser Gast diese Daten auch ausgehändigt bekommen kann, brauchen wir eine Übersicht der Zugangsdaten, die wir z.B. ausdrucken können. Zusätzlich wollen wir dem Gast vielleicht auch eine kleine Anleitung zur Seite stellen, wie er vorgehen muss (SSID des WLANs mit dem er sich verbinden muss, Anmeldevorgang). Darüber hinaus sollten wir den Benutzer auch darüber aufklären, dass seine Daten 3 Monate gespeichert werden und dass er sich mit dem Login dazu verpflichtet, dass er mit unserem Internetanschluss bzw. WLAN keinen Unfug treibt ;-)

Für die Generierung des PDFs benutzen wir eine PHP-Klasse, die den Namen TCPDF trägt. Die Objekte der Klasse TCPDF beinhalten Funktionen, die es uns ermöglichen Kopf, Körper und Fußzeile zu erzeugen. Um diese Klasse benutzen zu können, müssen wir sie zuerst im Webverzeichnis installieren. Die Installation ist denkbar einfach und wird hier beschrieben. Als Anregung, wie man sein PDF gestalten und wie man den Inhalt setzen kann, gibt es diverse Beispiele als PDF und dem dazugehörigem PHP-Code.

Beim Erzeugen unseres PDFs benutzen wir HTML zum Einfügen unseres Textes. Der nachfolgende Code macht dies deutlich. Abschließend wir das PDF mit dem Usernamen im Dateinamen im Verzeichnis ‚logins‘ gespeichert und automatisch geöffnet.

Quellcode   
require_once('tcpdf/config/lang/ger.php');
                require_once('tcpdf/tcpdf.php');
 
                // Extend the TCPDF class to create custom Header and Footer
                class MYPDF extends TCPDF {
 
                //Page header
                public function Header() {
        // Logo
        $image_file = 'images/logo.jpg';
        $this->Image($image_file, 10, 10, 30, '', 'JPG', '', 'M', false, 300, '', false, false, 0, false, false, false);
        // Set font
        $this->SetFont('helvetica', 'B', 20);
        // Title
        $this->Cell(0, 15, 'WLAN-Gastzugang', 0, false, 'C', 0, '', 0, false, 'M', 'M');
                        }
 
                // Page footer
                public function Footer() {
        // Position at 15 mm from bottom
        $this->SetY(-15);
        // Set font
        $this->SetFont('helvetica', 'I', 8);
        // Page number
        $this->Cell(0, 10, 'Page '.$this->getAliasNumPage().'/'.$this->getAliasNbPages(), 0, false, 'C', 0, '', 0, false, 'T', 'M');
                        }
                }
 
                // create new PDF document
                $pdf = new MYPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
 
                // set document information
                $pdf->SetCreator(PDF_CREATOR);
                $pdf->SetAuthor('Autor');
                $pdf->SetTitle('GastWLAN Zugangsdaten');
                $pdf->SetSubject('GastWLAN');
                $pdf->SetKeywords('GastWLAN');
 
                // set default header data
                //$pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE.' 006', PDF_HEADER_STRING);
                $pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE, PDF_HEADER_STRING);
 
                // remove default header/footer
                //$pdf->setPrintHeader(false);
                //$pdf->setPrintFooter(false);
// set header and footer fonts
                $pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
                $pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));
 
                // set default monospaced font
                $pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
 
                //set margins
                $pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
                $pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
                $pdf->SetFooterMargin(PDF_MARGIN_FOOTER);
 
                //set auto page breaks
                $pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
 
                //set image scale factor
                $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
 
                //set some language-dependent strings
                $pdf->setLanguageArray($l);
 
                // ---------------------------------------------------------
 
                // set font
                $pdf->SetFont('dejavusans', '', 10);
 
                // add a page
                $pdf->AddPage();
               // writeHTML($html, $ln=true, $fill=false, $reseth=false, $cell=false, $align='')
                // writeHTMLCell($w, $h, $x, $y, $html='', $border=0, $ln=0, $fill=0, $reseth=true, $align='', $autopadding=true)
 
                // create some HTML content
                // Print a text
                $html = <<<EOF
                <br />
                <br />
                <font size="10">Zur Benutzung des Gäste WLANs bitte die nachfolgende Punkte durchführen</font>
                <br />
                <br />
                <ol>
                        <li>Verbinden sie sich mit dem WLAN der SSID <b>GastWLAN</b></li>
                        <br />
                        <br />
                        <li>Rufen sie mit dem Browser eine beliebige Internetseite auf, sie werden dann zu einem Login-Fenster umgeleitet. Als Login benutzen sie nachfolgende Daten:
                        <br />
                        <br />
                        Benutzername: <font face="helvetica"><b>$username</b></font>
                        <br />
                        Passwort: <font face="helvetica"><b>$value1</b></font>
                        </li>
                        <br />
                        <br />
                        <li>Ihr Zugang ist für folgenden Zeitraum gültig: <font face="helvetica"><b>$value2</b> Tag(e)</font></li>
                <br />
                <br />
                <br />
                <br />
                </ol>
                <hr />
                <font size="9"><div align="center"><b>DISCLAIMER</b></div>
                <br />
                <br />
                Eine Verf&uuml;gbarkeit oder St&ouml;rungsfreiheit kann nicht garantiert werden!<br />
                <br />
                Der Benutzer verpflichtet sich mit dem Login, den Gastzugang ausschlie&szlig;lich im Rahmen seiner beruflichen T&auml;tigkeit zu nutzen.<br />
                Die Benutzerinformationen werden f&uuml;r einen Zeitraum von 3 Monaten gespeichert. </font>
EOF;
                $pdf->writeHTML($html, true, false, true, false, '');
 
                //Close and output PDF document
                $ziel = "logins/" . $username . ".pdf";
                $pdf->Output($ziel, 'FI');

 

Wir können nun unserem Gast seine für ihn erzeugten Benutzerdaten ausdrucken, mit denen er sich umgehend in das GastWLAN einloggen kann.

Das PDF würde in etwa wie folgt aussehn (fehlende oder schwarze Stellen gekonnt ignorieren, die habe ich nachträglich bearbeitet ;-) ):

Generiertes PDF

Das komplette PHP-Skript (create_user.php) für das Anlegen eines Benutzers und das Erzeugen des PDFs ist im nachfolgenden Code dargestellt.

Quellcode   
<?php
$db_host = "localhost";
$db_user = "datenbank_user"; //Anpassen!
$db_pass = "datenbank_passwort"; //Anpassen!
$db_name = "radius";
 
// Passwort-Generator
function passwort_create()
{
 $zeichen = 8;
 $chars = array_merge(
        range(0, 9),
        range('a', 'z'),
        range('A', 'Z')
    );
    shuffle($chars);
    $passwort_gen = implode('', array_slice($chars, 0, $zeichen));
        $password_ret = $passwort_gen;
        return $password_ret;
}
 
// User-Generator
function user_create()
{
 $zeichen = 5;
 $chars = array_merge(
        range(0, 9),
        range('a', 'z')
        //range('A', 'Z')
    );
    shuffle($chars);
    $user_gen = implode('', array_slice($chars, 0, $zeichen));
        $user_ret = $user_gen;
        return $user_ret;
}
 
//Zum Funktion benutzen
//$new_passwort = passwort_create();  
 
if (isset( $_POST['eintragen'] ))
{
    // Maskierende Slashes aus POST entfernen
    $_POST = get_magic_quotes_gpc() ? array_map( 'stripslashes', $_POST ) : $_POST;
 
    // Inhalte der Felder aus POST holen bzw. festlegen
    $id ="''";
        $username = user_create();
    $attribute1 = "'Password'";
        $attribute2 = "'Expire-After'";
        $op = "':='";
        $value1 = passwort_create();
        $value2 = $_POST['zeit'];
    $firma = $_POST['firma'];
        $name   = $_POST['name'];
        $vorname = $_POST['vorname'];
        $date_act = date("Y-m-d",time());
    /* ************************************************************************************************ */
    /* *** Hier sollten und MUESSEN die Benutzereingaben geprueft werden um Schadcode abzufangen!!! *** */
    /* ************************************************************************************************ */
 
 // Hier wird das Ablaufdatum des Accounts berechnet
 
        $date_exp1 = (time() + 86400*$value2);
        $date_exp2 = date("Y-m-d",$date_exp1);
 
    // Sind alle Eingaben durch die Validierung gekommen werden sie in die DB geschrieben
    // Verbindung oeffnen und Datenbank ausweahlen
    $conID = mysql_connect( $db_host, $db_user, $db_pass ) or die( "Die Datenbank konnte nicht erreicht werden!" );
    if ($conID)
    {
        mysql_select_db( $db_name, $conID );
    }
 
        // Auf doppelten Eintrag in der Datenbank pruefen
        $_query_double = "Select * from firma where name = '" .$name. "' and vorname = '" .$vorname. "' and gueltig_bis >= '" .$date_act. "' and firma = '" .
$firma. "'";
        If (mysql_num_rows(mysql_query($_query_double)))
                { echo "<html>
                                <head>
                                <title>Eintrag vorhanden</title>
                                </head>
                                <br/><br/><br/>
                                <center><div><font face=\"helvetica\" size='5'><b> Es besteht bereits ein noch g&uuml;ltiger Eintrag</b></font> </div></center><br/>
                                <body>
                                <center>
                                <button name=\"back\" type=\"button\" onclick = \"history.back()\">zur Anmeldung</button>
                                </center>
                                </body>
                                </html>
                                ";}
        else
        {
    // Anfrage zusammenstellen der an die DB geschickt werden soll
    $sql1 = "INSERT INTO `radcheck`
                (`id`, `username`, `attribute`, `op`, `value`)
            VALUES(
                " .$id. ",
                                '" .mysql_real_escape_string( $username ). "',
                                " .$attribute1. ",
                                " .$op. ",
                '" .mysql_real_escape_string( $value1 ). "'
                )";
 
        mysql_query( $sql1 );
        //Speicherung der Id, des Eintrags, der neu angelegt wurde
 
    $rad_id_firm = mysql_query("select max(id) from radcheck");
    $result = mysql_fetch_array ( $rad_id_firm );
 
        // Anfrage zusammenstellen der an die DB geschickt werden soll
    $sql2 = "INSERT INTO `radcheck`
                (`id`, `username`, `attribute`, `op`, `value`)
            VALUES(
                " .$id. ",
                                '" .mysql_real_escape_string( $username ). "',
                                " .$attribute2. ",
                                " .$op. ",
                '" .mysql_real_escape_string( 86400*$value2 ). "'
                )";
       // Anfrage zusammenstellen der an die DB geschickt werden soll
        $sql3 = "INSERT INTO `firma`
                (`firma_id`, `name`, `vorname`, `firma`, `datum`, `gueltig_bis`, `id`)
            VALUES(
                " .$id. ",
                                '" .mysql_real_escape_string( $name ). "',
                                '" .mysql_real_escape_string( $vorname ). "',
                                '" .mysql_real_escape_string( $firma ). "','
                                " .$date_act. "',
                                '" .$date_exp2. "',
                                " .$result[0]. "
                )";
 
   // Schickt die Anfrage an die DB und schreibt die Daten in die Tabelle
 
        mysql_query( $sql2 );
        mysql_query( $sql3 );
 
    // Pruefen ob der neue Datensatz tatsaechlich eingefuegt wurde
    if (mysql_affected_rows() == 1)
    {
        //echo "<h3>Der Datensatz wurde hinzugefügt</h3>";
                require_once('tcpdf/config/lang/ger.php');
                require_once('tcpdf/tcpdf.php');
 
                // Extend the TCPDF class to create custom Header and Footer
                class MYPDF extends TCPDF {
 
                //Page header
                public function Header() {
        // Logo
        $image_file = 'images/logo.jpg';
        $this->Image($image_file, 10, 10, 30, '', 'JPG', '', 'M', false, 300, '', false, false, 0, false, false, false);
        // Set font
        $this->SetFont('helvetica', 'B', 20);
        // Title
        $this->Cell(0, 15, 'WLAN-Gastzugang', 0, false, 'C', 0, '', 0, false, 'M', 'M');
                        }
 
                // Page footer
                public function Footer() {
        // Position at 15 mm from bottom
        $this->SetY(-15);
        // Set font
        $this->SetFont('helvetica', 'I', 8);
        // Page number
        $this->Cell(0, 10, 'Page '.$this->getAliasNumPage().'/'.$this->getAliasNbPages(), 0, false, 'C', 0, '', 0, false, 'T', 'M');
                        }
                }
 
                // create new PDF document
                $pdf = new MYPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
 
                // set document information
                $pdf->SetCreator(PDF_CREATOR);
                $pdf->SetAuthor('Autor');
                $pdf->SetTitle('GastWLAN Zugangsdaten');
                $pdf->SetSubject('GastWLAN');
                $pdf->SetKeywords('GastWLAN');
                // set default header data
                //$pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE.' 006', PDF_HEADER_STRING);
                $pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE, PDF_HEADER_STRING);
 
                // remove default header/footer
                //$pdf->setPrintHeader(false);
                //$pdf->setPrintFooter(false);
 
                // set header and footer fonts
                $pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
                $pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));
 
                // set default monospaced font
                $pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
 
                //set margins
                $pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
                $pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
                $pdf->SetFooterMargin(PDF_MARGIN_FOOTER);
 
                //set auto page breaks
                $pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
 
                //set image scale factor
                $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
 
                //set some language-dependent strings
                $pdf->setLanguageArray($l);
 
                // ---------------------------------------------------------
 
                // set font
                $pdf->SetFont('dejavusans', '', 10);
 
                // add a page
                $pdf->AddPage();
                // writeHTML($html, $ln=true, $fill=false, $reseth=false, $cell=false, $align='')
                // writeHTMLCell($w, $h, $x, $y, $html='', $border=0, $ln=0, $fill=0, $reseth=true, $align='', $autopadding=true)
 
                // create some HTML content
                // Print a text
                $html = <<<EOF
                <br />
                <br />
                <font size="10">Zur Benutzung des Gäste WLANs bitte die nachfolgende Punkte durchführen</font>
                <br />
                <br />
                <ol>
                        <li>Verbinden sie sich mit dem WLAN der SSID <b>GastWLAN</b></li>
                        <br />
                        <br />
                        <li>Rufen sie mit dem Browser eine beliebige Internetseite auf, sie werden dann zu einem Login-Fenster umgeleitet. Als Login benutzen sie nachfolgende Daten:
                        <br />
                        <br />
                        Benutzername: <font face="helvetica"><b>$username</b></font>
                        <br />
                        Passwort: <font face="helvetica"><b>$value1</b></font>
                        </li>
                        <br />
                        <br />
                        <li>Ihr Zugang ist für folgenden Zeitraum gültig: <font face="helvetica"><b>$value2</b> Tag(e)</font></li>
                <br />
                <br />
                <br />
                <br />
                </ol>
                <hr />
                <font size="9"><div align="center"><b>DISCLAIMER</b></div>
                <br />
                <br />
                Eine Verf&uuml;gbarkeit oder St&ouml;rungsfreiheit kann nicht garantiert werden!<br />
                <br />
                Der Benutzer verpflichtet sich mit dem Login, den Gastzugang ausschlie&szlig;lich im Rahmen seiner beruflichen T&auml;tigkeit zu nutzen.<br />
                Die Benutzerinformationen werden f&uuml;r einen Zeitraum von 3 Monaten gespeichert. </font>
EOF;
                $pdf->writeHTML($html, true, false, true, false, '');
 
                //Close and output PDF document
                $ziel = "logins/" . $username . ".pdf";
                $pdf->Output($ziel, 'FI');
 
                echo "<h3>Der Datensatz wurde hinzugef&uuml;gt!</h3>";
    }
    else
    {
        echo "<h3>Der Datensatz konnte <strong>nicht</strong> hinzugef&uuml;werden!</h3>";
        // Hier koennen Massnahmen ergriffen werden die ueber den Misserfolg informieren
        // wie z.B. den Benutzer darueber zu informieren, dem Admin eine Mail schicken
        // damit er sich um den Fehler kuemmern kann, etc pp
    }
}
}
?>

 

Natürlich kann der Code auch auf weitere Dateien aufgesplittet werden, damit er übersichtlicher wird. In unserem Fall habe ich mir das aber erspart.

 

Verwaltung der angelegten Accounts

 

Wie man auf dem Screenshot unserer Startseite sehen kann, gibt es einen weiteren Button Liste aller Accounts. Bei einem Klick auf den besagten Knopf erreicht man die Seite zu Verwaltung aller angelegten Useraccount und deren Datensätze. Dort kann man einzelne Benutzer oder alle Einträge auf einmal löschen. Ein weiteres Feature ist der erneute Aufruf der angelegten PDF, falls z.B. der Gast seine Daten erneut braucht.

Benutzerverwaltung

Das zugrunde liegende PHP-Skript greift auf die Datenbank zu und liest die Tabellen aus. Die Tabelle wird über eine For-Schleife ausgegeben, welche ein Array ausliest in dem zuvor die Daten aus der Datenbank zwischengespeichert wurden. Nachfolgend das Skript Admin_Auslesen_DB.php.

Quellcode   
<html>
<head>
<title> Account&uuml;bersicht</title>
<script type="text/javascript">
function get_ID(id,BN){
check_ID = confirm(unescape("Wirklich diesen Eintrag l%F6schen%3F"));
if(check_ID){
        document.Formular_Admin.hiddenField.value=id;
        document.Formular_Admin.hiddenBN.value=BN;
        this.document.Formular_Admin.submit();
        }
return check_ID;
}
 
function checkDelAll(){
check = false;
check = confirm(unescape("Wirklich alle Eintr%E4ge l%F6schen%3F"));
if (check==true){
        window.location="Del_all.php"}
}
 
</script>
</head>
<span style="font-family:'Helvetica'">
<center><h1>Auflistung aller Accounts</h1></center>
<body>
<?php
$db_host = "localhost";
$db_user = "datenbank_user"; //Anpassen!
$db_pass = "datenbank_passwort"; //Anpassen!
$db_name = "radius";
 
// Verbindung oeffnen und Datenbank ausweahlen
$conID = mysql_connect( $db_host, $db_user, $db_pass ) or die( "Die Datenbank konnte nicht erreicht werden!" );
if ($conID)
        {
    mysql_select_db( $db_name, $conID );}
 
// Fertige Befehl zum Auslesen an
        $_read_query = "Select firma_id, name, vorname, firma, datum, gueltig_bis, username from firma natural join radcheck";
// Ausfueren des mysql-Befehls
        $_result = mysql_query($_read_query);
// Ueberpruefung ob ein Eintrag vorliegt
        if(!mysql_num_rows($_result))
                {
                echo "<center><h3>Es liegen keine Eintr&auml;ge vor</h3></center>";}
        // Bei erfolgreichem auslesen wird Tabelle als html-datei erstellt
        else{
                echo"<form name=\"Formular_Admin\" action=\"single_DEL.php\" method=\"post\">
                        <input type=\"hidden\" name=\"hiddenField\"/>";
                echo"<input type=\"hidden\" name=\"hiddenBN\"/>";
                echo "<br /><center>";
                echo "<table border = \"5\">
                          <tr>
                          <th>firma_id</th>
                          <th>Name</th>
                          <th>Vorname</th>
                          <th>Firma</th>
                          <th>Erstellungsdatum</th>
                          <th>g&uuml;ltig bis</th>
                          <th>Username</th>
                          <th>Formular</th>
                          </tr>";
 
                while($_datablock = mysql_fetch_array($_result))
                        { echo "<tr align = \"center\">";
                          echo "<td>" .$_datablock [0]. "</td>";
                          echo "<td>" .$_datablock [1]. "</td>";
                          echo "<td>" .$_datablock [2]. "</td>";
                          echo "<td>" .$_datablock [3]. "</td>";
                          echo "<td>" .$_datablock [4]. "</td>";
                          echo "<td>" .$_datablock [5]. "</td>";
                          echo "<td>" .$_datablock [6]. "</td>";
                          echo "<td><a onclick=\"javascript:window.open('../logins/".$_datablock[6].".pdf')\"><img src=\"../images/pdf.jpg\" width= \"20\" height=\"20\"></a></td>";
                          echo "<td><input type=\"button\" name=\"".$_datablock [0]."\" value=\"DEL\" onclick=\"get_ID(".$_datablock [0].",'".$_datablock [6].".pdf')\" />";
 
                        }
                echo "</table></center></form>";
                echo "<br/><center><button name=\"del_all\" onclick=\"checkDelAll()\" >Alle Eintr&auml;ge l&ouml;schen</button></center>";
 
                }
?>
</body>
</span>
</html>

 

Bei der Löschen-Funktion einzelner Einträge bestand die Schwierigkeit, wie man die Information richtig überträgt, welcher Eintrag gelöscht werden soll. Dieses Problem wurde damit gelöst, dass bereits bei der dynamischen Erstellung der Tabelle die JavaScript-Funktion für die richtige Übergabe der ID ausgeführt wird. Beim Klick auf den Button Liste aller Accounts und damit beim Aufruf der Admin_Auslesen_DB.php schreibt die JavaScript-Funktion get_ID(id) die übergebene ID in ein verstecktes Formularfeld in PHP.

Quellcode   
<script type="text/javascript">
function get_ID(id,BN){
check_ID = confirm(unescape("Wirklich diesen Eintrag l%F6schen%3F"));
if(check_ID){
        document.Formular_Admin.hiddenField.value=id;
        document.Formular_Admin.hiddenBN.value=BN;
        this.document.Formular_Admin.submit();
        }
return check_ID;
}
 
function checkDelAll(){
check = false;
check = confirm(unescape("Wirklich alle Eintr%E4ge l%F6schen%3F"));
if (check==true){
        window.location="Del_all.php"}
}
 
</script>

 

Das Löschen eines einzelnen Eintrages übernimmt dann das Skript single_DEL.php. Zusätzlich korrigiert es die Zählung in der Tabelle und setzt das Autoinkrement wieder auf einen passenden Wert.

Quellcode   
<?php
$db_host = "localhost";
$db_user = "datenbank_user"; //Anpassen!
$db_pass = "datenbank_passwort"; //Anpassen!
$db_name = "radius";
 
//Anmelden an die DatenBank
$_POST = get_magic_quotes_gpc() ? array_map( 'stripslashes', $_POST ) : $_POST;
 
$ID_firma = $_POST ['hiddenField'];
$BName = $_POST ['hiddenBN'];
$ID_radcheck_Dur = 2*$ID_firma;
$ID_radcheck_BN = $ID_radcheck_Dur-1;
echo $ID_firma;
echo $BName;
$conID = mysql_connect( $db_host, $db_user, $db_pass ) or die( "Die Datenbank konnte nicht erreicht werden!" );
 
if($conID){
        mysql_select_db($db_name, $conID);}
 
//Queries zur Befehlausfuehrung
$query_delete_entry_firma="delete from firma where firma_id=".$ID_firma;
$query_delete_entry_radcheck="delete from radcheck where id=".$ID_radcheck_BN." or id=".$ID_radcheck_Dur;
$query_correct_count_firma = "update firma set firma_id = firma_id - 1, id = id-2 where firma_id > ".$ID_firma;
$query_correct_count_radcheck = "update radcheck set id = id - 2 where id > ".$ID_radcheck_Dur;
$query_all_entries_firma="select * from firma";
$query_all_entries_radcheck="select * from radcheck";
 
//Ausfuehrung der Mysql-Befehle
mysql_query($query_delete_entry_firma);
mysql_query($query_delete_entry_radcheck);
mysql_query($query_correct_count_firma);
mysql_query($query_correct_count_radcheck);
 
//Ermittlung wieviele Eintraege in den Tabellen vorhanden sind
$all_entries_firma=mysql_num_rows(mysql_query($query_all_entries_firma))+1;
$all_entries_radcheck=mysql_num_rows(mysql_query($query_all_entries_radcheck))+1;
 
//Queries zur Autoincrement-Korrektur
$query_autoincrement_firma="alter table firma auto_increment=".$all_entries_firma;
$query_autoincrement_radcheck="alter table radcheck auto_increment=".$all_entries_radcheck;
 
//Autoincremetn-queries auuehren
mysql_query($query_autoincrement_firma);
mysql_query($query_autoincrement_radcheck);
 
//Befehl zum Datenblt loeschen
$del_PDF = "rm ../logins/".$BName;
//sfuehrung des Befehls
exec($del_PDF);
 
header("Location:Admin_Auslesen_DB.php");
 
?>

 

Sollen alle Einträge gelöscht werden, wird vom User eine Bestätigung erfragt, ob wirklich alle Datensätze entfernt werden sollen. Wird diese Anfrage bestätigt, wird die komplette Löschung durch das Skript Del_all.php durchgeführt.

Quellcode   
function checkDelAll(){
check = false;
check = confirm(unescape("Wirklich alle Eintr%E4ge l%F6schen%3F"));
if (check==true){
        window.location="Del_all.php"}
}

 

Die Datei Del_all.php selbst beinhaltet nachfolgenden Code.

Quellcode   
<?php
$db_host = "localhost";
$db_user = "datenbank_user"; //Anpassen!
$db_pass = "datenbank_passwort"; //Anpassen!
$db_name = "radius";
 
//Anmelden an die DatenBank
//$_POST = get_magic_quotes_gpc() ? array_map( 'stripslashes', $_POST ) : $_POST;
 
/*$ID_firma = $_POST ['hiddenField'];
$ID_radcheck_Dur = 2*$ID_firma;
$ID_radcheck_BN = $ID_radcheck_Dur-1;
echo $ID_firma;*/
 
$conID = mysql_connect( $db_host, $db_user, $db_pass ) or die( "Die Datenbank konnte nicht erreicht werden!" );
 
if($conID){
        mysql_select_db($db_name, $conID);}
 
//Queries zur Befehlausfuehrung
$query_delete_entry_firma="delete from firma";
$query_delete_entry_radcheck="delete from radcheck";
 
//Ausfuehrung der Mysql-Befehle
mysql_query($query_delete_entry_firma);
mysql_query($query_delete_entry_radcheck);
 
//Ermittlung wieviele Eintraege in den Tabellen vorhanden sind
/*$all_entries_firma=mysql_num_rows(mysql_query($query_all_entries_firma))+1;
$all_entries_radcheck=mysql_num_rows(mysql_query($query_all_entries_radcheck))+1;
*/
 
//Queries zur Autoincrement-Korrektur
$query_autoincrement_firma="alter table firma auto_increment=1";
$query_autoincrement_radcheck="alter table radcheck auto_increment=1";
 
//Autoincremetn-queries auuehren
mysql_query($query_autoincrement_firma);
mysql_query($query_autoincrement_radcheck);
 
exec("rm ../logins/*.pdf");
 
header("Location:Admin_Auslesen_DB.php");
 
?>

 

Löschung der Datensätze, die älter sind als 3 Monate

 

Nachdem wir den Gast darauf hingewiesen haben, dass seine Daten für 3 Monate gespeichert werden, sollten wir natürlich auch sicherstellen, dass die Datensätze wirklich nach 3 Monaten gelöscht werden. Dafür gibt es zwei Möglichkeiten:

  1. Man macht sich einen Kalendereintrag für die Prüfung der Accounts und für das Löschen von Datensätzen älter als 3 Monate, oder…
  2. … man lässt es Linux mit einem Cronjob erledigen

Ich brauche wohl nicht erläutern weshalb wir natürlich die zweite Lösung gewählt haben ;-)

In regelmäßigen Abständen lassen wir also einen Cronjob laufen, der ein Shell-Skript aufruft, welches die Prüfung übernimmt. Nach dem Löschen der Einträge, die älter sind als 3 Monate, muss die Tabelle reorganisiert werden, damit die Zählung wieder von 1 beginnt. Danach wir das ‚auto_increment‘ auf einen Wert gesetzt, den der nächste Eintrag bekommen soll. Zu guter Letzt werden auch alle PDF-Dokumente gelöscht, die zu den entfernten Datensätzen gehören.

Quellcode   
#!/bin/sh
#Zugangsdaten fuer die Datenbank
TABLE_NAME="radius"
USER="root"
IP_ADDR="localhost"
PASSWORD="mysql_passwort"
 
#Auszufuehrender Code
datum=$(date -d "3 month ago" +%Y-%m-%d)                                                                                        #Ermittlung des Datums vor 3 Monaten
 
#mysql-Befehle
query_max_firma_id="select max(firma_id) from firma where datum <= '$datum'"
query_delete_firma="delete from firma where datum <= '$datum'"
#query_delete_radcheck="delete from radcheck where id <= ($max_firma_id * 2)"                           # wird erst weiter unten ausgefuert, da Variable noch nicht belegt ist
query_max_id="select max(firma_id) from firma"
#query_mod_id_firma="update firma set firma_id = firma_id - $korr_wert"
#query_mod_id="update radcheck set id = id - $korr_wert2"
query_min_id="select min(firma_id) from firma"
 
#Befehlausfuerhung
array_max_firma_id=($(mysql -u $USER -p$PASSWORD $TABLE_NAME -e "$query_max_firma_id"))
max_firma_id=${array_max_firma_id[1]}                                                                   # Ermittlung der groessten id in firma, die aelter als 3 Monate ist
array_max_id=($(mysql -u$USER -p$PASSWORD $TABLE_NAME -e "$query_max_id"))
max_id=${array_max_id[1]}                                                                               # Ermittlung der hoechsten id in firma
array_min_id=($(mysql -u$USER -p$PASSWORD $TABLE_NAME -e "$query_min_id"))
min_id=${array_min_id[1]}
 
query_delete_radcheck="delete from radcheck where id <= ($max_firma_id * 2)"                            # Eingeschobener query
 
if [ "$max_id" != "NULL" ]
then
mysql -u $USER -p$PASSWORD $TABLE_NAME -e "$query_delete_firma"                                         # 3 Monate alte Eintraege aus firma loeschen
mysql -u $USER -p$PASSWORD $TABLE_NAME -e "$query_delete_radcheck"                                      # 3 Monate alte Eintraege aus radcheck loeschen
 
#Korrektur der Nummerierung nur dann, wenn keine korrekte Nummerierung vorliegt
korr_wert=$max_firma_id
korr_wert2=$(expr $max_firma_id \* 2)
 
# Eingeschobene queries
query_mod_id_firma="update firma set firma_id = firma_id -$korr_wert, id = id - $korr_wert2"
query_mod_id="update radcheck set id = id - $korr_wert2"
 
new_count1=$(expr $max_id - $max_firma_id + 1 )
new_count2=$(expr $new_count1 \* 2 - 1 )
 
mysql -u $USER -p$PASSWORD $TABLE_NAME -e "$query_mod_id_firma"                                         # Korrektur der Nummerierung in firma
mysql -u $USER -p$PASSWORD $TABLE_NAME -e "$query_mod_id"                                               # Korrektur der Nummerierung in radcheck
mysql -u $USER -p$PASSWORD $TABLE_NAME -e "alter table radcheck auto_increment = $new_count2"
mysql -u $USER -p$PASSWORD $TABLE_NAME -e "alter table firma auto_increment = $new_count1"
 
# Loeschung der alten PDF-Files
find /var/www/logins/ *.pdf -mtime +90 -exec rm -f {} \;
fi

 

Schlussbemerkung

 

Puh, das war ja mal ein richtig langer Artikel. Jetzt habt ihr wahrscheinlich eine Vorstellung welche Arbeit hinter der Umsetzung unserer Ideen steckt. Es sei angemerkt, dass wir keine Programmierprofis sind und uns alles Schritt für Schritt beigebracht haben. Wir hatten eigene Vorgaben und selbst gesetzte Ziele, die wir erreichen und umsetzen wollten.

Ich denke, mit dieser Gesamtlösung ergeben sich interessante Einsatzgebiete für ein Hotspotsystem mit DD-WRT, freeradius und Chillispot. Durch die von uns entwickelte Benutzerverwaltung kann das ganze jetzt auch von normalen Usern benutzt werden, die Kenntnis vom Umgang mit einem schnöden Webbrowser vorausgesetzt ;-)

Wie gesagt, das ganze war kein Vorhaben von Profis im Bereich Webprogrammierung und dergleichen, deshalb weise ich ausdrücklich darauf hin, dass wir keine Haftung beim Einsatz unseres Systems übernehmen!

Falls jemand Verbesserungsvorschläge hat oder gar Schwachstellen in unserem Code gefunden hat, der möge sich doch bitte melden und so zur Verbesserung des Ganzen beitragen :-)

Abschließend danke ich noch Michael, der mir bei der Umsetzung des Projektes geholfen und große Teile des PHP-Codes und das Shell-Skript programmiert hat.

Zu guter Letzt findet ihr nachfolgend die Dateien des Webinterfaces gepackt als Zip zum Download:

hotspot_webinterface.zip

Autor

Hi! Ich bin Andreas und betreibe diese Seite, auf der ich über Themen rund um IT-Technik, Reisen und Fotografie schreibe. Dir gefallen meine Artikel und du möchtest mir einen virtuellen Kaffee ausgeben? Gerne! PayPal.me/imraz0r

97 Kommentare

  1. Hi,

    sehr schick!
    Wäre es möglich das Interface z.B. auf github zur Verfügung zu stellen? (Gebe auch gerne Unterstützung) Ich denke, dass würde die Wiederverwendbarkeit etwas erhöhen.

    Gruß,
    Ben

  2. Hallo Ben,

    ich habe es eigentlich geplant, das Webinterface gepackt hier noch zur Verfügung zu stellen. Github oder Sourceforge wäre eventuell natürlich auch eine Idee.
    Mit Github habe ich noch keine Erfahrungen gemacht, was sind die Vorteile zu Sourceforge?

    Gruß
    Imrazor

  3. Vorteile von Github gegenüber Sourceforge, hmm, wo fang ich da an :)
    Sourceforge ist leider ein wenig in den 90ern hängengeblieben und hat vergessen sich weiter zu entwickeln.
    Github macht es extrem einfach sich an Projekten anderer zu beteiligen, bzw. dazu beizutragen. Dazu ist es deutlich übersichtlicher und benutzerfreundlicher als SF. Ein Blick auf die beiden Anmeldeformulare spricht da meiner Meinung nach schon Bände :) (SF: , GH: .

    Falls man irgendwie helfen kann, einfach per mail melden, oder noch besser, Jabber (ben@einfachjabber.de)

    • Dann werde ich evtl. mal Github probieren. Sourceforge habe ich als irre umständlich in Erinnerung. Falls irgendwelche Fragen auftreten sollten, werde ich mich melden :-)

    • Nachdem Ubuntu ja auf Debian basiert, sollte es auch unter Debian funktionieren mit dieser Anleitung.
      Grundsätzlich lässt sich dieses System auf Debian (oder einer anderen Linux-Distribution) sicher umsetzen, vielleicht ist der ein oder andere Speicherort (z.B. von freeradius) ein anderer. Die Config-Dateien etc. sollten aber dennoch identisch sein.

      Die Weboberfläche an sich funktioniert ganz sicher auch unter Debian, solange die nötigen Apache Module (PHP5) installiert sind.

      • Vielen Dank.

        Ich hab nämlich ein ähnliches Projekt in meiner Firma am laufen. Nur sollen bei uns 8 Access-Points eingerichtet werden, kann ich den Server, Router, Access-Points und Clients alle in einem Netz händeln?

        • Prinzipiell wäre das auch möglich, ob es Sinn macht, ist die andere Frage. Grundsätzlich können die APs, der Server und der Router in einem Subnetz sein, ebenfalls die WLAN-Client. Allerdings macht es bei einem Gast-WLAN evtl. mehr Sinn, dass die Gäste in einem anderen Subnetz sind.
          Wenn das WLAN nicht nur für Gäste sein soll, sondern vielleicht für die Mitarbeiter der Firma, sollte man überlegen, ob man den Chillispot nicht vielleicht direkt auf dem Server betreibt, damit man einen festen WPA-Key verwenden kann (was mit meiner Lösung hier ohne weiteres nicht möglich ist).

          • Für die Mitarbeiter wird es ein seperates WLAN geben, das kein Radius benötigt, somit wäre dies nicht von Nöten.

            Kann ich dann das Gäste WLAN auf jedem Access-Point nutzen, also die 192.168.182.0/24 einstellen und die ersten acht IP’s bekommen dann die Access-Points die über die Firma verteilt sind. Der Rest würde für DHCP zur Verfügung stehen.

            Und ein letztes. Kann ich für alle acht Geräte die gleiche SSID nutzen?

          • Imrazor

            Nutzen kannst du das auf jedem AP, ich weiß nur nicht, ob man nicht besser den IP-Adress-Raum für jeden AP eindeutig machen muss, nicht, dass z.B. zwei APs die selbe IP verteilen.

            Die IPs der APs selbst sind kein Thema, die sollen ja im alle im selben Subnetz sein, vergeben wirst du die ja selbst. Die Gast-Clients sind ja im 182er Subnetz.

            Klar kannst du auf jedem AP die selbe SSID einstellen, der Client wird dann den mit der stärksten Leistung nehmen.

  4. Mit dem IP Adress Raum hast du Recht, müsste ich einen zentralen DHCP Server angeben, aber das muss ja nicht sein.

    Vielen Dank für deine Hilfe.

    • So ist es. Wenn du noch weitere Fragen hast, kannst du mir auch gerne eine Mail schicken.

  5. Hallo,

    erst mal vielen dank für die hammer Anleitung. Klappt fast alles.:-)

    Bin gerade bei den Datenbanken und da ich da nicht so ahnung habe bitte wie mache ich :

    „Mit einem Fremdschlüssel auf die ID der Benutzernamen in der Tabelle ‘radcheck’ verknüpfen wir die Tabllen ‘radcheck’ und ‘firma’ miteinander.“

    Und in der create_user.php muss ich nur die Zugangsdaten ändern oder?

    Vielen dank nochmal

    • Hallo Bierbauch,

      achja, ich dachte, das fällt keinem auf, dass ich genau an dieser Stelle nicht mehr genau wusste, wie man den Fremdschlüssel anlegt :-D

      Ich habe nochmals entsprechend nachgeforscht und die Anleitung erweitert (siehe oben). Aber um es hier auch nochmal zu sagen:
      Nachdem die beiden Tabellen bereits existieren muss nachträglich der Fremdschlüssel eingefügt werden, das geht (soweit ich mich nicht irre) mit:

      ALTER TABLE firma
      ADD FOREIGN KEY (id)
      REFERENCES radcheck(id);

      Zu deiner zweiten Frage:
      So ist es, du musst die nachfolgenden Zeilen entsprechend deiner Konfiguration ändern:

      $db_host = „localhost“; <– sollte passen, außer die Datenbank läuft auf einem anderen Server, als das Skript

      $db_user = "datenbank_user"; <– Den Usernamen angeben, den du angelegt hast und der auf die DB zugreifen darf.

      $db_pass = "datenbank_passwort"; <– Das Datenbankpasswort, das du gesetzt hast.

      $db_name = "radius"; <– Datenbankname, wenn du sie nicht "radius" genannt hast, entsprechend anpassen.

      Ich hoffe, ich konnte dir weiterhelfen.

      • Hi danke für die Antwort bekomme aber folgende Fehlermeldung:

        mysql> ALTER TABLE firma ADD FOREIGN KEY (id) REFERENCES radcheck(id);
        ERROR 1005 (HY000): Can’t create table ‚radius.#sql-26c_3a‘ (errno: 150)

        tabelle Firma ist unter radius angelegt und mit den parametern wie oben angegeben.

          • Bierbauch

            Fehler gelöst. in der Table firma muss die id unsigned sein! Das war sie nicht und dann hat es geklappt!!!!

            dafür bekomme ich jetzt, dass die Datenbank nicht errecihbar ist wenn ich auf „Auflistung aller Accounts“ klicke obwohl der Benutzername und das Passwort in der create_user.php richtig ist :-(

            Fragen über Fragen ;-)

          • Bierbauch

            Auflistung der Accounts -> Gelöst wenn man in allen Scripten den USer und das Paswort einträgt ;-)

            Neues Problem -> Beim anlgen eines neue Accounts –> TCPDF ERROR: [Image] Unable to get image: images/logo.jpg

            Der Ordner TCPDF liegt neben den Hotspot files

          • Imrazor

            Dir fehlt eine Logo-Bilddatei im Ordner images.

            Such dir ein logo.jpg, das du gerne in der PDF habe möchtest und kopier es in den entsprechenden Ordner, dann geht es.

            Oder du kommentiertst die beiden nachfolgenden Zeilen im Skript create_user.php aus:
            $image_file = ‚images/logo.jpg‘;
            $this->Image($image_file, 10, 10, 30, “, ‚JPG‘, “, ‚M‘, false, 300, “, false, false, 0, false, false, false);

          • Bierbauch

            Hi danke nochmal jetzt klappt alles!!!!

            Vielen dank

          • Imrazor

            Super, freut mich, dass alles geklappt hat und du dich nochmal gemeldet hast. So kann ich mir sicher sein, dass es nicht nur bei mir funktioniert hat ;-)

  6. Ja, heißt schon firma :-)

    Leider bekomme ich den Fehler immernoch!
    Noch eine Idee?

    Gruß

  7. Ich schon wieder.

    Bei folgendem Befehl:
    INSERT INTO radcheck VALUES (“,’User001′,’Password‘,‘:=‘,’passwort‘);

    Bekomme ich diese Meldung. Er schreibt mir die ID nicht automatisch. Hast du eine Idee?
    Warning | 1366 | Incorrect integer value: “ for column ‚id‘ at row 1

    Danke

    Ich hab das auf Debian aufgesetzt.

  8. 5.1.61-0 Version ist am laufen.

    Hab sql-mode=“NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION“ nun eingestellt, aber gewirkt hat es noch nicht, aber danke für den Tipp.

    • Tschuldigung, ich war zu übereillig. Der Fehler erscheint aber nun wird es eingetragen.

      • Anscheinend ist das ein Bug in der 5er Version von MySQL. Ich konnte den Fehler allerdings nicht nachvollziehen. Ist halt blöd, wenn bei jedem Eintrag eine Fehlermeldung im Log landet, selbst, wenns funktioniert hat.

  9. Wenn ich mich nun versuch einzuloggn bekomme ich folgende Fehlermeldung

    [sql] expand: SELECT id, username, attribute, value, op FROM radcheck WHERE username = ‚%{SQL-User-Name}‘ ORDER BY id -> SELECT id, username, attribute, value, op FROM radcheck WHERE username = ‚User001‘ ORDER BY id
    rlm_sql: Failed to create the pair: Invalid octet string „300“ for attribute name „Max-All-Session“
    rlm_sql (sql): Error getting data from database
    [sql] SQL query error; rejecting user
    rlm_sql (sql): Released sql socket id: 4
    ++[sql] returns fail

    Wieso kann der mit den 300 nichts anfangen? Füge wie oben beschrieben die Benutzer hinzu.

  10. Hallo,
    erstmal danke für das schöne HowTo :) Vorweg eine Frage: Welche Version von DD-WRT benutzt du denn? Das is leider nirgends ersichtlich
    Bei der von mir verwendeten Version (Router: E2000, Firmware: v24-sp2 (12/20/11) mega – v18024) gibt es bei Chillispot die Option „Seperate Wifi from the LAN Bridge“ nicht, dafür kann ich das bei den WLAN Einstellungen auswählen.
    Ansonsten läuft alles (freeradius, sql & apache). bei einem lokalen radtest funktioniert alles wunderbar, beim versuch mich per client in das interface einzuloggen scheitere ich allerdings – login failed. im debuglog bekomme ich „chap password check failed“, allerdings benutze ich das selbe passwort wie für den lokalen radtest…
    Evtl. fällt dir ja noch etwas ein? ;)
    Gruß iro

  11. Hallo!

    Freut mich, dass dir mein HowTo gefällt, danke! :-)

    Ich benutze für den Router Linksys WRT160NL die Firmware v24 preSP2 [BETA] Build: 14896. Das ist die aktuellste Firmware, die diesen Router unterstützt.

    „Separate Wifi from the LAN Bridge“ muss man nicht zwingend benutzen, das besagt nur, dass die LAN-Anschlüsse separat behandelt werden vom DHCP-Server.

    Was deinen Fehler hervorruft kann ich jetzt so auch nicht sagen, ist aber gut möglich, dass der Router keine richtige Verbindung zum Server bekommt. Prüfe ob der Server über das Subnetz des Routers ping-bar ist und ob die Client-Einstellungen beim freeradius richtig gesetzt sind. V.a. auf den IP-Eintrag achten, ob das schon der Router ist.

    Gruß
    Imrazor

  12. Hallo imrazot,
    das ging ja fix :) ok du hast also die aktuellste version laut router DB genommen. hier ftp://ftp.dd-wrt.com/others/eko/BrainSlayer-V24-preSP2 findest du n haufen weitere für deinen router ;) bzw. dort findest du alle builds die es gibt und bei der neusten version (r19342) findest du hier den build für den WRT160NL: ftp://ftp.dd-wrt.com/others/eko/BrainSlayer-V24-preSP2/2012/06-08-12-r19342/linksys_wrt160nl/

    zurück zum eigentlichen problem^^ mein setup sieht ein klein wenig anders aus wie bei dir, und zwar hat mein radiusserver die 192.168.1.2 und hängt mit am dd-wrt. der rest ist gleich (zweiter router bzw. noch ein dritter der fürs inet zuständig ist). das ist ein anderes netz (192.168.178.0/24). die bridge ist unter den wlan einstellugnen disabled und bei chillispot hab ich eth1 ausgewählt. die zweite option wäre LAN, was wir ja nicht wollen.

    per wlan client bekomme ich eine ip aus dem 192.168.182.0er netz und der radius server ist pingbar. die weiterleitung auf die hotspotlogin.cgi funktioniert auch, und bei einem loginversuch macht sich das debuglog des radius auch bemerkbar, rejected die anfrage allerdings mit einem chap-fehler. der hotspot ist auch als client eingetragen, ebenso (zur sicherheit) der radiusserver selbst und die loopback schnittstelle. über localhost funktioniert die authentifizierung auch ohne probleme, allerdings nicht über den chillispot. uam secret hab ich schon mehrfach überprüft und auch geändert, leider ohne erfolg.

    nächster versuch ist ein downgrade von r18024 auf r15962 und ne komplette neuinstallation von ubuntu. das mistding muss am wochenende laufen -.-

    vielleicht hast du noch ne weitere idee? :)

    gruß iro

  13. Hey Imrazor,

    auf den links war ich leider auch schon, aber danke für die hilfe! mittlerweile hab ich mich aus lauter verzweiflung an die freeradius mailing list gewandt (http://freeradius.1045715.n5.nabble.com/Problem-with-CHAP-Authentification-td5713646.html).
    laut den antworten liegt das ganze am dd-wrt, der anscheinend das CHAP Passwort falsch berechnet. „The hostspot device is NOT calculating the correct CHAP-Password. Go fix it.“
    Da chillispot nur chap und Wireless Protected Access (WPA) unterstützt und das zweite Setup garantiert nicht einfacher ist, bin ich jetzt etwas verloren^^ mittlerweile nutze ich build r14853, werde aber gleich mal ein upgrade auf dein build machen. und das ganze von vorn probieren…

    Gruß iro

  14. Nachtrag: ES TUT!

    Vielen Dank für deine Hilfe Imrazor. Nachdem mich die Maillingliste vom freeradius abgebracht hatte, hab ich nochmal etwas gespielt und dabei per zufall rausgefunden, dass die hotspotlogin.cgi, die ich immer wieder bearbeitet habe, im falschen Pfad lag… hatte die in /var/www/cgi-bin bearbeitet, dabei lag sie, wie von dir angegeben, unter /usr/lib/cgi-bin.

    Ergo war somit das UAM-Secret in der hotspotlogin.cgi nicht angepasst und deshalb der fehler bei der authentifizierung. Dabei war ich mir so sicher, dass ich den Pfad angepasst hatte^^

    Gruß iro

    • Super, das freut mich!
      Ich hab schon sowas vermutet, wie gesagt, meistens hakt es immer auf der Serverseite und nicht auf der Routerseite.

      CGI-Skrite liegen immer (oder standardmäßig) unter /usr/lib/cgi-bin, während richtigerweise alle andere „Web-Files“ unter /var/www/ liegen.

      Hauptsache es tut jetzt ;-)

  15. Hallo!

    Das ist eine super Arbeit.
    Aber ich habe das Problem, dass zwar die Daten in der Datenbank erstellt werden,
    ebenso wird ein PDF Dokument erstellt und geöffnet, dieses ist aber bis auf das Logo und dem Titel leer. Achja, die Seitenanzahl wird auch angezeigt, aber nicht der Text mit den Zugangsdaten.
    Hier mal der Code:

    // Pruefen ob der neue Datensatz tatsaechlich eingefuegt wurde
    if (mysql_affected_rows() == 1)
    {
    // echo „Der Datensatz wurde hinzugefügt“;
    require_once(‚tcpdf/config/lang/ger.php‘);
    require_once(‚tcpdf/tcpdf.php‘);

    // Extend the TCPDF class to create custom Header and Footer
    class MYPDF extends TCPDF {

    //Page header
    public function Header() {
    // Logo
    $image_file = ‚tcpdf/images/logo.jpg‘;
    $this->Image($image_file, 10, 10, 100, “, ‚JPG‘, “, ‚M‘, false, 300, “, false, false, 0, false, false, false);
    // Set font
    $this->SetFont(‚helvetica‘, ‚B‘, 20);
    // Title
    $this->Cell( 0, 15, ‚WLan-Gastzugang‘, 0, false, ‚C‘, 0, “, 0, false, ‚M‘, ‚M‘);
    }

    // Page footer
    public function Footer() {
    // Position at 15 mm from bottom
    $this->SetY(-15);
    // Set font
    $this->SetFont(‚helvetica‘, ‚I‘, 8);
    // Page number
    $this->Cell(0, 10, ‚Page ‚.$this->getAliasNumPage().’/‘.$this->getAliasNbPages(), 0, false, ‚C‘, 0, “, 0, false, ‚T‘, ‚M‘);
    }
    }

    // create new PDF document
    $pdf = new MYPDF(„L“, „mm“, „A5“, true, „UTF-8″, false); // L=Blatt quer – P=Blatt längs

    // set document information
    $pdf->SetCreator(PDF_CREATOR);
    $pdf->SetAuthor(‚Autor‘);
    $pdf->SetTitle(‚GastWLAN Zugangsdaten‘);
    $pdf->SetSubject(‚GastWLAN‘);
    $pdf->SetKeywords(‚GastWLAN‘);

    // set default header data
    //$pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE.‘ 006′, PDF_HEADER_STRING);
    $pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE, PDF_HEADER_STRING);

    // remove default header/footer
    //$pdf->setPrintHeader(false);
    //$pdf->setPrintFooter(false);

    // set header and footer fonts
    $pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, “, PDF_FONT_SIZE_MAIN));
    $pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, “, PDF_FONT_SIZE_DATA));

    // set default monospaced font
    $pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);

    //set margins
    $pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
    $pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
    $pdf->SetFooterMargin(PDF_MARGIN_FOOTER);

    //set auto page breaks
    $pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);

    //set image scale factor
    $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);

    //set some language-dependent strings
    $pdf->setLanguageArray($l);

    // ———————————————————

    // set font
    $pdf->SetFont(‚helvetica‘, “, 10);

    // add a page
    $pdf->AddPage();

    // writeHTML($html, $ln=true, $fill=false, $reseth=false, $cell=false, $align=“)
    // writeHTMLCell($w, $h, $x, $y, $html=“, $border=0, $ln=0, $fill=0, $reseth=true, $align=“, $autopadding=true)

    // create some HTML content
    // Print a text
    $html = <<<EOF

    Zur Benutzung des Gäste WLANs bitte die nachfolgende Punkte durchführen

    Verbinden sie sich mit dem WLAN der SSID GH

    Rufen sie mit dem Browser eine beliebige Internetseite auf, sie werden dann zu einem Login-Fenster umgeleitet. Als Login benutzen sie nachfolgende Daten:

    Benutzername: $username

    Passwort: $value1

    Ihr Zugang ist für folgenden Zeitraum gültig: $value2 Tag(e)

    DISCLAIMER

    Eine Verfügbarkeit oder Störungsfreiheit kann nicht garantiert werden!

    Der Benutzer verpflichtet sich mit dem Login, den Gastzugang ausschließlich im Rahmen seiner beruflichen Tätigkeit zu nutzen.
    Die Benutzerinformationen werden für einen Zeitraum von 6 Monaten gespeichert.
    EOF;
    $pdf->writeHTML($html, true, false, true, false, “);

    //Close and output PDF document
    $ziel = „logins/“ . $username . „.pdf“;
    $pdf->Output($ziel, ‚FI‘);

    echo „Der Datensatz wurde hinzugefügt!“;
    }
    else
    {
    echo „Der Datensatz konnte nicht hinzugefüwerden!“;
    // Hier koennen Massnahmen ergriffen werden die ueber den Misserfolg informieren
    // wie z.B. den Benutzer darueber zu informieren, dem Admin eine Mail schicken
    // damit er sich um den Fehler kuemmern kann, etc pp
    }
    }
    }
    ?>

    • Hallo!

      Ziemlich schwer zu sagen, wieso er bei dir die PDF nicht füllt.
      Aber wenn du sie wirklich genauso formatiert hast, wie sie hier dargestellt ist, dann kannst nicht gehen, weil Teile des HTML-Codes fehlen.

      Die Datei, die ich hier vorgestellt habe und die beim Download dabei ist geht 100%ig. Bitte prüf nochmal, ob der Code wirklich komplett ist.
      Als zweites solltest du nochmal prüfen, ob TCPDF auch richtig installiert und eingerichtet wurde.

      Grüße
      Imrazor

  16. Danke für deine schnelle Antwort.
    Ich habe den kompletten Code deiner Datei genommen (wollte nur nicht den gesamten Code posten) und nur ein paar Dinge abgeändert, Zugangsdaten zur Datenbank, Seitenformat auf A5 und den Text (Hinweise).
    Ich werde morgen mal die Installation von TCPDF prüfen und gib dann eine Rückmeldung.

    Gruß
    Nub

    • Ok, dann sollte es aber auch funktionieren, wenn TCPDF richtig installiert und eingerichtet ist (Dateirechte, etc.).
      Falls es dann immer noch nicht funktioniert, dann schick mir doch mal den Code für das Erzeugen der PDF an imrazor.rukimar[at]gmail[punkt]com. Dann schau ich mal drüber, ob mir was auffällt.

      Gruß
      Imrazor

  17. Hallo zusammen,

    ich habe das selbe unter OpenWRT versucht. Der freeRadius läuft auf einer virtuellen Maschine (Ubuntu Server 12.04). Würde aber gerne meine eigene Login-Seite erstellen und hinterlegen. Wie und wo kann ich die einfügen/abändern? Wäre es auch möglich den Radiusserver auf dem MS Windows Server 2003 laufen zu lassen und einen eigenen Webserver (xampp) damit zu verbinden? Wäre super, wenn Ihr mir dort helfen könntet.

    Gruß Jay

    • Hallo Jay!

      Die Login-Seite auf die umgeleitet wird, ist – wie im Artikel beschrieben – die hotspotlogin.cgi. Zu finden unter /usr/lib/cgi-bin/hotspotlogin.cgi.

      Diese kannst du entsprechend anpassen, wie du sie gerne hättest. Natürlich lässt sich wahrscheinlich auch auf eine PHP-Seite umleiten etc. Die Standardlösung aber ist halt mit der CGI.

      Es sollte bei richtiger Konfiguration auch möglich sein, dass ein anderer Radiusserver zum Einsatz kommt und/oder auf einem anderen Server läuft. Aus meiner Sicht alles Konfigurationssache.

      Selsbt gemacht habe ich es aber nur so, wie es hier beschrieben ist. Und so rennt es mittlerweile auch bald ein Jahr wunderbar und ohne Probleme.

      Grüße
      Imrazor

      • Hallo,

        danke für die schnelle Antwort.
        Problem bei mir ist, dass das Verzeichnis cgi-bin leer ist. Die Log-In Seite (von chillispot) wird aber korrekt angezeigt. Muss ich die Seite vor dem entpacken auf dem Ubuntu Server abändern?

        Gruß Jay

        • Dann kann es sein, dass die hotspotlogin.cgi von woanders geladen wird. Keine Ahnung, wie das mit OpenWRT und deiner Konfiguration ist.
          Nach meiner Anleitung muss man die hotspotlogin.cgi erst runterladen und dann ins entsprechende Verzeichnis kopieren. Und dann muss natürlich auch die Umleitung auf genau diese Seite eingerichtet werden: „Die Redirect URL ist die URL auf die ein Client umgeleitet wird, wenn er eine Internetseite aufruft. Diese URL verweist also auf die hotspotlogin.cgi auf unsrem Server: http://192.168.2.2/cgi-bin/hotspotlogin.cgi

          Wie gesagt, es steht alles in der Anleitung. Wie es bei deiner speziellen Konfig ist, kann ich ohne weiteres nicht sagen. Such doch einfach mal nach der hotspotlogin.cgi, wo die hingekommen ist: „locate hotspotlogin.cgi“ z.B.

          Die Seite wird – wie in der Anleitung beschrieben – heruntergeladen und entpackt. Danach kannst du sie „beliebig“ editieren (so, dass sie halt noch funktioniert ;-) )

          Grüße
          Imrazor

  18. So, da bin ich wieder.

    Leider bin ich keinen Schritt weiter gekommen.
    Fairerweise muss ich zugeben, dass ich nicht das hier beschriebene System benutze, aber bisher dachte ich, dass es zur Logindatenerstellung egal sei.
    Anscheined doch nicht. Hier mein System:

    Ich benutze pfsense auf einem alten PC mit dem installierten Paket freeradius2.
    Das funktioniert problemlos.

    Auf einer Qnap-NAS läuft mysql mit phpmyadmin.
    tcpdf liegt somit auch auf der NAS.
    Und schon stehe ich vor dem Problem,
    dass zwar die Daten vom hier zur Verfügung gestellten Web-Formular in mysql eingetragen werden, aber die PDF-Erstellung in die Hose geht.
    Die PDF wird erstellt, aber es ist nur das Logo, die Überschrift „WLAN-Gastzugang“ und die Seitenzahl unten zu sehen.
    Ansonsten bleibt die Seite leer.

    Eigentlich scheint die Seite ja erzeugt zu werden, nur Der „Haupttext“ mit den Logindaten wird nicht in die PDF geschrieben.
    Infolge dessen sollte tcpdf funktionieren.

    Es wäre super, wenn mir da Jemand helfen kann.

    • Hallo Nub,

      bitte schick mir doch einfach mal die Datei, in der du den TCPDF Code hast an imrazor.rukimar@gmail.com.
      So kann ich so besser ausschließen, dass keine Fehler in den Anweisungen sind.

      Normalerweise sollte das auch mit deiner Konfig klappen. Allerdings würde ich nochmal prüfen, welche PHP-Version auf deiner QNAP-Laufen und welche TCPDF benötigt.
      Sind alle Berechtigungen richtig gesetzt etc? (Dateiberechtigungen…)

      Kannst du ein Standardbeispiel von der TCPDF-Seite generieren? Also mal eins von denen Testen, ob das bei dir hinhaut.

      Grüße
      Imrazor

  19. Deine Lösung ist professionell öffnet aber gefährliche Schwachstellen.
    Jeder kann sich mit deinem Wlan verbinden und da du SSL desktiviert hast das Passwort für den Gastzugang binnen Sekunden aus deinem Traffic fischen.
    Bedingung:
    Es muss sich jemand anmelden.

    Nach Aktivierung von SSL brauchbar, sofern du deinen Webserver gut absicherst.
    Sonst attackiert man den und hat Jackpot-like nicht nur Internet sondern gleich noch einen Webserver, über den man ggf. unbemerkt dauerhaft den gesamten Traffic der Gäste abhören kann.
    Sehr angenehm.

    • Danke für deinen konstruktiven Hinweis. In der Praxis habe ich bereits SSL aktiviert, nur noch nicht in diese Anleitung aufgenommen.
      Auch der Webserver sollte ausreichend genug abgesichert sein. Eine 100%ige Sicherheit gibt es aber bekanntlich nie, wenn man etwas relativ öffentlich zugänglich macht.

      Wie man SSL aktiviert, werde ich bei Zeiten mal in das Tutorial einarbeiten.

  20. Hallo,

    Könntest du zu den Spalten der Tabelle firma noch die verwendeten Datentypen und ggf. Besonderheiten (AUTO-INCREMENT) schreiben?

    Das würde mir als SQL-Unbedarftem weiterhelfen.

    • Hallo Alex,

      sorry, dass ich leider erst mit etwas Verspätung antworte, dafür habe ich gerade eben den Beitrag erweitert. Die Datentypen und Besonderheiten habe ich ergänzt, ebenfalls einen Screenshot, wie die Tabelle in meinem phpMyAdmin aussieht.
      Ich hoffe das hilft dir ein wenig weiter.

      Grüße
      Imrazor

      • Hallo,

        Danke.

        Ich hatte mir für heute auch professionelle Hilfe organisiert.

        Wenn du am Ergebnis interessiert bist, kann ich dir das ja mal per Mail zuschicken.

        Wir haben folgendes geändert:

        * die 1-5 Tage gegen einen Datepicker und eine Uhrzeit-Auswahl ausgetauscht (bedingte die Änderung der beiden date-Spalten in Tabelle firma in datetime)

        * die Laufzeit der Accounts beginnt sofort mit dem Erstellen (durch Eintrag in radacct)

        * die Schriftart für Nutzer und Passwort in der PDF auf courier geändert (ist lesbarer – vor allem bei l und I gab es Probleme)

        * die hotspotlogin.cgi auf Deutsch umgestellt und die merkwürdige Radius-Meldung bei Ablauf des Accounts („Your maximum never usage time has been reached“) angepasst

        * die Löschfunktionen von der reinen Auflistung abgetrennt und via htaccess abgesichert

        * die ipup.sh so angepasst, dass nur erwünschte Dienste (HTTP POP3 SMTP IMAP und jeweils +S) nutzbar sind

  21. Hallo!

    Super HowTo! Habe so lange nach einer Anleitung gesucht um so etwas umzusetzen – klasse!
    Habe fast die selber Umgebung wie du – nur ist es ein AVM Router und der hängt an einem Switch (24 Ports) von TP-Link. Daran mein eigener kleiner NAS Server (Ubuntu 12.04.02 LTS). Als WLAN Router setze ich auch den WRT160NL ein ;-)
    Dank deiner Anleitung war es ein Kinderspiel den Router zu konfigurieren. Auch die Installation von FREERADIUS war eigentlich recht einfach. Dann der 1. Probelauf. Mit meinem Notebook via WLAN mit dem WRT160NL verbunden. Irgend eine Seite aufgerufen – direkt die Weiterleitung zum Login – super!
    Aber dann – FREERADIUS will einfach nicht (freeradius 2.1.10+dfsg-3ubuntu0.12.04.1). Habe dann mal FREERADIUS im DEBUG Modus gestartet. Folgende Meldung erscheint immer nach dem Login:
    Error: Ignoring request to authentication address * port 1812 from unknown client 192.168.178.5 port 32784

    192.168.178.5 ist die IP Adresse des WLAN Routers am WAN Port.
    Habe schon gegoogelt was das Zeug hält. Komme an diesem Punkt einfach nicht weiter!! (Bei dir ist der IP Bereich 192.168.2.0 , bei mir 192.168.178.0) – das alles habe ich berücksichtigt beim Router – da scheint ja auch alles zu klappen.
    Hast du für mich einen Rat woran es liegen kann? Denke ich bin ganz nah dran, dass es klappt! ;-)

    Grüße

    Christian G.

    • Hallo Christian!

      Vielen Dank für das Lob, freut mich, dass dir mein HowTo gefällt und es dir ein wenig weitergeholfen hat.

      Zu deiner Frage:
      Ich vermute schwer, dass du die IP 192.168.178.5 nicht richtig in die clients.conf eingetragen hast. Denn genau diese IP wird geprüft. Vorsicht: die IP ist die des WLAN-Routers, der den Chillispot im Bauch hat! Nicht der Internetrouter!

      Also Client-IP des WRT160NL eintragen. So wie ich es verstanden habe (du schreibst WLAN-Router am WAN Port, sprich nicht der WRT160NL?) hast du den falschen Router als Client eingetragen.

      Mit freeradius kommuniziert nämlich der Chillispot und der rennt nunmal auf dem WRT160NL.

      Falls ich das nur falsch verstanden habe, prüfe mal, ob in der sql.conf die Zeilen bzgl. Clients aus Datenbank lesen auskommentiert sind:
      #readclients = yes
      Denn sonst versucht er evtl in der Datenbank nach den Clients zu suchen, wo er natürlich nix findet, da nicht konfiguriert in meiner Anleitung…

      Grüße
      Andreas

      • Imrazor :
        Hallo Christian!
        Vielen Dank für das Lob, freut mich, dass dir mein HowTo gefällt und es dir ein wenig weitergeholfen hat.
        Zu deiner Frage:
        Ich vermute schwer, dass du die IP 192.168.178.5 nicht richtig in die clients.conf eingetragen hast. Denn genau diese IP wird geprüft. Vorsicht: die IP ist die des WLAN-Routers, der den Chillispot im Bauch hat! Nicht der Internetrouter!
        Also Client-IP des WRT160NL eintragen. So wie ich es verstanden habe (du schreibst WLAN-Router am WAN Port, sprich nicht der WRT160NL?) hast du den falschen Router als Client eingetragen.
        Mit freeradius kommuniziert nämlich der Chillispot und der rennt nunmal auf dem WRT160NL.
        Falls ich das nur falsch verstanden habe, prüfe mal, ob in der sql.conf die Zeilen bzgl. Clients aus Datenbank lesen auskommentiert sind:
        #readclients = yes
        Denn sonst versucht er evtl in der Datenbank nach den Clients zu suchen, wo er natürlich nix findet, da nicht konfiguriert in meiner Anleitung…
        Grüße
        Andreas

        Hallo Andreas!
        Es lag wirklich an der clients.conf. Eigentlich hatte ich es wie in der Anleitung gemacht. D. h. die IP Adresse des FREERADIUS Servers eingetragen. War bei mir die 192.168.178.25 . Habe sie aber durch die IP Adresse des WLAN Routers (192.168.178.5) ersetzt – und nun klappt es!! Echt klasse!! Kann es sein, dass es keine Weiterleitung zum ChilliSpot Login gibt wenn man eine https Seite aufruft und noch nicht eingeloggt ist?
        Grüße

        Christian

        • Hallo Christian!

          Schön, dass ich dir helfen konnte. Hier habe ich wohl evtl. einen Fehler in meiner Anleitung, muss ich mal korrigieren.

          Dass die Weiterleitung bei https-Seiten nicht geht, kann gut möglich sein, habe ich aber noch nicht getestet. Du solltest sowieso mal versuchen, die Chillispot Loginseite verschlüsselt anzubieten. Also den https-Teil in der hotspotlogin.cgi nicht auskommentieren und entspechende SSL-Zertifikate erzeugen (gibt’s einige Anleitungen im Internet).

          Vielleicht geht dann auch die Weiterleitung bei https-Seiten…

          Grüße
          Andreas

  22. Hallo,

    klappt teilweise bei mir.

    Ich hatte ausversehen, die Route auf LAn gestellt. Somit kam ich nicht mehr auf den WRT. -> Per Taste zurück gesetzt -> Route wieder neu eingetragen.

    Jetzt ist aber folgendes: Immer wenn ich in den 192.168.182.x Netz bin und eine Seite aufrufen werd eich auf [IP-Radius]/cgi-bin/hotspotlogin.cgi?res=notyet&uamip=192.168.182.1&uamport=3990&challenge= ….. umgeleitet.

    Aber es wird keine Seite aufgerufen, sondern es erscheint die Meldung, dass die Seite nicht geöffnet werden konnte :(

    Hat jemand eine Idee?

    Vielen Dank

  23. Hallo,

    ich habe strikt nach Anleitung die ganze Sache aufgesetzt. Allerdings hängt jetzt bei mir an 2 Problemen:

    1. wenn ich „sudo freeradius -XXX“ eingebe, bekomme ich folgende Fehlermeldung:

    Mon Jul 29 14:49:56 2013 : Error: Failed binding to authentication address * port 1812: Address already in use
    Mon Jul 29 14:49:56 2013 : Error: /etc/freeradius/radiusd.conf[240]: Error binding to port for 0.0.0.0 port 1812

    Bin leider am Ende mit meinem Latein. Was ist da schief gelaufen?

    2. An meinem Linksys-Router kann ich leider beim konfigurieren des Chillispots „ath0“ nicht auswählen. Bei mir gibt es nur: LAN, eth0, eth1, vlan0, etherip0

    Was ist nun meine Wahl?

    • Hallo Marcel,

      zu deiner ersten Frage: Könnte sein, dass freeradius schon gestartet wurde im Hintergrund. Bitte „/etc/init.d/freeradius stop“ ausführen und dann nochmal
      „freeradius -XXX“.

      Zu deiner zweiten Frage: Eventuell ist bei dir das WLAN eth1. Bitte mal testen, könnte funktionieren.

      Gruß
      Imrazor

  24. Hey,

    konnte beim Problem selbst lösen. Hatte einen Gateway-Fehler.

    Den Freeradius-Server-Fehler von Marcel hab ich auch. Wenn ich den Freeradius Kille und dann -XXX ausführe kommt das er Anfragen annimmt. Beim normalen Start kommt der Fehler.
    Vielleicht könnte mal jemand seine radius conf posten? :)

    @Marcel: ja, bei meinem Linksys ist eth1 auch das WLAN.

  25. Hallo,

    ein fantastischer Beitrag und sehr gut umzusetzen! Vielen Dank dafür!

    Leider bringt das Shell-Script für das Löschen der alten Datensätze nur Fehler, woran könnte das liegen?

    expr: Argument, das keine Zahl ist
    expr: Argument, das keine Zahl ist
    expr: Syntaxfehler
    ERROR 1064 (42000) at line 1: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near “ at line 1
    ERROR 1064 (42000) at line 1: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near “ at line 1
    ERROR 1064 (42000) at line 1: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near “ at line 1
    ERROR 1064 (42000) at line 1: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near “ at line 1

    • Hallo Marco,

      danke für das Lob, freut mich!

      Zu deiner Frage: Ich kanns mir auch nicht wirklich erklären, weshalb du die Fehler bekommst. Aber die Meldungen beziehen sich ja auch Syntaxfehler etc. In diesem Zusammenhang würde ich dann folgendes mal prüfen:

      1. Hattest du die Skript-Datei unter Windows offen und hat dir der Editor evtl. den Zeichensatz durcheinander gebracht?
      2. Hast du den Inhalt der Datei mit Copy und Paste eingefügt? Das kann ebenfalls zu Fehlern führen.
      3. Irgendwo eine auskommentierte Zeile aus Versehen wieder „einkommentiert“?

      Shellskripte haben oftmals ihre Tücken im Detail…

      Grüße
      Andreas

  26. Hallo Andreas,

    der Fehler tritt scheinbar auf, wenn kein Datensatz älter als 3 Monate ist.

    $max_firma_id hat dann den Wert „NULL“, und das führt in der Zeile

    korr_wert2=$(expr $max_firma_id * 2)

    dann zu der Fehlermeldung „expr: Argument, das keine Zahl ist“ – die Folgefehler resultieren, denke ich, daraus.

    Leider habe ich nicht wirklich Ahnung von Shellprogrammierung :-(

    Vielleicht hilft Dir das aber weiter. Script hat keine Fehler soweit ich sehen kann durch Copy-and-paste.

    Liebe Grüße
    Marco

    • Hallo Marco,

      OK, daran kann es liegen. Ist ja auch schon eine Zeit her, dass ich das umgesetzt hab und seitdem hab ich weder etwas daran verändert, noch verbessert. Shell-Skripte programmier ich auch so gut wie nie ;-)

      Aber, ich weiß, wieso der Fehler nicht aufgefallen ist bzw. weshalb ich den Fehler nicht abgefangen habe. Das Skript wird ja per Cronjob periodisch ausgeführt und da landen die Fehlermeldungen in der Logdatei und sind mir deswegen wohl nie aufgefallen, weil das Skript ja trotzdem das macht, was es soll: Einträge, die älter sind als drei Monate löschen ;-)

      Mal sehen, ob ich irgendwann mal dazu komme, das zu korrigieren.

      Schöne Grüße
      Andreas

  27. Hallo !

    Da bin ich mal wieder. Dank der Anleitung und deiner Hilfe habe ich hier in meiner kleinen Firma das Projekt umsetzen können!

    Ein Freund machte mich aber darauf aufmerksam, dass bei der Weiterleitung zum Login (192.168.2.2/cgi-bin/….) somit für den „Gast“ klar ist, dass es ein 192.168.2.2 Netz gibt. Wenn man sich nun erfolgreich angemeldet hat kann man ohne Probleme auf den Router zugreifen (192.168.2.1) – also wenn man das Passwort kennt ;-) . Auch eventuell andere Server im Netz 192.168.2.0 sind dann erreichbar.
    Ist das so gewollt? Besser gefragt – wie kann man das verhindern?

    Grüße,

    Christian

    • Hallo Christian,

      freut mich, dass deine Umsetzung funktioniert.

      Zu deiner Frage: Das ist wohl dem System geschuldet. Ich wüsste aus den Stegreif jetzt nicht, wie man die Sache umgehen könnte. Bei mir ist allerdings nur der Radiusserver in diesem Subnetz und auf den Router kommt man nicht ohne Passwort eh klar.

      Ich kann es im Moment nicht testen, aber trennt DDWRT die Netze nicht selbst?

  28. Hi,

    ich habe diese WLAN-Lösung an unserer Schule mit ca 1300 Schülern umgesetzt. Klappt super und ist im Vergleich zur unserer WPA2-Enterprise-WLA-n-Anbindung herrlich unkompliziert.

    Allerdings ist es für mich unumgänglich, einige APs für bestimmte Nutzergruppen zu reservieren und für andere zu sperren. Bei freeradius ralisiert man das mit huntgroups. Aber da brauche ich Hilfe. Kann mir jemand mit Einrichtung und Konfiguration weiterhelfen?

    Grüße aus Hessen
    Thomas

    • Hallo Thomas,

      freut mich, wenn dir mein HowTo sogar in einer solch großen Umgebung geholfen hat!

      Leider kann ich dir jedoch nicht bei deinem Problem weiterhelfen. Vielleicht ist es auch besser, wenn du in einem freeradius-Forum nachfragst, hier wird es wahrscheinlich nicht viele User geben, die genau diese Frage beantworten können.

      Grüße
      Andreas

  29. Hallo Andreas
    Danke für die viele Arbeit und die lange Betreuung der Kommentare.

    Wir haben das System bei uns in unser Jugendbildungsstätte eingerichtet, damit unsere Gastgruppen einen W_Lan Zugang bekommen und wir nicht ein Passwort für alle Gäste rausgeben müssen. (war bis lang so)

    Das System funktioniert auch super, aber es ist nicht so ganz benutzerfreundlich.

    Die errechneten Passwörter und Benutzernamen sind gut, aber schlecht zu merken. Der Gast wählt sich einmal ins Netz ein und muss es eine stunde später wieder tun, wenn er ins Netz will.
    Kann man das so einstellen, dass sich der Benutzer nicht ständig wieder neu Anmelden muss?

    und zum einfachen merken der Zugangsdaten, kann man nicht aus dem Namen einen Benutzer generieren und es gibt nur ein PW. Dass ist schon schwirig genug für unsere Gäste sich zu merken.

    Vielleicht hast Du dazu noch eine Idee.

    Auf jedenfall hast du unseren jugendlichen Gruppen imens in ihrem Bedürfnis weitergeholfen, Soziale Netzwerke ständig nutzen zu können.
    Und natürlich unserer Einrichtung auch, denn wir haben jetzt einen Komfort, der bislang noch nicht da war.

    Viel Grüße aus Bonn
    Rainer

  30. Hallo Rainer,

    es freut mich sehr, dass ich Dir und eurer Einrichtung mit meinem kleinen Projekt weitergeholfen habe.

    Zu deinen Fragen:

    Automatisches Ausloggen:
    Ich habe keine Möglichkeit gefunden, einen Re-Login zu vermeiden, wenn der User zwischenzeitig die Verbindung getrennt hatte. Auch klar, denn Chillispot muss nach einem erneuten Verbindungsaufbau natürlich die Zugriffsrechte des Users prüfen. Deshalb ist ein Re-Login erforderlich, wenn die Session geschlossen wurde. Dies zu umgehen würde sicherlich einiges an Aufwand bedeuten. Z.B. die MAC-Adresse des User passend zum Account speichern, was aber tendenziell unsicher ist, da man MAC-Adressen schnell fälschen/duplizieren kann. Man könnte es aber evtl. mit einem Cookie lösen, aber das ist lediglich eine Idee.

    Ich muss auch ganz ehrlich gestehen, dass ich sowas noch nie umgesetzt habe und auf Anhieb auch nicht weiß, wie es fuktionieren könnte…

    Username und Passwort:

    Der Username und das Passwort wird ja von zwei Funktionen im Skript generiert:
    function user_create()
    function passwort_create()

    Diese beiden Funktionen kann man natürlich auch nach seinen Wünschen anpassen – Username/Passwort mehr oder weniger komplex etc.

    In der Zeile 60 der create_user.php wird definiert, dass der username mittels user_create() erzeugt wird:

    $username = user_create();

    Die Variable $username wird später als Benutzername in die SQL-DB geschrieben.

    Würde man jetzt als Username lieber den echten Nachnamen des Benutzers haben, so könnte man der Variable $username das Nachnamenfeld des Formulars zuordnen (analog zu „name“ in der Zeile 67):

    $username = $_POST[’name‘];

    Alles andere kann bleiben wie es ist, und auch in der erzeugten PDF sollte jetzt der Nachname als Username auftauchen.

    Probier es einfach mal aus… Ich kann es leider nicht testen, da ich momentan keine DD-WRT Umgebung zum Testen zur Verfügung habe.

    Viel Spass und Erfolg weiterhin mit dem Hotspotsystem in eurer Jugendbildungsstätte!

    Grüße
    Andreas

  31. Hallo und Danke für die klasse Anleitung!!!

    Ich bin gerade dabei mir einen Hotspot für eine Ferienwohnung einzurichten, da kommt mir deine Anleitung natürlich sehr gelegen.

    Allerdings hab ich keinen Linux-Server im Haus. Geht das ganze auch mit Windows? Es gibt ja WinRadius. Oder kann ich das ganze über einen externen Server laufen lassen? Da hätte ich einen mit „Ubuntu-Mint“ im Angebot. Dazu müsste ich also über DynDNS gehen um den externen Server dauerhaft zu erreichen.

    Der Radius Server kann ja nicht auf dem „Hotspot-Router“ laufen oder?

    MfG Chris

    • Hallo Chris,

      danke, dass dir die Anleitung gefällt.

      Hm, sicher geht es iiiirgendwie mit Windows auch, aber sicherlich nicht so, wie mit meiner Anleitung. freeradius hat sicherlich andere SQL-Einträge, wie ein Windows-Radius-Server.

      Klar, das sollte mit richtiger Konfiguration auch über einen externen Server laufen können.

      Meines Wissens nach kann der nicht direkt auf dem Router laufen. Würde ich jetzt auch nicht unbedingt machen.

      Vielleicht mal überlegen, einen Raspberry Pi als Server zu benutzen. Reicht locker aus, kostet nicht die Welt und ist eine vollwertige Linuxmaschine.

      Schöne Grüße
      Andreas

  32. nochmals danke, schön das hier kommentare beantwortet werden.

    ich bin jetzt dabei alles nach deiner anleitung auf meinem server zu installieren.

    leider gibt es das paket chillispot nicht (mehr). weder bei debian wheezy, noch unter linux mint 16.

    Homeserver / # sudo apt-get install chillispot
    Paketlisten werden gelesen… Fertig
    Abhängigkeitsbaum wird aufgebaut.
    Statusinformationen werden eingelesen…. Fertig
    E: Paket chillispot kann nicht gefunden werden.

    ich muss wohl eine andere quelle für chillispot einbinden oder? bin leider nicht so der linuxprofi und stelle sicher dämliche fragen :)

    gruß chris

  33. perfekt, so klappt das natürlich auch!

    jetzt versuche ich mich weiter.

    danke dir.

    mfg chris

  34. ich habe deine anleitung jetzt abgearbeitet, aber ich kann die hotspotlogin seite nicht erreichen. apache funktioniert aber, andere seiten kann ich erreichen. mein cups druckerserver funktioniert samt interface problemlos.

    wenn ich freeradius start bekomme ich eine ellenlange ausgabe, ist das normal?

    http://nopaste.info/642db94f38.html

    ich habe meinen DD-WRT router mit meiner fritzbox (die fürs internet) verbunden. wenn ich mich jetzt mit dem wlan des DD-WRT routers verbinde, komme ich ohne weiteres ins internet. ich muss mich nicht extra einloggen. außerdem werde ich nicht in das gesonderte chillispot subnetz geleitet.

    ich habe anscheinend noch mehr verbockt.

    mfg chris

    mfg chris

  35. mittlerweile habe ich es wenigstens geschafft das mich mein DD-WRT nach dem verbinden umleitet. allerdings ist die seite nicht erreichbar.

    http://192.168.2.41/cgi-bin/hotspotlogin.cgi?res=notyet&uamip=192.168.182.1&uamport=3990&challenge=8e9f1407fed1356f0ec6536deca5b85c&called=64-66-B3-C6-F6-35&mac=74-F0-6D-37-BE-81&ip=192.168.182.2&nasid=64-66-B3-C6-F6-35&sessionid=52a8419c00000001&userurl=http%3a%2f%2fwww.google.de%2f&md=C4BD01987D7554020E11047334376115

    außerdem ist mir noch etwas aufgefallen, wenn ich mir eine feste IP zuweise die im subnetz des DD-WRT liegt, (192.168.1.x) dann bekomme ich ohne authentifizierung zugriff zum internet. darf das sein? ich denke eher nicht.

    mfg chris

  36. Hi,

    ich bins nochmal, sorry das ich so nerve. Also erstmal musste ich beim Apache2 noch CGI aktivieren, das geht so: a2enmod cgi

    Dann funktioniert es endlich 1A und es kann an das User anlegen und PDF erzeeugen gehen.

    User werden auch angelegt und löschen kann ich sie auch. Also alles i.o. soweit.

    Nur ich bekomme es einfach nicht hin das ein PDF file erstellt wird.
    TCPDF habe ich runtergeladen und in /var/www/TCPDF installiert.

    Kommt das woanders hin?

    MfG Chris

  37. TCPDF kommt dahin, wo du es hin haben willst ;-)
    Sprich, der Aufruf in der PHP-Datei, über die die PDF-Datei erzeugt wird, muss passen:

    require_once(‚tcpdf/tcpdf.php‘);

    Das heißt, in meinem Fall liegt der TCPDF-Installationsordner im Verzeichnis, wo die Haupt-PHP-Datei liegt.

    Du kannst den Pfad auf absolut angeben:
    require_once(‚/var/www/TCPDF/tcpdf.php‘);

    Zumindest denke ich, dass das auch funktionieren sollte ;-)

    Grüße
    Andreas

  38. Vielen Dank, das funktioniert wunderbar.

    User werden angelegt und das PDF erzeugt – so weit so gut.

    Der Chillispot Login schlägt aber leider jedes mal fehl. „Chillispot Login Failed“. Irgendwas passt ihm nicht, aber aus dem Freeradius.log werd ich nicht schlau.

    Habe es auch mit verschiedenen Usernamen und Passworten versucht.

    Bei mir sieht die Konfiguration so aus: http://abload.de/img/netzwerkwfi2a.jpeg

    Freeradius.log ist hier:

    Habe leider 4 Stunden damit verbracht und bekomme es nicht hin, dabei ging es schon, allerdings nicht im aktuellen Netzwerk und nicht mit dem jetzt genutzten und extra angeschafften RaspberryPi.

    MfG Chris

  39. Erstmal ein Frohes Fest!
    Und dann nochmals Danke!

    Ich hab jetzt alles neu installiert, jetzt läuft der Raspberry Pi auch wunderbar. Ich hab wohl irgendwas zerstört gehabt.

    Wenn man die 2-3 Hürden überwunden hat die evtl. für Anfänger wie mich nicht ganz klar sind, dann ist das Tutorial Spitzenklasse!!!

    Nur eines ist mir noch nicht klar, kommt jetzt eine Klage rein das ich irgendetwas Illegales gemacht haben soll, wie komme ich an die Verbindungsdaten des Nutzers?

    MfG und ein schönes Fest.

    Chris

    • Hallo Chris!
      Sorry, dass ich ich nicht eher geantwortet habe, aber anscheinend hast du ja dein Problem mit einer Neuinstallation in den Griff bekommen.
      Das Aufsetzen des Hotspots ist nicht trivial und verlangt ein perfektes Zusammenspiel vieler Einzelkomponenten, da kann es schon mit der geringsten Fehlkonfiguration zu Problemen kommen. Ich hab damals den Spaß auch mehrmals aufgesetzt ;-)

      Also wer welche IP bekommen sollte anhand der Logdateien in /var/log/ ersichtlich sein. Problematisch wird es natürlich, wenn sich viele viele User gleichzeitig angemeldet haben, da müsste der Traffic für ein genaues Loggen der Daten über einen eignen DNS-Server gelenkt werden. Das passiert zugegebenermaßen in der hier aufgezeigten Konfiguration nicht.

      Sollte ich irgendwann wieder mal etwas Zeit finden, würde ich den Hotspot sowieso noch etwas umbauen. Loggen der Zugriffsdaten etc. Das wird aber noch etwas dauern ;-)

      Dir auch noch ein schönes Fest!

      Grüße
      Andreas

  40. Hallo, bin auf diesen tollen Bericht gestoßen. Gib es die Datei noch als Download?
    Jürgen

    • Hallo Jürgen,

      ich hab keine Ahnung weshalb der Download nicht mehr ging, aber jetzt tut der Link wieder ;-)

      Grüße
      Andreas

  41. Hallo Andreas,
    danke für den Download. Soweit hat alles geklappt, nur wenn ich den Ausdruck ohne Kopf- und Fußzeile möchte, erfolgt kein Eintrag in der Datenbank. Habe mich an das TCPDF Beispiel 2 gehalten. Gibt es noch was zu beachten?
    Danke Jürgen

  42. Hallo,
    ich weiß der Beitrag ist schon etwas älter, aber immer noch klasse. Vielen Dank dafür, ich richte die Lösung gerade für eine Ferienwohnung ein. :) Ich wollte noch etwas ergänzen, falls jemand – wie ich – unter Debian Jessie und openWRT eine Authentifizierung über WPA-2-Enterprise ermöglichen möchte:
    in der /etc/freeradius/sites-enabled/inner-tunnel
    muss „sql“ ebenfalls noch auskommentiert werden, da der freeradius-Server die Anfragen sonst nicht richtig bearbeitet.

    Danke nochmal für die klasse Anleitung, Stefan.

  43. Ich habe versucht, das mit OpenWRT und CoovaChilli zu realisieren.

    Jedoch verzweifle ich bei der Configuration vonn CoovaChilli.

    Chillispot ist ja leider schon veraltet und coova der quasi nachfolger.

    Alles andere hat problemlos funktioniert.
    Radius/MySQL/Webserver läuft auf einem Raspberry Pi unter debian jessie
    Aber Coova will unter OpenWRT einfach nicht..

  44. Moin.

    Gibt es auch eine Möglichkeit das mit einem mikrotik Routerboard und ein im Rechenzentrum stehender freeradius zu realiesieren?

  45. Hallo Frage könnte man es ev auch für ubuntu 16.04 anpassen bekomme nur weisse seite Fehler in Mysql verbindung und die Datenbank läst sich nicht erstellen vieleicht wäre mal jemand so net eine SQL File export zu machen wegen Struktur. bräuchte es echt dringend Projekt Campingplatz Freunde.

    • Hallo Klaus,

      das HowTo wird von mir nicht mehr eingesetzt und damit auch nicht mehr gepflegt. Ein Grund war die fehlende Verschlüsselung, deren Implementierung doch etwas aufwändiger geworden wäre.

      Mittlerweile empfehle ich den Einsatz von Ubiquiti-WLAN-Geräten, die es über den WLAN-Controller erlauben, ein Gast-WLAN mit Vouchers zu erstellen.

      Einfach mal danach googlen.

      Die Geräte sind z.B. der Accesspoint UAP-AC-PRO und dazu noch der Controller als eigener kleiner Rechner: UniFi Cloud Key.

      Grüße
      Andreas

  46. Hallo ich bitte um Hilfe bekome folgenden Fehler beim erstellen der Firma Tabelle
    CREATE TABLE `firma` (
    firma_id int(7) auto_increment,
    username varchar(50),
    vorname varchar(50),
    firma varchar(50),
    datum date,
    gueltig_bis date,
    id int(7) unsigned
    ) ;
    Incorrect table definition; there can be only one auto column and it must be defined as a key
    root@hotspot:/etc/freeradius# ERROR 1075 (42000) at line 6: Incorrect table definition; there can be only one auto column and it must be defined as a key

    bitte um Hilfe
    ubuntu 16 mit PHP7 hoffe das ich das ans laufen bekomme

  47. Hallo Andreas ich habe es mitlerweile Hin bekommen
    habe die PHP Scripte auf PHP 7 angepasst mit User Login für Admin
    als CHilli Server benute ich ein TPlink WR841ND von Dort aus werden die AcessPoints angeschlossen die alle Offen Sind und kein DHCP Server aktiv haben
    ich habe aber noch 1 Frage wozu ist das SH Script muss das in ner Crown auf dem Server Laufen???

    ansonsten alles Pallet der WR841ND hat das Wlan abgeschaltet er dient nur als Chilli Server das funktioniert bisher 1 A

    das Ander ist für uns leider nicht machbar weil es ein Campingplatz ist und die Anschaffung das Kapital nicht reicht.

    • Das Shell-Script dient zum regelmäßigen Ablöschen der Benutzer, die in unserem Fall nur 3 Monate gespeichert werden. Bitte hier die DSGVO beachten, das könnte mittlerweile anders sein hinsichtlich Datenspeicherung.
      Das Skript sollte in einem Cron auf dem Server laufen, richtig.

  48. OK muste es umschreiben für ubuntu 16 und Mysql einige parameter sind anders
    jetzt bin ich begeistert mache noch ein Schönes Admin bereich mit Papall anbindung das ganze rennt bei mir auf nen Minipc mit einem Tplink als Cilli server an dem wird dan eine Kopfstation per lan angeschlossen und per wlan Repeater auf dem Ploatz verteilt der TPL hat kein Wlan er ist ausschlieslich zur autorisierung da im Test aufbau funktioniert es 1 A
    aufbau der Technik Skydsl von da aus in ein Draytek router mit LTE not verbindung am Draytek miniPC und der TPLink
    alles andere ist hinterm TP Link

  49. Seh ich das richtig, dass das ganze GastWlan überhaupt nicht Abmahnungssicher ist, weil da ein VPN fehlt?
    Oder hab ich das nicht richitg verstanden?
    Voucher über Ubiquiti könnte man zwar bezahlen lassen, und somit den P2P Nutzer für illegales Filesharing somit über seine Bezahldaten evtl. dran kriegen. Aber wenn er nicht P2P macht sondern sonstigen illegalen Mist, den man auch im vorhinein nicht sperren kann, und z.B. einen gehackten Paypal Account für den Voucher benutzt, dann kriegt man ihn auch nicht dran.
    Um aber gar nicht erst abgemahnt zu werden als Eigentümer des Internetanschlusses braucht es doch ein VPN oder?

    • Hallo Dieter,

      VPN hat damit nichts zu tun. Ein VPN verschleiert nur bis zu einem gewissen Grad deine tatsächliche IP-Adresse über die du identifizierbar bist.
      Wenn jemand über deinen Internetanschluss Mist machen will, dann macht er Mist. Ein VPN hilft da nur bedingt. In meinem Ansatz ging es damals nur darum einen zeit- und personenbezogenen Gastzugang erstellen zu können.
      Diese Lösung ist mittlerweile mehr als 10 Jahre alt. Das System, das ich hier vorstelle, ging davon aus, dass der Nutzer persönlich bekannt ist, für den der Zugang erstellt wird. Notfalls könnte man sich auch den Ausweis zeigen lassen. Heute kann man es immer noch vergleichbar umsetzen, sollte aber auf die aktuelle Technik angepasst werden. Würde ich so ein System in einem Hotel oder in einer Ferienwohnung oder Campingplatz etc. anbieten, dann würde ich sowieso per Firewall auch dafür sorgen, dass bestimmte Dienste blockiert werden – wie eben P2P/Filesharing. Das hat aber nicht direkt etwas mit dem Gastzugang des WLANs zu tun.
      Und wenn man gewerblich unterwegs ist und Rechtssicherheit haben möchte, dann sollte man so etwas professionell umsetzen lassen und sich bzgl. der Rahmenbedingungnen von einem Fachanwalt beraten lassen.
      Ich kann mir aber nicht vorstellen, dass das Risiko sonderlich hoch ist, dass jemand bei einem Gastzugang Filesharing anwirft, den er z.B. nur für ein paar Stunden nutzt.

      Grüße
      Andreas

Alex antworten Antwort abbrechen

Pin It