1/*
2 * Copyright (c) 2001-2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 * Modification History
26 *
27 * December 10, 2001	Dieter Siegmund (dieter@apple.com)
28 * - created
29 */
30
31#include <EAP8021X/EAPClientPlugin.h>
32#include <EAP8021X/EAPClientProperties.h>
33#include <EAP8021X/chap.h>
34#include <mach/boolean.h>
35#include <unistd.h>
36#include <stdlib.h>
37#include <string.h>
38#include <stdio.h>
39#include "EAPLog.h"
40
41/*
42 * Declare these here to ensure that the compiler
43 * generates appropriate errors/warnings
44 */
45EAPClientPluginFuncIntrospect md5_introspect;
46static EAPClientPluginFuncVersion md5_version;
47static EAPClientPluginFuncEAPType md5_type;
48static EAPClientPluginFuncEAPName md5_name;
49static EAPClientPluginFuncInit md5_init;
50static EAPClientPluginFuncFree md5_free;
51static EAPClientPluginFuncProcess md5_process;
52static EAPClientPluginFuncRequireProperties md5_require_props;
53static EAPClientPluginFuncFreePacket md5_free_packet;
54
55static EAPPacketRef
56md5_request(EAPClientPluginDataRef plugin, const EAPPacketRef in_pkt_p)
57{
58    uint16_t			in_length = EAPPacketGetLength(in_pkt_p);
59    EAPMD5ChallengePacketRef	in_md5_p = (EAPMD5ChallengePacketRef)in_pkt_p;
60    EAPMD5ResponsePacketRef	out_md5_p = NULL;
61    int				size;
62
63    if (in_length < sizeof(*in_md5_p)) {
64	EAPLOG_FL(LOG_NOTICE, "header too short (length %d < %ld)",
65		  in_length, sizeof(*in_md5_p));
66	goto failed;
67    }
68    if (in_length < (sizeof(*in_md5_p) + in_md5_p->value_size)) {
69	EAPLOG_FL(LOG_NOTICE, "value too short (length %d < %ld)",
70		  in_length, sizeof(*in_md5_p) + in_md5_p->value_size);
71	goto failed;
72    }
73    size = sizeof(*out_md5_p) + plugin->username_length;
74    out_md5_p = malloc(size);
75    if (out_md5_p == NULL) {
76	goto failed;
77    }
78    out_md5_p->code = kEAPCodeResponse;
79    out_md5_p->identifier = in_md5_p->identifier;
80    EAPPacketSetLength((EAPPacketRef)out_md5_p, size);
81    out_md5_p->type = kEAPTypeMD5Challenge;
82    out_md5_p->value_size = sizeof(out_md5_p->value);
83    chap_md5(in_md5_p->identifier, plugin->password, plugin->password_length,
84	     in_md5_p->value, in_md5_p->value_size, out_md5_p->value);
85    bcopy(plugin->username, out_md5_p->name, plugin->username_length);
86    return ((EAPPacketRef)out_md5_p);
87 failed:
88    if (out_md5_p != NULL) {
89	free(out_md5_p);
90    }
91    return (NULL);
92}
93
94static EAPClientStatus
95md5_init(EAPClientPluginDataRef plugin,
96	 CFArrayRef * required_props,
97	 EAPClientDomainSpecificError * error)
98{
99    *error = 0;
100    *required_props = NULL;
101    return (kEAPClientStatusOK);
102}
103
104static void
105md5_free(EAPClientPluginDataRef plugin)
106{
107    /* ignore, no context data */
108    return;
109}
110
111static void
112md5_free_packet(EAPClientPluginDataRef plugin, EAPPacketRef arg)
113{
114    if (arg != NULL) {
115	/* we malloc'd the packet, so free it */
116	free(arg);
117    }
118    return;
119}
120
121static EAPClientState
122md5_process(EAPClientPluginDataRef plugin,
123	    const EAPPacketRef in_pkt,
124	    EAPPacketRef * out_pkt_p,
125	    EAPClientStatus * client_status,
126	    EAPClientDomainSpecificError * error)
127{
128    EAPClientState	plugin_state;
129
130    *client_status = kEAPClientStatusOK;
131    *error = 0;
132    plugin_state = kEAPClientStateAuthenticating;
133    *out_pkt_p = NULL;
134
135    switch (in_pkt->code) {
136    case kEAPCodeRequest:
137	if (plugin->password == NULL) {
138	    *client_status = kEAPClientStatusUserInputRequired;
139	}
140	else {
141	    *out_pkt_p = md5_request(plugin, in_pkt);
142	}
143	break;
144    case kEAPCodeSuccess:
145	plugin_state = kEAPClientStateSuccess;
146	break;
147    case kEAPCodeFailure:
148	*client_status = kEAPClientStatusFailed;
149	plugin_state = kEAPClientStateFailure;
150	break;
151    default:
152	break;
153    }
154    return (plugin_state);
155}
156
157static CFArrayRef
158md5_require_props(EAPClientPluginDataRef plugin)
159{
160    CFStringRef		prop;
161
162    if (plugin->password != NULL) {
163	return (NULL);
164    }
165    prop = kEAPClientPropUserPassword;
166    return (CFArrayCreate(NULL, (const void **)&prop, 1,
167			  &kCFTypeArrayCallBacks));
168}
169
170static EAPType
171md5_type()
172{
173    return (kEAPTypeMD5Challenge);
174}
175
176static const char *
177md5_name()
178{
179    return ("MD5");
180}
181
182static EAPClientPluginVersion
183md5_version()
184{
185    return (kEAPClientPluginVersion);
186}
187
188static struct func_table_ent {
189    const char *		name;
190    void *			func;
191} func_table[] = {
192    { kEAPClientPluginFuncNameVersion, md5_version },
193    { kEAPClientPluginFuncNameEAPType, md5_type },
194    { kEAPClientPluginFuncNameEAPName, md5_name },
195    { kEAPClientPluginFuncNameInit, md5_init },
196    { kEAPClientPluginFuncNameFree, md5_free },
197    { kEAPClientPluginFuncNameProcess, md5_process },
198    { kEAPClientPluginFuncNameRequireProperties, md5_require_props },
199    { kEAPClientPluginFuncNameFreePacket, md5_free_packet },
200    { NULL, NULL},
201};
202
203
204EAPClientPluginFuncRef
205md5_introspect(EAPClientPluginFuncName name)
206{
207    struct func_table_ent * scan;
208
209
210    for (scan = func_table; scan->name != NULL; scan++) {
211	if (strcmp(name, scan->name) == 0) {
212	    return (scan->func);
213	}
214    }
215    return (NULL);
216}
217