Import of tac_plus.v8.tar.gz: 173206 bytes, md5:
[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 #include "tac_plus.h"
21
22 /* Everything to do with reading and writing packets */
23
24 /* send an accounting response packet */
25 send_acct_reply(status, msg, data)
26     u_char status;
27     char *msg, *data;
28 {
29     u_char *pak, *p;
30     HDR *hdr;
31     int len;
32     struct acct_reply *reply;
33     int msg_len, data_len;
34
35     msg_len = msg ? strlen(msg) : 0;
36     data_len = data ? strlen(data) : 0;
37
38     len = TAC_PLUS_HDR_SIZE + TAC_ACCT_REPLY_FIXED_FIELDS_SIZE + msg_len + data_len;
39
40     pak = (u_char *) tac_malloc(len);
41     reply = (struct acct_reply *) (pak + TAC_PLUS_HDR_SIZE);
42     hdr = (HDR *) pak;
43
44     bzero(pak, len);
45
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);
52
53     reply->status = status;
54     reply->msg_len  = msg_len;
55     reply->data_len = data_len;
56
57     p = pak + TAC_PLUS_HDR_SIZE + TAC_ACCT_REPLY_FIXED_FIELDS_SIZE;
58     bcopy(msg, p, msg_len);
59     p += msg_len;
60
61     bcopy(data, p, data_len);
62
63     if (debug & DEBUG_PACKET_FLAG) {
64         report(LOG_DEBUG, "Writing %s size=%d",
65                summarise_outgoing_packet_type(pak), len);
66         dump_tacacs_pak(pak);
67     }
68
69     reply->msg_len = ntohs(reply->msg_len);
70     reply->data_len = ntohs(reply->data_len);
71
72     write_packet(pak);
73     free(pak);
74 }
75
76 /* send an authorization reply packet */
77 send_author_reply(status, msg, data, arg_cnt, args)
78 u_char status;
79 char *msg;
80 char *data;
81 int arg_cnt;
82 char **args;
83 {
84     u_char *pak, *p;
85     HDR *hdr;
86     struct author_reply *reply;
87     int msg_len;
88     int len;
89     int data_len;
90     int i;
91
92     data_len = (data ? strlen(data) : 0);
93     msg_len  = (msg  ? strlen(msg)  : 0);
94
95     /* start calculating final packet size */
96     len = TAC_PLUS_HDR_SIZE + TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE + msg_len +
97         data_len;
98
99     for (i=0; i < arg_cnt; i++) {
100         /* space for the arg and its length */
101         len += strlen(args[i]) + 1;
102     }
103
104     pak = (u_char *) tac_malloc(len);
105
106     bzero(pak, len);
107
108     hdr = (HDR *) pak;
109
110     reply = (struct author_reply *) (pak + TAC_PLUS_HDR_SIZE);
111
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);
118
119     reply->status   = status;
120     reply->msg_len  = msg_len;
121     reply->data_len = data_len;
122     reply->arg_cnt  = arg_cnt;
123
124     p = pak + TAC_PLUS_HDR_SIZE + TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE;
125
126     /* place arg sizes into packet  */
127     for (i=0; i < arg_cnt; i++) {
128         *p++ = strlen(args[i]);
129     }
130
131     bcopy(msg, p, msg_len);
132     p += msg_len;
133
134     bcopy(data, p, data_len);
135     p += data_len;
136
137     /* copy arg bodies into packet */
138     for (i=0; i < arg_cnt; i++) {
139         int arglen = strlen(args[i]);
140
141         bcopy(args[i], p, arglen);
142         p += arglen;
143     }
144
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); 
149     }
150     
151     reply->msg_len  = htons(reply->msg_len);
152     reply->data_len = htons(reply->data_len);
153
154     write_packet(pak);
155     free(pak);
156 }
157
158
159 /* Send an authentication reply packet indicating an error has
160    occurred. msg is a null terminated character string */
161
162 send_authen_error(msg)
163 char *msg;
164 {
165     char buf[255];
166
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,
170                       buf,
171                       strlen(buf),
172                       NULL,
173                       0,
174                       0);
175 }
176
177 /* create and send an authentication reply packet from tacacs+ to a NAS */
178
179 send_authen_reply(status, msg, msg_len, data, data_len, flags)
180 int status;
181 char *msg;
182 u_short msg_len;
183 char *data;
184 u_short data_len;
185 u_char flags;
186 {
187     u_char *pak, *p;
188     HDR *hdr;
189     struct authen_reply *reply;
190
191     int len = TAC_PLUS_HDR_SIZE + TAC_AUTHEN_REPLY_FIXED_FIELDS_SIZE + msg_len + data_len;
192
193     pak = (u_char *) tac_malloc(len);
194     bzero(pak, len);
195
196     hdr = (HDR *) pak;
197     reply = (struct authen_reply *) (pak + TAC_PLUS_HDR_SIZE);
198
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);
205
206     reply->status = status;
207     reply->msg_len = msg_len;
208     reply->data_len = data_len;
209     reply->flags = flags;
210
211     p = pak + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_REPLY_FIXED_FIELDS_SIZE;
212
213     bcopy(msg, p, msg_len);
214     p += msg_len;
215     bcopy(data, p, data_len);
216
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);
221     }
222
223     reply->msg_len = htons(reply->msg_len);
224     reply->data_len = htons(reply->data_len);
225
226     write_packet(pak);
227     free(pak);
228 }
229
230
231 /* read an authentication GETDATA packet from a NAS. Return 0 on failure */
232 u_char *
233 get_authen_continue()
234 {
235     HDR *hdr;
236     u_char *pak, *read_packet();
237     struct authen_cont *cont;
238     char msg[255];
239
240     pak = read_packet();
241     if (!pak)
242         return(NULL);
243     hdr = (HDR *) pak;
244     cont = (struct authen_cont *) (pak + TAC_PLUS_HDR_SIZE);
245
246     if ((hdr->type != TAC_PLUS_AUTHEN) || (hdr->seq_no <= 1)) {
247         sprintf(msg,
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);
252         return(NULL);
253     }
254
255     cont->user_msg_len  = ntohs(cont->user_msg_len);
256     cont->user_data_len = ntohs(cont->user_data_len);
257
258     if (TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE + 
259         cont->user_msg_len + 
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);
265         return(NULL);
266     }
267
268     if (debug & DEBUG_PACKET_FLAG)
269         dump_nas_pak(pak);
270
271     return (pak);
272 }
273
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
276  * overall operation.
277  *
278  * Return -1 on error, eof or timeout. Otherwise return number of
279  * bytes read. */
280
281 int
282 sockread(fd, ptr, nbytes, timeout)
283 int fd;
284 u_char *ptr;
285 int nbytes;
286 int timeout;
287 {
288     int nleft, nread;
289     fd_set readfds, exceptfds;
290     struct timeval tout;
291
292     tout.tv_sec = timeout;
293     tout.tv_usec = 0;
294
295     FD_ZERO(&readfds);
296     FD_SET(fd, &readfds);
297
298     FD_ZERO(&exceptfds);
299     FD_SET(fd, &exceptfds);
300
301     nleft = nbytes;
302
303     while (nleft > 0) {
304         int status = select(fd + 1, &readfds, (fd_set *) NULL, 
305                             &exceptfds, &tout);
306
307         if (status == 0) {
308             report(LOG_DEBUG, "%s: timeout reading fd %d", session.peer, fd);
309             return(-1);
310         }
311         if (status < 0) {
312             if (errno == EINTR)
313                 continue;
314             report(LOG_DEBUG, "%s: error in select %s fd %d", 
315                    session.peer, sys_errlist[errno], fd);
316             return (-1);
317         }
318         if (FD_ISSET(fd, &exceptfds)) {
319             report(LOG_DEBUG, "%s: exception on fd %d",
320                    session.peer, fd);
321             return (-1);
322         }
323         if (!FD_ISSET(fd, &readfds)) {
324             report(LOG_DEBUG, "%s: spurious return from select",
325                    session.peer);
326             continue;
327         }
328     again:
329         nread = read(fd, ptr, nleft);
330
331         if (nread < 0) {
332             if (errno == EINTR)
333                 goto again;
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 */
337
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 */
342         }
343         nleft -= nread;
344         if (nleft) 
345             ptr += nread;
346     }
347     return (nbytes - nleft);
348 }
349
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
352  * overall operation.
353  *
354  * Return -1 on error, eof or timeout. Otherwise return number of
355  * bytes written. */
356
357 int
358 sockwrite(fd, ptr, bytes, timeout)
359 int fd;
360 u_char *ptr;
361 int bytes;
362 int timeout;
363 {
364     int remaining, sent;
365     fd_set writefds, exceptfds;
366     struct timeval tout;
367
368     sent = 0;
369
370     tout.tv_sec = timeout;
371     tout.tv_usec = 0;
372
373     FD_ZERO(&writefds);
374     FD_SET(fd, &writefds);
375
376     FD_ZERO(&exceptfds);
377     FD_SET(fd, &exceptfds);
378
379     remaining = bytes;
380
381     while (remaining > 0) {
382         int status = select(fd + 1, (fd_set *) NULL, 
383                             &writefds, &exceptfds, &tout);
384
385         if (status == 0) {
386             report(LOG_DEBUG, "%s: timeout writing to fd %d", 
387                    session.peer, fd);
388             return (-1);
389         }
390         if (status < 0) {
391             report(LOG_DEBUG, "%s: error in select fd %d", 
392                    session.peer, fd);
393             return (-1);
394         }
395         if (FD_ISSET(fd, &exceptfds)) {
396             report(LOG_DEBUG, "%s: exception on fd %d",
397                    session.peer, fd);
398             return (sent);      /* error */
399         }
400
401         if (!FD_ISSET(fd, &writefds)) {
402             report(LOG_DEBUG, "%s: spurious return from select",
403                    session.peer);
404             continue;
405         }
406         sent = write(fd, ptr, remaining);
407
408         if (sent <= 0) {
409             report(LOG_DEBUG, "%s: error writing fd %d sent=%d", 
410                    session.peer, fd, sent);
411             return (sent);      /* error */
412         }
413         remaining -= sent;
414         ptr += sent;
415     }
416     return (bytes - remaining);
417 }
418
419 /* read a packet from the wire, and decrypt it. Increment the global
420  seq_no return NULL on failure */
421
422 u_char *
423 read_packet()
424 {
425     HDR hdr;
426     u_char *pkt, *data;
427     int len;
428     char *tkey;
429
430     if (debug & DEBUG_PACKET_FLAG)
431         report(LOG_DEBUG, "Waiting for packet");
432
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);
438         return(NULL);
439     }
440
441     if ((hdr.version & TAC_PLUS_MAJOR_VER_MASK) != TAC_PLUS_MAJOR_VER) {
442         report(LOG_ERR, 
443                "%s: Illegal major version specified: found %d wanted %d\n",
444                session.peer, hdr.version, TAC_PLUS_MAJOR_VER);
445         return(NULL);
446     }
447
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) {
452        report(LOG_ERR,
453               "%s: Illegal data size: %lu\n",
454               session.peer, ntohl(hdr.datalength));
455        return(NULL);
456     }
457     pkt = (u_char *) tac_malloc(len);
458
459     /* initialise the packet */
460     bcopy(&hdr, pkt, TAC_PLUS_HDR_SIZE);
461
462     /* the data start here */
463     data = pkt + TAC_PLUS_HDR_SIZE;
464
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);
470         return (NULL);
471     }
472     session.seq_no++;           /* should now equal that of incoming packet */
473     session.last_exch = time(NULL);
474
475     if (session.seq_no != hdr.seq_no) {
476         report(LOG_ERR, "%s: Illegal session seq # %d != packet seq # %d",
477                session.peer,
478                session.seq_no, hdr.seq_no);
479         return (NULL);
480     }
481
482     /* decrypt the data portion */
483     if ( !(tkey=(char *)cfg_get_host_key(session.peer)) )
484                 tkey = session.key;     
485
486     if (md5_xor((HDR *)pkt, data, tkey)) {
487         report(LOG_ERR, "%s: start_session error decrypting data",
488                session.peer);
489         return (NULL);
490     }
491
492     if (debug & DEBUG_PACKET_FLAG)
493         report(LOG_DEBUG, "Read %s size=%d",
494                summarise_incoming_packet_type(pkt), len);
495
496     session.version = hdr.version;
497
498     return (pkt);
499 }
500
501 /* write a packet to the wire, encrypting it */
502 write_packet(pak)
503 u_char *pak;
504 {
505     HDR *hdr = (HDR *) pak;
506     u_char *data;
507     int len;
508     char *tkey;
509
510     len = TAC_PLUS_HDR_SIZE + ntohl(hdr->datalength);
511
512     /* the data start here */
513     data = pak + TAC_PLUS_HDR_SIZE;
514
515     /* encrypt the data portion */
516    if ( !(tkey=(char *)cfg_get_host_key(session.peer)) )
517                 tkey = session.key;
518
519    if (md5_xor((HDR *)pak, data, tkey)) {
520         report(LOG_ERR, "%s: write_packet: error encrypting data", session.peer);
521         return (-1);
522     }
523
524     if (sockwrite(session.sock, pak, len, TAC_PLUS_WRITE_TIMEOUT) != len) {
525         return (-1);
526     }
527     session.last_exch = time(NULL);
528     return (0);
529 }
530
531 send_error_reply(type, msg)
532 int type;
533 char *msg;
534 {
535     switch (type) {
536     case TAC_PLUS_AUTHEN:
537         send_authen_error(msg);
538         return;
539
540     case TAC_PLUS_AUTHOR:
541         send_author_reply(AUTHOR_STATUS_ERROR, msg, NULL, 0, NULL);
542         return;
543
544     case TAC_PLUS_ACCT:
545         send_acct_reply(TAC_PLUS_ACCT_STATUS_ERROR, msg, NULL);
546         return;
547
548     default:
549         report(LOG_ERR, "Illegal type %d for send_error_reply", type);
550         return;
551     }
552 }