summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpst <pst@FreeBSD.org>2002-09-25 23:18:51 +0000
committerpst <pst@FreeBSD.org>2002-09-25 23:18:51 +0000
commit91648a15549c3af714c84517495e7f1093c53a07 (patch)
treec44b602a3373c774dcba3c1d92b44d5c442d3c92
parent436cfa19831cbf8a0e28bcc3fba9b09701e8c0ae (diff)
downloadFreeBSD-src-91648a15549c3af714c84517495e7f1093c53a07.zip
FreeBSD-src-91648a15549c3af714c84517495e7f1093c53a07.tar.gz
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
-rw-r--r--lib/libtacplus/Makefile2
-rw-r--r--lib/libtacplus/libtacplus.3127
-rw-r--r--lib/libtacplus/taclib.c366
-rw-r--r--lib/libtacplus/taclib.h29
-rw-r--r--lib/libtacplus/taclib_private.h27
5 files changed, 486 insertions, 65 deletions
diff --git a/lib/libtacplus/Makefile b/lib/libtacplus/Makefile
index 2d6c376..e7b158f 100644
--- a/lib/libtacplus/Makefile
+++ b/lib/libtacplus/Makefile
@@ -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
diff --git a/lib/libtacplus/libtacplus.3 b/lib/libtacplus/libtacplus.3
index baec68a..bcaf609 100644
--- a/lib/libtacplus/libtacplus.3
+++ b/lib/libtacplus/libtacplus.3
@@ -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.
diff --git a/lib/libtacplus/taclib.c b/lib/libtacplus/taclib.c
index 861d2d0..d99995d 100644
--- a/lib/libtacplus/taclib.c
+++ b/lib/libtacplus/taclib.c
@@ -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;
-
- switch (action) {
-
- case TAC_AUTHEN_LOGIN:
- switch (type) {
+ int minor;
+
+ switch (msg_type) {
+ case TAC_AUTHEN:
+ /* 'var' represents the 'action' */
+ switch (var) {
+ 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;
+ break;
- case TAC_AUTHEN_TYPE_PAP:
- case TAC_AUTHEN_TYPE_CHAP:
- case TAC_AUTHEN_TYPE_MSCHAP:
- case TAC_AUTHEN_TYPE_ARAP:
- minor = 1;
+ default:
+ minor = 0;
break;
+ }
+ break;
+
+ case TAC_AUTHEN_SENDAUTH:
+ minor = 1;
+ break;
default:
- minor = 0;
- break;
- }
+ 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;
- case TAC_AUTHEN_SENDAUTH:
- minor = 1;
+ 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;
@@ -988,6 +1089,76 @@ tac_send_authen(struct tac_handle *h)
}
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)
{
return save_str(h, &h->rem_addr, addr, addr != NULL ? strlen(addr) : 0);
@@ -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)
{
diff --git a/lib/libtacplus/taclib.h b/lib/libtacplus/taclib.h
index 0da1b08..2ef36b9 100644
--- a/lib/libtacplus/taclib.h
+++ b/lib/libtacplus/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,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_ */
diff --git a/lib/libtacplus/taclib_private.h b/lib/libtacplus/taclib_private.h
index 830fc92..bbc1990 100644
--- a/lib/libtacplus/taclib_private.h
+++ b/lib/libtacplus/taclib_private.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
OpenPOWER on IntegriCloud