#  -*- text -*-
######################################################################
#
#######################################################################
#
#  = The tacacs Virtual Server
#
#  The `tacacs` virtual server processes TACACS+ packets.
#
#	https://www.rfc-editor.org/rfc/rfc8907
#
#	$Id: e71b25d623e641cda4e9e276b204791caac2e451 $
#
######################################################################

#
#  == The Virtual Server
#
#  This is the `tacacs` virtual server.
#
server tacacs {
	#
	#  namespace:: Needs to be "tacacs" for TACACS+ functionality.
	#
	namespace = tacacs

	#
	#  === TACACS+ Configuration
	#
	#  All of the configuration for processing TACACS+ packets goes here.
	#
	tacacs {
		#
		#  ==== Authentication subsection
		#
		#  This section contains configuration which is specific to
		#  processing `Authentication` packets.
		#
		#  Similar sections can be added, but are not necessary for
		#  Accounting-Request (and other) packets. At this time, there is no
		#  configuration needed for other packet types.
		#
		Authentication {
			#
			#  session:: Controls how ongoing (multi-round) sessions are
			#  handled
			#
			#  This section is only useful for ASCII authentications. It is the
			#  only authentication type which supports sending challenges for
			#  further data.
			#
			session {
				#
				#  max:: The maximum number of concurrent ongoing sessions
				#
#				max = 4096

				#
				#  max_rounds: The maximum number of round trips which are allowed
				#
				#  This is only enforced for `Authentication-Type = ASCII`, when the
				#  server replies with `GetUser` or `GetPass` or `GetData`.
				#
				#  Some broken clients will send packets in a loop, forever. This
				#  configuration helps to catch and prevent that.
				#
				max_rounds = 4

				#
				#  timeout:: How long to wait before expiring a session.
				#
				#  The timer starts when a response with a state value is sent. The timer
				#  stops when a request containing the previously sent state value is
				#  received.
				#
#				timeout = 15
			}
		}

		#
		#  There is currently no configuration for other packet types.
		#
	}

	listen {
		#
		#  type:: The type of packet to accept.
		#
		#  Multiple types can be accepted by using multiple lines of `type =
		#  ...`.
		#
		#  As described in RFC 8907, the packet types are:
		#
		type = Authentication-Start
		type = Authentication-Continue
		type = Authorization-Request
		type = Accounting-Request

		#
		#  transport:: The transport protocol.
		#
		#  Only `tcp` is allowed. TACACS+ does not use UDP or TLS.
		#
		transport = tcp

		#
		#  == Protocols
		#
		#  tcp { ... }:: TCP is configured here.
		#
		tcp {
			#
			#  NOTE: Don't change anything if you are not sure.
			#

			#
			#  port:: The port where we accept packets.
			#
			#  The port should be 49 for a production network.
			#
			port = 49

			#
			#  ipaddr:: The IP address where we accept packets.
			#
			ipaddr = *

			#
			#  interface:: Interface to bind to.
			#
#			interface = eth0

			#
			#  max_packet_size:: Our max packet size. may be different from the
			#  parent.
			#
#			max_packet_size = 4096

			#
			#  recv_buff:: How big the kernel's receive buffer should be.
			#
#			recv_buff = 1048576

			#
			#  send_buff:: How big the kernel's send buffer should be.
			#
#			send_buff = 1048576

			#
			#  src_ipaddr:: IP we open our socket on.
			#
#			src_ipaddr = ""
		}

		#
		#  limit:: limits for this socket.
		#
		#  The `limit` section contains configuration items which enforce
		#  various limits on the socket. These limits are usually
		#  transport-specific.
		#
		#  Limits are used to prevent "run-away" problems.
		#
		limit {
			#
			#  max_connections:: The maximum number of connected sockets which
			#  will be accepted for this listener.
			#
			#  Each connection opens a new socket, so be aware of system file
			#  descriptor limitations.
			#
			#  If the listeners do not use connected sockets (e.g. TCP), then
			#  this configuration item is ignored.
			#
			max_connections = 256

			#
			#  idle_timeout:: Time after which idle connections are deleted.
			#
			#  Useful range of values: 5 to 600
			#
			idle_timeout = 60.0

			#
			#  dynamic_timeout:: Time after which idle dynamic clients are
			#  deleted.
			#
			dynamic_timeout = 600.0
		}
	}

	#
	#  == Clients
	#
	#  A virtual server can have multiple `client` definitions. These
	#  clients take priority over the global `client` definitions.
	#
	#  See the main `clients.conf` file for documentation on the `client`
	#  section.
	#
	client tacacs {
		ipaddr = 127.0.0.1

		#
		#  This has to be specified for all TACACS+ clients.
		#
		#  There is no standard for TACACS+ over UDP.
		#
		proto = tcp

		#
		#  The TACACS+ key, or secret. If a secret is defined, then it will
		#  be used. All packets coming from this client MUST be encrypted
		#  with the shared secret.
		#
		#  The `secret` configuration item can be omitted or deleted, in
		#  which case all of the information (including passwords) are sent
		#  over the network in the clear. This practice is not recommended.
		#
		secret = testing123
	}

	#
	#  == Authentication-Start
	#

	#
	#  === Recv
	#
	#
	#  In general, it is not necessary to set `Auth-Type` in this
	#  section. The packet header contains a TACACS `Authentication-Type`
	#  with value `PAP`, `CHAP`, etc. That value will be used
	#  automatically by the server to set `Auth-Type`.
	#
	#  The only reason to set `Auth-Type` here is when you want to use a
	#  custom authentication method, such as `ldap`. You should ONLY set
	#  `Auth-Type := ldap` when the packet contains `Authentication-Type
	#  = PAP` _and_ the passwords in LDAP are stored in "crypt" or hashed
	#  form.
	#
	recv Authentication-Start {
		-sql
	}

	authenticate PAP {
		pap
	}

	authenticate CHAP {
		chap
	}

	authenticate MSCHAP {
		mschap
	}

	authenticate MSCHAPv2 {
		mschap
	}

	#
	#  LDAP authentication will only work with PAP authentication
	#
	#	authenticate ldap {
	#		if (Authentication-Type != PAP) {
	#			%log.warn("The packet is not PAP.  LDAP authentication is likely to fail!")
	#		}
	#
	#		ldap
	#	}

	#
	#  The automatic state machine will ensure that both User-Name and
	#  User-Password have been provided by this point making ASCII
	#  authentication equivalent to PAP.
	#
	#  Alternatively, if extra data is required, set reply.Packet-Type :=
	#  ::Authentication-GetData to request the extra data, which will be
	#  in User-Message in the next packet (if the client provides it)
	#
	authenticate ASCII {
		pap
	}

	#
	#  === Send
	#
	#  Note that "follow" is officially deprecated, and is not supported.
	#
	send Authentication-Pass {
		reply.Server-Message := "Hello %{User-Name}"

		#
		#  Call an instance of `linelog` to log the authentication success
		#  - equivalent to the previous log `auth = yes` option in v3.
		#  See `mods-enabled/linelog` for message formats and destinations.
		#
		#		log_auth_authentication_pass
	}

	send Authentication-Fail {
		reply.Server-Message := "Failed login!"

		#
		#  Call an instance of `linelog` to log the authentication failure
		#  - equivalent to the previous log `auth = yes` option in v3.
		#  See `mods-enabled/linelog` for message formats and destinations.
		#
		#		log_auth_authentication_fail
	}

	#
	#  With ASCII methods, GetUser and GetPass typically send a prompt
	#  for the client to present to the user.
	#
	send Authentication-GetUser {
		reply.Server-Message := "Username:"
	}

	send Authentication-GetPass {
		reply.Server-Message := "Password:"
	}

	#
	#  == Authentication-Continue
	#
	#  This section handles responses to challenges for
	#  `Authentication-Type = ASCII`
	#
	#  i.e. The server receives an `Authentication-Start` packet with
	#  `Authentication-Type = ASCII`, and replies with a challenge. The
	#  client returns the username or password in an
	#  `Authentication-Continue` packet. The server should then check the
	#  username or password.
	#
	#  The TACACS+ protocol puts the response username or password into
	#  the "data" field. For simplicity, the server copies that field
	#  into the User-Name or User-Password attribute as appropriate. This
	#  automatic copyinh means that it is a lot easier to understand and
	#  configure TACACS+.
	#

	#
	#  === Recv
	#
	#  Receive `Authentication-Continue` packet. When this section is
	#  done and has a User-Password, the server will run an `authenticate
	#  ... { }` section. It will then call one of the `send` sections to
	#  send the reply.
	#
	recv Authentication-Continue {
		#
		#	https://tools.ietf.org/id/draft-ietf-opsawg-07.html#rfc.section.4.3
		#
		"%{Authentication-Continue-Flags}"
		"%{User-Message}"
		"%{Data}"
	}

	#
	#  == Authorization
	#

	#
	#  === Recv
	#
	recv Authorization-Request {
		"%{Authentication-Method}"
		"%{Privilege-Level}"
		"%{Authentication-Type}"
		"%{Authentication-Service}"
		"%{User-Name}"
		"%{Client-Port}"
		"%{Remote-Address}"
		"%{Argument-List}"
	}

	#
	#  === Send
	#
	#	Add the arguments to whatever the user entered.
	#
	send Authorization-Pass-Add {
		reply.Server-Message := "authorization-response-server"
		reply.Data := "authorization-response-data"
		reply.Argument-List := "key1=var1"
	}

	#
	#	Replace whatever the user entered with the following arguments
	#
	send Authorization-Pass-Replace {
		reply.Server-Message := "authorization-response-server"
		reply.Data := "authorization-response-data"
		reply.Argument-List := "key1=var1"
	}

	#
	#	Reject the request
	#
	send Authorization-Fail {

	}

	#
	#  == Accounting
	#

	#
	#  === Recv
	#
	recv Accounting-Request {
		#
		#  Create a 'detail'ed log of the packets.
		#
		detail
	}

	#
	#  === Accounting "type" Sections
	#
	#  Each type of accounting packet is run through its own section. The
	#  section MUST return "ok" to indicate that it successfully handled
	#  the accounting data.
	#
	#  The "ok" return code is typically set automatically when an
	#  accounting module succeeds in its work. The explicit "ok" here is
	#  just so that the default configuration will return success for all
	#  accounting packets.
	#
	#  First packet for a session
	accounting Start {
		ok
	}

	#  Updates a previous start
	accounting Watchdog-Update {
		ok
	}

	#  Updates a session
	accounting Watchdog {
		ok
	}

	#  Stops a session
	accounting Stop {
		ok
	}

	#
	#  === Send Responses
	#
	send Accounting-Success {
		reply.Server-Message := "Success"
	}

	send Accounting-Error {
		reply.Server-Message := "Error"
	}

	#
	#	NOTE: Proxying of TACACS+ requests is NOT supported.
	#
}
