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.
24 #include <netinet/in.h> /* for ntohl() */
30 #include "choose_authen.h"
31 #include "do_author.h" /* for "struct identity" */
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));
48 #define TAC_PLUS_MAX_ITERATIONS 50
52 * Come here when we receive an authentication START packet
55 void authen TAC_ARGS((u_char *pak));
62 struct authen_start *start;
66 start = (struct authen_start *) (pak + TAC_PLUS_HDR_SIZE);
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 +
72 send_authen_error("Invalid AUTHEN/START packet (check keys)");
76 switch (start->action) {
77 case TAC_PLUS_AUTHEN_LOGIN:
78 case TAC_PLUS_AUTHEN_SENDAUTH:
79 case TAC_PLUS_AUTHEN_SENDPASS:
84 sprintf(msg, "Invalid AUTHEN/START action=%d", start->action);
85 send_authen_error(msg);
91 * We have a valid AUTHEN/START packet. Fill out data structures and
92 * attempt to authenticate.
95 static void do_start TAC_ARGS((u_char *pak));
101 struct identity identity;
102 struct authen_data authen_data;
103 struct authen_type authen_type;
104 struct authen_start *start;
108 if (debug & DEBUG_PACKET_FLAG)
109 report(LOG_DEBUG, "Authen Start request");
111 /* fixed fields of this packet */
112 start = (struct authen_start *) (pak + TAC_PLUS_HDR_SIZE);
114 /* variable length data starts here */
115 p = pak + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_START_FIXED_FIELDS_SIZE;
117 /* The identity structure */
119 /* zero out identity struct so that all strings can be NULL terminated */
120 bzero(&identity, sizeof(struct identity));
122 identity.username = tac_make_string(p, (int)start->user_len);
123 p += start->user_len;
125 identity.NAS_name = tac_strdup(session.peer);
127 identity.NAS_port = tac_make_string(p, (int)start->port_len);
128 p += start->port_len;
130 if (start->port_len <= 0) {
131 strcpy(session.port, "unknown-port");
133 strcpy(session.port, identity.NAS_port);
136 identity.NAC_address = tac_make_string(p, (int)start->rem_addr_len);
137 p += start->rem_addr_len;
139 identity.priv_lvl = start->priv_lvl;
141 cfg_request_identity(&identity);
143 /* The authen_data structure */
145 bzero(&authen_data, sizeof(struct authen_data));
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;
153 authen_data.client_data = tac_malloc(start->data_len);
154 bcopy(p, authen_data.client_data, start->data_len);
156 /* The authen_type structure */
158 bzero(&authen_type, sizeof(struct authen_type));
160 authen_type.authen_type = start->authen_type;
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. */
167 if (check_from_wrap(&identity)) {
169 ret = choose(&authen_data, &authen_type);
173 /* A successful choice. Authenticate */
174 authenticate(&authen_data, &authen_type);
178 /* We lost our connection, aborted, or something dreadful happened */
183 send_authen_error("You are not allowed to access here");
186 /* free data structures */
187 if (authen_data.server_msg) {
188 free(authen_data.server_msg);
189 authen_data.server_msg = NULL;
191 if (authen_data.server_data) {
192 free(authen_data.server_data);
193 authen_data.server_data = NULL;
195 if (authen_data.client_msg) {
196 free(authen_data.client_msg);
197 authen_data.client_msg = NULL;
199 if (authen_data.client_data) {
200 free(authen_data.client_data);
201 authen_data.client_data = NULL;
203 if (authen_data.method_data) {
205 "%s: Method data not set to NULL after authentication",
208 free(identity.username);
209 free(identity.NAS_name);
210 free(identity.NAS_port);
211 free(identity.NAC_address);
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 */
218 static int choose TAC_ARGS((struct authen_data *datap, struct authen_type *typep));
222 struct authen_data *datap;
223 struct authen_type *typep;
228 struct authen_cont *cont;
231 struct identity *identp;
235 /* check interation counter here */
237 if (++iterations >= TAC_PLUS_MAX_ITERATIONS) {
238 report(LOG_ERR, "%s: %s Too many iterations for choose_authen",
243 status = choose_authen(datap, typep);
245 if (status && (debug & DEBUG_PACKET_FLAG))
246 report(LOG_DEBUG, "choose_authen returns %d", status);
250 case CHOOSE_BADTYPE: /* FIXME */
252 send_authen_error("choose_authen: unexpected failure return");
256 if (debug & DEBUG_PACKET_FLAG)
257 report(LOG_DEBUG, "choose_authen chose %s", typep->authen_name);
261 send_authen_error("choose_authen: unacceptable authen method");
265 /* respond with GETUSER containing an optional message from
266 * authen_data.server_msg. */
268 datap->status = TAC_PLUS_AUTHEN_STATUS_GETUSER;
269 if (datap->service == TAC_PLUS_AUTHEN_SVC_LOGIN) {
270 prompt = "\nUser Access Verification\n\nUsername: ";
272 prompt = "Username: ";
274 send_authen_reply(TAC_PLUS_AUTHEN_STATUS_GETUSER, /* status */
276 strlen(prompt), /* msg_len */
281 if (datap->server_data) {
282 free(datap->server_data);
283 datap->server_dlen = 0;
285 /* expect a CONT from the NAS */
286 reply = get_authen_continue();
288 /* Typically premature close of connection */
289 report(LOG_ERR, "%s %s: Null reply packet, expecting CONTINUE",
290 session.peer, session.port);
294 cont = (struct authen_cont *) (reply + TAC_PLUS_HDR_SIZE);
296 if (cont->flags & TAC_PLUS_CONTINUE_FLAG_ABORT) {
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;
306 bcopy(p, buf, cont->user_data_len);
307 buf[cont->user_data_len] = '\0';
309 report(LOG_INFO, "%s %s: Login aborted by request -- msg: %s",
310 session.peer, session.port, buf);
315 p = reply + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE;
317 identp = datap->NAS_id;
319 if (identp->username) {
320 free(identp->username);
322 identp->username = tac_make_string(p, cont->user_msg_len);
329 static void authenticate TAC_ARGS((struct authen_data *datap, struct authen_type *typep));
331 /* Perform authentication assuming we have successfully chosen an
332 authentication method */
334 authenticate(datap, typep)
335 struct authen_data *datap;
336 struct authen_type *typep;
340 struct authen_cont *cont;
341 int (*func) TAC_ARGS((struct authen_data *data));
343 if (debug & DEBUG_PACKET_FLAG)
344 report(LOG_DEBUG, "Calling authentication function");
346 func = typep->authen_func;
349 send_authen_error("authenticate: cannot find function pointer");
357 if (++iterations >= TAC_PLUS_MAX_ITERATIONS) {
358 send_authen_error("Too many iterations while authenticating");
362 if ((*func) (datap)) {
363 send_authen_error("Unexpected authentication function failure");
367 switch (datap->status) {
370 send_authen_error("Illegal status value from authentication function");
373 case TAC_PLUS_AUTHEN_STATUS_PASS:
374 /* A successful authentication */
375 send_authen_reply(TAC_PLUS_AUTHEN_STATUS_PASS,
377 datap->server_msg ? strlen(datap->server_msg) : 0,
383 case TAC_PLUS_AUTHEN_STATUS_ERROR:
384 /* never supposed to happen. reply with a server_msg if any, and
386 send_authen_error(datap->server_msg ? datap->server_msg :
387 "authentication function: unspecified failure");
390 case TAC_PLUS_AUTHEN_STATUS_FAIL:
392 /* An invalid user/password combination */
393 send_authen_reply(TAC_PLUS_AUTHEN_STATUS_FAIL,
395 datap->server_msg ? strlen(datap->server_msg) : 0,
401 case TAC_PLUS_AUTHEN_STATUS_GETUSER:
402 case TAC_PLUS_AUTHEN_STATUS_GETPASS:
403 case TAC_PLUS_AUTHEN_STATUS_GETDATA:
405 /* ship GETPASS/GETDATA containing
406 * datap->server_msg to NAS. */
408 send_authen_reply(datap->status,
410 datap->server_msg ? strlen(datap->server_msg) : 0,
417 if (datap->server_msg) {
418 free(datap->server_msg);
419 datap->server_msg = NULL;
421 if (datap->server_data) {
422 free(datap->server_data);
423 datap->server_data = NULL;
425 if (datap->client_msg) {
426 free(datap->client_msg);
427 datap->client_msg = NULL;
429 reply = get_authen_continue();
432 /* Typically due to a premature connection close */
433 report(LOG_ERR, "%s %s: Null reply packet, expecting CONTINUE",
434 session.peer, session.port);
436 /* Tell the authentication function it should clean up
439 datap->flags |= TAC_PLUS_CONTINUE_FLAG_ABORT;
441 if (datap->method_data)
448 cont = (struct authen_cont *) (reply + TAC_PLUS_HDR_SIZE);
450 if (cont->flags & TAC_PLUS_CONTINUE_FLAG_ABORT) {
454 /* Tell the authentication function to clean up
455 its private data, if there is any */
457 datap->flags |= TAC_PLUS_CONTINUE_FLAG_ABORT;
458 if (datap->method_data)
462 if (cont->user_data_len) {
464 /* An abort message exists. Create a
465 null-terminated string for authen_data */
467 datap->client_data = (char *)
468 tac_malloc(cont->user_data_len + 1);
470 p = reply + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE +
473 bcopy(p, datap->client_data, cont->user_data_len);
474 datap->client_data[cont->user_data_len] = '\0';
481 p = reply + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE;
483 switch (datap->status) {
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';
495 case TAC_PLUS_AUTHEN_STATUS_GETUSER:
497 report(LOG_ERR, "%s: authenticate: cannot happen",
499 send_authen_error("authenticate: cannot happen");