Checks out moonshot code correctly: Builds with the following
[moonshot.git] / mac-client-installer / 0001-Move-moonshot-files-up.patch
1 From df22702d72d30843193d98589fee090f2fe63201 Mon Sep 17 00:00:00 2001
2 From: Pete Fotheringham <pete.fotheringham@codethink.co.uk>
3 Date: Thu, 29 Dec 2011 09:12:51 +0000
4 Subject: [PATCH] Move moonshot files up
5
6 ---
7  Makefile.am                           |    4 +
8  acinclude.m4                          |  364 ++++++++++
9  autogen.sh                            |   16 +
10  build-aux/compile                     |  144 ++++
11  configure.ac                          |   92 +++
12  m4/minuso.m4                          |   35 +
13  mech_eap.spec.in                      |   62 ++
14  mech_eap/.gitignore                   |   32 +
15  mech_eap/AUTHORS                      |    6 +
16  mech_eap/COPYING                      |    3 +
17  mech_eap/LICENSE                      |   31 +
18  mech_eap/Makefile.am                  |  189 ++++++
19  mech_eap/NOTES                        |    9 +
20  mech_eap/README                       |  147 ++++
21  mech_eap/README.samba4                |   52 ++
22  mech_eap/TODO                         |    6 +
23  mech_eap/accept_sec_context.c         | 1072 +++++++++++++++++++++++++++++
24  mech_eap/acquire_cred.c               |   52 ++
25  mech_eap/acquire_cred_with_password.c |   67 ++
26  mech_eap/add_cred.c                   |   87 +++
27  mech_eap/add_cred_with_password.c     |   93 +++
28  mech_eap/authdata_plugin.h            |  331 +++++++++
29  mech_eap/authorize_localname.c        |   54 ++
30  mech_eap/canonicalize_name.c          |   64 ++
31  mech_eap/compare_name.c               |   46 ++
32  mech_eap/context_time.c               |   69 ++
33  mech_eap/delete_name_attribute.c      |   60 ++
34  mech_eap/delete_sec_context.c         |   81 +++
35  mech_eap/dictionary.ukerna            |   20 +
36  mech_eap/display_name.c               |   48 ++
37  mech_eap/display_name_ext.c           |   51 ++
38  mech_eap/display_status.c             |  203 ++++++
39  mech_eap/duplicate_name.c             |   60 ++
40  mech_eap/eap_mech.c                   |  219 ++++++
41  mech_eap/exchange_meta_data.c         |   82 +++
42  mech_eap/export_name.c                |   60 ++
43  mech_eap/export_name_composite.c      |   62 ++
44  mech_eap/export_sec_context.c         |  246 +++++++
45  mech_eap/get_mic.c                    |   89 +++
46  mech_eap/get_name_attribute.c         |   67 ++
47  mech_eap/gssapiP_eap.h                |  410 +++++++++++
48  mech_eap/gssapi_eap.h                 |   90 +++
49  mech_eap/gsseap_err.et                |  162 +++++
50  mech_eap/import_name.c                |   47 ++
51  mech_eap/import_sec_context.c         |  374 ++++++++++
52  mech_eap/indicate_mechs.c             |   44 ++
53  mech_eap/init_sec_context.c           | 1097 ++++++++++++++++++++++++++++++
54  mech_eap/inquire_attrs_for_mech.c     |  137 ++++
55  mech_eap/inquire_context.c            |  116 ++++
56  mech_eap/inquire_cred.c               |   61 ++
57  mech_eap/inquire_cred_by_mech.c       |   76 +++
58  mech_eap/inquire_cred_by_oid.c        |   83 +++
59  mech_eap/inquire_mech_for_saslname.c  |   84 +++
60  mech_eap/inquire_mechs_for_name.c     |   69 ++
61  mech_eap/inquire_name.c               |   75 ++
62  mech_eap/inquire_names_for_mech.c     |   77 +++
63  mech_eap/inquire_saslname_for_mech.c  |   51 ++
64  mech_eap/inquire_sec_context_by_oid.c |  248 +++++++
65  mech_eap/install-sh                   |  520 ++++++++++++++
66  mech_eap/map_name_to_any.c            |   58 ++
67  mech_eap/mech                         |    8 +
68  mech_eap/mech_eap-noacceptor.exports  |   55 ++
69  mech_eap/mech_eap.exports             |   63 ++
70  mech_eap/mech_invoke.c                |   44 ++
71  mech_eap/process_context_token.c      |   71 ++
72  mech_eap/pseudo_random.c              |  195 ++++++
73  mech_eap/query_mechanism_info.c       |   67 ++
74  mech_eap/query_meta_data.c            |  116 ++++
75  mech_eap/radius_ad.exports            |    1 +
76  mech_eap/radsec.conf                  |   12 +
77  mech_eap/radsec_err.et                |   38 +
78  mech_eap/release_any_name_mapping.c   |   59 ++
79  mech_eap/release_cred.c               |   44 ++
80  mech_eap/release_name.c               |   44 ++
81  mech_eap/release_oid.c                |   44 ++
82  mech_eap/set_cred_option.c            |  208 ++++++
83  mech_eap/set_name_attribute.c         |   60 ++
84  mech_eap/set_sec_context_option.c     |   87 +++
85  mech_eap/store_cred.c                 |   83 +++
86  mech_eap/unwrap.c                     |   85 +++
87  mech_eap/unwrap_iov.c                 |  572 ++++++++++++++++
88  mech_eap/util.h                       | 1032 ++++++++++++++++++++++++++++
89  mech_eap/util_adshim.c                |  242 +++++++
90  mech_eap/util_attr.cpp                | 1191 ++++++++++++++++++++++++++++++++
91  mech_eap/util_attr.h                  |  389 +++++++++++
92  mech_eap/util_base64.c                |  161 +++++
93  mech_eap/util_base64.h                |   58 ++
94  mech_eap/util_buffer.c                |  103 +++
95  mech_eap/util_cksum.c                 |  242 +++++++
96  mech_eap/util_context.c               |  377 +++++++++++
97  mech_eap/util_cred.c                  |  756 +++++++++++++++++++++
98  mech_eap/util_crypt.c                 |  397 +++++++++++
99  mech_eap/util_json.cpp                |  513 ++++++++++++++
100  mech_eap/util_json.h                  |  182 +++++
101  mech_eap/util_krb.c                   |  632 +++++++++++++++++
102  mech_eap/util_lucid.c                 |  183 +++++
103  mech_eap/util_mech.c                  |  380 +++++++++++
104  mech_eap/util_moonshot.c              |  238 +++++++
105  mech_eap/util_name.c                  |  789 ++++++++++++++++++++++
106  mech_eap/util_oid.c                   |  206 ++++++
107  mech_eap/util_ordering.c              |  302 +++++++++
108  mech_eap/util_radius.cpp              |  899 +++++++++++++++++++++++++
109  mech_eap/util_radius.h                |  183 +++++
110  mech_eap/util_reauth.c                | 1196 +++++++++++++++++++++++++++++++++
111  mech_eap/util_reauth.h                |  151 +++++
112  mech_eap/util_saml.cpp                |  775 +++++++++++++++++++++
113  mech_eap/util_saml.h                  |  176 +++++
114  mech_eap/util_shib.cpp                |  555 +++++++++++++++
115  mech_eap/util_shib.h                  |  122 ++++
116  mech_eap/util_sm.c                    |  372 ++++++++++
117  mech_eap/util_tld.c                   |  167 +++++
118  mech_eap/util_token.c                 |  493 ++++++++++++++
119  mech_eap/verify_mic.c                 |   71 ++
120  mech_eap/wrap.c                       |  137 ++++
121  mech_eap/wrap_iov.c                   |  379 +++++++++++
122  mech_eap/wrap_iov_length.c            |  234 +++++++
123  mech_eap/wrap_size_limit.c            |   97 +++
124  117 files changed, 24690 insertions(+), 0 deletions(-)
125  create mode 100644 Makefile.am
126  create mode 100644 acinclude.m4
127  create mode 100755 autogen.sh
128  create mode 100755 build-aux/compile
129  create mode 100644 configure.ac
130  create mode 100644 m4/minuso.m4
131  create mode 100644 mech_eap.spec.in
132  create mode 100644 mech_eap/.gitignore
133  create mode 100644 mech_eap/AUTHORS
134  create mode 100644 mech_eap/COPYING
135  create mode 100644 mech_eap/LICENSE
136  create mode 100644 mech_eap/Makefile.am
137  create mode 100644 mech_eap/NEWS
138  create mode 100644 mech_eap/NOTES
139  create mode 100644 mech_eap/README
140  create mode 100644 mech_eap/README.samba4
141  create mode 100644 mech_eap/TODO
142  create mode 100644 mech_eap/accept_sec_context.c
143  create mode 100644 mech_eap/acquire_cred.c
144  create mode 100644 mech_eap/acquire_cred_with_password.c
145  create mode 100644 mech_eap/add_cred.c
146  create mode 100644 mech_eap/add_cred_with_password.c
147  create mode 100644 mech_eap/authdata_plugin.h
148  create mode 100644 mech_eap/authorize_localname.c
149  create mode 100644 mech_eap/canonicalize_name.c
150  create mode 100644 mech_eap/compare_name.c
151  create mode 100644 mech_eap/context_time.c
152  create mode 100644 mech_eap/delete_name_attribute.c
153  create mode 100644 mech_eap/delete_sec_context.c
154  create mode 100644 mech_eap/dictionary.ukerna
155  create mode 100644 mech_eap/display_name.c
156  create mode 100644 mech_eap/display_name_ext.c
157  create mode 100644 mech_eap/display_status.c
158  create mode 100644 mech_eap/duplicate_name.c
159  create mode 100644 mech_eap/eap_mech.c
160  create mode 100644 mech_eap/exchange_meta_data.c
161  create mode 100644 mech_eap/export_name.c
162  create mode 100644 mech_eap/export_name_composite.c
163  create mode 100644 mech_eap/export_sec_context.c
164  create mode 100644 mech_eap/get_mic.c
165  create mode 100644 mech_eap/get_name_attribute.c
166  create mode 100644 mech_eap/gssapiP_eap.h
167  create mode 100644 mech_eap/gssapi_eap.h
168  create mode 100644 mech_eap/gsseap_err.et
169  create mode 100644 mech_eap/import_name.c
170  create mode 100644 mech_eap/import_sec_context.c
171  create mode 100644 mech_eap/indicate_mechs.c
172  create mode 100644 mech_eap/init_sec_context.c
173  create mode 100644 mech_eap/inquire_attrs_for_mech.c
174  create mode 100644 mech_eap/inquire_context.c
175  create mode 100644 mech_eap/inquire_cred.c
176  create mode 100644 mech_eap/inquire_cred_by_mech.c
177  create mode 100644 mech_eap/inquire_cred_by_oid.c
178  create mode 100644 mech_eap/inquire_mech_for_saslname.c
179  create mode 100644 mech_eap/inquire_mechs_for_name.c
180  create mode 100644 mech_eap/inquire_name.c
181  create mode 100644 mech_eap/inquire_names_for_mech.c
182  create mode 100644 mech_eap/inquire_saslname_for_mech.c
183  create mode 100644 mech_eap/inquire_sec_context_by_oid.c
184  create mode 100755 mech_eap/install-sh
185  create mode 100644 mech_eap/map_name_to_any.c
186  create mode 100644 mech_eap/mech
187  create mode 100644 mech_eap/mech_eap-noacceptor.exports
188  create mode 100644 mech_eap/mech_eap.exports
189  create mode 100644 mech_eap/mech_invoke.c
190  create mode 100644 mech_eap/process_context_token.c
191  create mode 100644 mech_eap/pseudo_random.c
192  create mode 100644 mech_eap/query_mechanism_info.c
193  create mode 100644 mech_eap/query_meta_data.c
194  create mode 100644 mech_eap/radius_ad.exports
195  create mode 100644 mech_eap/radsec.conf
196  create mode 100644 mech_eap/radsec_err.et
197  create mode 100644 mech_eap/release_any_name_mapping.c
198  create mode 100644 mech_eap/release_cred.c
199  create mode 100644 mech_eap/release_name.c
200  create mode 100644 mech_eap/release_oid.c
201  create mode 100644 mech_eap/set_cred_option.c
202  create mode 100644 mech_eap/set_name_attribute.c
203  create mode 100644 mech_eap/set_sec_context_option.c
204  create mode 100644 mech_eap/store_cred.c
205  create mode 100644 mech_eap/unwrap.c
206  create mode 100644 mech_eap/unwrap_iov.c
207  create mode 100644 mech_eap/util.h
208  create mode 100644 mech_eap/util_adshim.c
209  create mode 100644 mech_eap/util_attr.cpp
210  create mode 100644 mech_eap/util_attr.h
211  create mode 100644 mech_eap/util_base64.c
212  create mode 100644 mech_eap/util_base64.h
213  create mode 100644 mech_eap/util_buffer.c
214  create mode 100644 mech_eap/util_cksum.c
215  create mode 100644 mech_eap/util_context.c
216  create mode 100644 mech_eap/util_cred.c
217  create mode 100644 mech_eap/util_crypt.c
218  create mode 100644 mech_eap/util_json.cpp
219  create mode 100644 mech_eap/util_json.h
220  create mode 100644 mech_eap/util_krb.c
221  create mode 100644 mech_eap/util_lucid.c
222  create mode 100644 mech_eap/util_mech.c
223  create mode 100644 mech_eap/util_moonshot.c
224  create mode 100644 mech_eap/util_name.c
225  create mode 100644 mech_eap/util_oid.c
226  create mode 100644 mech_eap/util_ordering.c
227  create mode 100644 mech_eap/util_radius.cpp
228  create mode 100644 mech_eap/util_radius.h
229  create mode 100644 mech_eap/util_reauth.c
230  create mode 100644 mech_eap/util_reauth.h
231  create mode 100644 mech_eap/util_saml.cpp
232  create mode 100644 mech_eap/util_saml.h
233  create mode 100644 mech_eap/util_shib.cpp
234  create mode 100644 mech_eap/util_shib.h
235  create mode 100644 mech_eap/util_sm.c
236  create mode 100644 mech_eap/util_tld.c
237  create mode 100644 mech_eap/util_token.c
238  create mode 100644 mech_eap/verify_mic.c
239  create mode 100644 mech_eap/wrap.c
240  create mode 100644 mech_eap/wrap_iov.c
241  create mode 100644 mech_eap/wrap_iov_length.c
242  create mode 100644 mech_eap/wrap_size_limit.c
243
244 diff --git a/Makefile.am b/Makefile.am
245 new file mode 100644
246 index 0000000..f9690bd
247 --- /dev/null
248 +++ b/Makefile.am
249 @@ -0,0 +1,4 @@
250 +AUTOMAKE_OPTIONS = foreign
251 +ACLOCAL_AMFLAGS = -I m4
252 +SUBDIRS = mech_eap
253 +EXTRA_DIST = mech_eap.spec
254 diff --git a/acinclude.m4 b/acinclude.m4
255 new file mode 100644
256 index 0000000..6f43261
257 --- /dev/null
258 +++ b/acinclude.m4
259 @@ -0,0 +1,364 @@
260 +dnl Based on the one from the Boinc project by Reinhard
261 +
262 +AC_DEFUN([AX_CHECK_WINDOWS],
263 +[AC_MSG_CHECKING(for windows)
264 +target_windows="no"
265 +AC_CHECK_HEADER(windows.h,[target_windows="yes"],[target_windows="no"])
266 +AC_MSG_RESULT($target_windows)
267 +AM_CONDITIONAL(TARGET_WINDOWS,test "x$target_windows" = "xyes")
268 +])dnl
269 +
270 +AC_DEFUN([AX_CHECK_KRB5],
271 +[AC_MSG_CHECKING(for GSS-API and Kerberos implementation)
272 +KRB5_DIR=
273 +found_krb5="no"
274 +AC_ARG_WITH(krb5,
275 +    AC_HELP_STRING([--with-krb5],
276 +       [Use krb5 (in specified installation directory)]),
277 +    [check_krb5_dir="$withval"],
278 +    [check_krb5_dir=])
279 +for dir in $check_krb5_dir $prefix /usr/local /usr ; do
280 +   krb5dir="$dir"
281 +   if test -x "$dir/bin/krb5-config"; then
282 +     found_krb5="yes";
283 +     if test "x$target_windows" = "xyes"; then
284 +        KRB5_CFLAGS=-I"$check_krb5_dir/include";
285 +        KRB5_LDFLAGS="-L$check_krb5_dir/lib/";
286 +        KRB5_LIBS="-lkrb5_32 -lgssapi32";
287 +        COMPILE_ET="$check_krb5_dir/bin/compile_et";
288 +       AC_MSG_RESULT([yes])
289 +     else
290 +        KRB5_CFLAGS=`$dir/bin/krb5-config gssapi --cflags`;
291 +        KRB5_LDFLAGS="-L$dir/lib";
292 +        KRB5_LIBS=`$dir/bin/krb5-config gssapi --libs`
293 +AC_MSG_RESULT([yes])
294 +        AC_PATH_PROG(COMPILE_ET, [compile_et], [compile_et], [$dir/bin$PATH_SEPARATOr])
295 +     fi
296 +     break;
297 +   fi
298 +done
299 +if test x_$found_krb5 != x_yes; then
300 +   AC_MSG_RESULT($found_krb5)
301 +   AC_MSG_ERROR([
302 +----------------------------------------------------------------------
303 +  Cannot find GSS-API/Kerberos libraries.
304 +
305 +  Please install MIT or Heimdal or specify installation directory with
306 +  --with-krb5=(dir).
307 +----------------------------------------------------------------------
308 +])
309 +else
310 +       printf "Kerberos found in $krb5dir\n";
311 +       AC_SUBST(KRB5_CFLAGS)
312 +        AC_SUBST(KRB5_LDFLAGS)
313 +       AC_SUBST(KRB5_LIBS)
314 +       AC_SUBST(COMPILE_ET)
315 +       AC_CHECK_LIB(krb5, GSS_C_NT_COMPOSITE_EXPORT, [AC_DEFINE_UNQUOTED([HAVE_GSS_C_NT_COMPOSITE_EXPORT], 1, [Define if GSS-API library supports recent naming extensions draft])], [], "$KRB5_LIBS")
316 +       AC_CHECK_LIB(krb5, gss_inquire_attrs_for_mech, [AC_DEFINE_UNQUOTED([HAVE_GSS_INQUIRE_ATTRS_FOR_MECH], 1, [Define if GSS-API library supports RFC 5587])], [], "$KRB5_LIBS")
317 +       AC_CHECK_LIB(krb5, gss_krb5_import_cred, [AC_DEFINE_UNQUOTED([HAVE_GSS_KRB5_IMPORT_CRED], 1, [Define if GSS-API library supports gss_krb5_import_cred])], [], "$KRB5_LIBS")
318 +       AC_CHECK_LIB(krb5, heimdal_version, [AC_DEFINE_UNQUOTED([HAVE_HEIMDAL_VERSION], 1, [Define if building against Heimdal Kerberos implementation]), heimdal=yes], [heimdal=no], "$KRB5_LIBS")
319 +       AM_CONDITIONAL(HEIMDAL, test "x$heimdal" != "xno")
320 +fi
321 +])dnl
322 +
323 +AC_DEFUN([AX_CHECK_EAP],
324 +[AC_MSG_CHECKING(for EAP implementation)
325 +EAP_DIR=
326 +found_eap="no"
327 +AC_ARG_WITH(eap,
328 +    AC_HELP_STRING([--with-eap],
329 +       [Use eap (in specified installation directory)]),
330 +    [check_eap_dir="$withval"],
331 +    [check_eap_dir=])
332 +for dir in $check_eap_dir $prefix /usr /usr/local ../libeap ; do
333 +   eapdir="$dir"
334 +   if test -f "$dir/src/eap_peer/eap.h"; then
335 +     found_eap="yes";
336 +     EAP_DIR="${eapdir}"
337 +     EAP_CFLAGS="-I$eapdir/src/common -I$eapdir/src -I$eapdir/src/utils";
338 +     break;
339 +   fi
340 +done
341 +AC_MSG_RESULT($found_eap)
342 +if test x_$found_eap != x_yes; then
343 +   AC_MSG_ERROR([
344 +----------------------------------------------------------------------
345 +  Cannot find EAP libraries.
346 +
347 +  Please install wpa_supplicant or specify installation directory with
348 +  --with-eap=(dir).
349 +----------------------------------------------------------------------
350 +])
351 +else
352 +       printf "EAP found in $eapdir\n";
353 +       EAP_CFLAGS="$EAP_CFLAGS \
354 +-DEAP_TLS \
355 +-DEAP_PEAP \
356 +-DEAP_TTLS \
357 +-DEAP_MD5 \
358 +-DEAP_MSCHAPv2 \
359 +-DEAP_GTC \
360 +-DEAP_OTP \
361 +-DEAP_LEAP \
362 +-DEAP_PSK \
363 +-DEAP_PAX \
364 +-DEAP_SAKE \
365 +-DEAP_GPSK \
366 +-DEAP_GPSK_SHA256 \
367 +-DEAP_SERVER_IDENTITY \
368 +-DEAP_SERVER_TLS \
369 +-DEAP_SERVER_PEAP \
370 +-DEAP_SERVER_TTLS \
371 +-DEAP_SERVER_MD5 \
372 +-DEAP_SERVER_MSCHAPV2 \
373 +-DEAP_SERVER_GTC \
374 +-DEAP_SERVER_PSK \
375 +-DEAP_SERVER_PAX \
376 +-DEAP_SERVER_SAKE \
377 +-DEAP_SERVER_GPSK \
378 +-DEAP_SERVER_GPSK_SHA256 \
379 +-DIEEE8021X_EAPOL";
380 +       EAP_LIBS="-leap -lutils -lcrypto -ltls";
381 +       EAP_LDFLAGS="-L$eapdir/eap_example -L$eapdir/src/utils -L$eapdir/src/crypto -L$eapdir/src/tls";
382 +       AC_SUBST(EAP_CFLAGS)
383 +       AC_SUBST(EAP_LDFLAGS)
384 +       AC_SUBST(EAP_LIBS)
385 +fi
386 +])dnl
387 +
388 +AC_DEFUN([AX_CHECK_SHIBSP],
389 +[AC_MSG_CHECKING(for Shibboleth implementation)
390 +SHIBSP_DIR=
391 +found_shibsp="no"
392 +AC_ARG_WITH(shibsp,
393 +    AC_HELP_STRING([--with-shibsp],
394 +       [Use shibspboleth (in specified installation directory)]),
395 +    [check_shibsp_dir="$withval"],
396 +    [check_shibsp_dir=])
397 +for dir in $check_shibsp_dir $prefix /usr /usr/local ; do
398 +   shibspdir="$dir"
399 +   if test -f "$dir/include/shibsp/SPConfig.h"; then
400 +     found_shibsp="yes";
401 +     SHIBSP_DIR="${shibspdir}"
402 +     SHIBSP_CXXFLAGS="-I$shibspdir/include";
403 +     break;
404 +   fi
405 +done
406 +AC_MSG_RESULT($found_shibsp)
407 +if test x_$found_shibsp != x_yes; then
408 +   AC_MSG_ERROR([
409 +----------------------------------------------------------------------
410 +  Cannot find Shibboleth libraries.
411 +
412 +  Please install Shibboleth or specify installation directory with
413 +  --with-shibsp=(dir).
414 +----------------------------------------------------------------------
415 +])
416 +else
417 +       printf "Shibboleth found in $shibspdir\n";
418 +       SHIBSP_LIBS="-lshibsp -lsaml -lxml-security-c -lxmltooling -lxerces-c";
419 +       SHIBSP_LDFLAGS="-L$shibspdir/lib";
420 +       AC_SUBST(SHIBSP_CXXFLAGS)
421 +       AC_SUBST(SHIBSP_LDFLAGS)
422 +       AC_SUBST(SHIBSP_LIBS)
423 +       AC_DEFINE_UNQUOTED([HAVE_SHIBSP], 1, [Define is Shibboleth SP is available])
424 +fi
425 +])dnl
426 +
427 +AC_DEFUN([AX_CHECK_SHIBRESOLVER],
428 +[AC_MSG_CHECKING(for Shibboleth resolver implementation)
429 +SHIBRESOLVER_DIR=
430 +found_shibresolver="no"
431 +AC_ARG_WITH(shibresolver,
432 +    AC_HELP_STRING([--with-shibresolver],
433 +       [Use Shibboleth resolver (in specified installation directory)]),
434 +    [check_shibresolver_dir="$withval"],
435 +    [check_shibresolver_dir=])
436 +if test x_$check_shibresolver_dir != x_no; then
437 +for dir in $check_shibresolver_dir $prefix /usr /usr/local ; do
438 +   shibresolverdir="$dir"
439 +   if test -f "$dir/include/shibresolver/resolver.h"; then
440 +     found_shibresolver="yes";
441 +     SHIBRESOLVER_DIR="${shibresolverdir}"
442 +     SHIBRESOLVER_CXXFLAGS="-I$shibresolverdir/include";
443 +     break;
444 +   fi
445 +done
446 +fi
447 +AC_MSG_RESULT($found_shibresolver)
448 +if test x_$check_shibresolver_dir != x_no; then
449 +if test x_$found_shibresolver != x_yes; then
450 +   AC_MSG_WARN([
451 +----------------------------------------------------------------------
452 +  Cannot find Shibboleth resolver libraries, building without
453 +  Shibboleth support.
454 +
455 +  Please install Shibboleth or specify installation directory with
456 +  --with-shibresolver=(dir).
457 +----------------------------------------------------------------------
458 +])
459 +else
460 +       printf "Shibboleth resolver found in $shibresolverdir\n";
461 +       SHIBRESOLVER_LIBS="-lshibresolver";
462 +       SHIBRESOLVER_LDFLAGS="-L$shibresolverdir/lib";
463 +       AC_SUBST(SHIBRESOLVER_CXXFLAGS)
464 +       AC_SUBST(SHIBRESOLVER_LDFLAGS)
465 +       AC_SUBST(SHIBRESOLVER_LIBS)
466 +       AC_DEFINE_UNQUOTED([HAVE_SHIBRESOLVER], 1, [Define is Shibboleth resolver is available])
467 +fi
468 +fi
469 +])dnl
470 +
471 +AC_DEFUN([AX_CHECK_OPENSAML],
472 +[AC_MSG_CHECKING(for OpenSAML implementation)
473 +OPENSAML_DIR=
474 +found_opensaml="no"
475 +AC_ARG_WITH(opensaml,
476 +    AC_HELP_STRING([--with-opensaml],
477 +       [Use OpenSAML (in specified installation directory)]),
478 +    [check_opensaml_dir="$withval"],
479 +    [check_opensaml_dir=])
480 +if test x_$check_opensaml_dir != x_no; then
481 +for dir in $check_opensaml_dir $prefix /usr /usr/local ; do
482 +   opensamldir="$dir"
483 +   if test -f "$dir/include/saml/Assertion.h"; then
484 +     found_opensaml="yes";
485 +     OPENSAML_DIR="${opensamldir}"
486 +     OPENSAML_CXXFLAGS="-I$opensamldir/include";
487 +     break;
488 +   fi
489 +done
490 +fi
491 +AC_MSG_RESULT($found_opensaml)
492 +if test x_$check_opensaml_dir != x_no; then
493 +if test x_$found_opensaml != x_yes; then
494 +   AC_MSG_WARN([
495 +----------------------------------------------------------------------
496 +  Cannot find OpenSAML libraries, building without OpenSAML support.
497 +
498 +  Please install OpenSAML or specify installation directory with
499 +  --with-opensaml=(dir).
500 +----------------------------------------------------------------------
501 +])
502 +else
503 +       printf "OpenSAML found in $opensamldir\n";
504 +       OPENSAML_LIBS="-lsaml -lxml-security-c -lxmltooling -lxerces-c";
505 +       OPENSAML_LDFLAGS="-L$opensamldir/lib";
506 +       AC_SUBST(OPENSAML_CXXFLAGS)
507 +       AC_SUBST(OPENSAML_LDFLAGS)
508 +       AC_SUBST(OPENSAML_LIBS)
509 +       AC_DEFINE_UNQUOTED([HAVE_OPENSAML], 1, [Define is OpenSAML is available])
510 +fi
511 +fi
512 +])dnl
513 +
514 +AC_DEFUN([AX_CHECK_RADSEC],
515 +[AC_MSG_CHECKING(for radsec)
516 +RADSEC_DIR=
517 +found_radsec="no"
518 +AC_ARG_WITH(radsec,
519 +    AC_HELP_STRING([--with-radsec],
520 +       [Use radsec (in specified installation directory)]),
521 +    [check_radsec_dir="$withval"],
522 +    [check_radsec_dir=])
523 +for dir in $check_radsec_dir $prefix /usr /usr/local ; do
524 +   radsecdir="$dir"
525 +   if test -f "$dir/include/radsec/radsec.h"; then
526 +     found_radsec="yes";
527 +     RADSEC_DIR="${radsecdir}"
528 +     RADSEC_CFLAGS="-I$radsecdir/include";
529 +     break;
530 +   fi
531 +done
532 +AC_MSG_RESULT($found_radsec)
533 +if test x_$found_radsec != x_yes; then
534 +   AC_MSG_ERROR([
535 +----------------------------------------------------------------------
536 +  Cannot find radsec libraries.
537 +
538 +  Please install libradsec or specify installation directory with
539 +  --with-radsec=(dir).
540 +----------------------------------------------------------------------
541 +])
542 +else
543 +       printf "radsec found in $radsecdir\n";
544 +       RADSEC_LIBS="-lradsec";
545 +       RADSEC_LDFLAGS="-L$radsecdir/lib";
546 +       AC_SUBST(RADSEC_CFLAGS)
547 +       AC_SUBST(RADSEC_LDFLAGS)
548 +       AC_SUBST(RADSEC_LIBS)
549 +fi
550 +])dnl
551 +
552 +AC_DEFUN([AX_CHECK_JANSSON],
553 +[AC_MSG_CHECKING(for jansson)
554 +JANSSON_DIR=
555 +found_jansson="no"
556 +AC_ARG_WITH(jansson,
557 +    AC_HELP_STRING([--with-jansson],
558 +       [Use jansson (in specified installation directory)]),
559 +    [check_jansson_dir="$withval"],
560 +    [check_jansson_dir=])
561 +for dir in $check_jansson_dir $prefix /usr /usr/local ; do
562 +   janssondir="$dir"
563 +   if test -f "$dir/include/jansson.h"; then
564 +     found_jansson="yes";
565 +     JANSSON_DIR="${janssondir}"
566 +     JANSSON_CFLAGS="-I$janssondir/include";
567 +     break;
568 +   fi
569 +done
570 +AC_MSG_RESULT($found_jansson)
571 +if test x_$found_jansson != x_yes; then
572 +   AC_MSG_ERROR([
573 +----------------------------------------------------------------------
574 +  Cannot find jansson libraries.
575 +
576 +  Please install libjansson or specify installation directory with
577 +  --with-jansson=(dir).
578 +----------------------------------------------------------------------
579 +])
580 +else
581 +       printf "jansson found in $janssondir\n";
582 +       JANSSON_LIBS="-ljansson";
583 +       JANSSON_LDFLAGS="-L$janssondir/lib";
584 +       AC_SUBST(JANSSON_CFLAGS)
585 +       AC_SUBST(JANSSON_LDFLAGS)
586 +       AC_SUBST(JANSSON_LIBS)
587 +fi
588 +])dnl
589 +
590 +AC_DEFUN([AX_CHECK_LIBMOONSHOT],
591 +[AC_MSG_CHECKING(for Moonshot identity selector implementation)
592 +LIBMOONSHOT_DIR=
593 +LIBMOONSHOT_CFLAGS=
594 +LIBMOONSHOT_LDFLAGS=
595 +LIBMOONSHOT_LIBS=
596 +found_libmoonshot="no"
597 +AC_ARG_WITH(libmoonshot,
598 +    AC_HELP_STRING([--with-libmoonshot],
599 +       [Use libmoonshot (in specified installation directory)]),
600 +    [check_libmoonshot_dir="$withval"],
601 +    [check_libmoonshot_dir=])
602 +for dir in $check_libmoonshot_dir $prefix /usr /usr/local ; do
603 +   libmoonshotdir="$dir"
604 +   if test -f "$dir/include/libmoonshot.h"; then
605 +     found_libmoonshot="yes";
606 +     LIBMOONSHOT_DIR="${libmoonshotdir}"
607 +     LIBMOONSHOT_CFLAGS="-I$libmoonshotdir/include";
608 +     break;
609 +   fi
610 +done
611 +AC_MSG_RESULT($found_libmoonshot)
612 +if test x_$found_libmoonshot = x_yes; then
613 +    printf "libmoonshot found in $libmoonshotdir\n";
614 +    LIBMOONSHOT_LIBS="-lmoonshot";
615 +    LIBMOONSHOT_LDFLAGS="-L$libmoonshot/lib";
616 +    AC_CHECK_LIB(moonshot, moonshot_get_identity, [AC_DEFINE_UNQUOTED([HAVE_MOONSHOT_GET_IDENTITY], 1, [Define if Moonshot identity selector is available])], [], "$LIBMOONSHOT_LIBS")
617 +fi
618 +    AC_SUBST(LIBMOONSHOT_CFLAGS)
619 +    AC_SUBST(LIBMOONSHOT_LDFLAGS)
620 +    AC_SUBST(LIBMOONSHOT_LIBS)
621 +    AM_CONDITIONAL(LIBMOONSHOT, test "x$found_libmoonshot" != "xno")
622 +])dnl
623 +
624 diff --git a/autogen.sh b/autogen.sh
625 new file mode 100755
626 index 0000000..13432d0
627 --- /dev/null
628 +++ b/autogen.sh
629 @@ -0,0 +1,16 @@
630 +#!/bin/sh
631 +#
632 +# Regenerate autotools files.
633 +#
634 +
635 +PATH=/usr/local/bin:$PATH
636 +
637 +if [ -x "`which autoreconf 2>/dev/null`" ] ; then
638 +   exec autoreconf -ivf
639 +fi
640 +
641 +aclocal -I . -I m4 && \
642 +    autoheader && \
643 +    libtoolize --automake -c && \
644 +    autoconf && \
645 +    automake --add-missing --copy
646 diff --git a/build-aux/compile b/build-aux/compile
647 new file mode 100755
648 index 0000000..5360806
649 --- /dev/null
650 +++ b/build-aux/compile
651 @@ -0,0 +1,144 @@
652 +#! /bin/sh
653 +# Wrapper for compilers which do not understand `-c -o'.
654 +
655 +scriptversion=2009-10-06.20; # UTC
656 +
657 +# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2009  Free Software
658 +# Foundation, Inc.
659 +# Written by Tom Tromey <tromey@cygnus.com>.
660 +#
661 +# This program is free software; you can redistribute it and/or modify
662 +# it under the terms of the GNU General Public License as published by
663 +# the Free Software Foundation; either version 2, or (at your option)
664 +# any later version.
665 +#
666 +# This program is distributed in the hope that it will be useful,
667 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
668 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
669 +# GNU General Public License for more details.
670 +#
671 +# You should have received a copy of the GNU General Public License
672 +# along with this program; if not, write to the Free Software
673 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
674 +
675 +# As a special exception to the GNU General Public License, if you
676 +# distribute this file as part of a program that contains a
677 +# configuration script generated by Autoconf, you may include it under
678 +# the same distribution terms that you use for the rest of that program.
679 +
680 +# This file is maintained in Automake, please report
681 +# bugs to <bug-automake@gnu.org> or send patches to
682 +# <automake-patches@gnu.org>.
683 +
684 +case $1 in
685 +  '')
686 +     echo "$0: No command.  Try \`$0 --help' for more information." 1>&2
687 +     exit 1;
688 +     ;;
689 +  -h | --h*)
690 +    cat <<\EOF
691 +Usage: compile [--help] [--version] PROGRAM [ARGS]
692 +
693 +Wrapper for compilers which do not understand `-c -o'.
694 +Remove `-o dest.o' from ARGS, run PROGRAM with the remaining
695 +arguments, and rename the output as expected.
696 +
697 +If you are trying to build a whole package this is not the
698 +right script to run: please start by reading the file `INSTALL'.
699 +
700 +Report bugs to <bug-automake@gnu.org>.
701 +EOF
702 +    exit $?
703 +    ;;
704 +  -v | --v*)
705 +    echo "compile $scriptversion"
706 +    exit $?
707 +    ;;
708 +esac
709 +
710 +ofile=
711 +cfile=
712 +eat=
713 +
714 +for arg
715 +do
716 +  if test -n "$eat"; then
717 +    eat=
718 +  else
719 +    case $1 in
720 +      -o)
721 +       # configure might choose to run compile as `compile cc -o foo foo.c'.
722 +       # So we strip `-o arg' only if arg is an object.
723 +       eat=1
724 +       case $2 in
725 +         *.o | *.obj)
726 +           ofile=$2
727 +           ;;
728 +         *)
729 +           set x "$@" -o "$2"
730 +           shift
731 +           ;;
732 +       esac
733 +       ;;
734 +      *.c)
735 +       cfile=$1
736 +       set x "$@" "$1"
737 +       shift
738 +       ;;
739 +      *)
740 +       set x "$@" "$1"
741 +       shift
742 +       ;;
743 +    esac
744 +  fi
745 +  shift
746 +done
747 +
748 +if test -z "$ofile" || test -z "$cfile"; then
749 +  # If no `-o' option was seen then we might have been invoked from a
750 +  # pattern rule where we don't need one.  That is ok -- this is a
751 +  # normal compilation that the losing compiler can handle.  If no
752 +  # `.c' file was seen then we are probably linking.  That is also
753 +  # ok.
754 +  exec "$@"
755 +fi
756 +
757 +# Name of file we expect compiler to create.
758 +cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
759 +
760 +# Create the lock directory.
761 +# Note: use `[/\\:.-]' here to ensure that we don't use the same name
762 +# that we are using for the .o file.  Also, base the name on the expected
763 +# object file name, since that is what matters with a parallel build.
764 +lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
765 +while true; do
766 +  if mkdir "$lockdir" >/dev/null 2>&1; then
767 +    break
768 +  fi
769 +  sleep 1
770 +done
771 +# FIXME: race condition here if user kills between mkdir and trap.
772 +trap "rmdir '$lockdir'; exit 1" 1 2 15
773 +
774 +# Run the compile.
775 +"$@"
776 +ret=$?
777 +
778 +if test -f "$cofile"; then
779 +  test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
780 +elif test -f "${cofile}bj"; then
781 +  test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
782 +fi
783 +
784 +rmdir "$lockdir"
785 +exit $ret
786 +
787 +# Local Variables:
788 +# mode: shell-script
789 +# sh-indentation: 2
790 +# eval: (add-hook 'write-file-hooks 'time-stamp)
791 +# time-stamp-start: "scriptversion="
792 +# time-stamp-format: "%:y-%02m-%02d.%02H"
793 +# time-stamp-time-zone: "UTC"
794 +# time-stamp-end: "; # UTC"
795 +# End:
796 diff --git a/configure.ac b/configure.ac
797 new file mode 100644
798 index 0000000..ba23c32
799 --- /dev/null
800 +++ b/configure.ac
801 @@ -0,0 +1,92 @@
802 +AC_PREREQ([2.61])
803 +AC_INIT([mech_eap], [0.1], [bugs@project-moonshot.org])
804 +AC_CONFIG_MACRO_DIR([m4])
805 +AC_CONFIG_AUX_DIR([build-aux])
806 +
807 +dnl AM_INIT_AUTOMAKE([silent-rules])
808 +AC_USE_SYSTEM_EXTENSIONS
809 +AM_INIT_AUTOMAKE
810 +AM_PROG_CC_C_O
811 +AM_MAINTAINER_MODE()
812 +LT_PREREQ([2.2])
813 +LT_INIT([dlopen disable-static win32-dll])
814 +
815 +dnl AC_PROG_CC
816 +AC_PROG_CXX
817 +AC_CONFIG_HEADERS([config.h])
818 +AC_CHECK_HEADERS(stdarg.h stdio.h stdint.h sys/param.h)
819 +AC_REPLACE_FUNCS(vasprintf)
820 +
821 +dnl Check if we're on Solaris and set CFLAGS accordingly
822 +dnl AC_CANONICAL_TARGET
823 +dnl case "${target_os}" in
824 +dnl   solaris*)
825 +dnl     TARGET_CFLAGS="-DSYS_SOLARIS9 -D_POSIX_PTHREAD_SEMANTICS"
826 +dnl     if test "$GCC" != yes ; then
827 +dnl       TARGET_CFLAGS="$TARGET_CFLAGS -mt"
828 +dnl     else
829 +dnl       TARGET_CFLAGS="$TARGET_CFLAGS -pthreads"
830 +dnl     fi
831 +dnl     TARGET_LDFLAGS="-lpthread -lsocket -lnsl"
832 +dnl     ;;
833 +dnl   *)
834 +dnl     TARGET_CFLAGS="-Wall -pedantic -pthread"
835 +dnl     TARGET_LDFLAGS=""
836 +dnl   esac
837 +
838 +reauth=no
839 +AC_ARG_ENABLE(reauth,
840 +  [  --enable-reauth whether to enable fast reauthentication protocol: yes/no; default no ],
841 +  [ if test "x$enableval" = "xyes" -o "x$enableval" = "xno" ; then
842 +      reauth=$enableval
843 +    else
844 +      echo "--enable-reauth argument must be yes or no"
845 +      exit -1
846 +    fi
847 +  ])
848 +
849 +if test "x$reauth" = "xyes" ; then
850 +  echo "Fast reauthentication protocol enabled"
851 +  TARGET_CFLAGS="$TARGET_CFLAGS -DGSSEAP_ENABLE_REAUTH"
852 +fi
853 +AM_CONDITIONAL(GSSEAP_ENABLE_REAUTH, test "x$reauth" != "xno")
854 +
855 +acceptor=yes
856 +AC_ARG_ENABLE(acceptor,
857 +  [  --enable-acceptor whether to enable acceptor codepaths: yes/no; default yes ],
858 +  [ if test "x$enableval" = "xyes" -o "x$enableval" = "xno" ; then
859 +      acceptor=$enableval
860 +    else
861 +      echo "--enable-acceptor argument must be yes or no"
862 +      exit -1
863 +    fi
864 +  ])
865 +
866 +if test "x$acceptor" = "xyes" ; then
867 +  echo "acceptor enabled"
868 +  TARGET_CFLAGS="$TARGET_CFLAGS -DGSSEAP_ENABLE_ACCEPTOR"
869 +fi
870 +AM_CONDITIONAL(GSSEAP_ENABLE_ACCEPTOR, test "x$acceptor" != "xno")
871 +
872 +AC_SUBST(TARGET_CFLAGS)
873 +AC_SUBST(TARGET_LDFLAGS)
874 +AX_CHECK_WINDOWS
875 +AX_CHECK_KRB5
876 +AX_CHECK_OPENSAML
877 +AM_CONDITIONAL(OPENSAML, test "x_$check_opensaml_dir" != "x_no")
878 +
879 +AX_CHECK_SHIBRESOLVER
880 +AM_CONDITIONAL(SHIBRESOLVER, test "x_$check_shibresolver_dir" != "x_no")
881 +if test x_$found_shibresolver = x_yes; then
882 +  AX_CHECK_SHIBSP
883 +fi
884 +
885 +if test "x$acceptor" = "xyes" ; then
886 +  AX_CHECK_RADSEC
887 +  AX_CHECK_JANSSON
888 +fi
889 +
890 +AX_CHECK_LIBMOONSHOT
891 +AC_CONFIG_FILES([Makefile mech_eap/Makefile
892 +                         mech_eap.spec])
893 +AC_OUTPUT
894 diff --git a/m4/minuso.m4 b/m4/minuso.m4
895 new file mode 100644
896 index 0000000..d8b1620
897 --- /dev/null
898 +++ b/m4/minuso.m4
899 @@ -0,0 +1,35 @@
900 +##                                                          -*- Autoconf -*-
901 +# Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2008
902 +# Free Software Foundation, Inc.
903 +#
904 +# This file is free software; the Free Software Foundation
905 +# gives unlimited permission to copy and/or distribute it,
906 +# with or without modifications, as long as this notice is preserved.
907 +
908 +# serial 6
909 +
910 +# AM_PROG_CC_C_O
911 +# --------------
912 +# Like AC_PROG_CC_C_O, but changed for automake.
913 +AC_DEFUN([AM_PROG_CC_C_O],
914 +[AC_REQUIRE([AC_PROG_CC_C_O])dnl
915 +AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
916 +AC_REQUIRE_AUX_FILE([compile])dnl
917 +# FIXME: we rely on the cache variable name because
918 +# there is no other way.
919 +set dummy $CC
920 +am_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']`
921 +eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o
922 +if test "$am_t" != yes; then
923 +   # Losing compiler, so override with the script.
924 +   # FIXME: It is wrong to rewrite CC.
925 +   # But if we don't then we get into trouble of one sort or another.
926 +   # A longer-term fix would be to have automake use am__CC in this case,
927 +   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
928 +   CC="$am_aux_dir/compile $CC"
929 +fi
930 +dnl Make sure AC_PROG_CC is never called again, or it will override our
931 +dnl setting of CC.
932 +m4_define([AC_PROG_CC],
933 +          [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])])
934 +])
935 diff --git a/mech_eap.spec.in b/mech_eap.spec.in
936 new file mode 100644
937 index 0000000..90ac6cf
938 --- /dev/null
939 +++ b/mech_eap.spec.in
940 @@ -0,0 +1,62 @@
941 +%global _moonshot_krb5 %{!?_moonshot_krb5:krb5-devel}%{?_moonshot_krb5}
942 +Name:          moonshot-gss-eap
943 +Version:       @VERSION@
944 +Release:       3%{?dist}
945 +Summary:       Moonshot GSS-API Mechanism
946 +
947 +Group:         Security Tools
948 +License:       BSD
949 +URL:           http://www.project-moonshot.org/
950 +Source0:       mech_eap-%{version}.tar.gz
951 +BuildRoot:     %{_tmppath}/%{name}-%{version}-%{release}-root
952 +
953 +BuildRequires:  %{_moonshot_krb5} >= 1.9.1
954 +BuildRequires:  moonshot-ui-devel
955 +BuildRequires: jansson-devel
956 +Requires:      moonshot-ui
957 +BuildRequires: libradsec-devel
958 +BuildRequires: shibboleth-devel >= 2.5
959 +BuildRequires: libshibresolver-devel
960 +
961 +
962 +
963 +%description
964 +Project Moonshot provides federated access management.
965 +
966 +
967 +%prep
968 +%setup -q -n mech_eap-%{version}
969 +
970 +
971 +%build
972 +       export LDFLAGS='-L/usr/%{_lib}/freeradius -Wl,--rpath=/usr/%{_lib}/freeradius'
973 +%configure  --with-libmoonshot=%{_prefix} --with-krb5=%{_prefix} --disable-reauth
974 +make %{?_smp_mflags}
975 +
976 +
977 +%install
978 +rm -rf $RPM_BUILD_ROOT
979 +make install DESTDIR=$RPM_BUILD_ROOT
980 +
981 +
982 +%clean
983 +rm -rf $RPM_BUILD_ROOT
984 +
985 +
986 +%files
987 +%defattr(-,root,root,-)
988 +%doc mech_eap/README
989 +%doc mech_eap/LICENSE
990 +%doc mech_eap/AUTHORS
991 +%{_libdir}/gss/mech_eap.so
992 +%exclude %{_libdir}/gss/mech_eap.la
993 +%{_includedir}/gssapi/*.h
994 +#%exclude %{_libdir}/krb5/plugins/authdata/*la
995 +#%{_libdir}/krb5/plugins/authdata/*.so
996 +
997 +
998 +
999 +%changelog
1000 +* Wed Sep 28 2011  <hartmans@moonbuildcentos.dev.ja.net> - @VERSION@-2
1001 +- Add radius_ad plugin
1002 +
1003 diff --git a/mech_eap/.gitignore b/mech_eap/.gitignore
1004 new file mode 100644
1005 index 0000000..06a3924
1006 --- /dev/null
1007 +++ b/mech_eap/.gitignore
1008 @@ -0,0 +1,32 @@
1009 +/aclocal.m4
1010 +/autom4te.cache
1011 +/compile
1012 +/config.guess
1013 +/config.log
1014 +/config.status
1015 +/config.sub
1016 +/config.h
1017 +/configure
1018 +/config.h.in
1019 +/depcomp
1020 +
1021 +/libtool
1022 +/ltmain.sh
1023 +/missing
1024 +
1025 +/gsseap_err.[ch]
1026 +/radsec_err.[ch]
1027 +
1028 +.DS_Store
1029 +
1030 +Makefile.in
1031 +Makefile
1032 +
1033 +*.la
1034 +*.lo
1035 +*~
1036 +
1037 +.deps
1038 +.libs
1039 +.a.out.dSYM
1040 +.dSYM
1041 diff --git a/mech_eap/AUTHORS b/mech_eap/AUTHORS
1042 new file mode 100644
1043 index 0000000..3007a4b
1044 --- /dev/null
1045 +++ b/mech_eap/AUTHORS
1046 @@ -0,0 +1,6 @@
1047 +The initial implementation of mech_eap was written by PADL Software
1048 +under contract to JANET(UK).
1049 +
1050 +--
1051 +Luke Howard <lukeh@padl.com>
1052 +January, 2011
1053 diff --git a/mech_eap/COPYING b/mech_eap/COPYING
1054 new file mode 100644
1055 index 0000000..7554e77
1056 --- /dev/null
1057 +++ b/mech_eap/COPYING
1058 @@ -0,0 +1,3 @@
1059 +Copyright (c) 2011, JANET(UK)
1060 +
1061 +See the LICENSE file for licensing terms.
1062 diff --git a/mech_eap/LICENSE b/mech_eap/LICENSE
1063 new file mode 100644
1064 index 0000000..1b03a95
1065 --- /dev/null
1066 +++ b/mech_eap/LICENSE
1067 @@ -0,0 +1,31 @@
1068 +/*
1069 + * Copyright (c) 2011, JANET(UK)
1070 + * All rights reserved.
1071 + *
1072 + * Redistribution and use in source and binary forms, with or without
1073 + * modification, are permitted provided that the following conditions
1074 + * are met:
1075 + *
1076 + * 1. Redistributions of source code must retain the above copyright
1077 + *    notice, this list of conditions and the following disclaimer.
1078 + *
1079 + * 2. Redistributions in binary form must reproduce the above copyright
1080 + *    notice, this list of conditions and the following disclaimer in the
1081 + *    documentation and/or other materials provided with the distribution.
1082 + *
1083 + * 3. Neither the name of JANET(UK) nor the names of its contributors
1084 + *    may be used to endorse or promote products derived from this software
1085 + *    without specific prior written permission.
1086 + *
1087 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1088 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1089 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1090 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
1091 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1092 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1093 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1094 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1095 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1096 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1097 + * SUCH DAMAGE.
1098 + */
1099 diff --git a/mech_eap/Makefile.am b/mech_eap/Makefile.am
1100 new file mode 100644
1101 index 0000000..23de6af
1102 --- /dev/null
1103 +++ b/mech_eap/Makefile.am
1104 @@ -0,0 +1,189 @@
1105 +AUTOMAKE_OPTIONS = foreign
1106 +
1107 +EXTRA_DIST = gsseap_err.et radsec_err.et \
1108 +       mech_eap.exports mech_eap-noacceptor.exports  radius_ad.exports \
1109 +       LICENSE AUTHORS
1110 +
1111 +
1112 +gssincludedir = $(includedir)/gssapi
1113 +gssinclude_HEADERS = gssapi_eap.h
1114 +
1115 +EAP_CFLAGS = -I$(srcdir)/../libeap/src -I$(srcdir)/../libeap/src/common -I$(srcdir)/../libeap/src/eap_common  \
1116 +       -I$(srcdir)/../libeap/src/utils
1117 +
1118 +if GSSEAP_ENABLE_ACCEPTOR
1119 +GSSEAP_EXPORTS = mech_eap.exports
1120 +else
1121 +GSSEAP_EXPORTS = mech_eap-noacceptor.exports
1122 +endif
1123 +
1124 +gssdir = $(libdir)/gss
1125 +gss_LTLIBRARIES = mech_eap.la
1126 +
1127 +if TARGET_WINDOWS
1128 +EAP_CFLAGS += -DCONFIG_WIN32_DEFAULTS -DUSE_INTERNAL_CRYPTO
1129 +OS_LIBS = -lshell32 -ladvapi32 -lws2_32 -lcomerr32
1130 +mech_eap_la_CFLAGS   = -Zi
1131 +mech_eap_la_CXXFLAGS = -Zi
1132 +else
1133 +EAP_CFLAGS += -DEAP_TLS -DEAP_PEAP -DEAP_TTLS -DEAP_MD5 -DEAP_MSCHAPv2 -DEAP_GTC -DEAP_OTP -DEAP_LEAP -DEAP_PSK -DEAP_PAX -DEAP_SAKE -DEAP_GPSK -DEAP_GPSK_SHA256 -DEAP_SERVER_IDENTITY -DEAP_SERVER_TLS -DEAP_SERVER_PEAP -DEAP_SERVER_TTLS -DEAP_SERVER_MD5 -DEAP_SERVER_MSCHAPV2 -DEAP_SERVER_GTC -DEAP_SERVER_PSK -DEAP_SERVER_PAX -DEAP_SERVER_SAKE -DEAP_SERVER_GPSK -DEAP_SERVER_GPSK_SHA256 -DIEEE8021X_EAPOL
1134 +OS_LIBS =
1135 +mech_eap_la_CFLAGS   = -Werror -Wall -Wunused-parameter
1136 +mech_eap_la_CXXFLAGS = -Werror -Wall -Wunused-parameter
1137 +endif
1138 +mech_eap_la_DEPENDENCIES = $(GSSEAP_EXPORTS)
1139 +
1140 +mech_eap_la_CPPFLAGS = -DBUILD_GSSEAP_LIB -DSYSCONFDIR=\"${sysconfdir}\" -DDATAROOTDIR=\"${datarootdir}\"
1141 +mech_eap_la_CFLAGS   += \
1142 +                       @KRB5_CFLAGS@ @RADSEC_CFLAGS@ @TARGET_CFLAGS@ $(EAP_CFLAGS)
1143 +mech_eap_la_CXXFLAGS += \
1144 +                       @KRB5_CFLAGS@ @RADSEC_CFLAGS@ \
1145 +                       @OPENSAML_CXXFLAGS@ @SHIBRESOLVER_CXXFLAGS@ @SHIBSP_CXXFLAGS@ \
1146 +                       @TARGET_CFLAGS@ $(EAP_CFLAGS)
1147 +mech_eap_la_LDFLAGS  = -avoid-version -module \
1148 +                       -export-symbols $(GSSEAP_EXPORTS) -no-undefined \
1149 +                       @KRB5_LDFLAGS@ @RADSEC_LDFLAGS@ @TARGET_LDFLAGS@
1150 +if TARGET_WINDOWS
1151 +mech_eap_la_LDFLAGS += -debug
1152 +endif
1153 +
1154 +mech_eap_la_LIBADD   = @KRB5_LIBS@ ../libeap/libeap.la @RADSEC_LIBS@ \
1155 +                      @OPENSAML_LIBS@ @SHIBRESOLVER_LIBS@ @SHIBSP_LIBS@ @JANSSON_LIBS@
1156 +mech_eap_la_SOURCES =                          \
1157 +       acquire_cred.c                          \
1158 +       acquire_cred_with_password.c            \
1159 +       add_cred.c                              \
1160 +       add_cred_with_password.c                \
1161 +       authorize_localname.c                   \
1162 +       canonicalize_name.c                     \
1163 +       compare_name.c                          \
1164 +       context_time.c                          \
1165 +       delete_sec_context.c                    \
1166 +       display_name.c                          \
1167 +       display_name_ext.c                      \
1168 +       display_status.c                        \
1169 +       duplicate_name.c                        \
1170 +       eap_mech.c                              \
1171 +       exchange_meta_data.c                    \
1172 +       export_name.c                           \
1173 +       export_sec_context.c                    \
1174 +       get_mic.c                               \
1175 +       gsseap_err.c                            \
1176 +       import_name.c                           \
1177 +       import_sec_context.c                    \
1178 +       indicate_mechs.c                        \
1179 +       init_sec_context.c                      \
1180 +       inquire_attrs_for_mech.c                \
1181 +       inquire_context.c                       \
1182 +       inquire_cred.c                          \
1183 +       inquire_cred_by_mech.c                  \
1184 +       inquire_cred_by_oid.c                   \
1185 +       inquire_mech_for_saslname.c             \
1186 +       inquire_mechs_for_name.c                \
1187 +       inquire_names_for_mech.c                \
1188 +       inquire_saslname_for_mech.c             \
1189 +       inquire_sec_context_by_oid.c            \
1190 +       process_context_token.c                 \
1191 +       pseudo_random.c                         \
1192 +       query_mechanism_info.c                  \
1193 +       query_meta_data.c                       \
1194 +       radsec_err.c                            \
1195 +       release_cred.c                          \
1196 +       release_name.c                          \
1197 +       release_oid.c                           \
1198 +       set_cred_option.c                       \
1199 +       set_sec_context_option.c                \
1200 +       store_cred.c                            \
1201 +       unwrap.c                                \
1202 +       unwrap_iov.c                            \
1203 +       util_buffer.c                           \
1204 +       util_context.c                          \
1205 +       util_cksum.c                            \
1206 +       util_cred.c                             \
1207 +       util_crypt.c                            \
1208 +       util_krb.c                              \
1209 +       util_lucid.c                            \
1210 +       util_mech.c                             \
1211 +       util_name.c                             \
1212 +       util_oid.c                              \
1213 +       util_ordering.c                         \
1214 +       util_sm.c                               \
1215 +       util_tld.c                              \
1216 +       util_token.c                            \
1217 +       verify_mic.c                            \
1218 +       wrap.c                                  \
1219 +       wrap_iov.c                              \
1220 +       wrap_iov_length.c                       \
1221 +       wrap_size_limit.c \
1222 +       gssapiP_eap.h \
1223 +       util_attr.h \
1224 +       util_base64.h \
1225 +       util.h \
1226 +       util_json.h \
1227 +       util_radius.h \
1228 +       util_reauth.h \
1229 +       util_saml.h \
1230 +       util_shib.h
1231 +
1232 +if LIBMOONSHOT
1233 +mech_eap_la_SOURCES += util_moonshot.c
1234 +mech_eap_la_CFLAGS  += @LIBMOONSHOT_CFLAGS@
1235 +mech_eap_la_LDFLAGS += @LIBMOONSHOT_LDFLAGS@
1236 +mech_eap_la_LIBADD  += @LIBMOONSHOT_LIBS@
1237 +endif
1238 +
1239 +
1240 +if GSSEAP_ENABLE_ACCEPTOR
1241 +
1242 +mech_eap_la_SOURCES +=                         \
1243 +       accept_sec_context.c                    \
1244 +       delete_name_attribute.c                 \
1245 +       export_name_composite.c                 \
1246 +       get_name_attribute.c                    \
1247 +       inquire_name.c                          \
1248 +       map_name_to_any.c                       \
1249 +       release_any_name_mapping.c              \
1250 +       set_name_attribute.c                    \
1251 +       util_attr.cpp                           \
1252 +       util_base64.c                           \
1253 +       util_json.cpp                           \
1254 +       util_radius.cpp
1255 +
1256 +if OPENSAML
1257 +mech_eap_la_SOURCES += util_saml.cpp
1258 +endif
1259 +
1260 +if SHIBRESOLVER
1261 +mech_eap_la_SOURCES += util_shib.cpp
1262 +endif
1263 +
1264 +endif
1265 +
1266 +BUILT_SOURCES = gsseap_err.c radsec_err.c gsseap_err.h radsec_err.h
1267 +
1268 +if GSSEAP_ENABLE_REAUTH
1269 +mech_eap_la_SOURCES += util_reauth.c
1270 +
1271 +if !HEIMDAL
1272 +krb5pluginsdir = $(libdir)/krb5/plugins/authdata
1273 +krb5plugins_LTLIBRARIES = radius_ad.la
1274 +
1275 +radius_ad_la_CFLAGS  = -Werror -Wall -Wunused-parameter \
1276 +                       @KRB5_CFLAGS@ $(EAP_CFLAGS) @RADSEC_CFLAGS@ @TARGET_CFLAGS@
1277 +radius_ad_la_LDFLAGS = -avoid-version -module \
1278 +                      -export-symbols radius_ad.exports -no-undefined
1279 +radius_ad_la_LIBADD  = @KRB5_LIBS@
1280 +radius_ad_la_SOURCES = util_adshim.c authdata_plugin.h
1281 +endif
1282 +endif
1283 +
1284 +gsseap_err.h gsseap_err.c: gsseap_err.et
1285 +       $(COMPILE_ET) $<
1286 +
1287 +radsec_err.h radsec_err.c: radsec_err.et
1288 +       $(COMPILE_ET) $<
1289 +
1290 +radsec_err.c: radsec_err.h
1291 +
1292 +clean-generic:
1293 +       rm -f gsseap_err.[ch] radsec_err.[ch]
1294 diff --git a/mech_eap/NEWS b/mech_eap/NEWS
1295 new file mode 100644
1296 index 0000000..e69de29
1297 diff --git a/mech_eap/NOTES b/mech_eap/NOTES
1298 new file mode 100644
1299 index 0000000..849ce4e
1300 --- /dev/null
1301 +++ b/mech_eap/NOTES
1302 @@ -0,0 +1,9 @@
1303 +- gss_xxx routines acquire lock, gssXxx don't
1304 +
1305 +- git
1306 +
1307 +If you do want to update with a rebase, deletethe branch from the
1308 +server first then push the rebased branch
1309 +
1310 +to delete a branch from a server git push origin :branch_to_del
1311 +
1312 diff --git a/mech_eap/README b/mech_eap/README
1313 new file mode 100644
1314 index 0000000..3cb2d50
1315 --- /dev/null
1316 +++ b/mech_eap/README
1317 @@ -0,0 +1,147 @@
1318 +Overview
1319 +========
1320 +
1321 +This is an implementation of the GSS EAP mechanism, as described in
1322 +draft-ietf-abfab-gss-eap-01.txt.
1323 +
1324 +Building
1325 +========
1326 +
1327 +In order to build this, a recent Kerberos implementation (MIT or
1328 +Heimdal), Shibboleth, and EAP libraries are required, along with
1329 +all of their dependencies.
1330 +
1331 +Note: not all SPIs are supported by the Heimdal mechanism glue,
1332 +so not all features will be available.
1333 +
1334 +Installing
1335 +==========
1336 +
1337 +GSS mechglue
1338 +------------
1339 +
1340 +When installing, be sure to edit $prefix/etc/gss/mech to register
1341 +the EAP mechanisms. A sample configuration file is in this directory.
1342 +You may need to specify an absolute path.
1343 +
1344 +RADIUS client library
1345 +---------------------
1346 +
1347 +Make sure your RADIUS library is configured to talk to the server of
1348 +your choice: see the example radsec.conf in this directory. If you
1349 +want to use TCP or TLS, you'll need to run radsecproxy in front of
1350 +your RADIUS server.
1351 +
1352 +RADIUS server
1353 +-------------
1354 +
1355 +These instructions apply to FreeRADIUS only, which is downloadable
1356 +from http://freeradius.org/. After configure, make, install, do the
1357 +following:
1358 +
1359 +On the RADIUS server side, you need to install dictionary.ukerna to
1360 +$prefix/etc/raddb and include it from the main dictionary file, by
1361 +adding:
1362 +
1363 +    $INCLUDE dictionary.ukerna
1364 +
1365 +to $prefix/etc/raddb/dictionary. Make sure these files are world-
1366 +readable; they weren't in my installation.
1367 +
1368 +Edit $prefix/etc/raddb/users to add your test user and password:
1369 +
1370 +    bob@PROJECT-MOONSHOT.ORG Cleartext-Password := secret
1371 +
1372 +Add an entry for your acceptor to $prefix/etc/raddb/clients.conf:
1373 +
1374 +    client somehost {
1375 +        ipaddr = 127.0.0.1
1376 +        secret = testing123
1377 +        require_message_authenticator = yes
1378 +    }
1379 +
1380 +Edit $prefix/etc/raddb/eap.conf and set:
1381 +
1382 +    eap {
1383 +...
1384 +        default_eap_type = ttls
1385 +...
1386 +        tls {
1387 +            certdir = ...
1388 +            cadir = ...
1389 +            private_key_file = ...
1390 +            certificate_file = ...
1391 +        }
1392 +        ttls {
1393 +            default_eap_type = mschapv2
1394 +            copy_request_to_tunnel = no
1395 +            use_tunneled_reply = no
1396 +            virtual_server = "inner-tunnel"
1397 +        }
1398 +...
1399 +    }
1400 +
1401 +to enable EAP-TTLS.
1402 +
1403 +If you want the acceptor be able to identify the user, the RADIUS
1404 +server needs to echo back the EAP username from the inner tunnel;
1405 +for privacy, mech_eap only sends the realm in the EAP Identity
1406 +response. To configure this with FreeRADIUS, add:
1407 +
1408 +    update outer.reply {
1409 +        User-Name = "%{request:User-Name}"
1410 +    }
1411 +
1412 +If you want to add a SAML assertion, do this with "update reply"
1413 +in $prefix/etc/raddb/sites-available/default:
1414 +
1415 +    update reply {
1416 +        SAML-AAA-Assertion = '<saml:Assertion ...'
1417 +        SAML-AAA-Assertion += '...'
1418 +    }
1419 +
1420 +You'll need to split it into multiple lines because of the RADIUS
1421 +attribute size limit.
1422 +
1423 +Testing
1424 +=======
1425 +
1426 +You can then test the MIT or Cyrus GSS and SASL example programs.
1427 +Sample usage is given below. Substitute <user>, <pass> and <host>
1428 +appropriately (<host> is the name of the host running the server,
1429 +not the RADIUS server).
1430 +
1431 +% gss-client -port 5555 -spnego -mech "{1 3 6 1 4 1 5322 22 1 18}" \
1432 +  -user <user>@<realm> -pass <pass> <host> host@<host> \
1433 +  "Testing GSS EAP"
1434 +% gss-server -port 5555 -export host@<host>
1435 +
1436 +Note: for SASL you will be prompted for a username and password.
1437 +
1438 +% client -C -p 5556 -s host -m EAP-AES128 <host>
1439 +% server -c -p 5556 -s host -h <host>
1440 +
1441 +To test fast reauthentication support, add the following to
1442 +/etc/krb5.conf:
1443 +
1444 +[appdefaults]
1445 +        eap_gss = {
1446 +                reauth_use_ccache = TRUE
1447 +        }
1448 +
1449 +This will store a Kerberos ticket for a GSS-EAP authenticated user
1450 +in a credentials cache, which can then be used for re-authentication
1451 +to the same acceptor. You must have a valid keytab configured.
1452 +
1453 +In this testing phase of Moonshot, it's also possible to store a
1454 +default identity and credential in a file. The format consists of
1455 +the string representation of the initiator identity and the password,
1456 +separated by newlines. The default location of this file is
1457 +.gss_eap_id in the user's home directory, however the GSSEAP_IDENTITY
1458 +environment variable can be used to set an alternate location.
1459 +
1460 +You can also set a default realm in [appdefaults]; the Kerberos
1461 +default realm is never used by mech_eap (or at least, that is the
1462 +intention), so if unspecified you must always qualify names. It should
1463 +generally not be necessary to specify this.
1464 +
1465 diff --git a/mech_eap/README.samba4 b/mech_eap/README.samba4
1466 new file mode 100644
1467 index 0000000..d0a94d1
1468 --- /dev/null
1469 +++ b/mech_eap/README.samba4
1470 @@ -0,0 +1,52 @@
1471 +Notes on using Moonshot with Samba4. Replace paths as appropriate.
1472 +
1473 +Samba
1474 +-----
1475 +
1476 +* Download Samba4 and apply patches for mechanism agnosticism which are
1477 +  available at http://www.padl.com/~lukeh/samba/
1478 +* Join Samba as a member server or domain controller (only tested former)
1479 +* Extract local service principal key to keytab (currently there do not
1480 +  appear to be tools to do this, but you can get the cleartext password
1481 +  from /usr/local/samba/private/secrets.ldb)
1482 +
1483 +Shibboleth
1484 +----------
1485 +
1486 +* Add a mapping from the PAC RADIUS attribute to urn:mspac: in the file
1487 +  /usr/local/etc/shibboleth/attribute-map.xml:
1488 +
1489 +  <GSSAPIAttribute name="urn:ietf:params:gss-eap:radius-avp urn:x-radius:1679163525"
1490 +                   id="urn:mspac:" binary="true"/>
1491 +
1492 +FreeRADIUS
1493 +----------
1494 +
1495 +Install the rlm_mspac module and configure per below.
1496 +
1497 +* Install dictionary.ukerna so MS-Windows-Auth-Data is defined
1498 +* Create /usr/local/etc/raddb/modules/mspac with the following:
1499 +
1500 +    mspac {
1501 +        keytab = /etc/krb5.keytab
1502 +        spn = host/host.fqdn@KERBEROS.REALM
1503 +    }       
1504 +
1505 +* Add mspac to instantiate stanza in radiusd.conf
1506 +* Add mspac to post-auth stanza in sites-enabled/inner-tunnel
1507 +
1508 +You will need to have a TGT for the host service principal before starting
1509 +radiusd. It's easiest to do this with kinit -k.
1510 +
1511 +Testing
1512 +-------
1513 +
1514 +The Samba server doesn't require any specific command line arguments, although
1515 +on OS X it was necessary to start it with -M single to function under gdb.
1516 +
1517 +For the client, the GSS EAP mechanism can be specified on the command line:
1518 +
1519 +smbclient --password samba --mechanism 1.3.6.1.4.1.5322.22.1.18 '\\host\share'".
1520 +
1521 +There is no Moonshot SSPI implementation as yet, so it is not possible to test
1522 +with a Windows client.
1523 diff --git a/mech_eap/TODO b/mech_eap/TODO
1524 new file mode 100644
1525 index 0000000..0111459
1526 --- /dev/null
1527 +++ b/mech_eap/TODO
1528 @@ -0,0 +1,6 @@
1529 +- integration with initiator-side EAP channel bindings
1530 +- investigate initiator-side credential locking
1531 +- always intern OIDs so they never need to be freed
1532 +- handle many-to-many Shibboleth attribute mappings; need to encode both attribute and value index into more
1533 +- add --with-xerces option
1534 +- proper acquire_cred_ext implementation pending specification
1535 diff --git a/mech_eap/accept_sec_context.c b/mech_eap/accept_sec_context.c
1536 new file mode 100644
1537 index 0000000..b089bae
1538 --- /dev/null
1539 +++ b/mech_eap/accept_sec_context.c
1540 @@ -0,0 +1,1072 @@
1541 +/*
1542 + * Copyright (c) 2011, JANET(UK)
1543 + * All rights reserved.
1544 + *
1545 + * Redistribution and use in source and binary forms, with or without
1546 + * modification, are permitted provided that the following conditions
1547 + * are met:
1548 + *
1549 + * 1. Redistributions of source code must retain the above copyright
1550 + *    notice, this list of conditions and the following disclaimer.
1551 + *
1552 + * 2. Redistributions in binary form must reproduce the above copyright
1553 + *    notice, this list of conditions and the following disclaimer in the
1554 + *    documentation and/or other materials provided with the distribution.
1555 + *
1556 + * 3. Neither the name of JANET(UK) nor the names of its contributors
1557 + *    may be used to endorse or promote products derived from this software
1558 + *    without specific prior written permission.
1559 + *
1560 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1561 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1562 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1563 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
1564 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1565 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1566 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1567 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1568 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1569 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1570 + * SUCH DAMAGE.
1571 + */
1572 +
1573 +/*
1574 + * Establish a security context on the acceptor (server). These functions
1575 + * wrap around libradsec and (thus) talk to a RADIUS server or proxy.
1576 + */
1577 +
1578 +#include "gssapiP_eap.h"
1579 +
1580 +#ifdef GSSEAP_ENABLE_REAUTH
1581 +static OM_uint32
1582 +eapGssSmAcceptGssReauth(OM_uint32 *minor,
1583 +                        gss_cred_id_t cred,
1584 +                        gss_ctx_id_t ctx,
1585 +                        gss_name_t target,
1586 +                        gss_OID mech,
1587 +                        OM_uint32 reqFlags,
1588 +                        OM_uint32 timeReq,
1589 +                        gss_channel_bindings_t chanBindings,
1590 +                        gss_buffer_t inputToken,
1591 +                        gss_buffer_t outputToken,
1592 +                        OM_uint32 *smFlags);
1593 +#endif
1594 +
1595 +/*
1596 + * Mark an acceptor context as ready for cryptographic operations
1597 + */
1598 +static OM_uint32
1599 +acceptReadyEap(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred)
1600 +{
1601 +    OM_uint32 major, tmpMinor;
1602 +    VALUE_PAIR *vp;
1603 +    gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
1604 +
1605 +    /* Cache encryption type derived from selected mechanism OID */
1606 +    major = gssEapOidToEnctype(minor, ctx->mechanismUsed,
1607 +                               &ctx->encryptionType);
1608 +    if (GSS_ERROR(major))
1609 +        return major;
1610 +
1611 +    gssEapReleaseName(&tmpMinor, &ctx->initiatorName);
1612 +
1613 +    major = gssEapRadiusGetRawAvp(minor, ctx->acceptorCtx.vps,
1614 +                                  PW_USER_NAME, 0, &vp);
1615 +    if (major == GSS_S_COMPLETE && vp->length) {
1616 +        nameBuf.length = vp->length;
1617 +        nameBuf.value = vp->vp_strvalue;
1618 +    } else {
1619 +        ctx->gssFlags |= GSS_C_ANON_FLAG;
1620 +    }
1621 +
1622 +    major = gssEapImportName(minor, &nameBuf,
1623 +                             (ctx->gssFlags & GSS_C_ANON_FLAG) ?
1624 +                                GSS_C_NT_ANONYMOUS : GSS_C_NT_USER_NAME,
1625 +                             ctx->mechanismUsed,
1626 +                             &ctx->initiatorName);
1627 +    if (GSS_ERROR(major))
1628 +        return major;
1629 +
1630 +    major = gssEapRadiusGetRawAvp(minor, ctx->acceptorCtx.vps,
1631 +                                  PW_MS_MPPE_SEND_KEY, VENDORPEC_MS, &vp);
1632 +    if (GSS_ERROR(major)) {
1633 +        *minor = GSSEAP_KEY_UNAVAILABLE;
1634 +        return GSS_S_UNAVAILABLE;
1635 +    }
1636 +
1637 +    major = gssEapDeriveRfc3961Key(minor,
1638 +                                   vp->vp_octets,
1639 +                                   vp->length,
1640 +                                   ctx->encryptionType,
1641 +                                   &ctx->rfc3961Key);
1642 +    if (GSS_ERROR(major))
1643 +        return major;
1644 +
1645 +    major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
1646 +                                       &ctx->checksumType);
1647 +    if (GSS_ERROR(major))
1648 +        return major;
1649 +
1650 +    major = sequenceInit(minor,
1651 +                         &ctx->seqState, ctx->recvSeq,
1652 +                         ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0),
1653 +                         ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0),
1654 +                         TRUE);
1655 +    if (GSS_ERROR(major))
1656 +        return major;
1657 +
1658 +    major = gssEapCreateAttrContext(minor, cred, ctx,
1659 +                                    &ctx->initiatorName->attrCtx,
1660 +                                    &ctx->expiryTime);
1661 +    if (GSS_ERROR(major))
1662 +        return major;
1663 +
1664 +    if (ctx->expiryTime != 0 && ctx->expiryTime < time(NULL)) {
1665 +        *minor = GSSEAP_CRED_EXPIRED;
1666 +        return GSS_S_CREDENTIALS_EXPIRED;
1667 +    }
1668 +
1669 +    *minor = 0;
1670 +    return GSS_S_COMPLETE;
1671 +}
1672 +
1673 +static OM_uint32
1674 +eapGssSmAcceptAcceptorName(OM_uint32 *minor,
1675 +                           gss_cred_id_t cred GSSEAP_UNUSED,
1676 +                           gss_ctx_id_t ctx,
1677 +                           gss_name_t target GSSEAP_UNUSED,
1678 +                           gss_OID mech GSSEAP_UNUSED,
1679 +                           OM_uint32 reqFlags GSSEAP_UNUSED,
1680 +                           OM_uint32 timeReq GSSEAP_UNUSED,
1681 +                           gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
1682 +                           gss_buffer_t inputToken GSSEAP_UNUSED,
1683 +                           gss_buffer_t outputToken,
1684 +                           OM_uint32 *smFlags GSSEAP_UNUSED)
1685 +{
1686 +    OM_uint32 major;
1687 +
1688 +    /* XXX TODO import and validate name from inputToken */
1689 +
1690 +    if (ctx->acceptorName != GSS_C_NO_NAME) {
1691 +        /* Send desired target name to acceptor */
1692 +        major = gssEapDisplayName(minor, ctx->acceptorName,
1693 +                                  outputToken, NULL);
1694 +        if (GSS_ERROR(major))
1695 +            return major;
1696 +    }
1697 +
1698 +    return GSS_S_CONTINUE_NEEDED;
1699 +}
1700 +
1701 +#ifdef GSSEAP_DEBUG
1702 +static OM_uint32
1703 +eapGssSmAcceptVendorInfo(OM_uint32 *minor,
1704 +                         gss_cred_id_t cred GSSEAP_UNUSED,
1705 +                         gss_ctx_id_t ctx GSSEAP_UNUSED,
1706 +                         gss_name_t target GSSEAP_UNUSED,
1707 +                         gss_OID mech GSSEAP_UNUSED,
1708 +                         OM_uint32 reqFlags GSSEAP_UNUSED,
1709 +                         OM_uint32 timeReq GSSEAP_UNUSED,
1710 +                         gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
1711 +                         gss_buffer_t inputToken,
1712 +                         gss_buffer_t outputToken GSSEAP_UNUSED,
1713 +                         OM_uint32 *smFlags GSSEAP_UNUSED)
1714 +{
1715 +    fprintf(stderr, "GSS-EAP: vendor: %.*s\n",
1716 +            (int)inputToken->length, (char *)inputToken->value);
1717 +
1718 +    *minor = 0;
1719 +    return GSS_S_CONTINUE_NEEDED;
1720 +}
1721 +#endif
1722 +
1723 +
1724 +/*
1725 + * Emit a identity EAP request to force the initiator (peer) to identify
1726 + * itself.
1727 + */
1728 +static OM_uint32
1729 +eapGssSmAcceptIdentity(OM_uint32 *minor,
1730 +                       gss_cred_id_t cred,
1731 +                       gss_ctx_id_t ctx,
1732 +                       gss_name_t target GSSEAP_UNUSED,
1733 +                       gss_OID mech GSSEAP_UNUSED,
1734 +                       OM_uint32 reqFlags GSSEAP_UNUSED,
1735 +                       OM_uint32 timeReq GSSEAP_UNUSED,
1736 +                       gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
1737 +                       gss_buffer_t inputToken,
1738 +                       gss_buffer_t outputToken,
1739 +                       OM_uint32 *smFlags)
1740 +{
1741 +    OM_uint32 major;
1742 +    struct wpabuf *reqData;
1743 +    gss_buffer_desc pktBuffer;
1744 +
1745 +    if (!gssEapCredAvailable(cred, ctx->mechanismUsed)) {
1746 +        *minor = GSSEAP_CRED_MECH_MISMATCH;
1747 +        return GSS_S_BAD_MECH;
1748 +    }
1749 +
1750 +    if (inputToken != GSS_C_NO_BUFFER && inputToken->length != 0) {
1751 +        *minor = GSSEAP_WRONG_SIZE;
1752 +        return GSS_S_DEFECTIVE_TOKEN;
1753 +    }
1754 +
1755 +    reqData = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, 0,
1756 +                            EAP_CODE_REQUEST, 0);
1757 +    if (reqData == NULL) {
1758 +        *minor = ENOMEM;
1759 +        return GSS_S_FAILURE;
1760 +    }
1761 +
1762 +    pktBuffer.length = wpabuf_len(reqData);
1763 +    pktBuffer.value = (void *)wpabuf_head(reqData);
1764 +
1765 +    major = duplicateBuffer(minor, &pktBuffer, outputToken);
1766 +    if (GSS_ERROR(major))
1767 +        return major;
1768 +
1769 +    wpabuf_free(reqData);
1770 +
1771 +    GSSEAP_SM_TRANSITION_NEXT(ctx);
1772 +
1773 +    *minor = 0;
1774 +    *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
1775 +
1776 +    return GSS_S_CONTINUE_NEEDED;
1777 +}
1778 +
1779 +/*
1780 + * Returns TRUE if the input token contains an EAP identity response.
1781 + */
1782 +static int
1783 +isIdentityResponseP(gss_buffer_t inputToken)
1784 +{
1785 +    struct wpabuf respData;
1786 +
1787 +    wpabuf_set(&respData, inputToken->value, inputToken->length);
1788 +
1789 +    return (eap_get_type(&respData) == EAP_TYPE_IDENTITY);
1790 +}
1791 +
1792 +/*
1793 + * Save the asserted initiator identity from the EAP identity response.
1794 + */
1795 +static OM_uint32
1796 +importInitiatorIdentity(OM_uint32 *minor,
1797 +                        gss_ctx_id_t ctx,
1798 +                        gss_buffer_t inputToken)
1799 +{
1800 +    OM_uint32 tmpMinor;
1801 +    struct wpabuf respData;
1802 +    const unsigned char *pos;
1803 +    size_t len;
1804 +    gss_buffer_desc nameBuf;
1805 +
1806 +    wpabuf_set(&respData, inputToken->value, inputToken->length);
1807 +
1808 +    pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
1809 +                           &respData, &len);
1810 +    if (pos == NULL) {
1811 +        *minor = GSSEAP_PEER_BAD_MESSAGE;
1812 +        return GSS_S_DEFECTIVE_TOKEN;
1813 +    }
1814 +
1815 +    nameBuf.value = (void *)pos;
1816 +    nameBuf.length = len;
1817 +
1818 +    gssEapReleaseName(&tmpMinor, &ctx->initiatorName);
1819 +
1820 +    return gssEapImportName(minor, &nameBuf, GSS_C_NT_USER_NAME,
1821 +                            ctx->mechanismUsed, &ctx->initiatorName);
1822 +}
1823 +
1824 +/*
1825 + * Pass the asserted initiator identity to the authentication server.
1826 + */
1827 +static OM_uint32
1828 +setInitiatorIdentity(OM_uint32 *minor,
1829 +                     gss_ctx_id_t ctx,
1830 +                     VALUE_PAIR **vps)
1831 +{
1832 +    OM_uint32 major, tmpMinor;
1833 +    gss_buffer_desc nameBuf;
1834 +
1835 +    /*
1836 +     * We should have got an EAP identity response, but if we didn't, then
1837 +     * we will just avoid sending User-Name. Note that radsecproxy requires
1838 +     * User-Name to be sent on every request (presumably so it can remain
1839 +     * stateless).
1840 +     */
1841 +    if (ctx->initiatorName != GSS_C_NO_NAME) {
1842 +        major = gssEapDisplayName(minor, ctx->initiatorName, &nameBuf, NULL);
1843 +        if (GSS_ERROR(major))
1844 +            return major;
1845 +
1846 +        major = gssEapRadiusAddAvp(minor, vps, PW_USER_NAME, 0, &nameBuf);
1847 +        if (GSS_ERROR(major))
1848 +            return major;
1849 +
1850 +        gss_release_buffer(&tmpMinor, &nameBuf);
1851 +    }
1852 +
1853 +    *minor = 0;
1854 +    return GSS_S_COMPLETE;
1855 +}
1856 +
1857 +/*
1858 + * Pass the asserted acceptor identity to the authentication server.
1859 + */
1860 +static OM_uint32
1861 +setAcceptorIdentity(OM_uint32 *minor,
1862 +                    gss_ctx_id_t ctx,
1863 +                    VALUE_PAIR **vps)
1864 +{
1865 +    OM_uint32 major;
1866 +    gss_buffer_desc nameBuf;
1867 +    krb5_context krbContext = NULL;
1868 +    krb5_principal krbPrinc;
1869 +    struct rs_context *rc = ctx->acceptorCtx.radContext;
1870 +
1871 +    GSSEAP_ASSERT(rc != NULL);
1872 +
1873 +    if (ctx->acceptorName == GSS_C_NO_NAME) {
1874 +        *minor = 0;
1875 +        return GSS_S_COMPLETE;
1876 +    }
1877 +
1878 +    if ((ctx->acceptorName->flags & NAME_FLAG_SERVICE) == 0) {
1879 +        *minor = GSSEAP_BAD_SERVICE_NAME;
1880 +        return GSS_S_BAD_NAME;
1881 +    }
1882 +
1883 +    GSSEAP_KRB_INIT(&krbContext);
1884 +
1885 +    krbPrinc = ctx->acceptorName->krbPrincipal;
1886 +    GSSEAP_ASSERT(krbPrinc != NULL);
1887 +    GSSEAP_ASSERT(KRB_PRINC_LENGTH(krbPrinc) >= 2);
1888 +
1889 +    /* Acceptor-Service-Name */
1890 +    krbPrincComponentToGssBuffer(krbPrinc, 0, &nameBuf);
1891 +
1892 +    major = gssEapRadiusAddAvp(minor, vps,
1893 +                               PW_GSS_ACCEPTOR_SERVICE_NAME,
1894 +                               VENDORPEC_UKERNA,
1895 +                               &nameBuf);
1896 +    if (GSS_ERROR(major))
1897 +        return major;
1898 +
1899 +    /* Acceptor-Host-Name */
1900 +    krbPrincComponentToGssBuffer(krbPrinc, 1, &nameBuf);
1901 +
1902 +    major = gssEapRadiusAddAvp(minor, vps,
1903 +                               PW_GSS_ACCEPTOR_HOST_NAME,
1904 +                               VENDORPEC_UKERNA,
1905 +                               &nameBuf);
1906 +    if (GSS_ERROR(major))
1907 +        return major;
1908 +
1909 +    if (KRB_PRINC_LENGTH(krbPrinc) > 2) {
1910 +        /* Acceptor-Service-Specific */
1911 +        krb5_principal_data ssiPrinc = *krbPrinc;
1912 +        char *ssi;
1913 +
1914 +        KRB_PRINC_LENGTH(&ssiPrinc) -= 2;
1915 +        KRB_PRINC_NAME(&ssiPrinc) += 2;
1916 +
1917 +        *minor = krb5_unparse_name_flags(krbContext, &ssiPrinc,
1918 +                                         KRB5_PRINCIPAL_UNPARSE_NO_REALM, &ssi);
1919 +        if (*minor != 0)
1920 +            return GSS_S_FAILURE;
1921 +
1922 +        nameBuf.value = ssi;
1923 +        nameBuf.length = strlen(ssi);
1924 +
1925 +        major = gssEapRadiusAddAvp(minor, vps,
1926 +                                   PW_GSS_ACCEPTOR_SERVICE_SPECIFIC,
1927 +                                   VENDORPEC_UKERNA,
1928 +                                   &nameBuf);
1929 +
1930 +        if (GSS_ERROR(major)) {
1931 +            krb5_free_unparsed_name(krbContext, ssi);
1932 +            return major;
1933 +        }
1934 +        krb5_free_unparsed_name(krbContext, ssi);
1935 +    }
1936 +
1937 +    krbPrincRealmToGssBuffer(krbPrinc, &nameBuf);
1938 +    if (nameBuf.length != 0) {
1939 +        /* Acceptor-Realm-Name */
1940 +        major = gssEapRadiusAddAvp(minor, vps,
1941 +                                   PW_GSS_ACCEPTOR_REALM_NAME,
1942 +                                   VENDORPEC_UKERNA,
1943 +                                   &nameBuf);
1944 +        if (GSS_ERROR(major))
1945 +            return major;
1946 +    }
1947 +
1948 +    *minor = 0;
1949 +    return GSS_S_COMPLETE;
1950 +}
1951 +
1952 +/*
1953 + * Allocate a RadSec handle
1954 + */
1955 +static OM_uint32
1956 +createRadiusHandle(OM_uint32 *minor,
1957 +                   gss_cred_id_t cred,
1958 +                   gss_ctx_id_t ctx)
1959 +{
1960 +    struct gss_eap_acceptor_ctx *actx = &ctx->acceptorCtx;
1961 +    struct rs_error *err;
1962 +    const char *configStanza = "gss-eap";
1963 +    OM_uint32 major;
1964 +
1965 +    GSSEAP_ASSERT(actx->radContext == NULL);
1966 +    GSSEAP_ASSERT(actx->radConn == NULL);
1967 +    GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL);
1968 +
1969 +    major = gssEapCreateRadiusContext(minor, cred, &actx->radContext);
1970 +    if (GSS_ERROR(major))
1971 +        return major;
1972 +
1973 +    if (cred->radiusConfigStanza.value != NULL)
1974 +        configStanza = (const char *)cred->radiusConfigStanza.value;
1975 +
1976 +    if (rs_conn_create(actx->radContext, &actx->radConn, configStanza) != 0) {
1977 +        err = rs_err_conn_pop(actx->radConn);
1978 +        return gssEapRadiusMapError(minor, err);
1979 +    }
1980 +
1981 +    if (actx->radServer != NULL) {
1982 +        if (rs_conn_select_peer(actx->radConn, actx->radServer) != 0) {
1983 +            err = rs_err_conn_pop(actx->radConn);
1984 +            return gssEapRadiusMapError(minor, err);
1985 +        }
1986 +    }
1987 +
1988 +    *minor = 0;
1989 +    return GSS_S_COMPLETE;
1990 +}
1991 +
1992 +/*
1993 + * Process a EAP response from the initiator.
1994 + */
1995 +static OM_uint32
1996 +eapGssSmAcceptAuthenticate(OM_uint32 *minor,
1997 +                           gss_cred_id_t cred,
1998 +                           gss_ctx_id_t ctx,
1999 +                           gss_name_t target GSSEAP_UNUSED,
2000 +                           gss_OID mech GSSEAP_UNUSED,
2001 +                           OM_uint32 reqFlags GSSEAP_UNUSED,
2002 +                           OM_uint32 timeReq GSSEAP_UNUSED,
2003 +                           gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
2004 +                           gss_buffer_t inputToken,
2005 +                           gss_buffer_t outputToken,
2006 +                           OM_uint32 *smFlags)
2007 +{
2008 +    OM_uint32 major, tmpMinor;
2009 +    struct rs_connection *rconn;
2010 +    struct rs_request *request = NULL;
2011 +    struct rs_packet *req = NULL, *resp = NULL;
2012 +    struct radius_packet *frreq, *frresp;
2013 +
2014 +    if (ctx->acceptorCtx.radContext == NULL) {
2015 +        /* May be NULL from an imported partial context */
2016 +        major = createRadiusHandle(minor, cred, ctx);
2017 +        if (GSS_ERROR(major))
2018 +            goto cleanup;
2019 +    }
2020 +
2021 +    if (isIdentityResponseP(inputToken)) {
2022 +        major = importInitiatorIdentity(minor, ctx, inputToken);
2023 +        if (GSS_ERROR(major))
2024 +            return major;
2025 +    }
2026 +
2027 +    rconn = ctx->acceptorCtx.radConn;
2028 +
2029 +    if (rs_packet_create_authn_request(rconn, &req, NULL, NULL) != 0) {
2030 +        major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn));
2031 +        goto cleanup;
2032 +    }
2033 +    frreq = rs_packet_frpkt(req);
2034 +
2035 +    major = setInitiatorIdentity(minor, ctx, &frreq->vps);
2036 +    if (GSS_ERROR(major))
2037 +        goto cleanup;
2038 +
2039 +    major = setAcceptorIdentity(minor, ctx, &frreq->vps);
2040 +    if (GSS_ERROR(major))
2041 +        goto cleanup;
2042 +
2043 +    major = gssEapRadiusAddAvp(minor, &frreq->vps,
2044 +                               PW_EAP_MESSAGE, 0, inputToken);
2045 +    if (GSS_ERROR(major))
2046 +        goto cleanup;
2047 +
2048 +    if (ctx->acceptorCtx.state.length != 0) {
2049 +        major = gssEapRadiusAddAvp(minor, &frreq->vps, PW_STATE, 0,
2050 +                                   &ctx->acceptorCtx.state);
2051 +        if (GSS_ERROR(major))
2052 +            goto cleanup;
2053 +
2054 +        gss_release_buffer(&tmpMinor, &ctx->acceptorCtx.state);
2055 +    }
2056 +
2057 +    if (rs_request_create(rconn, &request) != 0) {
2058 +        major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn));
2059 +        goto cleanup;
2060 +    }
2061 +
2062 +    rs_request_add_reqpkt(request, req);
2063 +    req = NULL;
2064 +
2065 +    if (rs_request_send(request, &resp) != 0) {
2066 +        major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn));
2067 +        goto cleanup;
2068 +    }
2069 +
2070 +    GSSEAP_ASSERT(resp != NULL);
2071 +
2072 +    frresp = rs_packet_frpkt(resp);
2073 +    switch (frresp->code) {
2074 +    case PW_ACCESS_CHALLENGE:
2075 +    case PW_AUTHENTICATION_ACK:
2076 +        break;
2077 +    case PW_AUTHENTICATION_REJECT:
2078 +        *minor = GSSEAP_RADIUS_AUTH_FAILURE;
2079 +        major = GSS_S_DEFECTIVE_CREDENTIAL;
2080 +        goto cleanup;
2081 +        break;
2082 +    default:
2083 +        *minor = GSSEAP_UNKNOWN_RADIUS_CODE;
2084 +        major = GSS_S_FAILURE;
2085 +        goto cleanup;
2086 +        break;
2087 +    }
2088 +
2089 +    major = gssEapRadiusGetAvp(minor, frresp->vps, PW_EAP_MESSAGE, 0,
2090 +                               outputToken, TRUE);
2091 +    if (major == GSS_S_UNAVAILABLE && frresp->code == PW_ACCESS_CHALLENGE) {
2092 +        *minor = GSSEAP_MISSING_EAP_REQUEST;
2093 +        major = GSS_S_DEFECTIVE_TOKEN;
2094 +        goto cleanup;
2095 +    } else if (GSS_ERROR(major))
2096 +        goto cleanup;
2097 +
2098 +    if (frresp->code == PW_ACCESS_CHALLENGE) {
2099 +        major = gssEapRadiusGetAvp(minor, frresp->vps, PW_STATE, 0,
2100 +                                   &ctx->acceptorCtx.state, TRUE);
2101 +        if (GSS_ERROR(major) && *minor != GSSEAP_NO_SUCH_ATTR)
2102 +            goto cleanup;
2103 +    } else {
2104 +        ctx->acceptorCtx.vps = frresp->vps;
2105 +        frresp->vps = NULL;
2106 +
2107 +        major = acceptReadyEap(minor, ctx, cred);
2108 +        if (GSS_ERROR(major))
2109 +            goto cleanup;
2110 +
2111 +        GSSEAP_SM_TRANSITION_NEXT(ctx);
2112 +    }
2113 +
2114 +    major = GSS_S_CONTINUE_NEEDED;
2115 +    *minor = 0;
2116 +    *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
2117 +
2118 +cleanup:
2119 +    if (request != NULL)
2120 +        rs_request_destroy(request);
2121 +    if (req != NULL)
2122 +        rs_packet_destroy(req);
2123 +    if (resp != NULL)
2124 +        rs_packet_destroy(resp);
2125 +    if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_INITIATOR_EXTS) {
2126 +        GSSEAP_ASSERT(major == GSS_S_CONTINUE_NEEDED);
2127 +
2128 +        rs_conn_destroy(ctx->acceptorCtx.radConn);
2129 +        ctx->acceptorCtx.radConn = NULL;
2130 +    }
2131 +
2132 +    return major;
2133 +}
2134 +
2135 +static OM_uint32
2136 +eapGssSmAcceptGssFlags(OM_uint32 *minor,
2137 +                       gss_cred_id_t cred GSSEAP_UNUSED,
2138 +                       gss_ctx_id_t ctx,
2139 +                       gss_name_t target GSSEAP_UNUSED,
2140 +                       gss_OID mech GSSEAP_UNUSED,
2141 +                       OM_uint32 reqFlags GSSEAP_UNUSED,
2142 +                       OM_uint32 timeReq GSSEAP_UNUSED,
2143 +                       gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
2144 +                       gss_buffer_t inputToken,
2145 +                       gss_buffer_t outputToken GSSEAP_UNUSED,
2146 +                       OM_uint32 *smFlags GSSEAP_UNUSED)
2147 +{
2148 +    unsigned char *p;
2149 +    OM_uint32 initiatorGssFlags;
2150 +
2151 +    GSSEAP_ASSERT((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0);
2152 +
2153 +    if (inputToken->length < 4) {
2154 +        *minor = GSSEAP_TOK_TRUNC;
2155 +        return GSS_S_DEFECTIVE_TOKEN;
2156 +    }
2157 +
2158 +    /* allow flags to grow for future expansion */
2159 +    p = (unsigned char *)inputToken->value + inputToken->length - 4;
2160 +
2161 +    initiatorGssFlags = load_uint32_be(p);
2162 +    initiatorGssFlags &= GSSEAP_WIRE_FLAGS_MASK;
2163 +
2164 +    ctx->gssFlags |= initiatorGssFlags;
2165 +
2166 +    return GSS_S_CONTINUE_NEEDED;
2167 +}
2168 +
2169 +static OM_uint32
2170 +eapGssSmAcceptGssChannelBindings(OM_uint32 *minor,
2171 +                                 gss_cred_id_t cred GSSEAP_UNUSED,
2172 +                                 gss_ctx_id_t ctx,
2173 +                                 gss_name_t target GSSEAP_UNUSED,
2174 +                                 gss_OID mech GSSEAP_UNUSED,
2175 +                                 OM_uint32 reqFlags GSSEAP_UNUSED,
2176 +                                 OM_uint32 timeReq GSSEAP_UNUSED,
2177 +                                 gss_channel_bindings_t chanBindings,
2178 +                                 gss_buffer_t inputToken,
2179 +                                 gss_buffer_t outputToken GSSEAP_UNUSED,
2180 +                                 OM_uint32 *smFlags GSSEAP_UNUSED)
2181 +{
2182 +    OM_uint32 major;
2183 +    gss_iov_buffer_desc iov[2];
2184 +
2185 +    iov[0].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
2186 +    iov[0].buffer.length = 0;
2187 +    iov[0].buffer.value = NULL;
2188 +
2189 +    iov[1].type = GSS_IOV_BUFFER_TYPE_STREAM | GSS_IOV_BUFFER_FLAG_ALLOCATED;
2190 +
2191 +    /* XXX necessary because decrypted in place and we verify it later */
2192 +    major = duplicateBuffer(minor, inputToken, &iov[1].buffer);
2193 +    if (GSS_ERROR(major))
2194 +        return major;
2195 +
2196 +    major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
2197 +                                    iov, 2, TOK_TYPE_WRAP);
2198 +    if (GSS_ERROR(major)) {
2199 +        gssEapReleaseIov(iov, 2);
2200 +        return major;
2201 +    }
2202 +
2203 +    if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS &&
2204 +        !bufferEqual(&iov[0].buffer, &chanBindings->application_data)) {
2205 +        major = GSS_S_BAD_BINDINGS;
2206 +        *minor = GSSEAP_BINDINGS_MISMATCH;
2207 +    } else {
2208 +        major = GSS_S_CONTINUE_NEEDED;
2209 +        *minor = 0;
2210 +    }
2211 +
2212 +    gssEapReleaseIov(iov, 2);
2213 +
2214 +    return major;
2215 +}
2216 +
2217 +static OM_uint32
2218 +eapGssSmAcceptInitiatorMIC(OM_uint32 *minor,
2219 +                           gss_cred_id_t cred GSSEAP_UNUSED,
2220 +                           gss_ctx_id_t ctx,
2221 +                           gss_name_t target GSSEAP_UNUSED,
2222 +                           gss_OID mech GSSEAP_UNUSED,
2223 +                           OM_uint32 reqFlags GSSEAP_UNUSED,
2224 +                           OM_uint32 timeReq GSSEAP_UNUSED,
2225 +                           gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
2226 +                           gss_buffer_t inputToken,
2227 +                           gss_buffer_t outputToken GSSEAP_UNUSED,
2228 +                           OM_uint32 *smFlags GSSEAP_UNUSED)
2229 +{
2230 +    OM_uint32 major;
2231 +
2232 +    major = gssEapVerifyTokenMIC(minor, ctx, inputToken);
2233 +    if (GSS_ERROR(major))
2234 +        return major;
2235 +
2236 +    GSSEAP_SM_TRANSITION_NEXT(ctx);
2237 +
2238 +    *minor = 0;
2239 +    return GSS_S_CONTINUE_NEEDED;
2240 +}
2241 +
2242 +#ifdef GSSEAP_ENABLE_REAUTH
2243 +static OM_uint32
2244 +eapGssSmAcceptReauthCreds(OM_uint32 *minor,
2245 +                          gss_cred_id_t cred,
2246 +                          gss_ctx_id_t ctx,
2247 +                          gss_name_t target GSSEAP_UNUSED,
2248 +                          gss_OID mech GSSEAP_UNUSED,
2249 +                          OM_uint32 reqFlags GSSEAP_UNUSED,
2250 +                          OM_uint32 timeReq GSSEAP_UNUSED,
2251 +                          gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
2252 +                          gss_buffer_t inputToken GSSEAP_UNUSED,
2253 +                          gss_buffer_t outputToken,
2254 +                          OM_uint32 *smFlags GSSEAP_UNUSED)
2255 +{
2256 +    OM_uint32 major;
2257 +
2258 +    /*
2259 +     * If we're built with fast reauthentication enabled, then
2260 +     * fabricate a ticket from the initiator to ourselves.
2261 +     */
2262 +    major = gssEapMakeReauthCreds(minor, ctx, cred, outputToken);
2263 +    if (major == GSS_S_UNAVAILABLE)
2264 +        major = GSS_S_COMPLETE;
2265 +    if (major == GSS_S_COMPLETE)
2266 +        major = GSS_S_CONTINUE_NEEDED;
2267 +
2268 +    return major;
2269 +}
2270 +#endif
2271 +
2272 +static OM_uint32
2273 +eapGssSmAcceptAcceptorMIC(OM_uint32 *minor,
2274 +                          gss_cred_id_t cred GSSEAP_UNUSED,
2275 +                          gss_ctx_id_t ctx,
2276 +                          gss_name_t target GSSEAP_UNUSED,
2277 +                          gss_OID mech GSSEAP_UNUSED,
2278 +                          OM_uint32 reqFlags GSSEAP_UNUSED,
2279 +                          OM_uint32 timeReq GSSEAP_UNUSED,
2280 +                          gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
2281 +                          gss_buffer_t inputToken GSSEAP_UNUSED,
2282 +                          gss_buffer_t outputToken,
2283 +                          OM_uint32 *smFlags)
2284 +{
2285 +    OM_uint32 major;
2286 +
2287 +    major = gssEapMakeTokenMIC(minor, ctx, outputToken);
2288 +    if (GSS_ERROR(major))
2289 +        return major;
2290 +
2291 +    GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
2292 +
2293 +    *minor = 0;
2294 +    *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
2295 +
2296 +    return GSS_S_COMPLETE;
2297 +}
2298 +
2299 +static struct gss_eap_sm eapGssAcceptorSm[] = {
2300 +    {
2301 +        ITOK_TYPE_ACCEPTOR_NAME_REQ,
2302 +        ITOK_TYPE_ACCEPTOR_NAME_RESP,
2303 +        GSSEAP_STATE_INITIAL,
2304 +        0,
2305 +        eapGssSmAcceptAcceptorName
2306 +    },
2307 +#ifdef GSSEAP_DEBUG
2308 +    {
2309 +        ITOK_TYPE_VENDOR_INFO,
2310 +        ITOK_TYPE_NONE,
2311 +        GSSEAP_STATE_INITIAL,
2312 +        0,
2313 +        eapGssSmAcceptVendorInfo,
2314 +    },
2315 +#endif
2316 +#ifdef GSSEAP_ENABLE_REAUTH
2317 +    {
2318 +        ITOK_TYPE_REAUTH_REQ,
2319 +        ITOK_TYPE_REAUTH_RESP,
2320 +        GSSEAP_STATE_INITIAL,
2321 +        0,
2322 +        eapGssSmAcceptGssReauth,
2323 +    },
2324 +#endif
2325 +    {
2326 +        ITOK_TYPE_NONE,
2327 +        ITOK_TYPE_EAP_REQ,
2328 +        GSSEAP_STATE_INITIAL,
2329 +        SM_ITOK_FLAG_REQUIRED,
2330 +        eapGssSmAcceptIdentity,
2331 +    },
2332 +    {
2333 +        ITOK_TYPE_EAP_RESP,
2334 +        ITOK_TYPE_EAP_REQ,
2335 +        GSSEAP_STATE_AUTHENTICATE,
2336 +        SM_ITOK_FLAG_REQUIRED,
2337 +        eapGssSmAcceptAuthenticate
2338 +    },
2339 +    {
2340 +        ITOK_TYPE_GSS_FLAGS,
2341 +        ITOK_TYPE_NONE,
2342 +        GSSEAP_STATE_INITIATOR_EXTS,
2343 +        0,
2344 +        eapGssSmAcceptGssFlags
2345 +    },
2346 +    {
2347 +        ITOK_TYPE_GSS_CHANNEL_BINDINGS,
2348 +        ITOK_TYPE_NONE,
2349 +        GSSEAP_STATE_INITIATOR_EXTS,
2350 +        SM_ITOK_FLAG_REQUIRED,
2351 +        eapGssSmAcceptGssChannelBindings,
2352 +    },
2353 +    {
2354 +        ITOK_TYPE_INITIATOR_MIC,
2355 +        ITOK_TYPE_NONE,
2356 +        GSSEAP_STATE_INITIATOR_EXTS,
2357 +        SM_ITOK_FLAG_REQUIRED,
2358 +        eapGssSmAcceptInitiatorMIC,
2359 +    },
2360 +#ifdef GSSEAP_ENABLE_REAUTH
2361 +    {
2362 +        ITOK_TYPE_NONE,
2363 +        ITOK_TYPE_REAUTH_CREDS,
2364 +        GSSEAP_STATE_ACCEPTOR_EXTS,
2365 +        0,
2366 +        eapGssSmAcceptReauthCreds,
2367 +    },
2368 +#endif
2369 +    {
2370 +        ITOK_TYPE_NONE,
2371 +        ITOK_TYPE_ACCEPTOR_MIC,
2372 +        GSSEAP_STATE_ACCEPTOR_EXTS,
2373 +        0,
2374 +        eapGssSmAcceptAcceptorMIC
2375 +    },
2376 +};
2377 +
2378 +OM_uint32
2379 +gssEapAcceptSecContext(OM_uint32 *minor,
2380 +                       gss_ctx_id_t ctx,
2381 +                       gss_cred_id_t cred,
2382 +                       gss_buffer_t input_token,
2383 +                       gss_channel_bindings_t input_chan_bindings,
2384 +                       gss_name_t *src_name,
2385 +                       gss_OID *mech_type,
2386 +                       gss_buffer_t output_token,
2387 +                       OM_uint32 *ret_flags,
2388 +                       OM_uint32 *time_rec,
2389 +                       gss_cred_id_t *delegated_cred_handle)
2390 +{
2391 +    OM_uint32 major, tmpMinor;
2392 +
2393 +    if (cred == GSS_C_NO_CREDENTIAL) {
2394 +        if (ctx->cred == GSS_C_NO_CREDENTIAL) {
2395 +            major = gssEapAcquireCred(minor,
2396 +                                      GSS_C_NO_NAME,
2397 +                                      GSS_C_INDEFINITE,
2398 +                                      GSS_C_NO_OID_SET,
2399 +                                      GSS_C_ACCEPT,
2400 +                                      &ctx->cred,
2401 +                                      NULL,
2402 +                                      NULL);
2403 +            if (GSS_ERROR(major))
2404 +                goto cleanup;
2405 +        }
2406 +
2407 +        cred = ctx->cred;
2408 +    }
2409 +
2410 +    /*
2411 +     * Previously we acquired the credential mutex here, but it should not be
2412 +     * necessary as the acceptor does not access any mutable elements of the
2413 +     * credential handle.
2414 +     */
2415 +
2416 +    /*
2417 +     * Calling gssEapInquireCred() forces the default acceptor credential name
2418 +     * to be resolved.
2419 +     */
2420 +    major = gssEapInquireCred(minor, cred, &ctx->acceptorName, NULL, NULL, NULL);
2421 +    if (GSS_ERROR(major))
2422 +        goto cleanup;
2423 +
2424 +    major = gssEapSmStep(minor,
2425 +                         cred,
2426 +                         ctx,
2427 +                         GSS_C_NO_NAME,
2428 +                         GSS_C_NO_OID,
2429 +                         0,
2430 +                         GSS_C_INDEFINITE,
2431 +                         input_chan_bindings,
2432 +                         input_token,
2433 +                         output_token,
2434 +                         eapGssAcceptorSm,
2435 +                         sizeof(eapGssAcceptorSm) / sizeof(eapGssAcceptorSm[0]));
2436 +    if (GSS_ERROR(major))
2437 +        goto cleanup;
2438 +
2439 +    if (mech_type != NULL) {
2440 +        OM_uint32 tmpMajor;
2441 +
2442 +        tmpMajor = gssEapCanonicalizeOid(&tmpMinor, ctx->mechanismUsed, 0, mech_type);
2443 +        if (GSS_ERROR(tmpMajor)) {
2444 +            major = tmpMajor;
2445 +            *minor = tmpMinor;
2446 +            goto cleanup;
2447 +        }
2448 +    }
2449 +    if (ret_flags != NULL)
2450 +        *ret_flags = ctx->gssFlags;
2451 +    if (delegated_cred_handle != NULL)
2452 +        *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
2453 +
2454 +    if (major == GSS_S_COMPLETE) {
2455 +        if (src_name != NULL && ctx->initiatorName != GSS_C_NO_NAME) {
2456 +            major = gssEapDuplicateName(&tmpMinor, ctx->initiatorName, src_name);
2457 +            if (GSS_ERROR(major))
2458 +                goto cleanup;
2459 +        }
2460 +        if (time_rec != NULL) {
2461 +            major = gssEapContextTime(&tmpMinor, ctx, time_rec);
2462 +            if (GSS_ERROR(major))
2463 +                goto cleanup;
2464 +        }
2465 +    }
2466 +
2467 +    GSSEAP_ASSERT(CTX_IS_ESTABLISHED(ctx) || major == GSS_S_CONTINUE_NEEDED);
2468 +
2469 +cleanup:
2470 +    return major;
2471 +}
2472 +
2473 +#ifdef GSSEAP_ENABLE_REAUTH
2474 +static OM_uint32
2475 +acceptReadyKrb(OM_uint32 *minor,
2476 +               gss_ctx_id_t ctx,
2477 +               gss_cred_id_t cred,
2478 +               const gss_name_t initiator,
2479 +               const gss_OID mech,
2480 +               OM_uint32 timeRec)
2481 +{
2482 +    OM_uint32 major;
2483 +
2484 +    major = gssEapGlueToMechName(minor, ctx, initiator, &ctx->initiatorName);
2485 +    if (GSS_ERROR(major))
2486 +        return major;
2487 +
2488 +    major = gssEapReauthComplete(minor, ctx, cred, mech, timeRec);
2489 +    if (GSS_ERROR(major))
2490 +        return major;
2491 +
2492 +    *minor = 0;
2493 +    return GSS_S_COMPLETE;
2494 +}
2495 +
2496 +static OM_uint32
2497 +eapGssSmAcceptGssReauth(OM_uint32 *minor,
2498 +                        gss_cred_id_t cred,
2499 +                        gss_ctx_id_t ctx,
2500 +                        gss_name_t target GSSEAP_UNUSED,
2501 +                        gss_OID mech,
2502 +                        OM_uint32 reqFlags GSSEAP_UNUSED,
2503 +                        OM_uint32 timeReq GSSEAP_UNUSED,
2504 +                        gss_channel_bindings_t chanBindings,
2505 +                        gss_buffer_t inputToken,
2506 +                        gss_buffer_t outputToken,
2507 +                        OM_uint32 *smFlags)
2508 +{
2509 +    OM_uint32 major, tmpMinor;
2510 +    gss_name_t krbInitiator = GSS_C_NO_NAME;
2511 +    OM_uint32 gssFlags, timeRec = GSS_C_INDEFINITE;
2512 +
2513 +    /*
2514 +     * If we're built with fast reauthentication support, it's valid
2515 +     * for an initiator to send a GSS reauthentication token as its
2516 +     * initial context token, causing us to short-circuit the state
2517 +     * machine and process Kerberos GSS messages instead.
2518 +     */
2519 +
2520 +    ctx->flags |= CTX_FLAG_KRB_REAUTH;
2521 +
2522 +    major = gssAcceptSecContext(minor,
2523 +                                &ctx->reauthCtx,
2524 +                                cred->reauthCred,
2525 +                                inputToken,
2526 +                                chanBindings,
2527 +                                &krbInitiator,
2528 +                                &mech,
2529 +                                outputToken,
2530 +                                &gssFlags,
2531 +                                &timeRec,
2532 +                                NULL);
2533 +    if (major == GSS_S_COMPLETE) {
2534 +        major = acceptReadyKrb(minor, ctx, cred,
2535 +                               krbInitiator, mech, timeRec);
2536 +        if (major == GSS_S_COMPLETE) {
2537 +            GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
2538 +        }
2539 +        ctx->gssFlags = gssFlags;
2540 +    } else if (GSS_ERROR(major) &&
2541 +        (*smFlags & SM_FLAG_INPUT_TOKEN_CRITICAL) == 0) {
2542 +        /* pretend reauthentication attempt never happened */
2543 +        gssDeleteSecContext(&tmpMinor, &ctx->reauthCtx, GSS_C_NO_BUFFER);
2544 +        ctx->flags &= ~(CTX_FLAG_KRB_REAUTH);
2545 +        GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_INITIAL);
2546 +        major = GSS_S_CONTINUE_NEEDED;
2547 +    }
2548 +
2549 +    gssReleaseName(&tmpMinor, &krbInitiator);
2550 +
2551 +    return major;
2552 +}
2553 +#endif /* GSSEAP_ENABLE_REAUTH */
2554 +
2555 +OM_uint32 GSSAPI_CALLCONV
2556 +gss_accept_sec_context(OM_uint32 *minor,
2557 +                       gss_ctx_id_t *context_handle,
2558 +                       gss_cred_id_t cred,
2559 +                       gss_buffer_t input_token,
2560 +                       gss_channel_bindings_t input_chan_bindings,
2561 +                       gss_name_t *src_name,
2562 +                       gss_OID *mech_type,
2563 +                       gss_buffer_t output_token,
2564 +                       OM_uint32 *ret_flags,
2565 +                       OM_uint32 *time_rec,
2566 +                       gss_cred_id_t *delegated_cred_handle)
2567 +{
2568 +    OM_uint32 major, tmpMinor;
2569 +    gss_ctx_id_t ctx = *context_handle;
2570 +
2571 +    *minor = 0;
2572 +
2573 +    output_token->length = 0;
2574 +    output_token->value = NULL;
2575 +
2576 +    if (src_name != NULL)
2577 +        *src_name = GSS_C_NO_NAME;
2578 +
2579 +    if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) {
2580 +        *minor = GSSEAP_TOK_TRUNC;
2581 +        return GSS_S_DEFECTIVE_TOKEN;
2582 +    }
2583 +
2584 +    if (ctx == GSS_C_NO_CONTEXT) {
2585 +        major = gssEapAllocContext(minor, &ctx);
2586 +        if (GSS_ERROR(major))
2587 +            return major;
2588 +
2589 +        *context_handle = ctx;
2590 +    }
2591 +
2592 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
2593 +
2594 +    major = gssEapAcceptSecContext(minor,
2595 +                                   ctx,
2596 +                                   cred,
2597 +                                   input_token,
2598 +                                   input_chan_bindings,
2599 +                                   src_name,
2600 +                                   mech_type,
2601 +                                   output_token,
2602 +                                   ret_flags,
2603 +                                   time_rec,
2604 +                                   delegated_cred_handle);
2605 +
2606 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
2607 +
2608 +    if (GSS_ERROR(major))
2609 +        gssEapReleaseContext(&tmpMinor, context_handle);
2610 +
2611 +    return major;
2612 +}
2613 diff --git a/mech_eap/acquire_cred.c b/mech_eap/acquire_cred.c
2614 new file mode 100644
2615 index 0000000..ae2648e
2616 --- /dev/null
2617 +++ b/mech_eap/acquire_cred.c
2618 @@ -0,0 +1,52 @@
2619 +/*
2620 + * Copyright (c) 2011, JANET(UK)
2621 + * All rights reserved.
2622 + *
2623 + * Redistribution and use in source and binary forms, with or without
2624 + * modification, are permitted provided that the following conditions
2625 + * are met:
2626 + *
2627 + * 1. Redistributions of source code must retain the above copyright
2628 + *    notice, this list of conditions and the following disclaimer.
2629 + *
2630 + * 2. Redistributions in binary form must reproduce the above copyright
2631 + *    notice, this list of conditions and the following disclaimer in the
2632 + *    documentation and/or other materials provided with the distribution.
2633 + *
2634 + * 3. Neither the name of JANET(UK) nor the names of its contributors
2635 + *    may be used to endorse or promote products derived from this software
2636 + *    without specific prior written permission.
2637 + *
2638 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2639 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2640 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2641 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
2642 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2643 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2644 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2645 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2646 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2647 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2648 + * SUCH DAMAGE.
2649 + */
2650 +
2651 +/*
2652 + * Wrapper for acquiring a credential handle.
2653 + */
2654 +
2655 +#include "gssapiP_eap.h"
2656 +
2657 +OM_uint32 GSSAPI_CALLCONV
2658 +gss_acquire_cred(OM_uint32 *minor,
2659 +                 gss_name_t desired_name,
2660 +                 OM_uint32 time_req,
2661 +                 gss_OID_set desired_mechs,
2662 +                 gss_cred_usage_t cred_usage,
2663 +                 gss_cred_id_t *output_cred_handle,
2664 +                 gss_OID_set *actual_mechs,
2665 +                 OM_uint32 *time_rec)
2666 +{
2667 +    return gssEapAcquireCred(minor, desired_name,
2668 +                             time_req, desired_mechs, cred_usage,
2669 +                             output_cred_handle, actual_mechs, time_rec);
2670 +}
2671 diff --git a/mech_eap/acquire_cred_with_password.c b/mech_eap/acquire_cred_with_password.c
2672 new file mode 100644
2673 index 0000000..8e08358
2674 --- /dev/null
2675 +++ b/mech_eap/acquire_cred_with_password.c
2676 @@ -0,0 +1,67 @@
2677 +/*
2678 + * Copyright (c) 2011, JANET(UK)
2679 + * All rights reserved.
2680 + *
2681 + * Redistribution and use in source and binary forms, with or without
2682 + * modification, are permitted provided that the following conditions
2683 + * are met:
2684 + *
2685 + * 1. Redistributions of source code must retain the above copyright
2686 + *    notice, this list of conditions and the following disclaimer.
2687 + *
2688 + * 2. Redistributions in binary form must reproduce the above copyright
2689 + *    notice, this list of conditions and the following disclaimer in the
2690 + *    documentation and/or other materials provided with the distribution.
2691 + *
2692 + * 3. Neither the name of JANET(UK) nor the names of its contributors
2693 + *    may be used to endorse or promote products derived from this software
2694 + *    without specific prior written permission.
2695 + *
2696 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2697 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2698 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2699 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
2700 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2701 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2702 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2703 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2704 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2705 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2706 + * SUCH DAMAGE.
2707 + */
2708 +
2709 +/*
2710 + * Wrapper for acquiring a credential handle using a password.
2711 + */
2712 +
2713 +#include "gssapiP_eap.h"
2714 +
2715 +OM_uint32 GSSAPI_CALLCONV
2716 +gssspi_acquire_cred_with_password(OM_uint32 *minor,
2717 +                                  const gss_name_t desired_name,
2718 +                                  const gss_buffer_t password,
2719 +                                  OM_uint32 time_req,
2720 +                                  const gss_OID_set desired_mechs,
2721 +                                  gss_cred_usage_t cred_usage,
2722 +                                  gss_cred_id_t *output_cred_handle,
2723 +                                  gss_OID_set *actual_mechs,
2724 +                                  OM_uint32 *time_rec)
2725 +{
2726 +    OM_uint32 major, tmpMinor;
2727 +
2728 +    major = gssEapAcquireCred(minor, desired_name,
2729 +                              time_req, desired_mechs, cred_usage,
2730 +                              output_cred_handle, actual_mechs, time_rec);
2731 +    if (GSS_ERROR(major))
2732 +        goto cleanup;
2733 +
2734 +    major = gssEapSetCredPassword(minor, *output_cred_handle, password);
2735 +    if (GSS_ERROR(major))
2736 +        goto cleanup;
2737 +
2738 +cleanup:
2739 +    if (GSS_ERROR(major))
2740 +        gssEapReleaseCred(&tmpMinor, output_cred_handle);
2741 +
2742 +    return major;
2743 +}
2744 diff --git a/mech_eap/add_cred.c b/mech_eap/add_cred.c
2745 new file mode 100644
2746 index 0000000..64d97c0
2747 --- /dev/null
2748 +++ b/mech_eap/add_cred.c
2749 @@ -0,0 +1,87 @@
2750 +/*
2751 + * Copyright (c) 2011, JANET(UK)
2752 + * All rights reserved.
2753 + *
2754 + * Redistribution and use in source and binary forms, with or without
2755 + * modification, are permitted provided that the following conditions
2756 + * are met:
2757 + *
2758 + * 1. Redistributions of source code must retain the above copyright
2759 + *    notice, this list of conditions and the following disclaimer.
2760 + *
2761 + * 2. Redistributions in binary form must reproduce the above copyright
2762 + *    notice, this list of conditions and the following disclaimer in the
2763 + *    documentation and/or other materials provided with the distribution.
2764 + *
2765 + * 3. Neither the name of JANET(UK) nor the names of its contributors
2766 + *    may be used to endorse or promote products derived from this software
2767 + *    without specific prior written permission.
2768 + *
2769 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2770 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2771 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2772 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
2773 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2774 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2775 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2776 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2777 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2778 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2779 + * SUCH DAMAGE.
2780 + */
2781 +
2782 +/*
2783 + * Wrapper for acquiring a credential handle.
2784 + */
2785 +
2786 +#include "gssapiP_eap.h"
2787 +
2788 +/*
2789 + * Note that this shouldn't really be required to be implemented by anything
2790 + * apart from the mechanism glue layer. However, Heimdal does call into the
2791 + * mechanism here.
2792 + */
2793 +OM_uint32 GSSAPI_CALLCONV
2794 +gss_add_cred(OM_uint32 *minor,
2795 +             gss_cred_id_t input_cred_handle GSSEAP_UNUSED,
2796 +             gss_name_t desired_name,
2797 +             gss_OID desired_mech,
2798 +             gss_cred_usage_t cred_usage,
2799 +             OM_uint32 initiator_time_req,
2800 +             OM_uint32 acceptor_time_req,
2801 +             gss_cred_id_t *output_cred_handle,
2802 +             gss_OID_set *actual_mechs,
2803 +             OM_uint32 *initiator_time_rec,
2804 +             OM_uint32 *acceptor_time_rec)
2805 +{
2806 +    OM_uint32 major;
2807 +    OM_uint32 time_req, time_rec = 0;
2808 +    gss_OID_set_desc mechs;
2809 +
2810 +    *minor = 0;
2811 +    *output_cred_handle = GSS_C_NO_CREDENTIAL;
2812 +
2813 +    if (cred_usage == GSS_C_ACCEPT)
2814 +        time_req = acceptor_time_req;
2815 +    else
2816 +        time_req = initiator_time_req;
2817 +
2818 +    mechs.count = 1;
2819 +    mechs.elements = desired_mech;
2820 +
2821 +    major = gssEapAcquireCred(minor,
2822 +                              desired_name,
2823 +                              time_req,
2824 +                              &mechs,
2825 +                              cred_usage,
2826 +                              output_cred_handle,
2827 +                              actual_mechs,
2828 +                              &time_rec);
2829 +
2830 +    if (initiator_time_rec != NULL)
2831 +        *initiator_time_rec = time_rec;
2832 +    if (acceptor_time_rec != NULL)
2833 +        *acceptor_time_rec = time_rec;
2834 +
2835 +    return major;
2836 +}
2837 diff --git a/mech_eap/add_cred_with_password.c b/mech_eap/add_cred_with_password.c
2838 new file mode 100644
2839 index 0000000..b982f0d
2840 --- /dev/null
2841 +++ b/mech_eap/add_cred_with_password.c
2842 @@ -0,0 +1,93 @@
2843 +/*
2844 + * Copyright (c) 2011, JANET(UK)
2845 + * All rights reserved.
2846 + *
2847 + * Redistribution and use in source and binary forms, with or without
2848 + * modification, are permitted provided that the following conditions
2849 + * are met:
2850 + *
2851 + * 1. Redistributions of source code must retain the above copyright
2852 + *    notice, this list of conditions and the following disclaimer.
2853 + *
2854 + * 2. Redistributions in binary form must reproduce the above copyright
2855 + *    notice, this list of conditions and the following disclaimer in the
2856 + *    documentation and/or other materials provided with the distribution.
2857 + *
2858 + * 3. Neither the name of JANET(UK) nor the names of its contributors
2859 + *    may be used to endorse or promote products derived from this software
2860 + *    without specific prior written permission.
2861 + *
2862 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2863 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2864 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2865 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
2866 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2867 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2868 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2869 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2870 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2871 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2872 + * SUCH DAMAGE.
2873 + */
2874 +
2875 +/*
2876 + * Wrapper for acquiring a credential handle using a password.
2877 + */
2878 +
2879 +#include "gssapiP_eap.h"
2880 +
2881 +OM_uint32 GSSAPI_CALLCONV
2882 +gss_add_cred_with_password(OM_uint32 *minor,
2883 +                           const gss_cred_id_t input_cred_handle GSSEAP_UNUSED,
2884 +                           const gss_name_t desired_name,
2885 +                           const gss_OID desired_mech,
2886 +                           const gss_buffer_t password,
2887 +                           gss_cred_usage_t cred_usage,
2888 +                           OM_uint32 initiator_time_req,
2889 +                           OM_uint32 acceptor_time_req,
2890 +                           gss_cred_id_t *output_cred_handle,
2891 +                           gss_OID_set *actual_mechs,
2892 +                           OM_uint32 *initiator_time_rec,
2893 +                           OM_uint32 *acceptor_time_rec)
2894 +{
2895 +    OM_uint32 major, tmpMinor;
2896 +    OM_uint32 time_req, time_rec = 0;
2897 +    gss_OID_set_desc mechs;
2898 +
2899 +    *minor = 0;
2900 +    *output_cred_handle = GSS_C_NO_CREDENTIAL;
2901 +
2902 +    if (cred_usage == GSS_C_ACCEPT)
2903 +        time_req = acceptor_time_req;
2904 +    else
2905 +        time_req = initiator_time_req;
2906 +
2907 +    mechs.count = 1;
2908 +    mechs.elements = desired_mech;
2909 +
2910 +    major = gssEapAcquireCred(minor,
2911 +                              desired_name,
2912 +                              time_req,
2913 +                              &mechs,
2914 +                              cred_usage,
2915 +                              output_cred_handle,
2916 +                              actual_mechs,
2917 +                              &time_rec);
2918 +    if (GSS_ERROR(major))
2919 +        goto cleanup;
2920 +
2921 +    major = gssEapSetCredPassword(minor, *output_cred_handle, password);
2922 +    if (GSS_ERROR(major))
2923 +        goto cleanup;
2924 +
2925 +    if (initiator_time_rec != NULL)
2926 +        *initiator_time_rec = time_rec;
2927 +    if (acceptor_time_rec != NULL)
2928 +        *acceptor_time_rec = time_rec;
2929 +
2930 +cleanup:
2931 +    if (GSS_ERROR(major))
2932 +        gssEapReleaseCred(&tmpMinor, output_cred_handle);
2933 +
2934 +    return major;
2935 +}
2936 diff --git a/mech_eap/authdata_plugin.h b/mech_eap/authdata_plugin.h
2937 new file mode 100644
2938 index 0000000..32bff2f
2939 --- /dev/null
2940 +++ b/mech_eap/authdata_plugin.h
2941 @@ -0,0 +1,331 @@
2942 +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2943 +/*
2944 + * krb5/authdata_plugin.h
2945 + *
2946 + * Copyright (C) 2007 Apple Inc.  All Rights Reserved.
2947 + *
2948 + * Export of this software from the United States of America may
2949 + *   require a specific license from the United States Government.
2950 + *   It is the responsibility of any person or organization contemplating
2951 + *   export to obtain such a license before exporting.
2952 + *
2953 + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
2954 + * distribute this software and its documentation for any purpose and
2955 + * without fee is hereby granted, provided that the above copyright
2956 + * notice appear in all copies and that both that copyright notice and
2957 + * this permission notice appear in supporting documentation, and that
2958 + * the name of M.I.T. not be used in advertising or publicity pertaining
2959 + * to distribution of the software without specific, written prior
2960 + * permission.  Furthermore if you modify this software you must label
2961 + * your software as modified software and not distribute it in such a
2962 + * fashion that it might be confused with the original M.I.T. software.
2963 + * M.I.T. makes no representations about the suitability of
2964 + * this software for any purpose.  It is provided "as is" without express
2965 + * or implied warranty.
2966 + *
2967 + * AuthorizationData plugin definitions for Kerberos 5.
2968 + */
2969 +
2970 +/*
2971 + * This is considered an INTERNAL interface at this time.
2972 + *
2973 + * Some work is needed before exporting it:
2974 + *
2975 + * + Documentation.
2976 + * + Sample code.
2977 + * + Test cases (preferably automated testing under "make check").
2978 + * + Hook into TGS exchange too; will change API.
2979 + * + Examine memory management issues, especially for Windows; may
2980 + *   change API.
2981 + *
2982 + * Other changes that would be nice to have, but not necessarily
2983 + * before making this interface public:
2984 + *
2985 + * + Library support for AD-IF-RELEVANT and similar wrappers.  (We can
2986 + *   make the plugin construct them if it wants them.)
2987 + * + KDC could combine/optimize wrapped AD elements provided by
2988 + *   multiple plugins, e.g., two IF-RELEVANT sequences could be
2989 + *   merged.  (The preauth plugin API also has this bug, we're going
2990 + *   to need a general fix.)
2991 + */
2992 +
2993 +#ifndef KRB5_AUTHDATA_PLUGIN_H_INCLUDED
2994 +#define KRB5_AUTHDATA_PLUGIN_H_INCLUDED
2995 +#include <krb5/krb5.h>
2996 +
2997 +/*
2998 + * While arguments of these types are passed-in, for the most part a
2999 + * authorization data module can treat them as opaque.  If we need
3000 + * keying data, we can ask for it directly.
3001 + */
3002 +struct _krb5_db_entry_new;
3003 +
3004 +/*
3005 + * The function table / structure which an authdata server module must export as
3006 + * "authdata_server_0".  NOTE: replace "0" with "1" for the type and
3007 + * variable names if this gets picked up by upstream.  If the interfaces work
3008 + * correctly, future versions of the table will add either more callbacks or
3009 + * more arguments to callbacks, and in both cases we'll be able to wrap the v0
3010 + * functions.
3011 + */
3012 +/* extern krb5plugin_authdata_ftable_v0 authdata_server_0; */
3013 +typedef struct krb5plugin_authdata_server_ftable_v0 {
3014 +    /* Not-usually-visible name. */
3015 +    char *name;
3016 +
3017 +    /*
3018 +     * Per-plugin initialization/cleanup.  The init function is called
3019 +     * by the KDC when the plugin is loaded, and the fini function is
3020 +     * called before the plugin is unloaded.  Both are optional.
3021 +     */
3022 +    krb5_error_code (*init_proc)(krb5_context, void **);
3023 +    void (*fini_proc)(krb5_context, void *);
3024 +    /*
3025 +     * Actual authorization data handling function.  If this field
3026 +     * holds a null pointer, this mechanism will be skipped, and the
3027 +     * init/fini functions will not be run.
3028 +     *
3029 +     * This function should only modify the field
3030 +     * enc_tkt_reply->authorization_data.  All other values should be
3031 +     * considered inputs only.  And, it should *modify* the field, not
3032 +     * overwrite it and assume that there are no other authdata
3033 +     * plugins in use.
3034 +     *
3035 +     * Memory management: authorization_data is a malloc-allocated,
3036 +     * null-terminated sequence of malloc-allocated pointers to
3037 +     * authorization data structures.  This plugin code currently
3038 +     * assumes the libraries, KDC, and plugin all use the same malloc
3039 +     * pool, which may be a problem if/when we get the KDC code
3040 +     * running on Windows.
3041 +     *
3042 +     * If this function returns a non-zero error code, a message
3043 +     * is logged, but no other action is taken.  Other authdata
3044 +     * plugins will be called, and a response will be sent to the
3045 +     * client (barring other problems).
3046 +     */
3047 +    krb5_error_code (*authdata_proc)(krb5_context,
3048 +                                     struct _krb5_db_entry_new *client,
3049 +                                     krb5_data *req_pkt,
3050 +                                     krb5_kdc_req *request,
3051 +                                     krb5_enc_tkt_part *enc_tkt_reply);
3052 +} krb5plugin_server_authdata_ftable_v0;
3053 +
3054 +typedef krb5plugin_server_authdata_ftable_v0 krb5plugin_authdata_ftable_v0;
3055 +
3056 +typedef struct krb5plugin_authdata_server_ftable_v2 {
3057 +    /* Not-usually-visible name. */
3058 +    char *name;
3059 +
3060 +    /*
3061 +     * Per-plugin initialization/cleanup.  The init function is called
3062 +     * by the KDC when the plugin is loaded, and the fini function is
3063 +     * called before the plugin is unloaded.  Both are optional.
3064 +     */
3065 +    krb5_error_code (*init_proc)(krb5_context, void **);
3066 +    void (*fini_proc)(krb5_context, void *);
3067 +    /*
3068 +     * Actual authorization data handling function.  If this field
3069 +     * holds a null pointer, this mechanism will be skipped, and the
3070 +     * init/fini functions will not be run.
3071 +     *
3072 +     * This function should only modify the field
3073 +     * enc_tkt_reply->authorization_data.  All other values should be
3074 +     * considered inputs only.  And, it should *modify* the field, not
3075 +     * overwrite it and assume that there are no other authdata
3076 +     * plugins in use.
3077 +     *
3078 +     * Memory management: authorization_data is a malloc-allocated,
3079 +     * null-terminated sequence of malloc-allocated pointers to
3080 +     * authorization data structures.  This plugin code currently
3081 +     * assumes the libraries, KDC, and plugin all use the same malloc
3082 +     * pool, which may be a problem if/when we get the KDC code
3083 +     * running on Windows.
3084 +     *
3085 +     * If this function returns a non-zero error code, a message
3086 +     * is logged, but no other action is taken.  Other authdata
3087 +     * plugins will be called, and a response will be sent to the
3088 +     * client (barring other problems).
3089 +     */
3090 +    krb5_error_code (*authdata_proc)(krb5_context,
3091 +                                     unsigned int flags,
3092 +                                     struct _krb5_db_entry_new *client,
3093 +                                     struct _krb5_db_entry_new *server,
3094 +                                     struct _krb5_db_entry_new *tgs,
3095 +                                     krb5_keyblock *client_key,
3096 +                                     krb5_keyblock *server_key,
3097 +                                     krb5_keyblock *tgs_key,
3098 +                                     krb5_data *req_pkt,
3099 +                                     krb5_kdc_req *request,
3100 +                                     krb5_const_principal for_user_princ,
3101 +                                     krb5_enc_tkt_part *enc_tkt_request,
3102 +                                     krb5_enc_tkt_part *enc_tkt_reply);
3103 +} krb5plugin_authdata_server_ftable_v2;
3104 +
3105 +typedef krb5plugin_authdata_server_ftable_v2 krb5plugin_authdata_ftable_v2;
3106 +
3107 +typedef krb5_error_code
3108 +(*authdata_client_plugin_init_proc)(krb5_context context,
3109 +                                    void **plugin_context);
3110 +
3111 +#define AD_USAGE_AS_REQ         0x01
3112 +#define AD_USAGE_TGS_REQ        0x02
3113 +#define AD_USAGE_AP_REQ         0x04
3114 +#define AD_USAGE_KDC_ISSUED     0x08
3115 +#define AD_USAGE_MASK           0x0F
3116 +#define AD_INFORMATIONAL        0x10
3117 +
3118 +struct _krb5_authdata_context;
3119 +
3120 +typedef void
3121 +(*authdata_client_plugin_flags_proc)(krb5_context kcontext,
3122 +                                     void *plugin_context,
3123 +                                     krb5_authdatatype ad_type,
3124 +                                     krb5_flags *flags);
3125 +
3126 +typedef void
3127 +(*authdata_client_plugin_fini_proc)(krb5_context kcontext,
3128 +                                    void *plugin_context);
3129 +
3130 +typedef krb5_error_code
3131 +(*authdata_client_request_init_proc)(krb5_context kcontext,
3132 +                                     struct _krb5_authdata_context *context,
3133 +                                     void *plugin_context,
3134 +                                     void **request_context);
3135 +
3136 +typedef void
3137 +(*authdata_client_request_fini_proc)(krb5_context kcontext,
3138 +                                     struct _krb5_authdata_context *context,
3139 +                                     void *plugin_context,
3140 +                                     void *request_context);
3141 +
3142 +typedef krb5_error_code
3143 +(*authdata_client_import_authdata_proc)(krb5_context kcontext,
3144 +                                        struct _krb5_authdata_context *context,
3145 +                                        void *plugin_context,
3146 +                                        void *request_context,
3147 +                                        krb5_authdata **authdata,
3148 +                                        krb5_boolean kdc_issued_flag,
3149 +                                        krb5_const_principal issuer);
3150 +
3151 +typedef krb5_error_code
3152 +(*authdata_client_export_authdata_proc)(krb5_context kcontext,
3153 +                                        struct _krb5_authdata_context *context,
3154 +                                        void *plugin_context,
3155 +                                        void *request_context,
3156 +                                        krb5_flags usage,
3157 +                                        krb5_authdata ***authdata);
3158 +
3159 +typedef krb5_error_code
3160 +(*authdata_client_get_attribute_types_proc)(krb5_context kcontext,
3161 +                                            struct _krb5_authdata_context *context,
3162 +                                            void *plugin_context,
3163 +                                            void *request_context,
3164 +                                            krb5_data **attrs);
3165 +
3166 +typedef krb5_error_code
3167 +(*authdata_client_get_attribute_proc)(krb5_context kcontext,
3168 +                                      struct _krb5_authdata_context *context,
3169 +                                      void *plugin_context,
3170 +                                      void *request_context,
3171 +                                      const krb5_data *attribute,
3172 +                                      krb5_boolean *authenticated,
3173 +                                      krb5_boolean *complete,
3174 +                                      krb5_data *value,
3175 +                                      krb5_data *display_value,
3176 +                                      int *more);
3177 +
3178 +typedef krb5_error_code
3179 +(*authdata_client_set_attribute_proc)(krb5_context kcontext,
3180 +                                      struct _krb5_authdata_context *context,
3181 +                                      void *plugin_context,
3182 +                                      void *request_context,
3183 +                                      krb5_boolean complete,
3184 +                                      const krb5_data *attribute,
3185 +                                      const krb5_data *value);
3186 +
3187 +typedef krb5_error_code
3188 +(*authdata_client_delete_attribute_proc)(krb5_context kcontext,
3189 +                                         struct _krb5_authdata_context *context,
3190 +                                         void *plugin_context,
3191 +                                         void *request_context,
3192 +                                         const krb5_data *attribute);
3193 +
3194 +typedef krb5_error_code
3195 +(*authdata_client_export_internal_proc)(krb5_context kcontext,
3196 +                                        struct _krb5_authdata_context *context,
3197 +                                        void *plugin_context,
3198 +                                        void *request_context,
3199 +                                        krb5_boolean restrict_authenticated,
3200 +                                        void **ptr);
3201 +
3202 +typedef void
3203 +(*authdata_client_free_internal_proc)(krb5_context kcontext,
3204 +                                      struct _krb5_authdata_context *context,
3205 +                                      void *plugin_context,
3206 +                                      void *request_context,
3207 +                                      void *ptr);
3208 +
3209 +typedef krb5_error_code
3210 +(*authdata_client_verify_proc)(krb5_context kcontext,
3211 +                               struct _krb5_authdata_context *context,
3212 +                               void *plugin_context,
3213 +                               void *request_context,
3214 +                               const krb5_auth_context *auth_context,
3215 +                               const krb5_keyblock *key,
3216 +                               const krb5_ap_req *req);
3217 +
3218 +typedef krb5_error_code
3219 +(*authdata_client_size_proc)(krb5_context kcontext,
3220 +                             struct _krb5_authdata_context *context,
3221 +                             void *plugin_context,
3222 +                             void *request_context,
3223 +                             size_t *sizep);
3224 +
3225 +typedef krb5_error_code
3226 +(*authdata_client_externalize_proc)(krb5_context kcontext,
3227 +                                    struct _krb5_authdata_context *context,
3228 +                                    void *plugin_context,
3229 +                                    void *request_context,
3230 +                                    krb5_octet **buffer,
3231 +                                    size_t *lenremain);
3232 +
3233 +typedef krb5_error_code
3234 +(*authdata_client_internalize_proc)(krb5_context kcontext,
3235 +                                    struct _krb5_authdata_context *context,
3236 +                                    void *plugin_context,
3237 +                                    void *request_context,
3238 +                                    krb5_octet **buffer,
3239 +                                    size_t *lenremain);
3240 +
3241 +typedef krb5_error_code
3242 +(*authdata_client_copy_proc)(krb5_context kcontext,
3243 +                             struct _krb5_authdata_context *context,
3244 +                             void *plugin_context,
3245 +                             void *request_context,
3246 +                             void *dst_plugin_context,
3247 +                             void *dst_request_context);
3248 +
3249 +typedef struct krb5plugin_authdata_client_ftable_v0 {
3250 +    char *name;
3251 +    krb5_authdatatype *ad_type_list;
3252 +    authdata_client_plugin_init_proc init;
3253 +    authdata_client_plugin_fini_proc fini;
3254 +    authdata_client_plugin_flags_proc flags;
3255 +    authdata_client_request_init_proc request_init;
3256 +    authdata_client_request_fini_proc request_fini;
3257 +    authdata_client_get_attribute_types_proc get_attribute_types;
3258 +    authdata_client_get_attribute_proc get_attribute;
3259 +    authdata_client_set_attribute_proc set_attribute;
3260 +    authdata_client_delete_attribute_proc delete_attribute;
3261 +    authdata_client_export_authdata_proc export_authdata;
3262 +    authdata_client_import_authdata_proc import_authdata;
3263 +    authdata_client_export_internal_proc export_internal;
3264 +    authdata_client_free_internal_proc free_internal;
3265 +    authdata_client_verify_proc verify;
3266 +    authdata_client_size_proc size;
3267 +    authdata_client_externalize_proc externalize;
3268 +    authdata_client_internalize_proc internalize;
3269 +    authdata_client_copy_proc copy; /* optional */
3270 +} krb5plugin_authdata_client_ftable_v0;
3271 +
3272 +#endif /* KRB5_AUTHDATA_PLUGIN_H_INCLUDED */
3273 diff --git a/mech_eap/authorize_localname.c b/mech_eap/authorize_localname.c
3274 new file mode 100644
3275 index 0000000..0037e2b
3276 --- /dev/null
3277 +++ b/mech_eap/authorize_localname.c
3278 @@ -0,0 +1,54 @@
3279 +/*
3280 + * Copyright (c) 2011, JANET(UK)
3281 + * All rights reserved.
3282 + *
3283 + * Redistribution and use in source and binary forms, with or without
3284 + * modification, are permitted provided that the following conditions
3285 + * are met:
3286 + *
3287 + * 1. Redistributions of source code must retain the above copyright
3288 + *    notice, this list of conditions and the following disclaimer.
3289 + *
3290 + * 2. Redistributions in binary form must reproduce the above copyright
3291 + *    notice, this list of conditions and the following disclaimer in the
3292 + *    documentation and/or other materials provided with the distribution.
3293 + *
3294 + * 3. Neither the name of JANET(UK) nor the names of its contributors
3295 + *    may be used to endorse or promote products derived from this software
3296 + *    without specific prior written permission.
3297 + *
3298 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3299 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3300 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3301 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3302 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3303 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3304 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3305 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3306 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3307 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3308 + * SUCH DAMAGE.
3309 + */
3310 +
3311 +/*
3312 + * Local authorization services.
3313 + */
3314 +
3315 +#include "gssapiP_eap.h"
3316 +
3317 +OM_uint32 GSSAPI_CALLCONV
3318 +gssspi_authorize_localname(OM_uint32 *minor,
3319 +                           const gss_name_t name GSSEAP_UNUSED,
3320 +                           gss_const_buffer_t local_user GSSEAP_UNUSED,
3321 +                           gss_const_OID local_nametype GSSEAP_UNUSED)
3322 +{
3323 +    /*
3324 +     * The MIT mechglue will fallback to comparing names in the absence
3325 +     * of a mechanism implementation of gss_userok. To avoid this and
3326 +     * force the mechglue to use attribute-based authorization, always
3327 +     * return access denied here.
3328 +     */
3329 +
3330 +    *minor = 0;
3331 +    return GSS_S_UNAUTHORIZED;
3332 +}
3333 diff --git a/mech_eap/canonicalize_name.c b/mech_eap/canonicalize_name.c
3334 new file mode 100644
3335 index 0000000..5e66798
3336 --- /dev/null
3337 +++ b/mech_eap/canonicalize_name.c
3338 @@ -0,0 +1,64 @@
3339 +/*
3340 + * Copyright (c) 2011, JANET(UK)
3341 + * All rights reserved.
3342 + *
3343 + * Redistribution and use in source and binary forms, with or without
3344 + * modification, are permitted provided that the following conditions
3345 + * are met:
3346 + *
3347 + * 1. Redistributions of source code must retain the above copyright
3348 + *    notice, this list of conditions and the following disclaimer.
3349 + *
3350 + * 2. Redistributions in binary form must reproduce the above copyright
3351 + *    notice, this list of conditions and the following disclaimer in the
3352 + *    documentation and/or other materials provided with the distribution.
3353 + *
3354 + * 3. Neither the name of JANET(UK) nor the names of its contributors
3355 + *    may be used to endorse or promote products derived from this software
3356 + *    without specific prior written permission.
3357 + *
3358 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3359 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3360 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3361 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3362 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3363 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3364 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3365 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3366 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3367 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3368 + * SUCH DAMAGE.
3369 + */
3370 +
3371 +/*
3372 + * Function for canonicalizing a name; presently just duplicates it.
3373 + */
3374 +
3375 +#include "gssapiP_eap.h"
3376 +
3377 +OM_uint32 GSSAPI_CALLCONV
3378 +gss_canonicalize_name(OM_uint32 *minor,
3379 +                      const gss_name_t input_name,
3380 +                      const gss_OID mech_type,
3381 +                      gss_name_t *output_name)
3382 +{
3383 +    OM_uint32 major;
3384 +
3385 +    *minor = 0;
3386 +
3387 +    if (!gssEapIsMechanismOid(mech_type))
3388 +        return GSS_S_BAD_MECH;
3389 +
3390 +    if (input_name == GSS_C_NO_NAME) {
3391 +        *minor = EINVAL;
3392 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
3393 +    }
3394 +
3395 +    GSSEAP_MUTEX_LOCK(&input_name->mutex);
3396 +
3397 +    major = gssEapCanonicalizeName(minor, input_name, mech_type, output_name);
3398 +
3399 +    GSSEAP_MUTEX_UNLOCK(&input_name->mutex);
3400 +
3401 +    return major;
3402 +}
3403 diff --git a/mech_eap/compare_name.c b/mech_eap/compare_name.c
3404 new file mode 100644
3405 index 0000000..edadf3e
3406 --- /dev/null
3407 +++ b/mech_eap/compare_name.c
3408 @@ -0,0 +1,46 @@
3409 +/*
3410 + * Copyright (c) 2011, JANET(UK)
3411 + * All rights reserved.
3412 + *
3413 + * Redistribution and use in source and binary forms, with or without
3414 + * modification, are permitted provided that the following conditions
3415 + * are met:
3416 + *
3417 + * 1. Redistributions of source code must retain the above copyright
3418 + *    notice, this list of conditions and the following disclaimer.
3419 + *
3420 + * 2. Redistributions in binary form must reproduce the above copyright
3421 + *    notice, this list of conditions and the following disclaimer in the
3422 + *    documentation and/or other materials provided with the distribution.
3423 + *
3424 + * 3. Neither the name of JANET(UK) nor the names of its contributors
3425 + *    may be used to endorse or promote products derived from this software
3426 + *    without specific prior written permission.
3427 + *
3428 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3429 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3430 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3431 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3432 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3433 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3434 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3435 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3436 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3437 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3438 + * SUCH DAMAGE.
3439 + */
3440 +
3441 +/*
3442 + * Compare two names.
3443 + */
3444 +
3445 +#include "gssapiP_eap.h"
3446 +
3447 +OM_uint32 GSSAPI_CALLCONV
3448 +gss_compare_name(OM_uint32 *minor,
3449 +                 gss_name_t name1,
3450 +                 gss_name_t name2,
3451 +                 int *name_equal)
3452 +{
3453 +    return gssEapCompareName(minor, name1, name2, name_equal);
3454 +}
3455 diff --git a/mech_eap/context_time.c b/mech_eap/context_time.c
3456 new file mode 100644
3457 index 0000000..ae47d6c
3458 --- /dev/null
3459 +++ b/mech_eap/context_time.c
3460 @@ -0,0 +1,69 @@
3461 +/*
3462 + * Copyright (c) 2011, JANET(UK)
3463 + * All rights reserved.
3464 + *
3465 + * Redistribution and use in source and binary forms, with or without
3466 + * modification, are permitted provided that the following conditions
3467 + * are met:
3468 + *
3469 + * 1. Redistributions of source code must retain the above copyright
3470 + *    notice, this list of conditions and the following disclaimer.
3471 + *
3472 + * 2. Redistributions in binary form must reproduce the above copyright
3473 + *    notice, this list of conditions and the following disclaimer in the
3474 + *    documentation and/or other materials provided with the distribution.
3475 + *
3476 + * 3. Neither the name of JANET(UK) nor the names of its contributors
3477 + *    may be used to endorse or promote products derived from this software
3478 + *    without specific prior written permission.
3479 + *
3480 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3481 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3482 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3483 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3484 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3485 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3486 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3487 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3488 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3489 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3490 + * SUCH DAMAGE.
3491 + */
3492 +
3493 +/*
3494 + * Determine remaining lifetime of a context handle.
3495 + */
3496 +
3497 +#include "gssapiP_eap.h"
3498 +
3499 +OM_uint32 GSSAPI_CALLCONV
3500 +gss_context_time(OM_uint32 *minor,
3501 +                 gss_ctx_id_t ctx,
3502 +                 OM_uint32 *time_rec)
3503 +{
3504 +    OM_uint32 major;
3505 +
3506 +    if (ctx == GSS_C_NO_CONTEXT) {
3507 +        *minor = EINVAL;
3508 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
3509 +    }
3510 +
3511 +    *minor = 0;
3512 +
3513 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
3514 +
3515 +    if (!CTX_IS_ESTABLISHED(ctx)) {
3516 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
3517 +        major = GSS_S_NO_CONTEXT;
3518 +        goto cleanup;
3519 +    }
3520 +
3521 +    major = gssEapContextTime(minor, ctx, time_rec);
3522 +    if (GSS_ERROR(major))
3523 +        goto cleanup;
3524 +
3525 +cleanup:
3526 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
3527 +
3528 +    return major;
3529 +}
3530 diff --git a/mech_eap/delete_name_attribute.c b/mech_eap/delete_name_attribute.c
3531 new file mode 100644
3532 index 0000000..fe0ff8f
3533 --- /dev/null
3534 +++ b/mech_eap/delete_name_attribute.c
3535 @@ -0,0 +1,60 @@
3536 +/*
3537 + * Copyright (c) 2011, JANET(UK)
3538 + * All rights reserved.
3539 + *
3540 + * Redistribution and use in source and binary forms, with or without
3541 + * modification, are permitted provided that the following conditions
3542 + * are met:
3543 + *
3544 + * 1. Redistributions of source code must retain the above copyright
3545 + *    notice, this list of conditions and the following disclaimer.
3546 + *
3547 + * 2. Redistributions in binary form must reproduce the above copyright
3548 + *    notice, this list of conditions and the following disclaimer in the
3549 + *    documentation and/or other materials provided with the distribution.
3550 + *
3551 + * 3. Neither the name of JANET(UK) nor the names of its contributors
3552 + *    may be used to endorse or promote products derived from this software
3553 + *    without specific prior written permission.
3554 + *
3555 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3556 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3557 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3558 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3559 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3560 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3561 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3562 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3563 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3564 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3565 + * SUCH DAMAGE.
3566 + */
3567 +
3568 +/*
3569 + * Wrapper for removing a name attribute.
3570 + */
3571 +
3572 +#include "gssapiP_eap.h"
3573 +
3574 +OM_uint32 GSSAPI_CALLCONV
3575 +gss_delete_name_attribute(OM_uint32 *minor,
3576 +                          gss_name_t name,
3577 +                          gss_buffer_t attr)
3578 +{
3579 +    OM_uint32 major;
3580 +
3581 +    *minor = 0;
3582 +
3583 +    if (name == GSS_C_NO_NAME) {
3584 +        *minor = EINVAL;
3585 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
3586 +    }
3587 +
3588 +    GSSEAP_MUTEX_LOCK(&name->mutex);
3589 +
3590 +    major = gssEapDeleteNameAttribute(minor, name, attr);
3591 +
3592 +    GSSEAP_MUTEX_UNLOCK(&name->mutex);
3593 +
3594 +    return major;
3595 +}
3596 diff --git a/mech_eap/delete_sec_context.c b/mech_eap/delete_sec_context.c
3597 new file mode 100644
3598 index 0000000..7913e45
3599 --- /dev/null
3600 +++ b/mech_eap/delete_sec_context.c
3601 @@ -0,0 +1,81 @@
3602 +/*
3603 + * Copyright (c) 2011, JANET(UK)
3604 + * All rights reserved.
3605 + *
3606 + * Redistribution and use in source and binary forms, with or without
3607 + * modification, are permitted provided that the following conditions
3608 + * are met:
3609 + *
3610 + * 1. Redistributions of source code must retain the above copyright
3611 + *    notice, this list of conditions and the following disclaimer.
3612 + *
3613 + * 2. Redistributions in binary form must reproduce the above copyright
3614 + *    notice, this list of conditions and the following disclaimer in the
3615 + *    documentation and/or other materials provided with the distribution.
3616 + *
3617 + * 3. Neither the name of JANET(UK) nor the names of its contributors
3618 + *    may be used to endorse or promote products derived from this software
3619 + *    without specific prior written permission.
3620 + *
3621 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3622 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3623 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3624 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3625 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3626 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3627 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3628 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3629 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3630 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3631 + * SUCH DAMAGE.
3632 + */
3633 +
3634 +/*
3635 + * Release a context handle.
3636 + */
3637 +
3638 +#include "gssapiP_eap.h"
3639 +
3640 +OM_uint32 GSSAPI_CALLCONV
3641 +gss_delete_sec_context(OM_uint32 *minor,
3642 +                       gss_ctx_id_t *context_handle,
3643 +                       gss_buffer_t output_token)
3644 +{
3645 +    OM_uint32 major;
3646 +    gss_ctx_id_t ctx = *context_handle;
3647 +
3648 +    *minor = 0;
3649 +
3650 +    if (output_token != GSS_C_NO_BUFFER) {
3651 +        output_token->length = 0;
3652 +        output_token->value = NULL;
3653 +    }
3654 +
3655 +    if (ctx == GSS_C_NO_CONTEXT)
3656 +        return GSS_S_COMPLETE;
3657 +
3658 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
3659 +
3660 +    if (output_token != GSS_C_NO_BUFFER) {
3661 +        gss_iov_buffer_desc iov[2];
3662 +
3663 +        iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
3664 +        iov[0].buffer.value = NULL;
3665 +        iov[0].buffer.length = 0;
3666 +
3667 +        iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
3668 +        iov[1].buffer.value = NULL;
3669 +        iov[1].buffer.length = 0;
3670 +
3671 +        major = gssEapWrapOrGetMIC(minor, ctx, FALSE, NULL,
3672 +                                   iov, 2, TOK_TYPE_DELETE_CONTEXT);
3673 +        if (GSS_ERROR(major)) {
3674 +            GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
3675 +            return major;
3676 +        }
3677 +    }
3678 +
3679 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
3680 +
3681 +    return gssEapReleaseContext(minor, context_handle);
3682 +}
3683 diff --git a/mech_eap/dictionary.ukerna b/mech_eap/dictionary.ukerna
3684 new file mode 100644
3685 index 0000000..0e35d43
3686 --- /dev/null
3687 +++ b/mech_eap/dictionary.ukerna
3688 @@ -0,0 +1,20 @@
3689 +# -*- text -*-
3690 +#
3691 +#      GSS-EAP VSAs
3692 +#
3693 +#      $Id$
3694 +#
3695 +
3696 +VENDOR UKERNA                          25622
3697 +
3698 +BEGIN-VENDOR UKERNA
3699 +
3700 +ATTRIBUTE      GSS-Acceptor-Service-Name       128     string
3701 +ATTRIBUTE      GSS-Acceptor-Host-Name          129     string
3702 +ATTRIBUTE      GSS-Acceptor-Service-Specific   130     string
3703 +ATTRIBUTE      GSS-Acceptor-Realm-Name         131     string
3704 +ATTRIBUTE      SAML-AAA-Assertion              132     string
3705 +ATTRIBUTE      MS-Windows-Auth-Data            133     octets
3706 +ATTRIBUTE      MS-Windows-Group-Sid            134     string
3707 +
3708 +END-VENDOR UKERNA
3709 diff --git a/mech_eap/display_name.c b/mech_eap/display_name.c
3710 new file mode 100644
3711 index 0000000..2d87e66
3712 --- /dev/null
3713 +++ b/mech_eap/display_name.c
3714 @@ -0,0 +1,48 @@
3715 +/*
3716 + * Copyright (c) 2011, JANET(UK)
3717 + * All rights reserved.
3718 + *
3719 + * Redistribution and use in source and binary forms, with or without
3720 + * modification, are permitted provided that the following conditions
3721 + * are met:
3722 + *
3723 + * 1. Redistributions of source code must retain the above copyright
3724 + *    notice, this list of conditions and the following disclaimer.
3725 + *
3726 + * 2. Redistributions in binary form must reproduce the above copyright
3727 + *    notice, this list of conditions and the following disclaimer in the
3728 + *    documentation and/or other materials provided with the distribution.
3729 + *
3730 + * 3. Neither the name of JANET(UK) nor the names of its contributors
3731 + *    may be used to endorse or promote products derived from this software
3732 + *    without specific prior written permission.
3733 + *
3734 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3735 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3736 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3737 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3738 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3739 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3740 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3741 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3742 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3743 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3744 + * SUCH DAMAGE.
3745 + */
3746 +
3747 +/*
3748 + * Wrapper for "displaying" (returning string representation of) a name.
3749 + */
3750 +
3751 +#include "gssapiP_eap.h"
3752 +
3753 +OM_uint32 GSSAPI_CALLCONV
3754 +gss_display_name(OM_uint32 *minor,
3755 +                 gss_name_t name,
3756 +                 gss_buffer_t output_name_buffer,
3757 +                 gss_OID *output_name_type)
3758 +{
3759 +    /* Lock not required as long as attributes are not used */
3760 +    return gssEapDisplayName(minor, name, output_name_buffer,
3761 +                             output_name_type);
3762 +}
3763 diff --git a/mech_eap/display_name_ext.c b/mech_eap/display_name_ext.c
3764 new file mode 100644
3765 index 0000000..d6791d4
3766 --- /dev/null
3767 +++ b/mech_eap/display_name_ext.c
3768 @@ -0,0 +1,51 @@
3769 +/*
3770 + * Copyright (c) 2011, JANET(UK)
3771 + * All rights reserved.
3772 + *
3773 + * Redistribution and use in source and binary forms, with or without
3774 + * modification, are permitted provided that the following conditions
3775 + * are met:
3776 + *
3777 + * 1. Redistributions of source code must retain the above copyright
3778 + *    notice, this list of conditions and the following disclaimer.
3779 + *
3780 + * 2. Redistributions in binary form must reproduce the above copyright
3781 + *    notice, this list of conditions and the following disclaimer in the
3782 + *    documentation and/or other materials provided with the distribution.
3783 + *
3784 + * 3. Neither the name of JANET(UK) nor the names of its contributors
3785 + *    may be used to endorse or promote products derived from this software
3786 + *    without specific prior written permission.
3787 + *
3788 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3789 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3790 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3791 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3792 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3793 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3794 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3795 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3796 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3797 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3798 + * SUCH DAMAGE.
3799 + */
3800 +
3801 +/*
3802 + * Parameterized version of gss_display_name(), currently unimplemented.
3803 + */
3804 +
3805 +#include "gssapiP_eap.h"
3806 +
3807 +OM_uint32 GSSAPI_CALLCONV
3808 +gss_display_name_ext(OM_uint32 *minor,
3809 +                     gss_name_t name GSSEAP_UNUSED,
3810 +                     gss_OID display_as_name_type GSSEAP_UNUSED,
3811 +                     gss_buffer_t display_name)
3812 +{
3813 +    *minor = 0;
3814 +
3815 +    display_name->length = 0;
3816 +    display_name->value = NULL;
3817 +
3818 +    return GSS_S_UNAVAILABLE;
3819 +}
3820 diff --git a/mech_eap/display_status.c b/mech_eap/display_status.c
3821 new file mode 100644
3822 index 0000000..fc0d1ab
3823 --- /dev/null
3824 +++ b/mech_eap/display_status.c
3825 @@ -0,0 +1,203 @@
3826 +/*
3827 + * Copyright (c) 2011, JANET(UK)
3828 + * All rights reserved.
3829 + *
3830 + * Redistribution and use in source and binary forms, with or without
3831 + * modification, are permitted provided that the following conditions
3832 + * are met:
3833 + *
3834 + * 1. Redistributions of source code must retain the above copyright
3835 + *    notice, this list of conditions and the following disclaimer.
3836 + *
3837 + * 2. Redistributions in binary form must reproduce the above copyright
3838 + *    notice, this list of conditions and the following disclaimer in the
3839 + *    documentation and/or other materials provided with the distribution.
3840 + *
3841 + * 3. Neither the name of JANET(UK) nor the names of its contributors
3842 + *    may be used to endorse or promote products derived from this software
3843 + *    without specific prior written permission.
3844 + *
3845 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3846 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3847 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3848 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3849 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3850 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3851 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3852 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3853 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3854 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3855 + * SUCH DAMAGE.
3856 + */
3857 +
3858 +/*
3859 + * Function for converting mechanism error codes to strings.
3860 + */
3861 +
3862 +#include "gssapiP_eap.h"
3863 +
3864 +struct gss_eap_status_info {
3865 +    OM_uint32 code;
3866 +    char *message;
3867 +    struct gss_eap_status_info *next;
3868 +};
3869 +
3870 +void
3871 +gssEapDestroyStatusInfo(struct gss_eap_status_info *p)
3872 +{
3873 +    struct gss_eap_status_info *next;
3874 +
3875 +    for (; p != NULL; p = next) {
3876 +        next = p->next;
3877 +        GSSEAP_FREE(p->message);
3878 +        GSSEAP_FREE(p);
3879 +    }
3880 +}
3881 +
3882 +/*
3883 + * Associate a message with a mechanism (minor) status code. This function
3884 + * takes ownership of the message regardless of success. The message must
3885 + * be explicitly cleared, if required, so it is suggested that a specific
3886 + * minor code is either always or never associated with a message, to avoid
3887 + * dangling (and potentially confusing) error messages.
3888 + */
3889 +static void
3890 +saveStatusInfoNoCopy(OM_uint32 minor, char *message)
3891 +{
3892 +    struct gss_eap_status_info **next = NULL, *p = NULL;
3893 +    struct gss_eap_thread_local_data *tld = gssEapGetThreadLocalData();
3894 +
3895 +    if (tld != NULL) {
3896 +        for (p = tld->statusInfo; p != NULL; p = p->next) {
3897 +            if (p->code == minor) {
3898 +                /* Set message in-place */
3899 +                if (p->message != NULL)
3900 +                    GSSEAP_FREE(p->message);
3901 +                p->message = message;
3902 +                return;
3903 +            }
3904 +            next = &p->next;
3905 +        }
3906 +        p = GSSEAP_CALLOC(1, sizeof(*p));
3907 +    }
3908 +
3909 +    if (p == NULL) {
3910 +        if (message != NULL)
3911 +            GSSEAP_FREE(message);
3912 +        return;
3913 +    }
3914 +
3915 +    p->code = minor;
3916 +    p->message = message;
3917 +
3918 +    if (next != NULL)
3919 +        *next = p;
3920 +    else
3921 +        tld->statusInfo = p;
3922 +}
3923 +
3924 +static const char *
3925 +getStatusInfo(OM_uint32 minor)
3926 +{
3927 +    struct gss_eap_status_info *p;
3928 +    struct gss_eap_thread_local_data *tld = gssEapGetThreadLocalData();
3929 +
3930 +    if (tld != NULL) {
3931 +        for (p = tld->statusInfo; p != NULL; p = p->next) {
3932 +            if (p->code == minor)
3933 +                return p->message;
3934 +        }
3935 +    }
3936 +    return NULL;
3937 +}
3938 +
3939 +void
3940 +gssEapSaveStatusInfo(OM_uint32 minor, const char *format, ...)
3941 +{
3942 +#ifdef WIN32
3943 +    OM_uint32 tmpMajor, tmpMinor;
3944 +    char buf[BUFSIZ];
3945 +    gss_buffer_desc s = GSS_C_EMPTY_BUFFER;
3946 +    va_list ap;
3947 +
3948 +    if (format != NULL) {
3949 +        va_start(ap, format);
3950 +        snprintf(buf, sizeof(buf), format, ap);
3951 +        va_end(ap);
3952 +    }
3953 +
3954 +    tmpMajor = makeStringBuffer(&tmpMinor, buf, &s);
3955 +    if (!GSS_ERROR(tmpMajor))
3956 +        saveStatusInfoNoCopy(minor, (char *)s.value);
3957 +#else
3958 +    char *s = NULL;
3959 +    int n;
3960 +    va_list ap;
3961 +
3962 +    if (format != NULL) {
3963 +        va_start(ap, format);
3964 +        n = vasprintf(&s, format, ap);
3965 +        if (n == -1)
3966 +            s = NULL;
3967 +        va_end(ap);
3968 +    }
3969 +
3970 +    saveStatusInfoNoCopy(minor, s);
3971 +#endif /* WIN32 */
3972 +}
3973 +
3974 +OM_uint32
3975 +gssEapDisplayStatus(OM_uint32 *minor,
3976 +                    OM_uint32 status_value,
3977 +                    gss_buffer_t status_string)
3978 +{
3979 +    OM_uint32 major;
3980 +    krb5_context krbContext = NULL;
3981 +    const char *errMsg;
3982 +
3983 +    status_string->length = 0;
3984 +    status_string->value = NULL;
3985 +
3986 +    errMsg = getStatusInfo(status_value);
3987 +    if (errMsg == NULL) {
3988 +        GSSEAP_KRB_INIT(&krbContext);
3989 +
3990 +        /* Try the com_err message */
3991 +        errMsg = krb5_get_error_message(krbContext, status_value);
3992 +    }
3993 +
3994 +    if (errMsg != NULL) {
3995 +        major = makeStringBuffer(minor, errMsg, status_string);
3996 +    } else {
3997 +        major = GSS_S_COMPLETE;
3998 +        *minor = 0;
3999 +    }
4000 +
4001 +    if (krbContext != NULL)
4002 +        krb5_free_error_message(krbContext, errMsg);
4003 +
4004 +    return major;
4005 +}
4006 +
4007 +OM_uint32 GSSAPI_CALLCONV
4008 +gss_display_status(OM_uint32 *minor,
4009 +                   OM_uint32 status_value,
4010 +                   int status_type,
4011 +                   gss_OID mech_type,
4012 +                   OM_uint32 *message_context,
4013 +                   gss_buffer_t status_string)
4014 +{
4015 +    if (!gssEapIsMechanismOid(mech_type)) {
4016 +        *minor = GSSEAP_WRONG_MECH;
4017 +        return GSS_S_BAD_MECH;
4018 +    }
4019 +
4020 +    if (status_type != GSS_C_MECH_CODE ||
4021 +        *message_context != 0) {
4022 +        /* we rely on the mechglue for GSS_C_GSS_CODE */
4023 +        *minor = 0;
4024 +        return GSS_S_BAD_STATUS;
4025 +    }
4026 +
4027 +    return gssEapDisplayStatus(minor, status_value, status_string);
4028 +}
4029 diff --git a/mech_eap/duplicate_name.c b/mech_eap/duplicate_name.c
4030 new file mode 100644
4031 index 0000000..303619e
4032 --- /dev/null
4033 +++ b/mech_eap/duplicate_name.c
4034 @@ -0,0 +1,60 @@
4035 +/*
4036 + * Copyright (c) 2011, JANET(UK)
4037 + * All rights reserved.
4038 + *
4039 + * Redistribution and use in source and binary forms, with or without
4040 + * modification, are permitted provided that the following conditions
4041 + * are met:
4042 + *
4043 + * 1. Redistributions of source code must retain the above copyright
4044 + *    notice, this list of conditions and the following disclaimer.
4045 + *
4046 + * 2. Redistributions in binary form must reproduce the above copyright
4047 + *    notice, this list of conditions and the following disclaimer in the
4048 + *    documentation and/or other materials provided with the distribution.
4049 + *
4050 + * 3. Neither the name of JANET(UK) nor the names of its contributors
4051 + *    may be used to endorse or promote products derived from this software
4052 + *    without specific prior written permission.
4053 + *
4054 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
4055 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4056 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4057 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
4058 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4059 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4060 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4061 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4062 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4063 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4064 + * SUCH DAMAGE.
4065 + */
4066 +
4067 +/*
4068 + * Duplicate a name.
4069 + */
4070 +
4071 +#include "gssapiP_eap.h"
4072 +
4073 +OM_uint32 GSSAPI_CALLCONV
4074 +gss_duplicate_name(OM_uint32 *minor,
4075 +                   const gss_name_t input_name,
4076 +                   gss_name_t *dest_name)
4077 +{
4078 +    OM_uint32 major;
4079 +
4080 +    *minor = 0;
4081 +
4082 +    if (input_name == GSS_C_NO_NAME) {
4083 +        *minor = EINVAL;
4084 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
4085 +    }
4086 +
4087 +    GSSEAP_MUTEX_LOCK(&input_name->mutex);
4088 +
4089 +    major = gssEapDuplicateName(minor, input_name, dest_name);
4090 +
4091 +    GSSEAP_MUTEX_UNLOCK(&input_name->mutex);
4092 +
4093 +    return major;
4094 +}
4095 diff --git a/mech_eap/eap_mech.c b/mech_eap/eap_mech.c
4096 new file mode 100644
4097 index 0000000..96e00c2
4098 --- /dev/null
4099 +++ b/mech_eap/eap_mech.c
4100 @@ -0,0 +1,219 @@
4101 +/*
4102 + * Copyright (c) 2011, JANET(UK)
4103 + * All rights reserved.
4104 + *
4105 + * Redistribution and use in source and binary forms, with or without
4106 + * modification, are permitted provided that the following conditions
4107 + * are met:
4108 + *
4109 + * 1. Redistributions of source code must retain the above copyright
4110 + *    notice, this list of conditions and the following disclaimer.
4111 + *
4112 + * 2. Redistributions in binary form must reproduce the above copyright
4113 + *    notice, this list of conditions and the following disclaimer in the
4114 + *    documentation and/or other materials provided with the distribution.
4115 + *
4116 + * 3. Neither the name of JANET(UK) nor the names of its contributors
4117 + *    may be used to endorse or promote products derived from this software
4118 + *    without specific prior written permission.
4119 + *
4120 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
4121 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4122 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4123 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
4124 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4125 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4126 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4127 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4128 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4129 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4130 + * SUCH DAMAGE.
4131 + */
4132 +
4133 +/*
4134 + * Initialisation and finalise functions.
4135 + */
4136 +
4137 +#include "gssapiP_eap.h"
4138 +
4139 +static OM_uint32
4140 +eapPeerRegisterMethods(OM_uint32 *minor)
4141 +{
4142 +    OM_uint32 ret = 0;
4143 +
4144 +#ifdef EAP_MD5
4145 +    if (ret == 0)
4146 +        ret = eap_peer_md5_register();
4147 +#endif /* EAP_MD5 */
4148 +
4149 +#ifdef EAP_TLS
4150 +    if (ret == 0)
4151 +        ret = eap_peer_tls_register();
4152 +#endif /* EAP_TLS */
4153 +
4154 +#ifdef EAP_MSCHAPv2
4155 +    if (ret == 0)
4156 +        ret = eap_peer_mschapv2_register();
4157 +#endif /* EAP_MSCHAPv2 */
4158 +
4159 +#ifdef EAP_PEAP
4160 +    if (ret == 0)
4161 +        ret = eap_peer_peap_register();
4162 +#endif /* EAP_PEAP */
4163 +
4164 +#ifdef EAP_TTLS
4165 +    if (ret == 0)
4166 +        ret = eap_peer_ttls_register();
4167 +#endif /* EAP_TTLS */
4168 +
4169 +#ifdef EAP_GTC
4170 +    if (ret == 0)
4171 +        ret = eap_peer_gtc_register();
4172 +#endif /* EAP_GTC */
4173 +
4174 +#ifdef EAP_OTP
4175 +    if (ret == 0)
4176 +        ret = eap_peer_otp_register();
4177 +#endif /* EAP_OTP */
4178 +
4179 +#ifdef EAP_SIM
4180 +    if (ret == 0)
4181 +        ret = eap_peer_sim_register();
4182 +#endif /* EAP_SIM */
4183 +
4184 +#ifdef EAP_LEAP
4185 +    if (ret == 0)
4186 +        ret = eap_peer_leap_register();
4187 +#endif /* EAP_LEAP */
4188 +
4189 +#ifdef EAP_PSK
4190 +    if (ret == 0)
4191 +        ret = eap_peer_psk_register();
4192 +#endif /* EAP_PSK */
4193 +
4194 +#ifdef EAP_AKA
4195 +    if (ret == 0)
4196 +        ret = eap_peer_aka_register();
4197 +#endif /* EAP_AKA */
4198 +
4199 +#ifdef EAP_AKA_PRIME
4200 +    if (ret == 0)
4201 +        ret = eap_peer_aka_prime_register();
4202 +#endif /* EAP_AKA_PRIME */
4203 +
4204 +#ifdef EAP_FAST
4205 +    if (ret == 0)
4206 +        ret = eap_peer_fast_register();
4207 +#endif /* EAP_FAST */
4208 +
4209 +#ifdef EAP_PAX
4210 +    if (ret == 0)
4211 +        ret = eap_peer_pax_register();
4212 +#endif /* EAP_PAX */
4213 +
4214 +#ifdef EAP_SAKE
4215 +    if (ret == 0)
4216 +        ret = eap_peer_sake_register();
4217 +#endif /* EAP_SAKE */
4218 +
4219 +#ifdef EAP_GPSK
4220 +    if (ret == 0)
4221 +        ret = eap_peer_gpsk_register();
4222 +#endif /* EAP_GPSK */
4223 +
4224 +#ifdef EAP_WSC
4225 +    if (ret == 0)
4226 +        ret = eap_peer_wsc_register();
4227 +#endif /* EAP_WSC */
4228 +
4229 +#ifdef EAP_IKEV2
4230 +    if (ret == 0)
4231 +        ret = eap_peer_ikev2_register();
4232 +#endif /* EAP_IKEV2 */
4233 +
4234 +#ifdef EAP_VENDOR_TEST
4235 +    if (ret == 0)
4236 +        ret = eap_peer_vendor_test_register();
4237 +#endif /* EAP_VENDOR_TEST */
4238 +
4239 +#ifdef EAP_TNC
4240 +    if (ret == 0)
4241 +        ret = eap_peer_tnc_register();
4242 +#endif /* EAP_TNC */
4243 +
4244 +    if (ret == 0)
4245 +        return GSS_S_COMPLETE;
4246 +
4247 +    *minor = GSSEAP_LIBEAP_INIT_FAILURE;
4248 +    return GSS_S_FAILURE;
4249 +}
4250 +
4251 +static OM_uint32
4252 +gssEapInitLibEap(OM_uint32 *minor)
4253 +{
4254 +    return eapPeerRegisterMethods(minor);
4255 +}
4256 +
4257 +static OM_uint32
4258 +gssEapInitLibRadsec(OM_uint32 *minor)
4259 +{
4260 +    if (0) {
4261 +        *minor = GSSEAP_RADSEC_INIT_FAILURE;
4262 +        return GSS_S_FAILURE;
4263 +    }
4264 +
4265 +    return GSS_S_COMPLETE;
4266 +}
4267 +
4268 +void gssEapFinalize(void) GSSEAP_DESTRUCTOR;
4269 +
4270 +OM_uint32
4271 +gssEapInitiatorInit(OM_uint32 *minor)
4272 +{
4273 +    OM_uint32 major;
4274 +
4275 +    initialize_eapg_error_table();
4276 +    initialize_rse_error_table();
4277 +
4278 +    major = gssEapInitLibEap(minor);
4279 +    if (GSS_ERROR(major))
4280 +        return major;
4281 +
4282 +    major = gssEapInitLibRadsec(minor);
4283 +    if (GSS_ERROR(major))
4284 +        return major;
4285 +
4286 +#ifdef GSSEAP_ENABLE_REAUTH
4287 +    major = gssEapReauthInitialize(minor);
4288 +    if (GSS_ERROR(major))
4289 +        return major;
4290 +#endif
4291 +
4292 +    *minor = 0;
4293 +    return GSS_S_COMPLETE;
4294 +}
4295 +
4296 +void
4297 +gssEapFinalize(void)
4298 +{
4299 +#ifdef GSSEAP_ENABLE_ACCEPTOR
4300 +    OM_uint32 minor;
4301 +
4302 +    gssEapAttrProvidersFinalize(&minor);
4303 +#endif
4304 +    eap_peer_unregister_methods();
4305 +}
4306 +
4307 +#ifdef GSSEAP_CONSTRUCTOR
4308 +static void gssEapInitiatorInitAssert(void) GSSEAP_CONSTRUCTOR;
4309 +
4310 +static void
4311 +gssEapInitiatorInitAssert(void)
4312 +{
4313 +    OM_uint32 major, minor;
4314 +
4315 +    major = gssEapInitiatorInit(&minor);
4316 +
4317 +    GSSEAP_ASSERT(!GSS_ERROR(major));
4318 +}
4319 +#endif
4320 diff --git a/mech_eap/exchange_meta_data.c b/mech_eap/exchange_meta_data.c
4321 new file mode 100644
4322 index 0000000..5d56795
4323 --- /dev/null
4324 +++ b/mech_eap/exchange_meta_data.c
4325 @@ -0,0 +1,82 @@
4326 +/*
4327 + * Copyright (c) 2011, JANET(UK)
4328 + * All rights reserved.
4329 + *
4330 + * Redistribution and use in source and binary forms, with or without
4331 + * modification, are permitted provided that the following conditions
4332 + * are met:
4333 + *
4334 + * 1. Redistributions of source code must retain the above copyright
4335 + *    notice, this list of conditions and the following disclaimer.
4336 + *
4337 + * 2. Redistributions in binary form must reproduce the above copyright
4338 + *    notice, this list of conditions and the following disclaimer in the
4339 + *    documentation and/or other materials provided with the distribution.
4340 + *
4341 + * 3. Neither the name of JANET(UK) nor the names of its contributors
4342 + *    may be used to endorse or promote products derived from this software
4343 + *    without specific prior written permission.
4344 + *
4345 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
4346 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4347 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4348 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
4349 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4350 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4351 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4352 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4353 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4354 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4355 + * SUCH DAMAGE.
4356 + */
4357 +
4358 +/*
4359 + *
4360 + */
4361 +
4362 +#include "gssapiP_eap.h"
4363 +
4364 +OM_uint32 GSSAPI_CALLCONV
4365 +gssEapExchangeMetaData(OM_uint32 *minor,
4366 +                       gss_const_OID mech GSSEAP_UNUSED,
4367 +                       gss_cred_id_t cred GSSEAP_UNUSED,
4368 +                       gss_ctx_id_t *ctx GSSEAP_UNUSED,
4369 +                       const gss_name_t name GSSEAP_UNUSED,
4370 +                       OM_uint32 req_flags GSSEAP_UNUSED,
4371 +                       gss_const_buffer_t meta_data GSSEAP_UNUSED)
4372 +{
4373 +    *minor = 0;
4374 +    return GSS_S_COMPLETE;
4375 +}
4376 +
4377 +OM_uint32 GSSAPI_CALLCONV
4378 +gss_exchange_meta_data(OM_uint32 *minor,
4379 +                       gss_const_OID mech,
4380 +                       gss_cred_id_t cred,
4381 +                       gss_ctx_id_t *context_handle,
4382 +                       const gss_name_t name,
4383 +                       OM_uint32 req_flags,
4384 +                       gss_const_buffer_t meta_data)
4385 +{
4386 +    gss_ctx_id_t ctx = *context_handle;
4387 +    OM_uint32 major;
4388 +
4389 +    if (cred != GSS_C_NO_CREDENTIAL)
4390 +        GSSEAP_MUTEX_LOCK(&cred->mutex);
4391 +
4392 +    if (*context_handle != GSS_C_NO_CONTEXT)
4393 +        GSSEAP_MUTEX_LOCK(&ctx->mutex);
4394 +
4395 +    major = gssEapExchangeMetaData(minor, mech, cred, &ctx,
4396 +                                   name, req_flags, meta_data);
4397 +
4398 +    if (*context_handle != GSS_C_NO_CONTEXT)
4399 +        GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
4400 +    else
4401 +        *context_handle = ctx;
4402 +
4403 +    if (cred != GSS_C_NO_CREDENTIAL)
4404 +        GSSEAP_MUTEX_UNLOCK(&cred->mutex);
4405 +
4406 +    return major;
4407 +}
4408 diff --git a/mech_eap/export_name.c b/mech_eap/export_name.c
4409 new file mode 100644
4410 index 0000000..d91033f
4411 --- /dev/null
4412 +++ b/mech_eap/export_name.c
4413 @@ -0,0 +1,60 @@
4414 +/*
4415 + * Copyright (c) 2011, JANET(UK)
4416 + * All rights reserved.
4417 + *
4418 + * Redistribution and use in source and binary forms, with or without
4419 + * modification, are permitted provided that the following conditions
4420 + * are met:
4421 + *
4422 + * 1. Redistributions of source code must retain the above copyright
4423 + *    notice, this list of conditions and the following disclaimer.
4424 + *
4425 + * 2. Redistributions in binary form must reproduce the above copyright
4426 + *    notice, this list of conditions and the following disclaimer in the
4427 + *    documentation and/or other materials provided with the distribution.
4428 + *
4429 + * 3. Neither the name of JANET(UK) nor the names of its contributors
4430 + *    may be used to endorse or promote products derived from this software
4431 + *    without specific prior written permission.
4432 + *
4433 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
4434 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4435 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4436 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
4437 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4438 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4439 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4440 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4441 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4442 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4443 + * SUCH DAMAGE.
4444 + */
4445 +
4446 +/*
4447 + * Serialise a name.
4448 + */
4449 +
4450 +#include "gssapiP_eap.h"
4451 +
4452 +OM_uint32 GSSAPI_CALLCONV
4453 +gss_export_name(OM_uint32 *minor,
4454 +                const gss_name_t input_name,
4455 +                gss_buffer_t exported_name)
4456 +{
4457 +    OM_uint32 major;
4458 +
4459 +    *minor = 0;
4460 +
4461 +    if (input_name == GSS_C_NO_NAME) {
4462 +        *minor = EINVAL;
4463 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
4464 +    }
4465 +
4466 +    GSSEAP_MUTEX_LOCK(&input_name->mutex);
4467 +
4468 +    major = gssEapExportName(minor, input_name, exported_name);
4469 +
4470 +    GSSEAP_MUTEX_UNLOCK(&input_name->mutex);
4471 +
4472 +    return major;
4473 +}
4474 diff --git a/mech_eap/export_name_composite.c b/mech_eap/export_name_composite.c
4475 new file mode 100644
4476 index 0000000..b2a90ae
4477 --- /dev/null
4478 +++ b/mech_eap/export_name_composite.c
4479 @@ -0,0 +1,62 @@
4480 +/*
4481 + * Copyright (c) 2011, JANET(UK)
4482 + * All rights reserved.
4483 + *
4484 + * Redistribution and use in source and binary forms, with or without
4485 + * modification, are permitted provided that the following conditions
4486 + * are met:
4487 + *
4488 + * 1. Redistributions of source code must retain the above copyright
4489 + *    notice, this list of conditions and the following disclaimer.
4490 + *
4491 + * 2. Redistributions in binary form must reproduce the above copyright
4492 + *    notice, this list of conditions and the following disclaimer in the
4493 + *    documentation and/or other materials provided with the distribution.
4494 + *
4495 + * 3. Neither the name of JANET(UK) nor the names of its contributors
4496 + *    may be used to endorse or promote products derived from this software
4497 + *    without specific prior written permission.
4498 + *
4499 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
4500 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4501 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4502 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
4503 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4504 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4505 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4506 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4507 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4508 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4509 + * SUCH DAMAGE.
4510 + */
4511 +
4512 +/*
4513 + * Serialise a name and its attributes.
4514 + */
4515 +
4516 +#include "gssapiP_eap.h"
4517 +
4518 +OM_uint32 GSSAPI_CALLCONV
4519 +gss_export_name_composite(OM_uint32 *minor,
4520 +                          gss_name_t input_name,
4521 +                          gss_buffer_t exported_name)
4522 +{
4523 +    OM_uint32 major;
4524 +
4525 +    *minor = 0;
4526 +
4527 +    if (input_name == GSS_C_NO_NAME) {
4528 +        *minor = EINVAL;
4529 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
4530 +    }
4531 +
4532 +    GSSEAP_MUTEX_LOCK(&input_name->mutex);
4533 +
4534 +    major = gssEapExportNameInternal(minor, input_name, exported_name,
4535 +                                     EXPORT_NAME_FLAG_OID |
4536 +                                     EXPORT_NAME_FLAG_COMPOSITE);
4537 +
4538 +    GSSEAP_MUTEX_UNLOCK(&input_name->mutex);
4539 +
4540 +    return major;
4541 +}
4542 diff --git a/mech_eap/export_sec_context.c b/mech_eap/export_sec_context.c
4543 new file mode 100644
4544 index 0000000..e5be6d8
4545 --- /dev/null
4546 +++ b/mech_eap/export_sec_context.c
4547 @@ -0,0 +1,246 @@
4548 +/*
4549 + * Copyright (c) 2011, JANET(UK)
4550 + * All rights reserved.
4551 + *
4552 + * Redistribution and use in source and binary forms, with or without
4553 + * modification, are permitted provided that the following conditions
4554 + * are met:
4555 + *
4556 + * 1. Redistributions of source code must retain the above copyright
4557 + *    notice, this list of conditions and the following disclaimer.
4558 + *
4559 + * 2. Redistributions in binary form must reproduce the above copyright
4560 + *    notice, this list of conditions and the following disclaimer in the
4561 + *    documentation and/or other materials provided with the distribution.
4562 + *
4563 + * 3. Neither the name of JANET(UK) nor the names of its contributors
4564 + *    may be used to endorse or promote products derived from this software
4565 + *    without specific prior written permission.
4566 + *
4567 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
4568 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4569 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4570 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
4571 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4572 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4573 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4574 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4575 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4576 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4577 + * SUCH DAMAGE.
4578 + */
4579 +
4580 +/*
4581 + * Serialise a security context. On the acceptor, this may be partially
4582 + * established.
4583 + */
4584 +
4585 +#include "gssapiP_eap.h"
4586 +
4587 +#ifdef GSSEAP_ENABLE_ACCEPTOR
4588 +static OM_uint32
4589 +gssEapExportPartialContext(OM_uint32 *minor,
4590 +                           gss_ctx_id_t ctx,
4591 +                           gss_buffer_t token)
4592 +{
4593 +    OM_uint32 major, tmpMinor;
4594 +    size_t length, serverLen = 0;
4595 +    unsigned char *p;
4596 +    char serverBuf[MAXHOSTNAMELEN];
4597 +    if (ctx->acceptorCtx.radConn != NULL) {
4598 +        if (rs_conn_get_current_peer(ctx->acceptorCtx.radConn,
4599 +                                     serverBuf, sizeof(serverBuf)) != 0) {
4600 +#if 0
4601 +            return gssEapRadiusMapError(minor,
4602 +                                        rs_err_conn_pop(ctx->acceptorCtx.radConn));
4603 +#else
4604 +            serverBuf[0] = '\0'; /* not implemented yet */
4605 +#endif
4606 +        }
4607 +        serverLen = strlen(serverBuf);
4608 +    }
4609 +    length = 4 + serverLen + 4 + ctx->acceptorCtx.state.length;
4610 +
4611 +    token->value = GSSEAP_MALLOC(length);
4612 +    if (token->value == NULL) {
4613 +        major = GSS_S_FAILURE;
4614 +        *minor = ENOMEM;
4615 +        goto cleanup;
4616 +    }
4617 +    token->length = length;
4618 +
4619 +    p = (unsigned char *)token->value;
4620 +
4621 +    store_uint32_be(serverLen, p);
4622 +    p += 4;
4623 +    if (serverLen != 0) {
4624 +        memcpy(p, serverBuf, serverLen);
4625 +        p += serverLen;
4626 +    }
4627 +
4628 +    store_uint32_be(ctx->acceptorCtx.state.length, p);
4629 +    p += 4;
4630 +    if (ctx->acceptorCtx.state.length != 0) {
4631 +        memcpy(p, ctx->acceptorCtx.state.value,
4632 +               ctx->acceptorCtx.state.length);
4633 +        p += ctx->acceptorCtx.state.length;
4634 +    }
4635 +
4636 +    GSSEAP_ASSERT(p == (unsigned char *)token->value + token->length);
4637 +
4638 +    major = GSS_S_COMPLETE;
4639 +    *minor = 0;
4640 +
4641 +cleanup:
4642 +    if (GSS_ERROR(major))
4643 +        gss_release_buffer(&tmpMinor, token);
4644 +
4645 +    return major;
4646 +}
4647 +#endif /* GSSEAP_ENABLE_ACCEPTOR */
4648 +
4649 +OM_uint32
4650 +gssEapExportSecContext(OM_uint32 *minor,
4651 +                       gss_ctx_id_t ctx,
4652 +                       gss_buffer_t token)
4653 +{
4654 +    OM_uint32 major, tmpMinor;
4655 +    size_t length;
4656 +    gss_buffer_desc initiatorName = GSS_C_EMPTY_BUFFER;
4657 +    gss_buffer_desc acceptorName = GSS_C_EMPTY_BUFFER;
4658 +    gss_buffer_desc partialCtx = GSS_C_EMPTY_BUFFER;
4659 +    gss_buffer_desc key;
4660 +    unsigned char *p;
4661 +
4662 +    if ((CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx)) ||
4663 +        ctx->mechanismUsed == GSS_C_NO_OID) {
4664 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
4665 +        return GSS_S_NO_CONTEXT;
4666 +    }
4667 +
4668 +    key.length = KRB_KEY_LENGTH(&ctx->rfc3961Key);
4669 +    key.value  = KRB_KEY_DATA(&ctx->rfc3961Key);
4670 +
4671 +    if (ctx->initiatorName != GSS_C_NO_NAME) {
4672 +        major = gssEapExportNameInternal(minor, ctx->initiatorName,
4673 +                                         &initiatorName,
4674 +                                         EXPORT_NAME_FLAG_COMPOSITE);
4675 +        if (GSS_ERROR(major))
4676 +            goto cleanup;
4677 +    }
4678 +
4679 +    if (ctx->acceptorName != GSS_C_NO_NAME) {
4680 +        major = gssEapExportNameInternal(minor, ctx->acceptorName,
4681 +                                         &acceptorName,
4682 +                                         EXPORT_NAME_FLAG_COMPOSITE);
4683 +        if (GSS_ERROR(major))
4684 +            goto cleanup;
4685 +    }
4686 +
4687 +#ifdef GSSEAP_ENABLE_ACCEPTOR
4688 +    /*
4689 +     * The partial context is only transmitted for unestablished acceptor
4690 +     * contexts.
4691 +     */
4692 +    if (!CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx) &&
4693 +        (ctx->flags & CTX_FLAG_KRB_REAUTH) == 0) {
4694 +        major = gssEapExportPartialContext(minor, ctx, &partialCtx);
4695 +        if (GSS_ERROR(major))
4696 +            goto cleanup;
4697 +    }
4698 +#endif
4699 +
4700 +    length  = 16;                               /* version, state, flags, */
4701 +    length += 4 + ctx->mechanismUsed->length;   /* mechanismUsed */
4702 +    length += 12 + key.length;                  /* rfc3961Key.value */
4703 +    length += 4 + initiatorName.length;         /* initiatorName.value */
4704 +    length += 4 + acceptorName.length;          /* acceptorName.value */
4705 +    length += 24 + sequenceSize(ctx->seqState); /* seqState */
4706 +
4707 +    if (partialCtx.value != NULL)
4708 +        length += 4 + partialCtx.length;        /* partialCtx.value */
4709 +
4710 +    token->value = GSSEAP_MALLOC(length);
4711 +    if (token->value == NULL) {
4712 +        major = GSS_S_FAILURE;
4713 +        *minor = ENOMEM;
4714 +        goto cleanup;
4715 +    }
4716 +    token->length = length;
4717 +
4718 +    p = (unsigned char *)token->value;
4719 +
4720 +    store_uint32_be(EAP_EXPORT_CONTEXT_V1, &p[0]);        /* version */
4721 +    store_uint32_be(GSSEAP_SM_STATE(ctx),  &p[4]);
4722 +    store_uint32_be(ctx->flags,            &p[8]);
4723 +    store_uint32_be(ctx->gssFlags,         &p[12]);
4724 +    p = store_oid(ctx->mechanismUsed,      &p[16]);
4725 +
4726 +    store_uint32_be(ctx->checksumType,     &p[0]);
4727 +    store_uint32_be(ctx->encryptionType,   &p[4]);
4728 +    p = store_buffer(&key,                 &p[8], FALSE);
4729 +
4730 +    p = store_buffer(&initiatorName,       p, FALSE);
4731 +    p = store_buffer(&acceptorName,        p, FALSE);
4732 +
4733 +    store_uint64_be(ctx->expiryTime,       &p[0]);
4734 +    store_uint64_be(ctx->sendSeq,          &p[8]);
4735 +    store_uint64_be(ctx->recvSeq,          &p[16]);
4736 +    p += 24;
4737 +
4738 +    major = sequenceExternalize(minor, ctx->seqState, &p, &length);
4739 +    if (GSS_ERROR(major))
4740 +        goto cleanup;
4741 +
4742 +    if (partialCtx.value != NULL)
4743 +        p = store_buffer(&partialCtx, p, FALSE);
4744 +
4745 +    GSSEAP_ASSERT(p == (unsigned char *)token->value + token->length);
4746 +
4747 +    major = GSS_S_COMPLETE;
4748 +    *minor = 0;
4749 +
4750 +cleanup:
4751 +    if (GSS_ERROR(major))
4752 +        gss_release_buffer(&tmpMinor, token);
4753 +    gss_release_buffer(&tmpMinor, &initiatorName);
4754 +    gss_release_buffer(&tmpMinor, &acceptorName);
4755 +    gss_release_buffer(&tmpMinor, &partialCtx);
4756 +
4757 +    return major;
4758 +}
4759 +
4760 +OM_uint32 GSSAPI_CALLCONV
4761 +gss_export_sec_context(OM_uint32 *minor,
4762 +                       gss_ctx_id_t *context_handle,
4763 +                       gss_buffer_t interprocess_token)
4764 +{
4765 +    OM_uint32 major, tmpMinor;
4766 +    gss_ctx_id_t ctx = *context_handle;
4767 +
4768 +    interprocess_token->length = 0;
4769 +    interprocess_token->value = NULL;
4770 +
4771 +    if (ctx == GSS_C_NO_CONTEXT) {
4772 +        *minor = EINVAL;
4773 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
4774 +    }
4775 +
4776 +    *minor = 0;
4777 +
4778 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
4779 +
4780 +    major = gssEapExportSecContext(minor, ctx, interprocess_token);
4781 +    if (GSS_ERROR(major)) {
4782 +        GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
4783 +        return major;
4784 +    }
4785 +
4786 +    *context_handle = GSS_C_NO_CONTEXT;
4787 +
4788 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
4789 +
4790 +    gssEapReleaseContext(&tmpMinor, &ctx);
4791 +
4792 +    return GSS_S_COMPLETE;
4793 +}
4794 diff --git a/mech_eap/get_mic.c b/mech_eap/get_mic.c
4795 new file mode 100644
4796 index 0000000..7161e9c
4797 --- /dev/null
4798 +++ b/mech_eap/get_mic.c
4799 @@ -0,0 +1,89 @@
4800 +/*
4801 + * Copyright (c) 2011, JANET(UK)
4802 + * All rights reserved.
4803 + *
4804 + * Redistribution and use in source and binary forms, with or without
4805 + * modification, are permitted provided that the following conditions
4806 + * are met:
4807 + *
4808 + * 1. Redistributions of source code must retain the above copyright
4809 + *    notice, this list of conditions and the following disclaimer.
4810 + *
4811 + * 2. Redistributions in binary form must reproduce the above copyright
4812 + *    notice, this list of conditions and the following disclaimer in the
4813 + *    documentation and/or other materials provided with the distribution.
4814 + *
4815 + * 3. Neither the name of JANET(UK) nor the names of its contributors
4816 + *    may be used to endorse or promote products derived from this software
4817 + *    without specific prior written permission.
4818 + *
4819 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
4820 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4821 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4822 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
4823 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4824 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4825 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4826 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4827 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4828 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4829 + * SUCH DAMAGE.
4830 + */
4831 +
4832 +/*
4833 + * Message protection services: make a message integerity check.
4834 + */
4835 +
4836 +#include "gssapiP_eap.h"
4837 +
4838 +OM_uint32 GSSAPI_CALLCONV
4839 +gss_get_mic(OM_uint32 *minor,
4840 +            gss_ctx_id_t ctx,
4841 +            gss_qop_t qop_req,
4842 +            gss_buffer_t message_buffer,
4843 +            gss_buffer_t message_token)
4844 +{
4845 +    OM_uint32 major;
4846 +    gss_iov_buffer_desc iov[2];
4847 +
4848 +    if (ctx == GSS_C_NO_CONTEXT) {
4849 +        *minor = EINVAL;
4850 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
4851 +    }
4852 +
4853 +    if (qop_req != GSS_C_QOP_DEFAULT) {
4854 +        *minor = GSSEAP_UNKNOWN_QOP;
4855 +        return GSS_S_UNAVAILABLE;
4856 +    }
4857 +
4858 +    *minor = 0;
4859 +
4860 +    message_token->value = NULL;
4861 +    message_token->length = 0;
4862 +
4863 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
4864 +
4865 +    if (!CTX_IS_ESTABLISHED(ctx)) {
4866 +        major = GSS_S_NO_CONTEXT;
4867 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
4868 +        goto cleanup;
4869 +    }
4870 +
4871 +    iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
4872 +    iov[0].buffer = *message_buffer;
4873 +
4874 +    iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
4875 +    iov[1].buffer.value = NULL;
4876 +    iov[1].buffer.length = 0;
4877 +
4878 +    major = gssEapWrapOrGetMIC(minor, ctx, FALSE, NULL, iov, 2, TOK_TYPE_MIC);
4879 +    if (GSS_ERROR(major))
4880 +        goto cleanup;
4881 +
4882 +    *message_token = iov[1].buffer;
4883 +
4884 +cleanup:
4885 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
4886 +
4887 +    return major;
4888 +}
4889 diff --git a/mech_eap/get_name_attribute.c b/mech_eap/get_name_attribute.c
4890 new file mode 100644
4891 index 0000000..a885823
4892 --- /dev/null
4893 +++ b/mech_eap/get_name_attribute.c
4894 @@ -0,0 +1,67 @@
4895 +/*
4896 + * Copyright (c) 2011, JANET(UK)
4897 + * All rights reserved.
4898 + *
4899 + * Redistribution and use in source and binary forms, with or without
4900 + * modification, are permitted provided that the following conditions
4901 + * are met:
4902 + *
4903 + * 1. Redistributions of source code must retain the above copyright
4904 + *    notice, this list of conditions and the following disclaimer.
4905 + *
4906 + * 2. Redistributions in binary form must reproduce the above copyright
4907 + *    notice, this list of conditions and the following disclaimer in the
4908 + *    documentation and/or other materials provided with the distribution.
4909 + *
4910 + * 3. Neither the name of JANET(UK) nor the names of its contributors
4911 + *    may be used to endorse or promote products derived from this software
4912 + *    without specific prior written permission.
4913 + *
4914 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
4915 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4916 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4917 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
4918 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4919 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4920 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4921 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4922 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4923 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4924 + * SUCH DAMAGE.
4925 + */
4926 +
4927 +#include "gssapiP_eap.h"
4928 +
4929 +/*
4930 + * Wrapper for retrieving a naming attribute.
4931 + */
4932 +
4933 +OM_uint32 GSSAPI_CALLCONV
4934 +gss_get_name_attribute(OM_uint32 *minor,
4935 +                       gss_name_t name,
4936 +                       gss_buffer_t attr,
4937 +                       int *authenticated,
4938 +                       int *complete,
4939 +                       gss_buffer_t value,
4940 +                       gss_buffer_t display_value,
4941 +                       int *more)
4942 +{
4943 +    OM_uint32 major;
4944 +
4945 +    *minor = 0;
4946 +
4947 +    if (name == GSS_C_NO_NAME) {
4948 +        *minor = EINVAL;
4949 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
4950 +    }
4951 +
4952 +    GSSEAP_MUTEX_LOCK(&name->mutex);
4953 +
4954 +    major = gssEapGetNameAttribute(minor, name, attr,
4955 +                                   authenticated, complete,
4956 +                                   value, display_value, more);
4957 +
4958 +    GSSEAP_MUTEX_UNLOCK(&name->mutex);
4959 +
4960 +    return major;
4961 +}
4962 diff --git a/mech_eap/gssapiP_eap.h b/mech_eap/gssapiP_eap.h
4963 new file mode 100644
4964 index 0000000..d1790a0
4965 --- /dev/null
4966 +++ b/mech_eap/gssapiP_eap.h
4967 @@ -0,0 +1,410 @@
4968 +/*
4969 + * Copyright (c) 2011, JANET(UK)
4970 + * All rights reserved.
4971 + *
4972 + * Redistribution and use in source and binary forms, with or without
4973 + * modification, are permitted provided that the following conditions
4974 + * are met:
4975 + *
4976 + * 1. Redistributions of source code must retain the above copyright
4977 + *    notice, this list of conditions and the following disclaimer.
4978 + *
4979 + * 2. Redistributions in binary form must reproduce the above copyright
4980 + *    notice, this list of conditions and the following disclaimer in the
4981 + *    documentation and/or other materials provided with the distribution.
4982 + *
4983 + * 3. Neither the name of JANET(UK) nor the names of its contributors
4984 + *    may be used to endorse or promote products derived from this software
4985 + *    without specific prior written permission.
4986 + *
4987 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
4988 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4989 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4990 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
4991 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4992 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4993 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4994 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4995 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4996 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4997 + * SUCH DAMAGE.
4998 + */
4999 +
5000 +#ifndef _GSSAPIP_EAP_H_
5001 +#define _GSSAPIP_EAP_H_ 1
5002 +
5003 +#include "config.h"
5004 +
5005 +#ifdef HAVE_HEIMDAL_VERSION
5006 +#define KRB5_DEPRECATED         /* so we can use krb5_free_unparsed_name() */
5007 +#endif
5008 +
5009 +#include <assert.h>
5010 +#include <string.h>
5011 +#include <errno.h>
5012 +#ifdef HAVE_UNISTD_H
5013 +#include <unistd.h>
5014 +#endif
5015 +#ifdef HAVE_STDLIB_H
5016 +#include <stdlib.h>
5017 +#endif
5018 +#ifdef HAVE_STDARG_H
5019 +#include <stdarg.h>
5020 +#endif
5021 +#include <time.h>
5022 +#ifdef HAVE_SYS_PARAM_H
5023 +#include <sys/param.h>
5024 +#endif
5025 +
5026 +#ifdef WIN32
5027 +#ifndef MAXHOSTNAMELEN
5028 +# include <WinSock2.h>
5029 +# define MAXHOSTNAMELEN NI_MAXHOST
5030 +#endif
5031 +#endif
5032 +
5033 +/* GSS headers */
5034 +#include <gssapi/gssapi.h>
5035 +#include <gssapi/gssapi_krb5.h>
5036 +#ifdef HAVE_HEIMDAL_VERSION
5037 +typedef struct gss_any *gss_any_t;
5038 +#else
5039 +#include <gssapi/gssapi_ext.h>
5040 +#endif
5041 +#include "gssapi_eap.h"
5042 +
5043 +#ifndef HAVE_GSS_INQUIRE_ATTRS_FOR_MECH
5044 +typedef const gss_OID_desc *gss_const_OID;
5045 +#endif
5046 +
5047 +/* Kerberos headers */
5048 +#include <krb5.h>
5049 +
5050 +/* EAP headers */
5051 +#include <includes.h>
5052 +#include <common.h>
5053 +#include <eap_peer/eap.h>
5054 +#include <eap_peer/eap_config.h>
5055 +#include <eap_peer/eap_methods.h>
5056 +#include <eap_common/eap_common.h>
5057 +#include <wpabuf.h>
5058 +
5059 +#ifdef GSSEAP_ENABLE_ACCEPTOR
5060 +/* FreeRADIUS headers */
5061 +#ifdef __cplusplus
5062 +extern "C" {
5063 +#ifndef WIN32
5064 +#define operator fr_operator
5065 +#endif
5066 +#endif
5067 +#include <freeradius/libradius.h>
5068 +#include <freeradius/radius.h>
5069 +
5070 +#undef pid_t
5071 +
5072 +/* libradsec headers */
5073 +#include <radsec/radsec.h>
5074 +#include <radsec/request.h>
5075 +#ifdef __cplusplus
5076 +#ifndef WIN32
5077 +#undef operator
5078 +#endif
5079 +}
5080 +#endif
5081 +#endif /* GSSEAP_ENABLE_ACCEPTOR */
5082 +
5083 +#include "gsseap_err.h"
5084 +#include "radsec_err.h"
5085 +#include "util.h"
5086 +
5087 +#ifdef __cplusplus
5088 +extern "C" {
5089 +#endif
5090 +
5091 +/* These name flags are informative and not actually used by anything yet */
5092 +#define NAME_FLAG_NAI                       0x00000001
5093 +#define NAME_FLAG_SERVICE                   0x00000002
5094 +#define NAME_FLAG_COMPOSITE                 0x00000004
5095 +
5096 +struct gss_eap_saml_attr_ctx;
5097 +struct gss_eap_attr_ctx;
5098 +
5099 +#ifdef HAVE_HEIMDAL_VERSION
5100 +struct gss_name_t_desc_struct
5101 +#else
5102 +struct gss_name_struct
5103 +#endif
5104 +{
5105 +    GSSEAP_MUTEX mutex; /* mutex protects attrCtx */
5106 +    OM_uint32 flags;
5107 +    gss_OID mechanismUsed; /* this is immutable */
5108 +    krb5_principal krbPrincipal; /* this is immutable */
5109 +#ifdef GSSEAP_ENABLE_ACCEPTOR
5110 +    struct gss_eap_attr_ctx *attrCtx;
5111 +#endif
5112 +};
5113 +
5114 +#define CRED_FLAG_INITIATE                  0x00010000
5115 +#define CRED_FLAG_ACCEPT                    0x00020000
5116 +#define CRED_FLAG_PASSWORD                  0x00040000
5117 +#define CRED_FLAG_DEFAULT_CCACHE            0x00080000
5118 +#define CRED_FLAG_RESOLVED                  0x00100000
5119 +#define CRED_FLAG_TARGET                    0x00200000
5120 +#define CRED_FLAG_PUBLIC_MASK               0x0000FFFF
5121 +
5122 +#ifdef HAVE_HEIMDAL_VERSION
5123 +struct gss_cred_id_t_desc_struct
5124 +#else
5125 +struct gss_cred_id_struct
5126 +#endif
5127 +{
5128 +    GSSEAP_MUTEX mutex;
5129 +    OM_uint32 flags;
5130 +    gss_name_t name;
5131 +    gss_name_t target; /* for initiator */
5132 +    gss_buffer_desc password;
5133 +    gss_OID_set mechanisms;
5134 +    time_t expiryTime;
5135 +    gss_buffer_desc radiusConfigFile;
5136 +    gss_buffer_desc radiusConfigStanza;
5137 +    gss_buffer_desc caCertificate;
5138 +    gss_buffer_desc subjectNameConstraint;
5139 +    gss_buffer_desc subjectAltNameConstraint;
5140 +#ifdef GSSEAP_ENABLE_REAUTH
5141 +    krb5_ccache krbCredCache;
5142 +    gss_cred_id_t reauthCred;
5143 +#endif
5144 +};
5145 +
5146 +#define CTX_FLAG_INITIATOR                  0x00000001
5147 +#define CTX_FLAG_KRB_REAUTH                 0x00000002
5148 +
5149 +#define CTX_IS_INITIATOR(ctx)               (((ctx)->flags & CTX_FLAG_INITIATOR) != 0)
5150 +
5151 +#define CTX_IS_ESTABLISHED(ctx)             ((ctx)->state == GSSEAP_STATE_ESTABLISHED)
5152 +
5153 +/* Initiator context flags */
5154 +#define CTX_FLAG_EAP_SUCCESS                0x00010000
5155 +#define CTX_FLAG_EAP_RESTART                0x00020000
5156 +#define CTX_FLAG_EAP_FAIL                   0x00040000
5157 +#define CTX_FLAG_EAP_RESP                   0x00080000
5158 +#define CTX_FLAG_EAP_NO_RESP                0x00100000
5159 +#define CTX_FLAG_EAP_REQ                    0x00200000
5160 +#define CTX_FLAG_EAP_PORT_ENABLED           0x00400000
5161 +#define CTX_FLAG_EAP_ALT_ACCEPT             0x00800000
5162 +#define CTX_FLAG_EAP_ALT_REJECT             0x01000000
5163 +#define CTX_FLAG_EAP_MASK                   0xFFFF0000
5164 +
5165 +struct gss_eap_initiator_ctx {
5166 +    unsigned int idleWhile;
5167 +    struct eap_peer_config eapPeerConfig;
5168 +    struct eap_sm *eap;
5169 +    struct wpabuf reqData;
5170 +};
5171 +
5172 +#ifdef GSSEAP_ENABLE_ACCEPTOR
5173 +struct gss_eap_acceptor_ctx {
5174 +    struct rs_context *radContext;
5175 +    struct rs_connection *radConn;
5176 +    char *radServer;
5177 +    gss_buffer_desc state;
5178 +    VALUE_PAIR *vps;
5179 +};
5180 +#endif
5181 +
5182 +#ifdef HAVE_HEIMDAL_VERSION
5183 +struct gss_ctx_id_t_desc_struct
5184 +#else
5185 +struct gss_ctx_id_struct
5186 +#endif
5187 +{
5188 +    GSSEAP_MUTEX mutex;
5189 +    enum gss_eap_state state;
5190 +    OM_uint32 flags;
5191 +    OM_uint32 gssFlags;
5192 +    gss_OID mechanismUsed;
5193 +    krb5_cksumtype checksumType;
5194 +    krb5_enctype encryptionType;
5195 +    krb5_keyblock rfc3961Key;
5196 +    gss_name_t initiatorName;
5197 +    gss_name_t acceptorName;
5198 +    time_t expiryTime;
5199 +    uint64_t sendSeq, recvSeq;
5200 +    void *seqState;
5201 +    gss_cred_id_t cred;
5202 +    union {
5203 +        struct gss_eap_initiator_ctx initiator;
5204 +        #define initiatorCtx         ctxU.initiator
5205 +#ifdef GSSEAP_ENABLE_ACCEPTOR
5206 +        struct gss_eap_acceptor_ctx  acceptor;
5207 +        #define acceptorCtx          ctxU.acceptor
5208 +#endif
5209 +#ifdef GSSEAP_ENABLE_REAUTH
5210 +        gss_ctx_id_t                 reauth;
5211 +        #define reauthCtx            ctxU.reauth
5212 +#endif
5213 +    } ctxU;
5214 +    const struct gss_eap_token_buffer_set *inputTokens;
5215 +    const struct gss_eap_token_buffer_set *outputTokens;
5216 +};
5217 +
5218 +#define TOK_FLAG_SENDER_IS_ACCEPTOR         0x01
5219 +#define TOK_FLAG_WRAP_CONFIDENTIAL          0x02
5220 +#define TOK_FLAG_ACCEPTOR_SUBKEY            0x04
5221 +
5222 +#define KEY_USAGE_ACCEPTOR_SEAL             22
5223 +#define KEY_USAGE_ACCEPTOR_SIGN             23
5224 +#define KEY_USAGE_INITIATOR_SEAL            24
5225 +#define KEY_USAGE_INITIATOR_SIGN            25
5226 +
5227 +/* accept_sec_context.c */
5228 +OM_uint32
5229 +gssEapAcceptSecContext(OM_uint32 *minor,
5230 +                       gss_ctx_id_t ctx,
5231 +                       gss_cred_id_t cred,
5232 +                       gss_buffer_t input_token,
5233 +                       gss_channel_bindings_t input_chan_bindings,
5234 +                       gss_name_t *src_name,
5235 +                       gss_OID *mech_type,
5236 +                       gss_buffer_t output_token,
5237 +                       OM_uint32 *ret_flags,
5238 +                       OM_uint32 *time_rec,
5239 +                       gss_cred_id_t *delegated_cred_handle);
5240 +
5241 +/* init_sec_context.c */
5242 +OM_uint32
5243 +gssEapInitSecContext(OM_uint32 *minor,
5244 +                     gss_cred_id_t cred,
5245 +                     gss_ctx_id_t ctx,
5246 +                     gss_name_t target_name,
5247 +                     gss_OID mech_type,
5248 +                     OM_uint32 req_flags,
5249 +                     OM_uint32 time_req,
5250 +                     gss_channel_bindings_t input_chan_bindings,
5251 +                     gss_buffer_t input_token,
5252 +                     gss_OID *actual_mech_type,
5253 +                     gss_buffer_t output_token,
5254 +                     OM_uint32 *ret_flags,
5255 +                     OM_uint32 *time_rec);
5256 +
5257 +/* wrap_iov.c */
5258 +OM_uint32
5259 +gssEapWrapOrGetMIC(OM_uint32 *minor,
5260 +                   gss_ctx_id_t ctx,
5261 +                   int conf_req_flag,
5262 +                   int *conf_state,
5263 +                   gss_iov_buffer_desc *iov,
5264 +                   int iov_count,
5265 +                   enum gss_eap_token_type toktype);
5266 +
5267 +OM_uint32
5268 +gssEapUnwrapOrVerifyMIC(OM_uint32 *minor_status,
5269 +                        gss_ctx_id_t ctx,
5270 +                        int *conf_state,
5271 +                        gss_qop_t *qop_state,
5272 +                        gss_iov_buffer_desc *iov,
5273 +                        int iov_count,
5274 +                        enum gss_eap_token_type toktype);
5275 +
5276 +OM_uint32
5277 +gssEapWrapIovLength(OM_uint32 *minor,
5278 +                    gss_ctx_id_t ctx,
5279 +                    int conf_req_flag,
5280 +                    gss_qop_t qop_req,
5281 +                    int *conf_state,
5282 +                    gss_iov_buffer_desc *iov,
5283 +                    int iov_count);
5284 +OM_uint32
5285 +gssEapWrap(OM_uint32 *minor,
5286 +           gss_ctx_id_t ctx,
5287 +           int conf_req_flag,
5288 +           gss_qop_t qop_req,
5289 +           gss_buffer_t input_message_buffer,
5290 +           int *conf_state,
5291 +           gss_buffer_t output_message_buffer);
5292 +
5293 +unsigned char
5294 +rfc4121Flags(gss_ctx_id_t ctx, int receiving);
5295 +
5296 +/* display_status.c */
5297 +void
5298 +gssEapSaveStatusInfo(OM_uint32 minor, const char *format, ...);
5299 +
5300 +OM_uint32
5301 +gssEapDisplayStatus(OM_uint32 *minor,
5302 +                    OM_uint32 status_value,
5303 +                    gss_buffer_t status_string);
5304 +
5305 +#define IS_WIRE_ERROR(err)              ((err) > GSSEAP_RESERVED && \
5306 +                                         (err) <= GSSEAP_RADIUS_PROT_FAILURE)
5307 +
5308 +/* upper bound of RADIUS error range must be kept in sync with radsec.h */
5309 +#define IS_RADIUS_ERROR(err)            ((err) >= ERROR_TABLE_BASE_rse && \
5310 +                                         (err) <= ERROR_TABLE_BASE_rse + 20)
5311 +
5312 +/* exchange_meta_data.c */
5313 +OM_uint32 GSSAPI_CALLCONV
5314 +gssEapExchangeMetaData(OM_uint32 *minor,
5315 +                       gss_const_OID mech,
5316 +                       gss_cred_id_t cred,
5317 +                       gss_ctx_id_t *ctx,
5318 +                       const gss_name_t name,
5319 +                       OM_uint32 req_flags,
5320 +                       gss_const_buffer_t meta_data);
5321 +
5322 +/* export_sec_context.c */
5323 +OM_uint32
5324 +gssEapExportSecContext(OM_uint32 *minor,
5325 +                       gss_ctx_id_t ctx,
5326 +                       gss_buffer_t token);
5327 +
5328 +/* import_sec_context.c */
5329 +OM_uint32
5330 +gssEapImportContext(OM_uint32 *minor,
5331 +                    gss_buffer_t token,
5332 +                    gss_ctx_id_t ctx);
5333 +
5334 +/* inquire_sec_context_by_oid.c */
5335 +#define NEGOEX_INITIATOR_SALT      "gss-eap-negoex-initiator"
5336 +#define NEGOEX_INITIATOR_SALT_LEN  (sizeof(NEGOEX_INITIATOR_SALT) - 1)
5337 +
5338 +#define NEGOEX_ACCEPTOR_SALT       "gss-eap-negoex-acceptor"
5339 +#define NEGOEX_ACCEPTOR_SALT_LEN   (sizeof(NEGOEX_ACCEPTOR_SALT) - 1)
5340 +
5341 +/* pseudo_random.c */
5342 +OM_uint32
5343 +gssEapPseudoRandom(OM_uint32 *minor,
5344 +                   gss_ctx_id_t ctx,
5345 +                   int prf_key,
5346 +                   const gss_buffer_t prf_in,
5347 +                   ssize_t desired_output_len,
5348 +                   gss_buffer_t prf_out);
5349 +
5350 +/* query_mechanism_info.c */
5351 +OM_uint32
5352 +gssQueryMechanismInfo(OM_uint32 *minor,
5353 +                      gss_const_OID mech_oid,
5354 +                      unsigned char auth_scheme[16]);
5355 +
5356 +/* query_meta_data.c */
5357 +OM_uint32
5358 +gssEapQueryMetaData(OM_uint32 *minor,
5359 +                    gss_const_OID mech GSSEAP_UNUSED,
5360 +                    gss_cred_id_t cred,
5361 +                    gss_ctx_id_t *context_handle,
5362 +                    const gss_name_t name,
5363 +                    OM_uint32 req_flags GSSEAP_UNUSED,
5364 +                    gss_buffer_t meta_data);
5365 +
5366 +/* eap_mech.c */
5367 +OM_uint32
5368 +gssEapInitiatorInit(OM_uint32 *minor);
5369 +
5370 +void
5371 +gssEapFinalize(void);
5372 +
5373 +#ifdef __cplusplus
5374 +}
5375 +#endif
5376 +
5377 +#endif /* _GSSAPIP_EAP_H_ */
5378 diff --git a/mech_eap/gssapi_eap.h b/mech_eap/gssapi_eap.h
5379 new file mode 100644
5380 index 0000000..588665b
5381 --- /dev/null
5382 +++ b/mech_eap/gssapi_eap.h
5383 @@ -0,0 +1,90 @@
5384 +/*
5385 + * Copyright (c) 2011, JANET(UK)
5386 + * All rights reserved.
5387 + *
5388 + * Redistribution and use in source and binary forms, with or without
5389 + * modification, are permitted provided that the following conditions
5390 + * are met:
5391 + *
5392 + * 1. Redistributions of source code must retain the above copyright
5393 + *    notice, this list of conditions and the following disclaimer.
5394 + *
5395 + * 2. Redistributions in binary form must reproduce the above copyright
5396 + *    notice, this list of conditions and the following disclaimer in the
5397 + *    documentation and/or other materials provided with the distribution.
5398 + *
5399 + * 3. Neither the name of JANET(UK) nor the names of its contributors
5400 + *    may be used to endorse or promote products derived from this software
5401 + *    without specific prior written permission.
5402 + *
5403 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
5404 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5405 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5406 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
5407 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5408 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5409 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5410 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5411 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5412 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5413 + * SUCH DAMAGE.
5414 + */
5415 +
5416 +#ifndef _GSSAPI_EAP_H_
5417 +#define _GSSAPI_EAP_H_ 1
5418 +
5419 +#include <gssapi/gssapi.h>
5420 +
5421 +#ifdef __cplusplus
5422 +extern "C" {
5423 +#endif /* __cplusplus */
5424 +
5425 +/*
5426 + * GSS EAP mechanism OIDs.
5427 + */
5428 +extern gss_OID GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM;
5429 +extern gss_OID GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM;
5430 +
5431 +/*
5432 + * Mechanism name OID.
5433 + */
5434 +extern gss_OID GSS_EAP_NT_EAP_NAME;
5435 +
5436 +/*
5437 + * The libradsec configuration file; defaults to radsec.conf
5438 + * in the system configuration directory if unspecified.
5439 + */
5440 +extern gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE;
5441 +
5442 +/*
5443 + * The stanza in the libradsec configuration file; defaults
5444 + * to "gss-eap" if unspecified.
5445 + */
5446 +extern gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_STANZA;
5447 +
5448 +/*
5449 + * Flags as a 32-bit integer in network byte order,
5450 + * followed by a boolean octet indicating whether to
5451 + * clear the specified flags (if absent, defaults to
5452 + * FALSE, ie. set flags).
5453 + */
5454 +extern gss_OID GSS_EAP_CRED_SET_CRED_FLAG;
5455 +
5456 +/*
5457 + * Password; for mechanism glues that do not support
5458 + * gss_acquire_cred_with_password(), this can be set
5459 + * on an existing credentials handle.
5460 + */
5461 +extern gss_OID GSS_EAP_CRED_SET_CRED_PASSWORD;
5462 +
5463 +/*
5464 + * Credentials flag indicating the local attributes
5465 + * processing should be skipped.
5466 + */
5467 +#define GSS_EAP_DISABLE_LOCAL_ATTRS_FLAG    0x00000001
5468 +
5469 +#ifdef __cplusplus
5470 +}
5471 +#endif /* __cplusplus */
5472 +
5473 +#endif /* _GSSAPI_EAP_H_ */
5474 diff --git a/mech_eap/gsseap_err.et b/mech_eap/gsseap_err.et
5475 new file mode 100644
5476 index 0000000..d60c2c7
5477 --- /dev/null
5478 +++ b/mech_eap/gsseap_err.et
5479 @@ -0,0 +1,162 @@
5480 +#
5481 +# Copyright (c) 2011, JANET(UK)
5482 +#  All rights reserved.
5483 +# 
5484 +#  Redistribution and use in source and binary forms, with or without
5485 +#  modification, are permitted provided that the following conditions
5486 +#  are met:
5487 +# 
5488 +#  1. Redistributions of source code must retain the above copyright
5489 +#     notice, this list of conditions and the following disclaimer.
5490 +# 
5491 +#  2. Redistributions in binary form must reproduce the above copyright
5492 +#     notice, this list of conditions and the following disclaimer in the
5493 +#     documentation and/or other materials provided with the distribution.
5494 +# 
5495 +#  3. Neither the name of JANET(UK) nor the names of its contributors
5496 +#     may be used to endorse or promote products derived from this software
5497 +#     without specific prior written permission.
5498 +# 
5499 +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
5500 +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5501 +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5502 +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
5503 +#  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5504 +#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5505 +#  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5506 +#  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5507 +#  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5508 +#  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5509 +#  SUCH DAMAGE.
5510 +#
5511 +
5512 +error_table eapg
5513 +
5514 +#
5515 +# Protocol errors that can be returned in an error token. This should match
5516 +# up with makeErrorToken in accept_sec_context.c.
5517 +#
5518 +error_code GSSEAP_RESERVED,                     ""
5519 +error_code GSSEAP_WRONG_SIZE,                   "Buffer is incorrect size"
5520 +error_code GSSEAP_WRONG_MECH,                   "Mechanism OID is incorrect"
5521 +error_code GSSEAP_BAD_TOK_HEADER,               "Token header is malformed or corrupt"
5522 +error_code GSSEAP_TOK_TRUNC,                    "Token is missing data"
5523 +error_code GSSEAP_BAD_DIRECTION,                "Packet was replayed in wrong direction"
5524 +error_code GSSEAP_WRONG_TOK_ID,                 "Received token ID does not match expected token ID"
5525 +error_code GSSEAP_CRIT_ITOK_UNAVAILABLE,        "Critical inner token type unavailable"
5526 +error_code GSSEAP_MISSING_REQUIRED_ITOK,        "Missing required inner token"
5527 +error_code GSSEAP_DUPLICATE_ITOK,               "Duplicate inner token received"
5528 +error_code GSSEAP_WRONG_ITOK,                   "Recieved invalid inner token for current state"
5529 +error_code GSSEAP_KEY_UNAVAILABLE,              "EAP key unavailable"
5530 +error_code GSSEAP_KEY_TOO_SHORT,                "EAP key too short"
5531 +error_code GSSEAP_RADIUS_AUTH_FAILURE,          "Authentication rejected by RADIUS server"
5532 +error_code GSSEAP_UNKNOWN_RADIUS_CODE,          "Received unknown response code from RADIUS server"
5533 +error_code GSSEAP_MISSING_EAP_REQUEST,          "RADIUS response is missing EAP request"
5534 +error_code GSSEAP_RADIUS_PROT_FAILURE,          "Generic RADIUS failure"
5535 +
5536 +#
5537 +# Context errors
5538 +#
5539 +error_code GSSEAP_CONTEXT_ESTABLISHED,          "Context is already fully established"
5540 +error_code GSSEAP_CONTEXT_INCOMPLETE,           "Attempt to use incomplete security context"
5541 +error_code GSSEAP_BAD_CONTEXT_TOKEN,            "Context token is malformed or corrupt"
5542 +error_code GSSEAP_BAD_ERROR_TOKEN,              "Error token is malformed or corrupt"
5543 +error_code GSSEAP_BAD_CONTEXT_OPTION,           "Bad context option"
5544 +
5545 +#
5546 +# Name errors
5547 +#
5548 +error_code GSSEAP_BAD_SERVICE_NAME,             "Name is not a valid service name"
5549 +error_code GSSEAP_BAD_INITIATOR_NAME,           "Initiator identity must be a valid name"
5550 +error_code GSSEAP_NO_HOSTNAME,                  "Could not determine local host name"
5551 +error_code GSSEAP_NO_ACCEPTOR_NAME,             "Could not determine acceptor identity"
5552 +error_code GSSEAP_BAD_NAME_TOKEN,               "Name token is malformed or corrupt"
5553 +error_code GSSEAP_NO_LOCAL_MAPPING,             "Unable to map name to a local identity"
5554 +
5555 +#
5556 +# Credential errors
5557 +#
5558 +error_code GSSEAP_BAD_USAGE,                    "Credential usage type is unknown"
5559 +error_code GSSEAP_CRED_USAGE_MISMATCH,          "Credential usage does not match requested usage"
5560 +error_code GSSEAP_CRED_MECH_MISMATCH,           "Credential is not usable with this mechanism"
5561 +error_code GSSEAP_CRED_EXPIRED,                 "Attributes indicate credentials have expired"
5562 +error_code GSSEAP_BAD_CRED_OPTION,              "Bad credential option"
5563 +error_code GSSEAP_NO_DEFAULT_IDENTITY,          "Default credentials identity unavailable"
5564 +error_code GSSEAP_NO_DEFAULT_CRED,              "Missing default password or other credentials"
5565 +error_code GSSEAP_CRED_RESOLVED,                "Credential is already fully resolved"
5566 +
5567 +#
5568 +# Local identity service errors
5569 +#
5570 +error_code GSSEAP_UNABLE_TO_START_IDENTITY_SERVICE,     "Unable to start identity service"
5571 +error_code GSSEAP_NO_IDENTITY_SELECTED,                 "No identity selected"
5572 +error_code GSSEAP_IDENTITY_SERVICE_INSTALL_ERROR,       "Identity service installation error"
5573 +error_code GSSEAP_IDENTITY_SERVICE_OS_ERROR,            "Identity service OS error"
5574 +error_code GSSEAP_IDENTITY_SERVICE_IPC_ERROR,           "Identity service IPC error"
5575 +error_code GSSEAP_IDENTITY_SERVICE_UNKNOWN_ERROR,       "Unknown identity service error"
5576 +
5577 +#
5578 +# Wrap/unwrap/PRF errors
5579 +#
5580 +error_code GSSEAP_BAD_WRAP_TOKEN,               "Bad RFC 4121 wrap or MIC token"
5581 +error_code GSSEAP_MISSING_IOV,                  "IOV is missing required buffer"
5582 +error_code GSSEAP_BAD_STREAM_IOV,               "Stream IOV can only contain a single data buffer"
5583 +error_code GSSEAP_BAD_PADDING_IOV,              "Padding IOV is not permitted for RFC 4121 tokens"
5584 +error_code GSSEAP_UNKNOWN_QOP,                  "Unknown quality of protection specified"
5585 +error_code GSSEAP_INPUT_TOO_LONG,               "PRF input too long"
5586 +error_code GSSEAP_BAD_PRF_KEY,                  "PRF key usage type is unknown"
5587 +
5588 +#
5589 +# libeap errors
5590 +#
5591 +error_code GSSEAP_LIBEAP_INIT_FAILURE,          "Failed to initialize EAP library"
5592 +error_code GSSEAP_PEER_SM_INIT_FAILURE,         "Failed to create EAP state machine"
5593 +error_code GSSEAP_PEER_SM_STEP_FAILURE,         "Failed to step EAP state machine"
5594 +error_code GSSEAP_PEER_AUTH_FAILURE,            "EAP peer authentication failure"
5595 +error_code GSSEAP_PEER_BAD_MESSAGE,             "Received bad EAP message"
5596 +
5597 +#
5598 +# RadSec initialisation errors
5599 +#
5600 +error_code GSSEAP_RADSEC_INIT_FAILURE,          "Failed to initialize RadSec library"
5601 +error_code GSSEAP_RADSEC_CONTEXT_FAILURE,       "Failed to create RadSec context"
5602 +
5603 +#
5604 +# Attribute errors
5605 +#
5606 +error_code GSSEAP_NO_ATTR_CONTEXT,              "Name has no attributes"
5607 +error_code GSSEAP_NO_ATTR_PROVIDERS,            "Failed to initialize attribute providers"
5608 +error_code GSSEAP_NO_SUCH_ATTR,                 "Unknown naming attribute"
5609 +error_code GSSEAP_BAD_ATTR_TOKEN,               "Serialised attributes are malformed or corrupt"
5610 +error_code GSSEAP_ATTR_CONTEXT_FAILURE,         "Failed to initialize attribute context"
5611 +
5612 +#
5613 +# OpenSAML errors
5614 +#
5615 +error_code GSSEAP_SAML_INIT_FAILURE,            "Failed to initialize SAML library"
5616 +error_code GSSEAP_SAML_SEC_POLICY_FAILURE,      "Failed to process SAML security policy"
5617 +error_code GSSEAP_SAML_BINDING_FAILURE,         "Failed in SAML binding processing"
5618 +error_code GSSEAP_SAML_PROFILE_FAILURE,         "Failed to process SAML profile"
5619 +error_code GSSEAP_SAML_FATAL_PROFILE_FAILURE,   "Non-recoverable failure in SAML profile processing"
5620 +error_code GSSEAP_SAML_RETRY_PROFILE_FAILURE,   "Temporary failure in SAML profile processing"
5621 +error_code GSSEAP_SAML_METADATA_FAILURE,        "Failure related to SAML metadata use"
5622 +
5623 +#
5624 +# Shibboleth errors
5625 +#
5626 +error_code GSSEAP_SHIB_INIT_FAILURE,            "Failed to initialize Shibboleth"
5627 +error_code GSSEAP_SHIB_ATTR_FAILURE,            "Failure during local attribute processing"
5628 +error_code GSSEAP_SHIB_ATTR_EXTRACT_FAILURE,    "Failed to extract local attributes"
5629 +error_code GSSEAP_SHIB_ATTR_FILTER_FAILURE,     "Failed to filter local attributes"
5630 +error_code GSSEAP_SHIB_ATTR_RESOLVE_FAILURE,    "Failed to resolve local attributes"
5631 +error_code GSSEAP_SHIB_CONFIG_FAILURE,          "Local attribute configuration failure"
5632 +error_code GSSEAP_SHIB_LISTENER_FAILURE,        "Failed to communicate with local attribute server"
5633 +
5634 +#
5635 +# Extensions
5636 +#
5637 +error_code GSSEAP_BINDINGS_MISMATCH,            "Channel bindings do not match"
5638 +error_code GSSEAP_NO_MECHGLUE_SYMBOL,           "Could not find symbol in mechanism glue"
5639 +error_code GSSEAP_BAD_INVOCATION,               "Bad mechanism invoke OID"
5640 +
5641 +end
5642 diff --git a/mech_eap/import_name.c b/mech_eap/import_name.c
5643 new file mode 100644
5644 index 0000000..8049e01
5645 --- /dev/null
5646 +++ b/mech_eap/import_name.c
5647 @@ -0,0 +1,47 @@
5648 +/*
5649 + * Copyright (c) 2011, JANET(UK)
5650 + * All rights reserved.
5651 + *
5652 + * Redistribution and use in source and binary forms, with or without
5653 + * modification, are permitted provided that the following conditions
5654 + * are met:
5655 + *
5656 + * 1. Redistributions of source code must retain the above copyright
5657 + *    notice, this list of conditions and the following disclaimer.
5658 + *
5659 + * 2. Redistributions in binary form must reproduce the above copyright
5660 + *    notice, this list of conditions and the following disclaimer in the
5661 + *    documentation and/or other materials provided with the distribution.
5662 + *
5663 + * 3. Neither the name of JANET(UK) nor the names of its contributors
5664 + *    may be used to endorse or promote products derived from this software
5665 + *    without specific prior written permission.
5666 + *
5667 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
5668 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5669 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5670 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
5671 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5672 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5673 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5674 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5675 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5676 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5677 + * SUCH DAMAGE.
5678 + */
5679 +
5680 +/*
5681 + * Deserialise a name.
5682 + */
5683 +
5684 +#include "gssapiP_eap.h"
5685 +
5686 +OM_uint32 GSSAPI_CALLCONV
5687 +gss_import_name(OM_uint32 *minor,
5688 +                gss_buffer_t import_name_buffer,
5689 +                gss_OID input_name_type,
5690 +                gss_name_t *output_name)
5691 +{
5692 +    return gssEapImportName(minor, import_name_buffer,
5693 +                            input_name_type, GSS_C_NO_OID, output_name);
5694 +}
5695 diff --git a/mech_eap/import_sec_context.c b/mech_eap/import_sec_context.c
5696 new file mode 100644
5697 index 0000000..1533a16
5698 --- /dev/null
5699 +++ b/mech_eap/import_sec_context.c
5700 @@ -0,0 +1,374 @@
5701 +/*
5702 + * Copyright (c) 2011, JANET(UK)
5703 + * All rights reserved.
5704 + *
5705 + * Redistribution and use in source and binary forms, with or without
5706 + * modification, are permitted provided that the following conditions
5707 + * are met:
5708 + *
5709 + * 1. Redistributions of source code must retain the above copyright
5710 + *    notice, this list of conditions and the following disclaimer.
5711 + *
5712 + * 2. Redistributions in binary form must reproduce the above copyright
5713 + *    notice, this list of conditions and the following disclaimer in the
5714 + *    documentation and/or other materials provided with the distribution.
5715 + *
5716 + * 3. Neither the name of JANET(UK) nor the names of its contributors
5717 + *    may be used to endorse or promote products derived from this software
5718 + *    without specific prior written permission.
5719 + *
5720 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
5721 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5722 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5723 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
5724 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5725 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5726 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5727 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5728 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5729 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5730 + * SUCH DAMAGE.
5731 + */
5732 +
5733 +/*
5734 + * Deserialise a context handle.
5735 + */
5736 +
5737 +#include "gssapiP_eap.h"
5738 +
5739 +#define UPDATE_REMAIN(n)    do {                \
5740 +        p += (n);                               \
5741 +        remain -= (n);                          \
5742 +    } while (0)
5743 +
5744 +#define CHECK_REMAIN(n)     do {                \
5745 +        if (remain < (n)) {                     \
5746 +            *minor = GSSEAP_TOK_TRUNC;          \
5747 +            return GSS_S_DEFECTIVE_TOKEN;       \
5748 +        }                                       \
5749 +    } while (0)
5750 +
5751 +#ifdef GSSEAP_ENABLE_ACCEPTOR
5752 +static OM_uint32
5753 +gssEapImportPartialContext(OM_uint32 *minor,
5754 +                           unsigned char **pBuf,
5755 +                           size_t *pRemain,
5756 +                           gss_ctx_id_t ctx)
5757 +{
5758 +    OM_uint32 major;
5759 +    unsigned char *p = *pBuf;
5760 +    size_t remain = *pRemain;
5761 +    gss_buffer_desc buf;
5762 +    size_t ctxLength, serverLen;
5763 +
5764 +    /* Length of partial RADIUS context */
5765 +    CHECK_REMAIN(4);
5766 +    ctxLength = load_uint32_be(p);
5767 +    UPDATE_REMAIN(4);
5768 +
5769 +    CHECK_REMAIN(ctxLength);
5770 +    remain = ctxLength; /* check against partial context length */
5771 +
5772 +    /* Selected RADIUS server */
5773 +    CHECK_REMAIN(4);
5774 +    serverLen = load_uint32_be(p);
5775 +    UPDATE_REMAIN(4);
5776 +
5777 +    if (serverLen != 0) {
5778 +        CHECK_REMAIN(serverLen);
5779 +
5780 +        ctx->acceptorCtx.radServer = GSSEAP_MALLOC(serverLen + 1);
5781 +        if (ctx->acceptorCtx.radServer == NULL) {
5782 +            *minor = ENOMEM;
5783 +            return GSS_S_FAILURE;
5784 +        }
5785 +        memcpy(ctx->acceptorCtx.radServer, p, serverLen);
5786 +        ctx->acceptorCtx.radServer[serverLen] = '\0';
5787 +
5788 +        UPDATE_REMAIN(serverLen);
5789 +    }
5790 +
5791 +    /* RADIUS state blob */
5792 +    CHECK_REMAIN(4);
5793 +    buf.length = load_uint32_be(p);
5794 +    UPDATE_REMAIN(4);
5795 +
5796 +    if (buf.length != 0) {
5797 +        CHECK_REMAIN(buf.length);
5798 +
5799 +        buf.value = p;
5800 +
5801 +        major = duplicateBuffer(minor, &buf, &ctx->acceptorCtx.state);
5802 +        if (GSS_ERROR(major))
5803 +            return major;
5804 +
5805 +        UPDATE_REMAIN(buf.length);
5806 +    }
5807 +
5808 +#ifdef GSSEAP_DEBUG
5809 +    GSSEAP_ASSERT(remain == 0);
5810 +#endif
5811 +
5812 +    *pBuf = p;
5813 +    *pRemain -= 4 + ctxLength;
5814 +
5815 +    return GSS_S_COMPLETE;
5816 +}
5817 +#endif /* GSSEAP_ENABLE_ACCEPTOR */
5818 +
5819 +static OM_uint32
5820 +importMechanismOid(OM_uint32 *minor,
5821 +                   unsigned char **pBuf,
5822 +                   size_t *pRemain,
5823 +                   gss_OID *pOid)
5824 +{
5825 +    OM_uint32 major;
5826 +    unsigned char *p = *pBuf;
5827 +    size_t remain = *pRemain;
5828 +    gss_OID_desc oidBuf;
5829 +
5830 +    oidBuf.length = load_uint32_be(p);
5831 +    if (remain < 4 + oidBuf.length || oidBuf.length == 0) {
5832 +        *minor = GSSEAP_TOK_TRUNC;
5833 +        return GSS_S_DEFECTIVE_TOKEN;
5834 +    }
5835 +
5836 +    oidBuf.elements = &p[4];
5837 +
5838 +    major = gssEapCanonicalizeOid(minor, &oidBuf, 0, pOid);
5839 +    if (GSS_ERROR(major))
5840 +        return major;
5841 +
5842 +    *pBuf    += 4 + oidBuf.length;
5843 +    *pRemain -= 4 + oidBuf.length;
5844 +
5845 +    *minor = 0;
5846 +    return GSS_S_COMPLETE;
5847 +}
5848 +
5849 +static OM_uint32
5850 +importKerberosKey(OM_uint32 *minor,
5851 +                  unsigned char **pBuf,
5852 +                  size_t *pRemain,
5853 +                  krb5_cksumtype *checksumType,
5854 +                  krb5_enctype *pEncryptionType,
5855 +                  krb5_keyblock *pKey)
5856 +{
5857 +    unsigned char *p = *pBuf;
5858 +    size_t remain = *pRemain;
5859 +    OM_uint32 encryptionType;
5860 +    OM_uint32 length;
5861 +    krb5_context krbContext;
5862 +    krb5_keyblock key;
5863 +    krb5_error_code code;
5864 +
5865 +    GSSEAP_KRB_INIT(&krbContext);
5866 +
5867 +    KRB_KEY_INIT(pKey);
5868 +
5869 +    if (remain < 12) {
5870 +        *minor = GSSEAP_TOK_TRUNC;
5871 +        return GSS_S_DEFECTIVE_TOKEN;
5872 +    }
5873 +
5874 +    *checksumType  = load_uint32_be(&p[0]);
5875 +    encryptionType = load_uint32_be(&p[4]);
5876 +    length         = load_uint32_be(&p[8]);
5877 +
5878 +    if ((length != 0) != (encryptionType != ENCTYPE_NULL)) {
5879 +        *minor = GSSEAP_BAD_CONTEXT_TOKEN;
5880 +        return GSS_S_DEFECTIVE_TOKEN;
5881 +    }
5882 +
5883 +    if (remain - 12 < length) {
5884 +        *minor = GSSEAP_TOK_TRUNC;
5885 +        return GSS_S_DEFECTIVE_TOKEN;
5886 +    }
5887 +
5888 +    if (encryptionType != ENCTYPE_NULL) {
5889 +        KRB_KEY_INIT(&key);
5890 +
5891 +        KRB_KEY_TYPE(&key)   = encryptionType;
5892 +        KRB_KEY_LENGTH(&key) = length;
5893 +        KRB_KEY_DATA(&key)   = &p[12];
5894 +
5895 +        code = krb5_copy_keyblock_contents(krbContext, &key, pKey);
5896 +        if (code != 0) {
5897 +            *minor = code;
5898 +            return GSS_S_FAILURE;
5899 +        }
5900 +    }
5901 +
5902 +    *pBuf    += 12 + length;
5903 +    *pRemain -= 12 + length;
5904 +    *pEncryptionType = encryptionType;
5905 +
5906 +    *minor = 0;
5907 +    return GSS_S_COMPLETE;
5908 +}
5909 +
5910 +static OM_uint32
5911 +importName(OM_uint32 *minor,
5912 +           unsigned char **pBuf,
5913 +           size_t *pRemain,
5914 +           gss_name_t *pName)
5915 +{
5916 +    OM_uint32 major;
5917 +    unsigned char *p = *pBuf;
5918 +    size_t remain = *pRemain;
5919 +    gss_buffer_desc tmp;
5920 +
5921 +    if (remain < 4) {
5922 +        *minor = GSSEAP_TOK_TRUNC;
5923 +        return GSS_S_DEFECTIVE_TOKEN;
5924 +    }
5925 +
5926 +    tmp.length = load_uint32_be(p);
5927 +    if (tmp.length != 0) {
5928 +        if (remain - 4 < tmp.length) {
5929 +            *minor = GSSEAP_TOK_TRUNC;
5930 +            return GSS_S_DEFECTIVE_TOKEN;
5931 +        }
5932 +
5933 +        tmp.value = p + 4;
5934 +
5935 +        major = gssEapImportNameInternal(minor, &tmp, pName,
5936 +                                         EXPORT_NAME_FLAG_COMPOSITE);
5937 +        if (GSS_ERROR(major))
5938 +            return major;
5939 +    }
5940 +
5941 +    *pBuf    += 4 + tmp.length;
5942 +    *pRemain -= 4 + tmp.length;
5943 +
5944 +    *minor = 0;
5945 +    return GSS_S_COMPLETE;
5946 +}
5947 +
5948 +OM_uint32
5949 +gssEapImportContext(OM_uint32 *minor,
5950 +                    gss_buffer_t token,
5951 +                    gss_ctx_id_t ctx)
5952 +{
5953 +    OM_uint32 major;
5954 +    unsigned char *p = (unsigned char *)token->value;
5955 +    size_t remain = token->length;
5956 +
5957 +    if (remain < 16) {
5958 +        *minor = GSSEAP_TOK_TRUNC;
5959 +        return GSS_S_DEFECTIVE_TOKEN;
5960 +    }
5961 +    if (load_uint32_be(&p[0]) != EAP_EXPORT_CONTEXT_V1) {
5962 +        *minor = GSSEAP_BAD_CONTEXT_TOKEN;
5963 +        return GSS_S_DEFECTIVE_TOKEN;
5964 +    }
5965 +    ctx->state      = load_uint32_be(&p[4]);
5966 +    ctx->flags      = load_uint32_be(&p[8]);
5967 +    ctx->gssFlags   = load_uint32_be(&p[12]);
5968 +    p      += 16;
5969 +    remain -= 16;
5970 +
5971 +    /* Validate state */
5972 +    if (GSSEAP_SM_STATE(ctx) < GSSEAP_STATE_INITIAL ||
5973 +        GSSEAP_SM_STATE(ctx) > GSSEAP_STATE_ESTABLISHED)
5974 +        return GSS_S_DEFECTIVE_TOKEN;
5975 +
5976 +    /* Only acceptor can export partial context tokens */
5977 +    if (CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx))
5978 +        return GSS_S_DEFECTIVE_TOKEN;
5979 +
5980 +    major = importMechanismOid(minor, &p, &remain, &ctx->mechanismUsed);
5981 +    if (GSS_ERROR(major))
5982 +        return major;
5983 +
5984 +    major = importKerberosKey(minor, &p, &remain,
5985 +                              &ctx->checksumType,
5986 +                              &ctx->encryptionType,
5987 +                              &ctx->rfc3961Key);
5988 +    if (GSS_ERROR(major))
5989 +        return major;
5990 +
5991 +    major = importName(minor, &p, &remain, &ctx->initiatorName);
5992 +    if (GSS_ERROR(major))
5993 +        return major;
5994 +
5995 +    major = importName(minor, &p, &remain, &ctx->acceptorName);
5996 +    if (GSS_ERROR(major))
5997 +        return major;
5998 +
5999 +    /* Check that, if context is established, names are valid */
6000 +    if (CTX_IS_ESTABLISHED(ctx) &&
6001 +        (CTX_IS_INITIATOR(ctx) ? ctx->acceptorName == GSS_C_NO_NAME
6002 +                               : ctx->initiatorName == GSS_C_NO_NAME)) {
6003 +        return GSS_S_DEFECTIVE_TOKEN;
6004 +    }
6005 +
6006 +    if (remain < 24 + sequenceSize(ctx->seqState)) {
6007 +        *minor = GSSEAP_TOK_TRUNC;
6008 +        return GSS_S_DEFECTIVE_TOKEN;
6009 +    }
6010 +    ctx->expiryTime = (time_t)load_uint64_be(&p[0]);
6011 +    ctx->sendSeq    = load_uint64_be(&p[8]);
6012 +    ctx->recvSeq    = load_uint64_be(&p[16]);
6013 +    p      += 24;
6014 +    remain -= 24;
6015 +
6016 +    major = sequenceInternalize(minor, &ctx->seqState, &p, &remain);
6017 +    if (GSS_ERROR(major))
6018 +        return major;
6019 +
6020 +#ifdef GSSEAP_ENABLE_ACCEPTOR
6021 +    /*
6022 +     * The partial context should only be expected for unestablished
6023 +     * acceptor contexts.
6024 +     */
6025 +    if (!CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx) &&
6026 +        (ctx->flags & CTX_FLAG_KRB_REAUTH) == 0) {
6027 +        major = gssEapImportPartialContext(minor, &p, &remain, ctx);
6028 +        if (GSS_ERROR(major))
6029 +            return major;
6030 +    }
6031 +
6032 +#ifdef GSSEAP_DEBUG
6033 +    GSSEAP_ASSERT(remain == 0);
6034 +#endif
6035 +#endif /* GSSEAP_ENABLE_ACCEPTOR */
6036 +
6037 +    major = GSS_S_COMPLETE;
6038 +    *minor = 0;
6039 +
6040 +    return major;
6041 +}
6042 +
6043 +OM_uint32 GSSAPI_CALLCONV
6044 +gss_import_sec_context(OM_uint32 *minor,
6045 +                       gss_buffer_t interprocess_token,
6046 +                       gss_ctx_id_t *context_handle)
6047 +{
6048 +    OM_uint32 major, tmpMinor;
6049 +    gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
6050 +
6051 +    *context_handle = GSS_C_NO_CONTEXT;
6052 +
6053 +    if (interprocess_token == GSS_C_NO_BUFFER ||
6054 +        interprocess_token->length == 0) {
6055 +        *minor = GSSEAP_TOK_TRUNC;
6056 +        return GSS_S_DEFECTIVE_TOKEN;
6057 +    }
6058 +
6059 +    major = gssEapAllocContext(minor, &ctx);
6060 +    if (GSS_ERROR(major))
6061 +        goto cleanup;
6062 +
6063 +    major = gssEapImportContext(minor, interprocess_token, ctx);
6064 +    if (GSS_ERROR(major))
6065 +        goto cleanup;
6066 +
6067 +    *context_handle = ctx;
6068 +
6069 +cleanup:
6070 +    if (GSS_ERROR(major))
6071 +        gssEapReleaseContext(&tmpMinor, &ctx);
6072 +
6073 +    return major;
6074 +}
6075 diff --git a/mech_eap/indicate_mechs.c b/mech_eap/indicate_mechs.c
6076 new file mode 100644
6077 index 0000000..d4d275e
6078 --- /dev/null
6079 +++ b/mech_eap/indicate_mechs.c
6080 @@ -0,0 +1,44 @@
6081 +/*
6082 + * Copyright (c) 2011, JANET(UK)
6083 + * All rights reserved.
6084 + *
6085 + * Redistribution and use in source and binary forms, with or without
6086 + * modification, are permitted provided that the following conditions
6087 + * are met:
6088 + *
6089 + * 1. Redistributions of source code must retain the above copyright
6090 + *    notice, this list of conditions and the following disclaimer.
6091 + *
6092 + * 2. Redistributions in binary form must reproduce the above copyright
6093 + *    notice, this list of conditions and the following disclaimer in the
6094 + *    documentation and/or other materials provided with the distribution.
6095 + *
6096 + * 3. Neither the name of JANET(UK) nor the names of its contributors
6097 + *    may be used to endorse or promote products derived from this software
6098 + *    without specific prior written permission.
6099 + *
6100 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
6101 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
6102 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
6103 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
6104 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
6105 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
6106 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6107 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6108 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6109 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6110 + * SUCH DAMAGE.
6111 + */
6112 +
6113 +/*
6114 + * Enumerate the supported mechanism OIDs.
6115 + */
6116 +
6117 +#include "gssapiP_eap.h"
6118 +
6119 +OM_uint32 GSSAPI_CALLCONV
6120 +gss_indicate_mechs(OM_uint32 *minor,
6121 +                   gss_OID_set *mech_set)
6122 +{
6123 +    return gssEapIndicateMechs(minor, mech_set);
6124 +}
6125 diff --git a/mech_eap/init_sec_context.c b/mech_eap/init_sec_context.c
6126 new file mode 100644
6127 index 0000000..e99b479
6128 --- /dev/null
6129 +++ b/mech_eap/init_sec_context.c
6130 @@ -0,0 +1,1097 @@
6131 +/*
6132 + * Copyright (c) 2011, JANET(UK)
6133 + * All rights reserved.
6134 + *
6135 + * Redistribution and use in source and binary forms, with or without
6136 + * modification, are permitted provided that the following conditions
6137 + * are met:
6138 + *
6139 + * 1. Redistributions of source code must retain the above copyright
6140 + *    notice, this list of conditions and the following disclaimer.
6141 + *
6142 + * 2. Redistributions in binary form must reproduce the above copyright
6143 + *    notice, this list of conditions and the following disclaimer in the
6144 + *    documentation and/or other materials provided with the distribution.
6145 + *
6146 + * 3. Neither the name of JANET(UK) nor the names of its contributors
6147 + *    may be used to endorse or promote products derived from this software
6148 + *    without specific prior written permission.
6149 + *
6150 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
6151 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
6152 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
6153 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
6154 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
6155 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
6156 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6157 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6158 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6159 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6160 + * SUCH DAMAGE.
6161 + */
6162 +
6163 +/*
6164 + * Establish a security context on the initiator (client). These functions
6165 + * wrap around libeap.
6166 + */
6167 +
6168 +#include "gssapiP_eap.h"
6169 +
6170 +static OM_uint32
6171 +policyVariableToFlag(enum eapol_bool_var variable)
6172 +{
6173 +    OM_uint32 flag = 0;
6174 +
6175 +    switch (variable) {
6176 +    case EAPOL_eapSuccess:
6177 +        flag = CTX_FLAG_EAP_SUCCESS;
6178 +        break;
6179 +    case EAPOL_eapRestart:
6180 +        flag = CTX_FLAG_EAP_RESTART;
6181 +        break;
6182 +    case EAPOL_eapFail:
6183 +        flag = CTX_FLAG_EAP_FAIL;
6184 +        break;
6185 +    case EAPOL_eapResp:
6186 +        flag = CTX_FLAG_EAP_RESP;
6187 +        break;
6188 +    case EAPOL_eapNoResp:
6189 +        flag = CTX_FLAG_EAP_NO_RESP;
6190 +        break;
6191 +    case EAPOL_eapReq:
6192 +        flag = CTX_FLAG_EAP_REQ;
6193 +        break;
6194 +    case EAPOL_portEnabled:
6195 +        flag = CTX_FLAG_EAP_PORT_ENABLED;
6196 +        break;
6197 +    case EAPOL_altAccept:
6198 +        flag = CTX_FLAG_EAP_ALT_ACCEPT;
6199 +        break;
6200 +    case EAPOL_altReject:
6201 +        flag = CTX_FLAG_EAP_ALT_REJECT;
6202 +        break;
6203 +    }
6204 +
6205 +    return flag;
6206 +}
6207 +
6208 +static struct eap_peer_config *
6209 +peerGetConfig(void *ctx)
6210 +{
6211 +    gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx;
6212 +
6213 +    return &gssCtx->initiatorCtx.eapPeerConfig;
6214 +}
6215 +
6216 +static Boolean
6217 +peerGetBool(void *data, enum eapol_bool_var variable)
6218 +{
6219 +    gss_ctx_id_t ctx = data;
6220 +    OM_uint32 flag;
6221 +
6222 +    if (ctx == GSS_C_NO_CONTEXT)
6223 +        return FALSE;
6224 +
6225 +    flag = policyVariableToFlag(variable);
6226 +
6227 +    return ((ctx->flags & flag) != 0);
6228 +}
6229 +
6230 +static void
6231 +peerSetBool(void *data, enum eapol_bool_var variable,
6232 +            Boolean value)
6233 +{
6234 +    gss_ctx_id_t ctx = data;
6235 +    OM_uint32 flag;
6236 +
6237 +    if (ctx == GSS_C_NO_CONTEXT)
6238 +        return;
6239 +
6240 +    flag = policyVariableToFlag(variable);
6241 +
6242 +    if (value)
6243 +        ctx->flags |= flag;
6244 +    else
6245 +        ctx->flags &= ~(flag);
6246 +}
6247 +
6248 +static unsigned int
6249 +peerGetInt(void *data, enum eapol_int_var variable)
6250 +{
6251 +    gss_ctx_id_t ctx = data;
6252 +
6253 +    if (ctx == GSS_C_NO_CONTEXT)
6254 +        return FALSE;
6255 +
6256 +    GSSEAP_ASSERT(CTX_IS_INITIATOR(ctx));
6257 +
6258 +    switch (variable) {
6259 +    case EAPOL_idleWhile:
6260 +        return ctx->initiatorCtx.idleWhile;
6261 +        break;
6262 +    }
6263 +
6264 +    return 0;
6265 +}
6266 +
6267 +static void
6268 +peerSetInt(void *data, enum eapol_int_var variable,
6269 +           unsigned int value)
6270 +{
6271 +    gss_ctx_id_t ctx = data;
6272 +
6273 +    if (ctx == GSS_C_NO_CONTEXT)
6274 +        return;
6275 +
6276 +    GSSEAP_ASSERT(CTX_IS_INITIATOR(ctx));
6277 +
6278 +    switch (variable) {
6279 +    case EAPOL_idleWhile:
6280 +        ctx->initiatorCtx.idleWhile = value;
6281 +        break;
6282 +    }
6283 +}
6284 +
6285 +static struct wpabuf *
6286 +peerGetEapReqData(void *ctx)
6287 +{
6288 +    gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx;
6289 +
6290 +    return &gssCtx->initiatorCtx.reqData;
6291 +}
6292 +
6293 +static void
6294 +peerSetConfigBlob(void *ctx GSSEAP_UNUSED,
6295 +                  struct wpa_config_blob *blob GSSEAP_UNUSED)
6296 +{
6297 +}
6298 +
6299 +static const struct wpa_config_blob *
6300 +peerGetConfigBlob(void *ctx GSSEAP_UNUSED,
6301 +                  const char *name GSSEAP_UNUSED)
6302 +{
6303 +    return NULL;
6304 +}
6305 +
6306 +static void
6307 +peerNotifyPending(void *ctx GSSEAP_UNUSED)
6308 +{
6309 +}
6310 +
6311 +static struct eapol_callbacks gssEapPolicyCallbacks = {
6312 +    peerGetConfig,
6313 +    peerGetBool,
6314 +    peerSetBool,
6315 +    peerGetInt,
6316 +    peerSetInt,
6317 +    peerGetEapReqData,
6318 +    peerSetConfigBlob,
6319 +    peerGetConfigBlob,
6320 +    peerNotifyPending,
6321 +};
6322 +
6323 +#ifdef GSSEAP_DEBUG
6324 +extern int wpa_debug_level;
6325 +#endif
6326 +
6327 +static OM_uint32
6328 +peerConfigInit(OM_uint32 *minor, gss_ctx_id_t ctx)
6329 +{
6330 +    OM_uint32 major;
6331 +    krb5_context krbContext;
6332 +    struct eap_peer_config *eapPeerConfig = &ctx->initiatorCtx.eapPeerConfig;
6333 +    gss_buffer_desc identity = GSS_C_EMPTY_BUFFER;
6334 +    gss_buffer_desc realm = GSS_C_EMPTY_BUFFER;
6335 +    gss_cred_id_t cred = ctx->cred;
6336 +
6337 +    eapPeerConfig->identity = NULL;
6338 +    eapPeerConfig->identity_len = 0;
6339 +    eapPeerConfig->anonymous_identity = NULL;
6340 +    eapPeerConfig->anonymous_identity_len = 0;
6341 +    eapPeerConfig->password = NULL;
6342 +    eapPeerConfig->password_len = 0;
6343 +
6344 +    GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL);
6345 +
6346 +    GSSEAP_KRB_INIT(&krbContext);
6347 +
6348 +    eapPeerConfig->fragment_size = 1024;
6349 +#ifdef GSSEAP_DEBUG
6350 +    wpa_debug_level = 0;
6351 +#endif
6352 +
6353 +    GSSEAP_ASSERT(cred->name != GSS_C_NO_NAME);
6354 +
6355 +    if ((cred->name->flags & (NAME_FLAG_NAI | NAME_FLAG_SERVICE)) == 0) {
6356 +        *minor = GSSEAP_BAD_INITIATOR_NAME;
6357 +        return GSS_S_BAD_NAME;
6358 +    }
6359 +
6360 +    /* identity */
6361 +    major = gssEapDisplayName(minor, cred->name, &identity, NULL);
6362 +    if (GSS_ERROR(major))
6363 +        return major;
6364 +
6365 +    eapPeerConfig->identity = (unsigned char *)identity.value;
6366 +    eapPeerConfig->identity_len = identity.length;
6367 +
6368 +    krbPrincRealmToGssBuffer(cred->name->krbPrincipal, &realm);
6369 +
6370 +    /* anonymous_identity */
6371 +    eapPeerConfig->anonymous_identity = GSSEAP_MALLOC(realm.length + 2);
6372 +    if (eapPeerConfig->anonymous_identity == NULL) {
6373 +        *minor = ENOMEM;
6374 +        return GSS_S_FAILURE;
6375 +    }
6376 +
6377 +    eapPeerConfig->anonymous_identity[0] = '@';
6378 +    memcpy(eapPeerConfig->anonymous_identity + 1, realm.value, realm.length);
6379 +    eapPeerConfig->anonymous_identity[1 + realm.length] = '\0';
6380 +    eapPeerConfig->anonymous_identity_len = 1 + realm.length;
6381 +
6382 +    /* password */
6383 +    eapPeerConfig->password = (unsigned char *)cred->password.value;
6384 +    eapPeerConfig->password_len = cred->password.length;
6385 +
6386 +    /* certs */
6387 +    eapPeerConfig->ca_cert = (unsigned char *)cred->caCertificate.value;
6388 +    eapPeerConfig->subject_match = (unsigned char *)cred->subjectNameConstraint.value;
6389 +    eapPeerConfig->altsubject_match = (unsigned char *)cred->subjectAltNameConstraint.value;
6390 +
6391 +    *minor = 0;
6392 +    return GSS_S_COMPLETE;
6393 +}
6394 +
6395 +static OM_uint32
6396 +peerConfigFree(OM_uint32 *minor,
6397 +               gss_ctx_id_t ctx)
6398 +{
6399 +    struct eap_peer_config *eapPeerConfig = &ctx->initiatorCtx.eapPeerConfig;
6400 +
6401 +    if (eapPeerConfig->identity != NULL) {
6402 +        GSSEAP_FREE(eapPeerConfig->identity);
6403 +        eapPeerConfig->identity = NULL;
6404 +        eapPeerConfig->identity_len = 0;
6405 +    }
6406 +
6407 +    if (eapPeerConfig->anonymous_identity != NULL) {
6408 +        GSSEAP_FREE(eapPeerConfig->anonymous_identity);
6409 +        eapPeerConfig->anonymous_identity = NULL;
6410 +        eapPeerConfig->anonymous_identity_len = 0;
6411 +    }
6412 +
6413 +    *minor = 0;
6414 +    return GSS_S_COMPLETE;
6415 +}
6416 +
6417 +/*
6418 + * Mark an initiator context as ready for cryptographic operations
6419 + */
6420 +static OM_uint32
6421 +initReady(OM_uint32 *minor, gss_ctx_id_t ctx, OM_uint32 reqFlags)
6422 +{
6423 +    OM_uint32 major;
6424 +    const unsigned char *key;
6425 +    size_t keyLength;
6426 +
6427 +#if 1
6428 +    /* XXX actually check for mutual auth */
6429 +    if (reqFlags & GSS_C_MUTUAL_FLAG)
6430 +        ctx->gssFlags |= GSS_C_MUTUAL_FLAG;
6431 +#endif
6432 +
6433 +    /* Cache encryption type derived from selected mechanism OID */
6434 +    major = gssEapOidToEnctype(minor, ctx->mechanismUsed, &ctx->encryptionType);
6435 +    if (GSS_ERROR(major))
6436 +        return major;
6437 +
6438 +    if (!eap_key_available(ctx->initiatorCtx.eap)) {
6439 +        *minor = GSSEAP_KEY_UNAVAILABLE;
6440 +        return GSS_S_UNAVAILABLE;
6441 +    }
6442 +
6443 +    key = eap_get_eapKeyData(ctx->initiatorCtx.eap, &keyLength);
6444 +
6445 +    if (keyLength < EAP_EMSK_LEN) {
6446 +        *minor = GSSEAP_KEY_TOO_SHORT;
6447 +        return GSS_S_UNAVAILABLE;
6448 +    }
6449 +
6450 +    major = gssEapDeriveRfc3961Key(minor,
6451 +                                   &key[EAP_EMSK_LEN / 2],
6452 +                                   EAP_EMSK_LEN / 2,
6453 +                                   ctx->encryptionType,
6454 +                                   &ctx->rfc3961Key);
6455 +       if (GSS_ERROR(major))
6456 +           return major;
6457 +
6458 +    major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
6459 +                                      &ctx->checksumType);
6460 +    if (GSS_ERROR(major))
6461 +        return major;
6462 +
6463 +    major = sequenceInit(minor,
6464 +                         &ctx->seqState,
6465 +                         ctx->recvSeq,
6466 +                         ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0),
6467 +                         ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0),
6468 +                         TRUE);
6469 +    if (GSS_ERROR(major))
6470 +        return major;
6471 +
6472 +    *minor = 0;
6473 +    return GSS_S_COMPLETE;
6474 +}
6475 +
6476 +static OM_uint32
6477 +initBegin(OM_uint32 *minor,
6478 +          gss_ctx_id_t ctx,
6479 +          gss_name_t target,
6480 +          gss_OID mech,
6481 +          OM_uint32 reqFlags GSSEAP_UNUSED,
6482 +          OM_uint32 timeReq,
6483 +          gss_channel_bindings_t chanBindings GSSEAP_UNUSED)
6484 +{
6485 +    OM_uint32 major;
6486 +    gss_cred_id_t cred = ctx->cred;
6487 +
6488 +    GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL);
6489 +
6490 +    if (cred->expiryTime)
6491 +        ctx->expiryTime = cred->expiryTime;
6492 +    else if (timeReq == 0 || timeReq == GSS_C_INDEFINITE)
6493 +        ctx->expiryTime = 0;
6494 +    else
6495 +        ctx->expiryTime = time(NULL) + timeReq;
6496 +
6497 +    /*
6498 +     * The credential mutex protects its name, however we need to
6499 +     * explicitly lock the acceptor name (unlikely as it may be
6500 +     * that it has attributes set on it).
6501 +     */
6502 +    major = gssEapDuplicateName(minor, cred->name, &ctx->initiatorName);
6503 +    if (GSS_ERROR(major))
6504 +        return major;
6505 +
6506 +    if (target != GSS_C_NO_NAME) {
6507 +        GSSEAP_MUTEX_LOCK(&target->mutex);
6508 +
6509 +        major = gssEapDuplicateName(minor, target, &ctx->acceptorName);
6510 +        if (GSS_ERROR(major)) {
6511 +            GSSEAP_MUTEX_UNLOCK(&target->mutex);
6512 +            return major;
6513 +        }
6514 +
6515 +        GSSEAP_MUTEX_UNLOCK(&target->mutex);
6516 +    }
6517 +
6518 +    major = gssEapCanonicalizeOid(minor,
6519 +                                  mech,
6520 +                                  OID_FLAG_NULL_VALID | OID_FLAG_MAP_NULL_TO_DEFAULT_MECH,
6521 +                                  &ctx->mechanismUsed);
6522 +    if (GSS_ERROR(major))
6523 +        return major;
6524 +
6525 +    /* If credentials were provided, check they're usable with this mech */
6526 +    if (!gssEapCredAvailable(cred, ctx->mechanismUsed)) {
6527 +        *minor = GSSEAP_CRED_MECH_MISMATCH;
6528 +        return GSS_S_BAD_MECH;
6529 +    }
6530 +
6531 +    *minor = 0;
6532 +    return GSS_S_COMPLETE;
6533 +}
6534 +
6535 +static OM_uint32
6536 +eapGssSmInitError(OM_uint32 *minor,
6537 +                  gss_cred_id_t cred GSSEAP_UNUSED,
6538 +                  gss_ctx_id_t ctx GSSEAP_UNUSED,
6539 +                  gss_name_t target GSSEAP_UNUSED,
6540 +                  gss_OID mech GSSEAP_UNUSED,
6541 +                  OM_uint32 reqFlags GSSEAP_UNUSED,
6542 +                  OM_uint32 timeReq GSSEAP_UNUSED,
6543 +                  gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
6544 +                  gss_buffer_t inputToken,
6545 +                  gss_buffer_t outputToken GSSEAP_UNUSED,
6546 +                  OM_uint32 *smFlags GSSEAP_UNUSED)
6547 +{
6548 +    OM_uint32 major;
6549 +    unsigned char *p;
6550 +
6551 +    if (inputToken->length < 8) {
6552 +        *minor = GSSEAP_TOK_TRUNC;
6553 +        return GSS_S_DEFECTIVE_TOKEN;
6554 +    }
6555 +
6556 +    p = (unsigned char *)inputToken->value;
6557 +
6558 +    major = load_uint32_be(&p[0]);
6559 +    *minor = ERROR_TABLE_BASE_eapg + load_uint32_be(&p[4]);
6560 +
6561 +    if (!GSS_ERROR(major) || !IS_WIRE_ERROR(*minor)) {
6562 +        major = GSS_S_FAILURE;
6563 +        *minor = GSSEAP_BAD_ERROR_TOKEN;
6564 +    }
6565 +
6566 +    GSSEAP_ASSERT(GSS_ERROR(major));
6567 +
6568 +    return major;
6569 +}
6570 +
6571 +#ifdef GSSEAP_ENABLE_REAUTH
6572 +static OM_uint32
6573 +eapGssSmInitGssReauth(OM_uint32 *minor,
6574 +                      gss_cred_id_t cred,
6575 +                      gss_ctx_id_t ctx,
6576 +                      gss_name_t target,
6577 +                      gss_OID mech GSSEAP_UNUSED,
6578 +                      OM_uint32 reqFlags,
6579 +                      OM_uint32 timeReq,
6580 +                      gss_channel_bindings_t chanBindings,
6581 +                      gss_buffer_t inputToken,
6582 +                      gss_buffer_t outputToken,
6583 +                      OM_uint32 *smFlags GSSEAP_UNUSED)
6584 +{
6585 +    OM_uint32 major, tmpMinor;
6586 +    gss_name_t mechTarget = GSS_C_NO_NAME;
6587 +    gss_OID actualMech = GSS_C_NO_OID;
6588 +    OM_uint32 gssFlags, timeRec;
6589 +
6590 +    /*
6591 +     * Here we use the passed in credential handle because the resolved
6592 +     * context credential does not currently have the reauth creds.
6593 +     */
6594 +    if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_INITIAL) {
6595 +        if (!gssEapCanReauthP(cred, target, timeReq))
6596 +            return GSS_S_CONTINUE_NEEDED;
6597 +
6598 +        ctx->flags |= CTX_FLAG_KRB_REAUTH;
6599 +    } else if ((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0) {
6600 +        major = GSS_S_DEFECTIVE_TOKEN;
6601 +        *minor = GSSEAP_WRONG_ITOK;
6602 +        goto cleanup;
6603 +    }
6604 +
6605 +    GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL);
6606 +
6607 +    major = gssEapMechToGlueName(minor, target, &mechTarget);
6608 +    if (GSS_ERROR(major))
6609 +        goto cleanup;
6610 +
6611 +    major = gssInitSecContext(minor,
6612 +                              cred->reauthCred,
6613 +                              &ctx->reauthCtx,
6614 +                              mechTarget,
6615 +                              (gss_OID)gss_mech_krb5,
6616 +                              reqFlags | GSS_C_MUTUAL_FLAG,
6617 +                              timeReq,
6618 +                              chanBindings,
6619 +                              inputToken,
6620 +                              &actualMech,
6621 +                              outputToken,
6622 +                              &gssFlags,
6623 +                              &timeRec);
6624 +    if (GSS_ERROR(major))
6625 +        goto cleanup;
6626 +
6627 +    ctx->gssFlags = gssFlags;
6628 +
6629 +    if (major == GSS_S_COMPLETE) {
6630 +        GSSEAP_ASSERT(GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_REAUTHENTICATE);
6631 +
6632 +        major = gssEapReauthComplete(minor, ctx, cred, actualMech, timeRec);
6633 +        if (GSS_ERROR(major))
6634 +            goto cleanup;
6635 +        GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
6636 +    } else {
6637 +        GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_REAUTHENTICATE);
6638 +    }
6639 +
6640 +cleanup:
6641 +    gssReleaseName(&tmpMinor, &mechTarget);
6642 +
6643 +    return major;
6644 +}
6645 +#endif /* GSSEAP_ENABLE_REAUTH */
6646 +
6647 +#ifdef GSSEAP_DEBUG
6648 +static OM_uint32
6649 +eapGssSmInitVendorInfo(OM_uint32 *minor,
6650 +                       gss_cred_id_t cred GSSEAP_UNUSED,
6651 +                       gss_ctx_id_t ctx GSSEAP_UNUSED,
6652 +                       gss_name_t target GSSEAP_UNUSED,
6653 +                       gss_OID mech GSSEAP_UNUSED,
6654 +                       OM_uint32 reqFlags GSSEAP_UNUSED,
6655 +                       OM_uint32 timeReq GSSEAP_UNUSED,
6656 +                       gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
6657 +                       gss_buffer_t inputToken GSSEAP_UNUSED,
6658 +                       gss_buffer_t outputToken,
6659 +                       OM_uint32 *smFlags GSSEAP_UNUSED)
6660 +{
6661 +    OM_uint32 major;
6662 +
6663 +    major = makeStringBuffer(minor, "JANET(UK)", outputToken);
6664 +    if (GSS_ERROR(major))
6665 +        return major;
6666 +
6667 +    return GSS_S_CONTINUE_NEEDED;
6668 +}
6669 +#endif
6670 +
6671 +static OM_uint32
6672 +eapGssSmInitAcceptorName(OM_uint32 *minor,
6673 +                         gss_cred_id_t cred GSSEAP_UNUSED,
6674 +                         gss_ctx_id_t ctx,
6675 +                         gss_name_t target GSSEAP_UNUSED,
6676 +                         gss_OID mech GSSEAP_UNUSED,
6677 +                         OM_uint32 reqFlags GSSEAP_UNUSED,
6678 +                         OM_uint32 timeReq GSSEAP_UNUSED,
6679 +                         gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
6680 +                         gss_buffer_t inputToken GSSEAP_UNUSED,
6681 +                         gss_buffer_t outputToken,
6682 +                         OM_uint32 *smFlags GSSEAP_UNUSED)
6683 +{
6684 +    OM_uint32 major;
6685 +
6686 +    if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_INITIAL &&
6687 +        ctx->acceptorName != GSS_C_NO_NAME) {
6688 +
6689 +        /* Send desired target name to acceptor */
6690 +        major = gssEapDisplayName(minor, ctx->acceptorName,
6691 +                                  outputToken, NULL);
6692 +        if (GSS_ERROR(major))
6693 +            return major;
6694 +    } else if (inputToken != GSS_C_NO_BUFFER &&
6695 +               ctx->acceptorName == GSS_C_NO_NAME) {
6696 +        /* Accept target name hint from acceptor */
6697 +        major = gssEapImportName(minor, inputToken,
6698 +                                 GSS_C_NT_USER_NAME,
6699 +                                 ctx->mechanismUsed,
6700 +                                 &ctx->acceptorName);
6701 +        if (GSS_ERROR(major))
6702 +            return major;
6703 +    }
6704 +
6705 +    /*
6706 +     * Currently, other parts of the code assume that the acceptor name
6707 +     * is available, hence this check.
6708 +     */
6709 +    if (ctx->acceptorName == GSS_C_NO_NAME) {
6710 +        *minor = GSSEAP_NO_ACCEPTOR_NAME;
6711 +        return GSS_S_FAILURE;
6712 +    }
6713 +
6714 +    return GSS_S_CONTINUE_NEEDED;
6715 +}
6716 +
6717 +static OM_uint32
6718 +eapGssSmInitIdentity(OM_uint32 *minor,
6719 +                     gss_cred_id_t cred GSSEAP_UNUSED,
6720 +                     gss_ctx_id_t ctx,
6721 +                     gss_name_t target GSSEAP_UNUSED,
6722 +                     gss_OID mech GSSEAP_UNUSED,
6723 +                     OM_uint32 reqFlags GSSEAP_UNUSED,
6724 +                     OM_uint32 timeReq GSSEAP_UNUSED,
6725 +                     gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
6726 +                     gss_buffer_t inputToken GSSEAP_UNUSED,
6727 +                     gss_buffer_t outputToken GSSEAP_UNUSED,
6728 +                     OM_uint32 *smFlags)
6729 +{
6730 +    struct eap_config eapConfig;
6731 +
6732 +#ifdef GSSEAP_ENABLE_REAUTH
6733 +    if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_REAUTHENTICATE) {
6734 +        OM_uint32 tmpMinor;
6735 +
6736 +        /* server didn't support reauthentication, sent EAP request */
6737 +        gssDeleteSecContext(&tmpMinor, &ctx->reauthCtx, GSS_C_NO_BUFFER);
6738 +        ctx->flags &= ~(CTX_FLAG_KRB_REAUTH);
6739 +        GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_INITIAL);
6740 +    } else
6741 +#endif
6742 +        *smFlags |= SM_FLAG_FORCE_SEND_TOKEN;
6743 +
6744 +    GSSEAP_ASSERT((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0);
6745 +    GSSEAP_ASSERT(inputToken == GSS_C_NO_BUFFER);
6746 +
6747 +    memset(&eapConfig, 0, sizeof(eapConfig));
6748 +
6749 +    ctx->initiatorCtx.eap = eap_peer_sm_init(ctx,
6750 +                                             &gssEapPolicyCallbacks,
6751 +                                             ctx,
6752 +                                             &eapConfig);
6753 +    if (ctx->initiatorCtx.eap == NULL) {
6754 +        *minor = GSSEAP_PEER_SM_INIT_FAILURE;
6755 +        return GSS_S_FAILURE;
6756 +    }
6757 +
6758 +    ctx->flags |= CTX_FLAG_EAP_RESTART | CTX_FLAG_EAP_PORT_ENABLED;
6759 +
6760 +    /* poke EAP state machine */
6761 +    if (eap_peer_sm_step(ctx->initiatorCtx.eap) != 0) {
6762 +        *minor = GSSEAP_PEER_SM_STEP_FAILURE;
6763 +        return GSS_S_FAILURE;
6764 +    }
6765 +
6766 +    GSSEAP_SM_TRANSITION_NEXT(ctx);
6767 +
6768 +    *minor = 0;
6769 +
6770 +    return GSS_S_CONTINUE_NEEDED;
6771 +}
6772 +
6773 +static OM_uint32
6774 +eapGssSmInitAuthenticate(OM_uint32 *minor,
6775 +                         gss_cred_id_t cred GSSEAP_UNUSED,
6776 +                         gss_ctx_id_t ctx,
6777 +                         gss_name_t target GSSEAP_UNUSED,
6778 +                         gss_OID mech GSSEAP_UNUSED,
6779 +                         OM_uint32 reqFlags GSSEAP_UNUSED,
6780 +                         OM_uint32 timeReq GSSEAP_UNUSED,
6781 +                         gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
6782 +                         gss_buffer_t inputToken GSSEAP_UNUSED,
6783 +                         gss_buffer_t outputToken,
6784 +                         OM_uint32 *smFlags)
6785 +{
6786 +    OM_uint32 major;
6787 +    OM_uint32 tmpMinor;
6788 +    struct wpabuf *resp = NULL;
6789 +
6790 +    *minor = 0;
6791 +
6792 +    GSSEAP_ASSERT(inputToken != GSS_C_NO_BUFFER);
6793 +
6794 +    major = peerConfigInit(minor, ctx);
6795 +    if (GSS_ERROR(major))
6796 +        goto cleanup;
6797 +
6798 +    GSSEAP_ASSERT(ctx->initiatorCtx.eap != NULL);
6799 +    GSSEAP_ASSERT(ctx->flags & CTX_FLAG_EAP_PORT_ENABLED);
6800 +
6801 +    ctx->flags |= CTX_FLAG_EAP_REQ; /* we have a Request from the acceptor */
6802 +
6803 +    wpabuf_set(&ctx->initiatorCtx.reqData,
6804 +               inputToken->value, inputToken->length);
6805 +
6806 +    major = GSS_S_CONTINUE_NEEDED;
6807 +
6808 +    eap_peer_sm_step(ctx->initiatorCtx.eap);
6809 +    if (ctx->flags & CTX_FLAG_EAP_RESP) {
6810 +        ctx->flags &= ~(CTX_FLAG_EAP_RESP);
6811 +
6812 +        resp = eap_get_eapRespData(ctx->initiatorCtx.eap);
6813 +    } else if (ctx->flags & CTX_FLAG_EAP_SUCCESS) {
6814 +        major = initReady(minor, ctx, reqFlags);
6815 +        if (GSS_ERROR(major))
6816 +            goto cleanup;
6817 +
6818 +        ctx->flags &= ~(CTX_FLAG_EAP_SUCCESS);
6819 +        major = GSS_S_CONTINUE_NEEDED;
6820 +        GSSEAP_SM_TRANSITION_NEXT(ctx);
6821 +    } else if (ctx->flags & CTX_FLAG_EAP_FAIL) {
6822 +        major = GSS_S_DEFECTIVE_CREDENTIAL;
6823 +        *minor = GSSEAP_PEER_AUTH_FAILURE;
6824 +    } else {
6825 +        major = GSS_S_DEFECTIVE_TOKEN;
6826 +        *minor = GSSEAP_PEER_BAD_MESSAGE;
6827 +    }
6828 +
6829 +cleanup:
6830 +    if (resp != NULL) {
6831 +        OM_uint32 tmpMajor;
6832 +        gss_buffer_desc respBuf;
6833 +
6834 +        GSSEAP_ASSERT(major == GSS_S_CONTINUE_NEEDED);
6835 +
6836 +        respBuf.length = wpabuf_len(resp);
6837 +        respBuf.value = (void *)wpabuf_head(resp);
6838 +
6839 +        tmpMajor = duplicateBuffer(&tmpMinor, &respBuf, outputToken);
6840 +        if (GSS_ERROR(tmpMajor)) {
6841 +            major = tmpMajor;
6842 +            *minor = tmpMinor;
6843 +        }
6844 +
6845 +        *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
6846 +    }
6847 +
6848 +    wpabuf_set(&ctx->initiatorCtx.reqData, NULL, 0);
6849 +    peerConfigFree(&tmpMinor, ctx);
6850 +
6851 +    return major;
6852 +}
6853 +
6854 +static OM_uint32
6855 +eapGssSmInitGssFlags(OM_uint32 *minor,
6856 +                     gss_cred_id_t cred GSSEAP_UNUSED,
6857 +                     gss_ctx_id_t ctx,
6858 +                     gss_name_t target GSSEAP_UNUSED,
6859 +                     gss_OID mech GSSEAP_UNUSED,
6860 +                     OM_uint32 reqFlags GSSEAP_UNUSED,
6861 +                     OM_uint32 timeReq GSSEAP_UNUSED,
6862 +                     gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
6863 +                     gss_buffer_t inputToken GSSEAP_UNUSED,
6864 +                     gss_buffer_t outputToken,
6865 +                     OM_uint32 *smFlags GSSEAP_UNUSED)
6866 +{
6867 +    unsigned char wireFlags[4];
6868 +    gss_buffer_desc flagsBuf;
6869 +
6870 +    store_uint32_be(ctx->gssFlags & GSSEAP_WIRE_FLAGS_MASK, wireFlags);
6871 +
6872 +    flagsBuf.length = sizeof(wireFlags);
6873 +    flagsBuf.value = wireFlags;
6874 +
6875 +    return duplicateBuffer(minor, &flagsBuf, outputToken);
6876 +}
6877 +
6878 +static OM_uint32
6879 +eapGssSmInitGssChannelBindings(OM_uint32 *minor,
6880 +                               gss_cred_id_t cred GSSEAP_UNUSED,
6881 +                               gss_ctx_id_t ctx,
6882 +                               gss_name_t target GSSEAP_UNUSED,
6883 +                               gss_OID mech GSSEAP_UNUSED,
6884 +                               OM_uint32 reqFlags GSSEAP_UNUSED,
6885 +                               OM_uint32 timeReq GSSEAP_UNUSED,
6886 +                               gss_channel_bindings_t chanBindings,
6887 +                               gss_buffer_t inputToken GSSEAP_UNUSED,
6888 +                               gss_buffer_t outputToken,
6889 +                               OM_uint32 *smFlags)
6890 +{
6891 +    OM_uint32 major;
6892 +    gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER;
6893 +
6894 +    if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS)
6895 +        buffer = chanBindings->application_data;
6896 +
6897 +    major = gssEapWrap(minor, ctx, TRUE, GSS_C_QOP_DEFAULT,
6898 +                       &buffer, NULL, outputToken);
6899 +    if (GSS_ERROR(major))
6900 +        return major;
6901 +
6902 +    GSSEAP_ASSERT(outputToken->value != NULL);
6903 +
6904 +    *minor = 0;
6905 +    *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
6906 +
6907 +    return GSS_S_CONTINUE_NEEDED;
6908 +}
6909 +
6910 +static OM_uint32
6911 +eapGssSmInitInitiatorMIC(OM_uint32 *minor,
6912 +                         gss_cred_id_t cred GSSEAP_UNUSED,
6913 +                         gss_ctx_id_t ctx,
6914 +                         gss_name_t target GSSEAP_UNUSED,
6915 +                         gss_OID mech GSSEAP_UNUSED,
6916 +                         OM_uint32 reqFlags GSSEAP_UNUSED,
6917 +                         OM_uint32 timeReq GSSEAP_UNUSED,
6918 +                         gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
6919 +                         gss_buffer_t inputToken GSSEAP_UNUSED,
6920 +                         gss_buffer_t outputToken,
6921 +                         OM_uint32 *smFlags)
6922 +{
6923 +    OM_uint32 major;
6924 +
6925 +    major = gssEapMakeTokenMIC(minor, ctx, outputToken);
6926 +    if (GSS_ERROR(major))
6927 +        return major;
6928 +
6929 +    GSSEAP_SM_TRANSITION_NEXT(ctx);
6930 +
6931 +    *minor = 0;
6932 +    *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
6933 +
6934 +    return GSS_S_CONTINUE_NEEDED;
6935 +}
6936
6937 +#ifdef GSSEAP_ENABLE_REAUTH
6938 +static OM_uint32
6939 +eapGssSmInitReauthCreds(OM_uint32 *minor,
6940 +                        gss_cred_id_t cred,
6941 +                        gss_ctx_id_t ctx,
6942 +                        gss_name_t target GSSEAP_UNUSED,
6943 +                        gss_OID mech GSSEAP_UNUSED,
6944 +                        OM_uint32 reqFlags GSSEAP_UNUSED,
6945 +                        OM_uint32 timeReq GSSEAP_UNUSED,
6946 +                        gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
6947 +                        gss_buffer_t inputToken,
6948 +                        gss_buffer_t outputToken GSSEAP_UNUSED,
6949 +                        OM_uint32 *smFlags GSSEAP_UNUSED)
6950 +{
6951 +    OM_uint32 major;
6952 +
6953 +    if (ctx->gssFlags & GSS_C_MUTUAL_FLAG) {
6954 +        major = gssEapStoreReauthCreds(minor, ctx, cred, inputToken);
6955 +        if (GSS_ERROR(major))
6956 +            return major;
6957 +    }
6958 +
6959 +    *minor = 0;
6960 +    return GSS_S_CONTINUE_NEEDED;
6961 +}
6962 +#endif /* GSSEAP_ENABLE_REAUTH */
6963 +
6964 +static OM_uint32
6965 +eapGssSmInitAcceptorMIC(OM_uint32 *minor,
6966 +                        gss_cred_id_t cred GSSEAP_UNUSED,
6967 +                        gss_ctx_id_t ctx,
6968 +                        gss_name_t target GSSEAP_UNUSED,
6969 +                        gss_OID mech GSSEAP_UNUSED,
6970 +                        OM_uint32 reqFlags GSSEAP_UNUSED,
6971 +                        OM_uint32 timeReq GSSEAP_UNUSED,
6972 +                        gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
6973 +                        gss_buffer_t inputToken,
6974 +                        gss_buffer_t outputToken GSSEAP_UNUSED,
6975 +                        OM_uint32 *smFlags GSSEAP_UNUSED)
6976 +{
6977 +    OM_uint32 major;
6978 +
6979 +    major = gssEapVerifyTokenMIC(minor, ctx, inputToken);
6980 +    if (GSS_ERROR(major))
6981 +        return major;
6982 +
6983 +    GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
6984 +
6985 +    *minor = 0;
6986 +
6987 +    return GSS_S_COMPLETE;
6988 +}
6989 +
6990 +static struct gss_eap_sm eapGssInitiatorSm[] = {
6991 +    {
6992 +        ITOK_TYPE_CONTEXT_ERR,
6993 +        ITOK_TYPE_NONE,
6994 +        GSSEAP_STATE_ALL & ~(GSSEAP_STATE_INITIAL),
6995 +        0,
6996 +        eapGssSmInitError
6997 +    },
6998 +    {
6999 +        ITOK_TYPE_ACCEPTOR_NAME_RESP,
7000 +        ITOK_TYPE_ACCEPTOR_NAME_REQ,
7001 +        GSSEAP_STATE_INITIAL | GSSEAP_STATE_AUTHENTICATE,
7002 +        0,
7003 +        eapGssSmInitAcceptorName
7004 +    },
7005 +#ifdef GSSEAP_DEBUG
7006 +    {
7007 +        ITOK_TYPE_NONE,
7008 +        ITOK_TYPE_VENDOR_INFO,
7009 +        GSSEAP_STATE_INITIAL,
7010 +        0,
7011 +        eapGssSmInitVendorInfo
7012 +    },
7013 +#endif
7014 +#ifdef GSSEAP_ENABLE_REAUTH
7015 +    {
7016 +        ITOK_TYPE_REAUTH_RESP,
7017 +        ITOK_TYPE_REAUTH_REQ,
7018 +        GSSEAP_STATE_INITIAL | GSSEAP_STATE_REAUTHENTICATE,
7019 +        0,
7020 +        eapGssSmInitGssReauth
7021 +    },
7022 +#endif
7023 +    {
7024 +        ITOK_TYPE_NONE,
7025 +        ITOK_TYPE_NONE,
7026 +#ifdef GSSEAP_ENABLE_REAUTH
7027 +        GSSEAP_STATE_REAUTHENTICATE |
7028 +#endif
7029 +        GSSEAP_STATE_INITIAL,
7030 +        SM_ITOK_FLAG_REQUIRED,
7031 +        eapGssSmInitIdentity
7032 +    },
7033 +    {
7034 +        ITOK_TYPE_EAP_REQ,
7035 +        ITOK_TYPE_EAP_RESP,
7036 +        GSSEAP_STATE_AUTHENTICATE,
7037 +        SM_ITOK_FLAG_REQUIRED,
7038 +        eapGssSmInitAuthenticate
7039 +    },
7040 +    {
7041 +        ITOK_TYPE_NONE,
7042 +        ITOK_TYPE_GSS_FLAGS,
7043 +        GSSEAP_STATE_INITIATOR_EXTS,
7044 +        0,
7045 +        eapGssSmInitGssFlags
7046 +    },
7047 +    {
7048 +        ITOK_TYPE_NONE,
7049 +        ITOK_TYPE_GSS_CHANNEL_BINDINGS,
7050 +        GSSEAP_STATE_INITIATOR_EXTS,
7051 +        SM_ITOK_FLAG_REQUIRED,
7052 +        eapGssSmInitGssChannelBindings
7053 +    },
7054 +    {
7055 +        ITOK_TYPE_NONE,
7056 +        ITOK_TYPE_INITIATOR_MIC,
7057 +        GSSEAP_STATE_INITIATOR_EXTS,
7058 +        SM_ITOK_FLAG_REQUIRED,
7059 +        eapGssSmInitInitiatorMIC
7060 +    },
7061 +#ifdef GSSEAP_ENABLE_REAUTH
7062 +    {
7063 +        ITOK_TYPE_REAUTH_CREDS,
7064 +        ITOK_TYPE_NONE,
7065 +        GSSEAP_STATE_ACCEPTOR_EXTS,
7066 +        0,
7067 +        eapGssSmInitReauthCreds
7068 +    },
7069 +#endif
7070 +    /* other extensions go here */
7071 +    {
7072 +        ITOK_TYPE_ACCEPTOR_MIC,
7073 +        ITOK_TYPE_NONE,
7074 +        GSSEAP_STATE_ACCEPTOR_EXTS,
7075 +        SM_ITOK_FLAG_REQUIRED,
7076 +        eapGssSmInitAcceptorMIC
7077 +    }
7078 +};
7079 +
7080 +OM_uint32
7081 +gssEapInitSecContext(OM_uint32 *minor,
7082 +                     gss_cred_id_t cred,
7083 +                     gss_ctx_id_t ctx,
7084 +                     gss_name_t target_name,
7085 +                     gss_OID mech_type,
7086 +                     OM_uint32 req_flags,
7087 +                     OM_uint32 time_req,
7088 +                     gss_channel_bindings_t input_chan_bindings,
7089 +                     gss_buffer_t input_token,
7090 +                     gss_OID *actual_mech_type,
7091 +                     gss_buffer_t output_token,
7092 +                     OM_uint32 *ret_flags,
7093 +                     OM_uint32 *time_rec)
7094 +{
7095 +    OM_uint32 major, tmpMinor;
7096 +    int initialContextToken = (ctx->mechanismUsed == GSS_C_NO_OID);
7097 +
7098 +    /*
7099 +     * XXX is acquiring the credential lock here necessary? The password is
7100 +     * mutable but the contract could specify that this is not updated whilst
7101 +     * a context is being initialized.
7102 +     */
7103 +    if (cred != GSS_C_NO_CREDENTIAL)
7104 +        GSSEAP_MUTEX_LOCK(&cred->mutex);
7105 +
7106 +    if (ctx->cred == GSS_C_NO_CREDENTIAL) {
7107 +        major = gssEapResolveInitiatorCred(minor, cred, target_name, &ctx->cred);
7108 +        if (GSS_ERROR(major))
7109 +            goto cleanup;
7110 +
7111 +        GSSEAP_ASSERT(ctx->cred != GSS_C_NO_CREDENTIAL);
7112 +    }
7113 +
7114 +    GSSEAP_MUTEX_LOCK(&ctx->cred->mutex);
7115 +
7116 +    GSSEAP_ASSERT(ctx->cred->flags & CRED_FLAG_RESOLVED);
7117 +    GSSEAP_ASSERT(ctx->cred->flags & CRED_FLAG_INITIATE);
7118 +
7119 +    if (initialContextToken) {
7120 +        major = initBegin(minor, ctx, target_name, mech_type,
7121 +                          req_flags, time_req, input_chan_bindings);
7122 +        if (GSS_ERROR(major))
7123 +            goto cleanup;
7124 +    }
7125 +
7126 +    major = gssEapSmStep(minor,
7127 +                         cred,
7128 +                         ctx,
7129 +                         target_name,
7130 +                         mech_type,
7131 +                         req_flags,
7132 +                         time_req,
7133 +                         input_chan_bindings,
7134 +                         input_token,
7135 +                         output_token,
7136 +                         eapGssInitiatorSm,
7137 +                         sizeof(eapGssInitiatorSm) / sizeof(eapGssInitiatorSm[0]));
7138 +    if (GSS_ERROR(major))
7139 +        goto cleanup;
7140 +
7141 +    if (actual_mech_type != NULL) {
7142 +        OM_uint32 tmpMajor;
7143 +
7144 +        tmpMajor = gssEapCanonicalizeOid(&tmpMinor, ctx->mechanismUsed, 0, actual_mech_type);
7145 +        if (GSS_ERROR(tmpMajor)) {
7146 +            major = tmpMajor;
7147 +            *minor = tmpMinor;
7148 +            goto cleanup;
7149 +        }
7150 +    }
7151 +    if (ret_flags != NULL)
7152 +        *ret_flags = ctx->gssFlags;
7153 +    if (time_rec != NULL)
7154 +        gssEapContextTime(&tmpMinor, ctx, time_rec);
7155 +
7156 +    GSSEAP_ASSERT(CTX_IS_ESTABLISHED(ctx) || major == GSS_S_CONTINUE_NEEDED);
7157 +
7158 +cleanup:
7159 +    if (cred != GSS_C_NO_CREDENTIAL)
7160 +        GSSEAP_MUTEX_UNLOCK(&cred->mutex);
7161 +    if (ctx->cred != GSS_C_NO_CREDENTIAL)
7162 +        GSSEAP_MUTEX_UNLOCK(&ctx->cred->mutex);
7163 +
7164 +    return major;
7165 +}
7166 +
7167 +OM_uint32 GSSAPI_CALLCONV
7168 +gss_init_sec_context(OM_uint32 *minor,
7169 +                     gss_cred_id_t cred,
7170 +                     gss_ctx_id_t *context_handle,
7171 +                     gss_name_t target_name,
7172 +                     gss_OID mech_type,
7173 +                     OM_uint32 req_flags,
7174 +                     OM_uint32 time_req,
7175 +                     gss_channel_bindings_t input_chan_bindings,
7176 +                     gss_buffer_t input_token,
7177 +                     gss_OID *actual_mech_type,
7178 +                     gss_buffer_t output_token,
7179 +                     OM_uint32 *ret_flags,
7180 +                     OM_uint32 *time_rec)
7181 +{
7182 +    OM_uint32 major, tmpMinor;
7183 +    gss_ctx_id_t ctx = *context_handle;
7184 +
7185 +    *minor = 0;
7186 +
7187 +    output_token->length = 0;
7188 +    output_token->value = NULL;
7189 +
7190 +    if (ctx == GSS_C_NO_CONTEXT) {
7191 +        if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) {
7192 +            *minor = GSSEAP_WRONG_SIZE;
7193 +            return GSS_S_DEFECTIVE_TOKEN;
7194 +        }
7195 +
7196 +        major = gssEapAllocContext(minor, &ctx);
7197 +        if (GSS_ERROR(major))
7198 +            return major;
7199 +
7200 +        ctx->flags |= CTX_FLAG_INITIATOR;
7201 +
7202 +        *context_handle = ctx;
7203 +    }
7204 +
7205 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
7206 +
7207 +    major = gssEapInitSecContext(minor,
7208 +                                 cred,
7209 +                                 ctx,
7210 +                                 target_name,
7211 +                                 mech_type,
7212 +                                 req_flags,
7213 +                                 time_req,
7214 +                                 input_chan_bindings,
7215 +                                 input_token,
7216 +                                 actual_mech_type,
7217 +                                 output_token,
7218 +                                 ret_flags,
7219 +                                 time_rec);
7220 +
7221 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
7222 +
7223 +    if (GSS_ERROR(major))
7224 +        gssEapReleaseContext(&tmpMinor, context_handle);
7225 +
7226 +    return major;
7227 +}
7228 diff --git a/mech_eap/inquire_attrs_for_mech.c b/mech_eap/inquire_attrs_for_mech.c
7229 new file mode 100644
7230 index 0000000..a359f68
7231 --- /dev/null
7232 +++ b/mech_eap/inquire_attrs_for_mech.c
7233 @@ -0,0 +1,137 @@
7234 +/*
7235 + * Copyright (c) 2011, JANET(UK)
7236 + * All rights reserved.
7237 + *
7238 + * Redistribution and use in source and binary forms, with or without
7239 + * modification, are permitted provided that the following conditions
7240 + * are met:
7241 + *
7242 + * 1. Redistributions of source code must retain the above copyright
7243 + *    notice, this list of conditions and the following disclaimer.
7244 + *
7245 + * 2. Redistributions in binary form must reproduce the above copyright
7246 + *    notice, this list of conditions and the following disclaimer in the
7247 + *    documentation and/or other materials provided with the distribution.
7248 + *
7249 + * 3. Neither the name of JANET(UK) nor the names of its contributors
7250 + *    may be used to endorse or promote products derived from this software
7251 + *    without specific prior written permission.
7252 + *
7253 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
7254 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7255 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7256 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7257 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7258 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
7259 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
7260 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
7261 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
7262 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7263 + * SUCH DAMAGE.
7264 + */
7265 +
7266 +/*
7267 + * Enumerate the features supported by the GSS EAP mechanism.
7268 + */
7269 +
7270 +#include "gssapiP_eap.h"
7271 +
7272 +#define MA_ADD(ma, set)    do { \
7273 +    major = gss_add_oid_set_member(minor, (gss_OID)(ma), (set));            \
7274 +    if (GSS_ERROR(major))                                                   \
7275 +        goto cleanup;                                                       \
7276 +    } while (0)
7277 +
7278 +#define MA_SUPPORTED(ma)    MA_ADD((ma), mech_attrs)
7279 +#define MA_KNOWN(ma)        MA_ADD((ma), known_mech_attrs)
7280 +
7281 +OM_uint32 GSSAPI_CALLCONV
7282 +gss_inquire_attrs_for_mech(OM_uint32 *minor,
7283 +                           gss_const_OID mech_oid,
7284 +                           gss_OID_set *mech_attrs,
7285 +                           gss_OID_set *known_mech_attrs)
7286 +{
7287 +    OM_uint32 major, tmpMinor;
7288 +
7289 +    if (mech_attrs != NULL)
7290 +        *mech_attrs = GSS_C_NO_OID_SET;
7291 +    if (known_mech_attrs != NULL)
7292 +        *known_mech_attrs = GSS_C_NO_OID_SET;
7293 +
7294 +    if (!gssEapIsConcreteMechanismOid((const gss_OID)mech_oid)) {
7295 +        *minor = GSSEAP_WRONG_MECH;
7296 +        return GSS_S_BAD_MECH;
7297 +    }
7298 +
7299 +    if (mech_attrs != NULL) {
7300 +        major = gss_create_empty_oid_set(minor, mech_attrs);
7301 +        if (GSS_ERROR(major))
7302 +            goto cleanup;
7303 +
7304 +#ifdef HAVE_GSS_INQUIRE_ATTRS_FOR_MECH
7305 +        if (oidEqual(mech_oid, GSS_EAP_MECHANISM))
7306 +            MA_SUPPORTED(GSS_C_MA_MECH_PSEUDO);
7307 +        else
7308 +            MA_SUPPORTED(GSS_C_MA_MECH_CONCRETE);
7309 +        MA_SUPPORTED(GSS_C_MA_ITOK_FRAMED);
7310 +        MA_SUPPORTED(GSS_C_MA_AUTH_INIT);
7311 +        MA_SUPPORTED(GSS_C_MA_AUTH_TARG);
7312 +        MA_SUPPORTED(GSS_C_MA_AUTH_INIT_INIT);
7313 +        MA_SUPPORTED(GSS_C_MA_INTEG_PROT);
7314 +        MA_SUPPORTED(GSS_C_MA_CONF_PROT);
7315 +        MA_SUPPORTED(GSS_C_MA_MIC);
7316 +        MA_SUPPORTED(GSS_C_MA_WRAP);
7317 +        MA_SUPPORTED(GSS_C_MA_REPLAY_DET);
7318 +        MA_SUPPORTED(GSS_C_MA_OOS_DET);
7319 +        MA_SUPPORTED(GSS_C_MA_CBINDINGS);
7320 +        MA_SUPPORTED(GSS_C_MA_CTX_TRANS);
7321 +#endif
7322 +    }
7323 +
7324 +    if (known_mech_attrs != NULL) {
7325 +        major = gss_create_empty_oid_set(minor, known_mech_attrs);
7326 +        if (GSS_ERROR(major))
7327 +            goto cleanup;
7328 +
7329 +#ifdef HAVE_GSS_INQUIRE_ATTRS_FOR_MECH
7330 +        MA_KNOWN(GSS_C_MA_MECH_CONCRETE);
7331 +        MA_KNOWN(GSS_C_MA_MECH_PSEUDO);
7332 +        MA_KNOWN(GSS_C_MA_MECH_COMPOSITE);
7333 +        MA_KNOWN(GSS_C_MA_MECH_NEGO);
7334 +        MA_KNOWN(GSS_C_MA_MECH_GLUE);
7335 +        MA_KNOWN(GSS_C_MA_NOT_MECH);
7336 +        MA_KNOWN(GSS_C_MA_DEPRECATED);
7337 +        MA_KNOWN(GSS_C_MA_NOT_DFLT_MECH);
7338 +        MA_KNOWN(GSS_C_MA_ITOK_FRAMED);
7339 +        MA_KNOWN(GSS_C_MA_AUTH_INIT);
7340 +        MA_KNOWN(GSS_C_MA_AUTH_TARG);
7341 +        MA_KNOWN(GSS_C_MA_AUTH_INIT_INIT);
7342 +        MA_KNOWN(GSS_C_MA_AUTH_TARG_INIT);
7343 +        MA_KNOWN(GSS_C_MA_AUTH_INIT_ANON);
7344 +        MA_KNOWN(GSS_C_MA_AUTH_TARG_ANON);
7345 +        MA_KNOWN(GSS_C_MA_DELEG_CRED);
7346 +        MA_KNOWN(GSS_C_MA_INTEG_PROT);
7347 +        MA_KNOWN(GSS_C_MA_CONF_PROT);
7348 +        MA_KNOWN(GSS_C_MA_MIC);
7349 +        MA_KNOWN(GSS_C_MA_WRAP);
7350 +        MA_KNOWN(GSS_C_MA_PROT_READY);
7351 +        MA_KNOWN(GSS_C_MA_REPLAY_DET);
7352 +        MA_KNOWN(GSS_C_MA_OOS_DET);
7353 +        MA_KNOWN(GSS_C_MA_CBINDINGS);
7354 +        MA_KNOWN(GSS_C_MA_PFS);
7355 +        MA_KNOWN(GSS_C_MA_COMPRESS);
7356 +        MA_KNOWN(GSS_C_MA_CTX_TRANS);
7357 +#endif
7358 +    }
7359 +
7360 +    major = GSS_S_COMPLETE;
7361 +    *minor = 0;
7362 +
7363 +cleanup:
7364 +    if (GSS_ERROR(major)) {
7365 +        gss_release_oid_set(&tmpMinor, mech_attrs);
7366 +        gss_release_oid_set(&tmpMinor, known_mech_attrs);
7367 +    }
7368 +
7369 +    return major;
7370 +}
7371 diff --git a/mech_eap/inquire_context.c b/mech_eap/inquire_context.c
7372 new file mode 100644
7373 index 0000000..d37818d
7374 --- /dev/null
7375 +++ b/mech_eap/inquire_context.c
7376 @@ -0,0 +1,116 @@
7377 +/*
7378 + * Copyright (c) 2011, JANET(UK)
7379 + * All rights reserved.
7380 + *
7381 + * Redistribution and use in source and binary forms, with or without
7382 + * modification, are permitted provided that the following conditions
7383 + * are met:
7384 + *
7385 + * 1. Redistributions of source code must retain the above copyright
7386 + *    notice, this list of conditions and the following disclaimer.
7387 + *
7388 + * 2. Redistributions in binary form must reproduce the above copyright
7389 + *    notice, this list of conditions and the following disclaimer in the
7390 + *    documentation and/or other materials provided with the distribution.
7391 + *
7392 + * 3. Neither the name of JANET(UK) nor the names of its contributors
7393 + *    may be used to endorse or promote products derived from this software
7394 + *    without specific prior written permission.
7395 + *
7396 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
7397 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7398 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7399 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7400 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7401 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
7402 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
7403 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
7404 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
7405 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7406 + * SUCH DAMAGE.
7407 + */
7408 +
7409 +/*
7410 + * Return context handle properties.
7411 + */
7412 +
7413 +#include "gssapiP_eap.h"
7414 +
7415 +OM_uint32 GSSAPI_CALLCONV
7416 +gss_inquire_context(OM_uint32 *minor,
7417 +                    gss_ctx_id_t ctx,
7418 +                    gss_name_t *src_name,
7419 +                    gss_name_t *targ_name,
7420 +                    OM_uint32 *lifetime_rec,
7421 +                    gss_OID *mech_type,
7422 +                    OM_uint32 *ctx_flags,
7423 +                    int *locally_initiated,
7424 +                    int *open)
7425 +{
7426 +    OM_uint32 major, tmpMinor;
7427 +
7428 +    if (ctx == GSS_C_NO_CONTEXT) {
7429 +        *minor = EINVAL;
7430 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
7431 +    }
7432 +
7433 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
7434 +
7435 +    if (src_name != NULL) {
7436 +        major = gssEapDuplicateName(minor, ctx->initiatorName, src_name);
7437 +        if (GSS_ERROR(major))
7438 +            goto cleanup;
7439 +    }
7440 +
7441 +    if (targ_name != NULL) {
7442 +        major = gssEapDuplicateName(minor, ctx->acceptorName, targ_name);
7443 +        if (GSS_ERROR(major))
7444 +            goto cleanup;
7445 +    }
7446 +
7447 +    if (lifetime_rec != NULL) {
7448 +        time_t now, lifetime;
7449 +
7450 +        if (ctx->expiryTime == 0) {
7451 +            lifetime = GSS_C_INDEFINITE;
7452 +        } else {
7453 +            now = time(NULL);
7454 +            lifetime = now - ctx->expiryTime;
7455 +            if (lifetime < 0)
7456 +                lifetime = 0;
7457 +        }
7458 +
7459 +        *lifetime_rec = lifetime;
7460 +    }
7461 +
7462 +    if (mech_type != NULL) {
7463 +        major = gssEapCanonicalizeOid(minor, ctx->mechanismUsed, 0, mech_type);
7464 +        if (GSS_ERROR(major))
7465 +            goto cleanup;
7466 +    }
7467 +
7468 +    if (ctx_flags != NULL) {
7469 +        *ctx_flags = ctx->gssFlags;
7470 +    }
7471 +
7472 +    if (locally_initiated != NULL) {
7473 +        *locally_initiated = CTX_IS_INITIATOR(ctx);
7474 +    }
7475 +
7476 +    if (open != NULL) {
7477 +        *open = CTX_IS_ESTABLISHED(ctx);
7478 +    }
7479 +
7480 +    major = GSS_S_COMPLETE;
7481 +    *minor = 0;
7482 +
7483 +cleanup:
7484 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
7485 +
7486 +    if (GSS_ERROR(major)) {
7487 +        gssEapReleaseName(&tmpMinor, src_name);
7488 +        gssEapReleaseName(&tmpMinor, targ_name);
7489 +    }
7490 +
7491 +    return major;
7492 +}
7493 diff --git a/mech_eap/inquire_cred.c b/mech_eap/inquire_cred.c
7494 new file mode 100644
7495 index 0000000..227ab16
7496 --- /dev/null
7497 +++ b/mech_eap/inquire_cred.c
7498 @@ -0,0 +1,61 @@
7499 +/*
7500 + * Copyright (c) 2011, JANET(UK)
7501 + * All rights reserved.
7502 + *
7503 + * Redistribution and use in source and binary forms, with or without
7504 + * modification, are permitted provided that the following conditions
7505 + * are met:
7506 + *
7507 + * 1. Redistributions of source code must retain the above copyright
7508 + *    notice, this list of conditions and the following disclaimer.
7509 + *
7510 + * 2. Redistributions in binary form must reproduce the above copyright
7511 + *    notice, this list of conditions and the following disclaimer in the
7512 + *    documentation and/or other materials provided with the distribution.
7513 + *
7514 + * 3. Neither the name of JANET(UK) nor the names of its contributors
7515 + *    may be used to endorse or promote products derived from this software
7516 + *    without specific prior written permission.
7517 + *
7518 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
7519 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7520 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7521 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7522 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7523 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
7524 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
7525 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
7526 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
7527 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7528 + * SUCH DAMAGE.
7529 + */
7530 +
7531 +/*
7532 + * Return credential handle properties.
7533 + */
7534 +
7535 +#include "gssapiP_eap.h"
7536 +
7537 +OM_uint32 GSSAPI_CALLCONV
7538 +gss_inquire_cred(OM_uint32 *minor,
7539 +                 gss_cred_id_t cred,
7540 +                 gss_name_t *name,
7541 +                 OM_uint32 *pLifetime,
7542 +                 gss_cred_usage_t *cred_usage,
7543 +                 gss_OID_set *mechanisms)
7544 +{
7545 +    OM_uint32 major;
7546 +
7547 +    if (cred == NULL) {
7548 +        *minor = EINVAL;
7549 +        return GSS_S_NO_CRED;
7550 +    }
7551 +
7552 +    GSSEAP_MUTEX_LOCK(&cred->mutex);
7553 +
7554 +    major = gssEapInquireCred(minor, cred, name, pLifetime, cred_usage, mechanisms);
7555 +
7556 +    GSSEAP_MUTEX_UNLOCK(&cred->mutex);
7557 +
7558 +    return major;
7559 +}
7560 diff --git a/mech_eap/inquire_cred_by_mech.c b/mech_eap/inquire_cred_by_mech.c
7561 new file mode 100644
7562 index 0000000..191902d
7563 --- /dev/null
7564 +++ b/mech_eap/inquire_cred_by_mech.c
7565 @@ -0,0 +1,76 @@
7566 +/*
7567 + * Copyright (c) 2011, JANET(UK)
7568 + * All rights reserved.
7569 + *
7570 + * Redistribution and use in source and binary forms, with or without
7571 + * modification, are permitted provided that the following conditions
7572 + * are met:
7573 + *
7574 + * 1. Redistributions of source code must retain the above copyright
7575 + *    notice, this list of conditions and the following disclaimer.
7576 + *
7577 + * 2. Redistributions in binary form must reproduce the above copyright
7578 + *    notice, this list of conditions and the following disclaimer in the
7579 + *    documentation and/or other materials provided with the distribution.
7580 + *
7581 + * 3. Neither the name of JANET(UK) nor the names of its contributors
7582 + *    may be used to endorse or promote products derived from this software
7583 + *    without specific prior written permission.
7584 + *
7585 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
7586 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7587 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7588 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7589 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7590 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
7591 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
7592 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
7593 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
7594 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7595 + * SUCH DAMAGE.
7596 + */
7597 +
7598 +/*
7599 + * Return credential handle properties.
7600 + */
7601 +
7602 +#include "gssapiP_eap.h"
7603 +
7604 +OM_uint32 GSSAPI_CALLCONV
7605 +gss_inquire_cred_by_mech(OM_uint32 *minor,
7606 +                         gss_cred_id_t cred,
7607 +                         gss_OID mech_type,
7608 +                         gss_name_t *name,
7609 +                         OM_uint32 *pInitiatorLifetime,
7610 +                         OM_uint32 *pAcceptorLifetime,
7611 +                         gss_cred_usage_t *cred_usage)
7612 +{
7613 +    OM_uint32 major, lifetime;
7614 +
7615 +    if (cred == NULL) {
7616 +        *minor = EINVAL;
7617 +        return GSS_S_NO_CRED;
7618 +    }
7619 +
7620 +    GSSEAP_MUTEX_LOCK(&cred->mutex);
7621 +
7622 +    if (!gssEapCredAvailable(cred, mech_type)) {
7623 +        major = GSS_S_BAD_MECH;
7624 +        *minor = GSSEAP_CRED_MECH_MISMATCH;
7625 +        goto cleanup;
7626 +    }
7627 +
7628 +    major = gssEapInquireCred(minor, cred, name, &lifetime, cred_usage, NULL);
7629 +    if (GSS_ERROR(major))
7630 +        goto cleanup;
7631 +
7632 +    if (pInitiatorLifetime != NULL)
7633 +        *pInitiatorLifetime = (cred->flags & CRED_FLAG_INITIATE) ? lifetime : 0;
7634 +    if (pAcceptorLifetime != NULL)
7635 +        *pAcceptorLifetime = (cred->flags & CRED_FLAG_ACCEPT) ? lifetime : 0;
7636 +
7637 +cleanup:
7638 +    GSSEAP_MUTEX_UNLOCK(&cred->mutex);
7639 +
7640 +    return major;
7641 +}
7642 diff --git a/mech_eap/inquire_cred_by_oid.c b/mech_eap/inquire_cred_by_oid.c
7643 new file mode 100644
7644 index 0000000..2ad34ed
7645 --- /dev/null
7646 +++ b/mech_eap/inquire_cred_by_oid.c
7647 @@ -0,0 +1,83 @@
7648 +/*
7649 + * Copyright (c) 2011, JANET(UK)
7650 + * All rights reserved.
7651 + *
7652 + * Redistribution and use in source and binary forms, with or without
7653 + * modification, are permitted provided that the following conditions
7654 + * are met:
7655 + *
7656 + * 1. Redistributions of source code must retain the above copyright
7657 + *    notice, this list of conditions and the following disclaimer.
7658 + *
7659 + * 2. Redistributions in binary form must reproduce the above copyright
7660 + *    notice, this list of conditions and the following disclaimer in the
7661 + *    documentation and/or other materials provided with the distribution.
7662 + *
7663 + * 3. Neither the name of JANET(UK) nor the names of its contributors
7664 + *    may be used to endorse or promote products derived from this software
7665 + *    without specific prior written permission.
7666 + *
7667 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
7668 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7669 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7670 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7671 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7672 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
7673 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
7674 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
7675 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
7676 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7677 + * SUCH DAMAGE.
7678 + */
7679 +
7680 +/*
7681 + * Return extended credential handle properties.
7682 + */
7683 +
7684 +#include "gssapiP_eap.h"
7685 +
7686 +#if 0
7687 +static struct {
7688 +    gss_OID_desc oid;
7689 +    OM_uint32 (*inquire)(OM_uint32 *, const gss_cred_id_t,
7690 +                         const gss_OID, gss_buffer_set_t *);
7691 +} inquireCredOps[] = {
7692 +};
7693 +#endif
7694 +
7695 +OM_uint32 GSSAPI_CALLCONV
7696 +gss_inquire_cred_by_oid(OM_uint32 *minor,
7697 +                        const gss_cred_id_t cred_handle,
7698 +                        const gss_OID desired_object GSSEAP_UNUSED,
7699 +                        gss_buffer_set_t *data_set)
7700 +{
7701 +    OM_uint32 major;
7702 +#if 0
7703 +    int i;
7704 +#endif
7705 +    *data_set = GSS_C_NO_BUFFER_SET;
7706 +
7707 +    if (cred_handle == GSS_C_NO_CREDENTIAL) {
7708 +        *minor = EINVAL;
7709 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED;
7710 +    }
7711 +
7712 +    GSSEAP_MUTEX_LOCK(&cred_handle->mutex);
7713 +
7714 +    major = GSS_S_UNAVAILABLE;
7715 +    *minor = GSSEAP_BAD_CRED_OPTION;
7716 +
7717 +#if 0
7718 +    for (i = 0; i < sizeof(inquireCredOps) / sizeof(inquireCredOps[0]); i++) {
7719 +        if (oidEqual(&inquireCredOps[i].oid, desired_object)) {
7720 +            major = (*inquireCredOps[i].inquire)(minor, cred_handle,
7721 +                                                 desired_object, data_set);
7722 +            break;
7723 +        }
7724 +    }
7725 +#endif
7726 +
7727 +    GSSEAP_MUTEX_UNLOCK(&cred_handle->mutex);
7728 +
7729 +    return major;
7730 +}
7731 diff --git a/mech_eap/inquire_mech_for_saslname.c b/mech_eap/inquire_mech_for_saslname.c
7732 new file mode 100644
7733 index 0000000..bd518c0
7734 --- /dev/null
7735 +++ b/mech_eap/inquire_mech_for_saslname.c
7736 @@ -0,0 +1,84 @@
7737 +/*
7738 + * Copyright (c) 2011, JANET(UK)
7739 + * All rights reserved.
7740 + *
7741 + * Redistribution and use in source and binary forms, with or without
7742 + * modification, are permitted provided that the following conditions
7743 + * are met:
7744 + *
7745 + * 1. Redistributions of source code must retain the above copyright
7746 + *    notice, this list of conditions and the following disclaimer.
7747 + *
7748 + * 2. Redistributions in binary form must reproduce the above copyright
7749 + *    notice, this list of conditions and the following disclaimer in the
7750 + *    documentation and/or other materials provided with the distribution.
7751 + *
7752 + * 3. Neither the name of JANET(UK) nor the names of its contributors
7753 + *    may be used to endorse or promote products derived from this software
7754 + *    without specific prior written permission.
7755 + *
7756 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
7757 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7758 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7759 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7760 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7761 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
7762 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
7763 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
7764 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
7765 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7766 + * SUCH DAMAGE.
7767 + */
7768 +
7769 +/*
7770 + * Map mechanism OID to a SASL mechanism name.
7771 + */
7772 +
7773 +#include "gssapiP_eap.h"
7774 +
7775 +OM_uint32 GSSAPI_CALLCONV
7776 +gss_inquire_saslname_for_mech(OM_uint32 *minor,
7777 +                              const gss_OID mech,
7778 +                              gss_buffer_t sasl_mech_name,
7779 +                              gss_buffer_t mech_name,
7780 +                              gss_buffer_t mech_description)
7781 +{
7782 +    OM_uint32 major;
7783 +    gss_buffer_t name;
7784 +    krb5_enctype etype = ENCTYPE_NULL;
7785 +
7786 +    /* Dynamically construct mechanism name from Kerberos string enctype */
7787 +    major = gssEapOidToEnctype(minor, mech, &etype);
7788 +    if (GSS_ERROR(major))
7789 +        return major;
7790 +
7791 +    if (mech_name != GSS_C_NO_BUFFER) {
7792 +        krb5_context krbContext;
7793 +
7794 +        GSSEAP_KRB_INIT(&krbContext);
7795 +
7796 +        *minor = krbEnctypeToString(krbContext, etype, "eap-", mech_name);
7797 +        if (*minor != 0)
7798 +            return GSS_S_FAILURE;
7799 +    }
7800 +
7801 +    if (mech_description != GSS_C_NO_BUFFER) {
7802 +        major = makeStringBuffer(minor,
7803 +                                 "Extensible Authentication Protocol GSS-API Mechanism",
7804 +                                 mech_description);
7805 +        if (GSS_ERROR(major))
7806 +            return major;
7807 +    }
7808 +
7809 +    if (sasl_mech_name != GSS_C_NO_BUFFER) {
7810 +        name = gssEapOidToSaslName(mech);
7811 +        if (name == GSS_C_NO_BUFFER) {
7812 +            major = GSS_S_BAD_MECH;
7813 +            *minor = GSSEAP_WRONG_MECH;
7814 +        } else {
7815 +            major = duplicateBuffer(minor, name, sasl_mech_name);
7816 +        }
7817 +    }
7818 +
7819 +    return major;
7820 +}
7821 diff --git a/mech_eap/inquire_mechs_for_name.c b/mech_eap/inquire_mechs_for_name.c
7822 new file mode 100644
7823 index 0000000..89c869c
7824 --- /dev/null
7825 +++ b/mech_eap/inquire_mechs_for_name.c
7826 @@ -0,0 +1,69 @@
7827 +/*
7828 + * Copyright (c) 2011, JANET(UK)
7829 + * All rights reserved.
7830 + *
7831 + * Redistribution and use in source and binary forms, with or without
7832 + * modification, are permitted provided that the following conditions
7833 + * are met:
7834 + *
7835 + * 1. Redistributions of source code must retain the above copyright
7836 + *    notice, this list of conditions and the following disclaimer.
7837 + *
7838 + * 2. Redistributions in binary form must reproduce the above copyright
7839 + *    notice, this list of conditions and the following disclaimer in the
7840 + *    documentation and/or other materials provided with the distribution.
7841 + *
7842 + * 3. Neither the name of JANET(UK) nor the names of its contributors
7843 + *    may be used to endorse or promote products derived from this software
7844 + *    without specific prior written permission.
7845 + *
7846 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
7847 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7848 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7849 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7850 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7851 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
7852 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
7853 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
7854 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
7855 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7856 + * SUCH DAMAGE.
7857 + */
7858 +
7859 +/*
7860 + * Determine mechanism OIDs supported by name.
7861 + */
7862 +
7863 +#include "gssapiP_eap.h"
7864 +
7865 +OM_uint32 GSSAPI_CALLCONV
7866 +gss_inquire_mechs_for_name(OM_uint32 *minor,
7867 +                           const gss_name_t input_name,
7868 +                           gss_OID_set *mech_types)
7869 +{
7870 +    OM_uint32 major, tmpMinor;
7871 +
7872 +    *minor = 0;
7873 +    *mech_types = GSS_C_NO_OID_SET;
7874 +
7875 +    if (input_name != GSS_C_NO_NAME &&
7876 +        input_name->mechanismUsed != GSS_C_NO_OID) {
7877 +        major = gss_create_empty_oid_set(minor, mech_types);
7878 +        if (GSS_ERROR(major))
7879 +            return major;
7880 +
7881 +        major = gss_add_oid_set_member(minor,
7882 +                                       input_name->mechanismUsed,
7883 +                                       mech_types);
7884 +        if (GSS_ERROR(major)) {
7885 +            gss_release_oid_set(&tmpMinor, mech_types);
7886 +            return major;
7887 +        }
7888 +    } else {
7889 +        major = gssEapIndicateMechs(minor, mech_types);
7890 +        if (GSS_ERROR(major))
7891 +            return major;
7892 +    }
7893 +
7894 +    return major;
7895 +}
7896 diff --git a/mech_eap/inquire_name.c b/mech_eap/inquire_name.c
7897 new file mode 100644
7898 index 0000000..78b08a0
7899 --- /dev/null
7900 +++ b/mech_eap/inquire_name.c
7901 @@ -0,0 +1,75 @@
7902 +/*
7903 + * Copyright (c) 2011, JANET(UK)
7904 + * All rights reserved.
7905 + *
7906 + * Redistribution and use in source and binary forms, with or without
7907 + * modification, are permitted provided that the following conditions
7908 + * are met:
7909 + *
7910 + * 1. Redistributions of source code must retain the above copyright
7911 + *    notice, this list of conditions and the following disclaimer.
7912 + *
7913 + * 2. Redistributions in binary form must reproduce the above copyright
7914 + *    notice, this list of conditions and the following disclaimer in the
7915 + *    documentation and/or other materials provided with the distribution.
7916 + *
7917 + * 3. Neither the name of JANET(UK) nor the names of its contributors
7918 + *    may be used to endorse or promote products derived from this software
7919 + *    without specific prior written permission.
7920 + *
7921 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
7922 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7923 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7924 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7925 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7926 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
7927 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
7928 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
7929 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
7930 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7931 + * SUCH DAMAGE.
7932 + */
7933 +
7934 +/*
7935 + * Enumerate name attributes.
7936 + */
7937 +
7938 +#include "gssapiP_eap.h"
7939 +
7940 +OM_uint32 GSSAPI_CALLCONV
7941 +gss_inquire_name(OM_uint32 *minor,
7942 +                 gss_name_t name,
7943 +                 int *name_is_MN,
7944 +                 gss_OID *MN_mech,
7945 +                 gss_buffer_set_t *attrs)
7946 +{
7947 +    OM_uint32 major, tmpMinor;
7948 +
7949 +    *minor = 0;
7950 +
7951 +    if (name_is_MN != NULL)
7952 +        *name_is_MN = 0;
7953 +    if (MN_mech != NULL)
7954 +        *MN_mech = GSS_C_NO_OID;
7955 +    if (attrs != NULL)
7956 +        *attrs = GSS_C_NO_BUFFER_SET;
7957 +
7958 +    if (name == GSS_C_NO_NAME) {
7959 +        *minor = EINVAL;
7960 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
7961 +    }
7962 +
7963 +    if (attrs == NULL)
7964 +        return GSS_S_COMPLETE;
7965 +
7966 +    GSSEAP_MUTEX_LOCK(&name->mutex);
7967 +
7968 +    major = gssEapInquireName(minor, name, name_is_MN, MN_mech, attrs);
7969 +
7970 +    GSSEAP_MUTEX_UNLOCK(&name->mutex);
7971 +
7972 +    if (GSS_ERROR(major))
7973 +        gss_release_buffer_set(&tmpMinor, attrs);
7974 +
7975 +    return major;
7976 +}
7977 diff --git a/mech_eap/inquire_names_for_mech.c b/mech_eap/inquire_names_for_mech.c
7978 new file mode 100644
7979 index 0000000..0e60340
7980 --- /dev/null
7981 +++ b/mech_eap/inquire_names_for_mech.c
7982 @@ -0,0 +1,77 @@
7983 +/*
7984 + * Copyright (c) 2011, JANET(UK)
7985 + * All rights reserved.
7986 + *
7987 + * Redistribution and use in source and binary forms, with or without
7988 + * modification, are permitted provided that the following conditions
7989 + * are met:
7990 + *
7991 + * 1. Redistributions of source code must retain the above copyright
7992 + *    notice, this list of conditions and the following disclaimer.
7993 + *
7994 + * 2. Redistributions in binary form must reproduce the above copyright
7995 + *    notice, this list of conditions and the following disclaimer in the
7996 + *    documentation and/or other materials provided with the distribution.
7997 + *
7998 + * 3. Neither the name of JANET(UK) nor the names of its contributors
7999 + *    may be used to endorse or promote products derived from this software
8000 + *    without specific prior written permission.
8001 + *
8002 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
8003 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
8004 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
8005 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
8006 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
8007 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
8008 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
8009 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
8010 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
8011 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
8012 + * SUCH DAMAGE.
8013 + */
8014 +
8015 +/*
8016 + * Return supported name OID types.
8017 + */
8018 +
8019 +#include "gssapiP_eap.h"
8020 +
8021 +OM_uint32 GSSAPI_CALLCONV
8022 +gss_inquire_names_for_mech(OM_uint32 *minor,
8023 +                           gss_OID mechanism,
8024 +                           gss_OID_set *ret_name_types)
8025 +{
8026 +    OM_uint32 major, tmpMinor;
8027 +    gss_OID nameTypes[] = {
8028 +        GSS_C_NT_USER_NAME,
8029 +        GSS_C_NT_HOSTBASED_SERVICE,
8030 +        GSS_C_NT_EXPORT_NAME,
8031 +#ifdef HAVE_GSS_C_NT_COMPOSITE_EXPORT
8032 +        GSS_C_NT_COMPOSITE_EXPORT,
8033 +#endif
8034 +        GSS_EAP_NT_EAP_NAME,
8035 +        GSS_C_NT_ANONYMOUS,
8036 +    };
8037 +    size_t i;
8038 +
8039 +    if (!gssEapIsMechanismOid(mechanism)) {
8040 +        *minor = GSSEAP_WRONG_MECH;
8041 +        return GSS_S_BAD_MECH;
8042 +    }
8043 +
8044 +    major = gss_create_empty_oid_set(minor, ret_name_types);
8045 +    if (GSS_ERROR(major))
8046 +        goto cleanup;
8047 +
8048 +    for (i = 0; i < sizeof(nameTypes)/sizeof(nameTypes[0]); i++) {
8049 +        major = gss_add_oid_set_member(minor, nameTypes[i], ret_name_types);
8050 +        if (GSS_ERROR(major))
8051 +            goto cleanup;
8052 +    }
8053 +
8054 +cleanup:
8055 +    if (GSS_ERROR(major))
8056 +        gss_release_oid_set(&tmpMinor, ret_name_types);
8057 +
8058 +    return major;
8059 +}
8060 diff --git a/mech_eap/inquire_saslname_for_mech.c b/mech_eap/inquire_saslname_for_mech.c
8061 new file mode 100644
8062 index 0000000..d6d7c14
8063 --- /dev/null
8064 +++ b/mech_eap/inquire_saslname_for_mech.c
8065 @@ -0,0 +1,51 @@
8066 +/*
8067 + * Copyright (c) 2011, JANET(UK)
8068 + * All rights reserved.
8069 + *
8070 + * Redistribution and use in source and binary forms, with or without
8071 + * modification, are permitted provided that the following conditions
8072 + * are met:
8073 + *
8074 + * 1. Redistributions of source code must retain the above copyright
8075 + *    notice, this list of conditions and the following disclaimer.
8076 + *
8077 + * 2. Redistributions in binary form must reproduce the above copyright
8078 + *    notice, this list of conditions and the following disclaimer in the
8079 + *    documentation and/or other materials provided with the distribution.
8080 + *
8081 + * 3. Neither the name of JANET(UK) nor the names of its contributors
8082 + *    may be used to endorse or promote products derived from this software
8083 + *    without specific prior written permission.
8084 + *
8085 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
8086 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
8087 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
8088 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
8089 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
8090 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
8091 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
8092 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
8093 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
8094 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
8095 + * SUCH DAMAGE.
8096 + */
8097 +
8098 +/*
8099 + * Map SASL mechanism name to a mechanism OID.
8100 + */
8101 +
8102 +#include "gssapiP_eap.h"
8103 +
8104 +OM_uint32 GSSAPI_CALLCONV
8105 +gss_inquire_mech_for_saslname(OM_uint32 *minor,
8106 +                              const gss_buffer_t sasl_mech_name,
8107 +                              gss_OID *mech_type)
8108 +{
8109 +    *mech_type = gssEapSaslNameToOid(sasl_mech_name);
8110 +    if (*mech_type == GSS_C_NO_OID) {
8111 +        *minor = GSSEAP_WRONG_MECH;
8112 +        return GSS_S_BAD_MECH;
8113 +    }
8114 +
8115 +    return GSS_S_COMPLETE;
8116 +}
8117 diff --git a/mech_eap/inquire_sec_context_by_oid.c b/mech_eap/inquire_sec_context_by_oid.c
8118 new file mode 100644
8119 index 0000000..7435f2e
8120 --- /dev/null
8121 +++ b/mech_eap/inquire_sec_context_by_oid.c
8122 @@ -0,0 +1,248 @@
8123 +/*
8124 + * Copyright (c) 2011, JANET(UK)
8125 + * All rights reserved.
8126 + *
8127 + * Redistribution and use in source and binary forms, with or without
8128 + * modification, are permitted provided that the following conditions
8129 + * are met:
8130 + *
8131 + * 1. Redistributions of source code must retain the above copyright
8132 + *    notice, this list of conditions and the following disclaimer.
8133 + *
8134 + * 2. Redistributions in binary form must reproduce the above copyright
8135 + *    notice, this list of conditions and the following disclaimer in the
8136 + *    documentation and/or other materials provided with the distribution.
8137 + *
8138 + * 3. Neither the name of JANET(UK) nor the names of its contributors
8139 + *    may be used to endorse or promote products derived from this software
8140 + *    without specific prior written permission.
8141 + *
8142 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
8143 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
8144 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
8145 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
8146 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
8147 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
8148 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
8149 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
8150 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
8151 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
8152 + * SUCH DAMAGE.
8153 + */
8154 +
8155 +/*
8156 + * Return extended properties of a context handle.
8157 + */
8158 +
8159 +#include "gssapiP_eap.h"
8160 +
8161 +static OM_uint32
8162 +addEnctypeOidToBufferSet(OM_uint32 *minor,
8163 +                         krb5_enctype encryptionType,
8164 +                         gss_buffer_set_t *dataSet)
8165 +{
8166 +    OM_uint32 major;
8167 +    unsigned char oidBuf[16];
8168 +    gss_OID_desc oid;
8169 +    gss_buffer_desc buf;
8170 +
8171 +    oid.length = sizeof(oidBuf);
8172 +    oid.elements = oidBuf;
8173 +
8174 +    major = composeOid(minor,
8175 +                       "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04",
8176 +                       10,
8177 +                       encryptionType,
8178 +                       &oid);
8179 +    if (GSS_ERROR(major))
8180 +        return major;
8181 +
8182 +    buf.length = oid.length;
8183 +    buf.value = oid.elements;
8184 +
8185 +    major = gss_add_buffer_set_member(minor, &buf, dataSet);
8186 +
8187 +    return major;
8188 +}
8189 +
8190 +static void
8191 +zeroAndReleaseBufferSet(gss_buffer_set_t *dataSet)
8192 +{
8193 +    OM_uint32 tmpMinor;
8194 +    gss_buffer_set_t set = *dataSet;
8195 +    size_t i;
8196 +
8197 +    if (set == GSS_C_NO_BUFFER_SET)
8198 +        return;
8199 +
8200 +    for (i = 0; i <set->count; i++)
8201 +        memset(set->elements[i].value, 0, set->elements[i].length);
8202 +
8203 +    gss_release_buffer_set(&tmpMinor, dataSet);
8204 +}
8205 +
8206 +static OM_uint32
8207 +inquireSessionKey(OM_uint32 *minor,
8208 +                  const gss_ctx_id_t ctx,
8209 +                  const gss_OID desired_object GSSEAP_UNUSED,
8210 +                  gss_buffer_set_t *dataSet)
8211 +{
8212 +    OM_uint32 major;
8213 +    gss_buffer_desc buf;
8214 +
8215 +    if (ctx->encryptionType == ENCTYPE_NULL) {
8216 +        major = GSS_S_UNAVAILABLE;
8217 +        *minor = GSSEAP_KEY_UNAVAILABLE;
8218 +        goto cleanup;
8219 +    }
8220 +
8221 +    buf.length = KRB_KEY_LENGTH(&ctx->rfc3961Key);
8222 +    buf.value = KRB_KEY_DATA(&ctx->rfc3961Key);
8223 +
8224 +    major = gss_add_buffer_set_member(minor, &buf, dataSet);
8225 +    if (GSS_ERROR(major))
8226 +        goto cleanup;
8227 +
8228 +    major = addEnctypeOidToBufferSet(minor, ctx->encryptionType, dataSet);
8229 +    if (GSS_ERROR(major))
8230 +        goto cleanup;
8231 +
8232 +    major = GSS_S_COMPLETE;
8233 +    *minor = 0;
8234 +
8235 +cleanup:
8236 +    if (GSS_ERROR(major))
8237 +        zeroAndReleaseBufferSet(dataSet);
8238 +
8239 +    return major;
8240 +}
8241 +
8242 +static OM_uint32
8243 +inquireNegoExKey(OM_uint32 *minor,
8244 +                  const gss_ctx_id_t ctx,
8245 +                  const gss_OID desired_object,
8246 +                  gss_buffer_set_t *dataSet)
8247 +{
8248 +    OM_uint32 major, tmpMinor;
8249 +    int bInitiatorKey;
8250 +    gss_buffer_desc salt;
8251 +    gss_buffer_desc key = GSS_C_EMPTY_BUFFER;
8252 +    size_t keySize;
8253 +
8254 +    bInitiatorKey = CTX_IS_INITIATOR(ctx);
8255 +
8256 +    if (ctx->encryptionType == ENCTYPE_NULL) {
8257 +        major = GSS_S_UNAVAILABLE;
8258 +        *minor = GSSEAP_KEY_UNAVAILABLE;
8259 +        goto cleanup;
8260 +    }
8261 +
8262 +    /*
8263 +     * If the caller supplied the verify key OID, then we need the acceptor
8264 +     * key if we are the initiator, and vice versa.
8265 +     */
8266 +    if (desired_object->length == 11 &&
8267 +        memcmp(desired_object->elements,
8268 +               "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x07", 11) == 0)
8269 +        bInitiatorKey ^= 1;
8270 +
8271 +    if (bInitiatorKey) {
8272 +        salt.length = NEGOEX_INITIATOR_SALT_LEN;
8273 +        salt.value  = NEGOEX_INITIATOR_SALT;
8274 +    } else {
8275 +        salt.length = NEGOEX_ACCEPTOR_SALT_LEN;
8276 +        salt.value  = NEGOEX_ACCEPTOR_SALT;
8277 +    }
8278 +
8279 +    keySize = KRB_KEY_LENGTH(&ctx->rfc3961Key);
8280 +
8281 +    major = gssEapPseudoRandom(minor, ctx, GSS_C_PRF_KEY_FULL, &salt,
8282 +                               keySize, &key);
8283 +    if (GSS_ERROR(major))
8284 +        goto cleanup;
8285 +
8286 +    major = gss_add_buffer_set_member(minor, &key, dataSet);
8287 +    if (GSS_ERROR(major))
8288 +        goto cleanup;
8289 +
8290 +    major = addEnctypeOidToBufferSet(minor, ctx->encryptionType, dataSet);
8291 +    if (GSS_ERROR(major))
8292 +        goto cleanup;
8293 +
8294 +    major = GSS_S_COMPLETE;
8295 +    *minor = 0;
8296 +
8297 +cleanup:
8298 +    if (key.value != NULL) {
8299 +        memset(key.value, 0, key.length);
8300 +        gss_release_buffer(&tmpMinor, &key);
8301 +    }
8302 +    if (GSS_ERROR(major))
8303 +        zeroAndReleaseBufferSet(dataSet);
8304 +
8305 +    return major;
8306 +}
8307 +
8308 +static struct {
8309 +    gss_OID_desc oid;
8310 +    OM_uint32 (*inquire)(OM_uint32 *, const gss_ctx_id_t,
8311 +                         const gss_OID, gss_buffer_set_t *);
8312 +} inquireCtxOps[] = {
8313 +    {
8314 +        /* GSS_C_INQ_SSPI_SESSION_KEY */
8315 +        { 11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05" },
8316 +        inquireSessionKey
8317 +    },
8318 +    {
8319 +        /* GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT + v1 */
8320 +        { 12, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x06\x01" },
8321 +        gssEapExportLucidSecContext
8322 +    },
8323 +    {
8324 +        /* GSS_C_INQ_NEGOEX_KEY */
8325 +        { 11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x06" },
8326 +        inquireNegoExKey
8327 +    },
8328 +    {
8329 +        /* GSS_C_INQ_NEGOEX_VERIFY_KEY */
8330 +        { 11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x07" },
8331 +        inquireNegoExKey
8332 +    },
8333 +};
8334 +
8335 +OM_uint32 GSSAPI_CALLCONV
8336 +gss_inquire_sec_context_by_oid(OM_uint32 *minor,
8337 +                               const gss_ctx_id_t ctx,
8338 +                               const gss_OID desired_object,
8339 +                               gss_buffer_set_t *data_set)
8340 +{
8341 +    OM_uint32 major;
8342 +    int i;
8343 +
8344 +    *data_set = GSS_C_NO_BUFFER_SET;
8345 +
8346 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
8347 +
8348 +#if 0
8349 +    if (!CTX_IS_ESTABLISHED(ctx)) {
8350 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
8351 +        major = GSS_S_NO_CONTEXT;
8352 +        goto cleanup;
8353 +    }
8354 +#endif
8355 +
8356 +    major = GSS_S_UNAVAILABLE;
8357 +    *minor = GSSEAP_BAD_CONTEXT_OPTION;
8358 +
8359 +    for (i = 0; i < sizeof(inquireCtxOps) / sizeof(inquireCtxOps[0]); i++) {
8360 +        if (oidEqual(&inquireCtxOps[i].oid, desired_object)) {
8361 +            major = (*inquireCtxOps[i].inquire)(minor, ctx,
8362 +                                                 desired_object, data_set);
8363 +            break;
8364 +        }
8365 +    }
8366 +
8367 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
8368 +
8369 +    return major;
8370 +}
8371 diff --git a/mech_eap/install-sh b/mech_eap/install-sh
8372 new file mode 100755
8373 index 0000000..6781b98
8374 --- /dev/null
8375 +++ b/mech_eap/install-sh
8376 @@ -0,0 +1,520 @@
8377 +#!/bin/sh
8378 +# install - install a program, script, or datafile
8379 +
8380 +scriptversion=2009-04-28.21; # UTC
8381 +
8382 +# This originates from X11R5 (mit/util/scripts/install.sh), which was
8383 +# later released in X11R6 (xc/config/util/install.sh) with the
8384 +# following copyright and license.
8385 +#
8386 +# Copyright (C) 1994 X Consortium
8387 +#
8388 +# Permission is hereby granted, free of charge, to any person obtaining a copy
8389 +# of this software and associated documentation files (the "Software"), to
8390 +# deal in the Software without restriction, including without limitation the
8391 +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8392 +# sell copies of the Software, and to permit persons to whom the Software is
8393 +# furnished to do so, subject to the following conditions:
8394 +#
8395 +# The above copyright notice and this permission notice shall be included in
8396 +# all copies or substantial portions of the Software.
8397 +#
8398 +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8399 +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
8400 +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
8401 +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
8402 +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
8403 +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8404 +#
8405 +# Except as contained in this notice, the name of the X Consortium shall not
8406 +# be used in advertising or otherwise to promote the sale, use or other deal-
8407 +# ings in this Software without prior written authorization from the X Consor-
8408 +# tium.
8409 +#
8410 +#
8411 +# FSF changes to this file are in the public domain.
8412 +#
8413 +# Calling this script install-sh is preferred over install.sh, to prevent
8414 +# `make' implicit rules from creating a file called install from it
8415 +# when there is no Makefile.
8416 +#
8417 +# This script is compatible with the BSD install script, but was written
8418 +# from scratch.
8419 +
8420 +nl='
8421 +'
8422 +IFS=" ""       $nl"
8423 +
8424 +# set DOITPROG to echo to test this script
8425 +
8426 +# Don't use :- since 4.3BSD and earlier shells don't like it.
8427 +doit=${DOITPROG-}
8428 +if test -z "$doit"; then
8429 +  doit_exec=exec
8430 +else
8431 +  doit_exec=$doit
8432 +fi
8433 +
8434 +# Put in absolute file names if you don't have them in your path;
8435 +# or use environment vars.
8436 +
8437 +chgrpprog=${CHGRPPROG-chgrp}
8438 +chmodprog=${CHMODPROG-chmod}
8439 +chownprog=${CHOWNPROG-chown}
8440 +cmpprog=${CMPPROG-cmp}
8441 +cpprog=${CPPROG-cp}
8442 +mkdirprog=${MKDIRPROG-mkdir}
8443 +mvprog=${MVPROG-mv}
8444 +rmprog=${RMPROG-rm}
8445 +stripprog=${STRIPPROG-strip}
8446 +
8447 +posix_glob='?'
8448 +initialize_posix_glob='
8449 +  test "$posix_glob" != "?" || {
8450 +    if (set -f) 2>/dev/null; then
8451 +      posix_glob=
8452 +    else
8453 +      posix_glob=:
8454 +    fi
8455 +  }
8456 +'
8457 +
8458 +posix_mkdir=
8459 +
8460 +# Desired mode of installed file.
8461 +mode=0755
8462 +
8463 +chgrpcmd=
8464 +chmodcmd=$chmodprog
8465 +chowncmd=
8466 +mvcmd=$mvprog
8467 +rmcmd="$rmprog -f"
8468 +stripcmd=
8469 +
8470 +src=
8471 +dst=
8472 +dir_arg=
8473 +dst_arg=
8474 +
8475 +copy_on_change=false
8476 +no_target_directory=
8477 +
8478 +usage="\
8479 +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
8480 +   or: $0 [OPTION]... SRCFILES... DIRECTORY
8481 +   or: $0 [OPTION]... -t DIRECTORY SRCFILES...
8482 +   or: $0 [OPTION]... -d DIRECTORIES...
8483 +
8484 +In the 1st form, copy SRCFILE to DSTFILE.
8485 +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
8486 +In the 4th, create DIRECTORIES.
8487 +
8488 +Options:
8489 +     --help     display this help and exit.
8490 +     --version  display version info and exit.
8491 +
8492 +  -c            (ignored)
8493 +  -C            install only if different (preserve the last data modification time)
8494 +  -d            create directories instead of installing files.
8495 +  -g GROUP      $chgrpprog installed files to GROUP.
8496 +  -m MODE       $chmodprog installed files to MODE.
8497 +  -o USER       $chownprog installed files to USER.
8498 +  -s            $stripprog installed files.
8499 +  -t DIRECTORY  install into DIRECTORY.
8500 +  -T            report an error if DSTFILE is a directory.
8501 +
8502 +Environment variables override the default commands:
8503 +  CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
8504 +  RMPROG STRIPPROG
8505 +"
8506 +
8507 +while test $# -ne 0; do
8508 +  case $1 in
8509 +    -c) ;;
8510 +
8511 +    -C) copy_on_change=true;;
8512 +
8513 +    -d) dir_arg=true;;
8514 +
8515 +    -g) chgrpcmd="$chgrpprog $2"
8516 +       shift;;
8517 +
8518 +    --help) echo "$usage"; exit $?;;
8519 +
8520 +    -m) mode=$2
8521 +       case $mode in
8522 +         *' '* | *'    '* | *'
8523 +'*       | *'*'* | *'?'* | *'['*)
8524 +           echo "$0: invalid mode: $mode" >&2
8525 +           exit 1;;
8526 +       esac
8527 +       shift;;
8528 +
8529 +    -o) chowncmd="$chownprog $2"
8530 +       shift;;
8531 +
8532 +    -s) stripcmd=$stripprog;;
8533 +
8534 +    -t) dst_arg=$2
8535 +       shift;;
8536 +
8537 +    -T) no_target_directory=true;;
8538 +
8539 +    --version) echo "$0 $scriptversion"; exit $?;;
8540 +
8541 +    --)        shift
8542 +       break;;
8543 +
8544 +    -*)        echo "$0: invalid option: $1" >&2
8545 +       exit 1;;
8546 +
8547 +    *)  break;;
8548 +  esac
8549 +  shift
8550 +done
8551 +
8552 +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
8553 +  # When -d is used, all remaining arguments are directories to create.
8554 +  # When -t is used, the destination is already specified.
8555 +  # Otherwise, the last argument is the destination.  Remove it from $@.
8556 +  for arg
8557 +  do
8558 +    if test -n "$dst_arg"; then
8559 +      # $@ is not empty: it contains at least $arg.
8560 +      set fnord "$@" "$dst_arg"
8561 +      shift # fnord
8562 +    fi
8563 +    shift # arg
8564 +    dst_arg=$arg
8565 +  done
8566 +fi
8567 +
8568 +if test $# -eq 0; then
8569 +  if test -z "$dir_arg"; then
8570 +    echo "$0: no input file specified." >&2
8571 +    exit 1
8572 +  fi
8573 +  # It's OK to call `install-sh -d' without argument.
8574 +  # This can happen when creating conditional directories.
8575 +  exit 0
8576 +fi
8577 +
8578 +if test -z "$dir_arg"; then
8579 +  trap '(exit $?); exit' 1 2 13 15
8580 +
8581 +  # Set umask so as not to create temps with too-generous modes.
8582 +  # However, 'strip' requires both read and write access to temps.
8583 +  case $mode in
8584 +    # Optimize common cases.
8585 +    *644) cp_umask=133;;
8586 +    *755) cp_umask=22;;
8587 +
8588 +    *[0-7])
8589 +      if test -z "$stripcmd"; then
8590 +       u_plus_rw=
8591 +      else
8592 +       u_plus_rw='% 200'
8593 +      fi
8594 +      cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
8595 +    *)
8596 +      if test -z "$stripcmd"; then
8597 +       u_plus_rw=
8598 +      else
8599 +       u_plus_rw=,u+rw
8600 +      fi
8601 +      cp_umask=$mode$u_plus_rw;;
8602 +  esac
8603 +fi
8604 +
8605 +for src
8606 +do
8607 +  # Protect names starting with `-'.
8608 +  case $src in
8609 +    -*) src=./$src;;
8610 +  esac
8611 +
8612 +  if test -n "$dir_arg"; then
8613 +    dst=$src
8614 +    dstdir=$dst
8615 +    test -d "$dstdir"
8616 +    dstdir_status=$?
8617 +  else
8618 +
8619 +    # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
8620 +    # might cause directories to be created, which would be especially bad
8621 +    # if $src (and thus $dsttmp) contains '*'.
8622 +    if test ! -f "$src" && test ! -d "$src"; then
8623 +      echo "$0: $src does not exist." >&2
8624 +      exit 1
8625 +    fi
8626 +
8627 +    if test -z "$dst_arg"; then
8628 +      echo "$0: no destination specified." >&2
8629 +      exit 1
8630 +    fi
8631 +
8632 +    dst=$dst_arg
8633 +    # Protect names starting with `-'.
8634 +    case $dst in
8635 +      -*) dst=./$dst;;
8636 +    esac
8637 +
8638 +    # If destination is a directory, append the input filename; won't work
8639 +    # if double slashes aren't ignored.
8640 +    if test -d "$dst"; then
8641 +      if test -n "$no_target_directory"; then
8642 +       echo "$0: $dst_arg: Is a directory" >&2
8643 +       exit 1
8644 +      fi
8645 +      dstdir=$dst
8646 +      dst=$dstdir/`basename "$src"`
8647 +      dstdir_status=0
8648 +    else
8649 +      # Prefer dirname, but fall back on a substitute if dirname fails.
8650 +      dstdir=`
8651 +       (dirname "$dst") 2>/dev/null ||
8652 +       expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
8653 +            X"$dst" : 'X\(//\)[^/]' \| \
8654 +            X"$dst" : 'X\(//\)$' \| \
8655 +            X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
8656 +       echo X"$dst" |
8657 +           sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
8658 +                  s//\1/
8659 +                  q
8660 +                }
8661 +                /^X\(\/\/\)[^/].*/{
8662 +                  s//\1/
8663 +                  q
8664 +                }
8665 +                /^X\(\/\/\)$/{
8666 +                  s//\1/
8667 +                  q
8668 +                }
8669 +                /^X\(\/\).*/{
8670 +                  s//\1/
8671 +                  q
8672 +                }
8673 +                s/.*/./; q'
8674 +      `
8675 +
8676 +      test -d "$dstdir"
8677 +      dstdir_status=$?
8678 +    fi
8679 +  fi
8680 +
8681 +  obsolete_mkdir_used=false
8682 +
8683 +  if test $dstdir_status != 0; then
8684 +    case $posix_mkdir in
8685 +      '')
8686 +       # Create intermediate dirs using mode 755 as modified by the umask.
8687 +       # This is like FreeBSD 'install' as of 1997-10-28.
8688 +       umask=`umask`
8689 +       case $stripcmd.$umask in
8690 +         # Optimize common cases.
8691 +         *[2367][2367]) mkdir_umask=$umask;;
8692 +         .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
8693 +
8694 +         *[0-7])
8695 +           mkdir_umask=`expr $umask + 22 \
8696 +             - $umask % 100 % 40 + $umask % 20 \
8697 +             - $umask % 10 % 4 + $umask % 2
8698 +           `;;
8699 +         *) mkdir_umask=$umask,go-w;;
8700 +       esac
8701 +
8702 +       # With -d, create the new directory with the user-specified mode.
8703 +       # Otherwise, rely on $mkdir_umask.
8704 +       if test -n "$dir_arg"; then
8705 +         mkdir_mode=-m$mode
8706 +       else
8707 +         mkdir_mode=
8708 +       fi
8709 +
8710 +       posix_mkdir=false
8711 +       case $umask in
8712 +         *[123567][0-7][0-7])
8713 +           # POSIX mkdir -p sets u+wx bits regardless of umask, which
8714 +           # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
8715 +           ;;
8716 +         *)
8717 +           tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
8718 +           trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
8719 +
8720 +           if (umask $mkdir_umask &&
8721 +               exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
8722 +           then
8723 +             if test -z "$dir_arg" || {
8724 +                  # Check for POSIX incompatibilities with -m.
8725 +                  # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
8726 +                  # other-writeable bit of parent directory when it shouldn't.
8727 +                  # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
8728 +                  ls_ld_tmpdir=`ls -ld "$tmpdir"`
8729 +                  case $ls_ld_tmpdir in
8730 +                    d????-?r-*) different_mode=700;;
8731 +                    d????-?--*) different_mode=755;;
8732 +                    *) false;;
8733 +                  esac &&
8734 +                  $mkdirprog -m$different_mode -p -- "$tmpdir" && {
8735 +                    ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
8736 +                    test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
8737 +                  }
8738 +                }
8739 +             then posix_mkdir=:
8740 +             fi
8741 +             rmdir "$tmpdir/d" "$tmpdir"
8742 +           else
8743 +             # Remove any dirs left behind by ancient mkdir implementations.
8744 +             rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
8745 +           fi
8746 +           trap '' 0;;
8747 +       esac;;
8748 +    esac
8749 +
8750 +    if
8751 +      $posix_mkdir && (
8752 +       umask $mkdir_umask &&
8753 +       $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
8754 +      )
8755 +    then :
8756 +    else
8757 +
8758 +      # The umask is ridiculous, or mkdir does not conform to POSIX,
8759 +      # or it failed possibly due to a race condition.  Create the
8760 +      # directory the slow way, step by step, checking for races as we go.
8761 +
8762 +      case $dstdir in
8763 +       /*) prefix='/';;
8764 +       -*) prefix='./';;
8765 +       *)  prefix='';;
8766 +      esac
8767 +
8768 +      eval "$initialize_posix_glob"
8769 +
8770 +      oIFS=$IFS
8771 +      IFS=/
8772 +      $posix_glob set -f
8773 +      set fnord $dstdir
8774 +      shift
8775 +      $posix_glob set +f
8776 +      IFS=$oIFS
8777 +
8778 +      prefixes=
8779 +
8780 +      for d
8781 +      do
8782 +       test -z "$d" && continue
8783 +
8784 +       prefix=$prefix$d
8785 +       if test -d "$prefix"; then
8786 +         prefixes=
8787 +       else
8788 +         if $posix_mkdir; then
8789 +           (umask=$mkdir_umask &&
8790 +            $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
8791 +           # Don't fail if two instances are running concurrently.
8792 +           test -d "$prefix" || exit 1
8793 +         else
8794 +           case $prefix in
8795 +             *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
8796 +             *) qprefix=$prefix;;
8797 +           esac
8798 +           prefixes="$prefixes '$qprefix'"
8799 +         fi
8800 +       fi
8801 +       prefix=$prefix/
8802 +      done
8803 +
8804 +      if test -n "$prefixes"; then
8805 +       # Don't fail if two instances are running concurrently.
8806 +       (umask $mkdir_umask &&
8807 +        eval "\$doit_exec \$mkdirprog $prefixes") ||
8808 +         test -d "$dstdir" || exit 1
8809 +       obsolete_mkdir_used=true
8810 +      fi
8811 +    fi
8812 +  fi
8813 +
8814 +  if test -n "$dir_arg"; then
8815 +    { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
8816 +    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
8817 +    { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
8818 +      test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
8819 +  else
8820 +
8821 +    # Make a couple of temp file names in the proper directory.
8822 +    dsttmp=$dstdir/_inst.$$_
8823 +    rmtmp=$dstdir/_rm.$$_
8824 +
8825 +    # Trap to clean up those temp files at exit.
8826 +    trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
8827 +
8828 +    # Copy the file name to the temp name.
8829 +    (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
8830 +
8831 +    # and set any options; do chmod last to preserve setuid bits.
8832 +    #
8833 +    # If any of these fail, we abort the whole thing.  If we want to
8834 +    # ignore errors from any of these, just make sure not to ignore
8835 +    # errors from the above "$doit $cpprog $src $dsttmp" command.
8836 +    #
8837 +    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
8838 +    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
8839 +    { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
8840 +    { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
8841 +
8842 +    # If -C, don't bother to copy if it wouldn't change the file.
8843 +    if $copy_on_change &&
8844 +       old=`LC_ALL=C ls -dlL "$dst"    2>/dev/null` &&
8845 +       new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
8846 +
8847 +       eval "$initialize_posix_glob" &&
8848 +       $posix_glob set -f &&
8849 +       set X $old && old=:$2:$4:$5:$6 &&
8850 +       set X $new && new=:$2:$4:$5:$6 &&
8851 +       $posix_glob set +f &&
8852 +
8853 +       test "$old" = "$new" &&
8854 +       $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
8855 +    then
8856 +      rm -f "$dsttmp"
8857 +    else
8858 +      # Rename the file to the real destination.
8859 +      $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
8860 +
8861 +      # The rename failed, perhaps because mv can't rename something else
8862 +      # to itself, or perhaps because mv is so ancient that it does not
8863 +      # support -f.
8864 +      {
8865 +       # Now remove or move aside any old file at destination location.
8866 +       # We try this two ways since rm can't unlink itself on some
8867 +       # systems and the destination file might be busy for other
8868 +       # reasons.  In this case, the final cleanup might fail but the new
8869 +       # file should still install successfully.
8870 +       {
8871 +         test ! -f "$dst" ||
8872 +         $doit $rmcmd -f "$dst" 2>/dev/null ||
8873 +         { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
8874 +           { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
8875 +         } ||
8876 +         { echo "$0: cannot unlink or rename $dst" >&2
8877 +           (exit 1); exit 1
8878 +         }
8879 +       } &&
8880 +
8881 +       # Now rename the file to the real destination.
8882 +       $doit $mvcmd "$dsttmp" "$dst"
8883 +      }
8884 +    fi || exit 1
8885 +
8886 +    trap '' 0
8887 +  fi
8888 +done
8889 +
8890 +# Local variables:
8891 +# eval: (add-hook 'write-file-hooks 'time-stamp)
8892 +# time-stamp-start: "scriptversion="
8893 +# time-stamp-format: "%:y-%02m-%02d.%02H"
8894 +# time-stamp-time-zone: "UTC"
8895 +# time-stamp-end: "; # UTC"
8896 +# End:
8897 diff --git a/mech_eap/map_name_to_any.c b/mech_eap/map_name_to_any.c
8898 new file mode 100644
8899 index 0000000..2a8a96c
8900 --- /dev/null
8901 +++ b/mech_eap/map_name_to_any.c
8902 @@ -0,0 +1,58 @@
8903 +/*
8904 + * Copyright (c) 2011, JANET(UK)
8905 + * All rights reserved.
8906 + *
8907 + * Redistribution and use in source and binary forms, with or without
8908 + * modification, are permitted provided that the following conditions
8909 + * are met:
8910 + *
8911 + * 1. Redistributions of source code must retain the above copyright
8912 + *    notice, this list of conditions and the following disclaimer.
8913 + *
8914 + * 2. Redistributions in binary form must reproduce the above copyright
8915 + *    notice, this list of conditions and the following disclaimer in the
8916 + *    documentation and/or other materials provided with the distribution.
8917 + *
8918 + * 3. Neither the name of JANET(UK) nor the names of its contributors
8919 + *    may be used to endorse or promote products derived from this software
8920 + *    without specific prior written permission.
8921 + *
8922 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
8923 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
8924 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
8925 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
8926 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
8927 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
8928 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
8929 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
8930 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
8931 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
8932 + * SUCH DAMAGE.
8933 + */
8934 +
8935 +#include "gssapiP_eap.h"
8936 +
8937 +OM_uint32 GSSAPI_CALLCONV
8938 +gss_map_name_to_any(OM_uint32 *minor,
8939 +                    gss_name_t name,
8940 +                    int authenticated,
8941 +                    gss_buffer_t type_id,
8942 +                    gss_any_t *output)
8943 +{
8944 +    OM_uint32 major;
8945 +
8946 +    *output = (gss_any_t)NULL;
8947 +
8948 +    if (name == GSS_C_NO_NAME) {
8949 +        *minor = EINVAL;
8950 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
8951 +    }
8952 +
8953 +    GSSEAP_MUTEX_LOCK(&name->mutex);
8954 +
8955 +    major = gssEapMapNameToAny(minor, name, authenticated, type_id, output);
8956 +
8957 +    GSSEAP_MUTEX_UNLOCK(&name->mutex);
8958 +
8959 +    return major;
8960 +}
8961 diff --git a/mech_eap/mech b/mech_eap/mech
8962 new file mode 100644
8963 index 0000000..258a43a
8964 --- /dev/null
8965 +++ b/mech_eap/mech
8966 @@ -0,0 +1,8 @@
8967 +#
8968 +# Sample mechanism glue configuration for EAP GSS mechanism.
8969 +#
8970 +# Any encryption type supported by Kerberos can be defined as the
8971 +# last element of the OID arc.
8972 +#
8973 +eap-aes128             1.3.6.1.4.1.5322.22.1.17        mech_eap.so
8974 +eap-aes256             1.3.6.1.4.1.5322.22.1.18        mech_eap.so
8975 diff --git a/mech_eap/mech_eap-noacceptor.exports b/mech_eap/mech_eap-noacceptor.exports
8976 new file mode 100644
8977 index 0000000..f00df8a
8978 --- /dev/null
8979 +++ b/mech_eap/mech_eap-noacceptor.exports
8980 @@ -0,0 +1,55 @@
8981 +gss_acquire_cred
8982 +gss_add_cred
8983 +gss_add_cred_with_password
8984 +gss_canonicalize_name
8985 +gss_compare_name
8986 +gss_context_time
8987 +gss_delete_sec_context
8988 +gss_display_name
8989 +gss_display_name_ext
8990 +gss_display_status
8991 +gss_duplicate_name
8992 +gss_exchange_meta_data
8993 +gss_export_name
8994 +gss_export_sec_context
8995 +gss_get_mic
8996 +gss_import_name
8997 +gss_import_sec_context
8998 +gss_indicate_mechs
8999 +gss_init_sec_context
9000 +gss_inquire_attrs_for_mech
9001 +gss_inquire_context
9002 +gss_inquire_cred
9003 +gss_inquire_cred_by_mech
9004 +gss_inquire_cred_by_oid
9005 +gss_inquire_mechs_for_name
9006 +gss_inquire_mech_for_saslname
9007 +gss_inquire_names_for_mech
9008 +gss_inquire_saslname_for_mech
9009 +gss_inquire_sec_context_by_oid
9010 +gss_process_context_token
9011 +gss_pseudo_random
9012 +gss_query_mechanism_info
9013 +gss_query_meta_data
9014 +gss_release_cred
9015 +gss_release_name
9016 +gss_internal_release_oid
9017 +gss_set_sec_context_option
9018 +gss_store_cred
9019 +gss_unwrap
9020 +gss_unwrap_iov
9021 +gss_verify_mic
9022 +gss_wrap
9023 +gss_wrap_iov
9024 +gss_wrap_iov_length
9025 +gss_wrap_size_limit
9026 +GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM
9027 +GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM
9028 +GSS_EAP_NT_EAP_NAME
9029 +GSS_EAP_CRED_SET_CRED_FLAG
9030 +GSS_EAP_CRED_SET_CRED_PASSWORD
9031 +GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE
9032 +GSS_EAP_CRED_SET_RADIUS_CONFIG_STANZA
9033 +gssspi_acquire_cred_with_password
9034 +gssspi_authorize_localname
9035 +gssspi_set_cred_option
9036 diff --git a/mech_eap/mech_eap.exports b/mech_eap/mech_eap.exports
9037 new file mode 100644
9038 index 0000000..6a17a17
9039 --- /dev/null
9040 +++ b/mech_eap/mech_eap.exports
9041 @@ -0,0 +1,63 @@
9042 +gss_accept_sec_context
9043 +gss_acquire_cred
9044 +gss_add_cred
9045 +gss_add_cred_with_password
9046 +gss_canonicalize_name
9047 +gss_compare_name
9048 +gss_context_time
9049 +gss_delete_name_attribute
9050 +gss_delete_sec_context
9051 +gss_display_name
9052 +gss_display_name_ext
9053 +gss_display_status
9054 +gss_duplicate_name
9055 +gss_exchange_meta_data
9056 +gss_export_name
9057 +gss_export_name_composite
9058 +gss_export_sec_context
9059 +gss_get_mic
9060 +gss_get_name_attribute
9061 +gss_import_name
9062 +gss_import_sec_context
9063 +gss_indicate_mechs
9064 +gss_init_sec_context
9065 +gss_inquire_attrs_for_mech
9066 +gss_inquire_context
9067 +gss_inquire_cred
9068 +gss_inquire_cred_by_mech
9069 +gss_inquire_cred_by_oid
9070 +gss_inquire_mechs_for_name
9071 +gss_inquire_mech_for_saslname
9072 +gss_inquire_name
9073 +gss_inquire_names_for_mech
9074 +gss_inquire_saslname_for_mech
9075 +gss_inquire_sec_context_by_oid
9076 +gss_map_name_to_any
9077 +gss_process_context_token
9078 +gss_pseudo_random
9079 +gss_query_mechanism_info
9080 +gss_query_meta_data
9081 +gss_release_any_name_mapping
9082 +gss_release_cred
9083 +gss_release_name
9084 +gss_internal_release_oid
9085 +gss_set_name_attribute
9086 +gss_set_sec_context_option
9087 +gss_store_cred
9088 +gss_unwrap
9089 +gss_unwrap_iov
9090 +gss_verify_mic
9091 +gss_wrap
9092 +gss_wrap_iov
9093 +gss_wrap_iov_length
9094 +gss_wrap_size_limit
9095 +GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM
9096 +GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM
9097 +GSS_EAP_NT_EAP_NAME
9098 +GSS_EAP_CRED_SET_CRED_FLAG
9099 +GSS_EAP_CRED_SET_CRED_PASSWORD
9100 +GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE
9101 +GSS_EAP_CRED_SET_RADIUS_CONFIG_STANZA
9102 +gssspi_acquire_cred_with_password
9103 +gssspi_authorize_localname
9104 +gssspi_set_cred_option
9105 diff --git a/mech_eap/mech_invoke.c b/mech_eap/mech_invoke.c
9106 new file mode 100644
9107 index 0000000..bc9bba3
9108 --- /dev/null
9109 +++ b/mech_eap/mech_invoke.c
9110 @@ -0,0 +1,44 @@
9111 +/*
9112 + * Copyright (c) 2011, JANET(UK)
9113 + * All rights reserved.
9114 + *
9115 + * Redistribution and use in source and binary forms, with or without
9116 + * modification, are permitted provided that the following conditions
9117 + * are met:
9118 + *
9119 + * 1. Redistributions of source code must retain the above copyright
9120 + *    notice, this list of conditions and the following disclaimer.
9121 + *
9122 + * 2. Redistributions in binary form must reproduce the above copyright
9123 + *    notice, this list of conditions and the following disclaimer in the
9124 + *    documentation and/or other materials provided with the distribution.
9125 + *
9126 + * 3. Neither the name of JANET(UK) nor the names of its contributors
9127 + *    may be used to endorse or promote products derived from this software
9128 + *    without specific prior written permission.
9129 + *
9130 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
9131 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9132 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9133 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
9134 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9135 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9136 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9137 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9138 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9139 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9140 + * SUCH DAMAGE.
9141 + */
9142 +
9143 +#include "gssapiP_eap.h"
9144 +
9145 +OM_uint32 GSSAPI_CALLCONV
9146 +gssspi_mech_invoke(OM_uint32 *minor,
9147 +                   const gss_OID desired_mech,
9148 +                   const gss_OID desired_object,
9149 +                   gss_buffer_t value)
9150 +{
9151 +    *minor = GSSEAP_BAD_INVOCATION;
9152 +
9153 +    return GSS_S_UNAVAILABLE;
9154 +}
9155 diff --git a/mech_eap/process_context_token.c b/mech_eap/process_context_token.c
9156 new file mode 100644
9157 index 0000000..02a4b6d
9158 --- /dev/null
9159 +++ b/mech_eap/process_context_token.c
9160 @@ -0,0 +1,71 @@
9161 +/*
9162 + * Copyright (c) 2011, JANET(UK)
9163 + * All rights reserved.
9164 + *
9165 + * Redistribution and use in source and binary forms, with or without
9166 + * modification, are permitted provided that the following conditions
9167 + * are met:
9168 + *
9169 + * 1. Redistributions of source code must retain the above copyright
9170 + *    notice, this list of conditions and the following disclaimer.
9171 + *
9172 + * 2. Redistributions in binary form must reproduce the above copyright
9173 + *    notice, this list of conditions and the following disclaimer in the
9174 + *    documentation and/or other materials provided with the distribution.
9175 + *
9176 + * 3. Neither the name of JANET(UK) nor the names of its contributors
9177 + *    may be used to endorse or promote products derived from this software
9178 + *    without specific prior written permission.
9179 + *
9180 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
9181 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9182 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9183 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
9184 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9185 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9186 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9187 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9188 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9189 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9190 + * SUCH DAMAGE.
9191 + */
9192 +
9193 +#include "gssapiP_eap.h"
9194 +
9195 +OM_uint32 GSSAPI_CALLCONV
9196 +gss_process_context_token(OM_uint32 *minor,
9197 +                          gss_ctx_id_t ctx,
9198 +                          gss_buffer_t token_buffer)
9199 +{
9200 +    OM_uint32 major;
9201 +    gss_iov_buffer_desc iov[1];
9202 +
9203 +    *minor = 0;
9204 +
9205 +    if (ctx == NULL) {
9206 +        *minor = EINVAL;
9207 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
9208 +    }
9209 +
9210 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
9211 +
9212 +    if (!CTX_IS_ESTABLISHED(ctx)) {
9213 +        GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
9214 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
9215 +        return GSS_S_NO_CONTEXT;
9216 +    }
9217 +
9218 +    iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
9219 +    iov[0].buffer = *token_buffer;
9220 +
9221 +    major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
9222 +                                    iov, 1, TOK_TYPE_DELETE_CONTEXT);
9223 +    if (GSS_ERROR(major)) {
9224 +        GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
9225 +        return major;
9226 +    }
9227 +
9228 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
9229 +
9230 +    return gssEapReleaseContext(minor, &ctx);
9231 +}
9232 diff --git a/mech_eap/pseudo_random.c b/mech_eap/pseudo_random.c
9233 new file mode 100644
9234 index 0000000..61d1f2a
9235 --- /dev/null
9236 +++ b/mech_eap/pseudo_random.c
9237 @@ -0,0 +1,195 @@
9238 +/*
9239 + * Copyright (c) 2011, JANET(UK)
9240 + * All rights reserved.
9241 + *
9242 + * Redistribution and use in source and binary forms, with or without
9243 + * modification, are permitted provided that the following conditions
9244 + * are met:
9245 + *
9246 + * 1. Redistributions of source code must retain the above copyright
9247 + *    notice, this list of conditions and the following disclaimer.
9248 + *
9249 + * 2. Redistributions in binary form must reproduce the above copyright
9250 + *    notice, this list of conditions and the following disclaimer in the
9251 + *    documentation and/or other materials provided with the distribution.
9252 + *
9253 + * 3. Neither the name of JANET(UK) nor the names of its contributors
9254 + *    may be used to endorse or promote products derived from this software
9255 + *    without specific prior written permission.
9256 + *
9257 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
9258 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9259 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9260 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
9261 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9262 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9263 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9264 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9265 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9266 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9267 + * SUCH DAMAGE.
9268 + */
9269 +/*
9270 + * Copyright 2009 by the Massachusetts Institute of Technology.
9271 + * All Rights Reserved.
9272 + *
9273 + * Export of this software from the United States of America may
9274 + *   require a specific license from the United States Government.
9275 + *   It is the responsibility of any person or organization contemplating
9276 + *   export to obtain such a license before exporting.
9277 + *
9278 + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
9279 + * distribute this software and its documentation for any purpose and
9280 + * without fee is hereby granted, provided that the above copyright
9281 + * notice appear in all copies and that both that copyright notice and
9282 + * this permission notice appear in supporting documentation, and that
9283 + * the name of M.I.T. not be used in advertising or publicity pertaining
9284 + * to distribution of the software without specific, written prior
9285 + * permission.  Furthermore if you modify this software you must label
9286 + * your software as modified software and not distribute it in such a
9287 + * fashion that it might be confused with the original M.I.T. software.
9288 + * M.I.T. makes no representations about the suitability of
9289 + * this software for any purpose.  It is provided "as is" without express
9290 + * or implied warranty.
9291 + */
9292 +
9293 +/*
9294 + * PRF
9295 + */
9296 +
9297 +#include "gssapiP_eap.h"
9298 +
9299 +OM_uint32
9300 +gssEapPseudoRandom(OM_uint32 *minor,
9301 +                   gss_ctx_id_t ctx,
9302 +                   int prf_key,
9303 +                   const gss_buffer_t prf_in,
9304 +                   ssize_t desired_output_len,
9305 +                   gss_buffer_t prf_out)
9306 +{
9307 +    krb5_error_code code;
9308 +    int i;
9309 +    OM_uint32 tmpMinor;
9310 +    size_t prflen;
9311 +    krb5_data t, ns;
9312 +    unsigned char *p;
9313 +    krb5_context krbContext;
9314 +
9315 +    prf_out->length = 0;
9316 +    prf_out->value = NULL;
9317 +
9318 +    *minor = 0;
9319 +
9320 +    GSSEAP_KRB_INIT(&krbContext);
9321 +
9322 +    KRB_DATA_INIT(&t);
9323 +    KRB_DATA_INIT(&ns);
9324 +
9325 +    if (prf_key != GSS_C_PRF_KEY_PARTIAL &&
9326 +        prf_key != GSS_C_PRF_KEY_FULL) {
9327 +        code = GSSEAP_BAD_PRF_KEY;
9328 +        goto cleanup;
9329 +    }
9330 +
9331 +    prf_out->value = GSSEAP_MALLOC(desired_output_len);
9332 +    if (prf_out->value == NULL) {
9333 +        code = ENOMEM;
9334 +        goto cleanup;
9335 +    }
9336 +    prf_out->length = desired_output_len;
9337 +
9338 +    code = krb5_c_prf_length(krbContext,
9339 +                             ctx->encryptionType,
9340 +                             &prflen);
9341 +    if (code != 0)
9342 +        goto cleanup;
9343 +
9344 +    ns.length = 4 + prf_in->length;
9345 +    ns.data = GSSEAP_MALLOC(ns.length);
9346 +    if (ns.data == NULL) {
9347 +        code = ENOMEM;
9348 +        goto cleanup;
9349 +    }
9350 +
9351 +#ifndef HAVE_HEIMDAL_VERSION
9352 +    /* Same API, but different allocation rules, unfortunately. */
9353 +    t.length = prflen;
9354 +    t.data = GSSEAP_MALLOC(t.length);
9355 +    if (t.data == NULL) {
9356 +        code = ENOMEM;
9357 +        goto cleanup;
9358 +    }
9359 +#endif
9360 +
9361 +    memcpy((unsigned char *)ns.data + 4, prf_in->value, prf_in->length);
9362 +    i = 0;
9363 +    p = (unsigned char *)prf_out->value;
9364 +    while (desired_output_len > 0) {
9365 +        store_uint32_be(i, ns.data);
9366 +
9367 +        code = krb5_c_prf(krbContext, &ctx->rfc3961Key, &ns, &t);
9368 +        if (code != 0)
9369 +            goto cleanup;
9370 +
9371 +        memcpy(p, t.data, MIN(t.length, desired_output_len));
9372 +
9373 +        p += t.length;
9374 +        desired_output_len -= t.length;
9375 +        i++;
9376 +    }
9377 +
9378 +cleanup:
9379 +    if (code != 0)
9380 +        gss_release_buffer(&tmpMinor, prf_out);
9381 +    if (ns.data != NULL) {
9382 +        memset(ns.data, 0, ns.length);
9383 +        GSSEAP_FREE(ns.data);
9384 +    }
9385 +#ifdef HAVE_HEIMDAL_VERSION
9386 +    krb5_free_data_contents(krbContext, &t);
9387 +#else
9388 +    if (t.data != NULL) {
9389 +        memset(t.data, 0, t.length);
9390 +        GSSEAP_FREE(t.data);
9391 +    }
9392 +#endif
9393 +
9394 +    *minor = code;
9395 +
9396 +    return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
9397 +}
9398 +
9399 +OM_uint32 GSSAPI_CALLCONV
9400 +gss_pseudo_random(OM_uint32 *minor,
9401 +                  gss_ctx_id_t ctx,
9402 +                  int prf_key,
9403 +                  const gss_buffer_t prf_in,
9404 +                  ssize_t desired_output_len,
9405 +                  gss_buffer_t prf_out)
9406 +{
9407 +    OM_uint32 major;
9408 +
9409 +    if (ctx == GSS_C_NO_CONTEXT) {
9410 +        *minor = EINVAL;
9411 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
9412 +    }
9413 +
9414 +    prf_out->length = 0;
9415 +    prf_out->value = NULL;
9416 +
9417 +    *minor = 0;
9418 +
9419 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
9420 +
9421 +    if (CTX_IS_ESTABLISHED(ctx)) {
9422 +        major = gssEapPseudoRandom(minor, ctx, prf_key,
9423 +                                   prf_in, desired_output_len, prf_out);
9424 +    } else {
9425 +        major = GSS_S_NO_CONTEXT;
9426 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
9427 +    }
9428 +
9429 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
9430 +
9431 +    return major;
9432 +}
9433 diff --git a/mech_eap/query_mechanism_info.c b/mech_eap/query_mechanism_info.c
9434 new file mode 100644
9435 index 0000000..acd3115
9436 --- /dev/null
9437 +++ b/mech_eap/query_mechanism_info.c
9438 @@ -0,0 +1,67 @@
9439 +/*
9440 + * Copyright (c) 2011, JANET(UK)
9441 + * All rights reserved.
9442 + *
9443 + * Redistribution and use in source and binary forms, with or without
9444 + * modification, are permitted provided that the following conditions
9445 + * are met:
9446 + *
9447 + * 1. Redistributions of source code must retain the above copyright
9448 + *    notice, this list of conditions and the following disclaimer.
9449 + *
9450 + * 2. Redistributions in binary form must reproduce the above copyright
9451 + *    notice, this list of conditions and the following disclaimer in the
9452 + *    documentation and/or other materials provided with the distribution.
9453 + *
9454 + * 3. Neither the name of JANET(UK) nor the names of its contributors
9455 + *    may be used to endorse or promote products derived from this software
9456 + *    without specific prior written permission.
9457 + *
9458 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
9459 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9460 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9461 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
9462 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9463 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9464 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9465 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9466 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9467 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9468 + * SUCH DAMAGE.
9469 + */
9470 +
9471 +/*
9472 + *
9473 + */
9474 +
9475 +#include "gssapiP_eap.h"
9476 +
9477 +OM_uint32
9478 +gssQueryMechanismInfo(OM_uint32 *minor,
9479 +                      gss_const_OID mech_oid,
9480 +                      unsigned char auth_scheme[16])
9481 +{
9482 +    OM_uint32 major;
9483 +    krb5_enctype enctype;
9484 +
9485 +    major = gssEapOidToEnctype(minor, (const gss_OID)mech_oid, &enctype);
9486 +    if (GSS_ERROR(major))
9487 +        return major;
9488 +
9489 +    /* the enctype is encoded in the increasing part of the GUID */
9490 +    memcpy(auth_scheme,
9491 +           "\x39\xd7\x7d\x00\xe5\x00\x11\xe0\xac\x64\xcd\x53\x46\x50\xac\xb9", 16);
9492 +
9493 +    auth_scheme[3] = (unsigned char)enctype;
9494 +
9495 +    *minor = 0;
9496 +    return GSS_S_COMPLETE;
9497 +}
9498 +
9499 +OM_uint32 GSSAPI_CALLCONV
9500 +gss_query_mechanism_info(OM_uint32 *minor,
9501 +                         gss_const_OID mech_oid,
9502 +                         unsigned char auth_scheme[16])
9503 +{
9504 +    return gssQueryMechanismInfo(minor, mech_oid, auth_scheme);
9505 +}
9506 diff --git a/mech_eap/query_meta_data.c b/mech_eap/query_meta_data.c
9507 new file mode 100644
9508 index 0000000..abc7e71
9509 --- /dev/null
9510 +++ b/mech_eap/query_meta_data.c
9511 @@ -0,0 +1,116 @@
9512 +/*
9513 + * Copyright (c) 2011, JANET(UK)
9514 + * All rights reserved.
9515 + *
9516 + * Redistribution and use in source and binary forms, with or without
9517 + * modification, are permitted provided that the following conditions
9518 + * are met:
9519 + *
9520 + * 1. Redistributions of source code must retain the above copyright
9521 + *    notice, this list of conditions and the following disclaimer.
9522 + *
9523 + * 2. Redistributions in binary form must reproduce the above copyright
9524 + *    notice, this list of conditions and the following disclaimer in the
9525 + *    documentation and/or other materials provided with the distribution.
9526 + *
9527 + * 3. Neither the name of JANET(UK) nor the names of its contributors
9528 + *    may be used to endorse or promote products derived from this software
9529 + *    without specific prior written permission.
9530 + *
9531 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
9532 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9533 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9534 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
9535 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9536 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9537 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9538 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9539 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9540 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9541 + * SUCH DAMAGE.
9542 + */
9543 +
9544 +/*
9545 + *
9546 + */
9547 +
9548 +#include "gssapiP_eap.h"
9549 +
9550 +OM_uint32
9551 +gssEapQueryMetaData(OM_uint32 *minor,
9552 +                    gss_const_OID mech GSSEAP_UNUSED,
9553 +                    gss_cred_id_t cred,
9554 +                    gss_ctx_id_t *context_handle,
9555 +                    const gss_name_t name,
9556 +                    OM_uint32 req_flags GSSEAP_UNUSED,
9557 +                    gss_buffer_t meta_data)
9558 +{
9559 +    OM_uint32 major = GSS_S_COMPLETE;
9560 +    int isInitiator = (name != GSS_C_NO_NAME);
9561 +    gss_ctx_id_t ctx = *context_handle;
9562 +
9563 +    meta_data->length = 0;
9564 +    meta_data->value = NULL;
9565 +
9566 +    if (ctx == GSS_C_NO_CONTEXT) {
9567 +        major = gssEapAllocContext(minor, &ctx);
9568 +        if (GSS_ERROR(major))
9569 +            return major;
9570 +
9571 +        if (isInitiator)
9572 +            ctx->flags |= CTX_FLAG_INITIATOR;
9573 +    }
9574 +
9575 +    if (ctx->cred == GSS_C_NO_CREDENTIAL) {
9576 +        if (isInitiator) {
9577 +            major = gssEapResolveInitiatorCred(minor, cred,
9578 +                                               name, &ctx->cred);
9579 +        } else {
9580 +            major = gssEapAcquireCred(minor,
9581 +                                      GSS_C_NO_NAME,
9582 +                                      GSS_C_INDEFINITE,
9583 +                                      GSS_C_NO_OID_SET,
9584 +                                      GSS_C_ACCEPT,
9585 +                                      &ctx->cred,
9586 +                                      NULL,
9587 +                                      NULL);
9588 +        }
9589 +    }
9590 +
9591 +    if (*context_handle == GSS_C_NO_CONTEXT)
9592 +        *context_handle = ctx;
9593 +
9594 +    return major;
9595 +}
9596 +
9597 +OM_uint32 GSSAPI_CALLCONV
9598 +gss_query_meta_data(OM_uint32 *minor,
9599 +                    gss_const_OID mech,
9600 +                    gss_cred_id_t cred,
9601 +                    gss_ctx_id_t *context_handle,
9602 +                    const gss_name_t name,
9603 +                    OM_uint32 req_flags,
9604 +                    gss_buffer_t meta_data)
9605 +{
9606 +    gss_ctx_id_t ctx = *context_handle;
9607 +    OM_uint32 major;
9608 +
9609 +    if (cred != GSS_C_NO_CREDENTIAL)
9610 +        GSSEAP_MUTEX_LOCK(&cred->mutex);
9611 +
9612 +    if (*context_handle != GSS_C_NO_CONTEXT)
9613 +        GSSEAP_MUTEX_LOCK(&ctx->mutex);
9614 +
9615 +    major = gssEapQueryMetaData(minor, mech, cred, &ctx,
9616 +                                name, req_flags, meta_data);
9617 +
9618 +    if (*context_handle != GSS_C_NO_CONTEXT)
9619 +        GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
9620 +    else
9621 +        *context_handle = ctx;
9622 +
9623 +    if (cred != GSS_C_NO_CREDENTIAL)
9624 +        GSSEAP_MUTEX_UNLOCK(&cred->mutex);
9625 +
9626 +    return major;
9627 +}
9628 diff --git a/mech_eap/radius_ad.exports b/mech_eap/radius_ad.exports
9629 new file mode 100644
9630 index 0000000..8d5d5c4
9631 --- /dev/null
9632 +++ b/mech_eap/radius_ad.exports
9633 @@ -0,0 +1 @@
9634 +authdata_client_0
9635 diff --git a/mech_eap/radsec.conf b/mech_eap/radsec.conf
9636 new file mode 100644
9637 index 0000000..27f895a
9638 --- /dev/null
9639 +++ b/mech_eap/radsec.conf
9640 @@ -0,0 +1,12 @@
9641 +dictionary = "/usr/local/etc/raddb/dictionary"
9642 +
9643 +realm gss-eap {
9644 +    type = "UDP"
9645 +    timeout = 5
9646 +    retries = 3
9647 +    server {
9648 +        hostname = "localhost"
9649 +        service = "1812"
9650 +        secret = "testing123"
9651 +    }
9652 +}
9653 diff --git a/mech_eap/radsec_err.et b/mech_eap/radsec_err.et
9654 new file mode 100644
9655 index 0000000..3b7fae2
9656 --- /dev/null
9657 +++ b/mech_eap/radsec_err.et
9658 @@ -0,0 +1,38 @@
9659 +#
9660 +# Copyright (c) 2011, JANET(UK)
9661 +#  All rights reserved.
9662 +# 
9663 +#  Redistribution and use in source and binary forms, with or without
9664 +#  modification, are permitted provided that the following conditions
9665 +#  are met:
9666 +# 
9667 +#  1. Redistributions of source code must retain the above copyright
9668 +#     notice, this list of conditions and the following disclaimer.
9669 +# 
9670 +#  2. Redistributions in binary form must reproduce the above copyright
9671 +#     notice, this list of conditions and the following disclaimer in the
9672 +#     documentation and/or other materials provided with the distribution.
9673 +# 
9674 +#  3. Neither the name of JANET(UK) nor the names of its contributors
9675 +#     may be used to endorse or promote products derived from this software
9676 +#     without specific prior written permission.
9677 +# 
9678 +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
9679 +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9680 +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9681 +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
9682 +#  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9683 +#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9684 +#  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9685 +#  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9686 +#  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9687 +#  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9688 +#  SUCH DAMAGE.
9689 +#
9690 +
9691 +# Placeholders only
9692 +error_table rse
9693 +
9694 +error_code GSSEAP_RSE_OK,                       ""
9695 +
9696 +end
9697 diff --git a/mech_eap/release_any_name_mapping.c b/mech_eap/release_any_name_mapping.c
9698 new file mode 100644
9699 index 0000000..d68fb45
9700 --- /dev/null
9701 +++ b/mech_eap/release_any_name_mapping.c
9702 @@ -0,0 +1,59 @@
9703 +/*
9704 + * Copyright (c) 2011, JANET(UK)
9705 + * All rights reserved.
9706 + *
9707 + * Redistribution and use in source and binary forms, with or without
9708 + * modification, are permitted provided that the following conditions
9709 + * are met:
9710 + *
9711 + * 1. Redistributions of source code must retain the above copyright
9712 + *    notice, this list of conditions and the following disclaimer.
9713 + *
9714 + * 2. Redistributions in binary form must reproduce the above copyright
9715 + *    notice, this list of conditions and the following disclaimer in the
9716 + *    documentation and/or other materials provided with the distribution.
9717 + *
9718 + * 3. Neither the name of JANET(UK) nor the names of its contributors
9719 + *    may be used to endorse or promote products derived from this software
9720 + *    without specific prior written permission.
9721 + *
9722 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
9723 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9724 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9725 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
9726 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9727 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9728 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9729 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9730 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9731 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9732 + * SUCH DAMAGE.
9733 + */
9734 +
9735 +#include "gssapiP_eap.h"
9736 +
9737 +OM_uint32 GSSAPI_CALLCONV
9738 +gss_release_any_name_mapping(OM_uint32 *minor,
9739 +                             gss_name_t name,
9740 +                             gss_buffer_t type_id,
9741 +                             gss_any_t *input)
9742 +{
9743 +    OM_uint32 major;
9744 +
9745 +    *minor = 0;
9746 +
9747 +    if (name == GSS_C_NO_NAME) {
9748 +        *minor = EINVAL;
9749 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
9750 +    }
9751 +
9752 +    GSSEAP_MUTEX_LOCK(&name->mutex);
9753 +
9754 +    major = gssEapReleaseAnyNameMapping(minor, name, type_id, input);
9755 +
9756 +    *input = NULL;
9757 +
9758 +    GSSEAP_MUTEX_UNLOCK(&name->mutex);
9759 +
9760 +    return major;
9761 +}
9762 diff --git a/mech_eap/release_cred.c b/mech_eap/release_cred.c
9763 new file mode 100644
9764 index 0000000..8bb7e54
9765 --- /dev/null
9766 +++ b/mech_eap/release_cred.c
9767 @@ -0,0 +1,44 @@
9768 +/*
9769 + * Copyright (c) 2011, JANET(UK)
9770 + * All rights reserved.
9771 + *
9772 + * Redistribution and use in source and binary forms, with or without
9773 + * modification, are permitted provided that the following conditions
9774 + * are met:
9775 + *
9776 + * 1. Redistributions of source code must retain the above copyright
9777 + *    notice, this list of conditions and the following disclaimer.
9778 + *
9779 + * 2. Redistributions in binary form must reproduce the above copyright
9780 + *    notice, this list of conditions and the following disclaimer in the
9781 + *    documentation and/or other materials provided with the distribution.
9782 + *
9783 + * 3. Neither the name of JANET(UK) nor the names of its contributors
9784 + *    may be used to endorse or promote products derived from this software
9785 + *    without specific prior written permission.
9786 + *
9787 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
9788 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9789 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9790 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
9791 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9792 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9793 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9794 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9795 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9796 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9797 + * SUCH DAMAGE.
9798 + */
9799 +
9800 +/*
9801 + * Release a credential handle.
9802 + */
9803 +
9804 +#include "gssapiP_eap.h"
9805 +
9806 +OM_uint32 GSSAPI_CALLCONV
9807 +gss_release_cred(OM_uint32 *minor,
9808 +                 gss_cred_id_t *cred_handle)
9809 +{
9810 +    return gssEapReleaseCred(minor, cred_handle);
9811 +}
9812 diff --git a/mech_eap/release_name.c b/mech_eap/release_name.c
9813 new file mode 100644
9814 index 0000000..3d527ce
9815 --- /dev/null
9816 +++ b/mech_eap/release_name.c
9817 @@ -0,0 +1,44 @@
9818 +/*
9819 + * Copyright (c) 2011, JANET(UK)
9820 + * All rights reserved.
9821 + *
9822 + * Redistribution and use in source and binary forms, with or without
9823 + * modification, are permitted provided that the following conditions
9824 + * are met:
9825 + *
9826 + * 1. Redistributions of source code must retain the above copyright
9827 + *    notice, this list of conditions and the following disclaimer.
9828 + *
9829 + * 2. Redistributions in binary form must reproduce the above copyright
9830 + *    notice, this list of conditions and the following disclaimer in the
9831 + *    documentation and/or other materials provided with the distribution.
9832 + *
9833 + * 3. Neither the name of JANET(UK) nor the names of its contributors
9834 + *    may be used to endorse or promote products derived from this software
9835 + *    without specific prior written permission.
9836 + *
9837 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
9838 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9839 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9840 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
9841 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9842 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9843 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9844 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9845 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9846 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9847 + * SUCH DAMAGE.
9848 + */
9849 +
9850 +/*
9851 + * Release a name.
9852 + */
9853 +
9854 +#include "gssapiP_eap.h"
9855 +
9856 +OM_uint32 GSSAPI_CALLCONV
9857 +gss_release_name(OM_uint32 *minor,
9858 +                 gss_name_t *name)
9859 +{
9860 +    return gssEapReleaseName(minor, name);
9861 +}
9862 diff --git a/mech_eap/release_oid.c b/mech_eap/release_oid.c
9863 new file mode 100644
9864 index 0000000..291da40
9865 --- /dev/null
9866 +++ b/mech_eap/release_oid.c
9867 @@ -0,0 +1,44 @@
9868 +/*
9869 + * Copyright (c) 2011, JANET(UK)
9870 + * All rights reserved.
9871 + *
9872 + * Redistribution and use in source and binary forms, with or without
9873 + * modification, are permitted provided that the following conditions
9874 + * are met:
9875 + *
9876 + * 1. Redistributions of source code must retain the above copyright
9877 + *    notice, this list of conditions and the following disclaimer.
9878 + *
9879 + * 2. Redistributions in binary form must reproduce the above copyright
9880 + *    notice, this list of conditions and the following disclaimer in the
9881 + *    documentation and/or other materials provided with the distribution.
9882 + *
9883 + * 3. Neither the name of JANET(UK) nor the names of its contributors
9884 + *    may be used to endorse or promote products derived from this software
9885 + *    without specific prior written permission.
9886 + *
9887 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
9888 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9889 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9890 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
9891 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9892 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9893 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9894 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9895 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9896 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9897 + * SUCH DAMAGE.
9898 + */
9899 +
9900 +/*
9901 + * Mark an internalized OID as not required to be released.
9902 + */
9903 +
9904 +#include "gssapiP_eap.h"
9905 +
9906 +OM_uint32 GSSAPI_CALLCONV
9907 +gss_internal_release_oid(OM_uint32 *minor,
9908 +                         gss_OID *oid)
9909 +{
9910 +    return gssEapReleaseOid(minor, oid);
9911 +}
9912 diff --git a/mech_eap/set_cred_option.c b/mech_eap/set_cred_option.c
9913 new file mode 100644
9914 index 0000000..7bb9b7b
9915 --- /dev/null
9916 +++ b/mech_eap/set_cred_option.c
9917 @@ -0,0 +1,208 @@
9918 +/*
9919 + * Copyright (c) 2011, JANET(UK)
9920 + * All rights reserved.
9921 + *
9922 + * Redistribution and use in source and binary forms, with or without
9923 + * modification, are permitted provided that the following conditions
9924 + * are met:
9925 + *
9926 + * 1. Redistributions of source code must retain the above copyright
9927 + *    notice, this list of conditions and the following disclaimer.
9928 + *
9929 + * 2. Redistributions in binary form must reproduce the above copyright
9930 + *    notice, this list of conditions and the following disclaimer in the
9931 + *    documentation and/or other materials provided with the distribution.
9932 + *
9933 + * 3. Neither the name of JANET(UK) nor the names of its contributors
9934 + *    may be used to endorse or promote products derived from this software
9935 + *    without specific prior written permission.
9936 + *
9937 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
9938 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9939 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9940 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
9941 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9942 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9943 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9944 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9945 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9946 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9947 + * SUCH DAMAGE.
9948 + */
9949 +
9950 +/*
9951 + * Set an extended property on a credential handle.
9952 + */
9953 +
9954 +#include "gssapiP_eap.h"
9955 +
9956 +static OM_uint32
9957 +setCredRadiusConfigFile(OM_uint32 *minor,
9958 +                        gss_cred_id_t cred,
9959 +                        const gss_OID oid GSSEAP_UNUSED,
9960 +                        const gss_buffer_t buffer)
9961 +{
9962 +    OM_uint32 major, tmpMinor;
9963 +    gss_buffer_desc configFileBuffer = GSS_C_EMPTY_BUFFER;
9964 +
9965 +    if (buffer != GSS_C_NO_BUFFER && buffer->length != 0) {
9966 +        major = duplicateBuffer(minor, buffer, &configFileBuffer);
9967 +        if (GSS_ERROR(major))
9968 +            return major;
9969 +    }
9970 +
9971 +    gss_release_buffer(&tmpMinor, &cred->radiusConfigFile);
9972 +    cred->radiusConfigFile = configFileBuffer;
9973 +
9974 +    *minor = 0;
9975 +    return GSS_S_COMPLETE;
9976 +}
9977 +
9978 +static OM_uint32
9979 +setCredRadiusConfigStanza(OM_uint32 *minor,
9980 +                          gss_cred_id_t cred,
9981 +                          const gss_OID oid GSSEAP_UNUSED,
9982 +                          const gss_buffer_t buffer)
9983 +{
9984 +    OM_uint32 major, tmpMinor;
9985 +    gss_buffer_desc configStanzaBuffer = GSS_C_EMPTY_BUFFER;
9986 +
9987 +    if (buffer != GSS_C_NO_BUFFER && buffer->length != 0) {
9988 +        major = duplicateBuffer(minor, buffer, &configStanzaBuffer);
9989 +        if (GSS_ERROR(major))
9990 +            return major;
9991 +    }
9992 +
9993 +    gss_release_buffer(&tmpMinor, &cred->radiusConfigStanza);
9994 +    cred->radiusConfigStanza = configStanzaBuffer;
9995 +
9996 +    *minor = 0;
9997 +    return GSS_S_COMPLETE;
9998 +}
9999 +
10000 +static OM_uint32
10001 +setCredFlag(OM_uint32 *minor,
10002 +            gss_cred_id_t cred,
10003 +            const gss_OID oid GSSEAP_UNUSED,
10004 +            const gss_buffer_t buffer)
10005 +{
10006 +    OM_uint32 flags;
10007 +    unsigned char *p;
10008 +
10009 +    if (buffer == GSS_C_NO_BUFFER) {
10010 +        *minor = EINVAL;
10011 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_FAILURE;
10012 +    }
10013 +
10014 +    if (buffer->length < 4) {
10015 +        *minor = GSSEAP_WRONG_SIZE;
10016 +        return GSS_S_FAILURE;
10017 +    }
10018 +
10019 +    p = (unsigned char *)buffer->value;
10020 +
10021 +    flags = load_uint32_be(buffer->value) & CRED_FLAG_PUBLIC_MASK;
10022 +
10023 +    if (buffer->length > 4 && p[4])
10024 +        cred->flags &= ~(flags);
10025 +    else
10026 +        cred->flags |= flags;
10027 +
10028 +    *minor = 0;
10029 +    return GSS_S_COMPLETE;
10030 +}
10031 +
10032 +static OM_uint32
10033 +setCredPassword(OM_uint32 *minor,
10034 +                gss_cred_id_t cred,
10035 +                const gss_OID oid GSSEAP_UNUSED,
10036 +                const gss_buffer_t buffer)
10037 +{
10038 +    return gssEapSetCredPassword(minor, cred, buffer);
10039 +}
10040 +
10041 +static struct {
10042 +    gss_OID_desc oid;
10043 +    OM_uint32 (*setOption)(OM_uint32 *, gss_cred_id_t cred,
10044 +                           const gss_OID, const gss_buffer_t);
10045 +} setCredOps[] = {
10046 +    /* 1.3.6.1.4.1.5322.22.3.3.1 */
10047 +    {
10048 +        { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x01" },
10049 +        setCredRadiusConfigFile,
10050 +    },
10051 +    /* 1.3.6.1.4.1.5322.22.3.3.2 */
10052 +    {
10053 +        { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x02" },
10054 +        setCredRadiusConfigStanza,
10055 +    },
10056 +    /* 1.3.6.1.4.1.5322.22.3.3.3 */
10057 +    {
10058 +        { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x03" },
10059 +        setCredFlag,
10060 +    },
10061 +    /* 1.3.6.1.4.1.5322.22.3.3.4 */
10062 +    {
10063 +        { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x04" },
10064 +        setCredPassword,
10065 +    },
10066 +};
10067 +
10068 +gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE     = &setCredOps[0].oid;
10069 +gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_STANZA   = &setCredOps[1].oid;
10070 +gss_OID GSS_EAP_CRED_SET_CRED_FLAG              = &setCredOps[2].oid;
10071 +gss_OID GSS_EAP_CRED_SET_CRED_PASSWORD          = &setCredOps[3].oid;
10072 +
10073 +OM_uint32 GSSAPI_CALLCONV
10074 +gssspi_set_cred_option(OM_uint32 *minor,
10075 +                       gss_cred_id_t *pCred,
10076 +                       const gss_OID desired_object,
10077 +                       const gss_buffer_t value)
10078 +{
10079 +    OM_uint32 major;
10080 +    gss_cred_id_t cred = *pCred;
10081 +    int i;
10082 +
10083 +    if (cred == GSS_C_NO_CREDENTIAL) {
10084 +        *minor = EINVAL;
10085 +        return GSS_S_UNAVAILABLE;
10086 +    }
10087 +
10088 +    GSSEAP_MUTEX_LOCK(&cred->mutex);
10089 +
10090 +    major = GSS_S_UNAVAILABLE;
10091 +    *minor = GSSEAP_BAD_CRED_OPTION;
10092 +
10093 +    for (i = 0; i < sizeof(setCredOps) / sizeof(setCredOps[0]); i++) {
10094 +        if (oidEqual(&setCredOps[i].oid, desired_object)) {
10095 +            major = (*setCredOps[i].setOption)(minor, cred,
10096 +                                               desired_object, value);
10097 +            break;
10098 +        }
10099 +    }
10100 +
10101 +    GSSEAP_MUTEX_UNLOCK(&cred->mutex);
10102 +
10103 +    return major;
10104 +}
10105 +
10106 +#if 0
10107 +OM_uint32
10108 +gsseap_set_cred_flag(OM_uint32 *minor,
10109 +                     gss_cred_id_t cred,
10110 +                     OM_uint32 flag,
10111 +                     int clear)
10112 +{
10113 +    unsigned char buf[5];
10114 +    gss_buffer_desc value;
10115 +
10116 +    value.length = sizeof(buf);
10117 +    value.value = buf;
10118 +
10119 +    store_uint32_be(flag, buf);
10120 +    buf[4] = (clear != 0);
10121 +
10122 +    return gssspi_set_cred_option(minor, &cred,
10123 +                                  GSS_EAP_CRED_SET_CRED_FLAG, &value);
10124 +}
10125 +#endif
10126 diff --git a/mech_eap/set_name_attribute.c b/mech_eap/set_name_attribute.c
10127 new file mode 100644
10128 index 0000000..2ccf5d7
10129 --- /dev/null
10130 +++ b/mech_eap/set_name_attribute.c
10131 @@ -0,0 +1,60 @@
10132 +/*
10133 + * Copyright (c) 2011, JANET(UK)
10134 + * All rights reserved.
10135 + *
10136 + * Redistribution and use in source and binary forms, with or without
10137 + * modification, are permitted provided that the following conditions
10138 + * are met:
10139 + *
10140 + * 1. Redistributions of source code must retain the above copyright
10141 + *    notice, this list of conditions and the following disclaimer.
10142 + *
10143 + * 2. Redistributions in binary form must reproduce the above copyright
10144 + *    notice, this list of conditions and the following disclaimer in the
10145 + *    documentation and/or other materials provided with the distribution.
10146 + *
10147 + * 3. Neither the name of JANET(UK) nor the names of its contributors
10148 + *    may be used to endorse or promote products derived from this software
10149 + *    without specific prior written permission.
10150 + *
10151 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
10152 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10153 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
10154 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
10155 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
10156 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
10157 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
10158 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
10159 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
10160 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
10161 + * SUCH DAMAGE.
10162 + */
10163 +
10164 +/*
10165 + * Set an attribute on a name.
10166 + */
10167 +
10168 +#include "gssapiP_eap.h"
10169 +
10170 +OM_uint32 GSSAPI_CALLCONV
10171 +gss_set_name_attribute(OM_uint32 *minor,
10172 +                       gss_name_t name,
10173 +                       int complete,
10174 +                       gss_buffer_t attr,
10175 +                       gss_buffer_t value)
10176 +{
10177 +    OM_uint32 major;
10178 +
10179 +    if (name == GSS_C_NO_NAME) {
10180 +        *minor = EINVAL;
10181 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
10182 +    }
10183 +
10184 +    GSSEAP_MUTEX_LOCK(&name->mutex);
10185 +
10186 +    major = gssEapSetNameAttribute(minor, name, complete, attr, value);
10187 +
10188 +    GSSEAP_MUTEX_UNLOCK(&name->mutex);
10189 +
10190 +    return major;
10191 +}
10192 diff --git a/mech_eap/set_sec_context_option.c b/mech_eap/set_sec_context_option.c
10193 new file mode 100644
10194 index 0000000..f9fa3a6
10195 --- /dev/null
10196 +++ b/mech_eap/set_sec_context_option.c
10197 @@ -0,0 +1,87 @@
10198 +/*
10199 + * Copyright (c) 2011, JANET(UK)
10200 + * All rights reserved.
10201 + *
10202 + * Redistribution and use in source and binary forms, with or without
10203 + * modification, are permitted provided that the following conditions
10204 + * are met:
10205 + *
10206 + * 1. Redistributions of source code must retain the above copyright
10207 + *    notice, this list of conditions and the following disclaimer.
10208 + *
10209 + * 2. Redistributions in binary form must reproduce the above copyright
10210 + *    notice, this list of conditions and the following disclaimer in the
10211 + *    documentation and/or other materials provided with the distribution.
10212 + *
10213 + * 3. Neither the name of JANET(UK) nor the names of its contributors
10214 + *    may be used to endorse or promote products derived from this software
10215 + *    without specific prior written permission.
10216 + *
10217 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
10218 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10219 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
10220 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
10221 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
10222 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
10223 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
10224 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
10225 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
10226 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
10227 + * SUCH DAMAGE.
10228 + */
10229 +
10230 +/*
10231 + * Set an extended property on a context handle.
10232 + */
10233 +
10234 +#include "gssapiP_eap.h"
10235 +
10236 +#if 0
10237 +static struct {
10238 +    gss_OID_desc oid;
10239 +    OM_uint32 (*setOption)(OM_uint32 *, gss_ctx_id_t *pCtx,
10240 +                           const gss_OID, const gss_buffer_t);
10241 +} setCtxOps[] = {
10242 +};
10243 +#endif
10244 +
10245 +OM_uint32 GSSAPI_CALLCONV
10246 +gss_set_sec_context_option(OM_uint32 *minor,
10247 +                           gss_ctx_id_t *pCtx,
10248 +                           const gss_OID desired_object GSSEAP_UNUSED,
10249 +                           const gss_buffer_t value GSSEAP_UNUSED)
10250 +{
10251 +    OM_uint32 major;
10252 +    gss_ctx_id_t ctx;
10253 +#if 0
10254 +    int i;
10255 +#endif
10256 +
10257 +    major = GSS_S_UNAVAILABLE;
10258 +    *minor = GSSEAP_BAD_CONTEXT_OPTION;
10259 +
10260 +    if (pCtx == NULL)
10261 +        ctx = GSS_C_NO_CONTEXT;
10262 +    else
10263 +        ctx = *pCtx;
10264 +
10265 +    if (ctx != GSS_C_NO_CONTEXT)
10266 +        GSSEAP_MUTEX_LOCK(&ctx->mutex);
10267 +
10268 +#if 0
10269 +    for (i = 0; i < sizeof(setCtxOps) / sizeof(setCtxOps[0]); i++) {
10270 +        if (oidEqual(&setCtxOps[i].oid, desired_object)) {
10271 +            major = (*setCtxOps[i].setOption)(minor, &ctx,
10272 +                                              desired_object, value);
10273 +            break;
10274 +        }
10275 +    }
10276 +#endif
10277 +
10278 +    if (pCtx != NULL && *pCtx == NULL)
10279 +        *pCtx = ctx;
10280 +    else if (ctx != GSS_C_NO_CONTEXT)
10281 +        GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
10282 +
10283 +    return major;
10284 +}
10285 diff --git a/mech_eap/store_cred.c b/mech_eap/store_cred.c
10286 new file mode 100644
10287 index 0000000..d17a3ac
10288 --- /dev/null
10289 +++ b/mech_eap/store_cred.c
10290 @@ -0,0 +1,83 @@
10291 +/*
10292 + * Copyright (c) 2011, JANET(UK)
10293 + * All rights reserved.
10294 + *
10295 + * Redistribution and use in source and binary forms, with or without
10296 + * modification, are permitted provided that the following conditions
10297 + * are met:
10298 + *
10299 + * 1. Redistributions of source code must retain the above copyright
10300 + *    notice, this list of conditions and the following disclaimer.
10301 + *
10302 + * 2. Redistributions in binary form must reproduce the above copyright
10303 + *    notice, this list of conditions and the following disclaimer in the
10304 + *    documentation and/or other materials provided with the distribution.
10305 + *
10306 + * 3. Neither the name of JANET(UK) nor the names of its contributors
10307 + *    may be used to endorse or promote products derived from this software
10308 + *    without specific prior written permission.
10309 + *
10310 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
10311 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10312 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
10313 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
10314 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
10315 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
10316 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
10317 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
10318 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
10319 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
10320 + * SUCH DAMAGE.
10321 + */
10322 +
10323 +#include "gssapiP_eap.h"
10324 +
10325 +OM_uint32 GSSAPI_CALLCONV
10326 +gss_store_cred(OM_uint32 *minor,
10327 +               const gss_cred_id_t cred,
10328 +               gss_cred_usage_t input_usage,
10329 +               const gss_OID desired_mech GSSEAP_UNUSED,
10330 +#ifdef GSSEAP_ENABLE_REAUTH
10331 +               OM_uint32 overwrite_cred,
10332 +               OM_uint32 default_cred,
10333 +#else
10334 +               OM_uint32 overwrite_cred GSSEAP_UNUSED,
10335 +               OM_uint32 default_cred GSSEAP_UNUSED,
10336 +#endif
10337 +               gss_OID_set *elements_stored,
10338 +               gss_cred_usage_t *cred_usage_stored)
10339 +{
10340 +    OM_uint32 major;
10341 +
10342 +    if (elements_stored != NULL)
10343 +        *elements_stored = GSS_C_NO_OID_SET;
10344 +    if (cred_usage_stored != NULL)
10345 +        *cred_usage_stored = input_usage;
10346 +
10347 +    if (cred == GSS_C_NO_CREDENTIAL) {
10348 +        *minor = EINVAL;
10349 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED;
10350 +    }
10351 +
10352 +    GSSEAP_MUTEX_LOCK(&cred->mutex);
10353 +
10354 +    major = GSS_S_COMPLETE;
10355 +    *minor = 0;
10356 +
10357 +#ifdef GSSEAP_ENABLE_REAUTH
10358 +    if (cred->reauthCred != GSS_C_NO_CREDENTIAL) {
10359 +        major = gssStoreCred(minor,
10360 +                             cred->reauthCred,
10361 +                             input_usage,
10362 +                             (gss_OID)gss_mech_krb5,
10363 +                             overwrite_cred,
10364 +                             default_cred,
10365 +                             elements_stored,
10366 +                             cred_usage_stored);
10367 +    }
10368 +#endif
10369 +
10370 +    GSSEAP_MUTEX_UNLOCK(&cred->mutex);
10371 +
10372 +    return major;
10373 +}
10374 diff --git a/mech_eap/unwrap.c b/mech_eap/unwrap.c
10375 new file mode 100644
10376 index 0000000..a185035
10377 --- /dev/null
10378 +++ b/mech_eap/unwrap.c
10379 @@ -0,0 +1,85 @@
10380 +/*
10381 + * Copyright (c) 2011, JANET(UK)
10382 + * All rights reserved.
10383 + *
10384 + * Redistribution and use in source and binary forms, with or without
10385 + * modification, are permitted provided that the following conditions
10386 + * are met:
10387 + *
10388 + * 1. Redistributions of source code must retain the above copyright
10389 + *    notice, this list of conditions and the following disclaimer.
10390 + *
10391 + * 2. Redistributions in binary form must reproduce the above copyright
10392 + *    notice, this list of conditions and the following disclaimer in the
10393 + *    documentation and/or other materials provided with the distribution.
10394 + *
10395 + * 3. Neither the name of JANET(UK) nor the names of its contributors
10396 + *    may be used to endorse or promote products derived from this software
10397 + *    without specific prior written permission.
10398 + *
10399 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
10400 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10401 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
10402 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
10403 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
10404 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
10405 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
10406 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
10407 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
10408 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
10409 + * SUCH DAMAGE.
10410 + */
10411 +
10412 +/*
10413 + * Message protection services: unwrap.
10414 + */
10415 +
10416 +#include "gssapiP_eap.h"
10417 +
10418 +OM_uint32 GSSAPI_CALLCONV
10419 +gss_unwrap(OM_uint32 *minor,
10420 +           gss_ctx_id_t ctx,
10421 +           gss_buffer_t input_message_buffer,
10422 +           gss_buffer_t output_message_buffer,
10423 +           int *conf_state,
10424 +           gss_qop_t *qop_state)
10425 +{
10426 +    OM_uint32 major, tmpMinor;
10427 +    gss_iov_buffer_desc iov[2];
10428 +
10429 +    if (ctx == GSS_C_NO_CONTEXT) {
10430 +        *minor = EINVAL;
10431 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
10432 +    }
10433 +
10434 +    *minor = 0;
10435 +
10436 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
10437 +
10438 +    if (!CTX_IS_ESTABLISHED(ctx)) {
10439 +        major = GSS_S_NO_CONTEXT;
10440 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
10441 +        goto cleanup;
10442 +    }
10443 +
10444 +    iov[0].type = GSS_IOV_BUFFER_TYPE_STREAM;
10445 +    iov[0].buffer = *input_message_buffer;
10446 +
10447 +    iov[1].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
10448 +    iov[1].buffer.value = NULL;
10449 +    iov[1].buffer.length = 0;
10450 +
10451 +    major = gssEapUnwrapOrVerifyMIC(minor, ctx, conf_state, qop_state,
10452 +                                    iov, 2, TOK_TYPE_WRAP);
10453 +    if (major == GSS_S_COMPLETE) {
10454 +        *output_message_buffer = iov[1].buffer;
10455 +    } else {
10456 +        if (iov[1].type & GSS_IOV_BUFFER_FLAG_ALLOCATED)
10457 +            gss_release_buffer(&tmpMinor, &iov[1].buffer);
10458 +    }
10459 +
10460 +cleanup:
10461 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
10462 +
10463 +    return major;
10464 +}
10465 diff --git a/mech_eap/unwrap_iov.c b/mech_eap/unwrap_iov.c
10466 new file mode 100644
10467 index 0000000..5ceefa2
10468 --- /dev/null
10469 +++ b/mech_eap/unwrap_iov.c
10470 @@ -0,0 +1,572 @@
10471 +/*
10472 + * Copyright (c) 2011, JANET(UK)
10473 + * All rights reserved.
10474 + *
10475 + * Redistribution and use in source and binary forms, with or without
10476 + * modification, are permitted provided that the following conditions
10477 + * are met:
10478 + *
10479 + * 1. Redistributions of source code must retain the above copyright
10480 + *    notice, this list of conditions and the following disclaimer.
10481 + *
10482 + * 2. Redistributions in binary form must reproduce the above copyright
10483 + *    notice, this list of conditions and the following disclaimer in the
10484 + *    documentation and/or other materials provided with the distribution.
10485 + *
10486 + * 3. Neither the name of JANET(UK) nor the names of its contributors
10487 + *    may be used to endorse or promote products derived from this software
10488 + *    without specific prior written permission.
10489 + *
10490 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
10491 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10492 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
10493 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
10494 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
10495 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
10496 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
10497 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
10498 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
10499 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
10500 + * SUCH DAMAGE.
10501 + */
10502 +/*
10503 + * Copyright 2008 by the Massachusetts Institute of Technology.
10504 + * All Rights Reserved.
10505 + *
10506 + * Export of this software from the United States of America may
10507 + *   require a specific license from the United States Government.
10508 + *   It is the responsibility of any person or organization contemplating
10509 + *   export to obtain such a license before exporting.
10510 + *
10511 + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
10512 + * distribute this software and its documentation for any purpose and
10513 + * without fee is hereby granted, provided that the above copyright
10514 + * notice appear in all copies and that both that copyright notice and
10515 + * this permission notice appear in supporting documentation, and that
10516 + * the name of M.I.T. not be used in advertising or publicity pertaining
10517 + * to distribution of the software without specific, written prior
10518 + * permission.  Furthermore if you modify this software you must label
10519 + * your software as modified software and not distribute it in such a
10520 + * fashion that it might be confused with the original M.I.T. software.
10521 + * M.I.T. makes no representations about the suitability of
10522 + * this software for any purpose.  It is provided "as is" without express
10523 + * or implied warranty.
10524 + */
10525 +
10526 +/*
10527 + * Message protection services: unwrap with scatter-gather API.
10528 + */
10529 +
10530 +#include "gssapiP_eap.h"
10531 +
10532 +/*
10533 + * Caller must provide TOKEN | DATA | PADDING | TRAILER, except
10534 + * for DCE in which case it can just provide TOKEN | DATA (must
10535 + * guarantee that DATA is padded)
10536 + */
10537 +OM_uint32
10538 +unwrapToken(OM_uint32 *minor,
10539 +            gss_ctx_id_t ctx,
10540 +#ifdef HAVE_HEIMDAL_VERSION
10541 +            krb5_crypto krbCrypto,
10542 +#else
10543 +            krb5_keyblock *unused GSSEAP_UNUSED,
10544 +#endif
10545 +            int *conf_state,
10546 +            gss_qop_t *qop_state,
10547 +            gss_iov_buffer_desc *iov,
10548 +            int iov_count,
10549 +            enum gss_eap_token_type toktype)
10550 +{
10551 +    OM_uint32 major = GSS_S_FAILURE, code;
10552 +    gss_iov_buffer_t header;
10553 +    gss_iov_buffer_t padding;
10554 +    gss_iov_buffer_t trailer;
10555 +    unsigned char flags;
10556 +    unsigned char *ptr = NULL;
10557 +    int keyUsage;
10558 +    size_t rrc, ec;
10559 +    size_t dataLen, assocDataLen;
10560 +    uint64_t seqnum;
10561 +    int valid = 0;
10562 +    int conf_flag = 0;
10563 +    krb5_context krbContext;
10564 +#ifdef HAVE_HEIMDAL_VERSION
10565 +    int freeCrypto = (krbCrypto == NULL);
10566 +#endif
10567 +
10568 +    GSSEAP_KRB_INIT(&krbContext);
10569 +
10570 +    *minor = 0;
10571 +
10572 +    if (qop_state != NULL)
10573 +        *qop_state = GSS_C_QOP_DEFAULT;
10574 +
10575 +    header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
10576 +    GSSEAP_ASSERT(header != NULL);
10577 +
10578 +    padding = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
10579 +    if (padding != NULL && padding->buffer.length != 0) {
10580 +        code = GSSEAP_BAD_PADDING_IOV;
10581 +        major = GSS_S_DEFECTIVE_TOKEN;
10582 +        goto cleanup;
10583 +    }
10584 +
10585 +    trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
10586 +
10587 +    flags = rfc4121Flags(ctx, TRUE);
10588 +
10589 +    if (toktype == TOK_TYPE_WRAP) {
10590 +        keyUsage = !CTX_IS_INITIATOR(ctx)
10591 +                   ? KEY_USAGE_INITIATOR_SEAL
10592 +                   : KEY_USAGE_ACCEPTOR_SEAL;
10593 +    } else {
10594 +        keyUsage = !CTX_IS_INITIATOR(ctx)
10595 +                   ? KEY_USAGE_INITIATOR_SIGN
10596 +                   : KEY_USAGE_ACCEPTOR_SIGN;
10597 +    }
10598 +
10599 +    gssEapIovMessageLength(iov, iov_count, &dataLen, &assocDataLen);
10600 +
10601 +    ptr = (unsigned char *)header->buffer.value;
10602 +
10603 +    if (header->buffer.length < 16) {
10604 +        code = GSSEAP_TOK_TRUNC;
10605 +        major = GSS_S_DEFECTIVE_TOKEN;
10606 +        goto cleanup;
10607 +    }
10608 +
10609 +    if ((ptr[2] & flags) != flags) {
10610 +        code = GSSEAP_BAD_DIRECTION;
10611 +        major = GSS_S_BAD_SIG;
10612 +        goto cleanup;
10613 +    }
10614 +
10615 +#ifdef HAVE_HEIMDAL_VERSION
10616 +    if (krbCrypto == NULL) {
10617 +        code = krb5_crypto_init(krbContext, &ctx->rfc3961Key,
10618 +                                ETYPE_NULL, &krbCrypto);
10619 +        if (code != 0)
10620 +            goto cleanup;
10621 +    }
10622 +#endif
10623 +
10624 +    if (toktype == TOK_TYPE_WRAP) {
10625 +        size_t krbTrailerLen;
10626 +
10627 +        if (load_uint16_be(ptr) != TOK_TYPE_WRAP)
10628 +            goto defective;
10629 +        conf_flag = ((ptr[2] & TOK_FLAG_WRAP_CONFIDENTIAL) != 0);
10630 +        if (ptr[3] != 0xFF)
10631 +            goto defective;
10632 +        ec = load_uint16_be(ptr + 4);
10633 +        rrc = load_uint16_be(ptr + 6);
10634 +        seqnum = load_uint64_be(ptr + 8);
10635 +
10636 +        code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
10637 +                               conf_flag ? KRB5_CRYPTO_TYPE_TRAILER :
10638 +                                           KRB5_CRYPTO_TYPE_CHECKSUM,
10639 +                               &krbTrailerLen);
10640 +        if (code != 0)
10641 +            goto cleanup;
10642 +
10643 +        /* Deal with RRC */
10644 +        if (trailer == NULL) {
10645 +            size_t desired_rrc = krbTrailerLen;
10646 +
10647 +            if (conf_flag) {
10648 +                desired_rrc += 16; /* E(Header) */
10649 +
10650 +                if ((ctx->gssFlags & GSS_C_DCE_STYLE) == 0)
10651 +                    desired_rrc += ec;
10652 +            }
10653 +
10654 +            /* According to MS, we only need to deal with a fixed RRC for DCE */
10655 +            if (rrc != desired_rrc)
10656 +                goto defective;
10657 +        } else if (rrc != 0) {
10658 +            goto defective;
10659 +        }
10660 +
10661 +        if (conf_flag) {
10662 +            unsigned char *althdr;
10663 +
10664 +            /* Decrypt */
10665 +            code = gssEapDecrypt(krbContext,
10666 +                                 ((ctx->gssFlags & GSS_C_DCE_STYLE) != 0),
10667 +                                 ec, rrc, KRB_CRYPTO_CONTEXT(ctx), keyUsage,
10668 +                                 iov, iov_count);
10669 +            if (code != 0) {
10670 +                major = GSS_S_BAD_SIG;
10671 +                goto cleanup;
10672 +            }
10673 +
10674 +            /* Validate header integrity */
10675 +            if (trailer == NULL)
10676 +                althdr = (unsigned char *)header->buffer.value + 16 + ec;
10677 +            else
10678 +                althdr = (unsigned char *)trailer->buffer.value + ec;
10679 +
10680 +            if (load_uint16_be(althdr) != TOK_TYPE_WRAP
10681 +                || althdr[2] != ptr[2]
10682 +                || althdr[3] != ptr[3]
10683 +                || memcmp(althdr + 8, ptr + 8, 8) != 0) {
10684 +                code = GSSEAP_BAD_WRAP_TOKEN;
10685 +                major = GSS_S_BAD_SIG;
10686 +                goto cleanup;
10687 +            }
10688 +        } else {
10689 +            /* Verify checksum: note EC is checksum size here, not padding */
10690 +            if (ec != krbTrailerLen)
10691 +                goto defective;
10692 +
10693 +            /* Zero EC, RRC before computing checksum */
10694 +            store_uint16_be(0, ptr + 4);
10695 +            store_uint16_be(0, ptr + 6);
10696 +
10697 +            code = gssEapVerify(krbContext, ctx->checksumType, rrc,
10698 +                                KRB_CRYPTO_CONTEXT(ctx), keyUsage,
10699 +                                iov, iov_count, &valid);
10700 +            if (code != 0 || valid == FALSE) {
10701 +                major = GSS_S_BAD_SIG;
10702 +                goto cleanup;
10703 +            }
10704 +        }
10705 +
10706 +        code = sequenceCheck(minor, &ctx->seqState, seqnum);
10707 +    } else if (toktype == TOK_TYPE_MIC) {
10708 +        if (load_uint16_be(ptr) != toktype)
10709 +            goto defective;
10710 +
10711 +    verify_mic_1:
10712 +        if (ptr[3] != 0xFF)
10713 +            goto defective;
10714 +        seqnum = load_uint64_be(ptr + 8);
10715 +
10716 +        /*
10717 +         * Although MIC tokens don't have a RRC, they are similarly
10718 +         * composed of a header and a checksum. So the verify_mic()
10719 +         * can be implemented with a single header buffer, fake the
10720 +         * RRC to the putative trailer length if no trailer buffer.
10721 +         */
10722 +        code = gssEapVerify(krbContext, ctx->checksumType,
10723 +                            trailer != NULL ? 0 : header->buffer.length - 16,
10724 +                            KRB_CRYPTO_CONTEXT(ctx), keyUsage,
10725 +                            iov, iov_count, &valid);
10726 +        if (code != 0 || valid == FALSE) {
10727 +            major = GSS_S_BAD_SIG;
10728 +            goto cleanup;
10729 +        }
10730 +        code = sequenceCheck(minor, &ctx->seqState, seqnum);
10731 +    } else if (toktype == TOK_TYPE_DELETE_CONTEXT) {
10732 +        if (load_uint16_be(ptr) != TOK_TYPE_DELETE_CONTEXT)
10733 +            goto defective;
10734 +        goto verify_mic_1;
10735 +    } else {
10736 +        goto defective;
10737 +    }
10738 +
10739 +    if (conf_state != NULL)
10740 +        *conf_state = conf_flag;
10741 +
10742 +    code = 0;
10743 +    major = GSS_S_COMPLETE;
10744 +    goto cleanup;
10745 +
10746 +defective:
10747 +    code = GSSEAP_BAD_WRAP_TOKEN;
10748 +    major = GSS_S_DEFECTIVE_TOKEN;
10749 +
10750 +cleanup:
10751 +    *minor = code;
10752 +#ifdef HAVE_HEIMDAL_VERSION
10753 +    if (freeCrypto && krbCrypto != NULL)
10754 +        krb5_crypto_destroy(krbContext, krbCrypto);
10755 +#endif
10756 +
10757 +    return major;
10758 +}
10759 +
10760 +int
10761 +rotateLeft(void *ptr, size_t bufsiz, size_t rc)
10762 +{
10763 +    void *tbuf;
10764 +
10765 +    if (bufsiz == 0)
10766 +        return 0;
10767 +    rc = rc % bufsiz;
10768 +    if (rc == 0)
10769 +        return 0;
10770 +
10771 +    tbuf = GSSEAP_MALLOC(rc);
10772 +    if (tbuf == NULL)
10773 +        return ENOMEM;
10774 +
10775 +    memcpy(tbuf, ptr, rc);
10776 +    memmove(ptr, (char *)ptr + rc, bufsiz - rc);
10777 +    memcpy((char *)ptr + bufsiz - rc, tbuf, rc);
10778 +    GSSEAP_FREE(tbuf);
10779 +
10780 +    return 0;
10781 +}
10782 +
10783 +/*
10784 + * Split a STREAM | SIGN_DATA | DATA into
10785 + *         HEADER | SIGN_DATA | DATA | PADDING | TRAILER
10786 + */
10787 +static OM_uint32
10788 +unwrapStream(OM_uint32 *minor,
10789 +             gss_ctx_id_t ctx,
10790 +             int *conf_state,
10791 +             gss_qop_t *qop_state,
10792 +             gss_iov_buffer_desc *iov,
10793 +             int iov_count,
10794 +             enum gss_eap_token_type toktype)
10795 +{
10796 +    unsigned char *ptr;
10797 +    OM_uint32 code = 0, major = GSS_S_FAILURE;
10798 +    krb5_context krbContext;
10799 +    int conf_req_flag;
10800 +    int i = 0, j;
10801 +    gss_iov_buffer_desc *tiov = NULL;
10802 +    gss_iov_buffer_t stream, data = NULL;
10803 +    gss_iov_buffer_t theader, tdata = NULL, tpadding, ttrailer;
10804 +#ifdef HAVE_HEIMDAL_VERSION
10805 +    krb5_crypto krbCrypto = NULL;
10806 +#endif
10807 +
10808 +    GSSEAP_KRB_INIT(&krbContext);
10809 +
10810 +    GSSEAP_ASSERT(toktype == TOK_TYPE_WRAP);
10811 +
10812 +    if (toktype != TOK_TYPE_WRAP) {
10813 +        code = GSSEAP_WRONG_TOK_ID;
10814 +        goto cleanup;
10815 +    }
10816 +
10817 +    stream = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_STREAM);
10818 +    GSSEAP_ASSERT(stream != NULL);
10819 +
10820 +    if (stream->buffer.length < 16) {
10821 +        major = GSS_S_DEFECTIVE_TOKEN;
10822 +        goto cleanup;
10823 +    }
10824 +
10825 +    ptr = (unsigned char *)stream->buffer.value;
10826 +    ptr += 2; /* skip token type */
10827 +
10828 +    tiov = (gss_iov_buffer_desc *)GSSEAP_CALLOC((size_t)iov_count + 2,
10829 +                                                sizeof(gss_iov_buffer_desc));
10830 +    if (tiov == NULL) {
10831 +        code = ENOMEM;
10832 +        goto cleanup;
10833 +    }
10834 +
10835 +    /* HEADER */
10836 +    theader = &tiov[i++];
10837 +    theader->type = GSS_IOV_BUFFER_TYPE_HEADER;
10838 +    theader->buffer.value = stream->buffer.value;
10839 +    theader->buffer.length = 16;
10840 +
10841 +    /* n[SIGN_DATA] | DATA | m[SIGN_DATA] */
10842 +    for (j = 0; j < iov_count; j++) {
10843 +        OM_uint32 type = GSS_IOV_BUFFER_TYPE(iov[j].type);
10844 +
10845 +        if (type == GSS_IOV_BUFFER_TYPE_DATA) {
10846 +            if (data != NULL) {
10847 +                /* only a single DATA buffer can appear */
10848 +                code = GSSEAP_BAD_STREAM_IOV;
10849 +                goto cleanup;
10850 +            }
10851 +
10852 +            data = &iov[j];
10853 +            tdata = &tiov[i];
10854 +        }
10855 +        if (type == GSS_IOV_BUFFER_TYPE_DATA ||
10856 +            type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
10857 +            tiov[i++] = iov[j];
10858 +    }
10859 +
10860 +    if (data == NULL) {
10861 +        /* a single DATA buffer must be present */
10862 +        code = GSSEAP_BAD_STREAM_IOV;
10863 +        goto cleanup;
10864 +    }
10865 +
10866 +    /* PADDING | TRAILER */
10867 +    tpadding = &tiov[i++];
10868 +    tpadding->type = GSS_IOV_BUFFER_TYPE_PADDING;
10869 +    tpadding->buffer.length = 0;
10870 +    tpadding->buffer.value = NULL;
10871 +
10872 +    ttrailer = &tiov[i++];
10873 +    ttrailer->type = GSS_IOV_BUFFER_TYPE_TRAILER;
10874 +
10875 +#ifdef HAVE_HEIMDAL_VERSION
10876 +    code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, ETYPE_NULL, &krbCrypto);
10877 +    if (code != 0)
10878 +        goto cleanup;
10879 +#endif
10880 +
10881 +    {
10882 +        size_t ec, rrc;
10883 +        size_t krbHeaderLen = 0;
10884 +        size_t krbTrailerLen = 0;
10885 +
10886 +        conf_req_flag = ((ptr[0] & TOK_FLAG_WRAP_CONFIDENTIAL) != 0);
10887 +        ec = conf_req_flag ? load_uint16_be(ptr + 2) : 0;
10888 +        rrc = load_uint16_be(ptr + 4);
10889 +
10890 +        if (rrc != 0) {
10891 +            code = rotateLeft((unsigned char *)stream->buffer.value + 16,
10892 +                              stream->buffer.length - 16, rrc);
10893 +            if (code != 0)
10894 +                goto cleanup;
10895 +            store_uint16_be(0, ptr + 4); /* set RRC to zero */
10896 +        }
10897 +
10898 +        if (conf_req_flag) {
10899 +            code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
10900 +                                    KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen);
10901 +            if (code != 0)
10902 +                goto cleanup;
10903 +            theader->buffer.length += krbHeaderLen; /* length validated later */
10904 +        }
10905 +
10906 +        /* no PADDING for CFX, EC is used instead */
10907 +        code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
10908 +                               conf_req_flag
10909 +                                  ? KRB5_CRYPTO_TYPE_TRAILER
10910 +                                  : KRB5_CRYPTO_TYPE_CHECKSUM,
10911 +                               &krbTrailerLen);
10912 +        if (code != 0)
10913 +            goto cleanup;
10914 +
10915 +        ttrailer->buffer.length = ec + (conf_req_flag ? 16 : 0 /* E(Header) */) +
10916 +                                  krbTrailerLen;
10917 +        ttrailer->buffer.value = (unsigned char *)stream->buffer.value +
10918 +            stream->buffer.length - ttrailer->buffer.length;
10919 +    }
10920 +
10921 +    /* IOV: -----------0-------------+---1---+--2--+----------------3--------------*/
10922 +    /* CFX: GSS-Header | Kerb-Header | Data  |     | EC | E(Header) | Kerb-Trailer */
10923 +    /* GSS: -------GSS-HEADER--------+-DATA--+-PAD-+----------GSS-TRAILER----------*/
10924 +
10925 +    /* validate lengths */
10926 +    if (stream->buffer.length < theader->buffer.length +
10927 +        tpadding->buffer.length +
10928 +        ttrailer->buffer.length) {
10929 +        major = GSS_S_DEFECTIVE_TOKEN;
10930 +        code = GSSEAP_TOK_TRUNC;
10931 +        goto cleanup;
10932 +    }
10933 +
10934 +    /* setup data */
10935 +    tdata->buffer.length = stream->buffer.length - ttrailer->buffer.length -
10936 +        tpadding->buffer.length - theader->buffer.length;
10937 +
10938 +    GSSEAP_ASSERT(data != NULL);
10939 +
10940 +    if (data->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
10941 +        code = gssEapAllocIov(tdata, tdata->buffer.length);
10942 +        if (code != 0)
10943 +            goto cleanup;
10944 +
10945 +        memcpy(tdata->buffer.value,
10946 +               (unsigned char *)stream->buffer.value + theader->buffer.length,
10947 +               tdata->buffer.length);
10948 +    } else {
10949 +        tdata->buffer.value = (unsigned char *)stream->buffer.value +
10950 +                              theader->buffer.length;
10951 +    }
10952 +
10953 +    GSSEAP_ASSERT(i <= iov_count + 2);
10954 +
10955 +    major = unwrapToken(&code, ctx, KRB_CRYPTO_CONTEXT(ctx),
10956 +                        conf_state, qop_state, tiov, i, toktype);
10957 +    if (major == GSS_S_COMPLETE) {
10958 +        *data = *tdata;
10959 +    } else if (tdata->type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {
10960 +        OM_uint32 tmp;
10961 +
10962 +        gss_release_buffer(&tmp, &tdata->buffer);
10963 +        tdata->type &= ~(GSS_IOV_BUFFER_FLAG_ALLOCATED);
10964 +    }
10965 +
10966 +cleanup:
10967 +    if (tiov != NULL)
10968 +        GSSEAP_FREE(tiov);
10969 +#ifdef HAVE_HEIMDAL_VERSION
10970 +    if (krbCrypto != NULL)
10971 +        krb5_crypto_destroy(krbContext, krbCrypto);
10972 +#endif
10973 +
10974 +    *minor = code;
10975 +
10976 +    return major;
10977 +}
10978 +
10979 +OM_uint32
10980 +gssEapUnwrapOrVerifyMIC(OM_uint32 *minor,
10981 +                        gss_ctx_id_t ctx,
10982 +                        int *conf_state,
10983 +                        gss_qop_t *qop_state,
10984 +                        gss_iov_buffer_desc *iov,
10985 +                        int iov_count,
10986 +                        enum gss_eap_token_type toktype)
10987 +{
10988 +    OM_uint32 major;
10989 +
10990 +    if (ctx->encryptionType == ENCTYPE_NULL) {
10991 +        *minor = GSSEAP_KEY_UNAVAILABLE;
10992 +        return GSS_S_UNAVAILABLE;
10993 +    }
10994 +
10995 +    if (gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_STREAM) != NULL) {
10996 +        major = unwrapStream(minor, ctx, conf_state, qop_state,
10997 +                             iov, iov_count, toktype);
10998 +    } else {
10999 +        major = unwrapToken(minor, ctx,
11000 +                            NULL, /* krbCrypto */
11001 +                            conf_state, qop_state,
11002 +                            iov, iov_count, toktype);
11003 +    }
11004 +
11005 +    return major;
11006 +}
11007 +
11008 +OM_uint32 GSSAPI_CALLCONV
11009 +gss_unwrap_iov(OM_uint32 *minor,
11010 +               gss_ctx_id_t ctx,
11011 +               int *conf_state,
11012 +               gss_qop_t *qop_state,
11013 +               gss_iov_buffer_desc *iov,
11014 +               int iov_count)
11015 +{
11016 +    OM_uint32 major;
11017 +
11018 +    if (ctx == GSS_C_NO_CONTEXT) {
11019 +        *minor = EINVAL;
11020 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
11021 +    }
11022 +
11023 +    *minor = 0;
11024 +
11025 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
11026 +
11027 +    if (!CTX_IS_ESTABLISHED(ctx)) {
11028 +        major = GSS_S_NO_CONTEXT;
11029 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
11030 +        goto cleanup;
11031 +    }
11032 +
11033 +    major = gssEapUnwrapOrVerifyMIC(minor, ctx, conf_state, qop_state,
11034 +                                    iov, iov_count, TOK_TYPE_WRAP);
11035 +    if (GSS_ERROR(major))
11036 +        goto cleanup;
11037 +
11038 +cleanup:
11039 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
11040 +
11041 +    return major;
11042 +}
11043 diff --git a/mech_eap/util.h b/mech_eap/util.h
11044 new file mode 100644
11045 index 0000000..4f54d41
11046 --- /dev/null
11047 +++ b/mech_eap/util.h
11048 @@ -0,0 +1,1032 @@
11049 +/*
11050 + * Copyright (c) 2011, JANET(UK)
11051 + * All rights reserved.
11052 + *
11053 + * Redistribution and use in source and binary forms, with or without
11054 + * modification, are permitted provided that the following conditions
11055 + * are met:
11056 + *
11057 + * 1. Redistributions of source code must retain the above copyright
11058 + *    notice, this list of conditions and the following disclaimer.
11059 + *
11060 + * 2. Redistributions in binary form must reproduce the above copyright
11061 + *    notice, this list of conditions and the following disclaimer in the
11062 + *    documentation and/or other materials provided with the distribution.
11063 + *
11064 + * 3. Neither the name of JANET(UK) nor the names of its contributors
11065 + *    may be used to endorse or promote products derived from this software
11066 + *    without specific prior written permission.
11067 + *
11068 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
11069 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
11070 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
11071 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
11072 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
11073 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
11074 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
11075 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
11076 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
11077 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
11078 + * SUCH DAMAGE.
11079 + */
11080 +/*
11081 + * Portions Copyright 2003-2010 Massachusetts Institute of Technology.
11082 + * All Rights Reserved.
11083 + *
11084 + * Export of this software from the United States of America may
11085 + *   require a specific license from the United States Government.
11086 + *   It is the responsibility of any person or organization contemplating
11087 + *   export to obtain such a license before exporting.
11088 + *
11089 + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
11090 + * distribute this software and its documentation for any purpose and
11091 + * without fee is hereby granted, provided that the above copyright
11092 + * notice appear in all copies and that both that copyright notice and
11093 + * this permission notice appear in supporting documentation, and that
11094 + * the name of M.I.T. not be used in advertising or publicity pertaining
11095 + * to distribution of the software without specific, written prior
11096 + * permission.  Furthermore if you modify this software you must label
11097 + * your software as modified software and not distribute it in such a
11098 + * fashion that it might be confused with the original M.I.T. software.
11099 + * M.I.T. makes no representations about the suitability of
11100 + * this software for any purpose.  It is provided "as is" without express
11101 + * or implied warranty.
11102 + *
11103 + */
11104 +
11105 +/*
11106 + * Utility functions.
11107 + */
11108 +
11109 +#ifndef _UTIL_H_
11110 +#define _UTIL_H_ 1
11111 +
11112 +#ifdef HAVE_SYS_PARAM_H
11113 +#include <sys/param.h>
11114 +#endif
11115 +#ifdef HAVE_STDINT_H
11116 +#include <stdint.h>
11117 +#endif
11118 +#include <string.h>
11119 +#include <errno.h>
11120 +
11121 +#include <krb5.h>
11122 +
11123 +#ifdef WIN32
11124 +#define inline __inline
11125 +#define snprintf _snprintf
11126 +#endif
11127 +
11128 +#ifdef __cplusplus
11129 +extern "C" {
11130 +#endif
11131 +
11132 +#ifndef MIN
11133 +#define MIN(_a,_b)  ((_a)<(_b)?(_a):(_b))
11134 +#endif
11135 +
11136 +#if !defined(WIN32) && !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
11137 +#define GSSEAP_UNUSED __attribute__ ((__unused__))
11138 +#else
11139 +#define GSSEAP_UNUSED
11140 +#endif
11141 +
11142 +/* util_buffer.c */
11143 +OM_uint32
11144 +makeStringBuffer(OM_uint32 *minor,
11145 +                 const char *string,
11146 +                 gss_buffer_t buffer);
11147 +
11148 +#define makeStringBufferOrCleanup(src, dst)             \
11149 +    do {                                                \
11150 +        major = makeStringBuffer((minor), (src), (dst));\
11151 +        if (GSS_ERROR(major))                           \
11152 +            goto cleanup;                               \
11153 +    } while (0)
11154 +
11155 +OM_uint32
11156 +bufferToString(OM_uint32 *minor,
11157 +               const gss_buffer_t buffer,
11158 +               char **pString);
11159 +
11160 +OM_uint32
11161 +duplicateBuffer(OM_uint32 *minor,
11162 +                const gss_buffer_t src,
11163 +                gss_buffer_t dst);
11164 +
11165 +#define duplicateBufferOrCleanup(src, dst)              \
11166 +    do {                                                \
11167 +        major = duplicateBuffer((minor), (src), (dst)); \
11168 +        if (GSS_ERROR(major))                           \
11169 +            goto cleanup;                               \
11170 +    } while (0)
11171 +
11172 +static inline int
11173 +bufferEqual(const gss_buffer_t b1, const gss_buffer_t b2)
11174 +{
11175 +    return (b1->length == b2->length &&
11176 +            memcmp(b1->value, b2->value, b2->length) == 0);
11177 +}
11178 +
11179 +static inline int
11180 +bufferEqualString(const gss_buffer_t b1, const char *s)
11181 +{
11182 +    gss_buffer_desc b2;
11183 +
11184 +    b2.length = strlen(s);
11185 +    b2.value = (char *)s;
11186 +
11187 +    return bufferEqual(b1, &b2);
11188 +}
11189 +
11190 +/* util_cksum.c */
11191 +int
11192 +gssEapSign(krb5_context context,
11193 +           krb5_cksumtype type,
11194 +           size_t rrc,
11195 +#ifdef HAVE_HEIMDAL_VERSION
11196 +           krb5_crypto crypto,
11197 +#else
11198 +           krb5_keyblock *key,
11199 +#endif
11200 +           krb5_keyusage sign_usage,
11201 +           gss_iov_buffer_desc *iov,
11202 +           int iov_count);
11203 +
11204 +int
11205 +gssEapVerify(krb5_context context,
11206 +             krb5_cksumtype type,
11207 +             size_t rrc,
11208 +#ifdef HAVE_HEIMDAL_VERSION
11209 +             krb5_crypto crypto,
11210 +#else
11211 +             krb5_keyblock *key,
11212 +#endif
11213 +             krb5_keyusage sign_usage,
11214 +             gss_iov_buffer_desc *iov,
11215 +             int iov_count,
11216 +             int *valid);
11217 +
11218 +#if 0
11219 +OM_uint32
11220 +gssEapEncodeGssChannelBindings(OM_uint32 *minor,
11221 +                               gss_channel_bindings_t chanBindings,
11222 +                               gss_buffer_t encodedBindings);
11223 +#endif
11224 +
11225 +/* util_context.c */
11226 +#define EAP_EXPORT_CONTEXT_V1           1
11227 +
11228 +enum gss_eap_token_type {
11229 +    TOK_TYPE_NONE                    = 0x0000,  /* no token */
11230 +    TOK_TYPE_MIC                     = 0x0404,  /* RFC 4121 MIC token */
11231 +    TOK_TYPE_WRAP                    = 0x0504,  /* RFC 4121 wrap token */
11232 +    TOK_TYPE_EXPORT_NAME             = 0x0401,  /* RFC 2743 exported name */
11233 +    TOK_TYPE_EXPORT_NAME_COMPOSITE   = 0x0402,  /* exported composite name */
11234 +    TOK_TYPE_DELETE_CONTEXT          = 0x0405,  /* RFC 2743 delete context */
11235 +    TOK_TYPE_INITIATOR_CONTEXT       = 0x0601,  /* initiator-sent context token */
11236 +    TOK_TYPE_ACCEPTOR_CONTEXT        = 0x0602,  /* acceptor-sent context token */
11237 +};
11238 +
11239 +/* inner token types and flags */
11240 +#define ITOK_TYPE_NONE                  0x00000000
11241 +#define ITOK_TYPE_CONTEXT_ERR           0x00000001 /* critical */
11242 +#define ITOK_TYPE_ACCEPTOR_NAME_REQ     0x00000002 /* TBD */
11243 +#define ITOK_TYPE_ACCEPTOR_NAME_RESP    0x00000003 /* TBD */
11244 +#define ITOK_TYPE_EAP_RESP              0x00000004 /* critical, required, if not reauth */
11245 +#define ITOK_TYPE_EAP_REQ               0x00000005 /* critical, required, if not reauth */
11246 +#define ITOK_TYPE_GSS_CHANNEL_BINDINGS  0x00000006 /* critical, required, if not reauth */
11247 +#define ITOK_TYPE_REAUTH_CREDS          0x00000007 /* optional */
11248 +#define ITOK_TYPE_REAUTH_REQ            0x00000008 /* optional */
11249 +#define ITOK_TYPE_REAUTH_RESP           0x00000009 /* optional */
11250 +#define ITOK_TYPE_VERSION_INFO          0x0000000A /* optional */
11251 +#define ITOK_TYPE_VENDOR_INFO           0x0000000B /* optional */
11252 +#define ITOK_TYPE_GSS_FLAGS             0x0000000C /* optional */
11253 +#define ITOK_TYPE_INITIATOR_MIC         0x0000000D /* critical, required, if not reauth */
11254 +#define ITOK_TYPE_ACCEPTOR_MIC          0x0000000E /* TBD */
11255 +
11256 +#define ITOK_FLAG_CRITICAL              0x80000000  /* critical, wire flag */
11257 +#define ITOK_FLAG_VERIFIED              0x40000000  /* verified, API flag */
11258 +
11259 +#define ITOK_TYPE_MASK                  (~(ITOK_FLAG_CRITICAL | ITOK_FLAG_VERIFIED))
11260 +
11261 +#define GSSEAP_WIRE_FLAGS_MASK          ( GSS_C_MUTUAL_FLAG             | \
11262 +                                          GSS_C_DCE_STYLE               | \
11263 +                                          GSS_C_IDENTIFY_FLAG           | \
11264 +                                          GSS_C_EXTENDED_ERROR_FLAG       )
11265 +
11266 +OM_uint32 gssEapAllocContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
11267 +OM_uint32 gssEapReleaseContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
11268 +
11269 +OM_uint32
11270 +gssEapMakeToken(OM_uint32 *minor,
11271 +                gss_ctx_id_t ctx,
11272 +                const gss_buffer_t innerToken,
11273 +                enum gss_eap_token_type tokenType,
11274 +                gss_buffer_t outputToken);
11275 +
11276 +OM_uint32
11277 +gssEapVerifyToken(OM_uint32 *minor,
11278 +                  gss_ctx_id_t ctx,
11279 +                  const gss_buffer_t inputToken,
11280 +                  enum gss_eap_token_type *tokenType,
11281 +                  gss_buffer_t innerInputToken);
11282 +
11283 +OM_uint32
11284 +gssEapContextTime(OM_uint32 *minor,
11285 +                  gss_ctx_id_t context_handle,
11286 +                  OM_uint32 *time_rec);
11287 +
11288 +OM_uint32
11289 +gssEapMakeTokenMIC(OM_uint32 *minor,
11290 +                   gss_ctx_id_t ctx,
11291 +                   gss_buffer_t tokenMIC);
11292 +
11293 +OM_uint32
11294 +gssEapVerifyTokenMIC(OM_uint32 *minor,
11295 +                     gss_ctx_id_t ctx,
11296 +                     const gss_buffer_t tokenMIC);
11297 +
11298 +/* util_cred.c */
11299 +OM_uint32 gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred);
11300 +OM_uint32 gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred);
11301 +
11302 +gss_OID
11303 +gssEapPrimaryMechForCred(gss_cred_id_t cred);
11304 +
11305 +OM_uint32
11306 +gssEapAcquireCred(OM_uint32 *minor,
11307 +                  const gss_name_t desiredName,
11308 +                  OM_uint32 timeReq,
11309 +                  const gss_OID_set desiredMechs,
11310 +                  int cred_usage,
11311 +                  gss_cred_id_t *pCred,
11312 +                  gss_OID_set *pActualMechs,
11313 +                  OM_uint32 *timeRec);
11314 +
11315 +OM_uint32
11316 +gssEapSetCredPassword(OM_uint32 *minor,
11317 +                      gss_cred_id_t cred,
11318 +                      const gss_buffer_t password);
11319 +
11320 +OM_uint32
11321 +gssEapSetCredService(OM_uint32 *minor,
11322 +                     gss_cred_id_t cred,
11323 +                     const gss_name_t target);
11324 +
11325 +OM_uint32
11326 +gssEapResolveInitiatorCred(OM_uint32 *minor,
11327 +                           const gss_cred_id_t cred,
11328 +                           const gss_name_t target,
11329 +                           gss_cred_id_t *resolvedCred);
11330 +
11331 +int gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech);
11332 +
11333 +OM_uint32
11334 +gssEapInquireCred(OM_uint32 *minor,
11335 +                  gss_cred_id_t cred,
11336 +                  gss_name_t *name,
11337 +                  OM_uint32 *pLifetime,
11338 +                  gss_cred_usage_t *cred_usage,
11339 +                  gss_OID_set *mechanisms);
11340 +
11341 +/* util_crypt.c */
11342 +int
11343 +gssEapEncrypt(krb5_context context, int dce_style, size_t ec,
11344 +              size_t rrc,
11345 +#ifdef HAVE_HEIMDAL_VERSION
11346 +              krb5_crypto crypto,
11347 +#else
11348 +              krb5_keyblock *key,
11349 +#endif
11350 +              int usage,
11351 +              gss_iov_buffer_desc *iov, int iov_count);
11352 +
11353 +int
11354 +gssEapDecrypt(krb5_context context, int dce_style, size_t ec,
11355 +              size_t rrc,
11356 +#ifdef HAVE_HEIMDAL_VERSION
11357 +              krb5_crypto crypto,
11358 +#else
11359 +              krb5_keyblock *key,
11360 +#endif
11361 +              int usage,
11362 +              gss_iov_buffer_desc *iov, int iov_count);
11363 +
11364 +int
11365 +gssEapMapCryptoFlag(OM_uint32 type);
11366 +
11367 +gss_iov_buffer_t
11368 +gssEapLocateIov(gss_iov_buffer_desc *iov,
11369 +                int iov_count,
11370 +                OM_uint32 type);
11371 +
11372 +void
11373 +gssEapIovMessageLength(gss_iov_buffer_desc *iov,
11374 +                       int iov_count,
11375 +                       size_t *data_length,
11376 +                       size_t *assoc_data_length);
11377 +
11378 +void
11379 +gssEapReleaseIov(gss_iov_buffer_desc *iov, int iov_count);
11380 +
11381 +int
11382 +gssEapIsIntegrityOnly(gss_iov_buffer_desc *iov, int iov_count);
11383 +
11384 +int
11385 +gssEapAllocIov(gss_iov_buffer_t iov, size_t size);
11386 +
11387 +OM_uint32
11388 +gssEapDeriveRfc3961Key(OM_uint32 *minor,
11389 +                       const unsigned char *key,
11390 +                       size_t keyLength,
11391 +                       krb5_enctype enctype,
11392 +                       krb5_keyblock *pKey);
11393 +
11394 +/* util_krb.c */
11395 +
11396 +#ifndef KRB_MALLOC
11397 +/*
11398 + * If your Kerberos library uses a different allocator to your
11399 + * GSS mechanism glue, then you might wish to define these in
11400 + * config.h or elsewhere. This should eventually go away when
11401 + * we no longer need to allocate memory that is freed by the
11402 + * Kerberos library.
11403 + */
11404 +#define KRB_CALLOC                      calloc
11405 +#define KRB_MALLOC                      malloc
11406 +#define KRB_FREE                        free
11407 +#define KRB_REALLOC                     realloc
11408 +#endif /* KRB_MALLOC */
11409 +
11410 +#ifdef HAVE_HEIMDAL_VERSION
11411 +
11412 +#define KRB_TIME_FOREVER        ((time_t)~0L)
11413 +
11414 +#define KRB_KEY_TYPE(key)       ((key)->keytype)
11415 +#define KRB_KEY_DATA(key)       ((key)->keyvalue.data)
11416 +#define KRB_KEY_LENGTH(key)     ((key)->keyvalue.length)
11417 +
11418 +#define KRB_PRINC_LENGTH(princ) ((princ)->name.name_string.len)
11419 +#define KRB_PRINC_TYPE(princ)   ((princ)->name.name_type)
11420 +#define KRB_PRINC_NAME(princ)   ((princ)->name.name_string.val)
11421 +#define KRB_PRINC_REALM(princ)  ((princ)->realm)
11422 +
11423 +#define KRB_KT_ENT_KEYBLOCK(e)  (&(e)->keyblock)
11424 +#define KRB_KT_ENT_FREE(c, e)   krb5_kt_free_entry((c), (e))
11425 +
11426 +#define KRB_CRYPTO_CONTEXT(ctx) (krbCrypto)
11427 +
11428 +#define KRB_DATA_INIT(d)        krb5_data_zero((d))
11429 +
11430 +#else
11431 +
11432 +#define KRB_TIME_FOREVER        KRB5_INT32_MAX
11433 +
11434 +#define KRB_KEY_TYPE(key)       ((key)->enctype)
11435 +#define KRB_KEY_DATA(key)       ((key)->contents)
11436 +#define KRB_KEY_LENGTH(key)     ((key)->length)
11437 +
11438 +#define KRB_PRINC_LENGTH(princ) (krb5_princ_size(NULL, (princ)))
11439 +#define KRB_PRINC_TYPE(princ)   (krb5_princ_type(NULL, (princ)))
11440 +#define KRB_PRINC_NAME(princ)   (krb5_princ_name(NULL, (princ)))
11441 +#define KRB_PRINC_REALM(princ)  (krb5_princ_realm(NULL, (princ)))
11442 +
11443 +#define KRB_KT_ENT_KEYBLOCK(e)  (&(e)->key)
11444 +#define KRB_KT_ENT_FREE(c, e)   krb5_free_keytab_entry_contents((c), (e))
11445 +
11446 +#define KRB_CRYPTO_CONTEXT(ctx) (&(ctx)->rfc3961Key)
11447 +
11448 +#define KRB_DATA_INIT(d)        do {        \
11449 +        (d)->magic = KV5M_DATA;             \
11450 +        (d)->length = 0;                    \
11451 +        (d)->data = NULL;                   \
11452 +    } while (0)
11453 +
11454 +#endif /* HAVE_HEIMDAL_VERSION */
11455 +
11456 +#define KRB_KEY_INIT(key)       do {        \
11457 +        KRB_KEY_TYPE(key) = ENCTYPE_NULL;   \
11458 +        KRB_KEY_DATA(key) = NULL;           \
11459 +        KRB_KEY_LENGTH(key) = 0;            \
11460 +    } while (0)
11461 +
11462 +#define GSSEAP_KRB_INIT(ctx) do {                   \
11463 +        OM_uint32 tmpMajor;                         \
11464 +                                                    \
11465 +        tmpMajor  = gssEapKerberosInit(minor, ctx); \
11466 +        if (GSS_ERROR(tmpMajor)) {                  \
11467 +            return tmpMajor;                        \
11468 +        }                                           \
11469 +    } while (0)
11470 +
11471 +OM_uint32
11472 +gssEapKerberosInit(OM_uint32 *minor, krb5_context *context);
11473 +
11474 +OM_uint32
11475 +rfc3961ChecksumTypeForKey(OM_uint32 *minor,
11476 +                          krb5_keyblock *key,
11477 +                          krb5_cksumtype *cksumtype);
11478 +
11479 +krb5_error_code
11480 +krbCryptoLength(krb5_context krbContext,
11481 +#ifdef HAVE_HEIMDAL_VERSION
11482 +                krb5_crypto krbCrypto,
11483 +#else
11484 +                krb5_keyblock *key,
11485 +#endif
11486 +                int type,
11487 +                size_t *length);
11488 +
11489 +krb5_error_code
11490 +krbPaddingLength(krb5_context krbContext,
11491 +#ifdef HAVE_HEIMDAL_VERSION
11492 +                 krb5_crypto krbCrypto,
11493 +#else
11494 +                 krb5_keyblock *key,
11495 +#endif
11496 +                 size_t dataLength,
11497 +                 size_t *padLength);
11498 +
11499 +krb5_error_code
11500 +krbBlockSize(krb5_context krbContext,
11501 +#ifdef HAVE_HEIMDAL_VERSION
11502 +                 krb5_crypto krbCrypto,
11503 +#else
11504 +                 krb5_keyblock *key,
11505 +#endif
11506 +                 size_t *blockSize);
11507 +
11508 +krb5_error_code
11509 +krbEnctypeToString(krb5_context krbContext,
11510 +                   krb5_enctype enctype,
11511 +                   const char *prefix,
11512 +                   gss_buffer_t string);
11513 +
11514 +krb5_error_code
11515 +krbMakeAuthDataKdcIssued(krb5_context context,
11516 +                         const krb5_keyblock *key,
11517 +                         krb5_const_principal issuer,
11518 +#ifdef HAVE_HEIMDAL_VERSION
11519 +                         const AuthorizationData *authdata,
11520 +                         AuthorizationData *adKdcIssued
11521 +#else
11522 +                         krb5_authdata *const *authdata,
11523 +                         krb5_authdata ***adKdcIssued
11524 +#endif
11525 +                         );
11526 +
11527 +krb5_error_code
11528 +krbMakeCred(krb5_context context,
11529 +            krb5_auth_context authcontext,
11530 +            krb5_creds *creds,
11531 +            krb5_data *data);
11532 +
11533 +/* util_lucid.c */
11534 +OM_uint32
11535 +gssEapExportLucidSecContext(OM_uint32 *minor,
11536 +                            gss_ctx_id_t ctx,
11537 +                            const gss_OID desiredObject,
11538 +                            gss_buffer_set_t *data_set);
11539 +
11540 +/* util_mech.c */
11541 +extern gss_OID GSS_EAP_MECHANISM;
11542 +
11543 +#define OID_FLAG_NULL_VALID                 0x00000001
11544 +#define OID_FLAG_FAMILY_MECH_VALID          0x00000002
11545 +#define OID_FLAG_MAP_NULL_TO_DEFAULT_MECH   0x00000004
11546 +#define OID_FLAG_MAP_FAMILY_MECH_TO_NULL    0x00000008
11547 +
11548 +OM_uint32
11549 +gssEapCanonicalizeOid(OM_uint32 *minor,
11550 +                      const gss_OID oid,
11551 +                      OM_uint32 flags,
11552 +                      gss_OID *pOid);
11553 +
11554 +OM_uint32
11555 +gssEapReleaseOid(OM_uint32 *minor, gss_OID *oid);
11556 +
11557 +OM_uint32
11558 +gssEapDefaultMech(OM_uint32 *minor,
11559 +                  gss_OID *oid);
11560 +
11561 +OM_uint32
11562 +gssEapIndicateMechs(OM_uint32 *minor,
11563 +                    gss_OID_set *mechs);
11564 +
11565 +OM_uint32
11566 +gssEapEnctypeToOid(OM_uint32 *minor,
11567 +                   krb5_enctype enctype,
11568 +                   gss_OID *pOid);
11569 +
11570 +OM_uint32
11571 +gssEapOidToEnctype(OM_uint32 *minor,
11572 +                   const gss_OID oid,
11573 +                   krb5_enctype *enctype);
11574 +
11575 +int
11576 +gssEapIsMechanismOid(const gss_OID oid);
11577 +
11578 +int
11579 +gssEapIsConcreteMechanismOid(const gss_OID oid);
11580 +
11581 +OM_uint32
11582 +gssEapValidateMechs(OM_uint32 *minor,
11583 +                   const gss_OID_set mechs);
11584 +
11585 +gss_buffer_t
11586 +gssEapOidToSaslName(const gss_OID oid);
11587 +
11588 +gss_OID
11589 +gssEapSaslNameToOid(const gss_buffer_t name);
11590 +
11591 +/* util_moonshot.c */
11592 +OM_uint32
11593 +libMoonshotResolveDefaultIdentity(OM_uint32 *minor,
11594 +                                  const gss_cred_id_t cred,
11595 +                                  gss_name_t *pName);
11596 +
11597 +OM_uint32
11598 +libMoonshotResolveInitiatorCred(OM_uint32 *minor,
11599 +                                gss_cred_id_t cred,
11600 +                                const gss_name_t targetName);
11601 +
11602 +/* util_name.c */
11603 +#define EXPORT_NAME_FLAG_OID                    0x1
11604 +#define EXPORT_NAME_FLAG_COMPOSITE              0x2
11605 +#define EXPORT_NAME_FLAG_ALLOW_COMPOSITE        0x4
11606 +
11607 +OM_uint32 gssEapAllocName(OM_uint32 *minor, gss_name_t *pName);
11608 +OM_uint32 gssEapReleaseName(OM_uint32 *minor, gss_name_t *pName);
11609 +OM_uint32 gssEapExportName(OM_uint32 *minor,
11610 +                           const gss_name_t name,
11611 +                           gss_buffer_t exportedName);
11612 +OM_uint32 gssEapExportNameInternal(OM_uint32 *minor,
11613 +                                   const gss_name_t name,
11614 +                                   gss_buffer_t exportedName,
11615 +                                   OM_uint32 flags);
11616 +OM_uint32 gssEapImportName(OM_uint32 *minor,
11617 +                           const gss_buffer_t input_name_buffer,
11618 +                           const gss_OID input_name_type,
11619 +                           const gss_OID input_mech_type,
11620 +                           gss_name_t *output_name);
11621 +OM_uint32 gssEapImportNameInternal(OM_uint32 *minor,
11622 +                                   const gss_buffer_t input_name_buffer,
11623 +                                   gss_name_t *output_name,
11624 +                                   OM_uint32 flags);
11625 +OM_uint32
11626 +gssEapDuplicateName(OM_uint32 *minor,
11627 +                    const gss_name_t input_name,
11628 +                    gss_name_t *dest_name);
11629 +
11630 +OM_uint32
11631 +gssEapCanonicalizeName(OM_uint32 *minor,
11632 +                       const gss_name_t input_name,
11633 +                       const gss_OID mech_type,
11634 +                       gss_name_t *dest_name);
11635 +
11636 +OM_uint32
11637 +gssEapDisplayName(OM_uint32 *minor,
11638 +                  gss_name_t name,
11639 +                  gss_buffer_t output_name_buffer,
11640 +                  gss_OID *output_name_type);
11641 +
11642 +OM_uint32
11643 +gssEapCompareName(OM_uint32 *minor,
11644 +                  gss_name_t name1,
11645 +                  gss_name_t name2,
11646 +                  int *name_equal);
11647 +
11648 +/* util_oid.c */
11649 +OM_uint32
11650 +composeOid(OM_uint32 *minor_status,
11651 +           const char *prefix,
11652 +           size_t prefix_len,
11653 +           int suffix,
11654 +           gss_OID_desc *oid);
11655 +
11656 +OM_uint32
11657 +decomposeOid(OM_uint32 *minor_status,
11658 +             const char *prefix,
11659 +             size_t prefix_len,
11660 +             gss_OID_desc *oid,
11661 +             int *suffix) ;
11662 +
11663 +OM_uint32
11664 +duplicateOid(OM_uint32 *minor_status,
11665 +             const gss_OID_desc * const oid,
11666 +             gss_OID *new_oid);
11667 +
11668 +OM_uint32
11669 +duplicateOidSet(OM_uint32 *minor,
11670 +                const gss_OID_set src,
11671 +                gss_OID_set *dst);
11672 +
11673 +static inline int
11674 +oidEqual(const gss_OID_desc *o1, const gss_OID_desc *o2)
11675 +{
11676 +    if (o1 == GSS_C_NO_OID)
11677 +        return (o2 == GSS_C_NO_OID);
11678 +    else if (o2 == GSS_C_NO_OID)
11679 +        return (o1 == GSS_C_NO_OID);
11680 +    else
11681 +        return (o1->length == o2->length &&
11682 +                memcmp(o1->elements, o2->elements, o1->length) == 0);
11683 +}
11684 +
11685 +/* util_ordering.c */
11686 +OM_uint32
11687 +sequenceInternalize(OM_uint32 *minor,
11688 +                    void **vqueue,
11689 +                    unsigned char **buf,
11690 +                    size_t *lenremain);
11691 +
11692 +OM_uint32
11693 +sequenceExternalize(OM_uint32 *minor,
11694 +                    void *vqueue,
11695 +                    unsigned char **buf,
11696 +                    size_t *lenremain);
11697 +
11698 +size_t
11699 +sequenceSize(void *vqueue);
11700 +
11701 +OM_uint32
11702 +sequenceFree(OM_uint32 *minor, void **vqueue);
11703 +
11704 +OM_uint32
11705 +sequenceCheck(OM_uint32 *minor, void **vqueue, uint64_t seqnum);
11706 +
11707 +OM_uint32
11708 +sequenceInit(OM_uint32 *minor, void **vqueue, uint64_t seqnum,
11709 +             int do_replay, int do_sequence, int wide_nums);
11710 +
11711 +/* util_sm.c */
11712 +enum gss_eap_state {
11713 +    GSSEAP_STATE_INITIAL        = 0x01,     /* initial state */
11714 +    GSSEAP_STATE_AUTHENTICATE   = 0x02,     /* exchange EAP messages */
11715 +    GSSEAP_STATE_INITIATOR_EXTS = 0x04,     /* initiator extensions */
11716 +    GSSEAP_STATE_ACCEPTOR_EXTS  = 0x08,     /* acceptor extensions */
11717 +#ifdef GSSEAP_ENABLE_REAUTH
11718 +    GSSEAP_STATE_REAUTHENTICATE = 0x10,     /* GSS reauthentication messages */
11719 +#endif
11720 +    GSSEAP_STATE_ESTABLISHED    = 0x20,     /* context established */
11721 +    GSSEAP_STATE_ALL            = 0x3F
11722 +};
11723 +
11724 +#define GSSEAP_STATE_NEXT(s)    ((s) << 1)
11725 +
11726 +#define GSSEAP_SM_STATE(ctx)                ((ctx)->state)
11727 +
11728 +#ifdef GSSEAP_DEBUG
11729 +void gssEapSmTransition(gss_ctx_id_t ctx, enum gss_eap_state state);
11730 +#define GSSEAP_SM_TRANSITION(ctx, state)    gssEapSmTransition((ctx), (state))
11731 +#else
11732 +#define GSSEAP_SM_TRANSITION(ctx, newstate)    do { (ctx)->state = (newstate); } while (0)
11733 +#endif
11734 +
11735 +#define GSSEAP_SM_TRANSITION_NEXT(ctx)      GSSEAP_SM_TRANSITION((ctx), GSSEAP_STATE_NEXT(GSSEAP_SM_STATE((ctx))))
11736 +
11737 +/* state machine entry */
11738 +struct gss_eap_sm {
11739 +    OM_uint32 inputTokenType;
11740 +    OM_uint32 outputTokenType;
11741 +    enum gss_eap_state validStates;
11742 +    OM_uint32 itokFlags;
11743 +    OM_uint32 (*processToken)(OM_uint32 *,
11744 +                              gss_cred_id_t,
11745 +                              gss_ctx_id_t,
11746 +                              gss_name_t,
11747 +                              gss_OID,
11748 +                              OM_uint32,
11749 +                              OM_uint32,
11750 +                              gss_channel_bindings_t,
11751 +                              gss_buffer_t,
11752 +                              gss_buffer_t,
11753 +                              OM_uint32 *);
11754 +};
11755 +
11756 +/* state machine flags, set by handler */
11757 +#define SM_FLAG_FORCE_SEND_TOKEN            0x00000001  /* send token even if no inner tokens */
11758 +#define SM_FLAG_OUTPUT_TOKEN_CRITICAL       0x00000002  /* output token is critical */
11759 +
11760 +/* state machine flags, set by state machine */
11761 +#define SM_FLAG_INPUT_TOKEN_CRITICAL        0x10000000  /* input token was critical */
11762 +
11763 +#define SM_ITOK_FLAG_REQUIRED               0x00000001  /* received tokens must be present */
11764 +
11765 +OM_uint32
11766 +gssEapSmStep(OM_uint32 *minor,
11767 +             gss_cred_id_t cred,
11768 +             gss_ctx_id_t ctx,
11769 +             gss_name_t target,
11770 +             gss_OID mech,
11771 +             OM_uint32 reqFlags,
11772 +             OM_uint32 timeReq,
11773 +             gss_channel_bindings_t chanBindings,
11774 +             gss_buffer_t inputToken,
11775 +             gss_buffer_t outputToken,
11776 +             struct gss_eap_sm *sm,
11777 +             size_t smCount);
11778 +
11779 +void
11780 +gssEapSmTransition(gss_ctx_id_t ctx, enum gss_eap_state state);
11781 +
11782 +/* util_token.c */
11783 +struct gss_eap_token_buffer_set {
11784 +    gss_buffer_set_desc buffers; /* pointers only */
11785 +    OM_uint32 *types;
11786 +};
11787 +
11788 +OM_uint32
11789 +gssEapEncodeInnerTokens(OM_uint32 *minor,
11790 +                        struct gss_eap_token_buffer_set *tokens,
11791 +                        gss_buffer_t buffer);
11792 +OM_uint32
11793 +gssEapDecodeInnerTokens(OM_uint32 *minor,
11794 +                        const gss_buffer_t buffer,
11795 +                        struct gss_eap_token_buffer_set *tokens);
11796 +
11797 +OM_uint32
11798 +gssEapReleaseInnerTokens(OM_uint32 *minor,
11799 +                         struct gss_eap_token_buffer_set *tokens,
11800 +                         int freeBuffers);
11801 +
11802 +OM_uint32
11803 +gssEapAllocInnerTokens(OM_uint32 *minor,
11804 +                       size_t count,
11805 +                       struct gss_eap_token_buffer_set *tokens);
11806 +
11807 +size_t
11808 +tokenSize(const gss_OID_desc *mech, size_t body_size);
11809 +
11810 +void
11811 +makeTokenHeader(const gss_OID_desc *mech,
11812 +                size_t body_size,
11813 +                unsigned char **buf,
11814 +                enum gss_eap_token_type tok_type);
11815 +
11816 +OM_uint32
11817 +verifyTokenHeader(OM_uint32 *minor,
11818 +                  gss_OID mech,
11819 +                  size_t *body_size,
11820 +                  unsigned char **buf_in,
11821 +                  size_t toksize_in,
11822 +                  enum gss_eap_token_type *ret_tok_type);
11823 +
11824 +/* Helper macros */
11825 +
11826 +#ifndef GSSEAP_MALLOC
11827 +#define GSSEAP_CALLOC                   calloc
11828 +#define GSSEAP_MALLOC                   malloc
11829 +#define GSSEAP_FREE                     free
11830 +#define GSSEAP_REALLOC                  realloc
11831 +#endif
11832 +
11833 +#ifndef GSSAPI_CALLCONV
11834 +#define GSSAPI_CALLCONV                 KRB5_CALLCONV
11835 +#endif
11836 +
11837 +#ifndef GSSEAP_ASSERT
11838 +#include <assert.h>
11839 +#define GSSEAP_ASSERT(x)                assert((x))
11840 +#endif /* !GSSEAP_ASSERT */
11841 +
11842 +#ifdef WIN32
11843 +#define GSSEAP_CONSTRUCTOR
11844 +#define GSSEAP_DESTRUCTOR
11845 +#else
11846 +#define GSSEAP_CONSTRUCTOR              __attribute__((constructor))
11847 +#define GSSEAP_DESTRUCTOR               __attribute__((destructor))
11848 +#endif
11849 +
11850 +#define GSSEAP_NOT_IMPLEMENTED          do {            \
11851 +        GSSEAP_ASSERT(0 && "not implemented");          \
11852 +        *minor = ENOSYS;                                \
11853 +        return GSS_S_FAILURE;                           \
11854 +    } while (0)
11855 +
11856 +#ifdef WIN32
11857 +
11858 +#include <winbase.h>
11859 +
11860 +#define GSSEAP_GET_LAST_ERROR()         (GetLastError()) /* XXX FIXME */
11861 +
11862 +#define GSSEAP_MUTEX                    CRITICAL_SECTION
11863 +#define GSSEAP_MUTEX_INIT(m)            (InitializeCriticalSection((m)), 0)
11864 +#define GSSEAP_MUTEX_DESTROY(m)         DeleteCriticalSection((m))
11865 +#define GSSEAP_MUTEX_LOCK(m)            EnterCriticalSection((m))
11866 +#define GSSEAP_MUTEX_UNLOCK(m)          LeaveCriticalSection((m))
11867 +#define GSSEAP_ONCE_LEAVE              do { return TRUE; } while (0)
11868 +
11869 +/* Thread-local is handled separately */
11870 +
11871 +#define GSSEAP_THREAD_ONCE              INIT_ONCE
11872 +#define GSSEAP_ONCE_CALLBACK(cb)        BOOL CALLBACK cb(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
11873 +#define GSSEAP_ONCE(o, i)               InitOnceExecuteOnce((o), (i), NULL, NULL)
11874 +#define GSSEAP_ONCE_INITIALIZER         INIT_ONCE_STATIC_INIT
11875 +
11876 +#else
11877 +
11878 +#include <pthread.h>
11879 +
11880 +#define GSSEAP_GET_LAST_ERROR()         (errno)
11881 +
11882 +#define GSSEAP_MUTEX                    pthread_mutex_t
11883 +#define GSSEAP_MUTEX_INIT(m)            pthread_mutex_init((m), NULL)
11884 +#define GSSEAP_MUTEX_DESTROY(m)         pthread_mutex_destroy((m))
11885 +#define GSSEAP_MUTEX_LOCK(m)            pthread_mutex_lock((m))
11886 +#define GSSEAP_MUTEX_UNLOCK(m)          pthread_mutex_unlock((m))
11887 +
11888 +#define GSSEAP_THREAD_KEY               pthread_key_t
11889 +#define GSSEAP_KEY_CREATE(k, d)         pthread_key_create((k), (d))
11890 +#define GSSEAP_GETSPECIFIC(k)           pthread_getspecific((k))
11891 +#define GSSEAP_SETSPECIFIC(k, d)        pthread_setspecific((k), (d))
11892 +
11893 +#define GSSEAP_THREAD_ONCE              pthread_once_t
11894 +#define GSSEAP_ONCE_CALLBACK(cb)        void cb(void)
11895 +#define GSSEAP_ONCE(o, i)               pthread_once((o), (i))
11896 +#define GSSEAP_ONCE_INITIALIZER         PTHREAD_ONCE_INIT
11897 +#define GSSEAP_ONCE_LEAVE              do { } while (0)
11898 +
11899 +#endif /* WIN32 */
11900 +
11901 +/* Helper functions */
11902 +static inline void
11903 +store_uint16_be(uint16_t val, void *vp)
11904 +{
11905 +    unsigned char *p = (unsigned char *)vp;
11906 +
11907 +    p[0] = (val >>  8) & 0xff;
11908 +    p[1] = (val      ) & 0xff;
11909 +}
11910 +
11911 +static inline uint16_t
11912 +load_uint16_be(const void *cvp)
11913 +{
11914 +    const unsigned char *p = (const unsigned char *)cvp;
11915 +
11916 +    return (p[1] | (p[0] << 8));
11917 +}
11918 +
11919 +static inline void
11920 +store_uint32_be(uint32_t val, void *vp)
11921 +{
11922 +    unsigned char *p = (unsigned char *)vp;
11923 +
11924 +    p[0] = (val >> 24) & 0xff;
11925 +    p[1] = (val >> 16) & 0xff;
11926 +    p[2] = (val >>  8) & 0xff;
11927 +    p[3] = (val      ) & 0xff;
11928 +}
11929 +
11930 +static inline uint32_t
11931 +load_uint32_be(const void *cvp)
11932 +{
11933 +    const unsigned char *p = (const unsigned char *)cvp;
11934 +
11935 +    return (p[3] | (p[2] << 8)
11936 +            | ((uint32_t) p[1] << 16)
11937 +            | ((uint32_t) p[0] << 24));
11938 +}
11939 +
11940 +static inline void
11941 +store_uint64_be(uint64_t val, void *vp)
11942 +{
11943 +    unsigned char *p = (unsigned char *)vp;
11944 +
11945 +    p[0] = (unsigned char)((val >> 56) & 0xff);
11946 +    p[1] = (unsigned char)((val >> 48) & 0xff);
11947 +    p[2] = (unsigned char)((val >> 40) & 0xff);
11948 +    p[3] = (unsigned char)((val >> 32) & 0xff);
11949 +    p[4] = (unsigned char)((val >> 24) & 0xff);
11950 +    p[5] = (unsigned char)((val >> 16) & 0xff);
11951 +    p[6] = (unsigned char)((val >>  8) & 0xff);
11952 +    p[7] = (unsigned char)((val      ) & 0xff);
11953 +}
11954 +
11955 +static inline uint64_t
11956 +load_uint64_be(const void *cvp)
11957 +{
11958 +    const unsigned char *p = (const unsigned char *)cvp;
11959 +
11960 +    return ((uint64_t)load_uint32_be(p) << 32) | load_uint32_be(p + 4);
11961 +}
11962 +
11963 +static inline unsigned char *
11964 +store_buffer(gss_buffer_t buffer, void *vp, int wide_nums)
11965 +{
11966 +    unsigned char *p = (unsigned char *)vp;
11967 +
11968 +    if (wide_nums) {
11969 +        store_uint64_be(buffer->length, p);
11970 +        p += 8;
11971 +    } else {
11972 +        store_uint32_be(buffer->length, p);
11973 +        p += 4;
11974 +    }
11975 +
11976 +    if (buffer->value != NULL) {
11977 +        memcpy(p, buffer->value, buffer->length);
11978 +        p += buffer->length;
11979 +    }
11980 +
11981 +    return p;
11982 +}
11983 +
11984 +static inline unsigned char *
11985 +load_buffer(const void *cvp, size_t length, gss_buffer_t buffer)
11986 +{
11987 +    buffer->length = 0;
11988 +    buffer->value = GSSEAP_MALLOC(length);
11989 +    if (buffer->value == NULL)
11990 +        return NULL;
11991 +    buffer->length = length;
11992 +    memcpy(buffer->value, cvp, length);
11993 +    return (unsigned char *)cvp + length;
11994 +}
11995 +
11996 +static inline unsigned char *
11997 +store_oid(gss_OID oid, void *vp)
11998 +{
11999 +    gss_buffer_desc buf;
12000 +
12001 +    if (oid != GSS_C_NO_OID) {
12002 +        buf.length = oid->length;
12003 +        buf.value = oid->elements;
12004 +    } else {
12005 +        buf.length = 0;
12006 +        buf.value = NULL;
12007 +    }
12008 +
12009 +    return store_buffer(&buf, vp, FALSE);
12010 +}
12011 +
12012 +static inline void
12013 +krbDataToGssBuffer(krb5_data *data, gss_buffer_t buffer)
12014 +{
12015 +    buffer->value = (void *)data->data;
12016 +    buffer->length = data->length;
12017 +}
12018 +
12019 +static inline void
12020 +krbPrincComponentToGssBuffer(krb5_principal krbPrinc,
12021 +                             int index, gss_buffer_t buffer)
12022 +{
12023 +#ifdef HAVE_HEIMDAL_VERSION
12024 +    buffer->value = (void *)KRB_PRINC_NAME(krbPrinc)[index];
12025 +    buffer->length = strlen((char *)buffer->value);
12026 +#else
12027 +    buffer->value = (void *)krb5_princ_component(NULL, krbPrinc, index)->data;
12028 +    buffer->length = krb5_princ_component(NULL, krbPrinc, index)->length;
12029 +#endif /* HAVE_HEIMDAL_VERSION */
12030 +}
12031 +
12032 +static inline void
12033 +krbPrincRealmToGssBuffer(krb5_principal krbPrinc, gss_buffer_t buffer)
12034 +{
12035 +#ifdef HAVE_HEIMDAL_VERSION
12036 +    buffer->value = (void *)KRB_PRINC_REALM(krbPrinc);
12037 +    buffer->length = strlen((char *)buffer->value);
12038 +#else
12039 +    krbDataToGssBuffer(KRB_PRINC_REALM(krbPrinc), buffer);
12040 +#endif
12041 +}
12042 +
12043 +static inline void
12044 +gssBufferToKrbData(gss_buffer_t buffer, krb5_data *data)
12045 +{
12046 +    data->data = (char *)buffer->value;
12047 +    data->length = buffer->length;
12048 +}
12049 +
12050 +/* util_tld.c */
12051 +struct gss_eap_status_info;
12052 +
12053 +struct gss_eap_thread_local_data {
12054 +    krb5_context krbContext;
12055 +    struct gss_eap_status_info *statusInfo;
12056 +};
12057 +
12058 +struct gss_eap_thread_local_data *
12059 +gssEapGetThreadLocalData(void);
12060 +
12061 +void
12062 +gssEapDestroyStatusInfo(struct gss_eap_status_info *status);
12063 +
12064 +void
12065 +gssEapDestroyKrbContext(krb5_context context);
12066 +
12067 +#ifdef __cplusplus
12068 +}
12069 +#endif
12070 +
12071 +#ifdef GSSEAP_ENABLE_ACCEPTOR
12072 +#include "util_json.h"
12073 +#include "util_attr.h"
12074 +#include "util_base64.h"
12075 +#endif /* GSSEAP_ENABLE_ACCEPTOR */
12076 +#ifdef GSSEAP_ENABLE_REAUTH
12077 +#include "util_reauth.h"
12078 +#endif
12079 +
12080 +#endif /* _UTIL_H_ */
12081 diff --git a/mech_eap/util_adshim.c b/mech_eap/util_adshim.c
12082 new file mode 100644
12083 index 0000000..513a1a8
12084 --- /dev/null
12085 +++ b/mech_eap/util_adshim.c
12086 @@ -0,0 +1,242 @@
12087 +/*
12088 + * Copyright (c) 2011, JANET(UK)
12089 + * All rights reserved.
12090 + *
12091 + * Redistribution and use in source and binary forms, with or without
12092 + * modification, are permitted provided that the following conditions
12093 + * are met:
12094 + *
12095 + * 1. Redistributions of source code must retain the above copyright
12096 + *    notice, this list of conditions and the following disclaimer.
12097 + *
12098 + * 2. Redistributions in binary form must reproduce the above copyright
12099 + *    notice, this list of conditions and the following disclaimer in the
12100 + *    documentation and/or other materials provided with the distribution.
12101 + *
12102 + * 3. Neither the name of JANET(UK) nor the names of its contributors
12103 + *    may be used to endorse or promote products derived from this software
12104 + *    without specific prior written permission.
12105 + *
12106 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
12107 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12108 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12109 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
12110 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12111 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12112 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12113 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12114 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12115 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12116 + * SUCH DAMAGE.
12117 + */
12118 +
12119 +#include "gssapiP_eap.h"
12120 +#include "authdata_plugin.h"
12121 +
12122 +/*
12123 + * This rubbish is necessary because MIT doesn't provide another way
12124 + * to access verified AD-KDCIssued elements. We can't verify them
12125 + * ourselves because they're signed in the ticket session key, which
12126 + * is destroyed immediately after the AP-REQ is processed.
12127 + */
12128 +
12129 +struct radius_ad_context {
12130 +    krb5_data avpdata;
12131 +    krb5_boolean verified;
12132 +};
12133 +
12134 +static krb5_data radius_ad_attr = {
12135 +    KV5M_DATA, sizeof("urn:authdata-radius-avp") - 1, "urn:authdata-radius-avp" };
12136 +
12137 +static krb5_error_code
12138 +radius_ad_init(krb5_context kcontext GSSEAP_UNUSED,
12139 +               void **plugin_context)
12140 +{
12141 +    *plugin_context = 0;
12142 +    return 0;
12143 +}
12144 +
12145 +static void
12146 +radius_ad_flags(krb5_context kcontext GSSEAP_UNUSED,
12147 +                void *plugin_context GSSEAP_UNUSED,
12148 +                krb5_authdatatype ad_type GSSEAP_UNUSED,
12149 +                krb5_flags *flags)
12150 +{
12151 +    *flags = AD_USAGE_KDC_ISSUED | AD_INFORMATIONAL;
12152 +}
12153 +
12154 +static void
12155 +radius_ad_fini(krb5_context kcontext GSSEAP_UNUSED,
12156 +               void *plugin_context GSSEAP_UNUSED)
12157 +{
12158 +    return;
12159 +}
12160 +
12161 +static krb5_error_code
12162 +radius_ad_request_init(krb5_context kcontext GSSEAP_UNUSED,
12163 +                       struct _krb5_authdata_context *context GSSEAP_UNUSED,
12164 +                       void *plugin_context GSSEAP_UNUSED,
12165 +                       void **request_context)
12166 +{
12167 +    struct radius_ad_context *ctx;
12168 +
12169 +    ctx = GSSEAP_CALLOC(1, sizeof(*ctx));
12170 +    if (ctx == NULL)
12171 +        return ENOMEM;
12172 +
12173 +    *request_context = ctx;
12174 +
12175 +    return 0;
12176 +}
12177 +
12178 +static krb5_error_code
12179 +radius_ad_export_authdata(krb5_context kcontext,
12180 +                          struct _krb5_authdata_context *context GSSEAP_UNUSED,
12181 +                          void *plugin_context GSSEAP_UNUSED,
12182 +                          void *request_context,
12183 +                          krb5_flags usage GSSEAP_UNUSED,
12184 +                          krb5_authdata ***out_authdata)
12185 +{
12186 +    struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context;
12187 +    krb5_authdata *data[2];
12188 +    krb5_authdata datum;
12189 +
12190 +    datum.ad_type = KRB5_AUTHDATA_RADIUS_AVP;
12191 +    datum.length = radius_ad->avpdata.length;
12192 +    datum.contents = (krb5_octet *)radius_ad->avpdata.data;
12193 +
12194 +    data[0] = &datum;
12195 +    data[1] = NULL;
12196 +
12197 +    return krb5_copy_authdata(kcontext, data, out_authdata);
12198 +}
12199 +
12200 +static krb5_error_code
12201 +radius_ad_import_authdata(krb5_context kcontext,
12202 +                          struct _krb5_authdata_context *context GSSEAP_UNUSED,
12203 +                          void *plugin_context GSSEAP_UNUSED,
12204 +                          void *request_context,
12205 +                          krb5_authdata **authdata,
12206 +                          krb5_boolean kdc_issued_flag,
12207 +                          krb5_const_principal issuer GSSEAP_UNUSED)
12208 +{
12209 +    struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context;
12210 +
12211 +    krb5_free_data_contents(kcontext, &radius_ad->avpdata);
12212 +    radius_ad->verified = FALSE;
12213 +
12214 +    GSSEAP_ASSERT(authdata[0] != NULL);
12215 +
12216 +    radius_ad->avpdata.data = GSSEAP_MALLOC(authdata[0]->length);
12217 +    if (radius_ad->avpdata.data == NULL)
12218 +        return ENOMEM;
12219 +
12220 +    memcpy(radius_ad->avpdata.data, authdata[0]->contents,
12221 +           authdata[0]->length);
12222 +    radius_ad->avpdata.length = authdata[0]->length;
12223 +
12224 +    radius_ad->verified = kdc_issued_flag;
12225 +
12226 +    return 0;
12227 +}
12228 +
12229 +static void
12230 +radius_ad_request_fini(krb5_context kcontext,
12231 +                       struct _krb5_authdata_context *context GSSEAP_UNUSED,
12232 +                       void *plugin_context GSSEAP_UNUSED,
12233 +                       void *request_context)
12234 +{
12235 +    struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context;
12236 +
12237 +    if (radius_ad != NULL) {
12238 +        krb5_free_data_contents(kcontext, &radius_ad->avpdata);
12239 +        GSSEAP_FREE(radius_ad);
12240 +    }
12241 +}
12242 +
12243 +static krb5_error_code
12244 +radius_ad_get_attribute(krb5_context kcontext GSSEAP_UNUSED,
12245 +                        struct _krb5_authdata_context *context GSSEAP_UNUSED,
12246 +                        void *plugin_context GSSEAP_UNUSED,
12247 +                        void *request_context,
12248 +                        const krb5_data *attribute,
12249 +                        krb5_boolean *authenticated,
12250 +                        krb5_boolean *complete,
12251 +                        krb5_data *value,
12252 +                        krb5_data *display_value GSSEAP_UNUSED,
12253 +                        int *more)
12254 +{
12255 +    struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context;
12256 +
12257 +    if (attribute->length != radius_ad_attr.length ||
12258 +        memcmp(attribute->data, radius_ad_attr.data,
12259 +               radius_ad_attr.length) != 0)
12260 +        return ENOENT;
12261 +
12262 +    if (radius_ad->avpdata.length == 0)
12263 +        return ENOENT;
12264 +
12265 +    *authenticated = radius_ad->verified;
12266 +    *complete = TRUE;
12267 +    *more = 0;
12268 +
12269 +    value->data = GSSEAP_MALLOC(radius_ad->avpdata.length);
12270 +    if (value->data == NULL)
12271 +        return ENOMEM;
12272 +
12273 +    memcpy(value->data, radius_ad->avpdata.data, radius_ad->avpdata.length);
12274 +    value->length = radius_ad->avpdata.length;
12275 +
12276 +    return 0;
12277 +}
12278 +
12279 +static krb5_error_code
12280 +radius_ad_copy(krb5_context kcontext GSSEAP_UNUSED,
12281 +               struct _krb5_authdata_context *context GSSEAP_UNUSED,
12282 +               void *plugin_context GSSEAP_UNUSED,
12283 +               void *request_context,
12284 +               void *dst_plugin_context GSSEAP_UNUSED,
12285 +               void *dst_request_context)
12286 +{
12287 +    struct radius_ad_context *radius_ad_src =
12288 +        (struct radius_ad_context *)request_context;
12289 +    struct radius_ad_context *radius_ad_dst =
12290 +        (struct radius_ad_context *)dst_request_context;
12291 +
12292 +    radius_ad_dst->avpdata.data = GSSEAP_MALLOC(radius_ad_src->avpdata.length);
12293 +    if (radius_ad_dst->avpdata.data == NULL)
12294 +        return ENOMEM;
12295 +
12296 +    memcpy(radius_ad_dst->avpdata.data, radius_ad_src->avpdata.data,
12297 +           radius_ad_src->avpdata.length);
12298 +    radius_ad_dst->avpdata.length = radius_ad_src->avpdata.length;
12299 +    radius_ad_dst->verified = radius_ad_src->verified;
12300 +
12301 +    return 0;
12302 +}
12303 +
12304 +static krb5_authdatatype radius_ad_ad_types[] =
12305 +    { KRB5_AUTHDATA_RADIUS_AVP, 0 };
12306 +
12307 +krb5plugin_authdata_client_ftable_v0 authdata_client_0 = {
12308 +    "radius_ad",
12309 +    radius_ad_ad_types,
12310 +    radius_ad_init,
12311 +    radius_ad_fini,
12312 +    radius_ad_flags,
12313 +    radius_ad_request_init,
12314 +    radius_ad_request_fini,
12315 +    NULL,
12316 +    radius_ad_get_attribute,
12317 +    NULL,
12318 +    NULL,
12319 +    radius_ad_export_authdata,
12320 +    radius_ad_import_authdata,
12321 +    NULL,
12322 +    NULL,
12323 +    NULL,
12324 +    NULL,
12325 +    NULL,
12326 +    NULL,
12327 +    radius_ad_copy
12328 +};
12329 diff --git a/mech_eap/util_attr.cpp b/mech_eap/util_attr.cpp
12330 new file mode 100644
12331 index 0000000..3bfe785
12332 --- /dev/null
12333 +++ b/mech_eap/util_attr.cpp
12334 @@ -0,0 +1,1191 @@
12335 +/*
12336 + * Copyright (c) 2011, JANET(UK)
12337 + * All rights reserved.
12338 + *
12339 + * Redistribution and use in source and binary forms, with or without
12340 + * modification, are permitted provided that the following conditions
12341 + * are met:
12342 + *
12343 + * 1. Redistributions of source code must retain the above copyright
12344 + *    notice, this list of conditions and the following disclaimer.
12345 + *
12346 + * 2. Redistributions in binary form must reproduce the above copyright
12347 + *    notice, this list of conditions and the following disclaimer in the
12348 + *    documentation and/or other materials provided with the distribution.
12349 + *
12350 + * 3. Neither the name of JANET(UK) nor the names of its contributors
12351 + *    may be used to endorse or promote products derived from this software
12352 + *    without specific prior written permission.
12353 + *
12354 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
12355 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12356 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12357 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
12358 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12359 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12360 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12361 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12362 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12363 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12364 + * SUCH DAMAGE.
12365 + */
12366 +
12367 +/*
12368 + * Attribute provider mechanism.
12369 + */
12370 +
12371 +#include "gssapiP_eap.h"
12372 +
12373 +#include <typeinfo>
12374 +#include <string>
12375 +#include <sstream>
12376 +#include <exception>
12377 +#include <new>
12378 +
12379 +/* lazy initialisation */
12380 +static GSSEAP_THREAD_ONCE gssEapAttrProvidersInitOnce = GSSEAP_ONCE_INITIALIZER;
12381 +static OM_uint32 gssEapAttrProvidersInitStatus = GSS_S_UNAVAILABLE;
12382 +
12383 +GSSEAP_ONCE_CALLBACK(gssEapAttrProvidersInitInternal)
12384 +{
12385 +    OM_uint32 major, minor;
12386 +
12387 +    GSSEAP_ASSERT(gssEapAttrProvidersInitStatus == GSS_S_UNAVAILABLE);
12388 +
12389 +    json_set_alloc_funcs(GSSEAP_MALLOC, GSSEAP_FREE);
12390 +
12391 +    major = gssEapRadiusAttrProviderInit(&minor);
12392 +    if (GSS_ERROR(major))
12393 +        goto cleanup;
12394 +
12395 +#ifdef HAVE_OPENSAML
12396 +    major = gssEapSamlAttrProvidersInit(&minor);
12397 +    if (GSS_ERROR(major))
12398 +        goto cleanup;
12399 +#endif
12400 +
12401 +#ifdef HAVE_SHIBRESOLVER
12402 +    /* Allow Shibboleth initialization failure to be non-fatal */
12403 +    gssEapLocalAttrProviderInit(&minor);
12404 +#endif
12405 +
12406 +cleanup:
12407 +#ifdef GSSEAP_DEBUG
12408 +    GSSEAP_ASSERT(major == GSS_S_COMPLETE);
12409 +#endif
12410 +
12411 +    gssEapAttrProvidersInitStatus = major;
12412 +
12413 +    GSSEAP_ONCE_LEAVE;
12414 +}
12415 +
12416 +static OM_uint32
12417 +gssEapAttrProvidersInit(OM_uint32 *minor)
12418 +{
12419 +    GSSEAP_ONCE(&gssEapAttrProvidersInitOnce, gssEapAttrProvidersInitInternal);
12420 +
12421 +    if (GSS_ERROR(gssEapAttrProvidersInitStatus))
12422 +        *minor = GSSEAP_NO_ATTR_PROVIDERS;
12423 +
12424 +    return gssEapAttrProvidersInitStatus;
12425 +}
12426 +
12427 +OM_uint32
12428 +gssEapAttrProvidersFinalize(OM_uint32 *minor)
12429 +{
12430 +    if (gssEapAttrProvidersInitStatus == GSS_S_COMPLETE) {
12431 +#ifdef HAVE_SHIBRESOLVER
12432 +        gssEapLocalAttrProviderFinalize(minor);
12433 +#endif
12434 +#ifdef HAVE_OPENSAML
12435 +        gssEapSamlAttrProvidersFinalize(minor);
12436 +#endif
12437 +        gssEapRadiusAttrProviderFinalize(minor);
12438 +
12439 +        gssEapAttrProvidersInitStatus = GSS_S_UNAVAILABLE;
12440 +    }
12441 +
12442 +    return GSS_S_COMPLETE;
12443 +}
12444 +
12445 +static gss_eap_attr_create_provider gssEapAttrFactories[ATTR_TYPE_MAX + 1];
12446 +
12447 +/*
12448 + * Register a provider for a particular type and prefix
12449 + */
12450 +void
12451 +gss_eap_attr_ctx::registerProvider(unsigned int type,
12452 +                                   gss_eap_attr_create_provider factory)
12453 +{
12454 +    GSSEAP_ASSERT(type <= ATTR_TYPE_MAX);
12455 +
12456 +    GSSEAP_ASSERT(gssEapAttrFactories[type] == NULL);
12457 +
12458 +    gssEapAttrFactories[type] = factory;
12459 +}
12460 +
12461 +/*
12462 + * Unregister a provider
12463 + */
12464 +void
12465 +gss_eap_attr_ctx::unregisterProvider(unsigned int type)
12466 +{
12467 +    GSSEAP_ASSERT(type <= ATTR_TYPE_MAX);
12468 +
12469 +    gssEapAttrFactories[type] = NULL;
12470 +}
12471 +
12472 +/*
12473 + * Create an attribute context, that manages instances of providers
12474 + */
12475 +gss_eap_attr_ctx::gss_eap_attr_ctx(void)
12476 +{
12477 +    m_flags = 0;
12478 +
12479 +    for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
12480 +        gss_eap_attr_provider *provider;
12481 +
12482 +        if (gssEapAttrFactories[i] != NULL) {
12483 +            provider = (gssEapAttrFactories[i])();
12484 +        } else {
12485 +            provider = NULL;
12486 +        }
12487 +
12488 +        m_providers[i] = provider;
12489 +    }
12490 +}
12491 +
12492 +/*
12493 + * Convert an attribute prefix to a type
12494 + */
12495 +unsigned int
12496 +gss_eap_attr_ctx::attributePrefixToType(const gss_buffer_t prefix) const
12497 +{
12498 +    unsigned int i;
12499 +
12500 +    for (i = ATTR_TYPE_MIN; i < ATTR_TYPE_MAX; i++) {
12501 +        const char *pprefix;
12502 +
12503 +        if (!providerEnabled(i))
12504 +            continue;
12505 +
12506 +        pprefix = m_providers[i]->prefix();
12507 +        if (pprefix == NULL)
12508 +            continue;
12509 +
12510 +        if (strlen(pprefix) == prefix->length &&
12511 +            memcmp(pprefix, prefix->value, prefix->length) == 0)
12512 +            return i;
12513 +    }
12514 +
12515 +    return ATTR_TYPE_LOCAL;
12516 +}
12517 +
12518 +/*
12519 + * Convert a type to an attribute prefix
12520 + */
12521 +gss_buffer_desc
12522 +gss_eap_attr_ctx::attributeTypeToPrefix(unsigned int type) const
12523 +{
12524 +    gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER;
12525 +
12526 +    if (type < ATTR_TYPE_MIN || type >= ATTR_TYPE_MAX)
12527 +        return prefix;
12528 +
12529 +    if (!providerEnabled(type))
12530 +        return prefix;
12531 +
12532 +    prefix.value = (void *)m_providers[type]->prefix();
12533 +    if (prefix.value != NULL)
12534 +        prefix.length = strlen((char *)prefix.value);
12535 +
12536 +    return prefix;
12537 +}
12538 +
12539 +bool
12540 +gss_eap_attr_ctx::providerEnabled(unsigned int type) const
12541 +{
12542 +    if (type == ATTR_TYPE_LOCAL &&
12543 +        (m_flags & ATTR_FLAG_DISABLE_LOCAL))
12544 +        return false;
12545 +
12546 +    if (m_providers[type] == NULL)
12547 +        return false;
12548 +
12549 +    return true;
12550 +}
12551 +
12552 +void
12553 +gss_eap_attr_ctx::releaseProvider(unsigned int type)
12554 +{
12555 +    delete m_providers[type];
12556 +    m_providers[type] = NULL;
12557 +}
12558 +
12559 +/*
12560 + * Initialize a context from an existing context.
12561 + */
12562 +bool
12563 +gss_eap_attr_ctx::initWithExistingContext(const gss_eap_attr_ctx *manager)
12564 +{
12565 +    bool ret = true;
12566 +
12567 +    m_flags = manager->m_flags;
12568 +
12569 +    for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
12570 +        gss_eap_attr_provider *provider;
12571 +
12572 +        if (!providerEnabled(i)) {
12573 +            releaseProvider(i);
12574 +            continue;
12575 +        }
12576 +
12577 +        provider = m_providers[i];
12578 +
12579 +        ret = provider->initWithExistingContext(this,
12580 +                                                manager->m_providers[i]);
12581 +        if (ret == false) {
12582 +            releaseProvider(i);
12583 +            break;
12584 +        }
12585 +    }
12586 +
12587 +    return ret;
12588 +}
12589 +
12590 +/*
12591 + * Initialize a context from a GSS credential and context.
12592 + */
12593 +bool
12594 +gss_eap_attr_ctx::initWithGssContext(const gss_cred_id_t cred,
12595 +                                     const gss_ctx_id_t ctx)
12596 +{
12597 +    bool ret = true;
12598 +
12599 +    if (cred != GSS_C_NO_CREDENTIAL &&
12600 +        (cred->flags & GSS_EAP_DISABLE_LOCAL_ATTRS_FLAG)) {
12601 +        m_flags |= ATTR_FLAG_DISABLE_LOCAL;
12602 +    }
12603 +
12604 +    for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
12605 +        gss_eap_attr_provider *provider;
12606 +
12607 +        if (!providerEnabled(i)) {
12608 +            releaseProvider(i);
12609 +            continue;
12610 +        }
12611 +
12612 +        provider = m_providers[i];
12613 +
12614 +        ret = provider->initWithGssContext(this, cred, ctx);
12615 +        if (ret == false) {
12616 +            releaseProvider(i);
12617 +            break;
12618 +        }
12619 +    }
12620 +
12621 +    return ret;
12622 +}
12623 +
12624 +bool
12625 +gss_eap_attr_ctx::initWithJsonObject(JSONObject &obj)
12626 +{
12627 +    bool ret = false;
12628 +    bool foundSource[ATTR_TYPE_MAX + 1];
12629 +    unsigned int type;
12630 +
12631 +    for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++)
12632 +        foundSource[type] = false;
12633 +
12634 +    if (obj["version"].integer() != 1)
12635 +        return false;
12636 +
12637 +    m_flags = obj["flags"].integer();
12638 +
12639 +    JSONObject sources = obj["sources"];
12640 +
12641 +    /* Initialize providers from serialized state */
12642 +    for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++) {
12643 +        gss_eap_attr_provider *provider;
12644 +        const char *key;
12645 +
12646 +        if (!providerEnabled(type)) {
12647 +            releaseProvider(type);
12648 +            continue;
12649 +        }
12650 +
12651 +        provider = m_providers[type];
12652 +        key = provider->name();
12653 +        if (key == NULL)
12654 +            continue;
12655 +
12656 +        JSONObject source = sources.get(key);
12657 +        if (!source.isNull() &&
12658 +            !provider->initWithJsonObject(this, source)) {
12659 +            releaseProvider(type);
12660 +            return false;
12661 +        }
12662 +
12663 +        foundSource[type] = true;
12664 +    }
12665 +
12666 +    /* Initialize remaining providers from initialized providers */
12667 +    for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++) {
12668 +        gss_eap_attr_provider *provider;
12669 +
12670 +        if (foundSource[type] || !providerEnabled(type))
12671 +            continue;
12672 +
12673 +        provider = m_providers[type];
12674 +
12675 +        ret = provider->initWithGssContext(this,
12676 +                                           GSS_C_NO_CREDENTIAL,
12677 +                                           GSS_C_NO_CONTEXT);
12678 +        if (ret == false) {
12679 +            releaseProvider(type);
12680 +            return false;
12681 +        }
12682 +    }
12683 +
12684 +    return true;
12685 +}
12686 +
12687 +JSONObject
12688 +gss_eap_attr_ctx::jsonRepresentation(void) const
12689 +{
12690 +    JSONObject obj, sources;
12691 +    unsigned int i;
12692 +
12693 +    obj.set("version", 1);
12694 +    obj.set("flags", m_flags);
12695 +
12696 +    for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
12697 +        gss_eap_attr_provider *provider;
12698 +        const char *key;
12699 +
12700 +        provider = m_providers[i];
12701 +        if (provider == NULL)
12702 +            continue; /* provider not initialised */
12703 +
12704 +        key = provider->name();
12705 +        if (key == NULL)
12706 +            continue; /* provider does not have state */
12707 +
12708 +        JSONObject source = provider->jsonRepresentation();
12709 +        sources.set(key, source);
12710 +    }
12711 +
12712 +    obj.set("sources", sources);
12713 +
12714 +    return obj;
12715 +}
12716 +
12717 +/*
12718 + * Initialize a context from an exported context or name token
12719 + */
12720 +bool
12721 +gss_eap_attr_ctx::initWithBuffer(const gss_buffer_t buffer)
12722 +{
12723 +    OM_uint32 major, minor;
12724 +    bool ret;
12725 +    char *s;
12726 +    json_error_t error;
12727 +
12728 +    major = bufferToString(&minor, buffer, &s);
12729 +    if (GSS_ERROR(major))
12730 +        return false;
12731 +
12732 +    JSONObject obj = JSONObject::load(s, 0, &error);
12733 +    if (!obj.isNull()) {
12734 +        ret = initWithJsonObject(obj);
12735 +    } else
12736 +        ret = false;
12737 +
12738 +    GSSEAP_FREE(s);
12739 +
12740 +    return ret;
12741 +}
12742 +
12743 +gss_eap_attr_ctx::~gss_eap_attr_ctx(void)
12744 +{
12745 +    for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++)
12746 +        delete m_providers[i];
12747 +}
12748 +
12749 +/*
12750 + * Locate provider for a given type
12751 + */
12752 +gss_eap_attr_provider *
12753 +gss_eap_attr_ctx::getProvider(unsigned int type) const
12754 +{
12755 +    GSSEAP_ASSERT(type >= ATTR_TYPE_MIN && type <= ATTR_TYPE_MAX);
12756 +    return m_providers[type];
12757 +}
12758 +
12759 +/*
12760 + * Get primary provider. Only the primary provider is serialised when
12761 + * gss_export_sec_context() or gss_export_name_composite() is called.
12762 + */
12763 +gss_eap_attr_provider *
12764 +gss_eap_attr_ctx::getPrimaryProvider(void) const
12765 +{
12766 +    return m_providers[ATTR_TYPE_MIN];
12767 +}
12768 +
12769 +/*
12770 + * Set an attribute
12771 + */
12772 +bool
12773 +gss_eap_attr_ctx::setAttribute(int complete,
12774 +                               const gss_buffer_t attr,
12775 +                               const gss_buffer_t value)
12776 +{
12777 +    gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
12778 +    unsigned int type;
12779 +    gss_eap_attr_provider *provider;
12780 +    bool ret = false;
12781 +
12782 +    decomposeAttributeName(attr, &type, &suffix);
12783 +
12784 +    provider = m_providers[type];
12785 +    if (provider != NULL) {
12786 +        ret = provider->setAttribute(complete,
12787 +                                     (type == ATTR_TYPE_LOCAL) ? attr : &suffix,
12788 +                                     value);
12789 +    }
12790 +
12791 +    return ret;
12792 +}
12793 +
12794 +/*
12795 + * Delete an attrbiute
12796 + */
12797 +bool
12798 +gss_eap_attr_ctx::deleteAttribute(const gss_buffer_t attr)
12799 +{
12800 +    gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
12801 +    unsigned int type;
12802 +    gss_eap_attr_provider *provider;
12803 +    bool ret = false;
12804 +
12805 +    decomposeAttributeName(attr, &type, &suffix);
12806 +
12807 +    provider = m_providers[type];
12808 +    if (provider != NULL) {
12809 +        ret = provider->deleteAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix);
12810 +    }
12811 +
12812 +    return ret;
12813 +}
12814 +
12815 +/*
12816 + * Enumerate attribute types with callback
12817 + */
12818 +bool
12819 +gss_eap_attr_ctx::getAttributeTypes(gss_eap_attr_enumeration_cb cb, void *data) const
12820 +{
12821 +    bool ret = false;
12822 +    size_t i;
12823 +
12824 +    for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
12825 +        gss_eap_attr_provider *provider = m_providers[i];
12826 +
12827 +        if (provider == NULL)
12828 +            continue;
12829 +
12830 +        ret = provider->getAttributeTypes(cb, data);
12831 +        if (ret == false)
12832 +            break;
12833 +    }
12834 +
12835 +    return ret;
12836 +}
12837 +
12838 +struct eap_gss_get_attr_types_args {
12839 +    unsigned int type;
12840 +    gss_buffer_set_t attrs;
12841 +};
12842 +
12843 +static bool
12844 +addAttribute(const gss_eap_attr_ctx *manager,
12845 +             const gss_eap_attr_provider *provider GSSEAP_UNUSED,
12846 +             const gss_buffer_t attribute,
12847 +             void *data)
12848 +{
12849 +    eap_gss_get_attr_types_args *args = (eap_gss_get_attr_types_args *)data;
12850 +    gss_buffer_desc qualified;
12851 +    OM_uint32 major, minor;
12852 +
12853 +    if (args->type != ATTR_TYPE_LOCAL) {
12854 +        manager->composeAttributeName(args->type, attribute, &qualified);
12855 +        major = gss_add_buffer_set_member(&minor, &qualified, &args->attrs);
12856 +        gss_release_buffer(&minor, &qualified);
12857 +    } else {
12858 +        major = gss_add_buffer_set_member(&minor, attribute, &args->attrs);
12859 +    }
12860 +
12861 +    return GSS_ERROR(major) == false;
12862 +}
12863 +
12864 +/*
12865 + * Enumerate attribute types, output is buffer set
12866 + */
12867 +bool
12868 +gss_eap_attr_ctx::getAttributeTypes(gss_buffer_set_t *attrs)
12869 +{
12870 +    eap_gss_get_attr_types_args args;
12871 +    OM_uint32 major, minor;
12872 +    bool ret = false;
12873 +    unsigned int i;
12874 +
12875 +    major = gss_create_empty_buffer_set(&minor, attrs);
12876 +    if (GSS_ERROR(major))
12877 +        throw std::bad_alloc();
12878 +
12879 +    args.attrs = *attrs;
12880 +
12881 +    for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
12882 +        gss_eap_attr_provider *provider = m_providers[i];
12883 +
12884 +        args.type = i;
12885 +
12886 +        if (provider == NULL)
12887 +            continue;
12888 +
12889 +        ret = provider->getAttributeTypes(addAttribute, (void *)&args);
12890 +        if (ret == false)
12891 +            break;
12892 +    }
12893 +
12894 +    if (ret == false)
12895 +        gss_release_buffer_set(&minor, attrs);
12896 +
12897 +    return ret;
12898 +}
12899 +
12900 +/*
12901 + * Get attribute with given name
12902 + */
12903 +bool
12904 +gss_eap_attr_ctx::getAttribute(const gss_buffer_t attr,
12905 +                               int *authenticated,
12906 +                               int *complete,
12907 +                               gss_buffer_t value,
12908 +                               gss_buffer_t display_value,
12909 +                               int *more) const
12910 +{
12911 +    gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
12912 +    unsigned int type;
12913 +    gss_eap_attr_provider *provider;
12914 +    bool ret;
12915 +
12916 +    decomposeAttributeName(attr, &type, &suffix);
12917 +
12918 +    provider = m_providers[type];
12919 +    if (provider == NULL)
12920 +        return false;
12921 +
12922 +    ret = provider->getAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix,
12923 +                                 authenticated, complete,
12924 +                                 value, display_value, more);
12925 +
12926 +    return ret;
12927 +}
12928 +
12929 +/*
12930 + * Map attribute context to C++ object
12931 + */
12932 +gss_any_t
12933 +gss_eap_attr_ctx::mapToAny(int authenticated,
12934 +                           gss_buffer_t type_id) const
12935 +{
12936 +    unsigned int type;
12937 +    gss_eap_attr_provider *provider;
12938 +    gss_buffer_desc suffix;
12939 +
12940 +    decomposeAttributeName(type_id, &type, &suffix);
12941 +
12942 +    provider = m_providers[type];
12943 +    if (provider == NULL)
12944 +        return (gss_any_t)NULL;
12945 +
12946 +    return provider->mapToAny(authenticated, &suffix);
12947 +}
12948 +
12949 +/*
12950 + * Release mapped context
12951 + */
12952 +void
12953 +gss_eap_attr_ctx::releaseAnyNameMapping(gss_buffer_t type_id,
12954 +                                        gss_any_t input) const
12955 +{
12956 +    unsigned int type;
12957 +    gss_eap_attr_provider *provider;
12958 +    gss_buffer_desc suffix;
12959 +
12960 +    decomposeAttributeName(type_id, &type, &suffix);
12961 +
12962 +    provider = m_providers[type];
12963 +    if (provider != NULL)
12964 +        provider->releaseAnyNameMapping(&suffix, input);
12965 +}
12966 +
12967 +/*
12968 + * Export attribute context to buffer
12969 + */
12970 +void
12971 +gss_eap_attr_ctx::exportToBuffer(gss_buffer_t buffer) const
12972 +{
12973 +    OM_uint32 minor;
12974 +    char *s;
12975 +
12976 +    JSONObject obj = jsonRepresentation();
12977 +
12978 +#if 0
12979 +    obj.dump(stdout);
12980 +#endif
12981 +
12982 +    s = obj.dump(JSON_COMPACT);
12983 +
12984 +    if (GSS_ERROR(makeStringBuffer(&minor, s, buffer)))
12985 +        throw std::bad_alloc();
12986 +}
12987 +
12988 +/*
12989 + * Return soonest expiry time of providers
12990 + */
12991 +time_t
12992 +gss_eap_attr_ctx::getExpiryTime(void) const
12993 +{
12994 +    unsigned int i;
12995 +    time_t expiryTime = 0;
12996 +
12997 +    for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
12998 +        gss_eap_attr_provider *provider = m_providers[i];
12999 +        time_t providerExpiryTime;
13000 +
13001 +        if (provider == NULL)
13002 +            continue;
13003 +
13004 +        providerExpiryTime = provider->getExpiryTime();
13005 +        if (providerExpiryTime == 0)
13006 +            continue;
13007 +
13008 +        if (expiryTime == 0 || providerExpiryTime < expiryTime)
13009 +            expiryTime = providerExpiryTime;
13010 +    }
13011 +
13012 +    return expiryTime;
13013 +}
13014 +
13015 +OM_uint32
13016 +gss_eap_attr_ctx::mapException(OM_uint32 *minor, std::exception &e) const
13017 +{
13018 +    unsigned int i;
13019 +    OM_uint32 major;
13020 +
13021 +    /* Errors we handle ourselves */
13022 +    if (typeid(e) == typeid(std::bad_alloc)) {
13023 +        major = GSS_S_FAILURE;
13024 +        *minor = ENOMEM;
13025 +        goto cleanup;
13026 +    } else if (typeid(e) == typeid(JSONException)) {
13027 +        major = GSS_S_BAD_NAME;
13028 +        *minor = GSSEAP_BAD_ATTR_TOKEN;
13029 +        gssEapSaveStatusInfo(*minor, "%s", e.what());
13030 +        goto cleanup;
13031 +    }
13032 +
13033 +    /* Errors we delegate to providers */
13034 +    major = GSS_S_CONTINUE_NEEDED;
13035 +
13036 +    for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
13037 +        gss_eap_attr_provider *provider = m_providers[i];
13038 +
13039 +        if (provider == NULL)
13040 +            continue;
13041 +
13042 +        major = provider->mapException(minor, e);
13043 +        if (major != GSS_S_CONTINUE_NEEDED)
13044 +            break;
13045 +    }
13046 +
13047 +    if (major == GSS_S_CONTINUE_NEEDED) {
13048 +        *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
13049 +        major = GSS_S_FAILURE;
13050 +    }
13051 +
13052 +cleanup:
13053 +    GSSEAP_ASSERT(GSS_ERROR(major));
13054 +
13055 +    return major;
13056 +}
13057 +
13058 +/*
13059 + * Decompose attribute name into prefix and suffix
13060 + */
13061 +void
13062 +gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
13063 +                                         gss_buffer_t prefix,
13064 +                                         gss_buffer_t suffix)
13065 +{
13066 +    char *p = NULL;
13067 +    size_t i;
13068 +
13069 +    for (i = 0; i < attribute->length; i++) {
13070 +        if (((char *)attribute->value)[i] == ' ') {
13071 +            p = (char *)attribute->value + i + 1;
13072 +            break;
13073 +        }
13074 +    }
13075 +
13076 +    prefix->value = attribute->value;
13077 +    prefix->length = i;
13078 +
13079 +    if (p != NULL && *p != '\0')  {
13080 +        suffix->length = attribute->length - 1 - prefix->length;
13081 +        suffix->value = p;
13082 +    } else {
13083 +        suffix->length = 0;
13084 +        suffix->value = NULL;
13085 +    }
13086 +}
13087 +
13088 +/*
13089 + * Decompose attribute name into type and suffix
13090 + */
13091 +void
13092 +gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
13093 +                                         unsigned int *type,
13094 +                                         gss_buffer_t suffix) const
13095 +{
13096 +    gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER;
13097 +
13098 +    decomposeAttributeName(attribute, &prefix, suffix);
13099 +    *type = attributePrefixToType(&prefix);
13100 +}
13101 +
13102 +/*
13103 + * Compose attribute name from prefix, suffix; returns C++ string
13104 + */
13105 +std::string
13106 +gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
13107 +                                       const gss_buffer_t suffix)
13108 +{
13109 +    std::string str;
13110 +
13111 +    if (prefix == GSS_C_NO_BUFFER || prefix->length == 0)
13112 +        return str;
13113 +
13114 +    str.append((const char *)prefix->value, prefix->length);
13115 +
13116 +    if (suffix != GSS_C_NO_BUFFER) {
13117 +        str.append(" ");
13118 +        str.append((const char *)suffix->value, suffix->length);
13119 +    }
13120 +
13121 +    return str;
13122 +}
13123 +
13124 +/*
13125 + * Compose attribute name from type, suffix; returns C++ string
13126 + */
13127 +std::string
13128 +gss_eap_attr_ctx::composeAttributeName(unsigned int type,
13129 +                                       const gss_buffer_t suffix)
13130 +{
13131 +    gss_buffer_desc prefix = attributeTypeToPrefix(type);
13132 +
13133 +    return composeAttributeName(&prefix, suffix);
13134 +}
13135 +
13136 +/*
13137 + * Compose attribute name from prefix, suffix; returns GSS buffer
13138 + */
13139 +void
13140 +gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
13141 +                                       const gss_buffer_t suffix,
13142 +                                       gss_buffer_t attribute)
13143 +{
13144 +    std::string str = composeAttributeName(prefix, suffix);
13145 +
13146 +    if (str.length() != 0) {
13147 +        return duplicateBuffer(str, attribute);
13148 +    } else {
13149 +        attribute->length = 0;
13150 +        attribute->value = NULL;
13151 +    }
13152 +}
13153 +
13154 +/*
13155 + * Compose attribute name from type, suffix; returns GSS buffer
13156 + */
13157 +void
13158 +gss_eap_attr_ctx::composeAttributeName(unsigned int type,
13159 +                                       const gss_buffer_t suffix,
13160 +                                       gss_buffer_t attribute) const
13161 +{
13162 +    gss_buffer_desc prefix = attributeTypeToPrefix(type);
13163 +
13164 +    return composeAttributeName(&prefix, suffix, attribute);
13165 +}
13166 +
13167 +/*
13168 + * C wrappers
13169 + */
13170 +OM_uint32
13171 +gssEapInquireName(OM_uint32 *minor,
13172 +                  gss_name_t name,
13173 +                  int *name_is_MN,
13174 +                  gss_OID *MN_mech,
13175 +                  gss_buffer_set_t *attrs)
13176 +{
13177 +    OM_uint32 major;
13178 +
13179 +    if (name_is_MN != NULL)
13180 +        *name_is_MN = (name->mechanismUsed != GSS_C_NULL_OID);
13181 +
13182 +    if (MN_mech != NULL) {
13183 +        major = gssEapCanonicalizeOid(minor, name->mechanismUsed,
13184 +                                      OID_FLAG_NULL_VALID, MN_mech);
13185 +        if (GSS_ERROR(major))
13186 +            return major;
13187 +    }
13188 +
13189 +    if (name->attrCtx == NULL) {
13190 +        *minor = GSSEAP_NO_ATTR_CONTEXT;
13191 +        return GSS_S_UNAVAILABLE;
13192 +    }
13193 +
13194 +    if (GSS_ERROR(gssEapAttrProvidersInit(minor))) {
13195 +        return GSS_S_UNAVAILABLE;
13196 +    }
13197 +
13198 +    try {
13199 +        if (!name->attrCtx->getAttributeTypes(attrs)) {
13200 +            *minor = GSSEAP_NO_ATTR_CONTEXT;
13201 +            return GSS_S_UNAVAILABLE;
13202 +        }
13203 +    } catch (std::exception &e) {
13204 +        return name->attrCtx->mapException(minor, e);
13205 +    }
13206 +
13207 +    return GSS_S_COMPLETE;
13208 +}
13209 +
13210 +OM_uint32
13211 +gssEapGetNameAttribute(OM_uint32 *minor,
13212 +                       gss_name_t name,
13213 +                       gss_buffer_t attr,
13214 +                       int *authenticated,
13215 +                       int *complete,
13216 +                       gss_buffer_t value,
13217 +                       gss_buffer_t display_value,
13218 +                       int *more)
13219 +{
13220 +    if (authenticated != NULL)
13221 +        *authenticated = 0;
13222 +    if (complete != NULL)
13223 +        *complete = 0;
13224 +
13225 +    if (value != NULL) {
13226 +        value->length = 0;
13227 +        value->value = NULL;
13228 +    }
13229 +
13230 +    if (display_value != NULL) {
13231 +        display_value->length = 0;
13232 +        display_value->value = NULL;
13233 +    }
13234 +
13235 +    if (name->attrCtx == NULL) {
13236 +        *minor = GSSEAP_NO_ATTR_CONTEXT;
13237 +        return GSS_S_UNAVAILABLE;
13238 +    }
13239 +
13240 +    if (GSS_ERROR(gssEapAttrProvidersInit(minor))) {
13241 +        return GSS_S_UNAVAILABLE;
13242 +    }
13243 +
13244 +    try {
13245 +        if (!name->attrCtx->getAttribute(attr, authenticated, complete,
13246 +                                         value, display_value, more)) {
13247 +            *minor = GSSEAP_NO_SUCH_ATTR;
13248 +            gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
13249 +                                 (int)attr->length, (char *)attr->value);
13250 +            return GSS_S_UNAVAILABLE;
13251 +        }
13252 +    } catch (std::exception &e) {
13253 +        return name->attrCtx->mapException(minor, e);
13254 +    }
13255 +
13256 +    return GSS_S_COMPLETE;
13257 +}
13258 +
13259 +OM_uint32
13260 +gssEapDeleteNameAttribute(OM_uint32 *minor,
13261 +                          gss_name_t name,
13262 +                          gss_buffer_t attr)
13263 +{
13264 +    if (name->attrCtx == NULL) {
13265 +        *minor = GSSEAP_NO_ATTR_CONTEXT;
13266 +        return GSS_S_UNAVAILABLE;
13267 +    }
13268 +
13269 +    if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
13270 +        return GSS_S_UNAVAILABLE;
13271 +
13272 +    try {
13273 +        if (!name->attrCtx->deleteAttribute(attr)) {
13274 +            *minor = GSSEAP_NO_SUCH_ATTR;
13275 +            gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
13276 +                                 (int)attr->length, (char *)attr->value);
13277 +            return GSS_S_UNAVAILABLE;
13278 +        }
13279 +    } catch (std::exception &e) {
13280 +        return name->attrCtx->mapException(minor, e);
13281 +    }
13282 +
13283 +    return GSS_S_COMPLETE;
13284 +}
13285 +
13286 +OM_uint32
13287 +gssEapSetNameAttribute(OM_uint32 *minor,
13288 +                       gss_name_t name,
13289 +                       int complete,
13290 +                       gss_buffer_t attr,
13291 +                       gss_buffer_t value)
13292 +{
13293 +    if (name->attrCtx == NULL) {
13294 +        *minor = GSSEAP_NO_ATTR_CONTEXT;
13295 +        return GSS_S_UNAVAILABLE;
13296 +    }
13297 +
13298 +    if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
13299 +        return GSS_S_UNAVAILABLE;
13300 +
13301 +    try {
13302 +        if (!name->attrCtx->setAttribute(complete, attr, value)) {
13303 +             *minor = GSSEAP_NO_SUCH_ATTR;
13304 +            gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
13305 +                                 (int)attr->length, (char *)attr->value);
13306 +            return GSS_S_UNAVAILABLE;
13307 +        }
13308 +    } catch (std::exception &e) {
13309 +        return name->attrCtx->mapException(minor, e);
13310 +    }
13311 +
13312 +    return GSS_S_COMPLETE;
13313 +}
13314 +
13315 +OM_uint32
13316 +gssEapExportAttrContext(OM_uint32 *minor,
13317 +                        gss_name_t name,
13318 +                        gss_buffer_t buffer)
13319 +{
13320 +    if (name->attrCtx == NULL) {
13321 +        buffer->length = 0;
13322 +        buffer->value = NULL;
13323 +
13324 +        return GSS_S_COMPLETE;
13325 +    }
13326 +
13327 +    if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
13328 +        return GSS_S_UNAVAILABLE;
13329 +
13330 +    try {
13331 +        name->attrCtx->exportToBuffer(buffer);
13332 +    } catch (std::exception &e) {
13333 +        return name->attrCtx->mapException(minor, e);
13334 +    }
13335 +
13336 +    return GSS_S_COMPLETE;
13337 +}
13338 +
13339 +OM_uint32
13340 +gssEapImportAttrContext(OM_uint32 *minor,
13341 +                        gss_buffer_t buffer,
13342 +                        gss_name_t name)
13343 +{
13344 +    gss_eap_attr_ctx *ctx = NULL;
13345 +    OM_uint32 major = GSS_S_FAILURE;
13346 +
13347 +    GSSEAP_ASSERT(name->attrCtx == NULL);
13348 +
13349 +    if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
13350 +        return GSS_S_UNAVAILABLE;
13351 +
13352 +    if (buffer->length == 0)
13353 +        return GSS_S_COMPLETE;
13354 +
13355 +    try {
13356 +        ctx = new gss_eap_attr_ctx();
13357 +
13358 +        if (ctx->initWithBuffer(buffer)) {
13359 +            name->attrCtx = ctx;
13360 +            major = GSS_S_COMPLETE;
13361 +            *minor = 0;
13362 +        } else {
13363 +            major = GSS_S_BAD_NAME;
13364 +            *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
13365 +        }
13366 +    } catch (std::exception &e) {
13367 +        if (ctx != NULL)
13368 +            major = ctx->mapException(minor, e);
13369 +    }
13370 +
13371 +    GSSEAP_ASSERT(major == GSS_S_COMPLETE || name->attrCtx == NULL);
13372 +
13373 +    if (GSS_ERROR(major))
13374 +        delete ctx;
13375 +
13376 +    return major;
13377 +}
13378 +
13379 +OM_uint32
13380 +gssEapDuplicateAttrContext(OM_uint32 *minor,
13381 +                           gss_name_t in,
13382 +                           gss_name_t out)
13383 +{
13384 +    gss_eap_attr_ctx *ctx = NULL;
13385 +    OM_uint32 major = GSS_S_FAILURE;
13386 +
13387 +    GSSEAP_ASSERT(out->attrCtx == NULL);
13388 +
13389 +    if (in->attrCtx == NULL) {
13390 +        *minor = 0;
13391 +        return GSS_S_COMPLETE;
13392 +    }
13393 +
13394 +    if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
13395 +        return GSS_S_UNAVAILABLE;
13396 +
13397 +    try {
13398 +        ctx = new gss_eap_attr_ctx();
13399 +
13400 +        if (ctx->initWithExistingContext(in->attrCtx)) {
13401 +            out->attrCtx = ctx;
13402 +            major = GSS_S_COMPLETE;
13403 +            *minor = 0;
13404 +        } else {
13405 +            major = GSS_S_FAILURE;
13406 +            *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
13407 +        }
13408 +    } catch (std::exception &e) {
13409 +        major = in->attrCtx->mapException(minor, e);
13410 +    }
13411 +
13412 +    GSSEAP_ASSERT(major == GSS_S_COMPLETE || out->attrCtx == NULL);
13413 +
13414 +    if (GSS_ERROR(major))
13415 +        delete ctx;
13416 +
13417 +    return GSS_S_COMPLETE;
13418 +}
13419 +
13420 +OM_uint32
13421 +gssEapMapNameToAny(OM_uint32 *minor,
13422 +                   gss_name_t name,
13423 +                   int authenticated,
13424 +                   gss_buffer_t type_id,
13425 +                   gss_any_t *output)
13426 +{
13427 +    if (name->attrCtx == NULL) {
13428 +        *minor = GSSEAP_NO_ATTR_CONTEXT;
13429 +        return GSS_S_UNAVAILABLE;
13430 +    }
13431 +
13432 +    if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
13433 +        return GSS_S_UNAVAILABLE;
13434 +
13435 +    try {
13436 +        *output = name->attrCtx->mapToAny(authenticated, type_id);
13437 +    } catch (std::exception &e) {
13438 +        return name->attrCtx->mapException(minor, e);
13439 +    }
13440 +
13441 +    return GSS_S_COMPLETE;
13442 +}
13443 +
13444 +OM_uint32
13445 +gssEapReleaseAnyNameMapping(OM_uint32 *minor,
13446 +                            gss_name_t name,
13447 +                            gss_buffer_t type_id,
13448 +                            gss_any_t *input)
13449 +{
13450 +    if (name->attrCtx == NULL) {
13451 +        *minor = GSSEAP_NO_ATTR_CONTEXT;
13452 +        return GSS_S_UNAVAILABLE;
13453 +    }
13454 +
13455 +    if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
13456 +        return GSS_S_UNAVAILABLE;
13457 +
13458 +    try {
13459 +        if (*input != NULL)
13460 +            name->attrCtx->releaseAnyNameMapping(type_id, *input);
13461 +        *input = NULL;
13462 +    } catch (std::exception &e) {
13463 +        return name->attrCtx->mapException(minor, e);
13464 +    }
13465 +
13466 +    return GSS_S_COMPLETE;
13467 +}
13468 +
13469 +OM_uint32
13470 +gssEapReleaseAttrContext(OM_uint32 *minor,
13471 +                         gss_name_t name)
13472 +{
13473 +    if (name->attrCtx != NULL)
13474 +        delete name->attrCtx;
13475 +
13476 +    *minor = 0;
13477 +    return GSS_S_COMPLETE;
13478 +}
13479 +
13480 +/*
13481 + * Public accessor for initialisng a context from a GSS context. Also
13482 + * sets expiry time on GSS context as a side-effect.
13483 + */
13484 +OM_uint32
13485 +gssEapCreateAttrContext(OM_uint32 *minor,
13486 +                        gss_cred_id_t gssCred,
13487 +                        gss_ctx_id_t gssCtx,
13488 +                        struct gss_eap_attr_ctx **pAttrContext,
13489 +                        time_t *pExpiryTime)
13490 +{
13491 +    gss_eap_attr_ctx *ctx = NULL;
13492 +    OM_uint32 major;
13493 +
13494 +    GSSEAP_ASSERT(gssCtx != GSS_C_NO_CONTEXT);
13495 +
13496 +    *pAttrContext = NULL;
13497 +
13498 +    major = gssEapAttrProvidersInit(minor);
13499 +    if (GSS_ERROR(major))
13500 +        return major;
13501 +
13502 +    try {
13503 +        /* Set *pAttrContext here to for reentrancy */
13504 +        *pAttrContext = ctx = new gss_eap_attr_ctx();
13505 +
13506 +        if (ctx->initWithGssContext(gssCred, gssCtx)) {
13507 +            *pExpiryTime = ctx->getExpiryTime();
13508 +            major = GSS_S_COMPLETE;
13509 +            *minor = 0;
13510 +        } else {
13511 +            major = GSS_S_FAILURE;
13512 +            *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
13513 +        }
13514 +    } catch (std::exception &e) {
13515 +        if (ctx != NULL)
13516 +            major = ctx->mapException(minor, e);
13517 +    }
13518 +
13519 +    if (GSS_ERROR(major)) {
13520 +        delete ctx;
13521 +        *pAttrContext = NULL;
13522 +    }
13523 +
13524 +    return major;
13525 +}
13526 diff --git a/mech_eap/util_attr.h b/mech_eap/util_attr.h
13527 new file mode 100644
13528 index 0000000..2af0850
13529 --- /dev/null
13530 +++ b/mech_eap/util_attr.h
13531 @@ -0,0 +1,389 @@
13532 +/*
13533 + * Copyright (c) 2011, JANET(UK)
13534 + * All rights reserved.
13535 + *
13536 + * Redistribution and use in source and binary forms, with or without
13537 + * modification, are permitted provided that the following conditions
13538 + * are met:
13539 + *
13540 + * 1. Redistributions of source code must retain the above copyright
13541 + *    notice, this list of conditions and the following disclaimer.
13542 + *
13543 + * 2. Redistributions in binary form must reproduce the above copyright
13544 + *    notice, this list of conditions and the following disclaimer in the
13545 + *    documentation and/or other materials provided with the distribution.
13546 + *
13547 + * 3. Neither the name of JANET(UK) nor the names of its contributors
13548 + *    may be used to endorse or promote products derived from this software
13549 + *    without specific prior written permission.
13550 + *
13551 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
13552 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13553 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13554 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
13555 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13556 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13557 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13558 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13559 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13560 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13561 + * SUCH DAMAGE.
13562 + */
13563 +
13564 +/*
13565 + * Attribute provider interface.
13566 + */
13567 +
13568 +#ifndef _UTIL_ATTR_H_
13569 +#define _UTIL_ATTR_H_ 1
13570 +
13571 +#ifdef __cplusplus
13572 +#include <string>
13573 +#include <new>
13574 +
13575 +using namespace gss_eap_util;
13576 +
13577 +struct gss_eap_attr_provider;
13578 +struct gss_eap_attr_ctx;
13579 +
13580 +typedef bool
13581 +(*gss_eap_attr_enumeration_cb)(const gss_eap_attr_ctx *ctx,
13582 +                               const gss_eap_attr_provider *source,
13583 +                               const gss_buffer_t attribute,
13584 +                               void *data);
13585 +
13586 +#define ATTR_TYPE_RADIUS            0U                  /* RADIUS AVPs */
13587 +#ifdef HAVE_OPENSAML
13588 +#define ATTR_TYPE_SAML_ASSERTION    1U                  /* SAML assertion */
13589 +#define ATTR_TYPE_SAML              2U                  /* SAML attributes */
13590 +#endif
13591 +#define ATTR_TYPE_LOCAL             3U                  /* Local attributes */
13592 +#define ATTR_TYPE_MIN               ATTR_TYPE_RADIUS
13593 +#define ATTR_TYPE_MAX               ATTR_TYPE_LOCAL
13594 +
13595 +#define ATTR_FLAG_DISABLE_LOCAL     0x00000001
13596 +
13597 +/*
13598 + * Attribute provider: this represents a source of attributes derived
13599 + * from the security context.
13600 + */
13601 +struct gss_eap_attr_provider
13602 +{
13603 +public:
13604 +    gss_eap_attr_provider(void) {}
13605 +    virtual ~gss_eap_attr_provider(void) {}
13606 +
13607 +    bool initWithManager(const gss_eap_attr_ctx *manager)
13608 +    {
13609 +        m_manager = manager;
13610 +        return true;
13611 +    }
13612 +
13613 +    virtual bool initWithExistingContext(const gss_eap_attr_ctx *manager,
13614 +                                         const gss_eap_attr_provider *ctx GSSEAP_UNUSED)
13615 +    {
13616 +        return initWithManager(manager);
13617 +    }
13618 +
13619 +    virtual bool initWithGssContext(const gss_eap_attr_ctx *manager,
13620 +                                    const gss_cred_id_t cred GSSEAP_UNUSED,
13621 +                                    const gss_ctx_id_t ctx GSSEAP_UNUSED)
13622 +    {
13623 +        return initWithManager(manager);
13624 +    }
13625 +
13626 +    virtual bool getAttributeTypes(gss_eap_attr_enumeration_cb GSSEAP_UNUSED,
13627 +                                   void *data GSSEAP_UNUSED) const
13628 +    {
13629 +        return false;
13630 +    }
13631 +
13632 +    virtual bool setAttribute(int complete GSSEAP_UNUSED,
13633 +                              const gss_buffer_t attr GSSEAP_UNUSED,
13634 +                              const gss_buffer_t value GSSEAP_UNUSED)
13635 +    {
13636 +        return false;
13637 +    }
13638 +
13639 +    virtual bool deleteAttribute(const gss_buffer_t value GSSEAP_UNUSED)
13640 +    {
13641 +        return false;
13642 +    }
13643 +
13644 +    virtual bool getAttribute(const gss_buffer_t attr GSSEAP_UNUSED,
13645 +                              int *authenticated GSSEAP_UNUSED,
13646 +                              int *complete GSSEAP_UNUSED,
13647 +                              gss_buffer_t value GSSEAP_UNUSED,
13648 +                              gss_buffer_t display_value GSSEAP_UNUSED,
13649 +                              int *more GSSEAP_UNUSED) const
13650 +    {
13651 +        return false;
13652 +    }
13653 +
13654 +    virtual gss_any_t mapToAny(int authenticated GSSEAP_UNUSED,
13655 +                               gss_buffer_t type_id GSSEAP_UNUSED) const
13656 +    {
13657 +        return NULL;
13658 +    }
13659 +
13660 +    virtual void releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED,
13661 +                                       gss_any_t input GSSEAP_UNUSED) const
13662 +    {
13663 +    }
13664 +
13665 +    /* prefix to be prepended to attributes emitted by gss_get_name_attribute */
13666 +    virtual const char *prefix(void) const
13667 +    {
13668 +        return NULL;
13669 +    }
13670 +
13671 +    /* optional key for storing JSON dictionary */
13672 +    virtual const char *name(void) const
13673 +    {
13674 +        return NULL;
13675 +    }
13676 +
13677 +    virtual bool initWithJsonObject(const gss_eap_attr_ctx *manager,
13678 +                                    JSONObject &object GSSEAP_UNUSED)
13679 +    {
13680 +        return initWithManager(manager);
13681 +    }
13682 +
13683 +
13684 +    virtual JSONObject jsonRepresentation(void) const
13685 +    {
13686 +        return JSONObject::null();
13687 +    }
13688 +
13689 +    virtual time_t getExpiryTime(void) const { return 0; }
13690 +
13691 +    virtual OM_uint32 mapException(OM_uint32 *minor GSSEAP_UNUSED,
13692 +                                   std::exception &e GSSEAP_UNUSED) const
13693 +    {
13694 +        return GSS_S_CONTINUE_NEEDED;
13695 +    }
13696 +
13697 +    static bool init(void) { return true; }
13698 +    static void finalize(void) {}
13699 +
13700 +    static gss_eap_attr_provider *createAttrContext(void) { return NULL; }
13701 +
13702 +protected:
13703 +    const gss_eap_attr_ctx *m_manager;
13704 +
13705 +private:
13706 +    /* make non-copyable */
13707 +    gss_eap_attr_provider(const gss_eap_attr_provider&);
13708 +    gss_eap_attr_provider& operator=(const gss_eap_attr_provider&);
13709 +};
13710 +
13711 +typedef gss_eap_attr_provider *(*gss_eap_attr_create_provider)(void);
13712 +
13713 +/*
13714 + * Attribute context: this manages a set of providers for a given
13715 + * security context.
13716 + */
13717 +struct gss_eap_attr_ctx
13718 +{
13719 +public:
13720 +    gss_eap_attr_ctx(void);
13721 +    ~gss_eap_attr_ctx(void);
13722 +
13723 +    bool initWithExistingContext(const gss_eap_attr_ctx *manager);
13724 +    bool initWithGssContext(const gss_cred_id_t cred,
13725 +                            const gss_ctx_id_t ctx);
13726 +
13727 +    bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const;
13728 +    bool getAttributeTypes(gss_buffer_set_t *attrs);
13729 +
13730 +    bool setAttribute(int complete,
13731 +                      const gss_buffer_t attr,
13732 +                      const gss_buffer_t value);
13733 +    bool deleteAttribute(const gss_buffer_t value);
13734 +    bool getAttribute(const gss_buffer_t attr,
13735 +                      int *authenticated,
13736 +                      int *complete,
13737 +                      gss_buffer_t value,
13738 +                      gss_buffer_t display_value,
13739 +                      int *more) const;
13740 +    gss_any_t mapToAny(int authenticated,
13741 +                       gss_buffer_t type_id) const;
13742 +    void releaseAnyNameMapping(gss_buffer_t type_id,
13743 +                               gss_any_t input) const;
13744 +
13745 +    void exportToBuffer(gss_buffer_t buffer) const;
13746 +    bool initWithBuffer(const gss_buffer_t buffer);
13747 +
13748 +    static std::string
13749 +    composeAttributeName(const gss_buffer_t prefix,
13750 +                         const gss_buffer_t suffix);
13751 +    static void
13752 +    decomposeAttributeName(const gss_buffer_t attribute,
13753 +                           gss_buffer_t prefix,
13754 +                           gss_buffer_t suffix);
13755 +    static void
13756 +    composeAttributeName(const gss_buffer_t prefix,
13757 +                         const gss_buffer_t suffix,
13758 +                         gss_buffer_t attribute);
13759 +
13760 +    std::string
13761 +    composeAttributeName(unsigned int type,
13762 +                         const gss_buffer_t suffix);
13763 +    void
13764 +    decomposeAttributeName(const gss_buffer_t attribute,
13765 +                           unsigned int *type,
13766 +                           gss_buffer_t suffix) const;
13767 +    void
13768 +    composeAttributeName(unsigned int type,
13769 +                         const gss_buffer_t suffix,
13770 +                         gss_buffer_t attribute) const;
13771 +
13772 +    gss_eap_attr_provider *getProvider(unsigned int type) const;
13773 +
13774 +    static void
13775 +    registerProvider(unsigned int type,
13776 +                     gss_eap_attr_create_provider factory);
13777 +    static void
13778 +    unregisterProvider(unsigned int type);
13779 +
13780 +    time_t getExpiryTime(void) const;
13781 +    OM_uint32 mapException(OM_uint32 *minor, std::exception &e) const;
13782 +
13783 +private:
13784 +    bool providerEnabled(unsigned int type) const;
13785 +    void releaseProvider(unsigned int type);
13786 +
13787 +    unsigned int attributePrefixToType(const gss_buffer_t prefix) const;
13788 +    gss_buffer_desc attributeTypeToPrefix(unsigned int type) const;
13789 +
13790 +    bool initWithJsonObject(JSONObject &object);
13791 +    JSONObject jsonRepresentation(void) const;
13792 +
13793 +    gss_eap_attr_provider *getPrimaryProvider(void) const;
13794 +
13795 +    /* make non-copyable */
13796 +    gss_eap_attr_ctx(const gss_eap_attr_ctx&);
13797 +    gss_eap_attr_ctx& operator=(const gss_eap_attr_ctx&);
13798 +
13799 +    uint32_t m_flags;
13800 +    gss_eap_attr_provider *m_providers[ATTR_TYPE_MAX + 1];
13801 +};
13802 +
13803 +#endif /* __cplusplus */
13804 +
13805 +#include "util_radius.h"
13806 +#include "util_saml.h"
13807 +#include "util_shib.h"
13808 +
13809 +#ifdef __cplusplus
13810 +
13811 +static inline void
13812 +duplicateBuffer(gss_buffer_desc &src, gss_buffer_t dst)
13813 +{
13814 +    OM_uint32 minor;
13815 +
13816 +    if (GSS_ERROR(duplicateBuffer(&minor, &src, dst)))
13817 +        throw std::bad_alloc();
13818 +}
13819 +
13820 +static inline void
13821 +duplicateBuffer(std::string &str, gss_buffer_t buffer)
13822 +{
13823 +    gss_buffer_desc tmp;
13824 +
13825 +    tmp.length = str.length();
13826 +    tmp.value = (char *)str.c_str();
13827 +
13828 +    duplicateBuffer(tmp, buffer);
13829 +}
13830 +
13831 +#else
13832 +struct gss_eap_attr_ctx;
13833 +#endif
13834 +
13835 +#ifdef __cplusplus
13836 +extern "C" {
13837 +#endif
13838 +
13839 +/*
13840 + * C wrappers for attribute context functions. These match their
13841 + * GSS naming extension equivalents. The caller is required to
13842 + * obtain the name mutex.
13843 + */
13844 +
13845 +OM_uint32
13846 +gssEapCreateAttrContext(OM_uint32 *minor,
13847 +                        gss_cred_id_t acceptorCred,
13848 +                        gss_ctx_id_t acceptorCtx,
13849 +                        struct gss_eap_attr_ctx **pAttrCtx,
13850 +                        time_t *pExpiryTime);
13851 +
13852 +OM_uint32
13853 +gssEapInquireName(OM_uint32 *minor,
13854 +                  gss_name_t name,
13855 +                  int *name_is_MN,
13856 +                  gss_OID *MN_mech,
13857 +                  gss_buffer_set_t *attrs);
13858 +
13859 +OM_uint32
13860 +gssEapGetNameAttribute(OM_uint32 *minor,
13861 +                       gss_name_t name,
13862 +                       gss_buffer_t attr,
13863 +                       int *authenticated,
13864 +                       int *complete,
13865 +                       gss_buffer_t value,
13866 +                       gss_buffer_t display_value,
13867 +                       int *more);
13868 +
13869 +OM_uint32
13870 +gssEapDeleteNameAttribute(OM_uint32 *minor,
13871 +                          gss_name_t name,
13872 +                          gss_buffer_t attr);
13873 +
13874 +OM_uint32
13875 +gssEapSetNameAttribute(OM_uint32 *minor,
13876 +                       gss_name_t name,
13877 +                       int complete,
13878 +                       gss_buffer_t attr,
13879 +                       gss_buffer_t value);
13880 +
13881 +OM_uint32
13882 +gssEapExportAttrContext(OM_uint32 *minor,
13883 +                        gss_name_t name,
13884 +                        gss_buffer_t buffer);
13885 +
13886 +OM_uint32
13887 +gssEapImportAttrContext(OM_uint32 *minor,
13888 +                        gss_buffer_t buffer,
13889 +                        gss_name_t name);
13890 +
13891 +OM_uint32
13892 +gssEapDuplicateAttrContext(OM_uint32 *minor,
13893 +                           gss_name_t in,
13894 +                           gss_name_t out);
13895 +
13896 +OM_uint32
13897 +gssEapMapNameToAny(OM_uint32 *minor,
13898 +                   gss_name_t name,
13899 +                   int authenticated,
13900 +                   gss_buffer_t type_id,
13901 +                   gss_any_t *output);
13902 +
13903 +OM_uint32
13904 +gssEapReleaseAnyNameMapping(OM_uint32 *minor,
13905 +                            gss_name_t name,
13906 +                            gss_buffer_t type_id,
13907 +                            gss_any_t *input);
13908 +
13909 +OM_uint32
13910 +gssEapReleaseAttrContext(OM_uint32 *minor,
13911 +                         gss_name_t name);
13912 +
13913 +OM_uint32
13914 +gssEapAttrProvidersFinalize(OM_uint32 *minor);
13915 +
13916 +#ifdef __cplusplus
13917 +}
13918 +#endif
13919 +
13920 +#endif /* _UTIL_ATTR_H_ */
13921 diff --git a/mech_eap/util_base64.c b/mech_eap/util_base64.c
13922 new file mode 100644
13923 index 0000000..aaa1ea8
13924 --- /dev/null
13925 +++ b/mech_eap/util_base64.c
13926 @@ -0,0 +1,161 @@
13927 +/*
13928 + * Copyright (c) 1995-2001 Kungliga Tekniska Högskolan
13929 + * (Royal Institute of Technology, Stockholm, Sweden).
13930 + * All rights reserved.
13931 + *
13932 + * Redistribution and use in source and binary forms, with or without
13933 + * modification, are permitted provided that the following conditions
13934 + * are met:
13935 + *
13936 + * 1. Redistributions of source code must retain the above copyright
13937 + *    notice, this list of conditions and the following disclaimer.
13938 + *
13939 + * 2. Redistributions in binary form must reproduce the above copyright
13940 + *    notice, this list of conditions and the following disclaimer in the
13941 + *    documentation and/or other materials provided with the distribution.
13942 + *
13943 + * 3. Neither the name of the Institute nor the names of its contributors
13944 + *    may be used to endorse or promote products derived from this software
13945 + *    without specific prior written permission.
13946 + *
13947 + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
13948 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13949 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13950 + * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
13951 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13952 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13953 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13954 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13955 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13956 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13957 + * SUCH DAMAGE.
13958 + */
13959 +
13960 +#include "gssapiP_eap.h"
13961 +
13962 +static const char base64_chars[] =
13963 +    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
13964 +
13965 +static int
13966 +pos(char c)
13967 +{
13968 +    const char *p;
13969 +    for (p = base64_chars; *p; p++)
13970 +       if (*p == c)
13971 +           return p - base64_chars;
13972 +    return -1;
13973 +}
13974 +
13975 +ssize_t
13976 +base64Encode(const void *data, int size, char **str)
13977 +{
13978 +    char *s, *p;
13979 +    int i;
13980 +    int c;
13981 +    const unsigned char *q;
13982 +
13983 +    if (size > INT_MAX/4 || size < 0) {
13984 +       *str = NULL;
13985 +       return -1;
13986 +    }
13987 +
13988 +    p = s = (char *)GSSEAP_MALLOC(BASE64_EXPAND(size));
13989 +    if (p == NULL) {
13990 +        *str = NULL;
13991 +       return -1;
13992 +    }
13993 +    q = (const unsigned char *) data;
13994 +
13995 +    for (i = 0; i < size;) {
13996 +       c = q[i++];
13997 +       c *= 256;
13998 +       if (i < size)
13999 +           c += q[i];
14000 +       i++;
14001 +       c *= 256;
14002 +       if (i < size)
14003 +           c += q[i];
14004 +       i++;
14005 +       p[0] = base64_chars[(c & 0x00fc0000) >> 18];
14006 +       p[1] = base64_chars[(c & 0x0003f000) >> 12];
14007 +       p[2] = base64_chars[(c & 0x00000fc0) >> 6];
14008 +       p[3] = base64_chars[(c & 0x0000003f) >> 0];
14009 +       if (i > size)
14010 +           p[3] = '=';
14011 +       if (i > size + 1)
14012 +           p[2] = '=';
14013 +       p += 4;
14014 +    }
14015 +    *p = 0;
14016 +    *str = s;
14017 +    return strlen(s);
14018 +}
14019 +
14020 +#define DECODE_ERROR 0xffffffff
14021 +
14022 +static unsigned int
14023 +token_decode(const char *token)
14024 +{
14025 +    int i;
14026 +    unsigned int val = 0;
14027 +    int marker = 0;
14028 +    if (strlen(token) < 4)
14029 +       return DECODE_ERROR;
14030 +    for (i = 0; i < 4; i++) {
14031 +       val *= 64;
14032 +       if (token[i] == '=')
14033 +           marker++;
14034 +       else if (marker > 0)
14035 +           return DECODE_ERROR;
14036 +       else
14037 +           val += pos(token[i]);
14038 +    }
14039 +    if (marker > 2)
14040 +       return DECODE_ERROR;
14041 +    return (marker << 24) | val;
14042 +}
14043 +
14044 +ssize_t
14045 +base64Decode(const char *str, void *data)
14046 +{
14047 +    const char *p;
14048 +    unsigned char *q;
14049 +
14050 +    q = data;
14051 +    p = str;
14052 +
14053 +    while (*p && *p && (*p == '=' || strchr(base64_chars, *p))) {
14054 +       unsigned int val = token_decode(p);
14055 +       unsigned int marker = (val >> 24) & 0xff;
14056 +       if (val == DECODE_ERROR)
14057 +           return -1;
14058 +       *q++ = (val >> 16) & 0xff;
14059 +       if (marker < 2)
14060 +           *q++ = (val >> 8) & 0xff;
14061 +       if (marker < 1)
14062 +           *q++ = val & 0xff;
14063 +       p += 4;
14064 +       if (*p == '\n')
14065 +           p++;
14066 +    }
14067 +    return q - (unsigned char *) data;
14068 +}
14069 +
14070 +int
14071 +base64Valid(const char *str)
14072 +{
14073 +    const char *p = str;
14074 +    int valid = 1;
14075 +
14076 +    while (*p && *p && (*p == '=' || strchr(base64_chars, *p))) {
14077 +       unsigned int val = token_decode(p);
14078 +       if (val == DECODE_ERROR) {
14079 +            valid = 0;
14080 +           break;
14081 +        }
14082 +       p += 4;
14083 +       if (*p == '\n')
14084 +           p++;
14085 +    }
14086 +    return valid;
14087 +}
14088 diff --git a/mech_eap/util_base64.h b/mech_eap/util_base64.h
14089 new file mode 100644
14090 index 0000000..d015efe
14091 --- /dev/null
14092 +++ b/mech_eap/util_base64.h
14093 @@ -0,0 +1,58 @@
14094 +/*
14095 + * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
14096 + * (Royal Institute of Technology, Stockholm, Sweden).
14097 + * All rights reserved.
14098 + *
14099 + * Redistribution and use in source and binary forms, with or without
14100 + * modification, are permitted provided that the following conditions
14101 + * are met:
14102 + *
14103 + * 1. Redistributions of source code must retain the above copyright
14104 + *    notice, this list of conditions and the following disclaimer.
14105 + *
14106 + * 2. Redistributions in binary form must reproduce the above copyright
14107 + *    notice, this list of conditions and the following disclaimer in the
14108 + *    documentation and/or other materials provided with the distribution.
14109 + *
14110 + * 3. Neither the name of the Institute nor the names of its contributors
14111 + *    may be used to endorse or promote products derived from this software
14112 + *    without specific prior written permission.
14113 + *
14114 + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
14115 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14116 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14117 + * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
14118 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14119 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14120 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14121 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14122 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14123 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14124 + * SUCH DAMAGE.
14125 + */
14126 +
14127 +/* $Id$ */
14128 +
14129 +#ifndef _UTIL_BASE64_H_
14130 +#define _UTIL_BASE64_H_
14131 +
14132 +#ifdef __cplusplus
14133 +extern "C" {
14134 +#endif
14135 +
14136 +ssize_t
14137 +base64Encode(const void *, int, char **);
14138 +
14139 +ssize_t
14140 +base64Decode(const char *, void *);
14141 +
14142 +int
14143 +base64Valid(const char *str);
14144 +
14145 +#define BASE64_EXPAND(n)        (n * 4 / 3 + 4)
14146 +
14147 +#ifdef __cplusplus
14148 +}
14149 +#endif
14150 +
14151 +#endif
14152 diff --git a/mech_eap/util_buffer.c b/mech_eap/util_buffer.c
14153 new file mode 100644
14154 index 0000000..e135db9
14155 --- /dev/null
14156 +++ b/mech_eap/util_buffer.c
14157 @@ -0,0 +1,103 @@
14158 +/*
14159 + * Copyright (c) 2011, JANET(UK)
14160 + * All rights reserved.
14161 + *
14162 + * Redistribution and use in source and binary forms, with or without
14163 + * modification, are permitted provided that the following conditions
14164 + * are met:
14165 + *
14166 + * 1. Redistributions of source code must retain the above copyright
14167 + *    notice, this list of conditions and the following disclaimer.
14168 + *
14169 + * 2. Redistributions in binary form must reproduce the above copyright
14170 + *    notice, this list of conditions and the following disclaimer in the
14171 + *    documentation and/or other materials provided with the distribution.
14172 + *
14173 + * 3. Neither the name of JANET(UK) nor the names of its contributors
14174 + *    may be used to endorse or promote products derived from this software
14175 + *    without specific prior written permission.
14176 + *
14177 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14178 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14179 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14180 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
14181 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14182 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14183 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14184 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14185 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14186 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14187 + * SUCH DAMAGE.
14188 + */
14189 +
14190 +/*
14191 + * Buffer handling helpers.
14192 + */
14193 +
14194 +#include "gssapiP_eap.h"
14195 +
14196 +OM_uint32
14197 +makeStringBuffer(OM_uint32 *minor,
14198 +                 const char *string,
14199 +                 gss_buffer_t buffer)
14200 +{
14201 +    size_t len = strlen(string);
14202 +
14203 +    buffer->value = GSSEAP_MALLOC(len + 1);
14204 +    if (buffer->value == NULL) {
14205 +        *minor = ENOMEM;
14206 +        return GSS_S_FAILURE;
14207 +    }
14208 +    memcpy(buffer->value, string, len + 1);
14209 +    buffer->length = len;
14210 +
14211 +    *minor = 0;
14212 +    return GSS_S_COMPLETE;
14213 +}
14214 +
14215 +OM_uint32
14216 +bufferToString(OM_uint32 *minor,
14217 +               const gss_buffer_t buffer,
14218 +               char **pString)
14219 +{
14220 +    char *s;
14221 +
14222 +    s = GSSEAP_MALLOC(buffer->length + 1);
14223 +    if (s == NULL) {
14224 +        *minor = ENOMEM;
14225 +        return GSS_S_FAILURE;
14226 +    }
14227 +    memcpy(s, buffer->value, buffer->length);
14228 +    s[buffer->length] = '\0';
14229 +
14230 +    *pString = s;
14231 +
14232 +    *minor = 0;
14233 +    return GSS_S_COMPLETE;
14234 +}
14235 +
14236 +OM_uint32
14237 +duplicateBuffer(OM_uint32 *minor,
14238 +                const gss_buffer_t src,
14239 +                gss_buffer_t dst)
14240 +{
14241 +    dst->length = 0;
14242 +    dst->value = NULL;
14243 +
14244 +    if (src == GSS_C_NO_BUFFER)
14245 +        return GSS_S_COMPLETE;
14246 +
14247 +    dst->value = GSSEAP_MALLOC(src->length + 1);
14248 +    if (dst->value == NULL) {
14249 +        *minor = ENOMEM;
14250 +        return GSS_S_FAILURE;
14251 +    }
14252 +
14253 +    dst->length = src->length;
14254 +    memcpy(dst->value, src->value, dst->length);
14255 +
14256 +    ((unsigned char *)dst->value)[dst->length] = '\0';
14257 +
14258 +    *minor = 0;
14259 +    return GSS_S_COMPLETE;
14260 +}
14261 diff --git a/mech_eap/util_cksum.c b/mech_eap/util_cksum.c
14262 new file mode 100644
14263 index 0000000..aedc93e
14264 --- /dev/null
14265 +++ b/mech_eap/util_cksum.c
14266 @@ -0,0 +1,242 @@
14267 +/*
14268 + * Copyright (c) 2011, JANET(UK)
14269 + * All rights reserved.
14270 + *
14271 + * Redistribution and use in source and binary forms, with or without
14272 + * modification, are permitted provided that the following conditions
14273 + * are met:
14274 + *
14275 + * 1. Redistributions of source code must retain the above copyright
14276 + *    notice, this list of conditions and the following disclaimer.
14277 + *
14278 + * 2. Redistributions in binary form must reproduce the above copyright
14279 + *    notice, this list of conditions and the following disclaimer in the
14280 + *    documentation and/or other materials provided with the distribution.
14281 + *
14282 + * 3. Neither the name of JANET(UK) nor the names of its contributors
14283 + *    may be used to endorse or promote products derived from this software
14284 + *    without specific prior written permission.
14285 + *
14286 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14287 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14288 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14289 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
14290 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14291 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14292 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14293 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14294 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14295 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14296 + * SUCH DAMAGE.
14297 + */
14298 +/*
14299 + * Copyright 1993 by OpenVision Technologies, Inc.
14300 + *
14301 + * Permission to use, copy, modify, distribute, and sell this software
14302 + * and its documentation for any purpose is hereby granted without fee,
14303 + * provided that the above copyright notice appears in all copies and
14304 + * that both that copyright notice and this permission notice appear in
14305 + * supporting documentation, and that the name of OpenVision not be used
14306 + * in advertising or publicity pertaining to distribution of the software
14307 + * without specific, written prior permission. OpenVision makes no
14308 + * representations about the suitability of this software for any
14309 + * purpose.  It is provided "as is" without express or implied warranty.
14310 + *
14311 + * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
14312 + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
14313 + * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
14314 + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
14315 + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14316 + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14317 + * PERFORMANCE OF THIS SOFTWARE.
14318 + */
14319 +
14320 +/*
14321 + * Message protection services: checksum helpers.
14322 + */
14323 +
14324 +#include "gssapiP_eap.h"
14325 +
14326 +static int
14327 +gssEapChecksum(krb5_context context,
14328 +               krb5_cksumtype type,
14329 +               size_t rrc,
14330 +#ifdef HAVE_HEIMDAL_VERSION
14331 +               krb5_crypto crypto,
14332 +#else
14333 +               krb5_keyblock *crypto,
14334 +#endif
14335 +               krb5_keyusage sign_usage,
14336 +               gss_iov_buffer_desc *iov,
14337 +               int iov_count,
14338 +               int verify,
14339 +               int *valid)
14340 +{
14341 +    krb5_error_code code;
14342 +    gss_iov_buffer_desc *header;
14343 +    gss_iov_buffer_desc *trailer;
14344 +    krb5_crypto_iov *kiov;
14345 +    size_t kiov_count;
14346 +    int i = 0, j;
14347 +    size_t k5_checksumlen;
14348 +
14349 +    if (verify)
14350 +        *valid = FALSE;
14351 +
14352 +    code = krbCryptoLength(context, crypto, KRB5_CRYPTO_TYPE_CHECKSUM, &k5_checksumlen);
14353 +    if (code != 0)
14354 +        return code;
14355 +
14356 +    header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
14357 +    GSSEAP_ASSERT(header != NULL);
14358 +
14359 +    trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
14360 +    GSSEAP_ASSERT(rrc != 0 || trailer != NULL);
14361 +
14362 +    if (trailer == NULL) {
14363 +        if (rrc != k5_checksumlen)
14364 +            return KRB5_BAD_MSIZE;
14365 +        if (header->buffer.length != 16 + k5_checksumlen)
14366 +            return KRB5_BAD_MSIZE;
14367 +    } else if (trailer->buffer.length != k5_checksumlen)
14368 +        return KRB5_BAD_MSIZE;
14369 +
14370 +    kiov_count = 2 + iov_count;
14371 +    kiov = (krb5_crypto_iov *)GSSEAP_MALLOC(kiov_count * sizeof(krb5_crypto_iov));
14372 +    if (kiov == NULL)
14373 +        return ENOMEM;
14374 +
14375 +    /* Checksum over ( Data | Header ) */
14376 +
14377 +    /* Data */
14378 +    for (j = 0; j < iov_count; j++) {
14379 +        kiov[i].flags = gssEapMapCryptoFlag(iov[j].type);
14380 +        kiov[i].data.length = iov[j].buffer.length;
14381 +        kiov[i].data.data = (char *)iov[j].buffer.value;
14382 +        i++;
14383 +    }
14384 +
14385 +    /* Header */
14386 +    kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
14387 +    kiov[i].data.length = 16;
14388 +    kiov[i].data.data = (char *)header->buffer.value;
14389 +    i++;
14390 +
14391 +    /* Checksum */
14392 +    kiov[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
14393 +    if (trailer == NULL) {
14394 +        kiov[i].data.length = header->buffer.length - 16;
14395 +        kiov[i].data.data = (char *)header->buffer.value + 16;
14396 +    } else {
14397 +        kiov[i].data.length = trailer->buffer.length;
14398 +        kiov[i].data.data = (char *)trailer->buffer.value;
14399 +    }
14400 +    i++;
14401 +
14402 +#ifdef HAVE_HEIMDAL_VERSION
14403 +    if (verify) {
14404 +        code = krb5_verify_checksum_iov(context, crypto, sign_usage,
14405 +                                        kiov, kiov_count, &type);
14406 +        *valid = (code == 0);
14407 +    } else {
14408 +        code = krb5_create_checksum_iov(context, crypto, sign_usage,
14409 +                                        kiov, kiov_count, &type);
14410 +    }
14411 +#else
14412 +    if (verify) {
14413 +        krb5_boolean kvalid = FALSE;
14414 +
14415 +        code = krb5_c_verify_checksum_iov(context, type, crypto,
14416 +                                          sign_usage, kiov, kiov_count, &kvalid);
14417 +
14418 +        *valid = kvalid;
14419 +    } else {
14420 +        code = krb5_c_make_checksum_iov(context, type, crypto,
14421 +                                        sign_usage, kiov, kiov_count);
14422 +    }
14423 +#endif /* HAVE_HEIMDAL_VERSION */
14424 +
14425 +    GSSEAP_FREE(kiov);
14426 +
14427 +    return code;
14428 +}
14429 +
14430 +int
14431 +gssEapSign(krb5_context context,
14432 +           krb5_cksumtype type,
14433 +           size_t rrc,
14434 +#ifdef HAVE_HEIMDAL_VERSION
14435 +           krb5_crypto crypto,
14436 +#else
14437 +           krb5_keyblock *crypto,
14438 +#endif
14439 +           krb5_keyusage sign_usage,
14440 +           gss_iov_buffer_desc *iov,
14441 +           int iov_count)
14442 +{
14443 +    return gssEapChecksum(context, type, rrc, crypto,
14444 +                          sign_usage, iov, iov_count, 0, NULL);
14445 +}
14446 +
14447 +int
14448 +gssEapVerify(krb5_context context,
14449 +             krb5_cksumtype type,
14450 +             size_t rrc,
14451 +#ifdef HAVE_HEIMDAL_VERSION
14452 +             krb5_crypto crypto,
14453 +#else
14454 +             krb5_keyblock *crypto,
14455 +#endif
14456 +             krb5_keyusage sign_usage,
14457 +             gss_iov_buffer_desc *iov,
14458 +             int iov_count,
14459 +             int *valid)
14460 +{
14461 +    return gssEapChecksum(context, type, rrc, crypto,
14462 +                          sign_usage, iov, iov_count, 1, valid);
14463 +}
14464 +
14465 +#if 0
14466 +OM_uint32
14467 +gssEapEncodeGssChannelBindings(OM_uint32 *minor,
14468 +                               gss_channel_bindings_t chanBindings,
14469 +                               gss_buffer_t encodedBindings)
14470 +{
14471 +    OM_uint32 major, tmpMinor;
14472 +    size_t length;
14473 +    unsigned char *p;
14474 +
14475 +    if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS) {
14476 +        length = 24;
14477 +        length += chanBindings->initiator_address.length;
14478 +        length += chanBindings->acceptor_address.length;
14479 +        length += chanBindings->application_data.length;
14480 +
14481 +        encodedBindings->value = GSSEAP_MALLOC(length);
14482 +        if (encodedBindings->value == NULL) {
14483 +            *minor = ENOMEM;
14484 +            return GSS_S_FAILURE;
14485 +        }
14486 +
14487 +        encodedBindings->length = length;
14488 +        p = (unsigned char *)encodedBindings->value;
14489 +
14490 +        store_uint32_be(chanBindings->initiator_addrtype, p);
14491 +        store_buffer(&chanBindings->initiator_address, p + 4, 0);
14492 +        p += 4 + chanBindings->initiator_address.length;
14493 +
14494 +        store_uint32_be(chanBindings->acceptor_addrtype, p);
14495 +        store_buffer(&chanBindings->acceptor_address, p + 4, 0);
14496 +        p += 4 + chanBindings->acceptor_address.length;
14497 +
14498 +        store_buffer(&chanBindings->application_data, p, 1);
14499 +        p += chanBindings->application_data.length;
14500 +    } else {
14501 +        encodedBindings->length = 0;
14502 +        encodedBindings->value = NULL;
14503 +    }
14504 +
14505 +    *minor = 0;
14506 +    return GSS_S_COMPLETE;
14507 +}
14508 +#endif
14509 diff --git a/mech_eap/util_context.c b/mech_eap/util_context.c
14510 new file mode 100644
14511 index 0000000..e18edc5
14512 --- /dev/null
14513 +++ b/mech_eap/util_context.c
14514 @@ -0,0 +1,377 @@
14515 +/*
14516 + * Copyright (c) 2011, JANET(UK)
14517 + * All rights reserved.
14518 + *
14519 + * Redistribution and use in source and binary forms, with or without
14520 + * modification, are permitted provided that the following conditions
14521 + * are met:
14522 + *
14523 + * 1. Redistributions of source code must retain the above copyright
14524 + *    notice, this list of conditions and the following disclaimer.
14525 + *
14526 + * 2. Redistributions in binary form must reproduce the above copyright
14527 + *    notice, this list of conditions and the following disclaimer in the
14528 + *    documentation and/or other materials provided with the distribution.
14529 + *
14530 + * 3. Neither the name of JANET(UK) nor the names of its contributors
14531 + *    may be used to endorse or promote products derived from this software
14532 + *    without specific prior written permission.
14533 + *
14534 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14535 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14536 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14537 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
14538 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14539 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14540 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14541 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14542 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14543 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14544 + * SUCH DAMAGE.
14545 + */
14546 +
14547 +/*
14548 + * Utility routines for context handles.
14549 + */
14550 +
14551 +#include "gssapiP_eap.h"
14552 +
14553 +OM_uint32
14554 +gssEapAllocContext(OM_uint32 *minor,
14555 +                   gss_ctx_id_t *pCtx)
14556 +{
14557 +    OM_uint32 tmpMinor;
14558 +    gss_ctx_id_t ctx;
14559 +
14560 +    GSSEAP_ASSERT(*pCtx == GSS_C_NO_CONTEXT);
14561 +
14562 +    ctx = (gss_ctx_id_t)GSSEAP_CALLOC(1, sizeof(*ctx));
14563 +    if (ctx == NULL) {
14564 +        *minor = ENOMEM;
14565 +        return GSS_S_FAILURE;
14566 +    }
14567 +
14568 +    if (GSSEAP_MUTEX_INIT(&ctx->mutex) != 0) {
14569 +        *minor = GSSEAP_GET_LAST_ERROR();
14570 +        gssEapReleaseContext(&tmpMinor, &ctx);
14571 +        return GSS_S_FAILURE;
14572 +    }
14573 +
14574 +    ctx->state = GSSEAP_STATE_INITIAL;
14575 +    ctx->mechanismUsed = GSS_C_NO_OID;
14576 +
14577 +    /*
14578 +     * Integrity, confidentiality, sequencing and replay detection are
14579 +     * always available.  Regardless of what flags are requested in
14580 +     * GSS_Init_sec_context, implementations MUST set the flag corresponding
14581 +     * to these services in the output of GSS_Init_sec_context and
14582 +     * GSS_Accept_sec_context.
14583 +    */
14584 +    ctx->gssFlags = GSS_C_TRANS_FLAG    |   /* exporting contexts */
14585 +                    GSS_C_INTEG_FLAG    |   /* integrity */
14586 +                    GSS_C_CONF_FLAG     |   /* confidentiality */
14587 +                    GSS_C_SEQUENCE_FLAG |   /* sequencing */
14588 +                    GSS_C_REPLAY_FLAG;      /* replay detection */
14589 +
14590 +    *pCtx = ctx;
14591 +
14592 +    return GSS_S_COMPLETE;
14593 +}
14594 +
14595 +static void
14596 +releaseInitiatorContext(struct gss_eap_initiator_ctx *ctx)
14597 +{
14598 +    eap_peer_sm_deinit(ctx->eap);
14599 +}
14600 +
14601 +#ifdef GSSEAP_ENABLE_ACCEPTOR
14602 +static void
14603 +releaseAcceptorContext(struct gss_eap_acceptor_ctx *ctx)
14604 +{
14605 +    OM_uint32 tmpMinor;
14606 +
14607 +    if (ctx->radConn != NULL)
14608 +        rs_conn_destroy(ctx->radConn);
14609 +    if (ctx->radContext != NULL)
14610 +        rs_context_destroy(ctx->radContext);
14611 +    if (ctx->radServer != NULL)
14612 +        GSSEAP_FREE(ctx->radServer);
14613 +    gss_release_buffer(&tmpMinor, &ctx->state);
14614 +    if (ctx->vps != NULL)
14615 +        gssEapRadiusFreeAvps(&tmpMinor, &ctx->vps);
14616 +}
14617 +#endif /* GSSEAP_ENABLE_ACCEPTOR */
14618 +
14619 +OM_uint32
14620 +gssEapReleaseContext(OM_uint32 *minor,
14621 +                     gss_ctx_id_t *pCtx)
14622 +{
14623 +    OM_uint32 tmpMinor;
14624 +    gss_ctx_id_t ctx = *pCtx;
14625 +    krb5_context krbContext = NULL;
14626 +
14627 +    if (ctx == GSS_C_NO_CONTEXT) {
14628 +        return GSS_S_COMPLETE;
14629 +    }
14630 +
14631 +    gssEapKerberosInit(&tmpMinor, &krbContext);
14632 +
14633 +#ifdef GSSEAP_ENABLE_REAUTH
14634 +    if (ctx->flags & CTX_FLAG_KRB_REAUTH) {
14635 +        gssDeleteSecContext(&tmpMinor, &ctx->reauthCtx, GSS_C_NO_BUFFER);
14636 +    } else
14637 +#endif /* GSSEAP_ENABLE_REAUTH */
14638 +    if (CTX_IS_INITIATOR(ctx)) {
14639 +        releaseInitiatorContext(&ctx->initiatorCtx);
14640 +    }
14641 +#ifdef GSSEAP_ENABLE_ACCEPTOR
14642 +    else {
14643 +        releaseAcceptorContext(&ctx->acceptorCtx);
14644 +    }
14645 +#endif /* GSSEAP_ENABLE_ACCEPTOR */
14646 +
14647 +    krb5_free_keyblock_contents(krbContext, &ctx->rfc3961Key);
14648 +    gssEapReleaseName(&tmpMinor, &ctx->initiatorName);
14649 +    gssEapReleaseName(&tmpMinor, &ctx->acceptorName);
14650 +    gssEapReleaseOid(&tmpMinor, &ctx->mechanismUsed);
14651 +    sequenceFree(&tmpMinor, &ctx->seqState);
14652 +    gssEapReleaseCred(&tmpMinor, &ctx->cred);
14653 +
14654 +    GSSEAP_MUTEX_DESTROY(&ctx->mutex);
14655 +
14656 +    memset(ctx, 0, sizeof(*ctx));
14657 +    GSSEAP_FREE(ctx);
14658 +    *pCtx = GSS_C_NO_CONTEXT;
14659 +
14660 +    *minor = 0;
14661 +    return GSS_S_COMPLETE;
14662 +}
14663 +
14664 +OM_uint32
14665 +gssEapMakeToken(OM_uint32 *minor,
14666 +                gss_ctx_id_t ctx,
14667 +                const gss_buffer_t innerToken,
14668 +                enum gss_eap_token_type tokenType,
14669 +                gss_buffer_t outputToken)
14670 +{
14671 +    unsigned char *p;
14672 +
14673 +    GSSEAP_ASSERT(ctx->mechanismUsed != GSS_C_NO_OID);
14674 +
14675 +    outputToken->length = tokenSize(ctx->mechanismUsed, innerToken->length);
14676 +    outputToken->value = GSSEAP_MALLOC(outputToken->length);
14677 +    if (outputToken->value == NULL) {
14678 +        *minor = ENOMEM;
14679 +        return GSS_S_FAILURE;
14680 +    }
14681 +
14682 +    p = (unsigned char *)outputToken->value;
14683 +    makeTokenHeader(ctx->mechanismUsed, innerToken->length, &p, tokenType);
14684 +    memcpy(p, innerToken->value, innerToken->length);
14685 +
14686 +    *minor = 0;
14687 +    return GSS_S_COMPLETE;
14688 +}
14689 +
14690 +OM_uint32
14691 +gssEapVerifyToken(OM_uint32 *minor,
14692 +                  gss_ctx_id_t ctx,
14693 +                  const gss_buffer_t inputToken,
14694 +                  enum gss_eap_token_type *actualToken,
14695 +                  gss_buffer_t innerInputToken)
14696 +{
14697 +    OM_uint32 major;
14698 +    size_t bodySize;
14699 +    unsigned char *p = (unsigned char *)inputToken->value;
14700 +    gss_OID_desc oidBuf;
14701 +    gss_OID oid;
14702 +
14703 +    if (ctx->mechanismUsed != GSS_C_NO_OID) {
14704 +        oid = ctx->mechanismUsed;
14705 +    } else {
14706 +        oidBuf.elements = NULL;
14707 +        oidBuf.length = 0;
14708 +        oid = &oidBuf;
14709 +    }
14710 +
14711 +    major = verifyTokenHeader(minor, oid, &bodySize, &p,
14712 +                              inputToken->length, actualToken);
14713 +    if (GSS_ERROR(major))
14714 +        return major;
14715 +
14716 +    if (ctx->mechanismUsed == GSS_C_NO_OID) {
14717 +        major = gssEapCanonicalizeOid(minor, oid, 0, &ctx->mechanismUsed);
14718 +        if (GSS_ERROR(major))
14719 +            return major;
14720 +    }
14721 +
14722 +    innerInputToken->length = bodySize;
14723 +    innerInputToken->value = p;
14724 +
14725 +    *minor = 0;
14726 +    return GSS_S_COMPLETE;
14727 +}
14728 +
14729 +OM_uint32
14730 +gssEapContextTime(OM_uint32 *minor,
14731 +                  gss_ctx_id_t context_handle,
14732 +                  OM_uint32 *time_rec)
14733 +{
14734 +    *minor = 0;
14735 +
14736 +    if (context_handle->expiryTime == 0) {
14737 +        *time_rec = GSS_C_INDEFINITE;
14738 +    } else {
14739 +        time_t now, lifetime;
14740 +
14741 +        time(&now);
14742 +        lifetime = context_handle->expiryTime - now;
14743 +        if (lifetime <= 0) {
14744 +            *time_rec = 0;
14745 +            return GSS_S_CONTEXT_EXPIRED;
14746 +        }
14747 +        *time_rec = lifetime;
14748 +    }
14749 +
14750 +    return GSS_S_COMPLETE;
14751 +}
14752 +
14753 +static OM_uint32
14754 +gssEapMakeOrVerifyTokenMIC(OM_uint32 *minor,
14755 +                           gss_ctx_id_t ctx,
14756 +                           gss_buffer_t tokenMIC,
14757 +                           int verifyMIC)
14758 +{
14759 +    OM_uint32 major;
14760 +    gss_iov_buffer_desc *iov = NULL;
14761 +    size_t i = 0, j;
14762 +    enum gss_eap_token_type tokType;
14763 +    OM_uint32 micTokType;
14764 +    unsigned char wireTokType[2];
14765 +    unsigned char *innerTokTypes = NULL, *innerTokLengths = NULL;
14766 +    const struct gss_eap_token_buffer_set *tokens;
14767 +
14768 +    tokens = verifyMIC ? ctx->inputTokens : ctx->outputTokens;
14769 +
14770 +    GSSEAP_ASSERT(tokens != NULL);
14771 +
14772 +    iov = GSSEAP_CALLOC(2 + (3 * tokens->buffers.count) + 1, sizeof(*iov));
14773 +    if (iov == NULL) {
14774 +        major = GSS_S_FAILURE;
14775 +        *minor = ENOMEM;
14776 +        goto cleanup;
14777 +    }
14778 +
14779 +    innerTokTypes = GSSEAP_MALLOC(4 * tokens->buffers.count);
14780 +    if (innerTokTypes == NULL) {
14781 +        *minor = ENOMEM;
14782 +        major = GSS_S_FAILURE;
14783 +        goto cleanup;
14784 +    }
14785 +
14786 +    innerTokLengths = GSSEAP_MALLOC(4 * tokens->buffers.count);
14787 +    if (innerTokLengths == NULL) {
14788 +        major = GSS_S_FAILURE;
14789 +        *minor = ENOMEM;
14790 +        goto cleanup;
14791 +    }
14792 +
14793 +    /* Mechanism OID */
14794 +    GSSEAP_ASSERT(ctx->mechanismUsed != GSS_C_NO_OID);
14795 +    iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
14796 +    iov[i].buffer.length = ctx->mechanismUsed->length;
14797 +    iov[i].buffer.value = ctx->mechanismUsed->elements;
14798 +    i++;
14799 +
14800 +    /* Token type */
14801 +    if (CTX_IS_INITIATOR(ctx) ^ verifyMIC) {
14802 +        tokType = TOK_TYPE_INITIATOR_CONTEXT;
14803 +        micTokType = ITOK_TYPE_INITIATOR_MIC;
14804 +    } else {
14805 +        tokType = TOK_TYPE_ACCEPTOR_CONTEXT;
14806 +        micTokType = ITOK_TYPE_ACCEPTOR_MIC;
14807 +    }
14808 +    store_uint16_be(tokType, wireTokType);
14809 +
14810 +    iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
14811 +    iov[i].buffer.length = sizeof(wireTokType);
14812 +    iov[i].buffer.value = wireTokType;
14813 +    i++;
14814 +
14815 +    for (j = 0; j < tokens->buffers.count; j++) {
14816 +        if (verifyMIC &&
14817 +            (tokens->types[j] & ITOK_TYPE_MASK) == micTokType)
14818 +            continue; /* will use this slot for trailer */
14819 +
14820 +        iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
14821 +        iov[i].buffer.length = 4;
14822 +        iov[i].buffer.value = &innerTokTypes[j * 4];
14823 +        store_uint32_be(tokens->types[j] & ~(ITOK_FLAG_VERIFIED),
14824 +                        iov[i].buffer.value);
14825 +        i++;
14826 +
14827 +        iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
14828 +        iov[i].buffer.length = 4;
14829 +        iov[i].buffer.value = &innerTokLengths[j * 4];
14830 +        store_uint32_be(tokens->buffers.elements[j].length,
14831 +                        iov[i].buffer.value);
14832 +        i++;
14833 +
14834 +        iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
14835 +        iov[i].buffer = tokens->buffers.elements[j];
14836 +        i++;
14837 +    }
14838 +
14839 +    if (verifyMIC) {
14840 +        GSSEAP_ASSERT(tokenMIC->length >= 16);
14841 +
14842 +        GSSEAP_ASSERT(i < 2 + (3 * tokens->buffers.count));
14843 +
14844 +        iov[i].type = GSS_IOV_BUFFER_TYPE_HEADER;
14845 +        iov[i].buffer = *tokenMIC;
14846 +        i++;
14847 +
14848 +        major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
14849 +                                        iov, i, TOK_TYPE_MIC);
14850 +    } else {
14851 +        iov[i++].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
14852 +        major = gssEapWrapOrGetMIC(minor, ctx, FALSE, NULL,
14853 +                                   iov, i, TOK_TYPE_MIC);
14854 +        if (!GSS_ERROR(major))
14855 +            *tokenMIC = iov[i - 1].buffer;
14856 +    }
14857 +
14858 +cleanup:
14859 +    if (iov != NULL)
14860 +        gssEapReleaseIov(iov, tokens->buffers.count);
14861 +    if (innerTokTypes != NULL)
14862 +        GSSEAP_FREE(innerTokTypes);
14863 +    if (innerTokLengths != NULL)
14864 +        GSSEAP_FREE(innerTokLengths);
14865 +
14866 +    return major;
14867 +}
14868 +
14869 +OM_uint32
14870 +gssEapMakeTokenMIC(OM_uint32 *minor,
14871 +                   gss_ctx_id_t ctx,
14872 +                   gss_buffer_t tokenMIC)
14873 +{
14874 +    tokenMIC->length = 0;
14875 +    tokenMIC->value = NULL;
14876 +
14877 +    return gssEapMakeOrVerifyTokenMIC(minor, ctx, tokenMIC, FALSE);
14878 +}
14879 +
14880 +OM_uint32
14881 +gssEapVerifyTokenMIC(OM_uint32 *minor,
14882 +                     gss_ctx_id_t ctx,
14883 +                     const gss_buffer_t tokenMIC)
14884 +{
14885 +    if (tokenMIC->length < 16) {
14886 +        *minor = GSSEAP_TOK_TRUNC;
14887 +        return GSS_S_BAD_SIG;
14888 +    }
14889 +
14890 +    return gssEapMakeOrVerifyTokenMIC(minor, ctx, tokenMIC, TRUE);
14891 +}
14892 diff --git a/mech_eap/util_cred.c b/mech_eap/util_cred.c
14893 new file mode 100644
14894 index 0000000..746bd61
14895 --- /dev/null
14896 +++ b/mech_eap/util_cred.c
14897 @@ -0,0 +1,756 @@
14898 +/*
14899 + * Copyright (c) 2011, JANET(UK)
14900 + * All rights reserved.
14901 + *
14902 + * Redistribution and use in source and binary forms, with or without
14903 + * modification, are permitted provided that the following conditions
14904 + * are met:
14905 + *
14906 + * 1. Redistributions of source code must retain the above copyright
14907 + *    notice, this list of conditions and the following disclaimer.
14908 + *
14909 + * 2. Redistributions in binary form must reproduce the above copyright
14910 + *    notice, this list of conditions and the following disclaimer in the
14911 + *    documentation and/or other materials provided with the distribution.
14912 + *
14913 + * 3. Neither the name of JANET(UK) nor the names of its contributors
14914 + *    may be used to endorse or promote products derived from this software
14915 + *    without specific prior written permission.
14916 + *
14917 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14918 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14919 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14920 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
14921 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14922 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14923 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14924 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14925 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14926 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14927 + * SUCH DAMAGE.
14928 + */
14929 +
14930 +/*
14931 + * Utility routines for credential handles.
14932 + */
14933 +
14934 +#include "gssapiP_eap.h"
14935 +
14936 +#ifdef WIN32
14937 +# include <shlobj.h>     /* may need to use ShFolder.h instead */
14938 +# include <stdio.h>
14939 +#else
14940 +# include <pwd.h>
14941 +#endif
14942 +
14943 +OM_uint32
14944 +gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred)
14945 +{
14946 +    OM_uint32 tmpMinor;
14947 +    gss_cred_id_t cred;
14948 +
14949 +    *pCred = GSS_C_NO_CREDENTIAL;
14950 +
14951 +    cred = (gss_cred_id_t)GSSEAP_CALLOC(1, sizeof(*cred));
14952 +    if (cred == NULL) {
14953 +        *minor = ENOMEM;
14954 +        return GSS_S_FAILURE;
14955 +    }
14956 +
14957 +    if (GSSEAP_MUTEX_INIT(&cred->mutex) != 0) {
14958 +        *minor = GSSEAP_GET_LAST_ERROR();
14959 +        gssEapReleaseCred(&tmpMinor, &cred);
14960 +        return GSS_S_FAILURE;
14961 +    }
14962 +
14963 +    *pCred = cred;
14964 +
14965 +    *minor = 0;
14966 +    return GSS_S_COMPLETE;
14967 +}
14968 +
14969 +static void
14970 +zeroAndReleasePassword(gss_buffer_t password)
14971 +{
14972 +    if (password->value != NULL) {
14973 +        memset(password->value, 0, password->length);
14974 +        GSSEAP_FREE(password->value);
14975 +    }
14976 +
14977 +    password->value = NULL;
14978 +    password->length = 0;
14979 +}
14980 +
14981 +OM_uint32
14982 +gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred)
14983 +{
14984 +    OM_uint32 tmpMinor;
14985 +    gss_cred_id_t cred = *pCred;
14986 +    krb5_context krbContext = NULL;
14987 +
14988 +    if (cred == GSS_C_NO_CREDENTIAL) {
14989 +        return GSS_S_COMPLETE;
14990 +    }
14991 +
14992 +    GSSEAP_KRB_INIT(&krbContext);
14993 +
14994 +    gssEapReleaseName(&tmpMinor, &cred->name);
14995 +    gssEapReleaseName(&tmpMinor, &cred->target);
14996 +
14997 +    zeroAndReleasePassword(&cred->password);
14998 +
14999 +    gss_release_buffer(&tmpMinor, &cred->radiusConfigFile);
15000 +    gss_release_buffer(&tmpMinor, &cred->radiusConfigStanza);
15001 +    gss_release_buffer(&tmpMinor, &cred->caCertificate);
15002 +    gss_release_buffer(&tmpMinor, &cred->subjectNameConstraint);
15003 +    gss_release_buffer(&tmpMinor, &cred->subjectAltNameConstraint);
15004 +
15005 +#ifdef GSSEAP_ENABLE_REAUTH
15006 +    if (cred->krbCredCache != NULL) {
15007 +        if (cred->flags & CRED_FLAG_DEFAULT_CCACHE)
15008 +            krb5_cc_close(krbContext, cred->krbCredCache);
15009 +        else
15010 +            krb5_cc_destroy(krbContext, cred->krbCredCache);
15011 +    }
15012 +    if (cred->reauthCred != GSS_C_NO_CREDENTIAL)
15013 +        gssReleaseCred(&tmpMinor, &cred->reauthCred);
15014 +#endif
15015 +
15016 +    GSSEAP_MUTEX_DESTROY(&cred->mutex);
15017 +    memset(cred, 0, sizeof(*cred));
15018 +    GSSEAP_FREE(cred);
15019 +    *pCred = NULL;
15020 +
15021 +    *minor = 0;
15022 +    return GSS_S_COMPLETE;
15023 +}
15024 +
15025 +static OM_uint32
15026 +readStaticIdentityFile(OM_uint32 *minor,
15027 +                       gss_buffer_t defaultIdentity,
15028 +                       gss_buffer_t defaultPassword)
15029 +{
15030 +    OM_uint32 major, tmpMinor;
15031 +    FILE *fp = NULL;
15032 +    char buf[BUFSIZ];
15033 +    char *ccacheName;
15034 +    int i = 0;
15035 +#ifndef WIN32
15036 +    struct passwd *pw = NULL, pwd;
15037 +    char pwbuf[BUFSIZ];
15038 +#endif
15039 +
15040 +    defaultIdentity->length = 0;
15041 +    defaultIdentity->value = NULL;
15042 +
15043 +    if (defaultPassword != GSS_C_NO_BUFFER) {
15044 +        defaultPassword->length = 0;
15045 +        defaultPassword->value = NULL;
15046 +    }
15047 +
15048 +    ccacheName = getenv("GSSEAP_IDENTITY");
15049 +    if (ccacheName == NULL) {
15050 +#ifdef WIN32
15051 +        TCHAR szPath[MAX_PATH];
15052 +
15053 +        if (!SUCCEEDED(SHGetFolderPath(NULL,
15054 +                                       CSIDL_APPDATA, /* |CSIDL_FLAG_CREATE */
15055 +                                       NULL, /* User access token */
15056 +                                       0,    /* SHGFP_TYPE_CURRENT */
15057 +                                       szPath))) {
15058 +            major = GSS_S_CRED_UNAVAIL;
15059 +            *minor = GSSEAP_GET_LAST_ERROR(); /* XXX */
15060 +            goto cleanup;
15061 +        }
15062 +
15063 +        snprintf(buf, sizeof(buf), "%s/.gss_eap_id", szPath);
15064 +#else
15065 +        if (getpwuid_r(getuid(), &pwd, pwbuf, sizeof(pwbuf), &pw) != 0 ||
15066 +            pw == NULL || pw->pw_dir == NULL) {
15067 +            major = GSS_S_CRED_UNAVAIL;
15068 +            *minor = GSSEAP_GET_LAST_ERROR();
15069 +            goto cleanup;
15070 +        }
15071 +
15072 +        snprintf(buf, sizeof(buf), "%s/.gss_eap_id", pw->pw_dir);
15073 +#endif /* WIN32 */
15074 +        ccacheName = buf;
15075 +    }
15076 +
15077 +    fp = fopen(ccacheName, "r");
15078 +    if (fp == NULL) {
15079 +        major = GSS_S_CRED_UNAVAIL;
15080 +        *minor = GSSEAP_NO_DEFAULT_CRED;
15081 +        goto cleanup;
15082 +    }
15083 +
15084 +    while (fgets(buf, sizeof(buf), fp) != NULL) {
15085 +        gss_buffer_desc src, *dst;
15086 +
15087 +        src.length = strlen(buf);
15088 +        src.value = buf;
15089 +
15090 +        if (src.length == 0)
15091 +            break;
15092 +
15093 +        if (buf[src.length - 1] == '\n') {
15094 +            buf[src.length - 1] = '\0';
15095 +            if (--src.length == 0)
15096 +                break;
15097 +        }
15098 +
15099 +        if (i == 0)
15100 +            dst = defaultIdentity;
15101 +        else if (i == 1)
15102 +            dst = defaultPassword;
15103 +        else
15104 +            break;
15105 +
15106 +        if (dst != GSS_C_NO_BUFFER) {
15107 +            major = duplicateBuffer(minor, &src, dst);
15108 +            if (GSS_ERROR(major))
15109 +                goto cleanup;
15110 +        }
15111 +
15112 +        i++;
15113 +    }
15114 +
15115 +    if (defaultIdentity->length == 0) {
15116 +        major = GSS_S_CRED_UNAVAIL;
15117 +        *minor = GSSEAP_NO_DEFAULT_CRED;
15118 +        goto cleanup;
15119 +    }
15120 +
15121 +    major = GSS_S_COMPLETE;
15122 +    *minor = 0;
15123 +
15124 +cleanup:
15125 +    if (fp != NULL)
15126 +        fclose(fp);
15127 +
15128 +    if (GSS_ERROR(major)) {
15129 +        gss_release_buffer(&tmpMinor, defaultIdentity);
15130 +        zeroAndReleasePassword(defaultPassword);
15131 +    }
15132 +
15133 +    memset(buf, 0, sizeof(buf));
15134 +
15135 +    return major;
15136 +}
15137 +
15138 +gss_OID
15139 +gssEapPrimaryMechForCred(gss_cred_id_t cred)
15140 +{
15141 +    gss_OID nameMech = GSS_C_NO_OID;
15142 +
15143 +    if (cred->mechanisms != GSS_C_NO_OID_SET &&
15144 +        cred->mechanisms->count == 1)
15145 +        nameMech = &cred->mechanisms->elements[0];
15146 +
15147 +    return nameMech;
15148 +}
15149 +
15150 +OM_uint32
15151 +gssEapAcquireCred(OM_uint32 *minor,
15152 +                  const gss_name_t desiredName,
15153 +                  OM_uint32 timeReq GSSEAP_UNUSED,
15154 +                  const gss_OID_set desiredMechs,
15155 +                  int credUsage,
15156 +                  gss_cred_id_t *pCred,
15157 +                  gss_OID_set *pActualMechs,
15158 +                  OM_uint32 *timeRec)
15159 +{
15160 +    OM_uint32 major, tmpMinor;
15161 +    gss_cred_id_t cred;
15162 +
15163 +    /* XXX TODO validate with changed set_cred_option API */
15164 +    *pCred = GSS_C_NO_CREDENTIAL;
15165 +
15166 +    major = gssEapAllocCred(minor, &cred);
15167 +    if (GSS_ERROR(major))
15168 +        goto cleanup;
15169 +
15170 +    switch (credUsage) {
15171 +    case GSS_C_BOTH:
15172 +        cred->flags |= CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT;
15173 +        break;
15174 +    case GSS_C_INITIATE:
15175 +        cred->flags |= CRED_FLAG_INITIATE;
15176 +        break;
15177 +    case GSS_C_ACCEPT:
15178 +        cred->flags |= CRED_FLAG_ACCEPT;
15179 +        break;
15180 +    default:
15181 +        major = GSS_S_FAILURE;
15182 +        *minor = GSSEAP_BAD_USAGE;
15183 +        goto cleanup;
15184 +        break;
15185 +    }
15186 +
15187 +    major = gssEapValidateMechs(minor, desiredMechs);
15188 +    if (GSS_ERROR(major))
15189 +        goto cleanup;
15190 +
15191 +    major = duplicateOidSet(minor, desiredMechs, &cred->mechanisms);
15192 +    if (GSS_ERROR(major))
15193 +        goto cleanup;
15194 +
15195 +    if (desiredName != GSS_C_NO_NAME) {
15196 +        GSSEAP_MUTEX_LOCK(&desiredName->mutex);
15197 +
15198 +        major = gssEapDuplicateName(minor, desiredName, &cred->name);
15199 +        if (GSS_ERROR(major)) {
15200 +            GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
15201 +            goto cleanup;
15202 +        }
15203 +
15204 +        GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
15205 +    }
15206 +
15207 +#ifdef GSSEAP_ENABLE_ACCEPTOR
15208 +    if (cred->flags & CRED_FLAG_ACCEPT) {
15209 +        struct rs_context *radContext;
15210 +
15211 +        major = gssEapCreateRadiusContext(minor, cred, &radContext);
15212 +        if (GSS_ERROR(major))
15213 +            goto cleanup;
15214 +
15215 +        rs_context_destroy(radContext);
15216 +    }
15217 +#endif
15218 +
15219 +    if (pActualMechs != NULL) {
15220 +        major = duplicateOidSet(minor, cred->mechanisms, pActualMechs);
15221 +        if (GSS_ERROR(major))
15222 +            goto cleanup;
15223 +    }
15224 +
15225 +    if (timeRec != NULL)
15226 +        *timeRec = GSS_C_INDEFINITE;
15227 +
15228 +    *pCred = cred;
15229 +
15230 +    major = GSS_S_COMPLETE;
15231 +    *minor = 0;
15232 +
15233 +cleanup:
15234 +    if (GSS_ERROR(major))
15235 +        gssEapReleaseCred(&tmpMinor, &cred);
15236 +
15237 +    return major;
15238 +}
15239 +
15240 +/*
15241 + * Return TRUE if cred available for mechanism. Caller need no acquire
15242 + * lock because mechanisms list is immutable.
15243 + */
15244 +int
15245 +gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech)
15246 +{
15247 +    OM_uint32 minor;
15248 +    int present = 0;
15249 +
15250 +    GSSEAP_ASSERT(mech != GSS_C_NO_OID);
15251 +
15252 +    if (cred == GSS_C_NO_CREDENTIAL || cred->mechanisms == GSS_C_NO_OID_SET)
15253 +        return TRUE;
15254 +
15255 +    gss_test_oid_set_member(&minor, mech, cred->mechanisms, &present);
15256 +
15257 +    return present;
15258 +}
15259 +
15260 +static OM_uint32
15261 +staticIdentityFileResolveDefaultIdentity(OM_uint32 *minor,
15262 +                                         const gss_cred_id_t cred,
15263 +                                         gss_name_t *pName)
15264 +{
15265 +    OM_uint32 major, tmpMinor;
15266 +    gss_OID nameMech = gssEapPrimaryMechForCred(cred);
15267 +    gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
15268 +
15269 +    *pName = GSS_C_NO_NAME;
15270 +
15271 +    major = readStaticIdentityFile(minor, &defaultIdentity, GSS_C_NO_BUFFER);
15272 +    if (major == GSS_S_COMPLETE) {
15273 +        major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
15274 +                                 nameMech, pName);
15275 +    }
15276 +
15277 +    gss_release_buffer(&tmpMinor, &defaultIdentity);
15278 +
15279 +    return major;
15280 +}
15281 +
15282 +static OM_uint32
15283 +gssEapResolveCredIdentity(OM_uint32 *minor,
15284 +                          gss_cred_id_t cred)
15285 +{
15286 +    OM_uint32 major;
15287 +    gss_OID nameMech = gssEapPrimaryMechForCred(cred);
15288 +
15289 +    if (cred->name != GSS_C_NO_NAME) {
15290 +        *minor = 0;
15291 +        return GSS_S_COMPLETE;
15292 +    }
15293 +
15294 +    if (cred->flags & CRED_FLAG_ACCEPT) {
15295 +        gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
15296 +        char serviceName[5 + MAXHOSTNAMELEN];
15297 +
15298 +        /* default host-based service is host@localhost */
15299 +        memcpy(serviceName, "host@", 5);
15300 +        if (gethostname(&serviceName[5], MAXHOSTNAMELEN) != 0) {
15301 +            *minor = GSSEAP_NO_HOSTNAME;
15302 +            return GSS_S_FAILURE;
15303 +        }
15304 +
15305 +        nameBuf.value = serviceName;
15306 +        nameBuf.length = strlen((char *)nameBuf.value);
15307 +
15308 +        major = gssEapImportName(minor, &nameBuf, GSS_C_NT_HOSTBASED_SERVICE,
15309 +                                 nameMech, &cred->name);
15310 +        if (GSS_ERROR(major))
15311 +            return major;
15312 +    } else if (cred->flags & CRED_FLAG_INITIATE) {
15313 +#ifdef HAVE_MOONSHOT_GET_IDENTITY
15314 +        major = libMoonshotResolveDefaultIdentity(minor, cred, &cred->name);
15315 +        if (major == GSS_S_CRED_UNAVAIL)
15316 +#endif
15317 +            major = staticIdentityFileResolveDefaultIdentity(minor, cred, &cred->name);
15318 +        if (major != GSS_S_CRED_UNAVAIL)
15319 +            return major;
15320 +    }
15321 +
15322 +    *minor = 0;
15323 +    return GSS_S_COMPLETE;
15324 +}
15325 +
15326 +OM_uint32
15327 +gssEapInquireCred(OM_uint32 *minor,
15328 +                  gss_cred_id_t cred,
15329 +                  gss_name_t *name,
15330 +                  OM_uint32 *pLifetime,
15331 +                  gss_cred_usage_t *cred_usage,
15332 +                  gss_OID_set *mechanisms)
15333 +{
15334 +    OM_uint32 major;
15335 +    time_t now, lifetime;
15336 +
15337 +    if (name != NULL) {
15338 +        major = gssEapResolveCredIdentity(minor, cred);
15339 +        if (GSS_ERROR(major))
15340 +            goto cleanup;
15341 +
15342 +        if (cred->name != GSS_C_NO_NAME) {
15343 +            major = gssEapDuplicateName(minor, cred->name, name);
15344 +            if (GSS_ERROR(major))
15345 +                goto cleanup;
15346 +        } else
15347 +            *name = GSS_C_NO_NAME;
15348 +    }
15349 +
15350 +    if (cred_usage != NULL) {
15351 +        OM_uint32 flags = (cred->flags & (CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT));
15352 +
15353 +        switch (flags) {
15354 +        case CRED_FLAG_INITIATE:
15355 +            *cred_usage = GSS_C_INITIATE;
15356 +            break;
15357 +        case CRED_FLAG_ACCEPT:
15358 +            *cred_usage = GSS_C_ACCEPT;
15359 +            break;
15360 +        default:
15361 +            *cred_usage = GSS_C_BOTH;
15362 +            break;
15363 +        }
15364 +    }
15365 +
15366 +    if (mechanisms != NULL) {
15367 +        if (cred->mechanisms != GSS_C_NO_OID_SET)
15368 +            major = duplicateOidSet(minor, cred->mechanisms, mechanisms);
15369 +        else
15370 +            major = gssEapIndicateMechs(minor, mechanisms);
15371 +        if (GSS_ERROR(major))
15372 +            goto cleanup;
15373 +    }
15374 +
15375 +    if (cred->expiryTime == 0) {
15376 +        lifetime = GSS_C_INDEFINITE;
15377 +    } else  {
15378 +        now = time(NULL);
15379 +        lifetime = now - cred->expiryTime;
15380 +        if (lifetime < 0)
15381 +            lifetime = 0;
15382 +    }
15383 +
15384 +    if (pLifetime != NULL) {
15385 +        *pLifetime = lifetime;
15386 +    }
15387 +
15388 +    if (lifetime == 0) {
15389 +        major = GSS_S_CREDENTIALS_EXPIRED;
15390 +        *minor = GSSEAP_CRED_EXPIRED;
15391 +        goto cleanup;
15392 +    }
15393 +
15394 +    major = GSS_S_COMPLETE;
15395 +    *minor = 0;
15396 +
15397 +cleanup:
15398 +    return major;
15399 +}
15400 +
15401 +OM_uint32
15402 +gssEapSetCredPassword(OM_uint32 *minor,
15403 +                      gss_cred_id_t cred,
15404 +                      const gss_buffer_t password)
15405 +{
15406 +    OM_uint32 major, tmpMinor;
15407 +    gss_buffer_desc newPassword = GSS_C_EMPTY_BUFFER;
15408 +
15409 +    if (cred->flags & CRED_FLAG_RESOLVED) {
15410 +        major = GSS_S_FAILURE;
15411 +        *minor = GSSEAP_CRED_RESOLVED;
15412 +        goto cleanup;
15413 +    }
15414 +
15415 +    if (password != GSS_C_NO_BUFFER) {
15416 +        major = duplicateBuffer(minor, password, &newPassword);
15417 +        if (GSS_ERROR(major))
15418 +            goto cleanup;
15419 +
15420 +        cred->flags |= CRED_FLAG_PASSWORD;
15421 +    } else {
15422 +        cred->flags &= ~(CRED_FLAG_PASSWORD);
15423 +    }
15424 +
15425 +    gss_release_buffer(&tmpMinor, &cred->password);
15426 +    cred->password = newPassword;
15427 +
15428 +    major = GSS_S_COMPLETE;
15429 +    *minor = 0;
15430 +
15431 +cleanup:
15432 +    return major;
15433 +}
15434 +
15435 +OM_uint32
15436 +gssEapSetCredService(OM_uint32 *minor,
15437 +                     gss_cred_id_t cred,
15438 +                     const gss_name_t target)
15439 +{
15440 +    OM_uint32 major, tmpMinor;
15441 +    gss_name_t newTarget = GSS_C_NO_NAME;
15442 +
15443 +    if (cred->flags & CRED_FLAG_RESOLVED) {
15444 +        major = GSS_S_FAILURE;
15445 +        *minor = GSSEAP_CRED_RESOLVED;
15446 +        goto cleanup;
15447 +    }
15448 +
15449 +    if (target != GSS_C_NO_NAME) {
15450 +        major = gssEapDuplicateName(minor, target, &newTarget);
15451 +        if (GSS_ERROR(major))
15452 +            goto cleanup;
15453 +
15454 +        cred->flags |= CRED_FLAG_TARGET;
15455 +    } else {
15456 +        cred->flags &= ~(CRED_FLAG_TARGET);
15457 +    }
15458 +
15459 +    gssEapReleaseName(&tmpMinor, &cred->target);
15460 +    cred->target = newTarget;
15461 +
15462 +    major = GSS_S_COMPLETE;
15463 +    *minor = 0;
15464 +
15465 +cleanup:
15466 +    return major;
15467 +}
15468 +
15469 +static OM_uint32
15470 +gssEapDuplicateCred(OM_uint32 *minor,
15471 +                    const gss_cred_id_t src,
15472 +                    gss_cred_id_t *pDst)
15473 +{
15474 +    OM_uint32 major, tmpMinor;
15475 +    gss_cred_id_t dst = GSS_C_NO_CREDENTIAL;
15476 +
15477 +    *pDst = GSS_C_NO_CREDENTIAL;
15478 +
15479 +    major = gssEapAllocCred(minor, &dst);
15480 +    if (GSS_ERROR(major))
15481 +        goto cleanup;
15482 +
15483 +    dst->flags = src->flags;
15484 +
15485 +    if (src->name != GSS_C_NO_NAME) {
15486 +        major = gssEapDuplicateName(minor, src->name, &dst->name);
15487 +        if (GSS_ERROR(major))
15488 +            goto cleanup;
15489 +    }
15490 +
15491 +    if (src->target != GSS_C_NO_NAME) {
15492 +        major = gssEapDuplicateName(minor, src->target, &dst->target);
15493 +        if (GSS_ERROR(major))
15494 +            goto cleanup;
15495 +    }
15496 +
15497 +    if (src->password.value != NULL) {
15498 +        major = duplicateBuffer(minor, &src->password, &dst->password);
15499 +        if (GSS_ERROR(major))
15500 +            goto cleanup;
15501 +    }
15502 +
15503 +    major = duplicateOidSet(minor, src->mechanisms, &dst->mechanisms);
15504 +    if (GSS_ERROR(major))
15505 +        goto cleanup;
15506 +
15507 +    dst->expiryTime = src->expiryTime;
15508 +
15509 +    if (src->radiusConfigFile.value != NULL)
15510 +        duplicateBufferOrCleanup(&src->radiusConfigFile, &dst->radiusConfigFile);
15511 +    if (src->radiusConfigStanza.value != NULL)
15512 +        duplicateBufferOrCleanup(&src->radiusConfigStanza, &dst->radiusConfigStanza);
15513 +    if (src->caCertificate.value != NULL)
15514 +        duplicateBufferOrCleanup(&src->caCertificate, &dst->caCertificate);
15515 +    if (src->subjectNameConstraint.value != NULL)
15516 +        duplicateBufferOrCleanup(&src->subjectNameConstraint, &dst->subjectNameConstraint);
15517 +    if (src->subjectAltNameConstraint.value != NULL)
15518 +        duplicateBufferOrCleanup(&src->subjectAltNameConstraint, &dst->subjectAltNameConstraint);
15519 +
15520 +#ifdef GSSEAP_ENABLE_REAUTH
15521 +    /* XXX krbCredCache, reauthCred */
15522 +#endif
15523 +
15524 +    *pDst = dst;
15525 +    dst = GSS_C_NO_CREDENTIAL;
15526 +
15527 +    major = GSS_S_COMPLETE;
15528 +    *minor = 0;
15529 +
15530 +cleanup:
15531 +    gssEapReleaseCred(&tmpMinor, &dst);
15532 +
15533 +    return major;
15534 +}
15535 +
15536 +static OM_uint32
15537 +staticIdentityFileResolveInitiatorCred(OM_uint32 *minor, gss_cred_id_t cred)
15538 +{
15539 +    OM_uint32 major, tmpMinor;
15540 +    gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
15541 +    gss_name_t defaultIdentityName = GSS_C_NO_NAME;
15542 +    gss_buffer_desc defaultPassword = GSS_C_EMPTY_BUFFER;
15543 +    int isDefaultIdentity = FALSE;
15544 +
15545 +    major = readStaticIdentityFile(minor, &defaultIdentity, &defaultPassword);
15546 +    if (GSS_ERROR(major))
15547 +        goto cleanup;
15548 +
15549 +    major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
15550 +                             gssEapPrimaryMechForCred(cred), &defaultIdentityName);
15551 +    if (GSS_ERROR(major))
15552 +        goto cleanup;
15553 +
15554 +    if (defaultIdentityName == GSS_C_NO_NAME) {
15555 +        if (cred->name == GSS_C_NO_NAME) {
15556 +            major = GSS_S_CRED_UNAVAIL;
15557 +            *minor = GSSEAP_NO_DEFAULT_IDENTITY;
15558 +            goto cleanup;
15559 +        }
15560 +    } else {
15561 +        if (cred->name == GSS_C_NO_NAME) {
15562 +            cred->name = defaultIdentityName;
15563 +            defaultIdentityName = GSS_C_NO_NAME;
15564 +            isDefaultIdentity = TRUE;
15565 +        } else {
15566 +            major = gssEapCompareName(minor, cred->name,
15567 +                                      defaultIdentityName, &isDefaultIdentity);
15568 +            if (GSS_ERROR(major))
15569 +                goto cleanup;
15570 +        }
15571 +    }
15572 +
15573 +    if (isDefaultIdentity &&
15574 +        (cred->flags & CRED_FLAG_PASSWORD) == 0) {
15575 +        major = gssEapSetCredPassword(minor, cred, &defaultPassword);
15576 +        if (GSS_ERROR(major))
15577 +            goto cleanup;
15578 +    }
15579 +
15580 +cleanup:
15581 +    gssEapReleaseName(&tmpMinor, &defaultIdentityName);
15582 +    zeroAndReleasePassword(&defaultPassword);
15583 +    gss_release_buffer(&tmpMinor, &defaultIdentity);
15584 +
15585 +    return major;
15586 +}
15587 +
15588 +OM_uint32
15589 +gssEapResolveInitiatorCred(OM_uint32 *minor,
15590 +                           const gss_cred_id_t cred,
15591 +                           const gss_name_t targetName
15592 +#ifndef HAVE_MOONSHOT_GET_IDENTITY
15593 +                                                       GSSEAP_UNUSED
15594 +#endif
15595 +                           ,
15596 +                           gss_cred_id_t *pResolvedCred)
15597 +{
15598 +    OM_uint32 major, tmpMinor;
15599 +    gss_cred_id_t resolvedCred = GSS_C_NO_CREDENTIAL;
15600 +
15601 +    if (cred == GSS_C_NO_CREDENTIAL) {
15602 +        major = gssEapAcquireCred(minor,
15603 +                                  GSS_C_NO_NAME,
15604 +                                  GSS_C_INDEFINITE,
15605 +                                  GSS_C_NO_OID_SET,
15606 +                                  GSS_C_INITIATE,
15607 +                                  &resolvedCred,
15608 +                                  NULL,
15609 +                                  NULL);
15610 +        if (GSS_ERROR(major))
15611 +            goto cleanup;
15612 +    } else {
15613 +        if ((cred->flags & CRED_FLAG_INITIATE) == 0) {
15614 +            major = GSS_S_NO_CRED;
15615 +            *minor = GSSEAP_CRED_USAGE_MISMATCH;
15616 +            goto cleanup;
15617 +        }
15618 +
15619 +        major = gssEapDuplicateCred(minor, cred, &resolvedCred);
15620 +        if (GSS_ERROR(major))
15621 +            goto cleanup;
15622 +    }
15623 +
15624 +    if ((resolvedCred->flags & CRED_FLAG_RESOLVED) == 0) {
15625 +#ifdef HAVE_MOONSHOT_GET_IDENTITY
15626 +        major = libMoonshotResolveInitiatorCred(minor, resolvedCred, targetName);
15627 +        if (major == GSS_S_CRED_UNAVAIL)
15628 +#endif
15629 +            major = staticIdentityFileResolveInitiatorCred(minor, resolvedCred);
15630 +        if (GSS_ERROR(major) && major != GSS_S_CRED_UNAVAIL)
15631 +            goto cleanup;
15632 +
15633 +        /* If we have a caller-supplied password, the credential is resolved. */
15634 +        if ((resolvedCred->flags & CRED_FLAG_PASSWORD) == 0) {
15635 +            major = GSS_S_CRED_UNAVAIL;
15636 +            *minor = GSSEAP_NO_DEFAULT_CRED;
15637 +            goto cleanup;
15638 +        }
15639 +
15640 +        resolvedCred->flags |= CRED_FLAG_RESOLVED;
15641 +    }
15642 +
15643 +    *pResolvedCred = resolvedCred;
15644 +    resolvedCred = GSS_C_NO_CREDENTIAL;
15645 +
15646 +    major = GSS_S_COMPLETE;
15647 +    *minor = 0;
15648 +
15649 +cleanup:
15650 +    gssEapReleaseCred(&tmpMinor, &resolvedCred);
15651 +
15652 +    return major;
15653 +}
15654 diff --git a/mech_eap/util_crypt.c b/mech_eap/util_crypt.c
15655 new file mode 100644
15656 index 0000000..b6e203e
15657 --- /dev/null
15658 +++ b/mech_eap/util_crypt.c
15659 @@ -0,0 +1,397 @@
15660 +/*
15661 + * Copyright (c) 2011, JANET(UK)
15662 + * All rights reserved.
15663 + *
15664 + * Redistribution and use in source and binary forms, with or without
15665 + * modification, are permitted provided that the following conditions
15666 + * are met:
15667 + *
15668 + * 1. Redistributions of source code must retain the above copyright
15669 + *    notice, this list of conditions and the following disclaimer.
15670 + *
15671 + * 2. Redistributions in binary form must reproduce the above copyright
15672 + *    notice, this list of conditions and the following disclaimer in the
15673 + *    documentation and/or other materials provided with the distribution.
15674 + *
15675 + * 3. Neither the name of JANET(UK) nor the names of its contributors
15676 + *    may be used to endorse or promote products derived from this software
15677 + *    without specific prior written permission.
15678 + *
15679 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15680 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15681 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15682 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
15683 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
15684 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
15685 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
15686 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
15687 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
15688 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
15689 + * SUCH DAMAGE.
15690 + */
15691 +/*
15692 + * Copyright 2001, 2008 by the Massachusetts Institute of Technology.
15693 + * Copyright 1993 by OpenVision Technologies, Inc.
15694 + *
15695 + * Permission to use, copy, modify, distribute, and sell this software
15696 + * and its documentation for any purpose is hereby granted without fee,
15697 + * provided that the above copyright notice appears in all copies and
15698 + * that both that copyright notice and this permission notice appear in
15699 + * supporting documentation, and that the name of OpenVision not be used
15700 + * in advertising or publicity pertaining to distribution of the software
15701 + * without specific, written prior permission. OpenVision makes no
15702 + * representations about the suitability of this software for any
15703 + * purpose.  It is provided "as is" without express or implied warranty.
15704 + *
15705 + * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15706 + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
15707 + * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
15708 + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
15709 + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
15710 + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15711 + * PERFORMANCE OF THIS SOFTWARE.
15712 + */
15713 +/*
15714 + * Copyright (C) 1998 by the FundsXpress, INC.
15715 + *
15716 + * All rights reserved.
15717 + *
15718 + * Export of this software from the United States of America may require
15719 + * a specific license from the United States Government.  It is the
15720 + * responsibility of any person or organization contemplating export to
15721 + * obtain such a license before exporting.
15722 + *
15723 + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
15724 + * distribute this software and its documentation for any purpose and
15725 + * without fee is hereby granted, provided that the above copyright
15726 + * notice appear in all copies and that both that copyright notice and
15727 + * this permission notice appear in supporting documentation, and that
15728 + * the name of FundsXpress. not be used in advertising or publicity pertaining
15729 + * to distribution of the software without specific, written prior
15730 + * permission.  FundsXpress makes no representations about the suitability of
15731 + * this software for any purpose.  It is provided "as is" without express
15732 + * or implied warranty.
15733 + *
15734 + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15735 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15736 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
15737 + */
15738 +
15739 +/*
15740 + * Message protection services: cryptography helpers.
15741 + */
15742 +
15743 +#include "gssapiP_eap.h"
15744 +
15745 +/*
15746 + * DCE_STYLE indicates actual RRC is EC + RRC
15747 + * EC is extra rotate count for DCE_STYLE, pad length otherwise
15748 + * RRC is rotate count.
15749 + */
15750 +static krb5_error_code
15751 +mapIov(krb5_context context, int dce_style, size_t ec, size_t rrc,
15752 +#ifdef HAVE_HEIMDAL_VERSION
15753 +       krb5_crypto crypto,
15754 +#else
15755 +       krb5_keyblock *crypto,
15756 +#endif
15757 +       gss_iov_buffer_desc *iov,
15758 +       int iov_count, krb5_crypto_iov **pkiov,
15759 +       size_t *pkiov_count)
15760 +{
15761 +    gss_iov_buffer_t header;
15762 +    gss_iov_buffer_t trailer;
15763 +    int i = 0, j;
15764 +    size_t kiov_count;
15765 +    krb5_crypto_iov *kiov;
15766 +    size_t k5_headerlen = 0, k5_trailerlen = 0;
15767 +    size_t gss_headerlen, gss_trailerlen;
15768 +    krb5_error_code code;
15769 +
15770 +    *pkiov = NULL;
15771 +    *pkiov_count = 0;
15772 +
15773 +    header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
15774 +    GSSEAP_ASSERT(header != NULL);
15775 +
15776 +    trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
15777 +    GSSEAP_ASSERT(trailer == NULL || rrc == 0);
15778 +
15779 +    code = krbCryptoLength(context, crypto, KRB5_CRYPTO_TYPE_HEADER, &k5_headerlen);
15780 +    if (code != 0)
15781 +        return code;
15782 +
15783 +    code = krbCryptoLength(context, crypto, KRB5_CRYPTO_TYPE_TRAILER, &k5_trailerlen);
15784 +    if (code != 0)
15785 +        return code;
15786 +
15787 +    /* Check header and trailer sizes */
15788 +    gss_headerlen = 16 /* GSS-Header */ + k5_headerlen; /* Kerb-Header */
15789 +    gss_trailerlen = ec + 16 /* E(GSS-Header) */ + k5_trailerlen; /* Kerb-Trailer */
15790 +
15791 +    /* If we're caller without a trailer, we must rotate by trailer length */
15792 +    if (trailer == NULL) {
15793 +        size_t actual_rrc = rrc;
15794 +
15795 +        if (dce_style)
15796 +            actual_rrc += ec; /* compensate for Windows bug */
15797 +
15798 +        if (actual_rrc != gss_trailerlen)
15799 +            return KRB5_BAD_MSIZE;
15800 +
15801 +        gss_headerlen += gss_trailerlen;
15802 +        gss_trailerlen = 0;
15803 +    } else {
15804 +        if (trailer->buffer.length != gss_trailerlen)
15805 +            return KRB5_BAD_MSIZE;
15806 +    }
15807 +
15808 +    if (header->buffer.length != gss_headerlen)
15809 +        return KRB5_BAD_MSIZE;
15810 +
15811 +    kiov_count = 3 + iov_count;
15812 +    kiov = (krb5_crypto_iov *)GSSEAP_MALLOC(kiov_count * sizeof(krb5_crypto_iov));
15813 +    if (kiov == NULL)
15814 +        return ENOMEM;
15815 +
15816 +    /*
15817 +     * The krb5 header is located at the end of the GSS header.
15818 +     */
15819 +    kiov[i].flags = KRB5_CRYPTO_TYPE_HEADER;
15820 +    kiov[i].data.length = k5_headerlen;
15821 +    kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - k5_headerlen;
15822 +    i++;
15823 +
15824 +    for (j = 0; j < iov_count; j++) {
15825 +        kiov[i].flags = gssEapMapCryptoFlag(iov[j].type);
15826 +        if (kiov[i].flags == KRB5_CRYPTO_TYPE_EMPTY)
15827 +            continue;
15828 +
15829 +        kiov[i].data.length = iov[j].buffer.length;
15830 +        kiov[i].data.data = (char *)iov[j].buffer.value;
15831 +        i++;
15832 +    }
15833 +
15834 +    /*
15835 +     * The EC and encrypted GSS header are placed in the trailer, which may
15836 +     * be rotated directly after the plaintext header if no trailer buffer
15837 +     * is provided.
15838 +     */
15839 +    kiov[i].flags = KRB5_CRYPTO_TYPE_DATA;
15840 +    kiov[i].data.length = ec + 16; /* E(Header) */
15841 +    if (trailer == NULL)
15842 +        kiov[i].data.data = (char *)header->buffer.value + 16;
15843 +    else
15844 +        kiov[i].data.data = (char *)trailer->buffer.value;
15845 +    i++;
15846 +
15847 +    /*
15848 +     * The krb5 trailer is placed after the encrypted copy of the
15849 +     * krb5 header (which may be in the GSS header or trailer).
15850 +     */
15851 +    kiov[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
15852 +    kiov[i].data.length = k5_trailerlen;
15853 +    kiov[i].data.data = (char *)kiov[i - 1].data.data + ec + 16; /* E(Header) */
15854 +    i++;
15855 +
15856 +    *pkiov = kiov;
15857 +    *pkiov_count = i;
15858 +
15859 +    return 0;
15860 +}
15861 +
15862 +int
15863 +gssEapEncrypt(krb5_context context,
15864 +              int dce_style,
15865 +              size_t ec,
15866 +              size_t rrc,
15867 +#ifdef HAVE_HEIMDAL_VERSION
15868 +              krb5_crypto crypto,
15869 +#else
15870 +              krb5_keyblock *crypto,
15871 +#endif
15872 +              int usage,
15873 +              gss_iov_buffer_desc *iov,
15874 +              int iov_count)
15875 +{
15876 +    krb5_error_code code;
15877 +    size_t kiov_count;
15878 +    krb5_crypto_iov *kiov = NULL;
15879 +
15880 +    code = mapIov(context, dce_style, ec, rrc, crypto,
15881 +                  iov, iov_count, &kiov, &kiov_count);
15882 +    if (code != 0)
15883 +        goto cleanup;
15884 +
15885 +#ifdef HAVE_HEIMDAL_VERSION
15886 +    code = krb5_encrypt_iov_ivec(context, crypto, usage, kiov, kiov_count, NULL);
15887 +#else
15888 +    code = krb5_c_encrypt_iov(context, crypto, usage, NULL, kiov, kiov_count);
15889 +#endif
15890 +    if (code != 0)
15891 +        goto cleanup;
15892 +
15893 +cleanup:
15894 +    if (kiov != NULL)
15895 +        GSSEAP_FREE(kiov);
15896 +
15897 +    return code;
15898 +}
15899 +
15900 +int
15901 +gssEapDecrypt(krb5_context context,
15902 +              int dce_style,
15903 +              size_t ec,
15904 +              size_t rrc,
15905 +#ifdef HAVE_HEIMDAL_VERSION
15906 +              krb5_crypto crypto,
15907 +#else
15908 +              krb5_keyblock *crypto,
15909 +#endif
15910 +              int usage,
15911 +              gss_iov_buffer_desc *iov,
15912 +              int iov_count)
15913 +{
15914 +    krb5_error_code code;
15915 +    size_t kiov_count;
15916 +    krb5_crypto_iov *kiov;
15917 +
15918 +    code = mapIov(context, dce_style, ec, rrc, crypto,
15919 +                  iov, iov_count, &kiov, &kiov_count);
15920 +    if (code != 0)
15921 +        goto cleanup;
15922 +
15923 +#ifdef HAVE_HEIMDAL_VERSION
15924 +    code = krb5_decrypt_iov_ivec(context, crypto, usage, kiov, kiov_count, NULL);
15925 +#else
15926 +    code = krb5_c_decrypt_iov(context, crypto, usage, NULL, kiov, kiov_count);
15927 +#endif
15928 +
15929 +cleanup:
15930 +    if (kiov != NULL)
15931 +        GSSEAP_FREE(kiov);
15932 +
15933 +    return code;
15934 +}
15935 +
15936 +int
15937 +gssEapMapCryptoFlag(OM_uint32 type)
15938 +{
15939 +    int ktype;
15940 +
15941 +    switch (GSS_IOV_BUFFER_TYPE(type)) {
15942 +    case GSS_IOV_BUFFER_TYPE_DATA:
15943 +    case GSS_IOV_BUFFER_TYPE_PADDING:
15944 +        ktype = KRB5_CRYPTO_TYPE_DATA;
15945 +        break;
15946 +    case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
15947 +        ktype = KRB5_CRYPTO_TYPE_SIGN_ONLY;
15948 +        break;
15949 +    default:
15950 +        ktype = KRB5_CRYPTO_TYPE_EMPTY;
15951 +        break;
15952 +    }
15953 +
15954 +    return ktype;
15955 +}
15956 +
15957 +gss_iov_buffer_t
15958 +gssEapLocateIov(gss_iov_buffer_desc *iov, int iov_count, OM_uint32 type)
15959 +{
15960 +    int i;
15961 +    gss_iov_buffer_t p = GSS_C_NO_IOV_BUFFER;
15962 +
15963 +    if (iov == GSS_C_NO_IOV_BUFFER)
15964 +        return GSS_C_NO_IOV_BUFFER;
15965 +
15966 +    for (i = iov_count - 1; i >= 0; i--) {
15967 +        if (GSS_IOV_BUFFER_TYPE(iov[i].type) == type) {
15968 +            if (p == GSS_C_NO_IOV_BUFFER)
15969 +                p = &iov[i];
15970 +            else
15971 +                return GSS_C_NO_IOV_BUFFER;
15972 +        }
15973 +    }
15974 +
15975 +    return p;
15976 +}
15977 +
15978 +void
15979 +gssEapIovMessageLength(gss_iov_buffer_desc *iov,
15980 +                       int iov_count,
15981 +                       size_t *data_length_p,
15982 +                       size_t *assoc_data_length_p)
15983 +{
15984 +    int i;
15985 +    size_t data_length = 0, assoc_data_length = 0;
15986 +
15987 +    GSSEAP_ASSERT(iov != GSS_C_NO_IOV_BUFFER);
15988 +
15989 +    *data_length_p = *assoc_data_length_p = 0;
15990 +
15991 +    for (i = 0; i < iov_count; i++) {
15992 +        OM_uint32 type = GSS_IOV_BUFFER_TYPE(iov[i].type);
15993 +
15994 +        if (type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
15995 +            assoc_data_length += iov[i].buffer.length;
15996 +
15997 +        if (type == GSS_IOV_BUFFER_TYPE_DATA ||
15998 +            type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
15999 +            data_length += iov[i].buffer.length;
16000 +    }
16001 +
16002 +    *data_length_p = data_length;
16003 +    *assoc_data_length_p = assoc_data_length;
16004 +}
16005 +
16006 +void
16007 +gssEapReleaseIov(gss_iov_buffer_desc *iov, int iov_count)
16008 +{
16009 +    int i;
16010 +    OM_uint32 min_stat;
16011 +
16012 +    GSSEAP_ASSERT(iov != GSS_C_NO_IOV_BUFFER);
16013 +
16014 +    for (i = 0; i < iov_count; i++) {
16015 +        if (iov[i].type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {
16016 +            gss_release_buffer(&min_stat, &iov[i].buffer);
16017 +            iov[i].type &= ~(GSS_IOV_BUFFER_FLAG_ALLOCATED);
16018 +        }
16019 +    }
16020 +}
16021 +
16022 +int
16023 +gssEapIsIntegrityOnly(gss_iov_buffer_desc *iov, int iov_count)
16024 +{
16025 +    int i;
16026 +    krb5_boolean has_conf_data = FALSE;
16027 +
16028 +    GSSEAP_ASSERT(iov != GSS_C_NO_IOV_BUFFER);
16029 +
16030 +    for (i = 0; i < iov_count; i++) {
16031 +        if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA) {
16032 +            has_conf_data = TRUE;
16033 +            break;
16034 +        }
16035 +    }
16036 +
16037 +    return (has_conf_data == FALSE);
16038 +}
16039 +
16040 +int
16041 +gssEapAllocIov(gss_iov_buffer_t iov, size_t size)
16042 +{
16043 +    GSSEAP_ASSERT(iov != GSS_C_NO_IOV_BUFFER);
16044 +    GSSEAP_ASSERT(iov->type & GSS_IOV_BUFFER_FLAG_ALLOCATE);
16045 +
16046 +    iov->buffer.length = size;
16047 +    iov->buffer.value = GSSEAP_MALLOC(size);
16048 +    if (iov->buffer.value == NULL) {
16049 +        iov->buffer.length = 0;
16050 +        return ENOMEM;
16051 +    }
16052 +
16053 +    iov->type |= GSS_IOV_BUFFER_FLAG_ALLOCATED;
16054 +
16055 +    return 0;
16056 +}
16057 diff --git a/mech_eap/util_json.cpp b/mech_eap/util_json.cpp
16058 new file mode 100644
16059 index 0000000..97eb1ed
16060 --- /dev/null
16061 +++ b/mech_eap/util_json.cpp
16062 @@ -0,0 +1,513 @@
16063 +/*
16064 + * Copyright (c) 2011, JANET(UK)
16065 + * All rights reserved.
16066 + *
16067 + * Redistribution and use in source and binary forms, with or without
16068 + * modification, are permitted provided that the following conditions
16069 + * are met:
16070 + *
16071 + * 1. Redistributions of source code must retain the above copyright
16072 + *    notice, this list of conditions and the following disclaimer.
16073 + *
16074 + * 2. Redistributions in binary form must reproduce the above copyright
16075 + *    notice, this list of conditions and the following disclaimer in the
16076 + *    documentation and/or other materials provided with the distribution.
16077 + *
16078 + * 3. Neither the name of JANET(UK) nor the names of its contributors
16079 + *    may be used to endorse or promote products derived from this software
16080 + *    without specific prior written permission.
16081 + *
16082 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16083 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16084 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16085 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
16086 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
16087 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
16088 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
16089 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16090 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16091 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
16092 + * SUCH DAMAGE.
16093 + */
16094 +
16095 +/*
16096 + * JSONObject utilities.
16097 + */
16098 +
16099 +#include "gssapiP_eap.h"
16100 +
16101 +#include <typeinfo>
16102 +#include <string>
16103 +#include <sstream>
16104 +#include <exception>
16105 +#include <new>
16106 +
16107 +#define JSON_INIT(obj) do {                                     \
16108 +        if ((obj) == NULL)                                      \
16109 +            throw std::bad_alloc();                             \
16110 +        m_obj = (obj);                                          \
16111 +    } while (0)
16112 +
16113 +#define JSON_CHECK_CONTAINER() do {                             \
16114 +        if (!json_is_object(m_obj) && !json_is_array(m_obj)) {  \
16115 +            std::string s("JSONObject is not a container");     \
16116 +            throw JSONException(m_obj);                         \
16117 +        }                                                       \
16118 +    } while (0)
16119 +
16120 +#define JSON_CHECK_OBJECT() do {                                \
16121 +        if (!json_is_object(m_obj)) {                           \
16122 +            std::string s("JSONObject is not a dictionary");    \
16123 +            throw JSONException(m_obj, JSON_OBJECT);            \
16124 +        }                                                       \
16125 +    } while (0)
16126 +
16127 +#define JSON_CHECK_ARRAY() do {                                 \
16128 +        if (!json_is_array(m_obj)) {                            \
16129 +            throw JSONException(m_obj, JSON_ARRAY);             \
16130 +        }                                                       \
16131 +    } while (0)
16132 +
16133 +#define JSON_CHECK(s) do {                                      \
16134 +        if ((s) != 0)                                           \
16135 +            throw JSONException();                              \
16136 +    } while (0)
16137 +
16138 +JSONObject
16139 +JSONObject::load(const char *input, size_t flags, json_error_t *error)
16140 +{
16141 +    json_t *obj;
16142 +
16143 +    obj = json_loads(input, flags, error);
16144 +
16145 +    return JSONObject(obj, false);
16146 +}
16147 +
16148 +JSONObject
16149 +JSONObject::load(FILE *fp, size_t flags, json_error_t *error)
16150 +{
16151 +    json_t *obj;
16152 +
16153 +    obj = json_loadf(fp, flags, error);
16154 +
16155 +    return JSONObject(obj, false);
16156 +}
16157 +
16158 +char *
16159 +JSONObject::dump(size_t flags) const
16160 +{
16161 +    char *s = json_dumps(m_obj, flags);
16162 +
16163 +    if (s == NULL)
16164 +        throw std::bad_alloc();
16165 +
16166 +    return s;
16167 +}
16168 +
16169 +void
16170 +JSONObject::dump(FILE *fp, size_t flags) const
16171 +{
16172 +    int r = json_dumpf(m_obj, fp, flags);
16173 +
16174 +    if (r != 0)
16175 +        throw std::bad_alloc();
16176 +}
16177 +
16178 +size_t
16179 +JSONObject::size(void) const
16180 +{
16181 +    if (json_is_object(m_obj))
16182 +        return json_object_size(m_obj);
16183 +    else if (json_is_array(m_obj))
16184 +        return json_array_size(m_obj);
16185 +    else
16186 +        return 0;
16187 +}
16188 +
16189 +JSONObject::JSONObject(json_t *obj, bool retain)
16190 +{
16191 +    if (retain)
16192 +        json_incref(obj);
16193 +    JSON_INIT(obj);
16194 +}
16195 +
16196 +JSONObject::JSONObject(const char *value)
16197 +{
16198 +    json_t *obj = json_string(value);
16199 +
16200 +    JSON_INIT(obj);
16201 +}
16202 +
16203 +JSONObject::JSONObject(json_int_t value)
16204 +{
16205 +    json_t *obj = json_integer(value);
16206 +
16207 +    JSON_INIT(obj);
16208 +}
16209 +
16210 +JSONObject::JSONObject(double value)
16211 +{
16212 +    json_t *obj = json_real(value);
16213 +
16214 +    JSON_INIT(obj);
16215 +}
16216 +
16217 +JSONObject::JSONObject(bool value)
16218 +{
16219 +    json_t *obj = value ? json_true() : json_false();
16220 +
16221 +    JSON_INIT(obj);
16222 +}
16223 +
16224 +JSONObject::JSONObject(void)
16225 +{
16226 +    json_t *obj = json_object();
16227 +
16228 +    JSON_INIT(obj);
16229 +}
16230 +
16231 +JSONObject
16232 +JSONObject::object(void)
16233 +{
16234 +    return JSONObject();
16235 +}
16236 +
16237 +JSONObject
16238 +JSONObject::null(void)
16239 +{
16240 +    return JSONObject(json_null(), false);
16241 +}
16242 +
16243 +JSONObject
16244 +JSONObject::array(void)
16245 +{
16246 +    return JSONObject(json_array(), false);
16247 +}
16248 +
16249 +void
16250 +JSONObject::set(const char *key, JSONObject &value)
16251 +{
16252 +    JSON_CHECK_OBJECT();
16253 +    JSON_CHECK(json_object_set_new(m_obj, key, value.get()));
16254 +}
16255 +
16256 +void
16257 +JSONObject::set(const char *key, const char *value)
16258 +{
16259 +    JSONObject jobj(value);
16260 +    set(key, jobj);
16261 +}
16262 +
16263 +void
16264 +JSONObject::set(const char *key, json_int_t value)
16265 +{
16266 +    JSONObject jobj(value);
16267 +    set(key, jobj);
16268 +}
16269 +
16270 +void
16271 +JSONObject::del(const char *key)
16272 +{
16273 +    json_object_del(m_obj, key);
16274 +}
16275 +
16276 +JSONObject
16277 +JSONObject::get(const char *key) const
16278 +{
16279 +    json_t *obj;
16280 +
16281 +    obj = json_object_get(m_obj, key);
16282 +    if (obj == NULL)
16283 +        return JSONObject::null();
16284 +
16285 +    return JSONObject(obj, true);
16286 +}
16287 +
16288 +JSONObject
16289 +JSONObject::get(size_t index) const
16290 +{
16291 +    json_t *obj;
16292 +
16293 +    obj = json_array_get(m_obj, index);
16294 +    if (obj == NULL)
16295 +        return JSONObject::null();
16296 +
16297 +    return JSONObject(obj, true);
16298 +}
16299 +
16300 +void
16301 +JSONObject::update(JSONObject &value)
16302 +{
16303 +    JSON_CHECK_OBJECT();
16304 +    json_t *other = value.get();
16305 +    JSON_CHECK(json_object_update(m_obj, other));
16306 +    json_decref(other);
16307 +}
16308 +
16309 +JSONObject
16310 +JSONObject::operator[](size_t index) const
16311 +{
16312 +    return get(index);
16313 +}
16314 +
16315 +JSONObject
16316 +JSONObject::operator[](const char *key) const
16317 +{
16318 +    return get(key);
16319 +}
16320 +
16321 +void
16322 +JSONObject::append(JSONObject &value)
16323 +{
16324 +    JSON_CHECK_ARRAY();
16325 +    JSON_CHECK(json_array_append_new(m_obj, value.get()));
16326 +}
16327 +
16328 +void
16329 +JSONObject::insert(size_t index, JSONObject &value)
16330 +{
16331 +    JSON_CHECK_ARRAY();
16332 +    JSON_CHECK(json_array_insert_new(m_obj, index, value.get()));
16333 +}
16334 +
16335 +void
16336 +JSONObject::remove(size_t index)
16337 +{
16338 +    JSON_CHECK_ARRAY();
16339 +    JSON_CHECK(json_array_remove(m_obj, index));
16340 +}
16341 +
16342 +void
16343 +JSONObject::clear(void)
16344 +{
16345 +    JSON_CHECK_CONTAINER();
16346 +
16347 +    if (json_is_object(m_obj)) {
16348 +        JSON_CHECK(json_object_clear(m_obj));
16349 +    } else if (json_is_array(m_obj)) {
16350 +        JSON_CHECK(json_array_clear(m_obj));
16351 +    }
16352 +}
16353 +
16354 +void
16355 +JSONObject::extend(JSONObject &value)
16356 +{
16357 +    JSON_CHECK_ARRAY();
16358 +    json_t *other = value.get();
16359 +    JSON_CHECK(json_array_extend(m_obj, other));
16360 +    json_decref(other);
16361 +}
16362 +
16363 +const char *
16364 +JSONObject::string(void) const
16365 +{
16366 +    return json_string_value(m_obj);
16367 +}
16368 +
16369 +json_int_t
16370 +JSONObject::integer(void) const
16371 +{
16372 +    return json_integer_value(m_obj);
16373 +}
16374 +
16375 +double
16376 +JSONObject::real(void) const
16377 +{
16378 +    return json_real_value(m_obj);
16379 +}
16380 +
16381 +double
16382 +JSONObject::number(void) const
16383 +{
16384 +    return json_number_value(m_obj);
16385 +}
16386 +
16387 +#ifdef HAVE_SHIBRESOLVER
16388 +JSONObject
16389 +JSONObject::ddf(DDF &ddf)
16390 +{
16391 +    if (ddf.isstruct()) {
16392 +        DDF elem = ddf.first();
16393 +        JSONObject jobj = JSONObject::object();
16394 +
16395 +        while (!elem.isnull()) {
16396 +            JSONObject jtmp = JSONObject::ddf(elem);
16397 +            jobj.set(elem.name(), jtmp);
16398 +            elem = ddf.next();
16399 +        }
16400 +
16401 +        return jobj;
16402 +    } else if (ddf.islist()) {
16403 +        DDF elem = ddf.first();
16404 +        JSONObject jobj = JSONObject::array();
16405 +
16406 +        while (!elem.isnull()) {
16407 +            JSONObject jtmp = JSONObject::ddf(elem);
16408 +            jobj.append(jtmp);
16409 +            elem = ddf.next();
16410 +        }
16411 +
16412 +        return jobj;
16413 +    } else if (ddf.isstring()) {
16414 +        return JSONObject(ddf.string());
16415 +    } else if (ddf.isint()) {
16416 +        return JSONObject((json_int_t)ddf.integer());
16417 +    } else if (ddf.isfloat()) {
16418 +        return JSONObject(ddf.floating());
16419 +    } else if (ddf.isempty() || ddf.ispointer()) {
16420 +        return JSONObject::object();
16421 +    } else if (ddf.isnull()) {
16422 +        return JSONObject::null();
16423 +    }
16424 +
16425 +    std::string s("Unbridgeable DDF object");
16426 +    throw JSONException();
16427 +}
16428 +
16429 +DDF
16430 +JSONObject::ddf(void) const
16431 +{
16432 +    DDF ddf(NULL);
16433 +
16434 +    switch (type()) {
16435 +    case JSON_OBJECT: {
16436 +        JSONIterator iter = iterator();
16437 +
16438 +        do {
16439 +            const char *key = iter.key();
16440 +            DDF value = iter.value().ddf();
16441 +            ddf.addmember(key).swap(value);
16442 +        } while (iter.next());
16443 +        break;
16444 +    }
16445 +    case JSON_ARRAY: {
16446 +        size_t i, nelems = size();
16447 +
16448 +        for (i = 0; i < nelems; i++) {
16449 +            DDF value = get(i).ddf();
16450 +            ddf.add(value);
16451 +        }
16452 +        break;
16453 +    }
16454 +    case JSON_STRING:
16455 +        ddf.string(string());
16456 +        break;
16457 +    case JSON_INTEGER:
16458 +        ddf.integer(integer());
16459 +        break;
16460 +    case JSON_REAL:
16461 +        ddf.floating(real());
16462 +        break;
16463 +    case JSON_TRUE:
16464 +        ddf.integer(1L);
16465 +        break;
16466 +    case JSON_FALSE:
16467 +        ddf.integer(0L);
16468 +        break;
16469 +    case JSON_NULL:
16470 +        break;
16471 +    }
16472 +
16473 +    return ddf;
16474 +}
16475 +#endif /* HAVE_SHIBRESOLVER */
16476 +
16477 +bool JSONObject::isObject(void) const
16478 +{
16479 +    return json_is_object(m_obj);
16480 +}
16481 +
16482 +bool JSONObject::isArray(void) const
16483 +{
16484 +    return json_is_array(m_obj);
16485 +}
16486 +
16487 +bool JSONObject::isString(void) const
16488 +{
16489 +    return json_is_string(m_obj);
16490 +}
16491 +
16492 +bool JSONObject::isInteger(void) const
16493 +{
16494 +    return json_is_integer(m_obj);
16495 +}
16496 +
16497 +bool JSONObject::isNumber(void) const
16498 +{
16499 +    return json_is_number(m_obj);
16500 +}
16501 +
16502 +bool JSONObject::isBoolean(void) const
16503 +{
16504 +    return json_is_boolean(m_obj);
16505 +}
16506 +
16507 +bool JSONObject::isNull(void) const
16508 +{
16509 +    return json_is_null(m_obj);
16510 +}
16511 +
16512 +JSONIterator::JSONIterator(const JSONObject &obj)
16513 +{
16514 +    m_obj = obj.get();
16515 +    m_iter = json_object_iter(m_obj);
16516 +}
16517 +
16518 +JSONIterator::~JSONIterator(void)
16519 +{
16520 +    json_decref(m_obj);
16521 +}
16522 +
16523 +const char *
16524 +JSONIterator::key(void) const
16525 +{
16526 +    return json_object_iter_key(m_iter);
16527 +}
16528 +
16529 +JSONObject
16530 +JSONIterator::value(void) const
16531 +{
16532 +    return JSONObject(json_object_iter_value(m_iter));
16533 +}
16534 +
16535 +bool
16536 +JSONIterator::next(void)
16537 +{
16538 +    m_iter = json_object_iter_next(m_obj, m_iter);
16539 +    return m_iter != NULL;
16540 +}
16541 +
16542 +JSONException::JSONException(json_t *obj, json_type type)
16543 +{
16544 +    char *s = NULL;
16545 +    const char *t;
16546 +
16547 +    m_obj = json_incref(obj);
16548 +    m_type = type;
16549 +
16550 +    if (obj != NULL)
16551 +        s = json_dumps(m_obj, 0);
16552 +
16553 +    switch (type) {
16554 +    case JSON_OBJECT:   t = "OBJECT";   break;
16555 +    case JSON_ARRAY:    t = "ARRAY";    break;
16556 +    case JSON_STRING:   t = "STRING";   break;
16557 +    case JSON_INTEGER:  t = "INTEGER";  break;
16558 +    case JSON_REAL:     t = "REAL";     break;
16559 +    case JSON_TRUE:     t = "TRUE";     break;
16560 +    case JSON_FALSE:    t = "FALSE";    break;
16561 +    case JSON_NULL:     t = "NULL";     break;
16562 +    default:            t = "UNKNOWN";  break;
16563 +    }
16564 +
16565 +    if (obj != NULL) {
16566 +        m_reason = "Invalid JSON object: " + std::string(s);
16567 +        if (type != JSON_NULL)
16568 +            m_reason += " (excepted type " + std::string(t) + ")";
16569 +    } else {
16570 +        m_reason = "Internal JSON error";
16571 +    }
16572 +
16573 +    if (s != NULL)
16574 +        GSSEAP_FREE(s);
16575 +}
16576 diff --git a/mech_eap/util_json.h b/mech_eap/util_json.h
16577 new file mode 100644
16578 index 0000000..4ffecc8
16579 --- /dev/null
16580 +++ b/mech_eap/util_json.h
16581 @@ -0,0 +1,182 @@
16582 +/*
16583 + * Copyright (c) 2011, JANET(UK)
16584 + * All rights reserved.
16585 + *
16586 + * Redistribution and use in source and binary forms, with or without
16587 + * modification, are permitted provided that the following conditions
16588 + * are met:
16589 + *
16590 + * 1. Redistributions of source code must retain the above copyright
16591 + *    notice, this list of conditions and the following disclaimer.
16592 + *
16593 + * 2. Redistributions in binary form must reproduce the above copyright
16594 + *    notice, this list of conditions and the following disclaimer in the
16595 + *    documentation and/or other materials provided with the distribution.
16596 + *
16597 + * 3. Neither the name of JANET(UK) nor the names of its contributors
16598 + *    may be used to endorse or promote products derived from this software
16599 + *    without specific prior written permission.
16600 + *
16601 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16602 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16603 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16604 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
16605 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
16606 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
16607 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
16608 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16609 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16610 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
16611 + * SUCH DAMAGE.
16612 + */
16613 +
16614 +/*
16615 + * JSON object wrapper with not-entirely-toll-free DDF bridging.
16616 + */
16617 +
16618 +#ifndef _UTIL_JSON_H_
16619 +#define _UTIL_JSON_H_ 1
16620 +
16621 +#ifdef __cplusplus
16622 +#include <string>
16623 +#include <new>
16624 +
16625 +#include <jansson.h>
16626 +
16627 +#ifdef HAVE_SHIBRESOLVER
16628 +#include <shibsp/remoting/ddf.h>
16629 +using namespace shibsp;
16630 +#endif
16631 +
16632 +namespace gss_eap_util {
16633 +    class JSONObject;
16634 +
16635 +    class JSONException : public std::exception {
16636 +    public:
16637 +        JSONException(json_t *obj = NULL, json_type type = JSON_NULL);
16638 +
16639 +        ~JSONException(void) throw() {
16640 +            json_decref(m_obj);
16641 +        }
16642 +
16643 +        virtual const char *what(void) const throw() {
16644 +            return m_reason.c_str();
16645 +        }
16646 +
16647 +    private:
16648 +        json_t *m_obj;
16649 +        json_type m_type;
16650 +        std::string m_reason;
16651 +    };
16652 +
16653 +    class JSONIterator {
16654 +    public:
16655 +        JSONIterator(const JSONObject &obj);
16656 +        ~JSONIterator(void);
16657 +        const char *key(void) const;
16658 +        JSONObject value(void) const;
16659 +        bool next(void);
16660 +
16661 +    private:
16662 +        json_t *m_obj;
16663 +        void *m_iter;
16664 +    };
16665 +
16666 +    class JSONObject {
16667 +    public:
16668 +        static JSONObject load(const char *input, size_t flags, json_error_t *error);
16669 +        static JSONObject load(FILE *, size_t flags, json_error_t *error);
16670 +
16671 +        static JSONObject object(void);
16672 +        static JSONObject array(void);
16673 +        static JSONObject null(void);
16674 +#ifdef HAVE_SHIBRESOLVER
16675 +        static JSONObject ddf(DDF &value);
16676 +#endif
16677 +
16678 +        char *dump(size_t flags = 0) const;
16679 +        void dump(FILE *fp, size_t flags = JSON_INDENT(4)) const;
16680 +
16681 +        json_type type(void) const { return json_typeof(m_obj); }
16682 +        size_t size(void) const;
16683 +
16684 +        JSONObject(void);
16685 +        JSONObject(const char *value);
16686 +        JSONObject(json_int_t value);
16687 +        JSONObject(double value);
16688 +        JSONObject(bool value);
16689 +
16690 +        void set(const char *key, JSONObject &value);
16691 +        void set(const char *key, const char *value);
16692 +        void set(const char *key, json_int_t value);
16693 +        void del(const char *key);
16694 +        void update(JSONObject &value);
16695 +        JSONIterator iterator(void) const { return JSONIterator(*this); }
16696 +        JSONObject get(const char *key) const;
16697 +        JSONObject operator[](const char *key) const;
16698 +
16699 +        JSONObject get(size_t index) const;
16700 +        JSONObject operator[](size_t index) const;
16701 +        void append(JSONObject &value);
16702 +        void insert(size_t index, JSONObject &value);
16703 +        void remove(size_t index);
16704 +        void clear(void);
16705 +        void extend(JSONObject &value);
16706 +
16707 +        const char *string(void) const;
16708 +        json_int_t integer(void) const;
16709 +        double real(void) const;
16710 +        double number(void) const;
16711 +#ifdef HAVE_SHIBRESOLVER
16712 +        DDF ddf(void) const;
16713 +#endif
16714 +
16715 +        bool isObject(void) const;
16716 +        bool isArray(void) const;
16717 +        bool isString(void) const;
16718 +        bool isInteger(void) const;
16719 +        bool isNumber(void) const;
16720 +        bool isBoolean(void) const;
16721 +        bool isNull(void) const;
16722 +
16723 +        ~JSONObject(void)
16724 +        {
16725 +            if (m_obj != NULL)
16726 +                json_decref(m_obj);
16727 +        }
16728 +
16729 +        JSONObject(const JSONObject &obj)
16730 +        {
16731 +            m_obj = json_incref(obj.m_obj);
16732 +        }
16733 +
16734 +        JSONObject& operator=(const JSONObject &obj)
16735 +        {
16736 +            if (this != &obj)
16737 +                set(obj.m_obj);
16738 +            return *this;
16739 +        }
16740 +
16741 +    private:
16742 +        friend class JSONIterator;
16743 +
16744 +        json_t *get(void) const {
16745 +            return json_incref(m_obj);
16746 +        }
16747 +
16748 +        void set(json_t *obj) {
16749 +            if (m_obj != obj) {
16750 +                json_decref(m_obj);
16751 +                m_obj = json_incref(m_obj);
16752 +            }
16753 +        }
16754 +
16755 +        JSONObject(json_t *obj, bool retain = true);
16756 +
16757 +        json_t *m_obj;
16758 +    };
16759 +}
16760 +
16761 +#endif /* __cplusplus */
16762 +
16763 +#endif /* _UTIL_JSON_H_ */
16764 diff --git a/mech_eap/util_krb.c b/mech_eap/util_krb.c
16765 new file mode 100644
16766 index 0000000..5eaa31e
16767 --- /dev/null
16768 +++ b/mech_eap/util_krb.c
16769 @@ -0,0 +1,632 @@
16770 +/*
16771 + * Copyright (c) 2011, JANET(UK)
16772 + * All rights reserved.
16773 + *
16774 + * Redistribution and use in source and binary forms, with or without
16775 + * modification, are permitted provided that the following conditions
16776 + * are met:
16777 + *
16778 + * 1. Redistributions of source code must retain the above copyright
16779 + *    notice, this list of conditions and the following disclaimer.
16780 + *
16781 + * 2. Redistributions in binary form must reproduce the above copyright
16782 + *    notice, this list of conditions and the following disclaimer in the
16783 + *    documentation and/or other materials provided with the distribution.
16784 + *
16785 + * 3. Neither the name of JANET(UK) nor the names of its contributors
16786 + *    may be used to endorse or promote products derived from this software
16787 + *    without specific prior written permission.
16788 + *
16789 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16790 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16791 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16792 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
16793 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
16794 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
16795 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
16796 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16797 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16798 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
16799 + * SUCH DAMAGE.
16800 + */
16801 +
16802 +/*
16803 + * Kerberos 5 helpers.
16804 + */
16805 +
16806 +#include "gssapiP_eap.h"
16807 +
16808 +void
16809 +gssEapDestroyKrbContext(krb5_context context)
16810 +{
16811 +    if (context != NULL)
16812 +        krb5_free_context(context);
16813 +}
16814 +
16815 +static krb5_error_code
16816 +initKrbContext(krb5_context *pKrbContext)
16817 +{
16818 +    krb5_context krbContext;
16819 +    krb5_error_code code;
16820 +    char *defaultRealm = NULL;
16821 +
16822 +    *pKrbContext = NULL;
16823 +
16824 +    code = krb5_init_context(&krbContext);
16825 +    if (code != 0)
16826 +        goto cleanup;
16827 +
16828 +    krb5_appdefault_string(krbContext, "eap_gss",
16829 +                           NULL, "default_realm", "", &defaultRealm);
16830 +
16831 +    if (defaultRealm != NULL && defaultRealm[0] != '\0') {
16832 +        code = krb5_set_default_realm(krbContext, defaultRealm);
16833 +        if (code != 0)
16834 +            goto cleanup;
16835 +    }
16836 +
16837 +    *pKrbContext = krbContext;
16838 +
16839 +cleanup:
16840 +    krb5_free_default_realm(krbContext, defaultRealm);
16841 +
16842 +    if (code != 0 && krbContext != NULL)
16843 +        krb5_free_context(krbContext);
16844 +
16845 +    return code;
16846 +}
16847 +
16848 +OM_uint32
16849 +gssEapKerberosInit(OM_uint32 *minor, krb5_context *context)
16850 +{
16851 +    struct gss_eap_thread_local_data *tld;
16852 +
16853 +    *minor = 0;
16854 +    *context = NULL;
16855 +
16856 +    tld = gssEapGetThreadLocalData();
16857 +    if (tld != NULL) {
16858 +        if (tld->krbContext == NULL) {
16859 +            *minor = initKrbContext(&tld->krbContext);
16860 +            if (*minor != 0)
16861 +                tld->krbContext = NULL;
16862 +        }
16863 +        *context = tld->krbContext;
16864 +    } else {
16865 +        *minor = GSSEAP_GET_LAST_ERROR();
16866 +    }
16867 +
16868 +    GSSEAP_ASSERT(*context != NULL || *minor != 0);
16869 +
16870 +    return (*minor == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
16871 +}
16872 +
16873 +/*
16874 + * Derive a key K for RFC 4121 use by using the following
16875 + * derivation function (based on RFC 4402);
16876 + *
16877 + * KMSK = random-to-key(MSK)
16878 + * Tn = pseudo-random(KMSK, n || "rfc4121-gss-eap")
16879 + * L = output key size
16880 + * K = truncate(L, T1 || T2 || .. || Tn)
16881 + *
16882 + * The output must be freed by krb5_free_keyblock_contents(),
16883 + * not GSSEAP_FREE().
16884 + */
16885 +OM_uint32
16886 +gssEapDeriveRfc3961Key(OM_uint32 *minor,
16887 +                       const unsigned char *inputKey,
16888 +                       size_t inputKeyLength,
16889 +                       krb5_enctype encryptionType,
16890 +                       krb5_keyblock *pKey)
16891 +{
16892 +    krb5_context krbContext;
16893 +#ifndef HAVE_HEIMDAL_VERSION
16894 +    krb5_data data;
16895 +#endif
16896 +    krb5_data ns, t, derivedKeyData;
16897 +    krb5_keyblock kd;
16898 +    krb5_error_code code;
16899 +    size_t randomLength, keyLength, prfLength;
16900 +    unsigned char constant[4 + sizeof("rfc4121-gss-eap") - 1], *p;
16901 +    ssize_t i, remain;
16902 +
16903 +    GSSEAP_KRB_INIT(&krbContext);
16904 +    GSSEAP_ASSERT(encryptionType != ENCTYPE_NULL);
16905 +
16906 +    KRB_KEY_INIT(pKey);
16907 +    KRB_KEY_INIT(&kd);
16908 +    KRB_KEY_TYPE(&kd) = encryptionType;
16909 +
16910 +    KRB_DATA_INIT(&ns);
16911 +    KRB_DATA_INIT(&t);
16912 +    KRB_DATA_INIT(&derivedKeyData);
16913 +
16914 +    code = krb5_c_keylengths(krbContext, encryptionType,
16915 +                             &randomLength, &keyLength);
16916 +    if (code != 0)
16917 +        goto cleanup;
16918 +
16919 +    /* Convert EAP MSK into a Kerberos key */
16920 +
16921 +#ifdef HAVE_HEIMDAL_VERSION
16922 +    code = krb5_random_to_key(krbContext, encryptionType, inputKey,
16923 +                              MIN(inputKeyLength, randomLength), &kd);
16924 +#else
16925 +    data.length = MIN(inputKeyLength, randomLength);
16926 +    data.data = (char *)inputKey;
16927 +
16928 +    KRB_KEY_DATA(&kd) = KRB_MALLOC(keyLength);
16929 +    if (KRB_KEY_DATA(&kd) == NULL) {
16930 +        code = ENOMEM;
16931 +        goto cleanup;
16932 +    }
16933 +    KRB_KEY_LENGTH(&kd) = keyLength;
16934 +
16935 +    code = krb5_c_random_to_key(krbContext, encryptionType, &data, &kd);
16936 +#endif /* HAVE_HEIMDAL_VERSION */
16937 +    if (code != 0)
16938 +        goto cleanup;
16939 +
16940 +    memset(&constant[0], 0, 4);
16941 +    memcpy(&constant[4], "rfc4121-gss-eap", sizeof("rfc4121-gss-eap") - 1);
16942 +
16943 +    ns.length = sizeof(constant);
16944 +    ns.data = (char *)constant;
16945 +
16946 +    /* Plug derivation constant and key into PRF */
16947 +    code = krb5_c_prf_length(krbContext, encryptionType, &prfLength);
16948 +    if (code != 0)
16949 +        goto cleanup;
16950 +
16951 +#ifndef HAVE_HEIMDAL_VERSION
16952 +    /* Same API, but different allocation rules, unfortunately. */
16953 +    t.length = prfLength;
16954 +    t.data = GSSEAP_MALLOC(t.length);
16955 +    if (t.data == NULL) {
16956 +        code = ENOMEM;
16957 +        goto cleanup;
16958 +    }
16959 +#endif
16960 +
16961 +    derivedKeyData.length = randomLength;
16962 +    derivedKeyData.data = GSSEAP_MALLOC(derivedKeyData.length);
16963 +    if (derivedKeyData.data == NULL) {
16964 +        code = ENOMEM;
16965 +        goto cleanup;
16966 +    }
16967 +
16968 +    for (i = 0, p = (unsigned char *)derivedKeyData.data, remain = randomLength;
16969 +         remain > 0;
16970 +         p += t.length, remain -= t.length, i++)
16971 +    {
16972 +        store_uint32_be(i, ns.data);
16973 +
16974 +        code = krb5_c_prf(krbContext, &kd, &ns, &t);
16975 +        if (code != 0)
16976 +            goto cleanup;
16977 +
16978 +        memcpy(p, t.data, MIN(t.length, remain));
16979 +     }
16980 +
16981 +    /* Finally, convert PRF output into a new key which we will return */
16982 +#ifdef HAVE_HEIMDAL_VERSION
16983 +    krb5_free_keyblock_contents(krbContext, &kd);
16984 +    KRB_KEY_INIT(&kd);
16985 +
16986 +    code = krb5_random_to_key(krbContext, encryptionType,
16987 +                              derivedKeyData.data, derivedKeyData.length, &kd);
16988 +#else
16989 +    code = krb5_c_random_to_key(krbContext, encryptionType,
16990 +                                &derivedKeyData, &kd);
16991 +#endif
16992 +    if (code != 0)
16993 +        goto cleanup;
16994 +
16995 +    *pKey = kd;
16996 +
16997 +cleanup:
16998 +    if (code != 0)
16999 +        krb5_free_keyblock_contents(krbContext, &kd);
17000 +#ifdef HAVE_HEIMDAL_VERSION
17001 +    krb5_free_data_contents(krbContext, &t);
17002 +#else
17003 +    if (t.data != NULL) {
17004 +        memset(t.data, 0, t.length);
17005 +        GSSEAP_FREE(t.data);
17006 +    }
17007 +#endif
17008 +    if (derivedKeyData.data != NULL) {
17009 +        memset(derivedKeyData.data, 0, derivedKeyData.length);
17010 +        GSSEAP_FREE(derivedKeyData.data);
17011 +    }
17012 +
17013 +    *minor = code;
17014 +
17015 +    return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
17016 +}
17017 +
17018 +#ifdef HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE
17019 +extern krb5_error_code
17020 +krb5int_c_mandatory_cksumtype(krb5_context, krb5_enctype, krb5_cksumtype *);
17021 +#endif
17022 +
17023 +OM_uint32
17024 +rfc3961ChecksumTypeForKey(OM_uint32 *minor,
17025 +                          krb5_keyblock *key,
17026 +                          krb5_cksumtype *cksumtype)
17027 +{
17028 +    krb5_context krbContext;
17029 +#ifndef HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE
17030 +    krb5_data data;
17031 +    krb5_checksum cksum;
17032 +#endif
17033 +
17034 +    GSSEAP_KRB_INIT(&krbContext);
17035 +
17036 +#ifdef HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE
17037 +    *minor = krb5int_c_mandatory_cksumtype(krbContext, KRB_KEY_TYPE(key),
17038 +                                           cksumtype);
17039 +    if (*minor != 0)
17040 +        return GSS_S_FAILURE;
17041 +#else
17042 +    KRB_DATA_INIT(&data);
17043 +
17044 +    memset(&cksum, 0, sizeof(cksum));
17045 +
17046 +    /*
17047 +     * This is a complete hack but it's the only way to work with
17048 +     * MIT Kerberos pre-1.9 without using private API, as it does
17049 +     * not support passing in zero as the checksum type.
17050 +     */
17051 +    *minor = krb5_c_make_checksum(krbContext, 0, key, 0, &data, &cksum);
17052 +    if (*minor != 0)
17053 +        return GSS_S_FAILURE;
17054 +
17055 +#ifdef HAVE_HEIMDAL_VERSION
17056 +    *cksumtype = cksum.cksumtype;
17057 +#else
17058 +    *cksumtype = cksum.checksum_type;
17059 +#endif
17060 +
17061 +    krb5_free_checksum_contents(krbContext, &cksum);
17062 +#endif /* HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE */
17063 +
17064 +    if (!krb5_c_is_keyed_cksum(*cksumtype)) {
17065 +        *minor = (OM_uint32)KRB5KRB_AP_ERR_INAPP_CKSUM;
17066 +        return GSS_S_FAILURE;
17067 +    }
17068 +
17069 +    return GSS_S_COMPLETE;
17070 +}
17071 +
17072 +krb5_error_code
17073 +krbCryptoLength(krb5_context krbContext,
17074 +#ifdef HAVE_HEIMDAL_VERSION
17075 +                krb5_crypto krbCrypto,
17076 +#else
17077 +                krb5_keyblock *key,
17078 +#endif
17079 +                int type,
17080 +                size_t *length)
17081 +{
17082 +#ifdef HAVE_HEIMDAL_VERSION
17083 +    return krb5_crypto_length(krbContext, krbCrypto, type, length);
17084 +#else
17085 +    unsigned int len;
17086 +    krb5_error_code code;
17087 +
17088 +    code = krb5_c_crypto_length(krbContext, KRB_KEY_TYPE(key), type, &len);
17089 +    if (code == 0)
17090 +        *length = (size_t)len;
17091 +
17092 +    return code;
17093 +#endif
17094 +}
17095 +
17096 +krb5_error_code
17097 +krbPaddingLength(krb5_context krbContext,
17098 +#ifdef HAVE_HEIMDAL_VERSION
17099 +                 krb5_crypto krbCrypto,
17100 +#else
17101 +                 krb5_keyblock *key,
17102 +#endif
17103 +                 size_t dataLength,
17104 +                 size_t *padLength)
17105 +{
17106 +    krb5_error_code code;
17107 +#ifdef HAVE_HEIMDAL_VERSION
17108 +    size_t headerLength, paddingLength;
17109 +
17110 +    code = krbCryptoLength(krbContext, krbCrypto,
17111 +                           KRB5_CRYPTO_TYPE_HEADER, &headerLength);
17112 +    if (code != 0)
17113 +        return code;
17114 +
17115 +    dataLength += headerLength;
17116 +
17117 +    code = krb5_crypto_length(krbContext, krbCrypto,
17118 +                              KRB5_CRYPTO_TYPE_PADDING, &paddingLength);
17119 +    if (code != 0)
17120 +        return code;
17121 +
17122 +    if (paddingLength != 0 && (dataLength % paddingLength) != 0)
17123 +        *padLength = paddingLength - (dataLength % paddingLength);
17124 +    else
17125 +        *padLength = 0;
17126 +
17127 +    return 0;
17128 +#else
17129 +    unsigned int pad;
17130 +
17131 +    code = krb5_c_padding_length(krbContext, KRB_KEY_TYPE(key), dataLength, &pad);
17132 +    if (code == 0)
17133 +        *padLength = (size_t)pad;
17134 +
17135 +    return code;
17136 +#endif /* HAVE_HEIMDAL_VERSION */
17137 +}
17138 +
17139 +krb5_error_code
17140 +krbBlockSize(krb5_context krbContext,
17141 +#ifdef HAVE_HEIMDAL_VERSION
17142 +                 krb5_crypto krbCrypto,
17143 +#else
17144 +                 krb5_keyblock *key,
17145 +#endif
17146 +                 size_t *blockSize)
17147 +{
17148 +#ifdef HAVE_HEIMDAL_VERSION
17149 +    return krb5_crypto_getblocksize(krbContext, krbCrypto, blockSize);
17150 +#else
17151 +    return krb5_c_block_size(krbContext, KRB_KEY_TYPE(key), blockSize);
17152 +#endif
17153 +}
17154 +
17155 +krb5_error_code
17156 +krbEnctypeToString(
17157 +#ifdef HAVE_HEIMDAL_VERSION
17158 +                   krb5_context krbContext,
17159 +#else
17160 +                   krb5_context krbContext GSSEAP_UNUSED,
17161 +#endif
17162 +                   krb5_enctype enctype,
17163 +                   const char *prefix,
17164 +                   gss_buffer_t string)
17165 +{
17166 +    krb5_error_code code;
17167 +#ifdef HAVE_HEIMDAL_VERSION
17168 +    char *enctypeBuf = NULL;
17169 +#else
17170 +    char enctypeBuf[128];
17171 +#endif
17172 +    size_t prefixLength, enctypeLength;
17173 +
17174 +#ifdef HAVE_HEIMDAL_VERSION
17175 +    code = krb5_enctype_to_string(krbContext, enctype, &enctypeBuf);
17176 +#else
17177 +    code = krb5_enctype_to_name(enctype, 0, enctypeBuf, sizeof(enctypeBuf));
17178 +#endif
17179 +    if (code != 0)
17180 +        return code;
17181 +
17182 +    prefixLength = (prefix != NULL) ? strlen(prefix) : 0;
17183 +    enctypeLength = strlen(enctypeBuf);
17184 +
17185 +    string->value = GSSEAP_MALLOC(prefixLength + enctypeLength + 1);
17186 +    if (string->value == NULL) {
17187 +#ifdef HAVE_HEIMDAL_VERSION
17188 +        krb5_xfree(enctypeBuf);
17189 +#endif
17190 +        return ENOMEM;
17191 +    }
17192 +
17193 +    if (prefixLength != 0)
17194 +        memcpy(string->value, prefix, prefixLength);
17195 +    memcpy((char *)string->value + prefixLength, enctypeBuf, enctypeLength);
17196 +
17197 +    string->length = prefixLength + enctypeLength;
17198 +    ((char *)string->value)[string->length] = '\0';
17199 +
17200 +#ifdef HAVE_HEIMDAL_VERSION
17201 +    krb5_xfree(enctypeBuf);
17202 +#endif
17203 +
17204 +    return 0;
17205 +}
17206 +
17207 +krb5_error_code
17208 +krbMakeAuthDataKdcIssued(krb5_context context,
17209 +                         const krb5_keyblock *key,
17210 +                         krb5_const_principal issuer,
17211 +#ifdef HAVE_HEIMDAL_VERSION
17212 +                         const AuthorizationData *authdata,
17213 +                         AuthorizationData *adKdcIssued
17214 +#else
17215 +                         krb5_authdata *const *authdata,
17216 +                         krb5_authdata ***adKdcIssued
17217 +#endif
17218 +                         )
17219 +{
17220 +#ifdef HAVE_HEIMDAL_VERSION
17221 +    krb5_error_code code;
17222 +    AD_KDCIssued kdcIssued;
17223 +    AuthorizationDataElement adDatum;
17224 +    unsigned char *buf;
17225 +    size_t buf_size, len;
17226 +    krb5_crypto crypto = NULL;
17227 +
17228 +    memset(&kdcIssued, 0, sizeof(kdcIssued));
17229 +    memset(adKdcIssued, 0, sizeof(*adKdcIssued));
17230 +
17231 +    kdcIssued.i_realm = issuer->realm != NULL ? (Realm *)&issuer->realm : NULL;
17232 +    kdcIssued.i_sname = (PrincipalName *)&issuer->name;
17233 +    kdcIssued.elements = *authdata;
17234 +
17235 +    ASN1_MALLOC_ENCODE(AuthorizationData, buf, buf_size, authdata, &len, code);
17236 +    if (code != 0)
17237 +        goto cleanup;
17238 +
17239 +    code = krb5_crypto_init(context, key, 0, &crypto);
17240 +    if (code != 0)
17241 +        goto cleanup;
17242 +
17243 +    code = krb5_create_checksum(context, crypto, KRB5_KU_AD_KDC_ISSUED,
17244 +                                0, buf, buf_size, &kdcIssued.ad_checksum);
17245 +    if (code != 0)
17246 +        goto cleanup;
17247 +
17248 +    free(buf); /* match ASN1_MALLOC_ENCODE */
17249 +    buf = NULL;
17250 +
17251 +    ASN1_MALLOC_ENCODE(AD_KDCIssued, buf, buf_size, &kdcIssued, &len, code);
17252 +    if (code != 0)
17253 +        goto cleanup;
17254 +
17255 +    adDatum.ad_type = KRB5_AUTHDATA_KDC_ISSUED;
17256 +    adDatum.ad_data.length = buf_size;
17257 +    adDatum.ad_data.data = buf;
17258 +
17259 +    code = add_AuthorizationData(adKdcIssued, &adDatum);
17260 +    if (code != 0)
17261 +        goto cleanup;
17262 +
17263 +cleanup:
17264 +    if (buf != NULL)
17265 +        free(buf); /* match ASN1_MALLOC_ENCODE */
17266 +    if (crypto != NULL)
17267 +        krb5_crypto_destroy(context, crypto);
17268 +    free_Checksum(&kdcIssued.ad_checksum);
17269 +
17270 +    return code;
17271 +#else
17272 +    return krb5_make_authdata_kdc_issued(context, key, issuer, authdata,
17273 +                                         adKdcIssued);
17274 +#endif /* HAVE_HEIMDAL_VERSION */
17275 +}
17276 +
17277 +krb5_error_code
17278 +krbMakeCred(krb5_context krbContext,
17279 +            krb5_auth_context authContext,
17280 +            krb5_creds *creds,
17281 +            krb5_data *data)
17282 +{
17283 +    krb5_error_code code;
17284 +#ifdef HAVE_HEIMDAL_VERSION
17285 +    KRB_CRED krbCred;
17286 +    KrbCredInfo krbCredInfo;
17287 +    EncKrbCredPart encKrbCredPart;
17288 +    krb5_keyblock *key;
17289 +    krb5_crypto krbCrypto = NULL;
17290 +    krb5_data encKrbCredPartData;
17291 +    krb5_replay_data rdata;
17292 +    size_t len;
17293 +#else
17294 +    krb5_data *d = NULL;
17295 +#endif
17296 +
17297 +    memset(data, 0, sizeof(*data));
17298 +#ifdef HAVE_HEIMDAL_VERSION
17299 +    memset(&krbCred,        0, sizeof(krbCred));
17300 +    memset(&krbCredInfo,    0, sizeof(krbCredInfo));
17301 +    memset(&encKrbCredPart, 0, sizeof(encKrbCredPart));
17302 +    memset(&rdata,          0, sizeof(rdata));
17303 +
17304 +    if (authContext->local_subkey)
17305 +        key = authContext->local_subkey;
17306 +    else if (authContext->remote_subkey)
17307 +        key = authContext->remote_subkey;
17308 +    else
17309 +        key = authContext->keyblock;
17310 +
17311 +    krbCred.pvno = 5;
17312 +    krbCred.msg_type = krb_cred;
17313 +    krbCred.tickets.val = (Ticket *)GSSEAP_CALLOC(1, sizeof(Ticket));
17314 +    if (krbCred.tickets.val == NULL) {
17315 +        code = ENOMEM;
17316 +        goto cleanup;
17317 +    }
17318 +    krbCred.tickets.len = 1;
17319 +
17320 +    code = decode_Ticket(creds->ticket.data,
17321 +                         creds->ticket.length,
17322 +                         krbCred.tickets.val, &len);
17323 +    if (code != 0)
17324 +        goto cleanup;
17325 +
17326 +    krbCredInfo.key         = creds->session;
17327 +    krbCredInfo.prealm      = &creds->client->realm;
17328 +    krbCredInfo.pname       = &creds->client->name;
17329 +    krbCredInfo.flags       = &creds->flags.b;
17330 +    krbCredInfo.authtime    = &creds->times.authtime;
17331 +    krbCredInfo.starttime   = &creds->times.starttime;
17332 +    krbCredInfo.endtime     = &creds->times.endtime;
17333 +    krbCredInfo.renew_till  = &creds->times.renew_till;
17334 +    krbCredInfo.srealm      = &creds->server->realm;
17335 +    krbCredInfo.sname       = &creds->server->name;
17336 +    krbCredInfo.caddr       = creds->addresses.len ? &creds->addresses : NULL;
17337 +
17338 +    encKrbCredPart.ticket_info.len = 1;
17339 +    encKrbCredPart.ticket_info.val = &krbCredInfo;
17340 +    if (authContext->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
17341 +        rdata.seq                  = authContext->local_seqnumber;
17342 +        encKrbCredPart.nonce       = (int32_t *)&rdata.seq;
17343 +    } else {
17344 +        encKrbCredPart.nonce       = NULL;
17345 +    }
17346 +    if (authContext->flags & KRB5_AUTH_CONTEXT_DO_TIME) {
17347 +        krb5_us_timeofday(krbContext, &rdata.timestamp, &rdata.usec);
17348 +        encKrbCredPart.timestamp   = &rdata.timestamp;
17349 +        encKrbCredPart.usec        = &rdata.usec;
17350 +    } else {
17351 +        encKrbCredPart.timestamp   = NULL;
17352 +        encKrbCredPart.usec        = NULL;
17353 +    }
17354 +    encKrbCredPart.s_address       = authContext->local_address;
17355 +    encKrbCredPart.r_address       = authContext->remote_address;
17356 +
17357 +    ASN1_MALLOC_ENCODE(EncKrbCredPart, encKrbCredPartData.data,
17358 +                       encKrbCredPartData.length, &encKrbCredPart,
17359 +                       &len, code);
17360 +    if (code != 0)
17361 +        goto cleanup;
17362 +
17363 +    code = krb5_crypto_init(krbContext, key, 0, &krbCrypto);
17364 +    if (code != 0)
17365 +        goto cleanup;
17366 +
17367 +    code = krb5_encrypt_EncryptedData(krbContext,
17368 +                                      krbCrypto,
17369 +                                      KRB5_KU_KRB_CRED,
17370 +                                      encKrbCredPartData.data,
17371 +                                      encKrbCredPartData.length,
17372 +                                      0,
17373 +                                      &krbCred.enc_part);
17374 +    if (code != 0)
17375 +        goto cleanup;
17376 +
17377 +    ASN1_MALLOC_ENCODE(KRB_CRED, data->data, data->length,
17378 +                       &krbCred, &len, code);
17379 +    if (code != 0)
17380 +        goto cleanup;
17381 +
17382 +    if (authContext->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE)
17383 +        authContext->local_seqnumber++;
17384 +
17385 +cleanup:
17386 +    if (krbCrypto != NULL)
17387 +        krb5_crypto_destroy(krbContext, krbCrypto);
17388 +    free_KRB_CRED(&krbCred);
17389 +    krb5_data_free(&encKrbCredPartData);
17390 +
17391 +    return code;
17392 +#else
17393 +    code = krb5_mk_1cred(krbContext, authContext, creds, &d, NULL);
17394 +    if (code == 0) {
17395 +        *data = *d;
17396 +        GSSEAP_FREE(d);
17397 +    }
17398 +
17399 +    return code;
17400 +#endif /* HAVE_HEIMDAL_VERSION */
17401 +}
17402 diff --git a/mech_eap/util_lucid.c b/mech_eap/util_lucid.c
17403 new file mode 100644
17404 index 0000000..f9e9941
17405 --- /dev/null
17406 +++ b/mech_eap/util_lucid.c
17407 @@ -0,0 +1,183 @@
17408 +/*
17409 + * Copyright (c) 2011, JANET(UK)
17410 + * All rights reserved.
17411 + *
17412 + * Redistribution and use in source and binary forms, with or without
17413 + * modification, are permitted provided that the following conditions
17414 + * are met:
17415 + *
17416 + * 1. Redistributions of source code must retain the above copyright
17417 + *    notice, this list of conditions and the following disclaimer.
17418 + *
17419 + * 2. Redistributions in binary form must reproduce the above copyright
17420 + *    notice, this list of conditions and the following disclaimer in the
17421 + *    documentation and/or other materials provided with the distribution.
17422 + *
17423 + * 3. Neither the name of JANET(UK) nor the names of its contributors
17424 + *    may be used to endorse or promote products derived from this software
17425 + *    without specific prior written permission.
17426 + *
17427 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17428 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17429 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17430 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
17431 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17432 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
17433 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
17434 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
17435 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
17436 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
17437 + * SUCH DAMAGE.
17438 + */
17439 +
17440 +/*
17441 + * "Lucid" security context export routine (called by MIT Kerberos mechanism).
17442 + */
17443 +
17444 +#include "gssapiP_eap.h"
17445 +
17446 +OM_uint32
17447 +gssEapExportLucidSecContext(OM_uint32 *minor,
17448 +                            gss_ctx_id_t ctx,
17449 +                            const gss_OID desiredObject GSSEAP_UNUSED,
17450 +                            gss_buffer_set_t *data_set)
17451 +{
17452 +    OM_uint32 major = GSS_S_COMPLETE;
17453 +    int haveAcceptorSubkey =
17454 +        ((rfc4121Flags(ctx, 0) & TOK_FLAG_ACCEPTOR_SUBKEY) != 0);
17455 +    gss_buffer_desc rep;
17456 +#ifdef HAVE_HEIMDAL_VERSION
17457 +    krb5_error_code code;
17458 +    krb5_storage *sp;
17459 +    krb5_data data = { 0 };
17460 +
17461 +    sp = krb5_storage_emem();
17462 +    if (sp == NULL) {
17463 +        code = ENOMEM;
17464 +        goto cleanup;
17465 +    }
17466 +
17467 +    code = krb5_store_int32(sp, 1);     /* version */
17468 +    if (code != 0)
17469 +        goto cleanup;
17470 +
17471 +    code = krb5_store_int32(sp, CTX_IS_INITIATOR(ctx));
17472 +    if (code != 0)
17473 +        goto cleanup;
17474 +
17475 +    code = krb5_store_int32(sp, ctx->expiryTime); 
17476 +    if (code != 0)
17477 +        goto cleanup;
17478 +
17479 +    code = krb5_store_int32(sp, 0);
17480 +    if (code != 0)
17481 +        goto cleanup;
17482 +
17483 +    code = krb5_store_int32(sp, ctx->sendSeq);
17484 +    if (code != 0)
17485 +        goto cleanup;
17486 +
17487 +    code = krb5_store_int32(sp, 0);
17488 +    if (code != 0)
17489 +        goto cleanup;
17490 +
17491 +    code = krb5_store_int32(sp, ctx->recvSeq);
17492 +    if (code != 0)
17493 +        goto cleanup;
17494 +
17495 +    code = krb5_store_int32(sp, 1);     /* is_cfx */
17496 +    if (code != 0)
17497 +        goto cleanup;
17498 +
17499 +    code = krb5_store_int32(sp, haveAcceptorSubkey);
17500 +    if (code != 0)
17501 +        goto cleanup;
17502 +
17503 +    code = krb5_store_keyblock(sp, ctx->rfc3961Key);
17504 +    if (code != 0)
17505 +        goto cleanup;
17506 +
17507 +    if (haveAcceptorSubkey) {
17508 +        code = krb5_store_keyblock(sp, ctx->rfc3961Key);
17509 +        if (code != 0)
17510 +            goto cleanup;
17511 +    }
17512 +
17513 +    code = krb5_storage_to_data(sp, &data);
17514 +    if (code != 0)
17515 +        goto cleanup;
17516 +
17517 +    rep.length = data.length;
17518 +    rep.value = data.data;
17519 +
17520 +    major = gss_add_buffer_set_member(minor, &rep, data_set);
17521 +    if (GSS_ERROR(major))
17522 +        goto cleanup;
17523 +
17524 +cleanup:
17525 +    krb5_data_free(&data);
17526 +
17527 +    if (major == GSS_S_COMPLETE) {
17528 +        *minor = code;
17529 +        major = (code != 0) ? GSS_S_FAILURE : GSS_S_COMPLETE;
17530 +    }
17531 +
17532 +    return major;
17533 +#else
17534 +    gss_krb5_lucid_context_v1_t *lctx;
17535 +    gss_krb5_lucid_key_t *lkey = NULL;
17536 +
17537 +    lctx = (gss_krb5_lucid_context_v1_t *)GSSEAP_CALLOC(1, sizeof(*lctx));
17538 +    if (lctx == NULL) {
17539 +        major = GSS_S_FAILURE;
17540 +        *minor = ENOMEM;
17541 +        goto cleanup;
17542 +    }
17543 +
17544 +    lctx->version = 1;
17545 +    lctx->initiate = CTX_IS_INITIATOR(ctx);
17546 +    if (ctx->expiryTime == 0)
17547 +        lctx->endtime = KRB_TIME_FOREVER;
17548 +    else
17549 +        lctx->endtime = ctx->expiryTime;
17550 +    lctx->send_seq = ctx->sendSeq;
17551 +    lctx->recv_seq = ctx->recvSeq;
17552 +    lctx->protocol = 1;
17553 +
17554 +    lctx->cfx_kd.have_acceptor_subkey = haveAcceptorSubkey;
17555 +
17556 +    lkey = haveAcceptorSubkey
17557 +           ? &lctx->cfx_kd.acceptor_subkey
17558 +           : &lctx->cfx_kd.ctx_key;
17559 +
17560 +    lkey->type = KRB_KEY_TYPE(&ctx->rfc3961Key);
17561 +    lkey->data = GSSEAP_MALLOC(KRB_KEY_LENGTH(&ctx->rfc3961Key));
17562 +    if (lkey->data == NULL) {
17563 +        major = GSS_S_FAILURE;
17564 +        *minor = ENOMEM;
17565 +        goto cleanup;
17566 +    }
17567 +    lkey->length = KRB_KEY_LENGTH(&ctx->rfc3961Key);
17568 +    memcpy(lkey->data, KRB_KEY_DATA(&ctx->rfc3961Key), lkey->length);
17569 +
17570 +    rep.value = &lctx;
17571 +    rep.length = sizeof(void *);
17572 +
17573 +    major = gss_add_buffer_set_member(minor, &rep, data_set);
17574 +    if (GSS_ERROR(major))
17575 +        goto cleanup;
17576 +
17577 +cleanup:
17578 +    if (GSS_ERROR(major)) {
17579 +        if (lctx != NULL) {
17580 +            if (lkey != NULL && lkey->data != NULL) {
17581 +                memset(lkey->data, 0, lkey->length);
17582 +                GSSEAP_FREE(lkey->data);
17583 +            }
17584 +            GSSEAP_FREE(lctx);
17585 +        }
17586 +    }
17587 +
17588 +    return major;
17589 +#endif /* HAVE_HEIMDAL_VERSION */
17590 +}
17591 diff --git a/mech_eap/util_mech.c b/mech_eap/util_mech.c
17592 new file mode 100644
17593 index 0000000..958e43d
17594 --- /dev/null
17595 +++ b/mech_eap/util_mech.c
17596 @@ -0,0 +1,380 @@
17597 +/*
17598 + * Copyright (c) 2011, JANET(UK)
17599 + * All rights reserved.
17600 + *
17601 + * Redistribution and use in source and binary forms, with or without
17602 + * modification, are permitted provided that the following conditions
17603 + * are met:
17604 + *
17605 + * 1. Redistributions of source code must retain the above copyright
17606 + *    notice, this list of conditions and the following disclaimer.
17607 + *
17608 + * 2. Redistributions in binary form must reproduce the above copyright
17609 + *    notice, this list of conditions and the following disclaimer in the
17610 + *    documentation and/or other materials provided with the distribution.
17611 + *
17612 + * 3. Neither the name of JANET(UK) nor the names of its contributors
17613 + *    may be used to endorse or promote products derived from this software
17614 + *    without specific prior written permission.
17615 + *
17616 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17617 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17618 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17619 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
17620 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17621 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
17622 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
17623 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
17624 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
17625 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
17626 + * SUCH DAMAGE.
17627 + */
17628 +
17629 +/*
17630 + * General mechanism utility routines.
17631 + */
17632 +
17633 +#include "gssapiP_eap.h"
17634 +
17635 +/*
17636 + * 1.3.6.1.4.1.5322(padl)
17637 + *      gssEap(22)
17638 + *       mechanisms(1)
17639 + *        eap-aes128-cts-hmac-sha1-96(17)
17640 + *        eap-aes256-cts-hmac-sha1-96(18)
17641 + *       nameTypes(2)
17642 + *       apiExtensions(3)
17643 + *        inquireSecContextByOid(1)
17644 + *        inquireCredByOid(2)
17645 + *        setSecContextOption(3)
17646 + *        setCredOption(4)
17647 + *        mechInvoke(5)
17648 + */
17649 +
17650 +/*
17651 + * Note: the enctype-less OID is used as the mechanism OID in non-
17652 + * canonicalized exported names.
17653 + */
17654 +static gss_OID_desc gssEapMechOids[] = {
17655 +    /* 1.3.6.1.4.1.5322.22.1  */
17656 +    { 9, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x01" },
17657 +    /* 1.3.6.1.4.1.5322.22.1.17 */
17658 +    { 10, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x01\x11" },
17659 +    /* 1.3.6.1.4.1.5322.22.1.18 */
17660 +    { 10, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x01\x12" }
17661 +};
17662 +
17663 +gss_OID GSS_EAP_MECHANISM                            = &gssEapMechOids[0];
17664 +gss_OID GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM    = &gssEapMechOids[1];
17665 +gss_OID GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM    = &gssEapMechOids[2];
17666 +
17667 +static int
17668 +internalizeOid(const gss_OID oid,
17669 +               gss_OID *const pInternalizedOid);
17670 +
17671 +/*
17672 + * Returns TRUE is the OID is a concrete mechanism OID, that is, one
17673 + * with a Kerberos enctype as the last element.
17674 + */
17675 +int
17676 +gssEapIsConcreteMechanismOid(const gss_OID oid)
17677 +{
17678 +    return oid->length > GSS_EAP_MECHANISM->length &&
17679 +           memcmp(oid->elements, GSS_EAP_MECHANISM->elements,
17680 +                  GSS_EAP_MECHANISM->length) == 0;
17681 +}
17682 +
17683 +int
17684 +gssEapIsMechanismOid(const gss_OID oid)
17685 +{
17686 +    return oid == GSS_C_NO_OID ||
17687 +           oidEqual(oid, GSS_EAP_MECHANISM) ||
17688 +           gssEapIsConcreteMechanismOid(oid);
17689 +}
17690 +
17691 +/*
17692 + * Validate that all elements are concrete mechanism OIDs.
17693 + */
17694 +OM_uint32
17695 +gssEapValidateMechs(OM_uint32 *minor,
17696 +                    const gss_OID_set mechs)
17697 +{
17698 +    int i;
17699 +
17700 +    *minor = 0;
17701 +
17702 +    if (mechs == GSS_C_NO_OID_SET) {
17703 +        return GSS_S_COMPLETE;
17704 +    }
17705 +
17706 +    for (i = 0; i < mechs->count; i++) {
17707 +        gss_OID oid = &mechs->elements[i];
17708 +
17709 +        if (!gssEapIsConcreteMechanismOid(oid)) {
17710 +            *minor = GSSEAP_WRONG_MECH;
17711 +            return GSS_S_BAD_MECH;
17712 +        }
17713 +    }
17714 +
17715 +    return GSS_S_COMPLETE;
17716 +}
17717 +
17718 +OM_uint32
17719 +gssEapOidToEnctype(OM_uint32 *minor,
17720 +                   const gss_OID oid,
17721 +                   krb5_enctype *enctype)
17722 +{
17723 +    OM_uint32 major;
17724 +    int suffix;
17725 +
17726 +    major = decomposeOid(minor,
17727 +                         GSS_EAP_MECHANISM->elements,
17728 +                         GSS_EAP_MECHANISM->length,
17729 +                         oid,
17730 +                         &suffix);
17731 +    if (major == GSS_S_COMPLETE)
17732 +        *enctype = suffix;
17733 +
17734 +    return major;
17735 +}
17736 +
17737 +OM_uint32
17738 +gssEapEnctypeToOid(OM_uint32 *minor,
17739 +                   krb5_enctype enctype,
17740 +                   gss_OID *pOid)
17741 +{
17742 +    OM_uint32 major;
17743 +    gss_OID oid;
17744 +
17745 +    *pOid = NULL;
17746 +
17747 +    oid = (gss_OID)GSSEAP_MALLOC(sizeof(*oid));
17748 +    if (oid == NULL) {
17749 +        *minor = ENOMEM;
17750 +        return GSS_S_FAILURE;
17751 +    }
17752 +
17753 +    oid->length = GSS_EAP_MECHANISM->length + 1;
17754 +    oid->elements = GSSEAP_MALLOC(oid->length);
17755 +    if (oid->elements == NULL) {
17756 +        *minor = ENOMEM;
17757 +        GSSEAP_FREE(oid);
17758 +        return GSS_S_FAILURE;
17759 +    }
17760 +
17761 +    major = composeOid(minor,
17762 +                       GSS_EAP_MECHANISM->elements,
17763 +                       GSS_EAP_MECHANISM->length,
17764 +                       enctype,
17765 +                       oid);
17766 +    if (major == GSS_S_COMPLETE) {
17767 +        internalizeOid(oid, pOid);
17768 +        *pOid = oid;
17769 +    } else {
17770 +        GSSEAP_FREE(oid->elements);
17771 +        GSSEAP_FREE(oid);
17772 +    }
17773 +
17774 +    return major;
17775 +}
17776 +
17777 +OM_uint32
17778 +gssEapIndicateMechs(OM_uint32 *minor,
17779 +                    gss_OID_set *mechs)
17780 +{
17781 +    krb5_context krbContext;
17782 +    OM_uint32 major;
17783 +    krb5_enctype *etypes;
17784 +    int i;
17785 +
17786 +    GSSEAP_KRB_INIT(&krbContext);
17787 +
17788 +    *minor = krb5_get_permitted_enctypes(krbContext, &etypes);
17789 +    if (*minor != 0) {
17790 +        return GSS_S_FAILURE;
17791 +    }
17792 +
17793 +    major = gss_create_empty_oid_set(minor, mechs);
17794 +    if (GSS_ERROR(major)) {
17795 +        GSSEAP_FREE(etypes);
17796 +        return major;
17797 +    }
17798 +
17799 +    for (i = 0; etypes[i] != ENCTYPE_NULL; i++) {
17800 +        gss_OID mechOid;
17801 +#ifndef HAVE_HEIMDAL_VERSION
17802 +        OM_uint32 tmpMinor;
17803 +#endif
17804 +
17805 +        /* XXX currently we aren't equipped to encode these enctypes */
17806 +        if (etypes[i] < 0 || etypes[i] > 127)
17807 +            continue;
17808 +
17809 +        major = gssEapEnctypeToOid(minor, etypes[i], &mechOid);
17810 +        if (GSS_ERROR(major))
17811 +            break;
17812 +
17813 +        major = gss_add_oid_set_member(minor, mechOid, mechs);
17814 +        if (GSS_ERROR(major))
17815 +            break;
17816 +
17817 +#ifndef HAVE_HEIMDAL_VERSION
17818 +        gss_release_oid(&tmpMinor, &mechOid);
17819 +#endif
17820 +    }
17821 +
17822 +    GSSEAP_FREE(etypes);
17823 +
17824 +    *minor = 0;
17825 +    return major;
17826 +}
17827 +
17828 +OM_uint32
17829 +gssEapDefaultMech(OM_uint32 *minor,
17830 +                  gss_OID *oid)
17831 +{
17832 +    gss_OID_set mechs;
17833 +    OM_uint32 major, tmpMinor;
17834 +
17835 +    major = gssEapIndicateMechs(minor, &mechs);
17836 +    if (GSS_ERROR(major)) {
17837 +        return major;
17838 +    }
17839 +
17840 +    if (mechs->count == 0) {
17841 +        gss_release_oid_set(&tmpMinor, &mechs);
17842 +        return GSS_S_BAD_MECH;
17843 +    }
17844 +
17845 +    if (!internalizeOid(&mechs->elements[0], oid)) {
17846 +        /* don't double-free if we didn't internalize it */
17847 +        mechs->elements[0].length = 0;
17848 +        mechs->elements[0].elements = NULL;
17849 +    }
17850 +
17851 +    gss_release_oid_set(&tmpMinor, &mechs);
17852 +
17853 +    *minor = 0;
17854 +    return GSS_S_COMPLETE;
17855 +}
17856 +
17857 +static int
17858 +internalizeOid(const gss_OID oid,
17859 +               gss_OID *const pInternalizedOid)
17860 +{
17861 +    int i;
17862 +
17863 +    *pInternalizedOid = GSS_C_NO_OID;
17864 +
17865 +    for (i = 0;
17866 +         i < sizeof(gssEapMechOids) / sizeof(gssEapMechOids[0]);
17867 +         i++) {
17868 +        if (oidEqual(oid, &gssEapMechOids[i])) {
17869 +            *pInternalizedOid = (const gss_OID)&gssEapMechOids[i];
17870 +            break;
17871 +        }
17872 +    }
17873 +
17874 +    if (*pInternalizedOid == GSS_C_NO_OID) {
17875 +        if (oidEqual(oid, GSS_EAP_NT_EAP_NAME))
17876 +            *pInternalizedOid = (const gss_OID)GSS_EAP_NT_EAP_NAME;
17877 +    }
17878 +
17879 +    if (*pInternalizedOid == GSS_C_NO_OID) {
17880 +        *pInternalizedOid = oid;
17881 +        return 0;
17882 +    }
17883 +
17884 +    return 1;
17885 +}
17886 +
17887 +OM_uint32
17888 +gssEapReleaseOid(OM_uint32 *minor, gss_OID *oid)
17889 +{
17890 +    gss_OID internalizedOid = GSS_C_NO_OID;
17891 +
17892 +    *minor = 0;
17893 +
17894 +    if (internalizeOid(*oid, &internalizedOid)) {
17895 +        /* OID was internalized, so we can mark it as "freed" */
17896 +        *oid = GSS_C_NO_OID;
17897 +        return GSS_S_COMPLETE;
17898 +    }
17899 +
17900 +    /* we don't know about this OID */
17901 +    return GSS_S_CONTINUE_NEEDED;
17902 +}
17903 +
17904 +OM_uint32
17905 +gssEapCanonicalizeOid(OM_uint32 *minor,
17906 +                      const gss_OID oid,
17907 +                      OM_uint32 flags,
17908 +                      gss_OID *pOid)
17909 +{
17910 +    OM_uint32 major;
17911 +    int mapToNull = 0;
17912 +
17913 +    major = GSS_S_COMPLETE;
17914 +    *minor = 0;
17915 +    *pOid = GSS_C_NULL_OID;
17916 +
17917 +    if (oid == GSS_C_NULL_OID) {
17918 +        if ((flags & OID_FLAG_NULL_VALID) == 0) {
17919 +            *minor = GSSEAP_WRONG_MECH;
17920 +            return GSS_S_BAD_MECH;
17921 +        } else if (flags & OID_FLAG_MAP_NULL_TO_DEFAULT_MECH) {
17922 +            return gssEapDefaultMech(minor, pOid);
17923 +        } else {
17924 +            mapToNull = 1;
17925 +        }
17926 +    } else if (oidEqual(oid, GSS_EAP_MECHANISM)) {
17927 +        if ((flags & OID_FLAG_FAMILY_MECH_VALID) == 0) {
17928 +            *minor = GSSEAP_WRONG_MECH;
17929 +            return GSS_S_BAD_MECH;
17930 +        } else if (flags & OID_FLAG_MAP_FAMILY_MECH_TO_NULL) {
17931 +            mapToNull = 1;
17932 +        }
17933 +    } else if (!gssEapIsConcreteMechanismOid(oid)) {
17934 +        *minor = GSSEAP_WRONG_MECH;
17935 +        return GSS_S_BAD_MECH;
17936 +    }
17937 +
17938 +    if (!mapToNull) {
17939 +        if (!internalizeOid(oid, pOid))
17940 +            major = duplicateOid(minor, oid, pOid);
17941 +    }
17942 +
17943 +    return major;
17944 +}
17945 +
17946 +static gss_buffer_desc gssEapSaslMechs[] = {
17947 +    { sizeof("EAP") - 1,        "EAP",       }, /* not used */
17948 +    { sizeof("EAP-AES128") - 1, "EAP-AES128" },
17949 +    { sizeof("EAP-AES256") - 1, "EAP-AES256" },
17950 +};
17951 +
17952 +gss_buffer_t
17953 +gssEapOidToSaslName(const gss_OID oid)
17954 +{
17955 +    size_t i;
17956 +
17957 +    for (i = 1; i < sizeof(gssEapMechOids)/sizeof(gssEapMechOids[0]); i++) {
17958 +        if (oidEqual(&gssEapMechOids[i], oid))
17959 +            return &gssEapSaslMechs[i];
17960 +    }
17961 +
17962 +    return GSS_C_NO_BUFFER;
17963 +}
17964 +
17965 +gss_OID
17966 +gssEapSaslNameToOid(const gss_buffer_t name)
17967 +{
17968 +    size_t i;
17969 +
17970 +    for (i = 1; i < sizeof(gssEapSaslMechs)/sizeof(gssEapSaslMechs[0]); i++) {
17971 +        if (bufferEqual(&gssEapSaslMechs[i], name))
17972 +            return &gssEapMechOids[i];
17973 +    }
17974 +
17975 +    return GSS_C_NO_OID;
17976 +}
17977 diff --git a/mech_eap/util_moonshot.c b/mech_eap/util_moonshot.c
17978 new file mode 100644
17979 index 0000000..dc0c35e
17980 --- /dev/null
17981 +++ b/mech_eap/util_moonshot.c
17982 @@ -0,0 +1,238 @@
17983 +/*
17984 + * Copyright (c) 2011, JANET(UK)
17985 + * All rights reserved.
17986 + *
17987 + * Redistribution and use in source and binary forms, with or without
17988 + * modification, are permitted provided that the following conditions
17989 + * are met:
17990 + *
17991 + * 1. Redistributions of source code must retain the above copyright
17992 + *    notice, this list of conditions and the following disclaimer.
17993 + *
17994 + * 2. Redistributions in binary form must reproduce the above copyright
17995 + *    notice, this list of conditions and the following disclaimer in the
17996 + *    documentation and/or other materials provided with the distribution.
17997 + *
17998 + * 3. Neither the name of JANET(UK) nor the names of its contributors
17999 + *    may be used to endorse or promote products derived from this software
18000 + *    without specific prior written permission.
18001 + *
18002 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18003 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18004 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18005 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18006 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18007 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18008 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
18009 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
18010 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
18011 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
18012 + * SUCH DAMAGE.
18013 + */
18014 +
18015 +#include "gssapiP_eap.h"
18016 +
18017 +#ifdef HAVE_MOONSHOT_GET_IDENTITY
18018 +#include <libmoonshot.h>
18019 +
18020 +static OM_uint32
18021 +libMoonshotMapError(OM_uint32 *minor,
18022 +                    MoonshotError **pError)
18023 +{
18024 +    MoonshotError *error = *pError;
18025 +
18026 +    GSSEAP_ASSERT(error != NULL);
18027 +
18028 +    switch (error->code) {
18029 +    case MOONSHOT_ERROR_UNABLE_TO_START_SERVICE:
18030 +        *minor = GSSEAP_UNABLE_TO_START_IDENTITY_SERVICE;
18031 +        break;
18032 +    case MOONSHOT_ERROR_NO_IDENTITY_SELECTED:
18033 +        *minor = GSSEAP_NO_IDENTITY_SELECTED;
18034 +        break;
18035 +    case MOONSHOT_ERROR_INSTALLATION_ERROR:
18036 +        *minor = GSSEAP_IDENTITY_SERVICE_INSTALL_ERROR;
18037 +        break;
18038 +    case MOONSHOT_ERROR_OS_ERROR:
18039 +        *minor = GSSEAP_IDENTITY_SERVICE_OS_ERROR;
18040 +        break;
18041 +    case MOONSHOT_ERROR_IPC_ERROR:
18042 +        *minor = GSSEAP_IDENTITY_SERVICE_IPC_ERROR;
18043 +        break;
18044 +    default:
18045 +        *minor = GSSEAP_IDENTITY_SERVICE_UNKNOWN_ERROR;
18046 +        break;
18047 +    }
18048 +
18049 +    gssEapSaveStatusInfo(*minor, error->message);
18050 +    moonshot_error_free(error);
18051 +    *pError = NULL;
18052 +
18053 +    return GSS_S_CRED_UNAVAIL;
18054 +}
18055 +
18056 +OM_uint32
18057 +libMoonshotResolveDefaultIdentity(OM_uint32 *minor,
18058 +                                  const gss_cred_id_t cred,
18059 +                                  gss_name_t *pName)
18060 +{
18061 +    OM_uint32 major, tmpMinor;
18062 +    gss_OID nameMech = gssEapPrimaryMechForCred(cred);
18063 +    gss_name_t name = GSS_C_NO_NAME;
18064 +    gss_buffer_desc tmpBuffer = GSS_C_EMPTY_BUFFER;
18065 +    char *nai = NULL;
18066 +    char *password = NULL;
18067 +    char *serverCertificateHash = NULL;
18068 +    char *caCertificate = NULL;
18069 +    char *subjectNameConstraint = NULL;
18070 +    char *subjectAltNameConstraint = NULL;
18071 +    MoonshotError *error = NULL;
18072 +
18073 +    *pName = GSS_C_NO_NAME;
18074 +
18075 +    if (!moonshot_get_default_identity(&nai,
18076 +                                       &password,
18077 +                                       &serverCertificateHash,
18078 +                                       &caCertificate,
18079 +                                       &subjectNameConstraint,
18080 +                                       &subjectAltNameConstraint,
18081 +                                       &error)) {
18082 +        if (error->code == MOONSHOT_ERROR_NO_IDENTITY_SELECTED) {
18083 +            major = GSS_S_CRED_UNAVAIL;
18084 +            *minor = GSSEAP_NO_DEFAULT_IDENTITY;
18085 +            moonshot_error_free(error);
18086 +        } else
18087 +            major = libMoonshotMapError(minor, &error);
18088 +        goto cleanup;
18089 +    }
18090 +
18091 +    tmpBuffer.value = nai;
18092 +    tmpBuffer.length = strlen(nai);
18093 +
18094 +    major = gssEapImportName(minor, &tmpBuffer, GSS_C_NT_USER_NAME, nameMech, &name);
18095 +    if (GSS_ERROR(major))
18096 +        goto cleanup;
18097 +
18098 +    *pName = name;
18099 +    name = GSS_C_NO_NAME;
18100 +
18101 +cleanup:
18102 +    moonshot_free(nai);
18103 +    moonshot_free(password);
18104 +    moonshot_free(serverCertificateHash);
18105 +    moonshot_free(caCertificate);
18106 +    moonshot_free(subjectNameConstraint);
18107 +    moonshot_free(subjectAltNameConstraint);
18108 +
18109 +    gssEapReleaseName(&tmpMinor, &name);
18110 +
18111 +    return major;
18112 +}
18113 +
18114 +OM_uint32
18115 +libMoonshotResolveInitiatorCred(OM_uint32 *minor,
18116 +                                gss_cred_id_t cred,
18117 +                                const gss_name_t targetName)
18118 +{
18119 +    OM_uint32 major, tmpMinor;
18120 +    gss_OID nameMech = gssEapPrimaryMechForCred(cred);
18121 +    gss_buffer_desc initiator = GSS_C_EMPTY_BUFFER;
18122 +    gss_buffer_desc target = GSS_C_EMPTY_BUFFER;
18123 +    gss_buffer_desc tmpBuffer = GSS_C_EMPTY_BUFFER;
18124 +    char *nai = NULL;
18125 +    char *password = NULL;
18126 +    char *serverCertificateHash = NULL;
18127 +    char *caCertificate = NULL;
18128 +    char *subjectNameConstraint = NULL;
18129 +    char *subjectAltNameConstraint = NULL;
18130 +    MoonshotError *error = NULL;
18131 +
18132 +    if (cred->name != GSS_C_NO_NAME) {
18133 +        major = gssEapExportName(minor, cred->name, &initiator);
18134 +        if (GSS_ERROR(major))
18135 +            goto cleanup;
18136 +    }
18137 +
18138 +    if (targetName != GSS_C_NO_NAME) {
18139 +        major = gssEapExportName(minor, targetName, &target);
18140 +        if (GSS_ERROR(major))
18141 +            goto cleanup;
18142 +    }
18143 +
18144 +    if (!moonshot_get_identity((const char *)initiator.value,
18145 +                               (const char *)cred->password.value,
18146 +                               (const char *)target.value,
18147 +                               &nai,
18148 +                               &password,
18149 +                               &serverCertificateHash,
18150 +                               &caCertificate,
18151 +                               &subjectNameConstraint,
18152 +                               &subjectAltNameConstraint,
18153 +                               &error)) {
18154 +        major = libMoonshotMapError(minor, &error);
18155 +        goto cleanup;
18156 +    }
18157 +
18158 +    gssEapReleaseName(&tmpMinor, &cred->name);
18159 +
18160 +    tmpBuffer.value = nai;
18161 +    tmpBuffer.length = strlen(nai);
18162 +
18163 +    major = gssEapImportName(minor, &tmpBuffer, GSS_C_NT_USER_NAME,
18164 +                             nameMech, &cred->name);
18165 +    if (GSS_ERROR(major))
18166 +        goto cleanup;
18167 +
18168 +    tmpBuffer.value = password;
18169 +    tmpBuffer.length = strlen(password);
18170 +
18171 +    major = gssEapSetCredPassword(minor, cred, &tmpBuffer);
18172 +    if (GSS_ERROR(major))
18173 +        goto cleanup;
18174 +
18175 +    gss_release_buffer(&tmpMinor, &cred->caCertificate);
18176 +    gss_release_buffer(&tmpMinor, &cred->subjectNameConstraint);
18177 +    gss_release_buffer(&tmpMinor, &cred->subjectAltNameConstraint);
18178 +
18179 +    if (serverCertificateHash != NULL) {
18180 +        size_t len = strlen(serverCertificateHash);
18181 +
18182 +        #define HASH_PREFIX             "hash://server/sha256/"
18183 +        #define HASH_PREFIX_LEN         (sizeof(HASH_PREFIX) - 1)
18184 +
18185 +        cred->caCertificate.value = GSSEAP_MALLOC(HASH_PREFIX_LEN + len + 1);
18186 +        if (cred->caCertificate.value == NULL) {
18187 +            major = GSS_S_FAILURE;
18188 +            *minor = ENOMEM;
18189 +            goto cleanup;
18190 +        }
18191 +
18192 +        memcpy(cred->caCertificate.value, HASH_PREFIX, HASH_PREFIX_LEN);
18193 +        memcpy((char *)cred->caCertificate.value + HASH_PREFIX_LEN, serverCertificateHash, len);
18194 +
18195 +        ((char *)cred->caCertificate.value)[HASH_PREFIX_LEN + len] = '\0';
18196 +
18197 +        cred->caCertificate.length = HASH_PREFIX_LEN + len;
18198 +    } else if (caCertificate != NULL) {
18199 +        makeStringBufferOrCleanup(caCertificate, &cred->caCertificate);
18200 +    }
18201 +
18202 +    if (subjectNameConstraint != NULL)
18203 +        makeStringBufferOrCleanup(subjectNameConstraint, &cred->subjectNameConstraint);
18204 +    if (subjectAltNameConstraint != NULL)
18205 +        makeStringBufferOrCleanup(subjectAltNameConstraint, &cred->subjectAltNameConstraint);
18206 +
18207 +cleanup:
18208 +    moonshot_free(nai);
18209 +    moonshot_free(password);
18210 +    moonshot_free(serverCertificateHash);
18211 +    moonshot_free(caCertificate);
18212 +    moonshot_free(subjectNameConstraint);
18213 +    moonshot_free(subjectAltNameConstraint);
18214 +
18215 +    gss_release_buffer(&tmpMinor, &initiator);
18216 +    gss_release_buffer(&tmpMinor, &target);
18217 +
18218 +    return major;
18219 +}
18220 +#endif /* HAVE_MOONSHOT_GET_IDENTITY */
18221 diff --git a/mech_eap/util_name.c b/mech_eap/util_name.c
18222 new file mode 100644
18223 index 0000000..6045724
18224 --- /dev/null
18225 +++ b/mech_eap/util_name.c
18226 @@ -0,0 +1,789 @@
18227 +/*
18228 + * Copyright (c) 2011, JANET(UK)
18229 + * All rights reserved.
18230 + *
18231 + * Redistribution and use in source and binary forms, with or without
18232 + * modification, are permitted provided that the following conditions
18233 + * are met:
18234 + *
18235 + * 1. Redistributions of source code must retain the above copyright
18236 + *    notice, this list of conditions and the following disclaimer.
18237 + *
18238 + * 2. Redistributions in binary form must reproduce the above copyright
18239 + *    notice, this list of conditions and the following disclaimer in the
18240 + *    documentation and/or other materials provided with the distribution.
18241 + *
18242 + * 3. Neither the name of JANET(UK) nor the names of its contributors
18243 + *    may be used to endorse or promote products derived from this software
18244 + *    without specific prior written permission.
18245 + *
18246 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18247 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18248 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18249 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18250 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18251 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18252 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
18253 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
18254 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
18255 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
18256 + * SUCH DAMAGE.
18257 + */
18258 +/*
18259 + * Portions Copyright 2009 by the Massachusetts Institute of Technology.
18260 + * All Rights Reserved.
18261 + *
18262 + * Export of this software from the United States of America may
18263 + *   require a specific license from the United States Government.
18264 + *   It is the responsibility of any person or organization contemplating
18265 + *   export to obtain such a license before exporting.
18266 + *
18267 + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
18268 + * distribute this software and its documentation for any purpose and
18269 + * without fee is hereby granted, provided that the above copyright
18270 + * notice appear in all copies and that both that copyright notice and
18271 + * this permission notice appear in supporting documentation, and that
18272 + * the name of M.I.T. not be used in advertising or publicity pertaining
18273 + * to distribution of the software without specific, written prior
18274 + * permission.  Furthermore if you modify this software you must label
18275 + * your software as modified software and not distribute it in such a
18276 + * fashion that it might be confused with the original M.I.T. software.
18277 + * M.I.T. makes no representations about the suitability of
18278 + * this software for any purpose.  It is provided "as is" without express
18279 + * or implied warranty.
18280 + */
18281 +
18282 +/*
18283 + * Name utility routines.
18284 + */
18285 +
18286 +#include "gssapiP_eap.h"
18287 +
18288 +static gss_OID_desc gssEapNtEapName = {
18289 +    /* 1.3.6.1.4.1.5322.22.2.1  */
18290 +    10, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x02\x01"
18291 +};
18292 +
18293 +gss_OID GSS_EAP_NT_EAP_NAME = &gssEapNtEapName;
18294 +
18295 +OM_uint32
18296 +gssEapAllocName(OM_uint32 *minor, gss_name_t *pName)
18297 +{
18298 +    OM_uint32 tmpMinor;
18299 +    gss_name_t name;
18300 +
18301 +    *pName = GSS_C_NO_NAME;
18302 +
18303 +    name = (gss_name_t)GSSEAP_CALLOC(1, sizeof(*name));
18304 +    if (name == NULL) {
18305 +        *minor = ENOMEM;
18306 +        return GSS_S_FAILURE;
18307 +    }
18308 +
18309 +    if (GSSEAP_MUTEX_INIT(&name->mutex) != 0) {
18310 +        *minor = GSSEAP_GET_LAST_ERROR();
18311 +        gssEapReleaseName(&tmpMinor, &name);
18312 +        return GSS_S_FAILURE;
18313 +    }
18314 +
18315 +    *pName = name;
18316 +
18317 +    return GSS_S_COMPLETE;
18318 +}
18319 +
18320 +OM_uint32
18321 +gssEapReleaseName(OM_uint32 *minor, gss_name_t *pName)
18322 +{
18323 +    gss_name_t name;
18324 +    krb5_context krbContext = NULL;
18325 +    OM_uint32 tmpMinor;
18326 +
18327 +    *minor = 0;
18328 +
18329 +    if (pName == NULL) {
18330 +        return GSS_S_COMPLETE;
18331 +    }
18332 +
18333 +    name = *pName;
18334 +    if (name == GSS_C_NO_NAME) {
18335 +        return GSS_S_COMPLETE;
18336 +    }
18337 +
18338 +    GSSEAP_KRB_INIT(&krbContext);
18339 +    krb5_free_principal(krbContext, name->krbPrincipal);
18340 +    gssEapReleaseOid(&tmpMinor, &name->mechanismUsed);
18341 +#ifdef GSSEAP_ENABLE_ACCEPTOR
18342 +    gssEapReleaseAttrContext(&tmpMinor, name);
18343 +#endif
18344 +
18345 +    GSSEAP_MUTEX_DESTROY(&name->mutex);
18346 +    GSSEAP_FREE(name);
18347 +    *pName = NULL;
18348 +
18349 +    return GSS_S_COMPLETE;
18350 +}
18351 +
18352 +static OM_uint32
18353 +krbPrincipalToName(OM_uint32 *minor,
18354 +                   krb5_principal *principal,
18355 +                   gss_name_t *pName)
18356 +{
18357 +    OM_uint32 major;
18358 +    gss_name_t name;
18359 +
18360 +    major = gssEapAllocName(minor, &name);
18361 +    if (GSS_ERROR(major))
18362 +        return major;
18363 +
18364 +    name->krbPrincipal = *principal;
18365 +    *principal = NULL;
18366 +
18367 +    if (KRB_PRINC_LENGTH(name->krbPrincipal) > 1) {
18368 +        name->flags |= NAME_FLAG_SERVICE;
18369 +    } else {
18370 +        name->flags |= NAME_FLAG_NAI;
18371 +    }
18372 +
18373 +    *pName = name;
18374 +    *minor = 0;
18375 +
18376 +    return GSS_S_COMPLETE;
18377 +}
18378 +
18379 +static char *
18380 +gssEapGetDefaultRealm(krb5_context krbContext)
18381 +{
18382 +    char *defaultRealm = NULL;
18383 +
18384 +    krb5_appdefault_string(krbContext, "eap_gss",
18385 +                           NULL, "default_realm", "", &defaultRealm);
18386 +
18387 +    return defaultRealm;
18388 +}
18389 +
18390 +static OM_uint32
18391 +importServiceName(OM_uint32 *minor,
18392 +                  const gss_buffer_t nameBuffer,
18393 +                  gss_name_t *pName)
18394 +{
18395 +    OM_uint32 major;
18396 +    krb5_error_code code;
18397 +    krb5_context krbContext;
18398 +    krb5_principal krbPrinc;
18399 +    char *service, *host, *realm = NULL;
18400 +
18401 +    GSSEAP_KRB_INIT(&krbContext);
18402 +
18403 +    major = bufferToString(minor, nameBuffer, &service);
18404 +    if (GSS_ERROR(major))
18405 +        return major;
18406 +
18407 +    host = strchr(service, '@');
18408 +    if (host != NULL) {
18409 +        *host = '\0';
18410 +        host++;
18411 +    }
18412 +
18413 +    realm = gssEapGetDefaultRealm(krbContext);
18414 +
18415 +    code = krb5_build_principal(krbContext,
18416 +                                &krbPrinc,
18417 +                                realm != NULL ? strlen(realm) : 0,
18418 +                                realm != NULL ? realm : "",
18419 +                                service,
18420 +                                host,
18421 +                                NULL);
18422 +
18423 +    if (code == 0) {
18424 +        KRB_PRINC_TYPE(krbPrinc) = KRB5_NT_SRV_HST;
18425 +
18426 +        major = krbPrincipalToName(minor, &krbPrinc, pName);
18427 +        if (GSS_ERROR(major))
18428 +            krb5_free_principal(krbContext, krbPrinc);
18429 +    } else {
18430 +        major = GSS_S_FAILURE;
18431 +        *minor = GSSEAP_BAD_SERVICE_NAME;
18432 +    }
18433 +
18434 +    if (realm != NULL)
18435 +        krb5_free_default_realm(krbContext, realm);
18436 +    GSSEAP_FREE(service);
18437 +
18438 +    return major;
18439 +}
18440 +
18441 +#define IMPORT_FLAG_DEFAULT_REALM           0x1
18442 +
18443 +/*
18444 + * Import an EAP name, possibly appending the default GSS EAP realm,
18445 + */
18446 +static OM_uint32
18447 +importEapNameFlags(OM_uint32 *minor,
18448 +                   const gss_buffer_t nameBuffer,
18449 +                   OM_uint32 importFlags,
18450 +                   gss_name_t *pName)
18451 +{
18452 +    OM_uint32 major;
18453 +    krb5_context krbContext;
18454 +    krb5_principal krbPrinc = NULL;
18455 +    krb5_error_code code;
18456 +    char *nameString;
18457 +
18458 +    GSSEAP_KRB_INIT(&krbContext);
18459 +
18460 +    if (nameBuffer == GSS_C_NO_BUFFER) {
18461 +        nameString = "";
18462 +        code = KRB5_PARSE_MALFORMED;
18463 +    } else {
18464 +        major = bufferToString(minor, nameBuffer, &nameString);
18465 +        if (GSS_ERROR(major))
18466 +            return major;
18467 +
18468 +        /*
18469 +         * First, attempt to parse the name on the assumption that it includes
18470 +         * a qualifying realm. This allows us to avoid accidentally appending
18471 +         * the default Kerberos realm to an unqualified name. (A bug in MIT
18472 +         * Kerberos prevents the default realm being set to an empty value.)
18473 +         */
18474 +        code = krb5_parse_name_flags(krbContext, nameString,
18475 +                                     KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &krbPrinc);
18476 +    }
18477 +
18478 +    if (code == KRB5_PARSE_MALFORMED) {
18479 +        char *defaultRealm = NULL;
18480 +        int parseFlags = 0;
18481 +
18482 +        /* Possibly append the default EAP realm if required */
18483 +        if (importFlags & IMPORT_FLAG_DEFAULT_REALM)
18484 +            defaultRealm = gssEapGetDefaultRealm(krbContext);
18485 +
18486 +        /* If no default realm, leave the realm empty in the parsed name */
18487 +        if (defaultRealm == NULL || defaultRealm[0] == '\0')
18488 +            parseFlags |= KRB5_PRINCIPAL_PARSE_NO_REALM;
18489 +
18490 +        code = krb5_parse_name_flags(krbContext, nameString, parseFlags, &krbPrinc);
18491 +
18492 +#ifdef HAVE_HEIMDAL_VERSION
18493 +        if (code == 0 && KRB_PRINC_REALM(krbPrinc) == NULL) {
18494 +            KRB_PRINC_REALM(krbPrinc) = KRB_CALLOC(1, sizeof(char));
18495 +            if (KRB_PRINC_REALM(krbPrinc) == NULL)
18496 +                code = ENOMEM;
18497 +        }
18498 +#endif
18499 +
18500 +        if (defaultRealm != NULL)
18501 +            krb5_free_default_realm(krbContext, defaultRealm);
18502 +    }
18503 +
18504 +    if (nameBuffer != GSS_C_NO_BUFFER)
18505 +        GSSEAP_FREE(nameString);
18506 +
18507 +    if (code != 0) {
18508 +        *minor = code;
18509 +        return GSS_S_FAILURE;
18510 +    }
18511 +
18512 +    GSSEAP_ASSERT(krbPrinc != NULL);
18513 +
18514 +    major = krbPrincipalToName(minor, &krbPrinc, pName);
18515 +    if (GSS_ERROR(major))
18516 +        krb5_free_principal(krbContext, krbPrinc);
18517 +
18518 +    return major;
18519 +}
18520 +
18521 +static OM_uint32
18522 +importEapName(OM_uint32 *minor,
18523 +              const gss_buffer_t nameBuffer,
18524 +              gss_name_t *pName)
18525 +{
18526 +    return importEapNameFlags(minor, nameBuffer, 0, pName);
18527 +}
18528 +
18529 +static OM_uint32
18530 +importUserName(OM_uint32 *minor,
18531 +               const gss_buffer_t nameBuffer,
18532 +               gss_name_t *pName)
18533 +{
18534 +    return importEapNameFlags(minor, nameBuffer, IMPORT_FLAG_DEFAULT_REALM, pName);
18535 +}
18536 +
18537 +static OM_uint32
18538 +importAnonymousName(OM_uint32 *minor,
18539 +                    const gss_buffer_t nameBuffer GSSEAP_UNUSED,
18540 +                    gss_name_t *pName)
18541 +{
18542 +    return importEapNameFlags(minor, GSS_C_NO_BUFFER, 0, pName);
18543 +}
18544 +
18545 +#define UPDATE_REMAIN(n)    do {            \
18546 +        p += (n);                           \
18547 +        remain -= (n);                      \
18548 +    } while (0)
18549 +
18550 +#define CHECK_REMAIN(n)     do {        \
18551 +        if (remain < (n)) {             \
18552 +            major = GSS_S_BAD_NAME;     \
18553 +            *minor = GSSEAP_TOK_TRUNC;  \
18554 +            goto cleanup;               \
18555 +        }                               \
18556 +    } while (0)
18557 +
18558 +OM_uint32
18559 +gssEapImportNameInternal(OM_uint32 *minor,
18560 +                         const gss_buffer_t nameBuffer,
18561 +                         gss_name_t *pName,
18562 +                         OM_uint32 flags)
18563 +{
18564 +    OM_uint32 major, tmpMinor;
18565 +    krb5_context krbContext;
18566 +    unsigned char *p;
18567 +    size_t len, remain;
18568 +    gss_buffer_desc buf;
18569 +    gss_name_t name = GSS_C_NO_NAME;
18570 +    gss_OID mechanismUsed = GSS_C_NO_OID;
18571 +
18572 +    GSSEAP_KRB_INIT(&krbContext);
18573 +
18574 +    p = (unsigned char *)nameBuffer->value;
18575 +    remain = nameBuffer->length;
18576 +
18577 +    if (flags & EXPORT_NAME_FLAG_OID) {
18578 +        gss_OID_desc mech;
18579 +        enum gss_eap_token_type tokType;
18580 +        uint16_t wireTokType;
18581 +
18582 +        /* TOK_ID || MECH_OID_LEN || MECH_OID */
18583 +        if (remain < 6) {
18584 +            *minor = GSSEAP_BAD_NAME_TOKEN;
18585 +            return GSS_S_BAD_NAME;
18586 +        }
18587 +
18588 +        if (flags & EXPORT_NAME_FLAG_COMPOSITE)
18589 +            tokType = TOK_TYPE_EXPORT_NAME_COMPOSITE;
18590 +        else
18591 +            tokType = TOK_TYPE_EXPORT_NAME;
18592 +
18593 +        /* TOK_ID */
18594 +        wireTokType = load_uint16_be(p);
18595 +
18596 +        if ((flags & EXPORT_NAME_FLAG_ALLOW_COMPOSITE) &&
18597 +            wireTokType == TOK_TYPE_EXPORT_NAME_COMPOSITE) {
18598 +            tokType = TOK_TYPE_EXPORT_NAME_COMPOSITE;
18599 +            flags |= EXPORT_NAME_FLAG_COMPOSITE;
18600 +        }
18601 +
18602 +        if (wireTokType != tokType) {
18603 +            *minor = GSSEAP_WRONG_TOK_ID;
18604 +            return GSS_S_BAD_NAME;
18605 +        }
18606 +        UPDATE_REMAIN(2);
18607 +
18608 +        /* MECH_OID_LEN */
18609 +        len = load_uint16_be(p);
18610 +        if (len < 2) {
18611 +            *minor = GSSEAP_BAD_NAME_TOKEN;
18612 +            return GSS_S_BAD_NAME;
18613 +        }
18614 +        UPDATE_REMAIN(2);
18615 +
18616 +        /* MECH_OID */
18617 +        if (p[0] != 0x06) {
18618 +            *minor = GSSEAP_BAD_NAME_TOKEN;
18619 +            return GSS_S_BAD_NAME;
18620 +        }
18621 +
18622 +        mech.length = p[1];
18623 +        mech.elements = &p[2];
18624 +
18625 +        CHECK_REMAIN(mech.length);
18626 +
18627 +        major = gssEapCanonicalizeOid(minor,
18628 +                                      &mech,
18629 +                                      OID_FLAG_FAMILY_MECH_VALID |
18630 +                                        OID_FLAG_MAP_FAMILY_MECH_TO_NULL,
18631 +                                      &mechanismUsed);
18632 +        if (GSS_ERROR(major))
18633 +            goto cleanup;
18634 +
18635 +        UPDATE_REMAIN(2 + mech.length);
18636 +    }
18637 +
18638 +    /* NAME_LEN */
18639 +    CHECK_REMAIN(4);
18640 +    len = load_uint32_be(p);
18641 +    UPDATE_REMAIN(4);
18642 +
18643 +    /* NAME */
18644 +    CHECK_REMAIN(len);
18645 +    buf.length = len;
18646 +    buf.value = p;
18647 +    UPDATE_REMAIN(len);
18648 +
18649 +    major = importEapNameFlags(minor, &buf, 0, &name);
18650 +    if (GSS_ERROR(major))
18651 +        goto cleanup;
18652 +
18653 +    name->mechanismUsed = mechanismUsed;
18654 +    mechanismUsed = GSS_C_NO_OID;
18655 +
18656 +#ifdef GSSEAP_ENABLE_ACCEPTOR
18657 +    if (flags & EXPORT_NAME_FLAG_COMPOSITE) {
18658 +        gss_buffer_desc buf;
18659 +
18660 +        buf.length = remain;
18661 +        buf.value = p;
18662 +
18663 +        major = gssEapImportAttrContext(minor, &buf, name);
18664 +        if (GSS_ERROR(major))
18665 +            goto cleanup;
18666 +    }
18667 +#endif
18668 +
18669 +    major = GSS_S_COMPLETE;
18670 +    *minor = 0;
18671 +
18672 +cleanup:
18673 +    if (GSS_ERROR(major)) {
18674 +        gssEapReleaseOid(&tmpMinor, &mechanismUsed);
18675 +        gssEapReleaseName(&tmpMinor, &name);
18676 +    } else {
18677 +        *pName = name;
18678 +    }
18679 +
18680 +    return major;
18681 +}
18682 +
18683 +static OM_uint32
18684 +importExportName(OM_uint32 *minor,
18685 +                 const gss_buffer_t nameBuffer,
18686 +                 gss_name_t *name)
18687 +{
18688 +    return gssEapImportNameInternal(minor, nameBuffer, name,
18689 +                                    EXPORT_NAME_FLAG_OID |
18690 +                                    EXPORT_NAME_FLAG_ALLOW_COMPOSITE);
18691 +}
18692 +
18693 +#ifdef HAVE_GSS_C_NT_COMPOSITE_EXPORT
18694 +static OM_uint32
18695 +importCompositeExportName(OM_uint32 *minor,
18696 +                          const gss_buffer_t nameBuffer,
18697 +                          gss_name_t *name)
18698 +{
18699 +    return gssEapImportNameInternal(minor, nameBuffer, name,
18700 +                                    EXPORT_NAME_FLAG_OID |
18701 +                                    EXPORT_NAME_FLAG_COMPOSITE);
18702 +}
18703 +#endif
18704 +
18705 +struct gss_eap_name_import_provider {
18706 +    gss_const_OID oid;
18707 +    OM_uint32 (*import)(OM_uint32 *, const gss_buffer_t, gss_name_t *);
18708 +};
18709 +
18710 +OM_uint32
18711 +gssEapImportName(OM_uint32 *minor,
18712 +                 const gss_buffer_t nameBuffer,
18713 +                 const gss_OID nameType,
18714 +                 const gss_OID mechType,
18715 +                 gss_name_t *pName)
18716 +{
18717 +    struct gss_eap_name_import_provider nameTypes[] = {
18718 +        { GSS_EAP_NT_EAP_NAME,              importEapName               },
18719 +        { GSS_C_NT_USER_NAME,               importUserName              },
18720 +        { GSS_C_NT_HOSTBASED_SERVICE,       importServiceName           },
18721 +        { GSS_C_NT_HOSTBASED_SERVICE_X,     importServiceName           },
18722 +        { GSS_C_NT_ANONYMOUS,               importAnonymousName         },
18723 +        { GSS_C_NT_EXPORT_NAME,             importExportName            },
18724 +        { GSS_KRB5_NT_PRINCIPAL_NAME,       importUserName              },
18725 +#ifdef HAVE_GSS_C_NT_COMPOSITE_EXPORT
18726 +        { GSS_C_NT_COMPOSITE_EXPORT,        importCompositeExportName   },
18727 +#endif
18728 +    };
18729 +    size_t i;
18730 +    OM_uint32 major = GSS_S_BAD_NAMETYPE;
18731 +    OM_uint32 tmpMinor;
18732 +    gss_name_t name = GSS_C_NO_NAME;
18733 +
18734 +    for (i = 0; i < sizeof(nameTypes) / sizeof(nameTypes[0]); i++) {
18735 +        if (oidEqual(nameTypes[i].oid,
18736 +                     nameType == GSS_C_NO_OID ? GSS_EAP_NT_EAP_NAME : nameType)) {
18737 +            major = nameTypes[i].import(minor, nameBuffer, &name);
18738 +            break;
18739 +        }
18740 +    }
18741 +
18742 +    if (major == GSS_S_COMPLETE &&
18743 +        mechType != GSS_C_NO_OID) {
18744 +        GSSEAP_ASSERT(gssEapIsConcreteMechanismOid(mechType));
18745 +        GSSEAP_ASSERT(name->mechanismUsed == GSS_C_NO_OID);
18746 +
18747 +        major = gssEapCanonicalizeOid(minor, mechType, 0, &name->mechanismUsed);
18748 +    }
18749 +
18750 +    if (GSS_ERROR(major))
18751 +        gssEapReleaseName(&tmpMinor, &name);
18752 +    else
18753 +        *pName = name;
18754 +
18755 +    return major;
18756 +}
18757 +
18758 +OM_uint32
18759 +gssEapExportName(OM_uint32 *minor,
18760 +                 const gss_name_t name,
18761 +                 gss_buffer_t exportedName)
18762 +{
18763 +    return gssEapExportNameInternal(minor, name, exportedName,
18764 +                                    EXPORT_NAME_FLAG_OID);
18765 +}
18766 +
18767 +OM_uint32
18768 +gssEapExportNameInternal(OM_uint32 *minor,
18769 +                         const gss_name_t name,
18770 +                         gss_buffer_t exportedName,
18771 +                         OM_uint32 flags)
18772 +{
18773 +    OM_uint32 major = GSS_S_FAILURE, tmpMinor;
18774 +    gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
18775 +    size_t exportedNameLen;
18776 +    unsigned char *p;
18777 +    gss_buffer_desc attrs = GSS_C_EMPTY_BUFFER;
18778 +    gss_OID mech;
18779 +
18780 +    exportedName->length = 0;
18781 +    exportedName->value = NULL;
18782 +
18783 +    if (name->mechanismUsed != GSS_C_NO_OID)
18784 +        mech = name->mechanismUsed;
18785 +    else
18786 +        mech = GSS_EAP_MECHANISM;
18787 +
18788 +    major = gssEapDisplayName(minor, name, &nameBuf, NULL);
18789 +    if (GSS_ERROR(major))
18790 +        goto cleanup;
18791 +
18792 +    exportedNameLen = 0;
18793 +    if (flags & EXPORT_NAME_FLAG_OID) {
18794 +        exportedNameLen += 6 + mech->length;
18795 +    }
18796 +    exportedNameLen += 4 + nameBuf.length;
18797 +#ifdef GSSEAP_ENABLE_ACCEPTOR
18798 +    if (flags & EXPORT_NAME_FLAG_COMPOSITE) {
18799 +        major = gssEapExportAttrContext(minor, name, &attrs);
18800 +        if (GSS_ERROR(major))
18801 +            goto cleanup;
18802 +        exportedNameLen += attrs.length;
18803 +    }
18804 +#endif
18805 +
18806 +    exportedName->value = GSSEAP_MALLOC(exportedNameLen);
18807 +    if (exportedName->value == NULL) {
18808 +        major = GSS_S_FAILURE;
18809 +        *minor = ENOMEM;
18810 +        goto cleanup;
18811 +    }
18812 +    exportedName->length = exportedNameLen;
18813 +
18814 +    p = (unsigned char *)exportedName->value;
18815 +
18816 +    if (flags & EXPORT_NAME_FLAG_OID) {
18817 +        /* TOK | MECH_OID_LEN */
18818 +        store_uint16_be((flags & EXPORT_NAME_FLAG_COMPOSITE)
18819 +                        ? TOK_TYPE_EXPORT_NAME_COMPOSITE
18820 +                        : TOK_TYPE_EXPORT_NAME,
18821 +                        p);
18822 +        p += 2;
18823 +        store_uint16_be(mech->length + 2, p);
18824 +        p += 2;
18825 +
18826 +        /* MECH_OID */
18827 +        *p++ = 0x06;
18828 +        *p++ = mech->length & 0xff;
18829 +        memcpy(p, mech->elements, mech->length);
18830 +        p += mech->length;
18831 +    }
18832 +
18833 +    /* NAME_LEN */
18834 +    store_uint32_be(nameBuf.length, p);
18835 +    p += 4;
18836 +
18837 +    /* NAME */
18838 +    memcpy(p, nameBuf.value, nameBuf.length);
18839 +    p += nameBuf.length;
18840 +
18841 +    if (flags & EXPORT_NAME_FLAG_COMPOSITE) {
18842 +        memcpy(p, attrs.value, attrs.length);
18843 +        p += attrs.length;
18844 +    }
18845 +
18846 +    GSSEAP_ASSERT(p == (unsigned char *)exportedName->value + exportedNameLen);
18847 +
18848 +    major = GSS_S_COMPLETE;
18849 +    *minor = 0;
18850 +
18851 +cleanup:
18852 +    gss_release_buffer(&tmpMinor, &attrs);
18853 +    gss_release_buffer(&tmpMinor, &nameBuf);
18854 +    if (GSS_ERROR(major))
18855 +        gss_release_buffer(&tmpMinor, exportedName);
18856 +
18857 +    return major;
18858 +}
18859 +
18860 +OM_uint32
18861 +gssEapCanonicalizeName(OM_uint32 *minor,
18862 +                       const gss_name_t input_name,
18863 +                       const gss_OID mech_type,
18864 +                       gss_name_t *dest_name)
18865 +{
18866 +    OM_uint32 major, tmpMinor;
18867 +    krb5_context krbContext;
18868 +    gss_name_t name;
18869 +    gss_OID mech_used;
18870 +
18871 +    if (input_name == GSS_C_NO_NAME) {
18872 +        *minor = EINVAL;
18873 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
18874 +    }
18875 +
18876 +    GSSEAP_KRB_INIT(&krbContext);
18877 +
18878 +    major = gssEapAllocName(minor, &name);
18879 +    if (GSS_ERROR(major)) {
18880 +        return major;
18881 +    }
18882 +
18883 +    if (mech_type != GSS_C_NO_OID)
18884 +        mech_used = mech_type;
18885 +    else
18886 +        mech_used = input_name->mechanismUsed;
18887 +
18888 +    major = gssEapCanonicalizeOid(minor,
18889 +                                  mech_used,
18890 +                                  OID_FLAG_NULL_VALID,
18891 +                                  &name->mechanismUsed);
18892 +    if (GSS_ERROR(major))
18893 +        goto cleanup;
18894 +
18895 +    name->flags = input_name->flags;
18896 +
18897 +    *minor = krb5_copy_principal(krbContext, input_name->krbPrincipal,
18898 +                                 &name->krbPrincipal);
18899 +    if (*minor != 0) {
18900 +        major = GSS_S_FAILURE;
18901 +        goto cleanup;
18902 +    }
18903 +
18904 +#ifdef GSSEAP_ENABLE_ACCEPTOR
18905 +    if (input_name->attrCtx != NULL) {
18906 +        major = gssEapDuplicateAttrContext(minor, input_name, name);
18907 +        if (GSS_ERROR(major))
18908 +            goto cleanup;
18909 +    }
18910 +#endif
18911 +
18912 +    *dest_name = name;
18913 +
18914 +cleanup:
18915 +    if (GSS_ERROR(major)) {
18916 +        gssEapReleaseName(&tmpMinor, &name);
18917 +    }
18918 +
18919 +    return major;
18920 +}
18921 +
18922 +OM_uint32
18923 +gssEapDuplicateName(OM_uint32 *minor,
18924 +                    const gss_name_t input_name,
18925 +                    gss_name_t *dest_name)
18926 +{
18927 +    return gssEapCanonicalizeName(minor, input_name,
18928 +                                  GSS_C_NO_OID, dest_name);
18929 +}
18930 +
18931 +OM_uint32
18932 +gssEapDisplayName(OM_uint32 *minor,
18933 +                  gss_name_t name,
18934 +                  gss_buffer_t output_name_buffer,
18935 +                  gss_OID *output_name_type)
18936 +{
18937 +    OM_uint32 major;
18938 +    krb5_context krbContext;
18939 +    char *krbName;
18940 +    gss_OID name_type;
18941 +    int flags = 0;
18942 +
18943 +    GSSEAP_KRB_INIT(&krbContext);
18944 +
18945 +    output_name_buffer->length = 0;
18946 +    output_name_buffer->value = NULL;
18947 +
18948 +    if (name == GSS_C_NO_NAME) {
18949 +        *minor = EINVAL;
18950 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
18951 +    }
18952 +
18953 +    /*
18954 +     * According to draft-ietf-abfab-gss-eap-01, when the realm is
18955 +     * absent the trailing '@' is not included.
18956 +     */
18957 +#ifdef HAVE_HEIMDAL_VERSION
18958 +    if (KRB_PRINC_REALM(name->krbPrincipal) == NULL ||
18959 +        KRB_PRINC_REALM(name->krbPrincipal)[0] == '\0')
18960 +#else
18961 +    if (KRB_PRINC_REALM(name->krbPrincipal)->length == 0)
18962 +#endif
18963 +        flags |= KRB5_PRINCIPAL_UNPARSE_NO_REALM;
18964 +
18965 +    *minor = krb5_unparse_name_flags(krbContext, name->krbPrincipal,
18966 +                                     flags, &krbName);
18967 +    if (*minor != 0) {
18968 +        return GSS_S_FAILURE;
18969 +    }
18970 +
18971 +    major = makeStringBuffer(minor, krbName, output_name_buffer);
18972 +    if (GSS_ERROR(major)) {
18973 +        krb5_free_unparsed_name(krbContext, krbName);
18974 +        return major;
18975 +    }
18976 +
18977 +    krb5_free_unparsed_name(krbContext, krbName);
18978 +
18979 +    if (output_name_buffer->length == 0) {
18980 +        name_type = GSS_C_NT_ANONYMOUS;
18981 +    } else if (name->flags & NAME_FLAG_NAI) {
18982 +        name_type = GSS_C_NT_USER_NAME;
18983 +    } else {
18984 +        name_type = GSS_EAP_NT_EAP_NAME;
18985 +    }
18986 +
18987 +    if (output_name_type != NULL)
18988 +        *output_name_type = name_type;
18989 +
18990 +    return GSS_S_COMPLETE;
18991 +}
18992 +
18993 +OM_uint32
18994 +gssEapCompareName(OM_uint32 *minor,
18995 +                  gss_name_t name1,
18996 +                  gss_name_t name2,
18997 +                  int *name_equal)
18998 +{
18999 +    krb5_context krbContext;
19000 +
19001 +    *minor = 0;
19002 +
19003 +    if (name1 == GSS_C_NO_NAME && name2 == GSS_C_NO_NAME) {
19004 +        *name_equal = 1;
19005 +    } else if (name1 != GSS_C_NO_NAME && name2 != GSS_C_NO_NAME) {
19006 +        GSSEAP_KRB_INIT(&krbContext);
19007 +
19008 +        /* krbPrincipal is immutable, so lock not required */
19009 +        *name_equal = krb5_principal_compare(krbContext,
19010 +                                             name1->krbPrincipal,
19011 +                                             name2->krbPrincipal);
19012 +    }
19013 +
19014 +    return GSS_S_COMPLETE;
19015 +}
19016 diff --git a/mech_eap/util_oid.c b/mech_eap/util_oid.c
19017 new file mode 100644
19018 index 0000000..096c9f8
19019 --- /dev/null
19020 +++ b/mech_eap/util_oid.c
19021 @@ -0,0 +1,206 @@
19022 +/*
19023 + * Copyright (c) 2011, JANET(UK)
19024 + * All rights reserved.
19025 + *
19026 + * Redistribution and use in source and binary forms, with or without
19027 + * modification, are permitted provided that the following conditions
19028 + * are met:
19029 + *
19030 + * 1. Redistributions of source code must retain the above copyright
19031 + *    notice, this list of conditions and the following disclaimer.
19032 + *
19033 + * 2. Redistributions in binary form must reproduce the above copyright
19034 + *    notice, this list of conditions and the following disclaimer in the
19035 + *    documentation and/or other materials provided with the distribution.
19036 + *
19037 + * 3. Neither the name of JANET(UK) nor the names of its contributors
19038 + *    may be used to endorse or promote products derived from this software
19039 + *    without specific prior written permission.
19040 + *
19041 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19042 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19043 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19044 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19045 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19046 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19047 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19048 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
19049 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
19050 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
19051 + * SUCH DAMAGE.
19052 + */
19053 +/*
19054 + * Copyright 1995-2010 by the Massachusetts Institute of Technology.
19055 + * All Rights Reserved.
19056 + *
19057 + * Export of this software from the United States of America may
19058 + *   require a specific license from the United States Government.
19059 + *   It is the responsibility of any person or organization contemplating
19060 + *   export to obtain such a license before exporting.
19061 + *
19062 + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
19063 + * distribute this software and its documentation for any purpose and
19064 + * without fee is hereby granted, provided that the above copyright
19065 + * notice appear in all copies and that both that copyright notice and
19066 + * this permission notice appear in supporting documentation, and that
19067 + * the name of M.I.T. not be used in advertising or publicity pertaining
19068 + * to distribution of the software without specific, written prior
19069 + * permission.  Furthermore if you modify this software you must label
19070 + * your software as modified software and not distribute it in such a
19071 + * fashion that it might be confused with the original M.I.T. software.
19072 + * M.I.T. makes no representations about the suitability of
19073 + * this software for any purpose.  It is provided "as is" without express
19074 + * or implied warranty.
19075 + *
19076 + */
19077 +
19078 +/*
19079 + * OID utility routines.
19080 + */
19081 +
19082 +#include "gssapiP_eap.h"
19083 +
19084 +OM_uint32
19085 +duplicateOid(OM_uint32 *minor,
19086 +             const gss_OID_desc * const oid,
19087 +             gss_OID *newOid)
19088 +{
19089 +    gss_OID p;
19090 +
19091 +    *newOid = GSS_C_NO_OID;
19092 +
19093 +    p = (gss_OID)GSSEAP_MALLOC(sizeof(*p));
19094 +    if (p == NULL) {
19095 +        *minor = ENOMEM;
19096 +        return GSS_S_FAILURE;
19097 +    }
19098 +    p->length = oid->length;
19099 +    p->elements = GSSEAP_MALLOC(p->length);
19100 +    if (p->elements == NULL) {
19101 +        GSSEAP_FREE(p);
19102 +        *minor = ENOMEM;
19103 +        return GSS_S_FAILURE;
19104 +    }
19105 +
19106 +    memcpy(p->elements, oid->elements, p->length);
19107 +    *newOid = p;
19108 +
19109 +    *minor = 0;
19110 +    return GSS_S_COMPLETE;
19111 +}
19112 +
19113 +/* Compose an OID of a prefix and an integer suffix */
19114 +OM_uint32
19115 +composeOid(OM_uint32 *minor,
19116 +           const char *prefix,
19117 +           size_t prefix_len,
19118 +           int suffix,
19119 +           gss_OID_desc *oid)
19120 +{
19121 +    int osuffix, i;
19122 +    size_t nbytes;
19123 +    unsigned char *op;
19124 +
19125 +    if (oid == GSS_C_NO_OID) {
19126 +        *minor = EINVAL;
19127 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_FAILURE;
19128 +    }
19129 +
19130 +    if (oid->length < prefix_len) {
19131 +        *minor = GSSEAP_WRONG_SIZE;
19132 +        return GSS_S_FAILURE;
19133 +    }
19134 +
19135 +    memcpy(oid->elements, prefix, prefix_len);
19136 +
19137 +    nbytes = 0;
19138 +    osuffix = suffix;
19139 +    while (suffix) {
19140 +        nbytes++;
19141 +        suffix >>= 7;
19142 +    }
19143 +    suffix = osuffix;
19144 +
19145 +    if (oid->length < prefix_len + nbytes) {
19146 +        *minor = GSSEAP_WRONG_SIZE;
19147 +        return GSS_S_FAILURE;
19148 +    }
19149 +
19150 +    op = (unsigned char *) oid->elements + prefix_len + nbytes;
19151 +    i = -1;
19152 +    while (suffix) {
19153 +        op[i] = (unsigned char)suffix & 0x7f;
19154 +        if (i != -1)
19155 +            op[i] |= 0x80;
19156 +        i--;
19157 +        suffix >>= 7;
19158 +    }
19159 +
19160 +    oid->length = prefix_len + nbytes;
19161 +
19162 +    *minor = 0;
19163 +    return GSS_S_COMPLETE;
19164 +}
19165 +
19166 +OM_uint32
19167 +decomposeOid(OM_uint32 *minor,
19168 +             const char *prefix,
19169 +             size_t prefix_len,
19170 +             gss_OID_desc *oid,
19171 +             int *suffix)
19172 +{
19173 +    size_t i, slen;
19174 +    unsigned char *op;
19175 +
19176 +    if (oid->length < prefix_len ||
19177 +        memcmp(oid->elements, prefix, prefix_len) != 0) {
19178 +        return GSS_S_BAD_MECH;
19179 +    }
19180 +
19181 +    op = (unsigned char *) oid->elements + prefix_len;
19182 +
19183 +    *suffix = 0;
19184 +
19185 +    slen = oid->length - prefix_len;
19186 +
19187 +    for (i = 0; i < slen; i++) {
19188 +        *suffix = (*suffix << 7) | (op[i] & 0x7f);
19189 +        if (i + 1 != slen && (op[i] & 0x80) == 0) {
19190 +            *minor = GSSEAP_WRONG_SIZE;
19191 +            return GSS_S_FAILURE;
19192 +        }
19193 +    }
19194 +
19195 +    return GSS_S_COMPLETE;
19196 +}
19197 +
19198 +OM_uint32
19199 +duplicateOidSet(OM_uint32 *minor,
19200 +                const gss_OID_set src,
19201 +                gss_OID_set *dst)
19202 +{
19203 +    OM_uint32 major, tmpMinor;
19204 +    int i;
19205 +
19206 +    if (src == GSS_C_NO_OID_SET) {
19207 +        *dst = GSS_C_NO_OID_SET;
19208 +        return GSS_S_COMPLETE;
19209 +    }
19210 +
19211 +    major = gss_create_empty_oid_set(minor, dst);
19212 +    if (GSS_ERROR(major))
19213 +        return major;
19214 +
19215 +    for (i = 0; i < src->count; i++) {
19216 +        gss_OID oid = &src->elements[i];
19217 +
19218 +        major = gss_add_oid_set_member(minor, oid, dst);
19219 +        if (GSS_ERROR(major))
19220 +            break;
19221 +    }
19222 +
19223 +    if (GSS_ERROR(major))
19224 +        gss_release_oid_set(&tmpMinor, dst);
19225 +
19226 +    return major;
19227 +}
19228 diff --git a/mech_eap/util_ordering.c b/mech_eap/util_ordering.c
19229 new file mode 100644
19230 index 0000000..71ebfb5
19231 --- /dev/null
19232 +++ b/mech_eap/util_ordering.c
19233 @@ -0,0 +1,302 @@
19234 +/*
19235 + * Copyright (c) 2011, JANET(UK)
19236 + * All rights reserved.
19237 + *
19238 + * Redistribution and use in source and binary forms, with or without
19239 + * modification, are permitted provided that the following conditions
19240 + * are met:
19241 + *
19242 + * 1. Redistributions of source code must retain the above copyright
19243 + *    notice, this list of conditions and the following disclaimer.
19244 + *
19245 + * 2. Redistributions in binary form must reproduce the above copyright
19246 + *    notice, this list of conditions and the following disclaimer in the
19247 + *    documentation and/or other materials provided with the distribution.
19248 + *
19249 + * 3. Neither the name of JANET(UK) nor the names of its contributors
19250 + *    may be used to endorse or promote products derived from this software
19251 + *    without specific prior written permission.
19252 + *
19253 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19254 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19255 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19256 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19257 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19258 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19259 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19260 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
19261 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
19262 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
19263 + * SUCH DAMAGE.
19264 + */
19265 +/*
19266 + * Copyright 1993 by OpenVision Technologies, Inc.
19267 + *
19268 + * Permission to use, copy, modify, distribute, and sell this software
19269 + * and its documentation for any purpose is hereby granted without fee,
19270 + * provided that the above copyright notice appears in all copies and
19271 + * that both that copyright notice and this permission notice appear in
19272 + * supporting documentation, and that the name of OpenVision not be used
19273 + * in advertising or publicity pertaining to distribution of the software
19274 + * without specific, written prior permission. OpenVision makes no
19275 + * representations about the suitability of this software for any
19276 + * purpose.  It is provided "as is" without express or implied warranty.
19277 + *
19278 + * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
19279 + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19280 + * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19281 + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
19282 + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
19283 + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19284 + * PERFORMANCE OF THIS SOFTWARE.
19285 + */
19286 +
19287 +/*
19288 + * Functions to check sequence numbers for replay and sequencing
19289 + */
19290 +
19291 +#include "gssapiP_eap.h"
19292 +
19293 +#define QUEUE_LENGTH 20
19294 +
19295 +typedef struct _queue {
19296 +    int do_replay;
19297 +    int do_sequence;
19298 +    int start;
19299 +    int length;
19300 +    uint64_t firstnum;
19301 +    /* Stored as deltas from firstnum.  This way, the high bit won't
19302 +       overflow unless we've actually gone through 2**n messages, or
19303 +       gotten something *way* out of sequence.  */
19304 +    uint64_t elem[QUEUE_LENGTH];
19305 +    /* All ones for 64-bit sequence numbers; 32 ones for 32-bit
19306 +       sequence numbers.  */
19307 +    uint64_t mask;
19308 +} queue;
19309 +
19310 +/* rep invariant:
19311 + *  - the queue is a circular queue.  The first element (q->elem[q->start])
19312 + * is the oldest.  The last element is the newest.
19313 + */
19314 +
19315 +#define QSIZE(q) (sizeof((q)->elem)/sizeof((q)->elem[0]))
19316 +#define QELEM(q,i) ((q)->elem[(i)%QSIZE(q)])
19317 +
19318 +static void
19319 +queue_insert(queue *q, int after, uint64_t seqnum)
19320 +{
19321 +    /* insert.  this is not the fastest way, but it's easy, and it's
19322 +       optimized for insert at end, which is the common case */
19323 +    int i;
19324 +
19325 +    /* common case: at end, after == q->start+q->length-1 */
19326 +
19327 +    /* move all the elements (after,last] up one slot */
19328 +
19329 +    for (i = q->start + q->length - 1; i > after; i--)
19330 +        QELEM(q,i+1) = QELEM(q,i);
19331 +
19332 +    /* fill in slot after+1 */
19333 +
19334 +    QELEM(q,after+1) = seqnum;
19335 +
19336 +    /* Either increase the length by one, or move the starting point up
19337 +       one (deleting the first element, which got bashed above), as
19338 +       appropriate. */
19339 +
19340 +    if (q->length == QSIZE(q)) {
19341 +        q->start++;
19342 +        if (q->start == QSIZE(q))
19343 +            q->start = 0;
19344 +    } else {
19345 +        q->length++;
19346 +    }
19347 +}
19348 +
19349 +OM_uint32
19350 +sequenceInit(OM_uint32 *minor,
19351 +             void **vqueue,
19352 +             uint64_t seqnum,
19353 +             int do_replay,
19354 +             int do_sequence,
19355 +             int wide_nums)
19356 +{
19357 +    queue *q;
19358 +
19359 +    q = (queue *)GSSEAP_CALLOC(1, sizeof(queue));
19360 +    if (q == NULL) {
19361 +        *minor = ENOMEM;
19362 +        return GSS_S_FAILURE;
19363 +    }
19364 +
19365 +    q->do_replay = do_replay;
19366 +    q->do_sequence = do_sequence;
19367 +    q->mask = wide_nums ? ~(uint64_t)0 : 0xffffffffUL;
19368 +
19369 +    q->start = 0;
19370 +    q->length = 1;
19371 +    q->firstnum = seqnum;
19372 +    q->elem[q->start] = ((uint64_t)0 - 1) & q->mask;
19373 +
19374 +    *vqueue = (void *)q;
19375 +
19376 +    return GSS_S_COMPLETE;
19377 +}
19378 +
19379 +OM_uint32
19380 +sequenceCheck(OM_uint32 *minor,
19381 +              void **vqueue,
19382 +              uint64_t seqnum)
19383 +{
19384 +    queue *q;
19385 +    int i;
19386 +    uint64_t expected;
19387 +
19388 +    *minor = 0;
19389 +
19390 +    q = (queue *) (*vqueue);
19391 +
19392 +    if (!q->do_replay && !q->do_sequence)
19393 +        return GSS_S_COMPLETE;
19394 +
19395 +    /* All checks are done relative to the initial sequence number, to
19396 +       avoid (or at least put off) the pain of wrapping.  */
19397 +    seqnum -= q->firstnum;
19398 +    /* If we're only doing 32-bit values, adjust for that again.
19399 +
19400 +       Note that this will probably be the wrong thing to if we get
19401 +       2**32 messages sent with 32-bit sequence numbers.  */
19402 +    seqnum &= q->mask;
19403 +
19404 +    /* rule 1: expected sequence number */
19405 +
19406 +    expected = (QELEM(q,q->start+q->length-1)+1) & q->mask;
19407 +    if (seqnum == expected) {
19408 +        queue_insert(q, q->start+q->length-1, seqnum);
19409 +        return GSS_S_COMPLETE;
19410 +    }
19411 +
19412 +    /* rule 2: > expected sequence number */
19413 +
19414 +    if ((seqnum > expected)) {
19415 +        queue_insert(q, q->start+q->length-1, seqnum);
19416 +        if (q->do_replay && !q->do_sequence)
19417 +            return GSS_S_COMPLETE;
19418 +        else
19419 +            return GSS_S_GAP_TOKEN;
19420 +    }
19421 +
19422 +    /* rule 3: seqnum < seqnum(first) */
19423 +
19424 +    if ((seqnum < QELEM(q,q->start)) &&
19425 +        /* Is top bit of whatever width we're using set?
19426 +
19427 +           We used to check for greater than or equal to firstnum, but
19428 +           (1) we've since switched to compute values relative to
19429 +           firstnum, so the lowest we can have is 0, and (2) the effect
19430 +           of the original scheme was highly dependent on whether
19431 +           firstnum was close to either side of 0.  (Consider
19432 +           firstnum==0xFFFFFFFE and we miss three packets; the next
19433 +           packet is *new* but would look old.)
19434 +
19435 +           This check should give us 2**31 or 2**63 messages "new", and
19436 +           just as many "old".  That's not quite right either.  */
19437 +        (seqnum & (1 + (q->mask >> 1)))
19438 +    ) {
19439 +        if (q->do_replay && !q->do_sequence)
19440 +            return GSS_S_OLD_TOKEN;
19441 +        else
19442 +            return GSS_S_UNSEQ_TOKEN;
19443 +    }
19444 +
19445 +    /* rule 4+5: seqnum in [seqnum(first),seqnum(last)]  */
19446 +
19447 +    else {
19448 +        if (seqnum == QELEM(q,q->start+q->length - 1))
19449 +            return GSS_S_DUPLICATE_TOKEN;
19450 +
19451 +        for (i = q->start; i < q->start + q->length - 1; i++) {
19452 +            if (seqnum == QELEM(q,i))
19453 +                return GSS_S_DUPLICATE_TOKEN;
19454 +            if ((seqnum > QELEM(q,i)) && (seqnum < QELEM(q,i+1))) {
19455 +                queue_insert(q, i, seqnum);
19456 +                if (q->do_replay && !q->do_sequence)
19457 +                    return GSS_S_COMPLETE;
19458 +                else
19459 +                    return GSS_S_UNSEQ_TOKEN;
19460 +            }
19461 +        }
19462 +    }
19463 +
19464 +    /* this should never happen */
19465 +    return GSS_S_FAILURE;
19466 +}
19467 +
19468 +OM_uint32
19469 +sequenceFree(OM_uint32 *minor, void **vqueue)
19470 +{
19471 +    queue *q;
19472 +
19473 +    q = (queue *) (*vqueue);
19474 +
19475 +    GSSEAP_FREE(q);
19476 +
19477 +    *vqueue = NULL;
19478 +
19479 +    *minor = 0;
19480 +    return GSS_S_COMPLETE;
19481 +}
19482 +
19483 +/*
19484 + * These support functions are for the serialization routines
19485 + */
19486 +size_t
19487 +sequenceSize(void *vqueue GSSEAP_UNUSED)
19488 +{
19489 +    return sizeof(queue);
19490 +}
19491 +
19492 +OM_uint32
19493 +sequenceExternalize(OM_uint32 *minor,
19494 +                    void *vqueue,
19495 +                    unsigned char **buf,
19496 +                    size_t *lenremain)
19497 +{
19498 +    if (*lenremain < sizeof(queue)) {
19499 +        *minor = GSSEAP_WRONG_SIZE;
19500 +        return GSS_S_FAILURE;
19501 +    }
19502 +    memcpy(*buf, vqueue, sizeof(queue));
19503 +    *buf += sizeof(queue);
19504 +    *lenremain -= sizeof(queue);
19505 +
19506 +    return 0;
19507 +}
19508 +
19509 +OM_uint32
19510 +sequenceInternalize(OM_uint32 *minor,
19511 +                    void **vqueue,
19512 +                    unsigned char **buf,
19513 +                    size_t *lenremain)
19514 +{
19515 +    void *q;
19516 +
19517 +    if (*lenremain < sizeof(queue)) {
19518 +        *minor = GSSEAP_TOK_TRUNC;
19519 +        return GSS_S_DEFECTIVE_TOKEN;
19520 +    }
19521 +
19522 +    q = GSSEAP_MALLOC(sizeof(queue));
19523 +    if (q == NULL) {
19524 +        *minor = ENOMEM;
19525 +        return GSS_S_FAILURE;
19526 +    }
19527 +
19528 +    memcpy(q, *buf, sizeof(queue));
19529 +    *buf += sizeof(queue);
19530 +    *lenremain -= sizeof(queue);
19531 +    *vqueue = q;
19532 +
19533 +    *minor = 0;
19534 +    return GSS_S_COMPLETE;
19535 +}
19536 diff --git a/mech_eap/util_radius.cpp b/mech_eap/util_radius.cpp
19537 new file mode 100644
19538 index 0000000..9111e20
19539 --- /dev/null
19540 +++ b/mech_eap/util_radius.cpp
19541 @@ -0,0 +1,899 @@
19542 +/*
19543 + * Copyright (c) 2011, JANET(UK)
19544 + * All rights reserved.
19545 + *
19546 + * Redistribution and use in source and binary forms, with or without
19547 + * modification, are permitted provided that the following conditions
19548 + * are met:
19549 + *
19550 + * 1. Redistributions of source code must retain the above copyright
19551 + *    notice, this list of conditions and the following disclaimer.
19552 + *
19553 + * 2. Redistributions in binary form must reproduce the above copyright
19554 + *    notice, this list of conditions and the following disclaimer in the
19555 + *    documentation and/or other materials provided with the distribution.
19556 + *
19557 + * 3. Neither the name of JANET(UK) nor the names of its contributors
19558 + *    may be used to endorse or promote products derived from this software
19559 + *    without specific prior written permission.
19560 + *
19561 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19562 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19563 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19564 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19565 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19566 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19567 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19568 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
19569 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
19570 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
19571 + * SUCH DAMAGE.
19572 + */
19573 +
19574 +/*
19575 + * RADIUS attribute provider implementation.
19576 + */
19577 +
19578 +#include "gssapiP_eap.h"
19579 +
19580 +/* stuff that should be provided by libradsec/libfreeradius-radius */
19581 +#define VENDORATTR(vendor, attr)            (((vendor) << 16) | (attr))
19582 +
19583 +#ifndef ATTRID
19584 +#define ATTRID(attr)                        ((attr) & 0xFFFF)
19585 +#endif
19586 +
19587 +static gss_buffer_desc radiusUrnPrefix = {
19588 +    sizeof("urn:x-radius:") - 1,
19589 +    (void *)"urn:x-radius:"
19590 +};
19591 +
19592 +static VALUE_PAIR *copyAvps(const VALUE_PAIR *src);
19593 +
19594 +gss_eap_radius_attr_provider::gss_eap_radius_attr_provider(void)
19595 +{
19596 +    m_vps = NULL;
19597 +    m_authenticated = false;
19598 +}
19599 +
19600 +gss_eap_radius_attr_provider::~gss_eap_radius_attr_provider(void)
19601 +{
19602 +    if (m_vps != NULL)
19603 +        pairfree(&m_vps);
19604 +}
19605 +
19606 +bool
19607 +gss_eap_radius_attr_provider::initWithExistingContext(const gss_eap_attr_ctx *manager,
19608 +                                                      const gss_eap_attr_provider *ctx)
19609 +{
19610 +    const gss_eap_radius_attr_provider *radius;
19611 +
19612 +    if (!gss_eap_attr_provider::initWithExistingContext(manager, ctx))
19613 +        return false;
19614 +
19615 +    radius = static_cast<const gss_eap_radius_attr_provider *>(ctx);
19616 +
19617 +    if (radius->m_vps != NULL)
19618 +        m_vps = copyAvps(const_cast<VALUE_PAIR *>(radius->getAvps()));
19619 +
19620 +    m_authenticated = radius->m_authenticated;
19621 +
19622 +    return true;
19623 +}
19624 +
19625 +bool
19626 +gss_eap_radius_attr_provider::initWithGssContext(const gss_eap_attr_ctx *manager,
19627 +                                                 const gss_cred_id_t gssCred,
19628 +                                                 const gss_ctx_id_t gssCtx)
19629 +{
19630 +    if (!gss_eap_attr_provider::initWithGssContext(manager, gssCred, gssCtx))
19631 +        return false;
19632 +
19633 +    if (gssCtx != GSS_C_NO_CONTEXT) {
19634 +        if (gssCtx->acceptorCtx.vps != NULL) {
19635 +            m_vps = copyAvps(gssCtx->acceptorCtx.vps);
19636 +            if (m_vps == NULL)
19637 +                return false;
19638 +
19639 +            /* We assume libradsec validated this for us */
19640 +            GSSEAP_ASSERT(pairfind(m_vps, PW_MESSAGE_AUTHENTICATOR) != NULL);
19641 +            m_authenticated = true;
19642 +        }
19643 +    }
19644 +
19645 +    return true;
19646 +}
19647 +
19648 +static bool
19649 +alreadyAddedAttributeP(std::vector <std::string> &attrs, VALUE_PAIR *vp)
19650 +{
19651 +    for (std::vector<std::string>::const_iterator a = attrs.begin();
19652 +         a != attrs.end();
19653 +         ++a) {
19654 +        if (strcmp(vp->name, (*a).c_str()) == 0)
19655 +            return true;
19656 +    }
19657 +
19658 +    return false;
19659 +}
19660 +
19661 +static bool
19662 +isSecretAttributeP(uint16_t attrid, uint16_t vendor)
19663 +{
19664 +    bool bSecretAttribute = false;
19665 +
19666 +    switch (vendor) {
19667 +    case VENDORPEC_MS:
19668 +        switch (attrid) {
19669 +        case PW_MS_MPPE_SEND_KEY:
19670 +        case PW_MS_MPPE_RECV_KEY:
19671 +            bSecretAttribute = true;
19672 +            break;
19673 +        default:
19674 +            break;
19675 +        }
19676 +    default:
19677 +        break;
19678 +    }
19679 +
19680 +    return bSecretAttribute;
19681 +}
19682 +
19683 +static bool
19684 +isSecretAttributeP(uint32_t attribute)
19685 +{
19686 +    return isSecretAttributeP(ATTRID(attribute), VENDOR(attribute));
19687 +}
19688 +
19689 +static bool
19690 +isInternalAttributeP(uint16_t attrid, uint16_t vendor)
19691 +{
19692 +    bool bInternalAttribute = false;
19693 +
19694 +    /* should have been filtered */
19695 +    GSSEAP_ASSERT(!isSecretAttributeP(attrid, vendor));
19696 +
19697 +    switch (vendor) {
19698 +    case VENDORPEC_UKERNA:
19699 +        switch (attrid) {
19700 +        case PW_GSS_ACCEPTOR_SERVICE_NAME:
19701 +        case PW_GSS_ACCEPTOR_HOST_NAME:
19702 +        case PW_GSS_ACCEPTOR_SERVICE_SPECIFIC:
19703 +        case PW_GSS_ACCEPTOR_REALM_NAME:
19704 +        case PW_SAML_AAA_ASSERTION:
19705 +            bInternalAttribute = true;
19706 +            break;
19707 +        default:
19708 +            break;
19709 +        }
19710 +        break;
19711 +    default:
19712 +        break;
19713 +    }
19714 +
19715 +    return bInternalAttribute;
19716 +}
19717 +
19718 +static bool
19719 +isInternalAttributeP(uint32_t attribute)
19720 +{
19721 +    return isInternalAttributeP(ATTRID(attribute), VENDOR(attribute));
19722 +}
19723 +
19724 +static bool
19725 +isFragmentedAttributeP(uint16_t attrid, uint16_t vendor)
19726 +{
19727 +    /* A bit of a hack for the PAC for now. Should be configurable. */
19728 +    return (vendor == VENDORPEC_UKERNA) &&
19729 +        !isInternalAttributeP(attrid, vendor);
19730 +}
19731 +
19732 +static bool
19733 +isFragmentedAttributeP(uint32_t attribute)
19734 +{
19735 +    return isFragmentedAttributeP(ATTRID(attribute), VENDOR(attribute));
19736 +}
19737 +
19738 +/*
19739 + * Copy AVP list, same as paircopy except it filters out attributes
19740 + * containing keys.
19741 + */
19742 +static VALUE_PAIR *
19743 +copyAvps(const VALUE_PAIR *src)
19744 +{
19745 +    const VALUE_PAIR *vp;
19746 +    VALUE_PAIR *dst = NULL, **pDst = &dst;
19747 +
19748 +    for (vp = src; vp != NULL; vp = vp->next) {
19749 +        VALUE_PAIR *vpcopy;
19750 +
19751 +        if (isSecretAttributeP(vp->attribute))
19752 +            continue;
19753 +
19754 +        vpcopy = paircopyvp(vp);
19755 +        if (vpcopy == NULL) {
19756 +            pairfree(&dst);
19757 +            throw std::bad_alloc();
19758 +        }
19759 +        *pDst = vpcopy;
19760 +        pDst = &vpcopy->next;
19761 +     }
19762 +
19763 +    return dst;
19764 +}
19765 +
19766 +bool
19767 +gss_eap_radius_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
19768 +                                                void *data) const
19769 +{
19770 +    VALUE_PAIR *vp;
19771 +    std::vector <std::string> seen;
19772 +
19773 +    for (vp = m_vps; vp != NULL; vp = vp->next) {
19774 +        gss_buffer_desc attribute;
19775 +        char attrid[64];
19776 +
19777 +        /* Don't advertise attributes that are internal to the GSS-EAP mechanism */
19778 +        if (isInternalAttributeP(vp->attribute))
19779 +            continue;
19780 +
19781 +        if (alreadyAddedAttributeP(seen, vp))
19782 +            continue;
19783 +
19784 +        snprintf(attrid, sizeof(attrid), "%s%d",
19785 +            (char *)radiusUrnPrefix.value, vp->attribute);
19786 +
19787 +        attribute.value = attrid;
19788 +        attribute.length = strlen(attrid);
19789 +
19790 +        if (!addAttribute(m_manager, this, &attribute, data))
19791 +            return false;
19792 +
19793 +        seen.push_back(std::string(vp->name));
19794 +    }
19795 +
19796 +    return true;
19797 +}
19798 +
19799 +uint32_t
19800 +getAttributeId(const gss_buffer_t attr)
19801 +{
19802 +    OM_uint32 tmpMinor;
19803 +    gss_buffer_desc strAttr = GSS_C_EMPTY_BUFFER;
19804 +    DICT_ATTR *da;
19805 +    char *s;
19806 +    uint32_t attrid = 0;
19807 +
19808 +    if (attr->length < radiusUrnPrefix.length ||
19809 +        memcmp(attr->value, radiusUrnPrefix.value, radiusUrnPrefix.length) != 0)
19810 +        return 0;
19811 +
19812 +    /* need to duplicate because attr may not be NUL terminated */
19813 +    duplicateBuffer(*attr, &strAttr);
19814 +    s = (char *)strAttr.value + radiusUrnPrefix.length;
19815 +
19816 +    if (isdigit(*s)) {
19817 +        attrid = strtoul(s, NULL, 10);
19818 +    } else {
19819 +        da = dict_attrbyname(s);
19820 +        if (da != NULL)
19821 +            attrid = da->attr;
19822 +    }
19823 +
19824 +    gss_release_buffer(&tmpMinor, &strAttr);
19825 +
19826 +    return attrid;
19827 +}
19828 +
19829 +bool
19830 +gss_eap_radius_attr_provider::setAttribute(int complete GSSEAP_UNUSED,
19831 +                                           uint32_t attrid,
19832 +                                           const gss_buffer_t value)
19833 +{
19834 +    OM_uint32 major = GSS_S_UNAVAILABLE, minor;
19835 +
19836 +    if (!isSecretAttributeP(attrid) &&
19837 +        !isInternalAttributeP(attrid)) {
19838 +        deleteAttribute(attrid);
19839 +
19840 +        major = gssEapRadiusAddAvp(&minor, &m_vps,
19841 +                                   ATTRID(attrid), VENDOR(attrid), 
19842 +                                   value);
19843 +    }
19844 +
19845 +    return !GSS_ERROR(major);
19846 +}
19847 +
19848 +bool
19849 +gss_eap_radius_attr_provider::setAttribute(int complete,
19850 +                                           const gss_buffer_t attr,
19851 +                                           const gss_buffer_t value)
19852 +{
19853 +    uint32_t attrid = getAttributeId(attr);
19854 +
19855 +    if (!attrid)
19856 +        return false;
19857 +
19858 +    return setAttribute(complete, attrid, value);
19859 +}
19860 +
19861 +bool
19862 +gss_eap_radius_attr_provider::deleteAttribute(uint32_t attrid)
19863 +{
19864 +    if (isSecretAttributeP(attrid) || isInternalAttributeP(attrid) ||
19865 +        pairfind(m_vps, attrid) == NULL)
19866 +        return false;
19867 +
19868 +    pairdelete(&m_vps, attrid);
19869 +
19870 +    return true;
19871 +}
19872 +
19873 +bool
19874 +gss_eap_radius_attr_provider::deleteAttribute(const gss_buffer_t attr)
19875 +{
19876 +    uint32_t attrid = getAttributeId(attr);
19877 +
19878 +    if (!attrid)
19879 +        return false;
19880 +
19881 +    return deleteAttribute(attrid);
19882 +}
19883 +
19884 +bool
19885 +gss_eap_radius_attr_provider::getAttribute(const gss_buffer_t attr,
19886 +                                           int *authenticated,
19887 +                                           int *complete,
19888 +                                           gss_buffer_t value,
19889 +                                           gss_buffer_t display_value,
19890 +                                           int *more) const
19891 +{
19892 +    uint32_t attrid;
19893 +
19894 +    attrid = getAttributeId(attr);
19895 +    if (!attrid)
19896 +        return false;
19897 +
19898 +    return getAttribute(attrid, authenticated, complete,
19899 +                        value, display_value, more);
19900 +}
19901 +
19902 +bool
19903 +gss_eap_radius_attr_provider::getAttribute(uint32_t attrid,
19904 +                                           int *authenticated,
19905 +                                           int *complete,
19906 +                                           gss_buffer_t value,
19907 +                                           gss_buffer_t display_value,
19908 +                                           int *more) const
19909 +{
19910 +    VALUE_PAIR *vp;
19911 +    int i = *more, count = 0;
19912 +
19913 +    *more = 0;
19914 +
19915 +    if (i == -1)
19916 +        i = 0;
19917 +
19918 +    if (isSecretAttributeP(attrid) || isInternalAttributeP(attrid)) {
19919 +        return false;
19920 +    } else if (isFragmentedAttributeP(attrid)) {
19921 +        return getFragmentedAttribute(attrid,
19922 +                                      authenticated,
19923 +                                      complete,
19924 +                                      value);
19925 +    }
19926 +
19927 +    for (vp = pairfind(m_vps, attrid);
19928 +         vp != NULL;
19929 +         vp = pairfind(vp->next, attrid)) {
19930 +        if (count++ == i) {
19931 +            if (pairfind(vp->next, attrid) != NULL)
19932 +                *more = count;
19933 +            break;
19934 +        }
19935 +    }
19936 +
19937 +    if (vp == NULL && *more == 0)
19938 +        return false;
19939 +
19940 +    if (value != GSS_C_NO_BUFFER) {
19941 +        gss_buffer_desc valueBuf;
19942 +
19943 +        valueBuf.value = (void *)vp->vp_octets;
19944 +        valueBuf.length = vp->length;
19945 +
19946 +        duplicateBuffer(valueBuf, value);
19947 +    }
19948 +
19949 +    if (display_value != GSS_C_NO_BUFFER &&
19950 +        vp->type != PW_TYPE_OCTETS) {
19951 +        char displayString[MAX_STRING_LEN];
19952 +        gss_buffer_desc displayBuf;
19953 +
19954 +        displayBuf.length = vp_prints_value(displayString,
19955 +                                            sizeof(displayString), vp, 0);
19956 +        displayBuf.value = (void *)displayString;
19957 +
19958 +        duplicateBuffer(displayBuf, display_value);
19959 +    }
19960 +
19961 +    if (authenticated != NULL)
19962 +        *authenticated = m_authenticated;
19963 +    if (complete != NULL)
19964 +        *complete = true;
19965 +
19966 +    return true;
19967 +}
19968 +
19969 +bool
19970 +gss_eap_radius_attr_provider::getFragmentedAttribute(uint16_t attribute,
19971 +                                                     uint16_t vendor,
19972 +                                                     int *authenticated,
19973 +                                                     int *complete,
19974 +                                                     gss_buffer_t value) const
19975 +{
19976 +    OM_uint32 major, minor;
19977 +
19978 +    major = gssEapRadiusGetAvp(&minor, m_vps, attribute, vendor, value, TRUE);
19979 +
19980 +    if (authenticated != NULL)
19981 +        *authenticated = m_authenticated;
19982 +    if (complete != NULL)
19983 +        *complete = true;
19984 +
19985 +    return !GSS_ERROR(major);
19986 +}
19987 +
19988 +bool
19989 +gss_eap_radius_attr_provider::getFragmentedAttribute(uint32_t attrid,
19990 +                                                     int *authenticated,
19991 +                                                     int *complete,
19992 +                                                     gss_buffer_t value) const
19993 +{
19994 +    return getFragmentedAttribute(ATTRID(attrid), VENDOR(attrid),
19995 +                                  authenticated, complete, value);
19996 +}
19997 +
19998 +bool
19999 +gss_eap_radius_attr_provider::getAttribute(uint16_t attribute,
20000 +                                           uint16_t vendor,
20001 +                                           int *authenticated,
20002 +                                           int *complete,
20003 +                                           gss_buffer_t value,
20004 +                                           gss_buffer_t display_value,
20005 +                                           int *more) const
20006 +{
20007 +
20008 +    return getAttribute(VENDORATTR(attribute, vendor),
20009 +                        authenticated, complete,
20010 +                        value, display_value, more);
20011 +}
20012 +
20013 +gss_any_t
20014 +gss_eap_radius_attr_provider::mapToAny(int authenticated,
20015 +                                       gss_buffer_t type_id GSSEAP_UNUSED) const
20016 +{
20017 +    if (authenticated && !m_authenticated)
20018 +        return (gss_any_t)NULL;
20019 +
20020 +    return (gss_any_t)copyAvps(m_vps);
20021 +}
20022 +
20023 +void
20024 +gss_eap_radius_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED,
20025 +                                                    gss_any_t input) const
20026 +{
20027 +    VALUE_PAIR *vp = (VALUE_PAIR *)input;
20028 +    pairfree(&vp);
20029 +}
20030 +
20031 +bool
20032 +gss_eap_radius_attr_provider::init(void)
20033 +{
20034 +    gss_eap_attr_ctx::registerProvider(ATTR_TYPE_RADIUS, createAttrContext);
20035 +
20036 +    return true;
20037 +}
20038 +
20039 +void
20040 +gss_eap_radius_attr_provider::finalize(void)
20041 +{
20042 +    gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_RADIUS);
20043 +}
20044 +
20045 +gss_eap_attr_provider *
20046 +gss_eap_radius_attr_provider::createAttrContext(void)
20047 +{
20048 +    return new gss_eap_radius_attr_provider;
20049 +}
20050 +
20051 +OM_uint32
20052 +gssEapRadiusAddAvp(OM_uint32 *minor,
20053 +                   VALUE_PAIR **vps,
20054 +                   uint16_t attribute,
20055 +                   uint16_t vendor,
20056 +                   const gss_buffer_t buffer)
20057 +{
20058 +    uint32_t attrid = VENDORATTR(vendor, attribute);
20059 +    unsigned char *p = (unsigned char *)buffer->value;
20060 +    size_t remain = buffer->length;
20061 +
20062 +    do {
20063 +        VALUE_PAIR *vp;
20064 +        size_t n = remain;
20065 +
20066 +        /*
20067 +         * There's an extra byte of padding; RADIUS AVPs can only
20068 +         * be 253 octets.
20069 +         */
20070 +        if (n >= MAX_STRING_LEN)
20071 +            n = MAX_STRING_LEN - 1;
20072 +
20073 +        vp = paircreate(attrid, PW_TYPE_OCTETS);
20074 +        if (vp == NULL) {
20075 +            *minor = ENOMEM;
20076 +            return GSS_S_FAILURE;
20077 +        }
20078 +
20079 +        memcpy(vp->vp_octets, p, n);
20080 +        vp->length = n;
20081 +
20082 +        pairadd(vps, vp);
20083 +
20084 +        p += n;
20085 +        remain -= n;
20086 +    } while (remain != 0);
20087 +
20088 +    return GSS_S_COMPLETE;
20089 +}
20090 +
20091 +OM_uint32
20092 +gssEapRadiusGetRawAvp(OM_uint32 *minor,
20093 +                      VALUE_PAIR *vps,
20094 +                      uint16_t attribute,
20095 +                      uint16_t vendor,
20096 +                      VALUE_PAIR **vp)
20097 +{
20098 +    uint32_t attr = VENDORATTR(vendor, attribute);
20099 +
20100 +    *vp = pairfind(vps, attr);
20101 +    if (*vp == NULL) {
20102 +        *minor = GSSEAP_NO_SUCH_ATTR;
20103 +        return GSS_S_UNAVAILABLE;
20104 +    }
20105 +
20106 +    return GSS_S_COMPLETE;
20107 +}
20108 +
20109 +OM_uint32
20110 +gssEapRadiusGetAvp(OM_uint32 *minor,
20111 +                   VALUE_PAIR *vps,
20112 +                   uint16_t attribute,
20113 +                   uint16_t vendor,
20114 +                   gss_buffer_t buffer,
20115 +                   int concat)
20116 +{
20117 +    VALUE_PAIR *vp;
20118 +    unsigned char *p;
20119 +    uint32_t attr = VENDORATTR(vendor, attribute);
20120 +
20121 +    if (buffer != GSS_C_NO_BUFFER) {
20122 +        buffer->length = 0;
20123 +        buffer->value = NULL;
20124 +    }
20125 +
20126 +    vp = pairfind(vps, attr);
20127 +    if (vp == NULL) {
20128 +        *minor = GSSEAP_NO_SUCH_ATTR;
20129 +        return GSS_S_UNAVAILABLE;
20130 +    }
20131 +
20132 +    if (buffer != GSS_C_NO_BUFFER) {
20133 +        do {
20134 +            buffer->length += vp->length;
20135 +        } while (concat && (vp = pairfind(vp->next, attr)) != NULL);
20136 +
20137 +        buffer->value = GSSEAP_MALLOC(buffer->length);
20138 +        if (buffer->value == NULL) {
20139 +            *minor = ENOMEM;
20140 +            return GSS_S_FAILURE;
20141 +        }
20142 +
20143 +        p = (unsigned char *)buffer->value;
20144 +
20145 +        for (vp = pairfind(vps, attr);
20146 +             concat && vp != NULL;
20147 +             vp = pairfind(vp->next, attr)) {
20148 +            memcpy(p, vp->vp_octets, vp->length);
20149 +            p += vp->length;
20150 +        }
20151 +    }
20152 +
20153 +    *minor = 0;
20154 +    return GSS_S_COMPLETE;
20155 +}
20156 +
20157 +OM_uint32
20158 +gssEapRadiusFreeAvps(OM_uint32 *minor,
20159 +                     VALUE_PAIR **vps)
20160 +{
20161 +    pairfree(vps);
20162 +    *minor = 0;
20163 +    return GSS_S_COMPLETE;
20164 +}
20165 +
20166 +OM_uint32
20167 +gssEapRadiusAttrProviderInit(OM_uint32 *minor)
20168 +{
20169 +    if (!gss_eap_radius_attr_provider::init()) {
20170 +        *minor = GSSEAP_RADSEC_INIT_FAILURE;
20171 +        return GSS_S_FAILURE;
20172 +    }
20173 +
20174 +    return GSS_S_COMPLETE;
20175 +}
20176 +
20177 +OM_uint32
20178 +gssEapRadiusAttrProviderFinalize(OM_uint32 *minor)
20179 +{
20180 +    gss_eap_radius_attr_provider::finalize();
20181 +
20182 +    *minor = 0;
20183 +    return GSS_S_COMPLETE;
20184 +}
20185 +
20186 +static JSONObject
20187 +avpToJson(const VALUE_PAIR *vp)
20188 +{
20189 +    JSONObject obj;
20190 +
20191 +    GSSEAP_ASSERT(vp->length <= MAX_STRING_LEN);
20192 +
20193 +    switch (vp->type) {
20194 +    case PW_TYPE_INTEGER:
20195 +    case PW_TYPE_IPADDR:
20196 +    case PW_TYPE_DATE:
20197 +        obj.set("value", vp->lvalue);
20198 +        break;
20199 +    case PW_TYPE_STRING:
20200 +        obj.set("value", vp->vp_strvalue);
20201 +        break;
20202 +    default: {
20203 +        char *b64;
20204 +
20205 +        if (base64Encode(vp->vp_octets, vp->length, &b64) < 0)
20206 +            throw std::bad_alloc();
20207 +
20208 +        obj.set("value", b64);
20209 +        GSSEAP_FREE(b64);
20210 +        break;
20211 +    }
20212 +    }
20213 +
20214 +    obj.set("type", vp->attribute);
20215 +
20216 +    return obj;
20217 +}
20218 +
20219 +static bool
20220 +jsonToAvp(VALUE_PAIR **pVp, JSONObject &obj)
20221 +{
20222 +    VALUE_PAIR *vp = NULL;
20223 +    DICT_ATTR *da;
20224 +    uint32_t attrid;
20225 +
20226 +    JSONObject type = obj["type"];
20227 +    JSONObject value = obj["value"];
20228 +
20229 +    if (!type.isInteger())
20230 +        goto fail;
20231 +
20232 +    attrid = type.integer();
20233 +    da = dict_attrbyvalue(attrid);
20234 +    if (da != NULL) {
20235 +        vp = pairalloc(da);
20236 +    } else {
20237 +        int type = base64Valid(value.string()) ?
20238 +            PW_TYPE_OCTETS : PW_TYPE_STRING;
20239 +        vp = paircreate(attrid, type);
20240 +    }
20241 +    if (vp == NULL)
20242 +        throw std::bad_alloc();
20243 +
20244 +    switch (vp->type) {
20245 +    case PW_TYPE_INTEGER:
20246 +    case PW_TYPE_IPADDR:
20247 +    case PW_TYPE_DATE:
20248 +        if (!value.isInteger())
20249 +            goto fail;
20250 +
20251 +        vp->length = 4;
20252 +        vp->lvalue = value.integer();
20253 +        break;
20254 +    case PW_TYPE_STRING: {
20255 +        if (!value.isString())
20256 +            goto fail;
20257 +
20258 +        const char *str = value.string();
20259 +        size_t len = strlen(str);
20260 +
20261 +        if (len >= MAX_STRING_LEN)
20262 +            goto fail;
20263 +
20264 +        vp->length = len;
20265 +        memcpy(vp->vp_strvalue, str, len + 1);
20266 +        break;
20267 +    }
20268 +    case PW_TYPE_OCTETS:
20269 +    default: {
20270 +        if (!value.isString())
20271 +            goto fail;
20272 +
20273 +        const char *str = value.string();
20274 +        ssize_t len = strlen(str);
20275 +
20276 +        /* this optimization requires base64Decode only understand packed encoding */
20277 +        if (len >= BASE64_EXPAND(MAX_STRING_LEN))
20278 +            goto fail;
20279 +
20280 +        len = base64Decode(str, vp->vp_octets);
20281 +        if (len < 0)
20282 +            goto fail;
20283 +
20284 +        vp->length = len;
20285 +        break;
20286 +    }
20287 +    }
20288 +
20289 +    *pVp = vp;
20290 +
20291 +    return true;
20292 +
20293 +fail:
20294 +    if (vp != NULL)
20295 +        pairbasicfree(vp);
20296 +    *pVp = NULL;
20297 +    return false;
20298 +}
20299 +
20300 +const char *
20301 +gss_eap_radius_attr_provider::name(void) const
20302 +{
20303 +    return "radius";
20304 +}
20305 +
20306 +bool
20307 +gss_eap_radius_attr_provider::initWithJsonObject(const gss_eap_attr_ctx *ctx,
20308 +                                                 JSONObject &obj)
20309 +{
20310 +    VALUE_PAIR **pNext = &m_vps;
20311 +
20312 +    if (!gss_eap_attr_provider::initWithJsonObject(ctx, obj))
20313 +        return false;
20314 +
20315 +    JSONObject attrs = obj["attributes"];
20316 +    size_t nelems = attrs.size();
20317 +
20318 +    for (size_t i = 0; i < nelems; i++) {
20319 +        JSONObject attr = attrs[i];
20320 +        VALUE_PAIR *vp;
20321 +
20322 +        if (!jsonToAvp(&vp, attr))
20323 +            return false;
20324 +
20325 +        *pNext = vp;
20326 +        pNext = &vp->next;
20327 +    }
20328 +
20329 +    m_authenticated = obj["authenticated"].integer() ? true : false;
20330 +
20331 +    return true;
20332 +}
20333 +
20334 +const char *
20335 +gss_eap_radius_attr_provider::prefix(void) const
20336 +{
20337 +    return "urn:ietf:params:gss-eap:radius-avp";
20338 +}
20339 +
20340 +JSONObject
20341 +gss_eap_radius_attr_provider::jsonRepresentation(void) const
20342 +{
20343 +    JSONObject obj, attrs = JSONObject::array();
20344 +
20345 +    for (VALUE_PAIR *vp = m_vps; vp != NULL; vp = vp->next) {
20346 +        JSONObject attr = avpToJson(vp);
20347 +        attrs.append(attr);
20348 +    }
20349 +
20350 +    obj.set("attributes", attrs);
20351 +
20352 +    obj.set("authenticated", m_authenticated);
20353 +
20354 +    return obj;
20355 +}
20356 +
20357 +time_t
20358 +gss_eap_radius_attr_provider::getExpiryTime(void) const
20359 +{
20360 +    VALUE_PAIR *vp;
20361 +
20362 +    vp = pairfind(m_vps, PW_SESSION_TIMEOUT);
20363 +    if (vp == NULL || vp->lvalue == 0)
20364 +        return 0;
20365 +
20366 +    return time(NULL) + vp->lvalue;
20367 +}
20368 +
20369 +OM_uint32
20370 +gssEapRadiusMapError(OM_uint32 *minor,
20371 +                     struct rs_error *err)
20372 +{
20373 +    int code;
20374 +
20375 +    GSSEAP_ASSERT(err != NULL);
20376 +
20377 +    code = rs_err_code(err, 0);
20378 +
20379 +    if (code == RSE_OK) {
20380 +        *minor = 0;
20381 +        return GSS_S_COMPLETE;
20382 +    }
20383 +
20384 +    *minor = ERROR_TABLE_BASE_rse + code;
20385 +
20386 +    gssEapSaveStatusInfo(*minor, "%s", rs_err_msg(err));
20387 +    rs_err_free(err);
20388 +
20389 +    return GSS_S_FAILURE;
20390 +}
20391 +
20392 +OM_uint32
20393 +gssEapCreateRadiusContext(OM_uint32 *minor,
20394 +                          gss_cred_id_t cred,
20395 +                          struct rs_context **pRadContext)
20396 +{
20397 +    const char *configFile = RS_CONFIG_FILE;
20398 +    struct rs_context *radContext;
20399 +    struct rs_alloc_scheme ralloc;
20400 +    struct rs_error *err;
20401 +    OM_uint32 major;
20402 +
20403 +    *pRadContext = NULL;
20404 +
20405 +    if (rs_context_create(&radContext) != 0) {
20406 +        *minor = GSSEAP_RADSEC_CONTEXT_FAILURE;
20407 +        return GSS_S_FAILURE;
20408 +    }
20409 +
20410 +    if (cred->radiusConfigFile.value != NULL)
20411 +        configFile = (const char *)cred->radiusConfigFile.value;
20412 +
20413 +    ralloc.calloc  = GSSEAP_CALLOC;
20414 +    ralloc.malloc  = GSSEAP_MALLOC;
20415 +    ralloc.free    = GSSEAP_FREE;
20416 +    ralloc.realloc = GSSEAP_REALLOC;
20417 +
20418 +    rs_context_set_alloc_scheme(radContext, &ralloc);
20419 +
20420 +    if (rs_context_read_config(radContext, configFile) != 0) {
20421 +        err = rs_err_ctx_pop(radContext);
20422 +        goto fail;
20423 +    }
20424 +
20425 +    if (rs_context_init_freeradius_dict(radContext, NULL) != 0) {
20426 +        err = rs_err_ctx_pop(radContext);
20427 +        goto fail;
20428 +    }
20429 +
20430 +    *pRadContext = radContext;
20431 +
20432 +    *minor = 0;
20433 +    return GSS_S_COMPLETE;
20434 +
20435 +fail:
20436 +    major = gssEapRadiusMapError(minor, err);
20437 +    rs_context_destroy(radContext);
20438 +
20439 +    return major;
20440 +}
20441 diff --git a/mech_eap/util_radius.h b/mech_eap/util_radius.h
20442 new file mode 100644
20443 index 0000000..481876a
20444 --- /dev/null
20445 +++ b/mech_eap/util_radius.h
20446 @@ -0,0 +1,183 @@
20447 +/*
20448 + * Copyright (c) 2011, JANET(UK)
20449 + * All rights reserved.
20450 + *
20451 + * Redistribution and use in source and binary forms, with or without
20452 + * modification, are permitted provided that the following conditions
20453 + * are met:
20454 + *
20455 + * 1. Redistributions of source code must retain the above copyright
20456 + *    notice, this list of conditions and the following disclaimer.
20457 + *
20458 + * 2. Redistributions in binary form must reproduce the above copyright
20459 + *    notice, this list of conditions and the following disclaimer in the
20460 + *    documentation and/or other materials provided with the distribution.
20461 + *
20462 + * 3. Neither the name of JANET(UK) nor the names of its contributors
20463 + *    may be used to endorse or promote products derived from this software
20464 + *    without specific prior written permission.
20465 + *
20466 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20467 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20468 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20469 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20470 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20471 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20472 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20473 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20474 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
20475 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
20476 + * SUCH DAMAGE.
20477 + */
20478 +
20479 +/*
20480 + * RADIUS attribute provider.
20481 + */
20482 +
20483 +#ifndef _UTIL_RADIUS_H_
20484 +#define _UTIL_RADIUS_H_ 1
20485 +
20486 +#ifdef __cplusplus
20487 +
20488 +struct gss_eap_radius_attr_provider : gss_eap_attr_provider {
20489 +public:
20490 +    gss_eap_radius_attr_provider(void);
20491 +    ~gss_eap_radius_attr_provider(void);
20492 +
20493 +    bool initWithExistingContext(const gss_eap_attr_ctx *source,
20494 +                                 const gss_eap_attr_provider *ctx);
20495 +    bool initWithGssContext(const gss_eap_attr_ctx *source,
20496 +                            const gss_cred_id_t cred,
20497 +                            const gss_ctx_id_t ctx);
20498 +
20499 +    bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const;
20500 +    bool setAttribute(int complete,
20501 +                      const gss_buffer_t attr,
20502 +                      const gss_buffer_t value);
20503 +    bool deleteAttribute(const gss_buffer_t attr);
20504 +    bool getAttribute(const gss_buffer_t attr,
20505 +                      int *authenticated,
20506 +                      int *complete,
20507 +                      gss_buffer_t value,
20508 +                      gss_buffer_t display_value,
20509 +                      int *more) const;
20510 +    gss_any_t mapToAny(int authenticated,
20511 +                       gss_buffer_t type_id) const;
20512 +    void releaseAnyNameMapping(gss_buffer_t type_id,
20513 +                               gss_any_t input) const;
20514 +
20515 +    const char *prefix(void) const;
20516 +    const char *name(void) const;
20517 +    bool initWithJsonObject(const gss_eap_attr_ctx *manager,
20518 +                           JSONObject &obj);
20519 +    JSONObject jsonRepresentation(void) const;
20520 +
20521 +    bool getAttribute(uint32_t attribute,
20522 +                      int *authenticated,
20523 +                      int *complete,
20524 +                      gss_buffer_t value,
20525 +                      gss_buffer_t display_value,
20526 +                      int *more) const;
20527 +    bool getAttribute(uint16_t attribute,
20528 +                      uint16_t vendor,
20529 +                      int *authenticated,
20530 +                      int *complete,
20531 +                      gss_buffer_t value,
20532 +                      gss_buffer_t display_value,
20533 +                      int *more) const;
20534 +    bool setAttribute(int complete,
20535 +                      uint32_t attribute,
20536 +                      const gss_buffer_t value);
20537 +    bool deleteAttribute(uint32_t attribute);
20538 +
20539 +    bool getFragmentedAttribute(uint16_t attribute,
20540 +                                uint16_t vendor,
20541 +                                int *authenticated,
20542 +                                int *complete,
20543 +                                gss_buffer_t value) const;
20544 +    bool getFragmentedAttribute(uint32_t attrid,
20545 +                                int *authenticated,
20546 +                                int *complete,
20547 +                                gss_buffer_t value) const;
20548 +
20549 +    bool authenticated(void) const { return m_authenticated; }
20550 +
20551 +    time_t getExpiryTime(void) const;
20552 +
20553 +    static bool init(void);
20554 +    static void finalize(void);
20555 +
20556 +    static gss_eap_attr_provider *createAttrContext(void);
20557 +
20558 +private:
20559 +    const VALUE_PAIR *getAvps(void) const {
20560 +        return m_vps;
20561 +    }
20562 +
20563 +    VALUE_PAIR *m_vps;
20564 +    bool m_authenticated;
20565 +};
20566 +
20567 +/* For now */
20568 +extern "C" {
20569 +#endif
20570 +
20571 +OM_uint32
20572 +gssEapRadiusAddAvp(OM_uint32 *minor,
20573 +                   VALUE_PAIR **vp,
20574 +                   uint16_t type,
20575 +                   uint16_t vendor,
20576 +                   const gss_buffer_t buffer);
20577 +
20578 +OM_uint32
20579 +gssEapRadiusGetAvp(OM_uint32 *minor,
20580 +                   VALUE_PAIR *vps,
20581 +                   uint16_t type,
20582 +                   uint16_t vendor,
20583 +                   gss_buffer_t buffer,
20584 +                   int concat);
20585 +
20586 +OM_uint32
20587 +gssEapRadiusGetRawAvp(OM_uint32 *minor,
20588 +                      VALUE_PAIR *vps,
20589 +                      uint16_t type,
20590 +                      uint16_t vendor,
20591 +                      VALUE_PAIR **vp);
20592 +OM_uint32
20593 +gssEapRadiusFreeAvps(OM_uint32 *minor,
20594 +                     VALUE_PAIR **vps);
20595 +
20596 +OM_uint32 gssEapRadiusAttrProviderInit(OM_uint32 *minor);
20597 +OM_uint32 gssEapRadiusAttrProviderFinalize(OM_uint32 *minor);
20598 +
20599 +OM_uint32
20600 +gssEapRadiusMapError(OM_uint32 *minor,
20601 +                     struct rs_error *err);
20602 +
20603 +OM_uint32
20604 +gssEapCreateRadiusContext(OM_uint32 *minor,
20605 +                          gss_cred_id_t cred,
20606 +                          struct rs_context **pRadContext);
20607 +
20608 +/* This really needs to be a function call on Windows */
20609 +#define RS_CONFIG_FILE      SYSCONFDIR "/radsec.conf"
20610 +
20611 +#define VENDORPEC_MS                        311 /* RFC 2548 */
20612 +
20613 +#define PW_MS_MPPE_SEND_KEY                 16
20614 +#define PW_MS_MPPE_RECV_KEY                 17
20615 +
20616 +#define VENDORPEC_UKERNA                    25622
20617 +
20618 +#define PW_GSS_ACCEPTOR_SERVICE_NAME        128
20619 +#define PW_GSS_ACCEPTOR_HOST_NAME           129
20620 +#define PW_GSS_ACCEPTOR_SERVICE_SPECIFIC    130
20621 +#define PW_GSS_ACCEPTOR_REALM_NAME          131
20622 +#define PW_SAML_AAA_ASSERTION               132
20623 +#define PW_MS_WINDOWS_AUTH_DATA             133
20624 +
20625 +#ifdef __cplusplus
20626 +}
20627 +#endif
20628 +
20629 +#endif /* _UTIL_RADIUS_H_ */
20630 diff --git a/mech_eap/util_reauth.c b/mech_eap/util_reauth.c
20631 new file mode 100644
20632 index 0000000..50011ca
20633 --- /dev/null
20634 +++ b/mech_eap/util_reauth.c
20635 @@ -0,0 +1,1196 @@
20636 +/*
20637 + * Copyright (c) 2011, JANET(UK)
20638 + * All rights reserved.
20639 + *
20640 + * Redistribution and use in source and binary forms, with or without
20641 + * modification, are permitted provided that the following conditions
20642 + * are met:
20643 + *
20644 + * 1. Redistributions of source code must retain the above copyright
20645 + *    notice, this list of conditions and the following disclaimer.
20646 + *
20647 + * 2. Redistributions in binary form must reproduce the above copyright
20648 + *    notice, this list of conditions and the following disclaimer in the
20649 + *    documentation and/or other materials provided with the distribution.
20650 + *
20651 + * 3. Neither the name of JANET(UK) nor the names of its contributors
20652 + *    may be used to endorse or promote products derived from this software
20653 + *    without specific prior written permission.
20654 + *
20655 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20656 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20657 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20658 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20659 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20660 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20661 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20662 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20663 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
20664 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
20665 + * SUCH DAMAGE.
20666 + */
20667 +
20668 +/*
20669 + * Fast reauthentication support.
20670 + */
20671 +
20672 +#include "gssapiP_eap.h"
20673 +
20674 +#include <dlfcn.h>
20675 +
20676 +/*
20677 + * Fast reauthentication support for EAP GSS.
20678 + */
20679 +
20680 +krb5_error_code
20681 +krb5_encrypt_tkt_part(krb5_context, const krb5_keyblock *, krb5_ticket *);
20682 +
20683 +krb5_error_code
20684 +encode_krb5_ticket(const krb5_ticket *rep, krb5_data **code);
20685 +
20686 +static OM_uint32
20687 +gssDisplayName(OM_uint32 *minor,
20688 +               gss_name_t name,
20689 +               gss_buffer_t buffer,
20690 +               gss_OID *name_type);
20691 +
20692 +static OM_uint32
20693 +gssImportName(OM_uint32 *minor,
20694 +              gss_buffer_t buffer,
20695 +              gss_OID name_type,
20696 +              gss_name_t *name);
20697 +
20698 +static krb5_error_code
20699 +getAcceptorKey(krb5_context krbContext,
20700 +               gss_ctx_id_t ctx,
20701 +               gss_cred_id_t cred,
20702 +               krb5_principal *princ,
20703 +               krb5_keyblock *key)
20704 +{
20705 +    krb5_error_code code;
20706 +    krb5_keytab keytab = NULL;
20707 +    krb5_keytab_entry ktent = { 0 };
20708 +    krb5_kt_cursor cursor;
20709 +
20710 +    *princ = NULL;
20711 +    memset(key, 0, sizeof(*key));
20712 +    memset(&cursor, 0, sizeof(cursor));
20713 +
20714 +    code = krb5_kt_default(krbContext, &keytab);
20715 +    if (code != 0)
20716 +        goto cleanup;
20717 +
20718 +    if (cred != GSS_C_NO_CREDENTIAL && cred->name != GSS_C_NO_NAME) {
20719 +        code = krb5_kt_get_entry(krbContext, keytab,
20720 +                                 cred->name->krbPrincipal, 0,
20721 +                                 ctx->encryptionType, &ktent);
20722 +        if (code != 0)
20723 +            goto cleanup;
20724 +    } else {
20725 +        /*
20726 +         * It's not clear that looking encrypting the ticket in the
20727 +         * requested EAP enctype provides any value.
20728 +         */
20729 +        code = krb5_kt_start_seq_get(krbContext, keytab, &cursor);
20730 +        if (code != 0)
20731 +            goto cleanup;
20732 +
20733 +        while ((code = krb5_kt_next_entry(krbContext, keytab,
20734 +                                          &ktent, &cursor)) == 0) {
20735 +            if (KRB_KEY_TYPE(KRB_KT_ENT_KEYBLOCK(&ktent)) == ctx->encryptionType)
20736 +                break;
20737 +            else
20738 +                KRB_KT_ENT_FREE(krbContext, &ktent);
20739 +        }
20740 +    }
20741 +
20742 +    if (code == 0) {
20743 +        *princ = ktent.principal;
20744 +        *key = *KRB_KT_ENT_KEYBLOCK(&ktent);
20745 +    }
20746 +
20747 +cleanup:
20748 +    if (cred == GSS_C_NO_CREDENTIAL || cred->name == GSS_C_NO_NAME)
20749 +        krb5_kt_end_seq_get(krbContext, keytab, &cursor);
20750 +    krb5_kt_close(krbContext, keytab);
20751 +    if (code != 0)
20752 +        KRB_KT_ENT_FREE(krbContext, &ktent);
20753 +
20754 +    return code;
20755 +}
20756 +
20757 +static OM_uint32
20758 +freezeAttrContext(OM_uint32 *minor,
20759 +                  gss_name_t initiatorName,
20760 +                  krb5_const_principal acceptorPrinc,
20761 +                  krb5_keyblock *session,
20762 +#ifdef HAVE_HEIMDAL_VERSION
20763 +                  krb5_authdata *kdcIssuedAuthData
20764 +#else
20765 +                  krb5_authdata ***kdcIssuedAuthData
20766 +#endif
20767 +                  )
20768 +{
20769 +    OM_uint32 major, tmpMinor;
20770 +    krb5_error_code code;
20771 +    krb5_context krbContext;
20772 +    gss_buffer_desc attrBuf = GSS_C_EMPTY_BUFFER;
20773 +#ifdef HAVE_HEIMDAL_VERSION
20774 +    krb5_authdata authDataBuf, *authData = &authDataBuf;
20775 +    AuthorizationDataElement authDatum = { 0 };
20776 +#else
20777 +    krb5_authdata *authData[2], authDatum = { 0 };
20778 +#endif
20779 +
20780 +    memset(kdcIssuedAuthData, 0, sizeof(*kdcIssuedAuthData));
20781 +
20782 +    GSSEAP_KRB_INIT(&krbContext);
20783 +
20784 +    major = gssEapExportAttrContext(minor, initiatorName, &attrBuf);
20785 +    if (GSS_ERROR(major))
20786 +        return major;
20787 +
20788 +    authDatum.ad_type = KRB5_AUTHDATA_RADIUS_AVP;
20789 +#ifdef HAVE_HEIMDAL_VERSION
20790 +    authDatum.ad_data.length = attrBuf.length;
20791 +    authDatum.ad_data.data = attrBuf.value;
20792 +    authData->len = 1;
20793 +    authData->val = &authDatum;
20794 +#else
20795 +    authDatum.length = attrBuf.length;
20796 +    authDatum.contents = attrBuf.value;
20797 +    authData[0] = &authDatum;
20798 +    authData[1] = NULL;
20799 +#endif
20800 +
20801 +    code = krbMakeAuthDataKdcIssued(krbContext, session, acceptorPrinc,
20802 +                                    authData, kdcIssuedAuthData);
20803 +    if (code != 0) {
20804 +        major = GSS_S_FAILURE;
20805 +        *minor = code;
20806 +    } else {
20807 +        major = GSS_S_COMPLETE;
20808 +    }
20809 +
20810 +    gss_release_buffer(&tmpMinor, &attrBuf);
20811 +
20812 +    return major;
20813 +}
20814 +
20815 +/*
20816 + * Fabricate a ticket to ourselves given a GSS EAP context.
20817 + */
20818 +OM_uint32
20819 +gssEapMakeReauthCreds(OM_uint32 *minor,
20820 +                      gss_ctx_id_t ctx,
20821 +                      gss_cred_id_t cred,
20822 +                      gss_buffer_t credBuf)
20823 +{
20824 +    OM_uint32 major = GSS_S_COMPLETE;
20825 +    krb5_error_code code;
20826 +    krb5_context krbContext = NULL;
20827 +    krb5_keyblock session = { 0 }, acceptorKey = { 0 };
20828 +    krb5_principal server = NULL;
20829 +#ifdef HAVE_HEIMDAL_VERSION
20830 +    Ticket ticket;
20831 +    EncTicketPart enc_part;
20832 +    AuthorizationData authData = { 0 };
20833 +    krb5_crypto krbCrypto = NULL;
20834 +    krb5_data ticketData = { 0 };
20835 +    krb5_data encPartData = { 0 };
20836 +    size_t len;
20837 +#else
20838 +    krb5_ticket ticket;
20839 +    krb5_enc_tkt_part enc_part;
20840 +    krb5_data *ticketData = NULL;
20841 +#endif
20842 +    krb5_data credsData = { 0 };
20843 +    krb5_creds creds = { 0 };
20844 +    krb5_auth_context authContext = NULL;
20845 +
20846 +    memset(&ticket, 0, sizeof(ticket));
20847 +    memset(&enc_part, 0, sizeof(enc_part));
20848 +
20849 +    credBuf->length = 0;
20850 +    credBuf->value = NULL;
20851 +
20852 +    GSSEAP_KRB_INIT(&krbContext);
20853 +
20854 +    code = getAcceptorKey(krbContext, ctx, cred, &server, &acceptorKey);
20855 +    if (code != 0) {
20856 +        *minor = code;
20857 +        return GSS_S_UNAVAILABLE;
20858 +    }
20859 +
20860 +    /*
20861 +     * Generate a random session key to place in the ticket and
20862 +     * sign the "KDC-Issued" authorization data element.
20863 +     */
20864 +#ifdef HAVE_HEIMDAL_VERSION
20865 +    ticket.realm = server->realm;
20866 +    ticket.sname = server->name;
20867 +
20868 +    code = krb5_generate_random_keyblock(krbContext, ctx->encryptionType,
20869 +                                         &session);
20870 +    if (code != 0)
20871 +        goto cleanup;
20872 +
20873 +    enc_part.flags.initial = 1;
20874 +    enc_part.key = session;
20875 +    enc_part.crealm = ctx->initiatorName->krbPrincipal->realm;
20876 +    enc_part.cname = ctx->initiatorName->krbPrincipal->name;
20877 +    enc_part.authtime = time(NULL);
20878 +    enc_part.starttime = &enc_part.authtime;
20879 +    enc_part.endtime = (ctx->expiryTime != 0)
20880 +                       ? ctx->expiryTime : KRB_TIME_FOREVER;
20881 +    enc_part.renew_till = NULL;
20882 +    enc_part.authorization_data = &authData;
20883 +
20884 +    major = freezeAttrContext(minor, ctx->initiatorName, server,
20885 +                              &session, &authData);
20886 +    if (GSS_ERROR(major))
20887 +        goto cleanup;
20888 +
20889 +    ASN1_MALLOC_ENCODE(EncTicketPart, encPartData.data, encPartData.length,
20890 +                       &enc_part, &len, code);
20891 +    if (code != 0)
20892 +        goto cleanup;
20893 +
20894 +    code = krb5_crypto_init(krbContext, &acceptorKey, 0, &krbCrypto);
20895 +    if (code != 0)
20896 +        goto cleanup;
20897 +
20898 +    code = krb5_encrypt_EncryptedData(krbContext,
20899 +                                      krbCrypto,
20900 +                                      KRB5_KU_TICKET,
20901 +                                      encPartData.data,
20902 +                                      encPartData.length,
20903 +                                      0,
20904 +                                      &ticket.enc_part);
20905 +    if (code != 0)
20906 +        goto cleanup;
20907 +
20908 +    ASN1_MALLOC_ENCODE(Ticket, ticketData.data, ticketData.length,
20909 +                       &ticket, &len, code);
20910 +    if (code != 0)
20911 +        goto cleanup;
20912 +#else
20913 +    ticket.server = server;
20914 +
20915 +    code = krb5_c_make_random_key(krbContext, ctx->encryptionType,
20916 +                                  &session);
20917 +    if (code != 0)
20918 +        goto cleanup;
20919 +
20920 +    enc_part.flags = TKT_FLG_INITIAL;
20921 +    enc_part.session = &session;
20922 +    enc_part.client = ctx->initiatorName->krbPrincipal;
20923 +    enc_part.times.authtime = time(NULL);
20924 +    enc_part.times.starttime = enc_part.times.authtime;
20925 +    enc_part.times.endtime = (ctx->expiryTime != 0)
20926 +                             ? ctx->expiryTime
20927 +                             : KRB_TIME_FOREVER;
20928 +    enc_part.times.renew_till = 0;
20929 +
20930 +    major = freezeAttrContext(minor, ctx->initiatorName, server,
20931 +                              &session, &enc_part.authorization_data);
20932 +    if (GSS_ERROR(major))
20933 +        goto cleanup;
20934 +
20935 +    ticket.enc_part2 = &enc_part;
20936 +
20937 +    code = krb5_encrypt_tkt_part(krbContext, &acceptorKey, &ticket);
20938 +    if (code != 0)
20939 +        goto cleanup;
20940 +
20941 +    code = encode_krb5_ticket(&ticket, &ticketData);
20942 +    if (code != 0)
20943 +        goto cleanup;
20944 +#endif /* HAVE_HEIMDAL_VERSION */
20945 +
20946 +    creds.client = ctx->initiatorName->krbPrincipal;
20947 +    creds.server = server;
20948 +#ifdef HAVE_HEIMDAL_VERSION
20949 +    creds.session = session;
20950 +    creds.times.authtime = enc_part.authtime;
20951 +    creds.times.starttime = *enc_part.starttime;
20952 +    creds.times.endtime = enc_part.endtime;
20953 +    creds.times.renew_till = 0;
20954 +    creds.flags.b = enc_part.flags;
20955 +    creds.ticket = ticketData;
20956 +    creds.authdata = authData;
20957 +#else
20958 +    creds.keyblock = session;
20959 +    creds.times = enc_part.times;
20960 +    creds.ticket_flags = enc_part.flags;
20961 +    creds.ticket = *ticketData;
20962 +    creds.authdata = enc_part.authorization_data;
20963 +#endif
20964 +
20965 +    code = krb5_auth_con_init(krbContext, &authContext);
20966 +    if (code != 0)
20967 +        goto cleanup;
20968 +
20969 +    code = krb5_auth_con_setflags(krbContext, authContext, 0);
20970 +    if (code != 0)
20971 +        goto cleanup;
20972 +
20973 +#ifdef HAVE_HEIMDAL_VERSION
20974 +    code = krb5_auth_con_setlocalsubkey(krbContext, authContext,
20975 +                                        &ctx->rfc3961Key);
20976 +#else
20977 +    code = krb5_auth_con_setsendsubkey(krbContext, authContext,
20978 +                                       &ctx->rfc3961Key);
20979 +#endif
20980 +    if (code != 0)
20981 +        goto cleanup;
20982 +
20983 +    code = krbMakeCred(krbContext, authContext, &creds, &credsData);
20984 +    if (code != 0)
20985 +        goto cleanup;
20986 +
20987 +    krbDataToGssBuffer(&credsData, credBuf);
20988 +
20989 +cleanup:
20990 +#ifdef HAVE_HEIMDAL_VERSION
20991 +    if (krbCrypto != NULL)
20992 +        krb5_crypto_destroy(krbContext, krbCrypto);
20993 +    free_AuthorizationData(&authData);
20994 +    free_EncryptedData(&ticket.enc_part);
20995 +    krb5_data_free(&ticketData);
20996 +    krb5_data_free(&encPartData);
20997 +#else
20998 +    krb5_free_authdata(krbContext, enc_part.authorization_data);
20999 +    if (ticket.enc_part.ciphertext.data != NULL)
21000 +        GSSEAP_FREE(ticket.enc_part.ciphertext.data);
21001 +    krb5_free_data(krbContext, ticketData);
21002 +#endif
21003 +    krb5_free_keyblock_contents(krbContext, &session);
21004 +    krb5_free_principal(krbContext, server);
21005 +    krb5_free_keyblock_contents(krbContext, &acceptorKey);
21006 +    krb5_auth_con_free(krbContext, authContext);
21007 +
21008 +    if (major == GSS_S_COMPLETE) {
21009 +        *minor = code;
21010 +        major = (code != 0) ? GSS_S_FAILURE : GSS_S_COMPLETE;
21011 +    }
21012 +
21013 +    return major;
21014 +}
21015 +
21016 +static int
21017 +isTicketGrantingServiceP(krb5_context krbContext GSSEAP_UNUSED,
21018 +                         krb5_const_principal principal)
21019 +{
21020 +    if (KRB_PRINC_LENGTH(principal) == 2 &&
21021 +#ifdef HAVE_HEIMDAL_VERSION
21022 +        strcmp(KRB_PRINC_NAME(principal)[0], "krbtgt") == 0
21023 +#else
21024 +        krb5_princ_component(krbContext, principal, 0)->length == 6 &&
21025 +        memcmp(krb5_princ_component(krbContext,
21026 +                                    principal, 0)->data, "krbtgt", 6) == 0
21027 +#endif
21028 +        )
21029 +        return TRUE;
21030 +
21031 +    return FALSE;
21032 +}
21033 +
21034 +/*
21035 + * Returns TRUE if the configuration variable reauth_use_ccache is
21036 + * set in krb5.conf for the eap_gss application and the client realm.
21037 + */
21038 +static int
21039 +reauthUseCredsCache(krb5_context krbContext,
21040 +                    krb5_principal principal)
21041 +{
21042 +    int reauthUseCCache;
21043 +
21044 +    /* if reauth_use_ccache, use default credentials cache if ticket is for us */
21045 +    krb5_appdefault_boolean(krbContext, "eap_gss",
21046 +                            KRB_PRINC_REALM(principal),
21047 +                            "reauth_use_ccache", 0, &reauthUseCCache);
21048 +
21049 +    return reauthUseCCache;
21050 +}
21051 +
21052 +/*
21053 + * Look in default credentials cache for reauthentication credentials,
21054 + * if policy allows.
21055 + */
21056 +static OM_uint32
21057 +getDefaultReauthCredentials(OM_uint32 *minor,
21058 +                            gss_cred_id_t cred,
21059 +                            gss_name_t target,
21060 +                            time_t now,
21061 +                            OM_uint32 timeReq)
21062 +{
21063 +    OM_uint32 major = GSS_S_CRED_UNAVAIL;
21064 +    krb5_context krbContext = NULL;
21065 +    krb5_error_code code = 0;
21066 +    krb5_ccache ccache = NULL;
21067 +    krb5_creds match = { 0 };
21068 +    krb5_creds creds = { 0 };
21069 +
21070 +    GSSEAP_KRB_INIT(&krbContext);
21071 +
21072 +    GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL);
21073 +    GSSEAP_ASSERT(target != GSS_C_NO_NAME);
21074 +
21075 +    if (cred->name == GSS_C_NO_NAME ||
21076 +        !reauthUseCredsCache(krbContext, cred->name->krbPrincipal))
21077 +        goto cleanup;
21078 +
21079 +    match.client = cred->name->krbPrincipal;
21080 +    match.server = target->krbPrincipal;
21081 +    if (timeReq != 0 && timeReq != GSS_C_INDEFINITE)
21082 +        match.times.endtime = now + timeReq;
21083 +
21084 +    code = krb5_cc_default(krbContext, &ccache);
21085 +    if (code != 0)
21086 +        goto cleanup;
21087 +
21088 +    code = krb5_cc_retrieve_cred(krbContext, ccache, 0, &match, &creds);
21089 +    if (code != 0)
21090 +        goto cleanup;
21091 +
21092 +    cred->flags |= CRED_FLAG_DEFAULT_CCACHE;
21093 +    cred->krbCredCache = ccache;
21094 +    ccache = NULL;
21095 +
21096 +    major = gss_krb5_import_cred(minor, cred->krbCredCache, NULL, NULL,
21097 +                                 &cred->reauthCred);
21098 +
21099 +cleanup:
21100 +    if (major == GSS_S_CRED_UNAVAIL)
21101 +        *minor = code;
21102 +
21103 +    if (ccache != NULL)
21104 +        krb5_cc_close(krbContext, ccache);
21105 +    krb5_free_cred_contents(krbContext, &creds);
21106 +
21107 +    return major;
21108 +}
21109 +
21110 +/*
21111 + * Returns TRUE if the credential handle's reauth credentials are
21112 + * valid or if we can use the default credentials cache. Credentials
21113 + * handle must be locked.
21114 + */
21115 +int
21116 +gssEapCanReauthP(gss_cred_id_t cred,
21117 +                 gss_name_t target,
21118 +                 OM_uint32 timeReq)
21119 +{
21120 +    time_t now, expiryReq;
21121 +    OM_uint32 minor;
21122 +
21123 +    if (cred == GSS_C_NO_CREDENTIAL)
21124 +        return FALSE;
21125 +
21126 +    now = time(NULL);
21127 +    expiryReq = now;
21128 +    if (timeReq != GSS_C_INDEFINITE)
21129 +        expiryReq += timeReq;
21130 +
21131 +    if (cred->krbCredCache != NULL && cred->expiryTime > expiryReq)
21132 +        return TRUE;
21133 +
21134 +    if (getDefaultReauthCredentials(&minor, cred, target,
21135 +                                    now, timeReq) == GSS_S_COMPLETE)
21136 +        return TRUE;
21137 +
21138 +    return FALSE;
21139 +}
21140 +
21141 +/*
21142 + * Store re-authentication (Kerberos) credentials in a credential handle.
21143 + * Credentials handle must be locked.
21144 + */
21145 +OM_uint32
21146 +gssEapStoreReauthCreds(OM_uint32 *minor,
21147 +                       gss_ctx_id_t ctx,
21148 +                       gss_cred_id_t cred,
21149 +                       gss_buffer_t credBuf)
21150 +{
21151 +    OM_uint32 major = GSS_S_COMPLETE;
21152 +    krb5_error_code code;
21153 +    krb5_context krbContext = NULL;
21154 +    krb5_auth_context authContext = NULL;
21155 +    krb5_data credData = { 0 };
21156 +    krb5_creds **creds = NULL;
21157 +    krb5_principal canonPrinc;
21158 +    krb5_principal ccPrinc = NULL;
21159 +    int i;
21160 +
21161 +    if (credBuf->length == 0 || cred == GSS_C_NO_CREDENTIAL)
21162 +        return GSS_S_COMPLETE;
21163 +
21164 +    GSSEAP_KRB_INIT(&krbContext);
21165 +
21166 +    code = krb5_auth_con_init(krbContext, &authContext);
21167 +    if (code != 0)
21168 +        goto cleanup;
21169 +
21170 +    code = krb5_auth_con_setflags(krbContext, authContext, 0);
21171 +    if (code != 0)
21172 +        goto cleanup;
21173 +
21174 +    code = krb5_auth_con_setrecvsubkey(krbContext, authContext,
21175 +                                       &ctx->rfc3961Key);
21176 +    if (code != 0)
21177 +        goto cleanup;
21178 +
21179 +    gssBufferToKrbData(credBuf, &credData);
21180 +
21181 +    code = krb5_rd_cred(krbContext, authContext, &credData, &creds, NULL);
21182 +    if (code != 0)
21183 +        goto cleanup;
21184 +
21185 +    if (creds == NULL || creds[0] == NULL)
21186 +        goto cleanup;
21187 +
21188 +    code = krb5_copy_principal(krbContext, creds[0]->client, &canonPrinc);
21189 +    if (code != 0)
21190 +        goto cleanup;
21191 +
21192 +    krb5_free_principal(krbContext, cred->name->krbPrincipal);
21193 +    cred->name->krbPrincipal = canonPrinc;
21194 +
21195 +    if (creds[0]->times.endtime == KRB_TIME_FOREVER)
21196 +        cred->expiryTime = 0;
21197 +    else
21198 +        cred->expiryTime = creds[0]->times.endtime;
21199 +
21200 +    if (cred->krbCredCache == NULL) {
21201 +        if (reauthUseCredsCache(krbContext, creds[0]->client) &&
21202 +            krb5_cc_default(krbContext, &cred->krbCredCache) == 0)
21203 +            cred->flags |= CRED_FLAG_DEFAULT_CCACHE;
21204 +    } else {
21205 +        /*
21206 +         * If we already have an associated credentials cache, possibly from
21207 +         * the last time we stored a reauthentication credential, then we
21208 +         * need to clear it out and release the associated GSS credential.
21209 +         */
21210 +        if (cred->flags & CRED_FLAG_DEFAULT_CCACHE) {
21211 +            krb5_cc_remove_cred(krbContext, cred->krbCredCache, 0, creds[0]);
21212 +        } else {
21213 +            krb5_cc_destroy(krbContext, cred->krbCredCache);
21214 +            cred->krbCredCache = NULL;
21215 +        }
21216 +        gssReleaseCred(minor, &cred->reauthCred);
21217 +    }
21218 +
21219 +    if (cred->krbCredCache == NULL) {
21220 +        code = krb5_cc_new_unique(krbContext, "MEMORY", NULL, &cred->krbCredCache);
21221 +        if (code != 0)
21222 +            goto cleanup;
21223 +    }
21224 +
21225 +    if ((cred->flags & CRED_FLAG_DEFAULT_CCACHE) == 0 ||
21226 +        krb5_cc_get_principal(krbContext, cred->krbCredCache, &ccPrinc) != 0) {
21227 +        code = krb5_cc_initialize(krbContext, cred->krbCredCache,
21228 +                                  creds[0]->client);
21229 +        if (code != 0)
21230 +            goto cleanup;
21231 +    }
21232 +
21233 +    for (i = 0; creds[i] != NULL; i++) {
21234 +        krb5_creds kcred = *(creds[i]);
21235 +
21236 +        /*
21237 +         * Swap in the acceptor name the client asked for so
21238 +         * get_credentials() works. We're making the assumption that
21239 +         * any service tickets returned are for us. We'll need to
21240 +         * reflect some more on whether that is a safe assumption.
21241 +         */
21242 +        if (!isTicketGrantingServiceP(krbContext, kcred.server))
21243 +            kcred.server = ctx->acceptorName->krbPrincipal;
21244 +
21245 +        code = krb5_cc_store_cred(krbContext, cred->krbCredCache, &kcred);
21246 +        if (code != 0)
21247 +            goto cleanup;
21248 +    }
21249 +
21250 +    major = gss_krb5_import_cred(minor, cred->krbCredCache, NULL, NULL,
21251 +                                 &cred->reauthCred);
21252 +    if (GSS_ERROR(major))
21253 +        goto cleanup;
21254 +
21255 +cleanup:
21256 +    *minor = code;
21257 +
21258 +    krb5_free_principal(krbContext, ccPrinc);
21259 +    krb5_auth_con_free(krbContext, authContext);
21260 +    if (creds != NULL) {
21261 +        for (i = 0; creds[i] != NULL; i++)
21262 +            krb5_free_creds(krbContext, creds[i]);
21263 +        GSSEAP_FREE(creds);
21264 +    }
21265 +    if (major == GSS_S_COMPLETE)
21266 +        major = *minor ? GSS_S_FAILURE : GSS_S_COMPLETE;
21267 +
21268 +    return major;
21269 +}
21270 +
21271 +#ifndef HAVE_HEIMDAL_VERSION
21272 +static gss_buffer_desc radiusAvpKrbAttr = {
21273 +    sizeof("urn:authdata-radius-avp") - 1, "urn:authdata-radius-avp"
21274 +};
21275 +#endif
21276 +
21277 +/*
21278 + * Unfortunately extracting an AD-KDCIssued authorization data element
21279 + * is pretty implementation-dependent. It's not possible to verify the
21280 + * signature ourselves because the ticket session key is not exposed
21281 + * outside GSS. In an ideal world, all AD-KDCIssued elements would be
21282 + * verified by the Kerberos library and authentication would fail if
21283 + * verification failed. We're not quite there yet and as a result have
21284 + * to go through some hoops to get this to work. The alternative would
21285 + * be to sign the authorization data with our long-term key, but it
21286 + * seems a pity to compromise the design because of current implementation
21287 + * limitations.
21288 + *
21289 + * (Specifically, the hoops involve a libkrb5 authorisation data plugin
21290 + * that exposes the verified and serialised attribute context through
21291 + * the Kerberos GSS mechanism's naming extensions API.)
21292 + */
21293 +static OM_uint32
21294 +defrostAttrContext(OM_uint32 *minor,
21295 +#ifdef HAVE_HEIMDAL_VERSION
21296 +                   gss_ctx_id_t glueContext,
21297 +#else
21298 +                   gss_name_t glueName,
21299 +#endif
21300 +                   gss_name_t mechName)
21301 +{
21302 +    OM_uint32 major, tmpMinor;
21303 +#ifdef HAVE_HEIMDAL_VERSION
21304 +    gss_OID_desc oid = { 0 };
21305 +    gss_buffer_set_t authData = GSS_C_NO_BUFFER_SET;
21306 +#else
21307 +    gss_buffer_desc authData = GSS_C_EMPTY_BUFFER;
21308 +    gss_buffer_desc authDataDisplay = GSS_C_EMPTY_BUFFER;
21309 +    int more = -1;
21310 +    int authenticated, complete;
21311 +#endif
21312 +
21313 +#ifdef HAVE_HEIMDAL_VERSION
21314 +    major = composeOid(minor,
21315 +                       GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->elements,
21316 +                       GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->length,
21317 +                       KRB5_AUTHDATA_RADIUS_AVP, &oid);
21318 +    if (GSS_ERROR(major))
21319 +        return major;
21320 +
21321 +    /* XXX we are assuming that this verifies AD-KDCIssued signature */
21322 +    major = gssInquireSecContextByOid(minor, glueContext,
21323 +                                      &oid, &authData);
21324 +    if (major == GSS_S_COMPLETE) {
21325 +        if (authData == GSS_C_NO_BUFFER_SET || authData->count != 1)
21326 +            major = GSS_S_FAILURE;
21327 +        else
21328 +            major = gssEapImportAttrContext(minor, authData->elements, mechName);
21329 +    } else if (major == GSS_S_FAILURE && *minor == ENOENT) {
21330 +        /* This is the equivalent of GSS_S_UNAVAILABLE for MIT attr APIs */
21331 +        *minor = 0;
21332 +        major = GSS_S_COMPLETE;
21333 +    }
21334 +
21335 +    gss_release_buffer_set(&tmpMinor, &authData);
21336 +    GSSEAP_FREE(oid.elements);
21337 +#else
21338 +    major = gssGetNameAttribute(minor, glueName, &radiusAvpKrbAttr,
21339 +                                &authenticated, &complete,
21340 +                                &authData, &authDataDisplay, &more);
21341 +    if (major == GSS_S_COMPLETE) {
21342 +        if (authenticated == 0)
21343 +            major = GSS_S_BAD_NAME;
21344 +        else
21345 +            major = gssEapImportAttrContext(minor, &authData, mechName);
21346 +    } else if (major == GSS_S_UNAVAILABLE) {
21347 +        major = GSS_S_COMPLETE;
21348 +    }
21349 +
21350 +    gss_release_buffer(&tmpMinor, &authData);
21351 +    gss_release_buffer(&tmpMinor, &authDataDisplay);
21352 +#endif /* HAVE_HEIMDAL_VERSION */
21353 +
21354 +    return major;
21355 +}
21356 +
21357 +/*
21358 + * Convert a mechanism glue to an EAP mechanism name by displaying and
21359 + * importing it. This also handles the RADIUS attributes.
21360 + */
21361 +OM_uint32
21362 +gssEapGlueToMechName(OM_uint32 *minor,
21363 +                     gss_ctx_id_t ctx,
21364 +                     gss_name_t glueName,
21365 +                     gss_name_t *pMechName)
21366 +{
21367 +    OM_uint32 major, tmpMinor;
21368 +    gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
21369 +
21370 +    *pMechName = GSS_C_NO_NAME;
21371 +
21372 +    major = gssDisplayName(minor, glueName, &nameBuf, NULL);
21373 +    if (GSS_ERROR(major))
21374 +        goto cleanup;
21375 +
21376 +    major = gssEapImportName(minor, &nameBuf, GSS_C_NT_USER_NAME,
21377 +                             ctx->mechanismUsed, pMechName);
21378 +    if (GSS_ERROR(major))
21379 +        goto cleanup;
21380 +
21381 +    major = defrostAttrContext(minor,
21382 +#ifdef HAVE_HEIMDAL_VERSION
21383 +                               ctx->reauthCtx,
21384 +#else
21385 +                               glueName,
21386 +#endif
21387 +                               *pMechName);
21388 +    if (GSS_ERROR(major))
21389 +        goto cleanup;
21390 +
21391 +cleanup:
21392 +    if (GSS_ERROR(major)) {
21393 +        gssReleaseName(&tmpMinor, pMechName);
21394 +        *pMechName = GSS_C_NO_NAME;
21395 +    }
21396 +
21397 +    gss_release_buffer(&tmpMinor, &nameBuf);
21398 +
21399 +    return major;
21400 +}
21401 +
21402 +/*
21403 + * Convert an EAP mechanism name to a mechanism glue name by displaying
21404 + * and importing it.
21405 + */
21406 +OM_uint32
21407 +gssEapMechToGlueName(OM_uint32 *minor,
21408 +                     gss_name_t mechName,
21409 +                     gss_name_t *pGlueName)
21410 +{
21411 +    OM_uint32 major, tmpMinor;
21412 +    gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
21413 +
21414 +    *pGlueName = GSS_C_NO_NAME;
21415 +
21416 +    major = gssEapDisplayName(minor, mechName, &nameBuf, NULL);
21417 +    if (GSS_ERROR(major))
21418 +        goto cleanup;
21419 +
21420 +    major = gssImportName(minor, &nameBuf, GSS_C_NT_USER_NAME,
21421 +                          pGlueName);
21422 +    if (GSS_ERROR(major))
21423 +        goto cleanup;
21424 +
21425 +cleanup:
21426 +    gss_release_buffer(&tmpMinor, &nameBuf);
21427 +
21428 +    return major;
21429 +}
21430 +
21431 +/*
21432 + * Suck out the analgous elements of a Kerberos GSS context into an EAP
21433 + * one so that the application doesn't know the difference.
21434 + */
21435 +OM_uint32
21436 +gssEapReauthComplete(OM_uint32 *minor,
21437 +                     gss_ctx_id_t ctx,
21438 +                     gss_cred_id_t cred GSSEAP_UNUSED,
21439 +                     const gss_OID mech,
21440 +                     OM_uint32 timeRec)
21441 +{
21442 +    OM_uint32 major, tmpMinor;
21443 +    gss_buffer_set_t keyData = GSS_C_NO_BUFFER_SET;
21444 +    krb5_context krbContext = NULL;
21445 +#ifdef HAVE_HEIMDAL_VERSION
21446 +    krb5_storage *sp = NULL;
21447 +#endif
21448 +
21449 +    GSSEAP_KRB_INIT(&krbContext);
21450 +
21451 +    if (!oidEqual(mech, gss_mech_krb5)) {
21452 +        major = GSS_S_BAD_MECH;
21453 +        goto cleanup;
21454 +    }
21455 +
21456 +    /* Get the raw subsession key and encryption type */
21457 +#ifdef HAVE_HEIMDAL_VERSION
21458 +#define KRB_GSS_SUBKEY_COUNT    1 /* encoded session key */
21459 +    major = gssInquireSecContextByOid(minor, ctx->reauthCtx,
21460 +                                      GSS_KRB5_GET_SUBKEY_X, &keyData);
21461 +#else
21462 +#define KRB_GSS_SUBKEY_COUNT    2 /* raw session key, enctype OID */
21463 +    major = gssInquireSecContextByOid(minor, ctx->reauthCtx,
21464 +                                      GSS_C_INQ_SSPI_SESSION_KEY, &keyData);
21465 +#endif
21466 +    if (GSS_ERROR(major))
21467 +        goto cleanup;
21468 +
21469 +    if (keyData == GSS_C_NO_BUFFER_SET || keyData->count < KRB_GSS_SUBKEY_COUNT) {
21470 +        *minor = GSSEAP_KEY_UNAVAILABLE;
21471 +        major = GSS_S_FAILURE;
21472 +        goto cleanup;
21473 +    }
21474 +
21475 +#ifdef HAVE_HEIMDAL_VERSION
21476 +    sp = krb5_storage_from_mem(keyData->elements[0].value,
21477 +                               keyData->elements[0].length);
21478 +    if (sp == NULL) {
21479 +        *minor = ENOMEM;
21480 +        major = GSS_S_FAILURE;
21481 +        goto cleanup;
21482 +    }
21483 +
21484 +    *minor = krb5_ret_keyblock(sp, &ctx->rfc3961Key);
21485 +    if (*minor != 0) {
21486 +        major = GSS_S_FAILURE;
21487 +        goto cleanup;
21488 +    }
21489 +#else
21490 +    {
21491 +        gss_OID_desc oid;
21492 +        int suffix;
21493 +
21494 +        oid.length = keyData->elements[1].length;
21495 +        oid.elements = keyData->elements[1].value;
21496 +
21497 +        /* GSS_KRB5_SESSION_KEY_ENCTYPE_OID */
21498 +        major = decomposeOid(minor,
21499 +                             "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04",
21500 +                             10, &oid, &suffix);
21501 +        if (GSS_ERROR(major))
21502 +            goto cleanup;
21503 +
21504 +        ctx->encryptionType = suffix;
21505 +    }
21506 +
21507 +    {
21508 +        krb5_keyblock key;
21509 +
21510 +        KRB_KEY_LENGTH(&key) = keyData->elements[0].length;
21511 +        KRB_KEY_DATA(&key)   = keyData->elements[0].value;
21512 +        KRB_KEY_TYPE(&key)   = ctx->encryptionType;
21513 +
21514 +        *minor = krb5_copy_keyblock_contents(krbContext,
21515 +                                             &key, &ctx->rfc3961Key);
21516 +        if (*minor != 0) {
21517 +            major = GSS_S_FAILURE;
21518 +            goto cleanup;
21519 +        }
21520 +    }
21521 +#endif /* HAVE_HEIMDAL_VERSION */
21522 +
21523 +    major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
21524 +                                      &ctx->checksumType);
21525 +    if (GSS_ERROR(major))
21526 +        goto cleanup;
21527 +
21528 +    if (timeRec != GSS_C_INDEFINITE)
21529 +        ctx->expiryTime = time(NULL) + timeRec;
21530 +
21531 +    /* Initialize our sequence state */
21532 +    major = sequenceInit(minor,
21533 +                         &ctx->seqState, ctx->recvSeq,
21534 +                         ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0),
21535 +                         ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0),
21536 +                         TRUE);
21537 +    if (GSS_ERROR(major))
21538 +        goto cleanup;
21539 +
21540 +    major = GSS_S_COMPLETE;
21541 +
21542 +cleanup:
21543 +#ifdef HAVE_HEIMDAL_VERSION
21544 +    if (sp != NULL)
21545 +        krb5_storage_free(sp);
21546 +#endif
21547 +    gss_release_buffer_set(&tmpMinor, &keyData);
21548 +
21549 +    return major;
21550 +}
21551 +
21552 +/*
21553 + * The remainder of this file consists of wrappers so we can call into the
21554 + * mechanism glue without calling ourselves.
21555 + */
21556 +static OM_uint32
21557 +(*gssInitSecContextNext)(OM_uint32 *,
21558 +                         gss_cred_id_t,
21559 +                         gss_ctx_id_t *,
21560 +                         gss_name_t,
21561 +                         gss_OID,
21562 +                         OM_uint32,
21563 +                         OM_uint32,
21564 +                         gss_channel_bindings_t,
21565 +                         gss_buffer_t,
21566 +                         gss_OID *,
21567 +                         gss_buffer_t,
21568 +                         OM_uint32 *,
21569 +                         OM_uint32 *);
21570 +
21571 +static OM_uint32
21572 +(*gssAcceptSecContextNext)(OM_uint32 *,
21573 +                           gss_ctx_id_t *,
21574 +                           gss_cred_id_t,
21575 +                           gss_buffer_t,
21576 +                           gss_channel_bindings_t,
21577 +                           gss_name_t *,
21578 +                           gss_OID *,
21579 +                           gss_buffer_t,
21580 +                           OM_uint32 *,
21581 +                           OM_uint32 *,
21582 +                           gss_cred_id_t *);
21583 +
21584 +static OM_uint32
21585 +(*gssReleaseCredNext)(OM_uint32 *, gss_cred_id_t *);
21586 +
21587 +static OM_uint32
21588 +(*gssReleaseNameNext)(OM_uint32 *, gss_name_t *);
21589 +
21590 +static OM_uint32
21591 +(*gssInquireSecContextByOidNext)(OM_uint32 *,
21592 +                                 const gss_ctx_id_t,
21593 +                                 const gss_OID,
21594 +                                 gss_buffer_set_t *);
21595 +
21596 +static OM_uint32
21597 +(*gssDeleteSecContextNext)(OM_uint32 *,
21598 +                          gss_ctx_id_t *,
21599 +                          gss_buffer_t);
21600 +
21601 +static OM_uint32
21602 +(*gssDisplayNameNext)(OM_uint32 *,
21603 +                      gss_name_t,
21604 +                      gss_buffer_t,
21605 +                      gss_OID *);
21606 +
21607 +static OM_uint32
21608 +(*gssImportNameNext)(OM_uint32 *,
21609 +                     gss_buffer_t,
21610 +                     gss_OID,
21611 +                     gss_name_t *);
21612 +
21613 +static OM_uint32
21614 +(*gssStoreCredNext)(OM_uint32 *,
21615 +                    const gss_cred_id_t,
21616 +                    gss_cred_usage_t,
21617 +                    const gss_OID,
21618 +                    OM_uint32,
21619 +                    OM_uint32,
21620 +                    gss_OID_set *,
21621 +                    gss_cred_usage_t *);
21622 +
21623 +static OM_uint32
21624 +(*gssGetNameAttributeNext)(OM_uint32 *,
21625 +                          gss_name_t,
21626 +                          gss_buffer_t,
21627 +                          int *,
21628 +                          int *,
21629 +                          gss_buffer_t,
21630 +                          gss_buffer_t,
21631 +                          int *);
21632 +
21633 +#define NEXT_SYMBOL(local, global)  do {        \
21634 +        ((local) = dlsym(RTLD_NEXT, (global))); \
21635 +        if ((local) == NULL) {                  \
21636 +            *minor = GSSEAP_NO_MECHGLUE_SYMBOL; \
21637 +            major = GSS_S_UNAVAILABLE;          \
21638 +            /* but continue */                  \
21639 +        }                                       \
21640 +    } while (0)
21641 +
21642 +OM_uint32
21643 +gssEapReauthInitialize(OM_uint32 *minor)
21644 +{
21645 +    OM_uint32 major = GSS_S_COMPLETE;
21646 +
21647 +    NEXT_SYMBOL(gssInitSecContextNext,         "gss_init_sec_context");
21648 +    NEXT_SYMBOL(gssAcceptSecContextNext,       "gss_accept_sec_context");
21649 +    NEXT_SYMBOL(gssReleaseCredNext,            "gss_release_cred");
21650 +    NEXT_SYMBOL(gssReleaseNameNext,            "gss_release_name");
21651 +    NEXT_SYMBOL(gssInquireSecContextByOidNext, "gss_inquire_sec_context_by_oid");
21652 +    NEXT_SYMBOL(gssDeleteSecContextNext,       "gss_delete_sec_context");
21653 +    NEXT_SYMBOL(gssDisplayNameNext,            "gss_display_name");
21654 +    NEXT_SYMBOL(gssImportNameNext,             "gss_import_name");
21655 +    NEXT_SYMBOL(gssStoreCredNext,              "gss_store_cred");
21656 +#ifndef HAVE_HEIMDAL_VERSION
21657 +    NEXT_SYMBOL(gssGetNameAttributeNext,       "gss_get_name_attribute");
21658 +#endif
21659 +
21660 +    return major;
21661 +}
21662 +
21663 +OM_uint32
21664 +gssInitSecContext(OM_uint32 *minor,
21665 +                  gss_cred_id_t cred,
21666 +                  gss_ctx_id_t *context_handle,
21667 +                  gss_name_t target_name,
21668 +                  gss_OID mech_type,
21669 +                  OM_uint32 req_flags,
21670 +                  OM_uint32 time_req,
21671 +                  gss_channel_bindings_t input_chan_bindings,
21672 +                  gss_buffer_t input_token,
21673 +                  gss_OID *actual_mech_type,
21674 +                  gss_buffer_t output_token,
21675 +                  OM_uint32 *ret_flags,
21676 +                  OM_uint32 *time_rec)
21677 +{
21678 +    if (gssInitSecContextNext == NULL) {
21679 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
21680 +        return GSS_S_UNAVAILABLE;
21681 +    }
21682 +
21683 +    return gssInitSecContextNext(minor, cred, context_handle,
21684 +                                 target_name, mech_type, req_flags,
21685 +                                 time_req, input_chan_bindings,
21686 +                                 input_token, actual_mech_type,
21687 +                                 output_token, ret_flags, time_rec);
21688 +}
21689 +
21690 +OM_uint32
21691 +gssAcceptSecContext(OM_uint32 *minor,
21692 +                    gss_ctx_id_t *context_handle,
21693 +                    gss_cred_id_t cred,
21694 +                    gss_buffer_t input_token,
21695 +                    gss_channel_bindings_t input_chan_bindings,
21696 +                    gss_name_t *src_name,
21697 +                    gss_OID *mech_type,
21698 +                    gss_buffer_t output_token,
21699 +                    OM_uint32 *ret_flags,
21700 +                    OM_uint32 *time_rec,
21701 +                    gss_cred_id_t *delegated_cred_handle)
21702 +{
21703 +    if (gssAcceptSecContextNext == NULL) {
21704 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
21705 +        return GSS_S_UNAVAILABLE;
21706 +    }
21707 +
21708 +    return gssAcceptSecContextNext(minor, context_handle, cred,
21709 +                                   input_token, input_chan_bindings,
21710 +                                   src_name, mech_type, output_token,
21711 +                                   ret_flags, time_rec, delegated_cred_handle);
21712 +}
21713 +
21714 +OM_uint32
21715 +gssReleaseCred(OM_uint32 *minor,
21716 +               gss_cred_id_t *cred_handle)
21717 +{
21718 +    if (gssReleaseCredNext == NULL) {
21719 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
21720 +        return GSS_S_UNAVAILABLE;
21721 +    }
21722 +
21723 +    return gssReleaseCredNext(minor, cred_handle);
21724 +}
21725 +
21726 +OM_uint32
21727 +gssReleaseName(OM_uint32 *minor,
21728 +               gss_name_t *name)
21729 +{
21730 +    if (gssReleaseName == NULL) {
21731 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
21732 +        return GSS_S_UNAVAILABLE;
21733 +    }
21734 +
21735 +    return gssReleaseNameNext(minor, name);
21736 +}
21737 +
21738 +OM_uint32
21739 +gssDeleteSecContext(OM_uint32 *minor,
21740 +                    gss_ctx_id_t *context_handle,
21741 +                    gss_buffer_t output_token)
21742 +{
21743 +    if (gssDeleteSecContextNext == NULL) {
21744 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
21745 +        return GSS_S_UNAVAILABLE;
21746 +    }
21747 +
21748 +    return gssDeleteSecContextNext(minor, context_handle, output_token);
21749 +}
21750 +
21751 +static OM_uint32
21752 +gssDisplayName(OM_uint32 *minor,
21753 +               gss_name_t name,
21754 +               gss_buffer_t buffer,
21755 +               gss_OID *name_type)
21756 +{
21757 +    if (gssDisplayNameNext == NULL) {
21758 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
21759 +        return GSS_S_UNAVAILABLE;
21760 +    }
21761 +
21762 +    return gssDisplayNameNext(minor, name, buffer, name_type);
21763 +}
21764 +
21765 +static OM_uint32
21766 +gssImportName(OM_uint32 *minor,
21767 +              gss_buffer_t buffer,
21768 +              gss_OID name_type,
21769 +              gss_name_t *name)
21770 +{
21771 +    if (gssImportNameNext == NULL) {
21772 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
21773 +        return GSS_S_UNAVAILABLE;
21774 +    }
21775 +
21776 +    return gssImportNameNext(minor, buffer, name_type, name);
21777 +}
21778 +
21779 +OM_uint32
21780 +gssInquireSecContextByOid(OM_uint32 *minor,
21781 +                          const gss_ctx_id_t context_handle,
21782 +                          const gss_OID desired_object,
21783 +                          gss_buffer_set_t *data_set)
21784 +{
21785 +    if (gssInquireSecContextByOidNext == NULL) {
21786 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
21787 +        return GSS_S_UNAVAILABLE;
21788 +    }
21789 +
21790 +    return gssInquireSecContextByOidNext(minor, context_handle,
21791 +                                         desired_object, data_set);
21792 +}
21793 +
21794 +OM_uint32
21795 +gssStoreCred(OM_uint32 *minor,
21796 +             const gss_cred_id_t input_cred_handle,
21797 +             gss_cred_usage_t input_usage,
21798 +             const gss_OID desired_mech,
21799 +             OM_uint32 overwrite_cred,
21800 +             OM_uint32 default_cred,
21801 +             gss_OID_set *elements_stored,
21802 +             gss_cred_usage_t *cred_usage_stored)
21803 +{
21804 +    if (gssStoreCredNext == NULL) {
21805 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
21806 +        return GSS_S_UNAVAILABLE;
21807 +    }
21808 +
21809 +    return gssStoreCredNext(minor, input_cred_handle, input_usage,
21810 +                            desired_mech, overwrite_cred, default_cred,
21811 +                            elements_stored, cred_usage_stored);
21812 +}
21813 +
21814 +OM_uint32
21815 +gssGetNameAttribute(OM_uint32 *minor,
21816 +                    gss_name_t name,
21817 +                    gss_buffer_t attr,
21818 +                    int *authenticated,
21819 +                    int *complete,
21820 +                    gss_buffer_t value,
21821 +                    gss_buffer_t display_value,
21822 +                    int *more)
21823 +{
21824 +    if (gssGetNameAttributeNext == NULL) {
21825 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
21826 +        return GSS_S_UNAVAILABLE;
21827 +    }
21828 +
21829 +    return gssGetNameAttributeNext(minor, name, attr, authenticated, complete,
21830 +                                   value, display_value, more);
21831 +}
21832 diff --git a/mech_eap/util_reauth.h b/mech_eap/util_reauth.h
21833 new file mode 100644
21834 index 0000000..9b9f264
21835 --- /dev/null
21836 +++ b/mech_eap/util_reauth.h
21837 @@ -0,0 +1,151 @@
21838 +/*
21839 + * Copyright (c) 2011, JANET(UK)
21840 + * All rights reserved.
21841 + *
21842 + * Redistribution and use in source and binary forms, with or without
21843 + * modification, are permitted provided that the following conditions
21844 + * are met:
21845 + *
21846 + * 1. Redistributions of source code must retain the above copyright
21847 + *    notice, this list of conditions and the following disclaimer.
21848 + *
21849 + * 2. Redistributions in binary form must reproduce the above copyright
21850 + *    notice, this list of conditions and the following disclaimer in the
21851 + *    documentation and/or other materials provided with the distribution.
21852 + *
21853 + * 3. Neither the name of JANET(UK) nor the names of its contributors
21854 + *    may be used to endorse or promote products derived from this software
21855 + *    without specific prior written permission.
21856 + *
21857 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21858 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21859 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21860 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
21861 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21862 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21863 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21864 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21865 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21866 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
21867 + * SUCH DAMAGE.
21868 + */
21869 +
21870 +/*
21871 + * Fast reauthentication support.
21872 + */
21873 +
21874 +#include "gssapiP_eap.h"
21875 +
21876 +#ifndef _UTIL_REAUTH_H_
21877 +#define _UTIL_REAUTH_H_ 1
21878 +
21879 +/* AD element containing serialised AVPs. */
21880 +#define KRB5_AUTHDATA_RADIUS_AVP        513
21881 +
21882 +OM_uint32
21883 +gssInitSecContext(OM_uint32 *minor,
21884 +                  gss_cred_id_t cred,
21885 +                  gss_ctx_id_t *context_handle,
21886 +                  gss_name_t target_name,
21887 +                  gss_OID mech_type,
21888 +                  OM_uint32 req_flags,
21889 +                  OM_uint32 time_req,
21890 +                  gss_channel_bindings_t input_chan_bindings,
21891 +                  gss_buffer_t input_token,
21892 +                  gss_OID *actual_mech_type,
21893 +                  gss_buffer_t output_token,
21894 +                  OM_uint32 *ret_flags,
21895 +                  OM_uint32 *time_rec);
21896 +
21897 +OM_uint32
21898 +gssAcceptSecContext(OM_uint32 *minor,
21899 +                    gss_ctx_id_t *context_handle,
21900 +                    gss_cred_id_t cred,
21901 +                    gss_buffer_t input_token,
21902 +                    gss_channel_bindings_t input_chan_bindings,
21903 +                    gss_name_t *src_name,
21904 +                    gss_OID *mech_type,
21905 +                    gss_buffer_t output_token,
21906 +                    OM_uint32 *ret_flags,
21907 +                    OM_uint32 *time_rec,
21908 +                    gss_cred_id_t *delegated_cred_handle);
21909 +
21910 +OM_uint32
21911 +gssReleaseCred(OM_uint32 *minor,
21912 +               gss_cred_id_t *cred_handle);
21913 +
21914 +OM_uint32
21915 +gssReleaseName(OM_uint32 *minor,
21916 +               gss_name_t *name);
21917 +
21918 +OM_uint32
21919 +gssDeleteSecContext(OM_uint32 *minor,
21920 +                    gss_ctx_id_t *context_handle,
21921 +                    gss_buffer_t output_token);
21922 +
21923 +OM_uint32
21924 +gssInquireSecContextByOid(OM_uint32 *minor,
21925 +                          const gss_ctx_id_t context_handle,
21926 +                          const gss_OID desired_object,
21927 +                          gss_buffer_set_t *data_set);
21928 +
21929 +OM_uint32
21930 +gssStoreCred(OM_uint32 *minor,
21931 +             const gss_cred_id_t input_cred_handle,
21932 +             gss_cred_usage_t input_usage,
21933 +             const gss_OID desired_mech,
21934 +             OM_uint32 overwrite_cred,
21935 +             OM_uint32 default_cred,
21936 +             gss_OID_set *elements_stored,
21937 +             gss_cred_usage_t *cred_usage_stored);
21938 +
21939 +OM_uint32
21940 +gssGetNameAttribute(OM_uint32 *minor,
21941 +                    gss_name_t name,
21942 +                    gss_buffer_t attr,
21943 +                    int *authenticated,
21944 +                    int *complete,
21945 +                    gss_buffer_t value,
21946 +                    gss_buffer_t display_value,
21947 +                    int *more);
21948 +
21949 +OM_uint32
21950 +gssEapMakeReauthCreds(OM_uint32 *minor,
21951 +                      gss_ctx_id_t ctx,
21952 +                      gss_cred_id_t cred,
21953 +                      gss_buffer_t credBuf);
21954 +
21955 +OM_uint32
21956 +gssEapStoreReauthCreds(OM_uint32 *minor,
21957 +                       gss_ctx_id_t ctx,
21958 +                       gss_cred_id_t cred,
21959 +                       gss_buffer_t credBuf);
21960 +
21961 +
21962 +OM_uint32
21963 +gssEapGlueToMechName(OM_uint32 *minor,
21964 +                     gss_ctx_id_t glueContext,
21965 +                     gss_name_t glueName,
21966 +                     gss_name_t *pMechName);
21967 +
21968 +OM_uint32
21969 +gssEapMechToGlueName(OM_uint32 *minor,
21970 +                     gss_name_t mechName,
21971 +                     gss_name_t *pGlueName);
21972 +
21973 +OM_uint32
21974 +gssEapReauthComplete(OM_uint32 *minor,
21975 +                    gss_ctx_id_t ctx,
21976 +                    gss_cred_id_t cred,
21977 +                    const gss_OID mech,
21978 +                    OM_uint32 timeRec);
21979 +
21980 +OM_uint32
21981 +gssEapReauthInitialize(OM_uint32 *minor);
21982 +
21983 +int
21984 +gssEapCanReauthP(gss_cred_id_t cred,
21985 +                 gss_name_t target,
21986 +                 OM_uint32 timeReq);
21987 +
21988 +#endif /* _UTIL_REAUTH_H_ */
21989 diff --git a/mech_eap/util_saml.cpp b/mech_eap/util_saml.cpp
21990 new file mode 100644
21991 index 0000000..ce7582e
21992 --- /dev/null
21993 +++ b/mech_eap/util_saml.cpp
21994 @@ -0,0 +1,775 @@
21995 +/*
21996 + * Copyright (c) 2011, JANET(UK)
21997 + * All rights reserved.
21998 + *
21999 + * Redistribution and use in source and binary forms, with or without
22000 + * modification, are permitted provided that the following conditions
22001 + * are met:
22002 + *
22003 + * 1. Redistributions of source code must retain the above copyright
22004 + *    notice, this list of conditions and the following disclaimer.
22005 + *
22006 + * 2. Redistributions in binary form must reproduce the above copyright
22007 + *    notice, this list of conditions and the following disclaimer in the
22008 + *    documentation and/or other materials provided with the distribution.
22009 + *
22010 + * 3. Neither the name of JANET(UK) nor the names of its contributors
22011 + *    may be used to endorse or promote products derived from this software
22012 + *    without specific prior written permission.
22013 + *
22014 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22015 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22016 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22017 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22018 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22019 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22020 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22021 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22022 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22023 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22024 + * SUCH DAMAGE.
22025 + */
22026 +
22027 +/*
22028 + * SAML attribute provider implementation.
22029 + */
22030 +
22031 +#include "gssapiP_eap.h"
22032 +
22033 +#include <sstream>
22034 +
22035 +#include <xercesc/util/XMLUniDefs.hpp>
22036 +#include <xmltooling/unicode.h>
22037 +#include <xmltooling/XMLToolingConfig.h>
22038 +#include <xmltooling/util/XMLHelper.h>
22039 +#include <xmltooling/util/ParserPool.h>
22040 +#include <xmltooling/util/DateTime.h>
22041 +
22042 +#include <saml/exceptions.h>
22043 +#include <saml/SAMLConfig.h>
22044 +#include <saml/saml1/core/Assertions.h>
22045 +#include <saml/saml2/core/Assertions.h>
22046 +#include <saml/saml2/metadata/Metadata.h>
22047 +#include <saml/saml2/metadata/MetadataProvider.h>
22048 +
22049 +using namespace xmltooling;
22050 +using namespace opensaml::saml2md;
22051 +using namespace opensaml;
22052 +using namespace xercesc;
22053 +using namespace std;
22054 +
22055 +static const XMLCh
22056 +base64Binary[] = {'b','a','s','e','6','4','B','i','n','a','r','y',0};
22057 +
22058 +/*
22059 + * gss_eap_saml_assertion_provider is for retrieving the underlying
22060 + * assertion.
22061 + */
22062 +gss_eap_saml_assertion_provider::gss_eap_saml_assertion_provider(void)
22063 +{
22064 +    m_assertion = NULL;
22065 +    m_authenticated = false;
22066 +}
22067 +
22068 +gss_eap_saml_assertion_provider::~gss_eap_saml_assertion_provider(void)
22069 +{
22070 +    delete m_assertion;
22071 +}
22072 +
22073 +bool
22074 +gss_eap_saml_assertion_provider::initWithExistingContext(const gss_eap_attr_ctx *manager,
22075 +                                                         const gss_eap_attr_provider *ctx)
22076 +{
22077 +    /* Then we may be creating from an existing attribute context */
22078 +    const gss_eap_saml_assertion_provider *saml;
22079 +
22080 +    GSSEAP_ASSERT(m_assertion == NULL);
22081 +
22082 +    if (!gss_eap_attr_provider::initWithExistingContext(manager, ctx))
22083 +        return false;
22084 +
22085 +    saml = static_cast<const gss_eap_saml_assertion_provider *>(ctx);
22086 +    setAssertion(saml->getAssertion(), saml->authenticated());
22087 +
22088 +    return true;
22089 +}
22090 +
22091 +bool
22092 +gss_eap_saml_assertion_provider::initWithGssContext(const gss_eap_attr_ctx *manager,
22093 +                                                    const gss_cred_id_t gssCred,
22094 +                                                    const gss_ctx_id_t gssCtx)
22095 +{
22096 +    const gss_eap_radius_attr_provider *radius;
22097 +    gss_buffer_desc value = GSS_C_EMPTY_BUFFER;
22098 +    int authenticated, complete;
22099 +    OM_uint32 minor;
22100 +
22101 +    GSSEAP_ASSERT(m_assertion == NULL);
22102 +
22103 +    if (!gss_eap_attr_provider::initWithGssContext(manager, gssCred, gssCtx))
22104 +        return false;
22105 +
22106 +    /*
22107 +     * XXX TODO we need to support draft-howlett-radius-saml-attr-00
22108 +     */
22109 +    radius = static_cast<const gss_eap_radius_attr_provider *>
22110 +        (m_manager->getProvider(ATTR_TYPE_RADIUS));
22111 +    if (radius != NULL &&
22112 +        radius->getFragmentedAttribute(PW_SAML_AAA_ASSERTION,
22113 +                                       VENDORPEC_UKERNA,
22114 +                                       &authenticated, &complete, &value)) {
22115 +        setAssertion(&value, authenticated);
22116 +        gss_release_buffer(&minor, &value);
22117 +    } else {
22118 +        m_assertion = NULL;
22119 +    }
22120 +
22121 +    return true;
22122 +}
22123 +
22124 +void
22125 +gss_eap_saml_assertion_provider::setAssertion(const saml2::Assertion *assertion,
22126 +                                              bool authenticated)
22127 +{
22128 +
22129 +    delete m_assertion;
22130 +
22131 +    if (assertion != NULL) {
22132 +#ifdef __APPLE__
22133 +        m_assertion = (saml2::Assertion *)((void *)assertion->clone());
22134 +#else
22135 +        m_assertion = dynamic_cast<saml2::Assertion *>(assertion->clone());
22136 +#endif
22137 +        m_authenticated = authenticated;
22138 +    } else {
22139 +        m_assertion = NULL;
22140 +        m_authenticated = false;
22141 +    }
22142 +}
22143 +
22144 +void
22145 +gss_eap_saml_assertion_provider::setAssertion(const gss_buffer_t buffer,
22146 +                                              bool authenticated)
22147 +{
22148 +    delete m_assertion;
22149 +
22150 +    m_assertion = parseAssertion(buffer);
22151 +    m_authenticated = (m_assertion != NULL && authenticated);
22152 +}
22153 +
22154 +saml2::Assertion *
22155 +gss_eap_saml_assertion_provider::parseAssertion(const gss_buffer_t buffer)
22156 +{
22157 +    string str((char *)buffer->value, buffer->length);
22158 +    istringstream istream(str);
22159 +    DOMDocument *doc;
22160 +    const XMLObjectBuilder *b;
22161 +
22162 +    try {
22163 +        doc = XMLToolingConfig::getConfig().getParser().parse(istream);
22164 +        if (doc == NULL)
22165 +            return NULL;
22166 +
22167 +        b = XMLObjectBuilder::getBuilder(doc->getDocumentElement());
22168 +
22169 +#ifdef __APPLE__
22170 +        return (saml2::Assertion *)((void *)b->buildFromDocument(doc));
22171 +#else
22172 +        return dynamic_cast<saml2::Assertion *>(b->buildFromDocument(doc));
22173 +#endif
22174 +    } catch (exception &e) {
22175 +        return NULL;
22176 +    }
22177 +}
22178 +
22179 +bool
22180 +gss_eap_saml_assertion_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
22181 +                                                   void *data) const
22182 +{
22183 +    bool ret;
22184 +
22185 +    /* just add the prefix */
22186 +    if (m_assertion != NULL)
22187 +        ret = addAttribute(m_manager, this, GSS_C_NO_BUFFER, data);
22188 +    else
22189 +        ret = true;
22190 +
22191 +    return ret;
22192 +}
22193 +
22194 +bool
22195 +gss_eap_saml_assertion_provider::setAttribute(int complete GSSEAP_UNUSED,
22196 +                                              const gss_buffer_t attr,
22197 +                                              const gss_buffer_t value)
22198 +{
22199 +    if (attr == GSS_C_NO_BUFFER || attr->length == 0) {
22200 +        setAssertion(value);
22201 +        return true;
22202 +    }
22203 +
22204 +    return false;
22205 +}
22206 +
22207 +bool
22208 +gss_eap_saml_assertion_provider::deleteAttribute(const gss_buffer_t value GSSEAP_UNUSED)
22209 +{
22210 +    delete m_assertion;
22211 +    m_assertion = NULL;
22212 +    m_authenticated = false;
22213 +
22214 +    return true;
22215 +}
22216 +
22217 +time_t
22218 +gss_eap_saml_assertion_provider::getExpiryTime(void) const
22219 +{
22220 +    saml2::Conditions *conditions;
22221 +    time_t expiryTime = 0;
22222 +
22223 +    if (m_assertion == NULL)
22224 +        return 0;
22225 +
22226 +    conditions = m_assertion->getConditions();
22227 +
22228 +    if (conditions != NULL && conditions->getNotOnOrAfter() != NULL)
22229 +        expiryTime = conditions->getNotOnOrAfter()->getEpoch();
22230 +
22231 +    return expiryTime;
22232 +}
22233 +
22234 +OM_uint32
22235 +gss_eap_saml_assertion_provider::mapException(OM_uint32 *minor,
22236 +                                              std::exception &e) const
22237 +{
22238 +    if (typeid(e) == typeid(SecurityPolicyException))
22239 +        *minor = GSSEAP_SAML_SEC_POLICY_FAILURE;
22240 +    else if (typeid(e) == typeid(BindingException))
22241 +        *minor = GSSEAP_SAML_BINDING_FAILURE;
22242 +    else if (typeid(e) == typeid(ProfileException))
22243 +        *minor = GSSEAP_SAML_PROFILE_FAILURE;
22244 +    else if (typeid(e) == typeid(FatalProfileException))
22245 +        *minor = GSSEAP_SAML_FATAL_PROFILE_FAILURE;
22246 +    else if (typeid(e) == typeid(RetryableProfileException))
22247 +        *minor = GSSEAP_SAML_RETRY_PROFILE_FAILURE;
22248 +    else if (typeid(e) == typeid(MetadataException))
22249 +        *minor = GSSEAP_SAML_METADATA_FAILURE;
22250 +    else
22251 +        return GSS_S_CONTINUE_NEEDED;
22252 +
22253 +    gssEapSaveStatusInfo(*minor, "%s", e.what());
22254 +
22255 +    return GSS_S_FAILURE;
22256 +}
22257 +
22258 +bool
22259 +gss_eap_saml_assertion_provider::getAttribute(const gss_buffer_t attr,
22260 +                                              int *authenticated,
22261 +                                              int *complete,
22262 +                                              gss_buffer_t value,
22263 +                                              gss_buffer_t display_value GSSEAP_UNUSED,
22264 +                                              int *more) const
22265 +{
22266 +    string str;
22267 +
22268 +    if (attr != GSS_C_NO_BUFFER && attr->length != 0)
22269 +        return false;
22270 +
22271 +    if (m_assertion == NULL)
22272 +        return false;
22273 +
22274 +    if (*more != -1)
22275 +        return false;
22276 +
22277 +    if (authenticated != NULL)
22278 +        *authenticated = m_authenticated;
22279 +    if (complete != NULL)
22280 +        *complete = true;
22281 +
22282 +    XMLHelper::serialize(m_assertion->marshall((DOMDocument *)NULL), str);
22283 +
22284 +    if (value != NULL)
22285 +        duplicateBuffer(str, value);
22286 +    if (display_value != NULL)
22287 +        duplicateBuffer(str, display_value);
22288 +
22289 +    *more = 0;
22290 +
22291 +    return true;
22292 +}
22293 +
22294 +gss_any_t
22295 +gss_eap_saml_assertion_provider::mapToAny(int authenticated,
22296 +                                          gss_buffer_t type_id GSSEAP_UNUSED) const
22297 +{
22298 +    if (authenticated && !m_authenticated)
22299 +        return (gss_any_t)NULL;
22300 +
22301 +    return (gss_any_t)m_assertion;
22302 +}
22303 +
22304 +void
22305 +gss_eap_saml_assertion_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED,
22306 +                                                       gss_any_t input) const
22307 +{
22308 +    delete ((saml2::Assertion *)input);
22309 +}
22310 +
22311 +const char *
22312 +gss_eap_saml_assertion_provider::prefix(void) const
22313 +{
22314 +    return "urn:ietf:params:gss-eap:saml-aaa-assertion";
22315 +}
22316 +
22317 +bool
22318 +gss_eap_saml_assertion_provider::init(void)
22319 +{
22320 +    bool ret = false;
22321 +
22322 +    try {
22323 +        ret = SAMLConfig::getConfig().init();
22324 +    } catch (exception &e) {
22325 +    }
22326 +
22327 +    if (ret)
22328 +        gss_eap_attr_ctx::registerProvider(ATTR_TYPE_SAML_ASSERTION, createAttrContext);
22329 +
22330 +    return ret;
22331 +}
22332 +
22333 +void
22334 +gss_eap_saml_assertion_provider::finalize(void)
22335 +{
22336 +    gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_SAML_ASSERTION);
22337 +}
22338 +
22339 +gss_eap_attr_provider *
22340 +gss_eap_saml_assertion_provider::createAttrContext(void)
22341 +{
22342 +    return new gss_eap_saml_assertion_provider;
22343 +}
22344 +
22345 +saml2::Assertion *
22346 +gss_eap_saml_assertion_provider::initAssertion(void)
22347 +{
22348 +    delete m_assertion;
22349 +    m_assertion = saml2::AssertionBuilder::buildAssertion();
22350 +    m_authenticated = false;
22351 +
22352 +    return m_assertion;
22353 +}
22354 +
22355 +/*
22356 + * gss_eap_saml_attr_provider is for retrieving the underlying attributes.
22357 + */
22358 +bool
22359 +gss_eap_saml_attr_provider::getAssertion(int *authenticated,
22360 +                                         saml2::Assertion **pAssertion,
22361 +                                         bool createIfAbsent) const
22362 +{
22363 +    gss_eap_saml_assertion_provider *saml;
22364 +
22365 +    if (authenticated != NULL)
22366 +        *authenticated = false;
22367 +    if (pAssertion != NULL)
22368 +        *pAssertion = NULL;
22369 +
22370 +    saml = static_cast<gss_eap_saml_assertion_provider *>
22371 +        (m_manager->getProvider(ATTR_TYPE_SAML_ASSERTION));
22372 +    if (saml == NULL)
22373 +        return false;
22374 +
22375 +    if (authenticated != NULL)
22376 +        *authenticated = saml->authenticated();
22377 +    if (pAssertion != NULL)
22378 +        *pAssertion = saml->getAssertion();
22379 +
22380 +    if (saml->getAssertion() == NULL) {
22381 +        if (createIfAbsent) {
22382 +            if (authenticated != NULL)
22383 +                *authenticated = false;
22384 +            if (pAssertion != NULL)
22385 +                *pAssertion = saml->initAssertion();
22386 +        } else
22387 +            return false;
22388 +    }
22389 +
22390 +    return true;
22391 +}
22392 +
22393 +bool
22394 +gss_eap_saml_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
22395 +                                              void *data) const
22396 +{
22397 +    saml2::Assertion *assertion;
22398 +    int authenticated;
22399 +
22400 +    if (!getAssertion(&authenticated, &assertion))
22401 +        return true;
22402 +
22403 +    /*
22404 +     * Note: the first prefix is added by the attribute provider manager
22405 +     *
22406 +     * From draft-hartman-gss-eap-naming-00:
22407 +     *
22408 +     *   Each attribute carried in the assertion SHOULD also be a GSS name
22409 +     *   attribute.  The name of this attribute has three parts, all separated
22410 +     *   by an ASCII space character.  The first part is
22411 +     *   urn:ietf:params:gss-eap:saml-attr.  The second part is the URI for
22412 +     *   the SAML attribute name format.  The final part is the name of the
22413 +     *   SAML attribute.  If the mechanism performs an additional attribute
22414 +     *   query, the retrieved attributes SHOULD be GSS-API name attributes
22415 +     *   using the same name syntax.
22416 +     */
22417 +    /* For each attribute statement, look for an attribute match */
22418 +    const vector <saml2::AttributeStatement *> &statements =
22419 +        const_cast<const saml2::Assertion *>(assertion)->getAttributeStatements();
22420 +
22421 +    for (vector<saml2::AttributeStatement *>::const_iterator s = statements.begin();
22422 +        s != statements.end();
22423 +        ++s) {
22424 +        const vector<saml2::Attribute*> &attrs =
22425 +            const_cast<const saml2::AttributeStatement*>(*s)->getAttributes();
22426 +
22427 +        for (vector<saml2::Attribute*>::const_iterator a = attrs.begin(); a != attrs.end(); ++a) {
22428 +            const XMLCh *attributeName, *attributeNameFormat;
22429 +            XMLCh space[2] = { ' ', 0 };
22430 +            gss_buffer_desc utf8;
22431 +
22432 +            attributeName = (*a)->getName();
22433 +            attributeNameFormat = (*a)->getNameFormat();
22434 +            if (attributeNameFormat == NULL || attributeNameFormat[0] == '\0')
22435 +                attributeNameFormat = saml2::Attribute::UNSPECIFIED;
22436 +
22437 +            XMLCh qualifiedName[XMLString::stringLen(attributeNameFormat) + 1 +
22438 +                                XMLString::stringLen(attributeName) + 1];
22439 +            XMLString::copyString(qualifiedName, attributeNameFormat);
22440 +            XMLString::catString(qualifiedName, space);
22441 +            XMLString::catString(qualifiedName, attributeName);
22442 +
22443 +            utf8.value = (void *)toUTF8(qualifiedName);
22444 +            utf8.length = strlen((char *)utf8.value);
22445 +
22446 +            if (!addAttribute(m_manager, this, &utf8, data))
22447 +                return false;
22448 +        }
22449 +    }
22450 +
22451 +    return true;
22452 +}
22453 +
22454 +static BaseRefVectorOf<XMLCh> *
22455 +decomposeAttributeName(const gss_buffer_t attr)
22456 +{
22457 +    BaseRefVectorOf<XMLCh> *components;
22458 +    string str((const char *)attr->value, attr->length);
22459 +    auto_ptr_XMLCh qualifiedAttr(str.c_str());
22460 +
22461 +    components = XMLString::tokenizeString(qualifiedAttr.get());
22462 +
22463 +    if (components->size() != 2) {
22464 +        delete components;
22465 +        components = NULL;
22466 +    }
22467 +
22468 +    return components;
22469 +}
22470 +
22471 +bool
22472 +gss_eap_saml_attr_provider::setAttribute(int complete GSSEAP_UNUSED,
22473 +                                         const gss_buffer_t attr,
22474 +                                         const gss_buffer_t value)
22475 +{
22476 +    saml2::Assertion *assertion;
22477 +    saml2::Attribute *attribute;
22478 +    saml2::AttributeValue *attributeValue;
22479 +    saml2::AttributeStatement *attributeStatement;
22480 +
22481 +    if (!getAssertion(NULL, &assertion, true))
22482 +        return false;
22483 +
22484 +    if (assertion->getAttributeStatements().size() != 0) {
22485 +        attributeStatement = assertion->getAttributeStatements().front();
22486 +    } else {
22487 +        attributeStatement = saml2::AttributeStatementBuilder::buildAttributeStatement();
22488 +        assertion->getAttributeStatements().push_back(attributeStatement);
22489 +    }
22490 +
22491 +    /* Check the attribute name consists of name format | whsp | name */
22492 +    BaseRefVectorOf<XMLCh> *components = decomposeAttributeName(attr);
22493 +    if (components == NULL)
22494 +        return false;
22495 +
22496 +    attribute = saml2::AttributeBuilder::buildAttribute();
22497 +    attribute->setNameFormat(components->elementAt(0));
22498 +    attribute->setName(components->elementAt(1));
22499 +
22500 +    attributeValue = saml2::AttributeValueBuilder::buildAttributeValue();
22501 +    auto_ptr_XMLCh unistr((char *)value->value, value->length);
22502 +    attributeValue->setTextContent(unistr.get());
22503 +
22504 +    attribute->getAttributeValues().push_back(attributeValue);
22505 +
22506 +    GSSEAP_ASSERT(attributeStatement != NULL);
22507 +    attributeStatement->getAttributes().push_back(attribute);
22508 +
22509 +    delete components;
22510 +
22511 +    return true;
22512 +}
22513 +
22514 +bool
22515 +gss_eap_saml_attr_provider::deleteAttribute(const gss_buffer_t attr)
22516 +{
22517 +    saml2::Assertion *assertion;
22518 +    bool ret = false;
22519 +
22520 +    if (!getAssertion(NULL, &assertion) ||
22521 +        assertion->getAttributeStatements().size() == 0)
22522 +        return false;
22523 +
22524 +    /* Check the attribute name consists of name format | whsp | name */
22525 +    BaseRefVectorOf<XMLCh> *components = decomposeAttributeName(attr);
22526 +    if (components == NULL)
22527 +        return false;
22528 +
22529 +    /* For each attribute statement, look for an attribute match */
22530 +    const vector<saml2::AttributeStatement *> &statements =
22531 +        const_cast<const saml2::Assertion *>(assertion)->getAttributeStatements();
22532 +
22533 +    for (vector<saml2::AttributeStatement *>::const_iterator s = statements.begin();
22534 +        s != statements.end();
22535 +        ++s) {
22536 +        const vector<saml2::Attribute *> &attrs =
22537 +            const_cast<const saml2::AttributeStatement *>(*s)->getAttributes();
22538 +        ssize_t index = -1, i = 0;
22539 +
22540 +        /* There's got to be an easier way to do this */
22541 +        for (vector<saml2::Attribute *>::const_iterator a = attrs.begin();
22542 +             a != attrs.end();
22543 +             ++a) {
22544 +            if (XMLString::equals((*a)->getNameFormat(), components->elementAt(0)) &&
22545 +                XMLString::equals((*a)->getName(), components->elementAt(1))) {
22546 +                index = i;
22547 +                break;
22548 +            }
22549 +            ++i;
22550 +        }
22551 +        if (index != -1) {
22552 +            (*s)->getAttributes().erase((*s)->getAttributes().begin() + index);
22553 +            ret = true;
22554 +        }
22555 +    }
22556 +
22557 +    delete components;
22558 +
22559 +    return ret;
22560 +}
22561 +
22562 +bool
22563 +gss_eap_saml_attr_provider::getAttribute(const gss_buffer_t attr,
22564 +                                         int *authenticated,
22565 +                                         int *complete,
22566 +                                         const saml2::Attribute **pAttribute) const
22567 +{
22568 +    saml2::Assertion *assertion;
22569 +
22570 +    if (authenticated != NULL)
22571 +        *authenticated = false;
22572 +    if (complete != NULL)
22573 +        *complete = true;
22574 +    *pAttribute = NULL;
22575 +
22576 +    if (!getAssertion(authenticated, &assertion) ||
22577 +        assertion->getAttributeStatements().size() == 0)
22578 +        return false;
22579 +
22580 +    /* Check the attribute name consists of name format | whsp | name */
22581 +    BaseRefVectorOf<XMLCh> *components = decomposeAttributeName(attr);
22582 +    if (components == NULL)
22583 +        return false;
22584 +
22585 +    /* For each attribute statement, look for an attribute match */
22586 +    const vector <saml2::AttributeStatement *> &statements =
22587 +        const_cast<const saml2::Assertion *>(assertion)->getAttributeStatements();
22588 +    const saml2::Attribute *ret = NULL;
22589 +
22590 +    for (vector<saml2::AttributeStatement *>::const_iterator s = statements.begin();
22591 +        s != statements.end();
22592 +        ++s) {
22593 +        const vector<saml2::Attribute *> &attrs =
22594 +            const_cast<const saml2::AttributeStatement*>(*s)->getAttributes();
22595 +
22596 +        for (vector<saml2::Attribute *>::const_iterator a = attrs.begin(); a != attrs.end(); ++a) {
22597 +            const XMLCh *attributeName, *attributeNameFormat;
22598 +
22599 +            attributeName = (*a)->getName();
22600 +            attributeNameFormat = (*a)->getNameFormat();
22601 +            if (attributeNameFormat == NULL || attributeNameFormat[0] == '\0')
22602 +                attributeNameFormat = saml2::Attribute::UNSPECIFIED;
22603 +
22604 +            if (XMLString::equals(attributeNameFormat, components->elementAt(0)) &&
22605 +                XMLString::equals(attributeName, components->elementAt(1))) {
22606 +                ret = *a;
22607 +                break;
22608 +            }
22609 +        }
22610 +
22611 +        if (ret != NULL)
22612 +            break;
22613 +    }
22614 +
22615 +    delete components;
22616 +
22617 +    *pAttribute = ret;
22618 +
22619 +    return (ret != NULL);
22620 +}
22621 +
22622 +static bool
22623 +isBase64EncodedAttributeValueP(const saml2::AttributeValue *av)
22624 +{
22625 +    const xmltooling::QName *type = av->getSchemaType();
22626 +
22627 +    if (type == NULL)
22628 +        return false;
22629 +
22630 +    if (!type->hasNamespaceURI() ||
22631 +        !XMLString::equals(type->getNamespaceURI(), xmlconstants::XSD_NS))
22632 +        return false;
22633 +
22634 +    if (!type->hasLocalPart() ||
22635 +        !XMLString::equals(type->getLocalPart(), base64Binary))
22636 +        return false;
22637 +
22638 +    return true;
22639 +}
22640 +
22641 +bool
22642 +gss_eap_saml_attr_provider::getAttribute(const gss_buffer_t attr,
22643 +                                         int *authenticated,
22644 +                                         int *complete,
22645 +                                         gss_buffer_t value,
22646 +                                         gss_buffer_t display_value,
22647 +                                         int *more) const
22648 +{
22649 +    const saml2::Attribute *a;
22650 +    const saml2::AttributeValue *av;
22651 +    int nvalues, i = *more;
22652 +
22653 +    *more = 0;
22654 +
22655 +    if (!getAttribute(attr, authenticated, complete, &a))
22656 +        return false;
22657 +
22658 +    nvalues = a->getAttributeValues().size();
22659 +
22660 +    if (i == -1)
22661 +        i = 0;
22662 +    if (i >= nvalues)
22663 +        return false;
22664 +#ifdef __APPLE__
22665 +    av = (const saml2::AttributeValue *)((void *)(a->getAttributeValues().at(i)));
22666 +#else
22667 +    av = dynamic_cast<const saml2::AttributeValue *>(a->getAttributeValues().at(i));
22668 +#endif
22669 +    if (av != NULL) {
22670 +        bool base64Encoded = isBase64EncodedAttributeValueP(av);
22671 +
22672 +        if (value != NULL) {
22673 +            char *stringValue = toUTF8(av->getTextContent(), true);
22674 +            size_t stringValueLen = strlen(stringValue);
22675 +
22676 +            if (base64Encoded) {
22677 +                ssize_t octetLen;
22678 +
22679 +                value->value = GSSEAP_MALLOC(stringValueLen);
22680 +                if (value->value == NULL) {
22681 +                    GSSEAP_FREE(stringValue);
22682 +                    throw new std::bad_alloc;
22683 +                }
22684 +
22685 +                octetLen = base64Decode(stringValue, value->value);
22686 +                if (octetLen < 0) {
22687 +                    GSSEAP_FREE(value->value);
22688 +                    GSSEAP_FREE(stringValue);
22689 +                    value->value = NULL;
22690 +                    return false;
22691 +                }
22692 +                value->length = octetLen;
22693 +                GSSEAP_FREE(stringValue);
22694 +            } else {
22695 +                value->value = stringValue;
22696 +                value->length = stringValueLen;
22697 +            }
22698 +        }
22699 +        if (display_value != NULL && base64Encoded == false) {
22700 +            display_value->value = toUTF8(av->getTextContent(), true);
22701 +            display_value->length = strlen((char *)value->value);
22702 +        }
22703 +    }
22704 +
22705 +    if (nvalues > ++i)
22706 +        *more = i;
22707 +
22708 +    return true;
22709 +}
22710 +
22711 +gss_any_t
22712 +gss_eap_saml_attr_provider::mapToAny(int authenticated GSSEAP_UNUSED,
22713 +                                     gss_buffer_t type_id GSSEAP_UNUSED) const
22714 +{
22715 +    return (gss_any_t)NULL;
22716 +}
22717 +
22718 +void
22719 +gss_eap_saml_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED,
22720 +                                                  gss_any_t input GSSEAP_UNUSED) const
22721 +{
22722 +}
22723 +
22724 +const char *
22725 +gss_eap_saml_attr_provider::prefix(void) const
22726 +{
22727 +    return "urn:ietf:params:gss-eap:saml-attr";
22728 +}
22729 +
22730 +bool
22731 +gss_eap_saml_attr_provider::init(void)
22732 +{
22733 +    gss_eap_attr_ctx::registerProvider(ATTR_TYPE_SAML, createAttrContext);
22734 +    return true;
22735 +}
22736 +
22737 +void
22738 +gss_eap_saml_attr_provider::finalize(void)
22739 +{
22740 +    gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_SAML);
22741 +}
22742 +
22743 +gss_eap_attr_provider *
22744 +gss_eap_saml_attr_provider::createAttrContext(void)
22745 +{
22746 +    return new gss_eap_saml_attr_provider;
22747 +}
22748 +
22749 +OM_uint32
22750 +gssEapSamlAttrProvidersInit(OM_uint32 *minor)
22751 +{
22752 +    if (!gss_eap_saml_assertion_provider::init() ||
22753 +        !gss_eap_saml_attr_provider::init()) {
22754 +        *minor = GSSEAP_SAML_INIT_FAILURE;
22755 +        return GSS_S_FAILURE;
22756 +    }
22757 +
22758 +    return GSS_S_COMPLETE;
22759 +}
22760 +
22761 +OM_uint32
22762 +gssEapSamlAttrProvidersFinalize(OM_uint32 *minor)
22763 +{
22764 +    gss_eap_saml_attr_provider::finalize();
22765 +    gss_eap_saml_assertion_provider::finalize();
22766 +
22767 +    *minor = 0;
22768 +    return GSS_S_COMPLETE;
22769 +}
22770 diff --git a/mech_eap/util_saml.h b/mech_eap/util_saml.h
22771 new file mode 100644
22772 index 0000000..9110ad4
22773 --- /dev/null
22774 +++ b/mech_eap/util_saml.h
22775 @@ -0,0 +1,176 @@
22776 +/*
22777 + * Copyright (c) 2011, JANET(UK)
22778 + * All rights reserved.
22779 + *
22780 + * Redistribution and use in source and binary forms, with or without
22781 + * modification, are permitted provided that the following conditions
22782 + * are met:
22783 + *
22784 + * 1. Redistributions of source code must retain the above copyright
22785 + *    notice, this list of conditions and the following disclaimer.
22786 + *
22787 + * 2. Redistributions in binary form must reproduce the above copyright
22788 + *    notice, this list of conditions and the following disclaimer in the
22789 + *    documentation and/or other materials provided with the distribution.
22790 + *
22791 + * 3. Neither the name of JANET(UK) nor the names of its contributors
22792 + *    may be used to endorse or promote products derived from this software
22793 + *    without specific prior written permission.
22794 + *
22795 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22796 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22797 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22798 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22799 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22800 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22801 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22802 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22803 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22804 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22805 + * SUCH DAMAGE.
22806 + */
22807 +
22808 +/*
22809 + * SAML attribute provider.
22810 + */
22811 +
22812 +#ifndef _UTIL_SAML_H_
22813 +#define _UTIL_SAML_H_ 1
22814 +
22815 +#ifdef __cplusplus
22816 +
22817 +namespace opensaml {
22818 +    namespace saml2 {
22819 +        class Attribute;
22820 +        class Assertion;
22821 +        class NameID;
22822 +    };
22823 +};
22824 +
22825 +struct gss_eap_saml_assertion_provider : gss_eap_attr_provider {
22826 +public:
22827 +    gss_eap_saml_assertion_provider(void);
22828 +    ~gss_eap_saml_assertion_provider(void);
22829 +
22830 +    bool initWithExistingContext(const gss_eap_attr_ctx *source,
22831 +                                 const gss_eap_attr_provider *ctx);
22832 +    bool initWithGssContext(const gss_eap_attr_ctx *source,
22833 +                            const gss_cred_id_t cred,
22834 +                            const gss_ctx_id_t ctx);
22835 +
22836 +    bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const;
22837 +    bool setAttribute(int complete,
22838 +                      const gss_buffer_t attr,
22839 +                      const gss_buffer_t value);
22840 +    bool deleteAttribute(const gss_buffer_t value);
22841 +    bool getAttribute(const gss_buffer_t attr,
22842 +                      int *authenticated,
22843 +                      int *complete,
22844 +                      gss_buffer_t value,
22845 +                      gss_buffer_t display_value,
22846 +                      int *more) const;
22847 +    gss_any_t mapToAny(int authenticated,
22848 +                       gss_buffer_t type_id) const;
22849 +    void releaseAnyNameMapping(gss_buffer_t type_id,
22850 +                               gss_any_t input) const;
22851 +
22852 +    const char *prefix(void) const;
22853 +    const char *name(void) const { return NULL; }
22854 +    bool initWithJsonObject(const gss_eap_attr_ctx *manager GSSEAP_UNUSED,
22855 +                           JSONObject &object GSSEAP_UNUSED) {
22856 +        return false;
22857 +    }
22858 +    JSONObject jsonRepresentation(void) const {
22859 +        return JSONObject::null();
22860 +    }
22861 +
22862 +    opensaml::saml2::Assertion *initAssertion(void);
22863 +
22864 +    opensaml::saml2::Assertion *getAssertion(void) const {
22865 +        return m_assertion;
22866 +    }
22867 +    bool authenticated(void) const {
22868 +        return m_authenticated;
22869 +    }
22870 +
22871 +    time_t getExpiryTime(void) const;
22872 +    OM_uint32 mapException(OM_uint32 *minor, std::exception &e) const;
22873 +
22874 +    static bool init(void);
22875 +    static void finalize(void);
22876 +
22877 +    static gss_eap_attr_provider *createAttrContext(void);
22878 +
22879 +private:
22880 +    static opensaml::saml2::Assertion *
22881 +        parseAssertion(const gss_buffer_t buffer);
22882 +
22883 +    void setAssertion(const opensaml::saml2::Assertion *assertion,
22884 +                      bool authenticated = false);
22885 +    void setAssertion(const gss_buffer_t buffer,
22886 +                      bool authenticated = false);
22887 +
22888 +    opensaml::saml2::Assertion *m_assertion;
22889 +    bool m_authenticated;
22890 +};
22891 +
22892 +struct gss_eap_saml_attr_provider : gss_eap_attr_provider {
22893 +public:
22894 +    gss_eap_saml_attr_provider(void) {}
22895 +    ~gss_eap_saml_attr_provider(void) {}
22896 +
22897 +    bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const;
22898 +    bool setAttribute(int complete,
22899 +                      const gss_buffer_t attr,
22900 +                      const gss_buffer_t value);
22901 +    bool deleteAttribute(const gss_buffer_t value);
22902 +    bool getAttribute(const gss_buffer_t attr,
22903 +                      int *authenticated,
22904 +                      int *complete,
22905 +                      gss_buffer_t value,
22906 +                      gss_buffer_t display_value,
22907 +                      int *more) const;
22908 +    gss_any_t mapToAny(int authenticated,
22909 +                       gss_buffer_t type_id) const;
22910 +    void releaseAnyNameMapping(gss_buffer_t type_id,
22911 +                               gss_any_t input) const;
22912 +
22913 +    const char *prefix(void) const;
22914 +    const char *name(void) const {
22915 +        return NULL;
22916 +    }
22917 +    bool initWithJsonObject(const gss_eap_attr_ctx *manager GSSEAP_UNUSED,
22918 +                            JSONObject &object GSSEAP_UNUSED) {
22919 +        return false;
22920 +    }
22921 +    JSONObject jsonRepresentation(void) const {
22922 +        return JSONObject::null();
22923 +    }
22924 +
22925 +    bool getAttribute(const gss_buffer_t attr,
22926 +                      int *authenticated,
22927 +                      int *complete,
22928 +                      const opensaml::saml2::Attribute **pAttribute) const;
22929 +    bool getAssertion(int *authenticated,
22930 +                      opensaml::saml2::Assertion **pAssertion,
22931 +                      bool createIfAbsent = false) const;
22932 +
22933 +    static bool init(void);
22934 +    static void finalize(void);
22935 +
22936 +    static gss_eap_attr_provider *createAttrContext(void);
22937 +
22938 +private:
22939 +};
22940 +
22941 +extern "C" {
22942 +#endif
22943 +
22944 +OM_uint32 gssEapSamlAttrProvidersInit(OM_uint32 *minor);
22945 +OM_uint32 gssEapSamlAttrProvidersFinalize(OM_uint32 *minor);
22946 +
22947 +#ifdef __cplusplus
22948 +}
22949 +#endif
22950 +
22951 +#endif /* _UTIL_SAML_H_ */
22952 diff --git a/mech_eap/util_shib.cpp b/mech_eap/util_shib.cpp
22953 new file mode 100644
22954 index 0000000..f8c702b
22955 --- /dev/null
22956 +++ b/mech_eap/util_shib.cpp
22957 @@ -0,0 +1,555 @@
22958 +/*
22959 + * Copyright (c) 2011, JANET(UK)
22960 + * All rights reserved.
22961 + *
22962 + * Redistribution and use in source and binary forms, with or without
22963 + * modification, are permitted provided that the following conditions
22964 + * are met:
22965 + *
22966 + * 1. Redistributions of source code must retain the above copyright
22967 + *    notice, this list of conditions and the following disclaimer.
22968 + *
22969 + * 2. Redistributions in binary form must reproduce the above copyright
22970 + *    notice, this list of conditions and the following disclaimer in the
22971 + *    documentation and/or other materials provided with the distribution.
22972 + *
22973 + * 3. Neither the name of JANET(UK) nor the names of its contributors
22974 + *    may be used to endorse or promote products derived from this software
22975 + *    without specific prior written permission.
22976 + *
22977 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22978 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22979 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22980 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22981 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22982 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22983 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22984 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22985 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22986 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22987 + * SUCH DAMAGE.
22988 + */
22989 +/*
22990 + * Copyright 2001-2009 Internet2
22991 + *
22992 + * Licensed under the Apache License, Version 2.0 (the "License");
22993 + * you may not use this file except in compliance with the License.
22994 + * You may obtain a copy of the License at
22995 + *
22996 + *     http://www.apache.org/licenses/LICENSE-2.0
22997 + *
22998 + * Unless required by applicable law or agreed to in writing, software
22999 + * distributed under the License is distributed on an "AS IS" BASIS,
23000 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23001 + * See the License for the specific language governing permissions and
23002 + * limitations under the License.
23003 + */
23004 +
23005 +/*
23006 + * Local attribute provider implementation.
23007 + */
23008 +
23009 +#include "gssapiP_eap.h"
23010 +
23011 +#include <xmltooling/XMLObject.h>
23012 +#ifndef HAVE_OPENSAML
23013 +#include <xmltooling/XMLToolingConfig.h>
23014 +#include <xmltooling/util/ParserPool.h>
23015 +#endif
23016 +
23017 +#include <saml/saml2/core/Assertions.h>
23018 +
23019 +#include <shibsp/exceptions.h>
23020 +#include <shibsp/attribute/SimpleAttribute.h>
23021 +#include <shibsp/attribute/BinaryAttribute.h>
23022 +#include <shibsp/attribute/ScopedAttribute.h>
23023 +#include <shibresolver/resolver.h>
23024 +
23025 +#include <sstream>
23026 +
23027 +using namespace shibsp;
23028 +using namespace shibresolver;
23029 +using namespace xmltooling;
23030 +using namespace std;
23031 +#ifdef HAVE_OPENSAML
23032 +using namespace opensaml::saml2md;
23033 +using namespace opensaml;
23034 +#else
23035 +using namespace xercesc;
23036 +#endif
23037 +
23038 +gss_eap_shib_attr_provider::gss_eap_shib_attr_provider(void)
23039 +{
23040 +    m_initialized = false;
23041 +    m_authenticated = false;
23042 +}
23043 +
23044 +gss_eap_shib_attr_provider::~gss_eap_shib_attr_provider(void)
23045 +{
23046 +    for_each(m_attributes.begin(),
23047 +             m_attributes.end(),
23048 +             xmltooling::cleanup<Attribute>())
23049 +        ;
23050 +}
23051 +
23052 +bool
23053 +gss_eap_shib_attr_provider::initWithExistingContext(const gss_eap_attr_ctx *manager,
23054 +                                                    const gss_eap_attr_provider *ctx)
23055 +{
23056 +    const gss_eap_shib_attr_provider *shib;
23057 +
23058 +    if (!gss_eap_attr_provider::initWithExistingContext(manager, ctx)) {
23059 +        return false;
23060 +    }
23061 +
23062 +    m_authenticated = false;
23063 +
23064 +    shib = static_cast<const gss_eap_shib_attr_provider *>(ctx);
23065 +    if (shib != NULL) {
23066 +        m_attributes = duplicateAttributes(shib->getAttributes());
23067 +        m_authenticated = shib->authenticated();
23068 +    }
23069 +
23070 +    m_initialized = true;
23071 +
23072 +    return true;
23073 +}
23074 +
23075 +bool
23076 +gss_eap_shib_attr_provider::initWithGssContext(const gss_eap_attr_ctx *manager,
23077 +                                               const gss_cred_id_t gssCred,
23078 +                                               const gss_ctx_id_t gssCtx)
23079 +{
23080 +    if (!gss_eap_attr_provider::initWithGssContext(manager, gssCred, gssCtx))
23081 +        return false;
23082 +
23083 +    auto_ptr<ShibbolethResolver> resolver(ShibbolethResolver::create());
23084 +
23085 +    /*
23086 +     * For now, leave ApplicationID defaulted.
23087 +     * Later on, we could allow this via config option to the mechanism
23088 +     * or rely on an SPRequest interface to pass in a URI identifying the
23089 +     * acceptor.
23090 +     */
23091 +#if 0
23092 +    gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
23093 +    if (gssCred != GSS_C_NO_CREDENTIAL &&
23094 +        gssEapDisplayName(&minor, gssCred->name, &nameBuf, NULL) == GSS_S_COMPLETE) {
23095 +        resolver->setApplicationID((const char *)nameBuf.value);
23096 +        gss_release_buffer(&minor, &nameBuf);
23097 +    }
23098 +#endif
23099 +
23100 +    gss_buffer_desc mechName = GSS_C_EMPTY_BUFFER;
23101 +    OM_uint32 major, minor;
23102 +
23103 +    major = gssEapExportNameInternal(&minor, gssCtx->initiatorName, &mechName,
23104 +                                     EXPORT_NAME_FLAG_OID |
23105 +                                     EXPORT_NAME_FLAG_COMPOSITE);
23106 +    if (major == GSS_S_COMPLETE) {
23107 +        resolver->addToken(&mechName);
23108 +        gss_release_buffer(&minor, &mechName);
23109 +    }
23110 +
23111 +#ifdef HAVE_OPENSAML
23112 +    const gss_eap_saml_assertion_provider *saml;
23113 +    saml = static_cast<const gss_eap_saml_assertion_provider *>
23114 +        (m_manager->getProvider(ATTR_TYPE_SAML_ASSERTION));
23115 +    if (saml != NULL && saml->getAssertion() != NULL) {
23116 +        resolver->addToken(saml->getAssertion());
23117 +    }
23118 +#else
23119 +    /* If no OpenSAML, parse the XML assertion explicitly */
23120 +    const gss_eap_radius_attr_provider *radius;
23121 +    int authenticated, complete;
23122 +    gss_buffer_desc value = GSS_C_EMPTY_BUFFER;
23123 +
23124 +    radius = static_cast<const gss_eap_radius_attr_provider *>
23125 +        (m_manager->getProvider(ATTR_TYPE_RADIUS));
23126 +    if (radius != NULL &&
23127 +        radius->getFragmentedAttribute(PW_SAML_AAA_ASSERTION,
23128 +                                       VENDORPEC_UKERNA,
23129 +                                       &authenticated, &complete, &value)) {
23130 +        string str((char *)value.value, value.length);
23131 +        istringstream istream(str);
23132 +        DOMDocument *doc = XMLToolingConfig::getConfig().getParser().parse(istream);
23133 +        const XMLObjectBuilder *b = XMLObjectBuilder::getBuilder(doc->getDocumentElement());
23134 +        resolver->addToken(b->buildFromDocument(doc));
23135 +        gss_release_buffer(&minor, &value);
23136 +    }
23137 +#endif /* HAVE_OPENSAML */
23138 +
23139 +    try {
23140 +        resolver->resolve();
23141 +        m_attributes = resolver->getResolvedAttributes();
23142 +        resolver->getResolvedAttributes().clear();
23143 +    } catch (exception &e) {
23144 +        return false;
23145 +    }
23146 +
23147 +    m_authenticated = true;
23148 +    m_initialized = true;
23149 +
23150 +    return true;
23151 +}
23152 +
23153 +ssize_t
23154 +gss_eap_shib_attr_provider::getAttributeIndex(const gss_buffer_t attr) const
23155 +{
23156 +    int i = 0;
23157 +
23158 +    GSSEAP_ASSERT(m_initialized);
23159 +
23160 +    for (vector<Attribute *>::const_iterator a = m_attributes.begin();
23161 +         a != m_attributes.end();
23162 +         ++a)
23163 +    {
23164 +        for (vector<string>::const_iterator s = (*a)->getAliases().begin();
23165 +             s != (*a)->getAliases().end();
23166 +             ++s) {
23167 +            if (attr->length == (*s).length() &&
23168 +                memcmp((*s).c_str(), attr->value, attr->length) == 0) {
23169 +                return i;
23170 +            }
23171 +        }
23172 +    }
23173 +
23174 +    return -1;
23175 +}
23176 +
23177 +bool
23178 +gss_eap_shib_attr_provider::setAttribute(int complete GSSEAP_UNUSED,
23179 +                                         const gss_buffer_t attr,
23180 +                                         const gss_buffer_t value)
23181 +{
23182 +    string attrStr((char *)attr->value, attr->length);
23183 +    vector <string> ids(1, attrStr);
23184 +    BinaryAttribute *a = new BinaryAttribute(ids);
23185 +
23186 +    GSSEAP_ASSERT(m_initialized);
23187 +
23188 +    if (value->length != 0) {
23189 +        string valueStr((char *)value->value, value->length);
23190 +
23191 +        a->getValues().push_back(valueStr);
23192 +    }
23193 +
23194 +    m_attributes.push_back(a);
23195 +    m_authenticated = false;
23196 +
23197 +    return true;
23198 +}
23199 +
23200 +bool
23201 +gss_eap_shib_attr_provider::deleteAttribute(const gss_buffer_t attr)
23202 +{
23203 +    int i;
23204 +
23205 +    GSSEAP_ASSERT(m_initialized);
23206 +
23207 +    i = getAttributeIndex(attr);
23208 +    if (i >= 0)
23209 +        m_attributes.erase(m_attributes.begin() + i);
23210 +
23211 +    m_authenticated = false;
23212 +
23213 +    return true;
23214 +}
23215 +
23216 +bool
23217 +gss_eap_shib_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
23218 +                                              void *data) const
23219 +{
23220 +    GSSEAP_ASSERT(m_initialized);
23221 +
23222 +    for (vector<Attribute*>::const_iterator a = m_attributes.begin();
23223 +        a != m_attributes.end();
23224 +        ++a)
23225 +    {
23226 +        gss_buffer_desc attribute;
23227 +
23228 +        attribute.value = (void *)((*a)->getId());
23229 +        attribute.length = strlen((char *)attribute.value);
23230 +
23231 +        if (!addAttribute(m_manager, this, &attribute, data))
23232 +            return false;
23233 +    }
23234 +
23235 +    return true;
23236 +}
23237 +
23238 +const Attribute *
23239 +gss_eap_shib_attr_provider::getAttribute(const gss_buffer_t attr) const
23240 +{
23241 +    const Attribute *ret = NULL;
23242 +
23243 +    GSSEAP_ASSERT(m_initialized);
23244 +
23245 +    for (vector<Attribute *>::const_iterator a = m_attributes.begin();
23246 +         a != m_attributes.end();
23247 +         ++a)
23248 +    {
23249 +        for (vector<string>::const_iterator s = (*a)->getAliases().begin();
23250 +             s != (*a)->getAliases().end();
23251 +             ++s) {
23252 +            if (attr->length == (*s).length() &&
23253 +                memcmp((*s).c_str(), attr->value, attr->length) == 0) {
23254 +                ret = *a;
23255 +                break;
23256 +            }
23257 +        }
23258 +        if (ret != NULL)
23259 +            break;
23260 +    }
23261 +
23262 +    return ret;
23263 +}
23264 +
23265 +bool
23266 +gss_eap_shib_attr_provider::getAttribute(const gss_buffer_t attr,
23267 +                                         int *authenticated,
23268 +                                         int *complete,
23269 +                                         gss_buffer_t value,
23270 +                                         gss_buffer_t display_value,
23271 +                                         int *more) const
23272 +{
23273 +    const Attribute *shibAttr = NULL;
23274 +    const BinaryAttribute *binaryAttr;
23275 +    gss_buffer_desc valueBuf = GSS_C_EMPTY_BUFFER;
23276 +    gss_buffer_desc displayValueBuf = GSS_C_EMPTY_BUFFER;
23277 +    int nvalues, i = *more;
23278 +
23279 +    GSSEAP_ASSERT(m_initialized);
23280 +
23281 +    *more = 0;
23282 +
23283 +    shibAttr = getAttribute(attr);
23284 +    if (shibAttr == NULL)
23285 +        return false;
23286 +
23287 +    nvalues = shibAttr->valueCount();
23288 +
23289 +    if (i == -1)
23290 +        i = 0;
23291 +    if (i >= nvalues)
23292 +        return false;
23293 +
23294 +    binaryAttr = dynamic_cast<const BinaryAttribute *>(shibAttr);
23295 +    if (binaryAttr != NULL) {
23296 +        std::string str = binaryAttr->getValues()[*more];
23297 +
23298 +        valueBuf.value = (void *)str.data();
23299 +        valueBuf.length = str.size();
23300 +    } else {
23301 +        std::string str = shibAttr->getSerializedValues()[*more];
23302 +
23303 +        valueBuf.value = (void *)str.c_str();
23304 +        valueBuf.length = str.length();
23305 +
23306 +        const SimpleAttribute *simpleAttr =
23307 +            dynamic_cast<const SimpleAttribute *>(shibAttr);
23308 +        const ScopedAttribute *scopedAttr =
23309 +            dynamic_cast<const ScopedAttribute *>(shibAttr);
23310 +        if (simpleAttr != NULL || scopedAttr != NULL)
23311 +            displayValueBuf = valueBuf;
23312 +    }
23313 +
23314 +    if (authenticated != NULL)
23315 +        *authenticated = m_authenticated;
23316 +    if (complete != NULL)
23317 +        *complete = true;
23318 +    if (value != NULL)
23319 +        duplicateBuffer(valueBuf, value);
23320 +    if (display_value != NULL)
23321 +        duplicateBuffer(displayValueBuf, display_value);
23322 +    if (nvalues > ++i)
23323 +        *more = i;
23324 +
23325 +    return true;
23326 +}
23327 +
23328 +gss_any_t
23329 +gss_eap_shib_attr_provider::mapToAny(int authenticated,
23330 +                                     gss_buffer_t type_id GSSEAP_UNUSED) const
23331 +{
23332 +    gss_any_t output;
23333 +
23334 +    GSSEAP_ASSERT(m_initialized);
23335 +
23336 +    if (authenticated && !m_authenticated)
23337 +        return (gss_any_t)NULL;
23338 +
23339 +    vector <Attribute *>v = duplicateAttributes(m_attributes);
23340 +
23341 +    output = (gss_any_t)new vector <Attribute *>(v);
23342 +
23343 +    return output;
23344 +}
23345 +
23346 +void
23347 +gss_eap_shib_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED,
23348 +                                                  gss_any_t input) const
23349 +{
23350 +    GSSEAP_ASSERT(m_initialized);
23351 +
23352 +    vector <Attribute *> *v = ((vector <Attribute *> *)input);
23353 +    delete v;
23354 +}
23355 +
23356 +const char *
23357 +gss_eap_shib_attr_provider::prefix(void) const
23358 +{
23359 +    return NULL;
23360 +}
23361 +
23362 +const char *
23363 +gss_eap_shib_attr_provider::name(void) const
23364 +{
23365 +    return "local";
23366 +}
23367 +
23368 +JSONObject
23369 +gss_eap_shib_attr_provider::jsonRepresentation(void) const
23370 +{
23371 +    JSONObject obj;
23372 +
23373 +    if (m_initialized == false)
23374 +        return obj; /* don't export incomplete context */
23375 +
23376 +    JSONObject jattrs = JSONObject::array();
23377 +
23378 +    for (vector<Attribute*>::const_iterator a = m_attributes.begin();
23379 +         a != m_attributes.end(); ++a) {
23380 +        DDF attr = (*a)->marshall();
23381 +        JSONObject jattr = JSONObject::ddf(attr);
23382 +        jattrs.append(jattr);
23383 +    }
23384 +
23385 +    obj.set("attributes", jattrs);
23386 +
23387 +    obj.set("authenticated", m_authenticated);
23388 +
23389 +    return obj;
23390 +}
23391 +
23392 +bool
23393 +gss_eap_shib_attr_provider::initWithJsonObject(const gss_eap_attr_ctx *ctx,
23394 +                                               JSONObject &obj)
23395 +{
23396 +    if (!gss_eap_attr_provider::initWithJsonObject(ctx, obj))
23397 +        return false;
23398 +
23399 +    GSSEAP_ASSERT(m_authenticated == false);
23400 +    GSSEAP_ASSERT(m_attributes.size() == 0);
23401 +
23402 +    JSONObject jattrs = obj["attributes"];
23403 +    size_t nelems = jattrs.size();
23404 +
23405 +    for (size_t i = 0; i < nelems; i++) {
23406 +        JSONObject jattr = jattrs.get(i);
23407 +
23408 +        DDF attr = jattr.ddf();
23409 +        Attribute *attribute = Attribute::unmarshall(attr);
23410 +        m_attributes.push_back(attribute);
23411 +    }
23412 +
23413 +    m_authenticated = obj["authenticated"].integer();
23414 +    m_initialized = true;
23415 +
23416 +    return true;
23417 +}
23418 +
23419 +bool
23420 +gss_eap_shib_attr_provider::init(void)
23421 +{
23422 +    bool ret = false;
23423 +
23424 +    try {
23425 +        ret = ShibbolethResolver::init();
23426 +    } catch (exception &e) {
23427 +    }
23428 +
23429 +    if (ret)
23430 +        gss_eap_attr_ctx::registerProvider(ATTR_TYPE_LOCAL, createAttrContext);
23431 +
23432 +    return ret;
23433 +}
23434 +
23435 +void
23436 +gss_eap_shib_attr_provider::finalize(void)
23437 +{
23438 +    gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_LOCAL);
23439 +    ShibbolethResolver::term();
23440 +}
23441 +
23442 +OM_uint32
23443 +gss_eap_shib_attr_provider::mapException(OM_uint32 *minor,
23444 +                                         std::exception &e) const
23445 +{
23446 +    if (typeid(e) == typeid(AttributeException))
23447 +        *minor = GSSEAP_SHIB_ATTR_FAILURE;
23448 +    else if (typeid(e) == typeid(AttributeExtractionException))
23449 +        *minor = GSSEAP_SHIB_ATTR_EXTRACT_FAILURE;
23450 +    else if (typeid(e) == typeid(AttributeFilteringException))
23451 +        *minor = GSSEAP_SHIB_ATTR_FILTER_FAILURE;
23452 +    else if (typeid(e) == typeid(AttributeResolutionException))
23453 +        *minor = GSSEAP_SHIB_ATTR_RESOLVE_FAILURE;
23454 +    else if (typeid(e) == typeid(ConfigurationException))
23455 +        *minor = GSSEAP_SHIB_CONFIG_FAILURE;
23456 +    else if (typeid(e) == typeid(ListenerException))
23457 +        *minor = GSSEAP_SHIB_LISTENER_FAILURE;
23458 +    else
23459 +        return GSS_S_CONTINUE_NEEDED;
23460 +
23461 +    gssEapSaveStatusInfo(*minor, "%s", e.what());
23462 +
23463 +    return GSS_S_FAILURE;
23464 +}
23465 +
23466 +gss_eap_attr_provider *
23467 +gss_eap_shib_attr_provider::createAttrContext(void)
23468 +{
23469 +    return new gss_eap_shib_attr_provider;
23470 +}
23471 +
23472 +Attribute *
23473 +gss_eap_shib_attr_provider::duplicateAttribute(const Attribute *src)
23474 +{
23475 +    DDF obj = src->marshall();
23476 +    Attribute *attribute = Attribute::unmarshall(obj);
23477 +    obj.destroy();
23478 +
23479 +    return attribute;
23480 +}
23481 +
23482 +vector <Attribute *>
23483 +gss_eap_shib_attr_provider::duplicateAttributes(const vector <Attribute *>src)
23484 +{
23485 +    vector <Attribute *> dst;
23486 +
23487 +    for (vector<Attribute *>::const_iterator a = src.begin();
23488 +         a != src.end();
23489 +         ++a)
23490 +        dst.push_back(duplicateAttribute(*a));
23491 +
23492 +    return dst;
23493 +}
23494 +
23495 +OM_uint32
23496 +gssEapLocalAttrProviderInit(OM_uint32 *minor)
23497 +{
23498 +    if (!gss_eap_shib_attr_provider::init()) {
23499 +        *minor = GSSEAP_SHIB_INIT_FAILURE;
23500 +        return GSS_S_FAILURE;
23501 +    }
23502 +    return GSS_S_COMPLETE;
23503 +}
23504 +
23505 +OM_uint32
23506 +gssEapLocalAttrProviderFinalize(OM_uint32 *minor)
23507 +{
23508 +    gss_eap_shib_attr_provider::finalize();
23509 +
23510 +    *minor = 0;
23511 +    return GSS_S_COMPLETE;
23512 +}
23513 diff --git a/mech_eap/util_shib.h b/mech_eap/util_shib.h
23514 new file mode 100644
23515 index 0000000..4cf7481
23516 --- /dev/null
23517 +++ b/mech_eap/util_shib.h
23518 @@ -0,0 +1,122 @@
23519 +/*
23520 + * Copyright (c) 2011, JANET(UK)
23521 + * All rights reserved.
23522 + *
23523 + * Redistribution and use in source and binary forms, with or without
23524 + * modification, are permitted provided that the following conditions
23525 + * are met:
23526 + *
23527 + * 1. Redistributions of source code must retain the above copyright
23528 + *    notice, this list of conditions and the following disclaimer.
23529 + *
23530 + * 2. Redistributions in binary form must reproduce the above copyright
23531 + *    notice, this list of conditions and the following disclaimer in the
23532 + *    documentation and/or other materials provided with the distribution.
23533 + *
23534 + * 3. Neither the name of JANET(UK) nor the names of its contributors
23535 + *    may be used to endorse or promote products derived from this software
23536 + *    without specific prior written permission.
23537 + *
23538 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23539 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23540 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23541 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23542 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23543 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23544 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23545 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23546 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23547 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23548 + * SUCH DAMAGE.
23549 + */
23550 +
23551 +/*
23552 + * Local attribute provider.
23553 + */
23554 +
23555 +#ifndef _UTIL_SHIB_H_
23556 +#define _UTIL_SHIB_H_ 1
23557 +
23558 +#ifdef __cplusplus
23559 +
23560 +#include <vector>
23561 +
23562 +namespace shibsp {
23563 +    class Attribute;
23564 +};
23565 +
23566 +namespace shibresolver {
23567 +    class ShibbolethResolver;
23568 +};
23569 +
23570 +struct gss_eap_shib_attr_provider : gss_eap_attr_provider {
23571 +public:
23572 +    gss_eap_shib_attr_provider(void);
23573 +    ~gss_eap_shib_attr_provider(void);
23574 +
23575 +    bool initWithExistingContext(const gss_eap_attr_ctx *source,
23576 +                                 const gss_eap_attr_provider *ctx);
23577 +    bool initWithGssContext(const gss_eap_attr_ctx *source,
23578 +                            const gss_cred_id_t cred,
23579 +                            const gss_ctx_id_t ctx);
23580 +
23581 +    bool setAttribute(int complete,
23582 +                      const gss_buffer_t attr,
23583 +                      const gss_buffer_t value);
23584 +    bool deleteAttribute(const gss_buffer_t value);
23585 +    bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const;
23586 +    bool getAttribute(const gss_buffer_t attr,
23587 +                      int *authenticated,
23588 +                      int *complete,
23589 +                      gss_buffer_t value,
23590 +                      gss_buffer_t display_value,
23591 +                      int *more) const;
23592 +    gss_any_t mapToAny(int authenticated,
23593 +                       gss_buffer_t type_id) const;
23594 +    void releaseAnyNameMapping(gss_buffer_t type_id,
23595 +                               gss_any_t input) const;
23596 +
23597 +    const char *prefix(void) const;
23598 +    const char *name(void) const;
23599 +    bool initWithJsonObject(const gss_eap_attr_ctx *manager,
23600 +                            JSONObject &obj);
23601 +    JSONObject jsonRepresentation(void) const;
23602 +
23603 +    static bool init(void);
23604 +    static void finalize(void);
23605 +
23606 +    OM_uint32 mapException(OM_uint32 *minor, std::exception &e) const;
23607 +
23608 +    static gss_eap_attr_provider *createAttrContext(void);
23609 +
23610 +    std::vector<shibsp::Attribute *> getAttributes(void) const {
23611 +        return m_attributes;
23612 +    }
23613 +
23614 +private:
23615 +    static shibsp::Attribute *
23616 +        duplicateAttribute(const shibsp::Attribute *src);
23617 +    static std::vector <shibsp::Attribute *>
23618 +        duplicateAttributes(const std::vector <shibsp::Attribute *>src);
23619 +
23620 +    ssize_t getAttributeIndex(const gss_buffer_t attr) const;
23621 +    const shibsp::Attribute *getAttribute(const gss_buffer_t attr) const;
23622 +
23623 +    bool authenticated(void) const { return m_authenticated; }
23624 +
23625 +    bool m_initialized;
23626 +    bool m_authenticated;
23627 +    std::vector<shibsp::Attribute *> m_attributes;
23628 +};
23629 +
23630 +extern "C" {
23631 +#endif
23632 +
23633 +OM_uint32 gssEapLocalAttrProviderInit(OM_uint32 *minor);
23634 +OM_uint32 gssEapLocalAttrProviderFinalize(OM_uint32 *minor);
23635 +
23636 +#ifdef __cplusplus
23637 +}
23638 +#endif
23639 +
23640 +#endif /* _UTIL_SHIB_H_ */
23641 diff --git a/mech_eap/util_sm.c b/mech_eap/util_sm.c
23642 new file mode 100644
23643 index 0000000..56248d8
23644 --- /dev/null
23645 +++ b/mech_eap/util_sm.c
23646 @@ -0,0 +1,372 @@
23647 +/*
23648 + * Copyright (c) 2011, JANET(UK)
23649 + * All rights reserved.
23650 + *
23651 + * Redistribution and use in source and binary forms, with or without
23652 + * modification, are permitted provided that the following conditions
23653 + * are met:
23654 + *
23655 + * 1. Redistributions of source code must retain the above copyright
23656 + *    notice, this list of conditions and the following disclaimer.
23657 + *
23658 + * 2. Redistributions in binary form must reproduce the above copyright
23659 + *    notice, this list of conditions and the following disclaimer in the
23660 + *    documentation and/or other materials provided with the distribution.
23661 + *
23662 + * 3. Neither the name of JANET(UK) nor the names of its contributors
23663 + *    may be used to endorse or promote products derived from this software
23664 + *    without specific prior written permission.
23665 + *
23666 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23667 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23668 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23669 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23670 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23671 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23672 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23673 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23674 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23675 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23676 + * SUCH DAMAGE.
23677 + */
23678 +
23679 +/*
23680 + * Context establishment state machine.
23681 + */
23682 +
23683 +#include "gssapiP_eap.h"
23684 +
23685 +/* private flags */
23686 +#define SM_FLAG_TRANSITED                   0x80000000
23687 +
23688 +#define SM_ASSERT_VALID(ctx, status)        do { \
23689 +        GSSEAP_ASSERT(GSS_ERROR((status)) || \
23690 +               ((status) == GSS_S_CONTINUE_NEEDED && ((ctx)->state > GSSEAP_STATE_INITIAL && (ctx)->state < GSSEAP_STATE_ESTABLISHED)) || \
23691 +               ((status) == GSS_S_COMPLETE && (ctx)->state == GSSEAP_STATE_ESTABLISHED)); \
23692 +    } while (0)
23693 +
23694 +#ifdef GSSEAP_DEBUG
23695 +static const char *
23696 +gssEapStateToString(enum gss_eap_state state)
23697 +{
23698 +    const char *s;
23699 +
23700 +    switch (state) {
23701 +    case GSSEAP_STATE_INITIAL:
23702 +        s = "INITIAL";
23703 +        break;
23704 +    case GSSEAP_STATE_AUTHENTICATE:
23705 +        s = "AUTHENTICATE";
23706 +        break;
23707 +    case GSSEAP_STATE_INITIATOR_EXTS:
23708 +        s = "INITIATOR_EXTS";
23709 +        break;
23710 +    case GSSEAP_STATE_ACCEPTOR_EXTS:
23711 +        s = "ACCEPTOR_EXTS";
23712 +        break;
23713 +#ifdef GSSEAP_ENABLE_REAUTH
23714 +    case GSSEAP_STATE_REAUTHENTICATE:
23715 +        s = "REAUTHENTICATE";
23716 +        break;
23717 +#endif
23718 +    case GSSEAP_STATE_ESTABLISHED:
23719 +        s = "ESTABLISHED";
23720 +        break;
23721 +    default:
23722 +        s = "INVALID";
23723 +        break;
23724 +    }
23725 +
23726 +    return s;
23727 +}
23728 +
23729 +void
23730 +gssEapSmTransition(gss_ctx_id_t ctx, enum gss_eap_state state)
23731 +{
23732 +    GSSEAP_ASSERT(state >= GSSEAP_STATE_INITIAL);
23733 +    GSSEAP_ASSERT(state <= GSSEAP_STATE_ESTABLISHED);
23734 +
23735 +    fprintf(stderr, "GSS-EAP: state transition %s->%s\n",
23736 +            gssEapStateToString(GSSEAP_SM_STATE(ctx)),
23737 +            gssEapStateToString(state));
23738 +
23739 +    ctx->state = state;
23740 +}
23741 +#endif /* GSSEAP_DEBUG */
23742 +
23743 +static OM_uint32
23744 +makeErrorToken(OM_uint32 *minor,
23745 +               OM_uint32 majorStatus,
23746 +               OM_uint32 minorStatus,
23747 +               struct gss_eap_token_buffer_set *token)
23748 +{
23749 +    OM_uint32 major, tmpMinor;
23750 +    unsigned char errorData[8];
23751 +    gss_buffer_desc errorBuffer;
23752 +
23753 +    GSSEAP_ASSERT(GSS_ERROR(majorStatus));
23754 +
23755 +    /*
23756 +     * Only return error codes that the initiator could have caused,
23757 +     * to avoid information leakage.
23758 +     */
23759 +    if (IS_RADIUS_ERROR(minorStatus)) {
23760 +        /* Squash RADIUS error codes */
23761 +        minorStatus = GSSEAP_RADIUS_PROT_FAILURE;
23762 +    } else if (!IS_WIRE_ERROR(minorStatus)) {
23763 +        /* Don't return non-wire error codes */
23764 +        return GSS_S_COMPLETE;
23765 +    }
23766 +
23767 +    minorStatus -= ERROR_TABLE_BASE_eapg;
23768 +
23769 +    store_uint32_be(majorStatus, &errorData[0]);
23770 +    store_uint32_be(minorStatus, &errorData[4]);
23771 +
23772 +    major = gssEapAllocInnerTokens(&tmpMinor, 1, token);
23773 +    if (GSS_ERROR(major)) {
23774 +        *minor = tmpMinor;
23775 +        return major;
23776 +    }
23777 +
23778 +    errorBuffer.length = sizeof(errorData);
23779 +    errorBuffer.value = errorData;
23780 +
23781 +    major = duplicateBuffer(&tmpMinor, &errorBuffer, &token->buffers.elements[0]);
23782 +    if (GSS_ERROR(major)) {
23783 +        gssEapReleaseInnerTokens(&tmpMinor, token, 1);
23784 +        *minor = tmpMinor;
23785 +        return major;
23786 +    }
23787 +
23788 +    token->buffers.count = 1;
23789 +    token->types[0] = ITOK_TYPE_CONTEXT_ERR | ITOK_FLAG_CRITICAL;
23790 +
23791 +    *minor = 0;
23792 +    return GSS_S_COMPLETE;
23793 +}
23794 +
23795 +OM_uint32
23796 +gssEapSmStep(OM_uint32 *minor,
23797 +             gss_cred_id_t cred,
23798 +             gss_ctx_id_t ctx,
23799 +             gss_name_t target,
23800 +             gss_OID mech,
23801 +             OM_uint32 reqFlags,
23802 +             OM_uint32 timeReq,
23803 +             gss_channel_bindings_t chanBindings,
23804 +             gss_buffer_t inputToken,
23805 +             gss_buffer_t outputToken,
23806 +             struct gss_eap_sm *sm, /* ordered by state */
23807 +             size_t smCount)
23808 +{
23809 +    OM_uint32 major, tmpMajor, tmpMinor;
23810 +    struct gss_eap_token_buffer_set inputTokens = { { 0, GSS_C_NO_BUFFER }, NULL };
23811 +    struct gss_eap_token_buffer_set outputTokens = { { 0, GSS_C_NO_BUFFER }, NULL };
23812 +    gss_buffer_desc unwrappedInputToken = GSS_C_EMPTY_BUFFER;
23813 +    gss_buffer_desc unwrappedOutputToken = GSS_C_EMPTY_BUFFER;
23814 +    unsigned int smFlags = 0;
23815 +    size_t i, j;
23816 +    int initialContextToken = 0;
23817 +    enum gss_eap_token_type tokType;
23818 +
23819 +    GSSEAP_ASSERT(smCount > 0);
23820 +
23821 +    *minor = 0;
23822 +
23823 +    outputToken->length = 0;
23824 +    outputToken->value = NULL;
23825 +
23826 +    if (inputToken != GSS_C_NO_BUFFER && inputToken->length != 0) {
23827 +        major = gssEapVerifyToken(minor, ctx, inputToken, &tokType,
23828 +                                  &unwrappedInputToken);
23829 +        if (GSS_ERROR(major))
23830 +            goto cleanup;
23831 +
23832 +        if (tokType != (CTX_IS_INITIATOR(ctx)
23833 +                    ? TOK_TYPE_ACCEPTOR_CONTEXT : TOK_TYPE_INITIATOR_CONTEXT)) {
23834 +            major = GSS_S_DEFECTIVE_TOKEN;
23835 +            *minor = GSSEAP_WRONG_TOK_ID;
23836 +            goto cleanup;
23837 +        }
23838 +    } else if (!CTX_IS_INITIATOR(ctx) || ctx->state != GSSEAP_STATE_INITIAL) {
23839 +        major = GSS_S_DEFECTIVE_TOKEN;
23840 +        *minor = GSSEAP_WRONG_SIZE;
23841 +        goto cleanup;
23842 +    } else {
23843 +        initialContextToken = 1;
23844 +    }
23845 +
23846 +    if (CTX_IS_ESTABLISHED(ctx)) {
23847 +        major = GSS_S_BAD_STATUS;
23848 +        *minor = GSSEAP_CONTEXT_ESTABLISHED;
23849 +        goto cleanup;
23850 +    }
23851 +
23852 +    GSSEAP_ASSERT(ctx->state < GSSEAP_STATE_ESTABLISHED);
23853 +
23854 +    major = gssEapDecodeInnerTokens(minor, &unwrappedInputToken, &inputTokens);
23855 +    if (GSS_ERROR(major))
23856 +        goto cleanup;
23857 +
23858 +    major = gssEapAllocInnerTokens(minor, smCount, &outputTokens);
23859 +    if (GSS_ERROR(major))
23860 +        goto cleanup;
23861 +
23862 +    ctx->inputTokens = &inputTokens;
23863 +    ctx->outputTokens = &outputTokens;
23864 +
23865 +    /* Process all the tokens that are valid for the current state. */
23866 +    for (i = 0; i < smCount; i++) {
23867 +        struct gss_eap_sm *smp = &sm[i];
23868 +        int processToken = 0;
23869 +        gss_buffer_t innerInputToken = GSS_C_NO_BUFFER;
23870 +        OM_uint32 *inputTokenType = NULL;
23871 +        gss_buffer_desc innerOutputToken = GSS_C_EMPTY_BUFFER;
23872 +
23873 +        if ((smp->validStates & ctx->state) == 0)
23874 +            continue;
23875 +
23876 +        /*
23877 +         * We special case the first call to gss_init_sec_context so that
23878 +         * all token providers have the opportunity to generate an initial
23879 +         * context token. Providers where inputTokenType is ITOK_TYPE_NONE
23880 +         * are always called and generally act on state transition boundaries,
23881 +         * for example to advance the state after a series of optional tokens
23882 +         * (as is the case with the extension token exchange) or to generate
23883 +         * a new token after the state was advanced by a provider which did
23884 +         * not emit a token.
23885 +         */
23886 +        if (smp->inputTokenType == ITOK_TYPE_NONE || initialContextToken) {
23887 +            processToken = 1;
23888 +        } else if ((smFlags & SM_FLAG_TRANSITED) == 0) {
23889 +            /* Don't regurgitate a token which belonds to a previous state. */
23890 +            for (j = 0; j < inputTokens.buffers.count; j++) {
23891 +                if ((inputTokens.types[j] & ITOK_TYPE_MASK) == smp->inputTokenType) {
23892 +                    if (processToken) {
23893 +                        /* Check for duplicate inner tokens */
23894 +                        major = GSS_S_DEFECTIVE_TOKEN;
23895 +                        *minor = GSSEAP_DUPLICATE_ITOK;
23896 +                        break;
23897 +                    }
23898 +                    processToken = 1;
23899 +                    innerInputToken = &inputTokens.buffers.elements[j];
23900 +                    inputTokenType = &inputTokens.types[j];
23901 +                }
23902 +            }
23903 +            if (GSS_ERROR(major))
23904 +                break;
23905 +        }
23906 +
23907 +        if (processToken) {
23908 +            enum gss_eap_state oldState = ctx->state;
23909 +
23910 +            smFlags = 0;
23911 +            if (inputTokenType != NULL && (*inputTokenType & ITOK_FLAG_CRITICAL))
23912 +                smFlags |= SM_FLAG_INPUT_TOKEN_CRITICAL;
23913 +
23914 +            major = smp->processToken(minor, cred, ctx, target, mech, reqFlags,
23915 +                                      timeReq, chanBindings, innerInputToken,
23916 +                                      &innerOutputToken, &smFlags);
23917 +            if (GSS_ERROR(major))
23918 +                break;
23919 +
23920 +            if (inputTokenType != NULL)
23921 +                *inputTokenType |= ITOK_FLAG_VERIFIED;
23922 +            if (ctx->state < oldState)
23923 +                i = 0; /* restart */
23924 +            else if (ctx->state != oldState)
23925 +                smFlags |= SM_FLAG_TRANSITED;
23926 +
23927 +            if (innerOutputToken.value != NULL) {
23928 +                outputTokens.buffers.elements[outputTokens.buffers.count] = innerOutputToken;
23929 +                GSSEAP_ASSERT(smp->outputTokenType != ITOK_TYPE_NONE);
23930 +                outputTokens.types[outputTokens.buffers.count] = smp->outputTokenType;
23931 +                if (smFlags & SM_FLAG_OUTPUT_TOKEN_CRITICAL)
23932 +                    outputTokens.types[outputTokens.buffers.count] |= ITOK_FLAG_CRITICAL;
23933 +                outputTokens.buffers.count++;
23934 +            }
23935 +            /*
23936 +             * Break out if we made a state transition and have some tokens to send.
23937 +             */
23938 +            if ((smFlags & SM_FLAG_TRANSITED) &&
23939 +                 ((smFlags & SM_FLAG_FORCE_SEND_TOKEN) || outputTokens.buffers.count != 0)) {
23940 +                SM_ASSERT_VALID(ctx, major);
23941 +                break;
23942 +            }
23943 +        } else if ((smp->itokFlags & SM_ITOK_FLAG_REQUIRED) &&
23944 +            smp->inputTokenType != ITOK_TYPE_NONE) {
23945 +            /* Check for required inner tokens */
23946 +            major = GSS_S_DEFECTIVE_TOKEN;
23947 +            *minor = GSSEAP_MISSING_REQUIRED_ITOK;
23948 +            break;
23949 +        }
23950 +    }
23951 +
23952 +    GSSEAP_ASSERT(outputTokens.buffers.count <= smCount);
23953 +
23954 +    /* Check we understood all critical tokens sent by peer */
23955 +    if (!GSS_ERROR(major)) {
23956 +        for (j = 0; j < inputTokens.buffers.count; j++) {
23957 +            if ((inputTokens.types[j] & ITOK_FLAG_CRITICAL) &&
23958 +                (inputTokens.types[j] & ITOK_FLAG_VERIFIED) == 0) {
23959 +                major = GSS_S_UNAVAILABLE;
23960 +                *minor = GSSEAP_CRIT_ITOK_UNAVAILABLE;
23961 +                goto cleanup;
23962 +            }
23963 +        }
23964 +    }
23965 +
23966 +    /* Optionaly emit an error token if we are the acceptor */
23967 +    if (GSS_ERROR(major)) {
23968 +        if (CTX_IS_INITIATOR(ctx))
23969 +            goto cleanup; /* return error directly to caller */
23970 +
23971 +        /* replace any emitted tokens with error token */
23972 +        gssEapReleaseInnerTokens(&tmpMinor, &outputTokens, 1);
23973 +
23974 +        tmpMajor = makeErrorToken(&tmpMinor, major, *minor, &outputTokens);
23975 +        if (GSS_ERROR(tmpMajor)) {
23976 +            major = tmpMajor;
23977 +            *minor = tmpMinor;
23978 +            goto cleanup;
23979 +        }
23980 +    }
23981 +
23982 +    /* Format output token from inner tokens */
23983 +    if (outputTokens.buffers.count != 0 ||            /* inner tokens to send */
23984 +        !CTX_IS_INITIATOR(ctx) ||                   /* any leg acceptor */
23985 +        !CTX_IS_ESTABLISHED(ctx)) {                 /* non-last leg initiator */
23986 +        tmpMajor = gssEapEncodeInnerTokens(&tmpMinor, &outputTokens, &unwrappedOutputToken);
23987 +        if (tmpMajor == GSS_S_COMPLETE) {
23988 +            if (CTX_IS_INITIATOR(ctx))
23989 +                tokType = TOK_TYPE_INITIATOR_CONTEXT;
23990 +            else
23991 +                tokType = TOK_TYPE_ACCEPTOR_CONTEXT;
23992 +
23993 +            tmpMajor = gssEapMakeToken(&tmpMinor, ctx, &unwrappedOutputToken,
23994 +                                       tokType, outputToken);
23995 +            if (GSS_ERROR(tmpMajor)) {
23996 +                major = tmpMajor;
23997 +                *minor = tmpMinor;
23998 +                goto cleanup;
23999 +            }
24000 +        }
24001 +    }
24002 +
24003 +    /* If the context is established, empty tokens only to be emitted by initiator */
24004 +    GSSEAP_ASSERT(!CTX_IS_ESTABLISHED(ctx) || ((outputToken->length == 0) == CTX_IS_INITIATOR(ctx)));
24005 +
24006 +    SM_ASSERT_VALID(ctx, major);
24007 +
24008 +cleanup:
24009 +    gssEapReleaseInnerTokens(&tmpMinor, &inputTokens, 0);
24010 +    gssEapReleaseInnerTokens(&tmpMinor, &inputTokens, 1);
24011 +
24012 +    gss_release_buffer(&tmpMinor, &unwrappedOutputToken);
24013 +
24014 +    ctx->inputTokens = NULL;
24015 +    ctx->outputTokens = NULL;
24016 +
24017 +    return major;
24018 +}
24019 diff --git a/mech_eap/util_tld.c b/mech_eap/util_tld.c
24020 new file mode 100644
24021 index 0000000..05bc3d1
24022 --- /dev/null
24023 +++ b/mech_eap/util_tld.c
24024 @@ -0,0 +1,167 @@
24025 +/*
24026 + * Copyright (c) 2011, JANET(UK)
24027 + * All rights reserved.
24028 + *
24029 + * Redistribution and use in source and binary forms, with or without
24030 + * modification, are permitted provided that the following conditions
24031 + * are met:
24032 + *
24033 + * 1. Redistributions of source code must retain the above copyright
24034 + *    notice, this list of conditions and the following disclaimer.
24035 + *
24036 + * 2. Redistributions in binary form must reproduce the above copyright
24037 + *    notice, this list of conditions and the following disclaimer in the
24038 + *    documentation and/or other materials provided with the distribution.
24039 + *
24040 + * 3. Neither the name of JANET(UK) nor the names of its contributors
24041 + *    may be used to endorse or promote products derived from this software
24042 + *    without specific prior written permission.
24043 + *
24044 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24045 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24046 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24047 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24048 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24049 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24050 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24051 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24052 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24053 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24054 + * SUCH DAMAGE.
24055 + */
24056 +
24057 +/*
24058 + * Thread local data abstraction, using pthreads on Unix and the TlsXXX
24059 + * APIs on Windows.
24060 + */
24061 +
24062 +#include "gssapiP_eap.h"
24063 +
24064 +/* Clean up thread-local data; called on thread detach */
24065 +static void
24066 +destroyThreadLocalData(struct gss_eap_thread_local_data *tld)
24067 +{
24068 +    if (tld->statusInfo != NULL)
24069 +        gssEapDestroyStatusInfo(tld->statusInfo);
24070 +    if (tld->krbContext != NULL)
24071 +        gssEapDestroyKrbContext(tld->krbContext);
24072 +    GSSEAP_FREE(tld);
24073 +}
24074 +
24075 +#ifdef WIN32
24076 +
24077 +/*
24078 + * This is the TLS index returned by TlsAlloc() on process init.
24079 + * Each thread, on thread attach in DllMain(), allocates its thread-local
24080 + * data and uses this index with TlsSetValue() to store it.
24081 + * It can then subsequently be retrieved with TlsGetValue().
24082 + */
24083 +static DWORD tlsIndex = TLS_OUT_OF_INDEXES;
24084 +
24085 +/* Access thread-local data */
24086 +struct gss_eap_thread_local_data *
24087 +gssEapGetThreadLocalData(void)
24088 +{
24089 +    struct gss_eap_thread_local_data *tlsData;
24090 +
24091 +    GSSEAP_ASSERT(tlsIndex != TLS_OUT_OF_INDEXES);
24092 +
24093 +    tlsData = TlsGetValue(tlsIndex);
24094 +    if (tlsData == NULL) {
24095 +        tlsData = GSSEAP_CALLOC(1, sizeof(*tlsData));
24096 +        TlsSetValue(tlsIndex, tlsData);
24097 +    }
24098 +
24099 +    return tlsData;
24100 +}
24101 +
24102 +BOOL WINAPI
24103 +DllMain(HINSTANCE hDLL,     /* DLL module handle */
24104 +        DWORD reason,       /* reason called */
24105 +        LPVOID reserved)    /* reserved */
24106 +{
24107 +    struct gss_eap_thread_local_data *tlsData;
24108 +    OM_uint32 major, minor;
24109 +
24110 +    switch (reason) {
24111 +        case DLL_PROCESS_ATTACH:
24112 +            /* Allocate a TLS index. */
24113 +            major = gssEapInitiatorInit(&minor);
24114 +            if (GSS_ERROR(major))
24115 +                return FALSE;
24116 +
24117 +            tlsIndex = TlsAlloc();
24118 +            if (tlsIndex == TLS_OUT_OF_INDEXES)
24119 +                return FALSE;
24120 +            /* No break: Initialize the index for first thread.*/
24121 +        case DLL_THREAD_ATTACH:
24122 +            /* Initialize the TLS index for this thread. */
24123 +            tlsData = GSSEAP_CALLOC(1, sizeof(*tlsData));
24124 +            if (tlsData == NULL)
24125 +                return FALSE;
24126 +            TlsSetValue(tlsIndex, tlsData);
24127 +            break;
24128 +        case DLL_THREAD_DETACH:
24129 +            /* Release the allocated memory for this thread. */
24130 +            tlsData = TlsGetValue(tlsIndex);
24131 +            if (tlsData != NULL) {
24132 +                destroyThreadLocalData(tlsData);
24133 +                TlsSetValue(tlsIndex, NULL);
24134 +            }
24135 +            break;
24136 +        case DLL_PROCESS_DETACH:
24137 +            /* Release the TLS index. */
24138 +            TlsFree(tlsIndex);
24139 +            gssEapFinalize();
24140 +            break;
24141 +        default:
24142 +            break;
24143 +    }
24144 +
24145 +    return TRUE;
24146 +    UNREFERENCED_PARAMETER(hDLL);
24147 +    UNREFERENCED_PARAMETER(reserved);
24148 +}
24149 +
24150 +#else /* WIN32 */
24151 +
24152 +/* pthreads implementation */
24153 +
24154 +static GSSEAP_THREAD_ONCE tldKeyOnce = GSSEAP_ONCE_INITIALIZER;
24155 +static GSSEAP_THREAD_KEY tldKey;
24156 +
24157 +static void
24158 +pthreadDestroyThreadLocalData(void *arg)
24159 +{
24160 +    struct gss_eap_thread_local_data* tld = arg;
24161 +
24162 +    if (tld != NULL)
24163 +        destroyThreadLocalData(tld);
24164 +}
24165 +
24166 +static void
24167 +createThreadLocalDataKey(void)
24168 +{
24169 +    GSSEAP_KEY_CREATE(&tldKey, pthreadDestroyThreadLocalData);
24170 +}
24171 +
24172 +struct gss_eap_thread_local_data *
24173 +gssEapGetThreadLocalData()
24174 +{
24175 +    struct gss_eap_thread_local_data *tld;
24176 +
24177 +    GSSEAP_ONCE(&tldKeyOnce, createThreadLocalDataKey);
24178 +
24179 +    tld = GSSEAP_GETSPECIFIC(tldKey);
24180 +    if (tld == NULL) {
24181 +        tld = GSSEAP_CALLOC(1, sizeof(*tld));
24182 +        if (tld == NULL)
24183 +            return NULL;
24184 +
24185 +        GSSEAP_SETSPECIFIC(tldKey, tld);
24186 +    }
24187 +
24188 +    return tld;
24189 +}
24190 +
24191 +#endif /* WIN32 */
24192 diff --git a/mech_eap/util_token.c b/mech_eap/util_token.c
24193 new file mode 100644
24194 index 0000000..a1aea0c
24195 --- /dev/null
24196 +++ b/mech_eap/util_token.c
24197 @@ -0,0 +1,493 @@
24198 +/*
24199 + * Copyright (c) 2011, JANET(UK)
24200 + * All rights reserved.
24201 + *
24202 + * Redistribution and use in source and binary forms, with or without
24203 + * modification, are permitted provided that the following conditions
24204 + * are met:
24205 + *
24206 + * 1. Redistributions of source code must retain the above copyright
24207 + *    notice, this list of conditions and the following disclaimer.
24208 + *
24209 + * 2. Redistributions in binary form must reproduce the above copyright
24210 + *    notice, this list of conditions and the following disclaimer in the
24211 + *    documentation and/or other materials provided with the distribution.
24212 + *
24213 + * 3. Neither the name of JANET(UK) nor the names of its contributors
24214 + *    may be used to endorse or promote products derived from this software
24215 + *    without specific prior written permission.
24216 + *
24217 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24218 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24219 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24220 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24221 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24222 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24223 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24224 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24225 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24226 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24227 + * SUCH DAMAGE.
24228 + */
24229 +/*
24230 + * Portions Copyright 1993 by OpenVision Technologies, Inc.
24231 + *
24232 + * Permission to use, copy, modify, distribute, and sell this software
24233 + * and its documentation for any purpose is hereby granted without fee,
24234 + * provided that the above copyright notice appears in all copies and
24235 + * that both that copyright notice and this permission notice appear in
24236 + * supporting documentation, and that the name of OpenVision not be used
24237 + * in advertising or publicity pertaining to distribution of the software
24238 + * without specific, written prior permission. OpenVision makes no
24239 + * representations about the suitability of this software for any
24240 + * purpose.  It is provided "as is" without express or implied warranty.
24241 + *
24242 + * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
24243 + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
24244 + * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
24245 + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
24246 + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
24247 + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
24248 + * PERFORMANCE OF THIS SOFTWARE.
24249 + */
24250 +
24251 +/*
24252 + * Utility routines for GSS tokens.
24253 + */
24254 +
24255 +#include "gssapiP_eap.h"
24256 +
24257 +OM_uint32
24258 +gssEapEncodeInnerTokens(OM_uint32 *minor,
24259 +                        struct gss_eap_token_buffer_set *tokens,
24260 +                        gss_buffer_t buffer)
24261 +{
24262 +    OM_uint32 major, tmpMinor;
24263 +    size_t required = 0, i;
24264 +    unsigned char *p;
24265 +
24266 +    buffer->value = NULL;
24267 +    buffer->length = 0;
24268 +
24269 +    for (i = 0; i < tokens->buffers.count; i++) {
24270 +        required += 8 + tokens->buffers.elements[i].length;
24271 +    }
24272 +
24273 +    /*
24274 +     * We must always return a non-NULL token otherwise the calling state
24275 +     * machine assumes we are finished. Hence care in case malloc(0) does
24276 +     * return NULL.
24277 +     */
24278 +    buffer->value = GSSEAP_MALLOC(required ? required : 1);
24279 +    if (buffer->value == NULL) {
24280 +        major = GSS_S_FAILURE;
24281 +        *minor = ENOMEM;
24282 +        goto cleanup;
24283 +    }
24284 +
24285 +    buffer->length = required;
24286 +    p = (unsigned char *)buffer->value;
24287 +
24288 +    for (i = 0; i < tokens->buffers.count; i++) {
24289 +        gss_buffer_t tokenBuffer = &tokens->buffers.elements[i];
24290 +
24291 +        GSSEAP_ASSERT((tokens->types[i] & ITOK_FLAG_VERIFIED) == 0); /* private flag */
24292 +
24293 +         /*
24294 +          * Extensions are encoded as type-length-value, where the upper
24295 +          * bit of the type indicates criticality.
24296 +          */
24297 +        store_uint32_be(tokens->types[i], &p[0]);
24298 +        store_uint32_be(tokenBuffer->length, &p[4]);
24299 +        memcpy(&p[8], tokenBuffer->value, tokenBuffer->length);
24300 +
24301 +        p += 8 + tokenBuffer->length;
24302 +    }
24303 +
24304 +    GSSEAP_ASSERT(p == (unsigned char *)buffer->value + required);
24305 +    GSSEAP_ASSERT(buffer->value != NULL);
24306 +
24307 +    major = GSS_S_COMPLETE;
24308 +    *minor = 0;
24309 +
24310 +cleanup:
24311 +    if (GSS_ERROR(major)) {
24312 +        gss_release_buffer(&tmpMinor, buffer);
24313 +    }
24314 +
24315 +    return major;
24316 +}
24317 +
24318 +OM_uint32
24319 +gssEapDecodeInnerTokens(OM_uint32 *minor,
24320 +                        const gss_buffer_t buffer,
24321 +                        struct gss_eap_token_buffer_set *tokens)
24322 +{
24323 +    OM_uint32 major, tmpMinor;
24324 +    unsigned char *p;
24325 +    size_t count = 0;
24326 +    size_t remain;
24327 +
24328 +    tokens->buffers.count = 0;
24329 +    tokens->buffers.elements = NULL;
24330 +    tokens->types = NULL;
24331 +
24332 +    if (buffer->length == 0) {
24333 +        major = GSS_S_COMPLETE;
24334 +        goto cleanup;
24335 +    }
24336 +
24337 +    p = (unsigned char *)buffer->value;
24338 +    remain = buffer->length;
24339 +
24340 +    do {
24341 +        OM_uint32 *ntypes;
24342 +        gss_buffer_desc tokenBuffer, *newTokenBuffers;
24343 +
24344 +        if (remain < 8) {
24345 +            major = GSS_S_DEFECTIVE_TOKEN;
24346 +            *minor = GSSEAP_TOK_TRUNC;
24347 +            goto cleanup;
24348 +        }
24349 +
24350 +        if (tokens->buffers.count <= count) {
24351 +            if (count == 0)
24352 +                count = 1;
24353 +            else
24354 +                count *= 2;
24355 +
24356 +            ntypes = GSSEAP_MALLOC(count * sizeof(OM_uint32));
24357 +            if (ntypes == NULL) {
24358 +                major = GSS_S_FAILURE;
24359 +                *minor = ENOMEM;
24360 +                goto cleanup;
24361 +            }
24362 +            if (tokens->types != NULL) {
24363 +                memcpy(ntypes, tokens->types, tokens->buffers.count * sizeof(OM_uint32));
24364 +                GSSEAP_FREE(tokens->types);
24365 +            }
24366 +            tokens->types = ntypes;
24367 +
24368 +            newTokenBuffers = GSSEAP_MALLOC(count * sizeof(gss_buffer_desc));
24369 +            if (newTokenBuffers == NULL) {
24370 +                major = GSS_S_FAILURE;
24371 +                *minor = ENOMEM;
24372 +                goto cleanup;
24373 +            }
24374 +            if (tokens->buffers.elements != NULL) {
24375 +                memcpy(newTokenBuffers, tokens->buffers.elements,
24376 +                       tokens->buffers.count * sizeof(gss_buffer_desc));
24377 +                GSSEAP_FREE(tokens->buffers.elements);
24378 +            }
24379 +            tokens->buffers.elements = newTokenBuffers;
24380 +        }
24381 +
24382 +        tokens->types[tokens->buffers.count] = load_uint32_be(&p[0]);
24383 +        tokenBuffer.length = load_uint32_be(&p[4]);
24384 +
24385 +        if (remain < 8 + tokenBuffer.length) {
24386 +            major = GSS_S_DEFECTIVE_TOKEN;
24387 +            *minor = GSSEAP_TOK_TRUNC;
24388 +            goto cleanup;
24389 +        }
24390 +        tokenBuffer.value = &p[8];
24391 +
24392 +        tokens->buffers.elements[tokens->buffers.count] = tokenBuffer;
24393 +        tokens->buffers.count++;
24394 +
24395 +        p      += 8 + tokenBuffer.length;
24396 +        remain -= 8 + tokenBuffer.length;
24397 +    } while (remain != 0);
24398 +
24399 +    major = GSS_S_COMPLETE;
24400 +    *minor = 0;
24401 +
24402 +cleanup:
24403 +    if (GSS_ERROR(major))
24404 +        gssEapReleaseInnerTokens(&tmpMinor, tokens, 0);
24405 +
24406 +    return major;
24407 +}
24408 +
24409 +/*
24410 + * $Id: util_token.c 23457 2009-12-08 00:04:48Z tlyu $
24411 + */
24412 +
24413 +/* XXXX this code currently makes the assumption that a mech oid will
24414 +   never be longer than 127 bytes.  This assumption is not inherent in
24415 +   the interfaces, so the code can be fixed if the OSI namespace
24416 +   balloons unexpectedly. */
24417 +
24418 +/*
24419 + * Each token looks like this:
24420 + * 0x60                 tag for APPLICATION 0, SEQUENCE
24421 + *                              (constructed, definite-length)
24422 + * <length>             possible multiple bytes, need to parse/generate
24423 + * 0x06                 tag for OBJECT IDENTIFIER
24424 + * <moid_length>        compile-time constant string (assume 1 byte)
24425 + * <moid_bytes>         compile-time constant string
24426 + * <inner_bytes>        the ANY containing the application token
24427 + * bytes 0,1 are the token type
24428 + * bytes 2,n are the token data
24429 + *
24430 + * Note that the token type field is a feature of RFC 1964 mechanisms and
24431 + * is not used by other GSSAPI mechanisms.  As such, a token type of -1
24432 + * is interpreted to mean that no token type should be expected or
24433 + * generated.
24434 + *
24435 + * For the purposes of this abstraction, the token "header" consists of
24436 + * the sequence tag and length octets, the mech OID DER encoding, and the
24437 + * first two inner bytes, which indicate the token type.  The token
24438 + * "body" consists of everything else.
24439 + */
24440 +
24441 +static size_t
24442 +der_length_size(size_t length)
24443 +{
24444 +    if (length < (1<<7))
24445 +        return 1;
24446 +    else if (length < (1<<8))
24447 +        return 2;
24448 +#if INT_MAX == 0x7fff
24449 +    else
24450 +        return 3;
24451 +#else
24452 +    else if (length < (1<<16))
24453 +        return 3;
24454 +    else if (length < (1<<24))
24455 +        return 4;
24456 +    else
24457 +        return 5;
24458 +#endif
24459 +}
24460 +
24461 +static void
24462 +der_write_length(unsigned char **buf, size_t length)
24463 +{
24464 +    if (length < (1<<7)) {
24465 +        *(*buf)++ = (unsigned char)length;
24466 +    } else {
24467 +        *(*buf)++ = (unsigned char)(der_length_size(length)+127);
24468 +#if INT_MAX > 0x7fff
24469 +        if (length >= (1<<24))
24470 +            *(*buf)++ = (unsigned char)(length>>24);
24471 +        if (length >= (1<<16))
24472 +            *(*buf)++ = (unsigned char)((length>>16)&0xff);
24473 +#endif
24474 +        if (length >= (1<<8))
24475 +            *(*buf)++ = (unsigned char)((length>>8)&0xff);
24476 +        *(*buf)++ = (unsigned char)(length&0xff);
24477 +    }
24478 +}
24479 +
24480 +/* returns decoded length, or < 0 on failure.  Advances buf and
24481 +   decrements bufsize */
24482 +
24483 +static int
24484 +der_read_length(unsigned char **buf, ssize_t *bufsize)
24485 +{
24486 +    unsigned char sf;
24487 +    int ret;
24488 +
24489 +    if (*bufsize < 1)
24490 +        return -1;
24491 +
24492 +    sf = *(*buf)++;
24493 +    (*bufsize)--;
24494 +    if (sf & 0x80) {
24495 +        if ((sf &= 0x7f) > ((*bufsize)-1))
24496 +            return -1;
24497 +        if (sf > sizeof(int))
24498 +            return -1;
24499 +        ret = 0;
24500 +        for (; sf; sf--) {
24501 +            ret = (ret<<8) + (*(*buf)++);
24502 +            (*bufsize)--;
24503 +        }
24504 +    } else {
24505 +        ret = sf;
24506 +    }
24507 +
24508 +    return ret;
24509 +}
24510 +
24511 +/* returns the length of a token, given the mech oid and the body size */
24512 +
24513 +size_t
24514 +tokenSize(const gss_OID_desc *mech, size_t body_size)
24515 +{
24516 +    GSSEAP_ASSERT(mech != GSS_C_NO_OID);
24517 +
24518 +    /* set body_size to sequence contents size */
24519 +    body_size += 4 + (size_t) mech->length;         /* NEED overflow check */
24520 +    return 1 + der_length_size(body_size) + body_size;
24521 +}
24522 +
24523 +/* fills in a buffer with the token header.  The buffer is assumed to
24524 +   be the right size.  buf is advanced past the token header */
24525 +
24526 +void
24527 +makeTokenHeader(
24528 +    const gss_OID_desc *mech,
24529 +    size_t body_size,
24530 +    unsigned char **buf,
24531 +    enum gss_eap_token_type tok_type)
24532 +{
24533 +    *(*buf)++ = 0x60;
24534 +    der_write_length(buf, (tok_type == -1) ?2:4 + mech->length + body_size);
24535 +    *(*buf)++ = 0x06;
24536 +    *(*buf)++ = (unsigned char)mech->length;
24537 +    memcpy(*buf, mech->elements, mech->length);
24538 +    *buf += mech->length;
24539 +    GSSEAP_ASSERT(tok_type != TOK_TYPE_NONE);
24540 +    *(*buf)++ = (unsigned char)((tok_type>>8) & 0xff);
24541 +    *(*buf)++ = (unsigned char)(tok_type & 0xff);
24542 +}
24543 +
24544 +/*
24545 + * Given a buffer containing a token, reads and verifies the token,
24546 + * leaving buf advanced past the token header, and setting body_size
24547 + * to the number of remaining bytes.  Returns 0 on success,
24548 + * G_BAD_TOK_HEADER for a variety of errors, and G_WRONG_MECH if the
24549 + * mechanism in the token does not match the mech argument.  buf and
24550 + * *body_size are left unmodified on error.
24551 + */
24552 +
24553 +OM_uint32
24554 +verifyTokenHeader(OM_uint32 *minor,
24555 +                  gss_OID mech,
24556 +                  size_t *body_size,
24557 +                  unsigned char **buf_in,
24558 +                  size_t toksize_in,
24559 +                  enum gss_eap_token_type *ret_tok_type)
24560 +{
24561 +    unsigned char *buf = *buf_in;
24562 +    ssize_t seqsize;
24563 +    gss_OID_desc toid;
24564 +    ssize_t toksize = (ssize_t)toksize_in;
24565 +
24566 +    *minor = GSSEAP_BAD_TOK_HEADER;
24567 +
24568 +    if (ret_tok_type != NULL)
24569 +        *ret_tok_type = TOK_TYPE_NONE;
24570 +
24571 +    if ((toksize -= 1) < 0)
24572 +        return GSS_S_DEFECTIVE_TOKEN;
24573 +
24574 +    if (*buf++ != 0x60)
24575 +        return GSS_S_DEFECTIVE_TOKEN;
24576 +
24577 +    seqsize = der_read_length(&buf, &toksize);
24578 +    if (seqsize < 0)
24579 +        return GSS_S_DEFECTIVE_TOKEN;
24580 +
24581 +    if (seqsize != toksize)
24582 +        return GSS_S_DEFECTIVE_TOKEN;
24583 +
24584 +    if ((toksize -= 1) < 0)
24585 +        return GSS_S_DEFECTIVE_TOKEN;
24586 +
24587 +    if (*buf++ != 0x06)
24588 +        return GSS_S_DEFECTIVE_TOKEN;
24589 +
24590 +    if ((toksize -= 1) < 0)
24591 +        return GSS_S_DEFECTIVE_TOKEN;
24592 +
24593 +    toid.length = *buf++;
24594 +
24595 +    if ((toksize -= toid.length) < 0)
24596 +        return GSS_S_DEFECTIVE_TOKEN;
24597 +
24598 +    toid.elements = buf;
24599 +    buf += toid.length;
24600 +
24601 +    if (mech->elements == NULL) {
24602 +        *mech = toid;
24603 +        if (toid.length == 0)
24604 +            return GSS_S_BAD_MECH;
24605 +    } else if (!oidEqual(&toid, mech)) {
24606 +        *minor = GSSEAP_WRONG_MECH;
24607 +        return GSS_S_BAD_MECH;
24608 +    }
24609 +
24610 +    if (ret_tok_type != NULL) {
24611 +        if ((toksize -= 2) < 0)
24612 +            return GSS_S_DEFECTIVE_TOKEN;
24613 +
24614 +        *ret_tok_type = load_uint16_be(buf);
24615 +        buf += 2;
24616 +    }
24617 +
24618 +    *buf_in = buf;
24619 +    *body_size = toksize;
24620 +
24621 +    *minor = 0;
24622 +    return GSS_S_COMPLETE;
24623 +}
24624 +
24625 +OM_uint32
24626 +gssEapAllocInnerTokens(OM_uint32 *minor,
24627 +                       size_t count,
24628 +                       struct gss_eap_token_buffer_set *tokens)
24629 +{
24630 +    OM_uint32 major;
24631 +
24632 +    tokens->buffers.count = 0;
24633 +    tokens->buffers.elements = (gss_buffer_desc *)GSSEAP_CALLOC(count, sizeof(gss_buffer_desc));
24634 +    if (tokens->buffers.elements == NULL) {
24635 +        major = GSS_S_FAILURE;
24636 +        *minor = ENOMEM;
24637 +        goto cleanup;
24638 +    }
24639 +
24640 +    tokens->types = (OM_uint32 *)GSSEAP_CALLOC(count, sizeof(OM_uint32));
24641 +    if (tokens->types == NULL) {
24642 +        major = GSS_S_FAILURE;
24643 +        *minor = ENOMEM;
24644 +        goto cleanup;
24645 +    }
24646 +
24647 +    major = GSS_S_COMPLETE;
24648 +    *minor = 0;
24649 +
24650 +cleanup:
24651 +    if (GSS_ERROR(major)) {
24652 +        if (tokens->buffers.elements != NULL) {
24653 +            GSSEAP_FREE(tokens->buffers.elements);
24654 +            tokens->buffers.elements = NULL;
24655 +        }
24656 +        if (tokens->types != NULL) {
24657 +            GSSEAP_FREE(tokens->types);
24658 +            tokens->types = NULL;
24659 +        }
24660 +    }
24661 +
24662 +    return major;
24663 +}
24664 +
24665 +OM_uint32
24666 +gssEapReleaseInnerTokens(OM_uint32 *minor,
24667 +                         struct gss_eap_token_buffer_set *tokens,
24668 +                         int freeBuffers)
24669 +{
24670 +    OM_uint32 tmpMinor;
24671 +    size_t i;
24672 +
24673 +    if (tokens->buffers.elements != NULL) {
24674 +        if (freeBuffers) {
24675 +            for (i = 0; i < tokens->buffers.count; i++)
24676 +                gss_release_buffer(&tmpMinor, &tokens->buffers.elements[i]);
24677 +        }
24678 +        GSSEAP_FREE(tokens->buffers.elements);
24679 +        tokens->buffers.elements = NULL;
24680 +    }
24681 +    tokens->buffers.count = 0;
24682 +
24683 +    if (tokens->types != NULL) {
24684 +        GSSEAP_FREE(tokens->types);
24685 +        tokens->types = NULL;
24686 +    }
24687 +
24688 +    *minor = 0;
24689 +    return GSS_S_COMPLETE;
24690 +}
24691 diff --git a/mech_eap/verify_mic.c b/mech_eap/verify_mic.c
24692 new file mode 100644
24693 index 0000000..c0829f5
24694 --- /dev/null
24695 +++ b/mech_eap/verify_mic.c
24696 @@ -0,0 +1,71 @@
24697 +/*
24698 + * Copyright (c) 2011, JANET(UK)
24699 + * All rights reserved.
24700 + *
24701 + * Redistribution and use in source and binary forms, with or without
24702 + * modification, are permitted provided that the following conditions
24703 + * are met:
24704 + *
24705 + * 1. Redistributions of source code must retain the above copyright
24706 + *    notice, this list of conditions and the following disclaimer.
24707 + *
24708 + * 2. Redistributions in binary form must reproduce the above copyright
24709 + *    notice, this list of conditions and the following disclaimer in the
24710 + *    documentation and/or other materials provided with the distribution.
24711 + *
24712 + * 3. Neither the name of JANET(UK) nor the names of its contributors
24713 + *    may be used to endorse or promote products derived from this software
24714 + *    without specific prior written permission.
24715 + *
24716 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24717 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24718 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24719 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24720 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24721 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24722 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24723 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24724 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24725 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24726 + * SUCH DAMAGE.
24727 + */
24728 +
24729 +/*
24730 + * Message protection services: verify a message integrity check.
24731 + */
24732 +
24733 +#include "gssapiP_eap.h"
24734 +
24735 +OM_uint32 GSSAPI_CALLCONV
24736 +gss_verify_mic(OM_uint32 *minor,
24737 +               gss_ctx_id_t ctx,
24738 +               gss_buffer_t message_buffer,
24739 +               gss_buffer_t message_token,
24740 +               gss_qop_t *qop_state)
24741 +{
24742 +    OM_uint32 major;
24743 +    gss_iov_buffer_desc iov[3];
24744 +    int conf_state;
24745 +
24746 +    if (message_token->length < 16) {
24747 +        *minor = GSSEAP_TOK_TRUNC;
24748 +        return GSS_S_BAD_SIG;
24749 +    }
24750 +
24751 +    *minor = 0;
24752 +
24753 +    iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
24754 +    iov[0].buffer = *message_buffer;
24755 +
24756 +    iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER;
24757 +    iov[1].buffer = *message_token;
24758 +
24759 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
24760 +
24761 +    major = gssEapUnwrapOrVerifyMIC(minor, ctx, &conf_state, qop_state,
24762 +                                    iov, 2, TOK_TYPE_MIC);
24763 +
24764 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
24765 +
24766 +    return major;
24767 +}
24768 diff --git a/mech_eap/wrap.c b/mech_eap/wrap.c
24769 new file mode 100644
24770 index 0000000..2e27fb3
24771 --- /dev/null
24772 +++ b/mech_eap/wrap.c
24773 @@ -0,0 +1,137 @@
24774 +/*
24775 + * Copyright (c) 2011, JANET(UK)
24776 + * All rights reserved.
24777 + *
24778 + * Redistribution and use in source and binary forms, with or without
24779 + * modification, are permitted provided that the following conditions
24780 + * are met:
24781 + *
24782 + * 1. Redistributions of source code must retain the above copyright
24783 + *    notice, this list of conditions and the following disclaimer.
24784 + *
24785 + * 2. Redistributions in binary form must reproduce the above copyright
24786 + *    notice, this list of conditions and the following disclaimer in the
24787 + *    documentation and/or other materials provided with the distribution.
24788 + *
24789 + * 3. Neither the name of JANET(UK) nor the names of its contributors
24790 + *    may be used to endorse or promote products derived from this software
24791 + *    without specific prior written permission.
24792 + *
24793 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24794 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24795 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24796 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24797 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24798 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24799 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24800 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24801 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24802 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24803 + * SUCH DAMAGE.
24804 + */
24805 +
24806 +/*
24807 + * Message protection services: wrap.
24808 + */
24809 +
24810 +#include "gssapiP_eap.h"
24811 +
24812 +OM_uint32 GSSAPI_CALLCONV
24813 +gss_wrap(OM_uint32 *minor,
24814 +         gss_ctx_id_t ctx,
24815 +         int conf_req_flag,
24816 +         gss_qop_t qop_req,
24817 +         gss_buffer_t input_message_buffer,
24818 +         int *conf_state,
24819 +         gss_buffer_t output_message_buffer)
24820 +{
24821 +    OM_uint32 major;
24822 +
24823 +    if (ctx == GSS_C_NO_CONTEXT) {
24824 +        *minor = EINVAL;
24825 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
24826 +    }
24827 +
24828 +    *minor = 0;
24829 +
24830 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
24831 +
24832 +    if (!CTX_IS_ESTABLISHED(ctx)) {
24833 +        major = GSS_S_NO_CONTEXT;
24834 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
24835 +        goto cleanup;
24836 +    }
24837 +
24838 +    major = gssEapWrap(minor, ctx, conf_req_flag, qop_req,
24839 +                       input_message_buffer,
24840 +                       conf_state, output_message_buffer);
24841 +    if (GSS_ERROR(major))
24842 +        goto cleanup;
24843 +
24844 +cleanup:
24845 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
24846 +
24847 +    return major;
24848 +}
24849 +
24850 +OM_uint32
24851 +gssEapWrap(OM_uint32 *minor,
24852 +           gss_ctx_id_t ctx,
24853 +           int conf_req_flag,
24854 +           gss_qop_t qop_req,
24855 +           gss_buffer_t input_message_buffer,
24856 +           int *conf_state,
24857 +           gss_buffer_t output_message_buffer)
24858 +{
24859 +    OM_uint32 major, tmpMinor;
24860 +    gss_iov_buffer_desc iov[4];
24861 +    unsigned char *p;
24862 +    int i;
24863 +
24864 +    iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
24865 +    iov[0].buffer.value = NULL;
24866 +    iov[0].buffer.length = 0;
24867 +
24868 +    iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
24869 +    iov[1].buffer = *input_message_buffer;
24870 +
24871 +    iov[2].type = GSS_IOV_BUFFER_TYPE_PADDING;
24872 +    iov[2].buffer.value = NULL;
24873 +    iov[2].buffer.length = 0;
24874 +
24875 +    iov[3].type = GSS_IOV_BUFFER_TYPE_TRAILER;
24876 +    iov[3].buffer.value = NULL;
24877 +    iov[3].buffer.length = 0;
24878 +
24879 +    major = gssEapWrapIovLength(minor, ctx, conf_req_flag, qop_req,
24880 +                                NULL, iov, 4);
24881 +    if (GSS_ERROR(major)) {
24882 +        return major;
24883 +    }
24884 +
24885 +    for (i = 0, output_message_buffer->length = 0; i < 4; i++) {
24886 +        output_message_buffer->length += iov[i].buffer.length;
24887 +    }
24888 +
24889 +    output_message_buffer->value = GSSEAP_MALLOC(output_message_buffer->length);
24890 +    if (output_message_buffer->value == NULL) {
24891 +        *minor = ENOMEM;
24892 +        return GSS_S_FAILURE;
24893 +    }
24894 +
24895 +    for (i = 0, p = output_message_buffer->value; i < 4; i++) {
24896 +        if (iov[i].type == GSS_IOV_BUFFER_TYPE_DATA) {
24897 +            memcpy(p, input_message_buffer->value, input_message_buffer->length);
24898 +        }
24899 +        iov[i].buffer.value = p;
24900 +        p += iov[i].buffer.length;
24901 +    }
24902 +
24903 +    major = gssEapWrapOrGetMIC(minor, ctx, conf_req_flag, conf_state,
24904 +                               iov, 4, TOK_TYPE_WRAP);
24905 +    if (GSS_ERROR(major)) {
24906 +        gss_release_buffer(&tmpMinor, output_message_buffer);
24907 +    }
24908 +
24909 +    return major;
24910 +}
24911 diff --git a/mech_eap/wrap_iov.c b/mech_eap/wrap_iov.c
24912 new file mode 100644
24913 index 0000000..be890b6
24914 --- /dev/null
24915 +++ b/mech_eap/wrap_iov.c
24916 @@ -0,0 +1,379 @@
24917 +/*
24918 + * Copyright (c) 2011, JANET(UK)
24919 + * All rights reserved.
24920 + *
24921 + * Redistribution and use in source and binary forms, with or without
24922 + * modification, are permitted provided that the following conditions
24923 + * are met:
24924 + *
24925 + * 1. Redistributions of source code must retain the above copyright
24926 + *    notice, this list of conditions and the following disclaimer.
24927 + *
24928 + * 2. Redistributions in binary form must reproduce the above copyright
24929 + *    notice, this list of conditions and the following disclaimer in the
24930 + *    documentation and/or other materials provided with the distribution.
24931 + *
24932 + * 3. Neither the name of JANET(UK) nor the names of its contributors
24933 + *    may be used to endorse or promote products derived from this software
24934 + *    without specific prior written permission.
24935 + *
24936 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24937 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24938 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24939 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24940 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24941 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24942 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24943 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24944 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24945 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24946 + * SUCH DAMAGE.
24947 + */
24948 +/*
24949 + * Copyright 2008 by the Massachusetts Institute of Technology.
24950 + * All Rights Reserved.
24951 + *
24952 + * Export of this software from the United States of America may
24953 + *   require a specific license from the United States Government.
24954 + *   It is the responsibility of any person or organization contemplating
24955 + *   export to obtain such a license before exporting.
24956 + *
24957 + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
24958 + * distribute this software and its documentation for any purpose and
24959 + * without fee is hereby granted, provided that the above copyright
24960 + * notice appear in all copies and that both that copyright notice and
24961 + * this permission notice appear in supporting documentation, and that
24962 + * the name of M.I.T. not be used in advertising or publicity pertaining
24963 + * to distribution of the software without specific, written prior
24964 + * permission.  Furthermore if you modify this software you must label
24965 + * your software as modified software and not distribute it in such a
24966 + * fashion that it might be confused with the original M.I.T. software.
24967 + * M.I.T. makes no representations about the suitability of
24968 + * this software for any purpose.  It is provided "as is" without express
24969 + * or implied warranty.
24970 + */
24971 +
24972 +/*
24973 + * Message protection services: wrap with scatter-gather API.
24974 + */
24975 +
24976 +#include "gssapiP_eap.h"
24977 +
24978 +unsigned char
24979 +rfc4121Flags(gss_ctx_id_t ctx, int receiving)
24980 +{
24981 +    unsigned char flags;
24982 +    int isAcceptor;
24983 +
24984 +    isAcceptor = !CTX_IS_INITIATOR(ctx);
24985 +    if (receiving)
24986 +        isAcceptor = !isAcceptor;
24987 +
24988 +    flags = 0;
24989 +    if (isAcceptor)
24990 +        flags |= TOK_FLAG_SENDER_IS_ACCEPTOR;
24991 +
24992 +    if ((ctx->flags & CTX_FLAG_KRB_REAUTH) &&
24993 +        (ctx->gssFlags & GSS_C_MUTUAL_FLAG))
24994 +        flags |= TOK_FLAG_ACCEPTOR_SUBKEY;
24995 +
24996 +    return flags;
24997 +}
24998 +
24999 +OM_uint32
25000 +gssEapWrapOrGetMIC(OM_uint32 *minor,
25001 +                   gss_ctx_id_t ctx,
25002 +                   int conf_req_flag,
25003 +                   int *conf_state,
25004 +                   gss_iov_buffer_desc *iov,
25005 +                   int iov_count,
25006 +                   enum gss_eap_token_type toktype)
25007 +{
25008 +    krb5_error_code code = 0;
25009 +    gss_iov_buffer_t header;
25010 +    gss_iov_buffer_t padding;
25011 +    gss_iov_buffer_t trailer;
25012 +    unsigned char flags;
25013 +    unsigned char *outbuf = NULL;
25014 +    unsigned char *tbuf = NULL;
25015 +    int keyUsage;
25016 +    size_t rrc = 0;
25017 +    size_t gssHeaderLen, gssTrailerLen;
25018 +    size_t dataLen, assocDataLen;
25019 +    krb5_context krbContext;
25020 +#ifdef HAVE_HEIMDAL_VERSION
25021 +    krb5_crypto krbCrypto = NULL;
25022 +#endif
25023 +
25024 +    if (ctx->encryptionType == ENCTYPE_NULL) {
25025 +        *minor = GSSEAP_KEY_UNAVAILABLE;
25026 +        return GSS_S_UNAVAILABLE;
25027 +    }
25028 +
25029 +    GSSEAP_KRB_INIT(&krbContext);
25030 +
25031 +    flags = rfc4121Flags(ctx, FALSE);
25032 +
25033 +    if (toktype == TOK_TYPE_WRAP) {
25034 +        keyUsage = CTX_IS_INITIATOR(ctx)
25035 +                   ? KEY_USAGE_INITIATOR_SEAL
25036 +                   : KEY_USAGE_ACCEPTOR_SEAL;
25037 +    } else {
25038 +        keyUsage = CTX_IS_INITIATOR(ctx)
25039 +                   ? KEY_USAGE_INITIATOR_SIGN
25040 +                   : KEY_USAGE_ACCEPTOR_SIGN;
25041 +    }
25042 +
25043 +    gssEapIovMessageLength(iov, iov_count, &dataLen, &assocDataLen);
25044 +
25045 +    header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
25046 +    if (header == NULL) {
25047 +        *minor = GSSEAP_MISSING_IOV;
25048 +        return GSS_S_FAILURE;
25049 +    }
25050 +
25051 +    padding = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
25052 +    if (padding != NULL)
25053 +        padding->buffer.length = 0;
25054 +
25055 +    trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
25056 +
25057 +#ifdef HAVE_HEIMDAL_VERSION
25058 +    code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, ETYPE_NULL, &krbCrypto);
25059 +    if (code != 0)
25060 +        goto cleanup;
25061 +#endif
25062 +
25063 +    if (toktype == TOK_TYPE_WRAP && conf_req_flag) {
25064 +        size_t krbHeaderLen, krbTrailerLen, krbPadLen;
25065 +        size_t ec = 0, confDataLen = dataLen - assocDataLen;
25066 +
25067 +        code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
25068 +                               KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen);
25069 +        if (code != 0)
25070 +            goto cleanup;
25071 +
25072 +        code = krbPaddingLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
25073 +                                confDataLen + 16 /* E(Header) */,
25074 +                                &krbPadLen);
25075 +        if (code != 0)
25076 +            goto cleanup;
25077 +
25078 +        if (krbPadLen == 0 && (ctx->gssFlags & GSS_C_DCE_STYLE)) {
25079 +            /* Windows rejects AEAD tokens with non-zero EC */
25080 +            code = krbBlockSize(krbContext, KRB_CRYPTO_CONTEXT(ctx), &ec);
25081 +            if (code != 0)
25082 +                goto cleanup;
25083 +        } else
25084 +            ec = krbPadLen;
25085 +
25086 +        code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
25087 +                               KRB5_CRYPTO_TYPE_TRAILER, &krbTrailerLen);
25088 +        if (code != 0)
25089 +            goto cleanup;
25090 +
25091 +        gssHeaderLen = 16 /* Header */ + krbHeaderLen;
25092 +        gssTrailerLen = ec + 16 /* E(Header) */ + krbTrailerLen;
25093 +
25094 +        if (trailer == NULL) {
25095 +            rrc = gssTrailerLen;
25096 +            /* Workaround for Windows bug where it rotates by EC + RRC */
25097 +            if (ctx->gssFlags & GSS_C_DCE_STYLE)
25098 +                rrc -= ec;
25099 +            gssHeaderLen += gssTrailerLen;
25100 +        }
25101 +
25102 +        if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
25103 +            code = gssEapAllocIov(header, (size_t)gssHeaderLen);
25104 +        } else if (header->buffer.length < gssHeaderLen)
25105 +            code = GSSEAP_WRONG_SIZE;
25106 +        if (code != 0)
25107 +            goto cleanup;
25108 +        outbuf = (unsigned char *)header->buffer.value;
25109 +        header->buffer.length = (size_t)gssHeaderLen;
25110 +
25111 +        if (trailer != NULL) {
25112 +            if (trailer->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
25113 +                code = gssEapAllocIov(trailer, (size_t)gssTrailerLen);
25114 +            else if (trailer->buffer.length < gssTrailerLen)
25115 +                code = GSSEAP_WRONG_SIZE;
25116 +            if (code != 0)
25117 +                goto cleanup;
25118 +            trailer->buffer.length = (size_t)gssTrailerLen;
25119 +        }
25120 +
25121 +        /* TOK_ID */
25122 +        store_uint16_be((uint16_t)toktype, outbuf);
25123 +        /* flags */
25124 +        outbuf[2] = flags
25125 +                     | (conf_req_flag ? TOK_FLAG_WRAP_CONFIDENTIAL : 0);
25126 +        /* filler */
25127 +        outbuf[3] = 0xFF;
25128 +        /* EC */
25129 +        store_uint16_be(ec, outbuf + 4);
25130 +        /* RRC */
25131 +        store_uint16_be(0, outbuf + 6);
25132 +        store_uint64_be(ctx->sendSeq, outbuf + 8);
25133 +
25134 +        /*
25135 +         * EC | copy of header to be encrypted, located in
25136 +         * (possibly rotated) trailer
25137 +         */
25138 +        if (trailer == NULL)
25139 +            tbuf = (unsigned char *)header->buffer.value + 16; /* Header */
25140 +        else
25141 +            tbuf = (unsigned char *)trailer->buffer.value;
25142 +
25143 +        memset(tbuf, 0xFF, ec);
25144 +        memcpy(tbuf + ec, header->buffer.value, 16);
25145 +
25146 +        code = gssEapEncrypt(krbContext,
25147 +                             ((ctx->gssFlags & GSS_C_DCE_STYLE) != 0),
25148 +                             ec, rrc, KRB_CRYPTO_CONTEXT(ctx),
25149 +                             keyUsage, iov, iov_count);
25150 +        if (code != 0)
25151 +            goto cleanup;
25152 +
25153 +        /* RRC */
25154 +        store_uint16_be(rrc, outbuf + 6);
25155 +
25156 +        ctx->sendSeq++;
25157 +    } else if (toktype == TOK_TYPE_WRAP && !conf_req_flag) {
25158 +    wrap_with_checksum:
25159 +
25160 +        gssHeaderLen = 16;
25161 +
25162 +        code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
25163 +                               KRB5_CRYPTO_TYPE_CHECKSUM, &gssTrailerLen);
25164 +        if (code != 0)
25165 +            goto cleanup;
25166 +
25167 +        GSSEAP_ASSERT(gssTrailerLen <= 0xFFFF);
25168 +
25169 +        if (trailer == NULL) {
25170 +            rrc = gssTrailerLen;
25171 +            gssHeaderLen += gssTrailerLen;
25172 +        }
25173 +
25174 +        if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
25175 +            code = gssEapAllocIov(header, (size_t)gssHeaderLen);
25176 +        else if (header->buffer.length < gssHeaderLen)
25177 +            code = GSSEAP_WRONG_SIZE;
25178 +        if (code != 0)
25179 +            goto cleanup;
25180 +        outbuf = (unsigned char *)header->buffer.value;
25181 +        header->buffer.length = (size_t)gssHeaderLen;
25182 +
25183 +        if (trailer != NULL) {
25184 +            if (trailer->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
25185 +                code = gssEapAllocIov(trailer, (size_t)gssTrailerLen);
25186 +            else if (trailer->buffer.length < gssTrailerLen)
25187 +                code = GSSEAP_WRONG_SIZE;
25188 +            if (code != 0)
25189 +                goto cleanup;
25190 +            trailer->buffer.length = (size_t)gssTrailerLen;
25191 +        }
25192 +
25193 +        /* TOK_ID */
25194 +        store_uint16_be((uint16_t)toktype, outbuf);
25195 +        /* flags */
25196 +        outbuf[2] = flags;
25197 +        /* filler */
25198 +        outbuf[3] = 0xFF;
25199 +        if (toktype == TOK_TYPE_WRAP) {
25200 +            /* Use 0 for checksum calculation, substitute
25201 +             * checksum length later.
25202 +             */
25203 +            /* EC */
25204 +            store_uint16_be(0, outbuf + 4);
25205 +            /* RRC */
25206 +            store_uint16_be(0, outbuf + 6);
25207 +        } else {
25208 +            /* MIC and DEL store 0xFF in EC and RRC */
25209 +            store_uint16_be(0xFFFF, outbuf + 4);
25210 +            store_uint16_be(0xFFFF, outbuf + 6);
25211 +        }
25212 +        store_uint64_be(ctx->sendSeq, outbuf + 8);
25213 +
25214 +        code = gssEapSign(krbContext, ctx->checksumType, rrc,
25215 +                          KRB_CRYPTO_CONTEXT(ctx), keyUsage,
25216 +                          iov, iov_count);
25217 +        if (code != 0)
25218 +            goto cleanup;
25219 +
25220 +        ctx->sendSeq++;
25221 +
25222 +        if (toktype == TOK_TYPE_WRAP) {
25223 +            /* Fix up EC field */
25224 +            store_uint16_be(gssTrailerLen, outbuf + 4);
25225 +            /* Fix up RRC field */
25226 +            store_uint16_be(rrc, outbuf + 6);
25227 +        }
25228 +    } else if (toktype == TOK_TYPE_MIC) {
25229 +        trailer = NULL;
25230 +        goto wrap_with_checksum;
25231 +    } else if (toktype == TOK_TYPE_DELETE_CONTEXT) {
25232 +        trailer = NULL;
25233 +        goto wrap_with_checksum;
25234 +    } else {
25235 +        abort();
25236 +    }
25237 +
25238 +    code = 0;
25239 +    if (conf_state != NULL)
25240 +        *conf_state = conf_req_flag;
25241 +
25242 +cleanup:
25243 +    if (code != 0)
25244 +        gssEapReleaseIov(iov, iov_count);
25245 +#ifdef HAVE_HEIMDAL_VERSION
25246 +    if (krbCrypto != NULL)
25247 +        krb5_crypto_destroy(krbContext, krbCrypto);
25248 +#endif
25249 +
25250 +    *minor = code;
25251 +
25252 +    return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
25253 +}
25254 +
25255 +OM_uint32 GSSAPI_CALLCONV
25256 +gss_wrap_iov(OM_uint32 *minor,
25257 +             gss_ctx_id_t ctx,
25258 +             int conf_req_flag,
25259 +             gss_qop_t qop_req,
25260 +             int *conf_state,
25261 +             gss_iov_buffer_desc *iov,
25262 +             int iov_count)
25263 +{
25264 +    OM_uint32 major;
25265 +
25266 +    if (ctx == GSS_C_NO_CONTEXT) {
25267 +        *minor = EINVAL;
25268 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
25269 +    }
25270 +
25271 +    if (qop_req != GSS_C_QOP_DEFAULT) {
25272 +        *minor = GSSEAP_UNKNOWN_QOP;
25273 +        return GSS_S_UNAVAILABLE;
25274 +    }
25275 +
25276 +    *minor = 0;
25277 +
25278 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
25279 +
25280 +    if (!CTX_IS_ESTABLISHED(ctx)) {
25281 +        major = GSS_S_NO_CONTEXT;
25282 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
25283 +        goto cleanup;
25284 +    }
25285 +
25286 +    major = gssEapWrapOrGetMIC(minor, ctx, conf_req_flag, conf_state,
25287 +                               iov, iov_count, TOK_TYPE_WRAP);
25288 +    if (GSS_ERROR(major))
25289 +        goto cleanup;
25290 +
25291 +cleanup:
25292 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
25293 +
25294 +    return major;
25295 +}
25296 diff --git a/mech_eap/wrap_iov_length.c b/mech_eap/wrap_iov_length.c
25297 new file mode 100644
25298 index 0000000..247b78d
25299 --- /dev/null
25300 +++ b/mech_eap/wrap_iov_length.c
25301 @@ -0,0 +1,234 @@
25302 +/*
25303 + * Copyright (c) 2011, JANET(UK)
25304 + * All rights reserved.
25305 + *
25306 + * Redistribution and use in source and binary forms, with or without
25307 + * modification, are permitted provided that the following conditions
25308 + * are met:
25309 + *
25310 + * 1. Redistributions of source code must retain the above copyright
25311 + *    notice, this list of conditions and the following disclaimer.
25312 + *
25313 + * 2. Redistributions in binary form must reproduce the above copyright
25314 + *    notice, this list of conditions and the following disclaimer in the
25315 + *    documentation and/or other materials provided with the distribution.
25316 + *
25317 + * 3. Neither the name of JANET(UK) nor the names of its contributors
25318 + *    may be used to endorse or promote products derived from this software
25319 + *    without specific prior written permission.
25320 + *
25321 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25322 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25323 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25324 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25325 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25326 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25327 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25328 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25329 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25330 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25331 + * SUCH DAMAGE.
25332 + */
25333 +/*
25334 + * Copyright 2008 by the Massachusetts Institute of Technology.
25335 + * All Rights Reserved.
25336 + *
25337 + * Export of this software from the United States of America may
25338 + *   require a specific license from the United States Government.
25339 + *   It is the responsibility of any person or organization contemplating
25340 + *   export to obtain such a license before exporting.
25341 + *
25342 + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
25343 + * distribute this software and its documentation for any purpose and
25344 + * without fee is hereby granted, provided that the above copyright
25345 + * notice appear in all copies and that both that copyright notice and
25346 + * this permission notice appear in supporting documentation, and that
25347 + * the name of M.I.T. not be used in advertising or publicity pertaining
25348 + * to distribution of the software without specific, written prior
25349 + * permission.  Furthermore if you modify this software you must label
25350 + * your software as modified software and not distribute it in such a
25351 + * fashion that it might be confused with the original M.I.T. software.
25352 + * M.I.T. makes no representations about the suitability of
25353 + * this software for any purpose.  It is provided "as is" without express
25354 + * or implied warranty.
25355 + */
25356 +
25357 +/*
25358 + * Message protection services: determine protected message size.
25359 + */
25360 +
25361 +#include "gssapiP_eap.h"
25362 +
25363 +#define INIT_IOV_DATA(_iov)     do { (_iov)->buffer.value = NULL;       \
25364 +        (_iov)->buffer.length = 0; }                                    \
25365 +    while (0)
25366 +
25367 +OM_uint32
25368 +gssEapWrapIovLength(OM_uint32 *minor,
25369 +                    gss_ctx_id_t ctx,
25370 +                    int conf_req_flag,
25371 +                    gss_qop_t qop_req,
25372 +                    int *conf_state,
25373 +                    gss_iov_buffer_desc *iov,
25374 +                    int iov_count)
25375 +{
25376 +    gss_iov_buffer_t header, trailer, padding;
25377 +    size_t dataLength, assocDataLength;
25378 +    size_t gssHeaderLen, gssPadLen, gssTrailerLen;
25379 +    size_t krbHeaderLen = 0, krbTrailerLen = 0, krbPadLen = 0;
25380 +    krb5_error_code code;
25381 +    krb5_context krbContext;
25382 +    int dce_style;
25383 +    size_t ec;
25384 +#ifdef HAVE_HEIMDAL_VERSION
25385 +    krb5_crypto krbCrypto = NULL;
25386 +#endif
25387 +
25388 +    if (qop_req != GSS_C_QOP_DEFAULT) {
25389 +        *minor = GSSEAP_UNKNOWN_QOP;
25390 +        return GSS_S_UNAVAILABLE;
25391 +    }
25392 +
25393 +    if (ctx->encryptionType == ENCTYPE_NULL) {
25394 +        *minor = GSSEAP_KEY_UNAVAILABLE;
25395 +        return GSS_S_UNAVAILABLE;
25396 +    }
25397 +
25398 +    GSSEAP_KRB_INIT(&krbContext);
25399 +
25400 +    header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
25401 +    if (header == NULL) {
25402 +        *minor = GSSEAP_MISSING_IOV;
25403 +        return GSS_S_FAILURE;
25404 +    }
25405 +    INIT_IOV_DATA(header);
25406 +
25407 +    trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
25408 +    if (trailer != NULL) {
25409 +        INIT_IOV_DATA(trailer);
25410 +    }
25411 +
25412 +    dce_style = ((ctx->gssFlags & GSS_C_DCE_STYLE) != 0);
25413 +
25414 +    /* For CFX, EC is used instead of padding, and is placed in header or trailer */
25415 +    padding = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
25416 +    if (padding != NULL) {
25417 +        INIT_IOV_DATA(padding);
25418 +    }
25419 +
25420 +    gssEapIovMessageLength(iov, iov_count, &dataLength, &assocDataLength);
25421 +
25422 +    if (conf_req_flag && gssEapIsIntegrityOnly(iov, iov_count))
25423 +        conf_req_flag = FALSE;
25424 +
25425 +    gssHeaderLen = gssPadLen = gssTrailerLen = 0;
25426 +
25427 +#ifdef HAVE_HEIMDAL_VERSION
25428 +    code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, ETYPE_NULL, &krbCrypto);
25429 +    if (code != 0)
25430 +        return code;
25431 +#endif
25432 +
25433 +    code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
25434 +                           conf_req_flag ?
25435 +                                KRB5_CRYPTO_TYPE_TRAILER : KRB5_CRYPTO_TYPE_CHECKSUM,
25436 +                           &krbTrailerLen);
25437 +    if (code != 0) {
25438 +        *minor = code;
25439 +        return GSS_S_FAILURE;
25440 +    }
25441 +
25442 +    if (conf_req_flag) {
25443 +        code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
25444 +                               KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen);
25445 +        if (code != 0) {
25446 +            *minor = code;
25447 +            return GSS_S_FAILURE;
25448 +        }
25449 +    }
25450 +
25451 +    gssHeaderLen = 16; /* Header */
25452 +    if (conf_req_flag) {
25453 +        gssHeaderLen += krbHeaderLen; /* Kerb-Header */
25454 +        gssTrailerLen = 16 /* E(Header) */ + krbTrailerLen; /* Kerb-Trailer */
25455 +
25456 +        code = krbPaddingLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
25457 +                                dataLength - assocDataLength + 16 /* E(Header) */,
25458 +                                &krbPadLen);
25459 +        if (code != 0) {
25460 +            *minor = code;
25461 +            return GSS_S_FAILURE;
25462 +        }
25463 +
25464 +        if (krbPadLen == 0 && dce_style) {
25465 +            /* Windows rejects AEAD tokens with non-zero EC */
25466 +            code = krbBlockSize(krbContext, KRB_CRYPTO_CONTEXT(ctx), &ec);
25467 +            if (code != 0) {
25468 +                *minor = code;
25469 +                return GSS_S_FAILURE;
25470 +            }
25471 +        } else
25472 +            ec = krbPadLen;
25473 +
25474 +        gssTrailerLen += ec;
25475 +    } else {
25476 +        gssTrailerLen = krbTrailerLen; /* Kerb-Checksum */
25477 +    }
25478 +
25479 +    dataLength += gssPadLen;
25480 +
25481 +    if (trailer == NULL)
25482 +        gssHeaderLen += gssTrailerLen;
25483 +    else
25484 +        trailer->buffer.length = gssTrailerLen;
25485 +
25486 +    GSSEAP_ASSERT(gssPadLen == 0 || padding != NULL);
25487 +
25488 +    if (padding != NULL)
25489 +        padding->buffer.length = gssPadLen;
25490 +
25491 +    header->buffer.length = gssHeaderLen;
25492 +
25493 +    if (conf_state != NULL)
25494 +        *conf_state = conf_req_flag;
25495 +
25496 +    *minor = 0;
25497 +    return GSS_S_COMPLETE;
25498 +}
25499 +
25500 +OM_uint32 GSSAPI_CALLCONV
25501 +gss_wrap_iov_length(OM_uint32 *minor,
25502 +                    gss_ctx_id_t ctx,
25503 +                    int conf_req_flag,
25504 +                    gss_qop_t qop_req,
25505 +                    int *conf_state,
25506 +                    gss_iov_buffer_desc *iov,
25507 +                    int iov_count)
25508 +{
25509 +    OM_uint32 major;
25510 +
25511 +    if (ctx == GSS_C_NO_CONTEXT) {
25512 +        *minor = EINVAL;
25513 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
25514 +    }
25515 +
25516 +    *minor = 0;
25517 +
25518 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
25519 +
25520 +    if (!CTX_IS_ESTABLISHED(ctx)) {
25521 +        major = GSS_S_NO_CONTEXT;
25522 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
25523 +        goto cleanup;
25524 +    }
25525 +
25526 +    major = gssEapWrapIovLength(minor, ctx, conf_req_flag, qop_req,
25527 +                                conf_state, iov, iov_count);
25528 +    if (GSS_ERROR(major))
25529 +        goto cleanup;
25530 +
25531 +cleanup:
25532 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
25533 +
25534 +    return major;
25535 +}
25536 diff --git a/mech_eap/wrap_size_limit.c b/mech_eap/wrap_size_limit.c
25537 new file mode 100644
25538 index 0000000..d11fd63
25539 --- /dev/null
25540 +++ b/mech_eap/wrap_size_limit.c
25541 @@ -0,0 +1,97 @@
25542 +/*
25543 + * Copyright (c) 2011, JANET(UK)
25544 + * All rights reserved.
25545 + *
25546 + * Redistribution and use in source and binary forms, with or without
25547 + * modification, are permitted provided that the following conditions
25548 + * are met:
25549 + *
25550 + * 1. Redistributions of source code must retain the above copyright
25551 + *    notice, this list of conditions and the following disclaimer.
25552 + *
25553 + * 2. Redistributions in binary form must reproduce the above copyright
25554 + *    notice, this list of conditions and the following disclaimer in the
25555 + *    documentation and/or other materials provided with the distribution.
25556 + *
25557 + * 3. Neither the name of JANET(UK) nor the names of its contributors
25558 + *    may be used to endorse or promote products derived from this software
25559 + *    without specific prior written permission.
25560 + *
25561 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25562 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25563 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25564 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25565 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25566 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25567 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25568 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25569 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25570 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25571 + * SUCH DAMAGE.
25572 + */
25573 +
25574 +/*
25575 + * Message protection services: determine maximum input size.
25576 + */
25577 +
25578 +#include "gssapiP_eap.h"
25579 +
25580 +OM_uint32 GSSAPI_CALLCONV
25581 +gss_wrap_size_limit(OM_uint32 *minor,
25582 +                    gss_ctx_id_t ctx,
25583 +                    int conf_req_flag,
25584 +                    gss_qop_t qop_req,
25585 +                    OM_uint32 req_output_size,
25586 +                    OM_uint32 *max_input_size)
25587 +{
25588 +    gss_iov_buffer_desc iov[4];
25589 +    OM_uint32 major, overhead;
25590 +
25591 +    if (ctx == GSS_C_NO_CONTEXT) {
25592 +        *minor = EINVAL;
25593 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
25594 +    }
25595 +
25596 +    *minor = 0;
25597 +
25598 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
25599 +
25600 +    if (!CTX_IS_ESTABLISHED(ctx)) {
25601 +        major = GSS_S_NO_CONTEXT;
25602 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
25603 +        goto cleanup;
25604 +    }
25605 +
25606 +    iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
25607 +    iov[0].buffer.value = NULL;
25608 +    iov[0].buffer.length = 0;
25609 +
25610 +    iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
25611 +    iov[1].buffer.length = req_output_size;
25612 +    iov[1].buffer.value = NULL;
25613 +
25614 +    iov[2].type = GSS_IOV_BUFFER_TYPE_PADDING;
25615 +    iov[2].buffer.value = NULL;
25616 +    iov[2].buffer.length = 0;
25617 +
25618 +    iov[3].type = GSS_IOV_BUFFER_TYPE_TRAILER;
25619 +    iov[3].buffer.value = NULL;
25620 +    iov[3].buffer.length = 0;
25621 +
25622 +    major = gssEapWrapIovLength(minor, ctx, conf_req_flag, qop_req,
25623 +                                NULL, iov, 4);
25624 +    if (GSS_ERROR(major))
25625 +        goto cleanup;
25626 +
25627 +    overhead = iov[0].buffer.length + iov[3].buffer.length;
25628 +
25629 +    if (iov[2].buffer.length == 0 && overhead < req_output_size)
25630 +        *max_input_size = req_output_size - overhead;
25631 +    else
25632 +        *max_input_size = 0;
25633 +
25634 +cleanup:
25635 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
25636 +
25637 +    return major;
25638 +}
25639 -- 
25640 1.7.5.4
25641