Authen-TacacsPlus-0.27/0000755000175000017500000000000013617706356013732 5ustar mikemmikemAuthen-TacacsPlus-0.27/MANIFEST0000644000175000017500000000066713617706354015072 0ustar mikemmikemChanges MANIFEST Makefile.PL TacacsPlus.pm TacacsPlus.xs test.pl README tacpluslib/Makefile.PL tacpluslib/encrypt.c tacpluslib/expire.h tacpluslib/md5.c tacpluslib/md5.h tacpluslib/parse.h tacpluslib/regexp.h tacpluslib/regmagic.h tacpluslib/tac_client.c tacpluslib/tac_plus.h tacpluslib/tacplus_client.h tacpluslib/utils.c META.json META.yml Authen-TacacsPlus-0.27/test.pl0000444000175000001440000000446610766601311015274 0ustar mikemusers# Before `make install' is performed this script should be runnable with # `make test'. After `make install' it should work as `perl test.pl' ######################### We start with some black magic to print on failure. # Change 1..1 below to 1..last_test_to_print . # (It may become useful if the test is moved to ./t subdirectory.) use Test; BEGIN { plan tests => 10 }; use Authen::TacacsPlus; ok(1); ######################### End of black magic. # Insert your test code below (better if it prints "ok 13" # (correspondingly "not ok 13") depending on the success of chunk 13 # of the test code): # You will have to change these to suit yourself: my $host = $ENV{AUTHEN_TACACSPLUS_TEST_HOST} || 'zulu.open.com.au'; my $key = $ENV{AUTHEN_TACACSPLUS_TEST_KEY} || 'mysecret'; my $timeout = 15; my $port = 49; my $username = $ENV{AUTHEN_TACACSPLUS_TEST_USERNAME} || 'mikem'; my $password = $ENV{AUTHEN_TACACSPLUS_TEST_PASSWORD} || 'fred'; # This is the CHAP encrypted password, including the challenge # and identifier my $chap_password = $ENV{AUTHEN_TACACSPLUS_TEST_CHAP_PASSWORD} || 'djfhafghlkdlkfjasgljksgljkdsjsdfshdfgsdfkjglgh'; my $tac = new Authen::TacacsPlus(Host=>$host, Key=>$key, Timeout=>$timeout, Port=>$port); if ($tac) { ok(1); } else { foreach (2..10) { skip('Unable to complete tests because the test Tacacs server could not be contacted'); } exit; } # test default type (ASCII), backwards compatible ok($tac->authen($username, $password)); ok($tac->close() == 0); my $tac = new Authen::TacacsPlus(Host=>$host, Key=>$key, Timeout=>$timeout, Port=>$port); ok($tac); # test default PAP type ok($tac->authen($username, $password, &Authen::TacacsPlus::TAC_PLUS_AUTHEN_TYPE_PAP)); ok($tac->close() == 0); $tac = new Authen::TacacsPlus(Host=>$host, Key=>$key, Timeout=>$timeout, Port=>$port); ok($tac); # test CHAP auth type require Digest::MD5; $chap_id = '5'; $chap_challenge = '1234567890123456'; # This is the CHAP response from the NAS. We will fake it here # by calculating it in the same way th eNAS does: $chap_response = Digest::MD5::md5($chap_id . $password . $chap_challenge); $chap_string = $chap_id . $chap_challenge . $chap_response; ok($tac->authen($username, $chap_string, &Authen::TacacsPlus::TAC_PLUS_AUTHEN_TYPE_CHAP)); ok($tac->close() == 0); Authen-TacacsPlus-0.27/META.json0000664000175000017500000000143613617706356015361 0ustar mikemmikem{ "abstract" : "unknown", "author" : [ "unknown" ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010", "license" : [ "unknown" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Authen-TacacsPlus", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } } }, "release_status" : "stable", "version" : "0.27", "x_serialization_backend" : "JSON::PP version 2.97001" } Authen-TacacsPlus-0.27/TacacsPlus.xs0000444000175000001440000000433710766577407016415 0ustar mikemusers#ifdef __cplusplus extern "C" { #endif #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #ifdef __cplusplus } #endif #include #include "tacpluslib/tacplus_client.h" #include "tacpluslib/tac_plus.h" static int not_here(s) char *s; { croak("%s not implemented on this architecture", s); return -1; } static double constant(name, arg) char *name; int arg; { errno = 0; switch (*name) { case 'A': break; case 'B': break; case 'C': break; case 'D': break; case 'E': break; case 'F': break; case 'G': break; case 'H': break; case 'I': break; case 'J': break; case 'K': break; case 'L': break; case 'M': break; case 'N': break; case 'O': break; case 'P': break; case 'Q': break; case 'R': break; case 'S': break; case 'T': if (strEQ(name, "TAC_PLUS_AUTHEN_TYPE_ASCII")) return TAC_PLUS_AUTHEN_TYPE_ASCII; else if (strEQ(name, "TAC_PLUS_AUTHEN_TYPE_PAP")) return TAC_PLUS_AUTHEN_TYPE_PAP; else if (strEQ(name, "TAC_PLUS_AUTHEN_TYPE_CHAP")) return TAC_PLUS_AUTHEN_TYPE_CHAP; else if (strEQ(name, "TAC_PLUS_AUTHEN_TYPE_ARAP")) return TAC_PLUS_AUTHEN_TYPE_ARAP; break; case 'U': break; case 'V': break; case 'W': break; case 'X': break; case 'Y': break; case 'Z': break; } errno = EINVAL; return 0; //not_there: // errno = ENOENT; // return 0; } MODULE = Authen::TacacsPlus PACKAGE = Authen::TacacsPlus double constant(name,arg) char * name int arg int init_tac_session (host_name,port_name,key,timeout) char* host_name char* port_name char* key int timeout OUTPUT: RETVAL int make_auth (username, password, authen_type) char* username char* password int authen_type CODE: STRLEN user_len; STRLEN password_len; username = (char *)SvPV(ST(0),user_len); password = (char *)SvPV(ST(1),password_len); RETVAL = make_auth(username, user_len, password, password_len, authen_type); OUTPUT: RETVAL void deinit_tac_session() char * errmsg() CODE: RETVAL = tac_err; OUTPUT: RETVAL Authen-TacacsPlus-0.27/META.yml0000664000175000017500000000074613617706356015214 0ustar mikemmikem--- abstract: unknown author: - unknown build_requires: ExtUtils::MakeMaker: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010' license: unknown meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Authen-TacacsPlus no_index: directory: - t - inc version: '0.27' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' Authen-TacacsPlus-0.27/README0000444000175000001440000000055612122716701014632 0ustar mikemusersPerl5 extension module for authentication using tacacs+ server. Copyright (C) 1998-99 Mike Shoyher , tacacs+ is Copyright (c) 1995-1996 by Cisco systems, Inc. Thanks to: Mike McCauley This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Authen-TacacsPlus-0.27/tacpluslib/0000755000175000017500000000000013617706356016074 5ustar mikemmikemAuthen-TacacsPlus-0.27/tacpluslib/tacplus_client.h0000444000175000001440000000054006715536234021303 0ustar mikemusers #ifndef TACPLUS_CLIENT #define TACPLUS_CLIENT extern int make_auth (char* username, int user_len, char* password, int password_len, int authen_type); extern int init_tac_session (char* host_name, char* port_name, char* key, int timeout); extern void deinit_tac_session(); extern char* tac_err; #endif Authen-TacacsPlus-0.27/tacpluslib/utils.c0000444000175000001440000001041510675055333017423 0ustar mikemusers/* Copyright (c) 1995-1996 by Cisco systems, Inc. Permission to use, copy, modify, and distribute this software for any purpose and without fee is hereby granted, provided that this copyright and permission notice appear on all copies of the software and supporting documentation, the name of Cisco Systems, Inc. not be used in advertising or publicity pertaining to distribution of the program without specific prior permission, and notice be given in supporting documentation that modification, copying and distribution is by permission of Cisco Systems, Inc. Cisco Systems, Inc. makes no representations about the suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #include "tac_plus.h" #include int tac_exit(status) int status; { if (debug & DEBUG_FORK_FLAG) report(LOG_DEBUG, "exit status=%d", status); exit(status); } char * tac_malloc(size) int size; { char *p; /* some mallocs don't like requests for zero length */ if (size == 0) { size++; } p = (char *) malloc(size); if (p == NULL) { report(LOG_ERR, "malloc %d failure", size); tac_exit(1); } return (p); } char * tac_realloc(ptr, size) char *ptr; int size; { char *p; if (ptr == NULL) { /* realloc(0, size) is not portable */ p = tac_malloc(size); } else { p = (char *)realloc(ptr, size); } if (p == NULL) { report(LOG_ERR, "realloc %d failure", size); tac_exit(1); } return (p); } char * tac_strdup(p) char *p; { char *n = strdup(p); if (n == NULL) { report(LOG_ERR, "strdup allocation failure"); tac_exit(1); } return (n); } char * tac_make_string(p, len) u_char *p; int len; { char *string; int new_len = len; /* * Add space for a null terminator if needed. Also, no telling * what various mallocs will do when asked for a length of zero. */ if (len == 0 || p[len - 1]) new_len++; string = (char *) tac_malloc(new_len); bzero(string, new_len); bcopy(p, string, len); return (string); } /* return a pointer to the end of substring in string, or NULL. Substring must begin at start of string. */ char * tac_find_substring(substring, string) char *substring, *string; { int len; if (!(substring && string)) { return(NULL); } len = strlen(substring); if (len > (int) strlen(string)) { return(NULL); } if (strncmp(substring, string, len)) { /* no match */ return(NULL); } return(string + len); } #ifdef NEED_BZERO int bzero(p, len) register char *p; int len; { register int n; if ((n = len) <= 0) return; do *p++ = 0; while (--n); } int bcopy(s1, s2, len) register char *s1, *s2; int len; { register int n; if ((n = len) <= 0) return; do *s2++ = *s1++; while (--n); } int bcmp(s1,s2,n) char *s1,*s2; int n; { while (n-- > 0) { if (*s1++ != *s2++) { return(1); } } return 0; } #endif /* NEED_BZERO */ /* Lock a file descriptor using fcntl. Returns 1 on successfully acquiring the lock. The lock dies when we close the file, so there's currently no separate unlock procedure. Note that if the locked file is on an NFS-mounted partition, you are at the mercy of SUN's lockd, which is probably a bad idea */ int tac_lockfd(filename,lockfd) char *filename; int lockfd; { int tries; struct flock flock; int status; flock.l_type = F_WRLCK; flock.l_whence = SEEK_SET; /* relative to bof */ flock.l_start = 0L; /* from offset zero */ flock.l_len = 0L; /* lock to eof */ for (tries = 0; tries < 60; tries++) { errno = 0; status = fcntl(lockfd, F_SETLK, &flock); if (status == -1) { if (errno == EACCES || errno == EAGAIN) { sleep(1); continue; } else { syslog(LOG_ERR, "fcntl lock error status %d on %s %d %s", status, filename, lockfd, strerror(errno)); return(0); } } /* successful lock */ break; } if (errno != 0) { syslog(LOG_ERR, "Cannot lock %s fd %d in %d tries %s", filename, lockfd, tries+1, strerror(errno)); return(0); } return(1); } Authen-TacacsPlus-0.27/tacpluslib/md5.h0000444000175000001440000000366410675055430016763 0ustar mikemusers/* Please NOTE: None of the TACACS code available here comes with any warranty or support. */ /* * MD5.H - header file for MD5C.C */ /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All * rights reserved. * * License to copy and use this software is granted provided that it * is identified as the "RSA Data Security, Inc. MD5 Message-Digest * Algorithm" in all material mentioning or referencing this software * or this function. * * License is also granted to make and use derivative works provided * that such works are identified as "derived from the RSA Data * Security, Inc. MD5 Message-Digest Algorithm" in all material * mentioning or referencing the derived work. * * RSA Data Security, Inc. makes no representations concerning either * the merchantability of this software or the suitability of this * software for any particular purpose. It is provided "as is" * without express or implied warranty of any kind. * * These notices must be retained in any copies of any part of this * documentation and/or software. */ #ifndef _MD5_H #define _MD5_H /* delineate the cisco changes to the RSA supplied module */ #define CISCO_MD5_MODS #if defined(CISCO_MD5_MODS) /* typedef a 32-bit type */ typedef unsigned int UINT4; /* typedef a generic pointer type */ typedef unsigned char *POINTER; /* enable prototyping */ /* #define PROTO_LIST(x) x */ /* disable prototyping */ #define PROTO_LIST(x) () #endif /* defined(CISCO_MD5_MODS) */ /* MD5 context. */ typedef struct { UINT4 state[4]; /* state (ABCD) */ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ unsigned char buffer[64]; /* input buffer */ } MD5_CTX; void MD5Init PROTO_LIST ((MD5_CTX *)); void MD5Update PROTO_LIST ((MD5_CTX *, unsigned char *, unsigned int)); void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *)); #endif /* _MD5_H */ Authen-TacacsPlus-0.27/tacpluslib/tac_client.c0000644000175000001440000002251712015355400020364 0ustar mikemusers /* (C) 1997 Mike Shoyher msh@corbina.net, msh@apache.lexa.ru */ #include #include #include #include #include #include #include #include #include #include #include #include"tac_plus.h" #include "tacplus_client.h" int tac_sequence; int tac_session_id; int tac_maxtry=3; int tac_timeout=15; int tac_fd; char tac_key[128]; struct sockaddr_in tac_port; struct hostent *tac_h; struct servent *tac_serv; char ourhost[128]; int ourhost_len; char* ourtty="Virtual00"; int ourtty_len; char* tac_err="NONE"; void fill_tac_hdr(struct tac_plus_pak_hdr* hdr) { hdr->version=TAC_PLUS_VER_0; hdr->type=TAC_PLUS_AUTHEN; hdr->seq_no=tac_sequence; hdr->encryption=TAC_PLUS_CLEAR; hdr->session_id=tac_session_id; } int send_data(void* buf, int buf_len, int fd); int read_reply(void** data); /* Need to specify the lengths, becuase CHAP passwords etc may have NULs in them */ void send_auth_cont(char* msg, int msg_len); int make_auth(char* username, int user_len, char* password, int password_len, int authen_type) { struct tac_plus_pak_hdr hdr; struct authen_start as; int datalength; void* buf; void* data; int data_len; int buf_len; struct authen_reply* ar; fill_tac_hdr(&hdr); datalength=TAC_AUTHEN_START_FIXED_FIELDS_SIZE; as.action= TAC_PLUS_AUTHEN_LOGIN ; as.priv_lvl= TAC_PLUS_PRIV_LVL_MIN ; as.authen_type = authen_type ; as.service= TAC_PLUS_AUTHEN_SVC_LOGIN ; as.user_len=as.port_len=as.rem_addr_len=as.data_len=0; if (authen_type != TAC_PLUS_AUTHEN_TYPE_ASCII) { /* This will be a version 1 request with the username and password in the start */ hdr.version=TAC_PLUS_VER_1; as.user_len = user_len; as.data_len = password_len; } buf=malloc(buf_len=TAC_PLUS_HDR_SIZE+TAC_AUTHEN_START_FIXED_FIELDS_SIZE+ourtty_len+ourhost_len+as.user_len+as.data_len); /* Append user name if required */ bcopy(username,buf+datalength+TAC_PLUS_HDR_SIZE,as.user_len); datalength+=(as.user_len); bcopy(ourtty,buf+datalength+TAC_PLUS_HDR_SIZE,ourtty_len); datalength+=(ourtty_len); as.port_len=ourtty_len; bcopy(ourhost,buf+datalength+TAC_PLUS_HDR_SIZE,ourhost_len); datalength+=(ourhost_len); as.rem_addr_len=ourhost_len; /* Append password if required */ bcopy(password,buf+datalength+TAC_PLUS_HDR_SIZE,as.data_len); datalength+=(as.data_len); hdr.datalength= htonl(datalength) ; bcopy(&hdr,buf,TAC_PLUS_HDR_SIZE); bcopy(&as,buf+TAC_PLUS_HDR_SIZE,TAC_AUTHEN_START_FIXED_FIELDS_SIZE); md5_xor(buf, buf+TAC_PLUS_HDR_SIZE, tac_key); send_data(buf,buf_len,tac_fd); free(buf); while ((data_len=read_reply(&data))!=-1){ ar=data; switch (ar->status) { case TAC_PLUS_AUTHEN_STATUS_GETUSER: free(data); send_auth_cont(username, user_len); break; case TAC_PLUS_AUTHEN_STATUS_GETPASS: free(data); send_auth_cont(password, password_len); break; case TAC_PLUS_AUTHEN_STATUS_PASS: return 1; case TAC_PLUS_AUTHEN_STATUS_FAIL: tac_err="Authentication failed"; return 0; default : tac_err="Protocol error"; return 0; } } tac_err="Unknown error"; return 0; } void send_auth_cont(char* msg, int msg_len) { struct tac_plus_pak_hdr hdr; struct authen_cont ac; int datalength; void* buf; int buf_len; buf_len=TAC_PLUS_HDR_SIZE+TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE+msg_len; buf=malloc(buf_len); fill_tac_hdr(&hdr); ac.user_data_len=ac.flags=0; ac.user_msg_len=htons(msg_len); bcopy(msg,buf+TAC_PLUS_HDR_SIZE+TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE,msg_len); datalength=msg_len+TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE; hdr.datalength=htonl(datalength); bcopy(&hdr,buf,TAC_PLUS_HDR_SIZE); bcopy(&ac,buf+TAC_PLUS_HDR_SIZE,TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE); md5_xor(buf, buf+TAC_PLUS_HDR_SIZE, tac_key); send_data(buf,buf_len,tac_fd); free(buf); } void myerror (char* s) { printf("%s\n",s); exit(1); } int init_tac_session(char* host_name, char* port_name, char* key, int timeout) { int flags; int res; int optval; socklen_t len; fd_set wset; struct timeval tv; gethostname(ourhost,127); ourhost_len=strlen(ourhost); ourtty_len=strlen(ourtty); srand(time(NULL)); if (timeout>0) tac_timeout=timeout; strcpy(tac_key,key); tac_session_id=rand(); tac_sequence=1; tac_port.sin_family = AF_INET; if (*host_name>='0' && *host_name<='9') { tac_port.sin_addr.s_addr = inet_addr(host_name); } else { tac_h = gethostbyname(host_name); if (!tac_h) { /*myerror("Cannot resolve host name");*/ tac_err="Cannot resolve host name"; return -1; } tac_port.sin_addr = *((struct in_addr *) tac_h->h_addr); } if (port_name==NULL) port_name="tacacs"; if (*port_name>='0' && *port_name<='9') { tac_port.sin_port=htons (atoi(port_name)); } else { tac_serv=getservbyname(port_name,"tcp"); if (tac_serv) tac_port.sin_port=tac_serv->s_port; else { /*myerror("Unknown port");*/ tac_err="Unknown port"; return -1; } } if((tac_fd = socket (AF_INET, SOCK_STREAM, 0))<0) return -1; // get flags flags = fcntl(tac_fd, F_GETFL, 0); if( flags < 0 ) { //fprintf( stderr, "fcntl: %s\n", strerror(errno) ); tac_err = "socket error"; return -1; } // set socket to nonblock res = fcntl( tac_fd, F_SETFL, flags | O_NONBLOCK ); if( res < 0 ) { //fprintf( stderr, "fcntl: %s\n", strerror(errno) ); tac_err = "socket error"; return -1; } // connect res = connect (tac_fd, (struct sockaddr *) &tac_port, sizeof tac_port); // connection not established, but in progress if( res < 0 && (errno != EINPROGRESS) ) { tac_err = "connection failed"; return -1; } // wait for connection or timeout if( res != 0 ) { FD_ZERO(&wset); FD_SET(tac_fd, &wset); tv.tv_sec = timeout; tv.tv_usec = 0; res = select( tac_fd+1, NULL, &wset, NULL, &tv ); if( res < 0 ) { tac_err = "select failed"; return -1; } else if( res == 0 ) { tac_err = "timeout"; return -1; } if( res > 0 ) { // socket is ready for writing. Check if connection was // established successfully len = sizeof(optval); if( getsockopt( tac_fd, SOL_SOCKET, SO_ERROR, (void *)&optval, &len ) > 0 ) { tac_err = "getsockopt failed"; return -1; } if( optval != 0 ) { tac_err = "connection failed"; return -1; } // optval == 0 --> no error, connection established } } return tac_fd; } int send_data(void* buf, int buf_len, int fd) { fd_set fds; int rr; int try; struct timeval tv; FD_ZERO(&fds); FD_SET(fd,&fds); tv.tv_sec = tac_timeout; tv.tv_usec = 0; for(try=0;try #define MD5_memcpy(out,in,len) memcpy(out, in, len) #define MD5_memset(ptr,val,len) memset(ptr, val, len) #else /* !defined(MD5_NEED_MEM_FUNCS) */ static void MD5_memcpy PROTO_LIST((POINTER, POINTER, unsigned int)); static void MD5_memset PROTO_LIST((POINTER, int, unsigned int)); #endif /* !defined(MD5_NEED_MEM_FUNCS) */ static unsigned char PADDING[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* F, G, H and I are basic MD5 functions. */ #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) #define H(x, y, z) ((x) ^ (y) ^ (z)) #define I(x, y, z) ((y) ^ ((x) | (~z))) /* ROTATE_LEFT rotates x left n bits. */ #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. Rotation is separate from addition to prevent recomputation. */ #define FF(a, b, c, d, x, s, ac) { \ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define GG(a, b, c, d, x, s, ac) { \ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define HH(a, b, c, d, x, s, ac) { \ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define II(a, b, c, d, x, s, ac) { \ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } /* MD5 initialization. Begins an MD5 operation, writing a new context. */ void MD5Init(context) MD5_CTX *context; /* context */ { context->count[0] = context->count[1] = 0; /* Load magic initialization constants. */ context->state[0] = 0x67452301; context->state[1] = 0xefcdab89; context->state[2] = 0x98badcfe; context->state[3] = 0x10325476; } /* MD5 block update operation. Continues an MD5 message-digest operation, processing another message block, and updating the context. */ void MD5Update(context, input, inputLen) MD5_CTX *context; /* context */ unsigned char *input; /* input block */ unsigned int inputLen; /* length of input block */ { unsigned int i, index, partLen; /* Compute number of bytes mod 64 */ index = (unsigned int) ((context->count[0] >> 3) & 0x3F); /* Update number of bits */ if ((context->count[0] += ((UINT4) inputLen << 3)) < ((UINT4) inputLen << 3)) context->count[1]++; context->count[1] += ((UINT4) inputLen >> 29); partLen = 64 - index; /* Transform as many times as possible. */ if (inputLen >= partLen) { MD5_memcpy ((POINTER) & context->buffer[index], (POINTER) input, partLen); MD5Transform(context->state, context->buffer); for (i = partLen; i + 63 < inputLen; i += 64) MD5Transform(context->state, &input[i]); index = 0; } else i = 0; /* Buffer remaining input */ MD5_memcpy ((POINTER) & context->buffer[index], (POINTER) & input[i], inputLen - i); } /* MD5 finalization. Ends an MD5 message-digest operation, writing the the message digest and zeroizing the context. */ void MD5Final(digest, context) unsigned char digest[16]; /* message digest */ MD5_CTX *context; /* context */ { unsigned char bits[8]; unsigned int index, padLen; /* Save number of bits */ Encode(bits, context->count, 8); /* Pad out to 56 mod 64. */ index = (unsigned int) ((context->count[0] >> 3) & 0x3f); padLen = (index < 56) ? (56 - index) : (120 - index); MD5Update(context, PADDING, padLen); /* Append length (before padding) */ MD5Update(context, bits, 8); /* Store state in digest */ Encode(digest, context->state, 16); /* Zeroize sensitive information. */ MD5_memset((POINTER) context, 0, sizeof(*context)); } /* MD5 basic transformation. Transforms state based on block. */ static void MD5Transform(state, block) UINT4 state[4]; unsigned char block[64]; { UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; Decode(x, block, 64); /* Round 1 */ FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */ FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */ FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */ FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */ FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */ FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */ FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */ FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */ FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */ FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */ FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ /* Round 2 */ GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */ GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */ GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */ GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */ GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */ GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */ GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */ GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */ GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */ GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */ GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ /* Round 3 */ HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */ HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */ HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */ HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */ HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */ HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */ HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */ HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */ HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */ HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */ /* Round 4 */ II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */ II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */ II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */ II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */ II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */ II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */ II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */ II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */ II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */ II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; /* Zeroize sensitive information. */ MD5_memset((POINTER) x, 0, sizeof(x)); } /* Encodes input (UINT4) into output (unsigned char). Assumes len is a multiple of 4. */ static void Encode(output, input, len) unsigned char *output; UINT4 *input; unsigned int len; { unsigned int i, j; for (i = 0, j = 0; j < len; i++, j += 4) { output[j] = (unsigned char) (input[i] & 0xff); output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff); output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff); output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff); } } /* Decodes input (unsigned char) into output (UINT4). Assumes len is a multiple of 4. */ static void Decode(output, input, len) UINT4 *output; unsigned char *input; unsigned int len; { unsigned int i, j; for (i = 0, j = 0; j < len; i++, j += 4) output[i] = ((UINT4) input[j]) | (((UINT4) input[j + 1]) << 8) | (((UINT4) input[j + 2]) << 16) | (((UINT4) input[j + 3]) << 24); } #if defined(MD5_NEED_MEM_FUNC) /* Note: Replace "for loop" with standard memcpy if possible. */ static void MD5_memcpy(output, input, len) POINTER output; POINTER input; unsigned int len; { unsigned int i; for (i = 0; i < len; i++) output[i] = input[i]; } /* Note: Replace "for loop" with standard memset if possible. */ static void MD5_memset(output, value, len) POINTER output; int value; unsigned int len; { unsigned int i; for (i = 0; i < len; i++) ((char *) output)[i] = (char) value; } #endif /* defined(MD5_NEED_MEM_FUNC) */ Authen-TacacsPlus-0.27/tacpluslib/parse.h0000444000175000001440000000431106442766236017410 0ustar mikemusers/* Copyright (c) 1995-1996 by Cisco systems, Inc. Permission to use, copy, modify, and distribute this software for any purpose and without fee is hereby granted, provided that this copyright and permission notice appear on all copies of the software and supporting documentation, the name of Cisco Systems, Inc. not be used in advertising or publicity pertaining to distribution of the program without specific prior permission, and notice be given in supporting documentation that modification, copying and distribution is by permission of Cisco Systems, Inc. Cisco Systems, Inc. makes no representations about the suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ /* Keywords & values */ #define S_eof 99 #define S_unknown 101 #define S_separator 104 #define S_string 106 #define S_openbra 107 #define S_closebra 108 #define S_svc_dflt 109 #define S_key 1 #define S_user 2 #define S_group 3 #define S_host 4 #define S_accounting 5 #define S_name 7 #define S_login 8 #define S_member 9 #define S_expires 10 #define S_cleartext 11 #define S_message 12 #define S_arap 13 #define S_chap 14 #define S_after 15 #define S_pap 16 #define S_svc 17 #define S_before 18 #define S_default 19 #define S_access 20 #define S_deny 21 #define S_permit 22 #define S_exec 23 #define S_protocol 24 #define S_optional 25 #define S_ip 26 #define S_ipx 27 #define S_slip 28 #define S_ppp 29 #define S_file 30 #define S_skey 31 #define S_authorization 32 #define S_authentication 33 #define S_cmd 34 #define S_attr 35 #define S_lcp 36 #define S_global 37 #define S_des 38 #define S_opap 39 #ifdef MAXSESS #define S_maxsess 40 #endif Authen-TacacsPlus-0.27/tacpluslib/regmagic.h0000444000175000001440000000040006442766236020047 0ustar mikemusers/* Please NOTE: None of the TACACS code available here comes with any warranty or support. */ /* * The first byte of the regexp internal "program" is actually this magic * number; the start node begins in the second byte. */ #define MAGIC 0234 Authen-TacacsPlus-0.27/tacpluslib/regexp.h0000444000175000001440000000124506442766236017573 0ustar mikemusers/* Please NOTE: None of the TACACS code available here comes with any warranty or support. */ /* * Definitions etc. for regexp(3) routines. * * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], * not the System V one. */ #define NSUBEXP 10 typedef struct regexp { char *startp[NSUBEXP]; char *endp[NSUBEXP]; char regstart; /* Internal use only. */ char reganch; /* Internal use only. */ char *regmust; /* Internal use only. */ int regmlen; /* Internal use only. */ char program[1]; /* Unwarranted chumminess with compiler. */ } regexp; extern regexp *regcomp(); extern int regexec(); extern void regsub(); extern void regerror(); Authen-TacacsPlus-0.27/tacpluslib/encrypt.c0000444000175000001440000001073710675055146017760 0ustar mikemusers/* Copyright (c) 1995-1996 by Cisco systems, Inc. Permission to use, copy, modify, and distribute this software for any purpose and without fee is hereby granted, provided that this copyright and permission notice appear on all copies of the software and supporting documentation, the name of Cisco Systems, Inc. not be used in advertising or publicity pertaining to distribution of the program without specific prior permission, and notice be given in supporting documentation that modification, copying and distribution is by permission of Cisco Systems, Inc. Cisco Systems, Inc. makes no representations about the suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #include #include "tac_plus.h" #include "md5.h" /* * create_md5_hash(): create an md5 hash of the "session_id", "the user's * key", "the version number", the "sequence number", and an optional * 16 bytes of data (a previously calculated hash). If not present, this * should be NULL pointer. * * Write resulting hash into the array pointed to by "hash". * * The caller must allocate sufficient space for the resulting hash * (which is 16 bytes long). The resulting hash can safely be used as * input to another call to create_md5_hash, as its contents are copied * before the new hash is generated. * * */ void create_md5_hash(session_id, key, version, seq_no, prev_hash, hash) int session_id; char *key; u_char version; u_char seq_no; u_char *prev_hash; u_char *hash; { u_char *md_stream, *mdp; int md_len; MD5_CTX mdcontext; md_len = sizeof(session_id) + strlen(key) + sizeof(version) + sizeof(seq_no); if (prev_hash) { md_len += MD5_LEN; } mdp = md_stream = (u_char *) tac_malloc(md_len); bcopy(&session_id, mdp, sizeof(session_id)); mdp += sizeof(session_id); bcopy(key, mdp, strlen(key)); mdp += strlen(key); bcopy(&version, mdp, sizeof(version)); mdp += sizeof(version); bcopy(&seq_no, mdp, sizeof(seq_no)); mdp += sizeof(seq_no); if (prev_hash) { bcopy(prev_hash, mdp, MD5_LEN); mdp += MD5_LEN; } MD5Init(&mdcontext); MD5Update(&mdcontext, md_stream, md_len); MD5Final(hash, &mdcontext); free(md_stream); return; } /* * Overwrite input data with en/decrypted version by generating an MD5 hash and * xor'ing data with it. * * When more than 16 bytes of hash is needed, the MD5 hash is performed * again with the same values as before, but with the previous hash value * appended to the MD5 input stream. * * Return 0 on success, -1 on failure. */ int md5_xor(HDR* hdr, u_char* data, char* key) { int i, j; u_char hash[MD5_LEN]; /* the md5 hash */ u_char last_hash[MD5_LEN]; /* the last hash we generated */ u_char *prev_hashp = (u_char *) NULL; /* pointer to last created * hash */ int data_len; int session_id; u_char version; u_char seq_no; data_len = ntohl(hdr->datalength); session_id = hdr->session_id; /* always in network order for hashing */ version = hdr->version; seq_no = hdr->seq_no; if (!key) return (0); for (i = 0; i < data_len; i += 16) { create_md5_hash(session_id, key, version, seq_no, prev_hashp, hash); if (debug & DEBUG_MD5_HASH_FLAG) { int k; report(LOG_DEBUG, "hash: session_id=%u, key=%s, version=%d, seq_no=%d", session_id, key, version, seq_no); if (prev_hashp) { report(LOG_DEBUG, "prev_hash:"); for (k = 0; k < MD5_LEN; k++) report(LOG_DEBUG, "0x%x", prev_hashp[k]); } else { report(LOG_DEBUG, "no prev. hash"); } report(LOG_DEBUG, "hash: "); for (k = 0; k < MD5_LEN; k++) report(LOG_DEBUG, "0x%x", hash[k]); } /* debug */ bcopy(hash, last_hash, MD5_LEN); prev_hashp = last_hash; for (j = 0; j < 16; j++) { if ((i + j) >= data_len) { hdr->encryption = (hdr->encryption == TAC_PLUS_CLEAR) ? TAC_PLUS_ENCRYPTED : TAC_PLUS_CLEAR; return (0); } if (debug & DEBUG_XOR_FLAG) { report(LOG_DEBUG, "data[%d] = 0x%x, xor'ed with hash[%d] = 0x%x -> 0x%x\n", i + j, data[i + j], j, hash[j], data[i + j] ^ hash[j]); } /* debug */ data[i + j] ^= hash[j]; } } hdr->encryption = (hdr->encryption == TAC_PLUS_CLEAR) ? TAC_PLUS_ENCRYPTED : TAC_PLUS_CLEAR; return (0); } Authen-TacacsPlus-0.27/tacpluslib/Makefile.PL0000644000175000001440000000260212631413523020063 0ustar mikemusersuse ExtUtils::MakeMaker; $Verbose = 1; use Config; $osname=$Config{osname}; %defines=( 'linux'=>'-DLINUX', 'freebsd'=>'-DFREEBSD', 'netbsd'=>'-DNETBSD', 'solaris'=>'-DSOLARIS', 'sunos'=>'-DSOLARIS', 'bsdi'=>'-DBSDI', 'aix'=>'-DAIX', 'hpux'=>'-DHPUX', ); WriteMakefile( NAME => 'Authen::TacacsPlus::tacplus', DEFINE => $defines{$osname}, SKIP => [qw(static dynamic)], clean => {'FILES' => 'libtacplus$(LIB_EXT)'}, CCFLAGS => "$ENV{'CFLAGS'} $ENV{'CPPFLAGS'}", ); sub MY::top_targets { ' all: static static: libtacplus$(LIB_EXT) libtacplus$(LIB_EXT): $(O_FILES) $(AR) cr libtacplus$(LIB_EXT) $(O_FILES) $(RANLIB) libtacplus$(LIB_EXT) pure_all : $(NOECHO) $(NOOP) '; } Authen-TacacsPlus-0.27/tacpluslib/tac_plus.h0000644000175000001440000004443013617705757020123 0ustar mikemusers/* Copyright (c) 1995-1996 by Cisco systems, Inc. Permission to use, copy, modify, and distribute this software for any purpose and without fee is hereby granted, provided that this copyright and permission notice appear on all copies of the software and supporting documentation, the name of Cisco Systems, Inc. not be used in advertising or publicity pertaining to distribution of the program without specific prior permission, and notice be given in supporting documentation that modification, copying and distribution is by permission of Cisco Systems, Inc. Cisco Systems, Inc. makes no representations about the suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ /* * If you are defining a system from scratch, the following may be useful. * Otherwise, just use the system definitions below this section. */ /* Define this for minor include file differences on SYSV-based systems */ /* #define SYSV */ /* Define this if your sys_errlist is defined using const */ /* #define CONST_SYSERRLIST */ /* Do you need tacacs+ versions of bzero etc. */ /* #define NEED_BZERO */ /* Define this if you have shadow passwords in /etc/passwd and * /etc/shadow. Note that you usually need to be root to read * /etc/shadow */ /* #define SHADOW_PASSWORDS */ /* Define this if your malloc is defined in malloc.h instead of stdlib.h */ /* #define STDLIB_MALLOC */ /* Define this if your wait call status is a union as opposed to an int */ /* #define UNIONWAIT */ /* Define this if your signal() uses a function returning void instead * of int */ /* #define VOIDSIG */ /* Define this if your password file does not contain age and comment fields. */ /* #define NO_PWAGE */ /* Define this if you need a getdtablesize routine defined */ /* #define GETDTABLESIZE */ /* Define this if your system does not reap children automatically * when you ignore SIGCLD */ /* #define REAPCHILD */ /* Define this if you have DES routines you can link to for ARAP (See * the user's guide for more details). */ /* #define ARAP_DES */ /* Define this if you find that your daemon quits after being sent more than * one SIGUSR1. Some systems need to explicitly rearm signals after they've been * used once */ /* #define REARMSIGNAL */ /*#define VERSION "3.0.11.alpha" */ /* * System definitions. */ #ifdef NETBSD #define STDLIB_MALLOC #define NO_PWAGE #define CONST_SYSERRLIST #define VOIDSIG #endif #ifdef AIX /* * The only way to properly compile BSD stuff on AIX is to define a * "bsdcc" compiler on your system. See /usr/lpp/bos/bsdport on your * system for details. People who do NOT do this tell me that the code * still compiles but that it then doesn't behave correctly e.g. child * processes are not reaped correctly. Don't expect much sympathy if * you do this. */ #define _BSD 1 #define _BSD_INCLUDES #define UNIONWAIT #define NO_PWAGE #endif /* AIX */ #ifdef LINUX #define VOIDSIG #define NO_PWAGE #define REAPCHILD #include #define REARMSIGNAL #endif /* LINUX */ #ifdef MIPS #define SYSV #define GETDTABLESIZE #define REAPCHILD #define NEED_BZERO #endif /* MIPS */ #ifdef SOLARIS #define SYSV #define GETDTABLESIZE #define REAPCHILD #define SHADOW_PASSWORDS #define NEED_BZERO #endif /* SOLARIS */ #ifdef HPUX #define SYSV #define GETDTABLESIZE #define REAPCHILD #define SYSLOG_IN_SYS #define REARMSIGNAL #endif /* HPUX */ #ifdef FREEBSD #define CONST_SYSERRLIST #define STDLIB_MALLOC #define VOIDSIG #define NO_PWAGE #endif #ifdef BSDI #define VOIDSIG #define STDLIB_MALLOC #define NO_PWAGE #endif #define MD5_LEN 16 #include #include #include #include #include #include #include #include #include #include #include #ifdef SYSLOG_IN_SYS #include #else #include #endif #ifdef LINUX #include #endif #include #include #ifdef SYSV #include #define index strchr #else /* ! SYSV */ #include #endif /* SYSV */ #ifndef TAC_PLUS_PIDFILE #define TAC_PLUS_PIDFILE "/etc/tac_plus.pid" #endif /* * You probably shouldn't be changing much below this line unless you really * know what you are doing. */ #define DOLLARSIGN '$' /* * XTACACSP protocol defintions */ /* * This structure describes an authentication method. * authen_name contains the name of the authentication method. * authen_func is a pointer to the authentication function. * authen_method numeric value of authentication method */ #define AUTHEN_NAME_SIZE 128 struct authen_type { char authen_name[AUTHEN_NAME_SIZE]; int (*authen_func)(); int authen_type; }; /* * This structure describes a principal that is to be authenticated. * username is the principals name (ASCII, null terminated) * NAS_name is the name of the NAS where the user is * NAS_port is the port on the NAS where the user is * NAC_address is the remote user location. This may be * a remote IP address or a caller-ID or ... * priv_lvl user's requested privilege level. */ struct identity { char *username; char *NAS_name; char *NAS_port; char *NAC_address; int priv_lvl; }; /* * The authen_data structure is the data structure for passing * information to and from the authentication function * (authen_type.authen_func). */ struct authen_data { struct identity *NAS_id; /* user identity */ char *server_msg; /* null-terminated output msg */ int server_dlen; /* output data length */ char *server_data; /* output data */ char *client_msg; /* null-terminated input msg a user typed */ int client_dlen; /* input data length */ char *client_data; /* input data */ void *method_data; /* opaque private method data */ int action; /* what's to be done */ int service; /* calling service */ int status; /* Authen status */ int type; /* Authen type */ u_char flags; /* input & output flags fields */ }; /* return values for choose_authen(); */ #define CHOOSE_FAILED -1 /* failed to choose an authentication function */ #define CHOOSE_OK 0 /* successfully chose an authentication function */ #define CHOOSE_GETUSER 1 /* need a username before choosing */ #define CHOOSE_BADTYPE 2 /* Invalid preferred authen function specified */ /* * This structure is the data structure for passing information to * and from the authorization function (do_author()). */ struct author_data { struct identity *id; /* user id */ int authen_method; /* authentication method */ #define AUTHEN_METH_NONE 0x01 #define AUTHEN_METH_KRB5 0x02 #define AUTHEN_METH_LINE 0x03 #define AUTHEN_METH_ENABLE 0x04 #define AUTHEN_METH_LOCAL 0x05 #define AUTHEN_METH_TACACSPLUS 0x06 #define AUTHEN_METH_RCMD 0x20 int authen_type; /* authentication type see authen_type */ int service; /* calling service */ char *msg; /* optional NULL-terminated return message */ char *admin_msg; /* optional NULL-terminated admin message */ int status; /* return status */ #define AUTHOR_STATUS_PASS_ADD 0x01 #define AUTHOR_STATUS_PASS_REPL 0x02 #define AUTHOR_STATUS_FAIL 0x10 #define AUTHOR_STATUS_ERROR 0x11 int num_in_args; /* input arg count */ char **input_args; /* input arguments */ int num_out_args; /* output arg cnt */ char **output_args; /* output arguments */ }; /* An API accounting record structure */ struct acct_rec { int acct_type; /* start, stop, update */ #define ACCT_TYPE_START 1 #define ACCT_TYPE_STOP 2 #define ACCT_TYPE_UPDATE 3 struct identity *identity; int authen_method; int authen_type; int authen_service; char *msg; /* output field */ char *admin_msg; /* output field */ int num_args; char **args; }; #ifndef TAC_PLUS_PORT #define TAC_PLUS_PORT 49 #endif #define TAC_PLUS_READ_TIMEOUT 180 /* seconds */ #define TAC_PLUS_WRITE_TIMEOUT 180 /* seconds */ #define NAS_PORT_MAX_LEN 255 struct session { int session_id; /* host specific unique session id */ int aborted; /* have we received an abort flag? */ int seq_no; /* seq. no. of last packet exchanged */ time_t last_exch; /* time of last packet exchange */ int sock; /* socket for this connection */ char *key; /* the key */ int keyline; /* line number key was found on */ char *peer; /* name of connected peer */ char *cfgfile; /* config file name */ char *acctfile; /* name of accounting file */ char port[NAS_PORT_MAX_LEN+1]; /* For error reporting */ u_char version; /* version of last packet read */ }; extern struct session session; /* the session */ /* Global variables */ /* Get type conflicts with Perl on some Linux unless we do this */ #define debug tacplus_client_debug extern int debug; /* debugging flag */ extern int logging; /* syslog logging flag */ //extern int single; /* do not fork (for debugging) */ extern int console; /* log to console */ extern FILE *ostream; /* for logging to console */ extern int parse_only; /* exit after parsing verbosely */ extern int sendauth_only; /* don't do sendauth */ /* All tacacs+ packets have the same header format */ struct tac_plus_pak_hdr { u_char version; #define TAC_PLUS_MAJOR_VER_MASK 0xf0 #define TAC_PLUS_MAJOR_VER 0xc0 #define TAC_PLUS_MINOR_VER_0 0x0 #define TAC_PLUS_VER_0 (TAC_PLUS_MAJOR_VER | TAC_PLUS_MINOR_VER_0) #define TAC_PLUS_MINOR_VER_1 0x01 #define TAC_PLUS_VER_1 (TAC_PLUS_MAJOR_VER | TAC_PLUS_MINOR_VER_1) u_char type; #define TAC_PLUS_AUTHEN 1 #define TAC_PLUS_AUTHOR 2 #define TAC_PLUS_ACCT 3 u_char seq_no; /* packet sequence number */ u_char encryption; /* packet is encrypted or cleartext */ #define TAC_PLUS_ENCRYPTED 0x0 /* packet is encrypted */ #define TAC_PLUS_CLEAR 0x1 /* packet is not encrypted */ int session_id; /* session identifier FIXME: Is this needed? */ int datalength; /* length of encrypted data following this * header */ /* datalength bytes of encrypted data */ }; #define HASH_TAB_SIZE 157 /* user and group hash table sizes */ #define TAC_PLUS_HDR_SIZE 12 typedef struct tac_plus_pak_hdr HDR; /* Authentication packet NAS sends to us */ struct authen_start { u_char action; #define TAC_PLUS_AUTHEN_LOGIN 0x1 #define TAC_PLUS_AUTHEN_CHPASS 0x2 #define TAC_PLUS_AUTHEN_SENDPASS 0x3 /* deprecated */ #define TAC_PLUS_AUTHEN_SENDAUTH 0x4 u_char priv_lvl; #define TAC_PLUS_PRIV_LVL_MIN 0x0 #define TAC_PLUS_PRIV_LVL_MAX 0xf u_char authen_type; #define TAC_PLUS_AUTHEN_TYPE_ASCII 1 #define TAC_PLUS_AUTHEN_TYPE_PAP 2 #define TAC_PLUS_AUTHEN_TYPE_CHAP 3 #define TAC_PLUS_AUTHEN_TYPE_ARAP 4 u_char service; #define TAC_PLUS_AUTHEN_SVC_LOGIN 1 #define TAC_PLUS_AUTHEN_SVC_ENABLE 2 #define TAC_PLUS_AUTHEN_SVC_PPP 3 #define TAC_PLUS_AUTHEN_SVC_ARAP 4 #define TAC_PLUS_AUTHEN_SVC_PT 5 #define TAC_PLUS_AUTHEN_SVC_RCMD 6 #define TAC_PLUS_AUTHEN_SVC_X25 7 #define TAC_PLUS_AUTHEN_SVC_NASI 8 u_char user_len; u_char port_len; u_char rem_addr_len; u_char data_len; /* */ /* */ /* */ /* */ }; #define TAC_AUTHEN_START_FIXED_FIELDS_SIZE 8 /* Authentication continue packet NAS sends to us */ struct authen_cont { u_short user_msg_len; u_short user_data_len; u_char flags; #define TAC_PLUS_CONTINUE_FLAG_ABORT 0x1 /* */ /* */ }; #define TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE 5 /* Authentication reply packet we send to NAS */ struct authen_reply { u_char status; #define TAC_PLUS_AUTHEN_STATUS_PASS 1 #define TAC_PLUS_AUTHEN_STATUS_FAIL 2 #define TAC_PLUS_AUTHEN_STATUS_GETDATA 3 #define TAC_PLUS_AUTHEN_STATUS_GETUSER 4 #define TAC_PLUS_AUTHEN_STATUS_GETPASS 5 #define TAC_PLUS_AUTHEN_STATUS_RESTART 6 #define TAC_PLUS_AUTHEN_STATUS_ERROR 7 #define TAC_PLUS_AUTHEN_STATUS_FOLLOW 0x21 u_char flags; #define TAC_PLUS_AUTHEN_FLAG_NOECHO 0x1 u_short msg_len; u_short data_len; /* */ /* */ }; #define TAC_AUTHEN_REPLY_FIXED_FIELDS_SIZE 6 /* An authorization request packet */ struct author { u_char authen_method; u_char priv_lvl; u_char authen_type; u_char service; u_char user_len; u_char port_len; u_char rem_addr_len; u_char arg_cnt; /* the number of args */ /* */ /* */ /* */ /* */ /* */ }; #define TAC_AUTHOR_REQ_FIXED_FIELDS_SIZE 8 /* An authorization reply packet */ struct author_reply { u_char status; u_char arg_cnt; u_short msg_len; u_short data_len; /* */ /* */ /* */ /* */ }; #define TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE 6 struct acct { u_char flags; #define TAC_PLUS_ACCT_FLAG_MORE 0x1 #define TAC_PLUS_ACCT_FLAG_START 0x2 #define TAC_PLUS_ACCT_FLAG_STOP 0x4 #define TAC_PLUS_ACCT_FLAG_WATCHDOG 0x8 u_char authen_method; u_char priv_lvl; u_char authen_type; u_char authen_service; u_char user_len; u_char port_len; u_char rem_addr_len; u_char arg_cnt; /* the number of cmd args */ /* one u_char containing size for each arg */ /* */ /* */ /* */ /* char data for args 1 ... n */ }; #define TAC_ACCT_REQ_FIXED_FIELDS_SIZE 9 struct acct_reply { u_short msg_len; u_short data_len; u_char status; #define TAC_PLUS_ACCT_STATUS_SUCCESS 0x1 #define TAC_PLUS_ACCT_STATUS_ERROR 0x2 #define TAC_PLUS_ACCT_STATUS_FOLLOW 0x21 }; #define TAC_ACCT_REPLY_FIXED_FIELDS_SIZE 5 /* Odds and ends */ #define TAC_PLUS_MAX_ITERATIONS 50 #undef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #define STREQ(a,b) (strcmp(a,b)==0) #define MAX_INPUT_LINE_LEN 255 /* Debugging flags */ #define DEBUG_PARSE_FLAG 2 #define DEBUG_FORK_FLAG 4 #define DEBUG_AUTHOR_FLAG 8 #define DEBUG_AUTHEN_FLAG 16 #define DEBUG_PASSWD_FLAG 32 #define DEBUG_ACCT_FLAG 64 #define DEBUG_CONFIG_FLAG 128 #define DEBUG_PACKET_FLAG 256 #define DEBUG_HEX_FLAG 512 #define DEBUG_MD5_HASH_FLAG 1024 #define DEBUG_XOR_FLAG 2048 #define DEBUG_CLEAN_FLAG 4096 #define DEBUG_SUBST_FLAG 8192 #define DEBUG_PROXY_FLAG 16384 #define DEBUG_MAXSESS_FLAG 32768 extern char *codestring(); extern int keycode(); #define TAC_IS_USER 1 #define TAC_PLUS_RECURSE 1 #define TAC_PLUS_NORECURSE 0 #define DEFAULT_USERNAME "DEFAULT" #include "parse.h" /* Node types */ #define N_arg 50 #define N_optarg 51 #define N_svc_exec 52 #define N_svc_slip 53 #define N_svc_ppp 54 #define N_svc_arap 55 #define N_svc_cmd 56 #define N_permit 57 #define N_deny 58 #define N_svc 59 /* A parse tree node */ struct node { int type; /* node type (arg, svc, proto) */ void *next; /* pointer to next node in chain */ void *value; /* node value */ void *value1; /* node value */ int dflt; /* default value for node */ int line; /* line number declared on */ }; typedef struct node NODE; union v { int intval; void *pval; }; typedef union v VALUE; /* acct.c */ extern void accounting(); /* report.c */ extern void report_string(); extern void report_hex(); extern void report(); /* packet.c */ extern u_char *get_authen_continue(); extern int send_authen_reply(); /* utils.c */ extern char *tac_malloc(); extern char *tac_strdup(); extern char *tac_make_string(); extern char *tac_find_substring(); extern char *tac_realloc(); /* dump.c */ extern char *summarise_outgoing_packet_type(); extern char *summarise_incoming_packet_type(); /* author.c */ extern void author(); /* hash.c */ extern void *hash_add_entry(); extern void **hash_get_entries(); extern void *hash_lookup(); /* config.c */ extern int cfg_get_intvalue(); extern char * cfg_get_pvalue(); extern char *cfg_get_authen_default(); extern char **cfg_get_svc_attrs(); extern NODE *cfg_get_cmd_node(); extern NODE *cfg_get_svc_node(); extern char *cfg_get_expires(); extern char *cfg_get_login_secret(); extern char *cfg_get_arap_secret(); extern char *cfg_get_chap_secret(); extern char *cfg_get_pap_secret(); extern char *cfg_get_opap_secret(); extern char *cfg_get_global_secret(); extern void cfg_clean_config(); extern char *cfg_nodestring(); /* pw.c */ extern struct passwd *tac_passwd_lookup(); /* parse.c */ extern void parser_init(); /* pwlib.c */ extern void set_expiration_status(); /* miscellaneous */ #ifdef CONST_SYSERRLIST extern const char *const sys_errlist[]; #else /*extern char *sys_errlist[];*/ #endif extern int errno; extern int sendauth_fn(); extern int sendpass_fn(); extern int enable_fn(); extern int default_fn(); extern int default_v0_fn(); extern int skey_fn(); int md5_xor(HDR* hdr, u_char* data, char* key); #ifdef MAXSESS extern void maxsess_loginit(); extern int maxsess_check_count(); /* * This is a shared file used to maintain a record of who's on */ #define WHOLOG "/var/tmp/tac.who_log" /* * This is state kept per user/session */ struct peruser { char username[64]; /* User name */ char NAS_name[32]; /* NAS user logged into */ char NAS_port[32]; /* ...port on that NAS */ char NAC_address[32]; /* ...IP address of NAS */ }; #endif /* MAXSESS */ Authen-TacacsPlus-0.27/tacpluslib/expire.h0000444000175000001440000000215306442766236017574 0ustar mikemusers/* Copyright (c) 1995-1996 by Cisco systems, Inc. Permission to use, copy, modify, and distribute this software for any purpose and without fee is hereby granted, provided that this copyright and permission notice appear on all copies of the software and supporting documentation, the name of Cisco Systems, Inc. not be used in advertising or publicity pertaining to distribution of the program without specific prior permission, and notice be given in supporting documentation that modification, copying and distribution is by permission of Cisco Systems, Inc. Cisco Systems, Inc. makes no representations about the suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #define PW_OK 0 /* pw not expired and not due to expire soon */ #define PW_EXPIRED 1 /* pw has expired */ #define PW_EXPIRING 2 /* pw will expire soon */ #define MAX_PASSWD_LEN 256 extern int check_expiration(); Authen-TacacsPlus-0.27/Makefile.PL0000444000175000001440000000147010714705051015721 0ustar mikemusersuse ExtUtils::MakeMaker; # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. use Config; # On some versions of Solaris, under some circumstances, # can get the wrong version of md5 unless we do this: # Will also get lots of complaints about undefined symbols if ($Config{osname} eq 'solaris') { # $ex_cc_flags='-symbolic'; } WriteMakefile( 'NAME' => 'Authen::TacacsPlus', 'VERSION_FROM' => 'TacacsPlus.pm', # finds $VERSION 'MYEXTLIB' => "$ex_cc_flags tacpluslib/libtacplus\$(LIB_EXT)", 'dist' => { COMPRESS => 'gzip', SUFFIX => 'gz' }, ); sub MY::postamble { ' $(MYEXTLIB): tacpluslib/Makefile cd tacpluslib && $(MAKE) -e '; } Authen-TacacsPlus-0.27/TacacsPlus.pm0000644000175000001440000001551413617706066016371 0ustar mikemusers# # (C) 1998 Mike Shoyher , package Authen::TacacsPlus; use strict; use Carp; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $AUTOLOAD); require Exporter; require DynaLoader; @ISA = qw(Exporter DynaLoader); # Items to export into callers namespace by default. Note: do not export # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. @EXPORT_OK = qw( TACPLUS_CLIENT ); $VERSION = '0.27'; sub new { my $class = shift; my %h; my $self = {}; bless $self, $class; $self->{'servers'} = []; if (ref $_[0] eq 'ARRAY') { %h = @{ $_[0] }; shift @_; push @{ $self->{'servers'} }, @_; } else { %h = @_; } my $res=-1; $self->{'timeout'} = $h{'Timeout'} ? $h{'Timeout'} : 15; $self->{'port'} = $h{'Port'} ? $h{'Port'} : 'tacacs'; $self->{'host'} = $h{'Host'}; $self->{'key'} = $h{'Key'}; $res=init_tac_session($self->{'host'},$self->{'port'}, $self->{'key'},$self->{'timeout'}); if ($res<0) { my $s = $self->{'servers'}; while ($s->[0]) { my %h = @{ $s->[0] }; shift @{ $s }; $res=init_tac_session( $h{'Host'}, $h{'Port'} ? $h{'Port'} : 'tacacs', $h{'Key'}, $h{'Timeout'} ? $h{'Timeout'} : 15 ); $self->{'open'} = 1 if ($res >= 0); last if ($res >= 0); } } undef $self if ($res < 0); $self; } # Third arg authen_type is optional, defaults to # TAC_PLUS_AUTHEN_TYPE_ASCII sub authen { my $self = shift; my $username = shift; my $password = shift; my $authen_type = shift || &Authen::TacacsPlus::TAC_PLUS_AUTHEN_TYPE_ASCII; my $res=make_auth($username,$password,$authen_type); unless ($res || errmsg() =~ /Authentication failed/) { my $s = $self->{'servers'}; while ($s->[0]) { my %h = @{ $s->[0] }; shift @{ $s }; my $ret=init_tac_session( $h{'Host'}, $h{'Port'} ? $h{'Port'} : 'tacacs', $h{'Key'}, $h{'Timeout'} ? $h{'Timeout'} : 15 ); next if ($ret < 0); $res=make_auth($username,$password,$authen_type); last if $res; } } $res; } sub close { my ($self) = @_; if ($self->{'open'}) { deinit_tac_session(); $self->{'open'} = 0; } } sub DESTROY { my ($self) = @_; $self->close(); } sub AUTOLOAD { # This AUTOLOAD is used to 'autoload' constants from the constant() # XS function. If a constant is not found then control is passed # to the AUTOLOAD in AutoLoader. my $constname; ($constname = $AUTOLOAD) =~ s/.*:://; my $val = constant($constname, @_ ? $_[0] : 0); if ($! != 0) { if ($! =~ /Invalid/) { $AutoLoader::AUTOLOAD = $AUTOLOAD; goto &AutoLoader::AUTOLOAD; } else { croak "Your vendor has not defined Authen::TacacsPlus macro $constname"; } } eval "sub $AUTOLOAD { $val }"; goto &$AUTOLOAD; } bootstrap Authen::TacacsPlus $VERSION; # Preloaded methods go here. # Autoload methods go after =cut, and are processed by the autosplit program. 1; __END__ # Below is the stub of documentation for your module. You better edit it! =head1 NAME Authen::TacacsPlus - Perl extension for authentication using tacacs+ server =head1 SYNOPSIS use Authen::TacacsPlus; $tac = new Authen::TacacsPlus(Host=>$server, Key=>$key, [Port=>'tacacs'], [Timeout=>15]); or $tac = new Authen::TacacsPlus( [ Host=>$server1, Key=>$key1, [Port=>'tacacs'], [Timeout=>15] ], [ Host=>$server2, Key=>$key2, [Port=>'tacacs'], [Timeout=>15] ], [ Host=>$server3, Key=>$key3, [Port=>'tacacs'], [Timeout=>15] ], ... ); $tac->authen($username,$passwords); Authen::TacacsPlus::errmsg(); $tac->close(); =head1 DESCRIPTION Authen::TacacsPlus allows you to authenticate using tacacs+ server. $tac = new Authen::TacacsPlus(Host=>$server, Key=>$key, [Port=>'tacacs'], [Timeout=>15]); Opens new session with tacacs+ server on host $server, encrypted with key $key. Undefined object is returned if something wrong (check errmsg()). With a list of servers the order is relevant. It checks the availability of the Tacacs+ service using the order you defined. Authen::TacacsPlus::errmsg(); Returns last error message. $tac->authen($username,$password,$authen_type); Tries an authentication with $username and $password. 1 is returned if authenticaton succeded and 0 if failed (check errmsg() for reason). $authen_type is an optional argument that specifies what type of authentication to perform. Allowable options are: Authen::TacacsPlus::TAC_PLUS_AUTHEN_TYPE_ASCII (default) Authen::TacacsPlus::TAC_PLUS_AUTHEN_TYPE_PAP Authen::TacacsPlus::TAC_PLUS_AUTHEN_TYPE_CHAP ASCII uses Tacacs+ version 0, and will authenticate against the "login" or "global" password on the Tacacs+ server. If no authen_type is specified, it defaults to this type of authentication. PAP uses Tacacs+ version 1, and will authenticate against the "pap" or "global" password on the Tacacs+ server. CHAP uses Tacacs+ version 1, and will authenticate against the "chap" or "global" password on the Tacacs+ server. With CHAP, the password if formed by the concatenation of chap id + chap challenge + chap response There is example code in test.pl If you use a list of servers you can continue using $tac->authen if one of them goes down or become unreachable. $tac->close(); Closes session with tacacs+ server. =head1 EXAMPLE use Authen::TacacsPlus; $tac = new Authen::TacacsPlus(Host=>'foo.bar.ru',Key=>'9999'); unless ($tac){ print "Error: ",Authen::TacacsPlus::errmsg(),"\n"; exit(1); } if ($tac->authen('john','johnpass')){ print "Granted\n"; } else { print "Denied: ",Authen::TacacsPlus::errmsg(),"\n"; } $tac->close(); =head1 AUTHOR Mike Shoyher, msh@corbina.net, msh@apache.lexa.ru Mike McCauley, mikem@airspayce.com =head1 BUGS only authentication is supported only one session may be active (you have to close one session before opening another one) =head1 SEE ALSO perl(1). =cut Authen-TacacsPlus-0.27/Changes0000644000175000001440000000566313617706241015263 0ustar mikemusersRevision history for Perl extension Authen::TacacsPlus. 0.01 Mon Dec 8 16:05:51 1997 - original version; created by h2xs 1.18 0.16 Mon Apr 26 10:22:22 1999 - Now does PAP and CHAP authentication, as well as the original ASCII. PAP and CHAP use TACACS+ version 1 - Added flag to make_auth to specify the authentication type, plus string lengths (because in some auth types, the password string may contain NULs. - Added optional flag to ->authen() to specify the authentication type. Defaults to ASCII - Some reformatting to make it easier to read. - Cleaned up Makefiles so it builds cleaner - Mike McCauley (mikem@open.com.au) 0.17 Sat Sep 22 2007, Mike McCauley - Mike McCauley (mikem@open.com.au) is now co-maintainer. - DISTNAME changed to Authen-TacacsPlus to be consistent with file naming of other Authen modules. - readme changed to README. - Added licensing statement to README, with the approval and consent of Mike Shoyher. - Fixed a typedef in md5.h that breaks md5 on 64 bit machines. Patch provided by Ernst Oudhof. - Removed bogus broken constant TACACS_CLIENT. - Fixed a number of compiler warnings, but still does not compile on Windows. 0.18 Sat Mar 15 2008, Mike McCauley - Disabled default setting of -symbolic in Makefile.PL on Solaris since it seems to be no longer required on most platforms. - Improved errmsg() so it works as advertised - test suite now uses Test. - test suite now skips if there is no Tacacs server to test against 0.19 Sun Mar 16 2008, Mike McCauley - Fixed 'make test' failure in taclibplus due to missing pure_all target 0.20 Fri July 10, 2009 Mike McCauley - Fixed incorect spelling of 'Authentication' in tac_client.c - implements a timeout for the connect() operation. It uses the timeout value which is passed to the init_tac_session() function. Contributed by Robert Leibl 0.21 Sat Aug 13, 2011 Mike McCauley - Changes to TacacsPlus.pm to permit multiple servers to be specified in new(). Patches provided by Paulo A Ferreira. 0.22 Wed Jan 18, 2012 Mike McCauley - Fixed warning under perl 5.14g 0.23 Wed Aug 23, 2012 Mike McCauley - Fixed problems in low level read_data() function triggered when an incorrect key is used with some Tacacs+ servers, resulting in a 0-length read(), causing a seg fault on some platforms, and a very slow exit on others. This problem appears to have been in tac_client ever since I inherited this library. 0.24 Fri Mar 22, 2013 Mike McCauley - Updated author and distribution location details to airspayce.com 0.26 2015-12-08 Mike McCauley - pass CFLAGS and CPPFLAGS explicitly in the subdirectory to get all hardening flags, Patch from Florian Schlichting. 0.27 2020-02-09 Mike McCauley - Patch from Jacob Farkas via RT to allow building under on Alpine Linux under Docker on armv7l, and possibly others