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.
23 static void authenticate();
24 static void do_start();
27 * Come here when we receive an authentication START packet
35 struct authen_start *start;
39 start = (struct authen_start *) (pak + TAC_PLUS_HDR_SIZE);
41 if ((hdr->seq_no != 1) ||
42 (ntohl(hdr->datalength) != TAC_AUTHEN_START_FIXED_FIELDS_SIZE +
43 start->user_len + start->port_len + start->rem_addr_len +
45 send_authen_error("Invalid AUTHEN/START packet (check keys)");
49 switch (start->action) {
50 case TAC_PLUS_AUTHEN_LOGIN:
51 case TAC_PLUS_AUTHEN_SENDAUTH:
52 case TAC_PLUS_AUTHEN_SENDPASS:
57 sprintf(msg, "Invalid AUTHEN/START action=%d", start->action);
58 send_authen_error(msg);
64 * We have a valid AUTHEN/START packet. Fill out data structures and
65 * attempt to authenticate.
72 struct identity identity;
73 struct authen_data authen_data;
74 struct authen_type authen_type;
75 struct authen_start *start;
79 if (debug & DEBUG_PACKET_FLAG)
80 report(LOG_DEBUG, "Authen Start request");
82 /* fixed fields of this packet */
83 start = (struct authen_start *) (pak + TAC_PLUS_HDR_SIZE);
85 /* variable length data starts here */
86 p = pak + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_START_FIXED_FIELDS_SIZE;
88 /* The identity structure */
90 /* zero out identity struct so that all strings can be NULL terminated */
91 bzero(&identity, sizeof(struct identity));
93 identity.username = tac_make_string(p, (int)start->user_len);
96 identity.NAS_name = tac_strdup(session.peer);
98 identity.NAS_port = tac_make_string(p, (int)start->port_len);
101 if (start->port_len <= 0) {
102 strcpy(session.port, "unknown-port");
104 strcpy(session.port, identity.NAS_port);
107 identity.NAC_address = tac_make_string(p, (int)start->rem_addr_len);
108 p += start->rem_addr_len;
110 identity.priv_lvl = start->priv_lvl;
112 /* The authen_data structure */
114 bzero(&authen_data, sizeof(struct authen_data));
116 authen_data.NAS_id = &identity;
117 authen_data.action = start->action;
118 authen_data.service = start->service;
119 authen_data.type = start->authen_type;
120 authen_data.client_dlen = start->data_len;
122 authen_data.client_data = tac_malloc(start->data_len);
123 bcopy(p, authen_data.client_data, start->data_len);
125 /* The authen_type structure */
127 bzero(&authen_type, sizeof(struct authen_type));
129 authen_type.authen_type = start->authen_type;
131 /* All data structures are now initialised. Now see if we can
132 * authenticate this puppy. Begin by choosing a suitable
133 * authentication function to call to actually do the work. */
136 if (check_from_wrap(&identity)) {
138 ret = choose(&authen_data, &authen_type);
142 /* A successful choice. Authenticate */
143 authenticate(&authen_data, &authen_type);
147 /* We lost our connection, aborted, or something dreadful happened */
152 send_authen_error("You are not allowed to access here");
155 /* free data structures */
156 if (authen_data.server_msg) {
157 free(authen_data.server_msg);
158 authen_data.server_msg = NULL;
160 if (authen_data.server_data) {
161 free(authen_data.server_data);
162 authen_data.server_data = NULL;
164 if (authen_data.client_msg) {
165 free(authen_data.client_msg);
166 authen_data.client_msg = NULL;
168 if (authen_data.client_data) {
169 free(authen_data.client_data);
170 authen_data.client_data = NULL;
172 if (authen_data.method_data) {
174 "%s: Method data not set to NULL after authentication",
177 free(identity.username);
178 free(identity.NAS_name);
179 free(identity.NAS_port);
180 free(identity.NAC_address);
184 /* Choose an authentication function. Return 1 if we successfully
185 chose a function. 0 if we couldn't make a choice for some reason */
189 struct authen_data *datap;
190 struct authen_type *typep;
195 struct authen_cont *cont;
198 struct identity *identp;
202 /* check interation counter here */
204 if (++iterations >= TAC_PLUS_MAX_ITERATIONS) {
205 report(LOG_ERR, "%s: %s Too many iterations for choose_authen",
210 status = choose_authen(datap, typep);
212 if (status && (debug & DEBUG_PACKET_FLAG))
213 report(LOG_DEBUG, "choose_authen returns %d", status);
217 case CHOOSE_BADTYPE: /* FIXME */
219 send_authen_error("choose_authen: unexpected failure return");
223 if (debug & DEBUG_PACKET_FLAG)
224 report(LOG_DEBUG, "choose_authen chose %s", typep->authen_name);
228 send_authen_error("choose_authen: unacceptable authen method");
232 /* respond with GETUSER containing an optional message from
233 * authen_data.server_msg. */
235 datap->status = TAC_PLUS_AUTHEN_STATUS_GETUSER;
236 if (datap->service == TAC_PLUS_AUTHEN_SVC_LOGIN) {
237 prompt = "\nUser Access Verification\n\nUsername: ";
239 prompt = "Username: ";
241 send_authen_reply(TAC_PLUS_AUTHEN_STATUS_GETUSER, /* status */
243 strlen(prompt), /* msg_len */
248 if (datap->server_data) {
249 free(datap->server_data);
250 datap->server_dlen = 0;
252 /* expect a CONT from the NAS */
253 reply = get_authen_continue();
255 /* Typically premature close of connection */
256 report(LOG_ERR, "%s %s: Null reply packet, expecting CONTINUE",
257 session.peer, session.port);
261 cont = (struct authen_cont *) (reply + TAC_PLUS_HDR_SIZE);
263 if (cont->flags & TAC_PLUS_CONTINUE_FLAG_ABORT) {
268 if (cont->user_data_len) {
269 /* An abort message exists. Log it */
270 p = reply + TAC_PLUS_HDR_SIZE +
271 TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE + cont->user_msg_len;
273 bcopy(p, buf, cont->user_data_len);
274 buf[cont->user_data_len] = '\0';
276 report(LOG_INFO, "%s %s: Login aborted by request -- msg: %s",
277 session.peer, session.port, buf);
282 p = reply + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE;
284 identp = datap->NAS_id;
286 if (identp->username) {
287 free(identp->username);
289 identp->username = tac_make_string(p, cont->user_msg_len);
296 /* Perform authentication assuming we have successfully chosen an
297 authentication method */
299 authenticate(datap, typep)
300 struct authen_data *datap;
301 struct authen_type *typep;
305 struct authen_cont *cont;
308 if (debug & DEBUG_PACKET_FLAG)
309 report(LOG_DEBUG, "Calling authentication function");
311 func = typep->authen_func;
314 send_authen_error("authenticate: cannot find function pointer");
322 if (++iterations >= TAC_PLUS_MAX_ITERATIONS) {
323 send_authen_error("Too many iterations while authenticating");
327 if ((*func) (datap)) {
328 send_authen_error("Unexpected authentication function failure");
332 switch (datap->status) {
335 send_authen_error("Illegal status value from authentication function");
338 case TAC_PLUS_AUTHEN_STATUS_PASS:
339 /* A successful authentication */
340 send_authen_reply(TAC_PLUS_AUTHEN_STATUS_PASS,
342 datap->server_msg ? strlen(datap->server_msg) : 0,
348 case TAC_PLUS_AUTHEN_STATUS_ERROR:
349 /* never supposed to happen. reply with a server_msg if any, and
351 send_authen_error(datap->server_msg ? datap->server_msg :
352 "authentication function: unspecified failure");
355 case TAC_PLUS_AUTHEN_STATUS_FAIL:
357 /* An invalid user/password combination */
358 send_authen_reply(TAC_PLUS_AUTHEN_STATUS_FAIL,
360 datap->server_msg ? strlen(datap->server_msg) : 0,
366 case TAC_PLUS_AUTHEN_STATUS_GETUSER:
367 case TAC_PLUS_AUTHEN_STATUS_GETPASS:
368 case TAC_PLUS_AUTHEN_STATUS_GETDATA:
370 /* ship GETPASS/GETDATA containing
371 * datap->server_msg to NAS. */
373 send_authen_reply(datap->status,
375 datap->server_msg ? strlen(datap->server_msg) : 0,
382 if (datap->server_msg) {
383 free(datap->server_msg);
384 datap->server_msg = NULL;
386 if (datap->server_data) {
387 free(datap->server_data);
388 datap->server_data = NULL;
390 if (datap->client_msg) {
391 free(datap->client_msg);
392 datap->client_msg = NULL;
394 reply = get_authen_continue();
397 /* Typically due to a premature connection close */
398 report(LOG_ERR, "%s %s: Null reply packet, expecting CONTINUE",
399 session.peer, session.port);
401 /* Tell the authentication function it should clean up
404 datap->flags |= TAC_PLUS_CONTINUE_FLAG_ABORT;
406 if (datap->method_data)
413 cont = (struct authen_cont *) (reply + TAC_PLUS_HDR_SIZE);
415 if (cont->flags & TAC_PLUS_CONTINUE_FLAG_ABORT) {
419 /* Tell the authentication function to clean up
420 its private data, if there is any */
422 datap->flags |= TAC_PLUS_CONTINUE_FLAG_ABORT;
423 if (datap->method_data)
427 if (cont->user_data_len) {
429 /* An abort message exists. Create a
430 null-terminated string for authen_data */
432 datap->client_data = (char *)
433 tac_malloc(cont->user_data_len + 1);
435 p = reply + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE +
438 bcopy(p, datap->client_data, cont->user_data_len);
439 datap->client_data[cont->user_data_len] = '\0';
446 p = reply + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE;
448 switch (datap->status) {
450 case TAC_PLUS_AUTHEN_STATUS_GETDATA:
451 case TAC_PLUS_AUTHEN_STATUS_GETPASS:
452 /* A response to our GETDATA/GETPASS request. Create a
453 * null-terminated string for authen_data */
454 datap->client_msg = (char *) tac_malloc(cont->user_msg_len + 1);
455 bcopy(p, datap->client_msg, cont->user_msg_len);
456 datap->client_msg[cont->user_msg_len] = '\0';
460 case TAC_PLUS_AUTHEN_STATUS_GETUSER:
462 report(LOG_ERR, "%s: authenticate: cannot happen",
464 send_authen_error("authenticate: cannot happen");