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