2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 #include <crypto/hashers/hasher.h>
22 #include <security/pam_appl.h>
24 #define GTC_REQUEST_MSG "password"
25 #define GTC_PAM_SERVICE "login"
27 typedef struct private_eap_gtc_t private_eap_gtc_t
;
30 * Private data of an eap_gtc_t object.
32 struct private_eap_gtc_t
{
35 * Public authenticator_t interface.
42 identification_t
*server
;
47 identification_t
*peer
;
50 * EAP message identififier
55 typedef struct eap_gtc_header_t eap_gtc_header_t
;
58 * packed eap GTC header struct
60 struct eap_gtc_header_t
{
61 /** EAP code (REQUEST/RESPONSE) */
63 /** unique message identifier */
65 /** length of whole message */
71 } __attribute__((__packed__
));
73 METHOD(eap_method_t
, initiate_peer
, status_t
,
74 private_eap_gtc_t
*this, eap_payload_t
**out
)
76 /* peer never initiates */
81 * PAM conv callback function
83 static int auth_conv(int num_msg
, const struct pam_message
**msg
,
84 struct pam_response
**resp
, char *password
)
86 struct pam_response
*response
;
92 response
= malloc(sizeof(struct pam_response
));
93 response
->resp
= strdup(password
);
94 response
->resp_retcode
= 0;
100 * Authenticate a username/password using PAM
102 static bool authenticate(char *service
, char *user
, char *password
)
104 pam_handle_t
*pamh
= NULL
;
105 static struct pam_conv conv
;
108 conv
.conv
= (void*)auth_conv
;
109 conv
.appdata_ptr
= password
;
111 ret
= pam_start(service
, user
, &conv
, &pamh
);
112 if (ret
!= PAM_SUCCESS
)
114 DBG1(DBG_IKE
, "EAP-GTC pam_start failed: %s",
115 pam_strerror(pamh
, ret
));
118 ret
= pam_authenticate(pamh
, 0);
119 if (ret
== PAM_SUCCESS
)
121 ret
= pam_acct_mgmt(pamh
, 0);
122 if (ret
!= PAM_SUCCESS
)
124 DBG1(DBG_IKE
, "EAP-GTC pam_acct_mgmt failed: %s",
125 pam_strerror(pamh
, ret
));
130 DBG1(DBG_IKE
, "EAP-GTC pam_authenticate failed: %s",
131 pam_strerror(pamh
, ret
));
134 return ret
== PAM_SUCCESS
;
137 METHOD(eap_method_t
, initiate_server
, status_t
,
138 private_eap_gtc_t
*this, eap_payload_t
**out
)
140 eap_gtc_header_t
*req
;
143 len
= strlen(GTC_REQUEST_MSG
);
144 req
= alloca(sizeof(eap_gtc_header_t
) + len
);
145 req
->length
= htons(sizeof(eap_gtc_header_t
) + len
);
146 req
->code
= EAP_REQUEST
;
147 req
->identifier
= this->identifier
;
149 memcpy(req
->data
, GTC_REQUEST_MSG
, len
);
151 *out
= eap_payload_create_data(chunk_create((void*)req
,
152 sizeof(eap_gtc_header_t
) + len
));
156 METHOD(eap_method_t
, process_peer
, status_t
,
157 private_eap_gtc_t
*this, eap_payload_t
*in
, eap_payload_t
**out
)
159 eap_gtc_header_t
*res
;
160 shared_key_t
*shared
;
164 shared
= lib
->credmgr
->get_shared(lib
->credmgr
, SHARED_EAP
,
165 this->peer
, this->server
);
168 DBG1(DBG_IKE
, "no EAP key found for '%Y' - '%Y'",
169 this->peer
, this->server
);
172 key
= shared
->get_key(shared
);
175 /* TODO: According to the draft we should "SASLprep" password, RFC4013. */
177 res
= alloca(sizeof(eap_gtc_header_t
) + len
);
178 res
->length
= htons(sizeof(eap_gtc_header_t
) + len
);
179 res
->code
= EAP_RESPONSE
;
180 res
->identifier
= in
->get_identifier(in
);
182 memcpy(res
->data
, key
.ptr
, len
);
184 shared
->destroy(shared
);
186 *out
= eap_payload_create_data(chunk_create((void*)res
,
187 sizeof(eap_gtc_header_t
) + len
));
191 METHOD(eap_method_t
, process_server
, status_t
,
192 private_eap_gtc_t
*this, eap_payload_t
*in
, eap_payload_t
**out
)
194 chunk_t data
, encoding
;
195 char *user
, *password
, *service
, *pos
;
197 data
= chunk_skip(in
->get_data(in
), 5);
198 if (this->identifier
!= in
->get_identifier(in
) || !data
.len
)
200 DBG1(DBG_IKE
, "received invalid EAP-GTC message");
204 encoding
= this->peer
->get_encoding(this->peer
);
205 /* if a RFC822_ADDR id is provided, we use the username part only */
206 pos
= memchr(encoding
.ptr
, '@', encoding
.len
);
209 encoding
.len
= (u_char
*)pos
- encoding
.ptr
;
211 user
= alloca(encoding
.len
+ 1);
212 memcpy(user
, encoding
.ptr
, encoding
.len
);
213 user
[encoding
.len
] = '\0';
215 password
= alloca(data
.len
+ 1);
216 memcpy(password
, data
.ptr
, data
.len
);
217 password
[data
.len
] = '\0';
219 service
= lib
->settings
->get_str(lib
->settings
,
220 "charon.plugins.eap-gtc.pam_service", GTC_PAM_SERVICE
);
222 if (!authenticate(service
, user
, password
))
229 METHOD(eap_method_t
, get_type
, eap_type_t
,
230 private_eap_gtc_t
*this, u_int32_t
*vendor
)
236 METHOD(eap_method_t
, get_msk
, status_t
,
237 private_eap_gtc_t
*this, chunk_t
*msk
)
242 METHOD(eap_method_t
, get_identifier
, u_int8_t
,
243 private_eap_gtc_t
*this)
245 return this->identifier
;
248 METHOD(eap_method_t
, set_identifier
, void,
249 private_eap_gtc_t
*this, u_int8_t identifier
)
251 this->identifier
= identifier
;
254 METHOD(eap_method_t
, is_mutual
, bool,
255 private_eap_gtc_t
*this)
260 METHOD(eap_method_t
, destroy
, void,
261 private_eap_gtc_t
*this)
263 this->peer
->destroy(this->peer
);
264 this->server
->destroy(this->server
);
269 * Generic constructor
271 static private_eap_gtc_t
*eap_gtc_create_generic(identification_t
*server
,
272 identification_t
*peer
)
274 private_eap_gtc_t
*this;
278 .eap_method_interface
= {
279 .get_type
= _get_type
,
280 .is_mutual
= _is_mutual
,
282 .get_identifier
= _get_identifier
,
283 .set_identifier
= _set_identifier
,
287 .peer
= peer
->clone(peer
),
288 .server
= server
->clone(server
),
297 eap_gtc_t
*eap_gtc_create_server(identification_t
*server
, identification_t
*peer
)
299 private_eap_gtc_t
*this = eap_gtc_create_generic(server
, peer
);
301 this->public.eap_method_interface
.initiate
= _initiate_server
;
302 this->public.eap_method_interface
.process
= _process_server
;
304 /* generate a non-zero identifier */
306 this->identifier
= random();
307 } while (!this->identifier
);
309 return &this->public;
315 eap_gtc_t
*eap_gtc_create_peer(identification_t
*server
, identification_t
*peer
)
317 private_eap_gtc_t
*this = eap_gtc_create_generic(server
, peer
);
319 this->public.eap_method_interface
.initiate
= _initiate_peer
;
320 this->public.eap_method_interface
.process
= _process_peer
;
322 return &this->public;