<?php
/*****************************************************************************
IP Reg, a PHP/MySQL IPAM tool
Copyright (C) 2007-2009 Wietse Warendorff (up to v0.5)
Copyright (C) 2011-2023 Thomas Hooge

SPDX-License-Identifier: GPL-3.0-or-later
*****************************************************************************/

session_name('ipreg');
session_start();

if (! include("config.php")) {
    echo "<!DOCTYPE html><html><head><title>IP Reg</title></head><body>\n";
    echo "<h1>IP Reg</h1><h2>No configuration</h2>\n";
    echo '<p>Error loading configuration.';
    echo 'Please <a href="install">check your installation</a>.', "</p>\n";
    echo "</body></html>\n";
    exit(1);
}

// connect to database
$dbh = new PDO("mysql:host=$config_mysql_host;dbname=$config_mysql_dbname;charset=utf8", $config_mysql_username, $config_mysql_password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);

include("lib.php"); // for smarty e.g.

// ========== LOGIN FUNCTIONS =================================================

function check_ldap_bind($user_name, $user_pass) {
    global $config_ldap_host;
    global $config_ldap_port;
    global $config_ldap_base_dn;
    global $config_ldap_bind_dn;
    global $config_ldap_bind_pass;
    global $config_ldap_login_attr;
    $ldap_conn = NULL;
    foreach ($config_ldap_host as $server) {
        if ($ldap_conn = ldap_connect($server, $config_ldap_port)) {
            if ($res = ldap_bind($ldap_conn, $config_ldap_bind_dn, $config_ldap_bind_pass)) {
                ldap_set_option($ldap_conn, LDAP_OPT_REFERRALS, 0);
                ldap_set_option($ldap_conn, LDAP_OPT_PROTOCOL_VERSION, 3);
                $filter = "(&(objectClass=user)($config_ldap_login_attr=$user_name))";
                $res = ldap_search($ldap_conn, $config_ldap_base_dn, $filter, ['dn']);
                if ($res) {
                    $info = ldap_get_entries($ldap_conn, $res);
                    $user_dn = $info[0]['dn'];
                    $res = @ldap_bind($ldap_conn, $user_dn, $user_pass);
                    if ($res) {
                        return TRUE;
                    }
                }
            }
            return FALSE;
        }
    }
    return FALSE;
}

function user_login ($user_name, $user_pass) {
    global $dbh;

    if (strlen($user_name) < 1) {
        return FALSE;
    }

    if (strlen($user_pass) < 1) {
        return FALSE;
    }

    $sql = "SELECT user_id, user_pass, user_displayname, user_language,
                user_imagesize, user_imagecount, user_mac, user_dateformat,
                user_dns1suffix, user_dns2suffix, user_tooltips,
                user_menu, user_role, user_flags, user_realm
            FROM user
            WHERE user_name=?";
    $sth = $dbh->prepare($sql);
    $sth->execute([$user_name]);

    if (!$user = $sth->fetch(PDO::FETCH_OBJ)) {
        // no user record found
        return FALSE;
    }

    if ($user->user_realm == 'ldap') {
        // check LDAP auth
        if (! check_ldap_bind($user_name, $user_pass)) {
            return FALSE;
        }
        // TODO sync LDAP data to local
    } else {
        // compare local passwords
        if (strcmp(md5($user_pass), rtrim($user->user_pass)) != 0) {
            // password does not match with md5, check if new hash matches
            // For future expansion: $pwd_peppered = hash_hmac('sha256', $user_pass, $config_pepper);
            if (! password_verify($user_pass, $user->user_pass)) {
                return FALSE;
            }
        } else {
            // md5 match but outdated. rewrite with new algo
            $sth = $dbh->prepare("UPDATE user SET user_pass=? WHERE user_id=?");
            $newhash = password_hash($user_pass, PASSWORD_BCRYPT);
            $sth->execute([$newhash, $user->user_id]);
        }
    }

    // all ok: user is logged in, register session data
    $_SESSION['suser_id'] = $user->user_id;
    $_SESSION['suser_realm'] = $user->user_realm;
    $_SESSION['suser_displayname'] = $user->user_displayname;
    $_SESSION['suser_language'] = $user->user_language;
    $_SESSION['suser_imagesize'] = $user->user_imagesize;
    $_SESSION['suser_imagecount'] = $user->user_imagecount;
    $_SESSION['suser_mac'] = $user->user_mac;
    $_SESSION['suser_dateformat'] = $user->user_dateformat;
    $_SESSION['suser_dns1suffix'] = $user->user_dns1suffix;
    $_SESSION['suser_dns2suffix'] = $user->user_dns2suffix;
    $_SESSION['suser_tooltips'] = $user->user_tooltips;

    $roles = explode(',', $user->user_role);
    if (in_array('admin', $roles)) {
        // admin means everything!
        $roles = ['add', 'edit', 'delete', 'manage', 'admin'];
        $_SESSION['suser_role_admin'] = true;
    }
    $_SESSION['suser_role_add'] = in_array('add', $roles);
    $_SESSION['suser_role_edit'] = in_array('edit', $roles);
    $_SESSION['suser_role_delete'] = in_array('delete', $roles);
    $_SESSION['suser_role_manage'] = in_array('manage', $roles);

    $menu = explode(',', $user->user_menu);
    $_SESSION['suser_menu_assets'] = in_array('asset', $menu);
    $_SESSION['suser_menu_assetclasses'] = in_array('class', $menu);
    $_SESSION['suser_menu_assetclassgroups'] = in_array('group', $menu);
    $_SESSION['suser_menu_cables'] = in_array('cable', $menu);
    $_SESSION['suser_menu_locations'] = in_array('location', $menu);
    $_SESSION['suser_menu_nodes'] = in_array('node', $menu);
    $_SESSION['suser_menu_nats'] = in_array('nat', $menu);
    $_SESSION['suser_menu_subnets'] = in_array('subnet', $menu);
    $_SESSION['suser_menu_vlans'] = in_array('vlan', $menu);
    $_SESSION['suser_menu_zones'] = in_array('zone', $menu);

    return TRUE;
}

// No header included, this page has no menu

// ========== LOGIN: HERE BE DRAGONS ==========================================

$language = lang_getfrombrowser($config_lang, $config_lang_default);
include('lang/' . $language . '.php');

if ($_SERVER['REQUEST_METHOD'] == "POST" ) {

    $user_name = sanitize($_POST['user_name']);
    $user_pass = sanitize($_POST['user_pass']);

    if (user_login($user_name, $user_pass) == TRUE) {
        header_location($_SESSION['prelogin'] ?? 'index.php');
    } else {
        $_SESSION = array();
        session_destroy();
    }
}

$smarty->assign("config_version", $config_version);
$smarty->assign($lang);
$smarty->display("login.tpl");

$smarty->display('footer.tpl');