/*
 *      auth.c from Access Point SNMP Utils for Linux
 *
 * Copyright (c) 2002 Roman Festchook <roma at polesye dot net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License Version 2 from
 * June 1991 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "ap-utils.h"

#define MAX_LINES LINES-6
#define PACKET_ERROR _("AuthorizedMacTableString packet error")

#define AUTH_TITLE _("APClient authorization credentials")

#define MAC_AUTH _("[A] MAC authorization: ")
#define MAC_ADD  _("Enter MAC: ")
#define MAC_DEL  _("Delete Num: ")
#define MAC_HEADER _("NUM       MAC address")
#define MAC_HELP _("A - auth; N - new; D - del; arrows - scroll; W - write conf; Q - quit")
#define MAC_RADIUS_HELP _("A - auth; IPSTF - set; W - write conf; Q - quit")
#define MAC_NONE_HELP _("A - auth; W - write conf; Q - quit")

#define RADIUS_IP _("[I] RADIUS SERVER IP: ")
#define RADIUS_DEST_PORT _("[P] RADIUS SERVER PORT: ")
#define RADIUS_SECRET _("[S] RADIUS SERVER SECRET: ")
#define RADIUS_TIME _("[T] REAUTHORIZATION TIME: ")
#define RADIUS_PORT _("[F] RADIUS SOURCE PORT: ")

extern WINDOW *main_sub;
extern int LINES;
extern short ap_type;

void atmel_auth()
{
    struct AuthorizedMacTableString {
	unsigned int short Action;
	unsigned int short NumOfAllTableAddresses;
	unsigned int short NumOfCurrentAddress;
	unsigned char MacAddress[6];
    } *AuthMac = NULL, get;

    struct MacListStat *pmac, *first = NULL, *curr = NULL;
    uint32_t auth_mac_hw;

    char EnableAuthMAC[] =
	{ 0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01,
	0x02, 0x06, 0x01, 0x00
    };
    char AutorizedMac[] = { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01,
	0x02, 0x06, 0x02, 0x00
    };

    char AuthRadiusIP[] = { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01,
	0x02, 0x06, 0x03, 0x00
    };
    char AuthRadiusSecret[] = { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01,
	0x02, 0x06, 0x04, 0x00
    };
    char AuthRadiusSecretLength[] = { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01,
	0x02, 0x06, 0x05, 0x00
    };
    char AuthRadiusPort[] = { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01,
	0x02, 0x06, 0x06, 0x00
    };
    char AuthRadiusReauthorizationTime[] = { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01,
	0x02, 0x06, 0x07, 0x00
    };
    char AuthRadiusDestinPort[] = { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01,
	0x02, 0x06, 0x08, 0x00
    };

    char *auth_types[] = { _("Internal"), OFF, "RADIUS" };

    struct in_addr radius_ip;
    char message[1024], m_authmac = 0, radius_secret[32], m_radius_secret=0, m_radius_ip=0;
    int radius_port, radius_time, radius_dest_port, m_radius_port=0, m_radius_time=0, m_radius_dest_port=0;
    int i, total_mac, auth_mac = 0, mac_num = 0, begin=0, end=0, c=0;
    varbind varbinds[7];

    memcpy(radius_secret, _("<hidden>"), 32); 

    varbinds[0].oid = EnableAuthMAC;
    varbinds[0].len_oid = sizeof(EnableAuthMAC);
    varbinds[0].type = NULL_VALUE;
    varbinds[0].len_val = 0;

    varbinds[1].oid = AuthRadiusIP;
    varbinds[1].len_oid = sizeof(AuthRadiusIP);
    varbinds[1].type = NULL_VALUE;
    varbinds[1].len_val = 0;

    varbinds[3].oid = AuthRadiusPort;
    varbinds[3].len_oid = sizeof(AuthRadiusPort);
    varbinds[3].type = NULL_VALUE;
    varbinds[3].len_val = 0;

    varbinds[4].oid = AuthRadiusReauthorizationTime;
    varbinds[4].len_oid = sizeof(AuthRadiusReauthorizationTime);
    varbinds[4].type = NULL_VALUE;
    varbinds[4].len_val = 0;

    varbinds[2].oid = AuthRadiusDestinPort;
    varbinds[2].len_oid = sizeof(AuthRadiusDestinPort);
    varbinds[2].type = NULL_VALUE;
    varbinds[2].len_val = 0;

    print_help(WAIT_RET);
    if (snmp(varbinds, 5, GET) < 5) {
	print_helperr(ERR_RET);
	goto exit;
    }
    print_top(NULL, AUTH_TITLE);

    auth_mac = *(varbinds[0].value);
    memcpy(&radius_ip.s_addr, varbinds[1].value, 4);
    memcpy(&radius_dest_port, varbinds[2].value, 2);
    radius_dest_port = ntohs(radius_dest_port);
    memcpy(&radius_port, varbinds[3].value, 2);
    radius_port = ntohs(radius_port);
    memcpy(&radius_time, varbinds[4].value, 2);
    radius_time = ntohs(radius_time);
	
    sprintf(message, "%s%s", MAC_AUTH, auth_types[auth_mac-1]);
    mvwaddstr(main_sub, 0, 0, message);
    wrefresh(main_sub);

    total_mac = 0;
    mac_num = 0;

    while (mac_num <= total_mac) {
	get.Action = 0x02; rshort(get.Action);
	get.NumOfAllTableAddresses = total_mac;	rshort(get.NumOfAllTableAddresses);
	get.NumOfCurrentAddress = mac_num; rshort(get.NumOfCurrentAddress);

	varbinds[0].oid = AutorizedMac;
	varbinds[0].len_oid = sizeof(AutorizedMac);
	varbinds[0].value = (char *) &get;
	varbinds[0].len_val = 12;
	varbinds[0].type = STRING_VALUE;

	i = snmp(varbinds, 1, SET);
	if (i == 0) {
	    print_helperr(ERR_SET);
	    goto exit;
	}
	if (i < 0)
	    break;

	if (varbinds[0].len_val == 12) {
	    if (AuthMac)
		free(AuthMac);
	    AuthMac =
		(struct AuthorizedMacTableString *) malloc(varbinds[0].
							   len_val);
	    memcpy(AuthMac, varbinds[0].value, varbinds[0].len_val);
/*	    AuthMac =
		(struct AuthorizedMacTableString *) varbinds[0].value;*/
	} else {
	    print_helperr(PACKET_ERROR);
	    goto exit;
	}

	rshort(AuthMac->NumOfAllTableAddresses);
	total_mac =
	    (AuthMac->NumOfAllTableAddresses ==
	     65535) ? 0 : AuthMac->NumOfAllTableAddresses;

	if (mac_num) {
	    if (first == NULL) {
		first = (struct MacListStat *)
		    malloc(sizeof(struct MacListStat));
		curr = first;
	    } else {
		curr->next = (struct MacListStat *)
		    malloc(sizeof(struct MacListStat));
		curr = curr->next;
	    }
	    memcpy(curr->addr, AuthMac->MacAddress, 6);
	    curr->next = NULL;
	}
	mac_num++;
    }

