diff options
author | Jeroen Nijhof <jeroenn@saralt0078.(none)> | 2010-12-22 11:12:08 +0100 |
---|---|---|
committer | Jeroen Nijhof <jeroenn@saralt0078.(none)> | 2010-12-22 11:12:08 +0100 |
commit | 4e0f4aa68e082b469663e3ebc8ec83c9400dab4b (patch) | |
tree | 08d50b522bc250659704b2dfc73d887979198fd4 /libtac | |
download | pam_tacplus-4e0f4aa68e082b469663e3ebc8ec83c9400dab4b.tar.gz pam_tacplus-4e0f4aa68e082b469663e3ebc8ec83c9400dab4b.zip |
Initial commit
Diffstat (limited to 'libtac')
-rw-r--r-- | libtac/include/cdefs.h | 58 | ||||
-rw-r--r-- | libtac/include/libtac.h | 83 | ||||
-rw-r--r-- | libtac/include/tacplus.h | 265 | ||||
-rw-r--r-- | libtac/lib/acct_r.c | 97 | ||||
-rw-r--r-- | libtac/lib/acct_s.c | 151 | ||||
-rw-r--r-- | libtac/lib/attrib.c | 80 | ||||
-rw-r--r-- | libtac/lib/authen_r.c | 104 | ||||
-rw-r--r-- | libtac/lib/authen_s.c | 143 | ||||
-rw-r--r-- | libtac/lib/author_r.c | 194 | ||||
-rw-r--r-- | libtac/lib/author_s.c | 152 | ||||
-rw-r--r-- | libtac/lib/connect.c | 144 | ||||
-rw-r--r-- | libtac/lib/cont_s.c | 92 | ||||
-rw-r--r-- | libtac/lib/crypt.c | 107 | ||||
-rw-r--r-- | libtac/lib/hdr_check.c | 53 | ||||
-rw-r--r-- | libtac/lib/header.c | 65 | ||||
-rw-r--r-- | libtac/lib/magic.c | 122 | ||||
-rw-r--r-- | libtac/lib/magic.h | 26 | ||||
-rw-r--r-- | libtac/lib/md5.c | 276 | ||||
-rw-r--r-- | libtac/lib/md5.h | 41 | ||||
-rw-r--r-- | libtac/lib/messages.c | 26 | ||||
-rw-r--r-- | libtac/lib/messages.h | 26 | ||||
-rw-r--r-- | libtac/lib/version.c | 24 | ||||
-rw-r--r-- | libtac/lib/xalloc.c | 43 | ||||
-rw-r--r-- | libtac/lib/xalloc.h | 23 |
24 files changed, 2395 insertions, 0 deletions
diff --git a/libtac/include/cdefs.h b/libtac/include/cdefs.h new file mode 100644 index 0000000..148f3d7 --- /dev/null +++ b/libtac/include/cdefs.h @@ -0,0 +1,58 @@ +/* cdefs.h + * + * Copyright (C) 2010, Pawel Krawczyk <kravietz@ceti.pl> and + * Jeroen Nijhof <jeroen@nijhofnet.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +#undef __P +#if defined(__STDC__) || defined(__cplusplus) +#define __P(p) p +#else +#define __P(p) +#endif +#define _PTR void * +#define _AND , +#define _NOARGS void +#define _CONST const +#define _VOLATILE volatile +#define _SIGNED signed +#define _DOTS , ... +#define _VOID void +#define _EXFUN(name, proto) name proto +#define _DEFUN(name, arglist, args) name(args) +#define _DEFUN_VOID(name) name(_NOARGS) +#define _CAST_VOID (void) +#ifndef _LONG_DOUBLE +#define _LONG_DOUBLE long double +#endif +#ifndef _PARAMS +#define _PARAMS(paramlist) paramlist +#endif + +/* Support gcc's __attribute__ facility. */ + +#define _ATTRIBUTE(attrs) __attribute__ ((attrs)) + +#if defined(__cplusplus) +#define __BEGIN_DECLS extern "C" { +#define __END_DECLS } +#else +#define __BEGIN_DECLS +#define __END_DECLS +#endif + diff --git a/libtac/include/libtac.h b/libtac/include/libtac.h new file mode 100644 index 0000000..023b60d --- /dev/null +++ b/libtac/include/libtac.h @@ -0,0 +1,83 @@ +/* libtac.h + * + * Copyright (C) 2010, Pawel Krawczyk <kravietz@ceti.pl> and + * Jeroen Nijhof <jeroen@nijhofnet.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +#ifndef _AUTH_TAC_H +#define _AUTH_TAC_H + +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <syslog.h> +#include <string.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <unistd.h> + +#if defined(DEBUGTAC) && !defined(TACDEBUG) +#define TACDEBUG(x) syslog x; +#else +#define TACDEBUG(x) +#endif + +/* u_int32_t support for sun */ +#ifdef sun +typedef unsigned int u_int32_t; +#endif + +/* version.c */ +extern int tac_ver_major; +extern int tac_ver_minor; +extern int tac_ver_patch; + +/* header.c */ +extern int session_id; +extern int tac_encryption; +extern char *tac_secret; +extern char *tac_login; + +/* connect.c */ +extern int tac_timeout; +extern int tac_connect(struct addrinfo **server, int servers); +extern int tac_connect_single(struct addrinfo *server); +extern char *tac_ntop(const struct sockaddr *sa, size_t ai_addrlen); + +extern int tac_authen_send(int fd, const char *user, char *pass, char *tty); +extern int tac_authen_read(int fd); +extern int tac_cont_send(int fd, char *pass); +extern HDR *_tac_req_header(u_char type); +extern void _tac_crypt(u_char *buf, HDR *th, int length); +extern u_char *_tac_md5_pad(int len, HDR *hdr); +extern void tac_add_attrib(struct tac_attrib **attr, char *name, char *value); +extern void tac_free_attrib(struct tac_attrib **attr); +extern int tac_account_send(int fd, int type, const char *user, char *tty, + struct tac_attrib *attr); +extern char *tac_account_read(int fd); +extern void *xcalloc(size_t nmemb, size_t size); +extern void *xrealloc(void *ptr, size_t size); +extern char *_tac_check_header(HDR *th, int type); +extern int tac_author_send(int fd, const char *user, char *tty, + struct tac_attrib *attr); +extern void tac_author_read(int fd, struct areply *arep); + +#endif + diff --git a/libtac/include/tacplus.h b/libtac/include/tacplus.h new file mode 100644 index 0000000..d43e563 --- /dev/null +++ b/libtac/include/tacplus.h @@ -0,0 +1,265 @@ +/* tacplus.h + * + * Copyright (C) 2010, Pawel Krawczyk <kravietz@ceti.pl> and + * Jeroen Nijhof <jeroen@nijhofnet.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +#ifndef _TACPLUS_H +#define _TACPLUS_H + +#include <sys/types.h> +#ifdef sun + #include "cdefs.h" +#else + #include <sys/cdefs.h> +#endif + +struct tac_attrib { + char *attr; + u_char attr_len; + struct tac_attrib *next; +}; + +struct areply { + struct tac_attrib *attr; + char *msg; + int status; +}; + +#ifndef TAC_PLUS_MAXSERVERS +#define TAC_PLUS_MAXSERVERS 4 +#endif + +#ifndef TAC_PLUS_PORT +#define TAC_PLUS_PORT 49 +#endif + +#define TAC_PLUS_READ_TIMEOUT 180 /* seconds */ +#define TAC_PLUS_WRITE_TIMEOUT 180 /* seconds */ + +/* 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 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; + /* <user_len bytes of char data> */ + /* <port_len bytes of char data> */ + /* <rem_addr_len bytes of u_char data> */ + /* <data_len bytes of u_char data> */ +}; + +#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 + + /* <user_msg_len bytes of u_char data> */ + /* <user_data_len bytes of u_char data> */ +}; + +#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; + + /* <msg_len bytes of char data> */ + /* <data_len bytes of u_char data> */ +}; + +#define TAC_AUTHEN_REPLY_FIXED_FIELDS_SIZE 6 + +#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 + +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 */ + /* <user_len bytes of char data> */ + /* <port_len bytes of char data> */ + /* <rem_addr_len bytes of u_char data> */ + /* 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 + +/* 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 */ + + /* <arg_cnt u_chars containing the lengths of args 1 to arg n> */ + /* <user_len bytes of char data> */ + /* <port_len bytes of char data> */ + /* <rem_addr_len bytes of u_char data> */ + /* <char data for each arg> */ +}; + +#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 AUTHOR_STATUS_PASS_ADD 0x01 +#define AUTHOR_STATUS_PASS_REPL 0x02 +#define AUTHOR_STATUS_FAIL 0x10 +#define AUTHOR_STATUS_ERROR 0x11 +#define AUTHOR_STATUS_FOLLOW 0x21 + + /* <arg_cnt u_chars containing the lengths of arg 1 to arg n> */ + /* <msg_len bytes of char data> */ + /* <data_len bytes of char data> */ + /* <char data for each arg> */ +}; + +#define TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE 6 + + +#endif diff --git a/libtac/lib/acct_r.c b/libtac/lib/acct_r.c new file mode 100644 index 0000000..d30d18f --- /dev/null +++ b/libtac/lib/acct_r.c @@ -0,0 +1,97 @@ +/* acct_r.c - Read accounting reply from server. + * + * Copyright (C) 2010, Pawel Krawczyk <kravietz@ceti.pl> and + * Jeroen Nijhof <jeroen@nijhofnet.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +#include "tacplus.h" +#include "libtac.h" +#include "messages.h" + +char *tac_account_read(int fd) { + HDR th; + struct acct_reply *tb; + int len_from_header, r, len_from_body; + char *msg = NULL; + + r=read(fd, &th, TAC_PLUS_HDR_SIZE); + if(r < TAC_PLUS_HDR_SIZE) { + syslog(LOG_ERR, + "%s: short acct header, %d of %d: %m", __FUNCTION__, + r, TAC_PLUS_HDR_SIZE); + return(system_err_msg); + } + + /* check the reply fields in header */ + msg = _tac_check_header(&th, TAC_PLUS_ACCT); + if(msg != NULL) + return(msg); + + len_from_header=ntohl(th.datalength); + tb=(struct acct_reply *) xcalloc(1, len_from_header); + + /* read reply packet body */ + r=read(fd, tb, len_from_header); + if(r < len_from_header) { + syslog(LOG_ERR, + "%s: incomplete message body, %d bytes, expected %d: %m", + __FUNCTION__, + r, len_from_header); + return(system_err_msg); + } + + /* decrypt the body */ + _tac_crypt((u_char *) tb, &th, len_from_header); + + /* Convert network byte order to host byte order */ + tb->msg_len = ntohs(tb->msg_len); + tb->data_len = ntohs(tb->data_len); + + /* check the length fields */ + len_from_body=sizeof(tb->msg_len) + sizeof(tb->data_len) + + sizeof(tb->status) + tb->msg_len + tb->data_len; + + if(len_from_header != len_from_body) { + syslog(LOG_ERR, + "%s: invalid reply content, incorrect key?", + __FUNCTION__); + return(system_err_msg); + } + + /* save status and clean up */ + r=tb->status; + if(tb->msg_len) { + msg=(char *) xcalloc(1, tb->msg_len); + bcopy((u_char *) tb+TAC_ACCT_REPLY_FIXED_FIELDS_SIZE, msg, tb->msg_len); + } else + msg="Accounting failed"; + + free(tb); + + /* server logged our request successfully */ + if(r == TAC_PLUS_ACCT_STATUS_SUCCESS) { + TACDEBUG((LOG_DEBUG, "%s: accounted ok", __FUNCTION__)) + msg=NULL; + return(NULL); + } + /* return pointer to server message */ + syslog(LOG_DEBUG, "%s: accounting failed, server reply was %d (%s)", + __FUNCTION__, r, msg); + return(msg); + +} diff --git a/libtac/lib/acct_s.c b/libtac/lib/acct_s.c new file mode 100644 index 0000000..5ca07c3 --- /dev/null +++ b/libtac/lib/acct_s.c @@ -0,0 +1,151 @@ +/* acct_s.c - Send accounting event information to server. + * + * Copyright (C) 2010, Pawel Krawczyk <kravietz@ceti.pl> and + * Jeroen Nijhof <jeroen@nijhofnet.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +#include "tacplus.h" +#include "libtac.h" +#include "xalloc.h" + +int tac_account_send(int fd, int type, const char *user, char *tty, + struct tac_attrib *attr) { + HDR *th; + struct acct tb; + u_char user_len, port_len; + struct tac_attrib *a; + int i = 0; /* arg count */ + int pkt_len = 0; + int pktl = 0; + int w; /* write count */ + u_char *pkt; + /* u_char *pktp; */ /* obsolute */ + int ret = 0; + + th=_tac_req_header(TAC_PLUS_ACCT); + + /* set header options */ + th->version=TAC_PLUS_VER_0; + th->encryption=tac_encryption ? TAC_PLUS_ENCRYPTED : TAC_PLUS_CLEAR; + + TACDEBUG((LOG_DEBUG, "%s: user '%s', tty '%s', encrypt: %s, type: %s", \ + __FUNCTION__, user, tty, \ + (tac_encryption) ? "yes" : "no", \ + (type == TAC_PLUS_ACCT_FLAG_START) ? "START" : "STOP")) + + user_len=(u_char) strlen(user); + port_len=(u_char) strlen(tty); + + tb.flags=(u_char) type; + tb.authen_method=AUTHEN_METH_TACACSPLUS; + tb.priv_lvl=TAC_PLUS_PRIV_LVL_MIN; + if(strcmp(tac_login,"chap") == 0) { + tb.authen_type=TAC_PLUS_AUTHEN_TYPE_CHAP; + } else if(strcmp(tac_login,"login") == 0) { + tb.authen_type=TAC_PLUS_AUTHEN_TYPE_ASCII; + } else { + tb.authen_type=TAC_PLUS_AUTHEN_TYPE_PAP; + } + tb.authen_service=TAC_PLUS_AUTHEN_SVC_PPP; + tb.user_len=user_len; + tb.port_len=port_len; + tb.rem_addr_len=0; + + /* allocate packet */ + pkt=(u_char *) xcalloc(1, TAC_ACCT_REQ_FIXED_FIELDS_SIZE); + pkt_len=sizeof(tb); + + /* fill attribute length fields */ + a = attr; + while(a) { + + pktl = pkt_len; + pkt_len += sizeof(a->attr_len); + pkt = xrealloc(pkt, pkt_len); + + /* see comments in author_s.c + pktp=pkt + pkt_len; + pkt_len += sizeof(a->attr_len); + pkt = xrealloc(pkt, pkt_len); + */ + + bcopy(&a->attr_len, pkt + pktl, sizeof(a->attr_len)); + i++; + + a = a->next; + } + + /* fill the arg count field and add the fixed fields to packet */ + tb.arg_cnt = i; + bcopy(&tb, pkt, TAC_ACCT_REQ_FIXED_FIELDS_SIZE); + + /* +#define PUTATTR(data, len) \ + pktp = pkt + pkt_len; \ + pkt_len += len; \ + pkt = xrealloc(pkt, pkt_len); \ + bcopy(data, pktp, len); +*/ +#define PUTATTR(data, len) \ + pktl = pkt_len; \ + pkt_len += len; \ + pkt = xrealloc(pkt, pkt_len); \ + bcopy(data, pkt + pktl, len); + + /* fill user and port fields */ + PUTATTR(user, user_len) + PUTATTR(tty, port_len) + + /* fill attributes */ + a = attr; + while(a) { + PUTATTR(a->attr, a->attr_len) + + a = a->next; + } + + /* finished building packet, fill len_from_header in header */ + th->datalength = htonl(pkt_len); + + /* write header */ + w=write(fd, th, TAC_PLUS_HDR_SIZE); + + if(w < TAC_PLUS_HDR_SIZE) { + syslog(LOG_ERR, "%s: acct hdr send failed: wrote %d of %d", + __FUNCTION__, w, + TAC_PLUS_HDR_SIZE); + ret = -1; + } + + /* encrypt packet body */ + _tac_crypt(pkt, th, pkt_len); + + /* write body */ + w=write(fd, pkt, pkt_len); + if(w < pkt_len) { + syslog(LOG_ERR, "%s: acct body send failed: wrote %d of %d", + __FUNCTION__, w, + pkt_len); + ret = -1; + } + + free(pkt); + free(th); + + return(ret); +} diff --git a/libtac/lib/attrib.c b/libtac/lib/attrib.c new file mode 100644 index 0000000..761cde0 --- /dev/null +++ b/libtac/lib/attrib.c @@ -0,0 +1,80 @@ +/* attrib.c - Procedures for handling internal list of attributes + * for accounting and authorization functions. + * + * Copyright (C) 2010, Pawel Krawczyk <kravietz@ceti.pl> and + * Jeroen Nijhof <jeroen@nijhofnet.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +#include "tacplus.h" +#include "libtac.h" +#include "xalloc.h" + +void tac_add_attrib(struct tac_attrib **attr, char *name, char *value) { + struct tac_attrib *a; + u_char l1 = (u_char) strlen(name); + u_char l2 = (u_char) strlen(value); + int total_len = l1 + l2 + 1; /* "name" + "=" + "value" */ + + if(total_len > 255) { + syslog(LOG_WARNING, "%s: attribute `%s' total length exceeds 255 characters, skipping", __FUNCTION__, name); + return; + } + + /* initialize the list if application passed us a null pointer */ + if(*attr == NULL) { + *attr = (struct tac_attrib *) xcalloc(1, sizeof(struct tac_attrib)); + a = *attr; + } else { + /* find the last allocated block */ + a = *attr; + while(a->next != NULL) + a = a->next; /* a holds last allocated block */ + + a->next = (struct tac_attrib *) xcalloc(1, sizeof(struct tac_attrib)); + a = a->next; /* set current block pointer to the new one */ + } + + /* fill the block */ + a->attr_len=total_len; + a->attr = (char *) xcalloc(1, total_len); + bcopy(name, a->attr, l1); /* paste name */ + *(a->attr+l1)='='; /* insert "=" */ + bcopy(value, (a->attr+l1+1), l2); /* paste value */ + + a->next = NULL; /* make sure it's null */ + +} + +void tac_free_attrib(struct tac_attrib **attr) { + struct tac_attrib *a; + struct tac_attrib *b; + + if(*attr == NULL) + return; + + a = b = *attr; + + /* find last allocated block */ + do { + a = b; + b = a->next; + free(a->attr); + free(a); + } while (b != NULL); + +} diff --git a/libtac/lib/authen_r.c b/libtac/lib/authen_r.c new file mode 100644 index 0000000..55acac5 --- /dev/null +++ b/libtac/lib/authen_r.c @@ -0,0 +1,104 @@ +/* authen_r.c - Read authentication reply from server. + * + * Copyright (C) 2010, Pawel Krawczyk <kravietz@ceti.pl> and + * Jeroen Nijhof <jeroen@nijhofnet.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +#include "tacplus.h" +#include "libtac.h" +#include "messages.h" + +/* reads packet from TACACS+ server; returns: + * TAC_PLUS_AUTHEN_STATUS_PASS if the authentication succeded + * an other integer if failed. Check tacplus.h for all possible values + */ +int tac_authen_read(int fd) { + HDR th; + struct authen_reply *tb; + int len_from_header, r, len_from_body; + char *msg = NULL; + + /* read the reply header */ + r=read(fd, &th, TAC_PLUS_HDR_SIZE); + if(r < TAC_PLUS_HDR_SIZE) { + syslog(LOG_ERR, + "%s: error reading authen header, read %d of %d: %m", + __FUNCTION__, + r, TAC_PLUS_HDR_SIZE); + return(TAC_PLUS_AUTHEN_STATUS_FAIL); + } + + /* check the reply fields in header */ + msg = _tac_check_header(&th, TAC_PLUS_AUTHEN); + if(msg != NULL) + return(TAC_PLUS_AUTHEN_STATUS_FAIL); + + len_from_header=ntohl(th.datalength); + tb=(struct authen_reply *) xcalloc(1, len_from_header); + + /* read reply packet body */ + r=read(fd, tb, len_from_header); + if(r < len_from_header) { + syslog(LOG_ERR, + "%s: incomplete message body, %d bytes, expected %d: %m", + __FUNCTION__, + r, len_from_header); + return(TAC_PLUS_AUTHEN_STATUS_FAIL); + } + + /* decrypt the body */ + _tac_crypt((u_char *) tb, &th, len_from_header); + + /* Convert network byte order to host byte order */ + tb->msg_len = ntohs(tb->msg_len); + tb->data_len = ntohs(tb->data_len); + + /* check the length fields */ + len_from_body=sizeof(tb->status) + sizeof(tb->flags) + + sizeof(tb->msg_len) + sizeof(tb->data_len) + + tb->msg_len + tb->data_len; + + if(len_from_header != len_from_body) { + syslog(LOG_ERR, + "%s: invalid reply content, incorrect key?", + __FUNCTION__); + return(TAC_PLUS_AUTHEN_STATUS_FAIL); + } + + /* save status and clean up */ + r=tb->status; + free(tb); + + /* server authenticated username and password successfully */ + if(r == TAC_PLUS_AUTHEN_STATUS_PASS) { + TACDEBUG((LOG_DEBUG, "%s: authentication ok", __FUNCTION__)) + return(r); + } + + /* server ask for continue packet with password */ + if(r == TAC_PLUS_AUTHEN_STATUS_GETPASS) { + TACDEBUG((LOG_DEBUG, "%s: continue packet with password needed", __FUNCTION__)) + return(r); + } + + /* return pointer to server message */ + syslog(LOG_DEBUG, "%s: authentication failed, server reply was %d", + __FUNCTION__, r); + return(r); + +} /* tac_authen_read */ diff --git a/libtac/lib/authen_s.c b/libtac/lib/authen_s.c new file mode 100644 index 0000000..4a7e55a --- /dev/null +++ b/libtac/lib/authen_s.c @@ -0,0 +1,143 @@ +/* authen_s.c - Send authentication request to the server. + * + * Copyright (C) 2010, Pawel Krawczyk <kravietz@ceti.pl> and + * Jeroen Nijhof <jeroen@nijhofnet.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +#include "tacplus.h" +#include "libtac.h" +#include "md5.h" + +/* this function sends a packet do TACACS+ server, asking + * for validation of given username and password + */ +int tac_authen_send(int fd, const char *user, char *pass, char *tty) +{ + HDR *th; /* TACACS+ packet header */ + struct authen_start tb; /* message body */ + int user_len, port_len, chal_len, mdp_len, token_len, bodylength, w; + int pkt_len=0; + int ret=0; + char *chal = "1234123412341234"; + char digest[MD5_LEN]; + char *token; + u_char *pkt, *mdp; + MD5_CTX mdcontext; + + th=_tac_req_header(TAC_PLUS_AUTHEN); + + /* set some header options */ + if(strcmp(tac_login,"login") == 0) { + th->version=TAC_PLUS_VER_0; + } else { + th->version=TAC_PLUS_VER_1; + } + th->encryption=tac_encryption ? TAC_PLUS_ENCRYPTED : TAC_PLUS_CLEAR; + + TACDEBUG((LOG_DEBUG, "%s: user '%s', tty '%s', encrypt: %s", \ + __FUNCTION__, user, tty, \ + (tac_encryption) ? "yes" : "no")) + + if(strcmp(tac_login,"chap") == 0) { + chal_len = strlen(chal); + mdp_len = sizeof(u_char) + strlen(pass) + chal_len; + mdp = (u_char *) xcalloc(1, mdp_len); + mdp[0] = 5; + memcpy(&mdp[1], pass, strlen(pass)); + memcpy(mdp + strlen(pass) + 1, chal, chal_len); + MD5Init(&mdcontext); + MD5Update(&mdcontext, mdp, mdp_len); + MD5Final((u_char *) digest, &mdcontext); + free(mdp); + token = xcalloc(1, sizeof(u_char) + 1 + chal_len + MD5_LEN); + token[0] = 5; + memcpy(&token[1], chal, chal_len); + memcpy(token + chal_len + 1, digest, MD5_LEN); + } else { + token = pass; + } + + /* get size of submitted data */ + user_len=strlen(user); + port_len=strlen(tty); + token_len=strlen(token); + + /* fill the body of message */ + tb.action=TAC_PLUS_AUTHEN_LOGIN; + tb.priv_lvl=TAC_PLUS_PRIV_LVL_MIN; + if(strcmp(tac_login,"chap") == 0) { + tb.authen_type=TAC_PLUS_AUTHEN_TYPE_CHAP; + } else if(strcmp(tac_login,"login") == 0) { + tb.authen_type=TAC_PLUS_AUTHEN_TYPE_ASCII; + } else { + tb.authen_type=TAC_PLUS_AUTHEN_TYPE_PAP; + } + tb.service=TAC_PLUS_AUTHEN_SVC_PPP; + tb.user_len=user_len; + tb.port_len=port_len; + tb.rem_addr_len=0; /* may be e.g Caller-ID in future */ + tb.data_len=token_len; + + /* fill body length in header */ + bodylength=sizeof(tb) + user_len + + port_len + token_len; /* + rem_addr_len */ + + th->datalength= htonl(bodylength); + + /* we can now write the header */ + w=write(fd, th, TAC_PLUS_HDR_SIZE); + if(w < 0 || w < TAC_PLUS_HDR_SIZE) { + syslog(LOG_ERR, "%s: short write on header: wrote %d of %d: %m", + __FUNCTION__, w, TAC_PLUS_HDR_SIZE); + ret=-1; + } + + /* build the packet */ + pkt=(u_char *) xcalloc(1, bodylength+10); + + bcopy(&tb, pkt+pkt_len, sizeof(tb)); /* packet body beginning */ + pkt_len+=sizeof(tb); + bcopy(user, pkt+pkt_len, user_len); /* user */ + pkt_len+=user_len; + bcopy(tty, pkt+pkt_len, port_len); /* tty */ + pkt_len+=port_len; + bcopy(token, pkt+pkt_len, token_len); /* password */ + pkt_len+=token_len; + + /* pkt_len == bodylength ? */ + if(pkt_len != bodylength) { + syslog(LOG_ERR, "%s: bodylength %d != pkt_len %d", + __FUNCTION__, bodylength, pkt_len); + ret=-1; + } + + /* encrypt the body */ + _tac_crypt(pkt, th, bodylength); + + w=write(fd, pkt, pkt_len); + if(w < 0 || w < pkt_len) { + syslog(LOG_ERR, "%s: short write on body: wrote %d of %d: %m", + __FUNCTION__, w, pkt_len); + ret=-1; + } + + free(pkt); + free(th); + + return(ret); +} /* tac_authen_send */ diff --git a/libtac/lib/author_r.c b/libtac/lib/author_r.c new file mode 100644 index 0000000..3740e6c --- /dev/null +++ b/libtac/lib/author_r.c @@ -0,0 +1,194 @@ +/* author_r.c - Reads authorization reply from the server. + * + * Copyright (C) 2010, Pawel Krawczyk <kravietz@ceti.pl> and + * Jeroen Nijhof <jeroen@nijhofnet.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +#include "tacplus.h" +#include "xalloc.h" +#include "libtac.h" +#include "messages.h" + +/* This function returns structure containing + 1. status (granted/denied) + 2. message for the user + 3. list of attributes returned by server + The attributes should be applied to service authorization + is requested for, but actually the aren't. Attributes are + discarded. +*/ +void tac_author_read(int fd, struct areply *re) { + HDR th; + struct author_reply *tb = NULL; + int len_from_header, r, len_from_body; + char *pktp; + char *msg = NULL; + + bzero(re, sizeof(struct areply)); + + r=read(fd, &th, TAC_PLUS_HDR_SIZE); + if(r < TAC_PLUS_HDR_SIZE) { + syslog(LOG_ERR, + "%s: short author header, %d of %d: %m", __FUNCTION__, + r, TAC_PLUS_HDR_SIZE); + re->msg = system_err_msg; + re->status = AUTHOR_STATUS_ERROR; + goto AuthorExit; + } + + /* check header consistency */ + msg = _tac_check_header(&th, TAC_PLUS_AUTHOR); + if(msg != NULL) { + /* no need to process body if header is broken */ + re->msg = msg; + re->status = AUTHOR_STATUS_ERROR; + goto AuthorExit; + } + + len_from_header=ntohl(th.datalength); + tb=(struct author_reply *) xcalloc(1, len_from_header); + + /* read reply packet body */ + r=read(fd, tb, len_from_header); + if(r < len_from_header) { + syslog(LOG_ERR, + "%s: short author body, %d of %d: %m", __FUNCTION__, + r, len_from_header); + re->msg = system_err_msg; + re->status = AUTHOR_STATUS_ERROR; + goto AuthorExit; + } + + /* decrypt the body */ + _tac_crypt((u_char *) tb, &th, len_from_header); + + /* Convert network byte order to host byte order */ + tb->msg_len = ntohs(tb->msg_len); + tb->data_len = ntohs(tb->data_len); + + /* check consistency of the reply body + * len_from_header = declared in header + * len_from_body = value computed from body fields + */ + len_from_body = TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE + + tb->msg_len + tb->data_len; + + pktp = (char *) tb + TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE; + + for(r = 0; r < tb->arg_cnt; r++) { + len_from_body += sizeof(u_char); /* add arg length field's size*/ + len_from_body += *pktp; /* add arg length itself */ + pktp++; + } + + if(len_from_header != len_from_body) { + syslog(LOG_ERR, + "%s: inconsistent author reply body, incorrect key?", + __FUNCTION__); + re->msg = system_err_msg; + re->status = AUTHOR_STATUS_ERROR; + goto AuthorExit; + } + + /* packet seems to be consistent, prepare return messages */ + /* server message for user */ + if(tb->msg_len) { + char *msg = (char *) xcalloc(1, tb->msg_len+1); + bcopy((u_char *) tb+TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE + + (tb->arg_cnt)*sizeof(u_char), + msg, tb->msg_len); + re->msg = msg; + } + + /* server message to syslog */ + if(tb->data_len) { + char *smsg=(char *) xcalloc(1, tb->data_len+1); + bcopy((u_char *) tb + TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE + + (tb->arg_cnt)*sizeof(u_char) + + tb->msg_len, smsg, + tb->data_len); + syslog(LOG_ERR, "%s: author failed: %s", __FUNCTION__,smsg); + free(smsg); + } + + /* prepare status */ + switch(tb->status) { + /* success conditions */ + /* XXX support optional vs mandatory arguments */ + case AUTHOR_STATUS_PASS_ADD: + case AUTHOR_STATUS_PASS_REPL: + { + char *argp; + + if(!re->msg) re->msg=author_ok_msg; + re->status=tb->status; + + /* add attributes received to attribute list returned to + the client */ + pktp = (char *) tb + TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE; + argp = pktp + (tb->arg_cnt * sizeof(u_char)) + tb->msg_len + + tb->data_len; + /* argp points to current argument string + pktp holds current argument length */ + for(r=0; r < tb->arg_cnt; r++) { + char buff[256]; + char *sep; + char *value; + + bcopy(argp, buff, *pktp); + buff[(int)*pktp] = '\0'; + sep=index(buff, '='); + if(sep == NULL) + sep=index(buff, '*'); + if(sep == NULL) + syslog(LOG_WARNING, "AUTHOR_STATUS_PASS_REPL: attribute contains no separator: %s", buff); + *sep = '\0'; + value = ++sep; + /* now buff points to attribute name, + value to the attribute value */ + tac_add_attrib(&re->attr, buff, value); + + argp += *pktp; + pktp++; + } + } + + break; + + /* authorization failure conditions */ + /* failing to follow is allowed by RFC, page 23 */ + case AUTHOR_STATUS_FOLLOW: + case AUTHOR_STATUS_FAIL: + if(!re->msg) re->msg=author_fail_msg; + re->status=AUTHOR_STATUS_FAIL; + break; + + /* error conditions */ + case AUTHOR_STATUS_ERROR: + default: + if(!re->msg) re->msg=author_err_msg; + re->status=AUTHOR_STATUS_ERROR; + } + +AuthorExit: + + free(tb); + TACDEBUG((LOG_DEBUG, "%s: server replied '%s'", __FUNCTION__, \ + re->msg)) + +} diff --git a/libtac/lib/author_s.c b/libtac/lib/author_s.c new file mode 100644 index 0000000..0bf6518 --- /dev/null +++ b/libtac/lib/author_s.c @@ -0,0 +1,152 @@ +/* author_s.c - Send authorization request to the server. + * + * Copyright (C) 2010, Pawel Krawczyk <kravietz@ceti.pl> and + * Jeroen Nijhof <jeroen@nijhofnet.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +#include "tacplus.h" +#include "libtac.h" +#include "xalloc.h" + +/* Send authorization request to the server, along with attributes + specified in attribute list prepared with tac_add_attrib. +*/ +int tac_author_send(int fd, const char *user, char *tty, struct tac_attrib *attr) { + HDR *th; + struct author tb; + u_char user_len, port_len; + struct tac_attrib *a; + int i = 0; /* attributes count */ + int pkt_len = 0; /* current packet length */ + int pktl = 0; /* temporary storage for previous pkt_len values */ + int w; /* write() return value */ + u_char *pkt; /* packet building pointer */ + /* u_char *pktp; */ /* obsolete */ + int ret = 0; + + th=_tac_req_header(TAC_PLUS_AUTHOR); + + /* set header options */ + th->version=TAC_PLUS_VER_0; + th->encryption=tac_encryption ? TAC_PLUS_ENCRYPTED : TAC_PLUS_CLEAR; + + TACDEBUG((LOG_DEBUG, "%s: user '%s', tty '%s', encrypt: %s", \ + __FUNCTION__, user, \ + tty, tac_encryption ? "yes" : "no")) + + user_len=(u_char) strlen(user); + port_len=(u_char) strlen(tty); + + tb.authen_method=AUTHEN_METH_TACACSPLUS; + tb.priv_lvl=TAC_PLUS_PRIV_LVL_MIN; + if(strcmp(tac_login,"chap") == 0) { + tb.authen_type=TAC_PLUS_AUTHEN_TYPE_CHAP; + } else if(strcmp(tac_login,"login") == 0) { + tb.authen_type=TAC_PLUS_AUTHEN_TYPE_ASCII; + } else { + tb.authen_type=TAC_PLUS_AUTHEN_TYPE_PAP; + } + tb.service=TAC_PLUS_AUTHEN_SVC_PPP; + tb.user_len=user_len; + tb.port_len=port_len; + tb.rem_addr_len=0; + + /* allocate packet */ + pkt=(u_char *) xcalloc(1, TAC_AUTHOR_REQ_FIXED_FIELDS_SIZE); + pkt_len=sizeof(tb); + + /* fill attribute length fields */ + a = attr; + while(a) { + + pktl = pkt_len; + pkt_len += sizeof(a->attr_len); + pkt = xrealloc(pkt, pkt_len); + + /* bad method: realloc() is allowed to return different pointer + with each call + pktp=pkt + pkt_len; + pkt_len += sizeof(a->attr_len); + pkt = xrealloc(pkt, pkt_len); + */ + + bcopy(&a->attr_len, pkt + pktl, sizeof(a->attr_len)); + i++; + + a = a->next; + } + + /* fill the arg count field and add the fixed fields to packet */ + tb.arg_cnt = i; + bcopy(&tb, pkt, TAC_AUTHOR_REQ_FIXED_FIELDS_SIZE); +/* +#define PUTATTR(data, len) \ + pktp = pkt + pkt_len; \ + pkt_len += len; \ + pkt = xrealloc(pkt, pkt_len); \ + bcopy(data, pktp, len); +*/ + +#define PUTATTR(data, len) \ + pktl = pkt_len; \ + pkt_len += len; \ + pkt = xrealloc(pkt, pkt_len); \ + bcopy(data, pkt + pktl, len); + + /* fill user and port fields */ + PUTATTR(user, user_len) + PUTATTR(tty, port_len) + + /* fill attributes */ + a = attr; + while(a) { + PUTATTR(a->attr, a->attr_len) + + a = a->next; + } + + /* finished building packet, fill len_from_header in header */ + th->datalength = htonl(pkt_len); + + /* write header */ + w=write(fd, th, TAC_PLUS_HDR_SIZE); + + if(w < TAC_PLUS_HDR_SIZE) { + syslog(LOG_ERR, "%s: author hdr send failed: wrote %d of %d", + __FUNCTION__, w, + TAC_PLUS_HDR_SIZE); + ret = -1; + } + + /* encrypt packet body */ + _tac_crypt(pkt, th, pkt_len); + + /* write body */ + w=write(fd, pkt, pkt_len); + if(w < pkt_len) { + syslog(LOG_ERR, "%s: author body send failed: wrote %d of %d", + __FUNCTION__, w, + pkt_len); + ret = -1; + } + + free(pkt); + free(th); + + return(ret); +} diff --git a/libtac/lib/connect.c b/libtac/lib/connect.c new file mode 100644 index 0000000..7b55645 --- /dev/null +++ b/libtac/lib/connect.c @@ -0,0 +1,144 @@ +/* connect.c - Open connection to server. + * + * Copyright (C) 2010, Pawel Krawczyk <kravietz@ceti.pl> and + * Jeroen Nijhof <jeroen@nijhofnet.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +#include <signal.h> +#include <arpa/inet.h> +#include <time.h> +#include <fcntl.h> +#include <errno.h> + +#ifdef _AIX + #include <sys/socket.h> +#endif + +#include "tacplus.h" +#include "libtac.h" + +/* Pointer to TACACS+ connection timeout */ +int tac_timeout = 5; + +/* Returns file descriptor of open connection + to the first available server from list passed + in server table. +*/ +int tac_connect(struct addrinfo **server, int servers) { + int tries = 0; + int fd, flags, retval; + fd_set readfds, writefds; + struct timeval tv; + + if(!servers) { + syslog(LOG_ERR, "%s: no TACACS+ servers defined", __FUNCTION__); + return(-1); + } + + while(tries < servers) { + if((fd=socket(server[tries]->ai_family, server[tries]->ai_socktype, server[tries]->ai_protocol)) == -1) { + syslog(LOG_WARNING, + "%s: socket creation error", __FUNCTION__); + tries++; + continue; + } + + /* put socket in non blocking mode for timeout support */ + flags = fcntl(fd, F_GETFL, 0); + if(fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { + syslog(LOG_WARNING, "%s: cannot set socket non blocking", + __FUNCTION__); + tries++; + continue; + } + + retval = connect(fd, server[tries]->ai_addr, server[tries]->ai_addrlen); + if((retval == -1) && (errno != EINPROGRESS)) { + syslog(LOG_WARNING, + "%s: connection to %s failed: %m", __FUNCTION__, + tac_ntop(server[tries]->ai_addr, server[tries]->ai_addrlen)); + if(fcntl(fd, F_SETFL, flags)) { + syslog(LOG_WARNING, "%s: cannot restore socket flags", + __FUNCTION__); + } + tries++; + continue; + } + + /* set fds for select */ + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + writefds = readfds; + + /* set timeout seconds */ + tv.tv_sec = tac_timeout; + tv.tv_usec = 0; + + /* check if socket is ready for read or write */ + if(!select(fd+1, &readfds, &writefds, NULL, &tv)) { + syslog(LOG_WARNING, + "%s: connection timeout with %s : %m", __FUNCTION__, + tac_ntop(server[tries]->ai_addr, server[tries]->ai_addrlen)); + if(fcntl(fd, F_SETFL, flags)) { + syslog(LOG_WARNING, "%s: cannot restore socket flags", + __FUNCTION__); + } + tries++; + continue; + } + + /* connected ok */ + if(fcntl(fd, F_SETFL, flags)) { + syslog(LOG_WARNING, "%s: cannot restore socket flags", + __FUNCTION__); + } + TACDEBUG((LOG_DEBUG, "%s: connected to %s", __FUNCTION__, \ + tac_ntop(server[tries]->ai_addr, server[tries]->ai_addrlen))); + + return(fd); + } + + /* all attempts failed */ + syslog(LOG_ERR, "%s: all possible TACACS+ servers failed", __FUNCTION__); + return(-1); +} /* tac_connect */ + + +int tac_connect_single(struct addrinfo *server) { + struct addrinfo *temp[1]; + temp[0] = server; + return(tac_connect(temp, 1)); +} /* tac_connect_single */ + + +char *tac_ntop(const struct sockaddr *sa, size_t ai_addrlen) { + char *str = (char *) xcalloc(1, ai_addrlen); + switch(sa->sa_family) { + case AF_INET: + inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr), + str, ai_addrlen); + break; + case AF_INET6: + inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), + str, ai_addrlen); + break; + default: + strncpy(str, "Unknown AF", ai_addrlen); + } + return str; +} /* tac_ntop */ diff --git a/libtac/lib/cont_s.c b/libtac/lib/cont_s.c new file mode 100644 index 0000000..17894cf --- /dev/null +++ b/libtac/lib/cont_s.c @@ -0,0 +1,92 @@ +/* cont_s.c - Send continue request to the server. + * + * Copyright (C) 2010, Jeroen Nijhof <jeroen@nijhofnet.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +#include "tacplus.h" +#include "libtac.h" +#include "md5.h" + +/* this function sends a continue packet do TACACS+ server, asking + * for validation of given password + */ +int tac_cont_send(int fd, char *pass) +{ + HDR *th; /* TACACS+ packet header */ + struct authen_cont tb; /* continue body */ + int pass_len, bodylength, w; + int pkt_len=0; + int ret=0; + u_char *pkt; + + th=_tac_req_header(TAC_PLUS_AUTHEN); + + /* set some header options */ + th->version=TAC_PLUS_VER_0; + th->seq_no=3; /* 1 = request, 2 = reply, 3 = continue, 4 = reply */ + th->encryption=tac_encryption ? TAC_PLUS_ENCRYPTED : TAC_PLUS_CLEAR; + + /* get size of submitted data */ + pass_len=strlen(pass); + + /* fill the body of message */ + tb.user_msg_len=htons(pass_len); + tb.user_data_len=tb.flags=0; + + /* fill body length in header */ + bodylength=TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE+0+pass_len; + + th->datalength=htonl(bodylength); + + /* we can now write the header */ + w=write(fd, th, TAC_PLUS_HDR_SIZE); + if(w < 0 || w < TAC_PLUS_HDR_SIZE) { + syslog(LOG_ERR, "%s: short write on header: wrote %d of %d: %m", + __FUNCTION__, w, TAC_PLUS_HDR_SIZE); + ret=-1; + } + + /* build the packet */ + pkt=(u_char *) xcalloc(1, bodylength); + + bcopy(&tb, pkt+pkt_len, TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE); /* packet body beginning */ + pkt_len+=TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE; + bcopy(pass, pkt+pkt_len, pass_len); /* password */ + pkt_len+=pass_len; + + /* pkt_len == bodylength ? */ + if(pkt_len != bodylength) { + syslog(LOG_ERR, "%s: bodylength %d != pkt_len %d", __FUNCTION__, bodylength, pkt_len); + ret=-1; + } + + /* encrypt the body */ + _tac_crypt(pkt, th, bodylength); + + w=write(fd, pkt, pkt_len); + if(w < 0 || w < pkt_len) { + syslog(LOG_ERR, "%s: short write on body: wrote %d of %d: %m", + __FUNCTION__, w, pkt_len); + ret=-1; + } + + free(pkt); + free(th); + + return(ret); +} /* tac_cont_send */ diff --git a/libtac/lib/crypt.c b/libtac/lib/crypt.c new file mode 100644 index 0000000..ae726fc --- /dev/null +++ b/libtac/lib/crypt.c @@ -0,0 +1,107 @@ +/* crypt.c - TACACS+ encryption related functions + * + * Copyright (C) 2010, Pawel Krawczyk <kravietz@ceti.pl> and + * Jeroen Nijhof <jeroen@nijhofnet.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +#include "tacplus.h" +#include "libtac.h" +#include "xalloc.h" +#include "md5.h" + +/* Produce MD5 pseudo-random pad for TACACS+ encryption. + Use data from packet header and secret, which + should be a global variable */ +u_char *_tac_md5_pad(int len, HDR *hdr) { + int n, i, bufsize; + int bp=0; /* buffer pointer */ + int pp=0; /* pad pointer */ + u_char *pad; + u_char *buf; + MD5_CTX mdcontext; + + /* make pseudo pad */ + n=(int)(len/16)+1; /* number of MD5 runs */ + bufsize=sizeof(hdr->session_id) + strlen(tac_secret) + sizeof(hdr->version) + + sizeof(hdr->seq_no) + MD5_LEN + 10; + buf= (u_char *) xcalloc(1, bufsize); + pad= (u_char *) xcalloc(n, MD5_LEN); + + for(i=0; i<n; i++) { + /* MD5_1 = MD5{session_id, secret, version, seq_no} + MD5_2 = MD5{session_id, secret, version, seq_no, MD5_1} */ + + /* place session_id, key, version and seq_no in buffer */ + bp=0; + bcopy(&hdr->session_id, buf, sizeof(session_id)); + bp+=sizeof(session_id); + bcopy(tac_secret, buf+bp, strlen(tac_secret)); + bp+=strlen(tac_secret); + bcopy(&hdr->version, buf+bp, sizeof(hdr->version)); + bp+=sizeof(hdr->version); + bcopy(&hdr->seq_no, buf+bp, sizeof(hdr->seq_no)); + bp+=sizeof(hdr->seq_no); + + /* append previous pad if this is not the first run */ + if(i) { + bcopy(pad+((i-1)*MD5_LEN), buf+bp, MD5_LEN); + bp+=MD5_LEN; + } + + MD5Init(&mdcontext); + MD5Update(&mdcontext, buf, bp); + /* this is because MD5 implementation has changed between + * pppd versions 2.2.0g and 2.3.4 + */ +#if 1 + MD5Final(pad+pp, &mdcontext); /* correct for pppd-2.3.4 */ +#else + MD5Final(&mdcontext); /* correct for pppd-2.2.0g */ + bcopy(&mdcontext.digest, pad+pp, MD5_LEN); +#endif + + pp+=MD5_LEN; + } + + free(buf); + return(pad); + +} /* _tac_md5_pad */ + +/* Perform encryption/decryption on buffer. This means simply XORing + each byte from buffer with according byte from pseudo-random + pad. */ +void _tac_crypt(u_char *buf, HDR *th, int length) { + int i; + u_char *pad; + + /* null operation if no encryption requested */ + if(th->encryption == TAC_PLUS_ENCRYPTED) { + + pad=_tac_md5_pad(length, th); + + for(i=0; i<length; i++) { + *(buf+i) ^= pad[i]; + } + + free(pad); + + } else { + syslog(LOG_WARNING, "%s: using no TACACS+ encryption", __FUNCTION__); + } +} /* _tac_crypt */ diff --git a/libtac/lib/hdr_check.c b/libtac/lib/hdr_check.c new file mode 100644 index 0000000..048a5e6 --- /dev/null +++ b/libtac/lib/hdr_check.c @@ -0,0 +1,53 @@ +/* hdr_check.c - Perform basic sanity checks on received packet. + * + * Copyright (C) 2010, Pawel Krawczyk <kravietz@ceti.pl> and + * Jeroen Nijhof <jeroen@nijhofnet.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +#include "tacplus.h" +#include "messages.h" +#include "libtac.h" + +/* Checks given reply header for possible inconsistencies: + * 1. reply type other than expected + * 2. sequence number other than 2 or 4 + * 3. session_id different from one sent in request + * Returns pointer to error message + * or NULL when the header seems to be correct + */ +char *_tac_check_header(HDR *th, int type) { + + if(th->type != type) { + syslog(LOG_ERR, + "%s: unrelated reply, type %d, expected %d", + __FUNCTION__, th->type, type); + return(protocol_err_msg); + } else if((th->seq_no != 2) && (th->seq_no != 4)) { + syslog(LOG_ERR, "%s: not a reply - seq_no %d != 2", + __FUNCTION__, th->seq_no); + return(protocol_err_msg); + } /* else if(ntohl(th->session_id) != session_id) { + syslog(LOG_ERR, + "%s: unrelated reply, received session_id %d != sent %d", + __FUNCTION__, ntohl(th->session_id), session_id); + return(protocol_err_msg); + } */ + + return(NULL); /* header is ok */ + +} /* check header */ diff --git a/libtac/lib/header.c b/libtac/lib/header.c new file mode 100644 index 0000000..eaccd82 --- /dev/null +++ b/libtac/lib/header.c @@ -0,0 +1,65 @@ +/* header.c - Create pre-filled header for TACACS+ request. + * + * Copyright (C) 2010, Pawel Krawczyk <kravietz@ceti.pl> and + * Jeroen Nijhof <jeroen@nijhofnet.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +#include "tacplus.h" +#include "libtac.h" +#include "xalloc.h" +#include "magic.h" + +/* Miscellaneous variables that are global, because we need + * store their values between different functions and connections. + */ +/* Session identifier. */ +int session_id; + +/* Encryption flag. */ +int tac_encryption; + +/* Pointer to TACACS+ shared secret string. */ +char *tac_secret; + +/* Pointer to TACACS+ shared login string. */ +char *tac_login = "pap"; + +/* Returns pre-filled TACACS+ packet header of given type. + * 1. you MUST fill th->datalength and th->version + * 2. you MAY fill th->encryption + * 3. you are responsible for freeing allocated header + * By default packet encryption is enabled. The version + * field depends on the TACACS+ request type and thus it + * cannot be predefined. + */ +HDR *_tac_req_header(u_char type) { + HDR *th; + + th=(HDR *) xcalloc(1, TAC_PLUS_HDR_SIZE); + + /* preset some packet options in header */ + th->type=type; + th->seq_no=1; /* always 1 for request */ + th->encryption=TAC_PLUS_ENCRYPTED; + + /* make session_id from pseudo-random number */ + session_id = magic(); + th->session_id = htonl(session_id); + + return(th); +} diff --git a/libtac/lib/magic.c b/libtac/lib/magic.c new file mode 100644 index 0000000..7ac5621 --- /dev/null +++ b/libtac/lib/magic.c @@ -0,0 +1,122 @@ +/* magic.c - PPP Magic Number routines. + * + * Copyright (C) 1989 Carnegie Mellon University. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/time.h> +#include <unistd.h> + +/* u_int32_t support for sun */ +#ifdef sun +typedef unsigned int u_int32_t; +#endif + +#include "magic.h" + +#ifndef __linux__ +extern long mrand48 __P((void)); +extern void srand48 __P((long)); +#else +#include <sys/stat.h> +#include <fcntl.h> + +/* on Linux we use /dev/urandom as random numbers source + I find it really cool :) */ +int rfd = 0; /* /dev/urandom */ +#endif + +/* + * magic_init - Initialize the magic number generator. + * + * Attempts to compute a random number seed which will not repeat. + * The current method uses the current hostid, current process ID + * and current time, currently. + */ +void +magic_init() +{ + long seed; + struct timeval t; + +#ifdef __linux__ + rfd = open("/dev/urandom", O_RDONLY); + if(rfd != -1) + return; + else { + rfd = 0; +#endif + /* if /dev/urandom fails, we try traditional method */ + gettimeofday(&t, NULL); + seed = gethostid() ^ t.tv_sec ^ t.tv_usec ^ getpid(); + srand48(seed); +#ifdef __linux__ + } +#endif +} + +/* + * magic - Returns the next magic number. + */ +u_int32_t +magic() +{ +#ifdef __linux__ + u_int32_t ret = 0; + int bytes = 0; + + if(rfd) + { + bytes = read(rfd, &ret, sizeof(ret)); + return(ret); + } + else + return (u_int32_t) mrand48(); +#else + return (u_int32_t) mrand48(); +#endif +} + +#ifdef NO_DRAND48 +/* + * Substitute procedures for those systems which don't have + * drand48 et al. + */ + +double +drand48() +{ + return (double)random() / (double)0x7fffffffL; /* 2**31-1 */ +} + +long +mrand48() +{ + return random(); +} + +void +srand48(seedval) +long seedval; +{ + srandom((int)seedval); +} + +#endif diff --git a/libtac/lib/magic.h b/libtac/lib/magic.h new file mode 100644 index 0000000..ac626b3 --- /dev/null +++ b/libtac/lib/magic.h @@ -0,0 +1,26 @@ +/* magic.h - PPP Magic Number definitions. + * + * Copyright (C) 1989 Carnegie Mellon University. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +#ifndef __linux__ + #include "cdefs.h" +#endif + +void magic_init __P((void)); /* Initialize the magic number generator */ +u_int32_t magic __P((void)); /* Returns the next magic number */ diff --git a/libtac/lib/md5.c b/libtac/lib/md5.c new file mode 100644 index 0000000..cf6799c --- /dev/null +++ b/libtac/lib/md5.c @@ -0,0 +1,276 @@ +/* md5.c - the source code for MD5 routines + * + * Copyright (C) 1990, RSA Data Security, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +#include <string.h> +#include "md5.h" + +/* forward declaration */ +static void Transform (); + +static unsigned char PADDING[64] = { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* 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); \ + } + +#ifdef __STDC__ +#define UL(x) x##U +#else +#define UL(x) x +#endif + +/* The routine MD5Init initializes the message-digest context + mdContext. All fields are set to zero. + */ +void MD5Init (mdContext) +MD5_CTX *mdContext; +{ + mdContext->i[0] = mdContext->i[1] = (UINT4)0; + + /* Load magic initialization constants. + */ + mdContext->buf[0] = (UINT4)0x67452301; + mdContext->buf[1] = (UINT4)0xefcdab89; + mdContext->buf[2] = (UINT4)0x98badcfe; + mdContext->buf[3] = (UINT4)0x10325476; +} + +/* The routine MD5Update updates the message-digest context to + account for the presence of each of the characters inBuf[0..inLen-1] + in the message whose digest is being computed. + */ +void MD5Update (mdContext, inBuf, inLen) +MD5_CTX *mdContext; +unsigned char *inBuf; +unsigned int inLen; +{ + UINT4 in[16]; + int mdi; + unsigned int i, ii; + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* update number of bits */ + if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0]) + mdContext->i[1]++; + mdContext->i[0] += ((UINT4)inLen << 3); + mdContext->i[1] += ((UINT4)inLen >> 29); + + while (inLen--) { + /* add new character to buffer, increment mdi */ + mdContext->in[mdi++] = *inBuf++; + + /* transform if necessary */ + if (mdi == 0x40) { + for (i = 0, ii = 0; i < 16; i++, ii += 4) + in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | + (((UINT4)mdContext->in[ii+2]) << 16) | + (((UINT4)mdContext->in[ii+1]) << 8) | + ((UINT4)mdContext->in[ii]); + Transform (mdContext->buf, in); + mdi = 0; + } + } +} + +/* The routine MD5Final terminates the message-digest computation and + ends with the desired message digest in mdContext->digest[0...15]. + */ +void MD5Final (hash, mdContext) +unsigned char hash[]; +MD5_CTX *mdContext; +{ + UINT4 in[16]; + int mdi; + unsigned int i, ii; + unsigned int padLen; + + /* save number of bits */ + in[14] = mdContext->i[0]; + in[15] = mdContext->i[1]; + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* pad out to 56 mod 64 */ + padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); + MD5Update (mdContext, PADDING, padLen); + + /* append length in bits and transform */ + for (i = 0, ii = 0; i < 14; i++, ii += 4) + in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | + (((UINT4)mdContext->in[ii+2]) << 16) | + (((UINT4)mdContext->in[ii+1]) << 8) | + ((UINT4)mdContext->in[ii]); + Transform (mdContext->buf, in); + + /* store buffer in digest */ + for (i = 0, ii = 0; i < 4; i++, ii += 4) { + mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF); + mdContext->digest[ii+1] = + (unsigned char)((mdContext->buf[i] >> 8) & 0xFF); + mdContext->digest[ii+2] = + (unsigned char)((mdContext->buf[i] >> 16) & 0xFF); + mdContext->digest[ii+3] = + (unsigned char)((mdContext->buf[i] >> 24) & 0xFF); + } + memcpy(hash, mdContext->digest, 16); +} + +/* Basic MD5 step. Transforms buf based on in. + */ +static void Transform (buf, in) +UINT4 *buf; +UINT4 *in; +{ + UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + /* Round 1 */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 + FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */ + FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */ + FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */ + FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */ + FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */ + FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */ + FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */ + FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */ + FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */ + FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */ + FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */ + FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */ + FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */ + FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */ + FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */ + FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */ + + /* Round 2 */ +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 + GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */ + GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */ + GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */ + GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */ + GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */ + GG ( d, a, b, c, in[10], S22, UL( 38016083)); /* 22 */ + GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */ + GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */ + GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */ + GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */ + GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */ + GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */ + GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */ + GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */ + GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */ + GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */ + + /* Round 3 */ +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 + HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */ + HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */ + HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */ + HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */ + HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */ + HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */ + HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */ + HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */ + HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */ + HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */ + HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */ + HH ( b, c, d, a, in[ 6], S34, UL( 76029189)); /* 44 */ + HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */ + HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */ + HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */ + HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */ + + /* Round 4 */ +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */ + II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */ + II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */ + II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */ + II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */ + II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */ + II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */ + II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */ + II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */ + II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */ + II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */ + II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */ + II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */ + II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */ + II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */ + II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */ + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + diff --git a/libtac/lib/md5.h b/libtac/lib/md5.h new file mode 100644 index 0000000..fc314ed --- /dev/null +++ b/libtac/lib/md5.h @@ -0,0 +1,41 @@ +/* md5.h - header file for implementation of MD5 + * + * Copyright (C) 1990, RSA Data Security, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +#ifndef __MD5_INCLUDE__ + +/* typedef a 32-bit type */ +typedef unsigned int UINT4; + +/* Data structure for MD5 (Message-Digest) computation */ +typedef struct { + UINT4 i[2]; /* number of _bits_ handled mod 2^64 */ + UINT4 buf[4]; /* scratch buffer */ + unsigned char in[64]; /* input buffer */ + unsigned char digest[16]; /* actual digest after MD5Final call */ +} MD5_CTX; + +void MD5Init (); +void MD5Update (); +void MD5Final (); + +#define MD5_LEN 16 + +#define __MD5_INCLUDE__ +#endif /* __MD5_INCLUDE__ */ diff --git a/libtac/lib/messages.c b/libtac/lib/messages.c new file mode 100644 index 0000000..8a1ae3e --- /dev/null +++ b/libtac/lib/messages.c @@ -0,0 +1,26 @@ +/* messages.c - Various messages returned to user. + * + * Copyright (C) 2010, Pawel Krawczyk <kravietz@ceti.pl> and + * Jeroen Nijhof <jeroen@nijhofnet.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +char *system_err_msg="Authentication error, please contact administrator."; +char *protocol_err_msg="Protocol error."; +char *author_ok_msg="Service granted."; +char *author_fail_msg="Service not allowed."; +char *author_err_msg="Protocol error."; diff --git a/libtac/lib/messages.h b/libtac/lib/messages.h new file mode 100644 index 0000000..37f2402 --- /dev/null +++ b/libtac/lib/messages.h @@ -0,0 +1,26 @@ +/* messages.h + * + * Copyright (C) 2010, Pawel Krawczyk <kravietz@ceti.pl> and + * Jeroen Nijhof <jeroen@nijhofnet.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +extern char *system_err_msg; +extern char *protocol_err_msg; +extern char *author_ok_msg; +extern char *author_fail_msg; +extern char *author_err_msg; diff --git a/libtac/lib/version.c b/libtac/lib/version.c new file mode 100644 index 0000000..ccf20ee --- /dev/null +++ b/libtac/lib/version.c @@ -0,0 +1,24 @@ +/* version.c - TACACS+ library version. + * + * Copyright (C) 2010, Pawel Krawczyk <kravietz@ceti.pl> and + * Jeroen Nijhof <jeroen@nijhofnet.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +int tac_ver_major = 1; +int tac_ver_minor = 6; +int tac_ver_patch = 5; /* patchlevel */ diff --git a/libtac/lib/xalloc.c b/libtac/lib/xalloc.c new file mode 100644 index 0000000..88bbb28 --- /dev/null +++ b/libtac/lib/xalloc.c @@ -0,0 +1,43 @@ +/* xalloc.c - Failsafe memory allocation functions. + * Taken from excellent glibc.info ;) + * + * Copyright (C) 2010, Pawel Krawczyk <kravietz@ceti.pl> and + * Jeroen Nijhof <jeroen@nijhofnet.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +#include <syslog.h> +#include <stdlib.h> + +void *xcalloc(size_t nmemb, size_t size) { + register void *val = calloc(nmemb, size); + if(val == 0) { + syslog(LOG_ERR, "%s: calloc(%u,%u) failed", __FUNCTION__, + (unsigned) nmemb, (unsigned) size); + exit(1); + } + return val; +} + +void *xrealloc(void *ptr, size_t size) { + register void *val = realloc(ptr, size); + if(val == 0) { + syslog(LOG_ERR, "%s: realloc(%u) failed", __FUNCTION__, (unsigned) size); + exit(1); + } + return val; +} diff --git a/libtac/lib/xalloc.h b/libtac/lib/xalloc.h new file mode 100644 index 0000000..da02dfa --- /dev/null +++ b/libtac/lib/xalloc.h @@ -0,0 +1,23 @@ +/* xalloc.h + * + * Copyright (C) 2010, Pawel Krawczyk <kravietz@ceti.pl> and + * Jeroen Nijhof <jeroen@nijhofnet.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program - see the file COPYING. + * + * See `CHANGES' file for revision history. + */ + +extern void *xcalloc(size_t nmemb, size_t size); +extern void *xrealloc(void *ptr, size_t size); |