summaryrefslogtreecommitdiff
path: root/libtac
diff options
context:
space:
mode:
authorJeroen Nijhof <jeroenn@saralt0078.(none)>2010-12-22 11:12:08 +0100
committerJeroen Nijhof <jeroenn@saralt0078.(none)>2010-12-22 11:12:08 +0100
commit4e0f4aa68e082b469663e3ebc8ec83c9400dab4b (patch)
tree08d50b522bc250659704b2dfc73d887979198fd4 /libtac
downloadpam_tacplus-4e0f4aa68e082b469663e3ebc8ec83c9400dab4b.tar.gz
pam_tacplus-4e0f4aa68e082b469663e3ebc8ec83c9400dab4b.zip
Initial commit
Diffstat (limited to 'libtac')
-rw-r--r--libtac/include/cdefs.h58
-rw-r--r--libtac/include/libtac.h83
-rw-r--r--libtac/include/tacplus.h265
-rw-r--r--libtac/lib/acct_r.c97
-rw-r--r--libtac/lib/acct_s.c151
-rw-r--r--libtac/lib/attrib.c80
-rw-r--r--libtac/lib/authen_r.c104
-rw-r--r--libtac/lib/authen_s.c143
-rw-r--r--libtac/lib/author_r.c194
-rw-r--r--libtac/lib/author_s.c152
-rw-r--r--libtac/lib/connect.c144
-rw-r--r--libtac/lib/cont_s.c92
-rw-r--r--libtac/lib/crypt.c107
-rw-r--r--libtac/lib/hdr_check.c53
-rw-r--r--libtac/lib/header.c65
-rw-r--r--libtac/lib/magic.c122
-rw-r--r--libtac/lib/magic.h26
-rw-r--r--libtac/lib/md5.c276
-rw-r--r--libtac/lib/md5.h41
-rw-r--r--libtac/lib/messages.c26
-rw-r--r--libtac/lib/messages.h26
-rw-r--r--libtac/lib/version.c24
-rw-r--r--libtac/lib/xalloc.c43
-rw-r--r--libtac/lib/xalloc.h23
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);