Overview | Index by: file name | procedure name | procedure call | annotation
vty-1.0.tm (annotations | original source)

#
#    Copyright (C) 2010 Alexandros Stergiakis <alsterg@gmail.com>
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    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 Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

#//#
# The "vty" module enables remote login.
#
# Supported transport protocol:
# * Telnet
#//#

module require base 1.0
module provide vty 1.0

namespace eval ::module::vty {
namespace import ::helper::* ::module::api::* ::module::base::auth_username_callback

proc description {} {
    return "VTY Configuration"
}

proc version {} {
    variable transport_proto
    if {"ssh" in $transport_proto} {
        return "Dropbear Version 0.52"
    }
}

proc check {} {    
    foreach feature [list \
                     CONFIG_LOGIN \
                     CONFIG_TELNETD \
                     CONFIG_FEATURE_TELNETD_STANDALONE] {
        if {! [::helper::busybox_has $feature]} { ;# Can return error.
            error "Busybox doesn't have support for $feature."
        }
    }
    
    if {! [lempty [auto_execok dropbear]]} {
        variable transport_proto
        lappend transport_proto "ssh"
    }
}

proc reset {} {
    Global VTY_USER BASE_DIR
    if {[auth user_exists $VTY_USER]} {
        auth lock $VTY_USER
    }
    
    variable vty_login 0
    variable vty_pass {}
    variable login_bin [file join $BASE_DIR "login-vty.sh"]
    variable username_used 0

    vty_reset
}

proc constructor {} {
    log::Info "Loading \"vty\" module: [description]"
    
    variable transport_proto "telnet"
    
    check ;# may append "ssh" as transport protocol.
    
    log::Info "Registered VTY Transport Protocols: $transport_proto"

    Global VTY_USER MC_SHELL
    auth adduser $VTY_USER $MC_SHELL
    
    reset

    # Finally load Command Specs
    sysconf loadspecs "modules/vty/vty.specs"
    
    auth_username_callback ::module::vty::use_username
}

proc destructor {} {
    # First unload Command Specs
    sysconf remove "vty"
    
    reset
}

################
# Handlers
################

proc vty_reset {} {
    Global ETC_DIR
    variable login_bin
    variable vty_login
    
    killall telnetd
    
    if {$vty_login} {
        exec telnetd -f [file join $ETC_DIR "issue"] -l $login_bin 
    }
}

proc use_username {used} {
    Global BASE_DIR VTY_USER
    variable login_bin
    variable username_used
    
    if {$used} {
        set login_bin [file join / bin login]
        set username_used 1
        auth lock $VTY_USER
    } else {
        set login_bin [file join $BASE_DIR "login-vty.sh"]
        set username_used 0
        auth unlock $VTY_USER
    }
    vty_reset ;# This will kill all active vty sessions.
}

# @diff One argument instead of two. Number is not zero-based.
# Note: If current number of active sessions are larger than new value for SOFT_MAX_SESSIONS
#       then no active session is closed, but new ones are not allowed.
command LineVty {cmdline argstart sid out no arguments args} {
    Global -rw SOFT_MAX_SESSIONS
    
    if {$no} {
        reset
        return
    }
    
    # Number range is guaranteed by xml spec.
    
    set num [dict get $arguments NUMBER]
    set SOFT_MAX_SESSIONS $num
    
    sysconf confmode $sid set "vty"
    return
}

proc print_LineVty {} {
    Global SOFT_MAX_SESSIONS
    variable vty_login
    variable vty_pass
    
    set result {}
    if {$SOFT_MAX_SESSIONS > 0} {
        append result "#\n# VTY Settings:\n"
        append result "line vty $SOFT_MAX_SESSIONS\n"
        if {$vty_login} {
            append result "  login\n"
        }
        if {! [lempty $vty_pass]} {
            append result "  password {$vty_pass}\n"
        }
        append result "  exit\n\n"
    }
    return $result
}

command VtyLogin {cmdline argstart sid out no arguments args} {
    variable vty_login
    
    if {$no} {
        set vty_login 0
    } else {
        set vty_login 1
    }
    vty_reset
    return
}

command VtyPassword {cmdline argstart sid out no arguments args} {
    Global VTY_USER
    variable vty_pass
    variable username_used
    
    if {$no} {
        set vty_pass {}
        auth lock $VTY_USER
        return
    }
    
    set pass [dict get $arguments PASSWORD]

    if {[string match {$1$*} $pass]} {
        auth passwd $VTY_USER $pass -nocrypt ;# error propagates
    } else {
        if {! [auth pass_is_ok $pass]} {
            ferror "invalid password string" [getpos PASSWORD]
        }
        set pass [auth passwd $VTY_USER $pass] ;# error propagates
        
        # Be careful not to unlock VTY_USER if Usernames are used.
        if {$username_used} {
            auth lock $VTY_USER
        } else {
            auth unlock $VTY_USER
        }
    }
    
    set vty_pass $pass
    return
}

proc dlist_vty {sid args} {
    Global MAX_SESSIONS
    set lst [list]
    for {set i 1} {$i <= $MAX_SESSIONS} {incr i} {
        lappend lst $i
    }
    return $lst
}

} ;# End of Namespace

Overview | Index by: file name | procedure name | procedure call | annotation
File generated 2010-03-13 at 22:28.