# # 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