Release bumped to "gts4".
[tac_plus.git] / choose_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 "choose_authen.h"
24 #include "expire.h"
25 #include "enable.h"
26 #include "report.h"
27 #include "cfgfile.h"
28 #include "default_fn.h"
29 #include "default_v0_fn.h"
30 #include "sendauth.h"
31 #include "sendpass.h"
32 #include "packet.h"
33 #include "main.h"
34 #include "do_author.h"                  /* for "struct identity" */
35
36 #ifdef SKEY
37 #include "skey_fn.h"
38 #endif
39
40
41 static int choose_sendpass TAC_ARGS((struct authen_data *data, struct authen_type *type));
42 static int choose_sendauth TAC_ARGS((struct authen_data *data, struct authen_type *type));
43 static int choose_login TAC_ARGS((struct authen_data *data, struct authen_type *type));
44
45
46 #if 0 /* unused */
47 static int
48 get_minor_version()
49 {
50     return(session.version & ~TAC_PLUS_MAJOR_VER_MASK);
51 }
52 #endif /* unused */
53
54 /*
55  * Choose an authentication function. Return CHOOSE_OK if chosen,
56  * CHOOSE_GETUSER if we need a username, CHOOSE_FAILED on failure
57  */
58
59 int choose_authen TAC_ARGS((struct authen_data *data, struct authen_type *type));
60
61 int
62 choose_authen(data, type)
63 struct authen_data *data;
64 struct authen_type *type;
65 {
66     char *name = data->NAS_id->username;
67
68     switch (data->action) {
69     case TAC_PLUS_AUTHEN_SENDPASS:
70         return(choose_sendpass(data, type));
71
72     case TAC_PLUS_AUTHEN_SENDAUTH:
73         return(choose_sendauth(data, type));
74
75     case TAC_PLUS_AUTHEN_LOGIN:
76         /* For enabling, enable_fn handles everything. Must be minor
77          * version zero
78          */
79         if (data->service == TAC_PLUS_AUTHEN_SVC_ENABLE) {
80             if (session.version != TAC_PLUS_VER_0) {
81                 /* must be version 0 */
82                 break;
83             }
84             type->authen_func = enable_fn;
85             strcpy(type->authen_name, "enable_fn");
86             return (CHOOSE_OK);
87         }
88         return(choose_login(data, type));
89
90     case TAC_PLUS_AUTHEN_CHPASS:
91         /* we don't support chpass */
92         return(CHOOSE_FAILED);
93
94     default:
95         break;
96     }
97
98     /* never heard of this lot */
99     report(LOG_ERR, "%s: %s %s Illegal packet ver=%d action=%d type=%d",
100            session.peer,
101            session.port,
102            name ? name : "<unknown>",
103            session.version,
104            data->action,
105            type->authen_type);
106
107     return(CHOOSE_FAILED);
108 }
109
110 static int choose_login TAC_ARGS((struct authen_data *data, struct authen_type *type));
111
112 /* Choose an authentication function for action == LOGIN, service != enable */
113 static int
114 choose_login(data, type)
115 struct authen_data *data;
116 struct authen_type *type;
117 {
118     const char *name = data->NAS_id->username;
119     const char *cfg_passwd;
120
121     switch(type->authen_type) {
122     case TAC_PLUS_AUTHEN_TYPE_ASCII:
123         if (session.version != TAC_PLUS_VER_0) {
124             break;
125         }
126
127         if (!name[0]) {
128             /* request a user name if not already supplied */
129             return (CHOOSE_GETUSER);
130         }
131
132         /* Does this user require s/key? */
133         cfg_passwd = cfg_get_login_secret(name, TAC_PLUS_RECURSE);
134         if (cfg_passwd && STREQ(cfg_passwd, "skey")) {
135             if (debug & DEBUG_PASSWD_FLAG)
136                 report(LOG_DEBUG, "%s %s: user %s requires skey",
137                        session.peer, session.port, name);
138 #ifdef SKEY
139             type->authen_func = skey_fn;
140             strcpy(type->authen_name, "skey_fn");
141             return (CHOOSE_OK);
142 #else /* SKEY */
143             report(LOG_ERR,
144                    "%s %s: user %s s/key support has not been compiled in",
145                    name ? name : "<unknown>",
146                    session.peer, session.port);
147             return(CHOOSE_FAILED);
148 #endif  /* SKEY */
149         }
150
151         /* Not an skey user. Must be none, des, cleartext or file password */
152         type->authen_func = default_fn;
153         strcpy(type->authen_name, "default_fn");
154         return (CHOOSE_OK);
155
156     case TAC_PLUS_AUTHEN_TYPE_ARAP:
157 #ifndef ARAP_DES
158         /*
159          * If we have no des code we can't do ARAP via SENDAUTH. We'll
160          * have to do it via SENDPASS. Return a down-rev reply
161          * packet and hope the NAS is smart enough to deal with it.
162          */
163         session.version = TAC_PLUS_VER_0;
164         report(LOG_ERR, "%s %s: user %s DES is unavailable",
165                name ? name : "<unknown>", session.peer, session.port);
166         return (CHOOSE_FAILED);
167 #endif /* ARAP_DES */
168         /* FALLTHROUGH */
169
170 #ifdef MSCHAP
171     case TAC_PLUS_AUTHEN_TYPE_MSCHAP:
172 #ifndef MSCHAP_DES
173         /*
174          * If we have no des code we can't do MSCHAP via LOGIN. We'll
175          * have to do it via SENDPASS. Return a down-rev reply
176          * packet and hope the NAS is smart enough to deal with it.
177          */
178         session.version = TAC_PLUS_VER_0;
179         report(LOG_ERR, "%s %s: user %s DES is unavailable",
180                name ? name : "<unknown>", session.peer, session.port);
181         return (CHOOSE_FAILED);
182 #endif /* MSCHAP_DES */
183         /* FALLTHROUGH */
184 #endif /* MSCHAP */
185
186     case TAC_PLUS_AUTHEN_TYPE_PAP:
187     case TAC_PLUS_AUTHEN_TYPE_CHAP:
188         if (session.version == TAC_PLUS_VER_0) {
189             type->authen_func = default_v0_fn;
190             strcpy(type->authen_name, "default_v0_fn");
191             return (CHOOSE_OK);
192         }
193
194         /* Version 1 login/[pap|chap|arap].
195          * The username must in the initial START packet
196          */
197         if (!name[0]) {
198             report(LOG_ERR, "%s %s: No user in START packet for PAP/CHAP/ARAP",
199                    session.peer, session.port);
200             return (CHOOSE_FAILED);
201         }
202         type->authen_func = default_fn;
203         strcpy(type->authen_name, "default_fn");
204         return (CHOOSE_OK);
205
206     default:
207         break;
208     }
209
210     /* Illegal value combination */
211     report(LOG_ERR, "%s: %s %s Illegal packet ver=%d action=%d type=%d",
212            session.peer,
213            session.port,
214            name ? name : "<unknown>",
215            session.version,
216            data->action,
217            type->authen_type);
218     return(CHOOSE_FAILED);
219 }
220
221 static int choose_sendauth TAC_ARGS((struct authen_data *data, struct authen_type *type));
222
223 static int
224 choose_sendauth(data, type)
225 struct authen_data *data;
226 struct authen_type *type;
227 {
228     char *name = data->NAS_id->username;
229
230     switch (type->authen_type) {
231 #ifdef MSCHAP
232     case TAC_PLUS_AUTHEN_TYPE_MSCHAP:
233 #ifndef MSCHAP_DES
234         /*
235          * If we have no des code we can't do MSCHAP via SENDAUTH. We'll
236          * have to do it via SENDPASS. Return a down-rev reply
237          * packet and hope the NAS is smart enough to deal with it.
238          */
239         session.version = TAC_PLUS_VER_0;
240         report(LOG_ERR, "%s %s: user %s DES is unavailable",
241                name ? name : "<unknown>", session.peer, session.port);
242         return (CHOOSE_FAILED);
243 #endif /* MSCHAP_DES */
244         /* FALLTHROUGH */
245 #endif /* MSCHAP */
246
247     case TAC_PLUS_AUTHEN_TYPE_CHAP:
248     case TAC_PLUS_AUTHEN_TYPE_PAP:
249         /* Must be minor version 1 */
250         if (session.version != TAC_PLUS_VER_1) {
251             break;
252         }
253
254         /* The start packet must contain the username */
255         if (!name[0]) {
256             return (CHOOSE_FAILED);
257         }
258         type->authen_func = sendauth_fn;
259         strcpy(type->authen_name, "sendauth_fn");
260         return (CHOOSE_OK);
261
262     default:
263         break;
264     }
265     /* Illegal value combination */
266     report(LOG_ERR, "%s: %s %s Illegal packet ver=%d action=%d type=%d",
267            session.peer,
268            session.port,
269            name ? name : "<unknown>",
270            session.version,
271            data->action,
272            type->authen_type);
273
274     return(CHOOSE_FAILED);
275 }
276
277 static int choose_sendpass TAC_ARGS((struct authen_data *data, struct authen_type *type));
278
279 /* Compatibility routine for (obsolete) minor version == 0 */
280 static int
281 choose_sendpass(data, type)
282 struct authen_data *data;
283 struct authen_type *type;
284 {
285     char *name = data->NAS_id->username;
286
287     switch (type->authen_type) {
288     case TAC_PLUS_AUTHEN_TYPE_CHAP:
289 #ifdef MSCHAP
290     case TAC_PLUS_AUTHEN_TYPE_MSCHAP:
291 #endif /* MSCHAP */
292     case TAC_PLUS_AUTHEN_TYPE_PAP:
293     case TAC_PLUS_AUTHEN_TYPE_ARAP:
294         /* must be minor version 0 */
295         if (TAC_PLUS_VER_0 != session.version) {
296             break;
297         }
298
299         /* We need a username */
300         if (!name[0]) {
301             return (CHOOSE_GETUSER);
302         }
303
304         type->authen_func = sendpass_fn;
305         strcpy(type->authen_name, "sendpass_fn");
306         return (CHOOSE_OK);
307
308     default:
309         break;
310     }
311
312     /* Illegal value combination */
313     report(LOG_ERR, "%s: %s %s Illegal packet ver=%d action=%d type=%d",
314            session.peer,
315            session.port,
316            name ? name : "<unknown>",
317            session.version,
318            data->action,
319            type->authen_type);
320
321     return(CHOOSE_FAILED);
322 }