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 static int do_sendauth_fn();
25 static void outbound_chap();
27 static void outbound_mschap();
32 struct authen_data *data;
37 name = data->NAS_id->username;
39 if (STREQ(name, DEFAULT_USERNAME)) {
40 /* This username is only valid for authorization */
41 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
43 status = do_sendauth_fn(data);
48 case TAC_PLUS_AUTHEN_TYPE_CHAP:
53 case TAC_PLUS_AUTHEN_TYPE_MSCHAP:
58 case TAC_PLUS_AUTHEN_TYPE_PAP:
67 report(LOG_INFO, "%s-sendauth query for '%s' %s from %s %s",
69 name && name[0] ? name : "unknown",
70 session.peer, session.port,
71 (data->status == TAC_PLUS_AUTHEN_STATUS_PASS) ?
72 "accepted" : "rejected");
78 * For PAP we need to supply the outgoing PAP cleartext password.
79 * from the config file.
81 * For CHAP, we expect an id and a challenge. We will return an MD5 hash
82 * if we're successful,
84 * Return 0 if data->status is valid, otherwise 1
89 struct authen_data *data;
91 char *name, *exp_date;
93 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
95 /* We must have a username */
96 if (!data->NAS_id->username[0]) {
97 /* Missing username is a gross error */
98 data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
99 data->server_msg = tac_strdup("No username supplied");
100 report(LOG_ERR, "%s: No username for sendauth_fn", session.peer);
103 name = data->NAS_id->username;
105 switch (data->type) {
106 case TAC_PLUS_AUTHEN_TYPE_CHAP:
111 case TAC_PLUS_AUTHEN_TYPE_MSCHAP:
112 outbound_mschap(data);
116 case TAC_PLUS_AUTHEN_TYPE_PAP:
121 data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
122 report(LOG_ERR, "%s %s: %s Illegal data type for sendauth_fn",
123 session.peer, session.port, name);
127 exp_date = cfg_get_expires(name, TAC_PLUS_RECURSE);
128 set_expiration_status(exp_date, data);
134 struct authen_data *data;
136 char *secret, *p, *name;
138 name = data->NAS_id->username;
140 /* We must have a username */
142 data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
146 /* Return her secret outbound PAP info */
147 secret = cfg_get_opap_secret(name, TAC_PLUS_RECURSE);
149 if (debug & DEBUG_AUTHEN_FLAG) {
150 report(LOG_ERR, "%s %s: No opap secret for %s",
151 session.peer, session.port, name);
153 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
157 p = tac_find_substring("cleartext ", secret);
159 /* Should never happen */
160 data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
161 report(LOG_ERR, "%s %s: Illegal opap secret format %s",
162 session.peer, session.port, secret);
166 data->server_data = tac_strdup(p);
167 data->server_dlen = strlen(data->server_data);
168 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
173 struct authen_data *data;
175 char *name, *secret, *chal, digest[MD5_LEN];
182 name = data->NAS_id->username;
185 report(LOG_ERR, "%s %s: no username for outbound_chap",
186 session.peer, session.port);
187 data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
191 id = data->client_data[0];
193 chal_len = data->client_dlen - 1;
195 data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
199 if (debug & DEBUG_AUTHEN_FLAG) {
200 report(LOG_DEBUG, "%s %s: user %s, id=%d chal_len=%d",
201 session.peer, session.port, name, (int)id, chal_len);
205 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
208 secret = cfg_get_chap_secret(name, TAC_PLUS_RECURSE);
210 /* If there is no chap password for this user, see if there is
211 a global password for her that we can use */
213 secret = cfg_get_global_secret(name, TAC_PLUS_RECURSE);
217 /* No secret. Fail */
218 if (debug & DEBUG_AUTHEN_FLAG) {
219 report(LOG_DEBUG, "%s %s: No chap or global secret for %s",
220 session.peer, session.port, name);
222 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
227 p = tac_find_substring("cleartext ", secret);
229 /* Should never happen */
230 data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
231 report(LOG_ERR, "%s %s: Illegal opap secret format %s",
232 session.peer, session.port, secret);
238 * We now have the secret, the id, and the challenge value.
239 * Put them all together, and run them through the MD5 digest
242 inlen = sizeof(u_char) + strlen(secret) + chal_len;
243 mdp = (u_char *)tac_malloc(inlen);
245 bcopy(secret, &mdp[1], strlen(secret));
246 chal = data->client_data + 1;
247 bcopy(chal, mdp + strlen(secret) + 1, chal_len);
249 MD5Update(&mdcontext, mdp, inlen);
250 MD5Final((u_char *)digest, &mdcontext);
254 * Now return the calculated response value */
256 data->server_data = tac_malloc(MD5_LEN);
257 bcopy(digest, data->server_data, MD5_LEN);
258 data->server_dlen = MD5_LEN;
260 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
266 outbound_mschap(data)
267 struct authen_data *data;
269 char *name, *secret, *chal;
274 name = data->NAS_id->username;
277 report(LOG_ERR, "%s %s: no username for outbound_mschap",
278 session.peer, session.port);
279 data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
283 id = data->client_data[0];
285 chal_len = data->client_dlen - 1;
286 if (data->client_dlen <= 2) {
287 data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
291 if (debug & DEBUG_AUTHEN_FLAG) {
292 report(LOG_DEBUG, "%s %s: user %s, id=%d chal_len=%d",
293 session.peer, session.port, name, (int)id, chal_len);
297 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
300 secret = cfg_get_mschap_secret(name, TAC_PLUS_RECURSE);
302 /* If there is no chap password for this user, see if there is
303 a global password for her that we can use */
305 secret = cfg_get_global_secret(name, TAC_PLUS_RECURSE);
309 /* No secret. Fail */
310 if (debug & DEBUG_AUTHEN_FLAG) {
311 report(LOG_DEBUG, "%s %s: No ms-chap or global secret for %s",
312 session.peer, session.port, name);
314 data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
318 p = tac_find_substring("cleartext ", secret);
320 /* Should never happen */
321 data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
322 report(LOG_ERR, "%s %s: Illegal ms-chap secret format %s",
323 session.peer, session.port, secret);
329 * We now have the secret, the id, and the challenge value.
330 * Put them all together, and run them through the MD4 digest
333 chal = data->client_data + 1;
336 * Now return the calculated response value */
338 data->server_data = tac_malloc(MSCHAP_DIGEST_LEN);
340 mschap_lmchallengeresponse(chal,secret,&data->server_data[0]);
341 mschap_ntchallengeresponse(chal,secret,&data->server_data[24]);
343 data->server_data[48] = 1; /* Mark it to use the NT response*/
344 data->server_dlen = MSCHAP_DIGEST_LEN;
346 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;