Enhance TACACS+ library to fully support authorization requests in

addition to existing authentication.  No change to the existing
APIs to preseve both binary and API compatibility, so I am not
inclined to bump the library version number unless someone thinks
this is necessary.

Submitted by:	Paul Fraley <fraley@juniper.net>
MFC after:	2 weeks
This commit is contained in:
pst 2002-09-25 23:18:51 +00:00
parent 91c878cfae
commit d5c1216e90
5 changed files with 485 additions and 64 deletions

View File

@ -1,4 +1,4 @@
# Copyright 1998 Juniper Networks, Inc.
# Copyright (c) 1998, 2001, Juniper Networks, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without

View File

@ -1,4 +1,4 @@
.\" Copyright 1998 Juniper Networks, Inc.
.\" Copyright (c) 1998, 2001, 2002, Juniper Networks, Inc.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@ -35,11 +35,19 @@
.Ft int
.Fn tac_add_server "struct tac_handle *h" "const char *host" "int port" "const char *secret" "int timeout" "int flags"
.Ft void
.Fn tac_clear_avs "struct tac_handle *h"
.Ft void
.Fn tac_close "struct tac_handle *h"
.Ft int
.Fn tac_config "struct tac_handle *h" "const char *path"
.Ft int
.Fn tac_create_authen "struct tac_handle *h" "int action" "int type" "int service"
.Ft int
.Fn tac_create_author "struct tac_handle *h" "int method" "int type" "int service"
.Ft char *
.Fn tac_get_av "struct tac_handle *h" "u_int index"
.Ft char *
.Fn tac_get_av_value "struct tac_handle *h" "const char *attribute"
.Ft void *
.Fn tac_get_data "struct tac_handle *h" "size_t *len"
.Ft char *
@ -49,6 +57,10 @@
.Ft int
.Fn tac_send_authen "struct tac_handle *h"
.Ft int
.Fn tac_send_author "struct tac_handle *h"
.Ft int
.Fn tac_set_av "struct tac_handle *h" "u_int index" "const char *av_pair"
.Ft int
.Fn tac_set_data "struct tac_handle *h" "const void *data" "size_t data_len"
.Ft int
.Fn tac_set_msg "struct tac_handle *h" "const char *msg"
@ -69,7 +81,7 @@ library implements the client side of the TACACS+ network access
control protocol. TACACS+ allows clients to perform authentication,
authorization, and accounting by means of network requests to remote
servers. This library currently supports only the authentication
portion of the protocol.
and authorization portion of the protocol.
.Sh INITIALIZATION
To use the library, an application must first call
.Fn tac_open
@ -158,10 +170,22 @@ arguments must be set to appropriate values as defined in the
TACACS+ protocol specification. The
.Aq taclib.h
header file contains symbolic constants for these values.
.Pp
After creating a request with
.Fn tac_create_authen ,
.Sh CREATING A TACACS+ AUTHORIZATION REQUEST
To begin constructing a new authorization request, call
.Fn tac_create_author .
The
.Va method ,
.Va type ,
and
.Va service
arguments must be set to appropriate values as defined in the
TACACS+ protocol specification. The
.Aq taclib.h
header file contains symbolic constants for these values.
.Sh SETTING OPTIONAL PARAMETERS ON A REQUEST
After creating a request,
various optional parameters may be attached to it through calls to
.Fn tac_set_av ,
.Fn tac_set_data ,
.Fn tac_set_port ,
.Fn tac_set_priv ,
@ -174,9 +198,21 @@ them. By default, each of these parameters is empty except for the
privilege level, which defaults to
.Ql USER
privilege.
.Pp
.Fn tac_set_av
only applies to the context of an authorization request. The format
for an attribute value pair is defined in the TACACS+ protocol
specification. The index specified can be any value between 0 and
255 inclusive and indicates the position in the list to place the
attribute value pair. Calling
.Fn tac_set_av
with same index twice effectively replaces the value at that position.
Use
.Fn tac_clear_avs
to clear all attribute value pairs that may have been set.
.Sh SENDING THE AUTHENTICATION REQUEST AND RECEIVING THE RESPONSE
After the TACACS+ request has been constructed, it is sent by means
of
After the TACACS+ authentication request has been constructed, it is
sent by means of
.Fn tac_send_authen .
This function connects to a server if not already connected, sends
the request, and waits for a reply. On failure,
@ -211,7 +247,7 @@ include:
The only flag is the no-echo flag, which can be tested using the
macro
.Fn TAC_AUTHEN_NOECHO .
.Sh EXTRACTING INFORMATION FROM THE SERVER'S RESPONSE
.Sh EXTRACTING INFORMATION FROM THE SERVER'S AUTHENTICATION RESPONSE
An authentication response packet from the server may contain a
server message, a data string, or both. After a successful call to
.Fn tac_send_authen ,
@ -264,6 +300,63 @@ or
.Dv TAC_AUTHEN_STATUS_GETPASS .
The application should send further CONTINUEs until some other
status is received from the server.
.Sh SENDING THE AUTHORIZATION REQUEST AND RECEIVING THE RESPONSE
After the TACACS+ authorization request has been constructed, it
is sent by means of
.Fn tac_send_author .
This function connects to a server if not already connected, sends
the request, and waits for a reply. On failure,
.Fn tac_send_author
returns -1. Otherwise, it returns the TACACS+ status code and
number of attribute value (AV) pairs received packed into an
integer value. The status can be extracted using the macro
.Fn TAC_AUTHOR_STATUS .
Possible status codes, defined in
.Aq taclib.h ,
include:
.Pp
.Bl -item -compact -offset indent
.It
.Dv TAC_AUTHOR_STATUS_PASS_ADD
.It
.Dv TAC_AUTHOR_STATUS_PASS_REPL
.It
.Dv TAC_AUTHOR_STATUS_FAIL
.It
.Dv TAC_AUTHOR_STATUS_ERROR
.El
.Pp
The number of AV pairs received is obtained using
.Fn TAC_AUTHEN_AV_COUNT .
.Sh EXTRACTING INFORMATION FROM THE SERVER'S AUTHORIZATION RESPONSE
Like an authentication response packet, an authorization
response packet from the
server may contain a server message, a data string, or both. Refer
to EXTRACTING INFORMATION FROM THE SERVER'S AUTHENTICATION RESPONSE
for instruction on extraction of those values.
.Pp
An authorization response packet from the server may also contain
attribute value (AV) pairs. To extract these, use
.Fn tac_get_av
or
.Fn tac_get_av_value .
.Fn tac_get_av
takes the index of the AV pair as it is positioned in the list.
The indexes start at 0 (use
.Fn TAC_AUTHEN_AV_COUNT
on the return value of
.Fn tac_send_author
to get the total number of items in this list).
Alternatively,
.Fn tac_get_av_value
can be used.
.Fn tac_get_av_value
takes the attribute name and returns the
corresponding value only, not the AV pair. These functions return
dynamically-allocated copies of the information from the packet.
The caller is responsible for freeing the copies when it no longer
needs them. The data returned from these functions is guaranteed
to be terminated by a null byte.
.Sh OBTAINING ERROR MESSAGES
Those functions which accept a
.Va struct tac_handle *
@ -291,8 +384,14 @@ which can be retrieved using
.It
.Fn tac_create_authen
.It
.Fn tac_create_author
.It
.Fn tac_send_authen
.It
.Fn tac_send_author
.It
.Fn tac_set_av
.It
.Fn tac_set_data
.It
.Fn tac_set_msg
@ -316,6 +415,10 @@ and record an error message which can be retrieved using
.Pp
.Bl -item -offset indent -compact
.It
.Fn tac_get_av
.It
.Fn tac_get_av_pair
.It
.Fn tac_get_data
.It
.Fn tac_get_msg
@ -345,6 +448,8 @@ without recording an error message.
.Sh AUTHORS
This software was written by
.An John Polstra ,
and
.An Paul Fraley ,
and donated to the
.Fx
project by Juniper Networks, Inc.

