From 1a61aeb8dd452e0f28993cd0bac61a9a8804e730 Mon Sep 17 00:00:00 2001 From: Paul Traina Date: Wed, 25 Sep 2002 23:18:51 +0000 Subject: [PATCH] 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 MFC after: 2 weeks --- lib/libtacplus/Makefile | 2 +- lib/libtacplus/libtacplus.3 | 127 ++++++++++- lib/libtacplus/taclib.c | 364 +++++++++++++++++++++++++++----- lib/libtacplus/taclib.h | 29 ++- lib/libtacplus/taclib_private.h | 27 ++- 5 files changed, 485 insertions(+), 64 deletions(-) diff --git a/lib/libtacplus/Makefile b/lib/libtacplus/Makefile index 2d6c376c6768..e7b158fc424e 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 baec68a87e9c..bcaf609045c9 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 861d2d06943f..d99995dfea6d 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; + 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; iavs[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; iavs[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; iavs[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; iavs[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; iavs[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; iav_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; isrvr_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; iavs[i]), NULL, 0); +} + +static void +clear_srvr_avs(struct tac_handle *h) +{ + int i; + for (i=0; isrvr_avs[i])); +} + + const char * tac_strerror(struct tac_handle *h) { diff --git a/lib/libtacplus/taclib.h b/lib/libtacplus/taclib.h index 0da1b0889ab3..2ef36b9efd50 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 830fc921fbf3..bbc1990c9269 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