Release bumped to "gts4".
[tac_plus.git] / packet.c
1 /*
2    Copyright (c) 1995-1998 by Cisco systems, Inc.
3
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.
12
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.
18 */
19
20
21 #include "tac_plus.h"
22
23 #include <stdlib.h>
24 #include <netinet/in.h>         /* for ntohl() */
25 #include <errno.h>
26 #include <time.h>
27 #ifdef HAVE_SYS_TIME_H
28 #include <sys/time.h>
29 #endif
30 #include <sys/types.h>
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34
35 #include "packet.h"
36 #include "utils.h"
37 #include "report.h"
38 #include "dump.h"
39 #include "cfgfile.h"
40 #include "encrypt.h"
41 #include "main.h"
42 #include "do_author.h"
43
44
45 static int write_packet TAC_ARGS((u_char *pak));
46
47
48 /* Configurable:
49  */
50
51 #define TAC_PLUS_READ_TIMEOUT           180     /* seconds */
52 #define TAC_PLUS_WRITE_TIMEOUT          180     /* seconds */
53
54
55 /* Everything to do with reading and writing packets */
56
57 void send_acct_reply TAC_ARGS((unsigned status, const char *msg, const char *data));
58
59 /* send an accounting response packet */
60 void
61 send_acct_reply(status, msg, data)
62 unsigned status;                        /* promoted "u_char" type */
63 const char *msg;
64 const char *data;
65 {
66     u_char *pak, *p;
67     HDR *hdr;
68     int len;
69     struct acct_reply *reply;
70     int msg_len, data_len;
71
72     msg_len = msg ? strlen(msg) : 0;
73     data_len = data ? strlen(data) : 0;
74
75     len = TAC_PLUS_HDR_SIZE + TAC_ACCT_REPLY_FIXED_FIELDS_SIZE + msg_len + data_len;
76
77     pak = (u_char *) tac_malloc(len);
78     reply = (struct acct_reply *) (pak + TAC_PLUS_HDR_SIZE);
79     hdr = (HDR *) pak;
80
81     bzero(pak, len);
82
83     hdr->version = TAC_PLUS_VER_0;
84     hdr->type = TAC_PLUS_ACCT;
85     hdr->seq_no = ++session.seq_no;
86     hdr->encryption = TAC_PLUS_CLEAR;
87     hdr->session_id = htonl(session.session_id);
88     hdr->datalength = htonl(len - TAC_PLUS_HDR_SIZE);
89
90     reply->status = status;
91     reply->msg_len  = msg_len;
92     reply->data_len = data_len;
93
94     p = pak + TAC_PLUS_HDR_SIZE + TAC_ACCT_REPLY_FIXED_FIELDS_SIZE;
95     bcopy(msg, p, msg_len);
96     p += msg_len;
97
98     bcopy(data, p, data_len);
99
100     if (debug & DEBUG_PACKET_FLAG) {
101         report(LOG_DEBUG, "Writing %s size=%d",
102                summarise_outgoing_packet_type(pak), len);
103         dump_tacacs_pak(pak);
104     }
105
106     reply->msg_len = ntohs(reply->msg_len);
107     reply->data_len = ntohs(reply->data_len);
108
109     write_packet(pak);
110     free(pak);
111 }
112
113 void send_author_reply TAC_ARGS((unsigned status, const char *msg, const char *data, int arg_cnt, /* const */ char **args));
114
115 /* send an authorization reply packet */
116 void
117 send_author_reply(status, msg, data, arg_cnt, args)
118 unsigned status;                        /* promoted "u_char" type */
119 const char *msg;
120 const char *data;
121 int arg_cnt;
122 /* const */ char **args;
123 {
124     u_char *pak, *p;
125     HDR *hdr;
126     struct author_reply *reply;
127     int msg_len;
128     int len;
129     int data_len;
130     int i;
131
132     data_len = (data ? strlen(data) : 0);
133     msg_len  = (msg  ? strlen(msg)  : 0);
134
135     /* start calculating final packet size */
136     len = TAC_PLUS_HDR_SIZE + TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE + msg_len +
137         data_len;
138
139     for (i=0; i < arg_cnt; i++) {
140         /* space for the arg and its length */
141         len += strlen(args[i]) + 1;
142     }
143
144     pak = (u_char *) tac_malloc(len);
145
146     bzero(pak, len);
147
148     hdr = (HDR *) pak;
149
150     reply = (struct author_reply *) (pak + TAC_PLUS_HDR_SIZE);
151
152     hdr->version = TAC_PLUS_VER_0;
153     hdr->type = TAC_PLUS_AUTHOR;
154     hdr->seq_no = ++session.seq_no;
155     hdr->encryption = TAC_PLUS_CLEAR;
156     hdr->session_id = htonl(session.session_id);
157     hdr->datalength = htonl(len - TAC_PLUS_HDR_SIZE);
158
159     reply->status   = status;
160     reply->msg_len  = msg_len;
161     reply->data_len = data_len;
162     reply->arg_cnt  = arg_cnt;
163
164     p = pak + TAC_PLUS_HDR_SIZE + TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE;
165
166     /* place arg sizes into packet  */
167     for (i=0; i < arg_cnt; i++) {
168         *p++ = strlen(args[i]);
169     }
170
171     bcopy(msg, p, msg_len);
172     p += msg_len;
173
174     bcopy(data, p, data_len);
175     p += data_len;
176
177     /* copy arg bodies into packet */
178     for (i=0; i < arg_cnt; i++) {
179         int arglen = strlen(args[i]);
180
181         bcopy(args[i], p, arglen);
182         p += arglen;
183     }
184
185     if (debug & DEBUG_PACKET_FLAG) {
186         report(LOG_DEBUG, "Writing %s size=%d",
187                summarise_outgoing_packet_type(pak), len);
188         dump_tacacs_pak(pak);
189     }
190
191     reply->msg_len  = htons(reply->msg_len);
192     reply->data_len = htons(reply->data_len);
193
194     write_packet(pak);
195     free(pak);
196 }
197
198
199 /* Send an authentication reply packet indicating an error has
200    occurred. msg is a null terminated character string */
201
202 void send_authen_error TAC_ARGS((const char *msg));
203
204 void
205 send_authen_error(msg)
206 const char *msg;
207 {
208     char buf[255];
209
210     sprintf(buf, "%s %s: %s", session.peer, session.port, msg);
211     report(LOG_ERR, buf);
212     send_authen_reply(TAC_PLUS_AUTHEN_STATUS_ERROR,
213                       buf,
214                       strlen(buf),
215                       NULL,
216                       0,
217                       0);
218 }
219
220 /* create and send an authentication reply packet from tacacs+ to a NAS */
221
222 void send_authen_reply TAC_ARGS((int status, const char *msg, unsigned msg_len, const unsigned char *data, unsigned data_len, unsigned flags));
223
224 void
225 send_authen_reply(status, msg, msg_len, data, data_len, flags)
226 int status;
227 const char *msg;
228 unsigned msg_len;                       /* promoted "u_short" type */
229 const unsigned char *data;
230 unsigned data_len;                      /* promoted "u_short" type */
231 unsigned flags;                         /* promoted "u_char" type */
232 {
233     u_char *pak, *p;
234     HDR *hdr;
235     struct authen_reply *reply;
236
237     int len = TAC_PLUS_HDR_SIZE + TAC_AUTHEN_REPLY_FIXED_FIELDS_SIZE + msg_len + data_len;
238
239     pak = (u_char *) tac_malloc(len);
240     bzero(pak, len);
241
242     hdr = (HDR *) pak;
243     reply = (struct authen_reply *) (pak + TAC_PLUS_HDR_SIZE);
244
245     hdr->version = session.version;
246     hdr->type = TAC_PLUS_AUTHEN;
247     hdr->seq_no = ++session.seq_no;
248     hdr->encryption = TAC_PLUS_CLEAR;
249     hdr->session_id = htonl(session.session_id);
250     hdr->datalength = htonl(TAC_AUTHEN_REPLY_FIXED_FIELDS_SIZE + msg_len + data_len);
251
252     reply->status = status;
253     reply->msg_len = msg_len;
254     reply->data_len = data_len;
255     reply->flags = flags;
256
257     p = pak + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_REPLY_FIXED_FIELDS_SIZE;
258
259     bcopy(msg, p, msg_len);
260     p += msg_len;
261     bcopy(data, p, data_len);
262
263     if (debug & DEBUG_PACKET_FLAG) {
264         report(LOG_DEBUG, "Writing %s size=%d",
265                summarise_outgoing_packet_type(pak), len);
266         dump_tacacs_pak(pak);
267     }
268
269     reply->msg_len = htons(reply->msg_len);
270     reply->data_len = htons(reply->data_len);
271
272     write_packet(pak);
273     free(pak);
274 }
275
276
277 u_char *get_authen_continue TAC_ARGS((void));
278
279 /* read an authentication GETDATA packet from a NAS. Return 0 on failure */
280 u_char *
281 get_authen_continue()
282 {
283     HDR *hdr;
284     u_char *pak;
285     struct authen_cont *cont;
286     char msg[255];
287
288     pak = read_packet();
289     if (!pak)
290         return(NULL);
291     hdr = (HDR *) pak;
292     cont = (struct authen_cont *) (pak + TAC_PLUS_HDR_SIZE);
293
294     if ((hdr->type != TAC_PLUS_AUTHEN) || (hdr->seq_no <= 1)) {
295         sprintf(msg,
296           "%s: Bad packet type=%d/seq no=%d when expecting authentication cont",
297                 session.peer, hdr->type, hdr->seq_no);
298         report(LOG_ERR, msg);
299         send_authen_error(msg);
300         return(NULL);
301     }
302
303     cont->user_msg_len  = ntohs(cont->user_msg_len);
304     cont->user_data_len = ntohs(cont->user_data_len);
305
306     if ((unsigned long)(TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE +
307         cont->user_msg_len +
308         cont->user_data_len) !=
309         (unsigned long) ntohl(hdr->datalength)) {
310         char *m = "Illegally sized authentication cont packet";
311         report(LOG_ERR, "%s: %s", session.peer, m);
312         send_authen_error(m);
313         return(NULL);
314     }
315
316     if (debug & DEBUG_PACKET_FLAG)
317         dump_nas_pak(pak);
318
319     return (pak);
320 }
321
322 /* Read n bytes from descriptor fd into array ptr with timeout t
323  * seconds. Note the timeout is applied to each read, not for the
324  * overall operation.
325  *
326  * Return -1 on error, eof or timeout. Otherwise return number of
327  * bytes read. */
328
329 static int sockread TAC_ARGS((int fd, u_char *ptr, int nbytes, int timeout));
330
331 static int
332 sockread(fd, ptr, nbytes, timeout)
333 int fd;
334 u_char *ptr;
335 int nbytes;
336 int timeout;
337 {
338     int nleft, nread;
339     fd_set readfds, exceptfds;
340     struct timeval tout;
341
342     tout.tv_sec = timeout;
343     tout.tv_usec = 0;
344
345     FD_ZERO(&readfds);
346     FD_SET(fd, &readfds);
347
348     FD_ZERO(&exceptfds);
349     FD_SET(fd, &exceptfds);
350
351     nleft = nbytes;
352
353     while (nleft > 0) {
354         int status = select(fd + 1, &readfds, (fd_set *) NULL,
355                             &exceptfds, &tout);
356
357         if (status == 0) {
358             report(LOG_DEBUG, "%s: timeout reading fd %d", session.peer, fd);
359             return(-1);
360         }
361         if (status < 0) {
362             if (errno == EINTR)
363                 continue;
364             report(LOG_DEBUG, "%s: error in select %s fd %d",
365                    session.peer, sys_errlist[errno], fd);
366             return (-1);
367         }
368         if (FD_ISSET(fd, &exceptfds)) {
369             report(LOG_DEBUG, "%s: exception on fd %d",
370                    session.peer, fd);
371             return (-1);
372         }
373         if (!FD_ISSET(fd, &readfds)) {
374             report(LOG_DEBUG, "%s: spurious return from select",
375                    session.peer);
376             continue;
377         }
378     again:
379         nread = read(fd, ptr, nleft);
380
381         if (nread < 0) {
382             if (errno == EINTR)
383                 goto again;
384             report(LOG_DEBUG, "%s %s: error reading fd %d nread=%d %s",
385                    session.peer, session.port, fd, nread, sys_errlist[errno]);
386             return (-1);        /* error */
387
388         } else if (nread == 0) {
389             report(LOG_DEBUG, "%s %s: fd %d eof (connection closed)",
390                    session.peer, session.port, fd);
391             return (-1);        /* eof */
392         }
393         nleft -= nread;
394         if (nleft)
395             ptr += nread;
396     }
397     return (nbytes - nleft);
398 }
399
400 /* Write n bytes to descriptor fd from array ptr with timeout t
401  * seconds. Note the timeout is applied to each write, not for the
402  * overall operation.
403  *
404  * Return -1 on error, eof or timeout. Otherwise return number of
405  * bytes written. */
406
407 static int sockwrite TAC_ARGS((int fd, u_char *ptr, int bytes, int timeout));
408
409 static int
410 sockwrite(fd, ptr, bytes, timeout)
411 int fd;
412 u_char *ptr;
413 int bytes;
414 int timeout;
415 {
416     int remaining, sent;
417     fd_set writefds, exceptfds;
418     struct timeval tout;
419
420     sent = 0;
421
422     tout.tv_sec = timeout;
423     tout.tv_usec = 0;
424
425     FD_ZERO(&writefds);
426     FD_SET(fd, &writefds);
427
428     FD_ZERO(&exceptfds);
429     FD_SET(fd, &exceptfds);
430
431     remaining = bytes;
432
433     while (remaining > 0) {
434         int status = select(fd + 1, (fd_set *) NULL,
435                             &writefds, &exceptfds, &tout);
436
437         if (status == 0) {
438             report(LOG_DEBUG, "%s: timeout writing to fd %d",
439                    session.peer, fd);
440             return (-1);
441         }
442         if (status < 0) {
443             report(LOG_DEBUG, "%s: error in select fd %d",
444                    session.peer, fd);
445             return (-1);
446         }
447         if (FD_ISSET(fd, &exceptfds)) {
448             report(LOG_DEBUG, "%s: exception on fd %d",
449                    session.peer, fd);
450             return (sent);      /* error */
451         }
452
453         if (!FD_ISSET(fd, &writefds)) {
454             report(LOG_DEBUG, "%s: spurious return from select",
455                    session.peer);
456             continue;
457         }
458         sent = write(fd, ptr, remaining);
459
460         if (sent <= 0) {
461             report(LOG_DEBUG, "%s: error writing fd %d sent=%d",
462                    session.peer, fd, sent);
463             return (sent);      /* error */
464         }
465         remaining -= sent;
466         ptr += sent;
467     }
468     return (bytes - remaining);
469 }
470
471 static const char *get_session_key TAC_ARGS((void));
472
473 static const char *
474 get_session_key()
475 {
476     const char *retval = NULL;
477
478     if ((retval = cfg_get_host_key(session.peer_addr)))
479         return (retval);
480     if (session.peer_addr != session.peer
481      && (retval = cfg_get_host_key(session.peer     )))
482         return (retval);
483     return (session.key);
484 }
485
486 /* read a packet from the wire, and decrypt it. Increment the global
487  seq_no return NULL on failure */
488
489 u_char *read_packet TAC_ARGS((void));
490
491 u_char *
492 read_packet()
493 {
494     HDR hdr;
495     u_char *pkt, *data;
496     int len;
497
498     if (debug & DEBUG_PACKET_FLAG)
499         report(LOG_DEBUG, "Waiting for packet");
500
501     /* read a packet header */
502     len = sockread(session.sock, (u_char *) & hdr, TAC_PLUS_HDR_SIZE, TAC_PLUS_READ_TIMEOUT);
503     if (len != TAC_PLUS_HDR_SIZE) {
504         report(LOG_DEBUG, "Read %d bytes from %s %s, expecting %d",
505                len, session.peer, session.port, TAC_PLUS_HDR_SIZE);
506         return(NULL);
507     }
508
509     if ((hdr.version & TAC_PLUS_MAJOR_VER_MASK) != TAC_PLUS_MAJOR_VER) {
510         report(LOG_ERR,
511                "%s: Illegal major version specified: found %d wanted %d\n",
512                session.peer, hdr.version, TAC_PLUS_MAJOR_VER);
513         return(NULL);
514     }
515
516     /* get memory for the packet */
517     len = TAC_PLUS_HDR_SIZE + ntohl(hdr.datalength);
518     if ((ntohl(hdr.datalength) & ~0xffffUL) ||
519        len < TAC_PLUS_HDR_SIZE || len > 0x10000) {
520        report(LOG_ERR,
521               "%s: Illegal data size: %lu\n",
522               session.peer, (unsigned long) ntohl(hdr.datalength));
523        return(NULL);
524     }
525     pkt = (u_char *) tac_malloc(len);
526
527     /* initialise the packet */
528     bcopy(&hdr, pkt, TAC_PLUS_HDR_SIZE);
529
530     /* the data start here */
531     data = pkt + TAC_PLUS_HDR_SIZE;
532
533     /* read the rest of the packet data */
534     if ((unsigned long)sockread(session.sock, data, ntohl(hdr.datalength),
535                  TAC_PLUS_READ_TIMEOUT) !=
536         (unsigned long) ntohl(hdr.datalength)) {
537         report(LOG_ERR, "%s: start_session: bad socket read", session.peer);
538         return (NULL);
539     }
540     session.seq_no++;           /* should now equal that of incoming packet */
541     session.last_exch = time(NULL);
542
543     if (session.seq_no != hdr.seq_no) {
544         report(LOG_ERR, "%s: Illegal session seq # %d != packet seq # %d",
545                session.peer,
546                session.seq_no, hdr.seq_no);
547         return (NULL);
548     }
549
550     /* decrypt the data portion */
551     if (md5_xor((HDR *)pkt, data, get_session_key())) {
552         report(LOG_ERR, "%s: start_session error decrypting data",
553                session.peer);
554         return (NULL);
555     }
556
557     if (debug & DEBUG_PACKET_FLAG)
558         report(LOG_DEBUG, "Read %s size=%d",
559                summarise_incoming_packet_type(pkt), len);
560
561     session.version = hdr.version;
562
563     return (pkt);
564 }
565
566 static int write_packet TAC_ARGS((u_char *pak));
567
568 /* write a packet to the wire, encrypting it */
569 static int
570 write_packet(pak)
571 u_char *pak;
572 {
573     HDR *hdr = (HDR *) pak;
574     u_char *data;
575     int len;
576
577     len = TAC_PLUS_HDR_SIZE + ntohl(hdr->datalength);
578
579     /* the data start here */
580     data = pak + TAC_PLUS_HDR_SIZE;
581
582     /* encrypt the data portion */
583     if (md5_xor((HDR *)pak, data, get_session_key())) {
584         report(LOG_ERR, "%s: write_packet: error encrypting data", session.peer);
585         return (-1);
586     }
587
588     if (sockwrite(session.sock, pak, len, TAC_PLUS_WRITE_TIMEOUT) != len) {
589         return (-1);
590     }
591     session.last_exch = time(NULL);
592     return (0);
593 }
594
595 void send_error_reply TAC_ARGS((int type, char *msg));
596
597 void
598 send_error_reply(type, msg)
599 int type;
600 char *msg;
601 {
602     switch (type) {
603     case TAC_PLUS_AUTHEN:
604         send_authen_error(msg);
605         return;
606
607     case TAC_PLUS_AUTHOR:
608         send_author_reply(AUTHOR_STATUS_ERROR, msg, NULL, 0, NULL);
609         return;
610
611     case TAC_PLUS_ACCT:
612         send_acct_reply(TAC_PLUS_ACCT_STATUS_ERROR, msg, NULL);
613         return;
614
615     default:
616         report(LOG_ERR, "Illegal type %d for send_error_reply", type);
617         return;
618     }
619 }