From d1134977b9317c6161ae12608684ea857915a63c Mon Sep 17 00:00:00 2001 From: Jeroen Date: Fri, 19 Aug 2011 22:05:10 +0200 Subject: Major contribution by Darren Besler --- libtac/include/cdefs.h | 32 +++-- libtac/include/libtac.h | 95 ++++++++++-- libtac/include/tacplus.h | 197 +++++++++++-------------- libtac/lib/acct_r.c | 198 ++++++++++++++++--------- libtac/lib/acct_s.c | 255 +++++++++++++++++---------------- libtac/lib/attrib.c | 96 +++++++------ libtac/lib/authen_r.c | 157 ++++++++++++-------- libtac/lib/authen_s.c | 252 +++++++++++++++++--------------- libtac/lib/author_r.c | 365 ++++++++++++++++++++++++++--------------------- libtac/lib/author_s.c | 252 ++++++++++++++++---------------- libtac/lib/connect.c | 267 +++++++++++++++++++--------------- libtac/lib/cont_s.c | 142 +++++++++--------- libtac/lib/crypt.c | 116 ++++++++------- libtac/lib/hdr_check.c | 38 +++-- libtac/lib/header.c | 41 ++++-- libtac/lib/magic.c | 35 +++-- libtac/lib/magic.h | 8 +- libtac/lib/md5.c | 331 +++++++++++++++++++++--------------------- libtac/lib/md5.h | 16 ++- libtac/lib/messages.c | 16 ++- libtac/lib/messages.h | 13 +- libtac/lib/read_wait.c | 119 +++++++++++++++ libtac/lib/version.c | 6 +- libtac/lib/xalloc.c | 42 +++--- libtac/lib/xalloc.h | 10 +- 25 files changed, 1765 insertions(+), 1334 deletions(-) create mode 100644 libtac/lib/read_wait.c (limited to 'libtac') diff --git a/libtac/include/cdefs.h b/libtac/include/cdefs.h index 148f3d7..2297d93 100644 --- a/libtac/include/cdefs.h +++ b/libtac/include/cdefs.h @@ -1,6 +1,6 @@ /* cdefs.h * - * Copyright (C) 2010, Pawel Krawczyk and + * Copyright (C) 2010, Pawel Krawczyk and * Jeroen Nijhof * * This program is free software; you can redistribute it and/or modify @@ -19,23 +19,26 @@ * See `CHANGES' file for revision history. */ +#ifndef _CDEFS_H +#define _CDEFS_H + #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 _PTR void * +#define _ANDi , +#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 @@ -49,10 +52,11 @@ #define _ATTRIBUTE(attrs) __attribute__ ((attrs)) #if defined(__cplusplus) -#define __BEGIN_DECLS extern "C" { -#define __END_DECLS } +#define __BEGIN_DECLS extern "C" { +#define __END_DECLS } #else #define __BEGIN_DECLS #define __END_DECLS #endif +#endif diff --git a/libtac/include/libtac.h b/libtac/include/libtac.h index dfa5ca0..fbe16ba 100644 --- a/libtac/include/libtac.h +++ b/libtac/include/libtac.h @@ -1,6 +1,6 @@ /* libtac.h * - * Copyright (C) 2010, Pawel Krawczyk and + * Copyright (C) 2010, Pawel Krawczyk and * Jeroen Nijhof * * This program is free software; you can redistribute it and/or modify @@ -19,8 +19,14 @@ * See `CHANGES' file for revision history. */ -#ifndef _AUTH_TAC_H -#define _AUTH_TAC_H +#ifndef _LIB_TAC_H +#define _LIB_TAC_H + +#include "tacplus.h" + +#ifdef __cplusplus +extern "C" { +#endif #include #include @@ -34,9 +40,20 @@ #include #if defined(DEBUGTAC) && !defined(TACDEBUG) -#define TACDEBUG(x) syslog x; +#define TACDEBUG(x) syslog x; #else -#define TACDEBUG(x) +#define TACDEBUG(x) syslog x; +// #define TACDEBUG(x) +#endif + +#define TACSYSLOG(x) syslog x; + +#if defined(TACDEBUG_AT_RUNTIME) +#undef TACDEBUG +#undef TACSYSLOG +#define TACDEBUG(x) if (tac_debug_enable) (void)logmsg x; +#define TACSYSLOG(x) (void)logmsg x; +extern int logmsg __P((int, const char*, ...)); #endif /* u_int32_t support for sun */ @@ -44,6 +61,45 @@ typedef unsigned int u_int32_t; #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 */ + +/* Internal status codes + * all negative, tacplus status codes are >= 0 + */ + +#define LIBTAC_STATUS_ASSEMBLY_ERR -1 +#define LIBTAC_STATUS_PROTOCOL_ERR -2 +#define LIBTAC_STATUS_READ_TIMEOUT -3 +#define LIBTAC_STATUS_WRITE_TIMEOUT -4 +#define LIBTAC_STATUS_WRITE_ERR -5 +#define LIBTAC_STATUS_SHORT_HDR -6 +#define LIBTAC_STATUS_SHORT_BODY -7 +#define LIBTAC_STATUS_CONN_TIMEOUT -8 +#define LIBTAC_STATUS_CONN_ERR -9 + +/* Runtime flags */ + /* version.c */ extern int tac_ver_major; extern int tac_ver_minor; @@ -54,6 +110,12 @@ extern int session_id; extern int tac_encryption; extern char *tac_secret; extern char *tac_login; +extern int tac_priv_lvl; +extern int tac_authen_method; +extern int tac_authen_service; + +extern int tac_debug_enable; +extern int tac_readtimeout_enable; /* connect.c */ extern int tac_timeout; @@ -61,23 +123,30 @@ extern int tac_connect(struct addrinfo **server, char **key, int servers); extern int tac_connect_single(struct addrinfo *server, char *key); 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_send(int fd, const char *user, char *pass, char *tty, + char *rem_addr); 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 HDR *_tac_req_header(u_char type, int cont_session); 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 int tac_account_send(int fd, int type, const char *user, char *tty, char *rem_addr, + struct tac_attrib *attr); +extern int tac_account_read(int fd, struct areply *arep); 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); +extern int tac_author_send(int fd, const char *user, char *tty, char *rem_addr, + struct tac_attrib *attr); +extern int tac_author_read(int fd, struct areply *arep); +extern void tac_add_attrib_pair(struct tac_attrib **attr, char *name, char sep, + char *value); +extern int tac_read_wait(int fd, int timeout, int size, int *time_left); +#ifdef __cplusplus +} #endif +#endif diff --git a/libtac/include/tacplus.h b/libtac/include/tacplus.h index d43e563..0838325 100644 --- a/libtac/include/tacplus.h +++ b/libtac/include/tacplus.h @@ -1,6 +1,6 @@ /* tacplus.h * - * Copyright (C) 2010, Pawel Krawczyk and + * Copyright (C) 2010, Pawel Krawczyk and * Jeroen Nijhof * * This program is free software; you can redistribute it and/or modify @@ -24,64 +24,40 @@ #include #ifdef sun - #include "cdefs.h" + #include "cdefs.h" #else - #include + #include #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_MINOR_VER_0 0x00 #define TAC_PLUS_VER_0 (TAC_PLUS_MAJOR_VER | TAC_PLUS_MINOR_VER_0) -#define TAC_PLUS_MINOR_VER_1 0x01 +#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 +#define TAC_PLUS_AUTHEN 0x01 +#define TAC_PLUS_AUTHOR 0x02 +#define TAC_PLUS_ACCT 0x03 - u_char seq_no; /* packet sequence number */ - u_char encryption; /* packet is encrypted or cleartext */ + 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 */ +#define TAC_PLUS_ENCRYPTED_FLAG 0x00 /* packet is encrypted */ +#define TAC_PLUS_UNENCRYPTED_FLAG 0x01 /* packet is unencrypted */ +#define TAC_PLUS_SINGLE_CONNECT_FLAG 0x04 /* multiplexing supported */ - int session_id; /* session identifier FIXME: Is this needed? */ - int datalength; /* length of encrypted data following this - * header */ - /* datalength bytes of encrypted data */ + 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 @@ -89,46 +65,46 @@ struct tac_plus_pak_hdr { 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 +#define TAC_PLUS_AUTHEN_LOGIN 0x01 +#define TAC_PLUS_AUTHEN_CHPASS 0x02 +#define TAC_PLUS_AUTHEN_SENDPASS 0x03 /* deprecated */ +#define TAC_PLUS_AUTHEN_SENDAUTH 0x04 u_char priv_lvl; -#define TAC_PLUS_PRIV_LVL_MIN 0x0 -#define TAC_PLUS_PRIV_LVL_MAX 0xf +#define TAC_PLUS_PRIV_LVL_MIN 0x00 +#define TAC_PLUS_PRIV_LVL_MAX 0x0f +#define TAC_PLUS_PRIV_LVL_USER 0x01 +#define TAC_PLUS_PRIV_LVL_ROOT 0x0f 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 +#define TAC_PLUS_AUTHEN_TYPE_ASCII 0x01 +#define TAC_PLUS_AUTHEN_TYPE_PAP 0x02 +#define TAC_PLUS_AUTHEN_TYPE_CHAP 0x03 +#define TAC_PLUS_AUTHEN_TYPE_ARAP 0x04 +#define TAC_PLUS_AUTHEN_TYPE_MSCHAP 0x05 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 +#define TAC_PLUS_AUTHEN_SVC_NONE 0x00 +#define TAC_PLUS_AUTHEN_SVC_LOGIN 0x01 +#define TAC_PLUS_AUTHEN_SVC_ENABLE 0x02 +#define TAC_PLUS_AUTHEN_SVC_PPP 0x03 +#define TAC_PLUS_AUTHEN_SVC_ARAP 0x04 +#define TAC_PLUS_AUTHEN_SVC_PT 0x05 +#define TAC_PLUS_AUTHEN_SVC_RCMD 0x06 +#define TAC_PLUS_AUTHEN_SVC_X25 0x07 +#define TAC_PLUS_AUTHEN_SVC_NASI 0x08 +#define TAC_PLUS_AUTHEN_SVC_FWPROXY 0x09 u_char user_len; u_char port_len; u_char rem_addr_len; u_char data_len; - /* */ - /* */ - /* */ - /* */ }; #define TAC_AUTHEN_START_FIXED_FIELDS_SIZE 8 @@ -139,10 +115,8 @@ struct authen_cont { u_short user_data_len; u_char flags; -#define TAC_PLUS_CONTINUE_FLAG_ABORT 0x1 +#define TAC_PLUS_CONTINUE_FLAG_ABORT 0x01 - /* */ - /* */ }; #define TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE 5 @@ -151,43 +125,52 @@ struct authen_cont { 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 +#define TAC_PLUS_AUTHEN_STATUS_PASS 0x01 +#define TAC_PLUS_AUTHEN_STATUS_FAIL 0x02 +#define TAC_PLUS_AUTHEN_STATUS_GETDATA 0x03 +#define TAC_PLUS_AUTHEN_STATUS_GETUSER 0x04 +#define TAC_PLUS_AUTHEN_STATUS_GETPASS 0x05 +#define TAC_PLUS_AUTHEN_STATUS_RESTART 0x06 +#define TAC_PLUS_AUTHEN_STATUS_ERROR 0x07 +#define TAC_PLUS_AUTHEN_STATUS_FOLLOW 0x21 u_char flags; -#define TAC_PLUS_AUTHEN_FLAG_NOECHO 0x1 +#define TAC_PLUS_AUTHEN_FLAG_NOECHO 0x01 u_short msg_len; u_short data_len; - - /* */ - /* */ }; #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 +#define TAC_PLUS_AUTHEN_METH_NOT_SET 0x00 +#define TAC_PLUS_AUTHEN_METH_NONE 0x01 +#define TAC_PLUS_AUTHEN_METH_KRB5 0x02 +#define TAC_PLUS_AUTHEN_METH_LINE 0x03 +#define TAC_PLUS_AUTHEN_METH_ENABLE 0x04 +#define TAC_PLUS_AUTHEN_METH_LOCAL 0x05 +#define TAC_PLUS_AUTHEN_METH_TACACSPLUS 0x06 +#define TAC_PLUS_AUTHEN_METH_GUEST 0x08 +#define TAC_PLUS_AUTHEN_METH_RADIUS 0x10 +#define TAC_PLUS_AUTHEN_METH_KRB4 0x11 +#define TAC_PLUS_AUTHEN_METH_RCMD 0x20 + +#define AUTHEN_METH_NONE TAC_PLUS_AUTHEN_METH_NONE +#define AUTHEN_METH_KRB5 TAC_PLUS_AUTHEN_METH_KRB5 +#define AUTHEN_METH_LINE TAC_PLUS_AUTHEN_METH_LINE +#define AUTHEN_METH_ENABLE TAC_PLUS_AUTHEN_METH_ENABLE +#define AUTHEN_METH_LOCAL TAC_PLUS_AUTHEN_METH_LOCAL +#define AUTHEN_METH_TACACSPLUS TAC_PLUS_AUTHEN_METH_TACACSPLUS +#define AUTHEN_METH_RCMD TAC_PLUS_AUTHEN_METH_RCMD 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 +#define TAC_PLUS_ACCT_FLAG_MORE 0x01 +#define TAC_PLUS_ACCT_FLAG_START 0x02 +#define TAC_PLUS_ACCT_FLAG_STOP 0x04 +#define TAC_PLUS_ACCT_FLAG_WATCHDOG 0x08 u_char authen_method; u_char priv_lvl; @@ -196,12 +179,7 @@ struct acct { u_char user_len; u_char port_len; u_char rem_addr_len; - u_char arg_cnt; /* the number of cmd args */ - /* one u_char containing size for each arg */ - /* */ - /* */ - /* */ - /* char data for args 1 ... n */ + u_char arg_cnt; /* the number of cmd args */ }; #define TAC_ACCT_REQ_FIXED_FIELDS_SIZE 9 @@ -229,13 +207,7 @@ struct author { u_char user_len; u_char port_len; u_char rem_addr_len; - u_char arg_cnt; /* the number of args */ - - /* */ - /* */ - /* */ - /* */ - /* */ + u_char arg_cnt; /* the number of args */ }; #define TAC_AUTHOR_REQ_FIXED_FIELDS_SIZE 8 @@ -247,19 +219,20 @@ struct author_reply { 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 +#define TAC_PLUS_AUTHOR_STATUS_PASS_ADD 0x01 +#define TAC_PLUS_AUTHOR_STATUS_PASS_REPL 0x02 +#define TAC_PLUS_AUTHOR_STATUS_FAIL 0x10 +#define TAC_PLUS_AUTHOR_STATUS_ERROR 0x11 +#define TAC_PLUS_AUTHOR_STATUS_FOLLOW 0x21 + +#define AUTHOR_STATUS_PASS_ADD TAC_PLUS_AUTHOR_STATUS_PASS_ADD +#define AUTHOR_STATUS_PASS_REPL TAC_PLUS_AUTHOR_STATUS_PASS_REPL +#define AUTHOR_STATUS_FAIL TAC_PLUS_AUTHOR_STATUS_FAIL +#define AUTHOR_STATUS_ERROR TAC_PLUS_AUTHOR_STATUS_ERROR +#define AUTHOR_STATUS_FOLLOW TAC_PLUS_AUTHOR_STATUS_FOLLOW - /* */ - /* */ - /* */ - /* */ }; #define TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE 6 - #endif diff --git a/libtac/lib/acct_r.c b/libtac/lib/acct_r.c index d30d18f..0f23d04 100644 --- a/libtac/lib/acct_r.c +++ b/libtac/lib/acct_r.c @@ -1,6 +1,6 @@ /* acct_r.c - Read accounting reply from server. * - * Copyright (C) 2010, Pawel Krawczyk and + * Copyright (C) 2010, Pawel Krawczyk and * Jeroen Nijhof * * This program is free software; you can redistribute it and/or modify @@ -20,78 +20,134 @@ */ #include "tacplus.h" +#include "xalloc.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); +/* + * return value: + * < 0 : error status code, see LIBTAC_STATUS_... + * LIBTAC_STATUS_READ_TIMEOUT + * LIBTAC_STATUS_SHORT_HDR + * LIBTAC_STATUS_SHORT_BODY + * LIBTAC_STATUS_PROTOCOL_ERR + * >= 0 : server response, see TAC_PLUS_AUTHEN_STATUS_... + */ +int tac_account_read(int fd, struct areply *re) { + HDR th; + struct acct_reply *tb = NULL; + int len_from_header, r, len_from_body; + char *msg = NULL; + int timeleft; + re->attr = NULL; /* unused */ + re->msg = NULL; + + if (tac_readtimeout_enable && + tac_read_wait(fd,tac_timeout*1000, TAC_PLUS_HDR_SIZE,&timeleft) < 0 ) { + TACSYSLOG((LOG_ERR,\ + "%s: reply timeout after %d secs", __FUNCTION__, tac_timeout)) + re->msg = xstrdup(acct_syserr_msg); + re->status = LIBTAC_STATUS_READ_TIMEOUT; + goto AcctExit; + } + + r=read(fd, &th, TAC_PLUS_HDR_SIZE); + if(r < TAC_PLUS_HDR_SIZE) { + TACSYSLOG((LOG_ERR,\ + "%s: short reply header, read %d of %d: %m", __FUNCTION__,\ + r, TAC_PLUS_HDR_SIZE)) + re->msg = xstrdup(acct_syserr_msg); + re->status = LIBTAC_STATUS_SHORT_HDR; + goto AcctExit; + } + + /* check the reply fields in header */ + msg = _tac_check_header(&th, TAC_PLUS_ACCT); + if(msg != NULL) { + re->msg = xstrdup(msg); + re->status = LIBTAC_STATUS_PROTOCOL_ERR; + goto AcctExit; + } + + len_from_header=ntohl(th.datalength); + tb=(struct acct_reply *) xcalloc(1, len_from_header); + + /* read reply packet body */ + if (tac_readtimeout_enable && + tac_read_wait(fd,timeleft,len_from_header,NULL) < 0 ) { + TACSYSLOG((LOG_ERR,\ + "%s: reply timeout after %d secs", __FUNCTION__, tac_timeout)) + re->msg = xstrdup(acct_syserr_msg); + re->status = LIBTAC_STATUS_READ_TIMEOUT; + goto AcctExit; + } + + r=read(fd, tb, len_from_header); + if(r < len_from_header) { + TACSYSLOG((LOG_ERR,\ + "%s: short reply body, read %d of %d: %m",\ + __FUNCTION__,\ + r, len_from_header)) + re->msg = xstrdup(acct_syserr_msg); + re->status = LIBTAC_STATUS_SHORT_BODY; + goto AcctExit; + } + + /* 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) { + TACSYSLOG((LOG_ERR,\ + "%s: inconsistent reply body, incorrect key?",\ + __FUNCTION__)) + re->msg = xstrdup(acct_syserr_msg); + re->status = LIBTAC_STATUS_PROTOCOL_ERR; + goto AcctExit; + } + + /* save status and clean up */ + r=tb->status; + if(tb->msg_len) { + msg=(char *) xcalloc(1, tb->msg_len+1); + bcopy((u_char *) tb+TAC_ACCT_REPLY_FIXED_FIELDS_SIZE, msg, tb->msg_len); + msg[(int)tb->msg_len] = '\0'; + re->msg = msg; // Freed by caller + } + + /* server logged our request successfully */ + if (tb->status == TAC_PLUS_ACCT_STATUS_SUCCESS) { + TACDEBUG((LOG_DEBUG, "%s: accounted ok", __FUNCTION__)) + if (!re->msg) re->msg=xstrdup(acct_ok_msg); + re->status = tb->status; + goto AcctExit; + } + + TACDEBUG((LOG_DEBUG, "%s: accounting failed, server reply status=%d",\ + __FUNCTION__, tb->status)) + switch(tb->status) { + case TAC_PLUS_ACCT_STATUS_FOLLOW: + re->status = tb->status; + if (!re->msg) re->msg=xstrdup(acct_fail_msg); + break; + + case TAC_PLUS_ACCT_STATUS_ERROR: + default: + re->status = tb->status; + if (!re->msg) re->msg=xstrdup(acct_err_msg); + break; + } +AcctExit: + free(tb); + TACDEBUG((LOG_DEBUG, "%s: exit status=%d, status message \"%s\"",\ + __FUNCTION__, re->status, re->msg != NULL ? re->msg : "")) + return(re->status); } diff --git a/libtac/lib/acct_s.c b/libtac/lib/acct_s.c index 5ca07c3..dd3dff9 100644 --- a/libtac/lib/acct_s.c +++ b/libtac/lib/acct_s.c @@ -1,6 +1,6 @@ /* acct_s.c - Send accounting event information to server. * - * Copyright (C) 2010, Pawel Krawczyk and + * Copyright (C) 2010, Pawel Krawczyk and * Jeroen Nijhof * * This program is free software; you can redistribute it and/or modify @@ -23,129 +23,138 @@ #include "libtac.h" #include "xalloc.h" +/* + * return value: + * 0 : success + * < 0 : error status code, see LIBTAC_STATUS_... + * LIBTAC_STATUS_WRITE_ERR + * LIBTAC_STATUS_WRITE_TIMEOUT (pending impl) + * LIBTAC_STATUS_ASSEMBLY_ERR (pending impl) + */ 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); - - /* + char *rem_addr, struct tac_attrib *attr) { + + HDR *th; + struct acct tb; + u_char user_len, port_len, rem_addr_len; + struct tac_attrib *a; + int i = 0; /* arg count */ + int pkt_len = 0; + int pktl = 0; + int w; /* write count */ + u_char *pkt=NULL; + /* u_char *pktp; */ /* obsolute */ + int ret = 0; + + th=_tac_req_header(TAC_PLUS_ACCT, 0); + + /* set header options */ + th->version=TAC_PLUS_VER_0; + th->encryption=tac_encryption ? TAC_PLUS_ENCRYPTED_FLAG : TAC_PLUS_UNENCRYPTED_FLAG; + + TACDEBUG((LOG_DEBUG, "%s: user '%s', tty '%s', rem_addr '%s', encrypt: %s, type: %s", \ + __FUNCTION__, user, tty, rem_addr, \ + (tac_encryption) ? "yes" : "no", \ + (type == TAC_PLUS_ACCT_FLAG_START) ? "START" : "STOP")) + + user_len=(u_char) strlen(user); + port_len=(u_char) strlen(tty); + rem_addr_len=(u_char) strlen(rem_addr); + + tb.flags=(u_char) type; + tb.authen_method=tac_authen_method; + tb.priv_lvl=tac_priv_lvl; + 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_authen_service; + tb.user_len=user_len; + tb.port_len=port_len; + tb.rem_addr_len=rem_addr_len; + + /* 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 = (u_char*) 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); -*/ + 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); + pktl = pkt_len; \ + pkt_len += len; \ + pkt = (u_char*) xrealloc(pkt, pkt_len); \ + bcopy(data, pkt + pktl, len); + + /* fill user and port fields */ + PUTATTR(user, user_len) + PUTATTR(tty, port_len) + PUTATTR(rem_addr, rem_addr_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) { + TACSYSLOG((LOG_ERR, "%s: short write on header, wrote %d of %d: %m",\ + __FUNCTION__, w, TAC_PLUS_HDR_SIZE)) + ret = LIBTAC_STATUS_WRITE_ERR; + goto AcctExit; + } + + /* encrypt packet body */ + _tac_crypt(pkt, th, pkt_len); + + /* write body */ + w=write(fd, pkt, pkt_len); + if(w < pkt_len) { + TACSYSLOG((LOG_ERR, "%s: short write on body, wrote %d of %d: %m",\ + __FUNCTION__, w, pkt_len)) + ret = LIBTAC_STATUS_WRITE_ERR; + } + +AcctExit: + free(pkt); + free(th); + TACDEBUG((LOG_DEBUG, "%s: exit status=%d", __FUNCTION__, ret)) + return(ret); } diff --git a/libtac/lib/attrib.c b/libtac/lib/attrib.c index 761cde0..f409796 100644 --- a/libtac/lib/attrib.c +++ b/libtac/lib/attrib.c @@ -1,7 +1,7 @@ /* attrib.c - Procedures for handling internal list of attributes - * for accounting and authorization functions. + * for accounting and authorization functions. * - * Copyright (C) 2010, Pawel Krawczyk and + * Copyright (C) 2010, Pawel Krawczyk and * Jeroen Nijhof * * This program is free software; you can redistribute it and/or modify @@ -25,56 +25,64 @@ #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" */ + tac_add_attrib_pair(attr, 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 */ +void tac_add_attrib_pair(struct tac_attrib **attr, char *name, char sep, 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" */ - a->next = (struct tac_attrib *) xcalloc(1, sizeof(struct tac_attrib)); - a = a->next; /* set current block pointer to the new one */ - } + if (total_len > 255) { + TACSYSLOG((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 */ - /* 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 = (struct tac_attrib *) xcalloc(1, sizeof(struct tac_attrib)); + a = a->next; /* set current block pointer to the new one */ + } - a->next = NULL; /* make sure it's null */ + if ( sep != '=' && sep != '*' ) { + sep = '='; + } + /* fill the block */ + a->attr_len=total_len; + a->attr = (char *) xcalloc(1, total_len+1); + bcopy(name, a->attr, l1); /* paste name */ + *(a->attr+l1)=sep; /* insert seperator "[=*]" */ + bcopy(value, (a->attr+l1+1), l2); /* paste value */ + *(a->attr+total_len) = '\0'; /* add 0 for safety */ + 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; + struct tac_attrib *a; + struct tac_attrib *b; - a = b = *attr; - - /* find last allocated block */ - do { - a = b; - b = a->next; - free(a->attr); - free(a); - } while (b != NULL); + 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 index 55acac5..cd2ab2a 100644 --- a/libtac/lib/authen_r.c +++ b/libtac/lib/authen_r.c @@ -1,6 +1,6 @@ /* authen_r.c - Read authentication reply from server. * - * Copyright (C) 2010, Pawel Krawczyk and + * Copyright (C) 2010, Pawel Krawczyk and * Jeroen Nijhof * * This program is free software; you can redistribute it and/or modify @@ -26,79 +26,110 @@ /* 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 + * + * return value: + * < 0 : error status code, see LIBTAC_STATUS_... + * LIBTAC_STATUS_READ_TIMEOUT + * LIBTAC_STATUS_SHORT_HDR + * LIBTAC_STATUS_SHORT_BODY + * LIBTAC_STATUS_PROTOCOL_ERR + * >= 0 : server response, see TAC_PLUS_AUTHEN_STATUS_... */ int tac_authen_read(int fd) { - HDR th; - struct authen_reply *tb; - int len_from_header, r, len_from_body; - char *msg = NULL; + HDR th; + struct authen_reply *tb = NULL; + int len_from_header, r, len_from_body; + char *msg = NULL; + int timeleft; + int status; - /* 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); - } + /* read the reply header */ + if (tac_readtimeout_enable && + tac_read_wait(fd,tac_timeout*1000,TAC_PLUS_HDR_SIZE,&timeleft) < 0 ) { + TACSYSLOG((LOG_ERR,\ + "%s: reply timeout after %d secs", __FUNCTION__, tac_timeout)) + status=LIBTAC_STATUS_READ_TIMEOUT; + goto AuthenExit; + } + r = read(fd, &th, TAC_PLUS_HDR_SIZE); + if (r < TAC_PLUS_HDR_SIZE) { + TACSYSLOG((LOG_ERR,\ + "%s: short reply header, read %d of %d: %m",\ + __FUNCTION__,\ + r, TAC_PLUS_HDR_SIZE)) + status=LIBTAC_STATUS_SHORT_HDR; + goto AuthenExit; + } - /* check the reply fields in header */ - msg = _tac_check_header(&th, TAC_PLUS_AUTHEN); - if(msg != NULL) - return(TAC_PLUS_AUTHEN_STATUS_FAIL); + /* check the reply fields in header */ + msg = _tac_check_header(&th, TAC_PLUS_AUTHEN); + if(msg != NULL) { + status = LIBTAC_STATUS_PROTOCOL_ERR; + goto AuthenExit; + } - len_from_header=ntohl(th.datalength); - tb=(struct authen_reply *) xcalloc(1, len_from_header); + 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); - } + /* read reply packet body */ + if (tac_readtimeout_enable && + tac_read_wait(fd,timeleft,len_from_header,NULL) < 0 ) { + TACSYSLOG((LOG_ERR,\ + "%s: reply timeout after %d secs", __FUNCTION__, tac_timeout)) + status=LIBTAC_STATUS_READ_TIMEOUT; + } + r = read(fd, tb, len_from_header); + if (r < len_from_header) { + TACSYSLOG((LOG_ERR,\ + "%s: short reply body, read %d of %d: %m",\ + __FUNCTION__,\ + r, len_from_header)) + status=LIBTAC_STATUS_SHORT_BODY; + goto AuthenExit; + } - /* decrypt the body */ - _tac_crypt((u_char *) tb, &th, len_from_header); + /* 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); + /* 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; + /* 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); - } + if(len_from_header != len_from_body) { + TACSYSLOG((LOG_ERR,\ + "%s: inconsistent reply body, incorrect key?",\ + __FUNCTION__)) + status=LIBTAC_STATUS_PROTOCOL_ERR; + goto AuthenExit; + } - /* save status and clean up */ - r=tb->status; - free(tb); + /* save status and clean up */ + r = tb->status; + status = r; - /* 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); - } + /* server authenticated username and password successfully */ + if (r == TAC_PLUS_AUTHEN_STATUS_PASS) { + TACDEBUG((LOG_DEBUG, "%s: authentication ok", __FUNCTION__)) + goto AuthenExit; + } + + /* server ask for continue packet with password */ + if (r == TAC_PLUS_AUTHEN_STATUS_GETPASS) { + TACDEBUG((LOG_DEBUG, "%s: continue packet with password needed", __FUNCTION__)) + goto AuthenExit; + } - /* return pointer to server message */ - syslog(LOG_DEBUG, "%s: authentication failed, server reply was %d", - __FUNCTION__, r); - return(r); + TACDEBUG((LOG_DEBUG, "%s: authentication failed, server reply status=%d",\ + __FUNCTION__, r)) -} /* tac_authen_read */ +AuthenExit: + free(tb); + TACDEBUG((LOG_DEBUG, "%s: exit status=%d",\ + __FUNCTION__, status)) + return(status); +} /* tac_authen_read */ diff --git a/libtac/lib/authen_s.c b/libtac/lib/authen_s.c index 4a7e55a..d241839 100644 --- a/libtac/lib/authen_s.c +++ b/libtac/lib/authen_s.c @@ -1,6 +1,6 @@ /* authen_s.c - Send authentication request to the server. * - * Copyright (C) 2010, Pawel Krawczyk and + * Copyright (C) 2010, Pawel Krawczyk and * Jeroen Nijhof * * This program is free software; you can redistribute it and/or modify @@ -21,123 +21,143 @@ #include "tacplus.h" #include "libtac.h" +#include "xalloc.h" #include "md5.h" /* this function sends a packet do TACACS+ server, asking * for validation of given username and password + * + * return value: + * 0 : success + * < 0 : error status code, see LIBTAC_STATUS_... + * LIBTAC_STATUS_WRITE_ERR + * LIBTAC_STATUS_WRITE_TIMEOUT + * LIBTAC_STATUS_ASSEMBLY_ERR */ -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 */ +int tac_authen_send(int fd, const char *user, char *pass, char *tty, + char *rem_addr) { + + 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 rem_addr_len; + int pkt_len = 0; + int ret = 0; + char *chal = "1234123412341234"; + char digest[MD5_LEN]; + char *token = NULL; + u_char *pkt = NULL, *mdp = NULL; + MD5_CTX mdcontext; + + th=_tac_req_header(TAC_PLUS_AUTHEN, 0); + + /* 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_FLAG : TAC_PLUS_UNENCRYPTED_FLAG; + + TACDEBUG((LOG_DEBUG, "%s: user '%s', tty '%s', rem_addr '%s', encrypt: %s", \ + __FUNCTION__, user, tty, rem_addr, \ + (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 = (char*) 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 = xstrdup(pass); + } + + /* get size of submitted data */ + user_len = strlen(user); + port_len = strlen(tty); + rem_addr_len = strlen(rem_addr); + token_len = strlen(token); + + /* fill the body of message */ + tb.action = TAC_PLUS_AUTHEN_LOGIN; + tb.priv_lvl = tac_priv_lvl; + 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_authen_service; + tb.user_len = user_len; + tb.port_len = port_len; + tb.rem_addr_len = rem_addr_len; /* 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 + rem_addr_len + token_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) { + TACSYSLOG((LOG_ERR,\ + "%s: short write on header, wrote %d of %d: %m",\ + __FUNCTION__, w, TAC_PLUS_HDR_SIZE)) + ret = LIBTAC_STATUS_WRITE_ERR; + goto AuthenExit; + } + + /* 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(rem_addr, pkt+pkt_len, rem_addr_len); /* rem addr */ + pkt_len += rem_addr_len; + + bcopy(token, pkt+pkt_len, token_len); /* password */ + pkt_len += token_len; + + /* pkt_len == bodylength ? */ + if (pkt_len != bodylength) { + TACSYSLOG((LOG_ERR, "%s: bodylength %d != pkt_len %d",\ + __FUNCTION__, bodylength, pkt_len)) + ret = LIBTAC_STATUS_ASSEMBLY_ERR; + goto AuthenExit; + } + + /* encrypt the body */ + _tac_crypt(pkt, th, bodylength); + + w = write(fd, pkt, pkt_len); + if (w < 0 || w < pkt_len) { + TACSYSLOG((LOG_ERR,\ + "%s: short write on body, wrote %d of %d: %m",\ + __FUNCTION__, w, pkt_len)) + ret = LIBTAC_STATUS_WRITE_ERR; + } + +AuthenExit: + free(token); + free(pkt); + free(th); + TACDEBUG((LOG_DEBUG, "%s: exit status=%d", __FUNCTION__, ret)) + return(ret); +} /* tac_authen_send */ diff --git a/libtac/lib/author_r.c b/libtac/lib/author_r.c index 3740e6c..8d52c0a 100644 --- a/libtac/lib/author_r.c +++ b/libtac/lib/author_r.c @@ -1,6 +1,6 @@ /* author_r.c - Reads authorization reply from the server. * - * Copyright (C) 2010, Pawel Krawczyk and + * Copyright (C) 2010, Pawel Krawczyk and * Jeroen Nijhof * * This program is free software; you can redistribute it and/or modify @@ -29,166 +29,209 @@ 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; - } + is requested for. + * + * return value: + * < 0 : error status code, see LIBTAC_STATUS_... + * LIBTAC_STATUS_READ_TIMEOUT + * LIBTAC_STATUS_SHORT_HDR + * LIBTAC_STATUS_SHORT_BODY + * LIBTAC_STATUS_PROTOCOL_ERR + * >= 0 : server response, see TAC_PLUS_AUTHOR_STATUS_... + */ +int tac_author_read(int fd, struct areply *re) { + HDR th; + struct author_reply *tb = NULL; + int len_from_header, r, len_from_body; + u_char *pktp = NULL; + char *msg = NULL; + int timeleft; + re->msg = NULL; + + bzero(re, sizeof(struct areply)); + if (tac_readtimeout_enable && + tac_read_wait(fd,tac_timeout*1000,TAC_PLUS_HDR_SIZE,&timeleft) < 0 ) { + + TACSYSLOG((LOG_ERR,\ + "%s: reply timeout after %d secs", __FUNCTION__, tac_timeout)) + re->msg = xstrdup(author_syserr_msg); + re->status = LIBTAC_STATUS_READ_TIMEOUT; + goto AuthorExit; + } + + r = read(fd, &th, TAC_PLUS_HDR_SIZE); + if(r < TAC_PLUS_HDR_SIZE) { + TACSYSLOG((LOG_ERR,\ + "%s: short reply header, read %d of %d: %m", __FUNCTION__,\ + r, TAC_PLUS_HDR_SIZE)) + re->msg = xstrdup(author_syserr_msg); + re->status = LIBTAC_STATUS_SHORT_HDR; + 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 = xstrdup(msg); + re->status = LIBTAC_STATUS_PROTOCOL_ERR; + goto AuthorExit; + } + + len_from_header = ntohl(th.datalength); + tb = (struct author_reply *) xcalloc(1, len_from_header); + + /* read reply packet body */ + if (tac_readtimeout_enable && + tac_read_wait(fd,timeleft,len_from_header,NULL) < 0 ) { + + TACSYSLOG((LOG_ERR,\ + "%s: reply timeout after %d secs", __FUNCTION__, tac_timeout)) + re->msg = xstrdup(author_syserr_msg); + re->status = LIBTAC_STATUS_READ_TIMEOUT; + goto AuthorExit; + } + r = read(fd, tb, len_from_header); + if (r < len_from_header) { + TACSYSLOG((LOG_ERR,\ + "%s: short reply body, read %d of %d: %m", __FUNCTION__,\ + r, len_from_header)) + re->msg = xstrdup(author_syserr_msg); + re->status = LIBTAC_STATUS_SHORT_BODY; + 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 = (u_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) { + TACSYSLOG((LOG_ERR,\ + "%s: inconsistent reply body, incorrect key?",\ + __FUNCTION__)) + re->msg = xstrdup(protocol_err_msg); + re->status = LIBTAC_STATUS_PROTOCOL_ERR; + 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); + msg[(int) tb->msg_len] = '\0'; + re->msg = msg; /* freed by caller */ + } + + /* 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); + smsg[(int) tb->data_len] = '\0'; + TACSYSLOG((LOG_ERR, "%s: reply message: %s", __FUNCTION__,smsg)) + free(smsg); + } + + /* prepare status */ + switch(tb->status) { + /* success conditions */ + /* XXX support optional vs mandatory arguments */ + case TAC_PLUS_AUTHOR_STATUS_PASS_REPL: + tac_free_attrib(&re->attr); + + case TAC_PLUS_AUTHOR_STATUS_PASS_ADD: + { + u_char *argp; + + if(!re->msg) re->msg=xstrdup(author_ok_msg); + re->status=tb->status; + + /* add attributes received to attribute list returned to + the client */ + pktp = (u_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 points to current argument length */ + for(r=0; r < tb->arg_cnt; r++) { + char buff[256]; + char *sep; + char *value; + char sepchar = '='; + + bcopy(argp, buff, (int)*pktp); + buff[(int)*pktp] = '\0'; + sep = strchr(buff, '='); + if ( sep == NULL ) { + sep = strchr(buff, '*'); + } + if(sep == NULL) { + TACSYSLOG((LOG_WARNING,\ + "AUTHOR_STATUS_PASS_ADD/REPL: av pair does not contain a separator: %s",\ + buff)) + /* now buff points to attribute name, make value "" + treat as "name=" */ + value = ""; + } else { + sepchar = *sep; + *sep = '\0'; + value = ++sep; + /* now buff points to attribute name, + value to the attribute value */ + } + tac_add_attrib_pair(&re->attr, buff, sepchar, value); + argp += *pktp; + pktp++; + } + } + + goto AuthorExit; + break; + } + + TACDEBUG((LOG_DEBUG, "%s: authorization failed, server reply status=%d",\ + __FUNCTION__, tb->status)) + switch (tb->status) { + /* authorization failure conditions */ + /* failing to follow is allowed by RFC, page 23 */ + case TAC_PLUS_AUTHOR_STATUS_FOLLOW: + case TAC_PLUS_AUTHOR_STATUS_FAIL: + if(!re->msg) re->msg = xstrdup(author_fail_msg); + re->status=TAC_PLUS_AUTHOR_STATUS_FAIL; + break; + /* error conditions */ + case TAC_PLUS_AUTHOR_STATUS_ERROR: + default: + if(!re->msg) re->msg = xstrdup(author_err_msg); + re->status=TAC_PLUS_AUTHOR_STATUS_ERROR; + } AuthorExit: - - free(tb); - TACDEBUG((LOG_DEBUG, "%s: server replied '%s'", __FUNCTION__, \ - re->msg)) - + free(tb); + TACDEBUG((LOG_DEBUG, "%s: exit status=%d, status message \"%s\"",\ + __FUNCTION__, re->status, re->msg != NULL ? re->msg : "")) + return(re->status); } diff --git a/libtac/lib/author_s.c b/libtac/lib/author_s.c index 0bf6518..53b7c89 100644 --- a/libtac/lib/author_s.c +++ b/libtac/lib/author_s.c @@ -1,6 +1,6 @@ /* author_s.c - Send authorization request to the server. * - * Copyright (C) 2010, Pawel Krawczyk and + * Copyright (C) 2010, Pawel Krawczyk and * Jeroen Nijhof * * This program is free software; you can redistribute it and/or modify @@ -25,128 +25,140 @@ /* 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); + * + * return value: + * 0 : success + * < 0 : error status code, see LIBTAC_STATUS_... + * LIBTAC_STATUS_WRITE_ERR + * LIBTAC_STATUS_WRITE_TIMEOUT (pending impl) + * LIBTAC_STATUS_ASSEMBLY_ERR (pending impl) + */ +int tac_author_send(int fd, const char *user, char *tty, char *rem_addr, + struct tac_attrib *attr) { + + HDR *th; + struct author tb; + u_char user_len, port_len, rem_addr_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 = NULL; /* packet building pointer */ + /* u_char *pktp; */ /* obsolete */ + int ret = 0; + + th=_tac_req_header(TAC_PLUS_AUTHOR, 0); + + /* set header options */ + th->version=TAC_PLUS_VER_0; + th->encryption=tac_encryption ? TAC_PLUS_ENCRYPTED_FLAG : TAC_PLUS_UNENCRYPTED_FLAG; + + TACDEBUG((LOG_DEBUG, "%s: user '%s', tty '%s', rem_addr '%s', encrypt: %s", \ + __FUNCTION__, user, \ + tty, rem_addr, tac_encryption ? "yes" : "no")) + + user_len = (u_char) strlen(user); + port_len = (u_char) strlen(tty); + rem_addr_len = (u_char) strlen(rem_addr); + + tb.authen_method = tac_authen_method; + tb.priv_lvl = tac_priv_lvl; + 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_authen_service; + tb.user_len = user_len; + tb.port_len = port_len; + tb.rem_addr_len = rem_addr_len; + + /* 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 = (u_char*) 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); + 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); + pktl = pkt_len; \ + pkt_len += len; \ + pkt = (u_char*) xrealloc(pkt, pkt_len); \ + bcopy(data, pkt + pktl, len); + + /* fill user and port fields */ + PUTATTR(user, user_len) + PUTATTR(tty, port_len) + PUTATTR(rem_addr, rem_addr_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) { + TACSYSLOG((LOG_ERR,\ + "%s: short write on header, wrote %d of %d: %m",\ + __FUNCTION__, w, TAC_PLUS_HDR_SIZE)) + ret = LIBTAC_STATUS_WRITE_ERR; + goto AuthorExit; + } + + /* encrypt packet body */ + _tac_crypt(pkt, th, pkt_len); + + /* write body */ + w = write(fd, pkt, pkt_len); + if (w < pkt_len) { + TACSYSLOG((LOG_ERR,\ + "%s: short write on body, wrote %d of %d: %m",\ + __FUNCTION__, w, pkt_len)) + ret = LIBTAC_STATUS_WRITE_ERR; + } + +AuthorExit: + free(pkt); + free(th); + TACDEBUG((LOG_DEBUG, "%s: exit status=%d", __FUNCTION__, ret)) + return(ret); } diff --git a/libtac/lib/connect.c b/libtac/lib/connect.c index c65edf8..bbbb270 100644 --- a/libtac/lib/connect.c +++ b/libtac/lib/connect.c @@ -1,6 +1,6 @@ /* connect.c - Open connection to server. * - * Copyright (C) 2010, Pawel Krawczyk and + * Copyright (C) 2010, Pawel Krawczyk and * Jeroen Nijhof * * This program is free software; you can redistribute it and/or modify @@ -26,7 +26,7 @@ #include #ifdef _AIX - #include + #include #endif #include "tacplus.h" @@ -38,126 +38,161 @@ int tac_timeout = 5; /* Returns file descriptor of open connection to the first available server from list passed in server table. -*/ + + * return value: + * >= 0 : valid fd + * < 0 : error status code, see LIBTAC_STATUS_... + */ int tac_connect(struct addrinfo **server, char **key, int servers) { - int tries = 0; - int fd, flags, retval; - fd_set readfds, writefds; - struct timeval tv; - socklen_t len; - struct sockaddr_storage addr; - - 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 and write */ - if(select(fd+1, &readfds, &writefds, NULL, &tv) < 1) { - syslog(LOG_WARNING, - "%s: connection failed 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; - } else { - /* check with getpeername if we have a valid connection */ - len = sizeof addr; - if(getpeername(fd, (struct sockaddr*)&addr, &len) == -1) { - syslog(LOG_WARNING, - "%s: connection failed 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))); - - /* set current tac_secret */ - tac_secret = key[tries]; - return(fd); - } - - /* all attempts failed */ - return(-1); + int tries; + int fd=-1; + + if(servers == 0 || server == NULL) { + TACSYSLOG((LOG_ERR, "%s: no TACACS+ servers defined", __FUNCTION__)) + } else { + for ( tries = 0; tries < servers; tries++ ) { + if((fd=tac_connect_single(server[tries], key[tries])) >= 0 ) { + /* tac_secret was set in tac_connect_single on success */ + break; + } + } + } + + /* all attempts failed if fd is still < 0 */ + TACDEBUG((LOG_DEBUG, "%s: exit status=%d",__FUNCTION__, fd)) + return(fd); } /* tac_connect */ +/* return value: + * >= 0 : valid fd + * < 0 : error status code, see LIBTAC_STATUS_... + */ int tac_connect_single(struct addrinfo *server, char *key) { - struct addrinfo *tmpaddr[1]; - tmpaddr[0] = server; - char *tmpkey[1]; - tmpkey[0] = key; - return(tac_connect(tmpaddr, tmpkey, 1)); + int retval = LIBTAC_STATUS_CONN_ERR; /* default retval */ + int fd = -1; + int flags, rc; + fd_set readfds, writefds; + struct timeval tv; + socklen_t len; + struct sockaddr_storage addr; + char *ip = NULL; + + if(server == NULL) { + TACSYSLOG((LOG_ERR, "%s: no TACACS+ server defined", __FUNCTION__)) + return LIBTAC_STATUS_CONN_ERR; + } + + /* format server address into a string for use in messages */ + ip = tac_ntop(server->ai_addr, 0); + + if((fd=socket(server->ai_family, server->ai_socktype, server->ai_protocol)) < 0) { + TACSYSLOG((LOG_ERR,"%s: socket creation error", __FUNCTION__)) + return LIBTAC_STATUS_CONN_ERR; + } + + /* get flags for restoration later */ + flags = fcntl(fd, F_GETFL, 0); + + /* put socket in non blocking mode for timeout support */ + if( fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1 ) { + TACSYSLOG((LOG_ERR, "%s: cannot set socket non blocking",\ + __FUNCTION__)) + return LIBTAC_STATUS_CONN_ERR; + } + + rc = connect(fd, server->ai_addr, server->ai_addrlen); + if((rc == -1) && (errno != EINPROGRESS)) { + TACSYSLOG((LOG_ERR,\ + "%s: connection to %s failed: %m", __FUNCTION__, ip)) + return LIBTAC_STATUS_CONN_ERR; + } + + /* set fds for select */ + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_SET(fd, &readfds); + FD_SET(fd, &writefds); + + /* set timeout seconds */ + tv.tv_sec = tac_timeout; + tv.tv_usec = 0; + + /* check if socket is ready for read and write */ + rc = select(fd+1, &readfds, &writefds, NULL, &tv); + + /* timeout */ + if ( rc == 0 ) { + return LIBTAC_STATUS_CONN_TIMEOUT; + } + + /* some other error or interrupt before timeout */ + if ( rc < 0 ) { + TACSYSLOG((LOG_ERR,\ + "%s: connection failed with %s: %m", __FUNCTION__, ip)) + return LIBTAC_STATUS_CONN_ERR; + } + + /* check with getpeername if we have a valid connection */ + len = sizeof addr; + if(getpeername(fd, (struct sockaddr*)&addr, &len) == -1) { + TACSYSLOG((LOG_ERR,\ + "%s: connection failed with %s: %m", __FUNCTION__, ip)) + return LIBTAC_STATUS_CONN_ERR; + } + + /* restore flags on socket - flags was set only when fd >= 0 */ + if(fcntl(fd, F_SETFL, flags) == -1) { + TACSYSLOG((LOG_ERR, "%s: cannot restore socket flags: %m",\ + __FUNCTION__)) + return LIBTAC_STATUS_CONN_ERR; + } + + /* connected ok */ + TACDEBUG((LOG_DEBUG, "%s: connected to %s", __FUNCTION__, ip)) + retval = fd; + + /* set current tac_secret */ + tac_secret = key; + + free(ip); + + /* if valid fd, but error experienced after open, close fd */ + if ( fd >= 0 && retval < 0 ) { + close(fd); + } + + TACDEBUG((LOG_DEBUG, "%s: exit status=%d (fd=%d)",\ + __FUNCTION__, retval < 0 ? retval:0, fd)) + return(retval); } /* 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; +/* return value: + * ptr to char* with format IP address + * must be freed by caller + */ +char *tac_ntop(const struct sockaddr *sa, size_t unused) { + char portstr[7]; + char *str = (char *) xcalloc(1, INET6_ADDRSTRLEN+sizeof(portstr)); + + switch(sa->sa_family) { + case AF_INET: + inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr), + str, INET_ADDRSTRLEN); + snprintf(portstr, sizeof(portstr), ":%hu", + htons(((struct sockaddr_in *)sa)->sin_port)); + strncat(str, portstr, sizeof(portstr)); + break; + case AF_INET6: + inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), + str, INET6_ADDRSTRLEN); + snprintf(portstr, sizeof(portstr), ":%hu", + htons(((struct sockaddr_in6 *)sa)->sin6_port)); + strncat(str, portstr, sizeof(portstr)); + break; + default: + strncpy(str, "Unknown AF", INET6_ADDRSTRLEN); + } + return str; } /* tac_ntop */ diff --git a/libtac/lib/cont_s.c b/libtac/lib/cont_s.c index 17894cf..a438a63 100644 --- a/libtac/lib/cont_s.c +++ b/libtac/lib/cont_s.c @@ -24,69 +24,83 @@ /* this function sends a continue packet do TACACS+ server, asking * for validation of given password + * + * return value: + * 0 : success + * < 0 : error status code, see LIBTAC_STATUS_... + * LIBTAC_STATUS_WRITE_ERR + * LIBTAC_STATUS_WRITE_TIMEOUT (pending impl) + * LIBTAC_STATUS_ASSEMBLY_ERR */ -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); +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 = NULL; + + th = _tac_req_header(TAC_PLUS_AUTHEN, 1); + + /* 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_FLAG : TAC_PLUS_UNENCRYPTED_FLAG; + + /* 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) { + TACSYSLOG((LOG_ERR, "%s: short write on header, wrote %d of %d: %m",\ + __FUNCTION__, w, TAC_PLUS_HDR_SIZE)) + ret=LIBTAC_STATUS_WRITE_ERR; + goto ContExit; + } + + /* 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) { + TACSYSLOG((LOG_ERR,\ + "%s: bodylength %d != pkt_len %d",\ + __FUNCTION__, bodylength, pkt_len)) + ret=LIBTAC_STATUS_ASSEMBLY_ERR; + goto ContExit; + } + + /* encrypt the body */ + _tac_crypt(pkt, th, bodylength); + + w = write(fd, pkt, pkt_len); + if (w < 0 || w < pkt_len) { + TACSYSLOG((LOG_ERR,\ + "%s: short write on body, wrote %d of %d: %m",\ + __FUNCTION__, w, pkt_len)) + ret=LIBTAC_STATUS_WRITE_ERR; + } + +ContExit: + + free(pkt); + free(th); + + TACDEBUG((LOG_DEBUG, "%s: exit status=%d", __FUNCTION__, ret)) + return(ret); } /* tac_cont_send */ diff --git a/libtac/lib/crypt.c b/libtac/lib/crypt.c index ae726fc..645cf8e 100644 --- a/libtac/lib/crypt.c +++ b/libtac/lib/crypt.c @@ -1,6 +1,6 @@ /* crypt.c - TACACS+ encryption related functions * - * Copyright (C) 2010, Pawel Krawczyk and + * Copyright (C) 2010, Pawel Krawczyk and * Jeroen Nijhof * * This program is free software; you can redistribute it and/or modify @@ -28,80 +28,78 @@ 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; + 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); + /* 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; isession_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); + /* 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; - } + /* 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 - */ + 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 */ + 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); + MD5Final(&mdcontext); /* correct for pppd-2.2.0g */ + bcopy(&mdcontext.digest, pad+pp, MD5_LEN); #endif - pp+=MD5_LEN; - } + pp += MD5_LEN; + } - free(buf); - return(pad); + free(buf); + return(pad); -} /* _tac_md5_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; + int i; + u_char *pad; - /* null operation if no encryption requested */ - if(th->encryption == TAC_PLUS_ENCRYPTED) { + /* null operation if no encryption requested */ + if(th->encryption == TAC_PLUS_ENCRYPTED_FLAG) { + pad = _tac_md5_pad(length, th); - pad=_tac_md5_pad(length, th); - - for(i=0; i and + * Copyright (C) 2010, Pawel Krawczyk and * Jeroen Nijhof * * This program is free software; you can redistribute it and/or modify @@ -31,23 +31,21 @@ * 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 */ - + if(th->type != type) { + TACSYSLOG((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)) { + TACSYSLOG((LOG_ERR, "%s: not a reply - seq_no %d != {2,4}",\ + __FUNCTION__, th->seq_no)) + return(protocol_err_msg); + } /* else if(ntohl(th->session_id) != session_id) { + TACSYSLOG((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 index 5fdd8f2..bb24918 100644 --- a/libtac/lib/header.c +++ b/libtac/lib/header.c @@ -1,6 +1,6 @@ /* header.c - Create pre-filled header for TACACS+ request. * - * Copyright (C) 2010, Pawel Krawczyk and + * Copyright (C) 2010, Pawel Krawczyk and * Jeroen Nijhof * * This program is free software; you can redistribute it and/or modify @@ -31,7 +31,7 @@ int session_id; /* Encryption flag. */ -int tac_encryption; +int tac_encryption = 0; /* Pointer to TACACS+ shared secret string. */ char *tac_secret = ""; @@ -39,6 +39,20 @@ char *tac_secret = ""; /* Pointer to TACACS+ shared login string. */ char *tac_login = "pap"; +/* priv_lvl */ +int tac_priv_lvl = TAC_PLUS_PRIV_LVL_MIN; + +/* Authentication Method */ +int tac_authen_method = TAC_PLUS_AUTHEN_METH_TACACSPLUS; + +/* Service requesting authentication */ +int tac_authen_service = TAC_PLUS_AUTHEN_SVC_PPP; + +/* additional runtime flags */ + +int tac_debug_enable = 0; +int tac_readtimeout_enable = 0; + /* Returns pre-filled TACACS+ packet header of given type. * 1. you MUST fill th->datalength and th->version * 2. you MAY fill th->encryption @@ -47,19 +61,20 @@ char *tac_login = "pap"; * field depends on the TACACS+ request type and thus it * cannot be predefined. */ -HDR *_tac_req_header(u_char type) { - HDR *th; +HDR *_tac_req_header(u_char type, int cont_session) { + HDR *th; - th=(HDR *) xcalloc(1, TAC_PLUS_HDR_SIZE); + 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; + /* preset some packet options in header */ + th->type=type; + th->seq_no=1; /* always 1 for request */ + th->encryption=TAC_PLUS_ENCRYPTED_FLAG; - /* make session_id from pseudo-random number */ - session_id = magic(); - th->session_id = htonl(session_id); + /* make session_id from pseudo-random number */ + if (!cont_session) + session_id = magic(); + th->session_id = htonl(session_id); - return(th); + return(th); } diff --git a/libtac/lib/magic.c b/libtac/lib/magic.c index 7ac5621..3b809eb 100644 --- a/libtac/lib/magic.c +++ b/libtac/lib/magic.c @@ -40,7 +40,8 @@ extern void srand48 __P((long)); /* on Linux we use /dev/urandom as random numbers source I find it really cool :) */ -int rfd = 0; /* /dev/urandom */ +int rfd = -1; /* /dev/urandom */ +int magic_inited = 0; #endif /* @@ -56,20 +57,16 @@ magic_init() long seed; struct timeval t; + magic_inited = 1; #ifdef __linux__ - rfd = open("/dev/urandom", O_RDONLY); - if(rfd != -1) - return; - else { - rfd = 0; + rfd = open("/dev/urandom", O_RDONLY); + if(rfd != -1) + return; #endif - /* if /dev/urandom fails, we try traditional method */ + /* 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 } /* @@ -79,16 +76,18 @@ u_int32_t magic() { #ifdef __linux__ - u_int32_t ret = 0; - int bytes = 0; + u_int32_t ret = 0; + int bytes = 0; + + if (magic_inited == 0 ) + magic_init(); - if(rfd) - { - bytes = read(rfd, &ret, sizeof(ret)); - return(ret); - } + if(rfd > -1) { + bytes = read(rfd, &ret, sizeof(ret)); + return(ret); + } else - return (u_int32_t) mrand48(); + return (u_int32_t) mrand48(); #else return (u_int32_t) mrand48(); #endif diff --git a/libtac/lib/magic.h b/libtac/lib/magic.h index ac626b3..44a8de9 100644 --- a/libtac/lib/magic.h +++ b/libtac/lib/magic.h @@ -18,9 +18,15 @@ * See `CHANGES' file for revision history. */ +#ifndef _MAGIC_H +#define _MAGIC_H #ifndef __linux__ - #include "cdefs.h" + #include "cdefs.h" #endif +__BEGIN_DECLS void magic_init __P((void)); /* Initialize the magic number generator */ u_int32_t magic __P((void)); /* Returns the next magic number */ +__END_DECLS + +#endif diff --git a/libtac/lib/md5.c b/libtac/lib/md5.c index cf6799c..7ae59ff 100644 --- a/libtac/lib/md5.c +++ b/libtac/lib/md5.c @@ -22,17 +22,17 @@ #include "md5.h" /* forward declaration */ -static void Transform (); +static void Transform __P((UINT4 *buf, UINT4 *in)); 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 + 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 */ @@ -47,25 +47,25 @@ static unsigned char PADDING[64] = { /* 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); \ - } + {(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); \ - } + {(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); \ - } + {(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); \ - } + {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } #ifdef __STDC__ #define UL(x) x##U @@ -76,201 +76,190 @@ static unsigned char PADDING[64] = { /* 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; +void MD5Init (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; + /* 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; +void MD5Update ( MD5_CTX *mdContext, unsigned char *inBuf, + unsigned int inLen) { - /* compute number of bytes mod 64 */ - mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + UINT4 in[16]; + int mdi; + unsigned int i, ii; - /* 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); + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); - while (inLen--) { - /* add new character to buffer, increment mdi */ - mdContext->in[mdi++] = *inBuf++; + /* 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); - /* 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; + 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; +void MD5Final (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]; + /* 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); + /* 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); + /* 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) | + /* 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); + 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); + /* 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]; +static void Transform ( UINT4 *buf, UINT4 *in) { + UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; - /* Round 1 */ + /* 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 */ + 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 */ + /* 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 */ + 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 */ + /* 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 */ + 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 */ + /* 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 */ + 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; + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; } diff --git a/libtac/lib/md5.h b/libtac/lib/md5.h index fc314ed..a1cbfbd 100644 --- a/libtac/lib/md5.h +++ b/libtac/lib/md5.h @@ -25,15 +25,17 @@ 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 */ + 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 (); +__BEGIN_DECLS +void MD5Init __P((MD5_CTX*)); +void MD5Update __P((MD5_CTX*, unsigned char*, UINT4)); +void MD5Final __P((unsigned char[], MD5_CTX*)); +__END_DECLS #define MD5_LEN 16 diff --git a/libtac/lib/messages.c b/libtac/lib/messages.c index 8a1ae3e..d24a809 100644 --- a/libtac/lib/messages.c +++ b/libtac/lib/messages.c @@ -1,6 +1,6 @@ /* messages.c - Various messages returned to user. * - * Copyright (C) 2010, Pawel Krawczyk and + * Copyright (C) 2010, Pawel Krawczyk and * Jeroen Nijhof * * This program is free software; you can redistribute it and/or modify @@ -19,8 +19,12 @@ * 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."; +char *protocol_err_msg = "(Protocol error)"; +char *author_ok_msg = "(Service granted)"; +char *author_fail_msg = "(Service not allowed)"; +char *author_err_msg = "(Service not allowed. Server error)"; +char *author_syserr_msg = "(Authorization system error)"; +char *acct_ok_msg = "(Accounted ok)"; +char *acct_fail_msg = "(Accounting failed)"; +char *acct_err_msg = "(Accounting failed. Server error)"; +char *acct_syserr_msg = "(Accounting system error)"; diff --git a/libtac/lib/messages.h b/libtac/lib/messages.h index 37f2402..041195f 100644 --- a/libtac/lib/messages.h +++ b/libtac/lib/messages.h @@ -1,6 +1,6 @@ /* messages.h * - * Copyright (C) 2010, Pawel Krawczyk and + * Copyright (C) 2010, Pawel Krawczyk and * Jeroen Nijhof * * This program is free software; you can redistribute it and/or modify @@ -19,8 +19,17 @@ * See `CHANGES' file for revision history. */ -extern char *system_err_msg; +#ifndef _MESSAGES_H +#define _MESSAGES_H + extern char *protocol_err_msg; extern char *author_ok_msg; extern char *author_fail_msg; extern char *author_err_msg; +extern char *author_syserr_msg; +extern char *acct_ok_msg; +extern char *acct_fail_msg; +extern char *acct_err_msg; +extern char *acct_syserr_msg; + +#endif diff --git a/libtac/lib/read_wait.c b/libtac/lib/read_wait.c new file mode 100644 index 0000000..e855ac9 --- /dev/null +++ b/libtac/lib/read_wait.c @@ -0,0 +1,119 @@ +/* read_wait.c - Wait for data to read on a fd. + * + * Copyright (C) 2011, Darren Besler (dbesler@beehive.mb.ca) + * + * 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 +#include +#include +#include + +#include "tacplus.h" +#include "libtac.h" + +static int delta_msecs(struct timeval *newer, struct timeval *older) { + long deltasecs, deltausecs; + struct timeval now; + + if (newer == NULL) { + gettimeofday(&now, NULL); + newer = &now; + } + + deltasecs = newer->tv_sec - older->tv_sec; + deltausecs = newer->tv_usec - older->tv_usec; + if ( newer->tv_usec < older->tv_usec ) { + deltasecs--; + deltausecs = (1000000+newer->tv_usec) - older->tv_usec; + } else { + deltausecs = newer->tv_usec - older->tv_usec; + } + return (deltasecs*1000)+(deltausecs/1000); +} + + +/* + * tac_read_wait + * + * Parms: + * fd - open fd to wait on till data avail, or timeout + * timeout - maximum time to wait in milliseconds + * size - amount of data to wait for + * 0 : any amount of data + * >0 : amount of data to wait for + * timeleft - return of time left from timeout + * + * Returns: + * 0 - data avail, no timeout + * -1 - timeout + * n - errno + */ + +int tac_read_wait(int fd, int timeout, int size, int *time_left) { + int retval = 0; + int remaining; + struct pollfd fds[1]; + + struct timeval start; + + gettimeofday(&start, NULL); + + /* setup for read timeout. + * will use poll() as it provides greatest compatibility + * vs setsockopt(SO_RCVTIMEO) which isn't supported on Solaris + */ + + remaining = timeout; /* in msecs */ + + fds[0].fd = fd; + fds[0].events = POLLIN; + + while (remaining > 0) { + int rc; + int avail = 0; + rc = poll(fds, 1, remaining); + remaining -= delta_msecs(NULL, &start); + if ( time_left != NULL ) { + *time_left = remaining > 0 ? remaining : 0; + } + + /* why did poll return */ + if (rc == 0) { /* Receive timeout */ + retval = -1; + break; + } + + if (rc > 0) { /* there is data available */ + if (size > 0 && /* check for enuf available? */ + ioctl(fd,FIONREAD,(char*)&avail) == 0 && avail < size) { + continue; /* not enuf yet, wait for more */ + } else { + break; + } + } + + if (rc < 0 && errno == EINTR) { // interrupt + continue; + } + + /* all other conditions is an error */ + retval = errno; + break; + } + return retval; +} /* read_wait */ diff --git a/libtac/lib/version.c b/libtac/lib/version.c index ccf20ee..16c8c7b 100644 --- a/libtac/lib/version.c +++ b/libtac/lib/version.c @@ -1,6 +1,6 @@ /* version.c - TACACS+ library version. * - * Copyright (C) 2010, Pawel Krawczyk and + * Copyright (C) 2010, Pawel Krawczyk and * Jeroen Nijhof * * This program is free software; you can redistribute it and/or modify @@ -20,5 +20,5 @@ */ int tac_ver_major = 1; -int tac_ver_minor = 6; -int tac_ver_patch = 5; /* patchlevel */ +int tac_ver_minor = 7; +int tac_ver_patch = 1; /* patchlevel */ diff --git a/libtac/lib/xalloc.c b/libtac/lib/xalloc.c index 88bbb28..a8e8302 100644 --- a/libtac/lib/xalloc.c +++ b/libtac/lib/xalloc.c @@ -1,7 +1,7 @@ /* xalloc.c - Failsafe memory allocation functions. * Taken from excellent glibc.info ;) * - * Copyright (C) 2010, Pawel Krawczyk and + * Copyright (C) 2010, Pawel Krawczyk and * Jeroen Nijhof * * This program is free software; you can redistribute it and/or modify @@ -20,24 +20,34 @@ * See `CHANGES' file for revision history. */ -#include -#include +#include "libtac.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; + register void *val = calloc(nmemb, size); + if(val == 0) { + TACSYSLOG((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; + register void *val = realloc(ptr, size); + if(val == 0) { + TACSYSLOG((LOG_ERR, "%s: realloc(%u) failed", __FUNCTION__, (unsigned) size)) + exit(1); + } + return val; +} + +char *xstrdup(char *s) { + char *p; + if (s == NULL) return NULL; + + if ( (p = strdup(s)) == NULL ) { + TACSYSLOG((LOG_ERR, "%s: strdup(%s) failed: %m", __FUNCTION__, s)) + exit(1); + } + return p; } diff --git a/libtac/lib/xalloc.h b/libtac/lib/xalloc.h index da02dfa..3573567 100644 --- a/libtac/lib/xalloc.h +++ b/libtac/lib/xalloc.h @@ -1,6 +1,6 @@ /* xalloc.h * - * Copyright (C) 2010, Pawel Krawczyk and + * Copyright (C) 2010, Pawel Krawczyk and * Jeroen Nijhof * * This program is free software; you can redistribute it and/or modify @@ -19,5 +19,13 @@ * See `CHANGES' file for revision history. */ +#ifndef _XALLOC_H +#define _XALLOC_H + +__BEGIN_DECLS extern void *xcalloc(size_t nmemb, size_t size); extern void *xrealloc(void *ptr, size_t size); +extern char *xstrdup(char *s); +__END_DECLS + +#endif -- cgit v1.2.3