Fórum Ubuntu CZ/SK

Ubuntu pro osobní počítače => Software => Příkazový řádek a programování pro GNU/Linux => Téma založeno: Martin Kiklhorn 01 Února 2009, 20:29:17

Název: freeradius authorize query, jak napsat mysql dotaz [vyřešeno]
Přispěvatel: Martin Kiklhorn 01 Února 2009, 20:29:17
Ahoj,
priorita této mé otázky je velice nízká (na fóru jsou lidi kteří potřebují opravdu popradit), jen kdyby někdo neměl do čeho píchnout a přišlo mu to zajímavé.

Mám Freeradius 2.něco, používám jej pro přiřazovaní stanic do VLANs. Jako backend mysql.

Protože mi to dnes už nemyslí tak bych chtěl poradit jak vytvořit jeden složený dotaz když mám následující podmínky:
1. jednoduchý select z první tabulky vrátí více než 0 záznamů -> složený dotaz vrací tyto záznamy
2. pokud vrátí 0 nula záznamů provede se druhý jednoduchý dotaz do druhé tabulky
2.1 pokud druhý dotaz také vrátí 0 záznamů -> složený dotaz vrací také 0 záznamů
2.2 pokud druhý dotaz vrátí více než 0 záznamů, provede se insert do první tabulky a provede se opět dotaz z bodu č. 1 který tentokrát již uspěje a vrátí nenulový počet záznamů (v první tabulce je použito automatické id které potřebuji také vracet)

Dá se tohle vůbec spáchat jedním(podmínka) složeným selectem, ideálně bez uložených procedur(není podmínkou)?

Pokud někoho zajímá co vlastně s tím freeradiusem páchám jenom kvůli lenosti psát ručně jedno číslo na tři místa a nechutí to řešit externím skriptem:
při připojení počítače do switche mi tento pošle:
Kód: [Vybrat]
rad_recv: Access-Request packet from host 192.168.4.123 port 1812, id=197, length=110
        User-Name = "00-0f-b0-f2-d8-1b"
        NAS-Port = 32
        NAS-Port-Type = Ethernet
        User-Password = "00-0f-b0-f2-d8-1b"
        NAS-IP-Address = 192.168.4.123
        Calling-Station-Id = "00-0F-B0-F2-D8-1B"
V defaultní instalaci freeradiusu musím mít tabulku radcheck s poli:
idusernameatributeopvalue
100-0f-b0-f2-d8-1bCleartext-Password:=00-0f-b0-f2-d8-1b
200-0f-b0-f2-d8-1cCleartext-Password:=00-0f-b0-f2-d8-1c
300-0f-b0-f2-d8-1dCleartext-Password:=00-0f-b0-f2-d8-1d
kde se neustále opakují jméno = heslo
v další tabulce radusergroup je opět totéž jméno a název vlan

Říkal jsem si že pro authorize použiju jiný modul, nějaké "compare", kde bych porovnal na shodu User-Name s User-Password, ale žádný "compare" jsem neobjevil, checkval by k tomu mohl svádět jménem, ale používá se imho jen na otestování zda je nějaký atribut v radius dotazu přítomný. Cesta přes DEFAULT záznam také nebyla správná.

Vrhnul jsem se tedy na prozkoumání skriptu pro mysql ( /etc/freeradius/sql/mysql/dialup.conf) kde je definovaný query č.1
Kód: [Vybrat]
        authorize_check_query = "SELECT id, username, attribute, value, op \
          FROM ${authcheck_table} \
          WHERE username = '%{SQL-User-Name}' \
          ORDER BY id"
který jsem si upravil na query č.2
Kód: [Vybrat]
        authorize_check_query = "SELECT id, username, 'Cleartext-Password' as attribute,  username as value, ':=' as op \
          FROM ${usergroup_table} \
          WHERE username = '%{SQL-User-Name}' \
          LIMIT 1"
Což mi dělá přesně to požadované, tedy že pokud se username nachází v tabulce radusergroup vrátí hodnoty které by původně musel číst z tabulky radcheck (kam se mi je opravdu nechtělo ručně psát), a autorizace projde.

Protože ale nikdy nevím jaká další zařízení/klienty budu přes freeradius autorizovat tak bych měl rád do budoucna funkčnost původní (s tabulkou radcheck), jen rozšířenou tímto hackem.
Název: Re: freeradius authorize query, jak napsat mysql dotaz
Přispěvatel: Martin Kiklhorn 02 Února 2009, 03:05:16
Tak jsem to vyřešil uloženou procedurou
Kód: [Vybrat]
drop procedure autorizace;
delimiter //
create procedure autorizace (username varchar(64), hack boolean)
obalka:BEGIN
DECLARE pocet1, pocet2 INT;
if !hack then
  SELECT `id`, `username`, `attribute`, `value`, `op` FROM radcheck WHERE radcheck.username = username ORDER by `id`;
  leave obalka;
end if;
#pokud je hack false tak koncim a vracim vysledek - stejne chovani jako puvodni volani

SELECT count(*) FROM radcheck WHERE radcheck.username = username into pocet1;
if pocet1 > 0 then
  SELECT `id`, `username`, `attribute`, `value`, `op` FROM radcheck WHERE radcheck.username = username ORDER by `id`;
  leave obalka;
else
  SELECT count(*) FROM radusergroup WHERE radusergroup.username = username into pocet2;
  if pocet2 > 0 then
    INSERT INTO `radcheck` (`username`, `attribute`, `op`, `value`) VALUES(username,'Cleartext-Password', ':=', username);
    SELECT `id`, `username`, `attribute`, `value`, `op` FROM radcheck WHERE radcheck.username = username ORDER by `id`;
    leave obalka;
  end if;
end if; 
END;
//
delimiter ;
test:
Kód: [Vybrat]
call autorizace('00-0f-b0-f2-d8-1b', false);
call autorizace('00-0f-b0-f2-d8-1b', true);
call autorizace('00-0f-b0-f2-d8-1f', true);

a upravit v konfiguráku původní query z
Kód: [Vybrat]
        authorize_check_query = "SELECT id, username, attribute, value, op \
          FROM ${authcheck_table} \
          WHERE username = '%{SQL-User-Name}' \
          ORDER BY id"
na
Kód: [Vybrat]
authorize_check_query = "call autorizace('%{SQL-User-Name}',true)"Takže je to funkční přesně jak jsem požadoval.
Napíšu username jen do tabulky radusergroup, pokud někdy bude použité tak si správný záznam v radcheck tabulce mysql vytvoří sama, stačí že jej najde v radusergroup.

Zkoušel jsem původně
Kód: [Vybrat]
SELECT `id`, `username`, `attribute`, `value`, `op` FROM radcheck WHERE radcheck.username = username ORDER by `id`;vyhodit jen na jedno místo za end, ale pokud se pokusím vytvořit konstrukci
vnejsi:BEGIN
obalka:BEGIN
... prikazy ...
... pokus o vyskok pomoci leave obalka
END
... tady ten posledni select
END
tak se mysql zblázní.

Teoreticky tato konstrukce imho měla fungovat, ale nefunguje. Moc oficiální dokumentace k LEAVE statementu není, prakticky jen komentáře v http://dev.mysql.com/doc/refman/5.0/en/leave-statement.html
Vypadá to na chybu v optimalizátoru http://bugs.mysql.com/bug.php?id=15737 která ale měla být už v roce 2005 vyřešená, nebo je to vztažené k nemožnosti vložených procedur.