Skip to content
This repository was archived by the owner on Feb 28, 2024. It is now read-only.

Commit 479e83b

Browse files
committed
Decouple marshalling/un-marshalling from socket I/O
It's precursory to separate marshalling functions from I/O if event-driven I/O is to be done, or if multiple Tacacs+ sessions can be active at the same time (you don't want to be polling on one socket and miss a timeout on another).
1 parent dd7a871 commit 479e83b

File tree

10 files changed

+761
-583
lines changed

10 files changed

+761
-583
lines changed

libtac/include/libtac.h

+52-11
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ extern "C" {
4242
#else
4343
#include "cdefs.h"
4444
#endif
45+
#include <assert.h>
46+
#include <stdbool.h>
47+
#include <limits.h>
4548
#include "tacplus.h"
4649

4750
#if defined(DEBUGTAC) && !defined(TACDEBUG)
@@ -87,6 +90,7 @@ struct tac_attrib {
8790
struct areply {
8891
struct tac_attrib *attr;
8992
char *msg;
93+
char *data;
9094
int status :8;
9195
int flags :8;
9296
int seq_no :8;
@@ -144,6 +148,8 @@ extern int tac_authen_service;
144148
extern int tac_debug_enable;
145149
extern int tac_readtimeout_enable;
146150

151+
HDR *_tac_req_header(u_char, int);
152+
147153
/* connect.c */
148154
extern int tac_timeout;
149155

@@ -152,30 +158,65 @@ int tac_connect_single(const struct addrinfo *, const char *, struct addrinfo *,
152158
int);
153159
char *tac_ntop(const struct sockaddr *);
154160

155-
int tac_authen_send(int, const char *, const char *, const char *, const char *,
156-
u_char);
161+
/* authen_s.c */
162+
u_char tac_get_authen_type(const char *);
163+
void tac_authen_send_pkt(const char *, const char *, const char *,
164+
const char *, u_char, u_char **, unsigned *);
165+
int tac_authen_send(int, const char *, const char *, const char *,
166+
const char *, u_char);
167+
168+
/* authen_r.c */
169+
int tac_authen_parse(struct areply *, u_char *, unsigned);
157170
int tac_authen_read(int, struct areply *);
158-
int tac_cont_send_seq(int, const char *, int);
171+
172+
/* cont_s.c */
173+
void tac_cont_send_pkt(const char *, uint8_t, u_char **, unsigned *);
174+
int tac_cont_send_seq(int, const char *, uint8_t);
159175
#define tac_cont_send(fd, pass) tac_cont_send_seq((fd), (pass), 3)
160-
HDR *_tac_req_header(u_char, int);
176+
177+
/* crypt.c */
161178
void _tac_crypt(u_char *, const HDR *);
179+
180+
/* author_r.c */
181+
int tac_author_parse(u_char *, unsigned, struct areply *);
182+
int tac_author_read(int, struct areply *);
183+
184+
/* author_s.c */
185+
void tac_author_send_pkt(const char *, const char *, const char *,
186+
struct tac_attrib *, u_char **, unsigned *);
187+
int tac_author_send(int, const char *, const char *, const char *,
188+
struct tac_attrib *);
189+
190+
/* attrib.c */
162191
void tac_add_attrib(struct tac_attrib **, char *, char *);
192+
void tac_add_attrib_pair(struct tac_attrib **, char *, char, char *);
163193
void tac_free_attrib(struct tac_attrib **);
164-
char *tac_acct_flag2str(int);
165-
int tac_acct_send(int, int, const char *, char *, char *, struct tac_attrib *);
194+
195+
/* acct_s.c */
196+
char *tac_acct_flag2str(u_char);
197+
void tac_acct_send_pkt(u_char, const char *, const char *, const char *,
198+
struct tac_attrib *, u_char **, unsigned *);
199+
int tac_acct_send(int, u_char, const char *, const char *, const char *,
200+
struct tac_attrib *);
201+
202+
/* acct_r.c */
203+
int tac_acct_parse(u_char *, unsigned, struct areply *);
166204
int tac_acct_read(int, struct areply *);
205+
206+
/* xalloc.c */
167207
void *xcalloc(size_t, size_t);
168208
void *xrealloc(void *, size_t);
169209
char *xstrcpy(char *, const char *, size_t);
170-
char *_tac_check_header(HDR *, int);
171-
int tac_author_send(int, const char *, char *, char *, struct tac_attrib *);
172-
int tac_author_read(int, struct areply *);
173-
void tac_add_attrib_pair(struct tac_attrib **, char *, char, char *);
174-
int tac_read_wait(int, int, int, int *);
210+
211+
/* hdr_check.c */
212+
char *_tac_check_header(HDR *, uint8_t);
175213

176214
/* magic.c */
177215
u_int32_t magic(void);
178216

217+
/* read_wait.c */
218+
int tac_read_wait(int, int, int, int *);
219+
179220
#ifdef __cplusplus
180221
}
181222
#endif

libtac/include/tacplus.h

+5
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ struct authen_cont {
107107
u_short user_msg_len;
108108
u_short user_data_len;
109109
u_char flags;
110+
u_char msg[0];
110111

111112
#define TAC_PLUS_CONTINUE_FLAG_ABORT 0x01
112113

@@ -133,6 +134,7 @@ struct authen_reply {
133134

134135
u_short msg_len;
135136
u_short data_len;
137+
u_char msg[0];
136138
};
137139

138140
#define TAC_AUTHEN_REPLY_FIXED_FIELDS_SIZE 6
@@ -173,6 +175,7 @@ struct acct {
173175
u_char port_len;
174176
u_char r_addr_len;
175177
u_char arg_cnt; /* the number of cmd args */
178+
u_char arg_len[0];
176179
};
177180

178181
#define TAC_ACCT_REQ_FIXED_FIELDS_SIZE 9
@@ -201,6 +204,7 @@ struct author {
201204
u_char port_len;
202205
u_char r_addr_len;
203206
u_char arg_cnt; /* the number of args */
207+
u_char arg_len[0];
204208
};
205209

206210
#define TAC_AUTHOR_REQ_FIXED_FIELDS_SIZE 8
@@ -211,6 +215,7 @@ struct author_reply {
211215
u_char arg_cnt;
212216
u_short msg_len;
213217
u_short data_len;
218+
u_char arg_len[0];
214219

215220
#define TAC_PLUS_AUTHOR_STATUS_PASS_ADD 0x01
216221
#define TAC_PLUS_AUTHOR_STATUS_PASS_REPL 0x02

libtac/lib/acct_r.c

+114-64
Original file line numberDiff line numberDiff line change
@@ -32,118 +32,80 @@
3232
* LIBTAC_STATUS_PROTOCOL_ERR
3333
* >= 0 : server response, see TAC_PLUS_AUTHEN_STATUS_...
3434
*/
35-
int tac_acct_read(int fd, struct areply *re) {
36-
HDR th;
35+
int tac_acct_parse(u_char *pkt, unsigned pkt_total, struct areply *re) {
36+
HDR *th = (HDR *)pkt;
3737
struct acct_reply *tb = NULL;
3838
size_t ulen_from_header, len_from_body;
39-
ssize_t spacket_read;
4039
char *msg = NULL;
41-
int timeleft = 0;
42-
re->attr = NULL; /* unused */
43-
re->msg = NULL;
44-
45-
if (tac_readtimeout_enable &&
46-
tac_read_wait(fd,tac_timeout*1000, TAC_PLUS_HDR_SIZE,&timeleft) < 0 ) {
47-
TACSYSLOG(LOG_ERR,\
48-
"%s: reply timeout after %u secs", __FUNCTION__, tac_timeout);
49-
re->msg = xstrdup(acct_syserr_msg);
50-
re->status = LIBTAC_STATUS_READ_TIMEOUT;
51-
free(tb);
52-
return re->status;
53-
}
5440

55-
spacket_read = read(fd, &th, TAC_PLUS_HDR_SIZE);
56-
if(spacket_read < TAC_PLUS_HDR_SIZE) {
57-
TACSYSLOG(LOG_ERR,\
58-
"%s: short reply header, read %zd of %u expected: %m", __FUNCTION__,\
59-
spacket_read, TAC_PLUS_HDR_SIZE);
60-
re->msg = xstrdup(acct_syserr_msg);
61-
re->status = LIBTAC_STATUS_SHORT_HDR;
62-
free(tb);
63-
return re->status;
64-
}
41+
re->attr = NULL; /* unused */
42+
re->msg = re->data = NULL;
6543

6644
/* check the reply fields in header */
67-
msg = _tac_check_header(&th, TAC_PLUS_ACCT);
45+
msg = _tac_check_header(th, TAC_PLUS_ACCT);
6846
if(msg != NULL) {
6947
re->msg = xstrdup(msg);
7048
re->status = LIBTAC_STATUS_PROTOCOL_ERR;
71-
free(tb);
7249
TACDEBUG(LOG_DEBUG, "%s: exit status=%d, status message \"%s\"",\
7350
__FUNCTION__, re->status, re->msg != NULL ? re->msg : "");
7451
return re->status;
7552
}
7653

77-
ulen_from_header = ntohl(th.datalength);
78-
if (ulen_from_header > TAC_PLUS_MAX_PACKET_SIZE) {
79-
TACSYSLOG(LOG_ERR,\
80-
"%s: length declared in the packet %zu exceeds max allowed packet size %d",\
81-
__FUNCTION__,\
82-
ulen_from_header, TAC_PLUS_MAX_PACKET_SIZE);
83-
re->status=LIBTAC_STATUS_SHORT_HDR;
84-
free(tb);
85-
return re->status;
86-
}
87-
tb=(struct acct_reply *) xcalloc(1, ulen_from_header);
54+
ulen_from_header = ntohl(th->datalength);
8855

89-
/* read reply packet body */
90-
if (tac_readtimeout_enable &&
91-
tac_read_wait(fd,timeleft,ulen_from_header,NULL) < 0 ) {
92-
TACSYSLOG(LOG_ERR,\
93-
"%s: reply timeout after %u secs", __FUNCTION__, tac_timeout);
94-
re->msg = xstrdup(acct_syserr_msg);
95-
re->status = LIBTAC_STATUS_READ_TIMEOUT;
96-
free(tb);
97-
return re->status;
98-
}
56+
tb = (struct acct_reply *)(pkt + TAC_PLUS_HDR_SIZE);
9957

100-
spacket_read = read(fd, tb, ulen_from_header);
101-
if(spacket_read < (ssize_t) ulen_from_header) {
58+
if (pkt_total != ulen_from_header) {
10259
TACSYSLOG(LOG_ERR,\
103-
"%s: short reply body, read %zd of %zu: %m",\
60+
"%s: short packet, got %u expected %zu: %m",\
10461
__FUNCTION__,\
105-
spacket_read, ulen_from_header);
62+
pkt_total, TAC_PLUS_HDR_SIZE + ulen_from_header);
10663
re->msg = xstrdup(acct_syserr_msg);
10764
re->status = LIBTAC_STATUS_SHORT_BODY;
108-
free(tb);
10965
return re->status;
11066
}
11167

11268
/* decrypt the body */
113-
_tac_crypt((u_char *) tb, &th);
69+
_tac_crypt((u_char *) tb, th);
11470

11571
/* Convert network byte order to host byte order */
11672
tb->msg_len = ntohs(tb->msg_len);
11773
tb->data_len = ntohs(tb->data_len);
11874

11975
/* check the length fields */
120-
len_from_body=sizeof(tb->msg_len) + sizeof(tb->data_len) +
121-
sizeof(tb->status) + tb->msg_len + tb->data_len;
76+
len_from_body = TAC_ACCT_REPLY_FIXED_FIELDS_SIZE + \
77+
tb->msg_len + tb->data_len;
12278

12379
if(ulen_from_header != len_from_body) {
12480
TACSYSLOG(LOG_ERR,\
125-
"%s: inconsistent reply body, incorrect key?",\
126-
__FUNCTION__);
81+
"%s: inconsistent reply body, header len %zu versus parsed len %zu",\
82+
__FUNCTION__, ulen_from_header, len_from_body);
12783
re->msg = xstrdup(acct_syserr_msg);
12884
re->status = LIBTAC_STATUS_PROTOCOL_ERR;
129-
free(tb);
13085
return re->status;
13186
}
13287

13388
/* save status and clean up */
13489
if(tb->msg_len) {
13590
msg=(char *) xcalloc(1, tb->msg_len+1);
13691
bcopy((u_char *) tb+TAC_ACCT_REPLY_FIXED_FIELDS_SIZE, msg, tb->msg_len);
137-
msg[(int)tb->msg_len] = '\0';
92+
msg[tb->msg_len] = '\0';
13893
re->msg = msg; /* Freed by caller */
13994
}
14095

96+
if(tb->data_len) {
97+
msg=(char *) xcalloc(1, tb->data_len+1);
98+
bcopy((u_char *) tb+TAC_ACCT_REPLY_FIXED_FIELDS_SIZE+tb->data_len,
99+
msg, tb->data_len);
100+
msg[tb->data_len] = '\0';
101+
re->data = msg; /* Freed by caller */
102+
}
103+
141104
/* server logged our request successfully */
142105
if (tb->status == TAC_PLUS_ACCT_STATUS_SUCCESS) {
143106
TACDEBUG(LOG_DEBUG, "%s: accounted ok", __FUNCTION__);
144107
if (!re->msg) re->msg = xstrdup(acct_ok_msg);
145108
re->status = tb->status;
146-
free(tb);
147109
return re->status;
148110
}
149111

@@ -162,6 +124,94 @@ int tac_acct_read(int fd, struct areply *re) {
162124
break;
163125
}
164126

165-
free(tb);
166127
return re->status;
167-
}
128+
} /* tac_acct_parse */
129+
130+
/*
131+
* return value:
132+
* < 0 : error status code, see LIBTAC_STATUS_...
133+
* LIBTAC_STATUS_READ_TIMEOUT
134+
* LIBTAC_STATUS_SHORT_HDR
135+
* LIBTAC_STATUS_SHORT_BODY
136+
* LIBTAC_STATUS_PROTOCOL_ERR
137+
* >= 0 : server response, see TAC_PLUS_AUTHEN_STATUS_...
138+
*/
139+
int tac_acct_read(int fd, struct areply *re) {
140+
HDR *th;
141+
struct acct_reply *tb = NULL;
142+
size_t ulen_from_header;
143+
ssize_t spacket_read;
144+
int status, timeleft = 0;
145+
146+
re->attr = NULL; /* unused */
147+
re->msg = re->data = NULL;
148+
149+
if (tac_readtimeout_enable &&
150+
tac_read_wait(fd, tac_timeout * 1000, TAC_PLUS_HDR_SIZE, &timeleft) < 0 ) {
151+
TACSYSLOG(LOG_ERR,\
152+
"%s: reply timeout after %u secs", __FUNCTION__, tac_timeout);
153+
re->msg = xstrdup(acct_syserr_msg);
154+
re->status = LIBTAC_STATUS_READ_TIMEOUT;
155+
return re->status;
156+
}
157+
158+
th = (HDR *)xcalloc(1, TAC_PLUS_HDR_SIZE);
159+
160+
spacket_read = read(fd, (char *)th, TAC_PLUS_HDR_SIZE);
161+
if(spacket_read < TAC_PLUS_HDR_SIZE) {
162+
TACSYSLOG(LOG_ERR,\
163+
"%s: short reply header, read %zd of %u expected: %m", __FUNCTION__,\
164+
((spacket_read >= 0) ? spacket_read : 0), TAC_PLUS_HDR_SIZE);
165+
re->msg = xstrdup(acct_syserr_msg);
166+
re->status = LIBTAC_STATUS_SHORT_HDR;
167+
free(th);
168+
return re->status;
169+
}
170+
171+
ulen_from_header = ntohl(th->datalength);
172+
if (ulen_from_header > TAC_PLUS_MAX_PACKET_SIZE) {
173+
TACSYSLOG(LOG_ERR,\
174+
"%s: length declared in the packet %zu exceeds max allowed packet size %u", __FUNCTION__,\
175+
ulen_from_header, TAC_PLUS_MAX_PACKET_SIZE);
176+
re->msg = xstrdup(acct_syserr_msg);
177+
re->status = LIBTAC_STATUS_PROTOCOL_ERR;
178+
free(th);
179+
return re->status;
180+
}
181+
182+
/* now make room for entire contiguous packet */
183+
th = (HDR *)xrealloc(th, TAC_PLUS_HDR_SIZE + ulen_from_header);
184+
tb = (struct acct_reply *)((u_char *)th + TAC_PLUS_HDR_SIZE);
185+
186+
/* read reply packet body */
187+
if (tac_readtimeout_enable &&
188+
tac_read_wait(fd, timeleft, ulen_from_header, NULL) < 0 ) {
189+
TACSYSLOG(LOG_ERR,\
190+
"%s: reply timeout after %u secs", __FUNCTION__, tac_timeout);
191+
re->msg = xstrdup(acct_syserr_msg);
192+
re->status = LIBTAC_STATUS_READ_TIMEOUT;
193+
free(th);
194+
return re->status;
195+
}
196+
197+
spacket_read = read(fd, (char *)tb, ulen_from_header);
198+
if(spacket_read < 0 || (size_t) spacket_read < ulen_from_header) {
199+
TACSYSLOG(LOG_ERR,\
200+
"%s: short reply body, read %zd of %zu: %m",\
201+
__FUNCTION__,\
202+
((spacket_read >= 0) ? spacket_read : 0), ulen_from_header);
203+
re->msg = xstrdup(acct_syserr_msg);
204+
re->status = LIBTAC_STATUS_SHORT_BODY;
205+
free(th);
206+
return re->status;
207+
}
208+
209+
/* now parse remaining packet fields */
210+
status = tac_acct_parse((u_char *)th, TAC_PLUS_HDR_SIZE + ulen_from_header, re);
211+
212+
/* all useful data has been copied out */
213+
free(th);
214+
215+
return status;
216+
} /* tac_acct_read */
217+

0 commit comments

Comments
 (0)