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:
parent
54f61a9394
commit
1a61aeb8dd
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=103976
@ -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
|
||||
|
@ -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 ,
|
||||
@ -258,12 +294,69 @@ initial authentication request.
|
||||
.Pp
|
||||
When it receives the CONTINUE packet, the server may again request
|
||||
more information by returning
|
||||
.Dv TAC_AUTHEN_STATUS_GETDATA ,
|
||||
.Dv TAC_AUTHEN_STATUS_GETDATA ,
|
||||
.Dv TAC_AUTHEN_STATUS_GETUSER ,
|
||||
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 *
|
||||
@ -272,7 +365,7 @@ can be retrieved by calling
|
||||
.Fn tac_strerror .
|
||||
The message text is overwritten on each new error for the given
|
||||
.Va struct tac_handle * .
|
||||
Thus the message must be copied if it is to be preserved through
|
||||
Thus the message must be copied if it is to be preserved through
|
||||
subsequent library calls using the same handle.
|
||||
.Sh CLEANUP
|
||||
To free the resources used by the TACACS+ library, call
|
||||
@ -283,7 +376,7 @@ they detect an error, they return -1 and record an error message
|
||||
which can be retrieved using
|
||||
.Fn tac_strerror .
|
||||
.Pp
|
||||
.Bl -item -offset indent -compact
|
||||
.Bl -item -offset indent -compact
|
||||
.It
|
||||
.Fn tac_add_server
|
||||
.It
|
||||
@ -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.
|
||||
|
@ -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,40 +140,86 @@ 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;
|
||||
int minor;
|
||||
|
||||
switch (action) {
|
||||
switch (msg_type) {
|
||||
case TAC_AUTHEN:
|
||||
/* 'var' represents the 'action' */
|
||||
switch (var) {
|
||||
case TAC_AUTHEN_LOGIN:
|
||||
switch (type) {
|
||||
|
||||
case TAC_AUTHEN_LOGIN:
|
||||
switch (type) {
|
||||
|
||||
case TAC_AUTHEN_TYPE_PAP:
|
||||
case TAC_AUTHEN_TYPE_CHAP:
|
||||
case TAC_AUTHEN_TYPE_MSCHAP:
|
||||
case TAC_AUTHEN_TYPE_ARAP:
|
||||
minor = 1;
|
||||
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;
|
||||
|
||||
case TAC_AUTHEN_SENDAUTH:
|
||||
minor = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
minor = 0;
|
||||
break;
|
||||
}
|
||||
minor = 0;
|
||||
break;
|
||||
};
|
||||
break;
|
||||
|
||||
case TAC_AUTHEN_SENDAUTH:
|
||||
minor = 1;
|
||||
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;
|
||||
};
|
||||
minor = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return TAC_VER_MAJOR << 4 | minor;
|
||||
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)
|
||||
{
|
||||
|
@ -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_ */
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user