View File

@ -1,5 +1,5 @@
/*-
* Copyright 1998 Juniper Networks, Inc.
* Copyright (c) 1998, 2001, 2002, Juniper Networks, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -51,7 +51,7 @@ static int add_str_8(struct tac_handle *, u_int8_t *,
struct clnt_str *);
static int add_str_16(struct tac_handle *, u_int16_t *,
struct clnt_str *);
static int authen_version(int, int);
static int protocol_version(int, int, int);
static void close_connection(struct tac_handle *);
static int conn_server(struct tac_handle *);
static void crypt_msg(struct tac_handle *, struct tac_msg *);
@ -63,8 +63,8 @@ static void generr(struct tac_handle *, const char *, ...)
__printflike(2, 3);
static void gen_session_id(struct tac_msg *);
static int get_srvr_end(struct tac_handle *);
static int get_srvr_str(struct tac_handle *, struct srvr_str *,
size_t);
static int get_srvr_str(struct tac_handle *, const char *,
struct srvr_str *, size_t);
static void init_clnt_str(struct clnt_str *);
static void init_srvr_str(struct srvr_str *);
static int read_timed(struct tac_handle *, void *, size_t,
@ -76,6 +76,8 @@ static int send_msg(struct tac_handle *);
static int split(char *, char *[], int, char *, size_t);
static void *xmalloc(struct tac_handle *, size_t);
static char *xstrdup(struct tac_handle *, const char *);
static void clear_srvr_avs(struct tac_handle *);
static void create_msg(struct tac_handle *, int, int, int);
/*
* Append some optional data to the current request, and store its
@ -138,12 +140,14 @@ add_str_16(struct tac_handle *h, u_int16_t *fld, struct clnt_str *cs)
}
static int
authen_version(int action, int type)
protocol_version(int msg_type, int var, int type)
{
int minor;
switch (action) {
switch (msg_type) {
case TAC_AUTHEN:
/* 'var' represents the 'action' */
switch (var) {
case TAC_AUTHEN_LOGIN:
switch (type) {
@ -168,10 +172,54 @@ authen_version(int action, int type)
minor = 0;
break;
};
break;
case TAC_AUTHOR:
/* 'var' represents the 'method' */
switch (var) {
/*
* When new authentication methods are added, include 'method'
* in determining the value of 'minor'. At this point, all
* methods defined in this implementation (see "Authorization
* authentication methods" in taclib.h) are minor version 0
* Not all types, however, indicate minor version 0.
*/
case TAC_AUTHEN_METH_NOT_SET:
case TAC_AUTHEN_METH_NONE:
case TAC_AUTHEN_METH_KRB5:
case TAC_AUTHEN_METH_LINE:
case TAC_AUTHEN_METH_ENABLE:
case TAC_AUTHEN_METH_LOCAL:
case TAC_AUTHEN_METH_TACACSPLUS:
case TAC_AUTHEN_METH_RCMD:
switch (type) {
case TAC_AUTHEN_TYPE_PAP:
case TAC_AUTHEN_TYPE_CHAP:
case TAC_AUTHEN_TYPE_MSCHAP:
case TAC_AUTHEN_TYPE_ARAP:
minor = 1;
break;
default:
minor = 0;
break;
}
break;
default:
minor = 0;
break;
}
break;
default:
minor = 0;
break;
}
return TAC_VER_MAJOR << 4 | minor;
}
static void
close_connection(struct tac_handle *h)
{
@ -393,18 +441,27 @@ gen_session_id(struct tac_msg *msg)
static int
get_srvr_end(struct tac_handle *h)
{
if (h->srvr_pos != ntohl(h->response.length)) {
generr(h, "Invalid length field in response from server");
int len;
len = ntohl(h->response.length);
if (h->srvr_pos != len) {
generr(h, "Invalid length field in response "
"from server: end expected at %u, response length %u",
h->srvr_pos, len);
return -1;
}
return 0;
}
static int
get_srvr_str(struct tac_handle *h, struct srvr_str *ss, size_t len)
get_srvr_str(struct tac_handle *h, const char *field,
struct srvr_str *ss, size_t len)
{
if (h->srvr_pos + len > ntohl(h->response.length)) {
generr(h, "Invalid length field in response from server");
generr(h, "Invalid length field in %s response from server "
"(%lu > %lu)", field, (u_long)(h->srvr_pos + len),
(u_long)ntohl(h->response.length));
return -1;
}
ss->data = len != 0 ? h->response.u.body + h->srvr_pos : NULL;
@ -489,7 +546,7 @@ recv_msg(struct tac_handle *h)
{
struct timeval deadline;
struct tac_msg *msg;
size_t len;
u_int32_t len;
msg = &h->response;
gettimeofday(&deadline, NULL);
@ -504,16 +561,21 @@ recv_msg(struct tac_handle *h)
return -1;
}
if (msg->type != h->request.type) {
generr(h, "Invalid type in received message");
generr(h, "Invalid type in received message"
" (got %u, expected %u)",
msg->type, h->request.type);
return -1;
}
len = ntohl(msg->length);
if (len > BODYSIZE) {
generr(h, "Received message too large");
generr(h, "Received message too large (%u > %u)",
len, BODYSIZE);
return -1;
}
if (msg->seq_no != ++h->last_seq_no) {
generr(h, "Invalid sequence number in received message");
generr(h, "Invalid sequence number in received message"
" (got %u, expected %u)",
msg->seq_no, h->last_seq_no);
return -1;
}
@ -564,15 +626,15 @@ send_msg(struct tac_handle *h)
return -1;
}
if (establish_connection(h) == -1)
return -1;
msg = &h->request;
msg->seq_no = ++h->last_seq_no;
if (msg->seq_no == 1)
gen_session_id(msg);
crypt_msg(h, msg);
if (establish_connection(h) == -1)
return -1;
if (h->single_connect)
msg->flags |= TAC_SINGLE_CONNECT;
else
@ -734,7 +796,7 @@ tac_add_server(struct tac_handle *h, const char *host, int port,
void
tac_close(struct tac_handle *h)
{
int srv;
int i, srv;
if (h->fd != -1)
close(h->fd);
@ -748,6 +810,11 @@ tac_close(struct tac_handle *h)
free_str(&h->rem_addr);
free_str(&h->data);
free_str(&h->user_msg);
for (i=0; i<MAXAVPAIRS; i++)
free_str(&(h->avs[i]));
/* Clear everything else before freeing memory */
memset(h, 0, sizeof(struct tac_handle));
free(h);
}
@ -786,7 +853,7 @@ tac_config(struct tac_handle *h, const char *path)
len = strlen(buf);
/* We know len > 0, else fgets would have returned NULL. */
if (buf[len - 1] != '\n') {
if (len == sizeof buf - 1)
if (len >= sizeof buf - 1)
generr(h, "%s:%d: line too long", path,
linenum);
else
@ -872,30 +939,56 @@ tac_config(struct tac_handle *h, const char *path)
int
tac_create_authen(struct tac_handle *h, int action, int type, int service)
{
struct tac_msg *msg;
struct tac_authen_start *as;
h->last_seq_no = 0;
create_msg(h, TAC_AUTHEN, action, type);
msg = &h->request;
msg->type = TAC_AUTHEN;
msg->version = authen_version(action, type);
msg->flags = 0;
as = &msg->u.authen_start;
as = &h->request.u.authen_start;
as->action = action;
as->priv_lvl = TAC_PRIV_LVL_USER;
as->authen_type = type;
as->service = service;
return 0;
}
int
tac_create_author(struct tac_handle *h, int method, int type, int service)
{
struct tac_author_request *areq;
create_msg(h, TAC_AUTHOR, method, type);
areq = &h->request.u.author_request;
areq->authen_meth = method;
areq->priv_lvl = TAC_PRIV_LVL_USER;
areq->authen_type = type;
areq->service = service;
return 0;
}
static void
create_msg(struct tac_handle *h, int msg_type, int var, int type)
{
struct tac_msg *msg;
int i;
h->last_seq_no = 0;
msg = &h->request;
msg->type = msg_type;
msg->version = protocol_version(msg_type, var, type);
msg->flags = 0; /* encrypted packet body */
free_str(&h->user);
free_str(&h->port);
free_str(&h->rem_addr);
free_str(&h->data);
free_str(&h->user_msg);
/* XXX - more to do */
return 0;
for (i=0; i<MAXAVPAIRS; i++)
free_str(&(h->avs[i]));
}
void *
@ -907,7 +1000,7 @@ tac_get_data(struct tac_handle *h, size_t *len)
char *
tac_get_msg(struct tac_handle *h)
{
return (char *)dup_str(h, &h->srvr_msg, NULL);
return dup_str(h, &h->srvr_msg, NULL);
}
/*
@ -918,6 +1011,7 @@ tac_get_msg(struct tac_handle *h)
struct tac_handle *
tac_open(void)
{
int i;
struct tac_handle *h;
h = (struct tac_handle *)malloc(sizeof(struct tac_handle));
@ -931,6 +1025,10 @@ tac_open(void)
init_clnt_str(&h->rem_addr);
init_clnt_str(&h->data);
init_clnt_str(&h->user_msg);
for (i=0; i<MAXAVPAIRS; i++) {
init_clnt_str(&(h->avs[i]));
init_srvr_str(&(h->srvr_avs[i]));
}
init_srvr_str(&h->srvr_msg);
init_srvr_str(&h->srvr_data);
srandomdev();
@ -943,6 +1041,9 @@ tac_send_authen(struct tac_handle *h)
{
struct tac_authen_reply *ar;
if (h->num_servers == 0)
return -1;
if (h->last_seq_no == 0) { /* Authentication START packet */
struct tac_authen_start *as;
@ -973,8 +1074,8 @@ tac_send_authen(struct tac_handle *h)
/* Scan the optional fields in the reply. */
ar = &h->response.u.authen_reply;
h->srvr_pos = offsetof(struct tac_authen_reply, rest[0]);
if (get_srvr_str(h, &h->srvr_msg, ntohs(ar->msg_len)) == -1 ||
get_srvr_str(h, &h->srvr_data, ntohs(ar->data_len)) == -1 ||
if (get_srvr_str(h, "msg", &h->srvr_msg, ntohs(ar->msg_len)) == -1 ||
get_srvr_str(h, "data", &h->srvr_data, ntohs(ar->data_len)) == -1 ||
get_srvr_end(h) == -1)
return -1;
@ -987,6 +1088,76 @@ tac_send_authen(struct tac_handle *h)
return ar->flags << 8 | ar->status;
}
int
tac_send_author(struct tac_handle *h)
{
int i, current;
char dbgstr[64];
struct tac_author_request *areq = &h->request.u.author_request;
struct tac_author_response *ares = &h->response.u.author_response;
h->request.length =
htonl(offsetof(struct tac_author_request, rest[0]));
/* Count each specified AV pair */
for (areq->av_cnt=0, i=0; i<MAXAVPAIRS; i++)
if (h->avs[i].len && h->avs[i].data)
areq->av_cnt++;
/*
* Each AV size is a byte starting right after 'av_cnt'. Update the
* offset to include these AV sizes.
*/
h->request.length = ntohl(htonl(h->request.length) + areq->av_cnt);
/* Now add the string arguments from 'h' */
if (add_str_8(h, &areq->user_len, &h->user) == -1 ||
add_str_8(h, &areq->port_len, &h->port) == -1 ||
add_str_8(h, &areq->rem_addr_len, &h->rem_addr) == -1)
return -1;
/* Add each AV pair, the size of each placed in areq->rest[current] */
for (current=0, i=0; i<MAXAVPAIRS; i++) {
if (h->avs[i].len && h->avs[i].data) {
if (add_str_8(h, &areq->rest[current++],
&(h->avs[i])) == -1)
return -1;
}
}
/* Send the message and retrieve the reply. */
if (send_msg(h) == -1 || recv_msg(h) == -1)
return -1;
/* Update the offset in the response packet based on av pairs count */
h->srvr_pos = offsetof(struct tac_author_response, rest[0]) +
ares->av_cnt;
/* Scan the optional fields in the response. */
if (get_srvr_str(h, "msg", &h->srvr_msg, ntohs(ares->msg_len)) == -1 ||
get_srvr_str(h, "data", &h->srvr_data, ntohs(ares->data_len)) ==-1)
return -1;
/* Get each AV pair (just setting pointers, not malloc'ing) */
clear_srvr_avs(h);
for (i=0; i<ares->av_cnt; i++) {
snprintf(dbgstr, sizeof dbgstr, "av-pair-%d", i);
if (get_srvr_str(h, dbgstr, &(h->srvr_avs[i]),
ares->rest[i]) == -1)
return -1;
}
/* Should have ended up at the end */
if (get_srvr_end(h) == -1)
return -1;
/* Sanity checks */
if (!h->single_connect)
close_connection(h);
return ares->av_cnt << 8 | ares->status;
}
int
tac_set_rem_addr(struct tac_handle *h, const char *addr)
{
@ -1028,6 +1199,99 @@ tac_set_user(struct tac_handle *h, const char *user)
return save_str(h, &h->user, user, user != NULL ? strlen(user) : 0);
}
int
tac_set_av(struct tac_handle *h, u_int index, const char *av)
{
if (index >= MAXAVPAIRS)
return -1;
return save_str(h, &(h->avs[index]), av, av != NULL ? strlen(av) : 0);
}
char *
tac_get_av(struct tac_handle *h, u_int index)
{
if (index >= MAXAVPAIRS)
return NULL;
return dup_str(h, &(h->srvr_avs[index]), NULL);
}
char *
tac_get_av_value(struct tac_handle *h, const char *attribute)
{
int i, len;
const char *ch, *end;
const char *candidate;
int candidate_len;
int found_seperator;
struct srvr_str srvr;
if (attribute == NULL || ((len = strlen(attribute)) == 0))
return NULL;
for (i=0; i<MAXAVPAIRS; i++) {
candidate = h->srvr_avs[i].data;
candidate_len = h->srvr_avs[i].len;
/*
* Valid 'srvr_avs' guaranteed to be contiguous starting at
* index 0 (not necessarily the case with 'avs'). Break out
* when the "end" of the list has been reached.
*/
if (!candidate)
break;
if (len < candidate_len &&
!strncmp(candidate, attribute, len)) {
ch = candidate + len;
end = candidate + candidate_len;
/*
* Sift out the white space between A and V (should not
* be any, but don't trust implementation of server...)
*/
found_seperator = 0;
while ((*ch == '=' || *ch == '*' || *ch == ' ' ||
*ch == '\t') && ch != end) {
if (*ch == '=' || *ch == '*')
found_seperator++;
ch++;
}
/*
* Note:
* The case of 'attribute' == "foo" and
* h->srvr_avs[0] = "foobie=var1"
* h->srvr_avs[1] = "foo=var2"
* is handled.
*/
if (found_seperator == 1 && ch != end) {
srvr.len = end - ch;
srvr.data = ch;
return dup_str(h, &srvr, NULL);
}
}
}
return NULL;
}
void
tac_clear_avs(struct tac_handle *h)
{
int i;
for (i=0; i<MAXAVPAIRS; i++)
save_str(h, &(h->avs[i]), NULL, 0);
}
static void
clear_srvr_avs(struct tac_handle *h)
{
int i;
for (i=0; i<MAXAVPAIRS; i++)
init_srvr_str(&(h->srvr_avs[i]));
}
const char *
tac_strerror(struct tac_handle *h)
{

View File

@ -1,5 +1,5 @@
/*-
* Copyright 1998 Juniper Networks, Inc.
* Copyright (c) 1998, 2001, Juniper Networks, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -41,6 +41,10 @@ struct tac_handle;
#define TAC_AUTHEN_STATUS(s) ((s) & 0xff)
#define TAC_AUTHEN_NOECHO(s) ((s) & (1<<8))
/* Disassembly of tac_send_author() return value. */
#define TAC_AUTHOR_STATUS(s) ((s) & 0xff)
#define TAC_AUTHEN_AV_COUNT(s) (((s)>>8) & 0xff)
/* Privilege levels */
#define TAC_PRIV_LVL_MIN 0x00
#define TAC_PRIV_LVL_USER 0x01
@ -82,6 +86,23 @@ struct tac_handle;
#define TAC_AUTHEN_STATUS_ERROR 0x07
#define TAC_AUTHEN_STATUS_FOLLOW 0x21
/* Authorization authenticatication methods */
#define TAC_AUTHEN_METH_NOT_SET 0x00
#define TAC_AUTHEN_METH_NONE 0x01
#define TAC_AUTHEN_METH_KRB5 0x02
#define TAC_AUTHEN_METH_LINE 0x03
#define TAC_AUTHEN_METH_ENABLE 0x04
#define TAC_AUTHEN_METH_LOCAL 0x05
#define TAC_AUTHEN_METH_TACACSPLUS 0x06
#define TAC_AUTHEN_METH_RCMD 0x20
/* If adding more, see comments in protocol_version() in taclib.c */
/* Authorization status */
#define TAC_AUTHOR_STATUS_PASS_ADD 0x01
#define TAC_AUTHOR_STATUS_PASS_REPL 0x02
#define TAC_AUTHOR_STATUS_FAIL 0x10
#define TAC_AUTHOR_STATUS_ERROR 0x11
__BEGIN_DECLS
int tac_add_server(struct tac_handle *,
const char *, int, const char *, int, int);
@ -100,6 +121,12 @@ int tac_set_priv(struct tac_handle *, int);
int tac_set_rem_addr(struct tac_handle *, const char *);
int tac_set_user(struct tac_handle *, const char *);
const char *tac_strerror(struct tac_handle *);
int tac_send_author(struct tac_handle *);
int tac_create_author(struct tac_handle *, int, int, int);
int tac_set_av(struct tac_handle *, u_int, const char *);
char *tac_get_av(struct tac_handle *, u_int);
char *tac_get_av_value(struct tac_handle *, const char *);
void tac_clear_avs(struct tac_handle *);
__END_DECLS
#endif /* _TACLIB_H_ */

View File

@ -1,5 +1,5 @@
/*-
* Copyright 1998 Juniper Networks, Inc.
* Copyright (c) 1998, 2001, Juniper Networks, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -41,6 +41,7 @@
#define ERRSIZE 128 /* Maximum error message length */
#define MAXCONFLINE 1024 /* Maximum config file line length */
#define MAXSERVERS 10 /* Maximum number of servers to try */
#define MAXAVPAIRS 255 /* Maximum number of AV pairs */
/* Protocol constants. */
#define HDRSIZE 12 /* Size of message header */
@ -111,6 +112,26 @@ struct tac_authen_cont {
unsigned char rest[1];
};
struct tac_author_request {
u_int8_t authen_meth;
u_int8_t priv_lvl;
u_int8_t authen_type;
u_int8_t service;
u_int8_t user_len;
u_int8_t port_len;
u_int8_t rem_addr_len;
u_int8_t av_cnt;
unsigned char rest[1];
};
struct tac_author_response {
u_int8_t status;
u_int8_t av_cnt;
u_int16_t msg_len;
u_int16_t data_len;
unsigned char rest[1];
};
struct tac_msg {
u_int8_t version;
u_int8_t type;
@ -122,6 +143,8 @@ struct tac_msg {
struct tac_authen_start authen_start;
struct tac_authen_reply authen_reply;
struct tac_authen_cont authen_cont;
struct tac_author_request author_request;
struct tac_author_response author_response;
unsigned char body[BODYSIZE];
} u;
};
@ -140,6 +163,7 @@ struct tac_handle {
struct clnt_str rem_addr;
struct clnt_str data;
struct clnt_str user_msg;
struct clnt_str avs[MAXAVPAIRS];
struct tac_msg request;
struct tac_msg response;
@ -147,6 +171,7 @@ struct tac_handle {
int srvr_pos; /* Scan position in response body */
struct srvr_str srvr_msg;
struct srvr_str srvr_data;
struct srvr_str srvr_avs[MAXAVPAIRS];
};
#endif