2 Copyright (c) 1995-1998 by Cisco systems, Inc.
4 Permission to use, copy, modify, and distribute this software for
5 any purpose and without fee is hereby granted, provided that this
6 copyright and permission notice appear on all copies of the
7 software and supporting documentation, the name of Cisco Systems,
8 Inc. not be used in advertising or publicity pertaining to
9 distribution of the program without specific prior permission, and
10 notice be given in supporting documentation that modification,
11 copying and distribution is by permission of Cisco Systems, Inc.
13 Cisco Systems, Inc. makes no representations about the suitability
14 of this software for any purpose. THIS SOFTWARE IS PROVIDED ``AS
15 IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
16 WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS FOR A PARTICULAR PURPOSE.
22 /* Everything to do with reading and writing packets */
24 /* send an accounting response packet */
25 send_acct_reply(status, msg, data)
32 struct acct_reply *reply;
33 int msg_len, data_len;
35 msg_len = msg ? strlen(msg) : 0;
36 data_len = data ? strlen(data) : 0;
38 len = TAC_PLUS_HDR_SIZE + TAC_ACCT_REPLY_FIXED_FIELDS_SIZE + msg_len + data_len;
40 pak = (u_char *) tac_malloc(len);
41 reply = (struct acct_reply *) (pak + TAC_PLUS_HDR_SIZE);
46 hdr->version = TAC_PLUS_VER_0;
47 hdr->type = TAC_PLUS_ACCT;
48 hdr->seq_no = ++session.seq_no;
49 hdr->encryption = TAC_PLUS_CLEAR;
50 hdr->session_id = htonl(session.session_id);
51 hdr->datalength = htonl(len - TAC_PLUS_HDR_SIZE);
53 reply->status = status;
54 reply->msg_len = msg_len;
55 reply->data_len = data_len;
57 p = pak + TAC_PLUS_HDR_SIZE + TAC_ACCT_REPLY_FIXED_FIELDS_SIZE;
58 bcopy(msg, p, msg_len);
61 bcopy(data, p, data_len);
63 if (debug & DEBUG_PACKET_FLAG) {
64 report(LOG_DEBUG, "Writing %s size=%d",
65 summarise_outgoing_packet_type(pak), len);
69 reply->msg_len = ntohs(reply->msg_len);
70 reply->data_len = ntohs(reply->data_len);
76 /* send an authorization reply packet */
77 send_author_reply(status, msg, data, arg_cnt, args)
86 struct author_reply *reply;
92 data_len = (data ? strlen(data) : 0);
93 msg_len = (msg ? strlen(msg) : 0);
95 /* start calculating final packet size */
96 len = TAC_PLUS_HDR_SIZE + TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE + msg_len +
99 for (i=0; i < arg_cnt; i++) {
100 /* space for the arg and its length */
101 len += strlen(args[i]) + 1;
104 pak = (u_char *) tac_malloc(len);
110 reply = (struct author_reply *) (pak + TAC_PLUS_HDR_SIZE);
112 hdr->version = TAC_PLUS_VER_0;
113 hdr->type = TAC_PLUS_AUTHOR;
114 hdr->seq_no = ++session.seq_no;
115 hdr->encryption = TAC_PLUS_CLEAR;
116 hdr->session_id = htonl(session.session_id);
117 hdr->datalength = htonl(len - TAC_PLUS_HDR_SIZE);
119 reply->status = status;
120 reply->msg_len = msg_len;
121 reply->data_len = data_len;
122 reply->arg_cnt = arg_cnt;
124 p = pak + TAC_PLUS_HDR_SIZE + TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE;
126 /* place arg sizes into packet */
127 for (i=0; i < arg_cnt; i++) {
128 *p++ = strlen(args[i]);
131 bcopy(msg, p, msg_len);
134 bcopy(data, p, data_len);
137 /* copy arg bodies into packet */
138 for (i=0; i < arg_cnt; i++) {
139 int arglen = strlen(args[i]);
141 bcopy(args[i], p, arglen);
145 if (debug & DEBUG_PACKET_FLAG) {
146 report(LOG_DEBUG, "Writing %s size=%d",
147 summarise_outgoing_packet_type(pak), len);
148 dump_tacacs_pak(pak);
151 reply->msg_len = htons(reply->msg_len);
152 reply->data_len = htons(reply->data_len);
159 /* Send an authentication reply packet indicating an error has
160 occurred. msg is a null terminated character string */
162 send_authen_error(msg)
167 sprintf(buf, "%s %s: %s", session.peer, session.port, msg);
168 report(LOG_ERR, buf);
169 send_authen_reply(TAC_PLUS_AUTHEN_STATUS_ERROR,
177 /* create and send an authentication reply packet from tacacs+ to a NAS */
179 send_authen_reply(status, msg, msg_len, data, data_len, flags)
189 struct authen_reply *reply;
191 int len = TAC_PLUS_HDR_SIZE + TAC_AUTHEN_REPLY_FIXED_FIELDS_SIZE + msg_len + data_len;
193 pak = (u_char *) tac_malloc(len);
197 reply = (struct authen_reply *) (pak + TAC_PLUS_HDR_SIZE);
199 hdr->version = session.version;
200 hdr->type = TAC_PLUS_AUTHEN;
201 hdr->seq_no = ++session.seq_no;
202 hdr->encryption = TAC_PLUS_CLEAR;
203 hdr->session_id = htonl(session.session_id);
204 hdr->datalength = htonl(TAC_AUTHEN_REPLY_FIXED_FIELDS_SIZE + msg_len + data_len);
206 reply->status = status;
207 reply->msg_len = msg_len;
208 reply->data_len = data_len;
209 reply->flags = flags;
211 p = pak + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_REPLY_FIXED_FIELDS_SIZE;
213 bcopy(msg, p, msg_len);
215 bcopy(data, p, data_len);
217 if (debug & DEBUG_PACKET_FLAG) {
218 report(LOG_DEBUG, "Writing %s size=%d",
219 summarise_outgoing_packet_type(pak), len);
220 dump_tacacs_pak(pak);
223 reply->msg_len = htons(reply->msg_len);
224 reply->data_len = htons(reply->data_len);
231 /* read an authentication GETDATA packet from a NAS. Return 0 on failure */
233 get_authen_continue()
236 u_char *pak, *read_packet();
237 struct authen_cont *cont;
244 cont = (struct authen_cont *) (pak + TAC_PLUS_HDR_SIZE);
246 if ((hdr->type != TAC_PLUS_AUTHEN) || (hdr->seq_no <= 1)) {
248 "%s: Bad packet type=%d/seq no=%d when expecting authentication cont",
249 session.peer, hdr->type, hdr->seq_no);
250 report(LOG_ERR, msg);
251 send_authen_error(msg);
255 cont->user_msg_len = ntohs(cont->user_msg_len);
256 cont->user_data_len = ntohs(cont->user_data_len);
258 if (TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE +
260 cont->user_data_len !=
261 ntohl(hdr->datalength)) {
262 char *m = "Illegally sized authentication cont packet";
263 report(LOG_ERR, "%s: %s", session.peer, m);
264 send_authen_error(m);
268 if (debug & DEBUG_PACKET_FLAG)
274 /* Read n bytes from descriptor fd into array ptr with timeout t
275 * seconds. Note the timeout is applied to each read, not for the
278 * Return -1 on error, eof or timeout. Otherwise return number of
282 sockread(fd, ptr, nbytes, timeout)
289 fd_set readfds, exceptfds;
292 tout.tv_sec = timeout;
296 FD_SET(fd, &readfds);
299 FD_SET(fd, &exceptfds);
304 int status = select(fd + 1, &readfds, (fd_set *) NULL,
308 report(LOG_DEBUG, "%s: timeout reading fd %d", session.peer, fd);
314 report(LOG_DEBUG, "%s: error in select %s fd %d",
315 session.peer, sys_errlist[errno], fd);
318 if (FD_ISSET(fd, &exceptfds)) {
319 report(LOG_DEBUG, "%s: exception on fd %d",
323 if (!FD_ISSET(fd, &readfds)) {
324 report(LOG_DEBUG, "%s: spurious return from select",
329 nread = read(fd, ptr, nleft);
334 report(LOG_DEBUG, "%s %s: error reading fd %d nread=%d %s",
335 session.peer, session.port, fd, nread, sys_errlist[errno]);
336 return (-1); /* error */
338 } else if (nread == 0) {
339 report(LOG_DEBUG, "%s %s: fd %d eof (connection closed)",
340 session.peer, session.port, fd);
341 return (-1); /* eof */
347 return (nbytes - nleft);
350 /* Write n bytes to descriptor fd from array ptr with timeout t
351 * seconds. Note the timeout is applied to each write, not for the
354 * Return -1 on error, eof or timeout. Otherwise return number of
358 sockwrite(fd, ptr, bytes, timeout)
365 fd_set writefds, exceptfds;
370 tout.tv_sec = timeout;
374 FD_SET(fd, &writefds);
377 FD_SET(fd, &exceptfds);
381 while (remaining > 0) {
382 int status = select(fd + 1, (fd_set *) NULL,
383 &writefds, &exceptfds, &tout);
386 report(LOG_DEBUG, "%s: timeout writing to fd %d",
391 report(LOG_DEBUG, "%s: error in select fd %d",
395 if (FD_ISSET(fd, &exceptfds)) {
396 report(LOG_DEBUG, "%s: exception on fd %d",
398 return (sent); /* error */
401 if (!FD_ISSET(fd, &writefds)) {
402 report(LOG_DEBUG, "%s: spurious return from select",
406 sent = write(fd, ptr, remaining);
409 report(LOG_DEBUG, "%s: error writing fd %d sent=%d",
410 session.peer, fd, sent);
411 return (sent); /* error */
416 return (bytes - remaining);
419 /* read a packet from the wire, and decrypt it. Increment the global
420 seq_no return NULL on failure */
430 if (debug & DEBUG_PACKET_FLAG)
431 report(LOG_DEBUG, "Waiting for packet");
433 /* read a packet header */
434 len = sockread(session.sock, (u_char *) & hdr, TAC_PLUS_HDR_SIZE, TAC_PLUS_READ_TIMEOUT);
435 if (len != TAC_PLUS_HDR_SIZE) {
436 report(LOG_DEBUG, "Read %d bytes from %s %s, expecting %d",
437 len, session.peer, session.port, TAC_PLUS_HDR_SIZE);
441 if ((hdr.version & TAC_PLUS_MAJOR_VER_MASK) != TAC_PLUS_MAJOR_VER) {
443 "%s: Illegal major version specified: found %d wanted %d\n",
444 session.peer, hdr.version, TAC_PLUS_MAJOR_VER);
448 /* get memory for the packet */
449 len = TAC_PLUS_HDR_SIZE + ntohl(hdr.datalength);
450 if ((ntohl(hdr.datalength) & ~0xffffUL) ||
451 len < TAC_PLUS_HDR_SIZE || len > 0x10000) {
453 "%s: Illegal data size: %lu\n",
454 session.peer, ntohl(hdr.datalength));
457 pkt = (u_char *) tac_malloc(len);
459 /* initialise the packet */
460 bcopy(&hdr, pkt, TAC_PLUS_HDR_SIZE);
462 /* the data start here */
463 data = pkt + TAC_PLUS_HDR_SIZE;
465 /* read the rest of the packet data */
466 if (sockread(session.sock, data, ntohl(hdr.datalength),
467 TAC_PLUS_READ_TIMEOUT) !=
468 ntohl(hdr.datalength)) {
469 report(LOG_ERR, "%s: start_session: bad socket read", session.peer);
472 session.seq_no++; /* should now equal that of incoming packet */
473 session.last_exch = time(NULL);
475 if (session.seq_no != hdr.seq_no) {
476 report(LOG_ERR, "%s: Illegal session seq # %d != packet seq # %d",
478 session.seq_no, hdr.seq_no);
482 /* decrypt the data portion */
483 if ( !(tkey=(char *)cfg_get_host_key(session.peer)) )
486 if (md5_xor((HDR *)pkt, data, tkey)) {
487 report(LOG_ERR, "%s: start_session error decrypting data",
492 if (debug & DEBUG_PACKET_FLAG)
493 report(LOG_DEBUG, "Read %s size=%d",
494 summarise_incoming_packet_type(pkt), len);
496 session.version = hdr.version;
501 /* write a packet to the wire, encrypting it */
505 HDR *hdr = (HDR *) pak;
510 len = TAC_PLUS_HDR_SIZE + ntohl(hdr->datalength);
512 /* the data start here */
513 data = pak + TAC_PLUS_HDR_SIZE;
515 /* encrypt the data portion */
516 if ( !(tkey=(char *)cfg_get_host_key(session.peer)) )
519 if (md5_xor((HDR *)pak, data, tkey)) {
520 report(LOG_ERR, "%s: write_packet: error encrypting data", session.peer);
524 if (sockwrite(session.sock, pak, len, TAC_PLUS_WRITE_TIMEOUT) != len) {
527 session.last_exch = time(NULL);
531 send_error_reply(type, msg)
536 case TAC_PLUS_AUTHEN:
537 send_authen_error(msg);
540 case TAC_PLUS_AUTHOR:
541 send_author_reply(AUTHOR_STATUS_ERROR, msg, NULL, 0, NULL);
545 send_acct_reply(TAC_PLUS_ACCT_STATUS_ERROR, msg, NULL);
549 report(LOG_ERR, "Illegal type %d for send_error_reply", type);