Release bumped to "gts4".
[tac_plus.git] / authen.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
26 #include "authen.h"
27 #include "packet.h"
28 #include "report.h"
29 #include "utils.h"
30 #include "choose_authen.h"
31 #include "do_author.h"          /* for "struct identity" */
32 #include "main.h"
33 #include "cfgfile.h"
34
35 #ifdef TCPWRAPPER
36 #include "tcpwrap.h"
37 #endif
38
39
40 static void do_start TAC_ARGS((u_char *pak));
41 static int choose TAC_ARGS((struct authen_data *datap, struct authen_type *typep));
42 static void authenticate TAC_ARGS((struct authen_data *datap, struct authen_type *typep));
43
44
45 /* Configurable:
46  */
47
48 #define TAC_PLUS_MAX_ITERATIONS 50
49
50
51 /*
52  *  Come here when we receive an authentication START packet
53  */
54
55 void authen TAC_ARGS((u_char *pak));
56
57 void
58 authen(pak)
59 u_char *pak;
60 {
61     char msg[55];
62     struct authen_start *start;
63     HDR *hdr;
64
65     hdr = (HDR *) pak;
66     start = (struct authen_start *) (pak + TAC_PLUS_HDR_SIZE);
67
68     if ((hdr->seq_no != 1) ||
69         ((unsigned long) ntohl(hdr->datalength) != (unsigned long)(TAC_AUTHEN_START_FIXED_FIELDS_SIZE +
70          start->user_len + start->port_len + start->rem_addr_len +
71          start->data_len))) {
72         send_authen_error("Invalid AUTHEN/START packet (check keys)");
73         return;
74     }
75
76     switch (start->action) {
77     case TAC_PLUS_AUTHEN_LOGIN:
78     case TAC_PLUS_AUTHEN_SENDAUTH:
79     case TAC_PLUS_AUTHEN_SENDPASS:
80         do_start(pak);
81         return;
82
83     default:
84         sprintf(msg, "Invalid AUTHEN/START action=%d", start->action);
85         send_authen_error(msg);
86         return;
87     }
88 }
89
90 /*
91  * We have a valid AUTHEN/START packet. Fill out data structures and
92  * attempt to authenticate.
93  */
94
95 static void do_start TAC_ARGS((u_char *pak));
96
97 static void
98 do_start(pak)
99 u_char *pak;
100 {
101     struct identity identity;
102     struct authen_data authen_data;
103     struct authen_type authen_type;
104     struct authen_start *start;
105     u_char *p;
106     int ret;
107
108     if (debug & DEBUG_PACKET_FLAG)
109         report(LOG_DEBUG, "Authen Start request");
110
111     /* fixed fields of this packet */
112     start = (struct authen_start *) (pak + TAC_PLUS_HDR_SIZE);
113
114     /* variable length data starts here */
115     p = pak + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_START_FIXED_FIELDS_SIZE;
116
117     /* The identity structure */
118
119     /* zero out identity struct so that all strings can be NULL terminated */
120     bzero(&identity, sizeof(struct identity));
121
122     identity.username = tac_make_string(p, (int)start->user_len);
123     p += start->user_len;
124
125     identity.NAS_name = tac_strdup(session.peer);
126
127     identity.NAS_port = tac_make_string(p, (int)start->port_len);
128     p += start->port_len;
129
130     if (start->port_len <= 0) {
131         strcpy(session.port, "unknown-port");
132     } else {
133         strcpy(session.port, identity.NAS_port);
134     }
135
136     identity.NAC_address = tac_make_string(p, (int)start->rem_addr_len);
137     p += start->rem_addr_len;
138
139     identity.priv_lvl = start->priv_lvl;
140
141     cfg_request_identity(&identity);
142
143     /* The authen_data structure */
144
145     bzero(&authen_data, sizeof(struct authen_data));
146
147     authen_data.NAS_id      = &identity;
148     authen_data.action      = start->action;
149     authen_data.service     = start->service;
150     authen_data.type        = start->authen_type;
151     authen_data.client_dlen = start->data_len;
152
153     authen_data.client_data = tac_malloc(start->data_len);
154     bcopy(p, authen_data.client_data, start->data_len);
155
156     /* The authen_type structure */
157
158     bzero(&authen_type, sizeof(struct authen_type));
159
160     authen_type.authen_type = start->authen_type;
161
162     /* All data structures are now initialised. Now see if we can
163      * authenticate this puppy. Begin by choosing a suitable
164      * authentication function to call to actually do the work. */
165
166 #ifdef TCPWRAPPER
167 if (check_from_wrap(&identity)) {
168 #endif
169     ret = choose(&authen_data, &authen_type);
170
171     switch (ret) {
172     case 1:
173         /* A successful choice. Authenticate */
174         authenticate(&authen_data, &authen_type);
175         break;
176
177     case 0:
178         /* We lost our connection, aborted, or something dreadful happened */
179         break;
180     }
181 #ifdef TCPWRAPPER
182 } else {
183 send_authen_error("You are not allowed to access here");
184 }
185 #endif
186     /* free data structures */
187     if (authen_data.server_msg) {
188         free(authen_data.server_msg);
189         authen_data.server_msg = NULL;
190     }
191     if (authen_data.server_data) {
192         free(authen_data.server_data);
193         authen_data.server_data = NULL;
194     }
195     if (authen_data.client_msg) {
196         free(authen_data.client_msg);
197         authen_data.client_msg = NULL;
198     }
199     if (authen_data.client_data) {
200         free(authen_data.client_data);
201         authen_data.client_data = NULL;
202     }
203     if (authen_data.method_data) {
204         report(LOG_ERR,
205                "%s: Method data not set to NULL after authentication",
206                session.peer);
207     }
208     free(identity.username);
209     free(identity.NAS_name);
210     free(identity.NAS_port);
211     free(identity.NAC_address);
212     return;
213 }
214
215 /* Choose an authentication function. Return 1 if we successfully
216    chose a function.  0 if we couldn't make a choice for some reason */
217
218 static int choose TAC_ARGS((struct authen_data *datap, struct authen_type *typep));
219
220 static int
221 choose(datap, typep)
222 struct authen_data *datap;
223 struct authen_type *typep;
224 {
225     int iterations = 0;
226     int status;
227     char *prompt;
228     struct authen_cont *cont;
229     u_char *reply;
230     u_char *p;
231     struct identity *identp;
232
233     while (1) {
234
235         /* check interation counter here */
236
237         if (++iterations >= TAC_PLUS_MAX_ITERATIONS) {
238             report(LOG_ERR, "%s: %s Too many iterations for choose_authen",
239                    session.peer,
240                    session.port);
241             return (0);
242         }
243         status = choose_authen(datap, typep);
244
245         if (status && (debug & DEBUG_PACKET_FLAG))
246             report(LOG_DEBUG, "choose_authen returns %d", status);
247
248         switch (status) {
249
250         case CHOOSE_BADTYPE: /* FIXME */
251         default:
252             send_authen_error("choose_authen: unexpected failure return");
253             return (0);
254
255         case CHOOSE_OK:
256             if (debug & DEBUG_PACKET_FLAG)
257                 report(LOG_DEBUG, "choose_authen chose %s", typep->authen_name);
258             return (1);
259
260         case CHOOSE_FAILED:
261             send_authen_error("choose_authen: unacceptable authen method");
262             return (0);
263
264         case CHOOSE_GETUSER:
265             /* respond with GETUSER containing an optional message from
266              * authen_data.server_msg. */
267
268             datap->status = TAC_PLUS_AUTHEN_STATUS_GETUSER;
269             if (datap->service == TAC_PLUS_AUTHEN_SVC_LOGIN) {
270                 prompt = "\nUser Access Verification\n\nUsername: ";
271             } else {
272                 prompt = "Username: ";
273             }
274             send_authen_reply(TAC_PLUS_AUTHEN_STATUS_GETUSER, /* status */
275                               prompt, /* msg */
276                               strlen(prompt), /* msg_len */
277                               datap->server_data,
278                               datap->server_dlen,
279                               0 /* flags */);
280
281             if (datap->server_data) {
282                 free(datap->server_data);
283                 datap->server_dlen = 0;
284             }
285             /* expect a CONT from the NAS */
286             reply = get_authen_continue();
287             if (reply == NULL) {
288                 /* Typically premature close of connection */
289                 report(LOG_ERR, "%s %s: Null reply packet, expecting CONTINUE",
290                        session.peer, session.port);
291                 return (0);
292             }
293
294             cont = (struct authen_cont *) (reply + TAC_PLUS_HDR_SIZE);
295
296             if (cont->flags & TAC_PLUS_CONTINUE_FLAG_ABORT) {
297                 char buf[65537];
298                 buf[0] = '\0';
299                 session.aborted = 1;
300
301                 if (cont->user_data_len) {
302                     /* An abort message exists. Log it */
303                     p = reply + TAC_PLUS_HDR_SIZE +
304                         TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE + cont->user_msg_len;
305
306                     bcopy(p, buf, cont->user_data_len);
307                     buf[cont->user_data_len] = '\0';
308                 }
309                 report(LOG_INFO, "%s %s: Login aborted by request -- msg: %s",
310                        session.peer, session.port, buf);
311                 free(reply);
312                 return(0);
313             }
314
315             p = reply + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE;
316
317             identp = datap->NAS_id;
318
319             if (identp->username) {
320                 free(identp->username);
321             }
322             identp->username = tac_make_string(p, cont->user_msg_len);
323             free(reply);
324         }
325     }
326     /* NOTREACHED */
327 }
328
329 static void authenticate TAC_ARGS((struct authen_data *datap, struct authen_type *typep));
330
331 /* Perform authentication assuming we have successfully chosen an
332    authentication method */
333 static void
334 authenticate(datap, typep)
335 struct authen_data *datap;
336 struct authen_type *typep;
337 {
338     int iterations = 0;
339     u_char *reply, *p;
340     struct authen_cont *cont;
341     int (*func) TAC_ARGS((struct authen_data *data));
342
343     if (debug & DEBUG_PACKET_FLAG)
344         report(LOG_DEBUG, "Calling authentication function");
345
346     func = typep->authen_func;
347
348     if (!func) {
349         send_authen_error("authenticate: cannot find function pointer");
350         return;
351     }
352
353     while (1) {
354         if (session.aborted)
355             return;
356
357         if (++iterations >= TAC_PLUS_MAX_ITERATIONS) {
358             send_authen_error("Too many iterations while authenticating");
359             return;
360         }
361
362         if ((*func) (datap)) {
363             send_authen_error("Unexpected authentication function failure");
364             return;
365         }
366
367         switch (datap->status) {
368
369         default:
370             send_authen_error("Illegal status value from authentication function");
371             return;
372
373         case TAC_PLUS_AUTHEN_STATUS_PASS:
374             /* A successful authentication */
375             send_authen_reply(TAC_PLUS_AUTHEN_STATUS_PASS,
376                               datap->server_msg,
377                               datap->server_msg ? strlen(datap->server_msg) : 0,
378                               datap->server_data,
379                               datap->server_dlen,
380                               0);
381             return;
382
383         case TAC_PLUS_AUTHEN_STATUS_ERROR:
384             /* never supposed to happen. reply with a server_msg if any, and
385              * bail out */
386             send_authen_error(datap->server_msg ? datap->server_msg :
387                             "authentication function: unspecified failure");
388             return;
389
390         case TAC_PLUS_AUTHEN_STATUS_FAIL:
391
392             /* An invalid user/password combination */
393             send_authen_reply(TAC_PLUS_AUTHEN_STATUS_FAIL,
394                               datap->server_msg,
395                               datap->server_msg ? strlen(datap->server_msg) : 0,
396                               NULL,
397                               0,
398                               0);
399             return;
400
401         case TAC_PLUS_AUTHEN_STATUS_GETUSER:
402         case TAC_PLUS_AUTHEN_STATUS_GETPASS:
403         case TAC_PLUS_AUTHEN_STATUS_GETDATA:
404
405             /* ship GETPASS/GETDATA containing
406              * datap->server_msg to NAS. */
407
408             send_authen_reply(datap->status,
409                               datap->server_msg,
410                               datap->server_msg ? strlen(datap->server_msg) : 0,
411                               datap->server_data,
412                               datap->server_dlen,
413                               datap->flags);
414
415             datap->flags = 0;
416
417             if (datap->server_msg) {
418                 free(datap->server_msg);
419                 datap->server_msg = NULL;
420             }
421             if (datap->server_data) {
422                 free(datap->server_data);
423                 datap->server_data = NULL;
424             }
425             if (datap->client_msg) {
426                 free(datap->client_msg);
427                 datap->client_msg = NULL;
428             }
429             reply = get_authen_continue();
430             if (!reply) {
431
432                 /* Typically due to a premature connection close */
433                 report(LOG_ERR, "%s %s: Null reply packet, expecting CONTINUE",
434                        session.peer, session.port);
435
436                 /* Tell the authentication function it should clean up
437                    any private data */
438
439                 datap->flags |= TAC_PLUS_CONTINUE_FLAG_ABORT;
440
441                 if (datap->method_data)
442                     ((*func) (datap));
443
444                 datap->flags = 0;
445                 return;
446             }
447
448             cont = (struct authen_cont *) (reply + TAC_PLUS_HDR_SIZE);
449
450             if (cont->flags & TAC_PLUS_CONTINUE_FLAG_ABORT) {
451
452                 session.aborted = 1;
453
454                 /* Tell the authentication function to clean up
455                    its private data, if there is any */
456
457                 datap->flags |= TAC_PLUS_CONTINUE_FLAG_ABORT;
458                 if (datap->method_data)
459                     ((*func) (datap));
460                 datap->flags = 0;
461
462                 if (cont->user_data_len) {
463
464                     /* An abort message exists. Create a
465                        null-terminated string for authen_data */
466
467                     datap->client_data = (char *)
468                         tac_malloc(cont->user_data_len + 1);
469
470                     p = reply + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE +
471                         cont->user_msg_len;
472
473                     bcopy(p, datap->client_data, cont->user_data_len);
474                     datap->client_data[cont->user_data_len] = '\0';
475                 }
476
477                 free(reply);
478                 return;
479             }
480
481             p = reply + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE;
482
483             switch (datap->status) {
484
485             case TAC_PLUS_AUTHEN_STATUS_GETDATA:
486             case TAC_PLUS_AUTHEN_STATUS_GETPASS:
487                 /* A response to our GETDATA/GETPASS request. Create a
488                  * null-terminated string for authen_data */
489                 datap->client_msg = (char *) tac_malloc(cont->user_msg_len + 1);
490                 bcopy(p, datap->client_msg, cont->user_msg_len);
491                 datap->client_msg[cont->user_msg_len] = '\0';
492                 free(reply);
493                 continue;
494
495             case TAC_PLUS_AUTHEN_STATUS_GETUSER:
496             default:
497                 report(LOG_ERR, "%s: authenticate: cannot happen",
498                        session.peer);
499                 send_authen_error("authenticate: cannot happen");
500                 free(reply);
501                 return;
502             }
503         }
504         /* NOTREACHED */
505     }
506 }