choose_view:
    clear_main(2);
    if (auth_mac == 1) {
	mvwaddstr(main_sub, 2, 1, MAC_HEADER);
	begin = 1;
	end = (MAX_LINES < mac_num) ? MAX_LINES : mac_num;
	scroll_rows(first, begin, end, 3, 0);
        print_help(MAC_HELP);
    } else if(auth_mac == 3) {
    	sprintf(message, "%s%s", RADIUS_IP, inet_ntoa(radius_ip));
    	mvwaddstr(main_sub, 2, 0, message);
    	sprintf(message, "%s%d", RADIUS_DEST_PORT, radius_dest_port);
    	mvwaddstr(main_sub, 3, 0, message);
    	sprintf(message, "%s%s", RADIUS_SECRET, radius_secret);
    	mvwaddstr(main_sub, 4, 0, message);
    	sprintf(message, "%s%d", RADIUS_TIME, radius_time);
    	mvwaddstr(main_sub, 5, 0, message);
    	sprintf(message, "%s%d", RADIUS_PORT, radius_port);
    	mvwaddstr(main_sub, 6, 0, message);

        wrefresh(main_sub);
        print_help(MAC_RADIUS_HELP);
    } else {
        print_help(MAC_NONE_HELP);
    }

    if (i < 0) {
        mvwaddstr(main_sub, 3, 1, _("(insufficient community used)"));
        wrefresh(main_sub);
    }

    noecho();

    while (1) {
	switch (getch()) {
	case 'q':
	case 'Q':
	    goto quit;
	case 'a':
	case 'A':
	    auth_mac = menu_choose(0, strlen(MAC_AUTH), auth_types, 3)+1;
	    clear_main_new(0, 1);
	    print_menusel(0, 0, MAC_AUTH, auth_types[auth_mac-1]);
	    m_authmac = 1;
	    goto choose_view;
	case 'S':
	case 's':
            if (auth_mac != 3) {
	                continue;
            }
	    get_value(radius_secret, 4, strlen(RADIUS_SECRET), 32, ANY_STRING, 0, 0, NULL);
	    m_radius_secret = 1;
	    continue;
	case 'P':
	case 'p':
            if (auth_mac != 3) {
               continue;
            }
	    get_value(message, 3, strlen(RADIUS_DEST_PORT), 6, INT_STRING, 0, 65535, MAC_RADIUS_HELP);
	    radius_dest_port = atoi(message);
	    m_radius_dest_port = 1;
            continue;
	case 'T':
        case 't':
            if (auth_mac != 3) {
	            continue;
	    }
            get_value(message, 5, strlen(RADIUS_TIME), 6, INT_STRING, 0, 65535, MAC_RADIUS_HELP);
            radius_time = atoi(message);
            m_radius_time = 1;
            continue;
	case 'F':
	case 'f':
	    if (auth_mac != 3) {
	       continue;
	    }
	    get_value(message, 6, strlen(RADIUS_PORT), 6, INT_STRING, 0, 65535, MAC_RADIUS_HELP);
	    radius_port = atoi(message);
	    m_radius_port = 1;
	    continue;
	case 'I':
	case 'i':
            if (auth_mac != 3) {
	   	continue;
	    }
	    get_ip(&radius_ip, 2, strlen(RADIUS_IP), MAC_RADIUS_HELP);
	    m_radius_ip = 1;
	    continue;
	case 'd':
	case 'D':
	    if (auth_mac != 1) {
		continue;
	    }
	    mvwaddstr(main_sub, 1, 0, MAC_DEL);
	    get_value(message, 1, strlen(MAC_DEL), 5, INT_STRING,
		1, mac_num - 1, NULL);
	    i = atoi(message);
	    if (i == 1) {
		pmac = first;
		first = first->next;
		free(pmac);
	    } else {
		curr = first;
		while (--i > 1)
		    curr = curr->next;
		pmac = curr->next;
		curr->next = pmac->next;
		free(pmac);
	    }
	    mac_num--;
	    begin = 1;
	    end = (MAX_LINES < mac_num) ? MAX_LINES : mac_num;
	    scroll_rows(first, begin, end, 3, 0);
	    clear_main_new(1, 2);
	    continue;
	case 'n':
	case 'N':
	    if (auth_mac != 1) {
		continue;
	    }
	    mvwaddstr(main_sub, 1, 0, MAC_ADD);
	    curr = first;
	    while (curr && curr->next)
		curr = curr->next;
	    if (first == NULL) {
		first = (struct MacListStat *)
		    malloc(sizeof(struct MacListStat));
		curr = first;
	    } else {
		curr->next = (struct MacListStat *)
		    malloc(sizeof(struct MacListStat));
		curr = curr->next;
	    }
	    curr->next = NULL;
	    mac_num++;
	    get_mac(curr->addr, 1, strlen(MAC_ADD));
	    begin = 1;
	    end = (MAX_LINES < mac_num) ? MAX_LINES : mac_num;
	    scroll_rows(first, begin, end, 3, 0);
	    clear_main_new(1, 2);
	    continue;
	case 'w':
	case 'W':
	    i=0;
	    if (m_authmac) {
		auth_mac_hw = swap4(auth_mac);
		varbinds[i].oid = EnableAuthMAC;
		varbinds[i].len_oid = sizeof(EnableAuthMAC);
		varbinds[i].type = INT_VALUE;
		varbinds[i].value = (char *) &auth_mac_hw;
		varbinds[i].len_val = 1;
		i++;
	    }
	    
	    if (m_radius_ip) {
                radius_ip.s_addr = htonl(radius_ip.s_addr);
		radius_ip.s_addr = swap4(radius_ip.s_addr);
                varbinds[i].oid = AuthRadiusIP;
                varbinds[i].len_oid = sizeof(AuthRadiusIP);
		varbinds[i].value = (char *) &radius_ip.s_addr;
		varbinds[i].len_val = 4;
		varbinds[i].type = INT_VALUE;
		i++;
	    }
	   
            if (m_radius_dest_port) {
	        varbinds[i].oid = AuthRadiusDestinPort;
	        varbinds[i].len_oid = sizeof(AuthRadiusDestinPort);
	        radius_dest_port = htons(radius_dest_port);
	        varbinds[i].value = (char *) &radius_dest_port;
	        varbinds[i].len_val = 2;
	        varbinds[i].type = 0x02;
	        i++;
	    }
	    
            if (m_radius_time) {
	        varbinds[i].oid = AuthRadiusReauthorizationTime;
	        varbinds[i].len_oid = sizeof(AuthRadiusReauthorizationTime);
	        radius_time = htons(radius_time);
	        varbinds[i].value = (char *) &radius_time;
                varbinds[i].len_val = 2;
                varbinds[i].type = 0x02;
                i++;
            }

           if (m_radius_port) {
	        varbinds[i].oid = AuthRadiusPort;
	        varbinds[i].len_oid = sizeof(AuthRadiusPort);
	        radius_port = htons(radius_port);
	        varbinds[i].value = (char *) &radius_port;
                varbinds[i].len_val = 2;
                varbinds[i].type = 0x02;
                i++;
            }
           if (m_radius_secret) {
                c = strlen(radius_secret);
		varbinds[i].oid = AuthRadiusSecretLength;
		varbinds[i].len_oid = sizeof(AuthRadiusSecretLength);
		varbinds[i].value = (char *)&c;
		varbinds[i].len_val = 1;
		varbinds[i].type = INT_VALUE;
		i++;
		varbinds[i].oid = AuthRadiusSecret;
		varbinds[i].len_oid = sizeof(AuthRadiusSecret);
		varbinds[i].value = radius_secret;
		varbinds[i].len_val = c;
		varbinds[i].type = STRING_VALUE;
		i++;
	   }

	    print_help(WAIT_SET);
	    if (snmp(varbinds, i, SET) <= 0) {
	        print_helperr(ERR_RET);
	        goto exit;
	    }
	    
	    curr = first;
	    i = 1;
	    while (curr != NULL) {
		get.Action = 0x01; rshort(get.Action);
		get.NumOfAllTableAddresses = mac_num - 1; rshort(get.NumOfAllTableAddresses);
		get.NumOfCurrentAddress = i; rshort(get.NumOfCurrentAddress);
		memcpy(get.MacAddress, curr->addr, 6);
		varbinds[0].oid = AutorizedMac;
		varbinds[0].len_oid = sizeof(AutorizedMac);
		varbinds[0].value = (char *) &get;
		varbinds[0].len_val = 12;
		varbinds[0].type = STRING_VALUE;
		print_help(WAIT_SET);
		if (snmp(varbinds, 1, SET) <= 0) {
		    print_helperr(ERR_RET);
		    goto exit;
		}
		if (varbinds[0].len_val != 12) {
		    print_helperr(PACKET_ERROR);
		    goto exit;
		}
		curr = curr->next;
		i++;
	    }
	    wbkgd(main_sub, A_NORMAL);
	    wrefresh(main_sub);
	    print_help(DONE_SET);
	    goto exit;
	case KEY_DOWN:
	case KEY_RIGHT:
	    if (auth_mac != 1) {
		continue;
	    }
	    if (end < mac_num) {
		begin++;
		end++;
		scroll_rows(first, begin, end, 3, 0);
	    }
	    continue;
	case KEY_UP:
	case KEY_LEFT:
	    if (auth_mac != 1) {
		continue;
	    }
	    if (begin > 1) {
		begin--;
		end--;
		scroll_rows(first, begin, end, 3, 0);
	    }
	    continue;
	}
	continue;
    }

    print_help(ANY_KEY);
  exit:
    getch();
  quit:
    while ((curr = first)) {
	first = curr->next;
	free(curr);
    }
    if (AuthMac)
	free(AuthMac);
    print_top(NULL, NULL);
    clear_main(0);
}
