Everything builds - instructions need completion
[moonshot.git] / mac-client-installer / 0001-Move-moonshot-files-up.patch
1 From d491bc19b59fd9d6d9a46fffef1ed82ddec2503d Mon Sep 17 00:00:00 2001
2 From: Pete Fotheringham <pete.fotheringham@codethink.co.uk>
3 Date: Thu, 29 Dec 2011 10:05:50 +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  libeap                                |    1 +
13  m4/minuso.m4                          |   35 +
14  mech_eap.spec.in                      |   62 ++
15  mech_eap/.gitignore                   |   32 +
16  mech_eap/AUTHORS                      |    6 +
17  mech_eap/COPYING                      |    3 +
18  mech_eap/LICENSE                      |   31 +
19  mech_eap/Makefile.am                  |  189 ++++++
20  mech_eap/NOTES                        |    9 +
21  mech_eap/README                       |  147 ++++
22  mech_eap/README.samba4                |   52 ++
23  mech_eap/TODO                         |    6 +
24  mech_eap/accept_sec_context.c         | 1072 +++++++++++++++++++++++++++++
25  mech_eap/acquire_cred.c               |   52 ++
26  mech_eap/acquire_cred_with_password.c |   67 ++
27  mech_eap/add_cred.c                   |   87 +++
28  mech_eap/add_cred_with_password.c     |   93 +++
29  mech_eap/authdata_plugin.h            |  331 +++++++++
30  mech_eap/authorize_localname.c        |   54 ++
31  mech_eap/canonicalize_name.c          |   64 ++
32  mech_eap/compare_name.c               |   46 ++
33  mech_eap/context_time.c               |   69 ++
34  mech_eap/delete_name_attribute.c      |   60 ++
35  mech_eap/delete_sec_context.c         |   81 +++
36  mech_eap/dictionary.ukerna            |   20 +
37  mech_eap/display_name.c               |   48 ++
38  mech_eap/display_name_ext.c           |   51 ++
39  mech_eap/display_status.c             |  203 ++++++
40  mech_eap/duplicate_name.c             |   60 ++
41  mech_eap/eap_mech.c                   |  219 ++++++
42  mech_eap/exchange_meta_data.c         |   82 +++
43  mech_eap/export_name.c                |   60 ++
44  mech_eap/export_name_composite.c      |   62 ++
45  mech_eap/export_sec_context.c         |  246 +++++++
46  mech_eap/get_mic.c                    |   89 +++
47  mech_eap/get_name_attribute.c         |   67 ++
48  mech_eap/gssapiP_eap.h                |  410 +++++++++++
49  mech_eap/gssapi_eap.h                 |   90 +++
50  mech_eap/gsseap_err.et                |  162 +++++
51  mech_eap/import_name.c                |   47 ++
52  mech_eap/import_sec_context.c         |  374 ++++++++++
53  mech_eap/indicate_mechs.c             |   44 ++
54  mech_eap/init_sec_context.c           | 1097 ++++++++++++++++++++++++++++++
55  mech_eap/inquire_attrs_for_mech.c     |  137 ++++
56  mech_eap/inquire_context.c            |  116 ++++
57  mech_eap/inquire_cred.c               |   61 ++
58  mech_eap/inquire_cred_by_mech.c       |   76 +++
59  mech_eap/inquire_cred_by_oid.c        |   83 +++
60  mech_eap/inquire_mech_for_saslname.c  |   84 +++
61  mech_eap/inquire_mechs_for_name.c     |   69 ++
62  mech_eap/inquire_name.c               |   75 ++
63  mech_eap/inquire_names_for_mech.c     |   77 +++
64  mech_eap/inquire_saslname_for_mech.c  |   51 ++
65  mech_eap/inquire_sec_context_by_oid.c |  248 +++++++
66  mech_eap/install-sh                   |  520 ++++++++++++++
67  mech_eap/map_name_to_any.c            |   58 ++
68  mech_eap/mech                         |    8 +
69  mech_eap/mech_eap-noacceptor.exports  |   55 ++
70  mech_eap/mech_eap.exports             |   63 ++
71  mech_eap/mech_invoke.c                |   44 ++
72  mech_eap/process_context_token.c      |   71 ++
73  mech_eap/pseudo_random.c              |  195 ++++++
74  mech_eap/query_mechanism_info.c       |   67 ++
75  mech_eap/query_meta_data.c            |  116 ++++
76  mech_eap/radius_ad.exports            |    1 +
77  mech_eap/radsec.conf                  |   12 +
78  mech_eap/radsec_err.et                |   38 +
79  mech_eap/release_any_name_mapping.c   |   59 ++
80  mech_eap/release_cred.c               |   44 ++
81  mech_eap/release_name.c               |   44 ++
82  mech_eap/release_oid.c                |   44 ++
83  mech_eap/set_cred_option.c            |  208 ++++++
84  mech_eap/set_name_attribute.c         |   60 ++
85  mech_eap/set_sec_context_option.c     |   87 +++
86  mech_eap/store_cred.c                 |   83 +++
87  mech_eap/unwrap.c                     |   85 +++
88  mech_eap/unwrap_iov.c                 |  572 ++++++++++++++++
89  mech_eap/util.h                       | 1032 ++++++++++++++++++++++++++++
90  mech_eap/util_adshim.c                |  242 +++++++
91  mech_eap/util_attr.cpp                | 1191 ++++++++++++++++++++++++++++++++
92  mech_eap/util_attr.h                  |  389 +++++++++++
93  mech_eap/util_base64.c                |  161 +++++
94  mech_eap/util_base64.h                |   58 ++
95  mech_eap/util_buffer.c                |  103 +++
96  mech_eap/util_cksum.c                 |  242 +++++++
97  mech_eap/util_context.c               |  377 +++++++++++
98  mech_eap/util_cred.c                  |  756 +++++++++++++++++++++
99  mech_eap/util_crypt.c                 |  397 +++++++++++
100  mech_eap/util_json.cpp                |  513 ++++++++++++++
101  mech_eap/util_json.h                  |  182 +++++
102  mech_eap/util_krb.c                   |  632 +++++++++++++++++
103  mech_eap/util_lucid.c                 |  183 +++++
104  mech_eap/util_mech.c                  |  380 +++++++++++
105  mech_eap/util_moonshot.c              |  238 +++++++
106  mech_eap/util_name.c                  |  789 ++++++++++++++++++++++
107  mech_eap/util_oid.c                   |  206 ++++++
108  mech_eap/util_ordering.c              |  302 +++++++++
109  mech_eap/util_radius.cpp              |  899 +++++++++++++++++++++++++
110  mech_eap/util_radius.h                |  183 +++++
111  mech_eap/util_reauth.c                | 1196 +++++++++++++++++++++++++++++++++
112  mech_eap/util_reauth.h                |  151 +++++
113  mech_eap/util_saml.cpp                |  775 +++++++++++++++++++++
114  mech_eap/util_saml.h                  |  176 +++++
115  mech_eap/util_shib.cpp                |  555 +++++++++++++++
116  mech_eap/util_shib.h                  |  122 ++++
117  mech_eap/util_sm.c                    |  372 ++++++++++
118  mech_eap/util_tld.c                   |  167 +++++
119  mech_eap/util_token.c                 |  493 ++++++++++++++
120  mech_eap/verify_mic.c                 |   71 ++
121  mech_eap/wrap.c                       |  137 ++++
122  mech_eap/wrap_iov.c                   |  379 +++++++++++
123  mech_eap/wrap_iov_length.c            |  234 +++++++
124  mech_eap/wrap_size_limit.c            |   97 +++
125  118 files changed, 24691 insertions(+), 0 deletions(-)
126  create mode 100644 Makefile.am
127  create mode 100644 acinclude.m4
128  create mode 100755 autogen.sh
129  create mode 100755 build-aux/compile
130  create mode 100644 configure.ac
131  create mode 160000 libeap
132  create mode 100644 m4/minuso.m4
133  create mode 100644 mech_eap.spec.in
134  create mode 100644 mech_eap/.gitignore
135  create mode 100644 mech_eap/AUTHORS
136  create mode 100644 mech_eap/COPYING
137  create mode 100644 mech_eap/LICENSE
138  create mode 100644 mech_eap/Makefile.am
139  create mode 100644 mech_eap/NEWS
140  create mode 100644 mech_eap/NOTES
141  create mode 100644 mech_eap/README
142  create mode 100644 mech_eap/README.samba4
143  create mode 100644 mech_eap/TODO
144  create mode 100644 mech_eap/accept_sec_context.c
145  create mode 100644 mech_eap/acquire_cred.c
146  create mode 100644 mech_eap/acquire_cred_with_password.c
147  create mode 100644 mech_eap/add_cred.c
148  create mode 100644 mech_eap/add_cred_with_password.c
149  create mode 100644 mech_eap/authdata_plugin.h
150  create mode 100644 mech_eap/authorize_localname.c
151  create mode 100644 mech_eap/canonicalize_name.c
152  create mode 100644 mech_eap/compare_name.c
153  create mode 100644 mech_eap/context_time.c
154  create mode 100644 mech_eap/delete_name_attribute.c
155  create mode 100644 mech_eap/delete_sec_context.c
156  create mode 100644 mech_eap/dictionary.ukerna
157  create mode 100644 mech_eap/display_name.c
158  create mode 100644 mech_eap/display_name_ext.c
159  create mode 100644 mech_eap/display_status.c
160  create mode 100644 mech_eap/duplicate_name.c
161  create mode 100644 mech_eap/eap_mech.c
162  create mode 100644 mech_eap/exchange_meta_data.c
163  create mode 100644 mech_eap/export_name.c
164  create mode 100644 mech_eap/export_name_composite.c
165  create mode 100644 mech_eap/export_sec_context.c
166  create mode 100644 mech_eap/get_mic.c
167  create mode 100644 mech_eap/get_name_attribute.c
168  create mode 100644 mech_eap/gssapiP_eap.h
169  create mode 100644 mech_eap/gssapi_eap.h
170  create mode 100644 mech_eap/gsseap_err.et
171  create mode 100644 mech_eap/import_name.c
172  create mode 100644 mech_eap/import_sec_context.c
173  create mode 100644 mech_eap/indicate_mechs.c
174  create mode 100644 mech_eap/init_sec_context.c
175  create mode 100644 mech_eap/inquire_attrs_for_mech.c
176  create mode 100644 mech_eap/inquire_context.c
177  create mode 100644 mech_eap/inquire_cred.c
178  create mode 100644 mech_eap/inquire_cred_by_mech.c
179  create mode 100644 mech_eap/inquire_cred_by_oid.c
180  create mode 100644 mech_eap/inquire_mech_for_saslname.c
181  create mode 100644 mech_eap/inquire_mechs_for_name.c
182  create mode 100644 mech_eap/inquire_name.c
183  create mode 100644 mech_eap/inquire_names_for_mech.c
184  create mode 100644 mech_eap/inquire_saslname_for_mech.c
185  create mode 100644 mech_eap/inquire_sec_context_by_oid.c
186  create mode 100755 mech_eap/install-sh
187  create mode 100644 mech_eap/map_name_to_any.c
188  create mode 100644 mech_eap/mech
189  create mode 100644 mech_eap/mech_eap-noacceptor.exports
190  create mode 100644 mech_eap/mech_eap.exports
191  create mode 100644 mech_eap/mech_invoke.c
192  create mode 100644 mech_eap/process_context_token.c
193  create mode 100644 mech_eap/pseudo_random.c
194  create mode 100644 mech_eap/query_mechanism_info.c
195  create mode 100644 mech_eap/query_meta_data.c
196  create mode 100644 mech_eap/radius_ad.exports
197  create mode 100644 mech_eap/radsec.conf
198  create mode 100644 mech_eap/radsec_err.et
199  create mode 100644 mech_eap/release_any_name_mapping.c
200  create mode 100644 mech_eap/release_cred.c
201  create mode 100644 mech_eap/release_name.c
202  create mode 100644 mech_eap/release_oid.c
203  create mode 100644 mech_eap/set_cred_option.c
204  create mode 100644 mech_eap/set_name_attribute.c
205  create mode 100644 mech_eap/set_sec_context_option.c
206  create mode 100644 mech_eap/store_cred.c
207  create mode 100644 mech_eap/unwrap.c
208  create mode 100644 mech_eap/unwrap_iov.c
209  create mode 100644 mech_eap/util.h
210  create mode 100644 mech_eap/util_adshim.c
211  create mode 100644 mech_eap/util_attr.cpp
212  create mode 100644 mech_eap/util_attr.h
213  create mode 100644 mech_eap/util_base64.c
214  create mode 100644 mech_eap/util_base64.h
215  create mode 100644 mech_eap/util_buffer.c
216  create mode 100644 mech_eap/util_cksum.c
217  create mode 100644 mech_eap/util_context.c
218  create mode 100644 mech_eap/util_cred.c
219  create mode 100644 mech_eap/util_crypt.c
220  create mode 100644 mech_eap/util_json.cpp
221  create mode 100644 mech_eap/util_json.h
222  create mode 100644 mech_eap/util_krb.c
223  create mode 100644 mech_eap/util_lucid.c
224  create mode 100644 mech_eap/util_mech.c
225  create mode 100644 mech_eap/util_moonshot.c
226  create mode 100644 mech_eap/util_name.c
227  create mode 100644 mech_eap/util_oid.c
228  create mode 100644 mech_eap/util_ordering.c
229  create mode 100644 mech_eap/util_radius.cpp
230  create mode 100644 mech_eap/util_radius.h
231  create mode 100644 mech_eap/util_reauth.c
232  create mode 100644 mech_eap/util_reauth.h
233  create mode 100644 mech_eap/util_saml.cpp
234  create mode 100644 mech_eap/util_saml.h
235  create mode 100644 mech_eap/util_shib.cpp
236  create mode 100644 mech_eap/util_shib.h
237  create mode 100644 mech_eap/util_sm.c
238  create mode 100644 mech_eap/util_tld.c
239  create mode 100644 mech_eap/util_token.c
240  create mode 100644 mech_eap/verify_mic.c
241  create mode 100644 mech_eap/wrap.c
242  create mode 100644 mech_eap/wrap_iov.c
243  create mode 100644 mech_eap/wrap_iov_length.c
244  create mode 100644 mech_eap/wrap_size_limit.c
245
246 diff --git a/Makefile.am b/Makefile.am
247 new file mode 100644
248 index 0000000..0165219
249 --- /dev/null
250 +++ b/Makefile.am
251 @@ -0,0 +1,4 @@
252 +AUTOMAKE_OPTIONS = foreign
253 +ACLOCAL_AMFLAGS = -I m4
254 +SUBDIRS = libeap mech_eap
255 +EXTRA_DIST = mech_eap.spec
256 diff --git a/acinclude.m4 b/acinclude.m4
257 new file mode 100644
258 index 0000000..6f43261
259 --- /dev/null
260 +++ b/acinclude.m4
261 @@ -0,0 +1,364 @@
262 +dnl Based on the one from the Boinc project by Reinhard
263 +
264 +AC_DEFUN([AX_CHECK_WINDOWS],
265 +[AC_MSG_CHECKING(for windows)
266 +target_windows="no"
267 +AC_CHECK_HEADER(windows.h,[target_windows="yes"],[target_windows="no"])
268 +AC_MSG_RESULT($target_windows)
269 +AM_CONDITIONAL(TARGET_WINDOWS,test "x$target_windows" = "xyes")
270 +])dnl
271 +
272 +AC_DEFUN([AX_CHECK_KRB5],
273 +[AC_MSG_CHECKING(for GSS-API and Kerberos implementation)
274 +KRB5_DIR=
275 +found_krb5="no"
276 +AC_ARG_WITH(krb5,
277 +    AC_HELP_STRING([--with-krb5],
278 +       [Use krb5 (in specified installation directory)]),
279 +    [check_krb5_dir="$withval"],
280 +    [check_krb5_dir=])
281 +for dir in $check_krb5_dir $prefix /usr/local /usr ; do
282 +   krb5dir="$dir"
283 +   if test -x "$dir/bin/krb5-config"; then
284 +     found_krb5="yes";
285 +     if test "x$target_windows" = "xyes"; then
286 +        KRB5_CFLAGS=-I"$check_krb5_dir/include";
287 +        KRB5_LDFLAGS="-L$check_krb5_dir/lib/";
288 +        KRB5_LIBS="-lkrb5_32 -lgssapi32";
289 +        COMPILE_ET="$check_krb5_dir/bin/compile_et";
290 +       AC_MSG_RESULT([yes])
291 +     else
292 +        KRB5_CFLAGS=`$dir/bin/krb5-config gssapi --cflags`;
293 +        KRB5_LDFLAGS="-L$dir/lib";
294 +        KRB5_LIBS=`$dir/bin/krb5-config gssapi --libs`
295 +AC_MSG_RESULT([yes])
296 +        AC_PATH_PROG(COMPILE_ET, [compile_et], [compile_et], [$dir/bin$PATH_SEPARATOr])
297 +     fi
298 +     break;
299 +   fi
300 +done
301 +if test x_$found_krb5 != x_yes; then
302 +   AC_MSG_RESULT($found_krb5)
303 +   AC_MSG_ERROR([
304 +----------------------------------------------------------------------
305 +  Cannot find GSS-API/Kerberos libraries.
306 +
307 +  Please install MIT or Heimdal or specify installation directory with
308 +  --with-krb5=(dir).
309 +----------------------------------------------------------------------
310 +])
311 +else
312 +       printf "Kerberos found in $krb5dir\n";
313 +       AC_SUBST(KRB5_CFLAGS)
314 +        AC_SUBST(KRB5_LDFLAGS)
315 +       AC_SUBST(KRB5_LIBS)
316 +       AC_SUBST(COMPILE_ET)
317 +       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")
318 +       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")
319 +       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")
320 +       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")
321 +       AM_CONDITIONAL(HEIMDAL, test "x$heimdal" != "xno")
322 +fi
323 +])dnl
324 +
325 +AC_DEFUN([AX_CHECK_EAP],
326 +[AC_MSG_CHECKING(for EAP implementation)
327 +EAP_DIR=
328 +found_eap="no"
329 +AC_ARG_WITH(eap,
330 +    AC_HELP_STRING([--with-eap],
331 +       [Use eap (in specified installation directory)]),
332 +    [check_eap_dir="$withval"],
333 +    [check_eap_dir=])
334 +for dir in $check_eap_dir $prefix /usr /usr/local ../libeap ; do
335 +   eapdir="$dir"
336 +   if test -f "$dir/src/eap_peer/eap.h"; then
337 +     found_eap="yes";
338 +     EAP_DIR="${eapdir}"
339 +     EAP_CFLAGS="-I$eapdir/src/common -I$eapdir/src -I$eapdir/src/utils";
340 +     break;
341 +   fi
342 +done
343 +AC_MSG_RESULT($found_eap)
344 +if test x_$found_eap != x_yes; then
345 +   AC_MSG_ERROR([
346 +----------------------------------------------------------------------
347 +  Cannot find EAP libraries.
348 +
349 +  Please install wpa_supplicant or specify installation directory with
350 +  --with-eap=(dir).
351 +----------------------------------------------------------------------
352 +])
353 +else
354 +       printf "EAP found in $eapdir\n";
355 +       EAP_CFLAGS="$EAP_CFLAGS \
356 +-DEAP_TLS \
357 +-DEAP_PEAP \
358 +-DEAP_TTLS \
359 +-DEAP_MD5 \
360 +-DEAP_MSCHAPv2 \
361 +-DEAP_GTC \
362 +-DEAP_OTP \
363 +-DEAP_LEAP \
364 +-DEAP_PSK \
365 +-DEAP_PAX \
366 +-DEAP_SAKE \
367 +-DEAP_GPSK \
368 +-DEAP_GPSK_SHA256 \
369 +-DEAP_SERVER_IDENTITY \
370 +-DEAP_SERVER_TLS \
371 +-DEAP_SERVER_PEAP \
372 +-DEAP_SERVER_TTLS \
373 +-DEAP_SERVER_MD5 \
374 +-DEAP_SERVER_MSCHAPV2 \
375 +-DEAP_SERVER_GTC \
376 +-DEAP_SERVER_PSK \
377 +-DEAP_SERVER_PAX \
378 +-DEAP_SERVER_SAKE \
379 +-DEAP_SERVER_GPSK \
380 +-DEAP_SERVER_GPSK_SHA256 \
381 +-DIEEE8021X_EAPOL";
382 +       EAP_LIBS="-leap -lutils -lcrypto -ltls";
383 +       EAP_LDFLAGS="-L$eapdir/eap_example -L$eapdir/src/utils -L$eapdir/src/crypto -L$eapdir/src/tls";
384 +       AC_SUBST(EAP_CFLAGS)
385 +       AC_SUBST(EAP_LDFLAGS)
386 +       AC_SUBST(EAP_LIBS)
387 +fi
388 +])dnl
389 +
390 +AC_DEFUN([AX_CHECK_SHIBSP],
391 +[AC_MSG_CHECKING(for Shibboleth implementation)
392 +SHIBSP_DIR=
393 +found_shibsp="no"
394 +AC_ARG_WITH(shibsp,
395 +    AC_HELP_STRING([--with-shibsp],
396 +       [Use shibspboleth (in specified installation directory)]),
397 +    [check_shibsp_dir="$withval"],
398 +    [check_shibsp_dir=])
399 +for dir in $check_shibsp_dir $prefix /usr /usr/local ; do
400 +   shibspdir="$dir"
401 +   if test -f "$dir/include/shibsp/SPConfig.h"; then
402 +     found_shibsp="yes";
403 +     SHIBSP_DIR="${shibspdir}"
404 +     SHIBSP_CXXFLAGS="-I$shibspdir/include";
405 +     break;
406 +   fi
407 +done
408 +AC_MSG_RESULT($found_shibsp)
409 +if test x_$found_shibsp != x_yes; then
410 +   AC_MSG_ERROR([
411 +----------------------------------------------------------------------
412 +  Cannot find Shibboleth libraries.
413 +
414 +  Please install Shibboleth or specify installation directory with
415 +  --with-shibsp=(dir).
416 +----------------------------------------------------------------------
417 +])
418 +else
419 +       printf "Shibboleth found in $shibspdir\n";
420 +       SHIBSP_LIBS="-lshibsp -lsaml -lxml-security-c -lxmltooling -lxerces-c";
421 +       SHIBSP_LDFLAGS="-L$shibspdir/lib";
422 +       AC_SUBST(SHIBSP_CXXFLAGS)
423 +       AC_SUBST(SHIBSP_LDFLAGS)
424 +       AC_SUBST(SHIBSP_LIBS)
425 +       AC_DEFINE_UNQUOTED([HAVE_SHIBSP], 1, [Define is Shibboleth SP is available])
426 +fi
427 +])dnl
428 +
429 +AC_DEFUN([AX_CHECK_SHIBRESOLVER],
430 +[AC_MSG_CHECKING(for Shibboleth resolver implementation)
431 +SHIBRESOLVER_DIR=
432 +found_shibresolver="no"
433 +AC_ARG_WITH(shibresolver,
434 +    AC_HELP_STRING([--with-shibresolver],
435 +       [Use Shibboleth resolver (in specified installation directory)]),
436 +    [check_shibresolver_dir="$withval"],
437 +    [check_shibresolver_dir=])
438 +if test x_$check_shibresolver_dir != x_no; then
439 +for dir in $check_shibresolver_dir $prefix /usr /usr/local ; do
440 +   shibresolverdir="$dir"
441 +   if test -f "$dir/include/shibresolver/resolver.h"; then
442 +     found_shibresolver="yes";
443 +     SHIBRESOLVER_DIR="${shibresolverdir}"
444 +     SHIBRESOLVER_CXXFLAGS="-I$shibresolverdir/include";
445 +     break;
446 +   fi
447 +done
448 +fi
449 +AC_MSG_RESULT($found_shibresolver)
450 +if test x_$check_shibresolver_dir != x_no; then
451 +if test x_$found_shibresolver != x_yes; then
452 +   AC_MSG_WARN([
453 +----------------------------------------------------------------------
454 +  Cannot find Shibboleth resolver libraries, building without
455 +  Shibboleth support.
456 +
457 +  Please install Shibboleth or specify installation directory with
458 +  --with-shibresolver=(dir).
459 +----------------------------------------------------------------------
460 +])
461 +else
462 +       printf "Shibboleth resolver found in $shibresolverdir\n";
463 +       SHIBRESOLVER_LIBS="-lshibresolver";
464 +       SHIBRESOLVER_LDFLAGS="-L$shibresolverdir/lib";
465 +       AC_SUBST(SHIBRESOLVER_CXXFLAGS)
466 +       AC_SUBST(SHIBRESOLVER_LDFLAGS)
467 +       AC_SUBST(SHIBRESOLVER_LIBS)
468 +       AC_DEFINE_UNQUOTED([HAVE_SHIBRESOLVER], 1, [Define is Shibboleth resolver is available])
469 +fi
470 +fi
471 +])dnl
472 +
473 +AC_DEFUN([AX_CHECK_OPENSAML],
474 +[AC_MSG_CHECKING(for OpenSAML implementation)
475 +OPENSAML_DIR=
476 +found_opensaml="no"
477 +AC_ARG_WITH(opensaml,
478 +    AC_HELP_STRING([--with-opensaml],
479 +       [Use OpenSAML (in specified installation directory)]),
480 +    [check_opensaml_dir="$withval"],
481 +    [check_opensaml_dir=])
482 +if test x_$check_opensaml_dir != x_no; then
483 +for dir in $check_opensaml_dir $prefix /usr /usr/local ; do
484 +   opensamldir="$dir"
485 +   if test -f "$dir/include/saml/Assertion.h"; then
486 +     found_opensaml="yes";
487 +     OPENSAML_DIR="${opensamldir}"
488 +     OPENSAML_CXXFLAGS="-I$opensamldir/include";
489 +     break;
490 +   fi
491 +done
492 +fi
493 +AC_MSG_RESULT($found_opensaml)
494 +if test x_$check_opensaml_dir != x_no; then
495 +if test x_$found_opensaml != x_yes; then
496 +   AC_MSG_WARN([
497 +----------------------------------------------------------------------
498 +  Cannot find OpenSAML libraries, building without OpenSAML support.
499 +
500 +  Please install OpenSAML or specify installation directory with
501 +  --with-opensaml=(dir).
502 +----------------------------------------------------------------------
503 +])
504 +else
505 +       printf "OpenSAML found in $opensamldir\n";
506 +       OPENSAML_LIBS="-lsaml -lxml-security-c -lxmltooling -lxerces-c";
507 +       OPENSAML_LDFLAGS="-L$opensamldir/lib";
508 +       AC_SUBST(OPENSAML_CXXFLAGS)
509 +       AC_SUBST(OPENSAML_LDFLAGS)
510 +       AC_SUBST(OPENSAML_LIBS)
511 +       AC_DEFINE_UNQUOTED([HAVE_OPENSAML], 1, [Define is OpenSAML is available])
512 +fi
513 +fi
514 +])dnl
515 +
516 +AC_DEFUN([AX_CHECK_RADSEC],
517 +[AC_MSG_CHECKING(for radsec)
518 +RADSEC_DIR=
519 +found_radsec="no"
520 +AC_ARG_WITH(radsec,
521 +    AC_HELP_STRING([--with-radsec],
522 +       [Use radsec (in specified installation directory)]),
523 +    [check_radsec_dir="$withval"],
524 +    [check_radsec_dir=])
525 +for dir in $check_radsec_dir $prefix /usr /usr/local ; do
526 +   radsecdir="$dir"
527 +   if test -f "$dir/include/radsec/radsec.h"; then
528 +     found_radsec="yes";
529 +     RADSEC_DIR="${radsecdir}"
530 +     RADSEC_CFLAGS="-I$radsecdir/include";
531 +     break;
532 +   fi
533 +done
534 +AC_MSG_RESULT($found_radsec)
535 +if test x_$found_radsec != x_yes; then
536 +   AC_MSG_ERROR([
537 +----------------------------------------------------------------------
538 +  Cannot find radsec libraries.
539 +
540 +  Please install libradsec or specify installation directory with
541 +  --with-radsec=(dir).
542 +----------------------------------------------------------------------
543 +])
544 +else
545 +       printf "radsec found in $radsecdir\n";
546 +       RADSEC_LIBS="-lradsec";
547 +       RADSEC_LDFLAGS="-L$radsecdir/lib";
548 +       AC_SUBST(RADSEC_CFLAGS)
549 +       AC_SUBST(RADSEC_LDFLAGS)
550 +       AC_SUBST(RADSEC_LIBS)
551 +fi
552 +])dnl
553 +
554 +AC_DEFUN([AX_CHECK_JANSSON],
555 +[AC_MSG_CHECKING(for jansson)
556 +JANSSON_DIR=
557 +found_jansson="no"
558 +AC_ARG_WITH(jansson,
559 +    AC_HELP_STRING([--with-jansson],
560 +       [Use jansson (in specified installation directory)]),
561 +    [check_jansson_dir="$withval"],
562 +    [check_jansson_dir=])
563 +for dir in $check_jansson_dir $prefix /usr /usr/local ; do
564 +   janssondir="$dir"
565 +   if test -f "$dir/include/jansson.h"; then
566 +     found_jansson="yes";
567 +     JANSSON_DIR="${janssondir}"
568 +     JANSSON_CFLAGS="-I$janssondir/include";
569 +     break;
570 +   fi
571 +done
572 +AC_MSG_RESULT($found_jansson)
573 +if test x_$found_jansson != x_yes; then
574 +   AC_MSG_ERROR([
575 +----------------------------------------------------------------------
576 +  Cannot find jansson libraries.
577 +
578 +  Please install libjansson or specify installation directory with
579 +  --with-jansson=(dir).
580 +----------------------------------------------------------------------
581 +])
582 +else
583 +       printf "jansson found in $janssondir\n";
584 +       JANSSON_LIBS="-ljansson";
585 +       JANSSON_LDFLAGS="-L$janssondir/lib";
586 +       AC_SUBST(JANSSON_CFLAGS)
587 +       AC_SUBST(JANSSON_LDFLAGS)
588 +       AC_SUBST(JANSSON_LIBS)
589 +fi
590 +])dnl
591 +
592 +AC_DEFUN([AX_CHECK_LIBMOONSHOT],
593 +[AC_MSG_CHECKING(for Moonshot identity selector implementation)
594 +LIBMOONSHOT_DIR=
595 +LIBMOONSHOT_CFLAGS=
596 +LIBMOONSHOT_LDFLAGS=
597 +LIBMOONSHOT_LIBS=
598 +found_libmoonshot="no"
599 +AC_ARG_WITH(libmoonshot,
600 +    AC_HELP_STRING([--with-libmoonshot],
601 +       [Use libmoonshot (in specified installation directory)]),
602 +    [check_libmoonshot_dir="$withval"],
603 +    [check_libmoonshot_dir=])
604 +for dir in $check_libmoonshot_dir $prefix /usr /usr/local ; do
605 +   libmoonshotdir="$dir"
606 +   if test -f "$dir/include/libmoonshot.h"; then
607 +     found_libmoonshot="yes";
608 +     LIBMOONSHOT_DIR="${libmoonshotdir}"
609 +     LIBMOONSHOT_CFLAGS="-I$libmoonshotdir/include";
610 +     break;
611 +   fi
612 +done
613 +AC_MSG_RESULT($found_libmoonshot)
614 +if test x_$found_libmoonshot = x_yes; then
615 +    printf "libmoonshot found in $libmoonshotdir\n";
616 +    LIBMOONSHOT_LIBS="-lmoonshot";
617 +    LIBMOONSHOT_LDFLAGS="-L$libmoonshot/lib";
618 +    AC_CHECK_LIB(moonshot, moonshot_get_identity, [AC_DEFINE_UNQUOTED([HAVE_MOONSHOT_GET_IDENTITY], 1, [Define if Moonshot identity selector is available])], [], "$LIBMOONSHOT_LIBS")
619 +fi
620 +    AC_SUBST(LIBMOONSHOT_CFLAGS)
621 +    AC_SUBST(LIBMOONSHOT_LDFLAGS)
622 +    AC_SUBST(LIBMOONSHOT_LIBS)
623 +    AM_CONDITIONAL(LIBMOONSHOT, test "x$found_libmoonshot" != "xno")
624 +])dnl
625 +
626 diff --git a/autogen.sh b/autogen.sh
627 new file mode 100755
628 index 0000000..13432d0
629 --- /dev/null
630 +++ b/autogen.sh
631 @@ -0,0 +1,16 @@
632 +#!/bin/sh
633 +#
634 +# Regenerate autotools files.
635 +#
636 +
637 +PATH=/usr/local/bin:$PATH
638 +
639 +if [ -x "`which autoreconf 2>/dev/null`" ] ; then
640 +   exec autoreconf -ivf
641 +fi
642 +
643 +aclocal -I . -I m4 && \
644 +    autoheader && \
645 +    libtoolize --automake -c && \
646 +    autoconf && \
647 +    automake --add-missing --copy
648 diff --git a/build-aux/compile b/build-aux/compile
649 new file mode 100755
650 index 0000000..5360806
651 --- /dev/null
652 +++ b/build-aux/compile
653 @@ -0,0 +1,144 @@
654 +#! /bin/sh
655 +# Wrapper for compilers which do not understand `-c -o'.
656 +
657 +scriptversion=2009-10-06.20; # UTC
658 +
659 +# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2009  Free Software
660 +# Foundation, Inc.
661 +# Written by Tom Tromey <tromey@cygnus.com>.
662 +#
663 +# This program is free software; you can redistribute it and/or modify
664 +# it under the terms of the GNU General Public License as published by
665 +# the Free Software Foundation; either version 2, or (at your option)
666 +# any later version.
667 +#
668 +# This program is distributed in the hope that it will be useful,
669 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
670 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
671 +# GNU General Public License for more details.
672 +#
673 +# You should have received a copy of the GNU General Public License
674 +# along with this program; if not, write to the Free Software
675 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
676 +
677 +# As a special exception to the GNU General Public License, if you
678 +# distribute this file as part of a program that contains a
679 +# configuration script generated by Autoconf, you may include it under
680 +# the same distribution terms that you use for the rest of that program.
681 +
682 +# This file is maintained in Automake, please report
683 +# bugs to <bug-automake@gnu.org> or send patches to
684 +# <automake-patches@gnu.org>.
685 +
686 +case $1 in
687 +  '')
688 +     echo "$0: No command.  Try \`$0 --help' for more information." 1>&2
689 +     exit 1;
690 +     ;;
691 +  -h | --h*)
692 +    cat <<\EOF
693 +Usage: compile [--help] [--version] PROGRAM [ARGS]
694 +
695 +Wrapper for compilers which do not understand `-c -o'.
696 +Remove `-o dest.o' from ARGS, run PROGRAM with the remaining
697 +arguments, and rename the output as expected.
698 +
699 +If you are trying to build a whole package this is not the
700 +right script to run: please start by reading the file `INSTALL'.
701 +
702 +Report bugs to <bug-automake@gnu.org>.
703 +EOF
704 +    exit $?
705 +    ;;
706 +  -v | --v*)
707 +    echo "compile $scriptversion"
708 +    exit $?
709 +    ;;
710 +esac
711 +
712 +ofile=
713 +cfile=
714 +eat=
715 +
716 +for arg
717 +do
718 +  if test -n "$eat"; then
719 +    eat=
720 +  else
721 +    case $1 in
722 +      -o)
723 +       # configure might choose to run compile as `compile cc -o foo foo.c'.
724 +       # So we strip `-o arg' only if arg is an object.
725 +       eat=1
726 +       case $2 in
727 +         *.o | *.obj)
728 +           ofile=$2
729 +           ;;
730 +         *)
731 +           set x "$@" -o "$2"
732 +           shift
733 +           ;;
734 +       esac
735 +       ;;
736 +      *.c)
737 +       cfile=$1
738 +       set x "$@" "$1"
739 +       shift
740 +       ;;
741 +      *)
742 +       set x "$@" "$1"
743 +       shift
744 +       ;;
745 +    esac
746 +  fi
747 +  shift
748 +done
749 +
750 +if test -z "$ofile" || test -z "$cfile"; then
751 +  # If no `-o' option was seen then we might have been invoked from a
752 +  # pattern rule where we don't need one.  That is ok -- this is a
753 +  # normal compilation that the losing compiler can handle.  If no
754 +  # `.c' file was seen then we are probably linking.  That is also
755 +  # ok.
756 +  exec "$@"
757 +fi
758 +
759 +# Name of file we expect compiler to create.
760 +cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
761 +
762 +# Create the lock directory.
763 +# Note: use `[/\\:.-]' here to ensure that we don't use the same name
764 +# that we are using for the .o file.  Also, base the name on the expected
765 +# object file name, since that is what matters with a parallel build.
766 +lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
767 +while true; do
768 +  if mkdir "$lockdir" >/dev/null 2>&1; then
769 +    break
770 +  fi
771 +  sleep 1
772 +done
773 +# FIXME: race condition here if user kills between mkdir and trap.
774 +trap "rmdir '$lockdir'; exit 1" 1 2 15
775 +
776 +# Run the compile.
777 +"$@"
778 +ret=$?
779 +
780 +if test -f "$cofile"; then
781 +  test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
782 +elif test -f "${cofile}bj"; then
783 +  test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
784 +fi
785 +
786 +rmdir "$lockdir"
787 +exit $ret
788 +
789 +# Local Variables:
790 +# mode: shell-script
791 +# sh-indentation: 2
792 +# eval: (add-hook 'write-file-hooks 'time-stamp)
793 +# time-stamp-start: "scriptversion="
794 +# time-stamp-format: "%:y-%02m-%02d.%02H"
795 +# time-stamp-time-zone: "UTC"
796 +# time-stamp-end: "; # UTC"
797 +# End:
798 diff --git a/configure.ac b/configure.ac
799 new file mode 100644
800 index 0000000..4297345
801 --- /dev/null
802 +++ b/configure.ac
803 @@ -0,0 +1,92 @@
804 +AC_PREREQ([2.61])
805 +AC_INIT([mech_eap], [0.1], [bugs@project-moonshot.org])
806 +AC_CONFIG_MACRO_DIR([m4])
807 +AC_CONFIG_AUX_DIR([build-aux])
808 +
809 +dnl AM_INIT_AUTOMAKE([silent-rules])
810 +AC_USE_SYSTEM_EXTENSIONS
811 +AM_INIT_AUTOMAKE
812 +AM_PROG_CC_C_O
813 +AM_MAINTAINER_MODE()
814 +LT_PREREQ([2.2])
815 +LT_INIT([dlopen disable-static win32-dll])
816 +
817 +dnl AC_PROG_CC
818 +AC_PROG_CXX
819 +AC_CONFIG_HEADERS([config.h])
820 +AC_CHECK_HEADERS(stdarg.h stdio.h stdint.h sys/param.h)
821 +AC_REPLACE_FUNCS(vasprintf)
822 +
823 +dnl Check if we're on Solaris and set CFLAGS accordingly
824 +dnl AC_CANONICAL_TARGET
825 +dnl case "${target_os}" in
826 +dnl   solaris*)
827 +dnl     TARGET_CFLAGS="-DSYS_SOLARIS9 -D_POSIX_PTHREAD_SEMANTICS"
828 +dnl     if test "$GCC" != yes ; then
829 +dnl       TARGET_CFLAGS="$TARGET_CFLAGS -mt"
830 +dnl     else
831 +dnl       TARGET_CFLAGS="$TARGET_CFLAGS -pthreads"
832 +dnl     fi
833 +dnl     TARGET_LDFLAGS="-lpthread -lsocket -lnsl"
834 +dnl     ;;
835 +dnl   *)
836 +dnl     TARGET_CFLAGS="-Wall -pedantic -pthread"
837 +dnl     TARGET_LDFLAGS=""
838 +dnl   esac
839 +
840 +reauth=no
841 +AC_ARG_ENABLE(reauth,
842 +  [  --enable-reauth whether to enable fast reauthentication protocol: yes/no; default no ],
843 +  [ if test "x$enableval" = "xyes" -o "x$enableval" = "xno" ; then
844 +      reauth=$enableval
845 +    else
846 +      echo "--enable-reauth argument must be yes or no"
847 +      exit -1
848 +    fi
849 +  ])
850 +
851 +if test "x$reauth" = "xyes" ; then
852 +  echo "Fast reauthentication protocol enabled"
853 +  TARGET_CFLAGS="$TARGET_CFLAGS -DGSSEAP_ENABLE_REAUTH"
854 +fi
855 +AM_CONDITIONAL(GSSEAP_ENABLE_REAUTH, test "x$reauth" != "xno")
856 +
857 +acceptor=yes
858 +AC_ARG_ENABLE(acceptor,
859 +  [  --enable-acceptor whether to enable acceptor codepaths: yes/no; default yes ],
860 +  [ if test "x$enableval" = "xyes" -o "x$enableval" = "xno" ; then
861 +      acceptor=$enableval
862 +    else
863 +      echo "--enable-acceptor argument must be yes or no"
864 +      exit -1
865 +    fi
866 +  ])
867 +
868 +if test "x$acceptor" = "xyes" ; then
869 +  echo "acceptor enabled"
870 +  TARGET_CFLAGS="$TARGET_CFLAGS -DGSSEAP_ENABLE_ACCEPTOR"
871 +fi
872 +AM_CONDITIONAL(GSSEAP_ENABLE_ACCEPTOR, test "x$acceptor" != "xno")
873 +
874 +AC_SUBST(TARGET_CFLAGS)
875 +AC_SUBST(TARGET_LDFLAGS)
876 +AX_CHECK_WINDOWS
877 +AX_CHECK_KRB5
878 +AX_CHECK_OPENSAML
879 +AM_CONDITIONAL(OPENSAML, test "x_$check_opensaml_dir" != "x_no")
880 +
881 +AX_CHECK_SHIBRESOLVER
882 +AM_CONDITIONAL(SHIBRESOLVER, test "x_$check_shibresolver_dir" != "x_no")
883 +if test x_$found_shibresolver = x_yes; then
884 +  AX_CHECK_SHIBSP
885 +fi
886 +
887 +if test "x$acceptor" = "xyes" ; then
888 +  AX_CHECK_RADSEC
889 +  AX_CHECK_JANSSON
890 +fi
891 +
892 +AX_CHECK_LIBMOONSHOT
893 +AC_CONFIG_FILES([Makefile libeap/Makefile mech_eap/Makefile
894 +                         mech_eap.spec])
895 +AC_OUTPUT
896 diff --git a/libeap b/libeap
897 new file mode 160000
898 index 0000000..3c68005
899 --- /dev/null
900 +++ b/libeap
901 @@ -0,0 +1 @@
902 +Subproject commit 3c6800594dbfcba5d36cfa5556288eae999f83ba
903 diff --git a/m4/minuso.m4 b/m4/minuso.m4
904 new file mode 100644
905 index 0000000..d8b1620
906 --- /dev/null
907 +++ b/m4/minuso.m4
908 @@ -0,0 +1,35 @@
909 +##                                                          -*- Autoconf -*-
910 +# Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2008
911 +# Free Software Foundation, Inc.
912 +#
913 +# This file is free software; the Free Software Foundation
914 +# gives unlimited permission to copy and/or distribute it,
915 +# with or without modifications, as long as this notice is preserved.
916 +
917 +# serial 6
918 +
919 +# AM_PROG_CC_C_O
920 +# --------------
921 +# Like AC_PROG_CC_C_O, but changed for automake.
922 +AC_DEFUN([AM_PROG_CC_C_O],
923 +[AC_REQUIRE([AC_PROG_CC_C_O])dnl
924 +AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
925 +AC_REQUIRE_AUX_FILE([compile])dnl
926 +# FIXME: we rely on the cache variable name because
927 +# there is no other way.
928 +set dummy $CC
929 +am_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']`
930 +eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o
931 +if test "$am_t" != yes; then
932 +   # Losing compiler, so override with the script.
933 +   # FIXME: It is wrong to rewrite CC.
934 +   # But if we don't then we get into trouble of one sort or another.
935 +   # A longer-term fix would be to have automake use am__CC in this case,
936 +   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
937 +   CC="$am_aux_dir/compile $CC"
938 +fi
939 +dnl Make sure AC_PROG_CC is never called again, or it will override our
940 +dnl setting of CC.
941 +m4_define([AC_PROG_CC],
942 +          [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])])
943 +])
944 diff --git a/mech_eap.spec.in b/mech_eap.spec.in
945 new file mode 100644
946 index 0000000..90ac6cf
947 --- /dev/null
948 +++ b/mech_eap.spec.in
949 @@ -0,0 +1,62 @@
950 +%global _moonshot_krb5 %{!?_moonshot_krb5:krb5-devel}%{?_moonshot_krb5}
951 +Name:          moonshot-gss-eap
952 +Version:       @VERSION@
953 +Release:       3%{?dist}
954 +Summary:       Moonshot GSS-API Mechanism
955 +
956 +Group:         Security Tools
957 +License:       BSD
958 +URL:           http://www.project-moonshot.org/
959 +Source0:       mech_eap-%{version}.tar.gz
960 +BuildRoot:     %{_tmppath}/%{name}-%{version}-%{release}-root
961 +
962 +BuildRequires:  %{_moonshot_krb5} >= 1.9.1
963 +BuildRequires:  moonshot-ui-devel
964 +BuildRequires: jansson-devel
965 +Requires:      moonshot-ui
966 +BuildRequires: libradsec-devel
967 +BuildRequires: shibboleth-devel >= 2.5
968 +BuildRequires: libshibresolver-devel
969 +
970 +
971 +
972 +%description
973 +Project Moonshot provides federated access management.
974 +
975 +
976 +%prep
977 +%setup -q -n mech_eap-%{version}
978 +
979 +
980 +%build
981 +       export LDFLAGS='-L/usr/%{_lib}/freeradius -Wl,--rpath=/usr/%{_lib}/freeradius'
982 +%configure  --with-libmoonshot=%{_prefix} --with-krb5=%{_prefix} --disable-reauth
983 +make %{?_smp_mflags}
984 +
985 +
986 +%install
987 +rm -rf $RPM_BUILD_ROOT
988 +make install DESTDIR=$RPM_BUILD_ROOT
989 +
990 +
991 +%clean
992 +rm -rf $RPM_BUILD_ROOT
993 +
994 +
995 +%files
996 +%defattr(-,root,root,-)
997 +%doc mech_eap/README
998 +%doc mech_eap/LICENSE
999 +%doc mech_eap/AUTHORS
1000 +%{_libdir}/gss/mech_eap.so
1001 +%exclude %{_libdir}/gss/mech_eap.la
1002 +%{_includedir}/gssapi/*.h
1003 +#%exclude %{_libdir}/krb5/plugins/authdata/*la
1004 +#%{_libdir}/krb5/plugins/authdata/*.so
1005 +
1006 +
1007 +
1008 +%changelog
1009 +* Wed Sep 28 2011  <hartmans@moonbuildcentos.dev.ja.net> - @VERSION@-2
1010 +- Add radius_ad plugin
1011 +
1012 diff --git a/mech_eap/.gitignore b/mech_eap/.gitignore
1013 new file mode 100644
1014 index 0000000..06a3924
1015 --- /dev/null
1016 +++ b/mech_eap/.gitignore
1017 @@ -0,0 +1,32 @@
1018 +/aclocal.m4
1019 +/autom4te.cache
1020 +/compile
1021 +/config.guess
1022 +/config.log
1023 +/config.status
1024 +/config.sub
1025 +/config.h
1026 +/configure
1027 +/config.h.in
1028 +/depcomp
1029 +
1030 +/libtool
1031 +/ltmain.sh
1032 +/missing
1033 +
1034 +/gsseap_err.[ch]
1035 +/radsec_err.[ch]
1036 +
1037 +.DS_Store
1038 +
1039 +Makefile.in
1040 +Makefile
1041 +
1042 +*.la
1043 +*.lo
1044 +*~
1045 +
1046 +.deps
1047 +.libs
1048 +.a.out.dSYM
1049 +.dSYM
1050 diff --git a/mech_eap/AUTHORS b/mech_eap/AUTHORS
1051 new file mode 100644
1052 index 0000000..3007a4b
1053 --- /dev/null
1054 +++ b/mech_eap/AUTHORS
1055 @@ -0,0 +1,6 @@
1056 +The initial implementation of mech_eap was written by PADL Software
1057 +under contract to JANET(UK).
1058 +
1059 +--
1060 +Luke Howard <lukeh@padl.com>
1061 +January, 2011
1062 diff --git a/mech_eap/COPYING b/mech_eap/COPYING
1063 new file mode 100644
1064 index 0000000..7554e77
1065 --- /dev/null
1066 +++ b/mech_eap/COPYING
1067 @@ -0,0 +1,3 @@
1068 +Copyright (c) 2011, JANET(UK)
1069 +
1070 +See the LICENSE file for licensing terms.
1071 diff --git a/mech_eap/LICENSE b/mech_eap/LICENSE
1072 new file mode 100644
1073 index 0000000..1b03a95
1074 --- /dev/null
1075 +++ b/mech_eap/LICENSE
1076 @@ -0,0 +1,31 @@
1077 +/*
1078 + * Copyright (c) 2011, JANET(UK)
1079 + * All rights reserved.
1080 + *
1081 + * Redistribution and use in source and binary forms, with or without
1082 + * modification, are permitted provided that the following conditions
1083 + * are met:
1084 + *
1085 + * 1. Redistributions of source code must retain the above copyright
1086 + *    notice, this list of conditions and the following disclaimer.
1087 + *
1088 + * 2. Redistributions in binary form must reproduce the above copyright
1089 + *    notice, this list of conditions and the following disclaimer in the
1090 + *    documentation and/or other materials provided with the distribution.
1091 + *
1092 + * 3. Neither the name of JANET(UK) nor the names of its contributors
1093 + *    may be used to endorse or promote products derived from this software
1094 + *    without specific prior written permission.
1095 + *
1096 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1097 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1098 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1099 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
1100 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1101 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1102 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1103 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1104 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1105 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1106 + * SUCH DAMAGE.
1107 + */
1108 diff --git a/mech_eap/Makefile.am b/mech_eap/Makefile.am
1109 new file mode 100644
1110 index 0000000..23de6af
1111 --- /dev/null
1112 +++ b/mech_eap/Makefile.am
1113 @@ -0,0 +1,189 @@
1114 +AUTOMAKE_OPTIONS = foreign
1115 +
1116 +EXTRA_DIST = gsseap_err.et radsec_err.et \
1117 +       mech_eap.exports mech_eap-noacceptor.exports  radius_ad.exports \
1118 +       LICENSE AUTHORS
1119 +
1120 +
1121 +gssincludedir = $(includedir)/gssapi
1122 +gssinclude_HEADERS = gssapi_eap.h
1123 +
1124 +EAP_CFLAGS = -I$(srcdir)/../libeap/src -I$(srcdir)/../libeap/src/common -I$(srcdir)/../libeap/src/eap_common  \
1125 +       -I$(srcdir)/../libeap/src/utils
1126 +
1127 +if GSSEAP_ENABLE_ACCEPTOR
1128 +GSSEAP_EXPORTS = mech_eap.exports
1129 +else
1130 +GSSEAP_EXPORTS = mech_eap-noacceptor.exports
1131 +endif
1132 +
1133 +gssdir = $(libdir)/gss
1134 +gss_LTLIBRARIES = mech_eap.la
1135 +
1136 +if TARGET_WINDOWS
1137 +EAP_CFLAGS += -DCONFIG_WIN32_DEFAULTS -DUSE_INTERNAL_CRYPTO
1138 +OS_LIBS = -lshell32 -ladvapi32 -lws2_32 -lcomerr32
1139 +mech_eap_la_CFLAGS   = -Zi
1140 +mech_eap_la_CXXFLAGS = -Zi
1141 +else
1142 +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
1143 +OS_LIBS =
1144 +mech_eap_la_CFLAGS   = -Werror -Wall -Wunused-parameter
1145 +mech_eap_la_CXXFLAGS = -Werror -Wall -Wunused-parameter
1146 +endif
1147 +mech_eap_la_DEPENDENCIES = $(GSSEAP_EXPORTS)
1148 +
1149 +mech_eap_la_CPPFLAGS = -DBUILD_GSSEAP_LIB -DSYSCONFDIR=\"${sysconfdir}\" -DDATAROOTDIR=\"${datarootdir}\"
1150 +mech_eap_la_CFLAGS   += \
1151 +                       @KRB5_CFLAGS@ @RADSEC_CFLAGS@ @TARGET_CFLAGS@ $(EAP_CFLAGS)
1152 +mech_eap_la_CXXFLAGS += \
1153 +                       @KRB5_CFLAGS@ @RADSEC_CFLAGS@ \
1154 +                       @OPENSAML_CXXFLAGS@ @SHIBRESOLVER_CXXFLAGS@ @SHIBSP_CXXFLAGS@ \
1155 +                       @TARGET_CFLAGS@ $(EAP_CFLAGS)
1156 +mech_eap_la_LDFLAGS  = -avoid-version -module \
1157 +                       -export-symbols $(GSSEAP_EXPORTS) -no-undefined \
1158 +                       @KRB5_LDFLAGS@ @RADSEC_LDFLAGS@ @TARGET_LDFLAGS@
1159 +if TARGET_WINDOWS
1160 +mech_eap_la_LDFLAGS += -debug
1161 +endif
1162 +
1163 +mech_eap_la_LIBADD   = @KRB5_LIBS@ ../libeap/libeap.la @RADSEC_LIBS@ \
1164 +                      @OPENSAML_LIBS@ @SHIBRESOLVER_LIBS@ @SHIBSP_LIBS@ @JANSSON_LIBS@
1165 +mech_eap_la_SOURCES =                          \
1166 +       acquire_cred.c                          \
1167 +       acquire_cred_with_password.c            \
1168 +       add_cred.c                              \
1169 +       add_cred_with_password.c                \
1170 +       authorize_localname.c                   \
1171 +       canonicalize_name.c                     \
1172 +       compare_name.c                          \
1173 +       context_time.c                          \
1174 +       delete_sec_context.c                    \
1175 +       display_name.c                          \
1176 +       display_name_ext.c                      \
1177 +       display_status.c                        \
1178 +       duplicate_name.c                        \
1179 +       eap_mech.c                              \
1180 +       exchange_meta_data.c                    \
1181 +       export_name.c                           \
1182 +       export_sec_context.c                    \
1183 +       get_mic.c                               \
1184 +       gsseap_err.c                            \
1185 +       import_name.c                           \
1186 +       import_sec_context.c                    \
1187 +       indicate_mechs.c                        \
1188 +       init_sec_context.c                      \
1189 +       inquire_attrs_for_mech.c                \
1190 +       inquire_context.c                       \
1191 +       inquire_cred.c                          \
1192 +       inquire_cred_by_mech.c                  \
1193 +       inquire_cred_by_oid.c                   \
1194 +       inquire_mech_for_saslname.c             \
1195 +       inquire_mechs_for_name.c                \
1196 +       inquire_names_for_mech.c                \
1197 +       inquire_saslname_for_mech.c             \
1198 +       inquire_sec_context_by_oid.c            \
1199 +       process_context_token.c                 \
1200 +       pseudo_random.c                         \
1201 +       query_mechanism_info.c                  \
1202 +       query_meta_data.c                       \
1203 +       radsec_err.c                            \
1204 +       release_cred.c                          \
1205 +       release_name.c                          \
1206 +       release_oid.c                           \
1207 +       set_cred_option.c                       \
1208 +       set_sec_context_option.c                \
1209 +       store_cred.c                            \
1210 +       unwrap.c                                \
1211 +       unwrap_iov.c                            \
1212 +       util_buffer.c                           \
1213 +       util_context.c                          \
1214 +       util_cksum.c                            \
1215 +       util_cred.c                             \
1216 +       util_crypt.c                            \
1217 +       util_krb.c                              \
1218 +       util_lucid.c                            \
1219 +       util_mech.c                             \
1220 +       util_name.c                             \
1221 +       util_oid.c                              \
1222 +       util_ordering.c                         \
1223 +       util_sm.c                               \
1224 +       util_tld.c                              \
1225 +       util_token.c                            \
1226 +       verify_mic.c                            \
1227 +       wrap.c                                  \
1228 +       wrap_iov.c                              \
1229 +       wrap_iov_length.c                       \
1230 +       wrap_size_limit.c \
1231 +       gssapiP_eap.h \
1232 +       util_attr.h \
1233 +       util_base64.h \
1234 +       util.h \
1235 +       util_json.h \
1236 +       util_radius.h \
1237 +       util_reauth.h \
1238 +       util_saml.h \
1239 +       util_shib.h
1240 +
1241 +if LIBMOONSHOT
1242 +mech_eap_la_SOURCES += util_moonshot.c
1243 +mech_eap_la_CFLAGS  += @LIBMOONSHOT_CFLAGS@
1244 +mech_eap_la_LDFLAGS += @LIBMOONSHOT_LDFLAGS@
1245 +mech_eap_la_LIBADD  += @LIBMOONSHOT_LIBS@
1246 +endif
1247 +
1248 +
1249 +if GSSEAP_ENABLE_ACCEPTOR
1250 +
1251 +mech_eap_la_SOURCES +=                         \
1252 +       accept_sec_context.c                    \
1253 +       delete_name_attribute.c                 \
1254 +       export_name_composite.c                 \
1255 +       get_name_attribute.c                    \
1256 +       inquire_name.c                          \
1257 +       map_name_to_any.c                       \
1258 +       release_any_name_mapping.c              \
1259 +       set_name_attribute.c                    \
1260 +       util_attr.cpp                           \
1261 +       util_base64.c                           \
1262 +       util_json.cpp                           \
1263 +       util_radius.cpp
1264 +
1265 +if OPENSAML
1266 +mech_eap_la_SOURCES += util_saml.cpp
1267 +endif
1268 +
1269 +if SHIBRESOLVER
1270 +mech_eap_la_SOURCES += util_shib.cpp
1271 +endif
1272 +
1273 +endif
1274 +
1275 +BUILT_SOURCES = gsseap_err.c radsec_err.c gsseap_err.h radsec_err.h
1276 +
1277 +if GSSEAP_ENABLE_REAUTH
1278 +mech_eap_la_SOURCES += util_reauth.c
1279 +
1280 +if !HEIMDAL
1281 +krb5pluginsdir = $(libdir)/krb5/plugins/authdata
1282 +krb5plugins_LTLIBRARIES = radius_ad.la
1283 +
1284 +radius_ad_la_CFLAGS  = -Werror -Wall -Wunused-parameter \
1285 +                       @KRB5_CFLAGS@ $(EAP_CFLAGS) @RADSEC_CFLAGS@ @TARGET_CFLAGS@
1286 +radius_ad_la_LDFLAGS = -avoid-version -module \
1287 +                      -export-symbols radius_ad.exports -no-undefined
1288 +radius_ad_la_LIBADD  = @KRB5_LIBS@
1289 +radius_ad_la_SOURCES = util_adshim.c authdata_plugin.h
1290 +endif
1291 +endif
1292 +
1293 +gsseap_err.h gsseap_err.c: gsseap_err.et
1294 +       $(COMPILE_ET) $<
1295 +
1296 +radsec_err.h radsec_err.c: radsec_err.et
1297 +       $(COMPILE_ET) $<
1298 +
1299 +radsec_err.c: radsec_err.h
1300 +
1301 +clean-generic:
1302 +       rm -f gsseap_err.[ch] radsec_err.[ch]
1303 diff --git a/mech_eap/NEWS b/mech_eap/NEWS
1304 new file mode 100644
1305 index 0000000..e69de29
1306 diff --git a/mech_eap/NOTES b/mech_eap/NOTES
1307 new file mode 100644
1308 index 0000000..849ce4e
1309 --- /dev/null
1310 +++ b/mech_eap/NOTES
1311 @@ -0,0 +1,9 @@
1312 +- gss_xxx routines acquire lock, gssXxx don't
1313 +
1314 +- git
1315 +
1316 +If you do want to update with a rebase, deletethe branch from the
1317 +server first then push the rebased branch
1318 +
1319 +to delete a branch from a server git push origin :branch_to_del
1320 +
1321 diff --git a/mech_eap/README b/mech_eap/README
1322 new file mode 100644
1323 index 0000000..3cb2d50
1324 --- /dev/null
1325 +++ b/mech_eap/README
1326 @@ -0,0 +1,147 @@
1327 +Overview
1328 +========
1329 +
1330 +This is an implementation of the GSS EAP mechanism, as described in
1331 +draft-ietf-abfab-gss-eap-01.txt.
1332 +
1333 +Building
1334 +========
1335 +
1336 +In order to build this, a recent Kerberos implementation (MIT or
1337 +Heimdal), Shibboleth, and EAP libraries are required, along with
1338 +all of their dependencies.
1339 +
1340 +Note: not all SPIs are supported by the Heimdal mechanism glue,
1341 +so not all features will be available.
1342 +
1343 +Installing
1344 +==========
1345 +
1346 +GSS mechglue
1347 +------------
1348 +
1349 +When installing, be sure to edit $prefix/etc/gss/mech to register
1350 +the EAP mechanisms. A sample configuration file is in this directory.
1351 +You may need to specify an absolute path.
1352 +
1353 +RADIUS client library
1354 +---------------------
1355 +
1356 +Make sure your RADIUS library is configured to talk to the server of
1357 +your choice: see the example radsec.conf in this directory. If you
1358 +want to use TCP or TLS, you'll need to run radsecproxy in front of
1359 +your RADIUS server.
1360 +
1361 +RADIUS server
1362 +-------------
1363 +
1364 +These instructions apply to FreeRADIUS only, which is downloadable
1365 +from http://freeradius.org/. After configure, make, install, do the
1366 +following:
1367 +
1368 +On the RADIUS server side, you need to install dictionary.ukerna to
1369 +$prefix/etc/raddb and include it from the main dictionary file, by
1370 +adding:
1371 +
1372 +    $INCLUDE dictionary.ukerna
1373 +
1374 +to $prefix/etc/raddb/dictionary. Make sure these files are world-
1375 +readable; they weren't in my installation.
1376 +
1377 +Edit $prefix/etc/raddb/users to add your test user and password:
1378 +
1379 +    bob@PROJECT-MOONSHOT.ORG Cleartext-Password := secret
1380 +
1381 +Add an entry for your acceptor to $prefix/etc/raddb/clients.conf:
1382 +
1383 +    client somehost {
1384 +        ipaddr = 127.0.0.1
1385 +        secret = testing123
1386 +        require_message_authenticator = yes
1387 +    }
1388 +
1389 +Edit $prefix/etc/raddb/eap.conf and set:
1390 +
1391 +    eap {
1392 +...
1393 +        default_eap_type = ttls
1394 +...
1395 +        tls {
1396 +            certdir = ...
1397 +            cadir = ...
1398 +            private_key_file = ...
1399 +            certificate_file = ...
1400 +        }
1401 +        ttls {
1402 +            default_eap_type = mschapv2
1403 +            copy_request_to_tunnel = no
1404 +            use_tunneled_reply = no
1405 +            virtual_server = "inner-tunnel"
1406 +        }
1407 +...
1408 +    }
1409 +
1410 +to enable EAP-TTLS.
1411 +
1412 +If you want the acceptor be able to identify the user, the RADIUS
1413 +server needs to echo back the EAP username from the inner tunnel;
1414 +for privacy, mech_eap only sends the realm in the EAP Identity
1415 +response. To configure this with FreeRADIUS, add:
1416 +
1417 +    update outer.reply {
1418 +        User-Name = "%{request:User-Name}"
1419 +    }
1420 +
1421 +If you want to add a SAML assertion, do this with "update reply"
1422 +in $prefix/etc/raddb/sites-available/default:
1423 +
1424 +    update reply {
1425 +        SAML-AAA-Assertion = '<saml:Assertion ...'
1426 +        SAML-AAA-Assertion += '...'
1427 +    }
1428 +
1429 +You'll need to split it into multiple lines because of the RADIUS
1430 +attribute size limit.
1431 +
1432 +Testing
1433 +=======
1434 +
1435 +You can then test the MIT or Cyrus GSS and SASL example programs.
1436 +Sample usage is given below. Substitute <user>, <pass> and <host>
1437 +appropriately (<host> is the name of the host running the server,
1438 +not the RADIUS server).
1439 +
1440 +% gss-client -port 5555 -spnego -mech "{1 3 6 1 4 1 5322 22 1 18}" \
1441 +  -user <user>@<realm> -pass <pass> <host> host@<host> \
1442 +  "Testing GSS EAP"
1443 +% gss-server -port 5555 -export host@<host>
1444 +
1445 +Note: for SASL you will be prompted for a username and password.
1446 +
1447 +% client -C -p 5556 -s host -m EAP-AES128 <host>
1448 +% server -c -p 5556 -s host -h <host>
1449 +
1450 +To test fast reauthentication support, add the following to
1451 +/etc/krb5.conf:
1452 +
1453 +[appdefaults]
1454 +        eap_gss = {
1455 +                reauth_use_ccache = TRUE
1456 +        }
1457 +
1458 +This will store a Kerberos ticket for a GSS-EAP authenticated user
1459 +in a credentials cache, which can then be used for re-authentication
1460 +to the same acceptor. You must have a valid keytab configured.
1461 +
1462 +In this testing phase of Moonshot, it's also possible to store a
1463 +default identity and credential in a file. The format consists of
1464 +the string representation of the initiator identity and the password,
1465 +separated by newlines. The default location of this file is
1466 +.gss_eap_id in the user's home directory, however the GSSEAP_IDENTITY
1467 +environment variable can be used to set an alternate location.
1468 +
1469 +You can also set a default realm in [appdefaults]; the Kerberos
1470 +default realm is never used by mech_eap (or at least, that is the
1471 +intention), so if unspecified you must always qualify names. It should
1472 +generally not be necessary to specify this.
1473 +
1474 diff --git a/mech_eap/README.samba4 b/mech_eap/README.samba4
1475 new file mode 100644
1476 index 0000000..d0a94d1
1477 --- /dev/null
1478 +++ b/mech_eap/README.samba4
1479 @@ -0,0 +1,52 @@
1480 +Notes on using Moonshot with Samba4. Replace paths as appropriate.
1481 +
1482 +Samba
1483 +-----
1484 +
1485 +* Download Samba4 and apply patches for mechanism agnosticism which are
1486 +  available at http://www.padl.com/~lukeh/samba/
1487 +* Join Samba as a member server or domain controller (only tested former)
1488 +* Extract local service principal key to keytab (currently there do not
1489 +  appear to be tools to do this, but you can get the cleartext password
1490 +  from /usr/local/samba/private/secrets.ldb)
1491 +
1492 +Shibboleth
1493 +----------
1494 +
1495 +* Add a mapping from the PAC RADIUS attribute to urn:mspac: in the file
1496 +  /usr/local/etc/shibboleth/attribute-map.xml:
1497 +
1498 +  <GSSAPIAttribute name="urn:ietf:params:gss-eap:radius-avp urn:x-radius:1679163525"
1499 +                   id="urn:mspac:" binary="true"/>
1500 +
1501 +FreeRADIUS
1502 +----------
1503 +
1504 +Install the rlm_mspac module and configure per below.
1505 +
1506 +* Install dictionary.ukerna so MS-Windows-Auth-Data is defined
1507 +* Create /usr/local/etc/raddb/modules/mspac with the following:
1508 +
1509 +    mspac {
1510 +        keytab = /etc/krb5.keytab
1511 +        spn = host/host.fqdn@KERBEROS.REALM
1512 +    }       
1513 +
1514 +* Add mspac to instantiate stanza in radiusd.conf
1515 +* Add mspac to post-auth stanza in sites-enabled/inner-tunnel
1516 +
1517 +You will need to have a TGT for the host service principal before starting
1518 +radiusd. It's easiest to do this with kinit -k.
1519 +
1520 +Testing
1521 +-------
1522 +
1523 +The Samba server doesn't require any specific command line arguments, although
1524 +on OS X it was necessary to start it with -M single to function under gdb.
1525 +
1526 +For the client, the GSS EAP mechanism can be specified on the command line:
1527 +
1528 +smbclient --password samba --mechanism 1.3.6.1.4.1.5322.22.1.18 '\\host\share'".
1529 +
1530 +There is no Moonshot SSPI implementation as yet, so it is not possible to test
1531 +with a Windows client.
1532 diff --git a/mech_eap/TODO b/mech_eap/TODO
1533 new file mode 100644
1534 index 0000000..0111459
1535 --- /dev/null
1536 +++ b/mech_eap/TODO
1537 @@ -0,0 +1,6 @@
1538 +- integration with initiator-side EAP channel bindings
1539 +- investigate initiator-side credential locking
1540 +- always intern OIDs so they never need to be freed
1541 +- handle many-to-many Shibboleth attribute mappings; need to encode both attribute and value index into more
1542 +- add --with-xerces option
1543 +- proper acquire_cred_ext implementation pending specification
1544 diff --git a/mech_eap/accept_sec_context.c b/mech_eap/accept_sec_context.c
1545 new file mode 100644
1546 index 0000000..b089bae
1547 --- /dev/null
1548 +++ b/mech_eap/accept_sec_context.c
1549 @@ -0,0 +1,1072 @@
1550 +/*
1551 + * Copyright (c) 2011, JANET(UK)
1552 + * All rights reserved.
1553 + *
1554 + * Redistribution and use in source and binary forms, with or without
1555 + * modification, are permitted provided that the following conditions
1556 + * are met:
1557 + *
1558 + * 1. Redistributions of source code must retain the above copyright
1559 + *    notice, this list of conditions and the following disclaimer.
1560 + *
1561 + * 2. Redistributions in binary form must reproduce the above copyright
1562 + *    notice, this list of conditions and the following disclaimer in the
1563 + *    documentation and/or other materials provided with the distribution.
1564 + *
1565 + * 3. Neither the name of JANET(UK) nor the names of its contributors
1566 + *    may be used to endorse or promote products derived from this software
1567 + *    without specific prior written permission.
1568 + *
1569 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1570 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1571 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1572 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
1573 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1574 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1575 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1576 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1577 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1578 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1579 + * SUCH DAMAGE.
1580 + */
1581 +
1582 +/*
1583 + * Establish a security context on the acceptor (server). These functions
1584 + * wrap around libradsec and (thus) talk to a RADIUS server or proxy.
1585 + */
1586 +
1587 +#include "gssapiP_eap.h"
1588 +
1589 +#ifdef GSSEAP_ENABLE_REAUTH
1590 +static OM_uint32
1591 +eapGssSmAcceptGssReauth(OM_uint32 *minor,
1592 +                        gss_cred_id_t cred,
1593 +                        gss_ctx_id_t ctx,
1594 +                        gss_name_t target,
1595 +                        gss_OID mech,
1596 +                        OM_uint32 reqFlags,
1597 +                        OM_uint32 timeReq,
1598 +                        gss_channel_bindings_t chanBindings,
1599 +                        gss_buffer_t inputToken,
1600 +                        gss_buffer_t outputToken,
1601 +                        OM_uint32 *smFlags);
1602 +#endif
1603 +
1604 +/*
1605 + * Mark an acceptor context as ready for cryptographic operations
1606 + */
1607 +static OM_uint32
1608 +acceptReadyEap(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred)
1609 +{
1610 +    OM_uint32 major, tmpMinor;
1611 +    VALUE_PAIR *vp;
1612 +    gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
1613 +
1614 +    /* Cache encryption type derived from selected mechanism OID */
1615 +    major = gssEapOidToEnctype(minor, ctx->mechanismUsed,
1616 +                               &ctx->encryptionType);
1617 +    if (GSS_ERROR(major))
1618 +        return major;
1619 +
1620 +    gssEapReleaseName(&tmpMinor, &ctx->initiatorName);
1621 +
1622 +    major = gssEapRadiusGetRawAvp(minor, ctx->acceptorCtx.vps,
1623 +                                  PW_USER_NAME, 0, &vp);
1624 +    if (major == GSS_S_COMPLETE && vp->length) {
1625 +        nameBuf.length = vp->length;
1626 +        nameBuf.value = vp->vp_strvalue;
1627 +    } else {
1628 +        ctx->gssFlags |= GSS_C_ANON_FLAG;
1629 +    }
1630 +
1631 +    major = gssEapImportName(minor, &nameBuf,
1632 +                             (ctx->gssFlags & GSS_C_ANON_FLAG) ?
1633 +                                GSS_C_NT_ANONYMOUS : GSS_C_NT_USER_NAME,
1634 +                             ctx->mechanismUsed,
1635 +                             &ctx->initiatorName);
1636 +    if (GSS_ERROR(major))
1637 +        return major;
1638 +
1639 +    major = gssEapRadiusGetRawAvp(minor, ctx->acceptorCtx.vps,
1640 +                                  PW_MS_MPPE_SEND_KEY, VENDORPEC_MS, &vp);
1641 +    if (GSS_ERROR(major)) {
1642 +        *minor = GSSEAP_KEY_UNAVAILABLE;
1643 +        return GSS_S_UNAVAILABLE;
1644 +    }
1645 +
1646 +    major = gssEapDeriveRfc3961Key(minor,
1647 +                                   vp->vp_octets,
1648 +                                   vp->length,
1649 +                                   ctx->encryptionType,
1650 +                                   &ctx->rfc3961Key);
1651 +    if (GSS_ERROR(major))
1652 +        return major;
1653 +
1654 +    major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
1655 +                                       &ctx->checksumType);
1656 +    if (GSS_ERROR(major))
1657 +        return major;
1658 +
1659 +    major = sequenceInit(minor,
1660 +                         &ctx->seqState, ctx->recvSeq,
1661 +                         ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0),
1662 +                         ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0),
1663 +                         TRUE);
1664 +    if (GSS_ERROR(major))
1665 +        return major;
1666 +
1667 +    major = gssEapCreateAttrContext(minor, cred, ctx,
1668 +                                    &ctx->initiatorName->attrCtx,
1669 +                                    &ctx->expiryTime);
1670 +    if (GSS_ERROR(major))
1671 +        return major;
1672 +
1673 +    if (ctx->expiryTime != 0 && ctx->expiryTime < time(NULL)) {
1674 +        *minor = GSSEAP_CRED_EXPIRED;
1675 +        return GSS_S_CREDENTIALS_EXPIRED;
1676 +    }
1677 +
1678 +    *minor = 0;
1679 +    return GSS_S_COMPLETE;
1680 +}
1681 +
1682 +static OM_uint32
1683 +eapGssSmAcceptAcceptorName(OM_uint32 *minor,
1684 +                           gss_cred_id_t cred GSSEAP_UNUSED,
1685 +                           gss_ctx_id_t ctx,
1686 +                           gss_name_t target GSSEAP_UNUSED,
1687 +                           gss_OID mech GSSEAP_UNUSED,
1688 +                           OM_uint32 reqFlags GSSEAP_UNUSED,
1689 +                           OM_uint32 timeReq GSSEAP_UNUSED,
1690 +                           gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
1691 +                           gss_buffer_t inputToken GSSEAP_UNUSED,
1692 +                           gss_buffer_t outputToken,
1693 +                           OM_uint32 *smFlags GSSEAP_UNUSED)
1694 +{
1695 +    OM_uint32 major;
1696 +
1697 +    /* XXX TODO import and validate name from inputToken */
1698 +
1699 +    if (ctx->acceptorName != GSS_C_NO_NAME) {
1700 +        /* Send desired target name to acceptor */
1701 +        major = gssEapDisplayName(minor, ctx->acceptorName,
1702 +                                  outputToken, NULL);
1703 +        if (GSS_ERROR(major))
1704 +            return major;
1705 +    }
1706 +
1707 +    return GSS_S_CONTINUE_NEEDED;
1708 +}
1709 +
1710 +#ifdef GSSEAP_DEBUG
1711 +static OM_uint32
1712 +eapGssSmAcceptVendorInfo(OM_uint32 *minor,
1713 +                         gss_cred_id_t cred GSSEAP_UNUSED,
1714 +                         gss_ctx_id_t ctx GSSEAP_UNUSED,
1715 +                         gss_name_t target GSSEAP_UNUSED,
1716 +                         gss_OID mech GSSEAP_UNUSED,
1717 +                         OM_uint32 reqFlags GSSEAP_UNUSED,
1718 +                         OM_uint32 timeReq GSSEAP_UNUSED,
1719 +                         gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
1720 +                         gss_buffer_t inputToken,
1721 +                         gss_buffer_t outputToken GSSEAP_UNUSED,
1722 +                         OM_uint32 *smFlags GSSEAP_UNUSED)
1723 +{
1724 +    fprintf(stderr, "GSS-EAP: vendor: %.*s\n",
1725 +            (int)inputToken->length, (char *)inputToken->value);
1726 +
1727 +    *minor = 0;
1728 +    return GSS_S_CONTINUE_NEEDED;
1729 +}
1730 +#endif
1731 +
1732 +
1733 +/*
1734 + * Emit a identity EAP request to force the initiator (peer) to identify
1735 + * itself.
1736 + */
1737 +static OM_uint32
1738 +eapGssSmAcceptIdentity(OM_uint32 *minor,
1739 +                       gss_cred_id_t cred,
1740 +                       gss_ctx_id_t ctx,
1741 +                       gss_name_t target GSSEAP_UNUSED,
1742 +                       gss_OID mech GSSEAP_UNUSED,
1743 +                       OM_uint32 reqFlags GSSEAP_UNUSED,
1744 +                       OM_uint32 timeReq GSSEAP_UNUSED,
1745 +                       gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
1746 +                       gss_buffer_t inputToken,
1747 +                       gss_buffer_t outputToken,
1748 +                       OM_uint32 *smFlags)
1749 +{
1750 +    OM_uint32 major;
1751 +    struct wpabuf *reqData;
1752 +    gss_buffer_desc pktBuffer;
1753 +
1754 +    if (!gssEapCredAvailable(cred, ctx->mechanismUsed)) {
1755 +        *minor = GSSEAP_CRED_MECH_MISMATCH;
1756 +        return GSS_S_BAD_MECH;
1757 +    }
1758 +
1759 +    if (inputToken != GSS_C_NO_BUFFER && inputToken->length != 0) {
1760 +        *minor = GSSEAP_WRONG_SIZE;
1761 +        return GSS_S_DEFECTIVE_TOKEN;
1762 +    }
1763 +
1764 +    reqData = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, 0,
1765 +                            EAP_CODE_REQUEST, 0);
1766 +    if (reqData == NULL) {
1767 +        *minor = ENOMEM;
1768 +        return GSS_S_FAILURE;
1769 +    }
1770 +
1771 +    pktBuffer.length = wpabuf_len(reqData);
1772 +    pktBuffer.value = (void *)wpabuf_head(reqData);
1773 +
1774 +    major = duplicateBuffer(minor, &pktBuffer, outputToken);
1775 +    if (GSS_ERROR(major))
1776 +        return major;
1777 +
1778 +    wpabuf_free(reqData);
1779 +
1780 +    GSSEAP_SM_TRANSITION_NEXT(ctx);
1781 +
1782 +    *minor = 0;
1783 +    *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
1784 +
1785 +    return GSS_S_CONTINUE_NEEDED;
1786 +}
1787 +
1788 +/*
1789 + * Returns TRUE if the input token contains an EAP identity response.
1790 + */
1791 +static int
1792 +isIdentityResponseP(gss_buffer_t inputToken)
1793 +{
1794 +    struct wpabuf respData;
1795 +
1796 +    wpabuf_set(&respData, inputToken->value, inputToken->length);
1797 +
1798 +    return (eap_get_type(&respData) == EAP_TYPE_IDENTITY);
1799 +}
1800 +
1801 +/*
1802 + * Save the asserted initiator identity from the EAP identity response.
1803 + */
1804 +static OM_uint32
1805 +importInitiatorIdentity(OM_uint32 *minor,
1806 +                        gss_ctx_id_t ctx,
1807 +                        gss_buffer_t inputToken)
1808 +{
1809 +    OM_uint32 tmpMinor;
1810 +    struct wpabuf respData;
1811 +    const unsigned char *pos;
1812 +    size_t len;
1813 +    gss_buffer_desc nameBuf;
1814 +
1815 +    wpabuf_set(&respData, inputToken->value, inputToken->length);
1816 +
1817 +    pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
1818 +                           &respData, &len);
1819 +    if (pos == NULL) {
1820 +        *minor = GSSEAP_PEER_BAD_MESSAGE;
1821 +        return GSS_S_DEFECTIVE_TOKEN;
1822 +    }
1823 +
1824 +    nameBuf.value = (void *)pos;
1825 +    nameBuf.length = len;
1826 +
1827 +    gssEapReleaseName(&tmpMinor, &ctx->initiatorName);
1828 +
1829 +    return gssEapImportName(minor, &nameBuf, GSS_C_NT_USER_NAME,
1830 +                            ctx->mechanismUsed, &ctx->initiatorName);
1831 +}
1832 +
1833 +/*
1834 + * Pass the asserted initiator identity to the authentication server.
1835 + */
1836 +static OM_uint32
1837 +setInitiatorIdentity(OM_uint32 *minor,
1838 +                     gss_ctx_id_t ctx,
1839 +                     VALUE_PAIR **vps)
1840 +{
1841 +    OM_uint32 major, tmpMinor;
1842 +    gss_buffer_desc nameBuf;
1843 +
1844 +    /*
1845 +     * We should have got an EAP identity response, but if we didn't, then
1846 +     * we will just avoid sending User-Name. Note that radsecproxy requires
1847 +     * User-Name to be sent on every request (presumably so it can remain
1848 +     * stateless).
1849 +     */
1850 +    if (ctx->initiatorName != GSS_C_NO_NAME) {
1851 +        major = gssEapDisplayName(minor, ctx->initiatorName, &nameBuf, NULL);
1852 +        if (GSS_ERROR(major))
1853 +            return major;
1854 +
1855 +        major = gssEapRadiusAddAvp(minor, vps, PW_USER_NAME, 0, &nameBuf);
1856 +        if (GSS_ERROR(major))
1857 +            return major;
1858 +
1859 +        gss_release_buffer(&tmpMinor, &nameBuf);
1860 +    }
1861 +
1862 +    *minor = 0;
1863 +    return GSS_S_COMPLETE;
1864 +}
1865 +
1866 +/*
1867 + * Pass the asserted acceptor identity to the authentication server.
1868 + */
1869 +static OM_uint32
1870 +setAcceptorIdentity(OM_uint32 *minor,
1871 +                    gss_ctx_id_t ctx,
1872 +                    VALUE_PAIR **vps)
1873 +{
1874 +    OM_uint32 major;
1875 +    gss_buffer_desc nameBuf;
1876 +    krb5_context krbContext = NULL;
1877 +    krb5_principal krbPrinc;
1878 +    struct rs_context *rc = ctx->acceptorCtx.radContext;
1879 +
1880 +    GSSEAP_ASSERT(rc != NULL);
1881 +
1882 +    if (ctx->acceptorName == GSS_C_NO_NAME) {
1883 +        *minor = 0;
1884 +        return GSS_S_COMPLETE;
1885 +    }
1886 +
1887 +    if ((ctx->acceptorName->flags & NAME_FLAG_SERVICE) == 0) {
1888 +        *minor = GSSEAP_BAD_SERVICE_NAME;
1889 +        return GSS_S_BAD_NAME;
1890 +    }
1891 +
1892 +    GSSEAP_KRB_INIT(&krbContext);
1893 +
1894 +    krbPrinc = ctx->acceptorName->krbPrincipal;
1895 +    GSSEAP_ASSERT(krbPrinc != NULL);
1896 +    GSSEAP_ASSERT(KRB_PRINC_LENGTH(krbPrinc) >= 2);
1897 +
1898 +    /* Acceptor-Service-Name */
1899 +    krbPrincComponentToGssBuffer(krbPrinc, 0, &nameBuf);
1900 +
1901 +    major = gssEapRadiusAddAvp(minor, vps,
1902 +                               PW_GSS_ACCEPTOR_SERVICE_NAME,
1903 +                               VENDORPEC_UKERNA,
1904 +                               &nameBuf);
1905 +    if (GSS_ERROR(major))
1906 +        return major;
1907 +
1908 +    /* Acceptor-Host-Name */
1909 +    krbPrincComponentToGssBuffer(krbPrinc, 1, &nameBuf);
1910 +
1911 +    major = gssEapRadiusAddAvp(minor, vps,
1912 +                               PW_GSS_ACCEPTOR_HOST_NAME,
1913 +                               VENDORPEC_UKERNA,
1914 +                               &nameBuf);
1915 +    if (GSS_ERROR(major))
1916 +        return major;
1917 +
1918 +    if (KRB_PRINC_LENGTH(krbPrinc) > 2) {
1919 +        /* Acceptor-Service-Specific */
1920 +        krb5_principal_data ssiPrinc = *krbPrinc;
1921 +        char *ssi;
1922 +
1923 +        KRB_PRINC_LENGTH(&ssiPrinc) -= 2;
1924 +        KRB_PRINC_NAME(&ssiPrinc) += 2;
1925 +
1926 +        *minor = krb5_unparse_name_flags(krbContext, &ssiPrinc,
1927 +                                         KRB5_PRINCIPAL_UNPARSE_NO_REALM, &ssi);
1928 +        if (*minor != 0)
1929 +            return GSS_S_FAILURE;
1930 +
1931 +        nameBuf.value = ssi;
1932 +        nameBuf.length = strlen(ssi);
1933 +
1934 +        major = gssEapRadiusAddAvp(minor, vps,
1935 +                                   PW_GSS_ACCEPTOR_SERVICE_SPECIFIC,
1936 +                                   VENDORPEC_UKERNA,
1937 +                                   &nameBuf);
1938 +
1939 +        if (GSS_ERROR(major)) {
1940 +            krb5_free_unparsed_name(krbContext, ssi);
1941 +            return major;
1942 +        }
1943 +        krb5_free_unparsed_name(krbContext, ssi);
1944 +    }
1945 +
1946 +    krbPrincRealmToGssBuffer(krbPrinc, &nameBuf);
1947 +    if (nameBuf.length != 0) {
1948 +        /* Acceptor-Realm-Name */
1949 +        major = gssEapRadiusAddAvp(minor, vps,
1950 +                                   PW_GSS_ACCEPTOR_REALM_NAME,
1951 +                                   VENDORPEC_UKERNA,
1952 +                                   &nameBuf);
1953 +        if (GSS_ERROR(major))
1954 +            return major;
1955 +    }
1956 +
1957 +    *minor = 0;
1958 +    return GSS_S_COMPLETE;
1959 +}
1960 +
1961 +/*
1962 + * Allocate a RadSec handle
1963 + */
1964 +static OM_uint32
1965 +createRadiusHandle(OM_uint32 *minor,
1966 +                   gss_cred_id_t cred,
1967 +                   gss_ctx_id_t ctx)
1968 +{
1969 +    struct gss_eap_acceptor_ctx *actx = &ctx->acceptorCtx;
1970 +    struct rs_error *err;
1971 +    const char *configStanza = "gss-eap";
1972 +    OM_uint32 major;
1973 +
1974 +    GSSEAP_ASSERT(actx->radContext == NULL);
1975 +    GSSEAP_ASSERT(actx->radConn == NULL);
1976 +    GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL);
1977 +
1978 +    major = gssEapCreateRadiusContext(minor, cred, &actx->radContext);
1979 +    if (GSS_ERROR(major))
1980 +        return major;
1981 +
1982 +    if (cred->radiusConfigStanza.value != NULL)
1983 +        configStanza = (const char *)cred->radiusConfigStanza.value;
1984 +
1985 +    if (rs_conn_create(actx->radContext, &actx->radConn, configStanza) != 0) {
1986 +        err = rs_err_conn_pop(actx->radConn);
1987 +        return gssEapRadiusMapError(minor, err);
1988 +    }
1989 +
1990 +    if (actx->radServer != NULL) {
1991 +        if (rs_conn_select_peer(actx->radConn, actx->radServer) != 0) {
1992 +            err = rs_err_conn_pop(actx->radConn);
1993 +            return gssEapRadiusMapError(minor, err);
1994 +        }
1995 +    }
1996 +
1997 +    *minor = 0;
1998 +    return GSS_S_COMPLETE;
1999 +}
2000 +
2001 +/*
2002 + * Process a EAP response from the initiator.
2003 + */
2004 +static OM_uint32
2005 +eapGssSmAcceptAuthenticate(OM_uint32 *minor,
2006 +                           gss_cred_id_t cred,
2007 +                           gss_ctx_id_t ctx,
2008 +                           gss_name_t target GSSEAP_UNUSED,
2009 +                           gss_OID mech GSSEAP_UNUSED,
2010 +                           OM_uint32 reqFlags GSSEAP_UNUSED,
2011 +                           OM_uint32 timeReq GSSEAP_UNUSED,
2012 +                           gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
2013 +                           gss_buffer_t inputToken,
2014 +                           gss_buffer_t outputToken,
2015 +                           OM_uint32 *smFlags)
2016 +{
2017 +    OM_uint32 major, tmpMinor;
2018 +    struct rs_connection *rconn;
2019 +    struct rs_request *request = NULL;
2020 +    struct rs_packet *req = NULL, *resp = NULL;
2021 +    struct radius_packet *frreq, *frresp;
2022 +
2023 +    if (ctx->acceptorCtx.radContext == NULL) {
2024 +        /* May be NULL from an imported partial context */
2025 +        major = createRadiusHandle(minor, cred, ctx);
2026 +        if (GSS_ERROR(major))
2027 +            goto cleanup;
2028 +    }
2029 +
2030 +    if (isIdentityResponseP(inputToken)) {
2031 +        major = importInitiatorIdentity(minor, ctx, inputToken);
2032 +        if (GSS_ERROR(major))
2033 +            return major;
2034 +    }
2035 +
2036 +    rconn = ctx->acceptorCtx.radConn;
2037 +
2038 +    if (rs_packet_create_authn_request(rconn, &req, NULL, NULL) != 0) {
2039 +        major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn));
2040 +        goto cleanup;
2041 +    }
2042 +    frreq = rs_packet_frpkt(req);
2043 +
2044 +    major = setInitiatorIdentity(minor, ctx, &frreq->vps);
2045 +    if (GSS_ERROR(major))
2046 +        goto cleanup;
2047 +
2048 +    major = setAcceptorIdentity(minor, ctx, &frreq->vps);
2049 +    if (GSS_ERROR(major))
2050 +        goto cleanup;
2051 +
2052 +    major = gssEapRadiusAddAvp(minor, &frreq->vps,
2053 +                               PW_EAP_MESSAGE, 0, inputToken);
2054 +    if (GSS_ERROR(major))
2055 +        goto cleanup;
2056 +
2057 +    if (ctx->acceptorCtx.state.length != 0) {
2058 +        major = gssEapRadiusAddAvp(minor, &frreq->vps, PW_STATE, 0,
2059 +                                   &ctx->acceptorCtx.state);
2060 +        if (GSS_ERROR(major))
2061 +            goto cleanup;
2062 +
2063 +        gss_release_buffer(&tmpMinor, &ctx->acceptorCtx.state);
2064 +    }
2065 +
2066 +    if (rs_request_create(rconn, &request) != 0) {
2067 +        major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn));
2068 +        goto cleanup;
2069 +    }
2070 +
2071 +    rs_request_add_reqpkt(request, req);
2072 +    req = NULL;
2073 +
2074 +    if (rs_request_send(request, &resp) != 0) {
2075 +        major = gssEapRadiusMapError(minor, rs_err_conn_pop(rconn));
2076 +        goto cleanup;
2077 +    }
2078 +
2079 +    GSSEAP_ASSERT(resp != NULL);
2080 +
2081 +    frresp = rs_packet_frpkt(resp);
2082 +    switch (frresp->code) {
2083 +    case PW_ACCESS_CHALLENGE:
2084 +    case PW_AUTHENTICATION_ACK:
2085 +        break;
2086 +    case PW_AUTHENTICATION_REJECT:
2087 +        *minor = GSSEAP_RADIUS_AUTH_FAILURE;
2088 +        major = GSS_S_DEFECTIVE_CREDENTIAL;
2089 +        goto cleanup;
2090 +        break;
2091 +    default:
2092 +        *minor = GSSEAP_UNKNOWN_RADIUS_CODE;
2093 +        major = GSS_S_FAILURE;
2094 +        goto cleanup;
2095 +        break;
2096 +    }
2097 +
2098 +    major = gssEapRadiusGetAvp(minor, frresp->vps, PW_EAP_MESSAGE, 0,
2099 +                               outputToken, TRUE);
2100 +    if (major == GSS_S_UNAVAILABLE && frresp->code == PW_ACCESS_CHALLENGE) {
2101 +        *minor = GSSEAP_MISSING_EAP_REQUEST;
2102 +        major = GSS_S_DEFECTIVE_TOKEN;
2103 +        goto cleanup;
2104 +    } else if (GSS_ERROR(major))
2105 +        goto cleanup;
2106 +
2107 +    if (frresp->code == PW_ACCESS_CHALLENGE) {
2108 +        major = gssEapRadiusGetAvp(minor, frresp->vps, PW_STATE, 0,
2109 +                                   &ctx->acceptorCtx.state, TRUE);
2110 +        if (GSS_ERROR(major) && *minor != GSSEAP_NO_SUCH_ATTR)
2111 +            goto cleanup;
2112 +    } else {
2113 +        ctx->acceptorCtx.vps = frresp->vps;
2114 +        frresp->vps = NULL;
2115 +
2116 +        major = acceptReadyEap(minor, ctx, cred);
2117 +        if (GSS_ERROR(major))
2118 +            goto cleanup;
2119 +
2120 +        GSSEAP_SM_TRANSITION_NEXT(ctx);
2121 +    }
2122 +
2123 +    major = GSS_S_CONTINUE_NEEDED;
2124 +    *minor = 0;
2125 +    *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
2126 +
2127 +cleanup:
2128 +    if (request != NULL)
2129 +        rs_request_destroy(request);
2130 +    if (req != NULL)
2131 +        rs_packet_destroy(req);
2132 +    if (resp != NULL)
2133 +        rs_packet_destroy(resp);
2134 +    if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_INITIATOR_EXTS) {
2135 +        GSSEAP_ASSERT(major == GSS_S_CONTINUE_NEEDED);
2136 +
2137 +        rs_conn_destroy(ctx->acceptorCtx.radConn);
2138 +        ctx->acceptorCtx.radConn = NULL;
2139 +    }
2140 +
2141 +    return major;
2142 +}
2143 +
2144 +static OM_uint32
2145 +eapGssSmAcceptGssFlags(OM_uint32 *minor,
2146 +                       gss_cred_id_t cred GSSEAP_UNUSED,
2147 +                       gss_ctx_id_t ctx,
2148 +                       gss_name_t target GSSEAP_UNUSED,
2149 +                       gss_OID mech GSSEAP_UNUSED,
2150 +                       OM_uint32 reqFlags GSSEAP_UNUSED,
2151 +                       OM_uint32 timeReq GSSEAP_UNUSED,
2152 +                       gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
2153 +                       gss_buffer_t inputToken,
2154 +                       gss_buffer_t outputToken GSSEAP_UNUSED,
2155 +                       OM_uint32 *smFlags GSSEAP_UNUSED)
2156 +{
2157 +    unsigned char *p;
2158 +    OM_uint32 initiatorGssFlags;
2159 +
2160 +    GSSEAP_ASSERT((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0);
2161 +
2162 +    if (inputToken->length < 4) {
2163 +        *minor = GSSEAP_TOK_TRUNC;
2164 +        return GSS_S_DEFECTIVE_TOKEN;
2165 +    }
2166 +
2167 +    /* allow flags to grow for future expansion */
2168 +    p = (unsigned char *)inputToken->value + inputToken->length - 4;
2169 +
2170 +    initiatorGssFlags = load_uint32_be(p);
2171 +    initiatorGssFlags &= GSSEAP_WIRE_FLAGS_MASK;
2172 +
2173 +    ctx->gssFlags |= initiatorGssFlags;
2174 +
2175 +    return GSS_S_CONTINUE_NEEDED;
2176 +}
2177 +
2178 +static OM_uint32
2179 +eapGssSmAcceptGssChannelBindings(OM_uint32 *minor,
2180 +                                 gss_cred_id_t cred GSSEAP_UNUSED,
2181 +                                 gss_ctx_id_t ctx,
2182 +                                 gss_name_t target GSSEAP_UNUSED,
2183 +                                 gss_OID mech GSSEAP_UNUSED,
2184 +                                 OM_uint32 reqFlags GSSEAP_UNUSED,
2185 +                                 OM_uint32 timeReq GSSEAP_UNUSED,
2186 +                                 gss_channel_bindings_t chanBindings,
2187 +                                 gss_buffer_t inputToken,
2188 +                                 gss_buffer_t outputToken GSSEAP_UNUSED,
2189 +                                 OM_uint32 *smFlags GSSEAP_UNUSED)
2190 +{
2191 +    OM_uint32 major;
2192 +    gss_iov_buffer_desc iov[2];
2193 +
2194 +    iov[0].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
2195 +    iov[0].buffer.length = 0;
2196 +    iov[0].buffer.value = NULL;
2197 +
2198 +    iov[1].type = GSS_IOV_BUFFER_TYPE_STREAM | GSS_IOV_BUFFER_FLAG_ALLOCATED;
2199 +
2200 +    /* XXX necessary because decrypted in place and we verify it later */
2201 +    major = duplicateBuffer(minor, inputToken, &iov[1].buffer);
2202 +    if (GSS_ERROR(major))
2203 +        return major;
2204 +
2205 +    major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
2206 +                                    iov, 2, TOK_TYPE_WRAP);
2207 +    if (GSS_ERROR(major)) {
2208 +        gssEapReleaseIov(iov, 2);
2209 +        return major;
2210 +    }
2211 +
2212 +    if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS &&
2213 +        !bufferEqual(&iov[0].buffer, &chanBindings->application_data)) {
2214 +        major = GSS_S_BAD_BINDINGS;
2215 +        *minor = GSSEAP_BINDINGS_MISMATCH;
2216 +    } else {
2217 +        major = GSS_S_CONTINUE_NEEDED;
2218 +        *minor = 0;
2219 +    }
2220 +
2221 +    gssEapReleaseIov(iov, 2);
2222 +
2223 +    return major;
2224 +}
2225 +
2226 +static OM_uint32
2227 +eapGssSmAcceptInitiatorMIC(OM_uint32 *minor,
2228 +                           gss_cred_id_t cred GSSEAP_UNUSED,
2229 +                           gss_ctx_id_t ctx,
2230 +                           gss_name_t target GSSEAP_UNUSED,
2231 +                           gss_OID mech GSSEAP_UNUSED,
2232 +                           OM_uint32 reqFlags GSSEAP_UNUSED,
2233 +                           OM_uint32 timeReq GSSEAP_UNUSED,
2234 +                           gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
2235 +                           gss_buffer_t inputToken,
2236 +                           gss_buffer_t outputToken GSSEAP_UNUSED,
2237 +                           OM_uint32 *smFlags GSSEAP_UNUSED)
2238 +{
2239 +    OM_uint32 major;
2240 +
2241 +    major = gssEapVerifyTokenMIC(minor, ctx, inputToken);
2242 +    if (GSS_ERROR(major))
2243 +        return major;
2244 +
2245 +    GSSEAP_SM_TRANSITION_NEXT(ctx);
2246 +
2247 +    *minor = 0;
2248 +    return GSS_S_CONTINUE_NEEDED;
2249 +}
2250 +
2251 +#ifdef GSSEAP_ENABLE_REAUTH
2252 +static OM_uint32
2253 +eapGssSmAcceptReauthCreds(OM_uint32 *minor,
2254 +                          gss_cred_id_t cred,
2255 +                          gss_ctx_id_t ctx,
2256 +                          gss_name_t target GSSEAP_UNUSED,
2257 +                          gss_OID mech GSSEAP_UNUSED,
2258 +                          OM_uint32 reqFlags GSSEAP_UNUSED,
2259 +                          OM_uint32 timeReq GSSEAP_UNUSED,
2260 +                          gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
2261 +                          gss_buffer_t inputToken GSSEAP_UNUSED,
2262 +                          gss_buffer_t outputToken,
2263 +                          OM_uint32 *smFlags GSSEAP_UNUSED)
2264 +{
2265 +    OM_uint32 major;
2266 +
2267 +    /*
2268 +     * If we're built with fast reauthentication enabled, then
2269 +     * fabricate a ticket from the initiator to ourselves.
2270 +     */
2271 +    major = gssEapMakeReauthCreds(minor, ctx, cred, outputToken);
2272 +    if (major == GSS_S_UNAVAILABLE)
2273 +        major = GSS_S_COMPLETE;
2274 +    if (major == GSS_S_COMPLETE)
2275 +        major = GSS_S_CONTINUE_NEEDED;
2276 +
2277 +    return major;
2278 +}
2279 +#endif
2280 +
2281 +static OM_uint32
2282 +eapGssSmAcceptAcceptorMIC(OM_uint32 *minor,
2283 +                          gss_cred_id_t cred GSSEAP_UNUSED,
2284 +                          gss_ctx_id_t ctx,
2285 +                          gss_name_t target GSSEAP_UNUSED,
2286 +                          gss_OID mech GSSEAP_UNUSED,
2287 +                          OM_uint32 reqFlags GSSEAP_UNUSED,
2288 +                          OM_uint32 timeReq GSSEAP_UNUSED,
2289 +                          gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
2290 +                          gss_buffer_t inputToken GSSEAP_UNUSED,
2291 +                          gss_buffer_t outputToken,
2292 +                          OM_uint32 *smFlags)
2293 +{
2294 +    OM_uint32 major;
2295 +
2296 +    major = gssEapMakeTokenMIC(minor, ctx, outputToken);
2297 +    if (GSS_ERROR(major))
2298 +        return major;
2299 +
2300 +    GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
2301 +
2302 +    *minor = 0;
2303 +    *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
2304 +
2305 +    return GSS_S_COMPLETE;
2306 +}
2307 +
2308 +static struct gss_eap_sm eapGssAcceptorSm[] = {
2309 +    {
2310 +        ITOK_TYPE_ACCEPTOR_NAME_REQ,
2311 +        ITOK_TYPE_ACCEPTOR_NAME_RESP,
2312 +        GSSEAP_STATE_INITIAL,
2313 +        0,
2314 +        eapGssSmAcceptAcceptorName
2315 +    },
2316 +#ifdef GSSEAP_DEBUG
2317 +    {
2318 +        ITOK_TYPE_VENDOR_INFO,
2319 +        ITOK_TYPE_NONE,
2320 +        GSSEAP_STATE_INITIAL,
2321 +        0,
2322 +        eapGssSmAcceptVendorInfo,
2323 +    },
2324 +#endif
2325 +#ifdef GSSEAP_ENABLE_REAUTH
2326 +    {
2327 +        ITOK_TYPE_REAUTH_REQ,
2328 +        ITOK_TYPE_REAUTH_RESP,
2329 +        GSSEAP_STATE_INITIAL,
2330 +        0,
2331 +        eapGssSmAcceptGssReauth,
2332 +    },
2333 +#endif
2334 +    {
2335 +        ITOK_TYPE_NONE,
2336 +        ITOK_TYPE_EAP_REQ,
2337 +        GSSEAP_STATE_INITIAL,
2338 +        SM_ITOK_FLAG_REQUIRED,
2339 +        eapGssSmAcceptIdentity,
2340 +    },
2341 +    {
2342 +        ITOK_TYPE_EAP_RESP,
2343 +        ITOK_TYPE_EAP_REQ,
2344 +        GSSEAP_STATE_AUTHENTICATE,
2345 +        SM_ITOK_FLAG_REQUIRED,
2346 +        eapGssSmAcceptAuthenticate
2347 +    },
2348 +    {
2349 +        ITOK_TYPE_GSS_FLAGS,
2350 +        ITOK_TYPE_NONE,
2351 +        GSSEAP_STATE_INITIATOR_EXTS,
2352 +        0,
2353 +        eapGssSmAcceptGssFlags
2354 +    },
2355 +    {
2356 +        ITOK_TYPE_GSS_CHANNEL_BINDINGS,
2357 +        ITOK_TYPE_NONE,
2358 +        GSSEAP_STATE_INITIATOR_EXTS,
2359 +        SM_ITOK_FLAG_REQUIRED,
2360 +        eapGssSmAcceptGssChannelBindings,
2361 +    },
2362 +    {
2363 +        ITOK_TYPE_INITIATOR_MIC,
2364 +        ITOK_TYPE_NONE,
2365 +        GSSEAP_STATE_INITIATOR_EXTS,
2366 +        SM_ITOK_FLAG_REQUIRED,
2367 +        eapGssSmAcceptInitiatorMIC,
2368 +    },
2369 +#ifdef GSSEAP_ENABLE_REAUTH
2370 +    {
2371 +        ITOK_TYPE_NONE,
2372 +        ITOK_TYPE_REAUTH_CREDS,
2373 +        GSSEAP_STATE_ACCEPTOR_EXTS,
2374 +        0,
2375 +        eapGssSmAcceptReauthCreds,
2376 +    },
2377 +#endif
2378 +    {
2379 +        ITOK_TYPE_NONE,
2380 +        ITOK_TYPE_ACCEPTOR_MIC,
2381 +        GSSEAP_STATE_ACCEPTOR_EXTS,
2382 +        0,
2383 +        eapGssSmAcceptAcceptorMIC
2384 +    },
2385 +};
2386 +
2387 +OM_uint32
2388 +gssEapAcceptSecContext(OM_uint32 *minor,
2389 +                       gss_ctx_id_t ctx,
2390 +                       gss_cred_id_t cred,
2391 +                       gss_buffer_t input_token,
2392 +                       gss_channel_bindings_t input_chan_bindings,
2393 +                       gss_name_t *src_name,
2394 +                       gss_OID *mech_type,
2395 +                       gss_buffer_t output_token,
2396 +                       OM_uint32 *ret_flags,
2397 +                       OM_uint32 *time_rec,
2398 +                       gss_cred_id_t *delegated_cred_handle)
2399 +{
2400 +    OM_uint32 major, tmpMinor;
2401 +
2402 +    if (cred == GSS_C_NO_CREDENTIAL) {
2403 +        if (ctx->cred == GSS_C_NO_CREDENTIAL) {
2404 +            major = gssEapAcquireCred(minor,
2405 +                                      GSS_C_NO_NAME,
2406 +                                      GSS_C_INDEFINITE,
2407 +                                      GSS_C_NO_OID_SET,
2408 +                                      GSS_C_ACCEPT,
2409 +                                      &ctx->cred,
2410 +                                      NULL,
2411 +                                      NULL);
2412 +            if (GSS_ERROR(major))
2413 +                goto cleanup;
2414 +        }
2415 +
2416 +        cred = ctx->cred;
2417 +    }
2418 +
2419 +    /*
2420 +     * Previously we acquired the credential mutex here, but it should not be
2421 +     * necessary as the acceptor does not access any mutable elements of the
2422 +     * credential handle.
2423 +     */
2424 +
2425 +    /*
2426 +     * Calling gssEapInquireCred() forces the default acceptor credential name
2427 +     * to be resolved.
2428 +     */
2429 +    major = gssEapInquireCred(minor, cred, &ctx->acceptorName, NULL, NULL, NULL);
2430 +    if (GSS_ERROR(major))
2431 +        goto cleanup;
2432 +
2433 +    major = gssEapSmStep(minor,
2434 +                         cred,
2435 +                         ctx,
2436 +                         GSS_C_NO_NAME,
2437 +                         GSS_C_NO_OID,
2438 +                         0,
2439 +                         GSS_C_INDEFINITE,
2440 +                         input_chan_bindings,
2441 +                         input_token,
2442 +                         output_token,
2443 +                         eapGssAcceptorSm,
2444 +                         sizeof(eapGssAcceptorSm) / sizeof(eapGssAcceptorSm[0]));
2445 +    if (GSS_ERROR(major))
2446 +        goto cleanup;
2447 +
2448 +    if (mech_type != NULL) {
2449 +        OM_uint32 tmpMajor;
2450 +
2451 +        tmpMajor = gssEapCanonicalizeOid(&tmpMinor, ctx->mechanismUsed, 0, mech_type);
2452 +        if (GSS_ERROR(tmpMajor)) {
2453 +            major = tmpMajor;
2454 +            *minor = tmpMinor;
2455 +            goto cleanup;
2456 +        }
2457 +    }
2458 +    if (ret_flags != NULL)
2459 +        *ret_flags = ctx->gssFlags;
2460 +    if (delegated_cred_handle != NULL)
2461 +        *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
2462 +
2463 +    if (major == GSS_S_COMPLETE) {
2464 +        if (src_name != NULL && ctx->initiatorName != GSS_C_NO_NAME) {
2465 +            major = gssEapDuplicateName(&tmpMinor, ctx->initiatorName, src_name);
2466 +            if (GSS_ERROR(major))
2467 +                goto cleanup;
2468 +        }
2469 +        if (time_rec != NULL) {
2470 +            major = gssEapContextTime(&tmpMinor, ctx, time_rec);
2471 +            if (GSS_ERROR(major))
2472 +                goto cleanup;
2473 +        }
2474 +    }
2475 +
2476 +    GSSEAP_ASSERT(CTX_IS_ESTABLISHED(ctx) || major == GSS_S_CONTINUE_NEEDED);
2477 +
2478 +cleanup:
2479 +    return major;
2480 +}
2481 +
2482 +#ifdef GSSEAP_ENABLE_REAUTH
2483 +static OM_uint32
2484 +acceptReadyKrb(OM_uint32 *minor,
2485 +               gss_ctx_id_t ctx,
2486 +               gss_cred_id_t cred,
2487 +               const gss_name_t initiator,
2488 +               const gss_OID mech,
2489 +               OM_uint32 timeRec)
2490 +{
2491 +    OM_uint32 major;
2492 +
2493 +    major = gssEapGlueToMechName(minor, ctx, initiator, &ctx->initiatorName);
2494 +    if (GSS_ERROR(major))
2495 +        return major;
2496 +
2497 +    major = gssEapReauthComplete(minor, ctx, cred, mech, timeRec);
2498 +    if (GSS_ERROR(major))
2499 +        return major;
2500 +
2501 +    *minor = 0;
2502 +    return GSS_S_COMPLETE;
2503 +}
2504 +
2505 +static OM_uint32
2506 +eapGssSmAcceptGssReauth(OM_uint32 *minor,
2507 +                        gss_cred_id_t cred,
2508 +                        gss_ctx_id_t ctx,
2509 +                        gss_name_t target GSSEAP_UNUSED,
2510 +                        gss_OID mech,
2511 +                        OM_uint32 reqFlags GSSEAP_UNUSED,
2512 +                        OM_uint32 timeReq GSSEAP_UNUSED,
2513 +                        gss_channel_bindings_t chanBindings,
2514 +                        gss_buffer_t inputToken,
2515 +                        gss_buffer_t outputToken,
2516 +                        OM_uint32 *smFlags)
2517 +{
2518 +    OM_uint32 major, tmpMinor;
2519 +    gss_name_t krbInitiator = GSS_C_NO_NAME;
2520 +    OM_uint32 gssFlags, timeRec = GSS_C_INDEFINITE;
2521 +
2522 +    /*
2523 +     * If we're built with fast reauthentication support, it's valid
2524 +     * for an initiator to send a GSS reauthentication token as its
2525 +     * initial context token, causing us to short-circuit the state
2526 +     * machine and process Kerberos GSS messages instead.
2527 +     */
2528 +
2529 +    ctx->flags |= CTX_FLAG_KRB_REAUTH;
2530 +
2531 +    major = gssAcceptSecContext(minor,
2532 +                                &ctx->reauthCtx,
2533 +                                cred->reauthCred,
2534 +                                inputToken,
2535 +                                chanBindings,
2536 +                                &krbInitiator,
2537 +                                &mech,
2538 +                                outputToken,
2539 +                                &gssFlags,
2540 +                                &timeRec,
2541 +                                NULL);
2542 +    if (major == GSS_S_COMPLETE) {
2543 +        major = acceptReadyKrb(minor, ctx, cred,
2544 +                               krbInitiator, mech, timeRec);
2545 +        if (major == GSS_S_COMPLETE) {
2546 +            GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
2547 +        }
2548 +        ctx->gssFlags = gssFlags;
2549 +    } else if (GSS_ERROR(major) &&
2550 +        (*smFlags & SM_FLAG_INPUT_TOKEN_CRITICAL) == 0) {
2551 +        /* pretend reauthentication attempt never happened */
2552 +        gssDeleteSecContext(&tmpMinor, &ctx->reauthCtx, GSS_C_NO_BUFFER);
2553 +        ctx->flags &= ~(CTX_FLAG_KRB_REAUTH);
2554 +        GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_INITIAL);
2555 +        major = GSS_S_CONTINUE_NEEDED;
2556 +    }
2557 +
2558 +    gssReleaseName(&tmpMinor, &krbInitiator);
2559 +
2560 +    return major;
2561 +}
2562 +#endif /* GSSEAP_ENABLE_REAUTH */
2563 +
2564 +OM_uint32 GSSAPI_CALLCONV
2565 +gss_accept_sec_context(OM_uint32 *minor,
2566 +                       gss_ctx_id_t *context_handle,
2567 +                       gss_cred_id_t cred,
2568 +                       gss_buffer_t input_token,
2569 +                       gss_channel_bindings_t input_chan_bindings,
2570 +                       gss_name_t *src_name,
2571 +                       gss_OID *mech_type,
2572 +                       gss_buffer_t output_token,
2573 +                       OM_uint32 *ret_flags,
2574 +                       OM_uint32 *time_rec,
2575 +                       gss_cred_id_t *delegated_cred_handle)
2576 +{
2577 +    OM_uint32 major, tmpMinor;
2578 +    gss_ctx_id_t ctx = *context_handle;
2579 +
2580 +    *minor = 0;
2581 +
2582 +    output_token->length = 0;
2583 +    output_token->value = NULL;
2584 +
2585 +    if (src_name != NULL)
2586 +        *src_name = GSS_C_NO_NAME;
2587 +
2588 +    if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) {
2589 +        *minor = GSSEAP_TOK_TRUNC;
2590 +        return GSS_S_DEFECTIVE_TOKEN;
2591 +    }
2592 +
2593 +    if (ctx == GSS_C_NO_CONTEXT) {
2594 +        major = gssEapAllocContext(minor, &ctx);
2595 +        if (GSS_ERROR(major))
2596 +            return major;
2597 +
2598 +        *context_handle = ctx;
2599 +    }
2600 +
2601 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
2602 +
2603 +    major = gssEapAcceptSecContext(minor,
2604 +                                   ctx,
2605 +                                   cred,
2606 +                                   input_token,
2607 +                                   input_chan_bindings,
2608 +                                   src_name,
2609 +                                   mech_type,
2610 +                                   output_token,
2611 +                                   ret_flags,
2612 +                                   time_rec,
2613 +                                   delegated_cred_handle);
2614 +
2615 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
2616 +
2617 +    if (GSS_ERROR(major))
2618 +        gssEapReleaseContext(&tmpMinor, context_handle);
2619 +
2620 +    return major;
2621 +}
2622 diff --git a/mech_eap/acquire_cred.c b/mech_eap/acquire_cred.c
2623 new file mode 100644
2624 index 0000000..ae2648e
2625 --- /dev/null
2626 +++ b/mech_eap/acquire_cred.c
2627 @@ -0,0 +1,52 @@
2628 +/*
2629 + * Copyright (c) 2011, JANET(UK)
2630 + * All rights reserved.
2631 + *
2632 + * Redistribution and use in source and binary forms, with or without
2633 + * modification, are permitted provided that the following conditions
2634 + * are met:
2635 + *
2636 + * 1. Redistributions of source code must retain the above copyright
2637 + *    notice, this list of conditions and the following disclaimer.
2638 + *
2639 + * 2. Redistributions in binary form must reproduce the above copyright
2640 + *    notice, this list of conditions and the following disclaimer in the
2641 + *    documentation and/or other materials provided with the distribution.
2642 + *
2643 + * 3. Neither the name of JANET(UK) nor the names of its contributors
2644 + *    may be used to endorse or promote products derived from this software
2645 + *    without specific prior written permission.
2646 + *
2647 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2648 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2649 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2650 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
2651 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2652 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2653 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2654 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2655 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2656 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2657 + * SUCH DAMAGE.
2658 + */
2659 +
2660 +/*
2661 + * Wrapper for acquiring a credential handle.
2662 + */
2663 +
2664 +#include "gssapiP_eap.h"
2665 +
2666 +OM_uint32 GSSAPI_CALLCONV
2667 +gss_acquire_cred(OM_uint32 *minor,
2668 +                 gss_name_t desired_name,
2669 +                 OM_uint32 time_req,
2670 +                 gss_OID_set desired_mechs,
2671 +                 gss_cred_usage_t cred_usage,
2672 +                 gss_cred_id_t *output_cred_handle,
2673 +                 gss_OID_set *actual_mechs,
2674 +                 OM_uint32 *time_rec)
2675 +{
2676 +    return gssEapAcquireCred(minor, desired_name,
2677 +                             time_req, desired_mechs, cred_usage,
2678 +                             output_cred_handle, actual_mechs, time_rec);
2679 +}
2680 diff --git a/mech_eap/acquire_cred_with_password.c b/mech_eap/acquire_cred_with_password.c
2681 new file mode 100644
2682 index 0000000..8e08358
2683 --- /dev/null
2684 +++ b/mech_eap/acquire_cred_with_password.c
2685 @@ -0,0 +1,67 @@
2686 +/*
2687 + * Copyright (c) 2011, JANET(UK)
2688 + * All rights reserved.
2689 + *
2690 + * Redistribution and use in source and binary forms, with or without
2691 + * modification, are permitted provided that the following conditions
2692 + * are met:
2693 + *
2694 + * 1. Redistributions of source code must retain the above copyright
2695 + *    notice, this list of conditions and the following disclaimer.
2696 + *
2697 + * 2. Redistributions in binary form must reproduce the above copyright
2698 + *    notice, this list of conditions and the following disclaimer in the
2699 + *    documentation and/or other materials provided with the distribution.
2700 + *
2701 + * 3. Neither the name of JANET(UK) nor the names of its contributors
2702 + *    may be used to endorse or promote products derived from this software
2703 + *    without specific prior written permission.
2704 + *
2705 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2706 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2707 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2708 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
2709 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2710 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2711 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2712 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2713 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2714 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2715 + * SUCH DAMAGE.
2716 + */
2717 +
2718 +/*
2719 + * Wrapper for acquiring a credential handle using a password.
2720 + */
2721 +
2722 +#include "gssapiP_eap.h"
2723 +
2724 +OM_uint32 GSSAPI_CALLCONV
2725 +gssspi_acquire_cred_with_password(OM_uint32 *minor,
2726 +                                  const gss_name_t desired_name,
2727 +                                  const gss_buffer_t password,
2728 +                                  OM_uint32 time_req,
2729 +                                  const gss_OID_set desired_mechs,
2730 +                                  gss_cred_usage_t cred_usage,
2731 +                                  gss_cred_id_t *output_cred_handle,
2732 +                                  gss_OID_set *actual_mechs,
2733 +                                  OM_uint32 *time_rec)
2734 +{
2735 +    OM_uint32 major, tmpMinor;
2736 +
2737 +    major = gssEapAcquireCred(minor, desired_name,
2738 +                              time_req, desired_mechs, cred_usage,
2739 +                              output_cred_handle, actual_mechs, time_rec);
2740 +    if (GSS_ERROR(major))
2741 +        goto cleanup;
2742 +
2743 +    major = gssEapSetCredPassword(minor, *output_cred_handle, password);
2744 +    if (GSS_ERROR(major))
2745 +        goto cleanup;
2746 +
2747 +cleanup:
2748 +    if (GSS_ERROR(major))
2749 +        gssEapReleaseCred(&tmpMinor, output_cred_handle);
2750 +
2751 +    return major;
2752 +}
2753 diff --git a/mech_eap/add_cred.c b/mech_eap/add_cred.c
2754 new file mode 100644
2755 index 0000000..64d97c0
2756 --- /dev/null
2757 +++ b/mech_eap/add_cred.c
2758 @@ -0,0 +1,87 @@
2759 +/*
2760 + * Copyright (c) 2011, JANET(UK)
2761 + * All rights reserved.
2762 + *
2763 + * Redistribution and use in source and binary forms, with or without
2764 + * modification, are permitted provided that the following conditions
2765 + * are met:
2766 + *
2767 + * 1. Redistributions of source code must retain the above copyright
2768 + *    notice, this list of conditions and the following disclaimer.
2769 + *
2770 + * 2. Redistributions in binary form must reproduce the above copyright
2771 + *    notice, this list of conditions and the following disclaimer in the
2772 + *    documentation and/or other materials provided with the distribution.
2773 + *
2774 + * 3. Neither the name of JANET(UK) nor the names of its contributors
2775 + *    may be used to endorse or promote products derived from this software
2776 + *    without specific prior written permission.
2777 + *
2778 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2779 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2780 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2781 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
2782 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2783 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2784 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2785 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2786 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2787 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2788 + * SUCH DAMAGE.
2789 + */
2790 +
2791 +/*
2792 + * Wrapper for acquiring a credential handle.
2793 + */
2794 +
2795 +#include "gssapiP_eap.h"
2796 +
2797 +/*
2798 + * Note that this shouldn't really be required to be implemented by anything
2799 + * apart from the mechanism glue layer. However, Heimdal does call into the
2800 + * mechanism here.
2801 + */
2802 +OM_uint32 GSSAPI_CALLCONV
2803 +gss_add_cred(OM_uint32 *minor,
2804 +             gss_cred_id_t input_cred_handle GSSEAP_UNUSED,
2805 +             gss_name_t desired_name,
2806 +             gss_OID desired_mech,
2807 +             gss_cred_usage_t cred_usage,
2808 +             OM_uint32 initiator_time_req,
2809 +             OM_uint32 acceptor_time_req,
2810 +             gss_cred_id_t *output_cred_handle,
2811 +             gss_OID_set *actual_mechs,
2812 +             OM_uint32 *initiator_time_rec,
2813 +             OM_uint32 *acceptor_time_rec)
2814 +{
2815 +    OM_uint32 major;
2816 +    OM_uint32 time_req, time_rec = 0;
2817 +    gss_OID_set_desc mechs;
2818 +
2819 +    *minor = 0;
2820 +    *output_cred_handle = GSS_C_NO_CREDENTIAL;
2821 +
2822 +    if (cred_usage == GSS_C_ACCEPT)
2823 +        time_req = acceptor_time_req;
2824 +    else
2825 +        time_req = initiator_time_req;
2826 +
2827 +    mechs.count = 1;
2828 +    mechs.elements = desired_mech;
2829 +
2830 +    major = gssEapAcquireCred(minor,
2831 +                              desired_name,
2832 +                              time_req,
2833 +                              &mechs,
2834 +                              cred_usage,
2835 +                              output_cred_handle,
2836 +                              actual_mechs,
2837 +                              &time_rec);
2838 +
2839 +    if (initiator_time_rec != NULL)
2840 +        *initiator_time_rec = time_rec;
2841 +    if (acceptor_time_rec != NULL)
2842 +        *acceptor_time_rec = time_rec;
2843 +
2844 +    return major;
2845 +}
2846 diff --git a/mech_eap/add_cred_with_password.c b/mech_eap/add_cred_with_password.c
2847 new file mode 100644
2848 index 0000000..b982f0d
2849 --- /dev/null
2850 +++ b/mech_eap/add_cred_with_password.c
2851 @@ -0,0 +1,93 @@
2852 +/*
2853 + * Copyright (c) 2011, JANET(UK)
2854 + * All rights reserved.
2855 + *
2856 + * Redistribution and use in source and binary forms, with or without
2857 + * modification, are permitted provided that the following conditions
2858 + * are met:
2859 + *
2860 + * 1. Redistributions of source code must retain the above copyright
2861 + *    notice, this list of conditions and the following disclaimer.
2862 + *
2863 + * 2. Redistributions in binary form must reproduce the above copyright
2864 + *    notice, this list of conditions and the following disclaimer in the
2865 + *    documentation and/or other materials provided with the distribution.
2866 + *
2867 + * 3. Neither the name of JANET(UK) nor the names of its contributors
2868 + *    may be used to endorse or promote products derived from this software
2869 + *    without specific prior written permission.
2870 + *
2871 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2872 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2873 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2874 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
2875 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2876 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2877 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2878 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2879 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2880 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2881 + * SUCH DAMAGE.
2882 + */
2883 +
2884 +/*
2885 + * Wrapper for acquiring a credential handle using a password.
2886 + */
2887 +
2888 +#include "gssapiP_eap.h"
2889 +
2890 +OM_uint32 GSSAPI_CALLCONV
2891 +gss_add_cred_with_password(OM_uint32 *minor,
2892 +                           const gss_cred_id_t input_cred_handle GSSEAP_UNUSED,
2893 +                           const gss_name_t desired_name,
2894 +                           const gss_OID desired_mech,
2895 +                           const gss_buffer_t password,
2896 +                           gss_cred_usage_t cred_usage,
2897 +                           OM_uint32 initiator_time_req,
2898 +                           OM_uint32 acceptor_time_req,
2899 +                           gss_cred_id_t *output_cred_handle,
2900 +                           gss_OID_set *actual_mechs,
2901 +                           OM_uint32 *initiator_time_rec,
2902 +                           OM_uint32 *acceptor_time_rec)
2903 +{
2904 +    OM_uint32 major, tmpMinor;
2905 +    OM_uint32 time_req, time_rec = 0;
2906 +    gss_OID_set_desc mechs;
2907 +
2908 +    *minor = 0;
2909 +    *output_cred_handle = GSS_C_NO_CREDENTIAL;
2910 +
2911 +    if (cred_usage == GSS_C_ACCEPT)
2912 +        time_req = acceptor_time_req;
2913 +    else
2914 +        time_req = initiator_time_req;
2915 +
2916 +    mechs.count = 1;
2917 +    mechs.elements = desired_mech;
2918 +
2919 +    major = gssEapAcquireCred(minor,
2920 +                              desired_name,
2921 +                              time_req,
2922 +                              &mechs,
2923 +                              cred_usage,
2924 +                              output_cred_handle,
2925 +                              actual_mechs,
2926 +                              &time_rec);
2927 +    if (GSS_ERROR(major))
2928 +        goto cleanup;
2929 +
2930 +    major = gssEapSetCredPassword(minor, *output_cred_handle, password);
2931 +    if (GSS_ERROR(major))
2932 +        goto cleanup;
2933 +
2934 +    if (initiator_time_rec != NULL)
2935 +        *initiator_time_rec = time_rec;
2936 +    if (acceptor_time_rec != NULL)
2937 +        *acceptor_time_rec = time_rec;
2938 +
2939 +cleanup:
2940 +    if (GSS_ERROR(major))
2941 +        gssEapReleaseCred(&tmpMinor, output_cred_handle);
2942 +
2943 +    return major;
2944 +}
2945 diff --git a/mech_eap/authdata_plugin.h b/mech_eap/authdata_plugin.h
2946 new file mode 100644
2947 index 0000000..32bff2f
2948 --- /dev/null
2949 +++ b/mech_eap/authdata_plugin.h
2950 @@ -0,0 +1,331 @@
2951 +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2952 +/*
2953 + * krb5/authdata_plugin.h
2954 + *
2955 + * Copyright (C) 2007 Apple Inc.  All Rights Reserved.
2956 + *
2957 + * Export of this software from the United States of America may
2958 + *   require a specific license from the United States Government.
2959 + *   It is the responsibility of any person or organization contemplating
2960 + *   export to obtain such a license before exporting.
2961 + *
2962 + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
2963 + * distribute this software and its documentation for any purpose and
2964 + * without fee is hereby granted, provided that the above copyright
2965 + * notice appear in all copies and that both that copyright notice and
2966 + * this permission notice appear in supporting documentation, and that
2967 + * the name of M.I.T. not be used in advertising or publicity pertaining
2968 + * to distribution of the software without specific, written prior
2969 + * permission.  Furthermore if you modify this software you must label
2970 + * your software as modified software and not distribute it in such a
2971 + * fashion that it might be confused with the original M.I.T. software.
2972 + * M.I.T. makes no representations about the suitability of
2973 + * this software for any purpose.  It is provided "as is" without express
2974 + * or implied warranty.
2975 + *
2976 + * AuthorizationData plugin definitions for Kerberos 5.
2977 + */
2978 +
2979 +/*
2980 + * This is considered an INTERNAL interface at this time.
2981 + *
2982 + * Some work is needed before exporting it:
2983 + *
2984 + * + Documentation.
2985 + * + Sample code.
2986 + * + Test cases (preferably automated testing under "make check").
2987 + * + Hook into TGS exchange too; will change API.
2988 + * + Examine memory management issues, especially for Windows; may
2989 + *   change API.
2990 + *
2991 + * Other changes that would be nice to have, but not necessarily
2992 + * before making this interface public:
2993 + *
2994 + * + Library support for AD-IF-RELEVANT and similar wrappers.  (We can
2995 + *   make the plugin construct them if it wants them.)
2996 + * + KDC could combine/optimize wrapped AD elements provided by
2997 + *   multiple plugins, e.g., two IF-RELEVANT sequences could be
2998 + *   merged.  (The preauth plugin API also has this bug, we're going
2999 + *   to need a general fix.)
3000 + */
3001 +
3002 +#ifndef KRB5_AUTHDATA_PLUGIN_H_INCLUDED
3003 +#define KRB5_AUTHDATA_PLUGIN_H_INCLUDED
3004 +#include <krb5/krb5.h>
3005 +
3006 +/*
3007 + * While arguments of these types are passed-in, for the most part a
3008 + * authorization data module can treat them as opaque.  If we need
3009 + * keying data, we can ask for it directly.
3010 + */
3011 +struct _krb5_db_entry_new;
3012 +
3013 +/*
3014 + * The function table / structure which an authdata server module must export as
3015 + * "authdata_server_0".  NOTE: replace "0" with "1" for the type and
3016 + * variable names if this gets picked up by upstream.  If the interfaces work
3017 + * correctly, future versions of the table will add either more callbacks or
3018 + * more arguments to callbacks, and in both cases we'll be able to wrap the v0
3019 + * functions.
3020 + */
3021 +/* extern krb5plugin_authdata_ftable_v0 authdata_server_0; */
3022 +typedef struct krb5plugin_authdata_server_ftable_v0 {
3023 +    /* Not-usually-visible name. */
3024 +    char *name;
3025 +
3026 +    /*
3027 +     * Per-plugin initialization/cleanup.  The init function is called
3028 +     * by the KDC when the plugin is loaded, and the fini function is
3029 +     * called before the plugin is unloaded.  Both are optional.
3030 +     */
3031 +    krb5_error_code (*init_proc)(krb5_context, void **);
3032 +    void (*fini_proc)(krb5_context, void *);
3033 +    /*
3034 +     * Actual authorization data handling function.  If this field
3035 +     * holds a null pointer, this mechanism will be skipped, and the
3036 +     * init/fini functions will not be run.
3037 +     *
3038 +     * This function should only modify the field
3039 +     * enc_tkt_reply->authorization_data.  All other values should be
3040 +     * considered inputs only.  And, it should *modify* the field, not
3041 +     * overwrite it and assume that there are no other authdata
3042 +     * plugins in use.
3043 +     *
3044 +     * Memory management: authorization_data is a malloc-allocated,
3045 +     * null-terminated sequence of malloc-allocated pointers to
3046 +     * authorization data structures.  This plugin code currently
3047 +     * assumes the libraries, KDC, and plugin all use the same malloc
3048 +     * pool, which may be a problem if/when we get the KDC code
3049 +     * running on Windows.
3050 +     *
3051 +     * If this function returns a non-zero error code, a message
3052 +     * is logged, but no other action is taken.  Other authdata
3053 +     * plugins will be called, and a response will be sent to the
3054 +     * client (barring other problems).
3055 +     */
3056 +    krb5_error_code (*authdata_proc)(krb5_context,
3057 +                                     struct _krb5_db_entry_new *client,
3058 +                                     krb5_data *req_pkt,
3059 +                                     krb5_kdc_req *request,
3060 +                                     krb5_enc_tkt_part *enc_tkt_reply);
3061 +} krb5plugin_server_authdata_ftable_v0;
3062 +
3063 +typedef krb5plugin_server_authdata_ftable_v0 krb5plugin_authdata_ftable_v0;
3064 +
3065 +typedef struct krb5plugin_authdata_server_ftable_v2 {
3066 +    /* Not-usually-visible name. */
3067 +    char *name;
3068 +
3069 +    /*
3070 +     * Per-plugin initialization/cleanup.  The init function is called
3071 +     * by the KDC when the plugin is loaded, and the fini function is
3072 +     * called before the plugin is unloaded.  Both are optional.
3073 +     */
3074 +    krb5_error_code (*init_proc)(krb5_context, void **);
3075 +    void (*fini_proc)(krb5_context, void *);
3076 +    /*
3077 +     * Actual authorization data handling function.  If this field
3078 +     * holds a null pointer, this mechanism will be skipped, and the
3079 +     * init/fini functions will not be run.
3080 +     *
3081 +     * This function should only modify the field
3082 +     * enc_tkt_reply->authorization_data.  All other values should be
3083 +     * considered inputs only.  And, it should *modify* the field, not
3084 +     * overwrite it and assume that there are no other authdata
3085 +     * plugins in use.
3086 +     *
3087 +     * Memory management: authorization_data is a malloc-allocated,
3088 +     * null-terminated sequence of malloc-allocated pointers to
3089 +     * authorization data structures.  This plugin code currently
3090 +     * assumes the libraries, KDC, and plugin all use the same malloc
3091 +     * pool, which may be a problem if/when we get the KDC code
3092 +     * running on Windows.
3093 +     *
3094 +     * If this function returns a non-zero error code, a message
3095 +     * is logged, but no other action is taken.  Other authdata
3096 +     * plugins will be called, and a response will be sent to the
3097 +     * client (barring other problems).
3098 +     */
3099 +    krb5_error_code (*authdata_proc)(krb5_context,
3100 +                                     unsigned int flags,
3101 +                                     struct _krb5_db_entry_new *client,
3102 +                                     struct _krb5_db_entry_new *server,
3103 +                                     struct _krb5_db_entry_new *tgs,
3104 +                                     krb5_keyblock *client_key,
3105 +                                     krb5_keyblock *server_key,
3106 +                                     krb5_keyblock *tgs_key,
3107 +                                     krb5_data *req_pkt,
3108 +                                     krb5_kdc_req *request,
3109 +                                     krb5_const_principal for_user_princ,
3110 +                                     krb5_enc_tkt_part *enc_tkt_request,
3111 +                                     krb5_enc_tkt_part *enc_tkt_reply);
3112 +} krb5plugin_authdata_server_ftable_v2;
3113 +
3114 +typedef krb5plugin_authdata_server_ftable_v2 krb5plugin_authdata_ftable_v2;
3115 +
3116 +typedef krb5_error_code
3117 +(*authdata_client_plugin_init_proc)(krb5_context context,
3118 +                                    void **plugin_context);
3119 +
3120 +#define AD_USAGE_AS_REQ         0x01
3121 +#define AD_USAGE_TGS_REQ        0x02
3122 +#define AD_USAGE_AP_REQ         0x04
3123 +#define AD_USAGE_KDC_ISSUED     0x08
3124 +#define AD_USAGE_MASK           0x0F
3125 +#define AD_INFORMATIONAL        0x10
3126 +
3127 +struct _krb5_authdata_context;
3128 +
3129 +typedef void
3130 +(*authdata_client_plugin_flags_proc)(krb5_context kcontext,
3131 +                                     void *plugin_context,
3132 +                                     krb5_authdatatype ad_type,
3133 +                                     krb5_flags *flags);
3134 +
3135 +typedef void
3136 +(*authdata_client_plugin_fini_proc)(krb5_context kcontext,
3137 +                                    void *plugin_context);
3138 +
3139 +typedef krb5_error_code
3140 +(*authdata_client_request_init_proc)(krb5_context kcontext,
3141 +                                     struct _krb5_authdata_context *context,
3142 +                                     void *plugin_context,
3143 +                                     void **request_context);
3144 +
3145 +typedef void
3146 +(*authdata_client_request_fini_proc)(krb5_context kcontext,
3147 +                                     struct _krb5_authdata_context *context,
3148 +                                     void *plugin_context,
3149 +                                     void *request_context);
3150 +
3151 +typedef krb5_error_code
3152 +(*authdata_client_import_authdata_proc)(krb5_context kcontext,
3153 +                                        struct _krb5_authdata_context *context,
3154 +                                        void *plugin_context,
3155 +                                        void *request_context,
3156 +                                        krb5_authdata **authdata,
3157 +                                        krb5_boolean kdc_issued_flag,
3158 +                                        krb5_const_principal issuer);
3159 +
3160 +typedef krb5_error_code
3161 +(*authdata_client_export_authdata_proc)(krb5_context kcontext,
3162 +                                        struct _krb5_authdata_context *context,
3163 +                                        void *plugin_context,
3164 +                                        void *request_context,
3165 +                                        krb5_flags usage,
3166 +                                        krb5_authdata ***authdata);
3167 +
3168 +typedef krb5_error_code
3169 +(*authdata_client_get_attribute_types_proc)(krb5_context kcontext,
3170 +                                            struct _krb5_authdata_context *context,
3171 +                                            void *plugin_context,
3172 +                                            void *request_context,
3173 +                                            krb5_data **attrs);
3174 +
3175 +typedef krb5_error_code
3176 +(*authdata_client_get_attribute_proc)(krb5_context kcontext,
3177 +                                      struct _krb5_authdata_context *context,
3178 +                                      void *plugin_context,
3179 +                                      void *request_context,
3180 +                                      const krb5_data *attribute,
3181 +                                      krb5_boolean *authenticated,
3182 +                                      krb5_boolean *complete,
3183 +                                      krb5_data *value,
3184 +                                      krb5_data *display_value,
3185 +                                      int *more);
3186 +
3187 +typedef krb5_error_code
3188 +(*authdata_client_set_attribute_proc)(krb5_context kcontext,
3189 +                                      struct _krb5_authdata_context *context,
3190 +                                      void *plugin_context,
3191 +                                      void *request_context,
3192 +                                      krb5_boolean complete,
3193 +                                      const krb5_data *attribute,
3194 +                                      const krb5_data *value);
3195 +
3196 +typedef krb5_error_code
3197 +(*authdata_client_delete_attribute_proc)(krb5_context kcontext,
3198 +                                         struct _krb5_authdata_context *context,
3199 +                                         void *plugin_context,
3200 +                                         void *request_context,
3201 +                                         const krb5_data *attribute);
3202 +
3203 +typedef krb5_error_code
3204 +(*authdata_client_export_internal_proc)(krb5_context kcontext,
3205 +                                        struct _krb5_authdata_context *context,
3206 +                                        void *plugin_context,
3207 +                                        void *request_context,
3208 +                                        krb5_boolean restrict_authenticated,
3209 +                                        void **ptr);
3210 +
3211 +typedef void
3212 +(*authdata_client_free_internal_proc)(krb5_context kcontext,
3213 +                                      struct _krb5_authdata_context *context,
3214 +                                      void *plugin_context,
3215 +                                      void *request_context,
3216 +                                      void *ptr);
3217 +
3218 +typedef krb5_error_code
3219 +(*authdata_client_verify_proc)(krb5_context kcontext,
3220 +                               struct _krb5_authdata_context *context,
3221 +                               void *plugin_context,
3222 +                               void *request_context,
3223 +                               const krb5_auth_context *auth_context,
3224 +                               const krb5_keyblock *key,
3225 +                               const krb5_ap_req *req);
3226 +
3227 +typedef krb5_error_code
3228 +(*authdata_client_size_proc)(krb5_context kcontext,
3229 +                             struct _krb5_authdata_context *context,
3230 +                             void *plugin_context,
3231 +                             void *request_context,
3232 +                             size_t *sizep);
3233 +
3234 +typedef krb5_error_code
3235 +(*authdata_client_externalize_proc)(krb5_context kcontext,
3236 +                                    struct _krb5_authdata_context *context,
3237 +                                    void *plugin_context,
3238 +                                    void *request_context,
3239 +                                    krb5_octet **buffer,
3240 +                                    size_t *lenremain);
3241 +
3242 +typedef krb5_error_code
3243 +(*authdata_client_internalize_proc)(krb5_context kcontext,
3244 +                                    struct _krb5_authdata_context *context,
3245 +                                    void *plugin_context,
3246 +                                    void *request_context,
3247 +                                    krb5_octet **buffer,
3248 +                                    size_t *lenremain);
3249 +
3250 +typedef krb5_error_code
3251 +(*authdata_client_copy_proc)(krb5_context kcontext,
3252 +                             struct _krb5_authdata_context *context,
3253 +                             void *plugin_context,
3254 +                             void *request_context,
3255 +                             void *dst_plugin_context,
3256 +                             void *dst_request_context);
3257 +
3258 +typedef struct krb5plugin_authdata_client_ftable_v0 {
3259 +    char *name;
3260 +    krb5_authdatatype *ad_type_list;
3261 +    authdata_client_plugin_init_proc init;
3262 +    authdata_client_plugin_fini_proc fini;
3263 +    authdata_client_plugin_flags_proc flags;
3264 +    authdata_client_request_init_proc request_init;
3265 +    authdata_client_request_fini_proc request_fini;
3266 +    authdata_client_get_attribute_types_proc get_attribute_types;
3267 +    authdata_client_get_attribute_proc get_attribute;
3268 +    authdata_client_set_attribute_proc set_attribute;
3269 +    authdata_client_delete_attribute_proc delete_attribute;
3270 +    authdata_client_export_authdata_proc export_authdata;
3271 +    authdata_client_import_authdata_proc import_authdata;
3272 +    authdata_client_export_internal_proc export_internal;
3273 +    authdata_client_free_internal_proc free_internal;
3274 +    authdata_client_verify_proc verify;
3275 +    authdata_client_size_proc size;
3276 +    authdata_client_externalize_proc externalize;
3277 +    authdata_client_internalize_proc internalize;
3278 +    authdata_client_copy_proc copy; /* optional */
3279 +} krb5plugin_authdata_client_ftable_v0;
3280 +
3281 +#endif /* KRB5_AUTHDATA_PLUGIN_H_INCLUDED */
3282 diff --git a/mech_eap/authorize_localname.c b/mech_eap/authorize_localname.c
3283 new file mode 100644
3284 index 0000000..0037e2b
3285 --- /dev/null
3286 +++ b/mech_eap/authorize_localname.c
3287 @@ -0,0 +1,54 @@
3288 +/*
3289 + * Copyright (c) 2011, JANET(UK)
3290 + * All rights reserved.
3291 + *
3292 + * Redistribution and use in source and binary forms, with or without
3293 + * modification, are permitted provided that the following conditions
3294 + * are met:
3295 + *
3296 + * 1. Redistributions of source code must retain the above copyright
3297 + *    notice, this list of conditions and the following disclaimer.
3298 + *
3299 + * 2. Redistributions in binary form must reproduce the above copyright
3300 + *    notice, this list of conditions and the following disclaimer in the
3301 + *    documentation and/or other materials provided with the distribution.
3302 + *
3303 + * 3. Neither the name of JANET(UK) nor the names of its contributors
3304 + *    may be used to endorse or promote products derived from this software
3305 + *    without specific prior written permission.
3306 + *
3307 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3308 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3309 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3310 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3311 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3312 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3313 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3314 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3315 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3316 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3317 + * SUCH DAMAGE.
3318 + */
3319 +
3320 +/*
3321 + * Local authorization services.
3322 + */
3323 +
3324 +#include "gssapiP_eap.h"
3325 +
3326 +OM_uint32 GSSAPI_CALLCONV
3327 +gssspi_authorize_localname(OM_uint32 *minor,
3328 +                           const gss_name_t name GSSEAP_UNUSED,
3329 +                           gss_const_buffer_t local_user GSSEAP_UNUSED,
3330 +                           gss_const_OID local_nametype GSSEAP_UNUSED)
3331 +{
3332 +    /*
3333 +     * The MIT mechglue will fallback to comparing names in the absence
3334 +     * of a mechanism implementation of gss_userok. To avoid this and
3335 +     * force the mechglue to use attribute-based authorization, always
3336 +     * return access denied here.
3337 +     */
3338 +
3339 +    *minor = 0;
3340 +    return GSS_S_UNAUTHORIZED;
3341 +}
3342 diff --git a/mech_eap/canonicalize_name.c b/mech_eap/canonicalize_name.c
3343 new file mode 100644
3344 index 0000000..5e66798
3345 --- /dev/null
3346 +++ b/mech_eap/canonicalize_name.c
3347 @@ -0,0 +1,64 @@
3348 +/*
3349 + * Copyright (c) 2011, JANET(UK)
3350 + * All rights reserved.
3351 + *
3352 + * Redistribution and use in source and binary forms, with or without
3353 + * modification, are permitted provided that the following conditions
3354 + * are met:
3355 + *
3356 + * 1. Redistributions of source code must retain the above copyright
3357 + *    notice, this list of conditions and the following disclaimer.
3358 + *
3359 + * 2. Redistributions in binary form must reproduce the above copyright
3360 + *    notice, this list of conditions and the following disclaimer in the
3361 + *    documentation and/or other materials provided with the distribution.
3362 + *
3363 + * 3. Neither the name of JANET(UK) nor the names of its contributors
3364 + *    may be used to endorse or promote products derived from this software
3365 + *    without specific prior written permission.
3366 + *
3367 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3368 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3369 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3370 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3371 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3372 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3373 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3374 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3375 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3376 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3377 + * SUCH DAMAGE.
3378 + */
3379 +
3380 +/*
3381 + * Function for canonicalizing a name; presently just duplicates it.
3382 + */
3383 +
3384 +#include "gssapiP_eap.h"
3385 +
3386 +OM_uint32 GSSAPI_CALLCONV
3387 +gss_canonicalize_name(OM_uint32 *minor,
3388 +                      const gss_name_t input_name,
3389 +                      const gss_OID mech_type,
3390 +                      gss_name_t *output_name)
3391 +{
3392 +    OM_uint32 major;
3393 +
3394 +    *minor = 0;
3395 +
3396 +    if (!gssEapIsMechanismOid(mech_type))
3397 +        return GSS_S_BAD_MECH;
3398 +
3399 +    if (input_name == GSS_C_NO_NAME) {
3400 +        *minor = EINVAL;
3401 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
3402 +    }
3403 +
3404 +    GSSEAP_MUTEX_LOCK(&input_name->mutex);
3405 +
3406 +    major = gssEapCanonicalizeName(minor, input_name, mech_type, output_name);
3407 +
3408 +    GSSEAP_MUTEX_UNLOCK(&input_name->mutex);
3409 +
3410 +    return major;
3411 +}
3412 diff --git a/mech_eap/compare_name.c b/mech_eap/compare_name.c
3413 new file mode 100644
3414 index 0000000..edadf3e
3415 --- /dev/null
3416 +++ b/mech_eap/compare_name.c
3417 @@ -0,0 +1,46 @@
3418 +/*
3419 + * Copyright (c) 2011, JANET(UK)
3420 + * All rights reserved.
3421 + *
3422 + * Redistribution and use in source and binary forms, with or without
3423 + * modification, are permitted provided that the following conditions
3424 + * are met:
3425 + *
3426 + * 1. Redistributions of source code must retain the above copyright
3427 + *    notice, this list of conditions and the following disclaimer.
3428 + *
3429 + * 2. Redistributions in binary form must reproduce the above copyright
3430 + *    notice, this list of conditions and the following disclaimer in the
3431 + *    documentation and/or other materials provided with the distribution.
3432 + *
3433 + * 3. Neither the name of JANET(UK) nor the names of its contributors
3434 + *    may be used to endorse or promote products derived from this software
3435 + *    without specific prior written permission.
3436 + *
3437 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3438 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3439 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3440 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3441 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3442 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3443 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3444 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3445 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3446 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3447 + * SUCH DAMAGE.
3448 + */
3449 +
3450 +/*
3451 + * Compare two names.
3452 + */
3453 +
3454 +#include "gssapiP_eap.h"
3455 +
3456 +OM_uint32 GSSAPI_CALLCONV
3457 +gss_compare_name(OM_uint32 *minor,
3458 +                 gss_name_t name1,
3459 +                 gss_name_t name2,
3460 +                 int *name_equal)
3461 +{
3462 +    return gssEapCompareName(minor, name1, name2, name_equal);
3463 +}
3464 diff --git a/mech_eap/context_time.c b/mech_eap/context_time.c
3465 new file mode 100644
3466 index 0000000..ae47d6c
3467 --- /dev/null
3468 +++ b/mech_eap/context_time.c
3469 @@ -0,0 +1,69 @@
3470 +/*
3471 + * Copyright (c) 2011, JANET(UK)
3472 + * All rights reserved.
3473 + *
3474 + * Redistribution and use in source and binary forms, with or without
3475 + * modification, are permitted provided that the following conditions
3476 + * are met:
3477 + *
3478 + * 1. Redistributions of source code must retain the above copyright
3479 + *    notice, this list of conditions and the following disclaimer.
3480 + *
3481 + * 2. Redistributions in binary form must reproduce the above copyright
3482 + *    notice, this list of conditions and the following disclaimer in the
3483 + *    documentation and/or other materials provided with the distribution.
3484 + *
3485 + * 3. Neither the name of JANET(UK) nor the names of its contributors
3486 + *    may be used to endorse or promote products derived from this software
3487 + *    without specific prior written permission.
3488 + *
3489 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3490 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3491 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3492 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3493 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3494 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3495 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3496 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3497 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3498 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3499 + * SUCH DAMAGE.
3500 + */
3501 +
3502 +/*
3503 + * Determine remaining lifetime of a context handle.
3504 + */
3505 +
3506 +#include "gssapiP_eap.h"
3507 +
3508 +OM_uint32 GSSAPI_CALLCONV
3509 +gss_context_time(OM_uint32 *minor,
3510 +                 gss_ctx_id_t ctx,
3511 +                 OM_uint32 *time_rec)
3512 +{
3513 +    OM_uint32 major;
3514 +
3515 +    if (ctx == GSS_C_NO_CONTEXT) {
3516 +        *minor = EINVAL;
3517 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
3518 +    }
3519 +
3520 +    *minor = 0;
3521 +
3522 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
3523 +
3524 +    if (!CTX_IS_ESTABLISHED(ctx)) {
3525 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
3526 +        major = GSS_S_NO_CONTEXT;
3527 +        goto cleanup;
3528 +    }
3529 +
3530 +    major = gssEapContextTime(minor, ctx, time_rec);
3531 +    if (GSS_ERROR(major))
3532 +        goto cleanup;
3533 +
3534 +cleanup:
3535 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
3536 +
3537 +    return major;
3538 +}
3539 diff --git a/mech_eap/delete_name_attribute.c b/mech_eap/delete_name_attribute.c
3540 new file mode 100644
3541 index 0000000..fe0ff8f
3542 --- /dev/null
3543 +++ b/mech_eap/delete_name_attribute.c
3544 @@ -0,0 +1,60 @@
3545 +/*
3546 + * Copyright (c) 2011, JANET(UK)
3547 + * All rights reserved.
3548 + *
3549 + * Redistribution and use in source and binary forms, with or without
3550 + * modification, are permitted provided that the following conditions
3551 + * are met:
3552 + *
3553 + * 1. Redistributions of source code must retain the above copyright
3554 + *    notice, this list of conditions and the following disclaimer.
3555 + *
3556 + * 2. Redistributions in binary form must reproduce the above copyright
3557 + *    notice, this list of conditions and the following disclaimer in the
3558 + *    documentation and/or other materials provided with the distribution.
3559 + *
3560 + * 3. Neither the name of JANET(UK) nor the names of its contributors
3561 + *    may be used to endorse or promote products derived from this software
3562 + *    without specific prior written permission.
3563 + *
3564 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3565 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3566 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3567 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3568 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3569 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3570 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3571 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3572 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3573 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3574 + * SUCH DAMAGE.
3575 + */
3576 +
3577 +/*
3578 + * Wrapper for removing a name attribute.
3579 + */
3580 +
3581 +#include "gssapiP_eap.h"
3582 +
3583 +OM_uint32 GSSAPI_CALLCONV
3584 +gss_delete_name_attribute(OM_uint32 *minor,
3585 +                          gss_name_t name,
3586 +                          gss_buffer_t attr)
3587 +{
3588 +    OM_uint32 major;
3589 +
3590 +    *minor = 0;
3591 +
3592 +    if (name == GSS_C_NO_NAME) {
3593 +        *minor = EINVAL;
3594 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
3595 +    }
3596 +
3597 +    GSSEAP_MUTEX_LOCK(&name->mutex);
3598 +
3599 +    major = gssEapDeleteNameAttribute(minor, name, attr);
3600 +
3601 +    GSSEAP_MUTEX_UNLOCK(&name->mutex);
3602 +
3603 +    return major;
3604 +}
3605 diff --git a/mech_eap/delete_sec_context.c b/mech_eap/delete_sec_context.c
3606 new file mode 100644
3607 index 0000000..7913e45
3608 --- /dev/null
3609 +++ b/mech_eap/delete_sec_context.c
3610 @@ -0,0 +1,81 @@
3611 +/*
3612 + * Copyright (c) 2011, JANET(UK)
3613 + * All rights reserved.
3614 + *
3615 + * Redistribution and use in source and binary forms, with or without
3616 + * modification, are permitted provided that the following conditions
3617 + * are met:
3618 + *
3619 + * 1. Redistributions of source code must retain the above copyright
3620 + *    notice, this list of conditions and the following disclaimer.
3621 + *
3622 + * 2. Redistributions in binary form must reproduce the above copyright
3623 + *    notice, this list of conditions and the following disclaimer in the
3624 + *    documentation and/or other materials provided with the distribution.
3625 + *
3626 + * 3. Neither the name of JANET(UK) nor the names of its contributors
3627 + *    may be used to endorse or promote products derived from this software
3628 + *    without specific prior written permission.
3629 + *
3630 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3631 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3632 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3633 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3634 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3635 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3636 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3637 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3638 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3639 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3640 + * SUCH DAMAGE.
3641 + */
3642 +
3643 +/*
3644 + * Release a context handle.
3645 + */
3646 +
3647 +#include "gssapiP_eap.h"
3648 +
3649 +OM_uint32 GSSAPI_CALLCONV
3650 +gss_delete_sec_context(OM_uint32 *minor,
3651 +                       gss_ctx_id_t *context_handle,
3652 +                       gss_buffer_t output_token)
3653 +{
3654 +    OM_uint32 major;
3655 +    gss_ctx_id_t ctx = *context_handle;
3656 +
3657 +    *minor = 0;
3658 +
3659 +    if (output_token != GSS_C_NO_BUFFER) {
3660 +        output_token->length = 0;
3661 +        output_token->value = NULL;
3662 +    }
3663 +
3664 +    if (ctx == GSS_C_NO_CONTEXT)
3665 +        return GSS_S_COMPLETE;
3666 +
3667 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
3668 +
3669 +    if (output_token != GSS_C_NO_BUFFER) {
3670 +        gss_iov_buffer_desc iov[2];
3671 +
3672 +        iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
3673 +        iov[0].buffer.value = NULL;
3674 +        iov[0].buffer.length = 0;
3675 +
3676 +        iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
3677 +        iov[1].buffer.value = NULL;
3678 +        iov[1].buffer.length = 0;
3679 +
3680 +        major = gssEapWrapOrGetMIC(minor, ctx, FALSE, NULL,
3681 +                                   iov, 2, TOK_TYPE_DELETE_CONTEXT);
3682 +        if (GSS_ERROR(major)) {
3683 +            GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
3684 +            return major;
3685 +        }
3686 +    }
3687 +
3688 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
3689 +
3690 +    return gssEapReleaseContext(minor, context_handle);
3691 +}
3692 diff --git a/mech_eap/dictionary.ukerna b/mech_eap/dictionary.ukerna
3693 new file mode 100644
3694 index 0000000..0e35d43
3695 --- /dev/null
3696 +++ b/mech_eap/dictionary.ukerna
3697 @@ -0,0 +1,20 @@
3698 +# -*- text -*-
3699 +#
3700 +#      GSS-EAP VSAs
3701 +#
3702 +#      $Id$
3703 +#
3704 +
3705 +VENDOR UKERNA                          25622
3706 +
3707 +BEGIN-VENDOR UKERNA
3708 +
3709 +ATTRIBUTE      GSS-Acceptor-Service-Name       128     string
3710 +ATTRIBUTE      GSS-Acceptor-Host-Name          129     string
3711 +ATTRIBUTE      GSS-Acceptor-Service-Specific   130     string
3712 +ATTRIBUTE      GSS-Acceptor-Realm-Name         131     string
3713 +ATTRIBUTE      SAML-AAA-Assertion              132     string
3714 +ATTRIBUTE      MS-Windows-Auth-Data            133     octets
3715 +ATTRIBUTE      MS-Windows-Group-Sid            134     string
3716 +
3717 +END-VENDOR UKERNA
3718 diff --git a/mech_eap/display_name.c b/mech_eap/display_name.c
3719 new file mode 100644
3720 index 0000000..2d87e66
3721 --- /dev/null
3722 +++ b/mech_eap/display_name.c
3723 @@ -0,0 +1,48 @@
3724 +/*
3725 + * Copyright (c) 2011, JANET(UK)
3726 + * All rights reserved.
3727 + *
3728 + * Redistribution and use in source and binary forms, with or without
3729 + * modification, are permitted provided that the following conditions
3730 + * are met:
3731 + *
3732 + * 1. Redistributions of source code must retain the above copyright
3733 + *    notice, this list of conditions and the following disclaimer.
3734 + *
3735 + * 2. Redistributions in binary form must reproduce the above copyright
3736 + *    notice, this list of conditions and the following disclaimer in the
3737 + *    documentation and/or other materials provided with the distribution.
3738 + *
3739 + * 3. Neither the name of JANET(UK) nor the names of its contributors
3740 + *    may be used to endorse or promote products derived from this software
3741 + *    without specific prior written permission.
3742 + *
3743 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3744 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3745 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3746 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3747 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3748 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3749 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3750 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3751 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3752 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3753 + * SUCH DAMAGE.
3754 + */
3755 +
3756 +/*
3757 + * Wrapper for "displaying" (returning string representation of) a name.
3758 + */
3759 +
3760 +#include "gssapiP_eap.h"
3761 +
3762 +OM_uint32 GSSAPI_CALLCONV
3763 +gss_display_name(OM_uint32 *minor,
3764 +                 gss_name_t name,
3765 +                 gss_buffer_t output_name_buffer,
3766 +                 gss_OID *output_name_type)
3767 +{
3768 +    /* Lock not required as long as attributes are not used */
3769 +    return gssEapDisplayName(minor, name, output_name_buffer,
3770 +                             output_name_type);
3771 +}
3772 diff --git a/mech_eap/display_name_ext.c b/mech_eap/display_name_ext.c
3773 new file mode 100644
3774 index 0000000..d6791d4
3775 --- /dev/null
3776 +++ b/mech_eap/display_name_ext.c
3777 @@ -0,0 +1,51 @@
3778 +/*
3779 + * Copyright (c) 2011, JANET(UK)
3780 + * All rights reserved.
3781 + *
3782 + * Redistribution and use in source and binary forms, with or without
3783 + * modification, are permitted provided that the following conditions
3784 + * are met:
3785 + *
3786 + * 1. Redistributions of source code must retain the above copyright
3787 + *    notice, this list of conditions and the following disclaimer.
3788 + *
3789 + * 2. Redistributions in binary form must reproduce the above copyright
3790 + *    notice, this list of conditions and the following disclaimer in the
3791 + *    documentation and/or other materials provided with the distribution.
3792 + *
3793 + * 3. Neither the name of JANET(UK) nor the names of its contributors
3794 + *    may be used to endorse or promote products derived from this software
3795 + *    without specific prior written permission.
3796 + *
3797 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3798 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3799 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3800 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3801 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3802 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3803 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3804 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3805 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3806 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3807 + * SUCH DAMAGE.
3808 + */
3809 +
3810 +/*
3811 + * Parameterized version of gss_display_name(), currently unimplemented.
3812 + */
3813 +
3814 +#include "gssapiP_eap.h"
3815 +
3816 +OM_uint32 GSSAPI_CALLCONV
3817 +gss_display_name_ext(OM_uint32 *minor,
3818 +                     gss_name_t name GSSEAP_UNUSED,
3819 +                     gss_OID display_as_name_type GSSEAP_UNUSED,
3820 +                     gss_buffer_t display_name)
3821 +{
3822 +    *minor = 0;
3823 +
3824 +    display_name->length = 0;
3825 +    display_name->value = NULL;
3826 +
3827 +    return GSS_S_UNAVAILABLE;
3828 +}
3829 diff --git a/mech_eap/display_status.c b/mech_eap/display_status.c
3830 new file mode 100644
3831 index 0000000..fc0d1ab
3832 --- /dev/null
3833 +++ b/mech_eap/display_status.c
3834 @@ -0,0 +1,203 @@
3835 +/*
3836 + * Copyright (c) 2011, JANET(UK)
3837 + * All rights reserved.
3838 + *
3839 + * Redistribution and use in source and binary forms, with or without
3840 + * modification, are permitted provided that the following conditions
3841 + * are met:
3842 + *
3843 + * 1. Redistributions of source code must retain the above copyright
3844 + *    notice, this list of conditions and the following disclaimer.
3845 + *
3846 + * 2. Redistributions in binary form must reproduce the above copyright
3847 + *    notice, this list of conditions and the following disclaimer in the
3848 + *    documentation and/or other materials provided with the distribution.
3849 + *
3850 + * 3. Neither the name of JANET(UK) nor the names of its contributors
3851 + *    may be used to endorse or promote products derived from this software
3852 + *    without specific prior written permission.
3853 + *
3854 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
3855 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3856 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3857 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
3858 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3859 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3860 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3861 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3862 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3863 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3864 + * SUCH DAMAGE.
3865 + */
3866 +
3867 +/*
3868 + * Function for converting mechanism error codes to strings.
3869 + */
3870 +
3871 +#include "gssapiP_eap.h"
3872 +
3873 +struct gss_eap_status_info {
3874 +    OM_uint32 code;
3875 +    char *message;
3876 +    struct gss_eap_status_info *next;
3877 +};
3878 +
3879 +void
3880 +gssEapDestroyStatusInfo(struct gss_eap_status_info *p)
3881 +{
3882 +    struct gss_eap_status_info *next;
3883 +
3884 +    for (; p != NULL; p = next) {
3885 +        next = p->next;
3886 +        GSSEAP_FREE(p->message);
3887 +        GSSEAP_FREE(p);
3888 +    }
3889 +}
3890 +
3891 +/*
3892 + * Associate a message with a mechanism (minor) status code. This function
3893 + * takes ownership of the message regardless of success. The message must
3894 + * be explicitly cleared, if required, so it is suggested that a specific
3895 + * minor code is either always or never associated with a message, to avoid
3896 + * dangling (and potentially confusing) error messages.
3897 + */
3898 +static void
3899 +saveStatusInfoNoCopy(OM_uint32 minor, char *message)
3900 +{
3901 +    struct gss_eap_status_info **next = NULL, *p = NULL;
3902 +    struct gss_eap_thread_local_data *tld = gssEapGetThreadLocalData();
3903 +
3904 +    if (tld != NULL) {
3905 +        for (p = tld->statusInfo; p != NULL; p = p->next) {
3906 +            if (p->code == minor) {
3907 +                /* Set message in-place */
3908 +                if (p->message != NULL)
3909 +                    GSSEAP_FREE(p->message);
3910 +                p->message = message;
3911 +                return;
3912 +            }
3913 +            next = &p->next;
3914 +        }
3915 +        p = GSSEAP_CALLOC(1, sizeof(*p));
3916 +    }
3917 +
3918 +    if (p == NULL) {
3919 +        if (message != NULL)
3920 +            GSSEAP_FREE(message);
3921 +        return;
3922 +    }
3923 +
3924 +    p->code = minor;
3925 +    p->message = message;
3926 +
3927 +    if (next != NULL)
3928 +        *next = p;
3929 +    else
3930 +        tld->statusInfo = p;
3931 +}
3932 +
3933 +static const char *
3934 +getStatusInfo(OM_uint32 minor)
3935 +{
3936 +    struct gss_eap_status_info *p;
3937 +    struct gss_eap_thread_local_data *tld = gssEapGetThreadLocalData();
3938 +
3939 +    if (tld != NULL) {
3940 +        for (p = tld->statusInfo; p != NULL; p = p->next) {
3941 +            if (p->code == minor)
3942 +                return p->message;
3943 +        }
3944 +    }
3945 +    return NULL;
3946 +}
3947 +
3948 +void
3949 +gssEapSaveStatusInfo(OM_uint32 minor, const char *format, ...)
3950 +{
3951 +#ifdef WIN32
3952 +    OM_uint32 tmpMajor, tmpMinor;
3953 +    char buf[BUFSIZ];
3954 +    gss_buffer_desc s = GSS_C_EMPTY_BUFFER;
3955 +    va_list ap;
3956 +
3957 +    if (format != NULL) {
3958 +        va_start(ap, format);
3959 +        snprintf(buf, sizeof(buf), format, ap);
3960 +        va_end(ap);
3961 +    }
3962 +
3963 +    tmpMajor = makeStringBuffer(&tmpMinor, buf, &s);
3964 +    if (!GSS_ERROR(tmpMajor))
3965 +        saveStatusInfoNoCopy(minor, (char *)s.value);
3966 +#else
3967 +    char *s = NULL;
3968 +    int n;
3969 +    va_list ap;
3970 +
3971 +    if (format != NULL) {
3972 +        va_start(ap, format);
3973 +        n = vasprintf(&s, format, ap);
3974 +        if (n == -1)
3975 +            s = NULL;
3976 +        va_end(ap);
3977 +    }
3978 +
3979 +    saveStatusInfoNoCopy(minor, s);
3980 +#endif /* WIN32 */
3981 +}
3982 +
3983 +OM_uint32
3984 +gssEapDisplayStatus(OM_uint32 *minor,
3985 +                    OM_uint32 status_value,
3986 +                    gss_buffer_t status_string)
3987 +{
3988 +    OM_uint32 major;
3989 +    krb5_context krbContext = NULL;
3990 +    const char *errMsg;
3991 +
3992 +    status_string->length = 0;
3993 +    status_string->value = NULL;
3994 +
3995 +    errMsg = getStatusInfo(status_value);
3996 +    if (errMsg == NULL) {
3997 +        GSSEAP_KRB_INIT(&krbContext);
3998 +
3999 +        /* Try the com_err message */
4000 +        errMsg = krb5_get_error_message(krbContext, status_value);
4001 +    }
4002 +
4003 +    if (errMsg != NULL) {
4004 +        major = makeStringBuffer(minor, errMsg, status_string);
4005 +    } else {
4006 +        major = GSS_S_COMPLETE;
4007 +        *minor = 0;
4008 +    }
4009 +
4010 +    if (krbContext != NULL)
4011 +        krb5_free_error_message(krbContext, errMsg);
4012 +
4013 +    return major;
4014 +}
4015 +
4016 +OM_uint32 GSSAPI_CALLCONV
4017 +gss_display_status(OM_uint32 *minor,
4018 +                   OM_uint32 status_value,
4019 +                   int status_type,
4020 +                   gss_OID mech_type,
4021 +                   OM_uint32 *message_context,
4022 +                   gss_buffer_t status_string)
4023 +{
4024 +    if (!gssEapIsMechanismOid(mech_type)) {
4025 +        *minor = GSSEAP_WRONG_MECH;
4026 +        return GSS_S_BAD_MECH;
4027 +    }
4028 +
4029 +    if (status_type != GSS_C_MECH_CODE ||
4030 +        *message_context != 0) {
4031 +        /* we rely on the mechglue for GSS_C_GSS_CODE */
4032 +        *minor = 0;
4033 +        return GSS_S_BAD_STATUS;
4034 +    }
4035 +
4036 +    return gssEapDisplayStatus(minor, status_value, status_string);
4037 +}
4038 diff --git a/mech_eap/duplicate_name.c b/mech_eap/duplicate_name.c
4039 new file mode 100644
4040 index 0000000..303619e
4041 --- /dev/null
4042 +++ b/mech_eap/duplicate_name.c
4043 @@ -0,0 +1,60 @@
4044 +/*
4045 + * Copyright (c) 2011, JANET(UK)
4046 + * All rights reserved.
4047 + *
4048 + * Redistribution and use in source and binary forms, with or without
4049 + * modification, are permitted provided that the following conditions
4050 + * are met:
4051 + *
4052 + * 1. Redistributions of source code must retain the above copyright
4053 + *    notice, this list of conditions and the following disclaimer.
4054 + *
4055 + * 2. Redistributions in binary form must reproduce the above copyright
4056 + *    notice, this list of conditions and the following disclaimer in the
4057 + *    documentation and/or other materials provided with the distribution.
4058 + *
4059 + * 3. Neither the name of JANET(UK) nor the names of its contributors
4060 + *    may be used to endorse or promote products derived from this software
4061 + *    without specific prior written permission.
4062 + *
4063 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
4064 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4065 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4066 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
4067 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4068 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4069 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4070 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4071 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4072 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4073 + * SUCH DAMAGE.
4074 + */
4075 +
4076 +/*
4077 + * Duplicate a name.
4078 + */
4079 +
4080 +#include "gssapiP_eap.h"
4081 +
4082 +OM_uint32 GSSAPI_CALLCONV
4083 +gss_duplicate_name(OM_uint32 *minor,
4084 +                   const gss_name_t input_name,
4085 +                   gss_name_t *dest_name)
4086 +{
4087 +    OM_uint32 major;
4088 +
4089 +    *minor = 0;
4090 +
4091 +    if (input_name == GSS_C_NO_NAME) {
4092 +        *minor = EINVAL;
4093 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
4094 +    }
4095 +
4096 +    GSSEAP_MUTEX_LOCK(&input_name->mutex);
4097 +
4098 +    major = gssEapDuplicateName(minor, input_name, dest_name);
4099 +
4100 +    GSSEAP_MUTEX_UNLOCK(&input_name->mutex);
4101 +
4102 +    return major;
4103 +}
4104 diff --git a/mech_eap/eap_mech.c b/mech_eap/eap_mech.c
4105 new file mode 100644
4106 index 0000000..96e00c2
4107 --- /dev/null
4108 +++ b/mech_eap/eap_mech.c
4109 @@ -0,0 +1,219 @@
4110 +/*
4111 + * Copyright (c) 2011, JANET(UK)
4112 + * All rights reserved.
4113 + *
4114 + * Redistribution and use in source and binary forms, with or without
4115 + * modification, are permitted provided that the following conditions
4116 + * are met:
4117 + *
4118 + * 1. Redistributions of source code must retain the above copyright
4119 + *    notice, this list of conditions and the following disclaimer.
4120 + *
4121 + * 2. Redistributions in binary form must reproduce the above copyright
4122 + *    notice, this list of conditions and the following disclaimer in the
4123 + *    documentation and/or other materials provided with the distribution.
4124 + *
4125 + * 3. Neither the name of JANET(UK) nor the names of its contributors
4126 + *    may be used to endorse or promote products derived from this software
4127 + *    without specific prior written permission.
4128 + *
4129 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
4130 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4131 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4132 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
4133 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4134 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4135 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4136 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4137 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4138 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4139 + * SUCH DAMAGE.
4140 + */
4141 +
4142 +/*
4143 + * Initialisation and finalise functions.
4144 + */
4145 +
4146 +#include "gssapiP_eap.h"
4147 +
4148 +static OM_uint32
4149 +eapPeerRegisterMethods(OM_uint32 *minor)
4150 +{
4151 +    OM_uint32 ret = 0;
4152 +
4153 +#ifdef EAP_MD5
4154 +    if (ret == 0)
4155 +        ret = eap_peer_md5_register();
4156 +#endif /* EAP_MD5 */
4157 +
4158 +#ifdef EAP_TLS
4159 +    if (ret == 0)
4160 +        ret = eap_peer_tls_register();
4161 +#endif /* EAP_TLS */
4162 +
4163 +#ifdef EAP_MSCHAPv2
4164 +    if (ret == 0)
4165 +        ret = eap_peer_mschapv2_register();
4166 +#endif /* EAP_MSCHAPv2 */
4167 +
4168 +#ifdef EAP_PEAP
4169 +    if (ret == 0)
4170 +        ret = eap_peer_peap_register();
4171 +#endif /* EAP_PEAP */
4172 +
4173 +#ifdef EAP_TTLS
4174 +    if (ret == 0)
4175 +        ret = eap_peer_ttls_register();
4176 +#endif /* EAP_TTLS */
4177 +
4178 +#ifdef EAP_GTC
4179 +    if (ret == 0)
4180 +        ret = eap_peer_gtc_register();
4181 +#endif /* EAP_GTC */
4182 +
4183 +#ifdef EAP_OTP
4184 +    if (ret == 0)
4185 +        ret = eap_peer_otp_register();
4186 +#endif /* EAP_OTP */
4187 +
4188 +#ifdef EAP_SIM
4189 +    if (ret == 0)
4190 +        ret = eap_peer_sim_register();
4191 +#endif /* EAP_SIM */
4192 +
4193 +#ifdef EAP_LEAP
4194 +    if (ret == 0)
4195 +        ret = eap_peer_leap_register();
4196 +#endif /* EAP_LEAP */
4197 +
4198 +#ifdef EAP_PSK
4199 +    if (ret == 0)
4200 +        ret = eap_peer_psk_register();
4201 +#endif /* EAP_PSK */
4202 +
4203 +#ifdef EAP_AKA
4204 +    if (ret == 0)
4205 +        ret = eap_peer_aka_register();
4206 +#endif /* EAP_AKA */
4207 +
4208 +#ifdef EAP_AKA_PRIME
4209 +    if (ret == 0)
4210 +        ret = eap_peer_aka_prime_register();
4211 +#endif /* EAP_AKA_PRIME */
4212 +
4213 +#ifdef EAP_FAST
4214 +    if (ret == 0)
4215 +        ret = eap_peer_fast_register();
4216 +#endif /* EAP_FAST */
4217 +
4218 +#ifdef EAP_PAX
4219 +    if (ret == 0)
4220 +        ret = eap_peer_pax_register();
4221 +#endif /* EAP_PAX */
4222 +
4223 +#ifdef EAP_SAKE
4224 +    if (ret == 0)
4225 +        ret = eap_peer_sake_register();
4226 +#endif /* EAP_SAKE */
4227 +
4228 +#ifdef EAP_GPSK
4229 +    if (ret == 0)
4230 +        ret = eap_peer_gpsk_register();
4231 +#endif /* EAP_GPSK */
4232 +
4233 +#ifdef EAP_WSC
4234 +    if (ret == 0)
4235 +        ret = eap_peer_wsc_register();
4236 +#endif /* EAP_WSC */
4237 +
4238 +#ifdef EAP_IKEV2
4239 +    if (ret == 0)
4240 +        ret = eap_peer_ikev2_register();
4241 +#endif /* EAP_IKEV2 */
4242 +
4243 +#ifdef EAP_VENDOR_TEST
4244 +    if (ret == 0)
4245 +        ret = eap_peer_vendor_test_register();
4246 +#endif /* EAP_VENDOR_TEST */
4247 +
4248 +#ifdef EAP_TNC
4249 +    if (ret == 0)
4250 +        ret = eap_peer_tnc_register();
4251 +#endif /* EAP_TNC */
4252 +
4253 +    if (ret == 0)
4254 +        return GSS_S_COMPLETE;
4255 +
4256 +    *minor = GSSEAP_LIBEAP_INIT_FAILURE;
4257 +    return GSS_S_FAILURE;
4258 +}
4259 +
4260 +static OM_uint32
4261 +gssEapInitLibEap(OM_uint32 *minor)
4262 +{
4263 +    return eapPeerRegisterMethods(minor);
4264 +}
4265 +
4266 +static OM_uint32
4267 +gssEapInitLibRadsec(OM_uint32 *minor)
4268 +{
4269 +    if (0) {
4270 +        *minor = GSSEAP_RADSEC_INIT_FAILURE;
4271 +        return GSS_S_FAILURE;
4272 +    }
4273 +
4274 +    return GSS_S_COMPLETE;
4275 +}
4276 +
4277 +void gssEapFinalize(void) GSSEAP_DESTRUCTOR;
4278 +
4279 +OM_uint32
4280 +gssEapInitiatorInit(OM_uint32 *minor)
4281 +{
4282 +    OM_uint32 major;
4283 +
4284 +    initialize_eapg_error_table();
4285 +    initialize_rse_error_table();
4286 +
4287 +    major = gssEapInitLibEap(minor);
4288 +    if (GSS_ERROR(major))
4289 +        return major;
4290 +
4291 +    major = gssEapInitLibRadsec(minor);
4292 +    if (GSS_ERROR(major))
4293 +        return major;
4294 +
4295 +#ifdef GSSEAP_ENABLE_REAUTH
4296 +    major = gssEapReauthInitialize(minor);
4297 +    if (GSS_ERROR(major))
4298 +        return major;
4299 +#endif
4300 +
4301 +    *minor = 0;
4302 +    return GSS_S_COMPLETE;
4303 +}
4304 +
4305 +void
4306 +gssEapFinalize(void)
4307 +{
4308 +#ifdef GSSEAP_ENABLE_ACCEPTOR
4309 +    OM_uint32 minor;
4310 +
4311 +    gssEapAttrProvidersFinalize(&minor);
4312 +#endif
4313 +    eap_peer_unregister_methods();
4314 +}
4315 +
4316 +#ifdef GSSEAP_CONSTRUCTOR
4317 +static void gssEapInitiatorInitAssert(void) GSSEAP_CONSTRUCTOR;
4318 +
4319 +static void
4320 +gssEapInitiatorInitAssert(void)
4321 +{
4322 +    OM_uint32 major, minor;
4323 +
4324 +    major = gssEapInitiatorInit(&minor);
4325 +
4326 +    GSSEAP_ASSERT(!GSS_ERROR(major));
4327 +}
4328 +#endif
4329 diff --git a/mech_eap/exchange_meta_data.c b/mech_eap/exchange_meta_data.c
4330 new file mode 100644
4331 index 0000000..5d56795
4332 --- /dev/null
4333 +++ b/mech_eap/exchange_meta_data.c
4334 @@ -0,0 +1,82 @@
4335 +/*
4336 + * Copyright (c) 2011, JANET(UK)
4337 + * All rights reserved.
4338 + *
4339 + * Redistribution and use in source and binary forms, with or without
4340 + * modification, are permitted provided that the following conditions
4341 + * are met:
4342 + *
4343 + * 1. Redistributions of source code must retain the above copyright
4344 + *    notice, this list of conditions and the following disclaimer.
4345 + *
4346 + * 2. Redistributions in binary form must reproduce the above copyright
4347 + *    notice, this list of conditions and the following disclaimer in the
4348 + *    documentation and/or other materials provided with the distribution.
4349 + *
4350 + * 3. Neither the name of JANET(UK) nor the names of its contributors
4351 + *    may be used to endorse or promote products derived from this software
4352 + *    without specific prior written permission.
4353 + *
4354 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
4355 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4356 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4357 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
4358 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4359 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4360 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4361 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4362 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4363 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4364 + * SUCH DAMAGE.
4365 + */
4366 +
4367 +/*
4368 + *
4369 + */
4370 +
4371 +#include "gssapiP_eap.h"
4372 +
4373 +OM_uint32 GSSAPI_CALLCONV
4374 +gssEapExchangeMetaData(OM_uint32 *minor,
4375 +                       gss_const_OID mech GSSEAP_UNUSED,
4376 +                       gss_cred_id_t cred GSSEAP_UNUSED,
4377 +                       gss_ctx_id_t *ctx GSSEAP_UNUSED,
4378 +                       const gss_name_t name GSSEAP_UNUSED,
4379 +                       OM_uint32 req_flags GSSEAP_UNUSED,
4380 +                       gss_const_buffer_t meta_data GSSEAP_UNUSED)
4381 +{
4382 +    *minor = 0;
4383 +    return GSS_S_COMPLETE;
4384 +}
4385 +
4386 +OM_uint32 GSSAPI_CALLCONV
4387 +gss_exchange_meta_data(OM_uint32 *minor,
4388 +                       gss_const_OID mech,
4389 +                       gss_cred_id_t cred,
4390 +                       gss_ctx_id_t *context_handle,
4391 +                       const gss_name_t name,
4392 +                       OM_uint32 req_flags,
4393 +                       gss_const_buffer_t meta_data)
4394 +{
4395 +    gss_ctx_id_t ctx = *context_handle;
4396 +    OM_uint32 major;
4397 +
4398 +    if (cred != GSS_C_NO_CREDENTIAL)
4399 +        GSSEAP_MUTEX_LOCK(&cred->mutex);
4400 +
4401 +    if (*context_handle != GSS_C_NO_CONTEXT)
4402 +        GSSEAP_MUTEX_LOCK(&ctx->mutex);
4403 +
4404 +    major = gssEapExchangeMetaData(minor, mech, cred, &ctx,
4405 +                                   name, req_flags, meta_data);
4406 +
4407 +    if (*context_handle != GSS_C_NO_CONTEXT)
4408 +        GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
4409 +    else
4410 +        *context_handle = ctx;
4411 +
4412 +    if (cred != GSS_C_NO_CREDENTIAL)
4413 +        GSSEAP_MUTEX_UNLOCK(&cred->mutex);
4414 +
4415 +    return major;
4416 +}
4417 diff --git a/mech_eap/export_name.c b/mech_eap/export_name.c
4418 new file mode 100644
4419 index 0000000..d91033f
4420 --- /dev/null
4421 +++ b/mech_eap/export_name.c
4422 @@ -0,0 +1,60 @@
4423 +/*
4424 + * Copyright (c) 2011, JANET(UK)
4425 + * All rights reserved.
4426 + *
4427 + * Redistribution and use in source and binary forms, with or without
4428 + * modification, are permitted provided that the following conditions
4429 + * are met:
4430 + *
4431 + * 1. Redistributions of source code must retain the above copyright
4432 + *    notice, this list of conditions and the following disclaimer.
4433 + *
4434 + * 2. Redistributions in binary form must reproduce the above copyright
4435 + *    notice, this list of conditions and the following disclaimer in the
4436 + *    documentation and/or other materials provided with the distribution.
4437 + *
4438 + * 3. Neither the name of JANET(UK) nor the names of its contributors
4439 + *    may be used to endorse or promote products derived from this software
4440 + *    without specific prior written permission.
4441 + *
4442 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
4443 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4444 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4445 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
4446 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4447 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4448 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4449 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4450 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4451 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4452 + * SUCH DAMAGE.
4453 + */
4454 +
4455 +/*
4456 + * Serialise a name.
4457 + */
4458 +
4459 +#include "gssapiP_eap.h"
4460 +
4461 +OM_uint32 GSSAPI_CALLCONV
4462 +gss_export_name(OM_uint32 *minor,
4463 +                const gss_name_t input_name,
4464 +                gss_buffer_t exported_name)
4465 +{
4466 +    OM_uint32 major;
4467 +
4468 +    *minor = 0;
4469 +
4470 +    if (input_name == GSS_C_NO_NAME) {
4471 +        *minor = EINVAL;
4472 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
4473 +    }
4474 +
4475 +    GSSEAP_MUTEX_LOCK(&input_name->mutex);
4476 +
4477 +    major = gssEapExportName(minor, input_name, exported_name);
4478 +
4479 +    GSSEAP_MUTEX_UNLOCK(&input_name->mutex);
4480 +
4481 +    return major;
4482 +}
4483 diff --git a/mech_eap/export_name_composite.c b/mech_eap/export_name_composite.c
4484 new file mode 100644
4485 index 0000000..b2a90ae
4486 --- /dev/null
4487 +++ b/mech_eap/export_name_composite.c
4488 @@ -0,0 +1,62 @@
4489 +/*
4490 + * Copyright (c) 2011, JANET(UK)
4491 + * All rights reserved.
4492 + *
4493 + * Redistribution and use in source and binary forms, with or without
4494 + * modification, are permitted provided that the following conditions
4495 + * are met:
4496 + *
4497 + * 1. Redistributions of source code must retain the above copyright
4498 + *    notice, this list of conditions and the following disclaimer.
4499 + *
4500 + * 2. Redistributions in binary form must reproduce the above copyright
4501 + *    notice, this list of conditions and the following disclaimer in the
4502 + *    documentation and/or other materials provided with the distribution.
4503 + *
4504 + * 3. Neither the name of JANET(UK) nor the names of its contributors
4505 + *    may be used to endorse or promote products derived from this software
4506 + *    without specific prior written permission.
4507 + *
4508 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
4509 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4510 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4511 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
4512 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4513 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4514 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4515 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4516 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4517 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4518 + * SUCH DAMAGE.
4519 + */
4520 +
4521 +/*
4522 + * Serialise a name and its attributes.
4523 + */
4524 +
4525 +#include "gssapiP_eap.h"
4526 +
4527 +OM_uint32 GSSAPI_CALLCONV
4528 +gss_export_name_composite(OM_uint32 *minor,
4529 +                          gss_name_t input_name,
4530 +                          gss_buffer_t exported_name)
4531 +{
4532 +    OM_uint32 major;
4533 +
4534 +    *minor = 0;
4535 +
4536 +    if (input_name == GSS_C_NO_NAME) {
4537 +        *minor = EINVAL;
4538 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
4539 +    }
4540 +
4541 +    GSSEAP_MUTEX_LOCK(&input_name->mutex);
4542 +
4543 +    major = gssEapExportNameInternal(minor, input_name, exported_name,
4544 +                                     EXPORT_NAME_FLAG_OID |
4545 +                                     EXPORT_NAME_FLAG_COMPOSITE);
4546 +
4547 +    GSSEAP_MUTEX_UNLOCK(&input_name->mutex);
4548 +
4549 +    return major;
4550 +}
4551 diff --git a/mech_eap/export_sec_context.c b/mech_eap/export_sec_context.c
4552 new file mode 100644
4553 index 0000000..e5be6d8
4554 --- /dev/null
4555 +++ b/mech_eap/export_sec_context.c
4556 @@ -0,0 +1,246 @@
4557 +/*
4558 + * Copyright (c) 2011, JANET(UK)
4559 + * All rights reserved.
4560 + *
4561 + * Redistribution and use in source and binary forms, with or without
4562 + * modification, are permitted provided that the following conditions
4563 + * are met:
4564 + *
4565 + * 1. Redistributions of source code must retain the above copyright
4566 + *    notice, this list of conditions and the following disclaimer.
4567 + *
4568 + * 2. Redistributions in binary form must reproduce the above copyright
4569 + *    notice, this list of conditions and the following disclaimer in the
4570 + *    documentation and/or other materials provided with the distribution.
4571 + *
4572 + * 3. Neither the name of JANET(UK) nor the names of its contributors
4573 + *    may be used to endorse or promote products derived from this software
4574 + *    without specific prior written permission.
4575 + *
4576 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
4577 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4578 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4579 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
4580 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4581 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4582 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4583 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4584 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4585 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4586 + * SUCH DAMAGE.
4587 + */
4588 +
4589 +/*
4590 + * Serialise a security context. On the acceptor, this may be partially
4591 + * established.
4592 + */
4593 +
4594 +#include "gssapiP_eap.h"
4595 +
4596 +#ifdef GSSEAP_ENABLE_ACCEPTOR
4597 +static OM_uint32
4598 +gssEapExportPartialContext(OM_uint32 *minor,
4599 +                           gss_ctx_id_t ctx,
4600 +                           gss_buffer_t token)
4601 +{
4602 +    OM_uint32 major, tmpMinor;
4603 +    size_t length, serverLen = 0;
4604 +    unsigned char *p;
4605 +    char serverBuf[MAXHOSTNAMELEN];
4606 +    if (ctx->acceptorCtx.radConn != NULL) {
4607 +        if (rs_conn_get_current_peer(ctx->acceptorCtx.radConn,
4608 +                                     serverBuf, sizeof(serverBuf)) != 0) {
4609 +#if 0
4610 +            return gssEapRadiusMapError(minor,
4611 +                                        rs_err_conn_pop(ctx->acceptorCtx.radConn));
4612 +#else
4613 +            serverBuf[0] = '\0'; /* not implemented yet */
4614 +#endif
4615 +        }
4616 +        serverLen = strlen(serverBuf);
4617 +    }
4618 +    length = 4 + serverLen + 4 + ctx->acceptorCtx.state.length;
4619 +
4620 +    token->value = GSSEAP_MALLOC(length);
4621 +    if (token->value == NULL) {
4622 +        major = GSS_S_FAILURE;
4623 +        *minor = ENOMEM;
4624 +        goto cleanup;
4625 +    }
4626 +    token->length = length;
4627 +
4628 +    p = (unsigned char *)token->value;
4629 +
4630 +    store_uint32_be(serverLen, p);
4631 +    p += 4;
4632 +    if (serverLen != 0) {
4633 +        memcpy(p, serverBuf, serverLen);
4634 +        p += serverLen;
4635 +    }
4636 +
4637 +    store_uint32_be(ctx->acceptorCtx.state.length, p);
4638 +    p += 4;
4639 +    if (ctx->acceptorCtx.state.length != 0) {
4640 +        memcpy(p, ctx->acceptorCtx.state.value,
4641 +               ctx->acceptorCtx.state.length);
4642 +        p += ctx->acceptorCtx.state.length;
4643 +    }
4644 +
4645 +    GSSEAP_ASSERT(p == (unsigned char *)token->value + token->length);
4646 +
4647 +    major = GSS_S_COMPLETE;
4648 +    *minor = 0;
4649 +
4650 +cleanup:
4651 +    if (GSS_ERROR(major))
4652 +        gss_release_buffer(&tmpMinor, token);
4653 +
4654 +    return major;
4655 +}
4656 +#endif /* GSSEAP_ENABLE_ACCEPTOR */
4657 +
4658 +OM_uint32
4659 +gssEapExportSecContext(OM_uint32 *minor,
4660 +                       gss_ctx_id_t ctx,
4661 +                       gss_buffer_t token)
4662 +{
4663 +    OM_uint32 major, tmpMinor;
4664 +    size_t length;
4665 +    gss_buffer_desc initiatorName = GSS_C_EMPTY_BUFFER;
4666 +    gss_buffer_desc acceptorName = GSS_C_EMPTY_BUFFER;
4667 +    gss_buffer_desc partialCtx = GSS_C_EMPTY_BUFFER;
4668 +    gss_buffer_desc key;
4669 +    unsigned char *p;
4670 +
4671 +    if ((CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx)) ||
4672 +        ctx->mechanismUsed == GSS_C_NO_OID) {
4673 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
4674 +        return GSS_S_NO_CONTEXT;
4675 +    }
4676 +
4677 +    key.length = KRB_KEY_LENGTH(&ctx->rfc3961Key);
4678 +    key.value  = KRB_KEY_DATA(&ctx->rfc3961Key);
4679 +
4680 +    if (ctx->initiatorName != GSS_C_NO_NAME) {
4681 +        major = gssEapExportNameInternal(minor, ctx->initiatorName,
4682 +                                         &initiatorName,
4683 +                                         EXPORT_NAME_FLAG_COMPOSITE);
4684 +        if (GSS_ERROR(major))
4685 +            goto cleanup;
4686 +    }
4687 +
4688 +    if (ctx->acceptorName != GSS_C_NO_NAME) {
4689 +        major = gssEapExportNameInternal(minor, ctx->acceptorName,
4690 +                                         &acceptorName,
4691 +                                         EXPORT_NAME_FLAG_COMPOSITE);
4692 +        if (GSS_ERROR(major))
4693 +            goto cleanup;
4694 +    }
4695 +
4696 +#ifdef GSSEAP_ENABLE_ACCEPTOR
4697 +    /*
4698 +     * The partial context is only transmitted for unestablished acceptor
4699 +     * contexts.
4700 +     */
4701 +    if (!CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx) &&
4702 +        (ctx->flags & CTX_FLAG_KRB_REAUTH) == 0) {
4703 +        major = gssEapExportPartialContext(minor, ctx, &partialCtx);
4704 +        if (GSS_ERROR(major))
4705 +            goto cleanup;
4706 +    }
4707 +#endif
4708 +
4709 +    length  = 16;                               /* version, state, flags, */
4710 +    length += 4 + ctx->mechanismUsed->length;   /* mechanismUsed */
4711 +    length += 12 + key.length;                  /* rfc3961Key.value */
4712 +    length += 4 + initiatorName.length;         /* initiatorName.value */
4713 +    length += 4 + acceptorName.length;          /* acceptorName.value */
4714 +    length += 24 + sequenceSize(ctx->seqState); /* seqState */
4715 +
4716 +    if (partialCtx.value != NULL)
4717 +        length += 4 + partialCtx.length;        /* partialCtx.value */
4718 +
4719 +    token->value = GSSEAP_MALLOC(length);
4720 +    if (token->value == NULL) {
4721 +        major = GSS_S_FAILURE;
4722 +        *minor = ENOMEM;
4723 +        goto cleanup;
4724 +    }
4725 +    token->length = length;
4726 +
4727 +    p = (unsigned char *)token->value;
4728 +
4729 +    store_uint32_be(EAP_EXPORT_CONTEXT_V1, &p[0]);        /* version */
4730 +    store_uint32_be(GSSEAP_SM_STATE(ctx),  &p[4]);
4731 +    store_uint32_be(ctx->flags,            &p[8]);
4732 +    store_uint32_be(ctx->gssFlags,         &p[12]);
4733 +    p = store_oid(ctx->mechanismUsed,      &p[16]);
4734 +
4735 +    store_uint32_be(ctx->checksumType,     &p[0]);
4736 +    store_uint32_be(ctx->encryptionType,   &p[4]);
4737 +    p = store_buffer(&key,                 &p[8], FALSE);
4738 +
4739 +    p = store_buffer(&initiatorName,       p, FALSE);
4740 +    p = store_buffer(&acceptorName,        p, FALSE);
4741 +
4742 +    store_uint64_be(ctx->expiryTime,       &p[0]);
4743 +    store_uint64_be(ctx->sendSeq,          &p[8]);
4744 +    store_uint64_be(ctx->recvSeq,          &p[16]);
4745 +    p += 24;
4746 +
4747 +    major = sequenceExternalize(minor, ctx->seqState, &p, &length);
4748 +    if (GSS_ERROR(major))
4749 +        goto cleanup;
4750 +
4751 +    if (partialCtx.value != NULL)
4752 +        p = store_buffer(&partialCtx, p, FALSE);
4753 +
4754 +    GSSEAP_ASSERT(p == (unsigned char *)token->value + token->length);
4755 +
4756 +    major = GSS_S_COMPLETE;
4757 +    *minor = 0;
4758 +
4759 +cleanup:
4760 +    if (GSS_ERROR(major))
4761 +        gss_release_buffer(&tmpMinor, token);
4762 +    gss_release_buffer(&tmpMinor, &initiatorName);
4763 +    gss_release_buffer(&tmpMinor, &acceptorName);
4764 +    gss_release_buffer(&tmpMinor, &partialCtx);
4765 +
4766 +    return major;
4767 +}
4768 +
4769 +OM_uint32 GSSAPI_CALLCONV
4770 +gss_export_sec_context(OM_uint32 *minor,
4771 +                       gss_ctx_id_t *context_handle,
4772 +                       gss_buffer_t interprocess_token)
4773 +{
4774 +    OM_uint32 major, tmpMinor;
4775 +    gss_ctx_id_t ctx = *context_handle;
4776 +
4777 +    interprocess_token->length = 0;
4778 +    interprocess_token->value = NULL;
4779 +
4780 +    if (ctx == GSS_C_NO_CONTEXT) {
4781 +        *minor = EINVAL;
4782 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
4783 +    }
4784 +
4785 +    *minor = 0;
4786 +
4787 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
4788 +
4789 +    major = gssEapExportSecContext(minor, ctx, interprocess_token);
4790 +    if (GSS_ERROR(major)) {
4791 +        GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
4792 +        return major;
4793 +    }
4794 +
4795 +    *context_handle = GSS_C_NO_CONTEXT;
4796 +
4797 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
4798 +
4799 +    gssEapReleaseContext(&tmpMinor, &ctx);
4800 +
4801 +    return GSS_S_COMPLETE;
4802 +}
4803 diff --git a/mech_eap/get_mic.c b/mech_eap/get_mic.c
4804 new file mode 100644
4805 index 0000000..7161e9c
4806 --- /dev/null
4807 +++ b/mech_eap/get_mic.c
4808 @@ -0,0 +1,89 @@
4809 +/*
4810 + * Copyright (c) 2011, JANET(UK)
4811 + * All rights reserved.
4812 + *
4813 + * Redistribution and use in source and binary forms, with or without
4814 + * modification, are permitted provided that the following conditions
4815 + * are met:
4816 + *
4817 + * 1. Redistributions of source code must retain the above copyright
4818 + *    notice, this list of conditions and the following disclaimer.
4819 + *
4820 + * 2. Redistributions in binary form must reproduce the above copyright
4821 + *    notice, this list of conditions and the following disclaimer in the
4822 + *    documentation and/or other materials provided with the distribution.
4823 + *
4824 + * 3. Neither the name of JANET(UK) nor the names of its contributors
4825 + *    may be used to endorse or promote products derived from this software
4826 + *    without specific prior written permission.
4827 + *
4828 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
4829 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4830 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4831 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
4832 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4833 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4834 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4835 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4836 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4837 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4838 + * SUCH DAMAGE.
4839 + */
4840 +
4841 +/*
4842 + * Message protection services: make a message integerity check.
4843 + */
4844 +
4845 +#include "gssapiP_eap.h"
4846 +
4847 +OM_uint32 GSSAPI_CALLCONV
4848 +gss_get_mic(OM_uint32 *minor,
4849 +            gss_ctx_id_t ctx,
4850 +            gss_qop_t qop_req,
4851 +            gss_buffer_t message_buffer,
4852 +            gss_buffer_t message_token)
4853 +{
4854 +    OM_uint32 major;
4855 +    gss_iov_buffer_desc iov[2];
4856 +
4857 +    if (ctx == GSS_C_NO_CONTEXT) {
4858 +        *minor = EINVAL;
4859 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
4860 +    }
4861 +
4862 +    if (qop_req != GSS_C_QOP_DEFAULT) {
4863 +        *minor = GSSEAP_UNKNOWN_QOP;
4864 +        return GSS_S_UNAVAILABLE;
4865 +    }
4866 +
4867 +    *minor = 0;
4868 +
4869 +    message_token->value = NULL;
4870 +    message_token->length = 0;
4871 +
4872 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
4873 +
4874 +    if (!CTX_IS_ESTABLISHED(ctx)) {
4875 +        major = GSS_S_NO_CONTEXT;
4876 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
4877 +        goto cleanup;
4878 +    }
4879 +
4880 +    iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
4881 +    iov[0].buffer = *message_buffer;
4882 +
4883 +    iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
4884 +    iov[1].buffer.value = NULL;
4885 +    iov[1].buffer.length = 0;
4886 +
4887 +    major = gssEapWrapOrGetMIC(minor, ctx, FALSE, NULL, iov, 2, TOK_TYPE_MIC);
4888 +    if (GSS_ERROR(major))
4889 +        goto cleanup;
4890 +
4891 +    *message_token = iov[1].buffer;
4892 +
4893 +cleanup:
4894 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
4895 +
4896 +    return major;
4897 +}
4898 diff --git a/mech_eap/get_name_attribute.c b/mech_eap/get_name_attribute.c
4899 new file mode 100644
4900 index 0000000..a885823
4901 --- /dev/null
4902 +++ b/mech_eap/get_name_attribute.c
4903 @@ -0,0 +1,67 @@
4904 +/*
4905 + * Copyright (c) 2011, JANET(UK)
4906 + * All rights reserved.
4907 + *
4908 + * Redistribution and use in source and binary forms, with or without
4909 + * modification, are permitted provided that the following conditions
4910 + * are met:
4911 + *
4912 + * 1. Redistributions of source code must retain the above copyright
4913 + *    notice, this list of conditions and the following disclaimer.
4914 + *
4915 + * 2. Redistributions in binary form must reproduce the above copyright
4916 + *    notice, this list of conditions and the following disclaimer in the
4917 + *    documentation and/or other materials provided with the distribution.
4918 + *
4919 + * 3. Neither the name of JANET(UK) nor the names of its contributors
4920 + *    may be used to endorse or promote products derived from this software
4921 + *    without specific prior written permission.
4922 + *
4923 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
4924 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4925 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4926 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
4927 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4928 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4929 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4930 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4931 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4932 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4933 + * SUCH DAMAGE.
4934 + */
4935 +
4936 +#include "gssapiP_eap.h"
4937 +
4938 +/*
4939 + * Wrapper for retrieving a naming attribute.
4940 + */
4941 +
4942 +OM_uint32 GSSAPI_CALLCONV
4943 +gss_get_name_attribute(OM_uint32 *minor,
4944 +                       gss_name_t name,
4945 +                       gss_buffer_t attr,
4946 +                       int *authenticated,
4947 +                       int *complete,
4948 +                       gss_buffer_t value,
4949 +                       gss_buffer_t display_value,
4950 +                       int *more)
4951 +{
4952 +    OM_uint32 major;
4953 +
4954 +    *minor = 0;
4955 +
4956 +    if (name == GSS_C_NO_NAME) {
4957 +        *minor = EINVAL;
4958 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
4959 +    }
4960 +
4961 +    GSSEAP_MUTEX_LOCK(&name->mutex);
4962 +
4963 +    major = gssEapGetNameAttribute(minor, name, attr,
4964 +                                   authenticated, complete,
4965 +                                   value, display_value, more);
4966 +
4967 +    GSSEAP_MUTEX_UNLOCK(&name->mutex);
4968 +
4969 +    return major;
4970 +}
4971 diff --git a/mech_eap/gssapiP_eap.h b/mech_eap/gssapiP_eap.h
4972 new file mode 100644
4973 index 0000000..d1790a0
4974 --- /dev/null
4975 +++ b/mech_eap/gssapiP_eap.h
4976 @@ -0,0 +1,410 @@
4977 +/*
4978 + * Copyright (c) 2011, JANET(UK)
4979 + * All rights reserved.
4980 + *
4981 + * Redistribution and use in source and binary forms, with or without
4982 + * modification, are permitted provided that the following conditions
4983 + * are met:
4984 + *
4985 + * 1. Redistributions of source code must retain the above copyright
4986 + *    notice, this list of conditions and the following disclaimer.
4987 + *
4988 + * 2. Redistributions in binary form must reproduce the above copyright
4989 + *    notice, this list of conditions and the following disclaimer in the
4990 + *    documentation and/or other materials provided with the distribution.
4991 + *
4992 + * 3. Neither the name of JANET(UK) nor the names of its contributors
4993 + *    may be used to endorse or promote products derived from this software
4994 + *    without specific prior written permission.
4995 + *
4996 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
4997 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4998 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4999 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
5000 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5001 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5002 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5003 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5004 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5005 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5006 + * SUCH DAMAGE.
5007 + */
5008 +
5009 +#ifndef _GSSAPIP_EAP_H_
5010 +#define _GSSAPIP_EAP_H_ 1
5011 +
5012 +#include "config.h"
5013 +
5014 +#ifdef HAVE_HEIMDAL_VERSION
5015 +#define KRB5_DEPRECATED         /* so we can use krb5_free_unparsed_name() */
5016 +#endif
5017 +
5018 +#include <assert.h>
5019 +#include <string.h>
5020 +#include <errno.h>
5021 +#ifdef HAVE_UNISTD_H
5022 +#include <unistd.h>
5023 +#endif
5024 +#ifdef HAVE_STDLIB_H
5025 +#include <stdlib.h>
5026 +#endif
5027 +#ifdef HAVE_STDARG_H
5028 +#include <stdarg.h>
5029 +#endif
5030 +#include <time.h>
5031 +#ifdef HAVE_SYS_PARAM_H
5032 +#include <sys/param.h>
5033 +#endif
5034 +
5035 +#ifdef WIN32
5036 +#ifndef MAXHOSTNAMELEN
5037 +# include <WinSock2.h>
5038 +# define MAXHOSTNAMELEN NI_MAXHOST
5039 +#endif
5040 +#endif
5041 +
5042 +/* GSS headers */
5043 +#include <gssapi/gssapi.h>
5044 +#include <gssapi/gssapi_krb5.h>
5045 +#ifdef HAVE_HEIMDAL_VERSION
5046 +typedef struct gss_any *gss_any_t;
5047 +#else
5048 +#include <gssapi/gssapi_ext.h>
5049 +#endif
5050 +#include "gssapi_eap.h"
5051 +
5052 +#ifndef HAVE_GSS_INQUIRE_ATTRS_FOR_MECH
5053 +typedef const gss_OID_desc *gss_const_OID;
5054 +#endif
5055 +
5056 +/* Kerberos headers */
5057 +#include <krb5.h>
5058 +
5059 +/* EAP headers */
5060 +#include <includes.h>
5061 +#include <common.h>
5062 +#include <eap_peer/eap.h>
5063 +#include <eap_peer/eap_config.h>
5064 +#include <eap_peer/eap_methods.h>
5065 +#include <eap_common/eap_common.h>
5066 +#include <wpabuf.h>
5067 +
5068 +#ifdef GSSEAP_ENABLE_ACCEPTOR
5069 +/* FreeRADIUS headers */
5070 +#ifdef __cplusplus
5071 +extern "C" {
5072 +#ifndef WIN32
5073 +#define operator fr_operator
5074 +#endif
5075 +#endif
5076 +#include <freeradius/libradius.h>
5077 +#include <freeradius/radius.h>
5078 +
5079 +#undef pid_t
5080 +
5081 +/* libradsec headers */
5082 +#include <radsec/radsec.h>
5083 +#include <radsec/request.h>
5084 +#ifdef __cplusplus
5085 +#ifndef WIN32
5086 +#undef operator
5087 +#endif
5088 +}
5089 +#endif
5090 +#endif /* GSSEAP_ENABLE_ACCEPTOR */
5091 +
5092 +#include "gsseap_err.h"
5093 +#include "radsec_err.h"
5094 +#include "util.h"
5095 +
5096 +#ifdef __cplusplus
5097 +extern "C" {
5098 +#endif
5099 +
5100 +/* These name flags are informative and not actually used by anything yet */
5101 +#define NAME_FLAG_NAI                       0x00000001
5102 +#define NAME_FLAG_SERVICE                   0x00000002
5103 +#define NAME_FLAG_COMPOSITE                 0x00000004
5104 +
5105 +struct gss_eap_saml_attr_ctx;
5106 +struct gss_eap_attr_ctx;
5107 +
5108 +#ifdef HAVE_HEIMDAL_VERSION
5109 +struct gss_name_t_desc_struct
5110 +#else
5111 +struct gss_name_struct
5112 +#endif
5113 +{
5114 +    GSSEAP_MUTEX mutex; /* mutex protects attrCtx */
5115 +    OM_uint32 flags;
5116 +    gss_OID mechanismUsed; /* this is immutable */
5117 +    krb5_principal krbPrincipal; /* this is immutable */
5118 +#ifdef GSSEAP_ENABLE_ACCEPTOR
5119 +    struct gss_eap_attr_ctx *attrCtx;
5120 +#endif
5121 +};
5122 +
5123 +#define CRED_FLAG_INITIATE                  0x00010000
5124 +#define CRED_FLAG_ACCEPT                    0x00020000
5125 +#define CRED_FLAG_PASSWORD                  0x00040000
5126 +#define CRED_FLAG_DEFAULT_CCACHE            0x00080000
5127 +#define CRED_FLAG_RESOLVED                  0x00100000
5128 +#define CRED_FLAG_TARGET                    0x00200000
5129 +#define CRED_FLAG_PUBLIC_MASK               0x0000FFFF
5130 +
5131 +#ifdef HAVE_HEIMDAL_VERSION
5132 +struct gss_cred_id_t_desc_struct
5133 +#else
5134 +struct gss_cred_id_struct
5135 +#endif
5136 +{
5137 +    GSSEAP_MUTEX mutex;
5138 +    OM_uint32 flags;
5139 +    gss_name_t name;
5140 +    gss_name_t target; /* for initiator */
5141 +    gss_buffer_desc password;
5142 +    gss_OID_set mechanisms;
5143 +    time_t expiryTime;
5144 +    gss_buffer_desc radiusConfigFile;
5145 +    gss_buffer_desc radiusConfigStanza;
5146 +    gss_buffer_desc caCertificate;
5147 +    gss_buffer_desc subjectNameConstraint;
5148 +    gss_buffer_desc subjectAltNameConstraint;
5149 +#ifdef GSSEAP_ENABLE_REAUTH
5150 +    krb5_ccache krbCredCache;
5151 +    gss_cred_id_t reauthCred;
5152 +#endif
5153 +};
5154 +
5155 +#define CTX_FLAG_INITIATOR                  0x00000001
5156 +#define CTX_FLAG_KRB_REAUTH                 0x00000002
5157 +
5158 +#define CTX_IS_INITIATOR(ctx)               (((ctx)->flags & CTX_FLAG_INITIATOR) != 0)
5159 +
5160 +#define CTX_IS_ESTABLISHED(ctx)             ((ctx)->state == GSSEAP_STATE_ESTABLISHED)
5161 +
5162 +/* Initiator context flags */
5163 +#define CTX_FLAG_EAP_SUCCESS                0x00010000
5164 +#define CTX_FLAG_EAP_RESTART                0x00020000
5165 +#define CTX_FLAG_EAP_FAIL                   0x00040000
5166 +#define CTX_FLAG_EAP_RESP                   0x00080000
5167 +#define CTX_FLAG_EAP_NO_RESP                0x00100000
5168 +#define CTX_FLAG_EAP_REQ                    0x00200000
5169 +#define CTX_FLAG_EAP_PORT_ENABLED           0x00400000
5170 +#define CTX_FLAG_EAP_ALT_ACCEPT             0x00800000
5171 +#define CTX_FLAG_EAP_ALT_REJECT             0x01000000
5172 +#define CTX_FLAG_EAP_MASK                   0xFFFF0000
5173 +
5174 +struct gss_eap_initiator_ctx {
5175 +    unsigned int idleWhile;
5176 +    struct eap_peer_config eapPeerConfig;
5177 +    struct eap_sm *eap;
5178 +    struct wpabuf reqData;
5179 +};
5180 +
5181 +#ifdef GSSEAP_ENABLE_ACCEPTOR
5182 +struct gss_eap_acceptor_ctx {
5183 +    struct rs_context *radContext;
5184 +    struct rs_connection *radConn;
5185 +    char *radServer;
5186 +    gss_buffer_desc state;
5187 +    VALUE_PAIR *vps;
5188 +};
5189 +#endif
5190 +
5191 +#ifdef HAVE_HEIMDAL_VERSION
5192 +struct gss_ctx_id_t_desc_struct
5193 +#else
5194 +struct gss_ctx_id_struct
5195 +#endif
5196 +{
5197 +    GSSEAP_MUTEX mutex;
5198 +    enum gss_eap_state state;
5199 +    OM_uint32 flags;
5200 +    OM_uint32 gssFlags;
5201 +    gss_OID mechanismUsed;
5202 +    krb5_cksumtype checksumType;
5203 +    krb5_enctype encryptionType;
5204 +    krb5_keyblock rfc3961Key;
5205 +    gss_name_t initiatorName;
5206 +    gss_name_t acceptorName;
5207 +    time_t expiryTime;
5208 +    uint64_t sendSeq, recvSeq;
5209 +    void *seqState;
5210 +    gss_cred_id_t cred;
5211 +    union {
5212 +        struct gss_eap_initiator_ctx initiator;
5213 +        #define initiatorCtx         ctxU.initiator
5214 +#ifdef GSSEAP_ENABLE_ACCEPTOR
5215 +        struct gss_eap_acceptor_ctx  acceptor;
5216 +        #define acceptorCtx          ctxU.acceptor
5217 +#endif
5218 +#ifdef GSSEAP_ENABLE_REAUTH
5219 +        gss_ctx_id_t                 reauth;
5220 +        #define reauthCtx            ctxU.reauth
5221 +#endif
5222 +    } ctxU;
5223 +    const struct gss_eap_token_buffer_set *inputTokens;
5224 +    const struct gss_eap_token_buffer_set *outputTokens;
5225 +};
5226 +
5227 +#define TOK_FLAG_SENDER_IS_ACCEPTOR         0x01
5228 +#define TOK_FLAG_WRAP_CONFIDENTIAL          0x02
5229 +#define TOK_FLAG_ACCEPTOR_SUBKEY            0x04
5230 +
5231 +#define KEY_USAGE_ACCEPTOR_SEAL             22
5232 +#define KEY_USAGE_ACCEPTOR_SIGN             23
5233 +#define KEY_USAGE_INITIATOR_SEAL            24
5234 +#define KEY_USAGE_INITIATOR_SIGN            25
5235 +
5236 +/* accept_sec_context.c */
5237 +OM_uint32
5238 +gssEapAcceptSecContext(OM_uint32 *minor,
5239 +                       gss_ctx_id_t ctx,
5240 +                       gss_cred_id_t cred,
5241 +                       gss_buffer_t input_token,
5242 +                       gss_channel_bindings_t input_chan_bindings,
5243 +                       gss_name_t *src_name,
5244 +                       gss_OID *mech_type,
5245 +                       gss_buffer_t output_token,
5246 +                       OM_uint32 *ret_flags,
5247 +                       OM_uint32 *time_rec,
5248 +                       gss_cred_id_t *delegated_cred_handle);
5249 +
5250 +/* init_sec_context.c */
5251 +OM_uint32
5252 +gssEapInitSecContext(OM_uint32 *minor,
5253 +                     gss_cred_id_t cred,
5254 +                     gss_ctx_id_t ctx,
5255 +                     gss_name_t target_name,
5256 +                     gss_OID mech_type,
5257 +                     OM_uint32 req_flags,
5258 +                     OM_uint32 time_req,
5259 +                     gss_channel_bindings_t input_chan_bindings,
5260 +                     gss_buffer_t input_token,
5261 +                     gss_OID *actual_mech_type,
5262 +                     gss_buffer_t output_token,
5263 +                     OM_uint32 *ret_flags,
5264 +                     OM_uint32 *time_rec);
5265 +
5266 +/* wrap_iov.c */
5267 +OM_uint32
5268 +gssEapWrapOrGetMIC(OM_uint32 *minor,
5269 +                   gss_ctx_id_t ctx,
5270 +                   int conf_req_flag,
5271 +                   int *conf_state,
5272 +                   gss_iov_buffer_desc *iov,
5273 +                   int iov_count,
5274 +                   enum gss_eap_token_type toktype);
5275 +
5276 +OM_uint32
5277 +gssEapUnwrapOrVerifyMIC(OM_uint32 *minor_status,
5278 +                        gss_ctx_id_t ctx,
5279 +                        int *conf_state,
5280 +                        gss_qop_t *qop_state,
5281 +                        gss_iov_buffer_desc *iov,
5282 +                        int iov_count,
5283 +                        enum gss_eap_token_type toktype);
5284 +
5285 +OM_uint32
5286 +gssEapWrapIovLength(OM_uint32 *minor,
5287 +                    gss_ctx_id_t ctx,
5288 +                    int conf_req_flag,
5289 +                    gss_qop_t qop_req,
5290 +                    int *conf_state,
5291 +                    gss_iov_buffer_desc *iov,
5292 +                    int iov_count);
5293 +OM_uint32
5294 +gssEapWrap(OM_uint32 *minor,
5295 +           gss_ctx_id_t ctx,
5296 +           int conf_req_flag,
5297 +           gss_qop_t qop_req,
5298 +           gss_buffer_t input_message_buffer,
5299 +           int *conf_state,
5300 +           gss_buffer_t output_message_buffer);
5301 +
5302 +unsigned char
5303 +rfc4121Flags(gss_ctx_id_t ctx, int receiving);
5304 +
5305 +/* display_status.c */
5306 +void
5307 +gssEapSaveStatusInfo(OM_uint32 minor, const char *format, ...);
5308 +
5309 +OM_uint32
5310 +gssEapDisplayStatus(OM_uint32 *minor,
5311 +                    OM_uint32 status_value,
5312 +                    gss_buffer_t status_string);
5313 +
5314 +#define IS_WIRE_ERROR(err)              ((err) > GSSEAP_RESERVED && \
5315 +                                         (err) <= GSSEAP_RADIUS_PROT_FAILURE)
5316 +
5317 +/* upper bound of RADIUS error range must be kept in sync with radsec.h */
5318 +#define IS_RADIUS_ERROR(err)            ((err) >= ERROR_TABLE_BASE_rse && \
5319 +                                         (err) <= ERROR_TABLE_BASE_rse + 20)
5320 +
5321 +/* exchange_meta_data.c */
5322 +OM_uint32 GSSAPI_CALLCONV
5323 +gssEapExchangeMetaData(OM_uint32 *minor,
5324 +                       gss_const_OID mech,
5325 +                       gss_cred_id_t cred,
5326 +                       gss_ctx_id_t *ctx,
5327 +                       const gss_name_t name,
5328 +                       OM_uint32 req_flags,
5329 +                       gss_const_buffer_t meta_data);
5330 +
5331 +/* export_sec_context.c */
5332 +OM_uint32
5333 +gssEapExportSecContext(OM_uint32 *minor,
5334 +                       gss_ctx_id_t ctx,
5335 +                       gss_buffer_t token);
5336 +
5337 +/* import_sec_context.c */
5338 +OM_uint32
5339 +gssEapImportContext(OM_uint32 *minor,
5340 +                    gss_buffer_t token,
5341 +                    gss_ctx_id_t ctx);
5342 +
5343 +/* inquire_sec_context_by_oid.c */
5344 +#define NEGOEX_INITIATOR_SALT      "gss-eap-negoex-initiator"
5345 +#define NEGOEX_INITIATOR_SALT_LEN  (sizeof(NEGOEX_INITIATOR_SALT) - 1)
5346 +
5347 +#define NEGOEX_ACCEPTOR_SALT       "gss-eap-negoex-acceptor"
5348 +#define NEGOEX_ACCEPTOR_SALT_LEN   (sizeof(NEGOEX_ACCEPTOR_SALT) - 1)
5349 +
5350 +/* pseudo_random.c */
5351 +OM_uint32
5352 +gssEapPseudoRandom(OM_uint32 *minor,
5353 +                   gss_ctx_id_t ctx,
5354 +                   int prf_key,
5355 +                   const gss_buffer_t prf_in,
5356 +                   ssize_t desired_output_len,
5357 +                   gss_buffer_t prf_out);
5358 +
5359 +/* query_mechanism_info.c */
5360 +OM_uint32
5361 +gssQueryMechanismInfo(OM_uint32 *minor,
5362 +                      gss_const_OID mech_oid,
5363 +                      unsigned char auth_scheme[16]);
5364 +
5365 +/* query_meta_data.c */
5366 +OM_uint32
5367 +gssEapQueryMetaData(OM_uint32 *minor,
5368 +                    gss_const_OID mech GSSEAP_UNUSED,
5369 +                    gss_cred_id_t cred,
5370 +                    gss_ctx_id_t *context_handle,
5371 +                    const gss_name_t name,
5372 +                    OM_uint32 req_flags GSSEAP_UNUSED,
5373 +                    gss_buffer_t meta_data);
5374 +
5375 +/* eap_mech.c */
5376 +OM_uint32
5377 +gssEapInitiatorInit(OM_uint32 *minor);
5378 +
5379 +void
5380 +gssEapFinalize(void);
5381 +
5382 +#ifdef __cplusplus
5383 +}
5384 +#endif
5385 +
5386 +#endif /* _GSSAPIP_EAP_H_ */
5387 diff --git a/mech_eap/gssapi_eap.h b/mech_eap/gssapi_eap.h
5388 new file mode 100644
5389 index 0000000..588665b
5390 --- /dev/null
5391 +++ b/mech_eap/gssapi_eap.h
5392 @@ -0,0 +1,90 @@
5393 +/*
5394 + * Copyright (c) 2011, JANET(UK)
5395 + * All rights reserved.
5396 + *
5397 + * Redistribution and use in source and binary forms, with or without
5398 + * modification, are permitted provided that the following conditions
5399 + * are met:
5400 + *
5401 + * 1. Redistributions of source code must retain the above copyright
5402 + *    notice, this list of conditions and the following disclaimer.
5403 + *
5404 + * 2. Redistributions in binary form must reproduce the above copyright
5405 + *    notice, this list of conditions and the following disclaimer in the
5406 + *    documentation and/or other materials provided with the distribution.
5407 + *
5408 + * 3. Neither the name of JANET(UK) nor the names of its contributors
5409 + *    may be used to endorse or promote products derived from this software
5410 + *    without specific prior written permission.
5411 + *
5412 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
5413 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5414 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5415 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
5416 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5417 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5418 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5419 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5420 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5421 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5422 + * SUCH DAMAGE.
5423 + */
5424 +
5425 +#ifndef _GSSAPI_EAP_H_
5426 +#define _GSSAPI_EAP_H_ 1
5427 +
5428 +#include <gssapi/gssapi.h>
5429 +
5430 +#ifdef __cplusplus
5431 +extern "C" {
5432 +#endif /* __cplusplus */
5433 +
5434 +/*
5435 + * GSS EAP mechanism OIDs.
5436 + */
5437 +extern gss_OID GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM;
5438 +extern gss_OID GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM;
5439 +
5440 +/*
5441 + * Mechanism name OID.
5442 + */
5443 +extern gss_OID GSS_EAP_NT_EAP_NAME;
5444 +
5445 +/*
5446 + * The libradsec configuration file; defaults to radsec.conf
5447 + * in the system configuration directory if unspecified.
5448 + */
5449 +extern gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE;
5450 +
5451 +/*
5452 + * The stanza in the libradsec configuration file; defaults
5453 + * to "gss-eap" if unspecified.
5454 + */
5455 +extern gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_STANZA;
5456 +
5457 +/*
5458 + * Flags as a 32-bit integer in network byte order,
5459 + * followed by a boolean octet indicating whether to
5460 + * clear the specified flags (if absent, defaults to
5461 + * FALSE, ie. set flags).
5462 + */
5463 +extern gss_OID GSS_EAP_CRED_SET_CRED_FLAG;
5464 +
5465 +/*
5466 + * Password; for mechanism glues that do not support
5467 + * gss_acquire_cred_with_password(), this can be set
5468 + * on an existing credentials handle.
5469 + */
5470 +extern gss_OID GSS_EAP_CRED_SET_CRED_PASSWORD;
5471 +
5472 +/*
5473 + * Credentials flag indicating the local attributes
5474 + * processing should be skipped.
5475 + */
5476 +#define GSS_EAP_DISABLE_LOCAL_ATTRS_FLAG    0x00000001
5477 +
5478 +#ifdef __cplusplus
5479 +}
5480 +#endif /* __cplusplus */
5481 +
5482 +#endif /* _GSSAPI_EAP_H_ */
5483 diff --git a/mech_eap/gsseap_err.et b/mech_eap/gsseap_err.et
5484 new file mode 100644
5485 index 0000000..d60c2c7
5486 --- /dev/null
5487 +++ b/mech_eap/gsseap_err.et
5488 @@ -0,0 +1,162 @@
5489 +#
5490 +# Copyright (c) 2011, JANET(UK)
5491 +#  All rights reserved.
5492 +# 
5493 +#  Redistribution and use in source and binary forms, with or without
5494 +#  modification, are permitted provided that the following conditions
5495 +#  are met:
5496 +# 
5497 +#  1. Redistributions of source code must retain the above copyright
5498 +#     notice, this list of conditions and the following disclaimer.
5499 +# 
5500 +#  2. Redistributions in binary form must reproduce the above copyright
5501 +#     notice, this list of conditions and the following disclaimer in the
5502 +#     documentation and/or other materials provided with the distribution.
5503 +# 
5504 +#  3. Neither the name of JANET(UK) nor the names of its contributors
5505 +#     may be used to endorse or promote products derived from this software
5506 +#     without specific prior written permission.
5507 +# 
5508 +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
5509 +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5510 +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5511 +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
5512 +#  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5513 +#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5514 +#  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5515 +#  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5516 +#  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5517 +#  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5518 +#  SUCH DAMAGE.
5519 +#
5520 +
5521 +error_table eapg
5522 +
5523 +#
5524 +# Protocol errors that can be returned in an error token. This should match
5525 +# up with makeErrorToken in accept_sec_context.c.
5526 +#
5527 +error_code GSSEAP_RESERVED,                     ""
5528 +error_code GSSEAP_WRONG_SIZE,                   "Buffer is incorrect size"
5529 +error_code GSSEAP_WRONG_MECH,                   "Mechanism OID is incorrect"
5530 +error_code GSSEAP_BAD_TOK_HEADER,               "Token header is malformed or corrupt"
5531 +error_code GSSEAP_TOK_TRUNC,                    "Token is missing data"
5532 +error_code GSSEAP_BAD_DIRECTION,                "Packet was replayed in wrong direction"
5533 +error_code GSSEAP_WRONG_TOK_ID,                 "Received token ID does not match expected token ID"
5534 +error_code GSSEAP_CRIT_ITOK_UNAVAILABLE,        "Critical inner token type unavailable"
5535 +error_code GSSEAP_MISSING_REQUIRED_ITOK,        "Missing required inner token"
5536 +error_code GSSEAP_DUPLICATE_ITOK,               "Duplicate inner token received"
5537 +error_code GSSEAP_WRONG_ITOK,                   "Recieved invalid inner token for current state"
5538 +error_code GSSEAP_KEY_UNAVAILABLE,              "EAP key unavailable"
5539 +error_code GSSEAP_KEY_TOO_SHORT,                "EAP key too short"
5540 +error_code GSSEAP_RADIUS_AUTH_FAILURE,          "Authentication rejected by RADIUS server"
5541 +error_code GSSEAP_UNKNOWN_RADIUS_CODE,          "Received unknown response code from RADIUS server"
5542 +error_code GSSEAP_MISSING_EAP_REQUEST,          "RADIUS response is missing EAP request"
5543 +error_code GSSEAP_RADIUS_PROT_FAILURE,          "Generic RADIUS failure"
5544 +
5545 +#
5546 +# Context errors
5547 +#
5548 +error_code GSSEAP_CONTEXT_ESTABLISHED,          "Context is already fully established"
5549 +error_code GSSEAP_CONTEXT_INCOMPLETE,           "Attempt to use incomplete security context"
5550 +error_code GSSEAP_BAD_CONTEXT_TOKEN,            "Context token is malformed or corrupt"
5551 +error_code GSSEAP_BAD_ERROR_TOKEN,              "Error token is malformed or corrupt"
5552 +error_code GSSEAP_BAD_CONTEXT_OPTION,           "Bad context option"
5553 +
5554 +#
5555 +# Name errors
5556 +#
5557 +error_code GSSEAP_BAD_SERVICE_NAME,             "Name is not a valid service name"
5558 +error_code GSSEAP_BAD_INITIATOR_NAME,           "Initiator identity must be a valid name"
5559 +error_code GSSEAP_NO_HOSTNAME,                  "Could not determine local host name"
5560 +error_code GSSEAP_NO_ACCEPTOR_NAME,             "Could not determine acceptor identity"
5561 +error_code GSSEAP_BAD_NAME_TOKEN,               "Name token is malformed or corrupt"
5562 +error_code GSSEAP_NO_LOCAL_MAPPING,             "Unable to map name to a local identity"
5563 +
5564 +#
5565 +# Credential errors
5566 +#
5567 +error_code GSSEAP_BAD_USAGE,                    "Credential usage type is unknown"
5568 +error_code GSSEAP_CRED_USAGE_MISMATCH,          "Credential usage does not match requested usage"
5569 +error_code GSSEAP_CRED_MECH_MISMATCH,           "Credential is not usable with this mechanism"
5570 +error_code GSSEAP_CRED_EXPIRED,                 "Attributes indicate credentials have expired"
5571 +error_code GSSEAP_BAD_CRED_OPTION,              "Bad credential option"
5572 +error_code GSSEAP_NO_DEFAULT_IDENTITY,          "Default credentials identity unavailable"
5573 +error_code GSSEAP_NO_DEFAULT_CRED,              "Missing default password or other credentials"
5574 +error_code GSSEAP_CRED_RESOLVED,                "Credential is already fully resolved"
5575 +
5576 +#
5577 +# Local identity service errors
5578 +#
5579 +error_code GSSEAP_UNABLE_TO_START_IDENTITY_SERVICE,     "Unable to start identity service"
5580 +error_code GSSEAP_NO_IDENTITY_SELECTED,                 "No identity selected"
5581 +error_code GSSEAP_IDENTITY_SERVICE_INSTALL_ERROR,       "Identity service installation error"
5582 +error_code GSSEAP_IDENTITY_SERVICE_OS_ERROR,            "Identity service OS error"
5583 +error_code GSSEAP_IDENTITY_SERVICE_IPC_ERROR,           "Identity service IPC error"
5584 +error_code GSSEAP_IDENTITY_SERVICE_UNKNOWN_ERROR,       "Unknown identity service error"
5585 +
5586 +#
5587 +# Wrap/unwrap/PRF errors
5588 +#
5589 +error_code GSSEAP_BAD_WRAP_TOKEN,               "Bad RFC 4121 wrap or MIC token"
5590 +error_code GSSEAP_MISSING_IOV,                  "IOV is missing required buffer"
5591 +error_code GSSEAP_BAD_STREAM_IOV,               "Stream IOV can only contain a single data buffer"
5592 +error_code GSSEAP_BAD_PADDING_IOV,              "Padding IOV is not permitted for RFC 4121 tokens"
5593 +error_code GSSEAP_UNKNOWN_QOP,                  "Unknown quality of protection specified"
5594 +error_code GSSEAP_INPUT_TOO_LONG,               "PRF input too long"
5595 +error_code GSSEAP_BAD_PRF_KEY,                  "PRF key usage type is unknown"
5596 +
5597 +#
5598 +# libeap errors
5599 +#
5600 +error_code GSSEAP_LIBEAP_INIT_FAILURE,          "Failed to initialize EAP library"
5601 +error_code GSSEAP_PEER_SM_INIT_FAILURE,         "Failed to create EAP state machine"
5602 +error_code GSSEAP_PEER_SM_STEP_FAILURE,         "Failed to step EAP state machine"
5603 +error_code GSSEAP_PEER_AUTH_FAILURE,            "EAP peer authentication failure"
5604 +error_code GSSEAP_PEER_BAD_MESSAGE,             "Received bad EAP message"
5605 +
5606 +#
5607 +# RadSec initialisation errors
5608 +#
5609 +error_code GSSEAP_RADSEC_INIT_FAILURE,          "Failed to initialize RadSec library"
5610 +error_code GSSEAP_RADSEC_CONTEXT_FAILURE,       "Failed to create RadSec context"
5611 +
5612 +#
5613 +# Attribute errors
5614 +#
5615 +error_code GSSEAP_NO_ATTR_CONTEXT,              "Name has no attributes"
5616 +error_code GSSEAP_NO_ATTR_PROVIDERS,            "Failed to initialize attribute providers"
5617 +error_code GSSEAP_NO_SUCH_ATTR,                 "Unknown naming attribute"
5618 +error_code GSSEAP_BAD_ATTR_TOKEN,               "Serialised attributes are malformed or corrupt"
5619 +error_code GSSEAP_ATTR_CONTEXT_FAILURE,         "Failed to initialize attribute context"
5620 +
5621 +#
5622 +# OpenSAML errors
5623 +#
5624 +error_code GSSEAP_SAML_INIT_FAILURE,            "Failed to initialize SAML library"
5625 +error_code GSSEAP_SAML_SEC_POLICY_FAILURE,      "Failed to process SAML security policy"
5626 +error_code GSSEAP_SAML_BINDING_FAILURE,         "Failed in SAML binding processing"
5627 +error_code GSSEAP_SAML_PROFILE_FAILURE,         "Failed to process SAML profile"
5628 +error_code GSSEAP_SAML_FATAL_PROFILE_FAILURE,   "Non-recoverable failure in SAML profile processing"
5629 +error_code GSSEAP_SAML_RETRY_PROFILE_FAILURE,   "Temporary failure in SAML profile processing"
5630 +error_code GSSEAP_SAML_METADATA_FAILURE,        "Failure related to SAML metadata use"
5631 +
5632 +#
5633 +# Shibboleth errors
5634 +#
5635 +error_code GSSEAP_SHIB_INIT_FAILURE,            "Failed to initialize Shibboleth"
5636 +error_code GSSEAP_SHIB_ATTR_FAILURE,            "Failure during local attribute processing"
5637 +error_code GSSEAP_SHIB_ATTR_EXTRACT_FAILURE,    "Failed to extract local attributes"
5638 +error_code GSSEAP_SHIB_ATTR_FILTER_FAILURE,     "Failed to filter local attributes"
5639 +error_code GSSEAP_SHIB_ATTR_RESOLVE_FAILURE,    "Failed to resolve local attributes"
5640 +error_code GSSEAP_SHIB_CONFIG_FAILURE,          "Local attribute configuration failure"
5641 +error_code GSSEAP_SHIB_LISTENER_FAILURE,        "Failed to communicate with local attribute server"
5642 +
5643 +#
5644 +# Extensions
5645 +#
5646 +error_code GSSEAP_BINDINGS_MISMATCH,            "Channel bindings do not match"
5647 +error_code GSSEAP_NO_MECHGLUE_SYMBOL,           "Could not find symbol in mechanism glue"
5648 +error_code GSSEAP_BAD_INVOCATION,               "Bad mechanism invoke OID"
5649 +
5650 +end
5651 diff --git a/mech_eap/import_name.c b/mech_eap/import_name.c
5652 new file mode 100644
5653 index 0000000..8049e01
5654 --- /dev/null
5655 +++ b/mech_eap/import_name.c
5656 @@ -0,0 +1,47 @@
5657 +/*
5658 + * Copyright (c) 2011, JANET(UK)
5659 + * All rights reserved.
5660 + *
5661 + * Redistribution and use in source and binary forms, with or without
5662 + * modification, are permitted provided that the following conditions
5663 + * are met:
5664 + *
5665 + * 1. Redistributions of source code must retain the above copyright
5666 + *    notice, this list of conditions and the following disclaimer.
5667 + *
5668 + * 2. Redistributions in binary form must reproduce the above copyright
5669 + *    notice, this list of conditions and the following disclaimer in the
5670 + *    documentation and/or other materials provided with the distribution.
5671 + *
5672 + * 3. Neither the name of JANET(UK) nor the names of its contributors
5673 + *    may be used to endorse or promote products derived from this software
5674 + *    without specific prior written permission.
5675 + *
5676 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
5677 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5678 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5679 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
5680 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5681 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5682 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5683 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5684 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5685 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5686 + * SUCH DAMAGE.
5687 + */
5688 +
5689 +/*
5690 + * Deserialise a name.
5691 + */
5692 +
5693 +#include "gssapiP_eap.h"
5694 +
5695 +OM_uint32 GSSAPI_CALLCONV
5696 +gss_import_name(OM_uint32 *minor,
5697 +                gss_buffer_t import_name_buffer,
5698 +                gss_OID input_name_type,
5699 +                gss_name_t *output_name)
5700 +{
5701 +    return gssEapImportName(minor, import_name_buffer,
5702 +                            input_name_type, GSS_C_NO_OID, output_name);
5703 +}
5704 diff --git a/mech_eap/import_sec_context.c b/mech_eap/import_sec_context.c
5705 new file mode 100644
5706 index 0000000..1533a16
5707 --- /dev/null
5708 +++ b/mech_eap/import_sec_context.c
5709 @@ -0,0 +1,374 @@
5710 +/*
5711 + * Copyright (c) 2011, JANET(UK)
5712 + * All rights reserved.
5713 + *
5714 + * Redistribution and use in source and binary forms, with or without
5715 + * modification, are permitted provided that the following conditions
5716 + * are met:
5717 + *
5718 + * 1. Redistributions of source code must retain the above copyright
5719 + *    notice, this list of conditions and the following disclaimer.
5720 + *
5721 + * 2. Redistributions in binary form must reproduce the above copyright
5722 + *    notice, this list of conditions and the following disclaimer in the
5723 + *    documentation and/or other materials provided with the distribution.
5724 + *
5725 + * 3. Neither the name of JANET(UK) nor the names of its contributors
5726 + *    may be used to endorse or promote products derived from this software
5727 + *    without specific prior written permission.
5728 + *
5729 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
5730 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5731 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5732 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
5733 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5734 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5735 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5736 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5737 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5738 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5739 + * SUCH DAMAGE.
5740 + */
5741 +
5742 +/*
5743 + * Deserialise a context handle.
5744 + */
5745 +
5746 +#include "gssapiP_eap.h"
5747 +
5748 +#define UPDATE_REMAIN(n)    do {                \
5749 +        p += (n);                               \
5750 +        remain -= (n);                          \
5751 +    } while (0)
5752 +
5753 +#define CHECK_REMAIN(n)     do {                \
5754 +        if (remain < (n)) {                     \
5755 +            *minor = GSSEAP_TOK_TRUNC;          \
5756 +            return GSS_S_DEFECTIVE_TOKEN;       \
5757 +        }                                       \
5758 +    } while (0)
5759 +
5760 +#ifdef GSSEAP_ENABLE_ACCEPTOR
5761 +static OM_uint32
5762 +gssEapImportPartialContext(OM_uint32 *minor,
5763 +                           unsigned char **pBuf,
5764 +                           size_t *pRemain,
5765 +                           gss_ctx_id_t ctx)
5766 +{
5767 +    OM_uint32 major;
5768 +    unsigned char *p = *pBuf;
5769 +    size_t remain = *pRemain;
5770 +    gss_buffer_desc buf;
5771 +    size_t ctxLength, serverLen;
5772 +
5773 +    /* Length of partial RADIUS context */
5774 +    CHECK_REMAIN(4);
5775 +    ctxLength = load_uint32_be(p);
5776 +    UPDATE_REMAIN(4);
5777 +
5778 +    CHECK_REMAIN(ctxLength);
5779 +    remain = ctxLength; /* check against partial context length */
5780 +
5781 +    /* Selected RADIUS server */
5782 +    CHECK_REMAIN(4);
5783 +    serverLen = load_uint32_be(p);
5784 +    UPDATE_REMAIN(4);
5785 +
5786 +    if (serverLen != 0) {
5787 +        CHECK_REMAIN(serverLen);
5788 +
5789 +        ctx->acceptorCtx.radServer = GSSEAP_MALLOC(serverLen + 1);
5790 +        if (ctx->acceptorCtx.radServer == NULL) {
5791 +            *minor = ENOMEM;
5792 +            return GSS_S_FAILURE;
5793 +        }
5794 +        memcpy(ctx->acceptorCtx.radServer, p, serverLen);
5795 +        ctx->acceptorCtx.radServer[serverLen] = '\0';
5796 +
5797 +        UPDATE_REMAIN(serverLen);
5798 +    }
5799 +
5800 +    /* RADIUS state blob */
5801 +    CHECK_REMAIN(4);
5802 +    buf.length = load_uint32_be(p);
5803 +    UPDATE_REMAIN(4);
5804 +
5805 +    if (buf.length != 0) {
5806 +        CHECK_REMAIN(buf.length);
5807 +
5808 +        buf.value = p;
5809 +
5810 +        major = duplicateBuffer(minor, &buf, &ctx->acceptorCtx.state);
5811 +        if (GSS_ERROR(major))
5812 +            return major;
5813 +
5814 +        UPDATE_REMAIN(buf.length);
5815 +    }
5816 +
5817 +#ifdef GSSEAP_DEBUG
5818 +    GSSEAP_ASSERT(remain == 0);
5819 +#endif
5820 +
5821 +    *pBuf = p;
5822 +    *pRemain -= 4 + ctxLength;
5823 +
5824 +    return GSS_S_COMPLETE;
5825 +}
5826 +#endif /* GSSEAP_ENABLE_ACCEPTOR */
5827 +
5828 +static OM_uint32
5829 +importMechanismOid(OM_uint32 *minor,
5830 +                   unsigned char **pBuf,
5831 +                   size_t *pRemain,
5832 +                   gss_OID *pOid)
5833 +{
5834 +    OM_uint32 major;
5835 +    unsigned char *p = *pBuf;
5836 +    size_t remain = *pRemain;
5837 +    gss_OID_desc oidBuf;
5838 +
5839 +    oidBuf.length = load_uint32_be(p);
5840 +    if (remain < 4 + oidBuf.length || oidBuf.length == 0) {
5841 +        *minor = GSSEAP_TOK_TRUNC;
5842 +        return GSS_S_DEFECTIVE_TOKEN;
5843 +    }
5844 +
5845 +    oidBuf.elements = &p[4];
5846 +
5847 +    major = gssEapCanonicalizeOid(minor, &oidBuf, 0, pOid);
5848 +    if (GSS_ERROR(major))
5849 +        return major;
5850 +
5851 +    *pBuf    += 4 + oidBuf.length;
5852 +    *pRemain -= 4 + oidBuf.length;
5853 +
5854 +    *minor = 0;
5855 +    return GSS_S_COMPLETE;
5856 +}
5857 +
5858 +static OM_uint32
5859 +importKerberosKey(OM_uint32 *minor,
5860 +                  unsigned char **pBuf,
5861 +                  size_t *pRemain,
5862 +                  krb5_cksumtype *checksumType,
5863 +                  krb5_enctype *pEncryptionType,
5864 +                  krb5_keyblock *pKey)
5865 +{
5866 +    unsigned char *p = *pBuf;
5867 +    size_t remain = *pRemain;
5868 +    OM_uint32 encryptionType;
5869 +    OM_uint32 length;
5870 +    krb5_context krbContext;
5871 +    krb5_keyblock key;
5872 +    krb5_error_code code;
5873 +
5874 +    GSSEAP_KRB_INIT(&krbContext);
5875 +
5876 +    KRB_KEY_INIT(pKey);
5877 +
5878 +    if (remain < 12) {
5879 +        *minor = GSSEAP_TOK_TRUNC;
5880 +        return GSS_S_DEFECTIVE_TOKEN;
5881 +    }
5882 +
5883 +    *checksumType  = load_uint32_be(&p[0]);
5884 +    encryptionType = load_uint32_be(&p[4]);
5885 +    length         = load_uint32_be(&p[8]);
5886 +
5887 +    if ((length != 0) != (encryptionType != ENCTYPE_NULL)) {
5888 +        *minor = GSSEAP_BAD_CONTEXT_TOKEN;
5889 +        return GSS_S_DEFECTIVE_TOKEN;
5890 +    }
5891 +
5892 +    if (remain - 12 < length) {
5893 +        *minor = GSSEAP_TOK_TRUNC;
5894 +        return GSS_S_DEFECTIVE_TOKEN;
5895 +    }
5896 +
5897 +    if (encryptionType != ENCTYPE_NULL) {
5898 +        KRB_KEY_INIT(&key);
5899 +
5900 +        KRB_KEY_TYPE(&key)   = encryptionType;
5901 +        KRB_KEY_LENGTH(&key) = length;
5902 +        KRB_KEY_DATA(&key)   = &p[12];
5903 +
5904 +        code = krb5_copy_keyblock_contents(krbContext, &key, pKey);
5905 +        if (code != 0) {
5906 +            *minor = code;
5907 +            return GSS_S_FAILURE;
5908 +        }
5909 +    }
5910 +
5911 +    *pBuf    += 12 + length;
5912 +    *pRemain -= 12 + length;
5913 +    *pEncryptionType = encryptionType;
5914 +
5915 +    *minor = 0;
5916 +    return GSS_S_COMPLETE;
5917 +}
5918 +
5919 +static OM_uint32
5920 +importName(OM_uint32 *minor,
5921 +           unsigned char **pBuf,
5922 +           size_t *pRemain,
5923 +           gss_name_t *pName)
5924 +{
5925 +    OM_uint32 major;
5926 +    unsigned char *p = *pBuf;
5927 +    size_t remain = *pRemain;
5928 +    gss_buffer_desc tmp;
5929 +
5930 +    if (remain < 4) {
5931 +        *minor = GSSEAP_TOK_TRUNC;
5932 +        return GSS_S_DEFECTIVE_TOKEN;
5933 +    }
5934 +
5935 +    tmp.length = load_uint32_be(p);
5936 +    if (tmp.length != 0) {
5937 +        if (remain - 4 < tmp.length) {
5938 +            *minor = GSSEAP_TOK_TRUNC;
5939 +            return GSS_S_DEFECTIVE_TOKEN;
5940 +        }
5941 +
5942 +        tmp.value = p + 4;
5943 +
5944 +        major = gssEapImportNameInternal(minor, &tmp, pName,
5945 +                                         EXPORT_NAME_FLAG_COMPOSITE);
5946 +        if (GSS_ERROR(major))
5947 +            return major;
5948 +    }
5949 +
5950 +    *pBuf    += 4 + tmp.length;
5951 +    *pRemain -= 4 + tmp.length;
5952 +
5953 +    *minor = 0;
5954 +    return GSS_S_COMPLETE;
5955 +}
5956 +
5957 +OM_uint32
5958 +gssEapImportContext(OM_uint32 *minor,
5959 +                    gss_buffer_t token,
5960 +                    gss_ctx_id_t ctx)
5961 +{
5962 +    OM_uint32 major;
5963 +    unsigned char *p = (unsigned char *)token->value;
5964 +    size_t remain = token->length;
5965 +
5966 +    if (remain < 16) {
5967 +        *minor = GSSEAP_TOK_TRUNC;
5968 +        return GSS_S_DEFECTIVE_TOKEN;
5969 +    }
5970 +    if (load_uint32_be(&p[0]) != EAP_EXPORT_CONTEXT_V1) {
5971 +        *minor = GSSEAP_BAD_CONTEXT_TOKEN;
5972 +        return GSS_S_DEFECTIVE_TOKEN;
5973 +    }
5974 +    ctx->state      = load_uint32_be(&p[4]);
5975 +    ctx->flags      = load_uint32_be(&p[8]);
5976 +    ctx->gssFlags   = load_uint32_be(&p[12]);
5977 +    p      += 16;
5978 +    remain -= 16;
5979 +
5980 +    /* Validate state */
5981 +    if (GSSEAP_SM_STATE(ctx) < GSSEAP_STATE_INITIAL ||
5982 +        GSSEAP_SM_STATE(ctx) > GSSEAP_STATE_ESTABLISHED)
5983 +        return GSS_S_DEFECTIVE_TOKEN;
5984 +
5985 +    /* Only acceptor can export partial context tokens */
5986 +    if (CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx))
5987 +        return GSS_S_DEFECTIVE_TOKEN;
5988 +
5989 +    major = importMechanismOid(minor, &p, &remain, &ctx->mechanismUsed);
5990 +    if (GSS_ERROR(major))
5991 +        return major;
5992 +
5993 +    major = importKerberosKey(minor, &p, &remain,
5994 +                              &ctx->checksumType,
5995 +                              &ctx->encryptionType,
5996 +                              &ctx->rfc3961Key);
5997 +    if (GSS_ERROR(major))
5998 +        return major;
5999 +
6000 +    major = importName(minor, &p, &remain, &ctx->initiatorName);
6001 +    if (GSS_ERROR(major))
6002 +        return major;
6003 +
6004 +    major = importName(minor, &p, &remain, &ctx->acceptorName);
6005 +    if (GSS_ERROR(major))
6006 +        return major;
6007 +
6008 +    /* Check that, if context is established, names are valid */
6009 +    if (CTX_IS_ESTABLISHED(ctx) &&
6010 +        (CTX_IS_INITIATOR(ctx) ? ctx->acceptorName == GSS_C_NO_NAME
6011 +                               : ctx->initiatorName == GSS_C_NO_NAME)) {
6012 +        return GSS_S_DEFECTIVE_TOKEN;
6013 +    }
6014 +
6015 +    if (remain < 24 + sequenceSize(ctx->seqState)) {
6016 +        *minor = GSSEAP_TOK_TRUNC;
6017 +        return GSS_S_DEFECTIVE_TOKEN;
6018 +    }
6019 +    ctx->expiryTime = (time_t)load_uint64_be(&p[0]);
6020 +    ctx->sendSeq    = load_uint64_be(&p[8]);
6021 +    ctx->recvSeq    = load_uint64_be(&p[16]);
6022 +    p      += 24;
6023 +    remain -= 24;
6024 +
6025 +    major = sequenceInternalize(minor, &ctx->seqState, &p, &remain);
6026 +    if (GSS_ERROR(major))
6027 +        return major;
6028 +
6029 +#ifdef GSSEAP_ENABLE_ACCEPTOR
6030 +    /*
6031 +     * The partial context should only be expected for unestablished
6032 +     * acceptor contexts.
6033 +     */
6034 +    if (!CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx) &&
6035 +        (ctx->flags & CTX_FLAG_KRB_REAUTH) == 0) {
6036 +        major = gssEapImportPartialContext(minor, &p, &remain, ctx);
6037 +        if (GSS_ERROR(major))
6038 +            return major;
6039 +    }
6040 +
6041 +#ifdef GSSEAP_DEBUG
6042 +    GSSEAP_ASSERT(remain == 0);
6043 +#endif
6044 +#endif /* GSSEAP_ENABLE_ACCEPTOR */
6045 +
6046 +    major = GSS_S_COMPLETE;
6047 +    *minor = 0;
6048 +
6049 +    return major;
6050 +}
6051 +
6052 +OM_uint32 GSSAPI_CALLCONV
6053 +gss_import_sec_context(OM_uint32 *minor,
6054 +                       gss_buffer_t interprocess_token,
6055 +                       gss_ctx_id_t *context_handle)
6056 +{
6057 +    OM_uint32 major, tmpMinor;
6058 +    gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
6059 +
6060 +    *context_handle = GSS_C_NO_CONTEXT;
6061 +
6062 +    if (interprocess_token == GSS_C_NO_BUFFER ||
6063 +        interprocess_token->length == 0) {
6064 +        *minor = GSSEAP_TOK_TRUNC;
6065 +        return GSS_S_DEFECTIVE_TOKEN;
6066 +    }
6067 +
6068 +    major = gssEapAllocContext(minor, &ctx);
6069 +    if (GSS_ERROR(major))
6070 +        goto cleanup;
6071 +
6072 +    major = gssEapImportContext(minor, interprocess_token, ctx);
6073 +    if (GSS_ERROR(major))
6074 +        goto cleanup;
6075 +
6076 +    *context_handle = ctx;
6077 +
6078 +cleanup:
6079 +    if (GSS_ERROR(major))
6080 +        gssEapReleaseContext(&tmpMinor, &ctx);
6081 +
6082 +    return major;
6083 +}
6084 diff --git a/mech_eap/indicate_mechs.c b/mech_eap/indicate_mechs.c
6085 new file mode 100644
6086 index 0000000..d4d275e
6087 --- /dev/null
6088 +++ b/mech_eap/indicate_mechs.c
6089 @@ -0,0 +1,44 @@
6090 +/*
6091 + * Copyright (c) 2011, JANET(UK)
6092 + * All rights reserved.
6093 + *
6094 + * Redistribution and use in source and binary forms, with or without
6095 + * modification, are permitted provided that the following conditions
6096 + * are met:
6097 + *
6098 + * 1. Redistributions of source code must retain the above copyright
6099 + *    notice, this list of conditions and the following disclaimer.
6100 + *
6101 + * 2. Redistributions in binary form must reproduce the above copyright
6102 + *    notice, this list of conditions and the following disclaimer in the
6103 + *    documentation and/or other materials provided with the distribution.
6104 + *
6105 + * 3. Neither the name of JANET(UK) nor the names of its contributors
6106 + *    may be used to endorse or promote products derived from this software
6107 + *    without specific prior written permission.
6108 + *
6109 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
6110 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
6111 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
6112 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
6113 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
6114 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
6115 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6116 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6117 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6118 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6119 + * SUCH DAMAGE.
6120 + */
6121 +
6122 +/*
6123 + * Enumerate the supported mechanism OIDs.
6124 + */
6125 +
6126 +#include "gssapiP_eap.h"
6127 +
6128 +OM_uint32 GSSAPI_CALLCONV
6129 +gss_indicate_mechs(OM_uint32 *minor,
6130 +                   gss_OID_set *mech_set)
6131 +{
6132 +    return gssEapIndicateMechs(minor, mech_set);
6133 +}
6134 diff --git a/mech_eap/init_sec_context.c b/mech_eap/init_sec_context.c
6135 new file mode 100644
6136 index 0000000..e99b479
6137 --- /dev/null
6138 +++ b/mech_eap/init_sec_context.c
6139 @@ -0,0 +1,1097 @@
6140 +/*
6141 + * Copyright (c) 2011, JANET(UK)
6142 + * All rights reserved.
6143 + *
6144 + * Redistribution and use in source and binary forms, with or without
6145 + * modification, are permitted provided that the following conditions
6146 + * are met:
6147 + *
6148 + * 1. Redistributions of source code must retain the above copyright
6149 + *    notice, this list of conditions and the following disclaimer.
6150 + *
6151 + * 2. Redistributions in binary form must reproduce the above copyright
6152 + *    notice, this list of conditions and the following disclaimer in the
6153 + *    documentation and/or other materials provided with the distribution.
6154 + *
6155 + * 3. Neither the name of JANET(UK) nor the names of its contributors
6156 + *    may be used to endorse or promote products derived from this software
6157 + *    without specific prior written permission.
6158 + *
6159 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
6160 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
6161 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
6162 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
6163 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
6164 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
6165 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6166 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6167 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6168 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6169 + * SUCH DAMAGE.
6170 + */
6171 +
6172 +/*
6173 + * Establish a security context on the initiator (client). These functions
6174 + * wrap around libeap.
6175 + */
6176 +
6177 +#include "gssapiP_eap.h"
6178 +
6179 +static OM_uint32
6180 +policyVariableToFlag(enum eapol_bool_var variable)
6181 +{
6182 +    OM_uint32 flag = 0;
6183 +
6184 +    switch (variable) {
6185 +    case EAPOL_eapSuccess:
6186 +        flag = CTX_FLAG_EAP_SUCCESS;
6187 +        break;
6188 +    case EAPOL_eapRestart:
6189 +        flag = CTX_FLAG_EAP_RESTART;
6190 +        break;
6191 +    case EAPOL_eapFail:
6192 +        flag = CTX_FLAG_EAP_FAIL;
6193 +        break;
6194 +    case EAPOL_eapResp:
6195 +        flag = CTX_FLAG_EAP_RESP;
6196 +        break;
6197 +    case EAPOL_eapNoResp:
6198 +        flag = CTX_FLAG_EAP_NO_RESP;
6199 +        break;
6200 +    case EAPOL_eapReq:
6201 +        flag = CTX_FLAG_EAP_REQ;
6202 +        break;
6203 +    case EAPOL_portEnabled:
6204 +        flag = CTX_FLAG_EAP_PORT_ENABLED;
6205 +        break;
6206 +    case EAPOL_altAccept:
6207 +        flag = CTX_FLAG_EAP_ALT_ACCEPT;
6208 +        break;
6209 +    case EAPOL_altReject:
6210 +        flag = CTX_FLAG_EAP_ALT_REJECT;
6211 +        break;
6212 +    }
6213 +
6214 +    return flag;
6215 +}
6216 +
6217 +static struct eap_peer_config *
6218 +peerGetConfig(void *ctx)
6219 +{
6220 +    gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx;
6221 +
6222 +    return &gssCtx->initiatorCtx.eapPeerConfig;
6223 +}
6224 +
6225 +static Boolean
6226 +peerGetBool(void *data, enum eapol_bool_var variable)
6227 +{
6228 +    gss_ctx_id_t ctx = data;
6229 +    OM_uint32 flag;
6230 +
6231 +    if (ctx == GSS_C_NO_CONTEXT)
6232 +        return FALSE;
6233 +
6234 +    flag = policyVariableToFlag(variable);
6235 +
6236 +    return ((ctx->flags & flag) != 0);
6237 +}
6238 +
6239 +static void
6240 +peerSetBool(void *data, enum eapol_bool_var variable,
6241 +            Boolean value)
6242 +{
6243 +    gss_ctx_id_t ctx = data;
6244 +    OM_uint32 flag;
6245 +
6246 +    if (ctx == GSS_C_NO_CONTEXT)
6247 +        return;
6248 +
6249 +    flag = policyVariableToFlag(variable);
6250 +
6251 +    if (value)
6252 +        ctx->flags |= flag;
6253 +    else
6254 +        ctx->flags &= ~(flag);
6255 +}
6256 +
6257 +static unsigned int
6258 +peerGetInt(void *data, enum eapol_int_var variable)
6259 +{
6260 +    gss_ctx_id_t ctx = data;
6261 +
6262 +    if (ctx == GSS_C_NO_CONTEXT)
6263 +        return FALSE;
6264 +
6265 +    GSSEAP_ASSERT(CTX_IS_INITIATOR(ctx));
6266 +
6267 +    switch (variable) {
6268 +    case EAPOL_idleWhile:
6269 +        return ctx->initiatorCtx.idleWhile;
6270 +        break;
6271 +    }
6272 +
6273 +    return 0;
6274 +}
6275 +
6276 +static void
6277 +peerSetInt(void *data, enum eapol_int_var variable,
6278 +           unsigned int value)
6279 +{
6280 +    gss_ctx_id_t ctx = data;
6281 +
6282 +    if (ctx == GSS_C_NO_CONTEXT)
6283 +        return;
6284 +
6285 +    GSSEAP_ASSERT(CTX_IS_INITIATOR(ctx));
6286 +
6287 +    switch (variable) {
6288 +    case EAPOL_idleWhile:
6289 +        ctx->initiatorCtx.idleWhile = value;
6290 +        break;
6291 +    }
6292 +}
6293 +
6294 +static struct wpabuf *
6295 +peerGetEapReqData(void *ctx)
6296 +{
6297 +    gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx;
6298 +
6299 +    return &gssCtx->initiatorCtx.reqData;
6300 +}
6301 +
6302 +static void
6303 +peerSetConfigBlob(void *ctx GSSEAP_UNUSED,
6304 +                  struct wpa_config_blob *blob GSSEAP_UNUSED)
6305 +{
6306 +}
6307 +
6308 +static const struct wpa_config_blob *
6309 +peerGetConfigBlob(void *ctx GSSEAP_UNUSED,
6310 +                  const char *name GSSEAP_UNUSED)
6311 +{
6312 +    return NULL;
6313 +}
6314 +
6315 +static void
6316 +peerNotifyPending(void *ctx GSSEAP_UNUSED)
6317 +{
6318 +}
6319 +
6320 +static struct eapol_callbacks gssEapPolicyCallbacks = {
6321 +    peerGetConfig,
6322 +    peerGetBool,
6323 +    peerSetBool,
6324 +    peerGetInt,
6325 +    peerSetInt,
6326 +    peerGetEapReqData,
6327 +    peerSetConfigBlob,
6328 +    peerGetConfigBlob,
6329 +    peerNotifyPending,
6330 +};
6331 +
6332 +#ifdef GSSEAP_DEBUG
6333 +extern int wpa_debug_level;
6334 +#endif
6335 +
6336 +static OM_uint32
6337 +peerConfigInit(OM_uint32 *minor, gss_ctx_id_t ctx)
6338 +{
6339 +    OM_uint32 major;
6340 +    krb5_context krbContext;
6341 +    struct eap_peer_config *eapPeerConfig = &ctx->initiatorCtx.eapPeerConfig;
6342 +    gss_buffer_desc identity = GSS_C_EMPTY_BUFFER;
6343 +    gss_buffer_desc realm = GSS_C_EMPTY_BUFFER;
6344 +    gss_cred_id_t cred = ctx->cred;
6345 +
6346 +    eapPeerConfig->identity = NULL;
6347 +    eapPeerConfig->identity_len = 0;
6348 +    eapPeerConfig->anonymous_identity = NULL;
6349 +    eapPeerConfig->anonymous_identity_len = 0;
6350 +    eapPeerConfig->password = NULL;
6351 +    eapPeerConfig->password_len = 0;
6352 +
6353 +    GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL);
6354 +
6355 +    GSSEAP_KRB_INIT(&krbContext);
6356 +
6357 +    eapPeerConfig->fragment_size = 1024;
6358 +#ifdef GSSEAP_DEBUG
6359 +    wpa_debug_level = 0;
6360 +#endif
6361 +
6362 +    GSSEAP_ASSERT(cred->name != GSS_C_NO_NAME);
6363 +
6364 +    if ((cred->name->flags & (NAME_FLAG_NAI | NAME_FLAG_SERVICE)) == 0) {
6365 +        *minor = GSSEAP_BAD_INITIATOR_NAME;
6366 +        return GSS_S_BAD_NAME;
6367 +    }
6368 +
6369 +    /* identity */
6370 +    major = gssEapDisplayName(minor, cred->name, &identity, NULL);
6371 +    if (GSS_ERROR(major))
6372 +        return major;
6373 +
6374 +    eapPeerConfig->identity = (unsigned char *)identity.value;
6375 +    eapPeerConfig->identity_len = identity.length;
6376 +
6377 +    krbPrincRealmToGssBuffer(cred->name->krbPrincipal, &realm);
6378 +
6379 +    /* anonymous_identity */
6380 +    eapPeerConfig->anonymous_identity = GSSEAP_MALLOC(realm.length + 2);
6381 +    if (eapPeerConfig->anonymous_identity == NULL) {
6382 +        *minor = ENOMEM;
6383 +        return GSS_S_FAILURE;
6384 +    }
6385 +
6386 +    eapPeerConfig->anonymous_identity[0] = '@';
6387 +    memcpy(eapPeerConfig->anonymous_identity + 1, realm.value, realm.length);
6388 +    eapPeerConfig->anonymous_identity[1 + realm.length] = '\0';
6389 +    eapPeerConfig->anonymous_identity_len = 1 + realm.length;
6390 +
6391 +    /* password */
6392 +    eapPeerConfig->password = (unsigned char *)cred->password.value;
6393 +    eapPeerConfig->password_len = cred->password.length;
6394 +
6395 +    /* certs */
6396 +    eapPeerConfig->ca_cert = (unsigned char *)cred->caCertificate.value;
6397 +    eapPeerConfig->subject_match = (unsigned char *)cred->subjectNameConstraint.value;
6398 +    eapPeerConfig->altsubject_match = (unsigned char *)cred->subjectAltNameConstraint.value;
6399 +
6400 +    *minor = 0;
6401 +    return GSS_S_COMPLETE;
6402 +}
6403 +
6404 +static OM_uint32
6405 +peerConfigFree(OM_uint32 *minor,
6406 +               gss_ctx_id_t ctx)
6407 +{
6408 +    struct eap_peer_config *eapPeerConfig = &ctx->initiatorCtx.eapPeerConfig;
6409 +
6410 +    if (eapPeerConfig->identity != NULL) {
6411 +        GSSEAP_FREE(eapPeerConfig->identity);
6412 +        eapPeerConfig->identity = NULL;
6413 +        eapPeerConfig->identity_len = 0;
6414 +    }
6415 +
6416 +    if (eapPeerConfig->anonymous_identity != NULL) {
6417 +        GSSEAP_FREE(eapPeerConfig->anonymous_identity);
6418 +        eapPeerConfig->anonymous_identity = NULL;
6419 +        eapPeerConfig->anonymous_identity_len = 0;
6420 +    }
6421 +
6422 +    *minor = 0;
6423 +    return GSS_S_COMPLETE;
6424 +}
6425 +
6426 +/*
6427 + * Mark an initiator context as ready for cryptographic operations
6428 + */
6429 +static OM_uint32
6430 +initReady(OM_uint32 *minor, gss_ctx_id_t ctx, OM_uint32 reqFlags)
6431 +{
6432 +    OM_uint32 major;
6433 +    const unsigned char *key;
6434 +    size_t keyLength;
6435 +
6436 +#if 1
6437 +    /* XXX actually check for mutual auth */
6438 +    if (reqFlags & GSS_C_MUTUAL_FLAG)
6439 +        ctx->gssFlags |= GSS_C_MUTUAL_FLAG;
6440 +#endif
6441 +
6442 +    /* Cache encryption type derived from selected mechanism OID */
6443 +    major = gssEapOidToEnctype(minor, ctx->mechanismUsed, &ctx->encryptionType);
6444 +    if (GSS_ERROR(major))
6445 +        return major;
6446 +
6447 +    if (!eap_key_available(ctx->initiatorCtx.eap)) {
6448 +        *minor = GSSEAP_KEY_UNAVAILABLE;
6449 +        return GSS_S_UNAVAILABLE;
6450 +    }
6451 +
6452 +    key = eap_get_eapKeyData(ctx->initiatorCtx.eap, &keyLength);
6453 +
6454 +    if (keyLength < EAP_EMSK_LEN) {
6455 +        *minor = GSSEAP_KEY_TOO_SHORT;
6456 +        return GSS_S_UNAVAILABLE;
6457 +    }
6458 +
6459 +    major = gssEapDeriveRfc3961Key(minor,
6460 +                                   &key[EAP_EMSK_LEN / 2],
6461 +                                   EAP_EMSK_LEN / 2,
6462 +                                   ctx->encryptionType,
6463 +                                   &ctx->rfc3961Key);
6464 +       if (GSS_ERROR(major))
6465 +           return major;
6466 +
6467 +    major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
6468 +                                      &ctx->checksumType);
6469 +    if (GSS_ERROR(major))
6470 +        return major;
6471 +
6472 +    major = sequenceInit(minor,
6473 +                         &ctx->seqState,
6474 +                         ctx->recvSeq,
6475 +                         ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0),
6476 +                         ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0),
6477 +                         TRUE);
6478 +    if (GSS_ERROR(major))
6479 +        return major;
6480 +
6481 +    *minor = 0;
6482 +    return GSS_S_COMPLETE;
6483 +}
6484 +
6485 +static OM_uint32
6486 +initBegin(OM_uint32 *minor,
6487 +          gss_ctx_id_t ctx,
6488 +          gss_name_t target,
6489 +          gss_OID mech,
6490 +          OM_uint32 reqFlags GSSEAP_UNUSED,
6491 +          OM_uint32 timeReq,
6492 +          gss_channel_bindings_t chanBindings GSSEAP_UNUSED)
6493 +{
6494 +    OM_uint32 major;
6495 +    gss_cred_id_t cred = ctx->cred;
6496 +
6497 +    GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL);
6498 +
6499 +    if (cred->expiryTime)
6500 +        ctx->expiryTime = cred->expiryTime;
6501 +    else if (timeReq == 0 || timeReq == GSS_C_INDEFINITE)
6502 +        ctx->expiryTime = 0;
6503 +    else
6504 +        ctx->expiryTime = time(NULL) + timeReq;
6505 +
6506 +    /*
6507 +     * The credential mutex protects its name, however we need to
6508 +     * explicitly lock the acceptor name (unlikely as it may be
6509 +     * that it has attributes set on it).
6510 +     */
6511 +    major = gssEapDuplicateName(minor, cred->name, &ctx->initiatorName);
6512 +    if (GSS_ERROR(major))
6513 +        return major;
6514 +
6515 +    if (target != GSS_C_NO_NAME) {
6516 +        GSSEAP_MUTEX_LOCK(&target->mutex);
6517 +
6518 +        major = gssEapDuplicateName(minor, target, &ctx->acceptorName);
6519 +        if (GSS_ERROR(major)) {
6520 +            GSSEAP_MUTEX_UNLOCK(&target->mutex);
6521 +            return major;
6522 +        }
6523 +
6524 +        GSSEAP_MUTEX_UNLOCK(&target->mutex);
6525 +    }
6526 +
6527 +    major = gssEapCanonicalizeOid(minor,
6528 +                                  mech,
6529 +                                  OID_FLAG_NULL_VALID | OID_FLAG_MAP_NULL_TO_DEFAULT_MECH,
6530 +                                  &ctx->mechanismUsed);
6531 +    if (GSS_ERROR(major))
6532 +        return major;
6533 +
6534 +    /* If credentials were provided, check they're usable with this mech */
6535 +    if (!gssEapCredAvailable(cred, ctx->mechanismUsed)) {
6536 +        *minor = GSSEAP_CRED_MECH_MISMATCH;
6537 +        return GSS_S_BAD_MECH;
6538 +    }
6539 +
6540 +    *minor = 0;
6541 +    return GSS_S_COMPLETE;
6542 +}
6543 +
6544 +static OM_uint32
6545 +eapGssSmInitError(OM_uint32 *minor,
6546 +                  gss_cred_id_t cred GSSEAP_UNUSED,
6547 +                  gss_ctx_id_t ctx GSSEAP_UNUSED,
6548 +                  gss_name_t target GSSEAP_UNUSED,
6549 +                  gss_OID mech GSSEAP_UNUSED,
6550 +                  OM_uint32 reqFlags GSSEAP_UNUSED,
6551 +                  OM_uint32 timeReq GSSEAP_UNUSED,
6552 +                  gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
6553 +                  gss_buffer_t inputToken,
6554 +                  gss_buffer_t outputToken GSSEAP_UNUSED,
6555 +                  OM_uint32 *smFlags GSSEAP_UNUSED)
6556 +{
6557 +    OM_uint32 major;
6558 +    unsigned char *p;
6559 +
6560 +    if (inputToken->length < 8) {
6561 +        *minor = GSSEAP_TOK_TRUNC;
6562 +        return GSS_S_DEFECTIVE_TOKEN;
6563 +    }
6564 +
6565 +    p = (unsigned char *)inputToken->value;
6566 +
6567 +    major = load_uint32_be(&p[0]);
6568 +    *minor = ERROR_TABLE_BASE_eapg + load_uint32_be(&p[4]);
6569 +
6570 +    if (!GSS_ERROR(major) || !IS_WIRE_ERROR(*minor)) {
6571 +        major = GSS_S_FAILURE;
6572 +        *minor = GSSEAP_BAD_ERROR_TOKEN;
6573 +    }
6574 +
6575 +    GSSEAP_ASSERT(GSS_ERROR(major));
6576 +
6577 +    return major;
6578 +}
6579 +
6580 +#ifdef GSSEAP_ENABLE_REAUTH
6581 +static OM_uint32
6582 +eapGssSmInitGssReauth(OM_uint32 *minor,
6583 +                      gss_cred_id_t cred,
6584 +                      gss_ctx_id_t ctx,
6585 +                      gss_name_t target,
6586 +                      gss_OID mech GSSEAP_UNUSED,
6587 +                      OM_uint32 reqFlags,
6588 +                      OM_uint32 timeReq,
6589 +                      gss_channel_bindings_t chanBindings,
6590 +                      gss_buffer_t inputToken,
6591 +                      gss_buffer_t outputToken,
6592 +                      OM_uint32 *smFlags GSSEAP_UNUSED)
6593 +{
6594 +    OM_uint32 major, tmpMinor;
6595 +    gss_name_t mechTarget = GSS_C_NO_NAME;
6596 +    gss_OID actualMech = GSS_C_NO_OID;
6597 +    OM_uint32 gssFlags, timeRec;
6598 +
6599 +    /*
6600 +     * Here we use the passed in credential handle because the resolved
6601 +     * context credential does not currently have the reauth creds.
6602 +     */
6603 +    if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_INITIAL) {
6604 +        if (!gssEapCanReauthP(cred, target, timeReq))
6605 +            return GSS_S_CONTINUE_NEEDED;
6606 +
6607 +        ctx->flags |= CTX_FLAG_KRB_REAUTH;
6608 +    } else if ((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0) {
6609 +        major = GSS_S_DEFECTIVE_TOKEN;
6610 +        *minor = GSSEAP_WRONG_ITOK;
6611 +        goto cleanup;
6612 +    }
6613 +
6614 +    GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL);
6615 +
6616 +    major = gssEapMechToGlueName(minor, target, &mechTarget);
6617 +    if (GSS_ERROR(major))
6618 +        goto cleanup;
6619 +
6620 +    major = gssInitSecContext(minor,
6621 +                              cred->reauthCred,
6622 +                              &ctx->reauthCtx,
6623 +                              mechTarget,
6624 +                              (gss_OID)gss_mech_krb5,
6625 +                              reqFlags | GSS_C_MUTUAL_FLAG,
6626 +                              timeReq,
6627 +                              chanBindings,
6628 +                              inputToken,
6629 +                              &actualMech,
6630 +                              outputToken,
6631 +                              &gssFlags,
6632 +                              &timeRec);
6633 +    if (GSS_ERROR(major))
6634 +        goto cleanup;
6635 +
6636 +    ctx->gssFlags = gssFlags;
6637 +
6638 +    if (major == GSS_S_COMPLETE) {
6639 +        GSSEAP_ASSERT(GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_REAUTHENTICATE);
6640 +
6641 +        major = gssEapReauthComplete(minor, ctx, cred, actualMech, timeRec);
6642 +        if (GSS_ERROR(major))
6643 +            goto cleanup;
6644 +        GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
6645 +    } else {
6646 +        GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_REAUTHENTICATE);
6647 +    }
6648 +
6649 +cleanup:
6650 +    gssReleaseName(&tmpMinor, &mechTarget);
6651 +
6652 +    return major;
6653 +}
6654 +#endif /* GSSEAP_ENABLE_REAUTH */
6655 +
6656 +#ifdef GSSEAP_DEBUG
6657 +static OM_uint32
6658 +eapGssSmInitVendorInfo(OM_uint32 *minor,
6659 +                       gss_cred_id_t cred GSSEAP_UNUSED,
6660 +                       gss_ctx_id_t ctx GSSEAP_UNUSED,
6661 +                       gss_name_t target GSSEAP_UNUSED,
6662 +                       gss_OID mech GSSEAP_UNUSED,
6663 +                       OM_uint32 reqFlags GSSEAP_UNUSED,
6664 +                       OM_uint32 timeReq GSSEAP_UNUSED,
6665 +                       gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
6666 +                       gss_buffer_t inputToken GSSEAP_UNUSED,
6667 +                       gss_buffer_t outputToken,
6668 +                       OM_uint32 *smFlags GSSEAP_UNUSED)
6669 +{
6670 +    OM_uint32 major;
6671 +
6672 +    major = makeStringBuffer(minor, "JANET(UK)", outputToken);
6673 +    if (GSS_ERROR(major))
6674 +        return major;
6675 +
6676 +    return GSS_S_CONTINUE_NEEDED;
6677 +}
6678 +#endif
6679 +
6680 +static OM_uint32
6681 +eapGssSmInitAcceptorName(OM_uint32 *minor,
6682 +                         gss_cred_id_t cred GSSEAP_UNUSED,
6683 +                         gss_ctx_id_t ctx,
6684 +                         gss_name_t target GSSEAP_UNUSED,
6685 +                         gss_OID mech GSSEAP_UNUSED,
6686 +                         OM_uint32 reqFlags GSSEAP_UNUSED,
6687 +                         OM_uint32 timeReq GSSEAP_UNUSED,
6688 +                         gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
6689 +                         gss_buffer_t inputToken GSSEAP_UNUSED,
6690 +                         gss_buffer_t outputToken,
6691 +                         OM_uint32 *smFlags GSSEAP_UNUSED)
6692 +{
6693 +    OM_uint32 major;
6694 +
6695 +    if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_INITIAL &&
6696 +        ctx->acceptorName != GSS_C_NO_NAME) {
6697 +
6698 +        /* Send desired target name to acceptor */
6699 +        major = gssEapDisplayName(minor, ctx->acceptorName,
6700 +                                  outputToken, NULL);
6701 +        if (GSS_ERROR(major))
6702 +            return major;
6703 +    } else if (inputToken != GSS_C_NO_BUFFER &&
6704 +               ctx->acceptorName == GSS_C_NO_NAME) {
6705 +        /* Accept target name hint from acceptor */
6706 +        major = gssEapImportName(minor, inputToken,
6707 +                                 GSS_C_NT_USER_NAME,
6708 +                                 ctx->mechanismUsed,
6709 +                                 &ctx->acceptorName);
6710 +        if (GSS_ERROR(major))
6711 +            return major;
6712 +    }
6713 +
6714 +    /*
6715 +     * Currently, other parts of the code assume that the acceptor name
6716 +     * is available, hence this check.
6717 +     */
6718 +    if (ctx->acceptorName == GSS_C_NO_NAME) {
6719 +        *minor = GSSEAP_NO_ACCEPTOR_NAME;
6720 +        return GSS_S_FAILURE;
6721 +    }
6722 +
6723 +    return GSS_S_CONTINUE_NEEDED;
6724 +}
6725 +
6726 +static OM_uint32
6727 +eapGssSmInitIdentity(OM_uint32 *minor,
6728 +                     gss_cred_id_t cred GSSEAP_UNUSED,
6729 +                     gss_ctx_id_t ctx,
6730 +                     gss_name_t target GSSEAP_UNUSED,
6731 +                     gss_OID mech GSSEAP_UNUSED,
6732 +                     OM_uint32 reqFlags GSSEAP_UNUSED,
6733 +                     OM_uint32 timeReq GSSEAP_UNUSED,
6734 +                     gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
6735 +                     gss_buffer_t inputToken GSSEAP_UNUSED,
6736 +                     gss_buffer_t outputToken GSSEAP_UNUSED,
6737 +                     OM_uint32 *smFlags)
6738 +{
6739 +    struct eap_config eapConfig;
6740 +
6741 +#ifdef GSSEAP_ENABLE_REAUTH
6742 +    if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_REAUTHENTICATE) {
6743 +        OM_uint32 tmpMinor;
6744 +
6745 +        /* server didn't support reauthentication, sent EAP request */
6746 +        gssDeleteSecContext(&tmpMinor, &ctx->reauthCtx, GSS_C_NO_BUFFER);
6747 +        ctx->flags &= ~(CTX_FLAG_KRB_REAUTH);
6748 +        GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_INITIAL);
6749 +    } else
6750 +#endif
6751 +        *smFlags |= SM_FLAG_FORCE_SEND_TOKEN;
6752 +
6753 +    GSSEAP_ASSERT((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0);
6754 +    GSSEAP_ASSERT(inputToken == GSS_C_NO_BUFFER);
6755 +
6756 +    memset(&eapConfig, 0, sizeof(eapConfig));
6757 +
6758 +    ctx->initiatorCtx.eap = eap_peer_sm_init(ctx,
6759 +                                             &gssEapPolicyCallbacks,
6760 +                                             ctx,
6761 +                                             &eapConfig);
6762 +    if (ctx->initiatorCtx.eap == NULL) {
6763 +        *minor = GSSEAP_PEER_SM_INIT_FAILURE;
6764 +        return GSS_S_FAILURE;
6765 +    }
6766 +
6767 +    ctx->flags |= CTX_FLAG_EAP_RESTART | CTX_FLAG_EAP_PORT_ENABLED;
6768 +
6769 +    /* poke EAP state machine */
6770 +    if (eap_peer_sm_step(ctx->initiatorCtx.eap) != 0) {
6771 +        *minor = GSSEAP_PEER_SM_STEP_FAILURE;
6772 +        return GSS_S_FAILURE;
6773 +    }
6774 +
6775 +    GSSEAP_SM_TRANSITION_NEXT(ctx);
6776 +
6777 +    *minor = 0;
6778 +
6779 +    return GSS_S_CONTINUE_NEEDED;
6780 +}
6781 +
6782 +static OM_uint32
6783 +eapGssSmInitAuthenticate(OM_uint32 *minor,
6784 +                         gss_cred_id_t cred GSSEAP_UNUSED,
6785 +                         gss_ctx_id_t ctx,
6786 +                         gss_name_t target GSSEAP_UNUSED,
6787 +                         gss_OID mech GSSEAP_UNUSED,
6788 +                         OM_uint32 reqFlags GSSEAP_UNUSED,
6789 +                         OM_uint32 timeReq GSSEAP_UNUSED,
6790 +                         gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
6791 +                         gss_buffer_t inputToken GSSEAP_UNUSED,
6792 +                         gss_buffer_t outputToken,
6793 +                         OM_uint32 *smFlags)
6794 +{
6795 +    OM_uint32 major;
6796 +    OM_uint32 tmpMinor;
6797 +    struct wpabuf *resp = NULL;
6798 +
6799 +    *minor = 0;
6800 +
6801 +    GSSEAP_ASSERT(inputToken != GSS_C_NO_BUFFER);
6802 +
6803 +    major = peerConfigInit(minor, ctx);
6804 +    if (GSS_ERROR(major))
6805 +        goto cleanup;
6806 +
6807 +    GSSEAP_ASSERT(ctx->initiatorCtx.eap != NULL);
6808 +    GSSEAP_ASSERT(ctx->flags & CTX_FLAG_EAP_PORT_ENABLED);
6809 +
6810 +    ctx->flags |= CTX_FLAG_EAP_REQ; /* we have a Request from the acceptor */
6811 +
6812 +    wpabuf_set(&ctx->initiatorCtx.reqData,
6813 +               inputToken->value, inputToken->length);
6814 +
6815 +    major = GSS_S_CONTINUE_NEEDED;
6816 +
6817 +    eap_peer_sm_step(ctx->initiatorCtx.eap);
6818 +    if (ctx->flags & CTX_FLAG_EAP_RESP) {
6819 +        ctx->flags &= ~(CTX_FLAG_EAP_RESP);
6820 +
6821 +        resp = eap_get_eapRespData(ctx->initiatorCtx.eap);
6822 +    } else if (ctx->flags & CTX_FLAG_EAP_SUCCESS) {
6823 +        major = initReady(minor, ctx, reqFlags);
6824 +        if (GSS_ERROR(major))
6825 +            goto cleanup;
6826 +
6827 +        ctx->flags &= ~(CTX_FLAG_EAP_SUCCESS);
6828 +        major = GSS_S_CONTINUE_NEEDED;
6829 +        GSSEAP_SM_TRANSITION_NEXT(ctx);
6830 +    } else if (ctx->flags & CTX_FLAG_EAP_FAIL) {
6831 +        major = GSS_S_DEFECTIVE_CREDENTIAL;
6832 +        *minor = GSSEAP_PEER_AUTH_FAILURE;
6833 +    } else {
6834 +        major = GSS_S_DEFECTIVE_TOKEN;
6835 +        *minor = GSSEAP_PEER_BAD_MESSAGE;
6836 +    }
6837 +
6838 +cleanup:
6839 +    if (resp != NULL) {
6840 +        OM_uint32 tmpMajor;
6841 +        gss_buffer_desc respBuf;
6842 +
6843 +        GSSEAP_ASSERT(major == GSS_S_CONTINUE_NEEDED);
6844 +
6845 +        respBuf.length = wpabuf_len(resp);
6846 +        respBuf.value = (void *)wpabuf_head(resp);
6847 +
6848 +        tmpMajor = duplicateBuffer(&tmpMinor, &respBuf, outputToken);
6849 +        if (GSS_ERROR(tmpMajor)) {
6850 +            major = tmpMajor;
6851 +            *minor = tmpMinor;
6852 +        }
6853 +
6854 +        *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
6855 +    }
6856 +
6857 +    wpabuf_set(&ctx->initiatorCtx.reqData, NULL, 0);
6858 +    peerConfigFree(&tmpMinor, ctx);
6859 +
6860 +    return major;
6861 +}
6862 +
6863 +static OM_uint32
6864 +eapGssSmInitGssFlags(OM_uint32 *minor,
6865 +                     gss_cred_id_t cred GSSEAP_UNUSED,
6866 +                     gss_ctx_id_t ctx,
6867 +                     gss_name_t target GSSEAP_UNUSED,
6868 +                     gss_OID mech GSSEAP_UNUSED,
6869 +                     OM_uint32 reqFlags GSSEAP_UNUSED,
6870 +                     OM_uint32 timeReq GSSEAP_UNUSED,
6871 +                     gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
6872 +                     gss_buffer_t inputToken GSSEAP_UNUSED,
6873 +                     gss_buffer_t outputToken,
6874 +                     OM_uint32 *smFlags GSSEAP_UNUSED)
6875 +{
6876 +    unsigned char wireFlags[4];
6877 +    gss_buffer_desc flagsBuf;
6878 +
6879 +    store_uint32_be(ctx->gssFlags & GSSEAP_WIRE_FLAGS_MASK, wireFlags);
6880 +
6881 +    flagsBuf.length = sizeof(wireFlags);
6882 +    flagsBuf.value = wireFlags;
6883 +
6884 +    return duplicateBuffer(minor, &flagsBuf, outputToken);
6885 +}
6886 +
6887 +static OM_uint32
6888 +eapGssSmInitGssChannelBindings(OM_uint32 *minor,
6889 +                               gss_cred_id_t cred GSSEAP_UNUSED,
6890 +                               gss_ctx_id_t ctx,
6891 +                               gss_name_t target GSSEAP_UNUSED,
6892 +                               gss_OID mech GSSEAP_UNUSED,
6893 +                               OM_uint32 reqFlags GSSEAP_UNUSED,
6894 +                               OM_uint32 timeReq GSSEAP_UNUSED,
6895 +                               gss_channel_bindings_t chanBindings,
6896 +                               gss_buffer_t inputToken GSSEAP_UNUSED,
6897 +                               gss_buffer_t outputToken,
6898 +                               OM_uint32 *smFlags)
6899 +{
6900 +    OM_uint32 major;
6901 +    gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER;
6902 +
6903 +    if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS)
6904 +        buffer = chanBindings->application_data;
6905 +
6906 +    major = gssEapWrap(minor, ctx, TRUE, GSS_C_QOP_DEFAULT,
6907 +                       &buffer, NULL, outputToken);
6908 +    if (GSS_ERROR(major))
6909 +        return major;
6910 +
6911 +    GSSEAP_ASSERT(outputToken->value != NULL);
6912 +
6913 +    *minor = 0;
6914 +    *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
6915 +
6916 +    return GSS_S_CONTINUE_NEEDED;
6917 +}
6918 +
6919 +static OM_uint32
6920 +eapGssSmInitInitiatorMIC(OM_uint32 *minor,
6921 +                         gss_cred_id_t cred GSSEAP_UNUSED,
6922 +                         gss_ctx_id_t ctx,
6923 +                         gss_name_t target GSSEAP_UNUSED,
6924 +                         gss_OID mech GSSEAP_UNUSED,
6925 +                         OM_uint32 reqFlags GSSEAP_UNUSED,
6926 +                         OM_uint32 timeReq GSSEAP_UNUSED,
6927 +                         gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
6928 +                         gss_buffer_t inputToken GSSEAP_UNUSED,
6929 +                         gss_buffer_t outputToken,
6930 +                         OM_uint32 *smFlags)
6931 +{
6932 +    OM_uint32 major;
6933 +
6934 +    major = gssEapMakeTokenMIC(minor, ctx, outputToken);
6935 +    if (GSS_ERROR(major))
6936 +        return major;
6937 +
6938 +    GSSEAP_SM_TRANSITION_NEXT(ctx);
6939 +
6940 +    *minor = 0;
6941 +    *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
6942 +
6943 +    return GSS_S_CONTINUE_NEEDED;
6944 +}
6945
6946 +#ifdef GSSEAP_ENABLE_REAUTH
6947 +static OM_uint32
6948 +eapGssSmInitReauthCreds(OM_uint32 *minor,
6949 +                        gss_cred_id_t cred,
6950 +                        gss_ctx_id_t ctx,
6951 +                        gss_name_t target GSSEAP_UNUSED,
6952 +                        gss_OID mech GSSEAP_UNUSED,
6953 +                        OM_uint32 reqFlags GSSEAP_UNUSED,
6954 +                        OM_uint32 timeReq GSSEAP_UNUSED,
6955 +                        gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
6956 +                        gss_buffer_t inputToken,
6957 +                        gss_buffer_t outputToken GSSEAP_UNUSED,
6958 +                        OM_uint32 *smFlags GSSEAP_UNUSED)
6959 +{
6960 +    OM_uint32 major;
6961 +
6962 +    if (ctx->gssFlags & GSS_C_MUTUAL_FLAG) {
6963 +        major = gssEapStoreReauthCreds(minor, ctx, cred, inputToken);
6964 +        if (GSS_ERROR(major))
6965 +            return major;
6966 +    }
6967 +
6968 +    *minor = 0;
6969 +    return GSS_S_CONTINUE_NEEDED;
6970 +}
6971 +#endif /* GSSEAP_ENABLE_REAUTH */
6972 +
6973 +static OM_uint32
6974 +eapGssSmInitAcceptorMIC(OM_uint32 *minor,
6975 +                        gss_cred_id_t cred GSSEAP_UNUSED,
6976 +                        gss_ctx_id_t ctx,
6977 +                        gss_name_t target GSSEAP_UNUSED,
6978 +                        gss_OID mech GSSEAP_UNUSED,
6979 +                        OM_uint32 reqFlags GSSEAP_UNUSED,
6980 +                        OM_uint32 timeReq GSSEAP_UNUSED,
6981 +                        gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
6982 +                        gss_buffer_t inputToken,
6983 +                        gss_buffer_t outputToken GSSEAP_UNUSED,
6984 +                        OM_uint32 *smFlags GSSEAP_UNUSED)
6985 +{
6986 +    OM_uint32 major;
6987 +
6988 +    major = gssEapVerifyTokenMIC(minor, ctx, inputToken);
6989 +    if (GSS_ERROR(major))
6990 +        return major;
6991 +
6992 +    GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
6993 +
6994 +    *minor = 0;
6995 +
6996 +    return GSS_S_COMPLETE;
6997 +}
6998 +
6999 +static struct gss_eap_sm eapGssInitiatorSm[] = {
7000 +    {
7001 +        ITOK_TYPE_CONTEXT_ERR,
7002 +        ITOK_TYPE_NONE,
7003 +        GSSEAP_STATE_ALL & ~(GSSEAP_STATE_INITIAL),
7004 +        0,
7005 +        eapGssSmInitError
7006 +    },
7007 +    {
7008 +        ITOK_TYPE_ACCEPTOR_NAME_RESP,
7009 +        ITOK_TYPE_ACCEPTOR_NAME_REQ,
7010 +        GSSEAP_STATE_INITIAL | GSSEAP_STATE_AUTHENTICATE,
7011 +        0,
7012 +        eapGssSmInitAcceptorName
7013 +    },
7014 +#ifdef GSSEAP_DEBUG
7015 +    {
7016 +        ITOK_TYPE_NONE,
7017 +        ITOK_TYPE_VENDOR_INFO,
7018 +        GSSEAP_STATE_INITIAL,
7019 +        0,
7020 +        eapGssSmInitVendorInfo
7021 +    },
7022 +#endif
7023 +#ifdef GSSEAP_ENABLE_REAUTH
7024 +    {
7025 +        ITOK_TYPE_REAUTH_RESP,
7026 +        ITOK_TYPE_REAUTH_REQ,
7027 +        GSSEAP_STATE_INITIAL | GSSEAP_STATE_REAUTHENTICATE,
7028 +        0,
7029 +        eapGssSmInitGssReauth
7030 +    },
7031 +#endif
7032 +    {
7033 +        ITOK_TYPE_NONE,
7034 +        ITOK_TYPE_NONE,
7035 +#ifdef GSSEAP_ENABLE_REAUTH
7036 +        GSSEAP_STATE_REAUTHENTICATE |
7037 +#endif
7038 +        GSSEAP_STATE_INITIAL,
7039 +        SM_ITOK_FLAG_REQUIRED,
7040 +        eapGssSmInitIdentity
7041 +    },
7042 +    {
7043 +        ITOK_TYPE_EAP_REQ,
7044 +        ITOK_TYPE_EAP_RESP,
7045 +        GSSEAP_STATE_AUTHENTICATE,
7046 +        SM_ITOK_FLAG_REQUIRED,
7047 +        eapGssSmInitAuthenticate
7048 +    },
7049 +    {
7050 +        ITOK_TYPE_NONE,
7051 +        ITOK_TYPE_GSS_FLAGS,
7052 +        GSSEAP_STATE_INITIATOR_EXTS,
7053 +        0,
7054 +        eapGssSmInitGssFlags
7055 +    },
7056 +    {
7057 +        ITOK_TYPE_NONE,
7058 +        ITOK_TYPE_GSS_CHANNEL_BINDINGS,
7059 +        GSSEAP_STATE_INITIATOR_EXTS,
7060 +        SM_ITOK_FLAG_REQUIRED,
7061 +        eapGssSmInitGssChannelBindings
7062 +    },
7063 +    {
7064 +        ITOK_TYPE_NONE,
7065 +        ITOK_TYPE_INITIATOR_MIC,
7066 +        GSSEAP_STATE_INITIATOR_EXTS,
7067 +        SM_ITOK_FLAG_REQUIRED,
7068 +        eapGssSmInitInitiatorMIC
7069 +    },
7070 +#ifdef GSSEAP_ENABLE_REAUTH
7071 +    {
7072 +        ITOK_TYPE_REAUTH_CREDS,
7073 +        ITOK_TYPE_NONE,
7074 +        GSSEAP_STATE_ACCEPTOR_EXTS,
7075 +        0,
7076 +        eapGssSmInitReauthCreds
7077 +    },
7078 +#endif
7079 +    /* other extensions go here */
7080 +    {
7081 +        ITOK_TYPE_ACCEPTOR_MIC,
7082 +        ITOK_TYPE_NONE,
7083 +        GSSEAP_STATE_ACCEPTOR_EXTS,
7084 +        SM_ITOK_FLAG_REQUIRED,
7085 +        eapGssSmInitAcceptorMIC
7086 +    }
7087 +};
7088 +
7089 +OM_uint32
7090 +gssEapInitSecContext(OM_uint32 *minor,
7091 +                     gss_cred_id_t cred,
7092 +                     gss_ctx_id_t ctx,
7093 +                     gss_name_t target_name,
7094 +                     gss_OID mech_type,
7095 +                     OM_uint32 req_flags,
7096 +                     OM_uint32 time_req,
7097 +                     gss_channel_bindings_t input_chan_bindings,
7098 +                     gss_buffer_t input_token,
7099 +                     gss_OID *actual_mech_type,
7100 +                     gss_buffer_t output_token,
7101 +                     OM_uint32 *ret_flags,
7102 +                     OM_uint32 *time_rec)
7103 +{
7104 +    OM_uint32 major, tmpMinor;
7105 +    int initialContextToken = (ctx->mechanismUsed == GSS_C_NO_OID);
7106 +
7107 +    /*
7108 +     * XXX is acquiring the credential lock here necessary? The password is
7109 +     * mutable but the contract could specify that this is not updated whilst
7110 +     * a context is being initialized.
7111 +     */
7112 +    if (cred != GSS_C_NO_CREDENTIAL)
7113 +        GSSEAP_MUTEX_LOCK(&cred->mutex);
7114 +
7115 +    if (ctx->cred == GSS_C_NO_CREDENTIAL) {
7116 +        major = gssEapResolveInitiatorCred(minor, cred, target_name, &ctx->cred);
7117 +        if (GSS_ERROR(major))
7118 +            goto cleanup;
7119 +
7120 +        GSSEAP_ASSERT(ctx->cred != GSS_C_NO_CREDENTIAL);
7121 +    }
7122 +
7123 +    GSSEAP_MUTEX_LOCK(&ctx->cred->mutex);
7124 +
7125 +    GSSEAP_ASSERT(ctx->cred->flags & CRED_FLAG_RESOLVED);
7126 +    GSSEAP_ASSERT(ctx->cred->flags & CRED_FLAG_INITIATE);
7127 +
7128 +    if (initialContextToken) {
7129 +        major = initBegin(minor, ctx, target_name, mech_type,
7130 +                          req_flags, time_req, input_chan_bindings);
7131 +        if (GSS_ERROR(major))
7132 +            goto cleanup;
7133 +    }
7134 +
7135 +    major = gssEapSmStep(minor,
7136 +                         cred,
7137 +                         ctx,
7138 +                         target_name,
7139 +                         mech_type,
7140 +                         req_flags,
7141 +                         time_req,
7142 +                         input_chan_bindings,
7143 +                         input_token,
7144 +                         output_token,
7145 +                         eapGssInitiatorSm,
7146 +                         sizeof(eapGssInitiatorSm) / sizeof(eapGssInitiatorSm[0]));
7147 +    if (GSS_ERROR(major))
7148 +        goto cleanup;
7149 +
7150 +    if (actual_mech_type != NULL) {
7151 +        OM_uint32 tmpMajor;
7152 +
7153 +        tmpMajor = gssEapCanonicalizeOid(&tmpMinor, ctx->mechanismUsed, 0, actual_mech_type);
7154 +        if (GSS_ERROR(tmpMajor)) {
7155 +            major = tmpMajor;
7156 +            *minor = tmpMinor;
7157 +            goto cleanup;
7158 +        }
7159 +    }
7160 +    if (ret_flags != NULL)
7161 +        *ret_flags = ctx->gssFlags;
7162 +    if (time_rec != NULL)
7163 +        gssEapContextTime(&tmpMinor, ctx, time_rec);
7164 +
7165 +    GSSEAP_ASSERT(CTX_IS_ESTABLISHED(ctx) || major == GSS_S_CONTINUE_NEEDED);
7166 +
7167 +cleanup:
7168 +    if (cred != GSS_C_NO_CREDENTIAL)
7169 +        GSSEAP_MUTEX_UNLOCK(&cred->mutex);
7170 +    if (ctx->cred != GSS_C_NO_CREDENTIAL)
7171 +        GSSEAP_MUTEX_UNLOCK(&ctx->cred->mutex);
7172 +
7173 +    return major;
7174 +}
7175 +
7176 +OM_uint32 GSSAPI_CALLCONV
7177 +gss_init_sec_context(OM_uint32 *minor,
7178 +                     gss_cred_id_t cred,
7179 +                     gss_ctx_id_t *context_handle,
7180 +                     gss_name_t target_name,
7181 +                     gss_OID mech_type,
7182 +                     OM_uint32 req_flags,
7183 +                     OM_uint32 time_req,
7184 +                     gss_channel_bindings_t input_chan_bindings,
7185 +                     gss_buffer_t input_token,
7186 +                     gss_OID *actual_mech_type,
7187 +                     gss_buffer_t output_token,
7188 +                     OM_uint32 *ret_flags,
7189 +                     OM_uint32 *time_rec)
7190 +{
7191 +    OM_uint32 major, tmpMinor;
7192 +    gss_ctx_id_t ctx = *context_handle;
7193 +
7194 +    *minor = 0;
7195 +
7196 +    output_token->length = 0;
7197 +    output_token->value = NULL;
7198 +
7199 +    if (ctx == GSS_C_NO_CONTEXT) {
7200 +        if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) {
7201 +            *minor = GSSEAP_WRONG_SIZE;
7202 +            return GSS_S_DEFECTIVE_TOKEN;
7203 +        }
7204 +
7205 +        major = gssEapAllocContext(minor, &ctx);
7206 +        if (GSS_ERROR(major))
7207 +            return major;
7208 +
7209 +        ctx->flags |= CTX_FLAG_INITIATOR;
7210 +
7211 +        *context_handle = ctx;
7212 +    }
7213 +
7214 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
7215 +
7216 +    major = gssEapInitSecContext(minor,
7217 +                                 cred,
7218 +                                 ctx,
7219 +                                 target_name,
7220 +                                 mech_type,
7221 +                                 req_flags,
7222 +                                 time_req,
7223 +                                 input_chan_bindings,
7224 +                                 input_token,
7225 +                                 actual_mech_type,
7226 +                                 output_token,
7227 +                                 ret_flags,
7228 +                                 time_rec);
7229 +
7230 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
7231 +
7232 +    if (GSS_ERROR(major))
7233 +        gssEapReleaseContext(&tmpMinor, context_handle);
7234 +
7235 +    return major;
7236 +}
7237 diff --git a/mech_eap/inquire_attrs_for_mech.c b/mech_eap/inquire_attrs_for_mech.c
7238 new file mode 100644
7239 index 0000000..a359f68
7240 --- /dev/null
7241 +++ b/mech_eap/inquire_attrs_for_mech.c
7242 @@ -0,0 +1,137 @@
7243 +/*
7244 + * Copyright (c) 2011, JANET(UK)
7245 + * All rights reserved.
7246 + *
7247 + * Redistribution and use in source and binary forms, with or without
7248 + * modification, are permitted provided that the following conditions
7249 + * are met:
7250 + *
7251 + * 1. Redistributions of source code must retain the above copyright
7252 + *    notice, this list of conditions and the following disclaimer.
7253 + *
7254 + * 2. Redistributions in binary form must reproduce the above copyright
7255 + *    notice, this list of conditions and the following disclaimer in the
7256 + *    documentation and/or other materials provided with the distribution.
7257 + *
7258 + * 3. Neither the name of JANET(UK) nor the names of its contributors
7259 + *    may be used to endorse or promote products derived from this software
7260 + *    without specific prior written permission.
7261 + *
7262 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
7263 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7264 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7265 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7266 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7267 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
7268 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
7269 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
7270 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
7271 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7272 + * SUCH DAMAGE.
7273 + */
7274 +
7275 +/*
7276 + * Enumerate the features supported by the GSS EAP mechanism.
7277 + */
7278 +
7279 +#include "gssapiP_eap.h"
7280 +
7281 +#define MA_ADD(ma, set)    do { \
7282 +    major = gss_add_oid_set_member(minor, (gss_OID)(ma), (set));            \
7283 +    if (GSS_ERROR(major))                                                   \
7284 +        goto cleanup;                                                       \
7285 +    } while (0)
7286 +
7287 +#define MA_SUPPORTED(ma)    MA_ADD((ma), mech_attrs)
7288 +#define MA_KNOWN(ma)        MA_ADD((ma), known_mech_attrs)
7289 +
7290 +OM_uint32 GSSAPI_CALLCONV
7291 +gss_inquire_attrs_for_mech(OM_uint32 *minor,
7292 +                           gss_const_OID mech_oid,
7293 +                           gss_OID_set *mech_attrs,
7294 +                           gss_OID_set *known_mech_attrs)
7295 +{
7296 +    OM_uint32 major, tmpMinor;
7297 +
7298 +    if (mech_attrs != NULL)
7299 +        *mech_attrs = GSS_C_NO_OID_SET;
7300 +    if (known_mech_attrs != NULL)
7301 +        *known_mech_attrs = GSS_C_NO_OID_SET;
7302 +
7303 +    if (!gssEapIsConcreteMechanismOid((const gss_OID)mech_oid)) {
7304 +        *minor = GSSEAP_WRONG_MECH;
7305 +        return GSS_S_BAD_MECH;
7306 +    }
7307 +
7308 +    if (mech_attrs != NULL) {
7309 +        major = gss_create_empty_oid_set(minor, mech_attrs);
7310 +        if (GSS_ERROR(major))
7311 +            goto cleanup;
7312 +
7313 +#ifdef HAVE_GSS_INQUIRE_ATTRS_FOR_MECH
7314 +        if (oidEqual(mech_oid, GSS_EAP_MECHANISM))
7315 +            MA_SUPPORTED(GSS_C_MA_MECH_PSEUDO);
7316 +        else
7317 +            MA_SUPPORTED(GSS_C_MA_MECH_CONCRETE);
7318 +        MA_SUPPORTED(GSS_C_MA_ITOK_FRAMED);
7319 +        MA_SUPPORTED(GSS_C_MA_AUTH_INIT);
7320 +        MA_SUPPORTED(GSS_C_MA_AUTH_TARG);
7321 +        MA_SUPPORTED(GSS_C_MA_AUTH_INIT_INIT);
7322 +        MA_SUPPORTED(GSS_C_MA_INTEG_PROT);
7323 +        MA_SUPPORTED(GSS_C_MA_CONF_PROT);
7324 +        MA_SUPPORTED(GSS_C_MA_MIC);
7325 +        MA_SUPPORTED(GSS_C_MA_WRAP);
7326 +        MA_SUPPORTED(GSS_C_MA_REPLAY_DET);
7327 +        MA_SUPPORTED(GSS_C_MA_OOS_DET);
7328 +        MA_SUPPORTED(GSS_C_MA_CBINDINGS);
7329 +        MA_SUPPORTED(GSS_C_MA_CTX_TRANS);
7330 +#endif
7331 +    }
7332 +
7333 +    if (known_mech_attrs != NULL) {
7334 +        major = gss_create_empty_oid_set(minor, known_mech_attrs);
7335 +        if (GSS_ERROR(major))
7336 +            goto cleanup;
7337 +
7338 +#ifdef HAVE_GSS_INQUIRE_ATTRS_FOR_MECH
7339 +        MA_KNOWN(GSS_C_MA_MECH_CONCRETE);
7340 +        MA_KNOWN(GSS_C_MA_MECH_PSEUDO);
7341 +        MA_KNOWN(GSS_C_MA_MECH_COMPOSITE);
7342 +        MA_KNOWN(GSS_C_MA_MECH_NEGO);
7343 +        MA_KNOWN(GSS_C_MA_MECH_GLUE);
7344 +        MA_KNOWN(GSS_C_MA_NOT_MECH);
7345 +        MA_KNOWN(GSS_C_MA_DEPRECATED);
7346 +        MA_KNOWN(GSS_C_MA_NOT_DFLT_MECH);
7347 +        MA_KNOWN(GSS_C_MA_ITOK_FRAMED);
7348 +        MA_KNOWN(GSS_C_MA_AUTH_INIT);
7349 +        MA_KNOWN(GSS_C_MA_AUTH_TARG);
7350 +        MA_KNOWN(GSS_C_MA_AUTH_INIT_INIT);
7351 +        MA_KNOWN(GSS_C_MA_AUTH_TARG_INIT);
7352 +        MA_KNOWN(GSS_C_MA_AUTH_INIT_ANON);
7353 +        MA_KNOWN(GSS_C_MA_AUTH_TARG_ANON);
7354 +        MA_KNOWN(GSS_C_MA_DELEG_CRED);
7355 +        MA_KNOWN(GSS_C_MA_INTEG_PROT);
7356 +        MA_KNOWN(GSS_C_MA_CONF_PROT);
7357 +        MA_KNOWN(GSS_C_MA_MIC);
7358 +        MA_KNOWN(GSS_C_MA_WRAP);
7359 +        MA_KNOWN(GSS_C_MA_PROT_READY);
7360 +        MA_KNOWN(GSS_C_MA_REPLAY_DET);
7361 +        MA_KNOWN(GSS_C_MA_OOS_DET);
7362 +        MA_KNOWN(GSS_C_MA_CBINDINGS);
7363 +        MA_KNOWN(GSS_C_MA_PFS);
7364 +        MA_KNOWN(GSS_C_MA_COMPRESS);
7365 +        MA_KNOWN(GSS_C_MA_CTX_TRANS);
7366 +#endif
7367 +    }
7368 +
7369 +    major = GSS_S_COMPLETE;
7370 +    *minor = 0;
7371 +
7372 +cleanup:
7373 +    if (GSS_ERROR(major)) {
7374 +        gss_release_oid_set(&tmpMinor, mech_attrs);
7375 +        gss_release_oid_set(&tmpMinor, known_mech_attrs);
7376 +    }
7377 +
7378 +    return major;
7379 +}
7380 diff --git a/mech_eap/inquire_context.c b/mech_eap/inquire_context.c
7381 new file mode 100644
7382 index 0000000..d37818d
7383 --- /dev/null
7384 +++ b/mech_eap/inquire_context.c
7385 @@ -0,0 +1,116 @@
7386 +/*
7387 + * Copyright (c) 2011, JANET(UK)
7388 + * All rights reserved.
7389 + *
7390 + * Redistribution and use in source and binary forms, with or without
7391 + * modification, are permitted provided that the following conditions
7392 + * are met:
7393 + *
7394 + * 1. Redistributions of source code must retain the above copyright
7395 + *    notice, this list of conditions and the following disclaimer.
7396 + *
7397 + * 2. Redistributions in binary form must reproduce the above copyright
7398 + *    notice, this list of conditions and the following disclaimer in the
7399 + *    documentation and/or other materials provided with the distribution.
7400 + *
7401 + * 3. Neither the name of JANET(UK) nor the names of its contributors
7402 + *    may be used to endorse or promote products derived from this software
7403 + *    without specific prior written permission.
7404 + *
7405 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
7406 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7407 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7408 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7409 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7410 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
7411 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
7412 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
7413 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
7414 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7415 + * SUCH DAMAGE.
7416 + */
7417 +
7418 +/*
7419 + * Return context handle properties.
7420 + */
7421 +
7422 +#include "gssapiP_eap.h"
7423 +
7424 +OM_uint32 GSSAPI_CALLCONV
7425 +gss_inquire_context(OM_uint32 *minor,
7426 +                    gss_ctx_id_t ctx,
7427 +                    gss_name_t *src_name,
7428 +                    gss_name_t *targ_name,
7429 +                    OM_uint32 *lifetime_rec,
7430 +                    gss_OID *mech_type,
7431 +                    OM_uint32 *ctx_flags,
7432 +                    int *locally_initiated,
7433 +                    int *open)
7434 +{
7435 +    OM_uint32 major, tmpMinor;
7436 +
7437 +    if (ctx == GSS_C_NO_CONTEXT) {
7438 +        *minor = EINVAL;
7439 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
7440 +    }
7441 +
7442 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
7443 +
7444 +    if (src_name != NULL) {
7445 +        major = gssEapDuplicateName(minor, ctx->initiatorName, src_name);
7446 +        if (GSS_ERROR(major))
7447 +            goto cleanup;
7448 +    }
7449 +
7450 +    if (targ_name != NULL) {
7451 +        major = gssEapDuplicateName(minor, ctx->acceptorName, targ_name);
7452 +        if (GSS_ERROR(major))
7453 +            goto cleanup;
7454 +    }
7455 +
7456 +    if (lifetime_rec != NULL) {
7457 +        time_t now, lifetime;
7458 +
7459 +        if (ctx->expiryTime == 0) {
7460 +            lifetime = GSS_C_INDEFINITE;
7461 +        } else {
7462 +            now = time(NULL);
7463 +            lifetime = now - ctx->expiryTime;
7464 +            if (lifetime < 0)
7465 +                lifetime = 0;
7466 +        }
7467 +
7468 +        *lifetime_rec = lifetime;
7469 +    }
7470 +
7471 +    if (mech_type != NULL) {
7472 +        major = gssEapCanonicalizeOid(minor, ctx->mechanismUsed, 0, mech_type);
7473 +        if (GSS_ERROR(major))
7474 +            goto cleanup;
7475 +    }
7476 +
7477 +    if (ctx_flags != NULL) {
7478 +        *ctx_flags = ctx->gssFlags;
7479 +    }
7480 +
7481 +    if (locally_initiated != NULL) {
7482 +        *locally_initiated = CTX_IS_INITIATOR(ctx);
7483 +    }
7484 +
7485 +    if (open != NULL) {
7486 +        *open = CTX_IS_ESTABLISHED(ctx);
7487 +    }
7488 +
7489 +    major = GSS_S_COMPLETE;
7490 +    *minor = 0;
7491 +
7492 +cleanup:
7493 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
7494 +
7495 +    if (GSS_ERROR(major)) {
7496 +        gssEapReleaseName(&tmpMinor, src_name);
7497 +        gssEapReleaseName(&tmpMinor, targ_name);
7498 +    }
7499 +
7500 +    return major;
7501 +}
7502 diff --git a/mech_eap/inquire_cred.c b/mech_eap/inquire_cred.c
7503 new file mode 100644
7504 index 0000000..227ab16
7505 --- /dev/null
7506 +++ b/mech_eap/inquire_cred.c
7507 @@ -0,0 +1,61 @@
7508 +/*
7509 + * Copyright (c) 2011, JANET(UK)
7510 + * All rights reserved.
7511 + *
7512 + * Redistribution and use in source and binary forms, with or without
7513 + * modification, are permitted provided that the following conditions
7514 + * are met:
7515 + *
7516 + * 1. Redistributions of source code must retain the above copyright
7517 + *    notice, this list of conditions and the following disclaimer.
7518 + *
7519 + * 2. Redistributions in binary form must reproduce the above copyright
7520 + *    notice, this list of conditions and the following disclaimer in the
7521 + *    documentation and/or other materials provided with the distribution.
7522 + *
7523 + * 3. Neither the name of JANET(UK) nor the names of its contributors
7524 + *    may be used to endorse or promote products derived from this software
7525 + *    without specific prior written permission.
7526 + *
7527 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
7528 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7529 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7530 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7531 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7532 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
7533 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
7534 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
7535 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
7536 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7537 + * SUCH DAMAGE.
7538 + */
7539 +
7540 +/*
7541 + * Return credential handle properties.
7542 + */
7543 +
7544 +#include "gssapiP_eap.h"
7545 +
7546 +OM_uint32 GSSAPI_CALLCONV
7547 +gss_inquire_cred(OM_uint32 *minor,
7548 +                 gss_cred_id_t cred,
7549 +                 gss_name_t *name,
7550 +                 OM_uint32 *pLifetime,
7551 +                 gss_cred_usage_t *cred_usage,
7552 +                 gss_OID_set *mechanisms)
7553 +{
7554 +    OM_uint32 major;
7555 +
7556 +    if (cred == NULL) {
7557 +        *minor = EINVAL;
7558 +        return GSS_S_NO_CRED;
7559 +    }
7560 +
7561 +    GSSEAP_MUTEX_LOCK(&cred->mutex);
7562 +
7563 +    major = gssEapInquireCred(minor, cred, name, pLifetime, cred_usage, mechanisms);
7564 +
7565 +    GSSEAP_MUTEX_UNLOCK(&cred->mutex);
7566 +
7567 +    return major;
7568 +}
7569 diff --git a/mech_eap/inquire_cred_by_mech.c b/mech_eap/inquire_cred_by_mech.c
7570 new file mode 100644
7571 index 0000000..191902d
7572 --- /dev/null
7573 +++ b/mech_eap/inquire_cred_by_mech.c
7574 @@ -0,0 +1,76 @@
7575 +/*
7576 + * Copyright (c) 2011, JANET(UK)
7577 + * All rights reserved.
7578 + *
7579 + * Redistribution and use in source and binary forms, with or without
7580 + * modification, are permitted provided that the following conditions
7581 + * are met:
7582 + *
7583 + * 1. Redistributions of source code must retain the above copyright
7584 + *    notice, this list of conditions and the following disclaimer.
7585 + *
7586 + * 2. Redistributions in binary form must reproduce the above copyright
7587 + *    notice, this list of conditions and the following disclaimer in the
7588 + *    documentation and/or other materials provided with the distribution.
7589 + *
7590 + * 3. Neither the name of JANET(UK) nor the names of its contributors
7591 + *    may be used to endorse or promote products derived from this software
7592 + *    without specific prior written permission.
7593 + *
7594 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
7595 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7596 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7597 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7598 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7599 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
7600 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
7601 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
7602 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
7603 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7604 + * SUCH DAMAGE.
7605 + */
7606 +
7607 +/*
7608 + * Return credential handle properties.
7609 + */
7610 +
7611 +#include "gssapiP_eap.h"
7612 +
7613 +OM_uint32 GSSAPI_CALLCONV
7614 +gss_inquire_cred_by_mech(OM_uint32 *minor,
7615 +                         gss_cred_id_t cred,
7616 +                         gss_OID mech_type,
7617 +                         gss_name_t *name,
7618 +                         OM_uint32 *pInitiatorLifetime,
7619 +                         OM_uint32 *pAcceptorLifetime,
7620 +                         gss_cred_usage_t *cred_usage)
7621 +{
7622 +    OM_uint32 major, lifetime;
7623 +
7624 +    if (cred == NULL) {
7625 +        *minor = EINVAL;
7626 +        return GSS_S_NO_CRED;
7627 +    }
7628 +
7629 +    GSSEAP_MUTEX_LOCK(&cred->mutex);
7630 +
7631 +    if (!gssEapCredAvailable(cred, mech_type)) {
7632 +        major = GSS_S_BAD_MECH;
7633 +        *minor = GSSEAP_CRED_MECH_MISMATCH;
7634 +        goto cleanup;
7635 +    }
7636 +
7637 +    major = gssEapInquireCred(minor, cred, name, &lifetime, cred_usage, NULL);
7638 +    if (GSS_ERROR(major))
7639 +        goto cleanup;
7640 +
7641 +    if (pInitiatorLifetime != NULL)
7642 +        *pInitiatorLifetime = (cred->flags & CRED_FLAG_INITIATE) ? lifetime : 0;
7643 +    if (pAcceptorLifetime != NULL)
7644 +        *pAcceptorLifetime = (cred->flags & CRED_FLAG_ACCEPT) ? lifetime : 0;
7645 +
7646 +cleanup:
7647 +    GSSEAP_MUTEX_UNLOCK(&cred->mutex);
7648 +
7649 +    return major;
7650 +}
7651 diff --git a/mech_eap/inquire_cred_by_oid.c b/mech_eap/inquire_cred_by_oid.c
7652 new file mode 100644
7653 index 0000000..2ad34ed
7654 --- /dev/null
7655 +++ b/mech_eap/inquire_cred_by_oid.c
7656 @@ -0,0 +1,83 @@
7657 +/*
7658 + * Copyright (c) 2011, JANET(UK)
7659 + * All rights reserved.
7660 + *
7661 + * Redistribution and use in source and binary forms, with or without
7662 + * modification, are permitted provided that the following conditions
7663 + * are met:
7664 + *
7665 + * 1. Redistributions of source code must retain the above copyright
7666 + *    notice, this list of conditions and the following disclaimer.
7667 + *
7668 + * 2. Redistributions in binary form must reproduce the above copyright
7669 + *    notice, this list of conditions and the following disclaimer in the
7670 + *    documentation and/or other materials provided with the distribution.
7671 + *
7672 + * 3. Neither the name of JANET(UK) nor the names of its contributors
7673 + *    may be used to endorse or promote products derived from this software
7674 + *    without specific prior written permission.
7675 + *
7676 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
7677 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7678 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7679 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7680 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7681 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
7682 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
7683 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
7684 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
7685 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7686 + * SUCH DAMAGE.
7687 + */
7688 +
7689 +/*
7690 + * Return extended credential handle properties.
7691 + */
7692 +
7693 +#include "gssapiP_eap.h"
7694 +
7695 +#if 0
7696 +static struct {
7697 +    gss_OID_desc oid;
7698 +    OM_uint32 (*inquire)(OM_uint32 *, const gss_cred_id_t,
7699 +                         const gss_OID, gss_buffer_set_t *);
7700 +} inquireCredOps[] = {
7701 +};
7702 +#endif
7703 +
7704 +OM_uint32 GSSAPI_CALLCONV
7705 +gss_inquire_cred_by_oid(OM_uint32 *minor,
7706 +                        const gss_cred_id_t cred_handle,
7707 +                        const gss_OID desired_object GSSEAP_UNUSED,
7708 +                        gss_buffer_set_t *data_set)
7709 +{
7710 +    OM_uint32 major;
7711 +#if 0
7712 +    int i;
7713 +#endif
7714 +    *data_set = GSS_C_NO_BUFFER_SET;
7715 +
7716 +    if (cred_handle == GSS_C_NO_CREDENTIAL) {
7717 +        *minor = EINVAL;
7718 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED;
7719 +    }
7720 +
7721 +    GSSEAP_MUTEX_LOCK(&cred_handle->mutex);
7722 +
7723 +    major = GSS_S_UNAVAILABLE;
7724 +    *minor = GSSEAP_BAD_CRED_OPTION;
7725 +
7726 +#if 0
7727 +    for (i = 0; i < sizeof(inquireCredOps) / sizeof(inquireCredOps[0]); i++) {
7728 +        if (oidEqual(&inquireCredOps[i].oid, desired_object)) {
7729 +            major = (*inquireCredOps[i].inquire)(minor, cred_handle,
7730 +                                                 desired_object, data_set);
7731 +            break;
7732 +        }
7733 +    }
7734 +#endif
7735 +
7736 +    GSSEAP_MUTEX_UNLOCK(&cred_handle->mutex);
7737 +
7738 +    return major;
7739 +}
7740 diff --git a/mech_eap/inquire_mech_for_saslname.c b/mech_eap/inquire_mech_for_saslname.c
7741 new file mode 100644
7742 index 0000000..bd518c0
7743 --- /dev/null
7744 +++ b/mech_eap/inquire_mech_for_saslname.c
7745 @@ -0,0 +1,84 @@
7746 +/*
7747 + * Copyright (c) 2011, JANET(UK)
7748 + * All rights reserved.
7749 + *
7750 + * Redistribution and use in source and binary forms, with or without
7751 + * modification, are permitted provided that the following conditions
7752 + * are met:
7753 + *
7754 + * 1. Redistributions of source code must retain the above copyright
7755 + *    notice, this list of conditions and the following disclaimer.
7756 + *
7757 + * 2. Redistributions in binary form must reproduce the above copyright
7758 + *    notice, this list of conditions and the following disclaimer in the
7759 + *    documentation and/or other materials provided with the distribution.
7760 + *
7761 + * 3. Neither the name of JANET(UK) nor the names of its contributors
7762 + *    may be used to endorse or promote products derived from this software
7763 + *    without specific prior written permission.
7764 + *
7765 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
7766 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7767 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7768 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7769 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7770 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
7771 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
7772 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
7773 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
7774 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7775 + * SUCH DAMAGE.
7776 + */
7777 +
7778 +/*
7779 + * Map mechanism OID to a SASL mechanism name.
7780 + */
7781 +
7782 +#include "gssapiP_eap.h"
7783 +
7784 +OM_uint32 GSSAPI_CALLCONV
7785 +gss_inquire_saslname_for_mech(OM_uint32 *minor,
7786 +                              const gss_OID mech,
7787 +                              gss_buffer_t sasl_mech_name,
7788 +                              gss_buffer_t mech_name,
7789 +                              gss_buffer_t mech_description)
7790 +{
7791 +    OM_uint32 major;
7792 +    gss_buffer_t name;
7793 +    krb5_enctype etype = ENCTYPE_NULL;
7794 +
7795 +    /* Dynamically construct mechanism name from Kerberos string enctype */
7796 +    major = gssEapOidToEnctype(minor, mech, &etype);
7797 +    if (GSS_ERROR(major))
7798 +        return major;
7799 +
7800 +    if (mech_name != GSS_C_NO_BUFFER) {
7801 +        krb5_context krbContext;
7802 +
7803 +        GSSEAP_KRB_INIT(&krbContext);
7804 +
7805 +        *minor = krbEnctypeToString(krbContext, etype, "eap-", mech_name);
7806 +        if (*minor != 0)
7807 +            return GSS_S_FAILURE;
7808 +    }
7809 +
7810 +    if (mech_description != GSS_C_NO_BUFFER) {
7811 +        major = makeStringBuffer(minor,
7812 +                                 "Extensible Authentication Protocol GSS-API Mechanism",
7813 +                                 mech_description);
7814 +        if (GSS_ERROR(major))
7815 +            return major;
7816 +    }
7817 +
7818 +    if (sasl_mech_name != GSS_C_NO_BUFFER) {
7819 +        name = gssEapOidToSaslName(mech);
7820 +        if (name == GSS_C_NO_BUFFER) {
7821 +            major = GSS_S_BAD_MECH;
7822 +            *minor = GSSEAP_WRONG_MECH;
7823 +        } else {
7824 +            major = duplicateBuffer(minor, name, sasl_mech_name);
7825 +        }
7826 +    }
7827 +
7828 +    return major;
7829 +}
7830 diff --git a/mech_eap/inquire_mechs_for_name.c b/mech_eap/inquire_mechs_for_name.c
7831 new file mode 100644
7832 index 0000000..89c869c
7833 --- /dev/null
7834 +++ b/mech_eap/inquire_mechs_for_name.c
7835 @@ -0,0 +1,69 @@
7836 +/*
7837 + * Copyright (c) 2011, JANET(UK)
7838 + * All rights reserved.
7839 + *
7840 + * Redistribution and use in source and binary forms, with or without
7841 + * modification, are permitted provided that the following conditions
7842 + * are met:
7843 + *
7844 + * 1. Redistributions of source code must retain the above copyright
7845 + *    notice, this list of conditions and the following disclaimer.
7846 + *
7847 + * 2. Redistributions in binary form must reproduce the above copyright
7848 + *    notice, this list of conditions and the following disclaimer in the
7849 + *    documentation and/or other materials provided with the distribution.
7850 + *
7851 + * 3. Neither the name of JANET(UK) nor the names of its contributors
7852 + *    may be used to endorse or promote products derived from this software
7853 + *    without specific prior written permission.
7854 + *
7855 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
7856 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7857 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7858 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7859 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7860 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
7861 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
7862 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
7863 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
7864 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7865 + * SUCH DAMAGE.
7866 + */
7867 +
7868 +/*
7869 + * Determine mechanism OIDs supported by name.
7870 + */
7871 +
7872 +#include "gssapiP_eap.h"
7873 +
7874 +OM_uint32 GSSAPI_CALLCONV
7875 +gss_inquire_mechs_for_name(OM_uint32 *minor,
7876 +                           const gss_name_t input_name,
7877 +                           gss_OID_set *mech_types)
7878 +{
7879 +    OM_uint32 major, tmpMinor;
7880 +
7881 +    *minor = 0;
7882 +    *mech_types = GSS_C_NO_OID_SET;
7883 +
7884 +    if (input_name != GSS_C_NO_NAME &&
7885 +        input_name->mechanismUsed != GSS_C_NO_OID) {
7886 +        major = gss_create_empty_oid_set(minor, mech_types);
7887 +        if (GSS_ERROR(major))
7888 +            return major;
7889 +
7890 +        major = gss_add_oid_set_member(minor,
7891 +                                       input_name->mechanismUsed,
7892 +                                       mech_types);
7893 +        if (GSS_ERROR(major)) {
7894 +            gss_release_oid_set(&tmpMinor, mech_types);
7895 +            return major;
7896 +        }
7897 +    } else {
7898 +        major = gssEapIndicateMechs(minor, mech_types);
7899 +        if (GSS_ERROR(major))
7900 +            return major;
7901 +    }
7902 +
7903 +    return major;
7904 +}
7905 diff --git a/mech_eap/inquire_name.c b/mech_eap/inquire_name.c
7906 new file mode 100644
7907 index 0000000..78b08a0
7908 --- /dev/null
7909 +++ b/mech_eap/inquire_name.c
7910 @@ -0,0 +1,75 @@
7911 +/*
7912 + * Copyright (c) 2011, JANET(UK)
7913 + * All rights reserved.
7914 + *
7915 + * Redistribution and use in source and binary forms, with or without
7916 + * modification, are permitted provided that the following conditions
7917 + * are met:
7918 + *
7919 + * 1. Redistributions of source code must retain the above copyright
7920 + *    notice, this list of conditions and the following disclaimer.
7921 + *
7922 + * 2. Redistributions in binary form must reproduce the above copyright
7923 + *    notice, this list of conditions and the following disclaimer in the
7924 + *    documentation and/or other materials provided with the distribution.
7925 + *
7926 + * 3. Neither the name of JANET(UK) nor the names of its contributors
7927 + *    may be used to endorse or promote products derived from this software
7928 + *    without specific prior written permission.
7929 + *
7930 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
7931 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7932 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7933 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
7934 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7935 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
7936 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
7937 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
7938 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
7939 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7940 + * SUCH DAMAGE.
7941 + */
7942 +
7943 +/*
7944 + * Enumerate name attributes.
7945 + */
7946 +
7947 +#include "gssapiP_eap.h"
7948 +
7949 +OM_uint32 GSSAPI_CALLCONV
7950 +gss_inquire_name(OM_uint32 *minor,
7951 +                 gss_name_t name,
7952 +                 int *name_is_MN,
7953 +                 gss_OID *MN_mech,
7954 +                 gss_buffer_set_t *attrs)
7955 +{
7956 +    OM_uint32 major, tmpMinor;
7957 +
7958 +    *minor = 0;
7959 +
7960 +    if (name_is_MN != NULL)
7961 +        *name_is_MN = 0;
7962 +    if (MN_mech != NULL)
7963 +        *MN_mech = GSS_C_NO_OID;
7964 +    if (attrs != NULL)
7965 +        *attrs = GSS_C_NO_BUFFER_SET;
7966 +
7967 +    if (name == GSS_C_NO_NAME) {
7968 +        *minor = EINVAL;
7969 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
7970 +    }
7971 +
7972 +    if (attrs == NULL)
7973 +        return GSS_S_COMPLETE;
7974 +
7975 +    GSSEAP_MUTEX_LOCK(&name->mutex);
7976 +
7977 +    major = gssEapInquireName(minor, name, name_is_MN, MN_mech, attrs);
7978 +
7979 +    GSSEAP_MUTEX_UNLOCK(&name->mutex);
7980 +
7981 +    if (GSS_ERROR(major))
7982 +        gss_release_buffer_set(&tmpMinor, attrs);
7983 +
7984 +    return major;
7985 +}
7986 diff --git a/mech_eap/inquire_names_for_mech.c b/mech_eap/inquire_names_for_mech.c
7987 new file mode 100644
7988 index 0000000..0e60340
7989 --- /dev/null
7990 +++ b/mech_eap/inquire_names_for_mech.c
7991 @@ -0,0 +1,77 @@
7992 +/*
7993 + * Copyright (c) 2011, JANET(UK)
7994 + * All rights reserved.
7995 + *
7996 + * Redistribution and use in source and binary forms, with or without
7997 + * modification, are permitted provided that the following conditions
7998 + * are met:
7999 + *
8000 + * 1. Redistributions of source code must retain the above copyright
8001 + *    notice, this list of conditions and the following disclaimer.
8002 + *
8003 + * 2. Redistributions in binary form must reproduce the above copyright
8004 + *    notice, this list of conditions and the following disclaimer in the
8005 + *    documentation and/or other materials provided with the distribution.
8006 + *
8007 + * 3. Neither the name of JANET(UK) nor the names of its contributors
8008 + *    may be used to endorse or promote products derived from this software
8009 + *    without specific prior written permission.
8010 + *
8011 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
8012 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
8013 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
8014 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
8015 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
8016 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
8017 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
8018 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
8019 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
8020 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
8021 + * SUCH DAMAGE.
8022 + */
8023 +
8024 +/*
8025 + * Return supported name OID types.
8026 + */
8027 +
8028 +#include "gssapiP_eap.h"
8029 +
8030 +OM_uint32 GSSAPI_CALLCONV
8031 +gss_inquire_names_for_mech(OM_uint32 *minor,
8032 +                           gss_OID mechanism,
8033 +                           gss_OID_set *ret_name_types)
8034 +{
8035 +    OM_uint32 major, tmpMinor;
8036 +    gss_OID nameTypes[] = {
8037 +        GSS_C_NT_USER_NAME,
8038 +        GSS_C_NT_HOSTBASED_SERVICE,
8039 +        GSS_C_NT_EXPORT_NAME,
8040 +#ifdef HAVE_GSS_C_NT_COMPOSITE_EXPORT
8041 +        GSS_C_NT_COMPOSITE_EXPORT,
8042 +#endif
8043 +        GSS_EAP_NT_EAP_NAME,
8044 +        GSS_C_NT_ANONYMOUS,
8045 +    };
8046 +    size_t i;
8047 +
8048 +    if (!gssEapIsMechanismOid(mechanism)) {
8049 +        *minor = GSSEAP_WRONG_MECH;
8050 +        return GSS_S_BAD_MECH;
8051 +    }
8052 +
8053 +    major = gss_create_empty_oid_set(minor, ret_name_types);
8054 +    if (GSS_ERROR(major))
8055 +        goto cleanup;
8056 +
8057 +    for (i = 0; i < sizeof(nameTypes)/sizeof(nameTypes[0]); i++) {
8058 +        major = gss_add_oid_set_member(minor, nameTypes[i], ret_name_types);
8059 +        if (GSS_ERROR(major))
8060 +            goto cleanup;
8061 +    }
8062 +
8063 +cleanup:
8064 +    if (GSS_ERROR(major))
8065 +        gss_release_oid_set(&tmpMinor, ret_name_types);
8066 +
8067 +    return major;
8068 +}
8069 diff --git a/mech_eap/inquire_saslname_for_mech.c b/mech_eap/inquire_saslname_for_mech.c
8070 new file mode 100644
8071 index 0000000..d6d7c14
8072 --- /dev/null
8073 +++ b/mech_eap/inquire_saslname_for_mech.c
8074 @@ -0,0 +1,51 @@
8075 +/*
8076 + * Copyright (c) 2011, JANET(UK)
8077 + * All rights reserved.
8078 + *
8079 + * Redistribution and use in source and binary forms, with or without
8080 + * modification, are permitted provided that the following conditions
8081 + * are met:
8082 + *
8083 + * 1. Redistributions of source code must retain the above copyright
8084 + *    notice, this list of conditions and the following disclaimer.
8085 + *
8086 + * 2. Redistributions in binary form must reproduce the above copyright
8087 + *    notice, this list of conditions and the following disclaimer in the
8088 + *    documentation and/or other materials provided with the distribution.
8089 + *
8090 + * 3. Neither the name of JANET(UK) nor the names of its contributors
8091 + *    may be used to endorse or promote products derived from this software
8092 + *    without specific prior written permission.
8093 + *
8094 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
8095 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
8096 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
8097 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
8098 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
8099 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
8100 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
8101 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
8102 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
8103 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
8104 + * SUCH DAMAGE.
8105 + */
8106 +
8107 +/*
8108 + * Map SASL mechanism name to a mechanism OID.
8109 + */
8110 +
8111 +#include "gssapiP_eap.h"
8112 +
8113 +OM_uint32 GSSAPI_CALLCONV
8114 +gss_inquire_mech_for_saslname(OM_uint32 *minor,
8115 +                              const gss_buffer_t sasl_mech_name,
8116 +                              gss_OID *mech_type)
8117 +{
8118 +    *mech_type = gssEapSaslNameToOid(sasl_mech_name);
8119 +    if (*mech_type == GSS_C_NO_OID) {
8120 +        *minor = GSSEAP_WRONG_MECH;
8121 +        return GSS_S_BAD_MECH;
8122 +    }
8123 +
8124 +    return GSS_S_COMPLETE;
8125 +}
8126 diff --git a/mech_eap/inquire_sec_context_by_oid.c b/mech_eap/inquire_sec_context_by_oid.c
8127 new file mode 100644
8128 index 0000000..7435f2e
8129 --- /dev/null
8130 +++ b/mech_eap/inquire_sec_context_by_oid.c
8131 @@ -0,0 +1,248 @@
8132 +/*
8133 + * Copyright (c) 2011, JANET(UK)
8134 + * All rights reserved.
8135 + *
8136 + * Redistribution and use in source and binary forms, with or without
8137 + * modification, are permitted provided that the following conditions
8138 + * are met:
8139 + *
8140 + * 1. Redistributions of source code must retain the above copyright
8141 + *    notice, this list of conditions and the following disclaimer.
8142 + *
8143 + * 2. Redistributions in binary form must reproduce the above copyright
8144 + *    notice, this list of conditions and the following disclaimer in the
8145 + *    documentation and/or other materials provided with the distribution.
8146 + *
8147 + * 3. Neither the name of JANET(UK) nor the names of its contributors
8148 + *    may be used to endorse or promote products derived from this software
8149 + *    without specific prior written permission.
8150 + *
8151 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
8152 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
8153 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
8154 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
8155 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
8156 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
8157 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
8158 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
8159 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
8160 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
8161 + * SUCH DAMAGE.
8162 + */
8163 +
8164 +/*
8165 + * Return extended properties of a context handle.
8166 + */
8167 +
8168 +#include "gssapiP_eap.h"
8169 +
8170 +static OM_uint32
8171 +addEnctypeOidToBufferSet(OM_uint32 *minor,
8172 +                         krb5_enctype encryptionType,
8173 +                         gss_buffer_set_t *dataSet)
8174 +{
8175 +    OM_uint32 major;
8176 +    unsigned char oidBuf[16];
8177 +    gss_OID_desc oid;
8178 +    gss_buffer_desc buf;
8179 +
8180 +    oid.length = sizeof(oidBuf);
8181 +    oid.elements = oidBuf;
8182 +
8183 +    major = composeOid(minor,
8184 +                       "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04",
8185 +                       10,
8186 +                       encryptionType,
8187 +                       &oid);
8188 +    if (GSS_ERROR(major))
8189 +        return major;
8190 +
8191 +    buf.length = oid.length;
8192 +    buf.value = oid.elements;
8193 +
8194 +    major = gss_add_buffer_set_member(minor, &buf, dataSet);
8195 +
8196 +    return major;
8197 +}
8198 +
8199 +static void
8200 +zeroAndReleaseBufferSet(gss_buffer_set_t *dataSet)
8201 +{
8202 +    OM_uint32 tmpMinor;
8203 +    gss_buffer_set_t set = *dataSet;
8204 +    size_t i;
8205 +
8206 +    if (set == GSS_C_NO_BUFFER_SET)
8207 +        return;
8208 +
8209 +    for (i = 0; i <set->count; i++)
8210 +        memset(set->elements[i].value, 0, set->elements[i].length);
8211 +
8212 +    gss_release_buffer_set(&tmpMinor, dataSet);
8213 +}
8214 +
8215 +static OM_uint32
8216 +inquireSessionKey(OM_uint32 *minor,
8217 +                  const gss_ctx_id_t ctx,
8218 +                  const gss_OID desired_object GSSEAP_UNUSED,
8219 +                  gss_buffer_set_t *dataSet)
8220 +{
8221 +    OM_uint32 major;
8222 +    gss_buffer_desc buf;
8223 +
8224 +    if (ctx->encryptionType == ENCTYPE_NULL) {
8225 +        major = GSS_S_UNAVAILABLE;
8226 +        *minor = GSSEAP_KEY_UNAVAILABLE;
8227 +        goto cleanup;
8228 +    }
8229 +
8230 +    buf.length = KRB_KEY_LENGTH(&ctx->rfc3961Key);
8231 +    buf.value = KRB_KEY_DATA(&ctx->rfc3961Key);
8232 +
8233 +    major = gss_add_buffer_set_member(minor, &buf, dataSet);
8234 +    if (GSS_ERROR(major))
8235 +        goto cleanup;
8236 +
8237 +    major = addEnctypeOidToBufferSet(minor, ctx->encryptionType, dataSet);
8238 +    if (GSS_ERROR(major))
8239 +        goto cleanup;
8240 +
8241 +    major = GSS_S_COMPLETE;
8242 +    *minor = 0;
8243 +
8244 +cleanup:
8245 +    if (GSS_ERROR(major))
8246 +        zeroAndReleaseBufferSet(dataSet);
8247 +
8248 +    return major;
8249 +}
8250 +
8251 +static OM_uint32
8252 +inquireNegoExKey(OM_uint32 *minor,
8253 +                  const gss_ctx_id_t ctx,
8254 +                  const gss_OID desired_object,
8255 +                  gss_buffer_set_t *dataSet)
8256 +{
8257 +    OM_uint32 major, tmpMinor;
8258 +    int bInitiatorKey;
8259 +    gss_buffer_desc salt;
8260 +    gss_buffer_desc key = GSS_C_EMPTY_BUFFER;
8261 +    size_t keySize;
8262 +
8263 +    bInitiatorKey = CTX_IS_INITIATOR(ctx);
8264 +
8265 +    if (ctx->encryptionType == ENCTYPE_NULL) {
8266 +        major = GSS_S_UNAVAILABLE;
8267 +        *minor = GSSEAP_KEY_UNAVAILABLE;
8268 +        goto cleanup;
8269 +    }
8270 +
8271 +    /*
8272 +     * If the caller supplied the verify key OID, then we need the acceptor
8273 +     * key if we are the initiator, and vice versa.
8274 +     */
8275 +    if (desired_object->length == 11 &&
8276 +        memcmp(desired_object->elements,
8277 +               "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x07", 11) == 0)
8278 +        bInitiatorKey ^= 1;
8279 +
8280 +    if (bInitiatorKey) {
8281 +        salt.length = NEGOEX_INITIATOR_SALT_LEN;
8282 +        salt.value  = NEGOEX_INITIATOR_SALT;
8283 +    } else {
8284 +        salt.length = NEGOEX_ACCEPTOR_SALT_LEN;
8285 +        salt.value  = NEGOEX_ACCEPTOR_SALT;
8286 +    }
8287 +
8288 +    keySize = KRB_KEY_LENGTH(&ctx->rfc3961Key);
8289 +
8290 +    major = gssEapPseudoRandom(minor, ctx, GSS_C_PRF_KEY_FULL, &salt,
8291 +                               keySize, &key);
8292 +    if (GSS_ERROR(major))
8293 +        goto cleanup;
8294 +
8295 +    major = gss_add_buffer_set_member(minor, &key, dataSet);
8296 +    if (GSS_ERROR(major))
8297 +        goto cleanup;
8298 +
8299 +    major = addEnctypeOidToBufferSet(minor, ctx->encryptionType, dataSet);
8300 +    if (GSS_ERROR(major))
8301 +        goto cleanup;
8302 +
8303 +    major = GSS_S_COMPLETE;
8304 +    *minor = 0;
8305 +
8306 +cleanup:
8307 +    if (key.value != NULL) {
8308 +        memset(key.value, 0, key.length);
8309 +        gss_release_buffer(&tmpMinor, &key);
8310 +    }
8311 +    if (GSS_ERROR(major))
8312 +        zeroAndReleaseBufferSet(dataSet);
8313 +
8314 +    return major;
8315 +}
8316 +
8317 +static struct {
8318 +    gss_OID_desc oid;
8319 +    OM_uint32 (*inquire)(OM_uint32 *, const gss_ctx_id_t,
8320 +                         const gss_OID, gss_buffer_set_t *);
8321 +} inquireCtxOps[] = {
8322 +    {
8323 +        /* GSS_C_INQ_SSPI_SESSION_KEY */
8324 +        { 11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05" },
8325 +        inquireSessionKey
8326 +    },
8327 +    {
8328 +        /* GSS_KRB5_EXPORT_LUCID_SEC_CONTEXT + v1 */
8329 +        { 12, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x06\x01" },
8330 +        gssEapExportLucidSecContext
8331 +    },
8332 +    {
8333 +        /* GSS_C_INQ_NEGOEX_KEY */
8334 +        { 11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x06" },
8335 +        inquireNegoExKey
8336 +    },
8337 +    {
8338 +        /* GSS_C_INQ_NEGOEX_VERIFY_KEY */
8339 +        { 11, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x07" },
8340 +        inquireNegoExKey
8341 +    },
8342 +};
8343 +
8344 +OM_uint32 GSSAPI_CALLCONV
8345 +gss_inquire_sec_context_by_oid(OM_uint32 *minor,
8346 +                               const gss_ctx_id_t ctx,
8347 +                               const gss_OID desired_object,
8348 +                               gss_buffer_set_t *data_set)
8349 +{
8350 +    OM_uint32 major;
8351 +    int i;
8352 +
8353 +    *data_set = GSS_C_NO_BUFFER_SET;
8354 +
8355 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
8356 +
8357 +#if 0
8358 +    if (!CTX_IS_ESTABLISHED(ctx)) {
8359 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
8360 +        major = GSS_S_NO_CONTEXT;
8361 +        goto cleanup;
8362 +    }
8363 +#endif
8364 +
8365 +    major = GSS_S_UNAVAILABLE;
8366 +    *minor = GSSEAP_BAD_CONTEXT_OPTION;
8367 +
8368 +    for (i = 0; i < sizeof(inquireCtxOps) / sizeof(inquireCtxOps[0]); i++) {
8369 +        if (oidEqual(&inquireCtxOps[i].oid, desired_object)) {
8370 +            major = (*inquireCtxOps[i].inquire)(minor, ctx,
8371 +                                                 desired_object, data_set);
8372 +            break;
8373 +        }
8374 +    }
8375 +
8376 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
8377 +
8378 +    return major;
8379 +}
8380 diff --git a/mech_eap/install-sh b/mech_eap/install-sh
8381 new file mode 100755
8382 index 0000000..6781b98
8383 --- /dev/null
8384 +++ b/mech_eap/install-sh
8385 @@ -0,0 +1,520 @@
8386 +#!/bin/sh
8387 +# install - install a program, script, or datafile
8388 +
8389 +scriptversion=2009-04-28.21; # UTC
8390 +
8391 +# This originates from X11R5 (mit/util/scripts/install.sh), which was
8392 +# later released in X11R6 (xc/config/util/install.sh) with the
8393 +# following copyright and license.
8394 +#
8395 +# Copyright (C) 1994 X Consortium
8396 +#
8397 +# Permission is hereby granted, free of charge, to any person obtaining a copy
8398 +# of this software and associated documentation files (the "Software"), to
8399 +# deal in the Software without restriction, including without limitation the
8400 +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8401 +# sell copies of the Software, and to permit persons to whom the Software is
8402 +# furnished to do so, subject to the following conditions:
8403 +#
8404 +# The above copyright notice and this permission notice shall be included in
8405 +# all copies or substantial portions of the Software.
8406 +#
8407 +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8408 +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
8409 +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
8410 +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
8411 +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
8412 +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8413 +#
8414 +# Except as contained in this notice, the name of the X Consortium shall not
8415 +# be used in advertising or otherwise to promote the sale, use or other deal-
8416 +# ings in this Software without prior written authorization from the X Consor-
8417 +# tium.
8418 +#
8419 +#
8420 +# FSF changes to this file are in the public domain.
8421 +#
8422 +# Calling this script install-sh is preferred over install.sh, to prevent
8423 +# `make' implicit rules from creating a file called install from it
8424 +# when there is no Makefile.
8425 +#
8426 +# This script is compatible with the BSD install script, but was written
8427 +# from scratch.
8428 +
8429 +nl='
8430 +'
8431 +IFS=" ""       $nl"
8432 +
8433 +# set DOITPROG to echo to test this script
8434 +
8435 +# Don't use :- since 4.3BSD and earlier shells don't like it.
8436 +doit=${DOITPROG-}
8437 +if test -z "$doit"; then
8438 +  doit_exec=exec
8439 +else
8440 +  doit_exec=$doit
8441 +fi
8442 +
8443 +# Put in absolute file names if you don't have them in your path;
8444 +# or use environment vars.
8445 +
8446 +chgrpprog=${CHGRPPROG-chgrp}
8447 +chmodprog=${CHMODPROG-chmod}
8448 +chownprog=${CHOWNPROG-chown}
8449 +cmpprog=${CMPPROG-cmp}
8450 +cpprog=${CPPROG-cp}
8451 +mkdirprog=${MKDIRPROG-mkdir}
8452 +mvprog=${MVPROG-mv}
8453 +rmprog=${RMPROG-rm}
8454 +stripprog=${STRIPPROG-strip}
8455 +
8456 +posix_glob='?'
8457 +initialize_posix_glob='
8458 +  test "$posix_glob" != "?" || {
8459 +    if (set -f) 2>/dev/null; then
8460 +      posix_glob=
8461 +    else
8462 +      posix_glob=:
8463 +    fi
8464 +  }
8465 +'
8466 +
8467 +posix_mkdir=
8468 +
8469 +# Desired mode of installed file.
8470 +mode=0755
8471 +
8472 +chgrpcmd=
8473 +chmodcmd=$chmodprog
8474 +chowncmd=
8475 +mvcmd=$mvprog
8476 +rmcmd="$rmprog -f"
8477 +stripcmd=
8478 +
8479 +src=
8480 +dst=
8481 +dir_arg=
8482 +dst_arg=
8483 +
8484 +copy_on_change=false
8485 +no_target_directory=
8486 +
8487 +usage="\
8488 +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
8489 +   or: $0 [OPTION]... SRCFILES... DIRECTORY
8490 +   or: $0 [OPTION]... -t DIRECTORY SRCFILES...
8491 +   or: $0 [OPTION]... -d DIRECTORIES...
8492 +
8493 +In the 1st form, copy SRCFILE to DSTFILE.
8494 +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
8495 +In the 4th, create DIRECTORIES.
8496 +
8497 +Options:
8498 +     --help     display this help and exit.
8499 +     --version  display version info and exit.
8500 +
8501 +  -c            (ignored)
8502 +  -C            install only if different (preserve the last data modification time)
8503 +  -d            create directories instead of installing files.
8504 +  -g GROUP      $chgrpprog installed files to GROUP.
8505 +  -m MODE       $chmodprog installed files to MODE.
8506 +  -o USER       $chownprog installed files to USER.
8507 +  -s            $stripprog installed files.
8508 +  -t DIRECTORY  install into DIRECTORY.
8509 +  -T            report an error if DSTFILE is a directory.
8510 +
8511 +Environment variables override the default commands:
8512 +  CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
8513 +  RMPROG STRIPPROG
8514 +"
8515 +
8516 +while test $# -ne 0; do
8517 +  case $1 in
8518 +    -c) ;;
8519 +
8520 +    -C) copy_on_change=true;;
8521 +
8522 +    -d) dir_arg=true;;
8523 +
8524 +    -g) chgrpcmd="$chgrpprog $2"
8525 +       shift;;
8526 +
8527 +    --help) echo "$usage"; exit $?;;
8528 +
8529 +    -m) mode=$2
8530 +       case $mode in
8531 +         *' '* | *'    '* | *'
8532 +'*       | *'*'* | *'?'* | *'['*)
8533 +           echo "$0: invalid mode: $mode" >&2
8534 +           exit 1;;
8535 +       esac
8536 +       shift;;
8537 +
8538 +    -o) chowncmd="$chownprog $2"
8539 +       shift;;
8540 +
8541 +    -s) stripcmd=$stripprog;;
8542 +
8543 +    -t) dst_arg=$2
8544 +       shift;;
8545 +
8546 +    -T) no_target_directory=true;;
8547 +
8548 +    --version) echo "$0 $scriptversion"; exit $?;;
8549 +
8550 +    --)        shift
8551 +       break;;
8552 +
8553 +    -*)        echo "$0: invalid option: $1" >&2
8554 +       exit 1;;
8555 +
8556 +    *)  break;;
8557 +  esac
8558 +  shift
8559 +done
8560 +
8561 +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
8562 +  # When -d is used, all remaining arguments are directories to create.
8563 +  # When -t is used, the destination is already specified.
8564 +  # Otherwise, the last argument is the destination.  Remove it from $@.
8565 +  for arg
8566 +  do
8567 +    if test -n "$dst_arg"; then
8568 +      # $@ is not empty: it contains at least $arg.
8569 +      set fnord "$@" "$dst_arg"
8570 +      shift # fnord
8571 +    fi
8572 +    shift # arg
8573 +    dst_arg=$arg
8574 +  done
8575 +fi
8576 +
8577 +if test $# -eq 0; then
8578 +  if test -z "$dir_arg"; then
8579 +    echo "$0: no input file specified." >&2
8580 +    exit 1
8581 +  fi
8582 +  # It's OK to call `install-sh -d' without argument.
8583 +  # This can happen when creating conditional directories.
8584 +  exit 0
8585 +fi
8586 +
8587 +if test -z "$dir_arg"; then
8588 +  trap '(exit $?); exit' 1 2 13 15
8589 +
8590 +  # Set umask so as not to create temps with too-generous modes.
8591 +  # However, 'strip' requires both read and write access to temps.
8592 +  case $mode in
8593 +    # Optimize common cases.
8594 +    *644) cp_umask=133;;
8595 +    *755) cp_umask=22;;
8596 +
8597 +    *[0-7])
8598 +      if test -z "$stripcmd"; then
8599 +       u_plus_rw=
8600 +      else
8601 +       u_plus_rw='% 200'
8602 +      fi
8603 +      cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
8604 +    *)
8605 +      if test -z "$stripcmd"; then
8606 +       u_plus_rw=
8607 +      else
8608 +       u_plus_rw=,u+rw
8609 +      fi
8610 +      cp_umask=$mode$u_plus_rw;;
8611 +  esac
8612 +fi
8613 +
8614 +for src
8615 +do
8616 +  # Protect names starting with `-'.
8617 +  case $src in
8618 +    -*) src=./$src;;
8619 +  esac
8620 +
8621 +  if test -n "$dir_arg"; then
8622 +    dst=$src
8623 +    dstdir=$dst
8624 +    test -d "$dstdir"
8625 +    dstdir_status=$?
8626 +  else
8627 +
8628 +    # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
8629 +    # might cause directories to be created, which would be especially bad
8630 +    # if $src (and thus $dsttmp) contains '*'.
8631 +    if test ! -f "$src" && test ! -d "$src"; then
8632 +      echo "$0: $src does not exist." >&2
8633 +      exit 1
8634 +    fi
8635 +
8636 +    if test -z "$dst_arg"; then
8637 +      echo "$0: no destination specified." >&2
8638 +      exit 1
8639 +    fi
8640 +
8641 +    dst=$dst_arg
8642 +    # Protect names starting with `-'.
8643 +    case $dst in
8644 +      -*) dst=./$dst;;
8645 +    esac
8646 +
8647 +    # If destination is a directory, append the input filename; won't work
8648 +    # if double slashes aren't ignored.
8649 +    if test -d "$dst"; then
8650 +      if test -n "$no_target_directory"; then
8651 +       echo "$0: $dst_arg: Is a directory" >&2
8652 +       exit 1
8653 +      fi
8654 +      dstdir=$dst
8655 +      dst=$dstdir/`basename "$src"`
8656 +      dstdir_status=0
8657 +    else
8658 +      # Prefer dirname, but fall back on a substitute if dirname fails.
8659 +      dstdir=`
8660 +       (dirname "$dst") 2>/dev/null ||
8661 +       expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
8662 +            X"$dst" : 'X\(//\)[^/]' \| \
8663 +            X"$dst" : 'X\(//\)$' \| \
8664 +            X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
8665 +       echo X"$dst" |
8666 +           sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
8667 +                  s//\1/
8668 +                  q
8669 +                }
8670 +                /^X\(\/\/\)[^/].*/{
8671 +                  s//\1/
8672 +                  q
8673 +                }
8674 +                /^X\(\/\/\)$/{
8675 +                  s//\1/
8676 +                  q
8677 +                }
8678 +                /^X\(\/\).*/{
8679 +                  s//\1/
8680 +                  q
8681 +                }
8682 +                s/.*/./; q'
8683 +      `
8684 +
8685 +      test -d "$dstdir"
8686 +      dstdir_status=$?
8687 +    fi
8688 +  fi
8689 +
8690 +  obsolete_mkdir_used=false
8691 +
8692 +  if test $dstdir_status != 0; then
8693 +    case $posix_mkdir in
8694 +      '')
8695 +       # Create intermediate dirs using mode 755 as modified by the umask.
8696 +       # This is like FreeBSD 'install' as of 1997-10-28.
8697 +       umask=`umask`
8698 +       case $stripcmd.$umask in
8699 +         # Optimize common cases.
8700 +         *[2367][2367]) mkdir_umask=$umask;;
8701 +         .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
8702 +
8703 +         *[0-7])
8704 +           mkdir_umask=`expr $umask + 22 \
8705 +             - $umask % 100 % 40 + $umask % 20 \
8706 +             - $umask % 10 % 4 + $umask % 2
8707 +           `;;
8708 +         *) mkdir_umask=$umask,go-w;;
8709 +       esac
8710 +
8711 +       # With -d, create the new directory with the user-specified mode.
8712 +       # Otherwise, rely on $mkdir_umask.
8713 +       if test -n "$dir_arg"; then
8714 +         mkdir_mode=-m$mode
8715 +       else
8716 +         mkdir_mode=
8717 +       fi
8718 +
8719 +       posix_mkdir=false
8720 +       case $umask in
8721 +         *[123567][0-7][0-7])
8722 +           # POSIX mkdir -p sets u+wx bits regardless of umask, which
8723 +           # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
8724 +           ;;
8725 +         *)
8726 +           tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
8727 +           trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
8728 +
8729 +           if (umask $mkdir_umask &&
8730 +               exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
8731 +           then
8732 +             if test -z "$dir_arg" || {
8733 +                  # Check for POSIX incompatibilities with -m.
8734 +                  # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
8735 +                  # other-writeable bit of parent directory when it shouldn't.
8736 +                  # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
8737 +                  ls_ld_tmpdir=`ls -ld "$tmpdir"`
8738 +                  case $ls_ld_tmpdir in
8739 +                    d????-?r-*) different_mode=700;;
8740 +                    d????-?--*) different_mode=755;;
8741 +                    *) false;;
8742 +                  esac &&
8743 +                  $mkdirprog -m$different_mode -p -- "$tmpdir" && {
8744 +                    ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
8745 +                    test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
8746 +                  }
8747 +                }
8748 +             then posix_mkdir=:
8749 +             fi
8750 +             rmdir "$tmpdir/d" "$tmpdir"
8751 +           else
8752 +             # Remove any dirs left behind by ancient mkdir implementations.
8753 +             rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
8754 +           fi
8755 +           trap '' 0;;
8756 +       esac;;
8757 +    esac
8758 +
8759 +    if
8760 +      $posix_mkdir && (
8761 +       umask $mkdir_umask &&
8762 +       $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
8763 +      )
8764 +    then :
8765 +    else
8766 +
8767 +      # The umask is ridiculous, or mkdir does not conform to POSIX,
8768 +      # or it failed possibly due to a race condition.  Create the
8769 +      # directory the slow way, step by step, checking for races as we go.
8770 +
8771 +      case $dstdir in
8772 +       /*) prefix='/';;
8773 +       -*) prefix='./';;
8774 +       *)  prefix='';;
8775 +      esac
8776 +
8777 +      eval "$initialize_posix_glob"
8778 +
8779 +      oIFS=$IFS
8780 +      IFS=/
8781 +      $posix_glob set -f
8782 +      set fnord $dstdir
8783 +      shift
8784 +      $posix_glob set +f
8785 +      IFS=$oIFS
8786 +
8787 +      prefixes=
8788 +
8789 +      for d
8790 +      do
8791 +       test -z "$d" && continue
8792 +
8793 +       prefix=$prefix$d
8794 +       if test -d "$prefix"; then
8795 +         prefixes=
8796 +       else
8797 +         if $posix_mkdir; then
8798 +           (umask=$mkdir_umask &&
8799 +            $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
8800 +           # Don't fail if two instances are running concurrently.
8801 +           test -d "$prefix" || exit 1
8802 +         else
8803 +           case $prefix in
8804 +             *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
8805 +             *) qprefix=$prefix;;
8806 +           esac
8807 +           prefixes="$prefixes '$qprefix'"
8808 +         fi
8809 +       fi
8810 +       prefix=$prefix/
8811 +      done
8812 +
8813 +      if test -n "$prefixes"; then
8814 +       # Don't fail if two instances are running concurrently.
8815 +       (umask $mkdir_umask &&
8816 +        eval "\$doit_exec \$mkdirprog $prefixes") ||
8817 +         test -d "$dstdir" || exit 1
8818 +       obsolete_mkdir_used=true
8819 +      fi
8820 +    fi
8821 +  fi
8822 +
8823 +  if test -n "$dir_arg"; then
8824 +    { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
8825 +    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
8826 +    { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
8827 +      test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
8828 +  else
8829 +
8830 +    # Make a couple of temp file names in the proper directory.
8831 +    dsttmp=$dstdir/_inst.$$_
8832 +    rmtmp=$dstdir/_rm.$$_
8833 +
8834 +    # Trap to clean up those temp files at exit.
8835 +    trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
8836 +
8837 +    # Copy the file name to the temp name.
8838 +    (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
8839 +
8840 +    # and set any options; do chmod last to preserve setuid bits.
8841 +    #
8842 +    # If any of these fail, we abort the whole thing.  If we want to
8843 +    # ignore errors from any of these, just make sure not to ignore
8844 +    # errors from the above "$doit $cpprog $src $dsttmp" command.
8845 +    #
8846 +    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
8847 +    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
8848 +    { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
8849 +    { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
8850 +
8851 +    # If -C, don't bother to copy if it wouldn't change the file.
8852 +    if $copy_on_change &&
8853 +       old=`LC_ALL=C ls -dlL "$dst"    2>/dev/null` &&
8854 +       new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
8855 +
8856 +       eval "$initialize_posix_glob" &&
8857 +       $posix_glob set -f &&
8858 +       set X $old && old=:$2:$4:$5:$6 &&
8859 +       set X $new && new=:$2:$4:$5:$6 &&
8860 +       $posix_glob set +f &&
8861 +
8862 +       test "$old" = "$new" &&
8863 +       $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
8864 +    then
8865 +      rm -f "$dsttmp"
8866 +    else
8867 +      # Rename the file to the real destination.
8868 +      $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
8869 +
8870 +      # The rename failed, perhaps because mv can't rename something else
8871 +      # to itself, or perhaps because mv is so ancient that it does not
8872 +      # support -f.
8873 +      {
8874 +       # Now remove or move aside any old file at destination location.
8875 +       # We try this two ways since rm can't unlink itself on some
8876 +       # systems and the destination file might be busy for other
8877 +       # reasons.  In this case, the final cleanup might fail but the new
8878 +       # file should still install successfully.
8879 +       {
8880 +         test ! -f "$dst" ||
8881 +         $doit $rmcmd -f "$dst" 2>/dev/null ||
8882 +         { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
8883 +           { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
8884 +         } ||
8885 +         { echo "$0: cannot unlink or rename $dst" >&2
8886 +           (exit 1); exit 1
8887 +         }
8888 +       } &&
8889 +
8890 +       # Now rename the file to the real destination.
8891 +       $doit $mvcmd "$dsttmp" "$dst"
8892 +      }
8893 +    fi || exit 1
8894 +
8895 +    trap '' 0
8896 +  fi
8897 +done
8898 +
8899 +# Local variables:
8900 +# eval: (add-hook 'write-file-hooks 'time-stamp)
8901 +# time-stamp-start: "scriptversion="
8902 +# time-stamp-format: "%:y-%02m-%02d.%02H"
8903 +# time-stamp-time-zone: "UTC"
8904 +# time-stamp-end: "; # UTC"
8905 +# End:
8906 diff --git a/mech_eap/map_name_to_any.c b/mech_eap/map_name_to_any.c
8907 new file mode 100644
8908 index 0000000..2a8a96c
8909 --- /dev/null
8910 +++ b/mech_eap/map_name_to_any.c
8911 @@ -0,0 +1,58 @@
8912 +/*
8913 + * Copyright (c) 2011, JANET(UK)
8914 + * All rights reserved.
8915 + *
8916 + * Redistribution and use in source and binary forms, with or without
8917 + * modification, are permitted provided that the following conditions
8918 + * are met:
8919 + *
8920 + * 1. Redistributions of source code must retain the above copyright
8921 + *    notice, this list of conditions and the following disclaimer.
8922 + *
8923 + * 2. Redistributions in binary form must reproduce the above copyright
8924 + *    notice, this list of conditions and the following disclaimer in the
8925 + *    documentation and/or other materials provided with the distribution.
8926 + *
8927 + * 3. Neither the name of JANET(UK) nor the names of its contributors
8928 + *    may be used to endorse or promote products derived from this software
8929 + *    without specific prior written permission.
8930 + *
8931 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
8932 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
8933 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
8934 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
8935 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
8936 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
8937 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
8938 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
8939 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
8940 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
8941 + * SUCH DAMAGE.
8942 + */
8943 +
8944 +#include "gssapiP_eap.h"
8945 +
8946 +OM_uint32 GSSAPI_CALLCONV
8947 +gss_map_name_to_any(OM_uint32 *minor,
8948 +                    gss_name_t name,
8949 +                    int authenticated,
8950 +                    gss_buffer_t type_id,
8951 +                    gss_any_t *output)
8952 +{
8953 +    OM_uint32 major;
8954 +
8955 +    *output = (gss_any_t)NULL;
8956 +
8957 +    if (name == GSS_C_NO_NAME) {
8958 +        *minor = EINVAL;
8959 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
8960 +    }
8961 +
8962 +    GSSEAP_MUTEX_LOCK(&name->mutex);
8963 +
8964 +    major = gssEapMapNameToAny(minor, name, authenticated, type_id, output);
8965 +
8966 +    GSSEAP_MUTEX_UNLOCK(&name->mutex);
8967 +
8968 +    return major;
8969 +}
8970 diff --git a/mech_eap/mech b/mech_eap/mech
8971 new file mode 100644
8972 index 0000000..258a43a
8973 --- /dev/null
8974 +++ b/mech_eap/mech
8975 @@ -0,0 +1,8 @@
8976 +#
8977 +# Sample mechanism glue configuration for EAP GSS mechanism.
8978 +#
8979 +# Any encryption type supported by Kerberos can be defined as the
8980 +# last element of the OID arc.
8981 +#
8982 +eap-aes128             1.3.6.1.4.1.5322.22.1.17        mech_eap.so
8983 +eap-aes256             1.3.6.1.4.1.5322.22.1.18        mech_eap.so
8984 diff --git a/mech_eap/mech_eap-noacceptor.exports b/mech_eap/mech_eap-noacceptor.exports
8985 new file mode 100644
8986 index 0000000..f00df8a
8987 --- /dev/null
8988 +++ b/mech_eap/mech_eap-noacceptor.exports
8989 @@ -0,0 +1,55 @@
8990 +gss_acquire_cred
8991 +gss_add_cred
8992 +gss_add_cred_with_password
8993 +gss_canonicalize_name
8994 +gss_compare_name
8995 +gss_context_time
8996 +gss_delete_sec_context
8997 +gss_display_name
8998 +gss_display_name_ext
8999 +gss_display_status
9000 +gss_duplicate_name
9001 +gss_exchange_meta_data
9002 +gss_export_name
9003 +gss_export_sec_context
9004 +gss_get_mic
9005 +gss_import_name
9006 +gss_import_sec_context
9007 +gss_indicate_mechs
9008 +gss_init_sec_context
9009 +gss_inquire_attrs_for_mech
9010 +gss_inquire_context
9011 +gss_inquire_cred
9012 +gss_inquire_cred_by_mech
9013 +gss_inquire_cred_by_oid
9014 +gss_inquire_mechs_for_name
9015 +gss_inquire_mech_for_saslname
9016 +gss_inquire_names_for_mech
9017 +gss_inquire_saslname_for_mech
9018 +gss_inquire_sec_context_by_oid
9019 +gss_process_context_token
9020 +gss_pseudo_random
9021 +gss_query_mechanism_info
9022 +gss_query_meta_data
9023 +gss_release_cred
9024 +gss_release_name
9025 +gss_internal_release_oid
9026 +gss_set_sec_context_option
9027 +gss_store_cred
9028 +gss_unwrap
9029 +gss_unwrap_iov
9030 +gss_verify_mic
9031 +gss_wrap
9032 +gss_wrap_iov
9033 +gss_wrap_iov_length
9034 +gss_wrap_size_limit
9035 +GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM
9036 +GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM
9037 +GSS_EAP_NT_EAP_NAME
9038 +GSS_EAP_CRED_SET_CRED_FLAG
9039 +GSS_EAP_CRED_SET_CRED_PASSWORD
9040 +GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE
9041 +GSS_EAP_CRED_SET_RADIUS_CONFIG_STANZA
9042 +gssspi_acquire_cred_with_password
9043 +gssspi_authorize_localname
9044 +gssspi_set_cred_option
9045 diff --git a/mech_eap/mech_eap.exports b/mech_eap/mech_eap.exports
9046 new file mode 100644
9047 index 0000000..6a17a17
9048 --- /dev/null
9049 +++ b/mech_eap/mech_eap.exports
9050 @@ -0,0 +1,63 @@
9051 +gss_accept_sec_context
9052 +gss_acquire_cred
9053 +gss_add_cred
9054 +gss_add_cred_with_password
9055 +gss_canonicalize_name
9056 +gss_compare_name
9057 +gss_context_time
9058 +gss_delete_name_attribute
9059 +gss_delete_sec_context
9060 +gss_display_name
9061 +gss_display_name_ext
9062 +gss_display_status
9063 +gss_duplicate_name
9064 +gss_exchange_meta_data
9065 +gss_export_name
9066 +gss_export_name_composite
9067 +gss_export_sec_context
9068 +gss_get_mic
9069 +gss_get_name_attribute
9070 +gss_import_name
9071 +gss_import_sec_context
9072 +gss_indicate_mechs
9073 +gss_init_sec_context
9074 +gss_inquire_attrs_for_mech
9075 +gss_inquire_context
9076 +gss_inquire_cred
9077 +gss_inquire_cred_by_mech
9078 +gss_inquire_cred_by_oid
9079 +gss_inquire_mechs_for_name
9080 +gss_inquire_mech_for_saslname
9081 +gss_inquire_name
9082 +gss_inquire_names_for_mech
9083 +gss_inquire_saslname_for_mech
9084 +gss_inquire_sec_context_by_oid
9085 +gss_map_name_to_any
9086 +gss_process_context_token
9087 +gss_pseudo_random
9088 +gss_query_mechanism_info
9089 +gss_query_meta_data
9090 +gss_release_any_name_mapping
9091 +gss_release_cred
9092 +gss_release_name
9093 +gss_internal_release_oid
9094 +gss_set_name_attribute
9095 +gss_set_sec_context_option
9096 +gss_store_cred
9097 +gss_unwrap
9098 +gss_unwrap_iov
9099 +gss_verify_mic
9100 +gss_wrap
9101 +gss_wrap_iov
9102 +gss_wrap_iov_length
9103 +gss_wrap_size_limit
9104 +GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM
9105 +GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM
9106 +GSS_EAP_NT_EAP_NAME
9107 +GSS_EAP_CRED_SET_CRED_FLAG
9108 +GSS_EAP_CRED_SET_CRED_PASSWORD
9109 +GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE
9110 +GSS_EAP_CRED_SET_RADIUS_CONFIG_STANZA
9111 +gssspi_acquire_cred_with_password
9112 +gssspi_authorize_localname
9113 +gssspi_set_cred_option
9114 diff --git a/mech_eap/mech_invoke.c b/mech_eap/mech_invoke.c
9115 new file mode 100644
9116 index 0000000..bc9bba3
9117 --- /dev/null
9118 +++ b/mech_eap/mech_invoke.c
9119 @@ -0,0 +1,44 @@
9120 +/*
9121 + * Copyright (c) 2011, JANET(UK)
9122 + * All rights reserved.
9123 + *
9124 + * Redistribution and use in source and binary forms, with or without
9125 + * modification, are permitted provided that the following conditions
9126 + * are met:
9127 + *
9128 + * 1. Redistributions of source code must retain the above copyright
9129 + *    notice, this list of conditions and the following disclaimer.
9130 + *
9131 + * 2. Redistributions in binary form must reproduce the above copyright
9132 + *    notice, this list of conditions and the following disclaimer in the
9133 + *    documentation and/or other materials provided with the distribution.
9134 + *
9135 + * 3. Neither the name of JANET(UK) nor the names of its contributors
9136 + *    may be used to endorse or promote products derived from this software
9137 + *    without specific prior written permission.
9138 + *
9139 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
9140 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9141 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9142 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
9143 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9144 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9145 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9146 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9147 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9148 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9149 + * SUCH DAMAGE.
9150 + */
9151 +
9152 +#include "gssapiP_eap.h"
9153 +
9154 +OM_uint32 GSSAPI_CALLCONV
9155 +gssspi_mech_invoke(OM_uint32 *minor,
9156 +                   const gss_OID desired_mech,
9157 +                   const gss_OID desired_object,
9158 +                   gss_buffer_t value)
9159 +{
9160 +    *minor = GSSEAP_BAD_INVOCATION;
9161 +
9162 +    return GSS_S_UNAVAILABLE;
9163 +}
9164 diff --git a/mech_eap/process_context_token.c b/mech_eap/process_context_token.c
9165 new file mode 100644
9166 index 0000000..02a4b6d
9167 --- /dev/null
9168 +++ b/mech_eap/process_context_token.c
9169 @@ -0,0 +1,71 @@
9170 +/*
9171 + * Copyright (c) 2011, JANET(UK)
9172 + * All rights reserved.
9173 + *
9174 + * Redistribution and use in source and binary forms, with or without
9175 + * modification, are permitted provided that the following conditions
9176 + * are met:
9177 + *
9178 + * 1. Redistributions of source code must retain the above copyright
9179 + *    notice, this list of conditions and the following disclaimer.
9180 + *
9181 + * 2. Redistributions in binary form must reproduce the above copyright
9182 + *    notice, this list of conditions and the following disclaimer in the
9183 + *    documentation and/or other materials provided with the distribution.
9184 + *
9185 + * 3. Neither the name of JANET(UK) nor the names of its contributors
9186 + *    may be used to endorse or promote products derived from this software
9187 + *    without specific prior written permission.
9188 + *
9189 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
9190 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9191 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9192 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
9193 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9194 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9195 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9196 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9197 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9198 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9199 + * SUCH DAMAGE.
9200 + */
9201 +
9202 +#include "gssapiP_eap.h"
9203 +
9204 +OM_uint32 GSSAPI_CALLCONV
9205 +gss_process_context_token(OM_uint32 *minor,
9206 +                          gss_ctx_id_t ctx,
9207 +                          gss_buffer_t token_buffer)
9208 +{
9209 +    OM_uint32 major;
9210 +    gss_iov_buffer_desc iov[1];
9211 +
9212 +    *minor = 0;
9213 +
9214 +    if (ctx == NULL) {
9215 +        *minor = EINVAL;
9216 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
9217 +    }
9218 +
9219 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
9220 +
9221 +    if (!CTX_IS_ESTABLISHED(ctx)) {
9222 +        GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
9223 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
9224 +        return GSS_S_NO_CONTEXT;
9225 +    }
9226 +
9227 +    iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
9228 +    iov[0].buffer = *token_buffer;
9229 +
9230 +    major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
9231 +                                    iov, 1, TOK_TYPE_DELETE_CONTEXT);
9232 +    if (GSS_ERROR(major)) {
9233 +        GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
9234 +        return major;
9235 +    }
9236 +
9237 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
9238 +
9239 +    return gssEapReleaseContext(minor, &ctx);
9240 +}
9241 diff --git a/mech_eap/pseudo_random.c b/mech_eap/pseudo_random.c
9242 new file mode 100644
9243 index 0000000..61d1f2a
9244 --- /dev/null
9245 +++ b/mech_eap/pseudo_random.c
9246 @@ -0,0 +1,195 @@
9247 +/*
9248 + * Copyright (c) 2011, JANET(UK)
9249 + * All rights reserved.
9250 + *
9251 + * Redistribution and use in source and binary forms, with or without
9252 + * modification, are permitted provided that the following conditions
9253 + * are met:
9254 + *
9255 + * 1. Redistributions of source code must retain the above copyright
9256 + *    notice, this list of conditions and the following disclaimer.
9257 + *
9258 + * 2. Redistributions in binary form must reproduce the above copyright
9259 + *    notice, this list of conditions and the following disclaimer in the
9260 + *    documentation and/or other materials provided with the distribution.
9261 + *
9262 + * 3. Neither the name of JANET(UK) nor the names of its contributors
9263 + *    may be used to endorse or promote products derived from this software
9264 + *    without specific prior written permission.
9265 + *
9266 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
9267 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9268 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9269 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
9270 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9271 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9272 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9273 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9274 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9275 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9276 + * SUCH DAMAGE.
9277 + */
9278 +/*
9279 + * Copyright 2009 by the Massachusetts Institute of Technology.
9280 + * All Rights Reserved.
9281 + *
9282 + * Export of this software from the United States of America may
9283 + *   require a specific license from the United States Government.
9284 + *   It is the responsibility of any person or organization contemplating
9285 + *   export to obtain such a license before exporting.
9286 + *
9287 + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
9288 + * distribute this software and its documentation for any purpose and
9289 + * without fee is hereby granted, provided that the above copyright
9290 + * notice appear in all copies and that both that copyright notice and
9291 + * this permission notice appear in supporting documentation, and that
9292 + * the name of M.I.T. not be used in advertising or publicity pertaining
9293 + * to distribution of the software without specific, written prior
9294 + * permission.  Furthermore if you modify this software you must label
9295 + * your software as modified software and not distribute it in such a
9296 + * fashion that it might be confused with the original M.I.T. software.
9297 + * M.I.T. makes no representations about the suitability of
9298 + * this software for any purpose.  It is provided "as is" without express
9299 + * or implied warranty.
9300 + */
9301 +
9302 +/*
9303 + * PRF
9304 + */
9305 +
9306 +#include "gssapiP_eap.h"
9307 +
9308 +OM_uint32
9309 +gssEapPseudoRandom(OM_uint32 *minor,
9310 +                   gss_ctx_id_t ctx,
9311 +                   int prf_key,
9312 +                   const gss_buffer_t prf_in,
9313 +                   ssize_t desired_output_len,
9314 +                   gss_buffer_t prf_out)
9315 +{
9316 +    krb5_error_code code;
9317 +    int i;
9318 +    OM_uint32 tmpMinor;
9319 +    size_t prflen;
9320 +    krb5_data t, ns;
9321 +    unsigned char *p;
9322 +    krb5_context krbContext;
9323 +
9324 +    prf_out->length = 0;
9325 +    prf_out->value = NULL;
9326 +
9327 +    *minor = 0;
9328 +
9329 +    GSSEAP_KRB_INIT(&krbContext);
9330 +
9331 +    KRB_DATA_INIT(&t);
9332 +    KRB_DATA_INIT(&ns);
9333 +
9334 +    if (prf_key != GSS_C_PRF_KEY_PARTIAL &&
9335 +        prf_key != GSS_C_PRF_KEY_FULL) {
9336 +        code = GSSEAP_BAD_PRF_KEY;
9337 +        goto cleanup;
9338 +    }
9339 +
9340 +    prf_out->value = GSSEAP_MALLOC(desired_output_len);
9341 +    if (prf_out->value == NULL) {
9342 +        code = ENOMEM;
9343 +        goto cleanup;
9344 +    }
9345 +    prf_out->length = desired_output_len;
9346 +
9347 +    code = krb5_c_prf_length(krbContext,
9348 +                             ctx->encryptionType,
9349 +                             &prflen);
9350 +    if (code != 0)
9351 +        goto cleanup;
9352 +
9353 +    ns.length = 4 + prf_in->length;
9354 +    ns.data = GSSEAP_MALLOC(ns.length);
9355 +    if (ns.data == NULL) {
9356 +        code = ENOMEM;
9357 +        goto cleanup;
9358 +    }
9359 +
9360 +#ifndef HAVE_HEIMDAL_VERSION
9361 +    /* Same API, but different allocation rules, unfortunately. */
9362 +    t.length = prflen;
9363 +    t.data = GSSEAP_MALLOC(t.length);
9364 +    if (t.data == NULL) {
9365 +        code = ENOMEM;
9366 +        goto cleanup;
9367 +    }
9368 +#endif
9369 +
9370 +    memcpy((unsigned char *)ns.data + 4, prf_in->value, prf_in->length);
9371 +    i = 0;
9372 +    p = (unsigned char *)prf_out->value;
9373 +    while (desired_output_len > 0) {
9374 +        store_uint32_be(i, ns.data);
9375 +
9376 +        code = krb5_c_prf(krbContext, &ctx->rfc3961Key, &ns, &t);
9377 +        if (code != 0)
9378 +            goto cleanup;
9379 +
9380 +        memcpy(p, t.data, MIN(t.length, desired_output_len));
9381 +
9382 +        p += t.length;
9383 +        desired_output_len -= t.length;
9384 +        i++;
9385 +    }
9386 +
9387 +cleanup:
9388 +    if (code != 0)
9389 +        gss_release_buffer(&tmpMinor, prf_out);
9390 +    if (ns.data != NULL) {
9391 +        memset(ns.data, 0, ns.length);
9392 +        GSSEAP_FREE(ns.data);
9393 +    }
9394 +#ifdef HAVE_HEIMDAL_VERSION
9395 +    krb5_free_data_contents(krbContext, &t);
9396 +#else
9397 +    if (t.data != NULL) {
9398 +        memset(t.data, 0, t.length);
9399 +        GSSEAP_FREE(t.data);
9400 +    }
9401 +#endif
9402 +
9403 +    *minor = code;
9404 +
9405 +    return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
9406 +}
9407 +
9408 +OM_uint32 GSSAPI_CALLCONV
9409 +gss_pseudo_random(OM_uint32 *minor,
9410 +                  gss_ctx_id_t ctx,
9411 +                  int prf_key,
9412 +                  const gss_buffer_t prf_in,
9413 +                  ssize_t desired_output_len,
9414 +                  gss_buffer_t prf_out)
9415 +{
9416 +    OM_uint32 major;
9417 +
9418 +    if (ctx == GSS_C_NO_CONTEXT) {
9419 +        *minor = EINVAL;
9420 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
9421 +    }
9422 +
9423 +    prf_out->length = 0;
9424 +    prf_out->value = NULL;
9425 +
9426 +    *minor = 0;
9427 +
9428 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
9429 +
9430 +    if (CTX_IS_ESTABLISHED(ctx)) {
9431 +        major = gssEapPseudoRandom(minor, ctx, prf_key,
9432 +                                   prf_in, desired_output_len, prf_out);
9433 +    } else {
9434 +        major = GSS_S_NO_CONTEXT;
9435 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
9436 +    }
9437 +
9438 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
9439 +
9440 +    return major;
9441 +}
9442 diff --git a/mech_eap/query_mechanism_info.c b/mech_eap/query_mechanism_info.c
9443 new file mode 100644
9444 index 0000000..acd3115
9445 --- /dev/null
9446 +++ b/mech_eap/query_mechanism_info.c
9447 @@ -0,0 +1,67 @@
9448 +/*
9449 + * Copyright (c) 2011, JANET(UK)
9450 + * All rights reserved.
9451 + *
9452 + * Redistribution and use in source and binary forms, with or without
9453 + * modification, are permitted provided that the following conditions
9454 + * are met:
9455 + *
9456 + * 1. Redistributions of source code must retain the above copyright
9457 + *    notice, this list of conditions and the following disclaimer.
9458 + *
9459 + * 2. Redistributions in binary form must reproduce the above copyright
9460 + *    notice, this list of conditions and the following disclaimer in the
9461 + *    documentation and/or other materials provided with the distribution.
9462 + *
9463 + * 3. Neither the name of JANET(UK) nor the names of its contributors
9464 + *    may be used to endorse or promote products derived from this software
9465 + *    without specific prior written permission.
9466 + *
9467 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
9468 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9469 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9470 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
9471 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9472 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9473 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9474 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9475 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9476 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9477 + * SUCH DAMAGE.
9478 + */
9479 +
9480 +/*
9481 + *
9482 + */
9483 +
9484 +#include "gssapiP_eap.h"
9485 +
9486 +OM_uint32
9487 +gssQueryMechanismInfo(OM_uint32 *minor,
9488 +                      gss_const_OID mech_oid,
9489 +                      unsigned char auth_scheme[16])
9490 +{
9491 +    OM_uint32 major;
9492 +    krb5_enctype enctype;
9493 +
9494 +    major = gssEapOidToEnctype(minor, (const gss_OID)mech_oid, &enctype);
9495 +    if (GSS_ERROR(major))
9496 +        return major;
9497 +
9498 +    /* the enctype is encoded in the increasing part of the GUID */
9499 +    memcpy(auth_scheme,
9500 +           "\x39\xd7\x7d\x00\xe5\x00\x11\xe0\xac\x64\xcd\x53\x46\x50\xac\xb9", 16);
9501 +
9502 +    auth_scheme[3] = (unsigned char)enctype;
9503 +
9504 +    *minor = 0;
9505 +    return GSS_S_COMPLETE;
9506 +}
9507 +
9508 +OM_uint32 GSSAPI_CALLCONV
9509 +gss_query_mechanism_info(OM_uint32 *minor,
9510 +                         gss_const_OID mech_oid,
9511 +                         unsigned char auth_scheme[16])
9512 +{
9513 +    return gssQueryMechanismInfo(minor, mech_oid, auth_scheme);
9514 +}
9515 diff --git a/mech_eap/query_meta_data.c b/mech_eap/query_meta_data.c
9516 new file mode 100644
9517 index 0000000..abc7e71
9518 --- /dev/null
9519 +++ b/mech_eap/query_meta_data.c
9520 @@ -0,0 +1,116 @@
9521 +/*
9522 + * Copyright (c) 2011, JANET(UK)
9523 + * All rights reserved.
9524 + *
9525 + * Redistribution and use in source and binary forms, with or without
9526 + * modification, are permitted provided that the following conditions
9527 + * are met:
9528 + *
9529 + * 1. Redistributions of source code must retain the above copyright
9530 + *    notice, this list of conditions and the following disclaimer.
9531 + *
9532 + * 2. Redistributions in binary form must reproduce the above copyright
9533 + *    notice, this list of conditions and the following disclaimer in the
9534 + *    documentation and/or other materials provided with the distribution.
9535 + *
9536 + * 3. Neither the name of JANET(UK) nor the names of its contributors
9537 + *    may be used to endorse or promote products derived from this software
9538 + *    without specific prior written permission.
9539 + *
9540 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
9541 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9542 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9543 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
9544 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9545 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9546 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9547 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9548 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9549 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9550 + * SUCH DAMAGE.
9551 + */
9552 +
9553 +/*
9554 + *
9555 + */
9556 +
9557 +#include "gssapiP_eap.h"
9558 +
9559 +OM_uint32
9560 +gssEapQueryMetaData(OM_uint32 *minor,
9561 +                    gss_const_OID mech GSSEAP_UNUSED,
9562 +                    gss_cred_id_t cred,
9563 +                    gss_ctx_id_t *context_handle,
9564 +                    const gss_name_t name,
9565 +                    OM_uint32 req_flags GSSEAP_UNUSED,
9566 +                    gss_buffer_t meta_data)
9567 +{
9568 +    OM_uint32 major = GSS_S_COMPLETE;
9569 +    int isInitiator = (name != GSS_C_NO_NAME);
9570 +    gss_ctx_id_t ctx = *context_handle;
9571 +
9572 +    meta_data->length = 0;
9573 +    meta_data->value = NULL;
9574 +
9575 +    if (ctx == GSS_C_NO_CONTEXT) {
9576 +        major = gssEapAllocContext(minor, &ctx);
9577 +        if (GSS_ERROR(major))
9578 +            return major;
9579 +
9580 +        if (isInitiator)
9581 +            ctx->flags |= CTX_FLAG_INITIATOR;
9582 +    }
9583 +
9584 +    if (ctx->cred == GSS_C_NO_CREDENTIAL) {
9585 +        if (isInitiator) {
9586 +            major = gssEapResolveInitiatorCred(minor, cred,
9587 +                                               name, &ctx->cred);
9588 +        } else {
9589 +            major = gssEapAcquireCred(minor,
9590 +                                      GSS_C_NO_NAME,
9591 +                                      GSS_C_INDEFINITE,
9592 +                                      GSS_C_NO_OID_SET,
9593 +                                      GSS_C_ACCEPT,
9594 +                                      &ctx->cred,
9595 +                                      NULL,
9596 +                                      NULL);
9597 +        }
9598 +    }
9599 +
9600 +    if (*context_handle == GSS_C_NO_CONTEXT)
9601 +        *context_handle = ctx;
9602 +
9603 +    return major;
9604 +}
9605 +
9606 +OM_uint32 GSSAPI_CALLCONV
9607 +gss_query_meta_data(OM_uint32 *minor,
9608 +                    gss_const_OID mech,
9609 +                    gss_cred_id_t cred,
9610 +                    gss_ctx_id_t *context_handle,
9611 +                    const gss_name_t name,
9612 +                    OM_uint32 req_flags,
9613 +                    gss_buffer_t meta_data)
9614 +{
9615 +    gss_ctx_id_t ctx = *context_handle;
9616 +    OM_uint32 major;
9617 +
9618 +    if (cred != GSS_C_NO_CREDENTIAL)
9619 +        GSSEAP_MUTEX_LOCK(&cred->mutex);
9620 +
9621 +    if (*context_handle != GSS_C_NO_CONTEXT)
9622 +        GSSEAP_MUTEX_LOCK(&ctx->mutex);
9623 +
9624 +    major = gssEapQueryMetaData(minor, mech, cred, &ctx,
9625 +                                name, req_flags, meta_data);
9626 +
9627 +    if (*context_handle != GSS_C_NO_CONTEXT)
9628 +        GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
9629 +    else
9630 +        *context_handle = ctx;
9631 +
9632 +    if (cred != GSS_C_NO_CREDENTIAL)
9633 +        GSSEAP_MUTEX_UNLOCK(&cred->mutex);
9634 +
9635 +    return major;
9636 +}
9637 diff --git a/mech_eap/radius_ad.exports b/mech_eap/radius_ad.exports
9638 new file mode 100644
9639 index 0000000..8d5d5c4
9640 --- /dev/null
9641 +++ b/mech_eap/radius_ad.exports
9642 @@ -0,0 +1 @@
9643 +authdata_client_0
9644 diff --git a/mech_eap/radsec.conf b/mech_eap/radsec.conf
9645 new file mode 100644
9646 index 0000000..27f895a
9647 --- /dev/null
9648 +++ b/mech_eap/radsec.conf
9649 @@ -0,0 +1,12 @@
9650 +dictionary = "/usr/local/etc/raddb/dictionary"
9651 +
9652 +realm gss-eap {
9653 +    type = "UDP"
9654 +    timeout = 5
9655 +    retries = 3
9656 +    server {
9657 +        hostname = "localhost"
9658 +        service = "1812"
9659 +        secret = "testing123"
9660 +    }
9661 +}
9662 diff --git a/mech_eap/radsec_err.et b/mech_eap/radsec_err.et
9663 new file mode 100644
9664 index 0000000..3b7fae2
9665 --- /dev/null
9666 +++ b/mech_eap/radsec_err.et
9667 @@ -0,0 +1,38 @@
9668 +#
9669 +# Copyright (c) 2011, JANET(UK)
9670 +#  All rights reserved.
9671 +# 
9672 +#  Redistribution and use in source and binary forms, with or without
9673 +#  modification, are permitted provided that the following conditions
9674 +#  are met:
9675 +# 
9676 +#  1. Redistributions of source code must retain the above copyright
9677 +#     notice, this list of conditions and the following disclaimer.
9678 +# 
9679 +#  2. Redistributions in binary form must reproduce the above copyright
9680 +#     notice, this list of conditions and the following disclaimer in the
9681 +#     documentation and/or other materials provided with the distribution.
9682 +# 
9683 +#  3. Neither the name of JANET(UK) nor the names of its contributors
9684 +#     may be used to endorse or promote products derived from this software
9685 +#     without specific prior written permission.
9686 +# 
9687 +#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
9688 +#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9689 +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9690 +#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
9691 +#  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9692 +#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9693 +#  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9694 +#  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9695 +#  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9696 +#  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9697 +#  SUCH DAMAGE.
9698 +#
9699 +
9700 +# Placeholders only
9701 +error_table rse
9702 +
9703 +error_code GSSEAP_RSE_OK,                       ""
9704 +
9705 +end
9706 diff --git a/mech_eap/release_any_name_mapping.c b/mech_eap/release_any_name_mapping.c
9707 new file mode 100644
9708 index 0000000..d68fb45
9709 --- /dev/null
9710 +++ b/mech_eap/release_any_name_mapping.c
9711 @@ -0,0 +1,59 @@
9712 +/*
9713 + * Copyright (c) 2011, JANET(UK)
9714 + * All rights reserved.
9715 + *
9716 + * Redistribution and use in source and binary forms, with or without
9717 + * modification, are permitted provided that the following conditions
9718 + * are met:
9719 + *
9720 + * 1. Redistributions of source code must retain the above copyright
9721 + *    notice, this list of conditions and the following disclaimer.
9722 + *
9723 + * 2. Redistributions in binary form must reproduce the above copyright
9724 + *    notice, this list of conditions and the following disclaimer in the
9725 + *    documentation and/or other materials provided with the distribution.
9726 + *
9727 + * 3. Neither the name of JANET(UK) nor the names of its contributors
9728 + *    may be used to endorse or promote products derived from this software
9729 + *    without specific prior written permission.
9730 + *
9731 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
9732 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9733 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9734 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
9735 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9736 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9737 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9738 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9739 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9740 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9741 + * SUCH DAMAGE.
9742 + */
9743 +
9744 +#include "gssapiP_eap.h"
9745 +
9746 +OM_uint32 GSSAPI_CALLCONV
9747 +gss_release_any_name_mapping(OM_uint32 *minor,
9748 +                             gss_name_t name,
9749 +                             gss_buffer_t type_id,
9750 +                             gss_any_t *input)
9751 +{
9752 +    OM_uint32 major;
9753 +
9754 +    *minor = 0;
9755 +
9756 +    if (name == GSS_C_NO_NAME) {
9757 +        *minor = EINVAL;
9758 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
9759 +    }
9760 +
9761 +    GSSEAP_MUTEX_LOCK(&name->mutex);
9762 +
9763 +    major = gssEapReleaseAnyNameMapping(minor, name, type_id, input);
9764 +
9765 +    *input = NULL;
9766 +
9767 +    GSSEAP_MUTEX_UNLOCK(&name->mutex);
9768 +
9769 +    return major;
9770 +}
9771 diff --git a/mech_eap/release_cred.c b/mech_eap/release_cred.c
9772 new file mode 100644
9773 index 0000000..8bb7e54
9774 --- /dev/null
9775 +++ b/mech_eap/release_cred.c
9776 @@ -0,0 +1,44 @@
9777 +/*
9778 + * Copyright (c) 2011, JANET(UK)
9779 + * All rights reserved.
9780 + *
9781 + * Redistribution and use in source and binary forms, with or without
9782 + * modification, are permitted provided that the following conditions
9783 + * are met:
9784 + *
9785 + * 1. Redistributions of source code must retain the above copyright
9786 + *    notice, this list of conditions and the following disclaimer.
9787 + *
9788 + * 2. Redistributions in binary form must reproduce the above copyright
9789 + *    notice, this list of conditions and the following disclaimer in the
9790 + *    documentation and/or other materials provided with the distribution.
9791 + *
9792 + * 3. Neither the name of JANET(UK) nor the names of its contributors
9793 + *    may be used to endorse or promote products derived from this software
9794 + *    without specific prior written permission.
9795 + *
9796 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
9797 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9798 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9799 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
9800 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9801 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9802 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9803 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9804 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9805 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9806 + * SUCH DAMAGE.
9807 + */
9808 +
9809 +/*
9810 + * Release a credential handle.
9811 + */
9812 +
9813 +#include "gssapiP_eap.h"
9814 +
9815 +OM_uint32 GSSAPI_CALLCONV
9816 +gss_release_cred(OM_uint32 *minor,
9817 +                 gss_cred_id_t *cred_handle)
9818 +{
9819 +    return gssEapReleaseCred(minor, cred_handle);
9820 +}
9821 diff --git a/mech_eap/release_name.c b/mech_eap/release_name.c
9822 new file mode 100644
9823 index 0000000..3d527ce
9824 --- /dev/null
9825 +++ b/mech_eap/release_name.c
9826 @@ -0,0 +1,44 @@
9827 +/*
9828 + * Copyright (c) 2011, JANET(UK)
9829 + * All rights reserved.
9830 + *
9831 + * Redistribution and use in source and binary forms, with or without
9832 + * modification, are permitted provided that the following conditions
9833 + * are met:
9834 + *
9835 + * 1. Redistributions of source code must retain the above copyright
9836 + *    notice, this list of conditions and the following disclaimer.
9837 + *
9838 + * 2. Redistributions in binary form must reproduce the above copyright
9839 + *    notice, this list of conditions and the following disclaimer in the
9840 + *    documentation and/or other materials provided with the distribution.
9841 + *
9842 + * 3. Neither the name of JANET(UK) nor the names of its contributors
9843 + *    may be used to endorse or promote products derived from this software
9844 + *    without specific prior written permission.
9845 + *
9846 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
9847 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9848 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9849 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
9850 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9851 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9852 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9853 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9854 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9855 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9856 + * SUCH DAMAGE.
9857 + */
9858 +
9859 +/*
9860 + * Release a name.
9861 + */
9862 +
9863 +#include "gssapiP_eap.h"
9864 +
9865 +OM_uint32 GSSAPI_CALLCONV
9866 +gss_release_name(OM_uint32 *minor,
9867 +                 gss_name_t *name)
9868 +{
9869 +    return gssEapReleaseName(minor, name);
9870 +}
9871 diff --git a/mech_eap/release_oid.c b/mech_eap/release_oid.c
9872 new file mode 100644
9873 index 0000000..291da40
9874 --- /dev/null
9875 +++ b/mech_eap/release_oid.c
9876 @@ -0,0 +1,44 @@
9877 +/*
9878 + * Copyright (c) 2011, JANET(UK)
9879 + * All rights reserved.
9880 + *
9881 + * Redistribution and use in source and binary forms, with or without
9882 + * modification, are permitted provided that the following conditions
9883 + * are met:
9884 + *
9885 + * 1. Redistributions of source code must retain the above copyright
9886 + *    notice, this list of conditions and the following disclaimer.
9887 + *
9888 + * 2. Redistributions in binary form must reproduce the above copyright
9889 + *    notice, this list of conditions and the following disclaimer in the
9890 + *    documentation and/or other materials provided with the distribution.
9891 + *
9892 + * 3. Neither the name of JANET(UK) nor the names of its contributors
9893 + *    may be used to endorse or promote products derived from this software
9894 + *    without specific prior written permission.
9895 + *
9896 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
9897 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9898 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9899 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
9900 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9901 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9902 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9903 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9904 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9905 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9906 + * SUCH DAMAGE.
9907 + */
9908 +
9909 +/*
9910 + * Mark an internalized OID as not required to be released.
9911 + */
9912 +
9913 +#include "gssapiP_eap.h"
9914 +
9915 +OM_uint32 GSSAPI_CALLCONV
9916 +gss_internal_release_oid(OM_uint32 *minor,
9917 +                         gss_OID *oid)
9918 +{
9919 +    return gssEapReleaseOid(minor, oid);
9920 +}
9921 diff --git a/mech_eap/set_cred_option.c b/mech_eap/set_cred_option.c
9922 new file mode 100644
9923 index 0000000..7bb9b7b
9924 --- /dev/null
9925 +++ b/mech_eap/set_cred_option.c
9926 @@ -0,0 +1,208 @@
9927 +/*
9928 + * Copyright (c) 2011, JANET(UK)
9929 + * All rights reserved.
9930 + *
9931 + * Redistribution and use in source and binary forms, with or without
9932 + * modification, are permitted provided that the following conditions
9933 + * are met:
9934 + *
9935 + * 1. Redistributions of source code must retain the above copyright
9936 + *    notice, this list of conditions and the following disclaimer.
9937 + *
9938 + * 2. Redistributions in binary form must reproduce the above copyright
9939 + *    notice, this list of conditions and the following disclaimer in the
9940 + *    documentation and/or other materials provided with the distribution.
9941 + *
9942 + * 3. Neither the name of JANET(UK) nor the names of its contributors
9943 + *    may be used to endorse or promote products derived from this software
9944 + *    without specific prior written permission.
9945 + *
9946 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
9947 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9948 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9949 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
9950 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9951 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9952 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9953 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9954 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9955 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9956 + * SUCH DAMAGE.
9957 + */
9958 +
9959 +/*
9960 + * Set an extended property on a credential handle.
9961 + */
9962 +
9963 +#include "gssapiP_eap.h"
9964 +
9965 +static OM_uint32
9966 +setCredRadiusConfigFile(OM_uint32 *minor,
9967 +                        gss_cred_id_t cred,
9968 +                        const gss_OID oid GSSEAP_UNUSED,
9969 +                        const gss_buffer_t buffer)
9970 +{
9971 +    OM_uint32 major, tmpMinor;
9972 +    gss_buffer_desc configFileBuffer = GSS_C_EMPTY_BUFFER;
9973 +
9974 +    if (buffer != GSS_C_NO_BUFFER && buffer->length != 0) {
9975 +        major = duplicateBuffer(minor, buffer, &configFileBuffer);
9976 +        if (GSS_ERROR(major))
9977 +            return major;
9978 +    }
9979 +
9980 +    gss_release_buffer(&tmpMinor, &cred->radiusConfigFile);
9981 +    cred->radiusConfigFile = configFileBuffer;
9982 +
9983 +    *minor = 0;
9984 +    return GSS_S_COMPLETE;
9985 +}
9986 +
9987 +static OM_uint32
9988 +setCredRadiusConfigStanza(OM_uint32 *minor,
9989 +                          gss_cred_id_t cred,
9990 +                          const gss_OID oid GSSEAP_UNUSED,
9991 +                          const gss_buffer_t buffer)
9992 +{
9993 +    OM_uint32 major, tmpMinor;
9994 +    gss_buffer_desc configStanzaBuffer = GSS_C_EMPTY_BUFFER;
9995 +
9996 +    if (buffer != GSS_C_NO_BUFFER && buffer->length != 0) {
9997 +        major = duplicateBuffer(minor, buffer, &configStanzaBuffer);
9998 +        if (GSS_ERROR(major))
9999 +            return major;
10000 +    }
10001 +
10002 +    gss_release_buffer(&tmpMinor, &cred->radiusConfigStanza);
10003 +    cred->radiusConfigStanza = configStanzaBuffer;
10004 +
10005 +    *minor = 0;
10006 +    return GSS_S_COMPLETE;
10007 +}
10008 +
10009 +static OM_uint32
10010 +setCredFlag(OM_uint32 *minor,
10011 +            gss_cred_id_t cred,
10012 +            const gss_OID oid GSSEAP_UNUSED,
10013 +            const gss_buffer_t buffer)
10014 +{
10015 +    OM_uint32 flags;
10016 +    unsigned char *p;
10017 +
10018 +    if (buffer == GSS_C_NO_BUFFER) {
10019 +        *minor = EINVAL;
10020 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_FAILURE;
10021 +    }
10022 +
10023 +    if (buffer->length < 4) {
10024 +        *minor = GSSEAP_WRONG_SIZE;
10025 +        return GSS_S_FAILURE;
10026 +    }
10027 +
10028 +    p = (unsigned char *)buffer->value;
10029 +
10030 +    flags = load_uint32_be(buffer->value) & CRED_FLAG_PUBLIC_MASK;
10031 +
10032 +    if (buffer->length > 4 && p[4])
10033 +        cred->flags &= ~(flags);
10034 +    else
10035 +        cred->flags |= flags;
10036 +
10037 +    *minor = 0;
10038 +    return GSS_S_COMPLETE;
10039 +}
10040 +
10041 +static OM_uint32
10042 +setCredPassword(OM_uint32 *minor,
10043 +                gss_cred_id_t cred,
10044 +                const gss_OID oid GSSEAP_UNUSED,
10045 +                const gss_buffer_t buffer)
10046 +{
10047 +    return gssEapSetCredPassword(minor, cred, buffer);
10048 +}
10049 +
10050 +static struct {
10051 +    gss_OID_desc oid;
10052 +    OM_uint32 (*setOption)(OM_uint32 *, gss_cred_id_t cred,
10053 +                           const gss_OID, const gss_buffer_t);
10054 +} setCredOps[] = {
10055 +    /* 1.3.6.1.4.1.5322.22.3.3.1 */
10056 +    {
10057 +        { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x01" },
10058 +        setCredRadiusConfigFile,
10059 +    },
10060 +    /* 1.3.6.1.4.1.5322.22.3.3.2 */
10061 +    {
10062 +        { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x02" },
10063 +        setCredRadiusConfigStanza,
10064 +    },
10065 +    /* 1.3.6.1.4.1.5322.22.3.3.3 */
10066 +    {
10067 +        { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x03" },
10068 +        setCredFlag,
10069 +    },
10070 +    /* 1.3.6.1.4.1.5322.22.3.3.4 */
10071 +    {
10072 +        { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x03\x03\x04" },
10073 +        setCredPassword,
10074 +    },
10075 +};
10076 +
10077 +gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE     = &setCredOps[0].oid;
10078 +gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_STANZA   = &setCredOps[1].oid;
10079 +gss_OID GSS_EAP_CRED_SET_CRED_FLAG              = &setCredOps[2].oid;
10080 +gss_OID GSS_EAP_CRED_SET_CRED_PASSWORD          = &setCredOps[3].oid;
10081 +
10082 +OM_uint32 GSSAPI_CALLCONV
10083 +gssspi_set_cred_option(OM_uint32 *minor,
10084 +                       gss_cred_id_t *pCred,
10085 +                       const gss_OID desired_object,
10086 +                       const gss_buffer_t value)
10087 +{
10088 +    OM_uint32 major;
10089 +    gss_cred_id_t cred = *pCred;
10090 +    int i;
10091 +
10092 +    if (cred == GSS_C_NO_CREDENTIAL) {
10093 +        *minor = EINVAL;
10094 +        return GSS_S_UNAVAILABLE;
10095 +    }
10096 +
10097 +    GSSEAP_MUTEX_LOCK(&cred->mutex);
10098 +
10099 +    major = GSS_S_UNAVAILABLE;
10100 +    *minor = GSSEAP_BAD_CRED_OPTION;
10101 +
10102 +    for (i = 0; i < sizeof(setCredOps) / sizeof(setCredOps[0]); i++) {
10103 +        if (oidEqual(&setCredOps[i].oid, desired_object)) {
10104 +            major = (*setCredOps[i].setOption)(minor, cred,
10105 +                                               desired_object, value);
10106 +            break;
10107 +        }
10108 +    }
10109 +
10110 +    GSSEAP_MUTEX_UNLOCK(&cred->mutex);
10111 +
10112 +    return major;
10113 +}
10114 +
10115 +#if 0
10116 +OM_uint32
10117 +gsseap_set_cred_flag(OM_uint32 *minor,
10118 +                     gss_cred_id_t cred,
10119 +                     OM_uint32 flag,
10120 +                     int clear)
10121 +{
10122 +    unsigned char buf[5];
10123 +    gss_buffer_desc value;
10124 +
10125 +    value.length = sizeof(buf);
10126 +    value.value = buf;
10127 +
10128 +    store_uint32_be(flag, buf);
10129 +    buf[4] = (clear != 0);
10130 +
10131 +    return gssspi_set_cred_option(minor, &cred,
10132 +                                  GSS_EAP_CRED_SET_CRED_FLAG, &value);
10133 +}
10134 +#endif
10135 diff --git a/mech_eap/set_name_attribute.c b/mech_eap/set_name_attribute.c
10136 new file mode 100644
10137 index 0000000..2ccf5d7
10138 --- /dev/null
10139 +++ b/mech_eap/set_name_attribute.c
10140 @@ -0,0 +1,60 @@
10141 +/*
10142 + * Copyright (c) 2011, JANET(UK)
10143 + * All rights reserved.
10144 + *
10145 + * Redistribution and use in source and binary forms, with or without
10146 + * modification, are permitted provided that the following conditions
10147 + * are met:
10148 + *
10149 + * 1. Redistributions of source code must retain the above copyright
10150 + *    notice, this list of conditions and the following disclaimer.
10151 + *
10152 + * 2. Redistributions in binary form must reproduce the above copyright
10153 + *    notice, this list of conditions and the following disclaimer in the
10154 + *    documentation and/or other materials provided with the distribution.
10155 + *
10156 + * 3. Neither the name of JANET(UK) nor the names of its contributors
10157 + *    may be used to endorse or promote products derived from this software
10158 + *    without specific prior written permission.
10159 + *
10160 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
10161 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10162 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
10163 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
10164 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
10165 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
10166 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
10167 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
10168 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
10169 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
10170 + * SUCH DAMAGE.
10171 + */
10172 +
10173 +/*
10174 + * Set an attribute on a name.
10175 + */
10176 +
10177 +#include "gssapiP_eap.h"
10178 +
10179 +OM_uint32 GSSAPI_CALLCONV
10180 +gss_set_name_attribute(OM_uint32 *minor,
10181 +                       gss_name_t name,
10182 +                       int complete,
10183 +                       gss_buffer_t attr,
10184 +                       gss_buffer_t value)
10185 +{
10186 +    OM_uint32 major;
10187 +
10188 +    if (name == GSS_C_NO_NAME) {
10189 +        *minor = EINVAL;
10190 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
10191 +    }
10192 +
10193 +    GSSEAP_MUTEX_LOCK(&name->mutex);
10194 +
10195 +    major = gssEapSetNameAttribute(minor, name, complete, attr, value);
10196 +
10197 +    GSSEAP_MUTEX_UNLOCK(&name->mutex);
10198 +
10199 +    return major;
10200 +}
10201 diff --git a/mech_eap/set_sec_context_option.c b/mech_eap/set_sec_context_option.c
10202 new file mode 100644
10203 index 0000000..f9fa3a6
10204 --- /dev/null
10205 +++ b/mech_eap/set_sec_context_option.c
10206 @@ -0,0 +1,87 @@
10207 +/*
10208 + * Copyright (c) 2011, JANET(UK)
10209 + * All rights reserved.
10210 + *
10211 + * Redistribution and use in source and binary forms, with or without
10212 + * modification, are permitted provided that the following conditions
10213 + * are met:
10214 + *
10215 + * 1. Redistributions of source code must retain the above copyright
10216 + *    notice, this list of conditions and the following disclaimer.
10217 + *
10218 + * 2. Redistributions in binary form must reproduce the above copyright
10219 + *    notice, this list of conditions and the following disclaimer in the
10220 + *    documentation and/or other materials provided with the distribution.
10221 + *
10222 + * 3. Neither the name of JANET(UK) nor the names of its contributors
10223 + *    may be used to endorse or promote products derived from this software
10224 + *    without specific prior written permission.
10225 + *
10226 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
10227 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10228 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
10229 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
10230 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
10231 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
10232 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
10233 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
10234 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
10235 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
10236 + * SUCH DAMAGE.
10237 + */
10238 +
10239 +/*
10240 + * Set an extended property on a context handle.
10241 + */
10242 +
10243 +#include "gssapiP_eap.h"
10244 +
10245 +#if 0
10246 +static struct {
10247 +    gss_OID_desc oid;
10248 +    OM_uint32 (*setOption)(OM_uint32 *, gss_ctx_id_t *pCtx,
10249 +                           const gss_OID, const gss_buffer_t);
10250 +} setCtxOps[] = {
10251 +};
10252 +#endif
10253 +
10254 +OM_uint32 GSSAPI_CALLCONV
10255 +gss_set_sec_context_option(OM_uint32 *minor,
10256 +                           gss_ctx_id_t *pCtx,
10257 +                           const gss_OID desired_object GSSEAP_UNUSED,
10258 +                           const gss_buffer_t value GSSEAP_UNUSED)
10259 +{
10260 +    OM_uint32 major;
10261 +    gss_ctx_id_t ctx;
10262 +#if 0
10263 +    int i;
10264 +#endif
10265 +
10266 +    major = GSS_S_UNAVAILABLE;
10267 +    *minor = GSSEAP_BAD_CONTEXT_OPTION;
10268 +
10269 +    if (pCtx == NULL)
10270 +        ctx = GSS_C_NO_CONTEXT;
10271 +    else
10272 +        ctx = *pCtx;
10273 +
10274 +    if (ctx != GSS_C_NO_CONTEXT)
10275 +        GSSEAP_MUTEX_LOCK(&ctx->mutex);
10276 +
10277 +#if 0
10278 +    for (i = 0; i < sizeof(setCtxOps) / sizeof(setCtxOps[0]); i++) {
10279 +        if (oidEqual(&setCtxOps[i].oid, desired_object)) {
10280 +            major = (*setCtxOps[i].setOption)(minor, &ctx,
10281 +                                              desired_object, value);
10282 +            break;
10283 +        }
10284 +    }
10285 +#endif
10286 +
10287 +    if (pCtx != NULL && *pCtx == NULL)
10288 +        *pCtx = ctx;
10289 +    else if (ctx != GSS_C_NO_CONTEXT)
10290 +        GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
10291 +
10292 +    return major;
10293 +}
10294 diff --git a/mech_eap/store_cred.c b/mech_eap/store_cred.c
10295 new file mode 100644
10296 index 0000000..d17a3ac
10297 --- /dev/null
10298 +++ b/mech_eap/store_cred.c
10299 @@ -0,0 +1,83 @@
10300 +/*
10301 + * Copyright (c) 2011, JANET(UK)
10302 + * All rights reserved.
10303 + *
10304 + * Redistribution and use in source and binary forms, with or without
10305 + * modification, are permitted provided that the following conditions
10306 + * are met:
10307 + *
10308 + * 1. Redistributions of source code must retain the above copyright
10309 + *    notice, this list of conditions and the following disclaimer.
10310 + *
10311 + * 2. Redistributions in binary form must reproduce the above copyright
10312 + *    notice, this list of conditions and the following disclaimer in the
10313 + *    documentation and/or other materials provided with the distribution.
10314 + *
10315 + * 3. Neither the name of JANET(UK) nor the names of its contributors
10316 + *    may be used to endorse or promote products derived from this software
10317 + *    without specific prior written permission.
10318 + *
10319 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
10320 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10321 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
10322 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
10323 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
10324 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
10325 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
10326 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
10327 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
10328 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
10329 + * SUCH DAMAGE.
10330 + */
10331 +
10332 +#include "gssapiP_eap.h"
10333 +
10334 +OM_uint32 GSSAPI_CALLCONV
10335 +gss_store_cred(OM_uint32 *minor,
10336 +               const gss_cred_id_t cred,
10337 +               gss_cred_usage_t input_usage,
10338 +               const gss_OID desired_mech GSSEAP_UNUSED,
10339 +#ifdef GSSEAP_ENABLE_REAUTH
10340 +               OM_uint32 overwrite_cred,
10341 +               OM_uint32 default_cred,
10342 +#else
10343 +               OM_uint32 overwrite_cred GSSEAP_UNUSED,
10344 +               OM_uint32 default_cred GSSEAP_UNUSED,
10345 +#endif
10346 +               gss_OID_set *elements_stored,
10347 +               gss_cred_usage_t *cred_usage_stored)
10348 +{
10349 +    OM_uint32 major;
10350 +
10351 +    if (elements_stored != NULL)
10352 +        *elements_stored = GSS_C_NO_OID_SET;
10353 +    if (cred_usage_stored != NULL)
10354 +        *cred_usage_stored = input_usage;
10355 +
10356 +    if (cred == GSS_C_NO_CREDENTIAL) {
10357 +        *minor = EINVAL;
10358 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED;
10359 +    }
10360 +
10361 +    GSSEAP_MUTEX_LOCK(&cred->mutex);
10362 +
10363 +    major = GSS_S_COMPLETE;
10364 +    *minor = 0;
10365 +
10366 +#ifdef GSSEAP_ENABLE_REAUTH
10367 +    if (cred->reauthCred != GSS_C_NO_CREDENTIAL) {
10368 +        major = gssStoreCred(minor,
10369 +                             cred->reauthCred,
10370 +                             input_usage,
10371 +                             (gss_OID)gss_mech_krb5,
10372 +                             overwrite_cred,
10373 +                             default_cred,
10374 +                             elements_stored,
10375 +                             cred_usage_stored);
10376 +    }
10377 +#endif
10378 +
10379 +    GSSEAP_MUTEX_UNLOCK(&cred->mutex);
10380 +
10381 +    return major;
10382 +}
10383 diff --git a/mech_eap/unwrap.c b/mech_eap/unwrap.c
10384 new file mode 100644
10385 index 0000000..a185035
10386 --- /dev/null
10387 +++ b/mech_eap/unwrap.c
10388 @@ -0,0 +1,85 @@
10389 +/*
10390 + * Copyright (c) 2011, JANET(UK)
10391 + * All rights reserved.
10392 + *
10393 + * Redistribution and use in source and binary forms, with or without
10394 + * modification, are permitted provided that the following conditions
10395 + * are met:
10396 + *
10397 + * 1. Redistributions of source code must retain the above copyright
10398 + *    notice, this list of conditions and the following disclaimer.
10399 + *
10400 + * 2. Redistributions in binary form must reproduce the above copyright
10401 + *    notice, this list of conditions and the following disclaimer in the
10402 + *    documentation and/or other materials provided with the distribution.
10403 + *
10404 + * 3. Neither the name of JANET(UK) nor the names of its contributors
10405 + *    may be used to endorse or promote products derived from this software
10406 + *    without specific prior written permission.
10407 + *
10408 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
10409 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10410 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
10411 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
10412 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
10413 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
10414 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
10415 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
10416 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
10417 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
10418 + * SUCH DAMAGE.
10419 + */
10420 +
10421 +/*
10422 + * Message protection services: unwrap.
10423 + */
10424 +
10425 +#include "gssapiP_eap.h"
10426 +
10427 +OM_uint32 GSSAPI_CALLCONV
10428 +gss_unwrap(OM_uint32 *minor,
10429 +           gss_ctx_id_t ctx,
10430 +           gss_buffer_t input_message_buffer,
10431 +           gss_buffer_t output_message_buffer,
10432 +           int *conf_state,
10433 +           gss_qop_t *qop_state)
10434 +{
10435 +    OM_uint32 major, tmpMinor;
10436 +    gss_iov_buffer_desc iov[2];
10437 +
10438 +    if (ctx == GSS_C_NO_CONTEXT) {
10439 +        *minor = EINVAL;
10440 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
10441 +    }
10442 +
10443 +    *minor = 0;
10444 +
10445 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
10446 +
10447 +    if (!CTX_IS_ESTABLISHED(ctx)) {
10448 +        major = GSS_S_NO_CONTEXT;
10449 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
10450 +        goto cleanup;
10451 +    }
10452 +
10453 +    iov[0].type = GSS_IOV_BUFFER_TYPE_STREAM;
10454 +    iov[0].buffer = *input_message_buffer;
10455 +
10456 +    iov[1].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
10457 +    iov[1].buffer.value = NULL;
10458 +    iov[1].buffer.length = 0;
10459 +
10460 +    major = gssEapUnwrapOrVerifyMIC(minor, ctx, conf_state, qop_state,
10461 +                                    iov, 2, TOK_TYPE_WRAP);
10462 +    if (major == GSS_S_COMPLETE) {
10463 +        *output_message_buffer = iov[1].buffer;
10464 +    } else {
10465 +        if (iov[1].type & GSS_IOV_BUFFER_FLAG_ALLOCATED)
10466 +            gss_release_buffer(&tmpMinor, &iov[1].buffer);
10467 +    }
10468 +
10469 +cleanup:
10470 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
10471 +
10472 +    return major;
10473 +}
10474 diff --git a/mech_eap/unwrap_iov.c b/mech_eap/unwrap_iov.c
10475 new file mode 100644
10476 index 0000000..5ceefa2
10477 --- /dev/null
10478 +++ b/mech_eap/unwrap_iov.c
10479 @@ -0,0 +1,572 @@
10480 +/*
10481 + * Copyright (c) 2011, JANET(UK)
10482 + * All rights reserved.
10483 + *
10484 + * Redistribution and use in source and binary forms, with or without
10485 + * modification, are permitted provided that the following conditions
10486 + * are met:
10487 + *
10488 + * 1. Redistributions of source code must retain the above copyright
10489 + *    notice, this list of conditions and the following disclaimer.
10490 + *
10491 + * 2. Redistributions in binary form must reproduce the above copyright
10492 + *    notice, this list of conditions and the following disclaimer in the
10493 + *    documentation and/or other materials provided with the distribution.
10494 + *
10495 + * 3. Neither the name of JANET(UK) nor the names of its contributors
10496 + *    may be used to endorse or promote products derived from this software
10497 + *    without specific prior written permission.
10498 + *
10499 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
10500 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10501 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
10502 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
10503 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
10504 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
10505 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
10506 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
10507 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
10508 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
10509 + * SUCH DAMAGE.
10510 + */
10511 +/*
10512 + * Copyright 2008 by the Massachusetts Institute of Technology.
10513 + * All Rights Reserved.
10514 + *
10515 + * Export of this software from the United States of America may
10516 + *   require a specific license from the United States Government.
10517 + *   It is the responsibility of any person or organization contemplating
10518 + *   export to obtain such a license before exporting.
10519 + *
10520 + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
10521 + * distribute this software and its documentation for any purpose and
10522 + * without fee is hereby granted, provided that the above copyright
10523 + * notice appear in all copies and that both that copyright notice and
10524 + * this permission notice appear in supporting documentation, and that
10525 + * the name of M.I.T. not be used in advertising or publicity pertaining
10526 + * to distribution of the software without specific, written prior
10527 + * permission.  Furthermore if you modify this software you must label
10528 + * your software as modified software and not distribute it in such a
10529 + * fashion that it might be confused with the original M.I.T. software.
10530 + * M.I.T. makes no representations about the suitability of
10531 + * this software for any purpose.  It is provided "as is" without express
10532 + * or implied warranty.
10533 + */
10534 +
10535 +/*
10536 + * Message protection services: unwrap with scatter-gather API.
10537 + */
10538 +
10539 +#include "gssapiP_eap.h"
10540 +
10541 +/*
10542 + * Caller must provide TOKEN | DATA | PADDING | TRAILER, except
10543 + * for DCE in which case it can just provide TOKEN | DATA (must
10544 + * guarantee that DATA is padded)
10545 + */
10546 +OM_uint32
10547 +unwrapToken(OM_uint32 *minor,
10548 +            gss_ctx_id_t ctx,
10549 +#ifdef HAVE_HEIMDAL_VERSION
10550 +            krb5_crypto krbCrypto,
10551 +#else
10552 +            krb5_keyblock *unused GSSEAP_UNUSED,
10553 +#endif
10554 +            int *conf_state,
10555 +            gss_qop_t *qop_state,
10556 +            gss_iov_buffer_desc *iov,
10557 +            int iov_count,
10558 +            enum gss_eap_token_type toktype)
10559 +{
10560 +    OM_uint32 major = GSS_S_FAILURE, code;
10561 +    gss_iov_buffer_t header;
10562 +    gss_iov_buffer_t padding;
10563 +    gss_iov_buffer_t trailer;
10564 +    unsigned char flags;
10565 +    unsigned char *ptr = NULL;
10566 +    int keyUsage;
10567 +    size_t rrc, ec;
10568 +    size_t dataLen, assocDataLen;
10569 +    uint64_t seqnum;
10570 +    int valid = 0;
10571 +    int conf_flag = 0;
10572 +    krb5_context krbContext;
10573 +#ifdef HAVE_HEIMDAL_VERSION
10574 +    int freeCrypto = (krbCrypto == NULL);
10575 +#endif
10576 +
10577 +    GSSEAP_KRB_INIT(&krbContext);
10578 +
10579 +    *minor = 0;
10580 +
10581 +    if (qop_state != NULL)
10582 +        *qop_state = GSS_C_QOP_DEFAULT;
10583 +
10584 +    header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
10585 +    GSSEAP_ASSERT(header != NULL);
10586 +
10587 +    padding = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
10588 +    if (padding != NULL && padding->buffer.length != 0) {
10589 +        code = GSSEAP_BAD_PADDING_IOV;
10590 +        major = GSS_S_DEFECTIVE_TOKEN;
10591 +        goto cleanup;
10592 +    }
10593 +
10594 +    trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
10595 +
10596 +    flags = rfc4121Flags(ctx, TRUE);
10597 +
10598 +    if (toktype == TOK_TYPE_WRAP) {
10599 +        keyUsage = !CTX_IS_INITIATOR(ctx)
10600 +                   ? KEY_USAGE_INITIATOR_SEAL
10601 +                   : KEY_USAGE_ACCEPTOR_SEAL;
10602 +    } else {
10603 +        keyUsage = !CTX_IS_INITIATOR(ctx)
10604 +                   ? KEY_USAGE_INITIATOR_SIGN
10605 +                   : KEY_USAGE_ACCEPTOR_SIGN;
10606 +    }
10607 +
10608 +    gssEapIovMessageLength(iov, iov_count, &dataLen, &assocDataLen);
10609 +
10610 +    ptr = (unsigned char *)header->buffer.value;
10611 +
10612 +    if (header->buffer.length < 16) {
10613 +        code = GSSEAP_TOK_TRUNC;
10614 +        major = GSS_S_DEFECTIVE_TOKEN;
10615 +        goto cleanup;
10616 +    }
10617 +
10618 +    if ((ptr[2] & flags) != flags) {
10619 +        code = GSSEAP_BAD_DIRECTION;
10620 +        major = GSS_S_BAD_SIG;
10621 +        goto cleanup;
10622 +    }
10623 +
10624 +#ifdef HAVE_HEIMDAL_VERSION
10625 +    if (krbCrypto == NULL) {
10626 +        code = krb5_crypto_init(krbContext, &ctx->rfc3961Key,
10627 +                                ETYPE_NULL, &krbCrypto);
10628 +        if (code != 0)
10629 +            goto cleanup;
10630 +    }
10631 +#endif
10632 +
10633 +    if (toktype == TOK_TYPE_WRAP) {
10634 +        size_t krbTrailerLen;
10635 +
10636 +        if (load_uint16_be(ptr) != TOK_TYPE_WRAP)
10637 +            goto defective;
10638 +        conf_flag = ((ptr[2] & TOK_FLAG_WRAP_CONFIDENTIAL) != 0);
10639 +        if (ptr[3] != 0xFF)
10640 +            goto defective;
10641 +        ec = load_uint16_be(ptr + 4);
10642 +        rrc = load_uint16_be(ptr + 6);
10643 +        seqnum = load_uint64_be(ptr + 8);
10644 +
10645 +        code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
10646 +                               conf_flag ? KRB5_CRYPTO_TYPE_TRAILER :
10647 +                                           KRB5_CRYPTO_TYPE_CHECKSUM,
10648 +                               &krbTrailerLen);
10649 +        if (code != 0)
10650 +            goto cleanup;
10651 +
10652 +        /* Deal with RRC */
10653 +        if (trailer == NULL) {
10654 +            size_t desired_rrc = krbTrailerLen;
10655 +
10656 +            if (conf_flag) {
10657 +                desired_rrc += 16; /* E(Header) */
10658 +
10659 +                if ((ctx->gssFlags & GSS_C_DCE_STYLE) == 0)
10660 +                    desired_rrc += ec;
10661 +            }
10662 +
10663 +            /* According to MS, we only need to deal with a fixed RRC for DCE */
10664 +            if (rrc != desired_rrc)
10665 +                goto defective;
10666 +        } else if (rrc != 0) {
10667 +            goto defective;
10668 +        }
10669 +
10670 +        if (conf_flag) {
10671 +            unsigned char *althdr;
10672 +
10673 +            /* Decrypt */
10674 +            code = gssEapDecrypt(krbContext,
10675 +                                 ((ctx->gssFlags & GSS_C_DCE_STYLE) != 0),
10676 +                                 ec, rrc, KRB_CRYPTO_CONTEXT(ctx), keyUsage,
10677 +                                 iov, iov_count);
10678 +            if (code != 0) {
10679 +                major = GSS_S_BAD_SIG;
10680 +                goto cleanup;
10681 +            }
10682 +
10683 +            /* Validate header integrity */
10684 +            if (trailer == NULL)
10685 +                althdr = (unsigned char *)header->buffer.value + 16 + ec;
10686 +            else
10687 +                althdr = (unsigned char *)trailer->buffer.value + ec;
10688 +
10689 +            if (load_uint16_be(althdr) != TOK_TYPE_WRAP
10690 +                || althdr[2] != ptr[2]
10691 +                || althdr[3] != ptr[3]
10692 +                || memcmp(althdr + 8, ptr + 8, 8) != 0) {
10693 +                code = GSSEAP_BAD_WRAP_TOKEN;
10694 +                major = GSS_S_BAD_SIG;
10695 +                goto cleanup;
10696 +            }
10697 +        } else {
10698 +            /* Verify checksum: note EC is checksum size here, not padding */
10699 +            if (ec != krbTrailerLen)
10700 +                goto defective;
10701 +
10702 +            /* Zero EC, RRC before computing checksum */
10703 +            store_uint16_be(0, ptr + 4);
10704 +            store_uint16_be(0, ptr + 6);
10705 +
10706 +            code = gssEapVerify(krbContext, ctx->checksumType, rrc,
10707 +                                KRB_CRYPTO_CONTEXT(ctx), keyUsage,
10708 +                                iov, iov_count, &valid);
10709 +            if (code != 0 || valid == FALSE) {
10710 +                major = GSS_S_BAD_SIG;
10711 +                goto cleanup;
10712 +            }
10713 +        }
10714 +
10715 +        code = sequenceCheck(minor, &ctx->seqState, seqnum);
10716 +    } else if (toktype == TOK_TYPE_MIC) {
10717 +        if (load_uint16_be(ptr) != toktype)
10718 +            goto defective;
10719 +
10720 +    verify_mic_1:
10721 +        if (ptr[3] != 0xFF)
10722 +            goto defective;
10723 +        seqnum = load_uint64_be(ptr + 8);
10724 +
10725 +        /*
10726 +         * Although MIC tokens don't have a RRC, they are similarly
10727 +         * composed of a header and a checksum. So the verify_mic()
10728 +         * can be implemented with a single header buffer, fake the
10729 +         * RRC to the putative trailer length if no trailer buffer.
10730 +         */
10731 +        code = gssEapVerify(krbContext, ctx->checksumType,
10732 +                            trailer != NULL ? 0 : header->buffer.length - 16,
10733 +                            KRB_CRYPTO_CONTEXT(ctx), keyUsage,
10734 +                            iov, iov_count, &valid);
10735 +        if (code != 0 || valid == FALSE) {
10736 +            major = GSS_S_BAD_SIG;
10737 +            goto cleanup;
10738 +        }
10739 +        code = sequenceCheck(minor, &ctx->seqState, seqnum);
10740 +    } else if (toktype == TOK_TYPE_DELETE_CONTEXT) {
10741 +        if (load_uint16_be(ptr) != TOK_TYPE_DELETE_CONTEXT)
10742 +            goto defective;
10743 +        goto verify_mic_1;
10744 +    } else {
10745 +        goto defective;
10746 +    }
10747 +
10748 +    if (conf_state != NULL)
10749 +        *conf_state = conf_flag;
10750 +
10751 +    code = 0;
10752 +    major = GSS_S_COMPLETE;
10753 +    goto cleanup;
10754 +
10755 +defective:
10756 +    code = GSSEAP_BAD_WRAP_TOKEN;
10757 +    major = GSS_S_DEFECTIVE_TOKEN;
10758 +
10759 +cleanup:
10760 +    *minor = code;
10761 +#ifdef HAVE_HEIMDAL_VERSION
10762 +    if (freeCrypto && krbCrypto != NULL)
10763 +        krb5_crypto_destroy(krbContext, krbCrypto);
10764 +#endif
10765 +
10766 +    return major;
10767 +}
10768 +
10769 +int
10770 +rotateLeft(void *ptr, size_t bufsiz, size_t rc)
10771 +{
10772 +    void *tbuf;
10773 +
10774 +    if (bufsiz == 0)
10775 +        return 0;
10776 +    rc = rc % bufsiz;
10777 +    if (rc == 0)
10778 +        return 0;
10779 +
10780 +    tbuf = GSSEAP_MALLOC(rc);
10781 +    if (tbuf == NULL)
10782 +        return ENOMEM;
10783 +
10784 +    memcpy(tbuf, ptr, rc);
10785 +    memmove(ptr, (char *)ptr + rc, bufsiz - rc);
10786 +    memcpy((char *)ptr + bufsiz - rc, tbuf, rc);
10787 +    GSSEAP_FREE(tbuf);
10788 +
10789 +    return 0;
10790 +}
10791 +
10792 +/*
10793 + * Split a STREAM | SIGN_DATA | DATA into
10794 + *         HEADER | SIGN_DATA | DATA | PADDING | TRAILER
10795 + */
10796 +static OM_uint32
10797 +unwrapStream(OM_uint32 *minor,
10798 +             gss_ctx_id_t ctx,
10799 +             int *conf_state,
10800 +             gss_qop_t *qop_state,
10801 +             gss_iov_buffer_desc *iov,
10802 +             int iov_count,
10803 +             enum gss_eap_token_type toktype)
10804 +{
10805 +    unsigned char *ptr;
10806 +    OM_uint32 code = 0, major = GSS_S_FAILURE;
10807 +    krb5_context krbContext;
10808 +    int conf_req_flag;
10809 +    int i = 0, j;
10810 +    gss_iov_buffer_desc *tiov = NULL;
10811 +    gss_iov_buffer_t stream, data = NULL;
10812 +    gss_iov_buffer_t theader, tdata = NULL, tpadding, ttrailer;
10813 +#ifdef HAVE_HEIMDAL_VERSION
10814 +    krb5_crypto krbCrypto = NULL;
10815 +#endif
10816 +
10817 +    GSSEAP_KRB_INIT(&krbContext);
10818 +
10819 +    GSSEAP_ASSERT(toktype == TOK_TYPE_WRAP);
10820 +
10821 +    if (toktype != TOK_TYPE_WRAP) {
10822 +        code = GSSEAP_WRONG_TOK_ID;
10823 +        goto cleanup;
10824 +    }
10825 +
10826 +    stream = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_STREAM);
10827 +    GSSEAP_ASSERT(stream != NULL);
10828 +
10829 +    if (stream->buffer.length < 16) {
10830 +        major = GSS_S_DEFECTIVE_TOKEN;
10831 +        goto cleanup;
10832 +    }
10833 +
10834 +    ptr = (unsigned char *)stream->buffer.value;
10835 +    ptr += 2; /* skip token type */
10836 +
10837 +    tiov = (gss_iov_buffer_desc *)GSSEAP_CALLOC((size_t)iov_count + 2,
10838 +                                                sizeof(gss_iov_buffer_desc));
10839 +    if (tiov == NULL) {
10840 +        code = ENOMEM;
10841 +        goto cleanup;
10842 +    }
10843 +
10844 +    /* HEADER */
10845 +    theader = &tiov[i++];
10846 +    theader->type = GSS_IOV_BUFFER_TYPE_HEADER;
10847 +    theader->buffer.value = stream->buffer.value;
10848 +    theader->buffer.length = 16;
10849 +
10850 +    /* n[SIGN_DATA] | DATA | m[SIGN_DATA] */
10851 +    for (j = 0; j < iov_count; j++) {
10852 +        OM_uint32 type = GSS_IOV_BUFFER_TYPE(iov[j].type);
10853 +
10854 +        if (type == GSS_IOV_BUFFER_TYPE_DATA) {
10855 +            if (data != NULL) {
10856 +                /* only a single DATA buffer can appear */
10857 +                code = GSSEAP_BAD_STREAM_IOV;
10858 +                goto cleanup;
10859 +            }
10860 +
10861 +            data = &iov[j];
10862 +            tdata = &tiov[i];
10863 +        }
10864 +        if (type == GSS_IOV_BUFFER_TYPE_DATA ||
10865 +            type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
10866 +            tiov[i++] = iov[j];
10867 +    }
10868 +
10869 +    if (data == NULL) {
10870 +        /* a single DATA buffer must be present */
10871 +        code = GSSEAP_BAD_STREAM_IOV;
10872 +        goto cleanup;
10873 +    }
10874 +
10875 +    /* PADDING | TRAILER */
10876 +    tpadding = &tiov[i++];
10877 +    tpadding->type = GSS_IOV_BUFFER_TYPE_PADDING;
10878 +    tpadding->buffer.length = 0;
10879 +    tpadding->buffer.value = NULL;
10880 +
10881 +    ttrailer = &tiov[i++];
10882 +    ttrailer->type = GSS_IOV_BUFFER_TYPE_TRAILER;
10883 +
10884 +#ifdef HAVE_HEIMDAL_VERSION
10885 +    code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, ETYPE_NULL, &krbCrypto);
10886 +    if (code != 0)
10887 +        goto cleanup;
10888 +#endif
10889 +
10890 +    {
10891 +        size_t ec, rrc;
10892 +        size_t krbHeaderLen = 0;
10893 +        size_t krbTrailerLen = 0;
10894 +
10895 +        conf_req_flag = ((ptr[0] & TOK_FLAG_WRAP_CONFIDENTIAL) != 0);
10896 +        ec = conf_req_flag ? load_uint16_be(ptr + 2) : 0;
10897 +        rrc = load_uint16_be(ptr + 4);
10898 +
10899 +        if (rrc != 0) {
10900 +            code = rotateLeft((unsigned char *)stream->buffer.value + 16,
10901 +                              stream->buffer.length - 16, rrc);
10902 +            if (code != 0)
10903 +                goto cleanup;
10904 +            store_uint16_be(0, ptr + 4); /* set RRC to zero */
10905 +        }
10906 +
10907 +        if (conf_req_flag) {
10908 +            code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
10909 +                                    KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen);
10910 +            if (code != 0)
10911 +                goto cleanup;
10912 +            theader->buffer.length += krbHeaderLen; /* length validated later */
10913 +        }
10914 +
10915 +        /* no PADDING for CFX, EC is used instead */
10916 +        code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
10917 +                               conf_req_flag
10918 +                                  ? KRB5_CRYPTO_TYPE_TRAILER
10919 +                                  : KRB5_CRYPTO_TYPE_CHECKSUM,
10920 +                               &krbTrailerLen);
10921 +        if (code != 0)
10922 +            goto cleanup;
10923 +
10924 +        ttrailer->buffer.length = ec + (conf_req_flag ? 16 : 0 /* E(Header) */) +
10925 +                                  krbTrailerLen;
10926 +        ttrailer->buffer.value = (unsigned char *)stream->buffer.value +
10927 +            stream->buffer.length - ttrailer->buffer.length;
10928 +    }
10929 +
10930 +    /* IOV: -----------0-------------+---1---+--2--+----------------3--------------*/
10931 +    /* CFX: GSS-Header | Kerb-Header | Data  |     | EC | E(Header) | Kerb-Trailer */
10932 +    /* GSS: -------GSS-HEADER--------+-DATA--+-PAD-+----------GSS-TRAILER----------*/
10933 +
10934 +    /* validate lengths */
10935 +    if (stream->buffer.length < theader->buffer.length +
10936 +        tpadding->buffer.length +
10937 +        ttrailer->buffer.length) {
10938 +        major = GSS_S_DEFECTIVE_TOKEN;
10939 +        code = GSSEAP_TOK_TRUNC;
10940 +        goto cleanup;
10941 +    }
10942 +
10943 +    /* setup data */
10944 +    tdata->buffer.length = stream->buffer.length - ttrailer->buffer.length -
10945 +        tpadding->buffer.length - theader->buffer.length;
10946 +
10947 +    GSSEAP_ASSERT(data != NULL);
10948 +
10949 +    if (data->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
10950 +        code = gssEapAllocIov(tdata, tdata->buffer.length);
10951 +        if (code != 0)
10952 +            goto cleanup;
10953 +
10954 +        memcpy(tdata->buffer.value,
10955 +               (unsigned char *)stream->buffer.value + theader->buffer.length,
10956 +               tdata->buffer.length);
10957 +    } else {
10958 +        tdata->buffer.value = (unsigned char *)stream->buffer.value +
10959 +                              theader->buffer.length;
10960 +    }
10961 +
10962 +    GSSEAP_ASSERT(i <= iov_count + 2);
10963 +
10964 +    major = unwrapToken(&code, ctx, KRB_CRYPTO_CONTEXT(ctx),
10965 +                        conf_state, qop_state, tiov, i, toktype);
10966 +    if (major == GSS_S_COMPLETE) {
10967 +        *data = *tdata;
10968 +    } else if (tdata->type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {
10969 +        OM_uint32 tmp;
10970 +
10971 +        gss_release_buffer(&tmp, &tdata->buffer);
10972 +        tdata->type &= ~(GSS_IOV_BUFFER_FLAG_ALLOCATED);
10973 +    }
10974 +
10975 +cleanup:
10976 +    if (tiov != NULL)
10977 +        GSSEAP_FREE(tiov);
10978 +#ifdef HAVE_HEIMDAL_VERSION
10979 +    if (krbCrypto != NULL)
10980 +        krb5_crypto_destroy(krbContext, krbCrypto);
10981 +#endif
10982 +
10983 +    *minor = code;
10984 +
10985 +    return major;
10986 +}
10987 +
10988 +OM_uint32
10989 +gssEapUnwrapOrVerifyMIC(OM_uint32 *minor,
10990 +                        gss_ctx_id_t ctx,
10991 +                        int *conf_state,
10992 +                        gss_qop_t *qop_state,
10993 +                        gss_iov_buffer_desc *iov,
10994 +                        int iov_count,
10995 +                        enum gss_eap_token_type toktype)
10996 +{
10997 +    OM_uint32 major;
10998 +
10999 +    if (ctx->encryptionType == ENCTYPE_NULL) {
11000 +        *minor = GSSEAP_KEY_UNAVAILABLE;
11001 +        return GSS_S_UNAVAILABLE;
11002 +    }
11003 +
11004 +    if (gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_STREAM) != NULL) {
11005 +        major = unwrapStream(minor, ctx, conf_state, qop_state,
11006 +                             iov, iov_count, toktype);
11007 +    } else {
11008 +        major = unwrapToken(minor, ctx,
11009 +                            NULL, /* krbCrypto */
11010 +                            conf_state, qop_state,
11011 +                            iov, iov_count, toktype);
11012 +    }
11013 +
11014 +    return major;
11015 +}
11016 +
11017 +OM_uint32 GSSAPI_CALLCONV
11018 +gss_unwrap_iov(OM_uint32 *minor,
11019 +               gss_ctx_id_t ctx,
11020 +               int *conf_state,
11021 +               gss_qop_t *qop_state,
11022 +               gss_iov_buffer_desc *iov,
11023 +               int iov_count)
11024 +{
11025 +    OM_uint32 major;
11026 +
11027 +    if (ctx == GSS_C_NO_CONTEXT) {
11028 +        *minor = EINVAL;
11029 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
11030 +    }
11031 +
11032 +    *minor = 0;
11033 +
11034 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
11035 +
11036 +    if (!CTX_IS_ESTABLISHED(ctx)) {
11037 +        major = GSS_S_NO_CONTEXT;
11038 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
11039 +        goto cleanup;
11040 +    }
11041 +
11042 +    major = gssEapUnwrapOrVerifyMIC(minor, ctx, conf_state, qop_state,
11043 +                                    iov, iov_count, TOK_TYPE_WRAP);
11044 +    if (GSS_ERROR(major))
11045 +        goto cleanup;
11046 +
11047 +cleanup:
11048 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
11049 +
11050 +    return major;
11051 +}
11052 diff --git a/mech_eap/util.h b/mech_eap/util.h
11053 new file mode 100644
11054 index 0000000..4f54d41
11055 --- /dev/null
11056 +++ b/mech_eap/util.h
11057 @@ -0,0 +1,1032 @@
11058 +/*
11059 + * Copyright (c) 2011, JANET(UK)
11060 + * All rights reserved.
11061 + *
11062 + * Redistribution and use in source and binary forms, with or without
11063 + * modification, are permitted provided that the following conditions
11064 + * are met:
11065 + *
11066 + * 1. Redistributions of source code must retain the above copyright
11067 + *    notice, this list of conditions and the following disclaimer.
11068 + *
11069 + * 2. Redistributions in binary form must reproduce the above copyright
11070 + *    notice, this list of conditions and the following disclaimer in the
11071 + *    documentation and/or other materials provided with the distribution.
11072 + *
11073 + * 3. Neither the name of JANET(UK) nor the names of its contributors
11074 + *    may be used to endorse or promote products derived from this software
11075 + *    without specific prior written permission.
11076 + *
11077 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
11078 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
11079 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
11080 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
11081 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
11082 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
11083 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
11084 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
11085 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
11086 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
11087 + * SUCH DAMAGE.
11088 + */
11089 +/*
11090 + * Portions Copyright 2003-2010 Massachusetts Institute of Technology.
11091 + * All Rights Reserved.
11092 + *
11093 + * Export of this software from the United States of America may
11094 + *   require a specific license from the United States Government.
11095 + *   It is the responsibility of any person or organization contemplating
11096 + *   export to obtain such a license before exporting.
11097 + *
11098 + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
11099 + * distribute this software and its documentation for any purpose and
11100 + * without fee is hereby granted, provided that the above copyright
11101 + * notice appear in all copies and that both that copyright notice and
11102 + * this permission notice appear in supporting documentation, and that
11103 + * the name of M.I.T. not be used in advertising or publicity pertaining
11104 + * to distribution of the software without specific, written prior
11105 + * permission.  Furthermore if you modify this software you must label
11106 + * your software as modified software and not distribute it in such a
11107 + * fashion that it might be confused with the original M.I.T. software.
11108 + * M.I.T. makes no representations about the suitability of
11109 + * this software for any purpose.  It is provided "as is" without express
11110 + * or implied warranty.
11111 + *
11112 + */
11113 +
11114 +/*
11115 + * Utility functions.
11116 + */
11117 +
11118 +#ifndef _UTIL_H_
11119 +#define _UTIL_H_ 1
11120 +
11121 +#ifdef HAVE_SYS_PARAM_H
11122 +#include <sys/param.h>
11123 +#endif
11124 +#ifdef HAVE_STDINT_H
11125 +#include <stdint.h>
11126 +#endif
11127 +#include <string.h>
11128 +#include <errno.h>
11129 +
11130 +#include <krb5.h>
11131 +
11132 +#ifdef WIN32
11133 +#define inline __inline
11134 +#define snprintf _snprintf
11135 +#endif
11136 +
11137 +#ifdef __cplusplus
11138 +extern "C" {
11139 +#endif
11140 +
11141 +#ifndef MIN
11142 +#define MIN(_a,_b)  ((_a)<(_b)?(_a):(_b))
11143 +#endif
11144 +
11145 +#if !defined(WIN32) && !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
11146 +#define GSSEAP_UNUSED __attribute__ ((__unused__))
11147 +#else
11148 +#define GSSEAP_UNUSED
11149 +#endif
11150 +
11151 +/* util_buffer.c */
11152 +OM_uint32
11153 +makeStringBuffer(OM_uint32 *minor,
11154 +                 const char *string,
11155 +                 gss_buffer_t buffer);
11156 +
11157 +#define makeStringBufferOrCleanup(src, dst)             \
11158 +    do {                                                \
11159 +        major = makeStringBuffer((minor), (src), (dst));\
11160 +        if (GSS_ERROR(major))                           \
11161 +            goto cleanup;                               \
11162 +    } while (0)
11163 +
11164 +OM_uint32
11165 +bufferToString(OM_uint32 *minor,
11166 +               const gss_buffer_t buffer,
11167 +               char **pString);
11168 +
11169 +OM_uint32
11170 +duplicateBuffer(OM_uint32 *minor,
11171 +                const gss_buffer_t src,
11172 +                gss_buffer_t dst);
11173 +
11174 +#define duplicateBufferOrCleanup(src, dst)              \
11175 +    do {                                                \
11176 +        major = duplicateBuffer((minor), (src), (dst)); \
11177 +        if (GSS_ERROR(major))                           \
11178 +            goto cleanup;                               \
11179 +    } while (0)
11180 +
11181 +static inline int
11182 +bufferEqual(const gss_buffer_t b1, const gss_buffer_t b2)
11183 +{
11184 +    return (b1->length == b2->length &&
11185 +            memcmp(b1->value, b2->value, b2->length) == 0);
11186 +}
11187 +
11188 +static inline int
11189 +bufferEqualString(const gss_buffer_t b1, const char *s)
11190 +{
11191 +    gss_buffer_desc b2;
11192 +
11193 +    b2.length = strlen(s);
11194 +    b2.value = (char *)s;
11195 +
11196 +    return bufferEqual(b1, &b2);
11197 +}
11198 +
11199 +/* util_cksum.c */
11200 +int
11201 +gssEapSign(krb5_context context,
11202 +           krb5_cksumtype type,
11203 +           size_t rrc,
11204 +#ifdef HAVE_HEIMDAL_VERSION
11205 +           krb5_crypto crypto,
11206 +#else
11207 +           krb5_keyblock *key,
11208 +#endif
11209 +           krb5_keyusage sign_usage,
11210 +           gss_iov_buffer_desc *iov,
11211 +           int iov_count);
11212 +
11213 +int
11214 +gssEapVerify(krb5_context context,
11215 +             krb5_cksumtype type,
11216 +             size_t rrc,
11217 +#ifdef HAVE_HEIMDAL_VERSION
11218 +             krb5_crypto crypto,
11219 +#else
11220 +             krb5_keyblock *key,
11221 +#endif
11222 +             krb5_keyusage sign_usage,
11223 +             gss_iov_buffer_desc *iov,
11224 +             int iov_count,
11225 +             int *valid);
11226 +
11227 +#if 0
11228 +OM_uint32
11229 +gssEapEncodeGssChannelBindings(OM_uint32 *minor,
11230 +                               gss_channel_bindings_t chanBindings,
11231 +                               gss_buffer_t encodedBindings);
11232 +#endif
11233 +
11234 +/* util_context.c */
11235 +#define EAP_EXPORT_CONTEXT_V1           1
11236 +
11237 +enum gss_eap_token_type {
11238 +    TOK_TYPE_NONE                    = 0x0000,  /* no token */
11239 +    TOK_TYPE_MIC                     = 0x0404,  /* RFC 4121 MIC token */
11240 +    TOK_TYPE_WRAP                    = 0x0504,  /* RFC 4121 wrap token */
11241 +    TOK_TYPE_EXPORT_NAME             = 0x0401,  /* RFC 2743 exported name */
11242 +    TOK_TYPE_EXPORT_NAME_COMPOSITE   = 0x0402,  /* exported composite name */
11243 +    TOK_TYPE_DELETE_CONTEXT          = 0x0405,  /* RFC 2743 delete context */
11244 +    TOK_TYPE_INITIATOR_CONTEXT       = 0x0601,  /* initiator-sent context token */
11245 +    TOK_TYPE_ACCEPTOR_CONTEXT        = 0x0602,  /* acceptor-sent context token */
11246 +};
11247 +
11248 +/* inner token types and flags */
11249 +#define ITOK_TYPE_NONE                  0x00000000
11250 +#define ITOK_TYPE_CONTEXT_ERR           0x00000001 /* critical */
11251 +#define ITOK_TYPE_ACCEPTOR_NAME_REQ     0x00000002 /* TBD */
11252 +#define ITOK_TYPE_ACCEPTOR_NAME_RESP    0x00000003 /* TBD */
11253 +#define ITOK_TYPE_EAP_RESP              0x00000004 /* critical, required, if not reauth */
11254 +#define ITOK_TYPE_EAP_REQ               0x00000005 /* critical, required, if not reauth */
11255 +#define ITOK_TYPE_GSS_CHANNEL_BINDINGS  0x00000006 /* critical, required, if not reauth */
11256 +#define ITOK_TYPE_REAUTH_CREDS          0x00000007 /* optional */
11257 +#define ITOK_TYPE_REAUTH_REQ            0x00000008 /* optional */
11258 +#define ITOK_TYPE_REAUTH_RESP           0x00000009 /* optional */
11259 +#define ITOK_TYPE_VERSION_INFO          0x0000000A /* optional */
11260 +#define ITOK_TYPE_VENDOR_INFO           0x0000000B /* optional */
11261 +#define ITOK_TYPE_GSS_FLAGS             0x0000000C /* optional */
11262 +#define ITOK_TYPE_INITIATOR_MIC         0x0000000D /* critical, required, if not reauth */
11263 +#define ITOK_TYPE_ACCEPTOR_MIC          0x0000000E /* TBD */
11264 +
11265 +#define ITOK_FLAG_CRITICAL              0x80000000  /* critical, wire flag */
11266 +#define ITOK_FLAG_VERIFIED              0x40000000  /* verified, API flag */
11267 +
11268 +#define ITOK_TYPE_MASK                  (~(ITOK_FLAG_CRITICAL | ITOK_FLAG_VERIFIED))
11269 +
11270 +#define GSSEAP_WIRE_FLAGS_MASK          ( GSS_C_MUTUAL_FLAG             | \
11271 +                                          GSS_C_DCE_STYLE               | \
11272 +                                          GSS_C_IDENTIFY_FLAG           | \
11273 +                                          GSS_C_EXTENDED_ERROR_FLAG       )
11274 +
11275 +OM_uint32 gssEapAllocContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
11276 +OM_uint32 gssEapReleaseContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
11277 +
11278 +OM_uint32
11279 +gssEapMakeToken(OM_uint32 *minor,
11280 +                gss_ctx_id_t ctx,
11281 +                const gss_buffer_t innerToken,
11282 +                enum gss_eap_token_type tokenType,
11283 +                gss_buffer_t outputToken);
11284 +
11285 +OM_uint32
11286 +gssEapVerifyToken(OM_uint32 *minor,
11287 +                  gss_ctx_id_t ctx,
11288 +                  const gss_buffer_t inputToken,
11289 +                  enum gss_eap_token_type *tokenType,
11290 +                  gss_buffer_t innerInputToken);
11291 +
11292 +OM_uint32
11293 +gssEapContextTime(OM_uint32 *minor,
11294 +                  gss_ctx_id_t context_handle,
11295 +                  OM_uint32 *time_rec);
11296 +
11297 +OM_uint32
11298 +gssEapMakeTokenMIC(OM_uint32 *minor,
11299 +                   gss_ctx_id_t ctx,
11300 +                   gss_buffer_t tokenMIC);
11301 +
11302 +OM_uint32
11303 +gssEapVerifyTokenMIC(OM_uint32 *minor,
11304 +                     gss_ctx_id_t ctx,
11305 +                     const gss_buffer_t tokenMIC);
11306 +
11307 +/* util_cred.c */
11308 +OM_uint32 gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred);
11309 +OM_uint32 gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred);
11310 +
11311 +gss_OID
11312 +gssEapPrimaryMechForCred(gss_cred_id_t cred);
11313 +
11314 +OM_uint32
11315 +gssEapAcquireCred(OM_uint32 *minor,
11316 +                  const gss_name_t desiredName,
11317 +                  OM_uint32 timeReq,
11318 +                  const gss_OID_set desiredMechs,
11319 +                  int cred_usage,
11320 +                  gss_cred_id_t *pCred,
11321 +                  gss_OID_set *pActualMechs,
11322 +                  OM_uint32 *timeRec);
11323 +
11324 +OM_uint32
11325 +gssEapSetCredPassword(OM_uint32 *minor,
11326 +                      gss_cred_id_t cred,
11327 +                      const gss_buffer_t password);
11328 +
11329 +OM_uint32
11330 +gssEapSetCredService(OM_uint32 *minor,
11331 +                     gss_cred_id_t cred,
11332 +                     const gss_name_t target);
11333 +
11334 +OM_uint32
11335 +gssEapResolveInitiatorCred(OM_uint32 *minor,
11336 +                           const gss_cred_id_t cred,
11337 +                           const gss_name_t target,
11338 +                           gss_cred_id_t *resolvedCred);
11339 +
11340 +int gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech);
11341 +
11342 +OM_uint32
11343 +gssEapInquireCred(OM_uint32 *minor,
11344 +                  gss_cred_id_t cred,
11345 +                  gss_name_t *name,
11346 +                  OM_uint32 *pLifetime,
11347 +                  gss_cred_usage_t *cred_usage,
11348 +                  gss_OID_set *mechanisms);
11349 +
11350 +/* util_crypt.c */
11351 +int
11352 +gssEapEncrypt(krb5_context context, int dce_style, size_t ec,
11353 +              size_t rrc,
11354 +#ifdef HAVE_HEIMDAL_VERSION
11355 +              krb5_crypto crypto,
11356 +#else
11357 +              krb5_keyblock *key,
11358 +#endif
11359 +              int usage,
11360 +              gss_iov_buffer_desc *iov, int iov_count);
11361 +
11362 +int
11363 +gssEapDecrypt(krb5_context context, int dce_style, size_t ec,
11364 +              size_t rrc,
11365 +#ifdef HAVE_HEIMDAL_VERSION
11366 +              krb5_crypto crypto,
11367 +#else
11368 +              krb5_keyblock *key,
11369 +#endif
11370 +              int usage,
11371 +              gss_iov_buffer_desc *iov, int iov_count);
11372 +
11373 +int
11374 +gssEapMapCryptoFlag(OM_uint32 type);
11375 +
11376 +gss_iov_buffer_t
11377 +gssEapLocateIov(gss_iov_buffer_desc *iov,
11378 +                int iov_count,
11379 +                OM_uint32 type);
11380 +
11381 +void
11382 +gssEapIovMessageLength(gss_iov_buffer_desc *iov,
11383 +                       int iov_count,
11384 +                       size_t *data_length,
11385 +                       size_t *assoc_data_length);
11386 +
11387 +void
11388 +gssEapReleaseIov(gss_iov_buffer_desc *iov, int iov_count);
11389 +
11390 +int
11391 +gssEapIsIntegrityOnly(gss_iov_buffer_desc *iov, int iov_count);
11392 +
11393 +int
11394 +gssEapAllocIov(gss_iov_buffer_t iov, size_t size);
11395 +
11396 +OM_uint32
11397 +gssEapDeriveRfc3961Key(OM_uint32 *minor,
11398 +                       const unsigned char *key,
11399 +                       size_t keyLength,
11400 +                       krb5_enctype enctype,
11401 +                       krb5_keyblock *pKey);
11402 +
11403 +/* util_krb.c */
11404 +
11405 +#ifndef KRB_MALLOC
11406 +/*
11407 + * If your Kerberos library uses a different allocator to your
11408 + * GSS mechanism glue, then you might wish to define these in
11409 + * config.h or elsewhere. This should eventually go away when
11410 + * we no longer need to allocate memory that is freed by the
11411 + * Kerberos library.
11412 + */
11413 +#define KRB_CALLOC                      calloc
11414 +#define KRB_MALLOC                      malloc
11415 +#define KRB_FREE                        free
11416 +#define KRB_REALLOC                     realloc
11417 +#endif /* KRB_MALLOC */
11418 +
11419 +#ifdef HAVE_HEIMDAL_VERSION
11420 +
11421 +#define KRB_TIME_FOREVER        ((time_t)~0L)
11422 +
11423 +#define KRB_KEY_TYPE(key)       ((key)->keytype)
11424 +#define KRB_KEY_DATA(key)       ((key)->keyvalue.data)
11425 +#define KRB_KEY_LENGTH(key)     ((key)->keyvalue.length)
11426 +
11427 +#define KRB_PRINC_LENGTH(princ) ((princ)->name.name_string.len)
11428 +#define KRB_PRINC_TYPE(princ)   ((princ)->name.name_type)
11429 +#define KRB_PRINC_NAME(princ)   ((princ)->name.name_string.val)
11430 +#define KRB_PRINC_REALM(princ)  ((princ)->realm)
11431 +
11432 +#define KRB_KT_ENT_KEYBLOCK(e)  (&(e)->keyblock)
11433 +#define KRB_KT_ENT_FREE(c, e)   krb5_kt_free_entry((c), (e))
11434 +
11435 +#define KRB_CRYPTO_CONTEXT(ctx) (krbCrypto)
11436 +
11437 +#define KRB_DATA_INIT(d)        krb5_data_zero((d))
11438 +
11439 +#else
11440 +
11441 +#define KRB_TIME_FOREVER        KRB5_INT32_MAX
11442 +
11443 +#define KRB_KEY_TYPE(key)       ((key)->enctype)
11444 +#define KRB_KEY_DATA(key)       ((key)->contents)
11445 +#define KRB_KEY_LENGTH(key)     ((key)->length)
11446 +
11447 +#define KRB_PRINC_LENGTH(princ) (krb5_princ_size(NULL, (princ)))
11448 +#define KRB_PRINC_TYPE(princ)   (krb5_princ_type(NULL, (princ)))
11449 +#define KRB_PRINC_NAME(princ)   (krb5_princ_name(NULL, (princ)))
11450 +#define KRB_PRINC_REALM(princ)  (krb5_princ_realm(NULL, (princ)))
11451 +
11452 +#define KRB_KT_ENT_KEYBLOCK(e)  (&(e)->key)
11453 +#define KRB_KT_ENT_FREE(c, e)   krb5_free_keytab_entry_contents((c), (e))
11454 +
11455 +#define KRB_CRYPTO_CONTEXT(ctx) (&(ctx)->rfc3961Key)
11456 +
11457 +#define KRB_DATA_INIT(d)        do {        \
11458 +        (d)->magic = KV5M_DATA;             \
11459 +        (d)->length = 0;                    \
11460 +        (d)->data = NULL;                   \
11461 +    } while (0)
11462 +
11463 +#endif /* HAVE_HEIMDAL_VERSION */
11464 +
11465 +#define KRB_KEY_INIT(key)       do {        \
11466 +        KRB_KEY_TYPE(key) = ENCTYPE_NULL;   \
11467 +        KRB_KEY_DATA(key) = NULL;           \
11468 +        KRB_KEY_LENGTH(key) = 0;            \
11469 +    } while (0)
11470 +
11471 +#define GSSEAP_KRB_INIT(ctx) do {                   \
11472 +        OM_uint32 tmpMajor;                         \
11473 +                                                    \
11474 +        tmpMajor  = gssEapKerberosInit(minor, ctx); \
11475 +        if (GSS_ERROR(tmpMajor)) {                  \
11476 +            return tmpMajor;                        \
11477 +        }                                           \
11478 +    } while (0)
11479 +
11480 +OM_uint32
11481 +gssEapKerberosInit(OM_uint32 *minor, krb5_context *context);
11482 +
11483 +OM_uint32
11484 +rfc3961ChecksumTypeForKey(OM_uint32 *minor,
11485 +                          krb5_keyblock *key,
11486 +                          krb5_cksumtype *cksumtype);
11487 +
11488 +krb5_error_code
11489 +krbCryptoLength(krb5_context krbContext,
11490 +#ifdef HAVE_HEIMDAL_VERSION
11491 +                krb5_crypto krbCrypto,
11492 +#else
11493 +                krb5_keyblock *key,
11494 +#endif
11495 +                int type,
11496 +                size_t *length);
11497 +
11498 +krb5_error_code
11499 +krbPaddingLength(krb5_context krbContext,
11500 +#ifdef HAVE_HEIMDAL_VERSION
11501 +                 krb5_crypto krbCrypto,
11502 +#else
11503 +                 krb5_keyblock *key,
11504 +#endif
11505 +                 size_t dataLength,
11506 +                 size_t *padLength);
11507 +
11508 +krb5_error_code
11509 +krbBlockSize(krb5_context krbContext,
11510 +#ifdef HAVE_HEIMDAL_VERSION
11511 +                 krb5_crypto krbCrypto,
11512 +#else
11513 +                 krb5_keyblock *key,
11514 +#endif
11515 +                 size_t *blockSize);
11516 +
11517 +krb5_error_code
11518 +krbEnctypeToString(krb5_context krbContext,
11519 +                   krb5_enctype enctype,
11520 +                   const char *prefix,
11521 +                   gss_buffer_t string);
11522 +
11523 +krb5_error_code
11524 +krbMakeAuthDataKdcIssued(krb5_context context,
11525 +                         const krb5_keyblock *key,
11526 +                         krb5_const_principal issuer,
11527 +#ifdef HAVE_HEIMDAL_VERSION
11528 +                         const AuthorizationData *authdata,
11529 +                         AuthorizationData *adKdcIssued
11530 +#else
11531 +                         krb5_authdata *const *authdata,
11532 +                         krb5_authdata ***adKdcIssued
11533 +#endif
11534 +                         );
11535 +
11536 +krb5_error_code
11537 +krbMakeCred(krb5_context context,
11538 +            krb5_auth_context authcontext,
11539 +            krb5_creds *creds,
11540 +            krb5_data *data);
11541 +
11542 +/* util_lucid.c */
11543 +OM_uint32
11544 +gssEapExportLucidSecContext(OM_uint32 *minor,
11545 +                            gss_ctx_id_t ctx,
11546 +                            const gss_OID desiredObject,
11547 +                            gss_buffer_set_t *data_set);
11548 +
11549 +/* util_mech.c */
11550 +extern gss_OID GSS_EAP_MECHANISM;
11551 +
11552 +#define OID_FLAG_NULL_VALID                 0x00000001
11553 +#define OID_FLAG_FAMILY_MECH_VALID          0x00000002
11554 +#define OID_FLAG_MAP_NULL_TO_DEFAULT_MECH   0x00000004
11555 +#define OID_FLAG_MAP_FAMILY_MECH_TO_NULL    0x00000008
11556 +
11557 +OM_uint32
11558 +gssEapCanonicalizeOid(OM_uint32 *minor,
11559 +                      const gss_OID oid,
11560 +                      OM_uint32 flags,
11561 +                      gss_OID *pOid);
11562 +
11563 +OM_uint32
11564 +gssEapReleaseOid(OM_uint32 *minor, gss_OID *oid);
11565 +
11566 +OM_uint32
11567 +gssEapDefaultMech(OM_uint32 *minor,
11568 +                  gss_OID *oid);
11569 +
11570 +OM_uint32
11571 +gssEapIndicateMechs(OM_uint32 *minor,
11572 +                    gss_OID_set *mechs);
11573 +
11574 +OM_uint32
11575 +gssEapEnctypeToOid(OM_uint32 *minor,
11576 +                   krb5_enctype enctype,
11577 +                   gss_OID *pOid);
11578 +
11579 +OM_uint32
11580 +gssEapOidToEnctype(OM_uint32 *minor,
11581 +                   const gss_OID oid,
11582 +                   krb5_enctype *enctype);
11583 +
11584 +int
11585 +gssEapIsMechanismOid(const gss_OID oid);
11586 +
11587 +int
11588 +gssEapIsConcreteMechanismOid(const gss_OID oid);
11589 +
11590 +OM_uint32
11591 +gssEapValidateMechs(OM_uint32 *minor,
11592 +                   const gss_OID_set mechs);
11593 +
11594 +gss_buffer_t
11595 +gssEapOidToSaslName(const gss_OID oid);
11596 +
11597 +gss_OID
11598 +gssEapSaslNameToOid(const gss_buffer_t name);
11599 +
11600 +/* util_moonshot.c */
11601 +OM_uint32
11602 +libMoonshotResolveDefaultIdentity(OM_uint32 *minor,
11603 +                                  const gss_cred_id_t cred,
11604 +                                  gss_name_t *pName);
11605 +
11606 +OM_uint32
11607 +libMoonshotResolveInitiatorCred(OM_uint32 *minor,
11608 +                                gss_cred_id_t cred,
11609 +                                const gss_name_t targetName);
11610 +
11611 +/* util_name.c */
11612 +#define EXPORT_NAME_FLAG_OID                    0x1
11613 +#define EXPORT_NAME_FLAG_COMPOSITE              0x2
11614 +#define EXPORT_NAME_FLAG_ALLOW_COMPOSITE        0x4
11615 +
11616 +OM_uint32 gssEapAllocName(OM_uint32 *minor, gss_name_t *pName);
11617 +OM_uint32 gssEapReleaseName(OM_uint32 *minor, gss_name_t *pName);
11618 +OM_uint32 gssEapExportName(OM_uint32 *minor,
11619 +                           const gss_name_t name,
11620 +                           gss_buffer_t exportedName);
11621 +OM_uint32 gssEapExportNameInternal(OM_uint32 *minor,
11622 +                                   const gss_name_t name,
11623 +                                   gss_buffer_t exportedName,
11624 +                                   OM_uint32 flags);
11625 +OM_uint32 gssEapImportName(OM_uint32 *minor,
11626 +                           const gss_buffer_t input_name_buffer,
11627 +                           const gss_OID input_name_type,
11628 +                           const gss_OID input_mech_type,
11629 +                           gss_name_t *output_name);
11630 +OM_uint32 gssEapImportNameInternal(OM_uint32 *minor,
11631 +                                   const gss_buffer_t input_name_buffer,
11632 +                                   gss_name_t *output_name,
11633 +                                   OM_uint32 flags);
11634 +OM_uint32
11635 +gssEapDuplicateName(OM_uint32 *minor,
11636 +                    const gss_name_t input_name,
11637 +                    gss_name_t *dest_name);
11638 +
11639 +OM_uint32
11640 +gssEapCanonicalizeName(OM_uint32 *minor,
11641 +                       const gss_name_t input_name,
11642 +                       const gss_OID mech_type,
11643 +                       gss_name_t *dest_name);
11644 +
11645 +OM_uint32
11646 +gssEapDisplayName(OM_uint32 *minor,
11647 +                  gss_name_t name,
11648 +                  gss_buffer_t output_name_buffer,
11649 +                  gss_OID *output_name_type);
11650 +
11651 +OM_uint32
11652 +gssEapCompareName(OM_uint32 *minor,
11653 +                  gss_name_t name1,
11654 +                  gss_name_t name2,
11655 +                  int *name_equal);
11656 +
11657 +/* util_oid.c */
11658 +OM_uint32
11659 +composeOid(OM_uint32 *minor_status,
11660 +           const char *prefix,
11661 +           size_t prefix_len,
11662 +           int suffix,
11663 +           gss_OID_desc *oid);
11664 +
11665 +OM_uint32
11666 +decomposeOid(OM_uint32 *minor_status,
11667 +             const char *prefix,
11668 +             size_t prefix_len,
11669 +             gss_OID_desc *oid,
11670 +             int *suffix) ;
11671 +
11672 +OM_uint32
11673 +duplicateOid(OM_uint32 *minor_status,
11674 +             const gss_OID_desc * const oid,
11675 +             gss_OID *new_oid);
11676 +
11677 +OM_uint32
11678 +duplicateOidSet(OM_uint32 *minor,
11679 +                const gss_OID_set src,
11680 +                gss_OID_set *dst);
11681 +
11682 +static inline int
11683 +oidEqual(const gss_OID_desc *o1, const gss_OID_desc *o2)
11684 +{
11685 +    if (o1 == GSS_C_NO_OID)
11686 +        return (o2 == GSS_C_NO_OID);
11687 +    else if (o2 == GSS_C_NO_OID)
11688 +        return (o1 == GSS_C_NO_OID);
11689 +    else
11690 +        return (o1->length == o2->length &&
11691 +                memcmp(o1->elements, o2->elements, o1->length) == 0);
11692 +}
11693 +
11694 +/* util_ordering.c */
11695 +OM_uint32
11696 +sequenceInternalize(OM_uint32 *minor,
11697 +                    void **vqueue,
11698 +                    unsigned char **buf,
11699 +                    size_t *lenremain);
11700 +
11701 +OM_uint32
11702 +sequenceExternalize(OM_uint32 *minor,
11703 +                    void *vqueue,
11704 +                    unsigned char **buf,
11705 +                    size_t *lenremain);
11706 +
11707 +size_t
11708 +sequenceSize(void *vqueue);
11709 +
11710 +OM_uint32
11711 +sequenceFree(OM_uint32 *minor, void **vqueue);
11712 +
11713 +OM_uint32
11714 +sequenceCheck(OM_uint32 *minor, void **vqueue, uint64_t seqnum);
11715 +
11716 +OM_uint32
11717 +sequenceInit(OM_uint32 *minor, void **vqueue, uint64_t seqnum,
11718 +             int do_replay, int do_sequence, int wide_nums);
11719 +
11720 +/* util_sm.c */
11721 +enum gss_eap_state {
11722 +    GSSEAP_STATE_INITIAL        = 0x01,     /* initial state */
11723 +    GSSEAP_STATE_AUTHENTICATE   = 0x02,     /* exchange EAP messages */
11724 +    GSSEAP_STATE_INITIATOR_EXTS = 0x04,     /* initiator extensions */
11725 +    GSSEAP_STATE_ACCEPTOR_EXTS  = 0x08,     /* acceptor extensions */
11726 +#ifdef GSSEAP_ENABLE_REAUTH
11727 +    GSSEAP_STATE_REAUTHENTICATE = 0x10,     /* GSS reauthentication messages */
11728 +#endif
11729 +    GSSEAP_STATE_ESTABLISHED    = 0x20,     /* context established */
11730 +    GSSEAP_STATE_ALL            = 0x3F
11731 +};
11732 +
11733 +#define GSSEAP_STATE_NEXT(s)    ((s) << 1)
11734 +
11735 +#define GSSEAP_SM_STATE(ctx)                ((ctx)->state)
11736 +
11737 +#ifdef GSSEAP_DEBUG
11738 +void gssEapSmTransition(gss_ctx_id_t ctx, enum gss_eap_state state);
11739 +#define GSSEAP_SM_TRANSITION(ctx, state)    gssEapSmTransition((ctx), (state))
11740 +#else
11741 +#define GSSEAP_SM_TRANSITION(ctx, newstate)    do { (ctx)->state = (newstate); } while (0)
11742 +#endif
11743 +
11744 +#define GSSEAP_SM_TRANSITION_NEXT(ctx)      GSSEAP_SM_TRANSITION((ctx), GSSEAP_STATE_NEXT(GSSEAP_SM_STATE((ctx))))
11745 +
11746 +/* state machine entry */
11747 +struct gss_eap_sm {
11748 +    OM_uint32 inputTokenType;
11749 +    OM_uint32 outputTokenType;
11750 +    enum gss_eap_state validStates;
11751 +    OM_uint32 itokFlags;
11752 +    OM_uint32 (*processToken)(OM_uint32 *,
11753 +                              gss_cred_id_t,
11754 +                              gss_ctx_id_t,
11755 +                              gss_name_t,
11756 +                              gss_OID,
11757 +                              OM_uint32,
11758 +                              OM_uint32,
11759 +                              gss_channel_bindings_t,
11760 +                              gss_buffer_t,
11761 +                              gss_buffer_t,
11762 +                              OM_uint32 *);
11763 +};
11764 +
11765 +/* state machine flags, set by handler */
11766 +#define SM_FLAG_FORCE_SEND_TOKEN            0x00000001  /* send token even if no inner tokens */
11767 +#define SM_FLAG_OUTPUT_TOKEN_CRITICAL       0x00000002  /* output token is critical */
11768 +
11769 +/* state machine flags, set by state machine */
11770 +#define SM_FLAG_INPUT_TOKEN_CRITICAL        0x10000000  /* input token was critical */
11771 +
11772 +#define SM_ITOK_FLAG_REQUIRED               0x00000001  /* received tokens must be present */
11773 +
11774 +OM_uint32
11775 +gssEapSmStep(OM_uint32 *minor,
11776 +             gss_cred_id_t cred,
11777 +             gss_ctx_id_t ctx,
11778 +             gss_name_t target,
11779 +             gss_OID mech,
11780 +             OM_uint32 reqFlags,
11781 +             OM_uint32 timeReq,
11782 +             gss_channel_bindings_t chanBindings,
11783 +             gss_buffer_t inputToken,
11784 +             gss_buffer_t outputToken,
11785 +             struct gss_eap_sm *sm,
11786 +             size_t smCount);
11787 +
11788 +void
11789 +gssEapSmTransition(gss_ctx_id_t ctx, enum gss_eap_state state);
11790 +
11791 +/* util_token.c */
11792 +struct gss_eap_token_buffer_set {
11793 +    gss_buffer_set_desc buffers; /* pointers only */
11794 +    OM_uint32 *types;
11795 +};
11796 +
11797 +OM_uint32
11798 +gssEapEncodeInnerTokens(OM_uint32 *minor,
11799 +                        struct gss_eap_token_buffer_set *tokens,
11800 +                        gss_buffer_t buffer);
11801 +OM_uint32
11802 +gssEapDecodeInnerTokens(OM_uint32 *minor,
11803 +                        const gss_buffer_t buffer,
11804 +                        struct gss_eap_token_buffer_set *tokens);
11805 +
11806 +OM_uint32
11807 +gssEapReleaseInnerTokens(OM_uint32 *minor,
11808 +                         struct gss_eap_token_buffer_set *tokens,
11809 +                         int freeBuffers);
11810 +
11811 +OM_uint32
11812 +gssEapAllocInnerTokens(OM_uint32 *minor,
11813 +                       size_t count,
11814 +                       struct gss_eap_token_buffer_set *tokens);
11815 +
11816 +size_t
11817 +tokenSize(const gss_OID_desc *mech, size_t body_size);
11818 +
11819 +void
11820 +makeTokenHeader(const gss_OID_desc *mech,
11821 +                size_t body_size,
11822 +                unsigned char **buf,
11823 +                enum gss_eap_token_type tok_type);
11824 +
11825 +OM_uint32
11826 +verifyTokenHeader(OM_uint32 *minor,
11827 +                  gss_OID mech,
11828 +                  size_t *body_size,
11829 +                  unsigned char **buf_in,
11830 +                  size_t toksize_in,
11831 +                  enum gss_eap_token_type *ret_tok_type);
11832 +
11833 +/* Helper macros */
11834 +
11835 +#ifndef GSSEAP_MALLOC
11836 +#define GSSEAP_CALLOC                   calloc
11837 +#define GSSEAP_MALLOC                   malloc
11838 +#define GSSEAP_FREE                     free
11839 +#define GSSEAP_REALLOC                  realloc
11840 +#endif
11841 +
11842 +#ifndef GSSAPI_CALLCONV
11843 +#define GSSAPI_CALLCONV                 KRB5_CALLCONV
11844 +#endif
11845 +
11846 +#ifndef GSSEAP_ASSERT
11847 +#include <assert.h>
11848 +#define GSSEAP_ASSERT(x)                assert((x))
11849 +#endif /* !GSSEAP_ASSERT */
11850 +
11851 +#ifdef WIN32
11852 +#define GSSEAP_CONSTRUCTOR
11853 +#define GSSEAP_DESTRUCTOR
11854 +#else
11855 +#define GSSEAP_CONSTRUCTOR              __attribute__((constructor))
11856 +#define GSSEAP_DESTRUCTOR               __attribute__((destructor))
11857 +#endif
11858 +
11859 +#define GSSEAP_NOT_IMPLEMENTED          do {            \
11860 +        GSSEAP_ASSERT(0 && "not implemented");          \
11861 +        *minor = ENOSYS;                                \
11862 +        return GSS_S_FAILURE;                           \
11863 +    } while (0)
11864 +
11865 +#ifdef WIN32
11866 +
11867 +#include <winbase.h>
11868 +
11869 +#define GSSEAP_GET_LAST_ERROR()         (GetLastError()) /* XXX FIXME */
11870 +
11871 +#define GSSEAP_MUTEX                    CRITICAL_SECTION
11872 +#define GSSEAP_MUTEX_INIT(m)            (InitializeCriticalSection((m)), 0)
11873 +#define GSSEAP_MUTEX_DESTROY(m)         DeleteCriticalSection((m))
11874 +#define GSSEAP_MUTEX_LOCK(m)            EnterCriticalSection((m))
11875 +#define GSSEAP_MUTEX_UNLOCK(m)          LeaveCriticalSection((m))
11876 +#define GSSEAP_ONCE_LEAVE              do { return TRUE; } while (0)
11877 +
11878 +/* Thread-local is handled separately */
11879 +
11880 +#define GSSEAP_THREAD_ONCE              INIT_ONCE
11881 +#define GSSEAP_ONCE_CALLBACK(cb)        BOOL CALLBACK cb(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
11882 +#define GSSEAP_ONCE(o, i)               InitOnceExecuteOnce((o), (i), NULL, NULL)
11883 +#define GSSEAP_ONCE_INITIALIZER         INIT_ONCE_STATIC_INIT
11884 +
11885 +#else
11886 +
11887 +#include <pthread.h>
11888 +
11889 +#define GSSEAP_GET_LAST_ERROR()         (errno)
11890 +
11891 +#define GSSEAP_MUTEX                    pthread_mutex_t
11892 +#define GSSEAP_MUTEX_INIT(m)            pthread_mutex_init((m), NULL)
11893 +#define GSSEAP_MUTEX_DESTROY(m)         pthread_mutex_destroy((m))
11894 +#define GSSEAP_MUTEX_LOCK(m)            pthread_mutex_lock((m))
11895 +#define GSSEAP_MUTEX_UNLOCK(m)          pthread_mutex_unlock((m))
11896 +
11897 +#define GSSEAP_THREAD_KEY               pthread_key_t
11898 +#define GSSEAP_KEY_CREATE(k, d)         pthread_key_create((k), (d))
11899 +#define GSSEAP_GETSPECIFIC(k)           pthread_getspecific((k))
11900 +#define GSSEAP_SETSPECIFIC(k, d)        pthread_setspecific((k), (d))
11901 +
11902 +#define GSSEAP_THREAD_ONCE              pthread_once_t
11903 +#define GSSEAP_ONCE_CALLBACK(cb)        void cb(void)
11904 +#define GSSEAP_ONCE(o, i)               pthread_once((o), (i))
11905 +#define GSSEAP_ONCE_INITIALIZER         PTHREAD_ONCE_INIT
11906 +#define GSSEAP_ONCE_LEAVE              do { } while (0)
11907 +
11908 +#endif /* WIN32 */
11909 +
11910 +/* Helper functions */
11911 +static inline void
11912 +store_uint16_be(uint16_t val, void *vp)
11913 +{
11914 +    unsigned char *p = (unsigned char *)vp;
11915 +
11916 +    p[0] = (val >>  8) & 0xff;
11917 +    p[1] = (val      ) & 0xff;
11918 +}
11919 +
11920 +static inline uint16_t
11921 +load_uint16_be(const void *cvp)
11922 +{
11923 +    const unsigned char *p = (const unsigned char *)cvp;
11924 +
11925 +    return (p[1] | (p[0] << 8));
11926 +}
11927 +
11928 +static inline void
11929 +store_uint32_be(uint32_t val, void *vp)
11930 +{
11931 +    unsigned char *p = (unsigned char *)vp;
11932 +
11933 +    p[0] = (val >> 24) & 0xff;
11934 +    p[1] = (val >> 16) & 0xff;
11935 +    p[2] = (val >>  8) & 0xff;
11936 +    p[3] = (val      ) & 0xff;
11937 +}
11938 +
11939 +static inline uint32_t
11940 +load_uint32_be(const void *cvp)
11941 +{
11942 +    const unsigned char *p = (const unsigned char *)cvp;
11943 +
11944 +    return (p[3] | (p[2] << 8)
11945 +            | ((uint32_t) p[1] << 16)
11946 +            | ((uint32_t) p[0] << 24));
11947 +}
11948 +
11949 +static inline void
11950 +store_uint64_be(uint64_t val, void *vp)
11951 +{
11952 +    unsigned char *p = (unsigned char *)vp;
11953 +
11954 +    p[0] = (unsigned char)((val >> 56) & 0xff);
11955 +    p[1] = (unsigned char)((val >> 48) & 0xff);
11956 +    p[2] = (unsigned char)((val >> 40) & 0xff);
11957 +    p[3] = (unsigned char)((val >> 32) & 0xff);
11958 +    p[4] = (unsigned char)((val >> 24) & 0xff);
11959 +    p[5] = (unsigned char)((val >> 16) & 0xff);
11960 +    p[6] = (unsigned char)((val >>  8) & 0xff);
11961 +    p[7] = (unsigned char)((val      ) & 0xff);
11962 +}
11963 +
11964 +static inline uint64_t
11965 +load_uint64_be(const void *cvp)
11966 +{
11967 +    const unsigned char *p = (const unsigned char *)cvp;
11968 +
11969 +    return ((uint64_t)load_uint32_be(p) << 32) | load_uint32_be(p + 4);
11970 +}
11971 +
11972 +static inline unsigned char *
11973 +store_buffer(gss_buffer_t buffer, void *vp, int wide_nums)
11974 +{
11975 +    unsigned char *p = (unsigned char *)vp;
11976 +
11977 +    if (wide_nums) {
11978 +        store_uint64_be(buffer->length, p);
11979 +        p += 8;
11980 +    } else {
11981 +        store_uint32_be(buffer->length, p);
11982 +        p += 4;
11983 +    }
11984 +
11985 +    if (buffer->value != NULL) {
11986 +        memcpy(p, buffer->value, buffer->length);
11987 +        p += buffer->length;
11988 +    }
11989 +
11990 +    return p;
11991 +}
11992 +
11993 +static inline unsigned char *
11994 +load_buffer(const void *cvp, size_t length, gss_buffer_t buffer)
11995 +{
11996 +    buffer->length = 0;
11997 +    buffer->value = GSSEAP_MALLOC(length);
11998 +    if (buffer->value == NULL)
11999 +        return NULL;
12000 +    buffer->length = length;
12001 +    memcpy(buffer->value, cvp, length);
12002 +    return (unsigned char *)cvp + length;
12003 +}
12004 +
12005 +static inline unsigned char *
12006 +store_oid(gss_OID oid, void *vp)
12007 +{
12008 +    gss_buffer_desc buf;
12009 +
12010 +    if (oid != GSS_C_NO_OID) {
12011 +        buf.length = oid->length;
12012 +        buf.value = oid->elements;
12013 +    } else {
12014 +        buf.length = 0;
12015 +        buf.value = NULL;
12016 +    }
12017 +
12018 +    return store_buffer(&buf, vp, FALSE);
12019 +}
12020 +
12021 +static inline void
12022 +krbDataToGssBuffer(krb5_data *data, gss_buffer_t buffer)
12023 +{
12024 +    buffer->value = (void *)data->data;
12025 +    buffer->length = data->length;
12026 +}
12027 +
12028 +static inline void
12029 +krbPrincComponentToGssBuffer(krb5_principal krbPrinc,
12030 +                             int index, gss_buffer_t buffer)
12031 +{
12032 +#ifdef HAVE_HEIMDAL_VERSION
12033 +    buffer->value = (void *)KRB_PRINC_NAME(krbPrinc)[index];
12034 +    buffer->length = strlen((char *)buffer->value);
12035 +#else
12036 +    buffer->value = (void *)krb5_princ_component(NULL, krbPrinc, index)->data;
12037 +    buffer->length = krb5_princ_component(NULL, krbPrinc, index)->length;
12038 +#endif /* HAVE_HEIMDAL_VERSION */
12039 +}
12040 +
12041 +static inline void
12042 +krbPrincRealmToGssBuffer(krb5_principal krbPrinc, gss_buffer_t buffer)
12043 +{
12044 +#ifdef HAVE_HEIMDAL_VERSION
12045 +    buffer->value = (void *)KRB_PRINC_REALM(krbPrinc);
12046 +    buffer->length = strlen((char *)buffer->value);
12047 +#else
12048 +    krbDataToGssBuffer(KRB_PRINC_REALM(krbPrinc), buffer);
12049 +#endif
12050 +}
12051 +
12052 +static inline void
12053 +gssBufferToKrbData(gss_buffer_t buffer, krb5_data *data)
12054 +{
12055 +    data->data = (char *)buffer->value;
12056 +    data->length = buffer->length;
12057 +}
12058 +
12059 +/* util_tld.c */
12060 +struct gss_eap_status_info;
12061 +
12062 +struct gss_eap_thread_local_data {
12063 +    krb5_context krbContext;
12064 +    struct gss_eap_status_info *statusInfo;
12065 +};
12066 +
12067 +struct gss_eap_thread_local_data *
12068 +gssEapGetThreadLocalData(void);
12069 +
12070 +void
12071 +gssEapDestroyStatusInfo(struct gss_eap_status_info *status);
12072 +
12073 +void
12074 +gssEapDestroyKrbContext(krb5_context context);
12075 +
12076 +#ifdef __cplusplus
12077 +}
12078 +#endif
12079 +
12080 +#ifdef GSSEAP_ENABLE_ACCEPTOR
12081 +#include "util_json.h"
12082 +#include "util_attr.h"
12083 +#include "util_base64.h"
12084 +#endif /* GSSEAP_ENABLE_ACCEPTOR */
12085 +#ifdef GSSEAP_ENABLE_REAUTH
12086 +#include "util_reauth.h"
12087 +#endif
12088 +
12089 +#endif /* _UTIL_H_ */
12090 diff --git a/mech_eap/util_adshim.c b/mech_eap/util_adshim.c
12091 new file mode 100644
12092 index 0000000..513a1a8
12093 --- /dev/null
12094 +++ b/mech_eap/util_adshim.c
12095 @@ -0,0 +1,242 @@
12096 +/*
12097 + * Copyright (c) 2011, JANET(UK)
12098 + * All rights reserved.
12099 + *
12100 + * Redistribution and use in source and binary forms, with or without
12101 + * modification, are permitted provided that the following conditions
12102 + * are met:
12103 + *
12104 + * 1. Redistributions of source code must retain the above copyright
12105 + *    notice, this list of conditions and the following disclaimer.
12106 + *
12107 + * 2. Redistributions in binary form must reproduce the above copyright
12108 + *    notice, this list of conditions and the following disclaimer in the
12109 + *    documentation and/or other materials provided with the distribution.
12110 + *
12111 + * 3. Neither the name of JANET(UK) nor the names of its contributors
12112 + *    may be used to endorse or promote products derived from this software
12113 + *    without specific prior written permission.
12114 + *
12115 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
12116 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12117 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12118 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
12119 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12120 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12121 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12122 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12123 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12124 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12125 + * SUCH DAMAGE.
12126 + */
12127 +
12128 +#include "gssapiP_eap.h"
12129 +#include "authdata_plugin.h"
12130 +
12131 +/*
12132 + * This rubbish is necessary because MIT doesn't provide another way
12133 + * to access verified AD-KDCIssued elements. We can't verify them
12134 + * ourselves because they're signed in the ticket session key, which
12135 + * is destroyed immediately after the AP-REQ is processed.
12136 + */
12137 +
12138 +struct radius_ad_context {
12139 +    krb5_data avpdata;
12140 +    krb5_boolean verified;
12141 +};
12142 +
12143 +static krb5_data radius_ad_attr = {
12144 +    KV5M_DATA, sizeof("urn:authdata-radius-avp") - 1, "urn:authdata-radius-avp" };
12145 +
12146 +static krb5_error_code
12147 +radius_ad_init(krb5_context kcontext GSSEAP_UNUSED,
12148 +               void **plugin_context)
12149 +{
12150 +    *plugin_context = 0;
12151 +    return 0;
12152 +}
12153 +
12154 +static void
12155 +radius_ad_flags(krb5_context kcontext GSSEAP_UNUSED,
12156 +                void *plugin_context GSSEAP_UNUSED,
12157 +                krb5_authdatatype ad_type GSSEAP_UNUSED,
12158 +                krb5_flags *flags)
12159 +{
12160 +    *flags = AD_USAGE_KDC_ISSUED | AD_INFORMATIONAL;
12161 +}
12162 +
12163 +static void
12164 +radius_ad_fini(krb5_context kcontext GSSEAP_UNUSED,
12165 +               void *plugin_context GSSEAP_UNUSED)
12166 +{
12167 +    return;
12168 +}
12169 +
12170 +static krb5_error_code
12171 +radius_ad_request_init(krb5_context kcontext GSSEAP_UNUSED,
12172 +                       struct _krb5_authdata_context *context GSSEAP_UNUSED,
12173 +                       void *plugin_context GSSEAP_UNUSED,
12174 +                       void **request_context)
12175 +{
12176 +    struct radius_ad_context *ctx;
12177 +
12178 +    ctx = GSSEAP_CALLOC(1, sizeof(*ctx));
12179 +    if (ctx == NULL)
12180 +        return ENOMEM;
12181 +
12182 +    *request_context = ctx;
12183 +
12184 +    return 0;
12185 +}
12186 +
12187 +static krb5_error_code
12188 +radius_ad_export_authdata(krb5_context kcontext,
12189 +                          struct _krb5_authdata_context *context GSSEAP_UNUSED,
12190 +                          void *plugin_context GSSEAP_UNUSED,
12191 +                          void *request_context,
12192 +                          krb5_flags usage GSSEAP_UNUSED,
12193 +                          krb5_authdata ***out_authdata)
12194 +{
12195 +    struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context;
12196 +    krb5_authdata *data[2];
12197 +    krb5_authdata datum;
12198 +
12199 +    datum.ad_type = KRB5_AUTHDATA_RADIUS_AVP;
12200 +    datum.length = radius_ad->avpdata.length;
12201 +    datum.contents = (krb5_octet *)radius_ad->avpdata.data;
12202 +
12203 +    data[0] = &datum;
12204 +    data[1] = NULL;
12205 +
12206 +    return krb5_copy_authdata(kcontext, data, out_authdata);
12207 +}
12208 +
12209 +static krb5_error_code
12210 +radius_ad_import_authdata(krb5_context kcontext,
12211 +                          struct _krb5_authdata_context *context GSSEAP_UNUSED,
12212 +                          void *plugin_context GSSEAP_UNUSED,
12213 +                          void *request_context,
12214 +                          krb5_authdata **authdata,
12215 +                          krb5_boolean kdc_issued_flag,
12216 +                          krb5_const_principal issuer GSSEAP_UNUSED)
12217 +{
12218 +    struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context;
12219 +
12220 +    krb5_free_data_contents(kcontext, &radius_ad->avpdata);
12221 +    radius_ad->verified = FALSE;
12222 +
12223 +    GSSEAP_ASSERT(authdata[0] != NULL);
12224 +
12225 +    radius_ad->avpdata.data = GSSEAP_MALLOC(authdata[0]->length);
12226 +    if (radius_ad->avpdata.data == NULL)
12227 +        return ENOMEM;
12228 +
12229 +    memcpy(radius_ad->avpdata.data, authdata[0]->contents,
12230 +           authdata[0]->length);
12231 +    radius_ad->avpdata.length = authdata[0]->length;
12232 +
12233 +    radius_ad->verified = kdc_issued_flag;
12234 +
12235 +    return 0;
12236 +}
12237 +
12238 +static void
12239 +radius_ad_request_fini(krb5_context kcontext,
12240 +                       struct _krb5_authdata_context *context GSSEAP_UNUSED,
12241 +                       void *plugin_context GSSEAP_UNUSED,
12242 +                       void *request_context)
12243 +{
12244 +    struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context;
12245 +
12246 +    if (radius_ad != NULL) {
12247 +        krb5_free_data_contents(kcontext, &radius_ad->avpdata);
12248 +        GSSEAP_FREE(radius_ad);
12249 +    }
12250 +}
12251 +
12252 +static krb5_error_code
12253 +radius_ad_get_attribute(krb5_context kcontext GSSEAP_UNUSED,
12254 +                        struct _krb5_authdata_context *context GSSEAP_UNUSED,
12255 +                        void *plugin_context GSSEAP_UNUSED,
12256 +                        void *request_context,
12257 +                        const krb5_data *attribute,
12258 +                        krb5_boolean *authenticated,
12259 +                        krb5_boolean *complete,
12260 +                        krb5_data *value,
12261 +                        krb5_data *display_value GSSEAP_UNUSED,
12262 +                        int *more)
12263 +{
12264 +    struct radius_ad_context *radius_ad = (struct radius_ad_context *)request_context;
12265 +
12266 +    if (attribute->length != radius_ad_attr.length ||
12267 +        memcmp(attribute->data, radius_ad_attr.data,
12268 +               radius_ad_attr.length) != 0)
12269 +        return ENOENT;
12270 +
12271 +    if (radius_ad->avpdata.length == 0)
12272 +        return ENOENT;
12273 +
12274 +    *authenticated = radius_ad->verified;
12275 +    *complete = TRUE;
12276 +    *more = 0;
12277 +
12278 +    value->data = GSSEAP_MALLOC(radius_ad->avpdata.length);
12279 +    if (value->data == NULL)
12280 +        return ENOMEM;
12281 +
12282 +    memcpy(value->data, radius_ad->avpdata.data, radius_ad->avpdata.length);
12283 +    value->length = radius_ad->avpdata.length;
12284 +
12285 +    return 0;
12286 +}
12287 +
12288 +static krb5_error_code
12289 +radius_ad_copy(krb5_context kcontext GSSEAP_UNUSED,
12290 +               struct _krb5_authdata_context *context GSSEAP_UNUSED,
12291 +               void *plugin_context GSSEAP_UNUSED,
12292 +               void *request_context,
12293 +               void *dst_plugin_context GSSEAP_UNUSED,
12294 +               void *dst_request_context)
12295 +{
12296 +    struct radius_ad_context *radius_ad_src =
12297 +        (struct radius_ad_context *)request_context;
12298 +    struct radius_ad_context *radius_ad_dst =
12299 +        (struct radius_ad_context *)dst_request_context;
12300 +
12301 +    radius_ad_dst->avpdata.data = GSSEAP_MALLOC(radius_ad_src->avpdata.length);
12302 +    if (radius_ad_dst->avpdata.data == NULL)
12303 +        return ENOMEM;
12304 +
12305 +    memcpy(radius_ad_dst->avpdata.data, radius_ad_src->avpdata.data,
12306 +           radius_ad_src->avpdata.length);
12307 +    radius_ad_dst->avpdata.length = radius_ad_src->avpdata.length;
12308 +    radius_ad_dst->verified = radius_ad_src->verified;
12309 +
12310 +    return 0;
12311 +}
12312 +
12313 +static krb5_authdatatype radius_ad_ad_types[] =
12314 +    { KRB5_AUTHDATA_RADIUS_AVP, 0 };
12315 +
12316 +krb5plugin_authdata_client_ftable_v0 authdata_client_0 = {
12317 +    "radius_ad",
12318 +    radius_ad_ad_types,
12319 +    radius_ad_init,
12320 +    radius_ad_fini,
12321 +    radius_ad_flags,
12322 +    radius_ad_request_init,
12323 +    radius_ad_request_fini,
12324 +    NULL,
12325 +    radius_ad_get_attribute,
12326 +    NULL,
12327 +    NULL,
12328 +    radius_ad_export_authdata,
12329 +    radius_ad_import_authdata,
12330 +    NULL,
12331 +    NULL,
12332 +    NULL,
12333 +    NULL,
12334 +    NULL,
12335 +    NULL,
12336 +    radius_ad_copy
12337 +};
12338 diff --git a/mech_eap/util_attr.cpp b/mech_eap/util_attr.cpp
12339 new file mode 100644
12340 index 0000000..3bfe785
12341 --- /dev/null
12342 +++ b/mech_eap/util_attr.cpp
12343 @@ -0,0 +1,1191 @@
12344 +/*
12345 + * Copyright (c) 2011, JANET(UK)
12346 + * All rights reserved.
12347 + *
12348 + * Redistribution and use in source and binary forms, with or without
12349 + * modification, are permitted provided that the following conditions
12350 + * are met:
12351 + *
12352 + * 1. Redistributions of source code must retain the above copyright
12353 + *    notice, this list of conditions and the following disclaimer.
12354 + *
12355 + * 2. Redistributions in binary form must reproduce the above copyright
12356 + *    notice, this list of conditions and the following disclaimer in the
12357 + *    documentation and/or other materials provided with the distribution.
12358 + *
12359 + * 3. Neither the name of JANET(UK) nor the names of its contributors
12360 + *    may be used to endorse or promote products derived from this software
12361 + *    without specific prior written permission.
12362 + *
12363 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
12364 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12365 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12366 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
12367 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12368 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12369 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12370 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12371 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12372 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12373 + * SUCH DAMAGE.
12374 + */
12375 +
12376 +/*
12377 + * Attribute provider mechanism.
12378 + */
12379 +
12380 +#include "gssapiP_eap.h"
12381 +
12382 +#include <typeinfo>
12383 +#include <string>
12384 +#include <sstream>
12385 +#include <exception>
12386 +#include <new>
12387 +
12388 +/* lazy initialisation */
12389 +static GSSEAP_THREAD_ONCE gssEapAttrProvidersInitOnce = GSSEAP_ONCE_INITIALIZER;
12390 +static OM_uint32 gssEapAttrProvidersInitStatus = GSS_S_UNAVAILABLE;
12391 +
12392 +GSSEAP_ONCE_CALLBACK(gssEapAttrProvidersInitInternal)
12393 +{
12394 +    OM_uint32 major, minor;
12395 +
12396 +    GSSEAP_ASSERT(gssEapAttrProvidersInitStatus == GSS_S_UNAVAILABLE);
12397 +
12398 +    json_set_alloc_funcs(GSSEAP_MALLOC, GSSEAP_FREE);
12399 +
12400 +    major = gssEapRadiusAttrProviderInit(&minor);
12401 +    if (GSS_ERROR(major))
12402 +        goto cleanup;
12403 +
12404 +#ifdef HAVE_OPENSAML
12405 +    major = gssEapSamlAttrProvidersInit(&minor);
12406 +    if (GSS_ERROR(major))
12407 +        goto cleanup;
12408 +#endif
12409 +
12410 +#ifdef HAVE_SHIBRESOLVER
12411 +    /* Allow Shibboleth initialization failure to be non-fatal */
12412 +    gssEapLocalAttrProviderInit(&minor);
12413 +#endif
12414 +
12415 +cleanup:
12416 +#ifdef GSSEAP_DEBUG
12417 +    GSSEAP_ASSERT(major == GSS_S_COMPLETE);
12418 +#endif
12419 +
12420 +    gssEapAttrProvidersInitStatus = major;
12421 +
12422 +    GSSEAP_ONCE_LEAVE;
12423 +}
12424 +
12425 +static OM_uint32
12426 +gssEapAttrProvidersInit(OM_uint32 *minor)
12427 +{
12428 +    GSSEAP_ONCE(&gssEapAttrProvidersInitOnce, gssEapAttrProvidersInitInternal);
12429 +
12430 +    if (GSS_ERROR(gssEapAttrProvidersInitStatus))
12431 +        *minor = GSSEAP_NO_ATTR_PROVIDERS;
12432 +
12433 +    return gssEapAttrProvidersInitStatus;
12434 +}
12435 +
12436 +OM_uint32
12437 +gssEapAttrProvidersFinalize(OM_uint32 *minor)
12438 +{
12439 +    if (gssEapAttrProvidersInitStatus == GSS_S_COMPLETE) {
12440 +#ifdef HAVE_SHIBRESOLVER
12441 +        gssEapLocalAttrProviderFinalize(minor);
12442 +#endif
12443 +#ifdef HAVE_OPENSAML
12444 +        gssEapSamlAttrProvidersFinalize(minor);
12445 +#endif
12446 +        gssEapRadiusAttrProviderFinalize(minor);
12447 +
12448 +        gssEapAttrProvidersInitStatus = GSS_S_UNAVAILABLE;
12449 +    }
12450 +
12451 +    return GSS_S_COMPLETE;
12452 +}
12453 +
12454 +static gss_eap_attr_create_provider gssEapAttrFactories[ATTR_TYPE_MAX + 1];
12455 +
12456 +/*
12457 + * Register a provider for a particular type and prefix
12458 + */
12459 +void
12460 +gss_eap_attr_ctx::registerProvider(unsigned int type,
12461 +                                   gss_eap_attr_create_provider factory)
12462 +{
12463 +    GSSEAP_ASSERT(type <= ATTR_TYPE_MAX);
12464 +
12465 +    GSSEAP_ASSERT(gssEapAttrFactories[type] == NULL);
12466 +
12467 +    gssEapAttrFactories[type] = factory;
12468 +}
12469 +
12470 +/*
12471 + * Unregister a provider
12472 + */
12473 +void
12474 +gss_eap_attr_ctx::unregisterProvider(unsigned int type)
12475 +{
12476 +    GSSEAP_ASSERT(type <= ATTR_TYPE_MAX);
12477 +
12478 +    gssEapAttrFactories[type] = NULL;
12479 +}
12480 +
12481 +/*
12482 + * Create an attribute context, that manages instances of providers
12483 + */
12484 +gss_eap_attr_ctx::gss_eap_attr_ctx(void)
12485 +{
12486 +    m_flags = 0;
12487 +
12488 +    for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
12489 +        gss_eap_attr_provider *provider;
12490 +
12491 +        if (gssEapAttrFactories[i] != NULL) {
12492 +            provider = (gssEapAttrFactories[i])();
12493 +        } else {
12494 +            provider = NULL;
12495 +        }
12496 +
12497 +        m_providers[i] = provider;
12498 +    }
12499 +}
12500 +
12501 +/*
12502 + * Convert an attribute prefix to a type
12503 + */
12504 +unsigned int
12505 +gss_eap_attr_ctx::attributePrefixToType(const gss_buffer_t prefix) const
12506 +{
12507 +    unsigned int i;
12508 +
12509 +    for (i = ATTR_TYPE_MIN; i < ATTR_TYPE_MAX; i++) {
12510 +        const char *pprefix;
12511 +
12512 +        if (!providerEnabled(i))
12513 +            continue;
12514 +
12515 +        pprefix = m_providers[i]->prefix();
12516 +        if (pprefix == NULL)
12517 +            continue;
12518 +
12519 +        if (strlen(pprefix) == prefix->length &&
12520 +            memcmp(pprefix, prefix->value, prefix->length) == 0)
12521 +            return i;
12522 +    }
12523 +
12524 +    return ATTR_TYPE_LOCAL;
12525 +}
12526 +
12527 +/*
12528 + * Convert a type to an attribute prefix
12529 + */
12530 +gss_buffer_desc
12531 +gss_eap_attr_ctx::attributeTypeToPrefix(unsigned int type) const
12532 +{
12533 +    gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER;
12534 +
12535 +    if (type < ATTR_TYPE_MIN || type >= ATTR_TYPE_MAX)
12536 +        return prefix;
12537 +
12538 +    if (!providerEnabled(type))
12539 +        return prefix;
12540 +
12541 +    prefix.value = (void *)m_providers[type]->prefix();
12542 +    if (prefix.value != NULL)
12543 +        prefix.length = strlen((char *)prefix.value);
12544 +
12545 +    return prefix;
12546 +}
12547 +
12548 +bool
12549 +gss_eap_attr_ctx::providerEnabled(unsigned int type) const
12550 +{
12551 +    if (type == ATTR_TYPE_LOCAL &&
12552 +        (m_flags & ATTR_FLAG_DISABLE_LOCAL))
12553 +        return false;
12554 +
12555 +    if (m_providers[type] == NULL)
12556 +        return false;
12557 +
12558 +    return true;
12559 +}
12560 +
12561 +void
12562 +gss_eap_attr_ctx::releaseProvider(unsigned int type)
12563 +{
12564 +    delete m_providers[type];
12565 +    m_providers[type] = NULL;
12566 +}
12567 +
12568 +/*
12569 + * Initialize a context from an existing context.
12570 + */
12571 +bool
12572 +gss_eap_attr_ctx::initWithExistingContext(const gss_eap_attr_ctx *manager)
12573 +{
12574 +    bool ret = true;
12575 +
12576 +    m_flags = manager->m_flags;
12577 +
12578 +    for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
12579 +        gss_eap_attr_provider *provider;
12580 +
12581 +        if (!providerEnabled(i)) {
12582 +            releaseProvider(i);
12583 +            continue;
12584 +        }
12585 +
12586 +        provider = m_providers[i];
12587 +
12588 +        ret = provider->initWithExistingContext(this,
12589 +                                                manager->m_providers[i]);
12590 +        if (ret == false) {
12591 +            releaseProvider(i);
12592 +            break;
12593 +        }
12594 +    }
12595 +
12596 +    return ret;
12597 +}
12598 +
12599 +/*
12600 + * Initialize a context from a GSS credential and context.
12601 + */
12602 +bool
12603 +gss_eap_attr_ctx::initWithGssContext(const gss_cred_id_t cred,
12604 +                                     const gss_ctx_id_t ctx)
12605 +{
12606 +    bool ret = true;
12607 +
12608 +    if (cred != GSS_C_NO_CREDENTIAL &&
12609 +        (cred->flags & GSS_EAP_DISABLE_LOCAL_ATTRS_FLAG)) {
12610 +        m_flags |= ATTR_FLAG_DISABLE_LOCAL;
12611 +    }
12612 +
12613 +    for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
12614 +        gss_eap_attr_provider *provider;
12615 +
12616 +        if (!providerEnabled(i)) {
12617 +            releaseProvider(i);
12618 +            continue;
12619 +        }
12620 +
12621 +        provider = m_providers[i];
12622 +
12623 +        ret = provider->initWithGssContext(this, cred, ctx);
12624 +        if (ret == false) {
12625 +            releaseProvider(i);
12626 +            break;
12627 +        }
12628 +    }
12629 +
12630 +    return ret;
12631 +}
12632 +
12633 +bool
12634 +gss_eap_attr_ctx::initWithJsonObject(JSONObject &obj)
12635 +{
12636 +    bool ret = false;
12637 +    bool foundSource[ATTR_TYPE_MAX + 1];
12638 +    unsigned int type;
12639 +
12640 +    for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++)
12641 +        foundSource[type] = false;
12642 +
12643 +    if (obj["version"].integer() != 1)
12644 +        return false;
12645 +
12646 +    m_flags = obj["flags"].integer();
12647 +
12648 +    JSONObject sources = obj["sources"];
12649 +
12650 +    /* Initialize providers from serialized state */
12651 +    for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++) {
12652 +        gss_eap_attr_provider *provider;
12653 +        const char *key;
12654 +
12655 +        if (!providerEnabled(type)) {
12656 +            releaseProvider(type);
12657 +            continue;
12658 +        }
12659 +
12660 +        provider = m_providers[type];
12661 +        key = provider->name();
12662 +        if (key == NULL)
12663 +            continue;
12664 +
12665 +        JSONObject source = sources.get(key);
12666 +        if (!source.isNull() &&
12667 +            !provider->initWithJsonObject(this, source)) {
12668 +            releaseProvider(type);
12669 +            return false;
12670 +        }
12671 +
12672 +        foundSource[type] = true;
12673 +    }
12674 +
12675 +    /* Initialize remaining providers from initialized providers */
12676 +    for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++) {
12677 +        gss_eap_attr_provider *provider;
12678 +
12679 +        if (foundSource[type] || !providerEnabled(type))
12680 +            continue;
12681 +
12682 +        provider = m_providers[type];
12683 +
12684 +        ret = provider->initWithGssContext(this,
12685 +                                           GSS_C_NO_CREDENTIAL,
12686 +                                           GSS_C_NO_CONTEXT);
12687 +        if (ret == false) {
12688 +            releaseProvider(type);
12689 +            return false;
12690 +        }
12691 +    }
12692 +
12693 +    return true;
12694 +}
12695 +
12696 +JSONObject
12697 +gss_eap_attr_ctx::jsonRepresentation(void) const
12698 +{
12699 +    JSONObject obj, sources;
12700 +    unsigned int i;
12701 +
12702 +    obj.set("version", 1);
12703 +    obj.set("flags", m_flags);
12704 +
12705 +    for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
12706 +        gss_eap_attr_provider *provider;
12707 +        const char *key;
12708 +
12709 +        provider = m_providers[i];
12710 +        if (provider == NULL)
12711 +            continue; /* provider not initialised */
12712 +
12713 +        key = provider->name();
12714 +        if (key == NULL)
12715 +            continue; /* provider does not have state */
12716 +
12717 +        JSONObject source = provider->jsonRepresentation();
12718 +        sources.set(key, source);
12719 +    }
12720 +
12721 +    obj.set("sources", sources);
12722 +
12723 +    return obj;
12724 +}
12725 +
12726 +/*
12727 + * Initialize a context from an exported context or name token
12728 + */
12729 +bool
12730 +gss_eap_attr_ctx::initWithBuffer(const gss_buffer_t buffer)
12731 +{
12732 +    OM_uint32 major, minor;
12733 +    bool ret;
12734 +    char *s;
12735 +    json_error_t error;
12736 +
12737 +    major = bufferToString(&minor, buffer, &s);
12738 +    if (GSS_ERROR(major))
12739 +        return false;
12740 +
12741 +    JSONObject obj = JSONObject::load(s, 0, &error);
12742 +    if (!obj.isNull()) {
12743 +        ret = initWithJsonObject(obj);
12744 +    } else
12745 +        ret = false;
12746 +
12747 +    GSSEAP_FREE(s);
12748 +
12749 +    return ret;
12750 +}
12751 +
12752 +gss_eap_attr_ctx::~gss_eap_attr_ctx(void)
12753 +{
12754 +    for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++)
12755 +        delete m_providers[i];
12756 +}
12757 +
12758 +/*
12759 + * Locate provider for a given type
12760 + */
12761 +gss_eap_attr_provider *
12762 +gss_eap_attr_ctx::getProvider(unsigned int type) const
12763 +{
12764 +    GSSEAP_ASSERT(type >= ATTR_TYPE_MIN && type <= ATTR_TYPE_MAX);
12765 +    return m_providers[type];
12766 +}
12767 +
12768 +/*
12769 + * Get primary provider. Only the primary provider is serialised when
12770 + * gss_export_sec_context() or gss_export_name_composite() is called.
12771 + */
12772 +gss_eap_attr_provider *
12773 +gss_eap_attr_ctx::getPrimaryProvider(void) const
12774 +{
12775 +    return m_providers[ATTR_TYPE_MIN];
12776 +}
12777 +
12778 +/*
12779 + * Set an attribute
12780 + */
12781 +bool
12782 +gss_eap_attr_ctx::setAttribute(int complete,
12783 +                               const gss_buffer_t attr,
12784 +                               const gss_buffer_t value)
12785 +{
12786 +    gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
12787 +    unsigned int type;
12788 +    gss_eap_attr_provider *provider;
12789 +    bool ret = false;
12790 +
12791 +    decomposeAttributeName(attr, &type, &suffix);
12792 +
12793 +    provider = m_providers[type];
12794 +    if (provider != NULL) {
12795 +        ret = provider->setAttribute(complete,
12796 +                                     (type == ATTR_TYPE_LOCAL) ? attr : &suffix,
12797 +                                     value);
12798 +    }
12799 +
12800 +    return ret;
12801 +}
12802 +
12803 +/*
12804 + * Delete an attrbiute
12805 + */
12806 +bool
12807 +gss_eap_attr_ctx::deleteAttribute(const gss_buffer_t attr)
12808 +{
12809 +    gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
12810 +    unsigned int type;
12811 +    gss_eap_attr_provider *provider;
12812 +    bool ret = false;
12813 +
12814 +    decomposeAttributeName(attr, &type, &suffix);
12815 +
12816 +    provider = m_providers[type];
12817 +    if (provider != NULL) {
12818 +        ret = provider->deleteAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix);
12819 +    }
12820 +
12821 +    return ret;
12822 +}
12823 +
12824 +/*
12825 + * Enumerate attribute types with callback
12826 + */
12827 +bool
12828 +gss_eap_attr_ctx::getAttributeTypes(gss_eap_attr_enumeration_cb cb, void *data) const
12829 +{
12830 +    bool ret = false;
12831 +    size_t i;
12832 +
12833 +    for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
12834 +        gss_eap_attr_provider *provider = m_providers[i];
12835 +
12836 +        if (provider == NULL)
12837 +            continue;
12838 +
12839 +        ret = provider->getAttributeTypes(cb, data);
12840 +        if (ret == false)
12841 +            break;
12842 +    }
12843 +
12844 +    return ret;
12845 +}
12846 +
12847 +struct eap_gss_get_attr_types_args {
12848 +    unsigned int type;
12849 +    gss_buffer_set_t attrs;
12850 +};
12851 +
12852 +static bool
12853 +addAttribute(const gss_eap_attr_ctx *manager,
12854 +             const gss_eap_attr_provider *provider GSSEAP_UNUSED,
12855 +             const gss_buffer_t attribute,
12856 +             void *data)
12857 +{
12858 +    eap_gss_get_attr_types_args *args = (eap_gss_get_attr_types_args *)data;
12859 +    gss_buffer_desc qualified;
12860 +    OM_uint32 major, minor;
12861 +
12862 +    if (args->type != ATTR_TYPE_LOCAL) {
12863 +        manager->composeAttributeName(args->type, attribute, &qualified);
12864 +        major = gss_add_buffer_set_member(&minor, &qualified, &args->attrs);
12865 +        gss_release_buffer(&minor, &qualified);
12866 +    } else {
12867 +        major = gss_add_buffer_set_member(&minor, attribute, &args->attrs);
12868 +    }
12869 +
12870 +    return GSS_ERROR(major) == false;
12871 +}
12872 +
12873 +/*
12874 + * Enumerate attribute types, output is buffer set
12875 + */
12876 +bool
12877 +gss_eap_attr_ctx::getAttributeTypes(gss_buffer_set_t *attrs)
12878 +{
12879 +    eap_gss_get_attr_types_args args;
12880 +    OM_uint32 major, minor;
12881 +    bool ret = false;
12882 +    unsigned int i;
12883 +
12884 +    major = gss_create_empty_buffer_set(&minor, attrs);
12885 +    if (GSS_ERROR(major))
12886 +        throw std::bad_alloc();
12887 +
12888 +    args.attrs = *attrs;
12889 +
12890 +    for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
12891 +        gss_eap_attr_provider *provider = m_providers[i];
12892 +
12893 +        args.type = i;
12894 +
12895 +        if (provider == NULL)
12896 +            continue;
12897 +
12898 +        ret = provider->getAttributeTypes(addAttribute, (void *)&args);
12899 +        if (ret == false)
12900 +            break;
12901 +    }
12902 +
12903 +    if (ret == false)
12904 +        gss_release_buffer_set(&minor, attrs);
12905 +
12906 +    return ret;
12907 +}
12908 +
12909 +/*
12910 + * Get attribute with given name
12911 + */
12912 +bool
12913 +gss_eap_attr_ctx::getAttribute(const gss_buffer_t attr,
12914 +                               int *authenticated,
12915 +                               int *complete,
12916 +                               gss_buffer_t value,
12917 +                               gss_buffer_t display_value,
12918 +                               int *more) const
12919 +{
12920 +    gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
12921 +    unsigned int type;
12922 +    gss_eap_attr_provider *provider;
12923 +    bool ret;
12924 +
12925 +    decomposeAttributeName(attr, &type, &suffix);
12926 +
12927 +    provider = m_providers[type];
12928 +    if (provider == NULL)
12929 +        return false;
12930 +
12931 +    ret = provider->getAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix,
12932 +                                 authenticated, complete,
12933 +                                 value, display_value, more);
12934 +
12935 +    return ret;
12936 +}
12937 +
12938 +/*
12939 + * Map attribute context to C++ object
12940 + */
12941 +gss_any_t
12942 +gss_eap_attr_ctx::mapToAny(int authenticated,
12943 +                           gss_buffer_t type_id) const
12944 +{
12945 +    unsigned int type;
12946 +    gss_eap_attr_provider *provider;
12947 +    gss_buffer_desc suffix;
12948 +
12949 +    decomposeAttributeName(type_id, &type, &suffix);
12950 +
12951 +    provider = m_providers[type];
12952 +    if (provider == NULL)
12953 +        return (gss_any_t)NULL;
12954 +
12955 +    return provider->mapToAny(authenticated, &suffix);
12956 +}
12957 +
12958 +/*
12959 + * Release mapped context
12960 + */
12961 +void
12962 +gss_eap_attr_ctx::releaseAnyNameMapping(gss_buffer_t type_id,
12963 +                                        gss_any_t input) const
12964 +{
12965 +    unsigned int type;
12966 +    gss_eap_attr_provider *provider;
12967 +    gss_buffer_desc suffix;
12968 +
12969 +    decomposeAttributeName(type_id, &type, &suffix);
12970 +
12971 +    provider = m_providers[type];
12972 +    if (provider != NULL)
12973 +        provider->releaseAnyNameMapping(&suffix, input);
12974 +}
12975 +
12976 +/*
12977 + * Export attribute context to buffer
12978 + */
12979 +void
12980 +gss_eap_attr_ctx::exportToBuffer(gss_buffer_t buffer) const
12981 +{
12982 +    OM_uint32 minor;
12983 +    char *s;
12984 +
12985 +    JSONObject obj = jsonRepresentation();
12986 +
12987 +#if 0
12988 +    obj.dump(stdout);
12989 +#endif
12990 +
12991 +    s = obj.dump(JSON_COMPACT);
12992 +
12993 +    if (GSS_ERROR(makeStringBuffer(&minor, s, buffer)))
12994 +        throw std::bad_alloc();
12995 +}
12996 +
12997 +/*
12998 + * Return soonest expiry time of providers
12999 + */
13000 +time_t
13001 +gss_eap_attr_ctx::getExpiryTime(void) const
13002 +{
13003 +    unsigned int i;
13004 +    time_t expiryTime = 0;
13005 +
13006 +    for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
13007 +        gss_eap_attr_provider *provider = m_providers[i];
13008 +        time_t providerExpiryTime;
13009 +
13010 +        if (provider == NULL)
13011 +            continue;
13012 +
13013 +        providerExpiryTime = provider->getExpiryTime();
13014 +        if (providerExpiryTime == 0)
13015 +            continue;
13016 +
13017 +        if (expiryTime == 0 || providerExpiryTime < expiryTime)
13018 +            expiryTime = providerExpiryTime;
13019 +    }
13020 +
13021 +    return expiryTime;
13022 +}
13023 +
13024 +OM_uint32
13025 +gss_eap_attr_ctx::mapException(OM_uint32 *minor, std::exception &e) const
13026 +{
13027 +    unsigned int i;
13028 +    OM_uint32 major;
13029 +
13030 +    /* Errors we handle ourselves */
13031 +    if (typeid(e) == typeid(std::bad_alloc)) {
13032 +        major = GSS_S_FAILURE;
13033 +        *minor = ENOMEM;
13034 +        goto cleanup;
13035 +    } else if (typeid(e) == typeid(JSONException)) {
13036 +        major = GSS_S_BAD_NAME;
13037 +        *minor = GSSEAP_BAD_ATTR_TOKEN;
13038 +        gssEapSaveStatusInfo(*minor, "%s", e.what());
13039 +        goto cleanup;
13040 +    }
13041 +
13042 +    /* Errors we delegate to providers */
13043 +    major = GSS_S_CONTINUE_NEEDED;
13044 +
13045 +    for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
13046 +        gss_eap_attr_provider *provider = m_providers[i];
13047 +
13048 +        if (provider == NULL)
13049 +            continue;
13050 +
13051 +        major = provider->mapException(minor, e);
13052 +        if (major != GSS_S_CONTINUE_NEEDED)
13053 +            break;
13054 +    }
13055 +
13056 +    if (major == GSS_S_CONTINUE_NEEDED) {
13057 +        *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
13058 +        major = GSS_S_FAILURE;
13059 +    }
13060 +
13061 +cleanup:
13062 +    GSSEAP_ASSERT(GSS_ERROR(major));
13063 +
13064 +    return major;
13065 +}
13066 +
13067 +/*
13068 + * Decompose attribute name into prefix and suffix
13069 + */
13070 +void
13071 +gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
13072 +                                         gss_buffer_t prefix,
13073 +                                         gss_buffer_t suffix)
13074 +{
13075 +    char *p = NULL;
13076 +    size_t i;
13077 +
13078 +    for (i = 0; i < attribute->length; i++) {
13079 +        if (((char *)attribute->value)[i] == ' ') {
13080 +            p = (char *)attribute->value + i + 1;
13081 +            break;
13082 +        }
13083 +    }
13084 +
13085 +    prefix->value = attribute->value;
13086 +    prefix->length = i;
13087 +
13088 +    if (p != NULL && *p != '\0')  {
13089 +        suffix->length = attribute->length - 1 - prefix->length;
13090 +        suffix->value = p;
13091 +    } else {
13092 +        suffix->length = 0;
13093 +        suffix->value = NULL;
13094 +    }
13095 +}
13096 +
13097 +/*
13098 + * Decompose attribute name into type and suffix
13099 + */
13100 +void
13101 +gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
13102 +                                         unsigned int *type,
13103 +                                         gss_buffer_t suffix) const
13104 +{
13105 +    gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER;
13106 +
13107 +    decomposeAttributeName(attribute, &prefix, suffix);
13108 +    *type = attributePrefixToType(&prefix);
13109 +}
13110 +
13111 +/*
13112 + * Compose attribute name from prefix, suffix; returns C++ string
13113 + */
13114 +std::string
13115 +gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
13116 +                                       const gss_buffer_t suffix)
13117 +{
13118 +    std::string str;
13119 +
13120 +    if (prefix == GSS_C_NO_BUFFER || prefix->length == 0)
13121 +        return str;
13122 +
13123 +    str.append((const char *)prefix->value, prefix->length);
13124 +
13125 +    if (suffix != GSS_C_NO_BUFFER) {
13126 +        str.append(" ");
13127 +        str.append((const char *)suffix->value, suffix->length);
13128 +    }
13129 +
13130 +    return str;
13131 +}
13132 +
13133 +/*
13134 + * Compose attribute name from type, suffix; returns C++ string
13135 + */
13136 +std::string
13137 +gss_eap_attr_ctx::composeAttributeName(unsigned int type,
13138 +                                       const gss_buffer_t suffix)
13139 +{
13140 +    gss_buffer_desc prefix = attributeTypeToPrefix(type);
13141 +
13142 +    return composeAttributeName(&prefix, suffix);
13143 +}
13144 +
13145 +/*
13146 + * Compose attribute name from prefix, suffix; returns GSS buffer
13147 + */
13148 +void
13149 +gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
13150 +                                       const gss_buffer_t suffix,
13151 +                                       gss_buffer_t attribute)
13152 +{
13153 +    std::string str = composeAttributeName(prefix, suffix);
13154 +
13155 +    if (str.length() != 0) {
13156 +        return duplicateBuffer(str, attribute);
13157 +    } else {
13158 +        attribute->length = 0;
13159 +        attribute->value = NULL;
13160 +    }
13161 +}
13162 +
13163 +/*
13164 + * Compose attribute name from type, suffix; returns GSS buffer
13165 + */
13166 +void
13167 +gss_eap_attr_ctx::composeAttributeName(unsigned int type,
13168 +                                       const gss_buffer_t suffix,
13169 +                                       gss_buffer_t attribute) const
13170 +{
13171 +    gss_buffer_desc prefix = attributeTypeToPrefix(type);
13172 +
13173 +    return composeAttributeName(&prefix, suffix, attribute);
13174 +}
13175 +
13176 +/*
13177 + * C wrappers
13178 + */
13179 +OM_uint32
13180 +gssEapInquireName(OM_uint32 *minor,
13181 +                  gss_name_t name,
13182 +                  int *name_is_MN,
13183 +                  gss_OID *MN_mech,
13184 +                  gss_buffer_set_t *attrs)
13185 +{
13186 +    OM_uint32 major;
13187 +
13188 +    if (name_is_MN != NULL)
13189 +        *name_is_MN = (name->mechanismUsed != GSS_C_NULL_OID);
13190 +
13191 +    if (MN_mech != NULL) {
13192 +        major = gssEapCanonicalizeOid(minor, name->mechanismUsed,
13193 +                                      OID_FLAG_NULL_VALID, MN_mech);
13194 +        if (GSS_ERROR(major))
13195 +            return major;
13196 +    }
13197 +
13198 +    if (name->attrCtx == NULL) {
13199 +        *minor = GSSEAP_NO_ATTR_CONTEXT;
13200 +        return GSS_S_UNAVAILABLE;
13201 +    }
13202 +
13203 +    if (GSS_ERROR(gssEapAttrProvidersInit(minor))) {
13204 +        return GSS_S_UNAVAILABLE;
13205 +    }
13206 +
13207 +    try {
13208 +        if (!name->attrCtx->getAttributeTypes(attrs)) {
13209 +            *minor = GSSEAP_NO_ATTR_CONTEXT;
13210 +            return GSS_S_UNAVAILABLE;
13211 +        }
13212 +    } catch (std::exception &e) {
13213 +        return name->attrCtx->mapException(minor, e);
13214 +    }
13215 +
13216 +    return GSS_S_COMPLETE;
13217 +}
13218 +
13219 +OM_uint32
13220 +gssEapGetNameAttribute(OM_uint32 *minor,
13221 +                       gss_name_t name,
13222 +                       gss_buffer_t attr,
13223 +                       int *authenticated,
13224 +                       int *complete,
13225 +                       gss_buffer_t value,
13226 +                       gss_buffer_t display_value,
13227 +                       int *more)
13228 +{
13229 +    if (authenticated != NULL)
13230 +        *authenticated = 0;
13231 +    if (complete != NULL)
13232 +        *complete = 0;
13233 +
13234 +    if (value != NULL) {
13235 +        value->length = 0;
13236 +        value->value = NULL;
13237 +    }
13238 +
13239 +    if (display_value != NULL) {
13240 +        display_value->length = 0;
13241 +        display_value->value = NULL;
13242 +    }
13243 +
13244 +    if (name->attrCtx == NULL) {
13245 +        *minor = GSSEAP_NO_ATTR_CONTEXT;
13246 +        return GSS_S_UNAVAILABLE;
13247 +    }
13248 +
13249 +    if (GSS_ERROR(gssEapAttrProvidersInit(minor))) {
13250 +        return GSS_S_UNAVAILABLE;
13251 +    }
13252 +
13253 +    try {
13254 +        if (!name->attrCtx->getAttribute(attr, authenticated, complete,
13255 +                                         value, display_value, more)) {
13256 +            *minor = GSSEAP_NO_SUCH_ATTR;
13257 +            gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
13258 +                                 (int)attr->length, (char *)attr->value);
13259 +            return GSS_S_UNAVAILABLE;
13260 +        }
13261 +    } catch (std::exception &e) {
13262 +        return name->attrCtx->mapException(minor, e);
13263 +    }
13264 +
13265 +    return GSS_S_COMPLETE;
13266 +}
13267 +
13268 +OM_uint32
13269 +gssEapDeleteNameAttribute(OM_uint32 *minor,
13270 +                          gss_name_t name,
13271 +                          gss_buffer_t attr)
13272 +{
13273 +    if (name->attrCtx == NULL) {
13274 +        *minor = GSSEAP_NO_ATTR_CONTEXT;
13275 +        return GSS_S_UNAVAILABLE;
13276 +    }
13277 +
13278 +    if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
13279 +        return GSS_S_UNAVAILABLE;
13280 +
13281 +    try {
13282 +        if (!name->attrCtx->deleteAttribute(attr)) {
13283 +            *minor = GSSEAP_NO_SUCH_ATTR;
13284 +            gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
13285 +                                 (int)attr->length, (char *)attr->value);
13286 +            return GSS_S_UNAVAILABLE;
13287 +        }
13288 +    } catch (std::exception &e) {
13289 +        return name->attrCtx->mapException(minor, e);
13290 +    }
13291 +
13292 +    return GSS_S_COMPLETE;
13293 +}
13294 +
13295 +OM_uint32
13296 +gssEapSetNameAttribute(OM_uint32 *minor,
13297 +                       gss_name_t name,
13298 +                       int complete,
13299 +                       gss_buffer_t attr,
13300 +                       gss_buffer_t value)
13301 +{
13302 +    if (name->attrCtx == NULL) {
13303 +        *minor = GSSEAP_NO_ATTR_CONTEXT;
13304 +        return GSS_S_UNAVAILABLE;
13305 +    }
13306 +
13307 +    if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
13308 +        return GSS_S_UNAVAILABLE;
13309 +
13310 +    try {
13311 +        if (!name->attrCtx->setAttribute(complete, attr, value)) {
13312 +             *minor = GSSEAP_NO_SUCH_ATTR;
13313 +            gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
13314 +                                 (int)attr->length, (char *)attr->value);
13315 +            return GSS_S_UNAVAILABLE;
13316 +        }
13317 +    } catch (std::exception &e) {
13318 +        return name->attrCtx->mapException(minor, e);
13319 +    }
13320 +
13321 +    return GSS_S_COMPLETE;
13322 +}
13323 +
13324 +OM_uint32
13325 +gssEapExportAttrContext(OM_uint32 *minor,
13326 +                        gss_name_t name,
13327 +                        gss_buffer_t buffer)
13328 +{
13329 +    if (name->attrCtx == NULL) {
13330 +        buffer->length = 0;
13331 +        buffer->value = NULL;
13332 +
13333 +        return GSS_S_COMPLETE;
13334 +    }
13335 +
13336 +    if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
13337 +        return GSS_S_UNAVAILABLE;
13338 +
13339 +    try {
13340 +        name->attrCtx->exportToBuffer(buffer);
13341 +    } catch (std::exception &e) {
13342 +        return name->attrCtx->mapException(minor, e);
13343 +    }
13344 +
13345 +    return GSS_S_COMPLETE;
13346 +}
13347 +
13348 +OM_uint32
13349 +gssEapImportAttrContext(OM_uint32 *minor,
13350 +                        gss_buffer_t buffer,
13351 +                        gss_name_t name)
13352 +{
13353 +    gss_eap_attr_ctx *ctx = NULL;
13354 +    OM_uint32 major = GSS_S_FAILURE;
13355 +
13356 +    GSSEAP_ASSERT(name->attrCtx == NULL);
13357 +
13358 +    if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
13359 +        return GSS_S_UNAVAILABLE;
13360 +
13361 +    if (buffer->length == 0)
13362 +        return GSS_S_COMPLETE;
13363 +
13364 +    try {
13365 +        ctx = new gss_eap_attr_ctx();
13366 +
13367 +        if (ctx->initWithBuffer(buffer)) {
13368 +            name->attrCtx = ctx;
13369 +            major = GSS_S_COMPLETE;
13370 +            *minor = 0;
13371 +        } else {
13372 +            major = GSS_S_BAD_NAME;
13373 +            *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
13374 +        }
13375 +    } catch (std::exception &e) {
13376 +        if (ctx != NULL)
13377 +            major = ctx->mapException(minor, e);
13378 +    }
13379 +
13380 +    GSSEAP_ASSERT(major == GSS_S_COMPLETE || name->attrCtx == NULL);
13381 +
13382 +    if (GSS_ERROR(major))
13383 +        delete ctx;
13384 +
13385 +    return major;
13386 +}
13387 +
13388 +OM_uint32
13389 +gssEapDuplicateAttrContext(OM_uint32 *minor,
13390 +                           gss_name_t in,
13391 +                           gss_name_t out)
13392 +{
13393 +    gss_eap_attr_ctx *ctx = NULL;
13394 +    OM_uint32 major = GSS_S_FAILURE;
13395 +
13396 +    GSSEAP_ASSERT(out->attrCtx == NULL);
13397 +
13398 +    if (in->attrCtx == NULL) {
13399 +        *minor = 0;
13400 +        return GSS_S_COMPLETE;
13401 +    }
13402 +
13403 +    if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
13404 +        return GSS_S_UNAVAILABLE;
13405 +
13406 +    try {
13407 +        ctx = new gss_eap_attr_ctx();
13408 +
13409 +        if (ctx->initWithExistingContext(in->attrCtx)) {
13410 +            out->attrCtx = ctx;
13411 +            major = GSS_S_COMPLETE;
13412 +            *minor = 0;
13413 +        } else {
13414 +            major = GSS_S_FAILURE;
13415 +            *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
13416 +        }
13417 +    } catch (std::exception &e) {
13418 +        major = in->attrCtx->mapException(minor, e);
13419 +    }
13420 +
13421 +    GSSEAP_ASSERT(major == GSS_S_COMPLETE || out->attrCtx == NULL);
13422 +
13423 +    if (GSS_ERROR(major))
13424 +        delete ctx;
13425 +
13426 +    return GSS_S_COMPLETE;
13427 +}
13428 +
13429 +OM_uint32
13430 +gssEapMapNameToAny(OM_uint32 *minor,
13431 +                   gss_name_t name,
13432 +                   int authenticated,
13433 +                   gss_buffer_t type_id,
13434 +                   gss_any_t *output)
13435 +{
13436 +    if (name->attrCtx == NULL) {
13437 +        *minor = GSSEAP_NO_ATTR_CONTEXT;
13438 +        return GSS_S_UNAVAILABLE;
13439 +    }
13440 +
13441 +    if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
13442 +        return GSS_S_UNAVAILABLE;
13443 +
13444 +    try {
13445 +        *output = name->attrCtx->mapToAny(authenticated, type_id);
13446 +    } catch (std::exception &e) {
13447 +        return name->attrCtx->mapException(minor, e);
13448 +    }
13449 +
13450 +    return GSS_S_COMPLETE;
13451 +}
13452 +
13453 +OM_uint32
13454 +gssEapReleaseAnyNameMapping(OM_uint32 *minor,
13455 +                            gss_name_t name,
13456 +                            gss_buffer_t type_id,
13457 +                            gss_any_t *input)
13458 +{
13459 +    if (name->attrCtx == NULL) {
13460 +        *minor = GSSEAP_NO_ATTR_CONTEXT;
13461 +        return GSS_S_UNAVAILABLE;
13462 +    }
13463 +
13464 +    if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
13465 +        return GSS_S_UNAVAILABLE;
13466 +
13467 +    try {
13468 +        if (*input != NULL)
13469 +            name->attrCtx->releaseAnyNameMapping(type_id, *input);
13470 +        *input = NULL;
13471 +    } catch (std::exception &e) {
13472 +        return name->attrCtx->mapException(minor, e);
13473 +    }
13474 +
13475 +    return GSS_S_COMPLETE;
13476 +}
13477 +
13478 +OM_uint32
13479 +gssEapReleaseAttrContext(OM_uint32 *minor,
13480 +                         gss_name_t name)
13481 +{
13482 +    if (name->attrCtx != NULL)
13483 +        delete name->attrCtx;
13484 +
13485 +    *minor = 0;
13486 +    return GSS_S_COMPLETE;
13487 +}
13488 +
13489 +/*
13490 + * Public accessor for initialisng a context from a GSS context. Also
13491 + * sets expiry time on GSS context as a side-effect.
13492 + */
13493 +OM_uint32
13494 +gssEapCreateAttrContext(OM_uint32 *minor,
13495 +                        gss_cred_id_t gssCred,
13496 +                        gss_ctx_id_t gssCtx,
13497 +                        struct gss_eap_attr_ctx **pAttrContext,
13498 +                        time_t *pExpiryTime)
13499 +{
13500 +    gss_eap_attr_ctx *ctx = NULL;
13501 +    OM_uint32 major;
13502 +
13503 +    GSSEAP_ASSERT(gssCtx != GSS_C_NO_CONTEXT);
13504 +
13505 +    *pAttrContext = NULL;
13506 +
13507 +    major = gssEapAttrProvidersInit(minor);
13508 +    if (GSS_ERROR(major))
13509 +        return major;
13510 +
13511 +    try {
13512 +        /* Set *pAttrContext here to for reentrancy */
13513 +        *pAttrContext = ctx = new gss_eap_attr_ctx();
13514 +
13515 +        if (ctx->initWithGssContext(gssCred, gssCtx)) {
13516 +            *pExpiryTime = ctx->getExpiryTime();
13517 +            major = GSS_S_COMPLETE;
13518 +            *minor = 0;
13519 +        } else {
13520 +            major = GSS_S_FAILURE;
13521 +            *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
13522 +        }
13523 +    } catch (std::exception &e) {
13524 +        if (ctx != NULL)
13525 +            major = ctx->mapException(minor, e);
13526 +    }
13527 +
13528 +    if (GSS_ERROR(major)) {
13529 +        delete ctx;
13530 +        *pAttrContext = NULL;
13531 +    }
13532 +
13533 +    return major;
13534 +}
13535 diff --git a/mech_eap/util_attr.h b/mech_eap/util_attr.h
13536 new file mode 100644
13537 index 0000000..2af0850
13538 --- /dev/null
13539 +++ b/mech_eap/util_attr.h
13540 @@ -0,0 +1,389 @@
13541 +/*
13542 + * Copyright (c) 2011, JANET(UK)
13543 + * All rights reserved.
13544 + *
13545 + * Redistribution and use in source and binary forms, with or without
13546 + * modification, are permitted provided that the following conditions
13547 + * are met:
13548 + *
13549 + * 1. Redistributions of source code must retain the above copyright
13550 + *    notice, this list of conditions and the following disclaimer.
13551 + *
13552 + * 2. Redistributions in binary form must reproduce the above copyright
13553 + *    notice, this list of conditions and the following disclaimer in the
13554 + *    documentation and/or other materials provided with the distribution.
13555 + *
13556 + * 3. Neither the name of JANET(UK) nor the names of its contributors
13557 + *    may be used to endorse or promote products derived from this software
13558 + *    without specific prior written permission.
13559 + *
13560 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
13561 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13562 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13563 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
13564 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13565 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13566 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13567 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13568 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13569 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13570 + * SUCH DAMAGE.
13571 + */
13572 +
13573 +/*
13574 + * Attribute provider interface.
13575 + */
13576 +
13577 +#ifndef _UTIL_ATTR_H_
13578 +#define _UTIL_ATTR_H_ 1
13579 +
13580 +#ifdef __cplusplus
13581 +#include <string>
13582 +#include <new>
13583 +
13584 +using namespace gss_eap_util;
13585 +
13586 +struct gss_eap_attr_provider;
13587 +struct gss_eap_attr_ctx;
13588 +
13589 +typedef bool
13590 +(*gss_eap_attr_enumeration_cb)(const gss_eap_attr_ctx *ctx,
13591 +                               const gss_eap_attr_provider *source,
13592 +                               const gss_buffer_t attribute,
13593 +                               void *data);
13594 +
13595 +#define ATTR_TYPE_RADIUS            0U                  /* RADIUS AVPs */
13596 +#ifdef HAVE_OPENSAML
13597 +#define ATTR_TYPE_SAML_ASSERTION    1U                  /* SAML assertion */
13598 +#define ATTR_TYPE_SAML              2U                  /* SAML attributes */
13599 +#endif
13600 +#define ATTR_TYPE_LOCAL             3U                  /* Local attributes */
13601 +#define ATTR_TYPE_MIN               ATTR_TYPE_RADIUS
13602 +#define ATTR_TYPE_MAX               ATTR_TYPE_LOCAL
13603 +
13604 +#define ATTR_FLAG_DISABLE_LOCAL     0x00000001
13605 +
13606 +/*
13607 + * Attribute provider: this represents a source of attributes derived
13608 + * from the security context.
13609 + */
13610 +struct gss_eap_attr_provider
13611 +{
13612 +public:
13613 +    gss_eap_attr_provider(void) {}
13614 +    virtual ~gss_eap_attr_provider(void) {}
13615 +
13616 +    bool initWithManager(const gss_eap_attr_ctx *manager)
13617 +    {
13618 +        m_manager = manager;
13619 +        return true;
13620 +    }
13621 +
13622 +    virtual bool initWithExistingContext(const gss_eap_attr_ctx *manager,
13623 +                                         const gss_eap_attr_provider *ctx GSSEAP_UNUSED)
13624 +    {
13625 +        return initWithManager(manager);
13626 +    }
13627 +
13628 +    virtual bool initWithGssContext(const gss_eap_attr_ctx *manager,
13629 +                                    const gss_cred_id_t cred GSSEAP_UNUSED,
13630 +                                    const gss_ctx_id_t ctx GSSEAP_UNUSED)
13631 +    {
13632 +        return initWithManager(manager);
13633 +    }
13634 +
13635 +    virtual bool getAttributeTypes(gss_eap_attr_enumeration_cb GSSEAP_UNUSED,
13636 +                                   void *data GSSEAP_UNUSED) const
13637 +    {
13638 +        return false;
13639 +    }
13640 +
13641 +    virtual bool setAttribute(int complete GSSEAP_UNUSED,
13642 +                              const gss_buffer_t attr GSSEAP_UNUSED,
13643 +                              const gss_buffer_t value GSSEAP_UNUSED)
13644 +    {
13645 +        return false;
13646 +    }
13647 +
13648 +    virtual bool deleteAttribute(const gss_buffer_t value GSSEAP_UNUSED)
13649 +    {
13650 +        return false;
13651 +    }
13652 +
13653 +    virtual bool getAttribute(const gss_buffer_t attr GSSEAP_UNUSED,
13654 +                              int *authenticated GSSEAP_UNUSED,
13655 +                              int *complete GSSEAP_UNUSED,
13656 +                              gss_buffer_t value GSSEAP_UNUSED,
13657 +                              gss_buffer_t display_value GSSEAP_UNUSED,
13658 +                              int *more GSSEAP_UNUSED) const
13659 +    {
13660 +        return false;
13661 +    }
13662 +
13663 +    virtual gss_any_t mapToAny(int authenticated GSSEAP_UNUSED,
13664 +                               gss_buffer_t type_id GSSEAP_UNUSED) const
13665 +    {
13666 +        return NULL;
13667 +    }
13668 +
13669 +    virtual void releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED,
13670 +                                       gss_any_t input GSSEAP_UNUSED) const
13671 +    {
13672 +    }
13673 +
13674 +    /* prefix to be prepended to attributes emitted by gss_get_name_attribute */
13675 +    virtual const char *prefix(void) const
13676 +    {
13677 +        return NULL;
13678 +    }
13679 +
13680 +    /* optional key for storing JSON dictionary */
13681 +    virtual const char *name(void) const
13682 +    {
13683 +        return NULL;
13684 +    }
13685 +
13686 +    virtual bool initWithJsonObject(const gss_eap_attr_ctx *manager,
13687 +                                    JSONObject &object GSSEAP_UNUSED)
13688 +    {
13689 +        return initWithManager(manager);
13690 +    }
13691 +
13692 +
13693 +    virtual JSONObject jsonRepresentation(void) const
13694 +    {
13695 +        return JSONObject::null();
13696 +    }
13697 +
13698 +    virtual time_t getExpiryTime(void) const { return 0; }
13699 +
13700 +    virtual OM_uint32 mapException(OM_uint32 *minor GSSEAP_UNUSED,
13701 +                                   std::exception &e GSSEAP_UNUSED) const
13702 +    {
13703 +        return GSS_S_CONTINUE_NEEDED;
13704 +    }
13705 +
13706 +    static bool init(void) { return true; }
13707 +    static void finalize(void) {}
13708 +
13709 +    static gss_eap_attr_provider *createAttrContext(void) { return NULL; }
13710 +
13711 +protected:
13712 +    const gss_eap_attr_ctx *m_manager;
13713 +
13714 +private:
13715 +    /* make non-copyable */
13716 +    gss_eap_attr_provider(const gss_eap_attr_provider&);
13717 +    gss_eap_attr_provider& operator=(const gss_eap_attr_provider&);
13718 +};
13719 +
13720 +typedef gss_eap_attr_provider *(*gss_eap_attr_create_provider)(void);
13721 +
13722 +/*
13723 + * Attribute context: this manages a set of providers for a given
13724 + * security context.
13725 + */
13726 +struct gss_eap_attr_ctx
13727 +{
13728 +public:
13729 +    gss_eap_attr_ctx(void);
13730 +    ~gss_eap_attr_ctx(void);
13731 +
13732 +    bool initWithExistingContext(const gss_eap_attr_ctx *manager);
13733 +    bool initWithGssContext(const gss_cred_id_t cred,
13734 +                            const gss_ctx_id_t ctx);
13735 +
13736 +    bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const;
13737 +    bool getAttributeTypes(gss_buffer_set_t *attrs);
13738 +
13739 +    bool setAttribute(int complete,
13740 +                      const gss_buffer_t attr,
13741 +                      const gss_buffer_t value);
13742 +    bool deleteAttribute(const gss_buffer_t value);
13743 +    bool getAttribute(const gss_buffer_t attr,
13744 +                      int *authenticated,
13745 +                      int *complete,
13746 +                      gss_buffer_t value,
13747 +                      gss_buffer_t display_value,
13748 +                      int *more) const;
13749 +    gss_any_t mapToAny(int authenticated,
13750 +                       gss_buffer_t type_id) const;
13751 +    void releaseAnyNameMapping(gss_buffer_t type_id,
13752 +                               gss_any_t input) const;
13753 +
13754 +    void exportToBuffer(gss_buffer_t buffer) const;
13755 +    bool initWithBuffer(const gss_buffer_t buffer);
13756 +
13757 +    static std::string
13758 +    composeAttributeName(const gss_buffer_t prefix,
13759 +                         const gss_buffer_t suffix);
13760 +    static void
13761 +    decomposeAttributeName(const gss_buffer_t attribute,
13762 +                           gss_buffer_t prefix,
13763 +                           gss_buffer_t suffix);
13764 +    static void
13765 +    composeAttributeName(const gss_buffer_t prefix,
13766 +                         const gss_buffer_t suffix,
13767 +                         gss_buffer_t attribute);
13768 +
13769 +    std::string
13770 +    composeAttributeName(unsigned int type,
13771 +                         const gss_buffer_t suffix);
13772 +    void
13773 +    decomposeAttributeName(const gss_buffer_t attribute,
13774 +                           unsigned int *type,
13775 +                           gss_buffer_t suffix) const;
13776 +    void
13777 +    composeAttributeName(unsigned int type,
13778 +                         const gss_buffer_t suffix,
13779 +                         gss_buffer_t attribute) const;
13780 +
13781 +    gss_eap_attr_provider *getProvider(unsigned int type) const;
13782 +
13783 +    static void
13784 +    registerProvider(unsigned int type,
13785 +                     gss_eap_attr_create_provider factory);
13786 +    static void
13787 +    unregisterProvider(unsigned int type);
13788 +
13789 +    time_t getExpiryTime(void) const;
13790 +    OM_uint32 mapException(OM_uint32 *minor, std::exception &e) const;
13791 +
13792 +private:
13793 +    bool providerEnabled(unsigned int type) const;
13794 +    void releaseProvider(unsigned int type);
13795 +
13796 +    unsigned int attributePrefixToType(const gss_buffer_t prefix) const;
13797 +    gss_buffer_desc attributeTypeToPrefix(unsigned int type) const;
13798 +
13799 +    bool initWithJsonObject(JSONObject &object);
13800 +    JSONObject jsonRepresentation(void) const;
13801 +
13802 +    gss_eap_attr_provider *getPrimaryProvider(void) const;
13803 +
13804 +    /* make non-copyable */
13805 +    gss_eap_attr_ctx(const gss_eap_attr_ctx&);
13806 +    gss_eap_attr_ctx& operator=(const gss_eap_attr_ctx&);
13807 +
13808 +    uint32_t m_flags;
13809 +    gss_eap_attr_provider *m_providers[ATTR_TYPE_MAX + 1];
13810 +};
13811 +
13812 +#endif /* __cplusplus */
13813 +
13814 +#include "util_radius.h"
13815 +#include "util_saml.h"
13816 +#include "util_shib.h"
13817 +
13818 +#ifdef __cplusplus
13819 +
13820 +static inline void
13821 +duplicateBuffer(gss_buffer_desc &src, gss_buffer_t dst)
13822 +{
13823 +    OM_uint32 minor;
13824 +
13825 +    if (GSS_ERROR(duplicateBuffer(&minor, &src, dst)))
13826 +        throw std::bad_alloc();
13827 +}
13828 +
13829 +static inline void
13830 +duplicateBuffer(std::string &str, gss_buffer_t buffer)
13831 +{
13832 +    gss_buffer_desc tmp;
13833 +
13834 +    tmp.length = str.length();
13835 +    tmp.value = (char *)str.c_str();
13836 +
13837 +    duplicateBuffer(tmp, buffer);
13838 +}
13839 +
13840 +#else
13841 +struct gss_eap_attr_ctx;
13842 +#endif
13843 +
13844 +#ifdef __cplusplus
13845 +extern "C" {
13846 +#endif
13847 +
13848 +/*
13849 + * C wrappers for attribute context functions. These match their
13850 + * GSS naming extension equivalents. The caller is required to
13851 + * obtain the name mutex.
13852 + */
13853 +
13854 +OM_uint32
13855 +gssEapCreateAttrContext(OM_uint32 *minor,
13856 +                        gss_cred_id_t acceptorCred,
13857 +                        gss_ctx_id_t acceptorCtx,
13858 +                        struct gss_eap_attr_ctx **pAttrCtx,
13859 +                        time_t *pExpiryTime);
13860 +
13861 +OM_uint32
13862 +gssEapInquireName(OM_uint32 *minor,
13863 +                  gss_name_t name,
13864 +                  int *name_is_MN,
13865 +                  gss_OID *MN_mech,
13866 +                  gss_buffer_set_t *attrs);
13867 +
13868 +OM_uint32
13869 +gssEapGetNameAttribute(OM_uint32 *minor,
13870 +                       gss_name_t name,
13871 +                       gss_buffer_t attr,
13872 +                       int *authenticated,
13873 +                       int *complete,
13874 +                       gss_buffer_t value,
13875 +                       gss_buffer_t display_value,
13876 +                       int *more);
13877 +
13878 +OM_uint32
13879 +gssEapDeleteNameAttribute(OM_uint32 *minor,
13880 +                          gss_name_t name,
13881 +                          gss_buffer_t attr);
13882 +
13883 +OM_uint32
13884 +gssEapSetNameAttribute(OM_uint32 *minor,
13885 +                       gss_name_t name,
13886 +                       int complete,
13887 +                       gss_buffer_t attr,
13888 +                       gss_buffer_t value);
13889 +
13890 +OM_uint32
13891 +gssEapExportAttrContext(OM_uint32 *minor,
13892 +                        gss_name_t name,
13893 +                        gss_buffer_t buffer);
13894 +
13895 +OM_uint32
13896 +gssEapImportAttrContext(OM_uint32 *minor,
13897 +                        gss_buffer_t buffer,
13898 +                        gss_name_t name);
13899 +
13900 +OM_uint32
13901 +gssEapDuplicateAttrContext(OM_uint32 *minor,
13902 +                           gss_name_t in,
13903 +                           gss_name_t out);
13904 +
13905 +OM_uint32
13906 +gssEapMapNameToAny(OM_uint32 *minor,
13907 +                   gss_name_t name,
13908 +                   int authenticated,
13909 +                   gss_buffer_t type_id,
13910 +                   gss_any_t *output);
13911 +
13912 +OM_uint32
13913 +gssEapReleaseAnyNameMapping(OM_uint32 *minor,
13914 +                            gss_name_t name,
13915 +                            gss_buffer_t type_id,
13916 +                            gss_any_t *input);
13917 +
13918 +OM_uint32
13919 +gssEapReleaseAttrContext(OM_uint32 *minor,
13920 +                         gss_name_t name);
13921 +
13922 +OM_uint32
13923 +gssEapAttrProvidersFinalize(OM_uint32 *minor);
13924 +
13925 +#ifdef __cplusplus
13926 +}
13927 +#endif
13928 +
13929 +#endif /* _UTIL_ATTR_H_ */
13930 diff --git a/mech_eap/util_base64.c b/mech_eap/util_base64.c
13931 new file mode 100644
13932 index 0000000..aaa1ea8
13933 --- /dev/null
13934 +++ b/mech_eap/util_base64.c
13935 @@ -0,0 +1,161 @@
13936 +/*
13937 + * Copyright (c) 1995-2001 Kungliga Tekniska Högskolan
13938 + * (Royal Institute of Technology, Stockholm, Sweden).
13939 + * All rights reserved.
13940 + *
13941 + * Redistribution and use in source and binary forms, with or without
13942 + * modification, are permitted provided that the following conditions
13943 + * are met:
13944 + *
13945 + * 1. Redistributions of source code must retain the above copyright
13946 + *    notice, this list of conditions and the following disclaimer.
13947 + *
13948 + * 2. Redistributions in binary form must reproduce the above copyright
13949 + *    notice, this list of conditions and the following disclaimer in the
13950 + *    documentation and/or other materials provided with the distribution.
13951 + *
13952 + * 3. Neither the name of the Institute nor the names of its contributors
13953 + *    may be used to endorse or promote products derived from this software
13954 + *    without specific prior written permission.
13955 + *
13956 + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
13957 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13958 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13959 + * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
13960 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13961 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13962 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13963 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13964 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13965 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13966 + * SUCH DAMAGE.
13967 + */
13968 +
13969 +#include "gssapiP_eap.h"
13970 +
13971 +static const char base64_chars[] =
13972 +    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
13973 +
13974 +static int
13975 +pos(char c)
13976 +{
13977 +    const char *p;
13978 +    for (p = base64_chars; *p; p++)
13979 +       if (*p == c)
13980 +           return p - base64_chars;
13981 +    return -1;
13982 +}
13983 +
13984 +ssize_t
13985 +base64Encode(const void *data, int size, char **str)
13986 +{
13987 +    char *s, *p;
13988 +    int i;
13989 +    int c;
13990 +    const unsigned char *q;
13991 +
13992 +    if (size > INT_MAX/4 || size < 0) {
13993 +       *str = NULL;
13994 +       return -1;
13995 +    }
13996 +
13997 +    p = s = (char *)GSSEAP_MALLOC(BASE64_EXPAND(size));
13998 +    if (p == NULL) {
13999 +        *str = NULL;
14000 +       return -1;
14001 +    }
14002 +    q = (const unsigned char *) data;
14003 +
14004 +    for (i = 0; i < size;) {
14005 +       c = q[i++];
14006 +       c *= 256;
14007 +       if (i < size)
14008 +           c += q[i];
14009 +       i++;
14010 +       c *= 256;
14011 +       if (i < size)
14012 +           c += q[i];
14013 +       i++;
14014 +       p[0] = base64_chars[(c & 0x00fc0000) >> 18];
14015 +       p[1] = base64_chars[(c & 0x0003f000) >> 12];
14016 +       p[2] = base64_chars[(c & 0x00000fc0) >> 6];
14017 +       p[3] = base64_chars[(c & 0x0000003f) >> 0];
14018 +       if (i > size)
14019 +           p[3] = '=';
14020 +       if (i > size + 1)
14021 +           p[2] = '=';
14022 +       p += 4;
14023 +    }
14024 +    *p = 0;
14025 +    *str = s;
14026 +    return strlen(s);
14027 +}
14028 +
14029 +#define DECODE_ERROR 0xffffffff
14030 +
14031 +static unsigned int
14032 +token_decode(const char *token)
14033 +{
14034 +    int i;
14035 +    unsigned int val = 0;
14036 +    int marker = 0;
14037 +    if (strlen(token) < 4)
14038 +       return DECODE_ERROR;
14039 +    for (i = 0; i < 4; i++) {
14040 +       val *= 64;
14041 +       if (token[i] == '=')
14042 +           marker++;
14043 +       else if (marker > 0)
14044 +           return DECODE_ERROR;
14045 +       else
14046 +           val += pos(token[i]);
14047 +    }
14048 +    if (marker > 2)
14049 +       return DECODE_ERROR;
14050 +    return (marker << 24) | val;
14051 +}
14052 +
14053 +ssize_t
14054 +base64Decode(const char *str, void *data)
14055 +{
14056 +    const char *p;
14057 +    unsigned char *q;
14058 +
14059 +    q = data;
14060 +    p = str;
14061 +
14062 +    while (*p && *p && (*p == '=' || strchr(base64_chars, *p))) {
14063 +       unsigned int val = token_decode(p);
14064 +       unsigned int marker = (val >> 24) & 0xff;
14065 +       if (val == DECODE_ERROR)
14066 +           return -1;
14067 +       *q++ = (val >> 16) & 0xff;
14068 +       if (marker < 2)
14069 +           *q++ = (val >> 8) & 0xff;
14070 +       if (marker < 1)
14071 +           *q++ = val & 0xff;
14072 +       p += 4;
14073 +       if (*p == '\n')
14074 +           p++;
14075 +    }
14076 +    return q - (unsigned char *) data;
14077 +}
14078 +
14079 +int
14080 +base64Valid(const char *str)
14081 +{
14082 +    const char *p = str;
14083 +    int valid = 1;
14084 +
14085 +    while (*p && *p && (*p == '=' || strchr(base64_chars, *p))) {
14086 +       unsigned int val = token_decode(p);
14087 +       if (val == DECODE_ERROR) {
14088 +            valid = 0;
14089 +           break;
14090 +        }
14091 +       p += 4;
14092 +       if (*p == '\n')
14093 +           p++;
14094 +    }
14095 +    return valid;
14096 +}
14097 diff --git a/mech_eap/util_base64.h b/mech_eap/util_base64.h
14098 new file mode 100644
14099 index 0000000..d015efe
14100 --- /dev/null
14101 +++ b/mech_eap/util_base64.h
14102 @@ -0,0 +1,58 @@
14103 +/*
14104 + * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
14105 + * (Royal Institute of Technology, Stockholm, Sweden).
14106 + * All rights reserved.
14107 + *
14108 + * Redistribution and use in source and binary forms, with or without
14109 + * modification, are permitted provided that the following conditions
14110 + * are met:
14111 + *
14112 + * 1. Redistributions of source code must retain the above copyright
14113 + *    notice, this list of conditions and the following disclaimer.
14114 + *
14115 + * 2. Redistributions in binary form must reproduce the above copyright
14116 + *    notice, this list of conditions and the following disclaimer in the
14117 + *    documentation and/or other materials provided with the distribution.
14118 + *
14119 + * 3. Neither the name of the Institute nor the names of its contributors
14120 + *    may be used to endorse or promote products derived from this software
14121 + *    without specific prior written permission.
14122 + *
14123 + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
14124 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14125 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14126 + * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
14127 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14128 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14129 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14130 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14131 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14132 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14133 + * SUCH DAMAGE.
14134 + */
14135 +
14136 +/* $Id$ */
14137 +
14138 +#ifndef _UTIL_BASE64_H_
14139 +#define _UTIL_BASE64_H_
14140 +
14141 +#ifdef __cplusplus
14142 +extern "C" {
14143 +#endif
14144 +
14145 +ssize_t
14146 +base64Encode(const void *, int, char **);
14147 +
14148 +ssize_t
14149 +base64Decode(const char *, void *);
14150 +
14151 +int
14152 +base64Valid(const char *str);
14153 +
14154 +#define BASE64_EXPAND(n)        (n * 4 / 3 + 4)
14155 +
14156 +#ifdef __cplusplus
14157 +}
14158 +#endif
14159 +
14160 +#endif
14161 diff --git a/mech_eap/util_buffer.c b/mech_eap/util_buffer.c
14162 new file mode 100644
14163 index 0000000..e135db9
14164 --- /dev/null
14165 +++ b/mech_eap/util_buffer.c
14166 @@ -0,0 +1,103 @@
14167 +/*
14168 + * Copyright (c) 2011, JANET(UK)
14169 + * All rights reserved.
14170 + *
14171 + * Redistribution and use in source and binary forms, with or without
14172 + * modification, are permitted provided that the following conditions
14173 + * are met:
14174 + *
14175 + * 1. Redistributions of source code must retain the above copyright
14176 + *    notice, this list of conditions and the following disclaimer.
14177 + *
14178 + * 2. Redistributions in binary form must reproduce the above copyright
14179 + *    notice, this list of conditions and the following disclaimer in the
14180 + *    documentation and/or other materials provided with the distribution.
14181 + *
14182 + * 3. Neither the name of JANET(UK) nor the names of its contributors
14183 + *    may be used to endorse or promote products derived from this software
14184 + *    without specific prior written permission.
14185 + *
14186 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14187 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14188 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14189 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
14190 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14191 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14192 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14193 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14194 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14195 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14196 + * SUCH DAMAGE.
14197 + */
14198 +
14199 +/*
14200 + * Buffer handling helpers.
14201 + */
14202 +
14203 +#include "gssapiP_eap.h"
14204 +
14205 +OM_uint32
14206 +makeStringBuffer(OM_uint32 *minor,
14207 +                 const char *string,
14208 +                 gss_buffer_t buffer)
14209 +{
14210 +    size_t len = strlen(string);
14211 +
14212 +    buffer->value = GSSEAP_MALLOC(len + 1);
14213 +    if (buffer->value == NULL) {
14214 +        *minor = ENOMEM;
14215 +        return GSS_S_FAILURE;
14216 +    }
14217 +    memcpy(buffer->value, string, len + 1);
14218 +    buffer->length = len;
14219 +
14220 +    *minor = 0;
14221 +    return GSS_S_COMPLETE;
14222 +}
14223 +
14224 +OM_uint32
14225 +bufferToString(OM_uint32 *minor,
14226 +               const gss_buffer_t buffer,
14227 +               char **pString)
14228 +{
14229 +    char *s;
14230 +
14231 +    s = GSSEAP_MALLOC(buffer->length + 1);
14232 +    if (s == NULL) {
14233 +        *minor = ENOMEM;
14234 +        return GSS_S_FAILURE;
14235 +    }
14236 +    memcpy(s, buffer->value, buffer->length);
14237 +    s[buffer->length] = '\0';
14238 +
14239 +    *pString = s;
14240 +
14241 +    *minor = 0;
14242 +    return GSS_S_COMPLETE;
14243 +}
14244 +
14245 +OM_uint32
14246 +duplicateBuffer(OM_uint32 *minor,
14247 +                const gss_buffer_t src,
14248 +                gss_buffer_t dst)
14249 +{
14250 +    dst->length = 0;
14251 +    dst->value = NULL;
14252 +
14253 +    if (src == GSS_C_NO_BUFFER)
14254 +        return GSS_S_COMPLETE;
14255 +
14256 +    dst->value = GSSEAP_MALLOC(src->length + 1);
14257 +    if (dst->value == NULL) {
14258 +        *minor = ENOMEM;
14259 +        return GSS_S_FAILURE;
14260 +    }
14261 +
14262 +    dst->length = src->length;
14263 +    memcpy(dst->value, src->value, dst->length);
14264 +
14265 +    ((unsigned char *)dst->value)[dst->length] = '\0';
14266 +
14267 +    *minor = 0;
14268 +    return GSS_S_COMPLETE;
14269 +}
14270 diff --git a/mech_eap/util_cksum.c b/mech_eap/util_cksum.c
14271 new file mode 100644
14272 index 0000000..aedc93e
14273 --- /dev/null
14274 +++ b/mech_eap/util_cksum.c
14275 @@ -0,0 +1,242 @@
14276 +/*
14277 + * Copyright (c) 2011, JANET(UK)
14278 + * All rights reserved.
14279 + *
14280 + * Redistribution and use in source and binary forms, with or without
14281 + * modification, are permitted provided that the following conditions
14282 + * are met:
14283 + *
14284 + * 1. Redistributions of source code must retain the above copyright
14285 + *    notice, this list of conditions and the following disclaimer.
14286 + *
14287 + * 2. Redistributions in binary form must reproduce the above copyright
14288 + *    notice, this list of conditions and the following disclaimer in the
14289 + *    documentation and/or other materials provided with the distribution.
14290 + *
14291 + * 3. Neither the name of JANET(UK) nor the names of its contributors
14292 + *    may be used to endorse or promote products derived from this software
14293 + *    without specific prior written permission.
14294 + *
14295 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14296 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14297 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14298 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
14299 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14300 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14301 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14302 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14303 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14304 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14305 + * SUCH DAMAGE.
14306 + */
14307 +/*
14308 + * Copyright 1993 by OpenVision Technologies, Inc.
14309 + *
14310 + * Permission to use, copy, modify, distribute, and sell this software
14311 + * and its documentation for any purpose is hereby granted without fee,
14312 + * provided that the above copyright notice appears in all copies and
14313 + * that both that copyright notice and this permission notice appear in
14314 + * supporting documentation, and that the name of OpenVision not be used
14315 + * in advertising or publicity pertaining to distribution of the software
14316 + * without specific, written prior permission. OpenVision makes no
14317 + * representations about the suitability of this software for any
14318 + * purpose.  It is provided "as is" without express or implied warranty.
14319 + *
14320 + * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
14321 + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
14322 + * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
14323 + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
14324 + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14325 + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14326 + * PERFORMANCE OF THIS SOFTWARE.
14327 + */
14328 +
14329 +/*
14330 + * Message protection services: checksum helpers.
14331 + */
14332 +
14333 +#include "gssapiP_eap.h"
14334 +
14335 +static int
14336 +gssEapChecksum(krb5_context context,
14337 +               krb5_cksumtype type,
14338 +               size_t rrc,
14339 +#ifdef HAVE_HEIMDAL_VERSION
14340 +               krb5_crypto crypto,
14341 +#else
14342 +               krb5_keyblock *crypto,
14343 +#endif
14344 +               krb5_keyusage sign_usage,
14345 +               gss_iov_buffer_desc *iov,
14346 +               int iov_count,
14347 +               int verify,
14348 +               int *valid)
14349 +{
14350 +    krb5_error_code code;
14351 +    gss_iov_buffer_desc *header;
14352 +    gss_iov_buffer_desc *trailer;
14353 +    krb5_crypto_iov *kiov;
14354 +    size_t kiov_count;
14355 +    int i = 0, j;
14356 +    size_t k5_checksumlen;
14357 +
14358 +    if (verify)
14359 +        *valid = FALSE;
14360 +
14361 +    code = krbCryptoLength(context, crypto, KRB5_CRYPTO_TYPE_CHECKSUM, &k5_checksumlen);
14362 +    if (code != 0)
14363 +        return code;
14364 +
14365 +    header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
14366 +    GSSEAP_ASSERT(header != NULL);
14367 +
14368 +    trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
14369 +    GSSEAP_ASSERT(rrc != 0 || trailer != NULL);
14370 +
14371 +    if (trailer == NULL) {
14372 +        if (rrc != k5_checksumlen)
14373 +            return KRB5_BAD_MSIZE;
14374 +        if (header->buffer.length != 16 + k5_checksumlen)
14375 +            return KRB5_BAD_MSIZE;
14376 +    } else if (trailer->buffer.length != k5_checksumlen)
14377 +        return KRB5_BAD_MSIZE;
14378 +
14379 +    kiov_count = 2 + iov_count;
14380 +    kiov = (krb5_crypto_iov *)GSSEAP_MALLOC(kiov_count * sizeof(krb5_crypto_iov));
14381 +    if (kiov == NULL)
14382 +        return ENOMEM;
14383 +
14384 +    /* Checksum over ( Data | Header ) */
14385 +
14386 +    /* Data */
14387 +    for (j = 0; j < iov_count; j++) {
14388 +        kiov[i].flags = gssEapMapCryptoFlag(iov[j].type);
14389 +        kiov[i].data.length = iov[j].buffer.length;
14390 +        kiov[i].data.data = (char *)iov[j].buffer.value;
14391 +        i++;
14392 +    }
14393 +
14394 +    /* Header */
14395 +    kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
14396 +    kiov[i].data.length = 16;
14397 +    kiov[i].data.data = (char *)header->buffer.value;
14398 +    i++;
14399 +
14400 +    /* Checksum */
14401 +    kiov[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
14402 +    if (trailer == NULL) {
14403 +        kiov[i].data.length = header->buffer.length - 16;
14404 +        kiov[i].data.data = (char *)header->buffer.value + 16;
14405 +    } else {
14406 +        kiov[i].data.length = trailer->buffer.length;
14407 +        kiov[i].data.data = (char *)trailer->buffer.value;
14408 +    }
14409 +    i++;
14410 +
14411 +#ifdef HAVE_HEIMDAL_VERSION
14412 +    if (verify) {
14413 +        code = krb5_verify_checksum_iov(context, crypto, sign_usage,
14414 +                                        kiov, kiov_count, &type);
14415 +        *valid = (code == 0);
14416 +    } else {
14417 +        code = krb5_create_checksum_iov(context, crypto, sign_usage,
14418 +                                        kiov, kiov_count, &type);
14419 +    }
14420 +#else
14421 +    if (verify) {
14422 +        krb5_boolean kvalid = FALSE;
14423 +
14424 +        code = krb5_c_verify_checksum_iov(context, type, crypto,
14425 +                                          sign_usage, kiov, kiov_count, &kvalid);
14426 +
14427 +        *valid = kvalid;
14428 +    } else {
14429 +        code = krb5_c_make_checksum_iov(context, type, crypto,
14430 +                                        sign_usage, kiov, kiov_count);
14431 +    }
14432 +#endif /* HAVE_HEIMDAL_VERSION */
14433 +
14434 +    GSSEAP_FREE(kiov);
14435 +
14436 +    return code;
14437 +}
14438 +
14439 +int
14440 +gssEapSign(krb5_context context,
14441 +           krb5_cksumtype type,
14442 +           size_t rrc,
14443 +#ifdef HAVE_HEIMDAL_VERSION
14444 +           krb5_crypto crypto,
14445 +#else
14446 +           krb5_keyblock *crypto,
14447 +#endif
14448 +           krb5_keyusage sign_usage,
14449 +           gss_iov_buffer_desc *iov,
14450 +           int iov_count)
14451 +{
14452 +    return gssEapChecksum(context, type, rrc, crypto,
14453 +                          sign_usage, iov, iov_count, 0, NULL);
14454 +}
14455 +
14456 +int
14457 +gssEapVerify(krb5_context context,
14458 +             krb5_cksumtype type,
14459 +             size_t rrc,
14460 +#ifdef HAVE_HEIMDAL_VERSION
14461 +             krb5_crypto crypto,
14462 +#else
14463 +             krb5_keyblock *crypto,
14464 +#endif
14465 +             krb5_keyusage sign_usage,
14466 +             gss_iov_buffer_desc *iov,
14467 +             int iov_count,
14468 +             int *valid)
14469 +{
14470 +    return gssEapChecksum(context, type, rrc, crypto,
14471 +                          sign_usage, iov, iov_count, 1, valid);
14472 +}
14473 +
14474 +#if 0
14475 +OM_uint32
14476 +gssEapEncodeGssChannelBindings(OM_uint32 *minor,
14477 +                               gss_channel_bindings_t chanBindings,
14478 +                               gss_buffer_t encodedBindings)
14479 +{
14480 +    OM_uint32 major, tmpMinor;
14481 +    size_t length;
14482 +    unsigned char *p;
14483 +
14484 +    if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS) {
14485 +        length = 24;
14486 +        length += chanBindings->initiator_address.length;
14487 +        length += chanBindings->acceptor_address.length;
14488 +        length += chanBindings->application_data.length;
14489 +
14490 +        encodedBindings->value = GSSEAP_MALLOC(length);
14491 +        if (encodedBindings->value == NULL) {
14492 +            *minor = ENOMEM;
14493 +            return GSS_S_FAILURE;
14494 +        }
14495 +
14496 +        encodedBindings->length = length;
14497 +        p = (unsigned char *)encodedBindings->value;
14498 +
14499 +        store_uint32_be(chanBindings->initiator_addrtype, p);
14500 +        store_buffer(&chanBindings->initiator_address, p + 4, 0);
14501 +        p += 4 + chanBindings->initiator_address.length;
14502 +
14503 +        store_uint32_be(chanBindings->acceptor_addrtype, p);
14504 +        store_buffer(&chanBindings->acceptor_address, p + 4, 0);
14505 +        p += 4 + chanBindings->acceptor_address.length;
14506 +
14507 +        store_buffer(&chanBindings->application_data, p, 1);
14508 +        p += chanBindings->application_data.length;
14509 +    } else {
14510 +        encodedBindings->length = 0;
14511 +        encodedBindings->value = NULL;
14512 +    }
14513 +
14514 +    *minor = 0;
14515 +    return GSS_S_COMPLETE;
14516 +}
14517 +#endif
14518 diff --git a/mech_eap/util_context.c b/mech_eap/util_context.c
14519 new file mode 100644
14520 index 0000000..e18edc5
14521 --- /dev/null
14522 +++ b/mech_eap/util_context.c
14523 @@ -0,0 +1,377 @@
14524 +/*
14525 + * Copyright (c) 2011, JANET(UK)
14526 + * All rights reserved.
14527 + *
14528 + * Redistribution and use in source and binary forms, with or without
14529 + * modification, are permitted provided that the following conditions
14530 + * are met:
14531 + *
14532 + * 1. Redistributions of source code must retain the above copyright
14533 + *    notice, this list of conditions and the following disclaimer.
14534 + *
14535 + * 2. Redistributions in binary form must reproduce the above copyright
14536 + *    notice, this list of conditions and the following disclaimer in the
14537 + *    documentation and/or other materials provided with the distribution.
14538 + *
14539 + * 3. Neither the name of JANET(UK) nor the names of its contributors
14540 + *    may be used to endorse or promote products derived from this software
14541 + *    without specific prior written permission.
14542 + *
14543 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14544 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14545 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14546 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
14547 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14548 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14549 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14550 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14551 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14552 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14553 + * SUCH DAMAGE.
14554 + */
14555 +
14556 +/*
14557 + * Utility routines for context handles.
14558 + */
14559 +
14560 +#include "gssapiP_eap.h"
14561 +
14562 +OM_uint32
14563 +gssEapAllocContext(OM_uint32 *minor,
14564 +                   gss_ctx_id_t *pCtx)
14565 +{
14566 +    OM_uint32 tmpMinor;
14567 +    gss_ctx_id_t ctx;
14568 +
14569 +    GSSEAP_ASSERT(*pCtx == GSS_C_NO_CONTEXT);
14570 +
14571 +    ctx = (gss_ctx_id_t)GSSEAP_CALLOC(1, sizeof(*ctx));
14572 +    if (ctx == NULL) {
14573 +        *minor = ENOMEM;
14574 +        return GSS_S_FAILURE;
14575 +    }
14576 +
14577 +    if (GSSEAP_MUTEX_INIT(&ctx->mutex) != 0) {
14578 +        *minor = GSSEAP_GET_LAST_ERROR();
14579 +        gssEapReleaseContext(&tmpMinor, &ctx);
14580 +        return GSS_S_FAILURE;
14581 +    }
14582 +
14583 +    ctx->state = GSSEAP_STATE_INITIAL;
14584 +    ctx->mechanismUsed = GSS_C_NO_OID;
14585 +
14586 +    /*
14587 +     * Integrity, confidentiality, sequencing and replay detection are
14588 +     * always available.  Regardless of what flags are requested in
14589 +     * GSS_Init_sec_context, implementations MUST set the flag corresponding
14590 +     * to these services in the output of GSS_Init_sec_context and
14591 +     * GSS_Accept_sec_context.
14592 +    */
14593 +    ctx->gssFlags = GSS_C_TRANS_FLAG    |   /* exporting contexts */
14594 +                    GSS_C_INTEG_FLAG    |   /* integrity */
14595 +                    GSS_C_CONF_FLAG     |   /* confidentiality */
14596 +                    GSS_C_SEQUENCE_FLAG |   /* sequencing */
14597 +                    GSS_C_REPLAY_FLAG;      /* replay detection */
14598 +
14599 +    *pCtx = ctx;
14600 +
14601 +    return GSS_S_COMPLETE;
14602 +}
14603 +
14604 +static void
14605 +releaseInitiatorContext(struct gss_eap_initiator_ctx *ctx)
14606 +{
14607 +    eap_peer_sm_deinit(ctx->eap);
14608 +}
14609 +
14610 +#ifdef GSSEAP_ENABLE_ACCEPTOR
14611 +static void
14612 +releaseAcceptorContext(struct gss_eap_acceptor_ctx *ctx)
14613 +{
14614 +    OM_uint32 tmpMinor;
14615 +
14616 +    if (ctx->radConn != NULL)
14617 +        rs_conn_destroy(ctx->radConn);
14618 +    if (ctx->radContext != NULL)
14619 +        rs_context_destroy(ctx->radContext);
14620 +    if (ctx->radServer != NULL)
14621 +        GSSEAP_FREE(ctx->radServer);
14622 +    gss_release_buffer(&tmpMinor, &ctx->state);
14623 +    if (ctx->vps != NULL)
14624 +        gssEapRadiusFreeAvps(&tmpMinor, &ctx->vps);
14625 +}
14626 +#endif /* GSSEAP_ENABLE_ACCEPTOR */
14627 +
14628 +OM_uint32
14629 +gssEapReleaseContext(OM_uint32 *minor,
14630 +                     gss_ctx_id_t *pCtx)
14631 +{
14632 +    OM_uint32 tmpMinor;
14633 +    gss_ctx_id_t ctx = *pCtx;
14634 +    krb5_context krbContext = NULL;
14635 +
14636 +    if (ctx == GSS_C_NO_CONTEXT) {
14637 +        return GSS_S_COMPLETE;
14638 +    }
14639 +
14640 +    gssEapKerberosInit(&tmpMinor, &krbContext);
14641 +
14642 +#ifdef GSSEAP_ENABLE_REAUTH
14643 +    if (ctx->flags & CTX_FLAG_KRB_REAUTH) {
14644 +        gssDeleteSecContext(&tmpMinor, &ctx->reauthCtx, GSS_C_NO_BUFFER);
14645 +    } else
14646 +#endif /* GSSEAP_ENABLE_REAUTH */
14647 +    if (CTX_IS_INITIATOR(ctx)) {
14648 +        releaseInitiatorContext(&ctx->initiatorCtx);
14649 +    }
14650 +#ifdef GSSEAP_ENABLE_ACCEPTOR
14651 +    else {
14652 +        releaseAcceptorContext(&ctx->acceptorCtx);
14653 +    }
14654 +#endif /* GSSEAP_ENABLE_ACCEPTOR */
14655 +
14656 +    krb5_free_keyblock_contents(krbContext, &ctx->rfc3961Key);
14657 +    gssEapReleaseName(&tmpMinor, &ctx->initiatorName);
14658 +    gssEapReleaseName(&tmpMinor, &ctx->acceptorName);
14659 +    gssEapReleaseOid(&tmpMinor, &ctx->mechanismUsed);
14660 +    sequenceFree(&tmpMinor, &ctx->seqState);
14661 +    gssEapReleaseCred(&tmpMinor, &ctx->cred);
14662 +
14663 +    GSSEAP_MUTEX_DESTROY(&ctx->mutex);
14664 +
14665 +    memset(ctx, 0, sizeof(*ctx));
14666 +    GSSEAP_FREE(ctx);
14667 +    *pCtx = GSS_C_NO_CONTEXT;
14668 +
14669 +    *minor = 0;
14670 +    return GSS_S_COMPLETE;
14671 +}
14672 +
14673 +OM_uint32
14674 +gssEapMakeToken(OM_uint32 *minor,
14675 +                gss_ctx_id_t ctx,
14676 +                const gss_buffer_t innerToken,
14677 +                enum gss_eap_token_type tokenType,
14678 +                gss_buffer_t outputToken)
14679 +{
14680 +    unsigned char *p;
14681 +
14682 +    GSSEAP_ASSERT(ctx->mechanismUsed != GSS_C_NO_OID);
14683 +
14684 +    outputToken->length = tokenSize(ctx->mechanismUsed, innerToken->length);
14685 +    outputToken->value = GSSEAP_MALLOC(outputToken->length);
14686 +    if (outputToken->value == NULL) {
14687 +        *minor = ENOMEM;
14688 +        return GSS_S_FAILURE;
14689 +    }
14690 +
14691 +    p = (unsigned char *)outputToken->value;
14692 +    makeTokenHeader(ctx->mechanismUsed, innerToken->length, &p, tokenType);
14693 +    memcpy(p, innerToken->value, innerToken->length);
14694 +
14695 +    *minor = 0;
14696 +    return GSS_S_COMPLETE;
14697 +}
14698 +
14699 +OM_uint32
14700 +gssEapVerifyToken(OM_uint32 *minor,
14701 +                  gss_ctx_id_t ctx,
14702 +                  const gss_buffer_t inputToken,
14703 +                  enum gss_eap_token_type *actualToken,
14704 +                  gss_buffer_t innerInputToken)
14705 +{
14706 +    OM_uint32 major;
14707 +    size_t bodySize;
14708 +    unsigned char *p = (unsigned char *)inputToken->value;
14709 +    gss_OID_desc oidBuf;
14710 +    gss_OID oid;
14711 +
14712 +    if (ctx->mechanismUsed != GSS_C_NO_OID) {
14713 +        oid = ctx->mechanismUsed;
14714 +    } else {
14715 +        oidBuf.elements = NULL;
14716 +        oidBuf.length = 0;
14717 +        oid = &oidBuf;
14718 +    }
14719 +
14720 +    major = verifyTokenHeader(minor, oid, &bodySize, &p,
14721 +                              inputToken->length, actualToken);
14722 +    if (GSS_ERROR(major))
14723 +        return major;
14724 +
14725 +    if (ctx->mechanismUsed == GSS_C_NO_OID) {
14726 +        major = gssEapCanonicalizeOid(minor, oid, 0, &ctx->mechanismUsed);
14727 +        if (GSS_ERROR(major))
14728 +            return major;
14729 +    }
14730 +
14731 +    innerInputToken->length = bodySize;
14732 +    innerInputToken->value = p;
14733 +
14734 +    *minor = 0;
14735 +    return GSS_S_COMPLETE;
14736 +}
14737 +
14738 +OM_uint32
14739 +gssEapContextTime(OM_uint32 *minor,
14740 +                  gss_ctx_id_t context_handle,
14741 +                  OM_uint32 *time_rec)
14742 +{
14743 +    *minor = 0;
14744 +
14745 +    if (context_handle->expiryTime == 0) {
14746 +        *time_rec = GSS_C_INDEFINITE;
14747 +    } else {
14748 +        time_t now, lifetime;
14749 +
14750 +        time(&now);
14751 +        lifetime = context_handle->expiryTime - now;
14752 +        if (lifetime <= 0) {
14753 +            *time_rec = 0;
14754 +            return GSS_S_CONTEXT_EXPIRED;
14755 +        }
14756 +        *time_rec = lifetime;
14757 +    }
14758 +
14759 +    return GSS_S_COMPLETE;
14760 +}
14761 +
14762 +static OM_uint32
14763 +gssEapMakeOrVerifyTokenMIC(OM_uint32 *minor,
14764 +                           gss_ctx_id_t ctx,
14765 +                           gss_buffer_t tokenMIC,
14766 +                           int verifyMIC)
14767 +{
14768 +    OM_uint32 major;
14769 +    gss_iov_buffer_desc *iov = NULL;
14770 +    size_t i = 0, j;
14771 +    enum gss_eap_token_type tokType;
14772 +    OM_uint32 micTokType;
14773 +    unsigned char wireTokType[2];
14774 +    unsigned char *innerTokTypes = NULL, *innerTokLengths = NULL;
14775 +    const struct gss_eap_token_buffer_set *tokens;
14776 +
14777 +    tokens = verifyMIC ? ctx->inputTokens : ctx->outputTokens;
14778 +
14779 +    GSSEAP_ASSERT(tokens != NULL);
14780 +
14781 +    iov = GSSEAP_CALLOC(2 + (3 * tokens->buffers.count) + 1, sizeof(*iov));
14782 +    if (iov == NULL) {
14783 +        major = GSS_S_FAILURE;
14784 +        *minor = ENOMEM;
14785 +        goto cleanup;
14786 +    }
14787 +
14788 +    innerTokTypes = GSSEAP_MALLOC(4 * tokens->buffers.count);
14789 +    if (innerTokTypes == NULL) {
14790 +        *minor = ENOMEM;
14791 +        major = GSS_S_FAILURE;
14792 +        goto cleanup;
14793 +    }
14794 +
14795 +    innerTokLengths = GSSEAP_MALLOC(4 * tokens->buffers.count);
14796 +    if (innerTokLengths == NULL) {
14797 +        major = GSS_S_FAILURE;
14798 +        *minor = ENOMEM;
14799 +        goto cleanup;
14800 +    }
14801 +
14802 +    /* Mechanism OID */
14803 +    GSSEAP_ASSERT(ctx->mechanismUsed != GSS_C_NO_OID);
14804 +    iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
14805 +    iov[i].buffer.length = ctx->mechanismUsed->length;
14806 +    iov[i].buffer.value = ctx->mechanismUsed->elements;
14807 +    i++;
14808 +
14809 +    /* Token type */
14810 +    if (CTX_IS_INITIATOR(ctx) ^ verifyMIC) {
14811 +        tokType = TOK_TYPE_INITIATOR_CONTEXT;
14812 +        micTokType = ITOK_TYPE_INITIATOR_MIC;
14813 +    } else {
14814 +        tokType = TOK_TYPE_ACCEPTOR_CONTEXT;
14815 +        micTokType = ITOK_TYPE_ACCEPTOR_MIC;
14816 +    }
14817 +    store_uint16_be(tokType, wireTokType);
14818 +
14819 +    iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
14820 +    iov[i].buffer.length = sizeof(wireTokType);
14821 +    iov[i].buffer.value = wireTokType;
14822 +    i++;
14823 +
14824 +    for (j = 0; j < tokens->buffers.count; j++) {
14825 +        if (verifyMIC &&
14826 +            (tokens->types[j] & ITOK_TYPE_MASK) == micTokType)
14827 +            continue; /* will use this slot for trailer */
14828 +
14829 +        iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
14830 +        iov[i].buffer.length = 4;
14831 +        iov[i].buffer.value = &innerTokTypes[j * 4];
14832 +        store_uint32_be(tokens->types[j] & ~(ITOK_FLAG_VERIFIED),
14833 +                        iov[i].buffer.value);
14834 +        i++;
14835 +
14836 +        iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
14837 +        iov[i].buffer.length = 4;
14838 +        iov[i].buffer.value = &innerTokLengths[j * 4];
14839 +        store_uint32_be(tokens->buffers.elements[j].length,
14840 +                        iov[i].buffer.value);
14841 +        i++;
14842 +
14843 +        iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
14844 +        iov[i].buffer = tokens->buffers.elements[j];
14845 +        i++;
14846 +    }
14847 +
14848 +    if (verifyMIC) {
14849 +        GSSEAP_ASSERT(tokenMIC->length >= 16);
14850 +
14851 +        GSSEAP_ASSERT(i < 2 + (3 * tokens->buffers.count));
14852 +
14853 +        iov[i].type = GSS_IOV_BUFFER_TYPE_HEADER;
14854 +        iov[i].buffer = *tokenMIC;
14855 +        i++;
14856 +
14857 +        major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
14858 +                                        iov, i, TOK_TYPE_MIC);
14859 +    } else {
14860 +        iov[i++].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
14861 +        major = gssEapWrapOrGetMIC(minor, ctx, FALSE, NULL,
14862 +                                   iov, i, TOK_TYPE_MIC);
14863 +        if (!GSS_ERROR(major))
14864 +            *tokenMIC = iov[i - 1].buffer;
14865 +    }
14866 +
14867 +cleanup:
14868 +    if (iov != NULL)
14869 +        gssEapReleaseIov(iov, tokens->buffers.count);
14870 +    if (innerTokTypes != NULL)
14871 +        GSSEAP_FREE(innerTokTypes);
14872 +    if (innerTokLengths != NULL)
14873 +        GSSEAP_FREE(innerTokLengths);
14874 +
14875 +    return major;
14876 +}
14877 +
14878 +OM_uint32
14879 +gssEapMakeTokenMIC(OM_uint32 *minor,
14880 +                   gss_ctx_id_t ctx,
14881 +                   gss_buffer_t tokenMIC)
14882 +{
14883 +    tokenMIC->length = 0;
14884 +    tokenMIC->value = NULL;
14885 +
14886 +    return gssEapMakeOrVerifyTokenMIC(minor, ctx, tokenMIC, FALSE);
14887 +}
14888 +
14889 +OM_uint32
14890 +gssEapVerifyTokenMIC(OM_uint32 *minor,
14891 +                     gss_ctx_id_t ctx,
14892 +                     const gss_buffer_t tokenMIC)
14893 +{
14894 +    if (tokenMIC->length < 16) {
14895 +        *minor = GSSEAP_TOK_TRUNC;
14896 +        return GSS_S_BAD_SIG;
14897 +    }
14898 +
14899 +    return gssEapMakeOrVerifyTokenMIC(minor, ctx, tokenMIC, TRUE);
14900 +}
14901 diff --git a/mech_eap/util_cred.c b/mech_eap/util_cred.c
14902 new file mode 100644
14903 index 0000000..746bd61
14904 --- /dev/null
14905 +++ b/mech_eap/util_cred.c
14906 @@ -0,0 +1,756 @@
14907 +/*
14908 + * Copyright (c) 2011, JANET(UK)
14909 + * All rights reserved.
14910 + *
14911 + * Redistribution and use in source and binary forms, with or without
14912 + * modification, are permitted provided that the following conditions
14913 + * are met:
14914 + *
14915 + * 1. Redistributions of source code must retain the above copyright
14916 + *    notice, this list of conditions and the following disclaimer.
14917 + *
14918 + * 2. Redistributions in binary form must reproduce the above copyright
14919 + *    notice, this list of conditions and the following disclaimer in the
14920 + *    documentation and/or other materials provided with the distribution.
14921 + *
14922 + * 3. Neither the name of JANET(UK) nor the names of its contributors
14923 + *    may be used to endorse or promote products derived from this software
14924 + *    without specific prior written permission.
14925 + *
14926 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14927 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14928 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14929 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
14930 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14931 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14932 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
14933 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14934 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
14935 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14936 + * SUCH DAMAGE.
14937 + */
14938 +
14939 +/*
14940 + * Utility routines for credential handles.
14941 + */
14942 +
14943 +#include "gssapiP_eap.h"
14944 +
14945 +#ifdef WIN32
14946 +# include <shlobj.h>     /* may need to use ShFolder.h instead */
14947 +# include <stdio.h>
14948 +#else
14949 +# include <pwd.h>
14950 +#endif
14951 +
14952 +OM_uint32
14953 +gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred)
14954 +{
14955 +    OM_uint32 tmpMinor;
14956 +    gss_cred_id_t cred;
14957 +
14958 +    *pCred = GSS_C_NO_CREDENTIAL;
14959 +
14960 +    cred = (gss_cred_id_t)GSSEAP_CALLOC(1, sizeof(*cred));
14961 +    if (cred == NULL) {
14962 +        *minor = ENOMEM;
14963 +        return GSS_S_FAILURE;
14964 +    }
14965 +
14966 +    if (GSSEAP_MUTEX_INIT(&cred->mutex) != 0) {
14967 +        *minor = GSSEAP_GET_LAST_ERROR();
14968 +        gssEapReleaseCred(&tmpMinor, &cred);
14969 +        return GSS_S_FAILURE;
14970 +    }
14971 +
14972 +    *pCred = cred;
14973 +
14974 +    *minor = 0;
14975 +    return GSS_S_COMPLETE;
14976 +}
14977 +
14978 +static void
14979 +zeroAndReleasePassword(gss_buffer_t password)
14980 +{
14981 +    if (password->value != NULL) {
14982 +        memset(password->value, 0, password->length);
14983 +        GSSEAP_FREE(password->value);
14984 +    }
14985 +
14986 +    password->value = NULL;
14987 +    password->length = 0;
14988 +}
14989 +
14990 +OM_uint32
14991 +gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred)
14992 +{
14993 +    OM_uint32 tmpMinor;
14994 +    gss_cred_id_t cred = *pCred;
14995 +    krb5_context krbContext = NULL;
14996 +
14997 +    if (cred == GSS_C_NO_CREDENTIAL) {
14998 +        return GSS_S_COMPLETE;
14999 +    }
15000 +
15001 +    GSSEAP_KRB_INIT(&krbContext);
15002 +
15003 +    gssEapReleaseName(&tmpMinor, &cred->name);
15004 +    gssEapReleaseName(&tmpMinor, &cred->target);
15005 +
15006 +    zeroAndReleasePassword(&cred->password);
15007 +
15008 +    gss_release_buffer(&tmpMinor, &cred->radiusConfigFile);
15009 +    gss_release_buffer(&tmpMinor, &cred->radiusConfigStanza);
15010 +    gss_release_buffer(&tmpMinor, &cred->caCertificate);
15011 +    gss_release_buffer(&tmpMinor, &cred->subjectNameConstraint);
15012 +    gss_release_buffer(&tmpMinor, &cred->subjectAltNameConstraint);
15013 +
15014 +#ifdef GSSEAP_ENABLE_REAUTH
15015 +    if (cred->krbCredCache != NULL) {
15016 +        if (cred->flags & CRED_FLAG_DEFAULT_CCACHE)
15017 +            krb5_cc_close(krbContext, cred->krbCredCache);
15018 +        else
15019 +            krb5_cc_destroy(krbContext, cred->krbCredCache);
15020 +    }
15021 +    if (cred->reauthCred != GSS_C_NO_CREDENTIAL)
15022 +        gssReleaseCred(&tmpMinor, &cred->reauthCred);
15023 +#endif
15024 +
15025 +    GSSEAP_MUTEX_DESTROY(&cred->mutex);
15026 +    memset(cred, 0, sizeof(*cred));
15027 +    GSSEAP_FREE(cred);
15028 +    *pCred = NULL;
15029 +
15030 +    *minor = 0;
15031 +    return GSS_S_COMPLETE;
15032 +}
15033 +
15034 +static OM_uint32
15035 +readStaticIdentityFile(OM_uint32 *minor,
15036 +                       gss_buffer_t defaultIdentity,
15037 +                       gss_buffer_t defaultPassword)
15038 +{
15039 +    OM_uint32 major, tmpMinor;
15040 +    FILE *fp = NULL;
15041 +    char buf[BUFSIZ];
15042 +    char *ccacheName;
15043 +    int i = 0;
15044 +#ifndef WIN32
15045 +    struct passwd *pw = NULL, pwd;
15046 +    char pwbuf[BUFSIZ];
15047 +#endif
15048 +
15049 +    defaultIdentity->length = 0;
15050 +    defaultIdentity->value = NULL;
15051 +
15052 +    if (defaultPassword != GSS_C_NO_BUFFER) {
15053 +        defaultPassword->length = 0;
15054 +        defaultPassword->value = NULL;
15055 +    }
15056 +
15057 +    ccacheName = getenv("GSSEAP_IDENTITY");
15058 +    if (ccacheName == NULL) {
15059 +#ifdef WIN32
15060 +        TCHAR szPath[MAX_PATH];
15061 +
15062 +        if (!SUCCEEDED(SHGetFolderPath(NULL,
15063 +                                       CSIDL_APPDATA, /* |CSIDL_FLAG_CREATE */
15064 +                                       NULL, /* User access token */
15065 +                                       0,    /* SHGFP_TYPE_CURRENT */
15066 +                                       szPath))) {
15067 +            major = GSS_S_CRED_UNAVAIL;
15068 +            *minor = GSSEAP_GET_LAST_ERROR(); /* XXX */
15069 +            goto cleanup;
15070 +        }
15071 +
15072 +        snprintf(buf, sizeof(buf), "%s/.gss_eap_id", szPath);
15073 +#else
15074 +        if (getpwuid_r(getuid(), &pwd, pwbuf, sizeof(pwbuf), &pw) != 0 ||
15075 +            pw == NULL || pw->pw_dir == NULL) {
15076 +            major = GSS_S_CRED_UNAVAIL;
15077 +            *minor = GSSEAP_GET_LAST_ERROR();
15078 +            goto cleanup;
15079 +        }
15080 +
15081 +        snprintf(buf, sizeof(buf), "%s/.gss_eap_id", pw->pw_dir);
15082 +#endif /* WIN32 */
15083 +        ccacheName = buf;
15084 +    }
15085 +
15086 +    fp = fopen(ccacheName, "r");
15087 +    if (fp == NULL) {
15088 +        major = GSS_S_CRED_UNAVAIL;
15089 +        *minor = GSSEAP_NO_DEFAULT_CRED;
15090 +        goto cleanup;
15091 +    }
15092 +
15093 +    while (fgets(buf, sizeof(buf), fp) != NULL) {
15094 +        gss_buffer_desc src, *dst;
15095 +
15096 +        src.length = strlen(buf);
15097 +        src.value = buf;
15098 +
15099 +        if (src.length == 0)
15100 +            break;
15101 +
15102 +        if (buf[src.length - 1] == '\n') {
15103 +            buf[src.length - 1] = '\0';
15104 +            if (--src.length == 0)
15105 +                break;
15106 +        }
15107 +
15108 +        if (i == 0)
15109 +            dst = defaultIdentity;
15110 +        else if (i == 1)
15111 +            dst = defaultPassword;
15112 +        else
15113 +            break;
15114 +
15115 +        if (dst != GSS_C_NO_BUFFER) {
15116 +            major = duplicateBuffer(minor, &src, dst);
15117 +            if (GSS_ERROR(major))
15118 +                goto cleanup;
15119 +        }
15120 +
15121 +        i++;
15122 +    }
15123 +
15124 +    if (defaultIdentity->length == 0) {
15125 +        major = GSS_S_CRED_UNAVAIL;
15126 +        *minor = GSSEAP_NO_DEFAULT_CRED;
15127 +        goto cleanup;
15128 +    }
15129 +
15130 +    major = GSS_S_COMPLETE;
15131 +    *minor = 0;
15132 +
15133 +cleanup:
15134 +    if (fp != NULL)
15135 +        fclose(fp);
15136 +
15137 +    if (GSS_ERROR(major)) {
15138 +        gss_release_buffer(&tmpMinor, defaultIdentity);
15139 +        zeroAndReleasePassword(defaultPassword);
15140 +    }
15141 +
15142 +    memset(buf, 0, sizeof(buf));
15143 +
15144 +    return major;
15145 +}
15146 +
15147 +gss_OID
15148 +gssEapPrimaryMechForCred(gss_cred_id_t cred)
15149 +{
15150 +    gss_OID nameMech = GSS_C_NO_OID;
15151 +
15152 +    if (cred->mechanisms != GSS_C_NO_OID_SET &&
15153 +        cred->mechanisms->count == 1)
15154 +        nameMech = &cred->mechanisms->elements[0];
15155 +
15156 +    return nameMech;
15157 +}
15158 +
15159 +OM_uint32
15160 +gssEapAcquireCred(OM_uint32 *minor,
15161 +                  const gss_name_t desiredName,
15162 +                  OM_uint32 timeReq GSSEAP_UNUSED,
15163 +                  const gss_OID_set desiredMechs,
15164 +                  int credUsage,
15165 +                  gss_cred_id_t *pCred,
15166 +                  gss_OID_set *pActualMechs,
15167 +                  OM_uint32 *timeRec)
15168 +{
15169 +    OM_uint32 major, tmpMinor;
15170 +    gss_cred_id_t cred;
15171 +
15172 +    /* XXX TODO validate with changed set_cred_option API */
15173 +    *pCred = GSS_C_NO_CREDENTIAL;
15174 +
15175 +    major = gssEapAllocCred(minor, &cred);
15176 +    if (GSS_ERROR(major))
15177 +        goto cleanup;
15178 +
15179 +    switch (credUsage) {
15180 +    case GSS_C_BOTH:
15181 +        cred->flags |= CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT;
15182 +        break;
15183 +    case GSS_C_INITIATE:
15184 +        cred->flags |= CRED_FLAG_INITIATE;
15185 +        break;
15186 +    case GSS_C_ACCEPT:
15187 +        cred->flags |= CRED_FLAG_ACCEPT;
15188 +        break;
15189 +    default:
15190 +        major = GSS_S_FAILURE;
15191 +        *minor = GSSEAP_BAD_USAGE;
15192 +        goto cleanup;
15193 +        break;
15194 +    }
15195 +
15196 +    major = gssEapValidateMechs(minor, desiredMechs);
15197 +    if (GSS_ERROR(major))
15198 +        goto cleanup;
15199 +
15200 +    major = duplicateOidSet(minor, desiredMechs, &cred->mechanisms);
15201 +    if (GSS_ERROR(major))
15202 +        goto cleanup;
15203 +
15204 +    if (desiredName != GSS_C_NO_NAME) {
15205 +        GSSEAP_MUTEX_LOCK(&desiredName->mutex);
15206 +
15207 +        major = gssEapDuplicateName(minor, desiredName, &cred->name);
15208 +        if (GSS_ERROR(major)) {
15209 +            GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
15210 +            goto cleanup;
15211 +        }
15212 +
15213 +        GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
15214 +    }
15215 +
15216 +#ifdef GSSEAP_ENABLE_ACCEPTOR
15217 +    if (cred->flags & CRED_FLAG_ACCEPT) {
15218 +        struct rs_context *radContext;
15219 +
15220 +        major = gssEapCreateRadiusContext(minor, cred, &radContext);
15221 +        if (GSS_ERROR(major))
15222 +            goto cleanup;
15223 +
15224 +        rs_context_destroy(radContext);
15225 +    }
15226 +#endif
15227 +
15228 +    if (pActualMechs != NULL) {
15229 +        major = duplicateOidSet(minor, cred->mechanisms, pActualMechs);
15230 +        if (GSS_ERROR(major))
15231 +            goto cleanup;
15232 +    }
15233 +
15234 +    if (timeRec != NULL)
15235 +        *timeRec = GSS_C_INDEFINITE;
15236 +
15237 +    *pCred = cred;
15238 +
15239 +    major = GSS_S_COMPLETE;
15240 +    *minor = 0;
15241 +
15242 +cleanup:
15243 +    if (GSS_ERROR(major))
15244 +        gssEapReleaseCred(&tmpMinor, &cred);
15245 +
15246 +    return major;
15247 +}
15248 +
15249 +/*
15250 + * Return TRUE if cred available for mechanism. Caller need no acquire
15251 + * lock because mechanisms list is immutable.
15252 + */
15253 +int
15254 +gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech)
15255 +{
15256 +    OM_uint32 minor;
15257 +    int present = 0;
15258 +
15259 +    GSSEAP_ASSERT(mech != GSS_C_NO_OID);
15260 +
15261 +    if (cred == GSS_C_NO_CREDENTIAL || cred->mechanisms == GSS_C_NO_OID_SET)
15262 +        return TRUE;
15263 +
15264 +    gss_test_oid_set_member(&minor, mech, cred->mechanisms, &present);
15265 +
15266 +    return present;
15267 +}
15268 +
15269 +static OM_uint32
15270 +staticIdentityFileResolveDefaultIdentity(OM_uint32 *minor,
15271 +                                         const gss_cred_id_t cred,
15272 +                                         gss_name_t *pName)
15273 +{
15274 +    OM_uint32 major, tmpMinor;
15275 +    gss_OID nameMech = gssEapPrimaryMechForCred(cred);
15276 +    gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
15277 +
15278 +    *pName = GSS_C_NO_NAME;
15279 +
15280 +    major = readStaticIdentityFile(minor, &defaultIdentity, GSS_C_NO_BUFFER);
15281 +    if (major == GSS_S_COMPLETE) {
15282 +        major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
15283 +                                 nameMech, pName);
15284 +    }
15285 +
15286 +    gss_release_buffer(&tmpMinor, &defaultIdentity);
15287 +
15288 +    return major;
15289 +}
15290 +
15291 +static OM_uint32
15292 +gssEapResolveCredIdentity(OM_uint32 *minor,
15293 +                          gss_cred_id_t cred)
15294 +{
15295 +    OM_uint32 major;
15296 +    gss_OID nameMech = gssEapPrimaryMechForCred(cred);
15297 +
15298 +    if (cred->name != GSS_C_NO_NAME) {
15299 +        *minor = 0;
15300 +        return GSS_S_COMPLETE;
15301 +    }
15302 +
15303 +    if (cred->flags & CRED_FLAG_ACCEPT) {
15304 +        gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
15305 +        char serviceName[5 + MAXHOSTNAMELEN];
15306 +
15307 +        /* default host-based service is host@localhost */
15308 +        memcpy(serviceName, "host@", 5);
15309 +        if (gethostname(&serviceName[5], MAXHOSTNAMELEN) != 0) {
15310 +            *minor = GSSEAP_NO_HOSTNAME;
15311 +            return GSS_S_FAILURE;
15312 +        }
15313 +
15314 +        nameBuf.value = serviceName;
15315 +        nameBuf.length = strlen((char *)nameBuf.value);
15316 +
15317 +        major = gssEapImportName(minor, &nameBuf, GSS_C_NT_HOSTBASED_SERVICE,
15318 +                                 nameMech, &cred->name);
15319 +        if (GSS_ERROR(major))
15320 +            return major;
15321 +    } else if (cred->flags & CRED_FLAG_INITIATE) {
15322 +#ifdef HAVE_MOONSHOT_GET_IDENTITY
15323 +        major = libMoonshotResolveDefaultIdentity(minor, cred, &cred->name);
15324 +        if (major == GSS_S_CRED_UNAVAIL)
15325 +#endif
15326 +            major = staticIdentityFileResolveDefaultIdentity(minor, cred, &cred->name);
15327 +        if (major != GSS_S_CRED_UNAVAIL)
15328 +            return major;
15329 +    }
15330 +
15331 +    *minor = 0;
15332 +    return GSS_S_COMPLETE;
15333 +}
15334 +
15335 +OM_uint32
15336 +gssEapInquireCred(OM_uint32 *minor,
15337 +                  gss_cred_id_t cred,
15338 +                  gss_name_t *name,
15339 +                  OM_uint32 *pLifetime,
15340 +                  gss_cred_usage_t *cred_usage,
15341 +                  gss_OID_set *mechanisms)
15342 +{
15343 +    OM_uint32 major;
15344 +    time_t now, lifetime;
15345 +
15346 +    if (name != NULL) {
15347 +        major = gssEapResolveCredIdentity(minor, cred);
15348 +        if (GSS_ERROR(major))
15349 +            goto cleanup;
15350 +
15351 +        if (cred->name != GSS_C_NO_NAME) {
15352 +            major = gssEapDuplicateName(minor, cred->name, name);
15353 +            if (GSS_ERROR(major))
15354 +                goto cleanup;
15355 +        } else
15356 +            *name = GSS_C_NO_NAME;
15357 +    }
15358 +
15359 +    if (cred_usage != NULL) {
15360 +        OM_uint32 flags = (cred->flags & (CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT));
15361 +
15362 +        switch (flags) {
15363 +        case CRED_FLAG_INITIATE:
15364 +            *cred_usage = GSS_C_INITIATE;
15365 +            break;
15366 +        case CRED_FLAG_ACCEPT:
15367 +            *cred_usage = GSS_C_ACCEPT;
15368 +            break;
15369 +        default:
15370 +            *cred_usage = GSS_C_BOTH;
15371 +            break;
15372 +        }
15373 +    }
15374 +
15375 +    if (mechanisms != NULL) {
15376 +        if (cred->mechanisms != GSS_C_NO_OID_SET)
15377 +            major = duplicateOidSet(minor, cred->mechanisms, mechanisms);
15378 +        else
15379 +            major = gssEapIndicateMechs(minor, mechanisms);
15380 +        if (GSS_ERROR(major))
15381 +            goto cleanup;
15382 +    }
15383 +
15384 +    if (cred->expiryTime == 0) {
15385 +        lifetime = GSS_C_INDEFINITE;
15386 +    } else  {
15387 +        now = time(NULL);
15388 +        lifetime = now - cred->expiryTime;
15389 +        if (lifetime < 0)
15390 +            lifetime = 0;
15391 +    }
15392 +
15393 +    if (pLifetime != NULL) {
15394 +        *pLifetime = lifetime;
15395 +    }
15396 +
15397 +    if (lifetime == 0) {
15398 +        major = GSS_S_CREDENTIALS_EXPIRED;
15399 +        *minor = GSSEAP_CRED_EXPIRED;
15400 +        goto cleanup;
15401 +    }
15402 +
15403 +    major = GSS_S_COMPLETE;
15404 +    *minor = 0;
15405 +
15406 +cleanup:
15407 +    return major;
15408 +}
15409 +
15410 +OM_uint32
15411 +gssEapSetCredPassword(OM_uint32 *minor,
15412 +                      gss_cred_id_t cred,
15413 +                      const gss_buffer_t password)
15414 +{
15415 +    OM_uint32 major, tmpMinor;
15416 +    gss_buffer_desc newPassword = GSS_C_EMPTY_BUFFER;
15417 +
15418 +    if (cred->flags & CRED_FLAG_RESOLVED) {
15419 +        major = GSS_S_FAILURE;
15420 +        *minor = GSSEAP_CRED_RESOLVED;
15421 +        goto cleanup;
15422 +    }
15423 +
15424 +    if (password != GSS_C_NO_BUFFER) {
15425 +        major = duplicateBuffer(minor, password, &newPassword);
15426 +        if (GSS_ERROR(major))
15427 +            goto cleanup;
15428 +
15429 +        cred->flags |= CRED_FLAG_PASSWORD;
15430 +    } else {
15431 +        cred->flags &= ~(CRED_FLAG_PASSWORD);
15432 +    }
15433 +
15434 +    gss_release_buffer(&tmpMinor, &cred->password);
15435 +    cred->password = newPassword;
15436 +
15437 +    major = GSS_S_COMPLETE;
15438 +    *minor = 0;
15439 +
15440 +cleanup:
15441 +    return major;
15442 +}
15443 +
15444 +OM_uint32
15445 +gssEapSetCredService(OM_uint32 *minor,
15446 +                     gss_cred_id_t cred,
15447 +                     const gss_name_t target)
15448 +{
15449 +    OM_uint32 major, tmpMinor;
15450 +    gss_name_t newTarget = GSS_C_NO_NAME;
15451 +
15452 +    if (cred->flags & CRED_FLAG_RESOLVED) {
15453 +        major = GSS_S_FAILURE;
15454 +        *minor = GSSEAP_CRED_RESOLVED;
15455 +        goto cleanup;
15456 +    }
15457 +
15458 +    if (target != GSS_C_NO_NAME) {
15459 +        major = gssEapDuplicateName(minor, target, &newTarget);
15460 +        if (GSS_ERROR(major))
15461 +            goto cleanup;
15462 +
15463 +        cred->flags |= CRED_FLAG_TARGET;
15464 +    } else {
15465 +        cred->flags &= ~(CRED_FLAG_TARGET);
15466 +    }
15467 +
15468 +    gssEapReleaseName(&tmpMinor, &cred->target);
15469 +    cred->target = newTarget;
15470 +
15471 +    major = GSS_S_COMPLETE;
15472 +    *minor = 0;
15473 +
15474 +cleanup:
15475 +    return major;
15476 +}
15477 +
15478 +static OM_uint32
15479 +gssEapDuplicateCred(OM_uint32 *minor,
15480 +                    const gss_cred_id_t src,
15481 +                    gss_cred_id_t *pDst)
15482 +{
15483 +    OM_uint32 major, tmpMinor;
15484 +    gss_cred_id_t dst = GSS_C_NO_CREDENTIAL;
15485 +
15486 +    *pDst = GSS_C_NO_CREDENTIAL;
15487 +
15488 +    major = gssEapAllocCred(minor, &dst);
15489 +    if (GSS_ERROR(major))
15490 +        goto cleanup;
15491 +
15492 +    dst->flags = src->flags;
15493 +
15494 +    if (src->name != GSS_C_NO_NAME) {
15495 +        major = gssEapDuplicateName(minor, src->name, &dst->name);
15496 +        if (GSS_ERROR(major))
15497 +            goto cleanup;
15498 +    }
15499 +
15500 +    if (src->target != GSS_C_NO_NAME) {
15501 +        major = gssEapDuplicateName(minor, src->target, &dst->target);
15502 +        if (GSS_ERROR(major))
15503 +            goto cleanup;
15504 +    }
15505 +
15506 +    if (src->password.value != NULL) {
15507 +        major = duplicateBuffer(minor, &src->password, &dst->password);
15508 +        if (GSS_ERROR(major))
15509 +            goto cleanup;
15510 +    }
15511 +
15512 +    major = duplicateOidSet(minor, src->mechanisms, &dst->mechanisms);
15513 +    if (GSS_ERROR(major))
15514 +        goto cleanup;
15515 +
15516 +    dst->expiryTime = src->expiryTime;
15517 +
15518 +    if (src->radiusConfigFile.value != NULL)
15519 +        duplicateBufferOrCleanup(&src->radiusConfigFile, &dst->radiusConfigFile);
15520 +    if (src->radiusConfigStanza.value != NULL)
15521 +        duplicateBufferOrCleanup(&src->radiusConfigStanza, &dst->radiusConfigStanza);
15522 +    if (src->caCertificate.value != NULL)
15523 +        duplicateBufferOrCleanup(&src->caCertificate, &dst->caCertificate);
15524 +    if (src->subjectNameConstraint.value != NULL)
15525 +        duplicateBufferOrCleanup(&src->subjectNameConstraint, &dst->subjectNameConstraint);
15526 +    if (src->subjectAltNameConstraint.value != NULL)
15527 +        duplicateBufferOrCleanup(&src->subjectAltNameConstraint, &dst->subjectAltNameConstraint);
15528 +
15529 +#ifdef GSSEAP_ENABLE_REAUTH
15530 +    /* XXX krbCredCache, reauthCred */
15531 +#endif
15532 +
15533 +    *pDst = dst;
15534 +    dst = GSS_C_NO_CREDENTIAL;
15535 +
15536 +    major = GSS_S_COMPLETE;
15537 +    *minor = 0;
15538 +
15539 +cleanup:
15540 +    gssEapReleaseCred(&tmpMinor, &dst);
15541 +
15542 +    return major;
15543 +}
15544 +
15545 +static OM_uint32
15546 +staticIdentityFileResolveInitiatorCred(OM_uint32 *minor, gss_cred_id_t cred)
15547 +{
15548 +    OM_uint32 major, tmpMinor;
15549 +    gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
15550 +    gss_name_t defaultIdentityName = GSS_C_NO_NAME;
15551 +    gss_buffer_desc defaultPassword = GSS_C_EMPTY_BUFFER;
15552 +    int isDefaultIdentity = FALSE;
15553 +
15554 +    major = readStaticIdentityFile(minor, &defaultIdentity, &defaultPassword);
15555 +    if (GSS_ERROR(major))
15556 +        goto cleanup;
15557 +
15558 +    major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
15559 +                             gssEapPrimaryMechForCred(cred), &defaultIdentityName);
15560 +    if (GSS_ERROR(major))
15561 +        goto cleanup;
15562 +
15563 +    if (defaultIdentityName == GSS_C_NO_NAME) {
15564 +        if (cred->name == GSS_C_NO_NAME) {
15565 +            major = GSS_S_CRED_UNAVAIL;
15566 +            *minor = GSSEAP_NO_DEFAULT_IDENTITY;
15567 +            goto cleanup;
15568 +        }
15569 +    } else {
15570 +        if (cred->name == GSS_C_NO_NAME) {
15571 +            cred->name = defaultIdentityName;
15572 +            defaultIdentityName = GSS_C_NO_NAME;
15573 +            isDefaultIdentity = TRUE;
15574 +        } else {
15575 +            major = gssEapCompareName(minor, cred->name,
15576 +                                      defaultIdentityName, &isDefaultIdentity);
15577 +            if (GSS_ERROR(major))
15578 +                goto cleanup;
15579 +        }
15580 +    }
15581 +
15582 +    if (isDefaultIdentity &&
15583 +        (cred->flags & CRED_FLAG_PASSWORD) == 0) {
15584 +        major = gssEapSetCredPassword(minor, cred, &defaultPassword);
15585 +        if (GSS_ERROR(major))
15586 +            goto cleanup;
15587 +    }
15588 +
15589 +cleanup:
15590 +    gssEapReleaseName(&tmpMinor, &defaultIdentityName);
15591 +    zeroAndReleasePassword(&defaultPassword);
15592 +    gss_release_buffer(&tmpMinor, &defaultIdentity);
15593 +
15594 +    return major;
15595 +}
15596 +
15597 +OM_uint32
15598 +gssEapResolveInitiatorCred(OM_uint32 *minor,
15599 +                           const gss_cred_id_t cred,
15600 +                           const gss_name_t targetName
15601 +#ifndef HAVE_MOONSHOT_GET_IDENTITY
15602 +                                                       GSSEAP_UNUSED
15603 +#endif
15604 +                           ,
15605 +                           gss_cred_id_t *pResolvedCred)
15606 +{
15607 +    OM_uint32 major, tmpMinor;
15608 +    gss_cred_id_t resolvedCred = GSS_C_NO_CREDENTIAL;
15609 +
15610 +    if (cred == GSS_C_NO_CREDENTIAL) {
15611 +        major = gssEapAcquireCred(minor,
15612 +                                  GSS_C_NO_NAME,
15613 +                                  GSS_C_INDEFINITE,
15614 +                                  GSS_C_NO_OID_SET,
15615 +                                  GSS_C_INITIATE,
15616 +                                  &resolvedCred,
15617 +                                  NULL,
15618 +                                  NULL);
15619 +        if (GSS_ERROR(major))
15620 +            goto cleanup;
15621 +    } else {
15622 +        if ((cred->flags & CRED_FLAG_INITIATE) == 0) {
15623 +            major = GSS_S_NO_CRED;
15624 +            *minor = GSSEAP_CRED_USAGE_MISMATCH;
15625 +            goto cleanup;
15626 +        }
15627 +
15628 +        major = gssEapDuplicateCred(minor, cred, &resolvedCred);
15629 +        if (GSS_ERROR(major))
15630 +            goto cleanup;
15631 +    }
15632 +
15633 +    if ((resolvedCred->flags & CRED_FLAG_RESOLVED) == 0) {
15634 +#ifdef HAVE_MOONSHOT_GET_IDENTITY
15635 +        major = libMoonshotResolveInitiatorCred(minor, resolvedCred, targetName);
15636 +        if (major == GSS_S_CRED_UNAVAIL)
15637 +#endif
15638 +            major = staticIdentityFileResolveInitiatorCred(minor, resolvedCred);
15639 +        if (GSS_ERROR(major) && major != GSS_S_CRED_UNAVAIL)
15640 +            goto cleanup;
15641 +
15642 +        /* If we have a caller-supplied password, the credential is resolved. */
15643 +        if ((resolvedCred->flags & CRED_FLAG_PASSWORD) == 0) {
15644 +            major = GSS_S_CRED_UNAVAIL;
15645 +            *minor = GSSEAP_NO_DEFAULT_CRED;
15646 +            goto cleanup;
15647 +        }
15648 +
15649 +        resolvedCred->flags |= CRED_FLAG_RESOLVED;
15650 +    }
15651 +
15652 +    *pResolvedCred = resolvedCred;
15653 +    resolvedCred = GSS_C_NO_CREDENTIAL;
15654 +
15655 +    major = GSS_S_COMPLETE;
15656 +    *minor = 0;
15657 +
15658 +cleanup:
15659 +    gssEapReleaseCred(&tmpMinor, &resolvedCred);
15660 +
15661 +    return major;
15662 +}
15663 diff --git a/mech_eap/util_crypt.c b/mech_eap/util_crypt.c
15664 new file mode 100644
15665 index 0000000..b6e203e
15666 --- /dev/null
15667 +++ b/mech_eap/util_crypt.c
15668 @@ -0,0 +1,397 @@
15669 +/*
15670 + * Copyright (c) 2011, JANET(UK)
15671 + * All rights reserved.
15672 + *
15673 + * Redistribution and use in source and binary forms, with or without
15674 + * modification, are permitted provided that the following conditions
15675 + * are met:
15676 + *
15677 + * 1. Redistributions of source code must retain the above copyright
15678 + *    notice, this list of conditions and the following disclaimer.
15679 + *
15680 + * 2. Redistributions in binary form must reproduce the above copyright
15681 + *    notice, this list of conditions and the following disclaimer in the
15682 + *    documentation and/or other materials provided with the distribution.
15683 + *
15684 + * 3. Neither the name of JANET(UK) nor the names of its contributors
15685 + *    may be used to endorse or promote products derived from this software
15686 + *    without specific prior written permission.
15687 + *
15688 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15689 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15690 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15691 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
15692 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
15693 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
15694 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
15695 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
15696 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
15697 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
15698 + * SUCH DAMAGE.
15699 + */
15700 +/*
15701 + * Copyright 2001, 2008 by the Massachusetts Institute of Technology.
15702 + * Copyright 1993 by OpenVision Technologies, Inc.
15703 + *
15704 + * Permission to use, copy, modify, distribute, and sell this software
15705 + * and its documentation for any purpose is hereby granted without fee,
15706 + * provided that the above copyright notice appears in all copies and
15707 + * that both that copyright notice and this permission notice appear in
15708 + * supporting documentation, and that the name of OpenVision not be used
15709 + * in advertising or publicity pertaining to distribution of the software
15710 + * without specific, written prior permission. OpenVision makes no
15711 + * representations about the suitability of this software for any
15712 + * purpose.  It is provided "as is" without express or implied warranty.
15713 + *
15714 + * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15715 + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
15716 + * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
15717 + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
15718 + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
15719 + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15720 + * PERFORMANCE OF THIS SOFTWARE.
15721 + */
15722 +/*
15723 + * Copyright (C) 1998 by the FundsXpress, INC.
15724 + *
15725 + * All rights reserved.
15726 + *
15727 + * Export of this software from the United States of America may require
15728 + * a specific license from the United States Government.  It is the
15729 + * responsibility of any person or organization contemplating export to
15730 + * obtain such a license before exporting.
15731 + *
15732 + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
15733 + * distribute this software and its documentation for any purpose and
15734 + * without fee is hereby granted, provided that the above copyright
15735 + * notice appear in all copies and that both that copyright notice and
15736 + * this permission notice appear in supporting documentation, and that
15737 + * the name of FundsXpress. not be used in advertising or publicity pertaining
15738 + * to distribution of the software without specific, written prior
15739 + * permission.  FundsXpress makes no representations about the suitability of
15740 + * this software for any purpose.  It is provided "as is" without express
15741 + * or implied warranty.
15742 + *
15743 + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15744 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15745 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
15746 + */
15747 +
15748 +/*
15749 + * Message protection services: cryptography helpers.
15750 + */
15751 +
15752 +#include "gssapiP_eap.h"
15753 +
15754 +/*
15755 + * DCE_STYLE indicates actual RRC is EC + RRC
15756 + * EC is extra rotate count for DCE_STYLE, pad length otherwise
15757 + * RRC is rotate count.
15758 + */
15759 +static krb5_error_code
15760 +mapIov(krb5_context context, int dce_style, size_t ec, size_t rrc,
15761 +#ifdef HAVE_HEIMDAL_VERSION
15762 +       krb5_crypto crypto,
15763 +#else
15764 +       krb5_keyblock *crypto,
15765 +#endif
15766 +       gss_iov_buffer_desc *iov,
15767 +       int iov_count, krb5_crypto_iov **pkiov,
15768 +       size_t *pkiov_count)
15769 +{
15770 +    gss_iov_buffer_t header;
15771 +    gss_iov_buffer_t trailer;
15772 +    int i = 0, j;
15773 +    size_t kiov_count;
15774 +    krb5_crypto_iov *kiov;
15775 +    size_t k5_headerlen = 0, k5_trailerlen = 0;
15776 +    size_t gss_headerlen, gss_trailerlen;
15777 +    krb5_error_code code;
15778 +
15779 +    *pkiov = NULL;
15780 +    *pkiov_count = 0;
15781 +
15782 +    header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
15783 +    GSSEAP_ASSERT(header != NULL);
15784 +
15785 +    trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
15786 +    GSSEAP_ASSERT(trailer == NULL || rrc == 0);
15787 +
15788 +    code = krbCryptoLength(context, crypto, KRB5_CRYPTO_TYPE_HEADER, &k5_headerlen);
15789 +    if (code != 0)
15790 +        return code;
15791 +
15792 +    code = krbCryptoLength(context, crypto, KRB5_CRYPTO_TYPE_TRAILER, &k5_trailerlen);
15793 +    if (code != 0)
15794 +        return code;
15795 +
15796 +    /* Check header and trailer sizes */
15797 +    gss_headerlen = 16 /* GSS-Header */ + k5_headerlen; /* Kerb-Header */
15798 +    gss_trailerlen = ec + 16 /* E(GSS-Header) */ + k5_trailerlen; /* Kerb-Trailer */
15799 +
15800 +    /* If we're caller without a trailer, we must rotate by trailer length */
15801 +    if (trailer == NULL) {
15802 +        size_t actual_rrc = rrc;
15803 +
15804 +        if (dce_style)
15805 +            actual_rrc += ec; /* compensate for Windows bug */
15806 +
15807 +        if (actual_rrc != gss_trailerlen)
15808 +            return KRB5_BAD_MSIZE;
15809 +
15810 +        gss_headerlen += gss_trailerlen;
15811 +        gss_trailerlen = 0;
15812 +    } else {
15813 +        if (trailer->buffer.length != gss_trailerlen)
15814 +            return KRB5_BAD_MSIZE;
15815 +    }
15816 +
15817 +    if (header->buffer.length != gss_headerlen)
15818 +        return KRB5_BAD_MSIZE;
15819 +
15820 +    kiov_count = 3 + iov_count;
15821 +    kiov = (krb5_crypto_iov *)GSSEAP_MALLOC(kiov_count * sizeof(krb5_crypto_iov));
15822 +    if (kiov == NULL)
15823 +        return ENOMEM;
15824 +
15825 +    /*
15826 +     * The krb5 header is located at the end of the GSS header.
15827 +     */
15828 +    kiov[i].flags = KRB5_CRYPTO_TYPE_HEADER;
15829 +    kiov[i].data.length = k5_headerlen;
15830 +    kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - k5_headerlen;
15831 +    i++;
15832 +
15833 +    for (j = 0; j < iov_count; j++) {
15834 +        kiov[i].flags = gssEapMapCryptoFlag(iov[j].type);
15835 +        if (kiov[i].flags == KRB5_CRYPTO_TYPE_EMPTY)
15836 +            continue;
15837 +
15838 +        kiov[i].data.length = iov[j].buffer.length;
15839 +        kiov[i].data.data = (char *)iov[j].buffer.value;
15840 +        i++;
15841 +    }
15842 +
15843 +    /*
15844 +     * The EC and encrypted GSS header are placed in the trailer, which may
15845 +     * be rotated directly after the plaintext header if no trailer buffer
15846 +     * is provided.
15847 +     */
15848 +    kiov[i].flags = KRB5_CRYPTO_TYPE_DATA;
15849 +    kiov[i].data.length = ec + 16; /* E(Header) */
15850 +    if (trailer == NULL)
15851 +        kiov[i].data.data = (char *)header->buffer.value + 16;
15852 +    else
15853 +        kiov[i].data.data = (char *)trailer->buffer.value;
15854 +    i++;
15855 +
15856 +    /*
15857 +     * The krb5 trailer is placed after the encrypted copy of the
15858 +     * krb5 header (which may be in the GSS header or trailer).
15859 +     */
15860 +    kiov[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
15861 +    kiov[i].data.length = k5_trailerlen;
15862 +    kiov[i].data.data = (char *)kiov[i - 1].data.data + ec + 16; /* E(Header) */
15863 +    i++;
15864 +
15865 +    *pkiov = kiov;
15866 +    *pkiov_count = i;
15867 +
15868 +    return 0;
15869 +}
15870 +
15871 +int
15872 +gssEapEncrypt(krb5_context context,
15873 +              int dce_style,
15874 +              size_t ec,
15875 +              size_t rrc,
15876 +#ifdef HAVE_HEIMDAL_VERSION
15877 +              krb5_crypto crypto,
15878 +#else
15879 +              krb5_keyblock *crypto,
15880 +#endif
15881 +              int usage,
15882 +              gss_iov_buffer_desc *iov,
15883 +              int iov_count)
15884 +{
15885 +    krb5_error_code code;
15886 +    size_t kiov_count;
15887 +    krb5_crypto_iov *kiov = NULL;
15888 +
15889 +    code = mapIov(context, dce_style, ec, rrc, crypto,
15890 +                  iov, iov_count, &kiov, &kiov_count);
15891 +    if (code != 0)
15892 +        goto cleanup;
15893 +
15894 +#ifdef HAVE_HEIMDAL_VERSION
15895 +    code = krb5_encrypt_iov_ivec(context, crypto, usage, kiov, kiov_count, NULL);
15896 +#else
15897 +    code = krb5_c_encrypt_iov(context, crypto, usage, NULL, kiov, kiov_count);
15898 +#endif
15899 +    if (code != 0)
15900 +        goto cleanup;
15901 +
15902 +cleanup:
15903 +    if (kiov != NULL)
15904 +        GSSEAP_FREE(kiov);
15905 +
15906 +    return code;
15907 +}
15908 +
15909 +int
15910 +gssEapDecrypt(krb5_context context,
15911 +              int dce_style,
15912 +              size_t ec,
15913 +              size_t rrc,
15914 +#ifdef HAVE_HEIMDAL_VERSION
15915 +              krb5_crypto crypto,
15916 +#else
15917 +              krb5_keyblock *crypto,
15918 +#endif
15919 +              int usage,
15920 +              gss_iov_buffer_desc *iov,
15921 +              int iov_count)
15922 +{
15923 +    krb5_error_code code;
15924 +    size_t kiov_count;
15925 +    krb5_crypto_iov *kiov;
15926 +
15927 +    code = mapIov(context, dce_style, ec, rrc, crypto,
15928 +                  iov, iov_count, &kiov, &kiov_count);
15929 +    if (code != 0)
15930 +        goto cleanup;
15931 +
15932 +#ifdef HAVE_HEIMDAL_VERSION
15933 +    code = krb5_decrypt_iov_ivec(context, crypto, usage, kiov, kiov_count, NULL);
15934 +#else
15935 +    code = krb5_c_decrypt_iov(context, crypto, usage, NULL, kiov, kiov_count);
15936 +#endif
15937 +
15938 +cleanup:
15939 +    if (kiov != NULL)
15940 +        GSSEAP_FREE(kiov);
15941 +
15942 +    return code;
15943 +}
15944 +
15945 +int
15946 +gssEapMapCryptoFlag(OM_uint32 type)
15947 +{
15948 +    int ktype;
15949 +
15950 +    switch (GSS_IOV_BUFFER_TYPE(type)) {
15951 +    case GSS_IOV_BUFFER_TYPE_DATA:
15952 +    case GSS_IOV_BUFFER_TYPE_PADDING:
15953 +        ktype = KRB5_CRYPTO_TYPE_DATA;
15954 +        break;
15955 +    case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
15956 +        ktype = KRB5_CRYPTO_TYPE_SIGN_ONLY;
15957 +        break;
15958 +    default:
15959 +        ktype = KRB5_CRYPTO_TYPE_EMPTY;
15960 +        break;
15961 +    }
15962 +
15963 +    return ktype;
15964 +}
15965 +
15966 +gss_iov_buffer_t
15967 +gssEapLocateIov(gss_iov_buffer_desc *iov, int iov_count, OM_uint32 type)
15968 +{
15969 +    int i;
15970 +    gss_iov_buffer_t p = GSS_C_NO_IOV_BUFFER;
15971 +
15972 +    if (iov == GSS_C_NO_IOV_BUFFER)
15973 +        return GSS_C_NO_IOV_BUFFER;
15974 +
15975 +    for (i = iov_count - 1; i >= 0; i--) {
15976 +        if (GSS_IOV_BUFFER_TYPE(iov[i].type) == type) {
15977 +            if (p == GSS_C_NO_IOV_BUFFER)
15978 +                p = &iov[i];
15979 +            else
15980 +                return GSS_C_NO_IOV_BUFFER;
15981 +        }
15982 +    }
15983 +
15984 +    return p;
15985 +}
15986 +
15987 +void
15988 +gssEapIovMessageLength(gss_iov_buffer_desc *iov,
15989 +                       int iov_count,
15990 +                       size_t *data_length_p,
15991 +                       size_t *assoc_data_length_p)
15992 +{
15993 +    int i;
15994 +    size_t data_length = 0, assoc_data_length = 0;
15995 +
15996 +    GSSEAP_ASSERT(iov != GSS_C_NO_IOV_BUFFER);
15997 +
15998 +    *data_length_p = *assoc_data_length_p = 0;
15999 +
16000 +    for (i = 0; i < iov_count; i++) {
16001 +        OM_uint32 type = GSS_IOV_BUFFER_TYPE(iov[i].type);
16002 +
16003 +        if (type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
16004 +            assoc_data_length += iov[i].buffer.length;
16005 +
16006 +        if (type == GSS_IOV_BUFFER_TYPE_DATA ||
16007 +            type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
16008 +            data_length += iov[i].buffer.length;
16009 +    }
16010 +
16011 +    *data_length_p = data_length;
16012 +    *assoc_data_length_p = assoc_data_length;
16013 +}
16014 +
16015 +void
16016 +gssEapReleaseIov(gss_iov_buffer_desc *iov, int iov_count)
16017 +{
16018 +    int i;
16019 +    OM_uint32 min_stat;
16020 +
16021 +    GSSEAP_ASSERT(iov != GSS_C_NO_IOV_BUFFER);
16022 +
16023 +    for (i = 0; i < iov_count; i++) {
16024 +        if (iov[i].type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {
16025 +            gss_release_buffer(&min_stat, &iov[i].buffer);
16026 +            iov[i].type &= ~(GSS_IOV_BUFFER_FLAG_ALLOCATED);
16027 +        }
16028 +    }
16029 +}
16030 +
16031 +int
16032 +gssEapIsIntegrityOnly(gss_iov_buffer_desc *iov, int iov_count)
16033 +{
16034 +    int i;
16035 +    krb5_boolean has_conf_data = FALSE;
16036 +
16037 +    GSSEAP_ASSERT(iov != GSS_C_NO_IOV_BUFFER);
16038 +
16039 +    for (i = 0; i < iov_count; i++) {
16040 +        if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA) {
16041 +            has_conf_data = TRUE;
16042 +            break;
16043 +        }
16044 +    }
16045 +
16046 +    return (has_conf_data == FALSE);
16047 +}
16048 +
16049 +int
16050 +gssEapAllocIov(gss_iov_buffer_t iov, size_t size)
16051 +{
16052 +    GSSEAP_ASSERT(iov != GSS_C_NO_IOV_BUFFER);
16053 +    GSSEAP_ASSERT(iov->type & GSS_IOV_BUFFER_FLAG_ALLOCATE);
16054 +
16055 +    iov->buffer.length = size;
16056 +    iov->buffer.value = GSSEAP_MALLOC(size);
16057 +    if (iov->buffer.value == NULL) {
16058 +        iov->buffer.length = 0;
16059 +        return ENOMEM;
16060 +    }
16061 +
16062 +    iov->type |= GSS_IOV_BUFFER_FLAG_ALLOCATED;
16063 +
16064 +    return 0;
16065 +}
16066 diff --git a/mech_eap/util_json.cpp b/mech_eap/util_json.cpp
16067 new file mode 100644
16068 index 0000000..97eb1ed
16069 --- /dev/null
16070 +++ b/mech_eap/util_json.cpp
16071 @@ -0,0 +1,513 @@
16072 +/*
16073 + * Copyright (c) 2011, JANET(UK)
16074 + * All rights reserved.
16075 + *
16076 + * Redistribution and use in source and binary forms, with or without
16077 + * modification, are permitted provided that the following conditions
16078 + * are met:
16079 + *
16080 + * 1. Redistributions of source code must retain the above copyright
16081 + *    notice, this list of conditions and the following disclaimer.
16082 + *
16083 + * 2. Redistributions in binary form must reproduce the above copyright
16084 + *    notice, this list of conditions and the following disclaimer in the
16085 + *    documentation and/or other materials provided with the distribution.
16086 + *
16087 + * 3. Neither the name of JANET(UK) nor the names of its contributors
16088 + *    may be used to endorse or promote products derived from this software
16089 + *    without specific prior written permission.
16090 + *
16091 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16092 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16093 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16094 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
16095 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
16096 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
16097 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
16098 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16099 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16100 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
16101 + * SUCH DAMAGE.
16102 + */
16103 +
16104 +/*
16105 + * JSONObject utilities.
16106 + */
16107 +
16108 +#include "gssapiP_eap.h"
16109 +
16110 +#include <typeinfo>
16111 +#include <string>
16112 +#include <sstream>
16113 +#include <exception>
16114 +#include <new>
16115 +
16116 +#define JSON_INIT(obj) do {                                     \
16117 +        if ((obj) == NULL)                                      \
16118 +            throw std::bad_alloc();                             \
16119 +        m_obj = (obj);                                          \
16120 +    } while (0)
16121 +
16122 +#define JSON_CHECK_CONTAINER() do {                             \
16123 +        if (!json_is_object(m_obj) && !json_is_array(m_obj)) {  \
16124 +            std::string s("JSONObject is not a container");     \
16125 +            throw JSONException(m_obj);                         \
16126 +        }                                                       \
16127 +    } while (0)
16128 +
16129 +#define JSON_CHECK_OBJECT() do {                                \
16130 +        if (!json_is_object(m_obj)) {                           \
16131 +            std::string s("JSONObject is not a dictionary");    \
16132 +            throw JSONException(m_obj, JSON_OBJECT);            \
16133 +        }                                                       \
16134 +    } while (0)
16135 +
16136 +#define JSON_CHECK_ARRAY() do {                                 \
16137 +        if (!json_is_array(m_obj)) {                            \
16138 +            throw JSONException(m_obj, JSON_ARRAY);             \
16139 +        }                                                       \
16140 +    } while (0)
16141 +
16142 +#define JSON_CHECK(s) do {                                      \
16143 +        if ((s) != 0)                                           \
16144 +            throw JSONException();                              \
16145 +    } while (0)
16146 +
16147 +JSONObject
16148 +JSONObject::load(const char *input, size_t flags, json_error_t *error)
16149 +{
16150 +    json_t *obj;
16151 +
16152 +    obj = json_loads(input, flags, error);
16153 +
16154 +    return JSONObject(obj, false);
16155 +}
16156 +
16157 +JSONObject
16158 +JSONObject::load(FILE *fp, size_t flags, json_error_t *error)
16159 +{
16160 +    json_t *obj;
16161 +
16162 +    obj = json_loadf(fp, flags, error);
16163 +
16164 +    return JSONObject(obj, false);
16165 +}
16166 +
16167 +char *
16168 +JSONObject::dump(size_t flags) const
16169 +{
16170 +    char *s = json_dumps(m_obj, flags);
16171 +
16172 +    if (s == NULL)
16173 +        throw std::bad_alloc();
16174 +
16175 +    return s;
16176 +}
16177 +
16178 +void
16179 +JSONObject::dump(FILE *fp, size_t flags) const
16180 +{
16181 +    int r = json_dumpf(m_obj, fp, flags);
16182 +
16183 +    if (r != 0)
16184 +        throw std::bad_alloc();
16185 +}
16186 +
16187 +size_t
16188 +JSONObject::size(void) const
16189 +{
16190 +    if (json_is_object(m_obj))
16191 +        return json_object_size(m_obj);
16192 +    else if (json_is_array(m_obj))
16193 +        return json_array_size(m_obj);
16194 +    else
16195 +        return 0;
16196 +}
16197 +
16198 +JSONObject::JSONObject(json_t *obj, bool retain)
16199 +{
16200 +    if (retain)
16201 +        json_incref(obj);
16202 +    JSON_INIT(obj);
16203 +}
16204 +
16205 +JSONObject::JSONObject(const char *value)
16206 +{
16207 +    json_t *obj = json_string(value);
16208 +
16209 +    JSON_INIT(obj);
16210 +}
16211 +
16212 +JSONObject::JSONObject(json_int_t value)
16213 +{
16214 +    json_t *obj = json_integer(value);
16215 +
16216 +    JSON_INIT(obj);
16217 +}
16218 +
16219 +JSONObject::JSONObject(double value)
16220 +{
16221 +    json_t *obj = json_real(value);
16222 +
16223 +    JSON_INIT(obj);
16224 +}
16225 +
16226 +JSONObject::JSONObject(bool value)
16227 +{
16228 +    json_t *obj = value ? json_true() : json_false();
16229 +
16230 +    JSON_INIT(obj);
16231 +}
16232 +
16233 +JSONObject::JSONObject(void)
16234 +{
16235 +    json_t *obj = json_object();
16236 +
16237 +    JSON_INIT(obj);
16238 +}
16239 +
16240 +JSONObject
16241 +JSONObject::object(void)
16242 +{
16243 +    return JSONObject();
16244 +}
16245 +
16246 +JSONObject
16247 +JSONObject::null(void)
16248 +{
16249 +    return JSONObject(json_null(), false);
16250 +}
16251 +
16252 +JSONObject
16253 +JSONObject::array(void)
16254 +{
16255 +    return JSONObject(json_array(), false);
16256 +}
16257 +
16258 +void
16259 +JSONObject::set(const char *key, JSONObject &value)
16260 +{
16261 +    JSON_CHECK_OBJECT();
16262 +    JSON_CHECK(json_object_set_new(m_obj, key, value.get()));
16263 +}
16264 +
16265 +void
16266 +JSONObject::set(const char *key, const char *value)
16267 +{
16268 +    JSONObject jobj(value);
16269 +    set(key, jobj);
16270 +}
16271 +
16272 +void
16273 +JSONObject::set(const char *key, json_int_t value)
16274 +{
16275 +    JSONObject jobj(value);
16276 +    set(key, jobj);
16277 +}
16278 +
16279 +void
16280 +JSONObject::del(const char *key)
16281 +{
16282 +    json_object_del(m_obj, key);
16283 +}
16284 +
16285 +JSONObject
16286 +JSONObject::get(const char *key) const
16287 +{
16288 +    json_t *obj;
16289 +
16290 +    obj = json_object_get(m_obj, key);
16291 +    if (obj == NULL)
16292 +        return JSONObject::null();
16293 +
16294 +    return JSONObject(obj, true);
16295 +}
16296 +
16297 +JSONObject
16298 +JSONObject::get(size_t index) const
16299 +{
16300 +    json_t *obj;
16301 +
16302 +    obj = json_array_get(m_obj, index);
16303 +    if (obj == NULL)
16304 +        return JSONObject::null();
16305 +
16306 +    return JSONObject(obj, true);
16307 +}
16308 +
16309 +void
16310 +JSONObject::update(JSONObject &value)
16311 +{
16312 +    JSON_CHECK_OBJECT();
16313 +    json_t *other = value.get();
16314 +    JSON_CHECK(json_object_update(m_obj, other));
16315 +    json_decref(other);
16316 +}
16317 +
16318 +JSONObject
16319 +JSONObject::operator[](size_t index) const
16320 +{
16321 +    return get(index);
16322 +}
16323 +
16324 +JSONObject
16325 +JSONObject::operator[](const char *key) const
16326 +{
16327 +    return get(key);
16328 +}
16329 +
16330 +void
16331 +JSONObject::append(JSONObject &value)
16332 +{
16333 +    JSON_CHECK_ARRAY();
16334 +    JSON_CHECK(json_array_append_new(m_obj, value.get()));
16335 +}
16336 +
16337 +void
16338 +JSONObject::insert(size_t index, JSONObject &value)
16339 +{
16340 +    JSON_CHECK_ARRAY();
16341 +    JSON_CHECK(json_array_insert_new(m_obj, index, value.get()));
16342 +}
16343 +
16344 +void
16345 +JSONObject::remove(size_t index)
16346 +{
16347 +    JSON_CHECK_ARRAY();
16348 +    JSON_CHECK(json_array_remove(m_obj, index));
16349 +}
16350 +
16351 +void
16352 +JSONObject::clear(void)
16353 +{
16354 +    JSON_CHECK_CONTAINER();
16355 +
16356 +    if (json_is_object(m_obj)) {
16357 +        JSON_CHECK(json_object_clear(m_obj));
16358 +    } else if (json_is_array(m_obj)) {
16359 +        JSON_CHECK(json_array_clear(m_obj));
16360 +    }
16361 +}
16362 +
16363 +void
16364 +JSONObject::extend(JSONObject &value)
16365 +{
16366 +    JSON_CHECK_ARRAY();
16367 +    json_t *other = value.get();
16368 +    JSON_CHECK(json_array_extend(m_obj, other));
16369 +    json_decref(other);
16370 +}
16371 +
16372 +const char *
16373 +JSONObject::string(void) const
16374 +{
16375 +    return json_string_value(m_obj);
16376 +}
16377 +
16378 +json_int_t
16379 +JSONObject::integer(void) const
16380 +{
16381 +    return json_integer_value(m_obj);
16382 +}
16383 +
16384 +double
16385 +JSONObject::real(void) const
16386 +{
16387 +    return json_real_value(m_obj);
16388 +}
16389 +
16390 +double
16391 +JSONObject::number(void) const
16392 +{
16393 +    return json_number_value(m_obj);
16394 +}
16395 +
16396 +#ifdef HAVE_SHIBRESOLVER
16397 +JSONObject
16398 +JSONObject::ddf(DDF &ddf)
16399 +{
16400 +    if (ddf.isstruct()) {
16401 +        DDF elem = ddf.first();
16402 +        JSONObject jobj = JSONObject::object();
16403 +
16404 +        while (!elem.isnull()) {
16405 +            JSONObject jtmp = JSONObject::ddf(elem);
16406 +            jobj.set(elem.name(), jtmp);
16407 +            elem = ddf.next();
16408 +        }
16409 +
16410 +        return jobj;
16411 +    } else if (ddf.islist()) {
16412 +        DDF elem = ddf.first();
16413 +        JSONObject jobj = JSONObject::array();
16414 +
16415 +        while (!elem.isnull()) {
16416 +            JSONObject jtmp = JSONObject::ddf(elem);
16417 +            jobj.append(jtmp);
16418 +            elem = ddf.next();
16419 +        }
16420 +
16421 +        return jobj;
16422 +    } else if (ddf.isstring()) {
16423 +        return JSONObject(ddf.string());
16424 +    } else if (ddf.isint()) {
16425 +        return JSONObject((json_int_t)ddf.integer());
16426 +    } else if (ddf.isfloat()) {
16427 +        return JSONObject(ddf.floating());
16428 +    } else if (ddf.isempty() || ddf.ispointer()) {
16429 +        return JSONObject::object();
16430 +    } else if (ddf.isnull()) {
16431 +        return JSONObject::null();
16432 +    }
16433 +
16434 +    std::string s("Unbridgeable DDF object");
16435 +    throw JSONException();
16436 +}
16437 +
16438 +DDF
16439 +JSONObject::ddf(void) const
16440 +{
16441 +    DDF ddf(NULL);
16442 +
16443 +    switch (type()) {
16444 +    case JSON_OBJECT: {
16445 +        JSONIterator iter = iterator();
16446 +
16447 +        do {
16448 +            const char *key = iter.key();
16449 +            DDF value = iter.value().ddf();
16450 +            ddf.addmember(key).swap(value);
16451 +        } while (iter.next());
16452 +        break;
16453 +    }
16454 +    case JSON_ARRAY: {
16455 +        size_t i, nelems = size();
16456 +
16457 +        for (i = 0; i < nelems; i++) {
16458 +            DDF value = get(i).ddf();
16459 +            ddf.add(value);
16460 +        }
16461 +        break;
16462 +    }
16463 +    case JSON_STRING:
16464 +        ddf.string(string());
16465 +        break;
16466 +    case JSON_INTEGER:
16467 +        ddf.integer(integer());
16468 +        break;
16469 +    case JSON_REAL:
16470 +        ddf.floating(real());
16471 +        break;
16472 +    case JSON_TRUE:
16473 +        ddf.integer(1L);
16474 +        break;
16475 +    case JSON_FALSE:
16476 +        ddf.integer(0L);
16477 +        break;
16478 +    case JSON_NULL:
16479 +        break;
16480 +    }
16481 +
16482 +    return ddf;
16483 +}
16484 +#endif /* HAVE_SHIBRESOLVER */
16485 +
16486 +bool JSONObject::isObject(void) const
16487 +{
16488 +    return json_is_object(m_obj);
16489 +}
16490 +
16491 +bool JSONObject::isArray(void) const
16492 +{
16493 +    return json_is_array(m_obj);
16494 +}
16495 +
16496 +bool JSONObject::isString(void) const
16497 +{
16498 +    return json_is_string(m_obj);
16499 +}
16500 +
16501 +bool JSONObject::isInteger(void) const
16502 +{
16503 +    return json_is_integer(m_obj);
16504 +}
16505 +
16506 +bool JSONObject::isNumber(void) const
16507 +{
16508 +    return json_is_number(m_obj);
16509 +}
16510 +
16511 +bool JSONObject::isBoolean(void) const
16512 +{
16513 +    return json_is_boolean(m_obj);
16514 +}
16515 +
16516 +bool JSONObject::isNull(void) const
16517 +{
16518 +    return json_is_null(m_obj);
16519 +}
16520 +
16521 +JSONIterator::JSONIterator(const JSONObject &obj)
16522 +{
16523 +    m_obj = obj.get();
16524 +    m_iter = json_object_iter(m_obj);
16525 +}
16526 +
16527 +JSONIterator::~JSONIterator(void)
16528 +{
16529 +    json_decref(m_obj);
16530 +}
16531 +
16532 +const char *
16533 +JSONIterator::key(void) const
16534 +{
16535 +    return json_object_iter_key(m_iter);
16536 +}
16537 +
16538 +JSONObject
16539 +JSONIterator::value(void) const
16540 +{
16541 +    return JSONObject(json_object_iter_value(m_iter));
16542 +}
16543 +
16544 +bool
16545 +JSONIterator::next(void)
16546 +{
16547 +    m_iter = json_object_iter_next(m_obj, m_iter);
16548 +    return m_iter != NULL;
16549 +}
16550 +
16551 +JSONException::JSONException(json_t *obj, json_type type)
16552 +{
16553 +    char *s = NULL;
16554 +    const char *t;
16555 +
16556 +    m_obj = json_incref(obj);
16557 +    m_type = type;
16558 +
16559 +    if (obj != NULL)
16560 +        s = json_dumps(m_obj, 0);
16561 +
16562 +    switch (type) {
16563 +    case JSON_OBJECT:   t = "OBJECT";   break;
16564 +    case JSON_ARRAY:    t = "ARRAY";    break;
16565 +    case JSON_STRING:   t = "STRING";   break;
16566 +    case JSON_INTEGER:  t = "INTEGER";  break;
16567 +    case JSON_REAL:     t = "REAL";     break;
16568 +    case JSON_TRUE:     t = "TRUE";     break;
16569 +    case JSON_FALSE:    t = "FALSE";    break;
16570 +    case JSON_NULL:     t = "NULL";     break;
16571 +    default:            t = "UNKNOWN";  break;
16572 +    }
16573 +
16574 +    if (obj != NULL) {
16575 +        m_reason = "Invalid JSON object: " + std::string(s);
16576 +        if (type != JSON_NULL)
16577 +            m_reason += " (excepted type " + std::string(t) + ")";
16578 +    } else {
16579 +        m_reason = "Internal JSON error";
16580 +    }
16581 +
16582 +    if (s != NULL)
16583 +        GSSEAP_FREE(s);
16584 +}
16585 diff --git a/mech_eap/util_json.h b/mech_eap/util_json.h
16586 new file mode 100644
16587 index 0000000..4ffecc8
16588 --- /dev/null
16589 +++ b/mech_eap/util_json.h
16590 @@ -0,0 +1,182 @@
16591 +/*
16592 + * Copyright (c) 2011, JANET(UK)
16593 + * All rights reserved.
16594 + *
16595 + * Redistribution and use in source and binary forms, with or without
16596 + * modification, are permitted provided that the following conditions
16597 + * are met:
16598 + *
16599 + * 1. Redistributions of source code must retain the above copyright
16600 + *    notice, this list of conditions and the following disclaimer.
16601 + *
16602 + * 2. Redistributions in binary form must reproduce the above copyright
16603 + *    notice, this list of conditions and the following disclaimer in the
16604 + *    documentation and/or other materials provided with the distribution.
16605 + *
16606 + * 3. Neither the name of JANET(UK) nor the names of its contributors
16607 + *    may be used to endorse or promote products derived from this software
16608 + *    without specific prior written permission.
16609 + *
16610 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16611 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16612 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16613 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
16614 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
16615 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
16616 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
16617 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16618 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16619 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
16620 + * SUCH DAMAGE.
16621 + */
16622 +
16623 +/*
16624 + * JSON object wrapper with not-entirely-toll-free DDF bridging.
16625 + */
16626 +
16627 +#ifndef _UTIL_JSON_H_
16628 +#define _UTIL_JSON_H_ 1
16629 +
16630 +#ifdef __cplusplus
16631 +#include <string>
16632 +#include <new>
16633 +
16634 +#include <jansson.h>
16635 +
16636 +#ifdef HAVE_SHIBRESOLVER
16637 +#include <shibsp/remoting/ddf.h>
16638 +using namespace shibsp;
16639 +#endif
16640 +
16641 +namespace gss_eap_util {
16642 +    class JSONObject;
16643 +
16644 +    class JSONException : public std::exception {
16645 +    public:
16646 +        JSONException(json_t *obj = NULL, json_type type = JSON_NULL);
16647 +
16648 +        ~JSONException(void) throw() {
16649 +            json_decref(m_obj);
16650 +        }
16651 +
16652 +        virtual const char *what(void) const throw() {
16653 +            return m_reason.c_str();
16654 +        }
16655 +
16656 +    private:
16657 +        json_t *m_obj;
16658 +        json_type m_type;
16659 +        std::string m_reason;
16660 +    };
16661 +
16662 +    class JSONIterator {
16663 +    public:
16664 +        JSONIterator(const JSONObject &obj);
16665 +        ~JSONIterator(void);
16666 +        const char *key(void) const;
16667 +        JSONObject value(void) const;
16668 +        bool next(void);
16669 +
16670 +    private:
16671 +        json_t *m_obj;
16672 +        void *m_iter;
16673 +    };
16674 +
16675 +    class JSONObject {
16676 +    public:
16677 +        static JSONObject load(const char *input, size_t flags, json_error_t *error);
16678 +        static JSONObject load(FILE *, size_t flags, json_error_t *error);
16679 +
16680 +        static JSONObject object(void);
16681 +        static JSONObject array(void);
16682 +        static JSONObject null(void);
16683 +#ifdef HAVE_SHIBRESOLVER
16684 +        static JSONObject ddf(DDF &value);
16685 +#endif
16686 +
16687 +        char *dump(size_t flags = 0) const;
16688 +        void dump(FILE *fp, size_t flags = JSON_INDENT(4)) const;
16689 +
16690 +        json_type type(void) const { return json_typeof(m_obj); }
16691 +        size_t size(void) const;
16692 +
16693 +        JSONObject(void);
16694 +        JSONObject(const char *value);
16695 +        JSONObject(json_int_t value);
16696 +        JSONObject(double value);
16697 +        JSONObject(bool value);
16698 +
16699 +        void set(const char *key, JSONObject &value);
16700 +        void set(const char *key, const char *value);
16701 +        void set(const char *key, json_int_t value);
16702 +        void del(const char *key);
16703 +        void update(JSONObject &value);
16704 +        JSONIterator iterator(void) const { return JSONIterator(*this); }
16705 +        JSONObject get(const char *key) const;
16706 +        JSONObject operator[](const char *key) const;
16707 +
16708 +        JSONObject get(size_t index) const;
16709 +        JSONObject operator[](size_t index) const;
16710 +        void append(JSONObject &value);
16711 +        void insert(size_t index, JSONObject &value);
16712 +        void remove(size_t index);
16713 +        void clear(void);
16714 +        void extend(JSONObject &value);
16715 +
16716 +        const char *string(void) const;
16717 +        json_int_t integer(void) const;
16718 +        double real(void) const;
16719 +        double number(void) const;
16720 +#ifdef HAVE_SHIBRESOLVER
16721 +        DDF ddf(void) const;
16722 +#endif
16723 +
16724 +        bool isObject(void) const;
16725 +        bool isArray(void) const;
16726 +        bool isString(void) const;
16727 +        bool isInteger(void) const;
16728 +        bool isNumber(void) const;
16729 +        bool isBoolean(void) const;
16730 +        bool isNull(void) const;
16731 +
16732 +        ~JSONObject(void)
16733 +        {
16734 +            if (m_obj != NULL)
16735 +                json_decref(m_obj);
16736 +        }
16737 +
16738 +        JSONObject(const JSONObject &obj)
16739 +        {
16740 +            m_obj = json_incref(obj.m_obj);
16741 +        }
16742 +
16743 +        JSONObject& operator=(const JSONObject &obj)
16744 +        {
16745 +            if (this != &obj)
16746 +                set(obj.m_obj);
16747 +            return *this;
16748 +        }
16749 +
16750 +    private:
16751 +        friend class JSONIterator;
16752 +
16753 +        json_t *get(void) const {
16754 +            return json_incref(m_obj);
16755 +        }
16756 +
16757 +        void set(json_t *obj) {
16758 +            if (m_obj != obj) {
16759 +                json_decref(m_obj);
16760 +                m_obj = json_incref(m_obj);
16761 +            }
16762 +        }
16763 +
16764 +        JSONObject(json_t *obj, bool retain = true);
16765 +
16766 +        json_t *m_obj;
16767 +    };
16768 +}
16769 +
16770 +#endif /* __cplusplus */
16771 +
16772 +#endif /* _UTIL_JSON_H_ */
16773 diff --git a/mech_eap/util_krb.c b/mech_eap/util_krb.c
16774 new file mode 100644
16775 index 0000000..5eaa31e
16776 --- /dev/null
16777 +++ b/mech_eap/util_krb.c
16778 @@ -0,0 +1,632 @@
16779 +/*
16780 + * Copyright (c) 2011, JANET(UK)
16781 + * All rights reserved.
16782 + *
16783 + * Redistribution and use in source and binary forms, with or without
16784 + * modification, are permitted provided that the following conditions
16785 + * are met:
16786 + *
16787 + * 1. Redistributions of source code must retain the above copyright
16788 + *    notice, this list of conditions and the following disclaimer.
16789 + *
16790 + * 2. Redistributions in binary form must reproduce the above copyright
16791 + *    notice, this list of conditions and the following disclaimer in the
16792 + *    documentation and/or other materials provided with the distribution.
16793 + *
16794 + * 3. Neither the name of JANET(UK) nor the names of its contributors
16795 + *    may be used to endorse or promote products derived from this software
16796 + *    without specific prior written permission.
16797 + *
16798 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16799 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16800 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16801 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
16802 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
16803 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
16804 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
16805 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16806 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
16807 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
16808 + * SUCH DAMAGE.
16809 + */
16810 +
16811 +/*
16812 + * Kerberos 5 helpers.
16813 + */
16814 +
16815 +#include "gssapiP_eap.h"
16816 +
16817 +void
16818 +gssEapDestroyKrbContext(krb5_context context)
16819 +{
16820 +    if (context != NULL)
16821 +        krb5_free_context(context);
16822 +}
16823 +
16824 +static krb5_error_code
16825 +initKrbContext(krb5_context *pKrbContext)
16826 +{
16827 +    krb5_context krbContext;
16828 +    krb5_error_code code;
16829 +    char *defaultRealm = NULL;
16830 +
16831 +    *pKrbContext = NULL;
16832 +
16833 +    code = krb5_init_context(&krbContext);
16834 +    if (code != 0)
16835 +        goto cleanup;
16836 +
16837 +    krb5_appdefault_string(krbContext, "eap_gss",
16838 +                           NULL, "default_realm", "", &defaultRealm);
16839 +
16840 +    if (defaultRealm != NULL && defaultRealm[0] != '\0') {
16841 +        code = krb5_set_default_realm(krbContext, defaultRealm);
16842 +        if (code != 0)
16843 +            goto cleanup;
16844 +    }
16845 +
16846 +    *pKrbContext = krbContext;
16847 +
16848 +cleanup:
16849 +    krb5_free_default_realm(krbContext, defaultRealm);
16850 +
16851 +    if (code != 0 && krbContext != NULL)
16852 +        krb5_free_context(krbContext);
16853 +
16854 +    return code;
16855 +}
16856 +
16857 +OM_uint32
16858 +gssEapKerberosInit(OM_uint32 *minor, krb5_context *context)
16859 +{
16860 +    struct gss_eap_thread_local_data *tld;
16861 +
16862 +    *minor = 0;
16863 +    *context = NULL;
16864 +
16865 +    tld = gssEapGetThreadLocalData();
16866 +    if (tld != NULL) {
16867 +        if (tld->krbContext == NULL) {
16868 +            *minor = initKrbContext(&tld->krbContext);
16869 +            if (*minor != 0)
16870 +                tld->krbContext = NULL;
16871 +        }
16872 +        *context = tld->krbContext;
16873 +    } else {
16874 +        *minor = GSSEAP_GET_LAST_ERROR();
16875 +    }
16876 +
16877 +    GSSEAP_ASSERT(*context != NULL || *minor != 0);
16878 +
16879 +    return (*minor == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
16880 +}
16881 +
16882 +/*
16883 + * Derive a key K for RFC 4121 use by using the following
16884 + * derivation function (based on RFC 4402);
16885 + *
16886 + * KMSK = random-to-key(MSK)
16887 + * Tn = pseudo-random(KMSK, n || "rfc4121-gss-eap")
16888 + * L = output key size
16889 + * K = truncate(L, T1 || T2 || .. || Tn)
16890 + *
16891 + * The output must be freed by krb5_free_keyblock_contents(),
16892 + * not GSSEAP_FREE().
16893 + */
16894 +OM_uint32
16895 +gssEapDeriveRfc3961Key(OM_uint32 *minor,
16896 +                       const unsigned char *inputKey,
16897 +                       size_t inputKeyLength,
16898 +                       krb5_enctype encryptionType,
16899 +                       krb5_keyblock *pKey)
16900 +{
16901 +    krb5_context krbContext;
16902 +#ifndef HAVE_HEIMDAL_VERSION
16903 +    krb5_data data;
16904 +#endif
16905 +    krb5_data ns, t, derivedKeyData;
16906 +    krb5_keyblock kd;
16907 +    krb5_error_code code;
16908 +    size_t randomLength, keyLength, prfLength;
16909 +    unsigned char constant[4 + sizeof("rfc4121-gss-eap") - 1], *p;
16910 +    ssize_t i, remain;
16911 +
16912 +    GSSEAP_KRB_INIT(&krbContext);
16913 +    GSSEAP_ASSERT(encryptionType != ENCTYPE_NULL);
16914 +
16915 +    KRB_KEY_INIT(pKey);
16916 +    KRB_KEY_INIT(&kd);
16917 +    KRB_KEY_TYPE(&kd) = encryptionType;
16918 +
16919 +    KRB_DATA_INIT(&ns);
16920 +    KRB_DATA_INIT(&t);
16921 +    KRB_DATA_INIT(&derivedKeyData);
16922 +
16923 +    code = krb5_c_keylengths(krbContext, encryptionType,
16924 +                             &randomLength, &keyLength);
16925 +    if (code != 0)
16926 +        goto cleanup;
16927 +
16928 +    /* Convert EAP MSK into a Kerberos key */
16929 +
16930 +#ifdef HAVE_HEIMDAL_VERSION
16931 +    code = krb5_random_to_key(krbContext, encryptionType, inputKey,
16932 +                              MIN(inputKeyLength, randomLength), &kd);
16933 +#else
16934 +    data.length = MIN(inputKeyLength, randomLength);
16935 +    data.data = (char *)inputKey;
16936 +
16937 +    KRB_KEY_DATA(&kd) = KRB_MALLOC(keyLength);
16938 +    if (KRB_KEY_DATA(&kd) == NULL) {
16939 +        code = ENOMEM;
16940 +        goto cleanup;
16941 +    }
16942 +    KRB_KEY_LENGTH(&kd) = keyLength;
16943 +
16944 +    code = krb5_c_random_to_key(krbContext, encryptionType, &data, &kd);
16945 +#endif /* HAVE_HEIMDAL_VERSION */
16946 +    if (code != 0)
16947 +        goto cleanup;
16948 +
16949 +    memset(&constant[0], 0, 4);
16950 +    memcpy(&constant[4], "rfc4121-gss-eap", sizeof("rfc4121-gss-eap") - 1);
16951 +
16952 +    ns.length = sizeof(constant);
16953 +    ns.data = (char *)constant;
16954 +
16955 +    /* Plug derivation constant and key into PRF */
16956 +    code = krb5_c_prf_length(krbContext, encryptionType, &prfLength);
16957 +    if (code != 0)
16958 +        goto cleanup;
16959 +
16960 +#ifndef HAVE_HEIMDAL_VERSION
16961 +    /* Same API, but different allocation rules, unfortunately. */
16962 +    t.length = prfLength;
16963 +    t.data = GSSEAP_MALLOC(t.length);
16964 +    if (t.data == NULL) {
16965 +        code = ENOMEM;
16966 +        goto cleanup;
16967 +    }
16968 +#endif
16969 +
16970 +    derivedKeyData.length = randomLength;
16971 +    derivedKeyData.data = GSSEAP_MALLOC(derivedKeyData.length);
16972 +    if (derivedKeyData.data == NULL) {
16973 +        code = ENOMEM;
16974 +        goto cleanup;
16975 +    }
16976 +
16977 +    for (i = 0, p = (unsigned char *)derivedKeyData.data, remain = randomLength;
16978 +         remain > 0;
16979 +         p += t.length, remain -= t.length, i++)
16980 +    {
16981 +        store_uint32_be(i, ns.data);
16982 +
16983 +        code = krb5_c_prf(krbContext, &kd, &ns, &t);
16984 +        if (code != 0)
16985 +            goto cleanup;
16986 +
16987 +        memcpy(p, t.data, MIN(t.length, remain));
16988 +     }
16989 +
16990 +    /* Finally, convert PRF output into a new key which we will return */
16991 +#ifdef HAVE_HEIMDAL_VERSION
16992 +    krb5_free_keyblock_contents(krbContext, &kd);
16993 +    KRB_KEY_INIT(&kd);
16994 +
16995 +    code = krb5_random_to_key(krbContext, encryptionType,
16996 +                              derivedKeyData.data, derivedKeyData.length, &kd);
16997 +#else
16998 +    code = krb5_c_random_to_key(krbContext, encryptionType,
16999 +                                &derivedKeyData, &kd);
17000 +#endif
17001 +    if (code != 0)
17002 +        goto cleanup;
17003 +
17004 +    *pKey = kd;
17005 +
17006 +cleanup:
17007 +    if (code != 0)
17008 +        krb5_free_keyblock_contents(krbContext, &kd);
17009 +#ifdef HAVE_HEIMDAL_VERSION
17010 +    krb5_free_data_contents(krbContext, &t);
17011 +#else
17012 +    if (t.data != NULL) {
17013 +        memset(t.data, 0, t.length);
17014 +        GSSEAP_FREE(t.data);
17015 +    }
17016 +#endif
17017 +    if (derivedKeyData.data != NULL) {
17018 +        memset(derivedKeyData.data, 0, derivedKeyData.length);
17019 +        GSSEAP_FREE(derivedKeyData.data);
17020 +    }
17021 +
17022 +    *minor = code;
17023 +
17024 +    return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
17025 +}
17026 +
17027 +#ifdef HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE
17028 +extern krb5_error_code
17029 +krb5int_c_mandatory_cksumtype(krb5_context, krb5_enctype, krb5_cksumtype *);
17030 +#endif
17031 +
17032 +OM_uint32
17033 +rfc3961ChecksumTypeForKey(OM_uint32 *minor,
17034 +                          krb5_keyblock *key,
17035 +                          krb5_cksumtype *cksumtype)
17036 +{
17037 +    krb5_context krbContext;
17038 +#ifndef HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE
17039 +    krb5_data data;
17040 +    krb5_checksum cksum;
17041 +#endif
17042 +
17043 +    GSSEAP_KRB_INIT(&krbContext);
17044 +
17045 +#ifdef HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE
17046 +    *minor = krb5int_c_mandatory_cksumtype(krbContext, KRB_KEY_TYPE(key),
17047 +                                           cksumtype);
17048 +    if (*minor != 0)
17049 +        return GSS_S_FAILURE;
17050 +#else
17051 +    KRB_DATA_INIT(&data);
17052 +
17053 +    memset(&cksum, 0, sizeof(cksum));
17054 +
17055 +    /*
17056 +     * This is a complete hack but it's the only way to work with
17057 +     * MIT Kerberos pre-1.9 without using private API, as it does
17058 +     * not support passing in zero as the checksum type.
17059 +     */
17060 +    *minor = krb5_c_make_checksum(krbContext, 0, key, 0, &data, &cksum);
17061 +    if (*minor != 0)
17062 +        return GSS_S_FAILURE;
17063 +
17064 +#ifdef HAVE_HEIMDAL_VERSION
17065 +    *cksumtype = cksum.cksumtype;
17066 +#else
17067 +    *cksumtype = cksum.checksum_type;
17068 +#endif
17069 +
17070 +    krb5_free_checksum_contents(krbContext, &cksum);
17071 +#endif /* HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE */
17072 +
17073 +    if (!krb5_c_is_keyed_cksum(*cksumtype)) {
17074 +        *minor = (OM_uint32)KRB5KRB_AP_ERR_INAPP_CKSUM;
17075 +        return GSS_S_FAILURE;
17076 +    }
17077 +
17078 +    return GSS_S_COMPLETE;
17079 +}
17080 +
17081 +krb5_error_code
17082 +krbCryptoLength(krb5_context krbContext,
17083 +#ifdef HAVE_HEIMDAL_VERSION
17084 +                krb5_crypto krbCrypto,
17085 +#else
17086 +                krb5_keyblock *key,
17087 +#endif
17088 +                int type,
17089 +                size_t *length)
17090 +{
17091 +#ifdef HAVE_HEIMDAL_VERSION
17092 +    return krb5_crypto_length(krbContext, krbCrypto, type, length);
17093 +#else
17094 +    unsigned int len;
17095 +    krb5_error_code code;
17096 +
17097 +    code = krb5_c_crypto_length(krbContext, KRB_KEY_TYPE(key), type, &len);
17098 +    if (code == 0)
17099 +        *length = (size_t)len;
17100 +
17101 +    return code;
17102 +#endif
17103 +}
17104 +
17105 +krb5_error_code
17106 +krbPaddingLength(krb5_context krbContext,
17107 +#ifdef HAVE_HEIMDAL_VERSION
17108 +                 krb5_crypto krbCrypto,
17109 +#else
17110 +                 krb5_keyblock *key,
17111 +#endif
17112 +                 size_t dataLength,
17113 +                 size_t *padLength)
17114 +{
17115 +    krb5_error_code code;
17116 +#ifdef HAVE_HEIMDAL_VERSION
17117 +    size_t headerLength, paddingLength;
17118 +
17119 +    code = krbCryptoLength(krbContext, krbCrypto,
17120 +                           KRB5_CRYPTO_TYPE_HEADER, &headerLength);
17121 +    if (code != 0)
17122 +        return code;
17123 +
17124 +    dataLength += headerLength;
17125 +
17126 +    code = krb5_crypto_length(krbContext, krbCrypto,
17127 +                              KRB5_CRYPTO_TYPE_PADDING, &paddingLength);
17128 +    if (code != 0)
17129 +        return code;
17130 +
17131 +    if (paddingLength != 0 && (dataLength % paddingLength) != 0)
17132 +        *padLength = paddingLength - (dataLength % paddingLength);
17133 +    else
17134 +        *padLength = 0;
17135 +
17136 +    return 0;
17137 +#else
17138 +    unsigned int pad;
17139 +
17140 +    code = krb5_c_padding_length(krbContext, KRB_KEY_TYPE(key), dataLength, &pad);
17141 +    if (code == 0)
17142 +        *padLength = (size_t)pad;
17143 +
17144 +    return code;
17145 +#endif /* HAVE_HEIMDAL_VERSION */
17146 +}
17147 +
17148 +krb5_error_code
17149 +krbBlockSize(krb5_context krbContext,
17150 +#ifdef HAVE_HEIMDAL_VERSION
17151 +                 krb5_crypto krbCrypto,
17152 +#else
17153 +                 krb5_keyblock *key,
17154 +#endif
17155 +                 size_t *blockSize)
17156 +{
17157 +#ifdef HAVE_HEIMDAL_VERSION
17158 +    return krb5_crypto_getblocksize(krbContext, krbCrypto, blockSize);
17159 +#else
17160 +    return krb5_c_block_size(krbContext, KRB_KEY_TYPE(key), blockSize);
17161 +#endif
17162 +}
17163 +
17164 +krb5_error_code
17165 +krbEnctypeToString(
17166 +#ifdef HAVE_HEIMDAL_VERSION
17167 +                   krb5_context krbContext,
17168 +#else
17169 +                   krb5_context krbContext GSSEAP_UNUSED,
17170 +#endif
17171 +                   krb5_enctype enctype,
17172 +                   const char *prefix,
17173 +                   gss_buffer_t string)
17174 +{
17175 +    krb5_error_code code;
17176 +#ifdef HAVE_HEIMDAL_VERSION
17177 +    char *enctypeBuf = NULL;
17178 +#else
17179 +    char enctypeBuf[128];
17180 +#endif
17181 +    size_t prefixLength, enctypeLength;
17182 +
17183 +#ifdef HAVE_HEIMDAL_VERSION
17184 +    code = krb5_enctype_to_string(krbContext, enctype, &enctypeBuf);
17185 +#else
17186 +    code = krb5_enctype_to_name(enctype, 0, enctypeBuf, sizeof(enctypeBuf));
17187 +#endif
17188 +    if (code != 0)
17189 +        return code;
17190 +
17191 +    prefixLength = (prefix != NULL) ? strlen(prefix) : 0;
17192 +    enctypeLength = strlen(enctypeBuf);
17193 +
17194 +    string->value = GSSEAP_MALLOC(prefixLength + enctypeLength + 1);
17195 +    if (string->value == NULL) {
17196 +#ifdef HAVE_HEIMDAL_VERSION
17197 +        krb5_xfree(enctypeBuf);
17198 +#endif
17199 +        return ENOMEM;
17200 +    }
17201 +
17202 +    if (prefixLength != 0)
17203 +        memcpy(string->value, prefix, prefixLength);
17204 +    memcpy((char *)string->value + prefixLength, enctypeBuf, enctypeLength);
17205 +
17206 +    string->length = prefixLength + enctypeLength;
17207 +    ((char *)string->value)[string->length] = '\0';
17208 +
17209 +#ifdef HAVE_HEIMDAL_VERSION
17210 +    krb5_xfree(enctypeBuf);
17211 +#endif
17212 +
17213 +    return 0;
17214 +}
17215 +
17216 +krb5_error_code
17217 +krbMakeAuthDataKdcIssued(krb5_context context,
17218 +                         const krb5_keyblock *key,
17219 +                         krb5_const_principal issuer,
17220 +#ifdef HAVE_HEIMDAL_VERSION
17221 +                         const AuthorizationData *authdata,
17222 +                         AuthorizationData *adKdcIssued
17223 +#else
17224 +                         krb5_authdata *const *authdata,
17225 +                         krb5_authdata ***adKdcIssued
17226 +#endif
17227 +                         )
17228 +{
17229 +#ifdef HAVE_HEIMDAL_VERSION
17230 +    krb5_error_code code;
17231 +    AD_KDCIssued kdcIssued;
17232 +    AuthorizationDataElement adDatum;
17233 +    unsigned char *buf;
17234 +    size_t buf_size, len;
17235 +    krb5_crypto crypto = NULL;
17236 +
17237 +    memset(&kdcIssued, 0, sizeof(kdcIssued));
17238 +    memset(adKdcIssued, 0, sizeof(*adKdcIssued));
17239 +
17240 +    kdcIssued.i_realm = issuer->realm != NULL ? (Realm *)&issuer->realm : NULL;
17241 +    kdcIssued.i_sname = (PrincipalName *)&issuer->name;
17242 +    kdcIssued.elements = *authdata;
17243 +
17244 +    ASN1_MALLOC_ENCODE(AuthorizationData, buf, buf_size, authdata, &len, code);
17245 +    if (code != 0)
17246 +        goto cleanup;
17247 +
17248 +    code = krb5_crypto_init(context, key, 0, &crypto);
17249 +    if (code != 0)
17250 +        goto cleanup;
17251 +
17252 +    code = krb5_create_checksum(context, crypto, KRB5_KU_AD_KDC_ISSUED,
17253 +                                0, buf, buf_size, &kdcIssued.ad_checksum);
17254 +    if (code != 0)
17255 +        goto cleanup;
17256 +
17257 +    free(buf); /* match ASN1_MALLOC_ENCODE */
17258 +    buf = NULL;
17259 +
17260 +    ASN1_MALLOC_ENCODE(AD_KDCIssued, buf, buf_size, &kdcIssued, &len, code);
17261 +    if (code != 0)
17262 +        goto cleanup;
17263 +
17264 +    adDatum.ad_type = KRB5_AUTHDATA_KDC_ISSUED;
17265 +    adDatum.ad_data.length = buf_size;
17266 +    adDatum.ad_data.data = buf;
17267 +
17268 +    code = add_AuthorizationData(adKdcIssued, &adDatum);
17269 +    if (code != 0)
17270 +        goto cleanup;
17271 +
17272 +cleanup:
17273 +    if (buf != NULL)
17274 +        free(buf); /* match ASN1_MALLOC_ENCODE */
17275 +    if (crypto != NULL)
17276 +        krb5_crypto_destroy(context, crypto);
17277 +    free_Checksum(&kdcIssued.ad_checksum);
17278 +
17279 +    return code;
17280 +#else
17281 +    return krb5_make_authdata_kdc_issued(context, key, issuer, authdata,
17282 +                                         adKdcIssued);
17283 +#endif /* HAVE_HEIMDAL_VERSION */
17284 +}
17285 +
17286 +krb5_error_code
17287 +krbMakeCred(krb5_context krbContext,
17288 +            krb5_auth_context authContext,
17289 +            krb5_creds *creds,
17290 +            krb5_data *data)
17291 +{
17292 +    krb5_error_code code;
17293 +#ifdef HAVE_HEIMDAL_VERSION
17294 +    KRB_CRED krbCred;
17295 +    KrbCredInfo krbCredInfo;
17296 +    EncKrbCredPart encKrbCredPart;
17297 +    krb5_keyblock *key;
17298 +    krb5_crypto krbCrypto = NULL;
17299 +    krb5_data encKrbCredPartData;
17300 +    krb5_replay_data rdata;
17301 +    size_t len;
17302 +#else
17303 +    krb5_data *d = NULL;
17304 +#endif
17305 +
17306 +    memset(data, 0, sizeof(*data));
17307 +#ifdef HAVE_HEIMDAL_VERSION
17308 +    memset(&krbCred,        0, sizeof(krbCred));
17309 +    memset(&krbCredInfo,    0, sizeof(krbCredInfo));
17310 +    memset(&encKrbCredPart, 0, sizeof(encKrbCredPart));
17311 +    memset(&rdata,          0, sizeof(rdata));
17312 +
17313 +    if (authContext->local_subkey)
17314 +        key = authContext->local_subkey;
17315 +    else if (authContext->remote_subkey)
17316 +        key = authContext->remote_subkey;
17317 +    else
17318 +        key = authContext->keyblock;
17319 +
17320 +    krbCred.pvno = 5;
17321 +    krbCred.msg_type = krb_cred;
17322 +    krbCred.tickets.val = (Ticket *)GSSEAP_CALLOC(1, sizeof(Ticket));
17323 +    if (krbCred.tickets.val == NULL) {
17324 +        code = ENOMEM;
17325 +        goto cleanup;
17326 +    }
17327 +    krbCred.tickets.len = 1;
17328 +
17329 +    code = decode_Ticket(creds->ticket.data,
17330 +                         creds->ticket.length,
17331 +                         krbCred.tickets.val, &len);
17332 +    if (code != 0)
17333 +        goto cleanup;
17334 +
17335 +    krbCredInfo.key         = creds->session;
17336 +    krbCredInfo.prealm      = &creds->client->realm;
17337 +    krbCredInfo.pname       = &creds->client->name;
17338 +    krbCredInfo.flags       = &creds->flags.b;
17339 +    krbCredInfo.authtime    = &creds->times.authtime;
17340 +    krbCredInfo.starttime   = &creds->times.starttime;
17341 +    krbCredInfo.endtime     = &creds->times.endtime;
17342 +    krbCredInfo.renew_till  = &creds->times.renew_till;
17343 +    krbCredInfo.srealm      = &creds->server->realm;
17344 +    krbCredInfo.sname       = &creds->server->name;
17345 +    krbCredInfo.caddr       = creds->addresses.len ? &creds->addresses : NULL;
17346 +
17347 +    encKrbCredPart.ticket_info.len = 1;
17348 +    encKrbCredPart.ticket_info.val = &krbCredInfo;
17349 +    if (authContext->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
17350 +        rdata.seq                  = authContext->local_seqnumber;
17351 +        encKrbCredPart.nonce       = (int32_t *)&rdata.seq;
17352 +    } else {
17353 +        encKrbCredPart.nonce       = NULL;
17354 +    }
17355 +    if (authContext->flags & KRB5_AUTH_CONTEXT_DO_TIME) {
17356 +        krb5_us_timeofday(krbContext, &rdata.timestamp, &rdata.usec);
17357 +        encKrbCredPart.timestamp   = &rdata.timestamp;
17358 +        encKrbCredPart.usec        = &rdata.usec;
17359 +    } else {
17360 +        encKrbCredPart.timestamp   = NULL;
17361 +        encKrbCredPart.usec        = NULL;
17362 +    }
17363 +    encKrbCredPart.s_address       = authContext->local_address;
17364 +    encKrbCredPart.r_address       = authContext->remote_address;
17365 +
17366 +    ASN1_MALLOC_ENCODE(EncKrbCredPart, encKrbCredPartData.data,
17367 +                       encKrbCredPartData.length, &encKrbCredPart,
17368 +                       &len, code);
17369 +    if (code != 0)
17370 +        goto cleanup;
17371 +
17372 +    code = krb5_crypto_init(krbContext, key, 0, &krbCrypto);
17373 +    if (code != 0)
17374 +        goto cleanup;
17375 +
17376 +    code = krb5_encrypt_EncryptedData(krbContext,
17377 +                                      krbCrypto,
17378 +                                      KRB5_KU_KRB_CRED,
17379 +                                      encKrbCredPartData.data,
17380 +                                      encKrbCredPartData.length,
17381 +                                      0,
17382 +                                      &krbCred.enc_part);
17383 +    if (code != 0)
17384 +        goto cleanup;
17385 +
17386 +    ASN1_MALLOC_ENCODE(KRB_CRED, data->data, data->length,
17387 +                       &krbCred, &len, code);
17388 +    if (code != 0)
17389 +        goto cleanup;
17390 +
17391 +    if (authContext->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE)
17392 +        authContext->local_seqnumber++;
17393 +
17394 +cleanup:
17395 +    if (krbCrypto != NULL)
17396 +        krb5_crypto_destroy(krbContext, krbCrypto);
17397 +    free_KRB_CRED(&krbCred);
17398 +    krb5_data_free(&encKrbCredPartData);
17399 +
17400 +    return code;
17401 +#else
17402 +    code = krb5_mk_1cred(krbContext, authContext, creds, &d, NULL);
17403 +    if (code == 0) {
17404 +        *data = *d;
17405 +        GSSEAP_FREE(d);
17406 +    }
17407 +
17408 +    return code;
17409 +#endif /* HAVE_HEIMDAL_VERSION */
17410 +}
17411 diff --git a/mech_eap/util_lucid.c b/mech_eap/util_lucid.c
17412 new file mode 100644
17413 index 0000000..f9e9941
17414 --- /dev/null
17415 +++ b/mech_eap/util_lucid.c
17416 @@ -0,0 +1,183 @@
17417 +/*
17418 + * Copyright (c) 2011, JANET(UK)
17419 + * All rights reserved.
17420 + *
17421 + * Redistribution and use in source and binary forms, with or without
17422 + * modification, are permitted provided that the following conditions
17423 + * are met:
17424 + *
17425 + * 1. Redistributions of source code must retain the above copyright
17426 + *    notice, this list of conditions and the following disclaimer.
17427 + *
17428 + * 2. Redistributions in binary form must reproduce the above copyright
17429 + *    notice, this list of conditions and the following disclaimer in the
17430 + *    documentation and/or other materials provided with the distribution.
17431 + *
17432 + * 3. Neither the name of JANET(UK) nor the names of its contributors
17433 + *    may be used to endorse or promote products derived from this software
17434 + *    without specific prior written permission.
17435 + *
17436 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17437 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17438 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17439 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
17440 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17441 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
17442 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
17443 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
17444 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
17445 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
17446 + * SUCH DAMAGE.
17447 + */
17448 +
17449 +/*
17450 + * "Lucid" security context export routine (called by MIT Kerberos mechanism).
17451 + */
17452 +
17453 +#include "gssapiP_eap.h"
17454 +
17455 +OM_uint32
17456 +gssEapExportLucidSecContext(OM_uint32 *minor,
17457 +                            gss_ctx_id_t ctx,
17458 +                            const gss_OID desiredObject GSSEAP_UNUSED,
17459 +                            gss_buffer_set_t *data_set)
17460 +{
17461 +    OM_uint32 major = GSS_S_COMPLETE;
17462 +    int haveAcceptorSubkey =
17463 +        ((rfc4121Flags(ctx, 0) & TOK_FLAG_ACCEPTOR_SUBKEY) != 0);
17464 +    gss_buffer_desc rep;
17465 +#ifdef HAVE_HEIMDAL_VERSION
17466 +    krb5_error_code code;
17467 +    krb5_storage *sp;
17468 +    krb5_data data = { 0 };
17469 +
17470 +    sp = krb5_storage_emem();
17471 +    if (sp == NULL) {
17472 +        code = ENOMEM;
17473 +        goto cleanup;
17474 +    }
17475 +
17476 +    code = krb5_store_int32(sp, 1);     /* version */
17477 +    if (code != 0)
17478 +        goto cleanup;
17479 +
17480 +    code = krb5_store_int32(sp, CTX_IS_INITIATOR(ctx));
17481 +    if (code != 0)
17482 +        goto cleanup;
17483 +
17484 +    code = krb5_store_int32(sp, ctx->expiryTime); 
17485 +    if (code != 0)
17486 +        goto cleanup;
17487 +
17488 +    code = krb5_store_int32(sp, 0);
17489 +    if (code != 0)
17490 +        goto cleanup;
17491 +
17492 +    code = krb5_store_int32(sp, ctx->sendSeq);
17493 +    if (code != 0)
17494 +        goto cleanup;
17495 +
17496 +    code = krb5_store_int32(sp, 0);
17497 +    if (code != 0)
17498 +        goto cleanup;
17499 +
17500 +    code = krb5_store_int32(sp, ctx->recvSeq);
17501 +    if (code != 0)
17502 +        goto cleanup;
17503 +
17504 +    code = krb5_store_int32(sp, 1);     /* is_cfx */
17505 +    if (code != 0)
17506 +        goto cleanup;
17507 +
17508 +    code = krb5_store_int32(sp, haveAcceptorSubkey);
17509 +    if (code != 0)
17510 +        goto cleanup;
17511 +
17512 +    code = krb5_store_keyblock(sp, ctx->rfc3961Key);
17513 +    if (code != 0)
17514 +        goto cleanup;
17515 +
17516 +    if (haveAcceptorSubkey) {
17517 +        code = krb5_store_keyblock(sp, ctx->rfc3961Key);
17518 +        if (code != 0)
17519 +            goto cleanup;
17520 +    }
17521 +
17522 +    code = krb5_storage_to_data(sp, &data);
17523 +    if (code != 0)
17524 +        goto cleanup;
17525 +
17526 +    rep.length = data.length;
17527 +    rep.value = data.data;
17528 +
17529 +    major = gss_add_buffer_set_member(minor, &rep, data_set);
17530 +    if (GSS_ERROR(major))
17531 +        goto cleanup;
17532 +
17533 +cleanup:
17534 +    krb5_data_free(&data);
17535 +
17536 +    if (major == GSS_S_COMPLETE) {
17537 +        *minor = code;
17538 +        major = (code != 0) ? GSS_S_FAILURE : GSS_S_COMPLETE;
17539 +    }
17540 +
17541 +    return major;
17542 +#else
17543 +    gss_krb5_lucid_context_v1_t *lctx;
17544 +    gss_krb5_lucid_key_t *lkey = NULL;
17545 +
17546 +    lctx = (gss_krb5_lucid_context_v1_t *)GSSEAP_CALLOC(1, sizeof(*lctx));
17547 +    if (lctx == NULL) {
17548 +        major = GSS_S_FAILURE;
17549 +        *minor = ENOMEM;
17550 +        goto cleanup;
17551 +    }
17552 +
17553 +    lctx->version = 1;
17554 +    lctx->initiate = CTX_IS_INITIATOR(ctx);
17555 +    if (ctx->expiryTime == 0)
17556 +        lctx->endtime = KRB_TIME_FOREVER;
17557 +    else
17558 +        lctx->endtime = ctx->expiryTime;
17559 +    lctx->send_seq = ctx->sendSeq;
17560 +    lctx->recv_seq = ctx->recvSeq;
17561 +    lctx->protocol = 1;
17562 +
17563 +    lctx->cfx_kd.have_acceptor_subkey = haveAcceptorSubkey;
17564 +
17565 +    lkey = haveAcceptorSubkey
17566 +           ? &lctx->cfx_kd.acceptor_subkey
17567 +           : &lctx->cfx_kd.ctx_key;
17568 +
17569 +    lkey->type = KRB_KEY_TYPE(&ctx->rfc3961Key);
17570 +    lkey->data = GSSEAP_MALLOC(KRB_KEY_LENGTH(&ctx->rfc3961Key));
17571 +    if (lkey->data == NULL) {
17572 +        major = GSS_S_FAILURE;
17573 +        *minor = ENOMEM;
17574 +        goto cleanup;
17575 +    }
17576 +    lkey->length = KRB_KEY_LENGTH(&ctx->rfc3961Key);
17577 +    memcpy(lkey->data, KRB_KEY_DATA(&ctx->rfc3961Key), lkey->length);
17578 +
17579 +    rep.value = &lctx;
17580 +    rep.length = sizeof(void *);
17581 +
17582 +    major = gss_add_buffer_set_member(minor, &rep, data_set);
17583 +    if (GSS_ERROR(major))
17584 +        goto cleanup;
17585 +
17586 +cleanup:
17587 +    if (GSS_ERROR(major)) {
17588 +        if (lctx != NULL) {
17589 +            if (lkey != NULL && lkey->data != NULL) {
17590 +                memset(lkey->data, 0, lkey->length);
17591 +                GSSEAP_FREE(lkey->data);
17592 +            }
17593 +            GSSEAP_FREE(lctx);
17594 +        }
17595 +    }
17596 +
17597 +    return major;
17598 +#endif /* HAVE_HEIMDAL_VERSION */
17599 +}
17600 diff --git a/mech_eap/util_mech.c b/mech_eap/util_mech.c
17601 new file mode 100644
17602 index 0000000..958e43d
17603 --- /dev/null
17604 +++ b/mech_eap/util_mech.c
17605 @@ -0,0 +1,380 @@
17606 +/*
17607 + * Copyright (c) 2011, JANET(UK)
17608 + * All rights reserved.
17609 + *
17610 + * Redistribution and use in source and binary forms, with or without
17611 + * modification, are permitted provided that the following conditions
17612 + * are met:
17613 + *
17614 + * 1. Redistributions of source code must retain the above copyright
17615 + *    notice, this list of conditions and the following disclaimer.
17616 + *
17617 + * 2. Redistributions in binary form must reproduce the above copyright
17618 + *    notice, this list of conditions and the following disclaimer in the
17619 + *    documentation and/or other materials provided with the distribution.
17620 + *
17621 + * 3. Neither the name of JANET(UK) nor the names of its contributors
17622 + *    may be used to endorse or promote products derived from this software
17623 + *    without specific prior written permission.
17624 + *
17625 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17626 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17627 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17628 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
17629 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17630 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
17631 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
17632 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
17633 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
17634 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
17635 + * SUCH DAMAGE.
17636 + */
17637 +
17638 +/*
17639 + * General mechanism utility routines.
17640 + */
17641 +
17642 +#include "gssapiP_eap.h"
17643 +
17644 +/*
17645 + * 1.3.6.1.4.1.5322(padl)
17646 + *      gssEap(22)
17647 + *       mechanisms(1)
17648 + *        eap-aes128-cts-hmac-sha1-96(17)
17649 + *        eap-aes256-cts-hmac-sha1-96(18)
17650 + *       nameTypes(2)
17651 + *       apiExtensions(3)
17652 + *        inquireSecContextByOid(1)
17653 + *        inquireCredByOid(2)
17654 + *        setSecContextOption(3)
17655 + *        setCredOption(4)
17656 + *        mechInvoke(5)
17657 + */
17658 +
17659 +/*
17660 + * Note: the enctype-less OID is used as the mechanism OID in non-
17661 + * canonicalized exported names.
17662 + */
17663 +static gss_OID_desc gssEapMechOids[] = {
17664 +    /* 1.3.6.1.4.1.5322.22.1  */
17665 +    { 9, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x01" },
17666 +    /* 1.3.6.1.4.1.5322.22.1.17 */
17667 +    { 10, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x01\x11" },
17668 +    /* 1.3.6.1.4.1.5322.22.1.18 */
17669 +    { 10, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x01\x12" }
17670 +};
17671 +
17672 +gss_OID GSS_EAP_MECHANISM                            = &gssEapMechOids[0];
17673 +gss_OID GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM    = &gssEapMechOids[1];
17674 +gss_OID GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM    = &gssEapMechOids[2];
17675 +
17676 +static int
17677 +internalizeOid(const gss_OID oid,
17678 +               gss_OID *const pInternalizedOid);
17679 +
17680 +/*
17681 + * Returns TRUE is the OID is a concrete mechanism OID, that is, one
17682 + * with a Kerberos enctype as the last element.
17683 + */
17684 +int
17685 +gssEapIsConcreteMechanismOid(const gss_OID oid)
17686 +{
17687 +    return oid->length > GSS_EAP_MECHANISM->length &&
17688 +           memcmp(oid->elements, GSS_EAP_MECHANISM->elements,
17689 +                  GSS_EAP_MECHANISM->length) == 0;
17690 +}
17691 +
17692 +int
17693 +gssEapIsMechanismOid(const gss_OID oid)
17694 +{
17695 +    return oid == GSS_C_NO_OID ||
17696 +           oidEqual(oid, GSS_EAP_MECHANISM) ||
17697 +           gssEapIsConcreteMechanismOid(oid);
17698 +}
17699 +
17700 +/*
17701 + * Validate that all elements are concrete mechanism OIDs.
17702 + */
17703 +OM_uint32
17704 +gssEapValidateMechs(OM_uint32 *minor,
17705 +                    const gss_OID_set mechs)
17706 +{
17707 +    int i;
17708 +
17709 +    *minor = 0;
17710 +
17711 +    if (mechs == GSS_C_NO_OID_SET) {
17712 +        return GSS_S_COMPLETE;
17713 +    }
17714 +
17715 +    for (i = 0; i < mechs->count; i++) {
17716 +        gss_OID oid = &mechs->elements[i];
17717 +
17718 +        if (!gssEapIsConcreteMechanismOid(oid)) {
17719 +            *minor = GSSEAP_WRONG_MECH;
17720 +            return GSS_S_BAD_MECH;
17721 +        }
17722 +    }
17723 +
17724 +    return GSS_S_COMPLETE;
17725 +}
17726 +
17727 +OM_uint32
17728 +gssEapOidToEnctype(OM_uint32 *minor,
17729 +                   const gss_OID oid,
17730 +                   krb5_enctype *enctype)
17731 +{
17732 +    OM_uint32 major;
17733 +    int suffix;
17734 +
17735 +    major = decomposeOid(minor,
17736 +                         GSS_EAP_MECHANISM->elements,
17737 +                         GSS_EAP_MECHANISM->length,
17738 +                         oid,
17739 +                         &suffix);
17740 +    if (major == GSS_S_COMPLETE)
17741 +        *enctype = suffix;
17742 +
17743 +    return major;
17744 +}
17745 +
17746 +OM_uint32
17747 +gssEapEnctypeToOid(OM_uint32 *minor,
17748 +                   krb5_enctype enctype,
17749 +                   gss_OID *pOid)
17750 +{
17751 +    OM_uint32 major;
17752 +    gss_OID oid;
17753 +
17754 +    *pOid = NULL;
17755 +
17756 +    oid = (gss_OID)GSSEAP_MALLOC(sizeof(*oid));
17757 +    if (oid == NULL) {
17758 +        *minor = ENOMEM;
17759 +        return GSS_S_FAILURE;
17760 +    }
17761 +
17762 +    oid->length = GSS_EAP_MECHANISM->length + 1;
17763 +    oid->elements = GSSEAP_MALLOC(oid->length);
17764 +    if (oid->elements == NULL) {
17765 +        *minor = ENOMEM;
17766 +        GSSEAP_FREE(oid);
17767 +        return GSS_S_FAILURE;
17768 +    }
17769 +
17770 +    major = composeOid(minor,
17771 +                       GSS_EAP_MECHANISM->elements,
17772 +                       GSS_EAP_MECHANISM->length,
17773 +                       enctype,
17774 +                       oid);
17775 +    if (major == GSS_S_COMPLETE) {
17776 +        internalizeOid(oid, pOid);
17777 +        *pOid = oid;
17778 +    } else {
17779 +        GSSEAP_FREE(oid->elements);
17780 +        GSSEAP_FREE(oid);
17781 +    }
17782 +
17783 +    return major;
17784 +}
17785 +
17786 +OM_uint32
17787 +gssEapIndicateMechs(OM_uint32 *minor,
17788 +                    gss_OID_set *mechs)
17789 +{
17790 +    krb5_context krbContext;
17791 +    OM_uint32 major;
17792 +    krb5_enctype *etypes;
17793 +    int i;
17794 +
17795 +    GSSEAP_KRB_INIT(&krbContext);
17796 +
17797 +    *minor = krb5_get_permitted_enctypes(krbContext, &etypes);
17798 +    if (*minor != 0) {
17799 +        return GSS_S_FAILURE;
17800 +    }
17801 +
17802 +    major = gss_create_empty_oid_set(minor, mechs);
17803 +    if (GSS_ERROR(major)) {
17804 +        GSSEAP_FREE(etypes);
17805 +        return major;
17806 +    }
17807 +
17808 +    for (i = 0; etypes[i] != ENCTYPE_NULL; i++) {
17809 +        gss_OID mechOid;
17810 +#ifndef HAVE_HEIMDAL_VERSION
17811 +        OM_uint32 tmpMinor;
17812 +#endif
17813 +
17814 +        /* XXX currently we aren't equipped to encode these enctypes */
17815 +        if (etypes[i] < 0 || etypes[i] > 127)
17816 +            continue;
17817 +
17818 +        major = gssEapEnctypeToOid(minor, etypes[i], &mechOid);
17819 +        if (GSS_ERROR(major))
17820 +            break;
17821 +
17822 +        major = gss_add_oid_set_member(minor, mechOid, mechs);
17823 +        if (GSS_ERROR(major))
17824 +            break;
17825 +
17826 +#ifndef HAVE_HEIMDAL_VERSION
17827 +        gss_release_oid(&tmpMinor, &mechOid);
17828 +#endif
17829 +    }
17830 +
17831 +    GSSEAP_FREE(etypes);
17832 +
17833 +    *minor = 0;
17834 +    return major;
17835 +}
17836 +
17837 +OM_uint32
17838 +gssEapDefaultMech(OM_uint32 *minor,
17839 +                  gss_OID *oid)
17840 +{
17841 +    gss_OID_set mechs;
17842 +    OM_uint32 major, tmpMinor;
17843 +
17844 +    major = gssEapIndicateMechs(minor, &mechs);
17845 +    if (GSS_ERROR(major)) {
17846 +        return major;
17847 +    }
17848 +
17849 +    if (mechs->count == 0) {
17850 +        gss_release_oid_set(&tmpMinor, &mechs);
17851 +        return GSS_S_BAD_MECH;
17852 +    }
17853 +
17854 +    if (!internalizeOid(&mechs->elements[0], oid)) {
17855 +        /* don't double-free if we didn't internalize it */
17856 +        mechs->elements[0].length = 0;
17857 +        mechs->elements[0].elements = NULL;
17858 +    }
17859 +
17860 +    gss_release_oid_set(&tmpMinor, &mechs);
17861 +
17862 +    *minor = 0;
17863 +    return GSS_S_COMPLETE;
17864 +}
17865 +
17866 +static int
17867 +internalizeOid(const gss_OID oid,
17868 +               gss_OID *const pInternalizedOid)
17869 +{
17870 +    int i;
17871 +
17872 +    *pInternalizedOid = GSS_C_NO_OID;
17873 +
17874 +    for (i = 0;
17875 +         i < sizeof(gssEapMechOids) / sizeof(gssEapMechOids[0]);
17876 +         i++) {
17877 +        if (oidEqual(oid, &gssEapMechOids[i])) {
17878 +            *pInternalizedOid = (const gss_OID)&gssEapMechOids[i];
17879 +            break;
17880 +        }
17881 +    }
17882 +
17883 +    if (*pInternalizedOid == GSS_C_NO_OID) {
17884 +        if (oidEqual(oid, GSS_EAP_NT_EAP_NAME))
17885 +            *pInternalizedOid = (const gss_OID)GSS_EAP_NT_EAP_NAME;
17886 +    }
17887 +
17888 +    if (*pInternalizedOid == GSS_C_NO_OID) {
17889 +        *pInternalizedOid = oid;
17890 +        return 0;
17891 +    }
17892 +
17893 +    return 1;
17894 +}
17895 +
17896 +OM_uint32
17897 +gssEapReleaseOid(OM_uint32 *minor, gss_OID *oid)
17898 +{
17899 +    gss_OID internalizedOid = GSS_C_NO_OID;
17900 +
17901 +    *minor = 0;
17902 +
17903 +    if (internalizeOid(*oid, &internalizedOid)) {
17904 +        /* OID was internalized, so we can mark it as "freed" */
17905 +        *oid = GSS_C_NO_OID;
17906 +        return GSS_S_COMPLETE;
17907 +    }
17908 +
17909 +    /* we don't know about this OID */
17910 +    return GSS_S_CONTINUE_NEEDED;
17911 +}
17912 +
17913 +OM_uint32
17914 +gssEapCanonicalizeOid(OM_uint32 *minor,
17915 +                      const gss_OID oid,
17916 +                      OM_uint32 flags,
17917 +                      gss_OID *pOid)
17918 +{
17919 +    OM_uint32 major;
17920 +    int mapToNull = 0;
17921 +
17922 +    major = GSS_S_COMPLETE;
17923 +    *minor = 0;
17924 +    *pOid = GSS_C_NULL_OID;
17925 +
17926 +    if (oid == GSS_C_NULL_OID) {
17927 +        if ((flags & OID_FLAG_NULL_VALID) == 0) {
17928 +            *minor = GSSEAP_WRONG_MECH;
17929 +            return GSS_S_BAD_MECH;
17930 +        } else if (flags & OID_FLAG_MAP_NULL_TO_DEFAULT_MECH) {
17931 +            return gssEapDefaultMech(minor, pOid);
17932 +        } else {
17933 +            mapToNull = 1;
17934 +        }
17935 +    } else if (oidEqual(oid, GSS_EAP_MECHANISM)) {
17936 +        if ((flags & OID_FLAG_FAMILY_MECH_VALID) == 0) {
17937 +            *minor = GSSEAP_WRONG_MECH;
17938 +            return GSS_S_BAD_MECH;
17939 +        } else if (flags & OID_FLAG_MAP_FAMILY_MECH_TO_NULL) {
17940 +            mapToNull = 1;
17941 +        }
17942 +    } else if (!gssEapIsConcreteMechanismOid(oid)) {
17943 +        *minor = GSSEAP_WRONG_MECH;
17944 +        return GSS_S_BAD_MECH;
17945 +    }
17946 +
17947 +    if (!mapToNull) {
17948 +        if (!internalizeOid(oid, pOid))
17949 +            major = duplicateOid(minor, oid, pOid);
17950 +    }
17951 +
17952 +    return major;
17953 +}
17954 +
17955 +static gss_buffer_desc gssEapSaslMechs[] = {
17956 +    { sizeof("EAP") - 1,        "EAP",       }, /* not used */
17957 +    { sizeof("EAP-AES128") - 1, "EAP-AES128" },
17958 +    { sizeof("EAP-AES256") - 1, "EAP-AES256" },
17959 +};
17960 +
17961 +gss_buffer_t
17962 +gssEapOidToSaslName(const gss_OID oid)
17963 +{
17964 +    size_t i;
17965 +
17966 +    for (i = 1; i < sizeof(gssEapMechOids)/sizeof(gssEapMechOids[0]); i++) {
17967 +        if (oidEqual(&gssEapMechOids[i], oid))
17968 +            return &gssEapSaslMechs[i];
17969 +    }
17970 +
17971 +    return GSS_C_NO_BUFFER;
17972 +}
17973 +
17974 +gss_OID
17975 +gssEapSaslNameToOid(const gss_buffer_t name)
17976 +{
17977 +    size_t i;
17978 +
17979 +    for (i = 1; i < sizeof(gssEapSaslMechs)/sizeof(gssEapSaslMechs[0]); i++) {
17980 +        if (bufferEqual(&gssEapSaslMechs[i], name))
17981 +            return &gssEapMechOids[i];
17982 +    }
17983 +
17984 +    return GSS_C_NO_OID;
17985 +}
17986 diff --git a/mech_eap/util_moonshot.c b/mech_eap/util_moonshot.c
17987 new file mode 100644
17988 index 0000000..dc0c35e
17989 --- /dev/null
17990 +++ b/mech_eap/util_moonshot.c
17991 @@ -0,0 +1,238 @@
17992 +/*
17993 + * Copyright (c) 2011, JANET(UK)
17994 + * All rights reserved.
17995 + *
17996 + * Redistribution and use in source and binary forms, with or without
17997 + * modification, are permitted provided that the following conditions
17998 + * are met:
17999 + *
18000 + * 1. Redistributions of source code must retain the above copyright
18001 + *    notice, this list of conditions and the following disclaimer.
18002 + *
18003 + * 2. Redistributions in binary form must reproduce the above copyright
18004 + *    notice, this list of conditions and the following disclaimer in the
18005 + *    documentation and/or other materials provided with the distribution.
18006 + *
18007 + * 3. Neither the name of JANET(UK) nor the names of its contributors
18008 + *    may be used to endorse or promote products derived from this software
18009 + *    without specific prior written permission.
18010 + *
18011 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18012 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18013 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18014 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18015 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18016 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18017 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
18018 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
18019 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
18020 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
18021 + * SUCH DAMAGE.
18022 + */
18023 +
18024 +#include "gssapiP_eap.h"
18025 +
18026 +#ifdef HAVE_MOONSHOT_GET_IDENTITY
18027 +#include <libmoonshot.h>
18028 +
18029 +static OM_uint32
18030 +libMoonshotMapError(OM_uint32 *minor,
18031 +                    MoonshotError **pError)
18032 +{
18033 +    MoonshotError *error = *pError;
18034 +
18035 +    GSSEAP_ASSERT(error != NULL);
18036 +
18037 +    switch (error->code) {
18038 +    case MOONSHOT_ERROR_UNABLE_TO_START_SERVICE:
18039 +        *minor = GSSEAP_UNABLE_TO_START_IDENTITY_SERVICE;
18040 +        break;
18041 +    case MOONSHOT_ERROR_NO_IDENTITY_SELECTED:
18042 +        *minor = GSSEAP_NO_IDENTITY_SELECTED;
18043 +        break;
18044 +    case MOONSHOT_ERROR_INSTALLATION_ERROR:
18045 +        *minor = GSSEAP_IDENTITY_SERVICE_INSTALL_ERROR;
18046 +        break;
18047 +    case MOONSHOT_ERROR_OS_ERROR:
18048 +        *minor = GSSEAP_IDENTITY_SERVICE_OS_ERROR;
18049 +        break;
18050 +    case MOONSHOT_ERROR_IPC_ERROR:
18051 +        *minor = GSSEAP_IDENTITY_SERVICE_IPC_ERROR;
18052 +        break;
18053 +    default:
18054 +        *minor = GSSEAP_IDENTITY_SERVICE_UNKNOWN_ERROR;
18055 +        break;
18056 +    }
18057 +
18058 +    gssEapSaveStatusInfo(*minor, error->message);
18059 +    moonshot_error_free(error);
18060 +    *pError = NULL;
18061 +
18062 +    return GSS_S_CRED_UNAVAIL;
18063 +}
18064 +
18065 +OM_uint32
18066 +libMoonshotResolveDefaultIdentity(OM_uint32 *minor,
18067 +                                  const gss_cred_id_t cred,
18068 +                                  gss_name_t *pName)
18069 +{
18070 +    OM_uint32 major, tmpMinor;
18071 +    gss_OID nameMech = gssEapPrimaryMechForCred(cred);
18072 +    gss_name_t name = GSS_C_NO_NAME;
18073 +    gss_buffer_desc tmpBuffer = GSS_C_EMPTY_BUFFER;
18074 +    char *nai = NULL;
18075 +    char *password = NULL;
18076 +    char *serverCertificateHash = NULL;
18077 +    char *caCertificate = NULL;
18078 +    char *subjectNameConstraint = NULL;
18079 +    char *subjectAltNameConstraint = NULL;
18080 +    MoonshotError *error = NULL;
18081 +
18082 +    *pName = GSS_C_NO_NAME;
18083 +
18084 +    if (!moonshot_get_default_identity(&nai,
18085 +                                       &password,
18086 +                                       &serverCertificateHash,
18087 +                                       &caCertificate,
18088 +                                       &subjectNameConstraint,
18089 +                                       &subjectAltNameConstraint,
18090 +                                       &error)) {
18091 +        if (error->code == MOONSHOT_ERROR_NO_IDENTITY_SELECTED) {
18092 +            major = GSS_S_CRED_UNAVAIL;
18093 +            *minor = GSSEAP_NO_DEFAULT_IDENTITY;
18094 +            moonshot_error_free(error);
18095 +        } else
18096 +            major = libMoonshotMapError(minor, &error);
18097 +        goto cleanup;
18098 +    }
18099 +
18100 +    tmpBuffer.value = nai;
18101 +    tmpBuffer.length = strlen(nai);
18102 +
18103 +    major = gssEapImportName(minor, &tmpBuffer, GSS_C_NT_USER_NAME, nameMech, &name);
18104 +    if (GSS_ERROR(major))
18105 +        goto cleanup;
18106 +
18107 +    *pName = name;
18108 +    name = GSS_C_NO_NAME;
18109 +
18110 +cleanup:
18111 +    moonshot_free(nai);
18112 +    moonshot_free(password);
18113 +    moonshot_free(serverCertificateHash);
18114 +    moonshot_free(caCertificate);
18115 +    moonshot_free(subjectNameConstraint);
18116 +    moonshot_free(subjectAltNameConstraint);
18117 +
18118 +    gssEapReleaseName(&tmpMinor, &name);
18119 +
18120 +    return major;
18121 +}
18122 +
18123 +OM_uint32
18124 +libMoonshotResolveInitiatorCred(OM_uint32 *minor,
18125 +                                gss_cred_id_t cred,
18126 +                                const gss_name_t targetName)
18127 +{
18128 +    OM_uint32 major, tmpMinor;
18129 +    gss_OID nameMech = gssEapPrimaryMechForCred(cred);
18130 +    gss_buffer_desc initiator = GSS_C_EMPTY_BUFFER;
18131 +    gss_buffer_desc target = GSS_C_EMPTY_BUFFER;
18132 +    gss_buffer_desc tmpBuffer = GSS_C_EMPTY_BUFFER;
18133 +    char *nai = NULL;
18134 +    char *password = NULL;
18135 +    char *serverCertificateHash = NULL;
18136 +    char *caCertificate = NULL;
18137 +    char *subjectNameConstraint = NULL;
18138 +    char *subjectAltNameConstraint = NULL;
18139 +    MoonshotError *error = NULL;
18140 +
18141 +    if (cred->name != GSS_C_NO_NAME) {
18142 +        major = gssEapExportName(minor, cred->name, &initiator);
18143 +        if (GSS_ERROR(major))
18144 +            goto cleanup;
18145 +    }
18146 +
18147 +    if (targetName != GSS_C_NO_NAME) {
18148 +        major = gssEapExportName(minor, targetName, &target);
18149 +        if (GSS_ERROR(major))
18150 +            goto cleanup;
18151 +    }
18152 +
18153 +    if (!moonshot_get_identity((const char *)initiator.value,
18154 +                               (const char *)cred->password.value,
18155 +                               (const char *)target.value,
18156 +                               &nai,
18157 +                               &password,
18158 +                               &serverCertificateHash,
18159 +                               &caCertificate,
18160 +                               &subjectNameConstraint,
18161 +                               &subjectAltNameConstraint,
18162 +                               &error)) {
18163 +        major = libMoonshotMapError(minor, &error);
18164 +        goto cleanup;
18165 +    }
18166 +
18167 +    gssEapReleaseName(&tmpMinor, &cred->name);
18168 +
18169 +    tmpBuffer.value = nai;
18170 +    tmpBuffer.length = strlen(nai);
18171 +
18172 +    major = gssEapImportName(minor, &tmpBuffer, GSS_C_NT_USER_NAME,
18173 +                             nameMech, &cred->name);
18174 +    if (GSS_ERROR(major))
18175 +        goto cleanup;
18176 +
18177 +    tmpBuffer.value = password;
18178 +    tmpBuffer.length = strlen(password);
18179 +
18180 +    major = gssEapSetCredPassword(minor, cred, &tmpBuffer);
18181 +    if (GSS_ERROR(major))
18182 +        goto cleanup;
18183 +
18184 +    gss_release_buffer(&tmpMinor, &cred->caCertificate);
18185 +    gss_release_buffer(&tmpMinor, &cred->subjectNameConstraint);
18186 +    gss_release_buffer(&tmpMinor, &cred->subjectAltNameConstraint);
18187 +
18188 +    if (serverCertificateHash != NULL) {
18189 +        size_t len = strlen(serverCertificateHash);
18190 +
18191 +        #define HASH_PREFIX             "hash://server/sha256/"
18192 +        #define HASH_PREFIX_LEN         (sizeof(HASH_PREFIX) - 1)
18193 +
18194 +        cred->caCertificate.value = GSSEAP_MALLOC(HASH_PREFIX_LEN + len + 1);
18195 +        if (cred->caCertificate.value == NULL) {
18196 +            major = GSS_S_FAILURE;
18197 +            *minor = ENOMEM;
18198 +            goto cleanup;
18199 +        }
18200 +
18201 +        memcpy(cred->caCertificate.value, HASH_PREFIX, HASH_PREFIX_LEN);
18202 +        memcpy((char *)cred->caCertificate.value + HASH_PREFIX_LEN, serverCertificateHash, len);
18203 +
18204 +        ((char *)cred->caCertificate.value)[HASH_PREFIX_LEN + len] = '\0';
18205 +
18206 +        cred->caCertificate.length = HASH_PREFIX_LEN + len;
18207 +    } else if (caCertificate != NULL) {
18208 +        makeStringBufferOrCleanup(caCertificate, &cred->caCertificate);
18209 +    }
18210 +
18211 +    if (subjectNameConstraint != NULL)
18212 +        makeStringBufferOrCleanup(subjectNameConstraint, &cred->subjectNameConstraint);
18213 +    if (subjectAltNameConstraint != NULL)
18214 +        makeStringBufferOrCleanup(subjectAltNameConstraint, &cred->subjectAltNameConstraint);
18215 +
18216 +cleanup:
18217 +    moonshot_free(nai);
18218 +    moonshot_free(password);
18219 +    moonshot_free(serverCertificateHash);
18220 +    moonshot_free(caCertificate);
18221 +    moonshot_free(subjectNameConstraint);
18222 +    moonshot_free(subjectAltNameConstraint);
18223 +
18224 +    gss_release_buffer(&tmpMinor, &initiator);
18225 +    gss_release_buffer(&tmpMinor, &target);
18226 +
18227 +    return major;
18228 +}
18229 +#endif /* HAVE_MOONSHOT_GET_IDENTITY */
18230 diff --git a/mech_eap/util_name.c b/mech_eap/util_name.c
18231 new file mode 100644
18232 index 0000000..6045724
18233 --- /dev/null
18234 +++ b/mech_eap/util_name.c
18235 @@ -0,0 +1,789 @@
18236 +/*
18237 + * Copyright (c) 2011, JANET(UK)
18238 + * All rights reserved.
18239 + *
18240 + * Redistribution and use in source and binary forms, with or without
18241 + * modification, are permitted provided that the following conditions
18242 + * are met:
18243 + *
18244 + * 1. Redistributions of source code must retain the above copyright
18245 + *    notice, this list of conditions and the following disclaimer.
18246 + *
18247 + * 2. Redistributions in binary form must reproduce the above copyright
18248 + *    notice, this list of conditions and the following disclaimer in the
18249 + *    documentation and/or other materials provided with the distribution.
18250 + *
18251 + * 3. Neither the name of JANET(UK) nor the names of its contributors
18252 + *    may be used to endorse or promote products derived from this software
18253 + *    without specific prior written permission.
18254 + *
18255 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18256 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18257 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18258 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18259 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18260 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18261 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
18262 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
18263 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
18264 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
18265 + * SUCH DAMAGE.
18266 + */
18267 +/*
18268 + * Portions Copyright 2009 by the Massachusetts Institute of Technology.
18269 + * All Rights Reserved.
18270 + *
18271 + * Export of this software from the United States of America may
18272 + *   require a specific license from the United States Government.
18273 + *   It is the responsibility of any person or organization contemplating
18274 + *   export to obtain such a license before exporting.
18275 + *
18276 + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
18277 + * distribute this software and its documentation for any purpose and
18278 + * without fee is hereby granted, provided that the above copyright
18279 + * notice appear in all copies and that both that copyright notice and
18280 + * this permission notice appear in supporting documentation, and that
18281 + * the name of M.I.T. not be used in advertising or publicity pertaining
18282 + * to distribution of the software without specific, written prior
18283 + * permission.  Furthermore if you modify this software you must label
18284 + * your software as modified software and not distribute it in such a
18285 + * fashion that it might be confused with the original M.I.T. software.
18286 + * M.I.T. makes no representations about the suitability of
18287 + * this software for any purpose.  It is provided "as is" without express
18288 + * or implied warranty.
18289 + */
18290 +
18291 +/*
18292 + * Name utility routines.
18293 + */
18294 +
18295 +#include "gssapiP_eap.h"
18296 +
18297 +static gss_OID_desc gssEapNtEapName = {
18298 +    /* 1.3.6.1.4.1.5322.22.2.1  */
18299 +    10, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x02\x01"
18300 +};
18301 +
18302 +gss_OID GSS_EAP_NT_EAP_NAME = &gssEapNtEapName;
18303 +
18304 +OM_uint32
18305 +gssEapAllocName(OM_uint32 *minor, gss_name_t *pName)
18306 +{
18307 +    OM_uint32 tmpMinor;
18308 +    gss_name_t name;
18309 +
18310 +    *pName = GSS_C_NO_NAME;
18311 +
18312 +    name = (gss_name_t)GSSEAP_CALLOC(1, sizeof(*name));
18313 +    if (name == NULL) {
18314 +        *minor = ENOMEM;
18315 +        return GSS_S_FAILURE;
18316 +    }
18317 +
18318 +    if (GSSEAP_MUTEX_INIT(&name->mutex) != 0) {
18319 +        *minor = GSSEAP_GET_LAST_ERROR();
18320 +        gssEapReleaseName(&tmpMinor, &name);
18321 +        return GSS_S_FAILURE;
18322 +    }
18323 +
18324 +    *pName = name;
18325 +
18326 +    return GSS_S_COMPLETE;
18327 +}
18328 +
18329 +OM_uint32
18330 +gssEapReleaseName(OM_uint32 *minor, gss_name_t *pName)
18331 +{
18332 +    gss_name_t name;
18333 +    krb5_context krbContext = NULL;
18334 +    OM_uint32 tmpMinor;
18335 +
18336 +    *minor = 0;
18337 +
18338 +    if (pName == NULL) {
18339 +        return GSS_S_COMPLETE;
18340 +    }
18341 +
18342 +    name = *pName;
18343 +    if (name == GSS_C_NO_NAME) {
18344 +        return GSS_S_COMPLETE;
18345 +    }
18346 +
18347 +    GSSEAP_KRB_INIT(&krbContext);
18348 +    krb5_free_principal(krbContext, name->krbPrincipal);
18349 +    gssEapReleaseOid(&tmpMinor, &name->mechanismUsed);
18350 +#ifdef GSSEAP_ENABLE_ACCEPTOR
18351 +    gssEapReleaseAttrContext(&tmpMinor, name);
18352 +#endif
18353 +
18354 +    GSSEAP_MUTEX_DESTROY(&name->mutex);
18355 +    GSSEAP_FREE(name);
18356 +    *pName = NULL;
18357 +
18358 +    return GSS_S_COMPLETE;
18359 +}
18360 +
18361 +static OM_uint32
18362 +krbPrincipalToName(OM_uint32 *minor,
18363 +                   krb5_principal *principal,
18364 +                   gss_name_t *pName)
18365 +{
18366 +    OM_uint32 major;
18367 +    gss_name_t name;
18368 +
18369 +    major = gssEapAllocName(minor, &name);
18370 +    if (GSS_ERROR(major))
18371 +        return major;
18372 +
18373 +    name->krbPrincipal = *principal;
18374 +    *principal = NULL;
18375 +
18376 +    if (KRB_PRINC_LENGTH(name->krbPrincipal) > 1) {
18377 +        name->flags |= NAME_FLAG_SERVICE;
18378 +    } else {
18379 +        name->flags |= NAME_FLAG_NAI;
18380 +    }
18381 +
18382 +    *pName = name;
18383 +    *minor = 0;
18384 +
18385 +    return GSS_S_COMPLETE;
18386 +}
18387 +
18388 +static char *
18389 +gssEapGetDefaultRealm(krb5_context krbContext)
18390 +{
18391 +    char *defaultRealm = NULL;
18392 +
18393 +    krb5_appdefault_string(krbContext, "eap_gss",
18394 +                           NULL, "default_realm", "", &defaultRealm);
18395 +
18396 +    return defaultRealm;
18397 +}
18398 +
18399 +static OM_uint32
18400 +importServiceName(OM_uint32 *minor,
18401 +                  const gss_buffer_t nameBuffer,
18402 +                  gss_name_t *pName)
18403 +{
18404 +    OM_uint32 major;
18405 +    krb5_error_code code;
18406 +    krb5_context krbContext;
18407 +    krb5_principal krbPrinc;
18408 +    char *service, *host, *realm = NULL;
18409 +
18410 +    GSSEAP_KRB_INIT(&krbContext);
18411 +
18412 +    major = bufferToString(minor, nameBuffer, &service);
18413 +    if (GSS_ERROR(major))
18414 +        return major;
18415 +
18416 +    host = strchr(service, '@');
18417 +    if (host != NULL) {
18418 +        *host = '\0';
18419 +        host++;
18420 +    }
18421 +
18422 +    realm = gssEapGetDefaultRealm(krbContext);
18423 +
18424 +    code = krb5_build_principal(krbContext,
18425 +                                &krbPrinc,
18426 +                                realm != NULL ? strlen(realm) : 0,
18427 +                                realm != NULL ? realm : "",
18428 +                                service,
18429 +                                host,
18430 +                                NULL);
18431 +
18432 +    if (code == 0) {
18433 +        KRB_PRINC_TYPE(krbPrinc) = KRB5_NT_SRV_HST;
18434 +
18435 +        major = krbPrincipalToName(minor, &krbPrinc, pName);
18436 +        if (GSS_ERROR(major))
18437 +            krb5_free_principal(krbContext, krbPrinc);
18438 +    } else {
18439 +        major = GSS_S_FAILURE;
18440 +        *minor = GSSEAP_BAD_SERVICE_NAME;
18441 +    }
18442 +
18443 +    if (realm != NULL)
18444 +        krb5_free_default_realm(krbContext, realm);
18445 +    GSSEAP_FREE(service);
18446 +
18447 +    return major;
18448 +}
18449 +
18450 +#define IMPORT_FLAG_DEFAULT_REALM           0x1
18451 +
18452 +/*
18453 + * Import an EAP name, possibly appending the default GSS EAP realm,
18454 + */
18455 +static OM_uint32
18456 +importEapNameFlags(OM_uint32 *minor,
18457 +                   const gss_buffer_t nameBuffer,
18458 +                   OM_uint32 importFlags,
18459 +                   gss_name_t *pName)
18460 +{
18461 +    OM_uint32 major;
18462 +    krb5_context krbContext;
18463 +    krb5_principal krbPrinc = NULL;
18464 +    krb5_error_code code;
18465 +    char *nameString;
18466 +
18467 +    GSSEAP_KRB_INIT(&krbContext);
18468 +
18469 +    if (nameBuffer == GSS_C_NO_BUFFER) {
18470 +        nameString = "";
18471 +        code = KRB5_PARSE_MALFORMED;
18472 +    } else {
18473 +        major = bufferToString(minor, nameBuffer, &nameString);
18474 +        if (GSS_ERROR(major))
18475 +            return major;
18476 +
18477 +        /*
18478 +         * First, attempt to parse the name on the assumption that it includes
18479 +         * a qualifying realm. This allows us to avoid accidentally appending
18480 +         * the default Kerberos realm to an unqualified name. (A bug in MIT
18481 +         * Kerberos prevents the default realm being set to an empty value.)
18482 +         */
18483 +        code = krb5_parse_name_flags(krbContext, nameString,
18484 +                                     KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &krbPrinc);
18485 +    }
18486 +
18487 +    if (code == KRB5_PARSE_MALFORMED) {
18488 +        char *defaultRealm = NULL;
18489 +        int parseFlags = 0;
18490 +
18491 +        /* Possibly append the default EAP realm if required */
18492 +        if (importFlags & IMPORT_FLAG_DEFAULT_REALM)
18493 +            defaultRealm = gssEapGetDefaultRealm(krbContext);
18494 +
18495 +        /* If no default realm, leave the realm empty in the parsed name */
18496 +        if (defaultRealm == NULL || defaultRealm[0] == '\0')
18497 +            parseFlags |= KRB5_PRINCIPAL_PARSE_NO_REALM;
18498 +
18499 +        code = krb5_parse_name_flags(krbContext, nameString, parseFlags, &krbPrinc);
18500 +
18501 +#ifdef HAVE_HEIMDAL_VERSION
18502 +        if (code == 0 && KRB_PRINC_REALM(krbPrinc) == NULL) {
18503 +            KRB_PRINC_REALM(krbPrinc) = KRB_CALLOC(1, sizeof(char));
18504 +            if (KRB_PRINC_REALM(krbPrinc) == NULL)
18505 +                code = ENOMEM;
18506 +        }
18507 +#endif
18508 +
18509 +        if (defaultRealm != NULL)
18510 +            krb5_free_default_realm(krbContext, defaultRealm);
18511 +    }
18512 +
18513 +    if (nameBuffer != GSS_C_NO_BUFFER)
18514 +        GSSEAP_FREE(nameString);
18515 +
18516 +    if (code != 0) {
18517 +        *minor = code;
18518 +        return GSS_S_FAILURE;
18519 +    }
18520 +
18521 +    GSSEAP_ASSERT(krbPrinc != NULL);
18522 +
18523 +    major = krbPrincipalToName(minor, &krbPrinc, pName);
18524 +    if (GSS_ERROR(major))
18525 +        krb5_free_principal(krbContext, krbPrinc);
18526 +
18527 +    return major;
18528 +}
18529 +
18530 +static OM_uint32
18531 +importEapName(OM_uint32 *minor,
18532 +              const gss_buffer_t nameBuffer,
18533 +              gss_name_t *pName)
18534 +{
18535 +    return importEapNameFlags(minor, nameBuffer, 0, pName);
18536 +}
18537 +
18538 +static OM_uint32
18539 +importUserName(OM_uint32 *minor,
18540 +               const gss_buffer_t nameBuffer,
18541 +               gss_name_t *pName)
18542 +{
18543 +    return importEapNameFlags(minor, nameBuffer, IMPORT_FLAG_DEFAULT_REALM, pName);
18544 +}
18545 +
18546 +static OM_uint32
18547 +importAnonymousName(OM_uint32 *minor,
18548 +                    const gss_buffer_t nameBuffer GSSEAP_UNUSED,
18549 +                    gss_name_t *pName)
18550 +{
18551 +    return importEapNameFlags(minor, GSS_C_NO_BUFFER, 0, pName);
18552 +}
18553 +
18554 +#define UPDATE_REMAIN(n)    do {            \
18555 +        p += (n);                           \
18556 +        remain -= (n);                      \
18557 +    } while (0)
18558 +
18559 +#define CHECK_REMAIN(n)     do {        \
18560 +        if (remain < (n)) {             \
18561 +            major = GSS_S_BAD_NAME;     \
18562 +            *minor = GSSEAP_TOK_TRUNC;  \
18563 +            goto cleanup;               \
18564 +        }                               \
18565 +    } while (0)
18566 +
18567 +OM_uint32
18568 +gssEapImportNameInternal(OM_uint32 *minor,
18569 +                         const gss_buffer_t nameBuffer,
18570 +                         gss_name_t *pName,
18571 +                         OM_uint32 flags)
18572 +{
18573 +    OM_uint32 major, tmpMinor;
18574 +    krb5_context krbContext;
18575 +    unsigned char *p;
18576 +    size_t len, remain;
18577 +    gss_buffer_desc buf;
18578 +    gss_name_t name = GSS_C_NO_NAME;
18579 +    gss_OID mechanismUsed = GSS_C_NO_OID;
18580 +
18581 +    GSSEAP_KRB_INIT(&krbContext);
18582 +
18583 +    p = (unsigned char *)nameBuffer->value;
18584 +    remain = nameBuffer->length;
18585 +
18586 +    if (flags & EXPORT_NAME_FLAG_OID) {
18587 +        gss_OID_desc mech;
18588 +        enum gss_eap_token_type tokType;
18589 +        uint16_t wireTokType;
18590 +
18591 +        /* TOK_ID || MECH_OID_LEN || MECH_OID */
18592 +        if (remain < 6) {
18593 +            *minor = GSSEAP_BAD_NAME_TOKEN;
18594 +            return GSS_S_BAD_NAME;
18595 +        }
18596 +
18597 +        if (flags & EXPORT_NAME_FLAG_COMPOSITE)
18598 +            tokType = TOK_TYPE_EXPORT_NAME_COMPOSITE;
18599 +        else
18600 +            tokType = TOK_TYPE_EXPORT_NAME;
18601 +
18602 +        /* TOK_ID */
18603 +        wireTokType = load_uint16_be(p);
18604 +
18605 +        if ((flags & EXPORT_NAME_FLAG_ALLOW_COMPOSITE) &&
18606 +            wireTokType == TOK_TYPE_EXPORT_NAME_COMPOSITE) {
18607 +            tokType = TOK_TYPE_EXPORT_NAME_COMPOSITE;
18608 +            flags |= EXPORT_NAME_FLAG_COMPOSITE;
18609 +        }
18610 +
18611 +        if (wireTokType != tokType) {
18612 +            *minor = GSSEAP_WRONG_TOK_ID;
18613 +            return GSS_S_BAD_NAME;
18614 +        }
18615 +        UPDATE_REMAIN(2);
18616 +
18617 +        /* MECH_OID_LEN */
18618 +        len = load_uint16_be(p);
18619 +        if (len < 2) {
18620 +            *minor = GSSEAP_BAD_NAME_TOKEN;
18621 +            return GSS_S_BAD_NAME;
18622 +        }
18623 +        UPDATE_REMAIN(2);
18624 +
18625 +        /* MECH_OID */
18626 +        if (p[0] != 0x06) {
18627 +            *minor = GSSEAP_BAD_NAME_TOKEN;
18628 +            return GSS_S_BAD_NAME;
18629 +        }
18630 +
18631 +        mech.length = p[1];
18632 +        mech.elements = &p[2];
18633 +
18634 +        CHECK_REMAIN(mech.length);
18635 +
18636 +        major = gssEapCanonicalizeOid(minor,
18637 +                                      &mech,
18638 +                                      OID_FLAG_FAMILY_MECH_VALID |
18639 +                                        OID_FLAG_MAP_FAMILY_MECH_TO_NULL,
18640 +                                      &mechanismUsed);
18641 +        if (GSS_ERROR(major))
18642 +            goto cleanup;
18643 +
18644 +        UPDATE_REMAIN(2 + mech.length);
18645 +    }
18646 +
18647 +    /* NAME_LEN */
18648 +    CHECK_REMAIN(4);
18649 +    len = load_uint32_be(p);
18650 +    UPDATE_REMAIN(4);
18651 +
18652 +    /* NAME */
18653 +    CHECK_REMAIN(len);
18654 +    buf.length = len;
18655 +    buf.value = p;
18656 +    UPDATE_REMAIN(len);
18657 +
18658 +    major = importEapNameFlags(minor, &buf, 0, &name);
18659 +    if (GSS_ERROR(major))
18660 +        goto cleanup;
18661 +
18662 +    name->mechanismUsed = mechanismUsed;
18663 +    mechanismUsed = GSS_C_NO_OID;
18664 +
18665 +#ifdef GSSEAP_ENABLE_ACCEPTOR
18666 +    if (flags & EXPORT_NAME_FLAG_COMPOSITE) {
18667 +        gss_buffer_desc buf;
18668 +
18669 +        buf.length = remain;
18670 +        buf.value = p;
18671 +
18672 +        major = gssEapImportAttrContext(minor, &buf, name);
18673 +        if (GSS_ERROR(major))
18674 +            goto cleanup;
18675 +    }
18676 +#endif
18677 +
18678 +    major = GSS_S_COMPLETE;
18679 +    *minor = 0;
18680 +
18681 +cleanup:
18682 +    if (GSS_ERROR(major)) {
18683 +        gssEapReleaseOid(&tmpMinor, &mechanismUsed);
18684 +        gssEapReleaseName(&tmpMinor, &name);
18685 +    } else {
18686 +        *pName = name;
18687 +    }
18688 +
18689 +    return major;
18690 +}
18691 +
18692 +static OM_uint32
18693 +importExportName(OM_uint32 *minor,
18694 +                 const gss_buffer_t nameBuffer,
18695 +                 gss_name_t *name)
18696 +{
18697 +    return gssEapImportNameInternal(minor, nameBuffer, name,
18698 +                                    EXPORT_NAME_FLAG_OID |
18699 +                                    EXPORT_NAME_FLAG_ALLOW_COMPOSITE);
18700 +}
18701 +
18702 +#ifdef HAVE_GSS_C_NT_COMPOSITE_EXPORT
18703 +static OM_uint32
18704 +importCompositeExportName(OM_uint32 *minor,
18705 +                          const gss_buffer_t nameBuffer,
18706 +                          gss_name_t *name)
18707 +{
18708 +    return gssEapImportNameInternal(minor, nameBuffer, name,
18709 +                                    EXPORT_NAME_FLAG_OID |
18710 +                                    EXPORT_NAME_FLAG_COMPOSITE);
18711 +}
18712 +#endif
18713 +
18714 +struct gss_eap_name_import_provider {
18715 +    gss_const_OID oid;
18716 +    OM_uint32 (*import)(OM_uint32 *, const gss_buffer_t, gss_name_t *);
18717 +};
18718 +
18719 +OM_uint32
18720 +gssEapImportName(OM_uint32 *minor,
18721 +                 const gss_buffer_t nameBuffer,
18722 +                 const gss_OID nameType,
18723 +                 const gss_OID mechType,
18724 +                 gss_name_t *pName)
18725 +{
18726 +    struct gss_eap_name_import_provider nameTypes[] = {
18727 +        { GSS_EAP_NT_EAP_NAME,              importEapName               },
18728 +        { GSS_C_NT_USER_NAME,               importUserName              },
18729 +        { GSS_C_NT_HOSTBASED_SERVICE,       importServiceName           },
18730 +        { GSS_C_NT_HOSTBASED_SERVICE_X,     importServiceName           },
18731 +        { GSS_C_NT_ANONYMOUS,               importAnonymousName         },
18732 +        { GSS_C_NT_EXPORT_NAME,             importExportName            },
18733 +        { GSS_KRB5_NT_PRINCIPAL_NAME,       importUserName              },
18734 +#ifdef HAVE_GSS_C_NT_COMPOSITE_EXPORT
18735 +        { GSS_C_NT_COMPOSITE_EXPORT,        importCompositeExportName   },
18736 +#endif
18737 +    };
18738 +    size_t i;
18739 +    OM_uint32 major = GSS_S_BAD_NAMETYPE;
18740 +    OM_uint32 tmpMinor;
18741 +    gss_name_t name = GSS_C_NO_NAME;
18742 +
18743 +    for (i = 0; i < sizeof(nameTypes) / sizeof(nameTypes[0]); i++) {
18744 +        if (oidEqual(nameTypes[i].oid,
18745 +                     nameType == GSS_C_NO_OID ? GSS_EAP_NT_EAP_NAME : nameType)) {
18746 +            major = nameTypes[i].import(minor, nameBuffer, &name);
18747 +            break;
18748 +        }
18749 +    }
18750 +
18751 +    if (major == GSS_S_COMPLETE &&
18752 +        mechType != GSS_C_NO_OID) {
18753 +        GSSEAP_ASSERT(gssEapIsConcreteMechanismOid(mechType));
18754 +        GSSEAP_ASSERT(name->mechanismUsed == GSS_C_NO_OID);
18755 +
18756 +        major = gssEapCanonicalizeOid(minor, mechType, 0, &name->mechanismUsed);
18757 +    }
18758 +
18759 +    if (GSS_ERROR(major))
18760 +        gssEapReleaseName(&tmpMinor, &name);
18761 +    else
18762 +        *pName = name;
18763 +
18764 +    return major;
18765 +}
18766 +
18767 +OM_uint32
18768 +gssEapExportName(OM_uint32 *minor,
18769 +                 const gss_name_t name,
18770 +                 gss_buffer_t exportedName)
18771 +{
18772 +    return gssEapExportNameInternal(minor, name, exportedName,
18773 +                                    EXPORT_NAME_FLAG_OID);
18774 +}
18775 +
18776 +OM_uint32
18777 +gssEapExportNameInternal(OM_uint32 *minor,
18778 +                         const gss_name_t name,
18779 +                         gss_buffer_t exportedName,
18780 +                         OM_uint32 flags)
18781 +{
18782 +    OM_uint32 major = GSS_S_FAILURE, tmpMinor;
18783 +    gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
18784 +    size_t exportedNameLen;
18785 +    unsigned char *p;
18786 +    gss_buffer_desc attrs = GSS_C_EMPTY_BUFFER;
18787 +    gss_OID mech;
18788 +
18789 +    exportedName->length = 0;
18790 +    exportedName->value = NULL;
18791 +
18792 +    if (name->mechanismUsed != GSS_C_NO_OID)
18793 +        mech = name->mechanismUsed;
18794 +    else
18795 +        mech = GSS_EAP_MECHANISM;
18796 +
18797 +    major = gssEapDisplayName(minor, name, &nameBuf, NULL);
18798 +    if (GSS_ERROR(major))
18799 +        goto cleanup;
18800 +
18801 +    exportedNameLen = 0;
18802 +    if (flags & EXPORT_NAME_FLAG_OID) {
18803 +        exportedNameLen += 6 + mech->length;
18804 +    }
18805 +    exportedNameLen += 4 + nameBuf.length;
18806 +#ifdef GSSEAP_ENABLE_ACCEPTOR
18807 +    if (flags & EXPORT_NAME_FLAG_COMPOSITE) {
18808 +        major = gssEapExportAttrContext(minor, name, &attrs);
18809 +        if (GSS_ERROR(major))
18810 +            goto cleanup;
18811 +        exportedNameLen += attrs.length;
18812 +    }
18813 +#endif
18814 +
18815 +    exportedName->value = GSSEAP_MALLOC(exportedNameLen);
18816 +    if (exportedName->value == NULL) {
18817 +        major = GSS_S_FAILURE;
18818 +        *minor = ENOMEM;
18819 +        goto cleanup;
18820 +    }
18821 +    exportedName->length = exportedNameLen;
18822 +
18823 +    p = (unsigned char *)exportedName->value;
18824 +
18825 +    if (flags & EXPORT_NAME_FLAG_OID) {
18826 +        /* TOK | MECH_OID_LEN */
18827 +        store_uint16_be((flags & EXPORT_NAME_FLAG_COMPOSITE)
18828 +                        ? TOK_TYPE_EXPORT_NAME_COMPOSITE
18829 +                        : TOK_TYPE_EXPORT_NAME,
18830 +                        p);
18831 +        p += 2;
18832 +        store_uint16_be(mech->length + 2, p);
18833 +        p += 2;
18834 +
18835 +        /* MECH_OID */
18836 +        *p++ = 0x06;
18837 +        *p++ = mech->length & 0xff;
18838 +        memcpy(p, mech->elements, mech->length);
18839 +        p += mech->length;
18840 +    }
18841 +
18842 +    /* NAME_LEN */
18843 +    store_uint32_be(nameBuf.length, p);
18844 +    p += 4;
18845 +
18846 +    /* NAME */
18847 +    memcpy(p, nameBuf.value, nameBuf.length);
18848 +    p += nameBuf.length;
18849 +
18850 +    if (flags & EXPORT_NAME_FLAG_COMPOSITE) {
18851 +        memcpy(p, attrs.value, attrs.length);
18852 +        p += attrs.length;
18853 +    }
18854 +
18855 +    GSSEAP_ASSERT(p == (unsigned char *)exportedName->value + exportedNameLen);
18856 +
18857 +    major = GSS_S_COMPLETE;
18858 +    *minor = 0;
18859 +
18860 +cleanup:
18861 +    gss_release_buffer(&tmpMinor, &attrs);
18862 +    gss_release_buffer(&tmpMinor, &nameBuf);
18863 +    if (GSS_ERROR(major))
18864 +        gss_release_buffer(&tmpMinor, exportedName);
18865 +
18866 +    return major;
18867 +}
18868 +
18869 +OM_uint32
18870 +gssEapCanonicalizeName(OM_uint32 *minor,
18871 +                       const gss_name_t input_name,
18872 +                       const gss_OID mech_type,
18873 +                       gss_name_t *dest_name)
18874 +{
18875 +    OM_uint32 major, tmpMinor;
18876 +    krb5_context krbContext;
18877 +    gss_name_t name;
18878 +    gss_OID mech_used;
18879 +
18880 +    if (input_name == GSS_C_NO_NAME) {
18881 +        *minor = EINVAL;
18882 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
18883 +    }
18884 +
18885 +    GSSEAP_KRB_INIT(&krbContext);
18886 +
18887 +    major = gssEapAllocName(minor, &name);
18888 +    if (GSS_ERROR(major)) {
18889 +        return major;
18890 +    }
18891 +
18892 +    if (mech_type != GSS_C_NO_OID)
18893 +        mech_used = mech_type;
18894 +    else
18895 +        mech_used = input_name->mechanismUsed;
18896 +
18897 +    major = gssEapCanonicalizeOid(minor,
18898 +                                  mech_used,
18899 +                                  OID_FLAG_NULL_VALID,
18900 +                                  &name->mechanismUsed);
18901 +    if (GSS_ERROR(major))
18902 +        goto cleanup;
18903 +
18904 +    name->flags = input_name->flags;
18905 +
18906 +    *minor = krb5_copy_principal(krbContext, input_name->krbPrincipal,
18907 +                                 &name->krbPrincipal);
18908 +    if (*minor != 0) {
18909 +        major = GSS_S_FAILURE;
18910 +        goto cleanup;
18911 +    }
18912 +
18913 +#ifdef GSSEAP_ENABLE_ACCEPTOR
18914 +    if (input_name->attrCtx != NULL) {
18915 +        major = gssEapDuplicateAttrContext(minor, input_name, name);
18916 +        if (GSS_ERROR(major))
18917 +            goto cleanup;
18918 +    }
18919 +#endif
18920 +
18921 +    *dest_name = name;
18922 +
18923 +cleanup:
18924 +    if (GSS_ERROR(major)) {
18925 +        gssEapReleaseName(&tmpMinor, &name);
18926 +    }
18927 +
18928 +    return major;
18929 +}
18930 +
18931 +OM_uint32
18932 +gssEapDuplicateName(OM_uint32 *minor,
18933 +                    const gss_name_t input_name,
18934 +                    gss_name_t *dest_name)
18935 +{
18936 +    return gssEapCanonicalizeName(minor, input_name,
18937 +                                  GSS_C_NO_OID, dest_name);
18938 +}
18939 +
18940 +OM_uint32
18941 +gssEapDisplayName(OM_uint32 *minor,
18942 +                  gss_name_t name,
18943 +                  gss_buffer_t output_name_buffer,
18944 +                  gss_OID *output_name_type)
18945 +{
18946 +    OM_uint32 major;
18947 +    krb5_context krbContext;
18948 +    char *krbName;
18949 +    gss_OID name_type;
18950 +    int flags = 0;
18951 +
18952 +    GSSEAP_KRB_INIT(&krbContext);
18953 +
18954 +    output_name_buffer->length = 0;
18955 +    output_name_buffer->value = NULL;
18956 +
18957 +    if (name == GSS_C_NO_NAME) {
18958 +        *minor = EINVAL;
18959 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
18960 +    }
18961 +
18962 +    /*
18963 +     * According to draft-ietf-abfab-gss-eap-01, when the realm is
18964 +     * absent the trailing '@' is not included.
18965 +     */
18966 +#ifdef HAVE_HEIMDAL_VERSION
18967 +    if (KRB_PRINC_REALM(name->krbPrincipal) == NULL ||
18968 +        KRB_PRINC_REALM(name->krbPrincipal)[0] == '\0')
18969 +#else
18970 +    if (KRB_PRINC_REALM(name->krbPrincipal)->length == 0)
18971 +#endif
18972 +        flags |= KRB5_PRINCIPAL_UNPARSE_NO_REALM;
18973 +
18974 +    *minor = krb5_unparse_name_flags(krbContext, name->krbPrincipal,
18975 +                                     flags, &krbName);
18976 +    if (*minor != 0) {
18977 +        return GSS_S_FAILURE;
18978 +    }
18979 +
18980 +    major = makeStringBuffer(minor, krbName, output_name_buffer);
18981 +    if (GSS_ERROR(major)) {
18982 +        krb5_free_unparsed_name(krbContext, krbName);
18983 +        return major;
18984 +    }
18985 +
18986 +    krb5_free_unparsed_name(krbContext, krbName);
18987 +
18988 +    if (output_name_buffer->length == 0) {
18989 +        name_type = GSS_C_NT_ANONYMOUS;
18990 +    } else if (name->flags & NAME_FLAG_NAI) {
18991 +        name_type = GSS_C_NT_USER_NAME;
18992 +    } else {
18993 +        name_type = GSS_EAP_NT_EAP_NAME;
18994 +    }
18995 +
18996 +    if (output_name_type != NULL)
18997 +        *output_name_type = name_type;
18998 +
18999 +    return GSS_S_COMPLETE;
19000 +}
19001 +
19002 +OM_uint32
19003 +gssEapCompareName(OM_uint32 *minor,
19004 +                  gss_name_t name1,
19005 +                  gss_name_t name2,
19006 +                  int *name_equal)
19007 +{
19008 +    krb5_context krbContext;
19009 +
19010 +    *minor = 0;
19011 +
19012 +    if (name1 == GSS_C_NO_NAME && name2 == GSS_C_NO_NAME) {
19013 +        *name_equal = 1;
19014 +    } else if (name1 != GSS_C_NO_NAME && name2 != GSS_C_NO_NAME) {
19015 +        GSSEAP_KRB_INIT(&krbContext);
19016 +
19017 +        /* krbPrincipal is immutable, so lock not required */
19018 +        *name_equal = krb5_principal_compare(krbContext,
19019 +                                             name1->krbPrincipal,
19020 +                                             name2->krbPrincipal);
19021 +    }
19022 +
19023 +    return GSS_S_COMPLETE;
19024 +}
19025 diff --git a/mech_eap/util_oid.c b/mech_eap/util_oid.c
19026 new file mode 100644
19027 index 0000000..096c9f8
19028 --- /dev/null
19029 +++ b/mech_eap/util_oid.c
19030 @@ -0,0 +1,206 @@
19031 +/*
19032 + * Copyright (c) 2011, JANET(UK)
19033 + * All rights reserved.
19034 + *
19035 + * Redistribution and use in source and binary forms, with or without
19036 + * modification, are permitted provided that the following conditions
19037 + * are met:
19038 + *
19039 + * 1. Redistributions of source code must retain the above copyright
19040 + *    notice, this list of conditions and the following disclaimer.
19041 + *
19042 + * 2. Redistributions in binary form must reproduce the above copyright
19043 + *    notice, this list of conditions and the following disclaimer in the
19044 + *    documentation and/or other materials provided with the distribution.
19045 + *
19046 + * 3. Neither the name of JANET(UK) nor the names of its contributors
19047 + *    may be used to endorse or promote products derived from this software
19048 + *    without specific prior written permission.
19049 + *
19050 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19051 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19052 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19053 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19054 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19055 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19056 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19057 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
19058 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
19059 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
19060 + * SUCH DAMAGE.
19061 + */
19062 +/*
19063 + * Copyright 1995-2010 by the Massachusetts Institute of Technology.
19064 + * All Rights Reserved.
19065 + *
19066 + * Export of this software from the United States of America may
19067 + *   require a specific license from the United States Government.
19068 + *   It is the responsibility of any person or organization contemplating
19069 + *   export to obtain such a license before exporting.
19070 + *
19071 + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
19072 + * distribute this software and its documentation for any purpose and
19073 + * without fee is hereby granted, provided that the above copyright
19074 + * notice appear in all copies and that both that copyright notice and
19075 + * this permission notice appear in supporting documentation, and that
19076 + * the name of M.I.T. not be used in advertising or publicity pertaining
19077 + * to distribution of the software without specific, written prior
19078 + * permission.  Furthermore if you modify this software you must label
19079 + * your software as modified software and not distribute it in such a
19080 + * fashion that it might be confused with the original M.I.T. software.
19081 + * M.I.T. makes no representations about the suitability of
19082 + * this software for any purpose.  It is provided "as is" without express
19083 + * or implied warranty.
19084 + *
19085 + */
19086 +
19087 +/*
19088 + * OID utility routines.
19089 + */
19090 +
19091 +#include "gssapiP_eap.h"
19092 +
19093 +OM_uint32
19094 +duplicateOid(OM_uint32 *minor,
19095 +             const gss_OID_desc * const oid,
19096 +             gss_OID *newOid)
19097 +{
19098 +    gss_OID p;
19099 +
19100 +    *newOid = GSS_C_NO_OID;
19101 +
19102 +    p = (gss_OID)GSSEAP_MALLOC(sizeof(*p));
19103 +    if (p == NULL) {
19104 +        *minor = ENOMEM;
19105 +        return GSS_S_FAILURE;
19106 +    }
19107 +    p->length = oid->length;
19108 +    p->elements = GSSEAP_MALLOC(p->length);
19109 +    if (p->elements == NULL) {
19110 +        GSSEAP_FREE(p);
19111 +        *minor = ENOMEM;
19112 +        return GSS_S_FAILURE;
19113 +    }
19114 +
19115 +    memcpy(p->elements, oid->elements, p->length);
19116 +    *newOid = p;
19117 +
19118 +    *minor = 0;
19119 +    return GSS_S_COMPLETE;
19120 +}
19121 +
19122 +/* Compose an OID of a prefix and an integer suffix */
19123 +OM_uint32
19124 +composeOid(OM_uint32 *minor,
19125 +           const char *prefix,
19126 +           size_t prefix_len,
19127 +           int suffix,
19128 +           gss_OID_desc *oid)
19129 +{
19130 +    int osuffix, i;
19131 +    size_t nbytes;
19132 +    unsigned char *op;
19133 +
19134 +    if (oid == GSS_C_NO_OID) {
19135 +        *minor = EINVAL;
19136 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_FAILURE;
19137 +    }
19138 +
19139 +    if (oid->length < prefix_len) {
19140 +        *minor = GSSEAP_WRONG_SIZE;
19141 +        return GSS_S_FAILURE;
19142 +    }
19143 +
19144 +    memcpy(oid->elements, prefix, prefix_len);
19145 +
19146 +    nbytes = 0;
19147 +    osuffix = suffix;
19148 +    while (suffix) {
19149 +        nbytes++;
19150 +        suffix >>= 7;
19151 +    }
19152 +    suffix = osuffix;
19153 +
19154 +    if (oid->length < prefix_len + nbytes) {
19155 +        *minor = GSSEAP_WRONG_SIZE;
19156 +        return GSS_S_FAILURE;
19157 +    }
19158 +
19159 +    op = (unsigned char *) oid->elements + prefix_len + nbytes;
19160 +    i = -1;
19161 +    while (suffix) {
19162 +        op[i] = (unsigned char)suffix & 0x7f;
19163 +        if (i != -1)
19164 +            op[i] |= 0x80;
19165 +        i--;
19166 +        suffix >>= 7;
19167 +    }
19168 +
19169 +    oid->length = prefix_len + nbytes;
19170 +
19171 +    *minor = 0;
19172 +    return GSS_S_COMPLETE;
19173 +}
19174 +
19175 +OM_uint32
19176 +decomposeOid(OM_uint32 *minor,
19177 +             const char *prefix,
19178 +             size_t prefix_len,
19179 +             gss_OID_desc *oid,
19180 +             int *suffix)
19181 +{
19182 +    size_t i, slen;
19183 +    unsigned char *op;
19184 +
19185 +    if (oid->length < prefix_len ||
19186 +        memcmp(oid->elements, prefix, prefix_len) != 0) {
19187 +        return GSS_S_BAD_MECH;
19188 +    }
19189 +
19190 +    op = (unsigned char *) oid->elements + prefix_len;
19191 +
19192 +    *suffix = 0;
19193 +
19194 +    slen = oid->length - prefix_len;
19195 +
19196 +    for (i = 0; i < slen; i++) {
19197 +        *suffix = (*suffix << 7) | (op[i] & 0x7f);
19198 +        if (i + 1 != slen && (op[i] & 0x80) == 0) {
19199 +            *minor = GSSEAP_WRONG_SIZE;
19200 +            return GSS_S_FAILURE;
19201 +        }
19202 +    }
19203 +
19204 +    return GSS_S_COMPLETE;
19205 +}
19206 +
19207 +OM_uint32
19208 +duplicateOidSet(OM_uint32 *minor,
19209 +                const gss_OID_set src,
19210 +                gss_OID_set *dst)
19211 +{
19212 +    OM_uint32 major, tmpMinor;
19213 +    int i;
19214 +
19215 +    if (src == GSS_C_NO_OID_SET) {
19216 +        *dst = GSS_C_NO_OID_SET;
19217 +        return GSS_S_COMPLETE;
19218 +    }
19219 +
19220 +    major = gss_create_empty_oid_set(minor, dst);
19221 +    if (GSS_ERROR(major))
19222 +        return major;
19223 +
19224 +    for (i = 0; i < src->count; i++) {
19225 +        gss_OID oid = &src->elements[i];
19226 +
19227 +        major = gss_add_oid_set_member(minor, oid, dst);
19228 +        if (GSS_ERROR(major))
19229 +            break;
19230 +    }
19231 +
19232 +    if (GSS_ERROR(major))
19233 +        gss_release_oid_set(&tmpMinor, dst);
19234 +
19235 +    return major;
19236 +}
19237 diff --git a/mech_eap/util_ordering.c b/mech_eap/util_ordering.c
19238 new file mode 100644
19239 index 0000000..71ebfb5
19240 --- /dev/null
19241 +++ b/mech_eap/util_ordering.c
19242 @@ -0,0 +1,302 @@
19243 +/*
19244 + * Copyright (c) 2011, JANET(UK)
19245 + * All rights reserved.
19246 + *
19247 + * Redistribution and use in source and binary forms, with or without
19248 + * modification, are permitted provided that the following conditions
19249 + * are met:
19250 + *
19251 + * 1. Redistributions of source code must retain the above copyright
19252 + *    notice, this list of conditions and the following disclaimer.
19253 + *
19254 + * 2. Redistributions in binary form must reproduce the above copyright
19255 + *    notice, this list of conditions and the following disclaimer in the
19256 + *    documentation and/or other materials provided with the distribution.
19257 + *
19258 + * 3. Neither the name of JANET(UK) nor the names of its contributors
19259 + *    may be used to endorse or promote products derived from this software
19260 + *    without specific prior written permission.
19261 + *
19262 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19263 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19264 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19265 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19266 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19267 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19268 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19269 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
19270 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
19271 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
19272 + * SUCH DAMAGE.
19273 + */
19274 +/*
19275 + * Copyright 1993 by OpenVision Technologies, Inc.
19276 + *
19277 + * Permission to use, copy, modify, distribute, and sell this software
19278 + * and its documentation for any purpose is hereby granted without fee,
19279 + * provided that the above copyright notice appears in all copies and
19280 + * that both that copyright notice and this permission notice appear in
19281 + * supporting documentation, and that the name of OpenVision not be used
19282 + * in advertising or publicity pertaining to distribution of the software
19283 + * without specific, written prior permission. OpenVision makes no
19284 + * representations about the suitability of this software for any
19285 + * purpose.  It is provided "as is" without express or implied warranty.
19286 + *
19287 + * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
19288 + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19289 + * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19290 + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
19291 + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
19292 + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19293 + * PERFORMANCE OF THIS SOFTWARE.
19294 + */
19295 +
19296 +/*
19297 + * Functions to check sequence numbers for replay and sequencing
19298 + */
19299 +
19300 +#include "gssapiP_eap.h"
19301 +
19302 +#define QUEUE_LENGTH 20
19303 +
19304 +typedef struct _queue {
19305 +    int do_replay;
19306 +    int do_sequence;
19307 +    int start;
19308 +    int length;
19309 +    uint64_t firstnum;
19310 +    /* Stored as deltas from firstnum.  This way, the high bit won't
19311 +       overflow unless we've actually gone through 2**n messages, or
19312 +       gotten something *way* out of sequence.  */
19313 +    uint64_t elem[QUEUE_LENGTH];
19314 +    /* All ones for 64-bit sequence numbers; 32 ones for 32-bit
19315 +       sequence numbers.  */
19316 +    uint64_t mask;
19317 +} queue;
19318 +
19319 +/* rep invariant:
19320 + *  - the queue is a circular queue.  The first element (q->elem[q->start])
19321 + * is the oldest.  The last element is the newest.
19322 + */
19323 +
19324 +#define QSIZE(q) (sizeof((q)->elem)/sizeof((q)->elem[0]))
19325 +#define QELEM(q,i) ((q)->elem[(i)%QSIZE(q)])
19326 +
19327 +static void
19328 +queue_insert(queue *q, int after, uint64_t seqnum)
19329 +{
19330 +    /* insert.  this is not the fastest way, but it's easy, and it's
19331 +       optimized for insert at end, which is the common case */
19332 +    int i;
19333 +
19334 +    /* common case: at end, after == q->start+q->length-1 */
19335 +
19336 +    /* move all the elements (after,last] up one slot */
19337 +
19338 +    for (i = q->start + q->length - 1; i > after; i--)
19339 +        QELEM(q,i+1) = QELEM(q,i);
19340 +
19341 +    /* fill in slot after+1 */
19342 +
19343 +    QELEM(q,after+1) = seqnum;
19344 +
19345 +    /* Either increase the length by one, or move the starting point up
19346 +       one (deleting the first element, which got bashed above), as
19347 +       appropriate. */
19348 +
19349 +    if (q->length == QSIZE(q)) {
19350 +        q->start++;
19351 +        if (q->start == QSIZE(q))
19352 +            q->start = 0;
19353 +    } else {
19354 +        q->length++;
19355 +    }
19356 +}
19357 +
19358 +OM_uint32
19359 +sequenceInit(OM_uint32 *minor,
19360 +             void **vqueue,
19361 +             uint64_t seqnum,
19362 +             int do_replay,
19363 +             int do_sequence,
19364 +             int wide_nums)
19365 +{
19366 +    queue *q;
19367 +
19368 +    q = (queue *)GSSEAP_CALLOC(1, sizeof(queue));
19369 +    if (q == NULL) {
19370 +        *minor = ENOMEM;
19371 +        return GSS_S_FAILURE;
19372 +    }
19373 +
19374 +    q->do_replay = do_replay;
19375 +    q->do_sequence = do_sequence;
19376 +    q->mask = wide_nums ? ~(uint64_t)0 : 0xffffffffUL;
19377 +
19378 +    q->start = 0;
19379 +    q->length = 1;
19380 +    q->firstnum = seqnum;
19381 +    q->elem[q->start] = ((uint64_t)0 - 1) & q->mask;
19382 +
19383 +    *vqueue = (void *)q;
19384 +
19385 +    return GSS_S_COMPLETE;
19386 +}
19387 +
19388 +OM_uint32
19389 +sequenceCheck(OM_uint32 *minor,
19390 +              void **vqueue,
19391 +              uint64_t seqnum)
19392 +{
19393 +    queue *q;
19394 +    int i;
19395 +    uint64_t expected;
19396 +
19397 +    *minor = 0;
19398 +
19399 +    q = (queue *) (*vqueue);
19400 +
19401 +    if (!q->do_replay && !q->do_sequence)
19402 +        return GSS_S_COMPLETE;
19403 +
19404 +    /* All checks are done relative to the initial sequence number, to
19405 +       avoid (or at least put off) the pain of wrapping.  */
19406 +    seqnum -= q->firstnum;
19407 +    /* If we're only doing 32-bit values, adjust for that again.
19408 +
19409 +       Note that this will probably be the wrong thing to if we get
19410 +       2**32 messages sent with 32-bit sequence numbers.  */
19411 +    seqnum &= q->mask;
19412 +
19413 +    /* rule 1: expected sequence number */
19414 +
19415 +    expected = (QELEM(q,q->start+q->length-1)+1) & q->mask;
19416 +    if (seqnum == expected) {
19417 +        queue_insert(q, q->start+q->length-1, seqnum);
19418 +        return GSS_S_COMPLETE;
19419 +    }
19420 +
19421 +    /* rule 2: > expected sequence number */
19422 +
19423 +    if ((seqnum > expected)) {
19424 +        queue_insert(q, q->start+q->length-1, seqnum);
19425 +        if (q->do_replay && !q->do_sequence)
19426 +            return GSS_S_COMPLETE;
19427 +        else
19428 +            return GSS_S_GAP_TOKEN;
19429 +    }
19430 +
19431 +    /* rule 3: seqnum < seqnum(first) */
19432 +
19433 +    if ((seqnum < QELEM(q,q->start)) &&
19434 +        /* Is top bit of whatever width we're using set?
19435 +
19436 +           We used to check for greater than or equal to firstnum, but
19437 +           (1) we've since switched to compute values relative to
19438 +           firstnum, so the lowest we can have is 0, and (2) the effect
19439 +           of the original scheme was highly dependent on whether
19440 +           firstnum was close to either side of 0.  (Consider
19441 +           firstnum==0xFFFFFFFE and we miss three packets; the next
19442 +           packet is *new* but would look old.)
19443 +
19444 +           This check should give us 2**31 or 2**63 messages "new", and
19445 +           just as many "old".  That's not quite right either.  */
19446 +        (seqnum & (1 + (q->mask >> 1)))
19447 +    ) {
19448 +        if (q->do_replay && !q->do_sequence)
19449 +            return GSS_S_OLD_TOKEN;
19450 +        else
19451 +            return GSS_S_UNSEQ_TOKEN;
19452 +    }
19453 +
19454 +    /* rule 4+5: seqnum in [seqnum(first),seqnum(last)]  */
19455 +
19456 +    else {
19457 +        if (seqnum == QELEM(q,q->start+q->length - 1))
19458 +            return GSS_S_DUPLICATE_TOKEN;
19459 +
19460 +        for (i = q->start; i < q->start + q->length - 1; i++) {
19461 +            if (seqnum == QELEM(q,i))
19462 +                return GSS_S_DUPLICATE_TOKEN;
19463 +            if ((seqnum > QELEM(q,i)) && (seqnum < QELEM(q,i+1))) {
19464 +                queue_insert(q, i, seqnum);
19465 +                if (q->do_replay && !q->do_sequence)
19466 +                    return GSS_S_COMPLETE;
19467 +                else
19468 +                    return GSS_S_UNSEQ_TOKEN;
19469 +            }
19470 +        }
19471 +    }
19472 +
19473 +    /* this should never happen */
19474 +    return GSS_S_FAILURE;
19475 +}
19476 +
19477 +OM_uint32
19478 +sequenceFree(OM_uint32 *minor, void **vqueue)
19479 +{
19480 +    queue *q;
19481 +
19482 +    q = (queue *) (*vqueue);
19483 +
19484 +    GSSEAP_FREE(q);
19485 +
19486 +    *vqueue = NULL;
19487 +
19488 +    *minor = 0;
19489 +    return GSS_S_COMPLETE;
19490 +}
19491 +
19492 +/*
19493 + * These support functions are for the serialization routines
19494 + */
19495 +size_t
19496 +sequenceSize(void *vqueue GSSEAP_UNUSED)
19497 +{
19498 +    return sizeof(queue);
19499 +}
19500 +
19501 +OM_uint32
19502 +sequenceExternalize(OM_uint32 *minor,
19503 +                    void *vqueue,
19504 +                    unsigned char **buf,
19505 +                    size_t *lenremain)
19506 +{
19507 +    if (*lenremain < sizeof(queue)) {
19508 +        *minor = GSSEAP_WRONG_SIZE;
19509 +        return GSS_S_FAILURE;
19510 +    }
19511 +    memcpy(*buf, vqueue, sizeof(queue));
19512 +    *buf += sizeof(queue);
19513 +    *lenremain -= sizeof(queue);
19514 +
19515 +    return 0;
19516 +}
19517 +
19518 +OM_uint32
19519 +sequenceInternalize(OM_uint32 *minor,
19520 +                    void **vqueue,
19521 +                    unsigned char **buf,
19522 +                    size_t *lenremain)
19523 +{
19524 +    void *q;
19525 +
19526 +    if (*lenremain < sizeof(queue)) {
19527 +        *minor = GSSEAP_TOK_TRUNC;
19528 +        return GSS_S_DEFECTIVE_TOKEN;
19529 +    }
19530 +
19531 +    q = GSSEAP_MALLOC(sizeof(queue));
19532 +    if (q == NULL) {
19533 +        *minor = ENOMEM;
19534 +        return GSS_S_FAILURE;
19535 +    }
19536 +
19537 +    memcpy(q, *buf, sizeof(queue));
19538 +    *buf += sizeof(queue);
19539 +    *lenremain -= sizeof(queue);
19540 +    *vqueue = q;
19541 +
19542 +    *minor = 0;
19543 +    return GSS_S_COMPLETE;
19544 +}
19545 diff --git a/mech_eap/util_radius.cpp b/mech_eap/util_radius.cpp
19546 new file mode 100644
19547 index 0000000..9111e20
19548 --- /dev/null
19549 +++ b/mech_eap/util_radius.cpp
19550 @@ -0,0 +1,899 @@
19551 +/*
19552 + * Copyright (c) 2011, JANET(UK)
19553 + * All rights reserved.
19554 + *
19555 + * Redistribution and use in source and binary forms, with or without
19556 + * modification, are permitted provided that the following conditions
19557 + * are met:
19558 + *
19559 + * 1. Redistributions of source code must retain the above copyright
19560 + *    notice, this list of conditions and the following disclaimer.
19561 + *
19562 + * 2. Redistributions in binary form must reproduce the above copyright
19563 + *    notice, this list of conditions and the following disclaimer in the
19564 + *    documentation and/or other materials provided with the distribution.
19565 + *
19566 + * 3. Neither the name of JANET(UK) nor the names of its contributors
19567 + *    may be used to endorse or promote products derived from this software
19568 + *    without specific prior written permission.
19569 + *
19570 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19571 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19572 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19573 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19574 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19575 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19576 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19577 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
19578 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
19579 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
19580 + * SUCH DAMAGE.
19581 + */
19582 +
19583 +/*
19584 + * RADIUS attribute provider implementation.
19585 + */
19586 +
19587 +#include "gssapiP_eap.h"
19588 +
19589 +/* stuff that should be provided by libradsec/libfreeradius-radius */
19590 +#define VENDORATTR(vendor, attr)            (((vendor) << 16) | (attr))
19591 +
19592 +#ifndef ATTRID
19593 +#define ATTRID(attr)                        ((attr) & 0xFFFF)
19594 +#endif
19595 +
19596 +static gss_buffer_desc radiusUrnPrefix = {
19597 +    sizeof("urn:x-radius:") - 1,
19598 +    (void *)"urn:x-radius:"
19599 +};
19600 +
19601 +static VALUE_PAIR *copyAvps(const VALUE_PAIR *src);
19602 +
19603 +gss_eap_radius_attr_provider::gss_eap_radius_attr_provider(void)
19604 +{
19605 +    m_vps = NULL;
19606 +    m_authenticated = false;
19607 +}
19608 +
19609 +gss_eap_radius_attr_provider::~gss_eap_radius_attr_provider(void)
19610 +{
19611 +    if (m_vps != NULL)
19612 +        pairfree(&m_vps);
19613 +}
19614 +
19615 +bool
19616 +gss_eap_radius_attr_provider::initWithExistingContext(const gss_eap_attr_ctx *manager,
19617 +                                                      const gss_eap_attr_provider *ctx)
19618 +{
19619 +    const gss_eap_radius_attr_provider *radius;
19620 +
19621 +    if (!gss_eap_attr_provider::initWithExistingContext(manager, ctx))
19622 +        return false;
19623 +
19624 +    radius = static_cast<const gss_eap_radius_attr_provider *>(ctx);
19625 +
19626 +    if (radius->m_vps != NULL)
19627 +        m_vps = copyAvps(const_cast<VALUE_PAIR *>(radius->getAvps()));
19628 +
19629 +    m_authenticated = radius->m_authenticated;
19630 +
19631 +    return true;
19632 +}
19633 +
19634 +bool
19635 +gss_eap_radius_attr_provider::initWithGssContext(const gss_eap_attr_ctx *manager,
19636 +                                                 const gss_cred_id_t gssCred,
19637 +                                                 const gss_ctx_id_t gssCtx)
19638 +{
19639 +    if (!gss_eap_attr_provider::initWithGssContext(manager, gssCred, gssCtx))
19640 +        return false;
19641 +
19642 +    if (gssCtx != GSS_C_NO_CONTEXT) {
19643 +        if (gssCtx->acceptorCtx.vps != NULL) {
19644 +            m_vps = copyAvps(gssCtx->acceptorCtx.vps);
19645 +            if (m_vps == NULL)
19646 +                return false;
19647 +
19648 +            /* We assume libradsec validated this for us */
19649 +            GSSEAP_ASSERT(pairfind(m_vps, PW_MESSAGE_AUTHENTICATOR) != NULL);
19650 +            m_authenticated = true;
19651 +        }
19652 +    }
19653 +
19654 +    return true;
19655 +}
19656 +
19657 +static bool
19658 +alreadyAddedAttributeP(std::vector <std::string> &attrs, VALUE_PAIR *vp)
19659 +{
19660 +    for (std::vector<std::string>::const_iterator a = attrs.begin();
19661 +         a != attrs.end();
19662 +         ++a) {
19663 +        if (strcmp(vp->name, (*a).c_str()) == 0)
19664 +            return true;
19665 +    }
19666 +
19667 +    return false;
19668 +}
19669 +
19670 +static bool
19671 +isSecretAttributeP(uint16_t attrid, uint16_t vendor)
19672 +{
19673 +    bool bSecretAttribute = false;
19674 +
19675 +    switch (vendor) {
19676 +    case VENDORPEC_MS:
19677 +        switch (attrid) {
19678 +        case PW_MS_MPPE_SEND_KEY:
19679 +        case PW_MS_MPPE_RECV_KEY:
19680 +            bSecretAttribute = true;
19681 +            break;
19682 +        default:
19683 +            break;
19684 +        }
19685 +    default:
19686 +        break;
19687 +    }
19688 +
19689 +    return bSecretAttribute;
19690 +}
19691 +
19692 +static bool
19693 +isSecretAttributeP(uint32_t attribute)
19694 +{
19695 +    return isSecretAttributeP(ATTRID(attribute), VENDOR(attribute));
19696 +}
19697 +
19698 +static bool
19699 +isInternalAttributeP(uint16_t attrid, uint16_t vendor)
19700 +{
19701 +    bool bInternalAttribute = false;
19702 +
19703 +    /* should have been filtered */
19704 +    GSSEAP_ASSERT(!isSecretAttributeP(attrid, vendor));
19705 +
19706 +    switch (vendor) {
19707 +    case VENDORPEC_UKERNA:
19708 +        switch (attrid) {
19709 +        case PW_GSS_ACCEPTOR_SERVICE_NAME:
19710 +        case PW_GSS_ACCEPTOR_HOST_NAME:
19711 +        case PW_GSS_ACCEPTOR_SERVICE_SPECIFIC:
19712 +        case PW_GSS_ACCEPTOR_REALM_NAME:
19713 +        case PW_SAML_AAA_ASSERTION:
19714 +            bInternalAttribute = true;
19715 +            break;
19716 +        default:
19717 +            break;
19718 +        }
19719 +        break;
19720 +    default:
19721 +        break;
19722 +    }
19723 +
19724 +    return bInternalAttribute;
19725 +}
19726 +
19727 +static bool
19728 +isInternalAttributeP(uint32_t attribute)
19729 +{
19730 +    return isInternalAttributeP(ATTRID(attribute), VENDOR(attribute));
19731 +}
19732 +
19733 +static bool
19734 +isFragmentedAttributeP(uint16_t attrid, uint16_t vendor)
19735 +{
19736 +    /* A bit of a hack for the PAC for now. Should be configurable. */
19737 +    return (vendor == VENDORPEC_UKERNA) &&
19738 +        !isInternalAttributeP(attrid, vendor);
19739 +}
19740 +
19741 +static bool
19742 +isFragmentedAttributeP(uint32_t attribute)
19743 +{
19744 +    return isFragmentedAttributeP(ATTRID(attribute), VENDOR(attribute));
19745 +}
19746 +
19747 +/*
19748 + * Copy AVP list, same as paircopy except it filters out attributes
19749 + * containing keys.
19750 + */
19751 +static VALUE_PAIR *
19752 +copyAvps(const VALUE_PAIR *src)
19753 +{
19754 +    const VALUE_PAIR *vp;
19755 +    VALUE_PAIR *dst = NULL, **pDst = &dst;
19756 +
19757 +    for (vp = src; vp != NULL; vp = vp->next) {
19758 +        VALUE_PAIR *vpcopy;
19759 +
19760 +        if (isSecretAttributeP(vp->attribute))
19761 +            continue;
19762 +
19763 +        vpcopy = paircopyvp(vp);
19764 +        if (vpcopy == NULL) {
19765 +            pairfree(&dst);
19766 +            throw std::bad_alloc();
19767 +        }
19768 +        *pDst = vpcopy;
19769 +        pDst = &vpcopy->next;
19770 +     }
19771 +
19772 +    return dst;
19773 +}
19774 +
19775 +bool
19776 +gss_eap_radius_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
19777 +                                                void *data) const
19778 +{
19779 +    VALUE_PAIR *vp;
19780 +    std::vector <std::string> seen;
19781 +
19782 +    for (vp = m_vps; vp != NULL; vp = vp->next) {
19783 +        gss_buffer_desc attribute;
19784 +        char attrid[64];
19785 +
19786 +        /* Don't advertise attributes that are internal to the GSS-EAP mechanism */
19787 +        if (isInternalAttributeP(vp->attribute))
19788 +            continue;
19789 +
19790 +        if (alreadyAddedAttributeP(seen, vp))
19791 +            continue;
19792 +
19793 +        snprintf(attrid, sizeof(attrid), "%s%d",
19794 +            (char *)radiusUrnPrefix.value, vp->attribute);
19795 +
19796 +        attribute.value = attrid;
19797 +        attribute.length = strlen(attrid);
19798 +
19799 +        if (!addAttribute(m_manager, this, &attribute, data))
19800 +            return false;
19801 +
19802 +        seen.push_back(std::string(vp->name));
19803 +    }
19804 +
19805 +    return true;
19806 +}
19807 +
19808 +uint32_t
19809 +getAttributeId(const gss_buffer_t attr)
19810 +{
19811 +    OM_uint32 tmpMinor;
19812 +    gss_buffer_desc strAttr = GSS_C_EMPTY_BUFFER;
19813 +    DICT_ATTR *da;
19814 +    char *s;
19815 +    uint32_t attrid = 0;
19816 +
19817 +    if (attr->length < radiusUrnPrefix.length ||
19818 +        memcmp(attr->value, radiusUrnPrefix.value, radiusUrnPrefix.length) != 0)
19819 +        return 0;
19820 +
19821 +    /* need to duplicate because attr may not be NUL terminated */
19822 +    duplicateBuffer(*attr, &strAttr);
19823 +    s = (char *)strAttr.value + radiusUrnPrefix.length;
19824 +
19825 +    if (isdigit(*s)) {
19826 +        attrid = strtoul(s, NULL, 10);
19827 +    } else {
19828 +        da = dict_attrbyname(s);
19829 +        if (da != NULL)
19830 +            attrid = da->attr;
19831 +    }
19832 +
19833 +    gss_release_buffer(&tmpMinor, &strAttr);
19834 +
19835 +    return attrid;
19836 +}
19837 +
19838 +bool
19839 +gss_eap_radius_attr_provider::setAttribute(int complete GSSEAP_UNUSED,
19840 +                                           uint32_t attrid,
19841 +                                           const gss_buffer_t value)
19842 +{
19843 +    OM_uint32 major = GSS_S_UNAVAILABLE, minor;
19844 +
19845 +    if (!isSecretAttributeP(attrid) &&
19846 +        !isInternalAttributeP(attrid)) {
19847 +        deleteAttribute(attrid);
19848 +
19849 +        major = gssEapRadiusAddAvp(&minor, &m_vps,
19850 +                                   ATTRID(attrid), VENDOR(attrid), 
19851 +                                   value);
19852 +    }
19853 +
19854 +    return !GSS_ERROR(major);
19855 +}
19856 +
19857 +bool
19858 +gss_eap_radius_attr_provider::setAttribute(int complete,
19859 +                                           const gss_buffer_t attr,
19860 +                                           const gss_buffer_t value)
19861 +{
19862 +    uint32_t attrid = getAttributeId(attr);
19863 +
19864 +    if (!attrid)
19865 +        return false;
19866 +
19867 +    return setAttribute(complete, attrid, value);
19868 +}
19869 +
19870 +bool
19871 +gss_eap_radius_attr_provider::deleteAttribute(uint32_t attrid)
19872 +{
19873 +    if (isSecretAttributeP(attrid) || isInternalAttributeP(attrid) ||
19874 +        pairfind(m_vps, attrid) == NULL)
19875 +        return false;
19876 +
19877 +    pairdelete(&m_vps, attrid);
19878 +
19879 +    return true;
19880 +}
19881 +
19882 +bool
19883 +gss_eap_radius_attr_provider::deleteAttribute(const gss_buffer_t attr)
19884 +{
19885 +    uint32_t attrid = getAttributeId(attr);
19886 +
19887 +    if (!attrid)
19888 +        return false;
19889 +
19890 +    return deleteAttribute(attrid);
19891 +}
19892 +
19893 +bool
19894 +gss_eap_radius_attr_provider::getAttribute(const gss_buffer_t attr,
19895 +                                           int *authenticated,
19896 +                                           int *complete,
19897 +                                           gss_buffer_t value,
19898 +                                           gss_buffer_t display_value,
19899 +                                           int *more) const
19900 +{
19901 +    uint32_t attrid;
19902 +
19903 +    attrid = getAttributeId(attr);
19904 +    if (!attrid)
19905 +        return false;
19906 +
19907 +    return getAttribute(attrid, authenticated, complete,
19908 +                        value, display_value, more);
19909 +}
19910 +
19911 +bool
19912 +gss_eap_radius_attr_provider::getAttribute(uint32_t attrid,
19913 +                                           int *authenticated,
19914 +                                           int *complete,
19915 +                                           gss_buffer_t value,
19916 +                                           gss_buffer_t display_value,
19917 +                                           int *more) const
19918 +{
19919 +    VALUE_PAIR *vp;
19920 +    int i = *more, count = 0;
19921 +
19922 +    *more = 0;
19923 +
19924 +    if (i == -1)
19925 +        i = 0;
19926 +
19927 +    if (isSecretAttributeP(attrid) || isInternalAttributeP(attrid)) {
19928 +        return false;
19929 +    } else if (isFragmentedAttributeP(attrid)) {
19930 +        return getFragmentedAttribute(attrid,
19931 +                                      authenticated,
19932 +                                      complete,
19933 +                                      value);
19934 +    }
19935 +
19936 +    for (vp = pairfind(m_vps, attrid);
19937 +         vp != NULL;
19938 +         vp = pairfind(vp->next, attrid)) {
19939 +        if (count++ == i) {
19940 +            if (pairfind(vp->next, attrid) != NULL)
19941 +                *more = count;
19942 +            break;
19943 +        }
19944 +    }
19945 +
19946 +    if (vp == NULL && *more == 0)
19947 +        return false;
19948 +
19949 +    if (value != GSS_C_NO_BUFFER) {
19950 +        gss_buffer_desc valueBuf;
19951 +
19952 +        valueBuf.value = (void *)vp->vp_octets;
19953 +        valueBuf.length = vp->length;
19954 +
19955 +        duplicateBuffer(valueBuf, value);
19956 +    }
19957 +
19958 +    if (display_value != GSS_C_NO_BUFFER &&
19959 +        vp->type != PW_TYPE_OCTETS) {
19960 +        char displayString[MAX_STRING_LEN];
19961 +        gss_buffer_desc displayBuf;
19962 +
19963 +        displayBuf.length = vp_prints_value(displayString,
19964 +                                            sizeof(displayString), vp, 0);
19965 +        displayBuf.value = (void *)displayString;
19966 +
19967 +        duplicateBuffer(displayBuf, display_value);
19968 +    }
19969 +
19970 +    if (authenticated != NULL)
19971 +        *authenticated = m_authenticated;
19972 +    if (complete != NULL)
19973 +        *complete = true;
19974 +
19975 +    return true;
19976 +}
19977 +
19978 +bool
19979 +gss_eap_radius_attr_provider::getFragmentedAttribute(uint16_t attribute,
19980 +                                                     uint16_t vendor,
19981 +                                                     int *authenticated,
19982 +                                                     int *complete,
19983 +                                                     gss_buffer_t value) const
19984 +{
19985 +    OM_uint32 major, minor;
19986 +
19987 +    major = gssEapRadiusGetAvp(&minor, m_vps, attribute, vendor, value, TRUE);
19988 +
19989 +    if (authenticated != NULL)
19990 +        *authenticated = m_authenticated;
19991 +    if (complete != NULL)
19992 +        *complete = true;
19993 +
19994 +    return !GSS_ERROR(major);
19995 +}
19996 +
19997 +bool
19998 +gss_eap_radius_attr_provider::getFragmentedAttribute(uint32_t attrid,
19999 +                                                     int *authenticated,
20000 +                                                     int *complete,
20001 +                                                     gss_buffer_t value) const
20002 +{
20003 +    return getFragmentedAttribute(ATTRID(attrid), VENDOR(attrid),
20004 +                                  authenticated, complete, value);
20005 +}
20006 +
20007 +bool
20008 +gss_eap_radius_attr_provider::getAttribute(uint16_t attribute,
20009 +                                           uint16_t vendor,
20010 +                                           int *authenticated,
20011 +                                           int *complete,
20012 +                                           gss_buffer_t value,
20013 +                                           gss_buffer_t display_value,
20014 +                                           int *more) const
20015 +{
20016 +
20017 +    return getAttribute(VENDORATTR(attribute, vendor),
20018 +                        authenticated, complete,
20019 +                        value, display_value, more);
20020 +}
20021 +
20022 +gss_any_t
20023 +gss_eap_radius_attr_provider::mapToAny(int authenticated,
20024 +                                       gss_buffer_t type_id GSSEAP_UNUSED) const
20025 +{
20026 +    if (authenticated && !m_authenticated)
20027 +        return (gss_any_t)NULL;
20028 +
20029 +    return (gss_any_t)copyAvps(m_vps);
20030 +}
20031 +
20032 +void
20033 +gss_eap_radius_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED,
20034 +                                                    gss_any_t input) const
20035 +{
20036 +    VALUE_PAIR *vp = (VALUE_PAIR *)input;
20037 +    pairfree(&vp);
20038 +}
20039 +
20040 +bool
20041 +gss_eap_radius_attr_provider::init(void)
20042 +{
20043 +    gss_eap_attr_ctx::registerProvider(ATTR_TYPE_RADIUS, createAttrContext);
20044 +
20045 +    return true;
20046 +}
20047 +
20048 +void
20049 +gss_eap_radius_attr_provider::finalize(void)
20050 +{
20051 +    gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_RADIUS);
20052 +}
20053 +
20054 +gss_eap_attr_provider *
20055 +gss_eap_radius_attr_provider::createAttrContext(void)
20056 +{
20057 +    return new gss_eap_radius_attr_provider;
20058 +}
20059 +
20060 +OM_uint32
20061 +gssEapRadiusAddAvp(OM_uint32 *minor,
20062 +                   VALUE_PAIR **vps,
20063 +                   uint16_t attribute,
20064 +                   uint16_t vendor,
20065 +                   const gss_buffer_t buffer)
20066 +{
20067 +    uint32_t attrid = VENDORATTR(vendor, attribute);
20068 +    unsigned char *p = (unsigned char *)buffer->value;
20069 +    size_t remain = buffer->length;
20070 +
20071 +    do {
20072 +        VALUE_PAIR *vp;
20073 +        size_t n = remain;
20074 +
20075 +        /*
20076 +         * There's an extra byte of padding; RADIUS AVPs can only
20077 +         * be 253 octets.
20078 +         */
20079 +        if (n >= MAX_STRING_LEN)
20080 +            n = MAX_STRING_LEN - 1;
20081 +
20082 +        vp = paircreate(attrid, PW_TYPE_OCTETS);
20083 +        if (vp == NULL) {
20084 +            *minor = ENOMEM;
20085 +            return GSS_S_FAILURE;
20086 +        }
20087 +
20088 +        memcpy(vp->vp_octets, p, n);
20089 +        vp->length = n;
20090 +
20091 +        pairadd(vps, vp);
20092 +
20093 +        p += n;
20094 +        remain -= n;
20095 +    } while (remain != 0);
20096 +
20097 +    return GSS_S_COMPLETE;
20098 +}
20099 +
20100 +OM_uint32
20101 +gssEapRadiusGetRawAvp(OM_uint32 *minor,
20102 +                      VALUE_PAIR *vps,
20103 +                      uint16_t attribute,
20104 +                      uint16_t vendor,
20105 +                      VALUE_PAIR **vp)
20106 +{
20107 +    uint32_t attr = VENDORATTR(vendor, attribute);
20108 +
20109 +    *vp = pairfind(vps, attr);
20110 +    if (*vp == NULL) {
20111 +        *minor = GSSEAP_NO_SUCH_ATTR;
20112 +        return GSS_S_UNAVAILABLE;
20113 +    }
20114 +
20115 +    return GSS_S_COMPLETE;
20116 +}
20117 +
20118 +OM_uint32
20119 +gssEapRadiusGetAvp(OM_uint32 *minor,
20120 +                   VALUE_PAIR *vps,
20121 +                   uint16_t attribute,
20122 +                   uint16_t vendor,
20123 +                   gss_buffer_t buffer,
20124 +                   int concat)
20125 +{
20126 +    VALUE_PAIR *vp;
20127 +    unsigned char *p;
20128 +    uint32_t attr = VENDORATTR(vendor, attribute);
20129 +
20130 +    if (buffer != GSS_C_NO_BUFFER) {
20131 +        buffer->length = 0;
20132 +        buffer->value = NULL;
20133 +    }
20134 +
20135 +    vp = pairfind(vps, attr);
20136 +    if (vp == NULL) {
20137 +        *minor = GSSEAP_NO_SUCH_ATTR;
20138 +        return GSS_S_UNAVAILABLE;
20139 +    }
20140 +
20141 +    if (buffer != GSS_C_NO_BUFFER) {
20142 +        do {
20143 +            buffer->length += vp->length;
20144 +        } while (concat && (vp = pairfind(vp->next, attr)) != NULL);
20145 +
20146 +        buffer->value = GSSEAP_MALLOC(buffer->length);
20147 +        if (buffer->value == NULL) {
20148 +            *minor = ENOMEM;
20149 +            return GSS_S_FAILURE;
20150 +        }
20151 +
20152 +        p = (unsigned char *)buffer->value;
20153 +
20154 +        for (vp = pairfind(vps, attr);
20155 +             concat && vp != NULL;
20156 +             vp = pairfind(vp->next, attr)) {
20157 +            memcpy(p, vp->vp_octets, vp->length);
20158 +            p += vp->length;
20159 +        }
20160 +    }
20161 +
20162 +    *minor = 0;
20163 +    return GSS_S_COMPLETE;
20164 +}
20165 +
20166 +OM_uint32
20167 +gssEapRadiusFreeAvps(OM_uint32 *minor,
20168 +                     VALUE_PAIR **vps)
20169 +{
20170 +    pairfree(vps);
20171 +    *minor = 0;
20172 +    return GSS_S_COMPLETE;
20173 +}
20174 +
20175 +OM_uint32
20176 +gssEapRadiusAttrProviderInit(OM_uint32 *minor)
20177 +{
20178 +    if (!gss_eap_radius_attr_provider::init()) {
20179 +        *minor = GSSEAP_RADSEC_INIT_FAILURE;
20180 +        return GSS_S_FAILURE;
20181 +    }
20182 +
20183 +    return GSS_S_COMPLETE;
20184 +}
20185 +
20186 +OM_uint32
20187 +gssEapRadiusAttrProviderFinalize(OM_uint32 *minor)
20188 +{
20189 +    gss_eap_radius_attr_provider::finalize();
20190 +
20191 +    *minor = 0;
20192 +    return GSS_S_COMPLETE;
20193 +}
20194 +
20195 +static JSONObject
20196 +avpToJson(const VALUE_PAIR *vp)
20197 +{
20198 +    JSONObject obj;
20199 +
20200 +    GSSEAP_ASSERT(vp->length <= MAX_STRING_LEN);
20201 +
20202 +    switch (vp->type) {
20203 +    case PW_TYPE_INTEGER:
20204 +    case PW_TYPE_IPADDR:
20205 +    case PW_TYPE_DATE:
20206 +        obj.set("value", vp->lvalue);
20207 +        break;
20208 +    case PW_TYPE_STRING:
20209 +        obj.set("value", vp->vp_strvalue);
20210 +        break;
20211 +    default: {
20212 +        char *b64;
20213 +
20214 +        if (base64Encode(vp->vp_octets, vp->length, &b64) < 0)
20215 +            throw std::bad_alloc();
20216 +
20217 +        obj.set("value", b64);
20218 +        GSSEAP_FREE(b64);
20219 +        break;
20220 +    }
20221 +    }
20222 +
20223 +    obj.set("type", vp->attribute);
20224 +
20225 +    return obj;
20226 +}
20227 +
20228 +static bool
20229 +jsonToAvp(VALUE_PAIR **pVp, JSONObject &obj)
20230 +{
20231 +    VALUE_PAIR *vp = NULL;
20232 +    DICT_ATTR *da;
20233 +    uint32_t attrid;
20234 +
20235 +    JSONObject type = obj["type"];
20236 +    JSONObject value = obj["value"];
20237 +
20238 +    if (!type.isInteger())
20239 +        goto fail;
20240 +
20241 +    attrid = type.integer();
20242 +    da = dict_attrbyvalue(attrid);
20243 +    if (da != NULL) {
20244 +        vp = pairalloc(da);
20245 +    } else {
20246 +        int type = base64Valid(value.string()) ?
20247 +            PW_TYPE_OCTETS : PW_TYPE_STRING;
20248 +        vp = paircreate(attrid, type);
20249 +    }
20250 +    if (vp == NULL)
20251 +        throw std::bad_alloc();
20252 +
20253 +    switch (vp->type) {
20254 +    case PW_TYPE_INTEGER:
20255 +    case PW_TYPE_IPADDR:
20256 +    case PW_TYPE_DATE:
20257 +        if (!value.isInteger())
20258 +            goto fail;
20259 +
20260 +        vp->length = 4;
20261 +        vp->lvalue = value.integer();
20262 +        break;
20263 +    case PW_TYPE_STRING: {
20264 +        if (!value.isString())
20265 +            goto fail;
20266 +
20267 +        const char *str = value.string();
20268 +        size_t len = strlen(str);
20269 +
20270 +        if (len >= MAX_STRING_LEN)
20271 +            goto fail;
20272 +
20273 +        vp->length = len;
20274 +        memcpy(vp->vp_strvalue, str, len + 1);
20275 +        break;
20276 +    }
20277 +    case PW_TYPE_OCTETS:
20278 +    default: {
20279 +        if (!value.isString())
20280 +            goto fail;
20281 +
20282 +        const char *str = value.string();
20283 +        ssize_t len = strlen(str);
20284 +
20285 +        /* this optimization requires base64Decode only understand packed encoding */
20286 +        if (len >= BASE64_EXPAND(MAX_STRING_LEN))
20287 +            goto fail;
20288 +
20289 +        len = base64Decode(str, vp->vp_octets);
20290 +        if (len < 0)
20291 +            goto fail;
20292 +
20293 +        vp->length = len;
20294 +        break;
20295 +    }
20296 +    }
20297 +
20298 +    *pVp = vp;
20299 +
20300 +    return true;
20301 +
20302 +fail:
20303 +    if (vp != NULL)
20304 +        pairbasicfree(vp);
20305 +    *pVp = NULL;
20306 +    return false;
20307 +}
20308 +
20309 +const char *
20310 +gss_eap_radius_attr_provider::name(void) const
20311 +{
20312 +    return "radius";
20313 +}
20314 +
20315 +bool
20316 +gss_eap_radius_attr_provider::initWithJsonObject(const gss_eap_attr_ctx *ctx,
20317 +                                                 JSONObject &obj)
20318 +{
20319 +    VALUE_PAIR **pNext = &m_vps;
20320 +
20321 +    if (!gss_eap_attr_provider::initWithJsonObject(ctx, obj))
20322 +        return false;
20323 +
20324 +    JSONObject attrs = obj["attributes"];
20325 +    size_t nelems = attrs.size();
20326 +
20327 +    for (size_t i = 0; i < nelems; i++) {
20328 +        JSONObject attr = attrs[i];
20329 +        VALUE_PAIR *vp;
20330 +
20331 +        if (!jsonToAvp(&vp, attr))
20332 +            return false;
20333 +
20334 +        *pNext = vp;
20335 +        pNext = &vp->next;
20336 +    }
20337 +
20338 +    m_authenticated = obj["authenticated"].integer() ? true : false;
20339 +
20340 +    return true;
20341 +}
20342 +
20343 +const char *
20344 +gss_eap_radius_attr_provider::prefix(void) const
20345 +{
20346 +    return "urn:ietf:params:gss-eap:radius-avp";
20347 +}
20348 +
20349 +JSONObject
20350 +gss_eap_radius_attr_provider::jsonRepresentation(void) const
20351 +{
20352 +    JSONObject obj, attrs = JSONObject::array();
20353 +
20354 +    for (VALUE_PAIR *vp = m_vps; vp != NULL; vp = vp->next) {
20355 +        JSONObject attr = avpToJson(vp);
20356 +        attrs.append(attr);
20357 +    }
20358 +
20359 +    obj.set("attributes", attrs);
20360 +
20361 +    obj.set("authenticated", m_authenticated);
20362 +
20363 +    return obj;
20364 +}
20365 +
20366 +time_t
20367 +gss_eap_radius_attr_provider::getExpiryTime(void) const
20368 +{
20369 +    VALUE_PAIR *vp;
20370 +
20371 +    vp = pairfind(m_vps, PW_SESSION_TIMEOUT);
20372 +    if (vp == NULL || vp->lvalue == 0)
20373 +        return 0;
20374 +
20375 +    return time(NULL) + vp->lvalue;
20376 +}
20377 +
20378 +OM_uint32
20379 +gssEapRadiusMapError(OM_uint32 *minor,
20380 +                     struct rs_error *err)
20381 +{
20382 +    int code;
20383 +
20384 +    GSSEAP_ASSERT(err != NULL);
20385 +
20386 +    code = rs_err_code(err, 0);
20387 +
20388 +    if (code == RSE_OK) {
20389 +        *minor = 0;
20390 +        return GSS_S_COMPLETE;
20391 +    }
20392 +
20393 +    *minor = ERROR_TABLE_BASE_rse + code;
20394 +
20395 +    gssEapSaveStatusInfo(*minor, "%s", rs_err_msg(err));
20396 +    rs_err_free(err);
20397 +
20398 +    return GSS_S_FAILURE;
20399 +}
20400 +
20401 +OM_uint32
20402 +gssEapCreateRadiusContext(OM_uint32 *minor,
20403 +                          gss_cred_id_t cred,
20404 +                          struct rs_context **pRadContext)
20405 +{
20406 +    const char *configFile = RS_CONFIG_FILE;
20407 +    struct rs_context *radContext;
20408 +    struct rs_alloc_scheme ralloc;
20409 +    struct rs_error *err;
20410 +    OM_uint32 major;
20411 +
20412 +    *pRadContext = NULL;
20413 +
20414 +    if (rs_context_create(&radContext) != 0) {
20415 +        *minor = GSSEAP_RADSEC_CONTEXT_FAILURE;
20416 +        return GSS_S_FAILURE;
20417 +    }
20418 +
20419 +    if (cred->radiusConfigFile.value != NULL)
20420 +        configFile = (const char *)cred->radiusConfigFile.value;
20421 +
20422 +    ralloc.calloc  = GSSEAP_CALLOC;
20423 +    ralloc.malloc  = GSSEAP_MALLOC;
20424 +    ralloc.free    = GSSEAP_FREE;
20425 +    ralloc.realloc = GSSEAP_REALLOC;
20426 +
20427 +    rs_context_set_alloc_scheme(radContext, &ralloc);
20428 +
20429 +    if (rs_context_read_config(radContext, configFile) != 0) {
20430 +        err = rs_err_ctx_pop(radContext);
20431 +        goto fail;
20432 +    }
20433 +
20434 +    if (rs_context_init_freeradius_dict(radContext, NULL) != 0) {
20435 +        err = rs_err_ctx_pop(radContext);
20436 +        goto fail;
20437 +    }
20438 +
20439 +    *pRadContext = radContext;
20440 +
20441 +    *minor = 0;
20442 +    return GSS_S_COMPLETE;
20443 +
20444 +fail:
20445 +    major = gssEapRadiusMapError(minor, err);
20446 +    rs_context_destroy(radContext);
20447 +
20448 +    return major;
20449 +}
20450 diff --git a/mech_eap/util_radius.h b/mech_eap/util_radius.h
20451 new file mode 100644
20452 index 0000000..481876a
20453 --- /dev/null
20454 +++ b/mech_eap/util_radius.h
20455 @@ -0,0 +1,183 @@
20456 +/*
20457 + * Copyright (c) 2011, JANET(UK)
20458 + * All rights reserved.
20459 + *
20460 + * Redistribution and use in source and binary forms, with or without
20461 + * modification, are permitted provided that the following conditions
20462 + * are met:
20463 + *
20464 + * 1. Redistributions of source code must retain the above copyright
20465 + *    notice, this list of conditions and the following disclaimer.
20466 + *
20467 + * 2. Redistributions in binary form must reproduce the above copyright
20468 + *    notice, this list of conditions and the following disclaimer in the
20469 + *    documentation and/or other materials provided with the distribution.
20470 + *
20471 + * 3. Neither the name of JANET(UK) nor the names of its contributors
20472 + *    may be used to endorse or promote products derived from this software
20473 + *    without specific prior written permission.
20474 + *
20475 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20476 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20477 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20478 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20479 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20480 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20481 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20482 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20483 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
20484 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
20485 + * SUCH DAMAGE.
20486 + */
20487 +
20488 +/*
20489 + * RADIUS attribute provider.
20490 + */
20491 +
20492 +#ifndef _UTIL_RADIUS_H_
20493 +#define _UTIL_RADIUS_H_ 1
20494 +
20495 +#ifdef __cplusplus
20496 +
20497 +struct gss_eap_radius_attr_provider : gss_eap_attr_provider {
20498 +public:
20499 +    gss_eap_radius_attr_provider(void);
20500 +    ~gss_eap_radius_attr_provider(void);
20501 +
20502 +    bool initWithExistingContext(const gss_eap_attr_ctx *source,
20503 +                                 const gss_eap_attr_provider *ctx);
20504 +    bool initWithGssContext(const gss_eap_attr_ctx *source,
20505 +                            const gss_cred_id_t cred,
20506 +                            const gss_ctx_id_t ctx);
20507 +
20508 +    bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const;
20509 +    bool setAttribute(int complete,
20510 +                      const gss_buffer_t attr,
20511 +                      const gss_buffer_t value);
20512 +    bool deleteAttribute(const gss_buffer_t attr);
20513 +    bool getAttribute(const gss_buffer_t attr,
20514 +                      int *authenticated,
20515 +                      int *complete,
20516 +                      gss_buffer_t value,
20517 +                      gss_buffer_t display_value,
20518 +                      int *more) const;
20519 +    gss_any_t mapToAny(int authenticated,
20520 +                       gss_buffer_t type_id) const;
20521 +    void releaseAnyNameMapping(gss_buffer_t type_id,
20522 +                               gss_any_t input) const;
20523 +
20524 +    const char *prefix(void) const;
20525 +    const char *name(void) const;
20526 +    bool initWithJsonObject(const gss_eap_attr_ctx *manager,
20527 +                           JSONObject &obj);
20528 +    JSONObject jsonRepresentation(void) const;
20529 +
20530 +    bool getAttribute(uint32_t attribute,
20531 +                      int *authenticated,
20532 +                      int *complete,
20533 +                      gss_buffer_t value,
20534 +                      gss_buffer_t display_value,
20535 +                      int *more) const;
20536 +    bool getAttribute(uint16_t attribute,
20537 +                      uint16_t vendor,
20538 +                      int *authenticated,
20539 +                      int *complete,
20540 +                      gss_buffer_t value,
20541 +                      gss_buffer_t display_value,
20542 +                      int *more) const;
20543 +    bool setAttribute(int complete,
20544 +                      uint32_t attribute,
20545 +                      const gss_buffer_t value);
20546 +    bool deleteAttribute(uint32_t attribute);
20547 +
20548 +    bool getFragmentedAttribute(uint16_t attribute,
20549 +                                uint16_t vendor,
20550 +                                int *authenticated,
20551 +                                int *complete,
20552 +                                gss_buffer_t value) const;
20553 +    bool getFragmentedAttribute(uint32_t attrid,
20554 +                                int *authenticated,
20555 +                                int *complete,
20556 +                                gss_buffer_t value) const;
20557 +
20558 +    bool authenticated(void) const { return m_authenticated; }
20559 +
20560 +    time_t getExpiryTime(void) const;
20561 +
20562 +    static bool init(void);
20563 +    static void finalize(void);
20564 +
20565 +    static gss_eap_attr_provider *createAttrContext(void);
20566 +
20567 +private:
20568 +    const VALUE_PAIR *getAvps(void) const {
20569 +        return m_vps;
20570 +    }
20571 +
20572 +    VALUE_PAIR *m_vps;
20573 +    bool m_authenticated;
20574 +};
20575 +
20576 +/* For now */
20577 +extern "C" {
20578 +#endif
20579 +
20580 +OM_uint32
20581 +gssEapRadiusAddAvp(OM_uint32 *minor,
20582 +                   VALUE_PAIR **vp,
20583 +                   uint16_t type,
20584 +                   uint16_t vendor,
20585 +                   const gss_buffer_t buffer);
20586 +
20587 +OM_uint32
20588 +gssEapRadiusGetAvp(OM_uint32 *minor,
20589 +                   VALUE_PAIR *vps,
20590 +                   uint16_t type,
20591 +                   uint16_t vendor,
20592 +                   gss_buffer_t buffer,
20593 +                   int concat);
20594 +
20595 +OM_uint32
20596 +gssEapRadiusGetRawAvp(OM_uint32 *minor,
20597 +                      VALUE_PAIR *vps,
20598 +                      uint16_t type,
20599 +                      uint16_t vendor,
20600 +                      VALUE_PAIR **vp);
20601 +OM_uint32
20602 +gssEapRadiusFreeAvps(OM_uint32 *minor,
20603 +                     VALUE_PAIR **vps);
20604 +
20605 +OM_uint32 gssEapRadiusAttrProviderInit(OM_uint32 *minor);
20606 +OM_uint32 gssEapRadiusAttrProviderFinalize(OM_uint32 *minor);
20607 +
20608 +OM_uint32
20609 +gssEapRadiusMapError(OM_uint32 *minor,
20610 +                     struct rs_error *err);
20611 +
20612 +OM_uint32
20613 +gssEapCreateRadiusContext(OM_uint32 *minor,
20614 +                          gss_cred_id_t cred,
20615 +                          struct rs_context **pRadContext);
20616 +
20617 +/* This really needs to be a function call on Windows */
20618 +#define RS_CONFIG_FILE      SYSCONFDIR "/radsec.conf"
20619 +
20620 +#define VENDORPEC_MS                        311 /* RFC 2548 */
20621 +
20622 +#define PW_MS_MPPE_SEND_KEY                 16
20623 +#define PW_MS_MPPE_RECV_KEY                 17
20624 +
20625 +#define VENDORPEC_UKERNA                    25622
20626 +
20627 +#define PW_GSS_ACCEPTOR_SERVICE_NAME        128
20628 +#define PW_GSS_ACCEPTOR_HOST_NAME           129
20629 +#define PW_GSS_ACCEPTOR_SERVICE_SPECIFIC    130
20630 +#define PW_GSS_ACCEPTOR_REALM_NAME          131
20631 +#define PW_SAML_AAA_ASSERTION               132
20632 +#define PW_MS_WINDOWS_AUTH_DATA             133
20633 +
20634 +#ifdef __cplusplus
20635 +}
20636 +#endif
20637 +
20638 +#endif /* _UTIL_RADIUS_H_ */
20639 diff --git a/mech_eap/util_reauth.c b/mech_eap/util_reauth.c
20640 new file mode 100644
20641 index 0000000..50011ca
20642 --- /dev/null
20643 +++ b/mech_eap/util_reauth.c
20644 @@ -0,0 +1,1196 @@
20645 +/*
20646 + * Copyright (c) 2011, JANET(UK)
20647 + * All rights reserved.
20648 + *
20649 + * Redistribution and use in source and binary forms, with or without
20650 + * modification, are permitted provided that the following conditions
20651 + * are met:
20652 + *
20653 + * 1. Redistributions of source code must retain the above copyright
20654 + *    notice, this list of conditions and the following disclaimer.
20655 + *
20656 + * 2. Redistributions in binary form must reproduce the above copyright
20657 + *    notice, this list of conditions and the following disclaimer in the
20658 + *    documentation and/or other materials provided with the distribution.
20659 + *
20660 + * 3. Neither the name of JANET(UK) nor the names of its contributors
20661 + *    may be used to endorse or promote products derived from this software
20662 + *    without specific prior written permission.
20663 + *
20664 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20665 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20666 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20667 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20668 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20669 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20670 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20671 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20672 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
20673 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
20674 + * SUCH DAMAGE.
20675 + */
20676 +
20677 +/*
20678 + * Fast reauthentication support.
20679 + */
20680 +
20681 +#include "gssapiP_eap.h"
20682 +
20683 +#include <dlfcn.h>
20684 +
20685 +/*
20686 + * Fast reauthentication support for EAP GSS.
20687 + */
20688 +
20689 +krb5_error_code
20690 +krb5_encrypt_tkt_part(krb5_context, const krb5_keyblock *, krb5_ticket *);
20691 +
20692 +krb5_error_code
20693 +encode_krb5_ticket(const krb5_ticket *rep, krb5_data **code);
20694 +
20695 +static OM_uint32
20696 +gssDisplayName(OM_uint32 *minor,
20697 +               gss_name_t name,
20698 +               gss_buffer_t buffer,
20699 +               gss_OID *name_type);
20700 +
20701 +static OM_uint32
20702 +gssImportName(OM_uint32 *minor,
20703 +              gss_buffer_t buffer,
20704 +              gss_OID name_type,
20705 +              gss_name_t *name);
20706 +
20707 +static krb5_error_code
20708 +getAcceptorKey(krb5_context krbContext,
20709 +               gss_ctx_id_t ctx,
20710 +               gss_cred_id_t cred,
20711 +               krb5_principal *princ,
20712 +               krb5_keyblock *key)
20713 +{
20714 +    krb5_error_code code;
20715 +    krb5_keytab keytab = NULL;
20716 +    krb5_keytab_entry ktent = { 0 };
20717 +    krb5_kt_cursor cursor;
20718 +
20719 +    *princ = NULL;
20720 +    memset(key, 0, sizeof(*key));
20721 +    memset(&cursor, 0, sizeof(cursor));
20722 +
20723 +    code = krb5_kt_default(krbContext, &keytab);
20724 +    if (code != 0)
20725 +        goto cleanup;
20726 +
20727 +    if (cred != GSS_C_NO_CREDENTIAL && cred->name != GSS_C_NO_NAME) {
20728 +        code = krb5_kt_get_entry(krbContext, keytab,
20729 +                                 cred->name->krbPrincipal, 0,
20730 +                                 ctx->encryptionType, &ktent);
20731 +        if (code != 0)
20732 +            goto cleanup;
20733 +    } else {
20734 +        /*
20735 +         * It's not clear that looking encrypting the ticket in the
20736 +         * requested EAP enctype provides any value.
20737 +         */
20738 +        code = krb5_kt_start_seq_get(krbContext, keytab, &cursor);
20739 +        if (code != 0)
20740 +            goto cleanup;
20741 +
20742 +        while ((code = krb5_kt_next_entry(krbContext, keytab,
20743 +                                          &ktent, &cursor)) == 0) {
20744 +            if (KRB_KEY_TYPE(KRB_KT_ENT_KEYBLOCK(&ktent)) == ctx->encryptionType)
20745 +                break;
20746 +            else
20747 +                KRB_KT_ENT_FREE(krbContext, &ktent);
20748 +        }
20749 +    }
20750 +
20751 +    if (code == 0) {
20752 +        *princ = ktent.principal;
20753 +        *key = *KRB_KT_ENT_KEYBLOCK(&ktent);
20754 +    }
20755 +
20756 +cleanup:
20757 +    if (cred == GSS_C_NO_CREDENTIAL || cred->name == GSS_C_NO_NAME)
20758 +        krb5_kt_end_seq_get(krbContext, keytab, &cursor);
20759 +    krb5_kt_close(krbContext, keytab);
20760 +    if (code != 0)
20761 +        KRB_KT_ENT_FREE(krbContext, &ktent);
20762 +
20763 +    return code;
20764 +}
20765 +
20766 +static OM_uint32
20767 +freezeAttrContext(OM_uint32 *minor,
20768 +                  gss_name_t initiatorName,
20769 +                  krb5_const_principal acceptorPrinc,
20770 +                  krb5_keyblock *session,
20771 +#ifdef HAVE_HEIMDAL_VERSION
20772 +                  krb5_authdata *kdcIssuedAuthData
20773 +#else
20774 +                  krb5_authdata ***kdcIssuedAuthData
20775 +#endif
20776 +                  )
20777 +{
20778 +    OM_uint32 major, tmpMinor;
20779 +    krb5_error_code code;
20780 +    krb5_context krbContext;
20781 +    gss_buffer_desc attrBuf = GSS_C_EMPTY_BUFFER;
20782 +#ifdef HAVE_HEIMDAL_VERSION
20783 +    krb5_authdata authDataBuf, *authData = &authDataBuf;
20784 +    AuthorizationDataElement authDatum = { 0 };
20785 +#else
20786 +    krb5_authdata *authData[2], authDatum = { 0 };
20787 +#endif
20788 +
20789 +    memset(kdcIssuedAuthData, 0, sizeof(*kdcIssuedAuthData));
20790 +
20791 +    GSSEAP_KRB_INIT(&krbContext);
20792 +
20793 +    major = gssEapExportAttrContext(minor, initiatorName, &attrBuf);
20794 +    if (GSS_ERROR(major))
20795 +        return major;
20796 +
20797 +    authDatum.ad_type = KRB5_AUTHDATA_RADIUS_AVP;
20798 +#ifdef HAVE_HEIMDAL_VERSION
20799 +    authDatum.ad_data.length = attrBuf.length;
20800 +    authDatum.ad_data.data = attrBuf.value;
20801 +    authData->len = 1;
20802 +    authData->val = &authDatum;
20803 +#else
20804 +    authDatum.length = attrBuf.length;
20805 +    authDatum.contents = attrBuf.value;
20806 +    authData[0] = &authDatum;
20807 +    authData[1] = NULL;
20808 +#endif
20809 +
20810 +    code = krbMakeAuthDataKdcIssued(krbContext, session, acceptorPrinc,
20811 +                                    authData, kdcIssuedAuthData);
20812 +    if (code != 0) {
20813 +        major = GSS_S_FAILURE;
20814 +        *minor = code;
20815 +    } else {
20816 +        major = GSS_S_COMPLETE;
20817 +    }
20818 +
20819 +    gss_release_buffer(&tmpMinor, &attrBuf);
20820 +
20821 +    return major;
20822 +}
20823 +
20824 +/*
20825 + * Fabricate a ticket to ourselves given a GSS EAP context.
20826 + */
20827 +OM_uint32
20828 +gssEapMakeReauthCreds(OM_uint32 *minor,
20829 +                      gss_ctx_id_t ctx,
20830 +                      gss_cred_id_t cred,
20831 +                      gss_buffer_t credBuf)
20832 +{
20833 +    OM_uint32 major = GSS_S_COMPLETE;
20834 +    krb5_error_code code;
20835 +    krb5_context krbContext = NULL;
20836 +    krb5_keyblock session = { 0 }, acceptorKey = { 0 };
20837 +    krb5_principal server = NULL;
20838 +#ifdef HAVE_HEIMDAL_VERSION
20839 +    Ticket ticket;
20840 +    EncTicketPart enc_part;
20841 +    AuthorizationData authData = { 0 };
20842 +    krb5_crypto krbCrypto = NULL;
20843 +    krb5_data ticketData = { 0 };
20844 +    krb5_data encPartData = { 0 };
20845 +    size_t len;
20846 +#else
20847 +    krb5_ticket ticket;
20848 +    krb5_enc_tkt_part enc_part;
20849 +    krb5_data *ticketData = NULL;
20850 +#endif
20851 +    krb5_data credsData = { 0 };
20852 +    krb5_creds creds = { 0 };
20853 +    krb5_auth_context authContext = NULL;
20854 +
20855 +    memset(&ticket, 0, sizeof(ticket));
20856 +    memset(&enc_part, 0, sizeof(enc_part));
20857 +
20858 +    credBuf->length = 0;
20859 +    credBuf->value = NULL;
20860 +
20861 +    GSSEAP_KRB_INIT(&krbContext);
20862 +
20863 +    code = getAcceptorKey(krbContext, ctx, cred, &server, &acceptorKey);
20864 +    if (code != 0) {
20865 +        *minor = code;
20866 +        return GSS_S_UNAVAILABLE;
20867 +    }
20868 +
20869 +    /*
20870 +     * Generate a random session key to place in the ticket and
20871 +     * sign the "KDC-Issued" authorization data element.
20872 +     */
20873 +#ifdef HAVE_HEIMDAL_VERSION
20874 +    ticket.realm = server->realm;
20875 +    ticket.sname = server->name;
20876 +
20877 +    code = krb5_generate_random_keyblock(krbContext, ctx->encryptionType,
20878 +                                         &session);
20879 +    if (code != 0)
20880 +        goto cleanup;
20881 +
20882 +    enc_part.flags.initial = 1;
20883 +    enc_part.key = session;
20884 +    enc_part.crealm = ctx->initiatorName->krbPrincipal->realm;
20885 +    enc_part.cname = ctx->initiatorName->krbPrincipal->name;
20886 +    enc_part.authtime = time(NULL);
20887 +    enc_part.starttime = &enc_part.authtime;
20888 +    enc_part.endtime = (ctx->expiryTime != 0)
20889 +                       ? ctx->expiryTime : KRB_TIME_FOREVER;
20890 +    enc_part.renew_till = NULL;
20891 +    enc_part.authorization_data = &authData;
20892 +
20893 +    major = freezeAttrContext(minor, ctx->initiatorName, server,
20894 +                              &session, &authData);
20895 +    if (GSS_ERROR(major))
20896 +        goto cleanup;
20897 +
20898 +    ASN1_MALLOC_ENCODE(EncTicketPart, encPartData.data, encPartData.length,
20899 +                       &enc_part, &len, code);
20900 +    if (code != 0)
20901 +        goto cleanup;
20902 +
20903 +    code = krb5_crypto_init(krbContext, &acceptorKey, 0, &krbCrypto);
20904 +    if (code != 0)
20905 +        goto cleanup;
20906 +
20907 +    code = krb5_encrypt_EncryptedData(krbContext,
20908 +                                      krbCrypto,
20909 +                                      KRB5_KU_TICKET,
20910 +                                      encPartData.data,
20911 +                                      encPartData.length,
20912 +                                      0,
20913 +                                      &ticket.enc_part);
20914 +    if (code != 0)
20915 +        goto cleanup;
20916 +
20917 +    ASN1_MALLOC_ENCODE(Ticket, ticketData.data, ticketData.length,
20918 +                       &ticket, &len, code);
20919 +    if (code != 0)
20920 +        goto cleanup;
20921 +#else
20922 +    ticket.server = server;
20923 +
20924 +    code = krb5_c_make_random_key(krbContext, ctx->encryptionType,
20925 +                                  &session);
20926 +    if (code != 0)
20927 +        goto cleanup;
20928 +
20929 +    enc_part.flags = TKT_FLG_INITIAL;
20930 +    enc_part.session = &session;
20931 +    enc_part.client = ctx->initiatorName->krbPrincipal;
20932 +    enc_part.times.authtime = time(NULL);
20933 +    enc_part.times.starttime = enc_part.times.authtime;
20934 +    enc_part.times.endtime = (ctx->expiryTime != 0)
20935 +                             ? ctx->expiryTime
20936 +                             : KRB_TIME_FOREVER;
20937 +    enc_part.times.renew_till = 0;
20938 +
20939 +    major = freezeAttrContext(minor, ctx->initiatorName, server,
20940 +                              &session, &enc_part.authorization_data);
20941 +    if (GSS_ERROR(major))
20942 +        goto cleanup;
20943 +
20944 +    ticket.enc_part2 = &enc_part;
20945 +
20946 +    code = krb5_encrypt_tkt_part(krbContext, &acceptorKey, &ticket);
20947 +    if (code != 0)
20948 +        goto cleanup;
20949 +
20950 +    code = encode_krb5_ticket(&ticket, &ticketData);
20951 +    if (code != 0)
20952 +        goto cleanup;
20953 +#endif /* HAVE_HEIMDAL_VERSION */
20954 +
20955 +    creds.client = ctx->initiatorName->krbPrincipal;
20956 +    creds.server = server;
20957 +#ifdef HAVE_HEIMDAL_VERSION
20958 +    creds.session = session;
20959 +    creds.times.authtime = enc_part.authtime;
20960 +    creds.times.starttime = *enc_part.starttime;
20961 +    creds.times.endtime = enc_part.endtime;
20962 +    creds.times.renew_till = 0;
20963 +    creds.flags.b = enc_part.flags;
20964 +    creds.ticket = ticketData;
20965 +    creds.authdata = authData;
20966 +#else
20967 +    creds.keyblock = session;
20968 +    creds.times = enc_part.times;
20969 +    creds.ticket_flags = enc_part.flags;
20970 +    creds.ticket = *ticketData;
20971 +    creds.authdata = enc_part.authorization_data;
20972 +#endif
20973 +
20974 +    code = krb5_auth_con_init(krbContext, &authContext);
20975 +    if (code != 0)
20976 +        goto cleanup;
20977 +
20978 +    code = krb5_auth_con_setflags(krbContext, authContext, 0);
20979 +    if (code != 0)
20980 +        goto cleanup;
20981 +
20982 +#ifdef HAVE_HEIMDAL_VERSION
20983 +    code = krb5_auth_con_setlocalsubkey(krbContext, authContext,
20984 +                                        &ctx->rfc3961Key);
20985 +#else
20986 +    code = krb5_auth_con_setsendsubkey(krbContext, authContext,
20987 +                                       &ctx->rfc3961Key);
20988 +#endif
20989 +    if (code != 0)
20990 +        goto cleanup;
20991 +
20992 +    code = krbMakeCred(krbContext, authContext, &creds, &credsData);
20993 +    if (code != 0)
20994 +        goto cleanup;
20995 +
20996 +    krbDataToGssBuffer(&credsData, credBuf);
20997 +
20998 +cleanup:
20999 +#ifdef HAVE_HEIMDAL_VERSION
21000 +    if (krbCrypto != NULL)
21001 +        krb5_crypto_destroy(krbContext, krbCrypto);
21002 +    free_AuthorizationData(&authData);
21003 +    free_EncryptedData(&ticket.enc_part);
21004 +    krb5_data_free(&ticketData);
21005 +    krb5_data_free(&encPartData);
21006 +#else
21007 +    krb5_free_authdata(krbContext, enc_part.authorization_data);
21008 +    if (ticket.enc_part.ciphertext.data != NULL)
21009 +        GSSEAP_FREE(ticket.enc_part.ciphertext.data);
21010 +    krb5_free_data(krbContext, ticketData);
21011 +#endif
21012 +    krb5_free_keyblock_contents(krbContext, &session);
21013 +    krb5_free_principal(krbContext, server);
21014 +    krb5_free_keyblock_contents(krbContext, &acceptorKey);
21015 +    krb5_auth_con_free(krbContext, authContext);
21016 +
21017 +    if (major == GSS_S_COMPLETE) {
21018 +        *minor = code;
21019 +        major = (code != 0) ? GSS_S_FAILURE : GSS_S_COMPLETE;
21020 +    }
21021 +
21022 +    return major;
21023 +}
21024 +
21025 +static int
21026 +isTicketGrantingServiceP(krb5_context krbContext GSSEAP_UNUSED,
21027 +                         krb5_const_principal principal)
21028 +{
21029 +    if (KRB_PRINC_LENGTH(principal) == 2 &&
21030 +#ifdef HAVE_HEIMDAL_VERSION
21031 +        strcmp(KRB_PRINC_NAME(principal)[0], "krbtgt") == 0
21032 +#else
21033 +        krb5_princ_component(krbContext, principal, 0)->length == 6 &&
21034 +        memcmp(krb5_princ_component(krbContext,
21035 +                                    principal, 0)->data, "krbtgt", 6) == 0
21036 +#endif
21037 +        )
21038 +        return TRUE;
21039 +
21040 +    return FALSE;
21041 +}
21042 +
21043 +/*
21044 + * Returns TRUE if the configuration variable reauth_use_ccache is
21045 + * set in krb5.conf for the eap_gss application and the client realm.
21046 + */
21047 +static int
21048 +reauthUseCredsCache(krb5_context krbContext,
21049 +                    krb5_principal principal)
21050 +{
21051 +    int reauthUseCCache;
21052 +
21053 +    /* if reauth_use_ccache, use default credentials cache if ticket is for us */
21054 +    krb5_appdefault_boolean(krbContext, "eap_gss",
21055 +                            KRB_PRINC_REALM(principal),
21056 +                            "reauth_use_ccache", 0, &reauthUseCCache);
21057 +
21058 +    return reauthUseCCache;
21059 +}
21060 +
21061 +/*
21062 + * Look in default credentials cache for reauthentication credentials,
21063 + * if policy allows.
21064 + */
21065 +static OM_uint32
21066 +getDefaultReauthCredentials(OM_uint32 *minor,
21067 +                            gss_cred_id_t cred,
21068 +                            gss_name_t target,
21069 +                            time_t now,
21070 +                            OM_uint32 timeReq)
21071 +{
21072 +    OM_uint32 major = GSS_S_CRED_UNAVAIL;
21073 +    krb5_context krbContext = NULL;
21074 +    krb5_error_code code = 0;
21075 +    krb5_ccache ccache = NULL;
21076 +    krb5_creds match = { 0 };
21077 +    krb5_creds creds = { 0 };
21078 +
21079 +    GSSEAP_KRB_INIT(&krbContext);
21080 +
21081 +    GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL);
21082 +    GSSEAP_ASSERT(target != GSS_C_NO_NAME);
21083 +
21084 +    if (cred->name == GSS_C_NO_NAME ||
21085 +        !reauthUseCredsCache(krbContext, cred->name->krbPrincipal))
21086 +        goto cleanup;
21087 +
21088 +    match.client = cred->name->krbPrincipal;
21089 +    match.server = target->krbPrincipal;
21090 +    if (timeReq != 0 && timeReq != GSS_C_INDEFINITE)
21091 +        match.times.endtime = now + timeReq;
21092 +
21093 +    code = krb5_cc_default(krbContext, &ccache);
21094 +    if (code != 0)
21095 +        goto cleanup;
21096 +
21097 +    code = krb5_cc_retrieve_cred(krbContext, ccache, 0, &match, &creds);
21098 +    if (code != 0)
21099 +        goto cleanup;
21100 +
21101 +    cred->flags |= CRED_FLAG_DEFAULT_CCACHE;
21102 +    cred->krbCredCache = ccache;
21103 +    ccache = NULL;
21104 +
21105 +    major = gss_krb5_import_cred(minor, cred->krbCredCache, NULL, NULL,
21106 +                                 &cred->reauthCred);
21107 +
21108 +cleanup:
21109 +    if (major == GSS_S_CRED_UNAVAIL)
21110 +        *minor = code;
21111 +
21112 +    if (ccache != NULL)
21113 +        krb5_cc_close(krbContext, ccache);
21114 +    krb5_free_cred_contents(krbContext, &creds);
21115 +
21116 +    return major;
21117 +}
21118 +
21119 +/*
21120 + * Returns TRUE if the credential handle's reauth credentials are
21121 + * valid or if we can use the default credentials cache. Credentials
21122 + * handle must be locked.
21123 + */
21124 +int
21125 +gssEapCanReauthP(gss_cred_id_t cred,
21126 +                 gss_name_t target,
21127 +                 OM_uint32 timeReq)
21128 +{
21129 +    time_t now, expiryReq;
21130 +    OM_uint32 minor;
21131 +
21132 +    if (cred == GSS_C_NO_CREDENTIAL)
21133 +        return FALSE;
21134 +
21135 +    now = time(NULL);
21136 +    expiryReq = now;
21137 +    if (timeReq != GSS_C_INDEFINITE)
21138 +        expiryReq += timeReq;
21139 +
21140 +    if (cred->krbCredCache != NULL && cred->expiryTime > expiryReq)
21141 +        return TRUE;
21142 +
21143 +    if (getDefaultReauthCredentials(&minor, cred, target,
21144 +                                    now, timeReq) == GSS_S_COMPLETE)
21145 +        return TRUE;
21146 +
21147 +    return FALSE;
21148 +}
21149 +
21150 +/*
21151 + * Store re-authentication (Kerberos) credentials in a credential handle.
21152 + * Credentials handle must be locked.
21153 + */
21154 +OM_uint32
21155 +gssEapStoreReauthCreds(OM_uint32 *minor,
21156 +                       gss_ctx_id_t ctx,
21157 +                       gss_cred_id_t cred,
21158 +                       gss_buffer_t credBuf)
21159 +{
21160 +    OM_uint32 major = GSS_S_COMPLETE;
21161 +    krb5_error_code code;
21162 +    krb5_context krbContext = NULL;
21163 +    krb5_auth_context authContext = NULL;
21164 +    krb5_data credData = { 0 };
21165 +    krb5_creds **creds = NULL;
21166 +    krb5_principal canonPrinc;
21167 +    krb5_principal ccPrinc = NULL;
21168 +    int i;
21169 +
21170 +    if (credBuf->length == 0 || cred == GSS_C_NO_CREDENTIAL)
21171 +        return GSS_S_COMPLETE;
21172 +
21173 +    GSSEAP_KRB_INIT(&krbContext);
21174 +
21175 +    code = krb5_auth_con_init(krbContext, &authContext);
21176 +    if (code != 0)
21177 +        goto cleanup;
21178 +
21179 +    code = krb5_auth_con_setflags(krbContext, authContext, 0);
21180 +    if (code != 0)
21181 +        goto cleanup;
21182 +
21183 +    code = krb5_auth_con_setrecvsubkey(krbContext, authContext,
21184 +                                       &ctx->rfc3961Key);
21185 +    if (code != 0)
21186 +        goto cleanup;
21187 +
21188 +    gssBufferToKrbData(credBuf, &credData);
21189 +
21190 +    code = krb5_rd_cred(krbContext, authContext, &credData, &creds, NULL);
21191 +    if (code != 0)
21192 +        goto cleanup;
21193 +
21194 +    if (creds == NULL || creds[0] == NULL)
21195 +        goto cleanup;
21196 +
21197 +    code = krb5_copy_principal(krbContext, creds[0]->client, &canonPrinc);
21198 +    if (code != 0)
21199 +        goto cleanup;
21200 +
21201 +    krb5_free_principal(krbContext, cred->name->krbPrincipal);
21202 +    cred->name->krbPrincipal = canonPrinc;
21203 +
21204 +    if (creds[0]->times.endtime == KRB_TIME_FOREVER)
21205 +        cred->expiryTime = 0;
21206 +    else
21207 +        cred->expiryTime = creds[0]->times.endtime;
21208 +
21209 +    if (cred->krbCredCache == NULL) {
21210 +        if (reauthUseCredsCache(krbContext, creds[0]->client) &&
21211 +            krb5_cc_default(krbContext, &cred->krbCredCache) == 0)
21212 +            cred->flags |= CRED_FLAG_DEFAULT_CCACHE;
21213 +    } else {
21214 +        /*
21215 +         * If we already have an associated credentials cache, possibly from
21216 +         * the last time we stored a reauthentication credential, then we
21217 +         * need to clear it out and release the associated GSS credential.
21218 +         */
21219 +        if (cred->flags & CRED_FLAG_DEFAULT_CCACHE) {
21220 +            krb5_cc_remove_cred(krbContext, cred->krbCredCache, 0, creds[0]);
21221 +        } else {
21222 +            krb5_cc_destroy(krbContext, cred->krbCredCache);
21223 +            cred->krbCredCache = NULL;
21224 +        }
21225 +        gssReleaseCred(minor, &cred->reauthCred);
21226 +    }
21227 +
21228 +    if (cred->krbCredCache == NULL) {
21229 +        code = krb5_cc_new_unique(krbContext, "MEMORY", NULL, &cred->krbCredCache);
21230 +        if (code != 0)
21231 +            goto cleanup;
21232 +    }
21233 +
21234 +    if ((cred->flags & CRED_FLAG_DEFAULT_CCACHE) == 0 ||
21235 +        krb5_cc_get_principal(krbContext, cred->krbCredCache, &ccPrinc) != 0) {
21236 +        code = krb5_cc_initialize(krbContext, cred->krbCredCache,
21237 +                                  creds[0]->client);
21238 +        if (code != 0)
21239 +            goto cleanup;
21240 +    }
21241 +
21242 +    for (i = 0; creds[i] != NULL; i++) {
21243 +        krb5_creds kcred = *(creds[i]);
21244 +
21245 +        /*
21246 +         * Swap in the acceptor name the client asked for so
21247 +         * get_credentials() works. We're making the assumption that
21248 +         * any service tickets returned are for us. We'll need to
21249 +         * reflect some more on whether that is a safe assumption.
21250 +         */
21251 +        if (!isTicketGrantingServiceP(krbContext, kcred.server))
21252 +            kcred.server = ctx->acceptorName->krbPrincipal;
21253 +
21254 +        code = krb5_cc_store_cred(krbContext, cred->krbCredCache, &kcred);
21255 +        if (code != 0)
21256 +            goto cleanup;
21257 +    }
21258 +
21259 +    major = gss_krb5_import_cred(minor, cred->krbCredCache, NULL, NULL,
21260 +                                 &cred->reauthCred);
21261 +    if (GSS_ERROR(major))
21262 +        goto cleanup;
21263 +
21264 +cleanup:
21265 +    *minor = code;
21266 +
21267 +    krb5_free_principal(krbContext, ccPrinc);
21268 +    krb5_auth_con_free(krbContext, authContext);
21269 +    if (creds != NULL) {
21270 +        for (i = 0; creds[i] != NULL; i++)
21271 +            krb5_free_creds(krbContext, creds[i]);
21272 +        GSSEAP_FREE(creds);
21273 +    }
21274 +    if (major == GSS_S_COMPLETE)
21275 +        major = *minor ? GSS_S_FAILURE : GSS_S_COMPLETE;
21276 +
21277 +    return major;
21278 +}
21279 +
21280 +#ifndef HAVE_HEIMDAL_VERSION
21281 +static gss_buffer_desc radiusAvpKrbAttr = {
21282 +    sizeof("urn:authdata-radius-avp") - 1, "urn:authdata-radius-avp"
21283 +};
21284 +#endif
21285 +
21286 +/*
21287 + * Unfortunately extracting an AD-KDCIssued authorization data element
21288 + * is pretty implementation-dependent. It's not possible to verify the
21289 + * signature ourselves because the ticket session key is not exposed
21290 + * outside GSS. In an ideal world, all AD-KDCIssued elements would be
21291 + * verified by the Kerberos library and authentication would fail if
21292 + * verification failed. We're not quite there yet and as a result have
21293 + * to go through some hoops to get this to work. The alternative would
21294 + * be to sign the authorization data with our long-term key, but it
21295 + * seems a pity to compromise the design because of current implementation
21296 + * limitations.
21297 + *
21298 + * (Specifically, the hoops involve a libkrb5 authorisation data plugin
21299 + * that exposes the verified and serialised attribute context through
21300 + * the Kerberos GSS mechanism's naming extensions API.)
21301 + */
21302 +static OM_uint32
21303 +defrostAttrContext(OM_uint32 *minor,
21304 +#ifdef HAVE_HEIMDAL_VERSION
21305 +                   gss_ctx_id_t glueContext,
21306 +#else
21307 +                   gss_name_t glueName,
21308 +#endif
21309 +                   gss_name_t mechName)
21310 +{
21311 +    OM_uint32 major, tmpMinor;
21312 +#ifdef HAVE_HEIMDAL_VERSION
21313 +    gss_OID_desc oid = { 0 };
21314 +    gss_buffer_set_t authData = GSS_C_NO_BUFFER_SET;
21315 +#else
21316 +    gss_buffer_desc authData = GSS_C_EMPTY_BUFFER;
21317 +    gss_buffer_desc authDataDisplay = GSS_C_EMPTY_BUFFER;
21318 +    int more = -1;
21319 +    int authenticated, complete;
21320 +#endif
21321 +
21322 +#ifdef HAVE_HEIMDAL_VERSION
21323 +    major = composeOid(minor,
21324 +                       GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->elements,
21325 +                       GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->length,
21326 +                       KRB5_AUTHDATA_RADIUS_AVP, &oid);
21327 +    if (GSS_ERROR(major))
21328 +        return major;
21329 +
21330 +    /* XXX we are assuming that this verifies AD-KDCIssued signature */
21331 +    major = gssInquireSecContextByOid(minor, glueContext,
21332 +                                      &oid, &authData);
21333 +    if (major == GSS_S_COMPLETE) {
21334 +        if (authData == GSS_C_NO_BUFFER_SET || authData->count != 1)
21335 +            major = GSS_S_FAILURE;
21336 +        else
21337 +            major = gssEapImportAttrContext(minor, authData->elements, mechName);
21338 +    } else if (major == GSS_S_FAILURE && *minor == ENOENT) {
21339 +        /* This is the equivalent of GSS_S_UNAVAILABLE for MIT attr APIs */
21340 +        *minor = 0;
21341 +        major = GSS_S_COMPLETE;
21342 +    }
21343 +
21344 +    gss_release_buffer_set(&tmpMinor, &authData);
21345 +    GSSEAP_FREE(oid.elements);
21346 +#else
21347 +    major = gssGetNameAttribute(minor, glueName, &radiusAvpKrbAttr,
21348 +                                &authenticated, &complete,
21349 +                                &authData, &authDataDisplay, &more);
21350 +    if (major == GSS_S_COMPLETE) {
21351 +        if (authenticated == 0)
21352 +            major = GSS_S_BAD_NAME;
21353 +        else
21354 +            major = gssEapImportAttrContext(minor, &authData, mechName);
21355 +    } else if (major == GSS_S_UNAVAILABLE) {
21356 +        major = GSS_S_COMPLETE;
21357 +    }
21358 +
21359 +    gss_release_buffer(&tmpMinor, &authData);
21360 +    gss_release_buffer(&tmpMinor, &authDataDisplay);
21361 +#endif /* HAVE_HEIMDAL_VERSION */
21362 +
21363 +    return major;
21364 +}
21365 +
21366 +/*
21367 + * Convert a mechanism glue to an EAP mechanism name by displaying and
21368 + * importing it. This also handles the RADIUS attributes.
21369 + */
21370 +OM_uint32
21371 +gssEapGlueToMechName(OM_uint32 *minor,
21372 +                     gss_ctx_id_t ctx,
21373 +                     gss_name_t glueName,
21374 +                     gss_name_t *pMechName)
21375 +{
21376 +    OM_uint32 major, tmpMinor;
21377 +    gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
21378 +
21379 +    *pMechName = GSS_C_NO_NAME;
21380 +
21381 +    major = gssDisplayName(minor, glueName, &nameBuf, NULL);
21382 +    if (GSS_ERROR(major))
21383 +        goto cleanup;
21384 +
21385 +    major = gssEapImportName(minor, &nameBuf, GSS_C_NT_USER_NAME,
21386 +                             ctx->mechanismUsed, pMechName);
21387 +    if (GSS_ERROR(major))
21388 +        goto cleanup;
21389 +
21390 +    major = defrostAttrContext(minor,
21391 +#ifdef HAVE_HEIMDAL_VERSION
21392 +                               ctx->reauthCtx,
21393 +#else
21394 +                               glueName,
21395 +#endif
21396 +                               *pMechName);
21397 +    if (GSS_ERROR(major))
21398 +        goto cleanup;
21399 +
21400 +cleanup:
21401 +    if (GSS_ERROR(major)) {
21402 +        gssReleaseName(&tmpMinor, pMechName);
21403 +        *pMechName = GSS_C_NO_NAME;
21404 +    }
21405 +
21406 +    gss_release_buffer(&tmpMinor, &nameBuf);
21407 +
21408 +    return major;
21409 +}
21410 +
21411 +/*
21412 + * Convert an EAP mechanism name to a mechanism glue name by displaying
21413 + * and importing it.
21414 + */
21415 +OM_uint32
21416 +gssEapMechToGlueName(OM_uint32 *minor,
21417 +                     gss_name_t mechName,
21418 +                     gss_name_t *pGlueName)
21419 +{
21420 +    OM_uint32 major, tmpMinor;
21421 +    gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
21422 +
21423 +    *pGlueName = GSS_C_NO_NAME;
21424 +
21425 +    major = gssEapDisplayName(minor, mechName, &nameBuf, NULL);
21426 +    if (GSS_ERROR(major))
21427 +        goto cleanup;
21428 +
21429 +    major = gssImportName(minor, &nameBuf, GSS_C_NT_USER_NAME,
21430 +                          pGlueName);
21431 +    if (GSS_ERROR(major))
21432 +        goto cleanup;
21433 +
21434 +cleanup:
21435 +    gss_release_buffer(&tmpMinor, &nameBuf);
21436 +
21437 +    return major;
21438 +}
21439 +
21440 +/*
21441 + * Suck out the analgous elements of a Kerberos GSS context into an EAP
21442 + * one so that the application doesn't know the difference.
21443 + */
21444 +OM_uint32
21445 +gssEapReauthComplete(OM_uint32 *minor,
21446 +                     gss_ctx_id_t ctx,
21447 +                     gss_cred_id_t cred GSSEAP_UNUSED,
21448 +                     const gss_OID mech,
21449 +                     OM_uint32 timeRec)
21450 +{
21451 +    OM_uint32 major, tmpMinor;
21452 +    gss_buffer_set_t keyData = GSS_C_NO_BUFFER_SET;
21453 +    krb5_context krbContext = NULL;
21454 +#ifdef HAVE_HEIMDAL_VERSION
21455 +    krb5_storage *sp = NULL;
21456 +#endif
21457 +
21458 +    GSSEAP_KRB_INIT(&krbContext);
21459 +
21460 +    if (!oidEqual(mech, gss_mech_krb5)) {
21461 +        major = GSS_S_BAD_MECH;
21462 +        goto cleanup;
21463 +    }
21464 +
21465 +    /* Get the raw subsession key and encryption type */
21466 +#ifdef HAVE_HEIMDAL_VERSION
21467 +#define KRB_GSS_SUBKEY_COUNT    1 /* encoded session key */
21468 +    major = gssInquireSecContextByOid(minor, ctx->reauthCtx,
21469 +                                      GSS_KRB5_GET_SUBKEY_X, &keyData);
21470 +#else
21471 +#define KRB_GSS_SUBKEY_COUNT    2 /* raw session key, enctype OID */
21472 +    major = gssInquireSecContextByOid(minor, ctx->reauthCtx,
21473 +                                      GSS_C_INQ_SSPI_SESSION_KEY, &keyData);
21474 +#endif
21475 +    if (GSS_ERROR(major))
21476 +        goto cleanup;
21477 +
21478 +    if (keyData == GSS_C_NO_BUFFER_SET || keyData->count < KRB_GSS_SUBKEY_COUNT) {
21479 +        *minor = GSSEAP_KEY_UNAVAILABLE;
21480 +        major = GSS_S_FAILURE;
21481 +        goto cleanup;
21482 +    }
21483 +
21484 +#ifdef HAVE_HEIMDAL_VERSION
21485 +    sp = krb5_storage_from_mem(keyData->elements[0].value,
21486 +                               keyData->elements[0].length);
21487 +    if (sp == NULL) {
21488 +        *minor = ENOMEM;
21489 +        major = GSS_S_FAILURE;
21490 +        goto cleanup;
21491 +    }
21492 +
21493 +    *minor = krb5_ret_keyblock(sp, &ctx->rfc3961Key);
21494 +    if (*minor != 0) {
21495 +        major = GSS_S_FAILURE;
21496 +        goto cleanup;
21497 +    }
21498 +#else
21499 +    {
21500 +        gss_OID_desc oid;
21501 +        int suffix;
21502 +
21503 +        oid.length = keyData->elements[1].length;
21504 +        oid.elements = keyData->elements[1].value;
21505 +
21506 +        /* GSS_KRB5_SESSION_KEY_ENCTYPE_OID */
21507 +        major = decomposeOid(minor,
21508 +                             "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04",
21509 +                             10, &oid, &suffix);
21510 +        if (GSS_ERROR(major))
21511 +            goto cleanup;
21512 +
21513 +        ctx->encryptionType = suffix;
21514 +    }
21515 +
21516 +    {
21517 +        krb5_keyblock key;
21518 +
21519 +        KRB_KEY_LENGTH(&key) = keyData->elements[0].length;
21520 +        KRB_KEY_DATA(&key)   = keyData->elements[0].value;
21521 +        KRB_KEY_TYPE(&key)   = ctx->encryptionType;
21522 +
21523 +        *minor = krb5_copy_keyblock_contents(krbContext,
21524 +                                             &key, &ctx->rfc3961Key);
21525 +        if (*minor != 0) {
21526 +            major = GSS_S_FAILURE;
21527 +            goto cleanup;
21528 +        }
21529 +    }
21530 +#endif /* HAVE_HEIMDAL_VERSION */
21531 +
21532 +    major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
21533 +                                      &ctx->checksumType);
21534 +    if (GSS_ERROR(major))
21535 +        goto cleanup;
21536 +
21537 +    if (timeRec != GSS_C_INDEFINITE)
21538 +        ctx->expiryTime = time(NULL) + timeRec;
21539 +
21540 +    /* Initialize our sequence state */
21541 +    major = sequenceInit(minor,
21542 +                         &ctx->seqState, ctx->recvSeq,
21543 +                         ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0),
21544 +                         ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0),
21545 +                         TRUE);
21546 +    if (GSS_ERROR(major))
21547 +        goto cleanup;
21548 +
21549 +    major = GSS_S_COMPLETE;
21550 +
21551 +cleanup:
21552 +#ifdef HAVE_HEIMDAL_VERSION
21553 +    if (sp != NULL)
21554 +        krb5_storage_free(sp);
21555 +#endif
21556 +    gss_release_buffer_set(&tmpMinor, &keyData);
21557 +
21558 +    return major;
21559 +}
21560 +
21561 +/*
21562 + * The remainder of this file consists of wrappers so we can call into the
21563 + * mechanism glue without calling ourselves.
21564 + */
21565 +static OM_uint32
21566 +(*gssInitSecContextNext)(OM_uint32 *,
21567 +                         gss_cred_id_t,
21568 +                         gss_ctx_id_t *,
21569 +                         gss_name_t,
21570 +                         gss_OID,
21571 +                         OM_uint32,
21572 +                         OM_uint32,
21573 +                         gss_channel_bindings_t,
21574 +                         gss_buffer_t,
21575 +                         gss_OID *,
21576 +                         gss_buffer_t,
21577 +                         OM_uint32 *,
21578 +                         OM_uint32 *);
21579 +
21580 +static OM_uint32
21581 +(*gssAcceptSecContextNext)(OM_uint32 *,
21582 +                           gss_ctx_id_t *,
21583 +                           gss_cred_id_t,
21584 +                           gss_buffer_t,
21585 +                           gss_channel_bindings_t,
21586 +                           gss_name_t *,
21587 +                           gss_OID *,
21588 +                           gss_buffer_t,
21589 +                           OM_uint32 *,
21590 +                           OM_uint32 *,
21591 +                           gss_cred_id_t *);
21592 +
21593 +static OM_uint32
21594 +(*gssReleaseCredNext)(OM_uint32 *, gss_cred_id_t *);
21595 +
21596 +static OM_uint32
21597 +(*gssReleaseNameNext)(OM_uint32 *, gss_name_t *);
21598 +
21599 +static OM_uint32
21600 +(*gssInquireSecContextByOidNext)(OM_uint32 *,
21601 +                                 const gss_ctx_id_t,
21602 +                                 const gss_OID,
21603 +                                 gss_buffer_set_t *);
21604 +
21605 +static OM_uint32
21606 +(*gssDeleteSecContextNext)(OM_uint32 *,
21607 +                          gss_ctx_id_t *,
21608 +                          gss_buffer_t);
21609 +
21610 +static OM_uint32
21611 +(*gssDisplayNameNext)(OM_uint32 *,
21612 +                      gss_name_t,
21613 +                      gss_buffer_t,
21614 +                      gss_OID *);
21615 +
21616 +static OM_uint32
21617 +(*gssImportNameNext)(OM_uint32 *,
21618 +                     gss_buffer_t,
21619 +                     gss_OID,
21620 +                     gss_name_t *);
21621 +
21622 +static OM_uint32
21623 +(*gssStoreCredNext)(OM_uint32 *,
21624 +                    const gss_cred_id_t,
21625 +                    gss_cred_usage_t,
21626 +                    const gss_OID,
21627 +                    OM_uint32,
21628 +                    OM_uint32,
21629 +                    gss_OID_set *,
21630 +                    gss_cred_usage_t *);
21631 +
21632 +static OM_uint32
21633 +(*gssGetNameAttributeNext)(OM_uint32 *,
21634 +                          gss_name_t,
21635 +                          gss_buffer_t,
21636 +                          int *,
21637 +                          int *,
21638 +                          gss_buffer_t,
21639 +                          gss_buffer_t,
21640 +                          int *);
21641 +
21642 +#define NEXT_SYMBOL(local, global)  do {        \
21643 +        ((local) = dlsym(RTLD_NEXT, (global))); \
21644 +        if ((local) == NULL) {                  \
21645 +            *minor = GSSEAP_NO_MECHGLUE_SYMBOL; \
21646 +            major = GSS_S_UNAVAILABLE;          \
21647 +            /* but continue */                  \
21648 +        }                                       \
21649 +    } while (0)
21650 +
21651 +OM_uint32
21652 +gssEapReauthInitialize(OM_uint32 *minor)
21653 +{
21654 +    OM_uint32 major = GSS_S_COMPLETE;
21655 +
21656 +    NEXT_SYMBOL(gssInitSecContextNext,         "gss_init_sec_context");
21657 +    NEXT_SYMBOL(gssAcceptSecContextNext,       "gss_accept_sec_context");
21658 +    NEXT_SYMBOL(gssReleaseCredNext,            "gss_release_cred");
21659 +    NEXT_SYMBOL(gssReleaseNameNext,            "gss_release_name");
21660 +    NEXT_SYMBOL(gssInquireSecContextByOidNext, "gss_inquire_sec_context_by_oid");
21661 +    NEXT_SYMBOL(gssDeleteSecContextNext,       "gss_delete_sec_context");
21662 +    NEXT_SYMBOL(gssDisplayNameNext,            "gss_display_name");
21663 +    NEXT_SYMBOL(gssImportNameNext,             "gss_import_name");
21664 +    NEXT_SYMBOL(gssStoreCredNext,              "gss_store_cred");
21665 +#ifndef HAVE_HEIMDAL_VERSION
21666 +    NEXT_SYMBOL(gssGetNameAttributeNext,       "gss_get_name_attribute");
21667 +#endif
21668 +
21669 +    return major;
21670 +}
21671 +
21672 +OM_uint32
21673 +gssInitSecContext(OM_uint32 *minor,
21674 +                  gss_cred_id_t cred,
21675 +                  gss_ctx_id_t *context_handle,
21676 +                  gss_name_t target_name,
21677 +                  gss_OID mech_type,
21678 +                  OM_uint32 req_flags,
21679 +                  OM_uint32 time_req,
21680 +                  gss_channel_bindings_t input_chan_bindings,
21681 +                  gss_buffer_t input_token,
21682 +                  gss_OID *actual_mech_type,
21683 +                  gss_buffer_t output_token,
21684 +                  OM_uint32 *ret_flags,
21685 +                  OM_uint32 *time_rec)
21686 +{
21687 +    if (gssInitSecContextNext == NULL) {
21688 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
21689 +        return GSS_S_UNAVAILABLE;
21690 +    }
21691 +
21692 +    return gssInitSecContextNext(minor, cred, context_handle,
21693 +                                 target_name, mech_type, req_flags,
21694 +                                 time_req, input_chan_bindings,
21695 +                                 input_token, actual_mech_type,
21696 +                                 output_token, ret_flags, time_rec);
21697 +}
21698 +
21699 +OM_uint32
21700 +gssAcceptSecContext(OM_uint32 *minor,
21701 +                    gss_ctx_id_t *context_handle,
21702 +                    gss_cred_id_t cred,
21703 +                    gss_buffer_t input_token,
21704 +                    gss_channel_bindings_t input_chan_bindings,
21705 +                    gss_name_t *src_name,
21706 +                    gss_OID *mech_type,
21707 +                    gss_buffer_t output_token,
21708 +                    OM_uint32 *ret_flags,
21709 +                    OM_uint32 *time_rec,
21710 +                    gss_cred_id_t *delegated_cred_handle)
21711 +{
21712 +    if (gssAcceptSecContextNext == NULL) {
21713 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
21714 +        return GSS_S_UNAVAILABLE;
21715 +    }
21716 +
21717 +    return gssAcceptSecContextNext(minor, context_handle, cred,
21718 +                                   input_token, input_chan_bindings,
21719 +                                   src_name, mech_type, output_token,
21720 +                                   ret_flags, time_rec, delegated_cred_handle);
21721 +}
21722 +
21723 +OM_uint32
21724 +gssReleaseCred(OM_uint32 *minor,
21725 +               gss_cred_id_t *cred_handle)
21726 +{
21727 +    if (gssReleaseCredNext == NULL) {
21728 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
21729 +        return GSS_S_UNAVAILABLE;
21730 +    }
21731 +
21732 +    return gssReleaseCredNext(minor, cred_handle);
21733 +}
21734 +
21735 +OM_uint32
21736 +gssReleaseName(OM_uint32 *minor,
21737 +               gss_name_t *name)
21738 +{
21739 +    if (gssReleaseName == NULL) {
21740 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
21741 +        return GSS_S_UNAVAILABLE;
21742 +    }
21743 +
21744 +    return gssReleaseNameNext(minor, name);
21745 +}
21746 +
21747 +OM_uint32
21748 +gssDeleteSecContext(OM_uint32 *minor,
21749 +                    gss_ctx_id_t *context_handle,
21750 +                    gss_buffer_t output_token)
21751 +{
21752 +    if (gssDeleteSecContextNext == NULL) {
21753 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
21754 +        return GSS_S_UNAVAILABLE;
21755 +    }
21756 +
21757 +    return gssDeleteSecContextNext(minor, context_handle, output_token);
21758 +}
21759 +
21760 +static OM_uint32
21761 +gssDisplayName(OM_uint32 *minor,
21762 +               gss_name_t name,
21763 +               gss_buffer_t buffer,
21764 +               gss_OID *name_type)
21765 +{
21766 +    if (gssDisplayNameNext == NULL) {
21767 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
21768 +        return GSS_S_UNAVAILABLE;
21769 +    }
21770 +
21771 +    return gssDisplayNameNext(minor, name, buffer, name_type);
21772 +}
21773 +
21774 +static OM_uint32
21775 +gssImportName(OM_uint32 *minor,
21776 +              gss_buffer_t buffer,
21777 +              gss_OID name_type,
21778 +              gss_name_t *name)
21779 +{
21780 +    if (gssImportNameNext == NULL) {
21781 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
21782 +        return GSS_S_UNAVAILABLE;
21783 +    }
21784 +
21785 +    return gssImportNameNext(minor, buffer, name_type, name);
21786 +}
21787 +
21788 +OM_uint32
21789 +gssInquireSecContextByOid(OM_uint32 *minor,
21790 +                          const gss_ctx_id_t context_handle,
21791 +                          const gss_OID desired_object,
21792 +                          gss_buffer_set_t *data_set)
21793 +{
21794 +    if (gssInquireSecContextByOidNext == NULL) {
21795 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
21796 +        return GSS_S_UNAVAILABLE;
21797 +    }
21798 +
21799 +    return gssInquireSecContextByOidNext(minor, context_handle,
21800 +                                         desired_object, data_set);
21801 +}
21802 +
21803 +OM_uint32
21804 +gssStoreCred(OM_uint32 *minor,
21805 +             const gss_cred_id_t input_cred_handle,
21806 +             gss_cred_usage_t input_usage,
21807 +             const gss_OID desired_mech,
21808 +             OM_uint32 overwrite_cred,
21809 +             OM_uint32 default_cred,
21810 +             gss_OID_set *elements_stored,
21811 +             gss_cred_usage_t *cred_usage_stored)
21812 +{
21813 +    if (gssStoreCredNext == NULL) {
21814 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
21815 +        return GSS_S_UNAVAILABLE;
21816 +    }
21817 +
21818 +    return gssStoreCredNext(minor, input_cred_handle, input_usage,
21819 +                            desired_mech, overwrite_cred, default_cred,
21820 +                            elements_stored, cred_usage_stored);
21821 +}
21822 +
21823 +OM_uint32
21824 +gssGetNameAttribute(OM_uint32 *minor,
21825 +                    gss_name_t name,
21826 +                    gss_buffer_t attr,
21827 +                    int *authenticated,
21828 +                    int *complete,
21829 +                    gss_buffer_t value,
21830 +                    gss_buffer_t display_value,
21831 +                    int *more)
21832 +{
21833 +    if (gssGetNameAttributeNext == NULL) {
21834 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
21835 +        return GSS_S_UNAVAILABLE;
21836 +    }
21837 +
21838 +    return gssGetNameAttributeNext(minor, name, attr, authenticated, complete,
21839 +                                   value, display_value, more);
21840 +}
21841 diff --git a/mech_eap/util_reauth.h b/mech_eap/util_reauth.h
21842 new file mode 100644
21843 index 0000000..9b9f264
21844 --- /dev/null
21845 +++ b/mech_eap/util_reauth.h
21846 @@ -0,0 +1,151 @@
21847 +/*
21848 + * Copyright (c) 2011, JANET(UK)
21849 + * All rights reserved.
21850 + *
21851 + * Redistribution and use in source and binary forms, with or without
21852 + * modification, are permitted provided that the following conditions
21853 + * are met:
21854 + *
21855 + * 1. Redistributions of source code must retain the above copyright
21856 + *    notice, this list of conditions and the following disclaimer.
21857 + *
21858 + * 2. Redistributions in binary form must reproduce the above copyright
21859 + *    notice, this list of conditions and the following disclaimer in the
21860 + *    documentation and/or other materials provided with the distribution.
21861 + *
21862 + * 3. Neither the name of JANET(UK) nor the names of its contributors
21863 + *    may be used to endorse or promote products derived from this software
21864 + *    without specific prior written permission.
21865 + *
21866 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21867 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21868 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21869 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
21870 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21871 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21872 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21873 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21874 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21875 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
21876 + * SUCH DAMAGE.
21877 + */
21878 +
21879 +/*
21880 + * Fast reauthentication support.
21881 + */
21882 +
21883 +#include "gssapiP_eap.h"
21884 +
21885 +#ifndef _UTIL_REAUTH_H_
21886 +#define _UTIL_REAUTH_H_ 1
21887 +
21888 +/* AD element containing serialised AVPs. */
21889 +#define KRB5_AUTHDATA_RADIUS_AVP        513
21890 +
21891 +OM_uint32
21892 +gssInitSecContext(OM_uint32 *minor,
21893 +                  gss_cred_id_t cred,
21894 +                  gss_ctx_id_t *context_handle,
21895 +                  gss_name_t target_name,
21896 +                  gss_OID mech_type,
21897 +                  OM_uint32 req_flags,
21898 +                  OM_uint32 time_req,
21899 +                  gss_channel_bindings_t input_chan_bindings,
21900 +                  gss_buffer_t input_token,
21901 +                  gss_OID *actual_mech_type,
21902 +                  gss_buffer_t output_token,
21903 +                  OM_uint32 *ret_flags,
21904 +                  OM_uint32 *time_rec);
21905 +
21906 +OM_uint32
21907 +gssAcceptSecContext(OM_uint32 *minor,
21908 +                    gss_ctx_id_t *context_handle,
21909 +                    gss_cred_id_t cred,
21910 +                    gss_buffer_t input_token,
21911 +                    gss_channel_bindings_t input_chan_bindings,
21912 +                    gss_name_t *src_name,
21913 +                    gss_OID *mech_type,
21914 +                    gss_buffer_t output_token,
21915 +                    OM_uint32 *ret_flags,
21916 +                    OM_uint32 *time_rec,
21917 +                    gss_cred_id_t *delegated_cred_handle);
21918 +
21919 +OM_uint32
21920 +gssReleaseCred(OM_uint32 *minor,
21921 +               gss_cred_id_t *cred_handle);
21922 +
21923 +OM_uint32
21924 +gssReleaseName(OM_uint32 *minor,
21925 +               gss_name_t *name);
21926 +
21927 +OM_uint32
21928 +gssDeleteSecContext(OM_uint32 *minor,
21929 +                    gss_ctx_id_t *context_handle,
21930 +                    gss_buffer_t output_token);
21931 +
21932 +OM_uint32
21933 +gssInquireSecContextByOid(OM_uint32 *minor,
21934 +                          const gss_ctx_id_t context_handle,
21935 +                          const gss_OID desired_object,
21936 +                          gss_buffer_set_t *data_set);
21937 +
21938 +OM_uint32
21939 +gssStoreCred(OM_uint32 *minor,
21940 +             const gss_cred_id_t input_cred_handle,
21941 +             gss_cred_usage_t input_usage,
21942 +             const gss_OID desired_mech,
21943 +             OM_uint32 overwrite_cred,
21944 +             OM_uint32 default_cred,
21945 +             gss_OID_set *elements_stored,
21946 +             gss_cred_usage_t *cred_usage_stored);
21947 +
21948 +OM_uint32
21949 +gssGetNameAttribute(OM_uint32 *minor,
21950 +                    gss_name_t name,
21951 +                    gss_buffer_t attr,
21952 +                    int *authenticated,
21953 +                    int *complete,
21954 +                    gss_buffer_t value,
21955 +                    gss_buffer_t display_value,
21956 +                    int *more);
21957 +
21958 +OM_uint32
21959 +gssEapMakeReauthCreds(OM_uint32 *minor,
21960 +                      gss_ctx_id_t ctx,
21961 +                      gss_cred_id_t cred,
21962 +                      gss_buffer_t credBuf);
21963 +
21964 +OM_uint32
21965 +gssEapStoreReauthCreds(OM_uint32 *minor,
21966 +                       gss_ctx_id_t ctx,
21967 +                       gss_cred_id_t cred,
21968 +                       gss_buffer_t credBuf);
21969 +
21970 +
21971 +OM_uint32
21972 +gssEapGlueToMechName(OM_uint32 *minor,
21973 +                     gss_ctx_id_t glueContext,
21974 +                     gss_name_t glueName,
21975 +                     gss_name_t *pMechName);
21976 +
21977 +OM_uint32
21978 +gssEapMechToGlueName(OM_uint32 *minor,
21979 +                     gss_name_t mechName,
21980 +                     gss_name_t *pGlueName);
21981 +
21982 +OM_uint32
21983 +gssEapReauthComplete(OM_uint32 *minor,
21984 +                    gss_ctx_id_t ctx,
21985 +                    gss_cred_id_t cred,
21986 +                    const gss_OID mech,
21987 +                    OM_uint32 timeRec);
21988 +
21989 +OM_uint32
21990 +gssEapReauthInitialize(OM_uint32 *minor);
21991 +
21992 +int
21993 +gssEapCanReauthP(gss_cred_id_t cred,
21994 +                 gss_name_t target,
21995 +                 OM_uint32 timeReq);
21996 +
21997 +#endif /* _UTIL_REAUTH_H_ */
21998 diff --git a/mech_eap/util_saml.cpp b/mech_eap/util_saml.cpp
21999 new file mode 100644
22000 index 0000000..ce7582e
22001 --- /dev/null
22002 +++ b/mech_eap/util_saml.cpp
22003 @@ -0,0 +1,775 @@
22004 +/*
22005 + * Copyright (c) 2011, JANET(UK)
22006 + * All rights reserved.
22007 + *
22008 + * Redistribution and use in source and binary forms, with or without
22009 + * modification, are permitted provided that the following conditions
22010 + * are met:
22011 + *
22012 + * 1. Redistributions of source code must retain the above copyright
22013 + *    notice, this list of conditions and the following disclaimer.
22014 + *
22015 + * 2. Redistributions in binary form must reproduce the above copyright
22016 + *    notice, this list of conditions and the following disclaimer in the
22017 + *    documentation and/or other materials provided with the distribution.
22018 + *
22019 + * 3. Neither the name of JANET(UK) nor the names of its contributors
22020 + *    may be used to endorse or promote products derived from this software
22021 + *    without specific prior written permission.
22022 + *
22023 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22024 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22025 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22026 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22027 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22028 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22029 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22030 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22031 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22032 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22033 + * SUCH DAMAGE.
22034 + */
22035 +
22036 +/*
22037 + * SAML attribute provider implementation.
22038 + */
22039 +
22040 +#include "gssapiP_eap.h"
22041 +
22042 +#include <sstream>
22043 +
22044 +#include <xercesc/util/XMLUniDefs.hpp>
22045 +#include <xmltooling/unicode.h>
22046 +#include <xmltooling/XMLToolingConfig.h>
22047 +#include <xmltooling/util/XMLHelper.h>
22048 +#include <xmltooling/util/ParserPool.h>
22049 +#include <xmltooling/util/DateTime.h>
22050 +
22051 +#include <saml/exceptions.h>
22052 +#include <saml/SAMLConfig.h>
22053 +#include <saml/saml1/core/Assertions.h>
22054 +#include <saml/saml2/core/Assertions.h>
22055 +#include <saml/saml2/metadata/Metadata.h>
22056 +#include <saml/saml2/metadata/MetadataProvider.h>
22057 +
22058 +using namespace xmltooling;
22059 +using namespace opensaml::saml2md;
22060 +using namespace opensaml;
22061 +using namespace xercesc;
22062 +using namespace std;
22063 +
22064 +static const XMLCh
22065 +base64Binary[] = {'b','a','s','e','6','4','B','i','n','a','r','y',0};
22066 +
22067 +/*
22068 + * gss_eap_saml_assertion_provider is for retrieving the underlying
22069 + * assertion.
22070 + */
22071 +gss_eap_saml_assertion_provider::gss_eap_saml_assertion_provider(void)
22072 +{
22073 +    m_assertion = NULL;
22074 +    m_authenticated = false;
22075 +}
22076 +
22077 +gss_eap_saml_assertion_provider::~gss_eap_saml_assertion_provider(void)
22078 +{
22079 +    delete m_assertion;
22080 +}
22081 +
22082 +bool
22083 +gss_eap_saml_assertion_provider::initWithExistingContext(const gss_eap_attr_ctx *manager,
22084 +                                                         const gss_eap_attr_provider *ctx)
22085 +{
22086 +    /* Then we may be creating from an existing attribute context */
22087 +    const gss_eap_saml_assertion_provider *saml;
22088 +
22089 +    GSSEAP_ASSERT(m_assertion == NULL);
22090 +
22091 +    if (!gss_eap_attr_provider::initWithExistingContext(manager, ctx))
22092 +        return false;
22093 +
22094 +    saml = static_cast<const gss_eap_saml_assertion_provider *>(ctx);
22095 +    setAssertion(saml->getAssertion(), saml->authenticated());
22096 +
22097 +    return true;
22098 +}
22099 +
22100 +bool
22101 +gss_eap_saml_assertion_provider::initWithGssContext(const gss_eap_attr_ctx *manager,
22102 +                                                    const gss_cred_id_t gssCred,
22103 +                                                    const gss_ctx_id_t gssCtx)
22104 +{
22105 +    const gss_eap_radius_attr_provider *radius;
22106 +    gss_buffer_desc value = GSS_C_EMPTY_BUFFER;
22107 +    int authenticated, complete;
22108 +    OM_uint32 minor;
22109 +
22110 +    GSSEAP_ASSERT(m_assertion == NULL);
22111 +
22112 +    if (!gss_eap_attr_provider::initWithGssContext(manager, gssCred, gssCtx))
22113 +        return false;
22114 +
22115 +    /*
22116 +     * XXX TODO we need to support draft-howlett-radius-saml-attr-00
22117 +     */
22118 +    radius = static_cast<const gss_eap_radius_attr_provider *>
22119 +        (m_manager->getProvider(ATTR_TYPE_RADIUS));
22120 +    if (radius != NULL &&
22121 +        radius->getFragmentedAttribute(PW_SAML_AAA_ASSERTION,
22122 +                                       VENDORPEC_UKERNA,
22123 +                                       &authenticated, &complete, &value)) {
22124 +        setAssertion(&value, authenticated);
22125 +        gss_release_buffer(&minor, &value);
22126 +    } else {
22127 +        m_assertion = NULL;
22128 +    }
22129 +
22130 +    return true;
22131 +}
22132 +
22133 +void
22134 +gss_eap_saml_assertion_provider::setAssertion(const saml2::Assertion *assertion,
22135 +                                              bool authenticated)
22136 +{
22137 +
22138 +    delete m_assertion;
22139 +
22140 +    if (assertion != NULL) {
22141 +#ifdef __APPLE__
22142 +        m_assertion = (saml2::Assertion *)((void *)assertion->clone());
22143 +#else
22144 +        m_assertion = dynamic_cast<saml2::Assertion *>(assertion->clone());
22145 +#endif
22146 +        m_authenticated = authenticated;
22147 +    } else {
22148 +        m_assertion = NULL;
22149 +        m_authenticated = false;
22150 +    }
22151 +}
22152 +
22153 +void
22154 +gss_eap_saml_assertion_provider::setAssertion(const gss_buffer_t buffer,
22155 +                                              bool authenticated)
22156 +{
22157 +    delete m_assertion;
22158 +
22159 +    m_assertion = parseAssertion(buffer);
22160 +    m_authenticated = (m_assertion != NULL && authenticated);
22161 +}
22162 +
22163 +saml2::Assertion *
22164 +gss_eap_saml_assertion_provider::parseAssertion(const gss_buffer_t buffer)
22165 +{
22166 +    string str((char *)buffer->value, buffer->length);
22167 +    istringstream istream(str);
22168 +    DOMDocument *doc;
22169 +    const XMLObjectBuilder *b;
22170 +
22171 +    try {
22172 +        doc = XMLToolingConfig::getConfig().getParser().parse(istream);
22173 +        if (doc == NULL)
22174 +            return NULL;
22175 +
22176 +        b = XMLObjectBuilder::getBuilder(doc->getDocumentElement());
22177 +
22178 +#ifdef __APPLE__
22179 +        return (saml2::Assertion *)((void *)b->buildFromDocument(doc));
22180 +#else
22181 +        return dynamic_cast<saml2::Assertion *>(b->buildFromDocument(doc));
22182 +#endif
22183 +    } catch (exception &e) {
22184 +        return NULL;
22185 +    }
22186 +}
22187 +
22188 +bool
22189 +gss_eap_saml_assertion_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
22190 +                                                   void *data) const
22191 +{
22192 +    bool ret;
22193 +
22194 +    /* just add the prefix */
22195 +    if (m_assertion != NULL)
22196 +        ret = addAttribute(m_manager, this, GSS_C_NO_BUFFER, data);
22197 +    else
22198 +        ret = true;
22199 +
22200 +    return ret;
22201 +}
22202 +
22203 +bool
22204 +gss_eap_saml_assertion_provider::setAttribute(int complete GSSEAP_UNUSED,
22205 +                                              const gss_buffer_t attr,
22206 +                                              const gss_buffer_t value)
22207 +{
22208 +    if (attr == GSS_C_NO_BUFFER || attr->length == 0) {
22209 +        setAssertion(value);
22210 +        return true;
22211 +    }
22212 +
22213 +    return false;
22214 +}
22215 +
22216 +bool
22217 +gss_eap_saml_assertion_provider::deleteAttribute(const gss_buffer_t value GSSEAP_UNUSED)
22218 +{
22219 +    delete m_assertion;
22220 +    m_assertion = NULL;
22221 +    m_authenticated = false;
22222 +
22223 +    return true;
22224 +}
22225 +
22226 +time_t
22227 +gss_eap_saml_assertion_provider::getExpiryTime(void) const
22228 +{
22229 +    saml2::Conditions *conditions;
22230 +    time_t expiryTime = 0;
22231 +
22232 +    if (m_assertion == NULL)
22233 +        return 0;
22234 +
22235 +    conditions = m_assertion->getConditions();
22236 +
22237 +    if (conditions != NULL && conditions->getNotOnOrAfter() != NULL)
22238 +        expiryTime = conditions->getNotOnOrAfter()->getEpoch();
22239 +
22240 +    return expiryTime;
22241 +}
22242 +
22243 +OM_uint32
22244 +gss_eap_saml_assertion_provider::mapException(OM_uint32 *minor,
22245 +                                              std::exception &e) const
22246 +{
22247 +    if (typeid(e) == typeid(SecurityPolicyException))
22248 +        *minor = GSSEAP_SAML_SEC_POLICY_FAILURE;
22249 +    else if (typeid(e) == typeid(BindingException))
22250 +        *minor = GSSEAP_SAML_BINDING_FAILURE;
22251 +    else if (typeid(e) == typeid(ProfileException))
22252 +        *minor = GSSEAP_SAML_PROFILE_FAILURE;
22253 +    else if (typeid(e) == typeid(FatalProfileException))
22254 +        *minor = GSSEAP_SAML_FATAL_PROFILE_FAILURE;
22255 +    else if (typeid(e) == typeid(RetryableProfileException))
22256 +        *minor = GSSEAP_SAML_RETRY_PROFILE_FAILURE;
22257 +    else if (typeid(e) == typeid(MetadataException))
22258 +        *minor = GSSEAP_SAML_METADATA_FAILURE;
22259 +    else
22260 +        return GSS_S_CONTINUE_NEEDED;
22261 +
22262 +    gssEapSaveStatusInfo(*minor, "%s", e.what());
22263 +
22264 +    return GSS_S_FAILURE;
22265 +}
22266 +
22267 +bool
22268 +gss_eap_saml_assertion_provider::getAttribute(const gss_buffer_t attr,
22269 +                                              int *authenticated,
22270 +                                              int *complete,
22271 +                                              gss_buffer_t value,
22272 +                                              gss_buffer_t display_value GSSEAP_UNUSED,
22273 +                                              int *more) const
22274 +{
22275 +    string str;
22276 +
22277 +    if (attr != GSS_C_NO_BUFFER && attr->length != 0)
22278 +        return false;
22279 +
22280 +    if (m_assertion == NULL)
22281 +        return false;
22282 +
22283 +    if (*more != -1)
22284 +        return false;
22285 +
22286 +    if (authenticated != NULL)
22287 +        *authenticated = m_authenticated;
22288 +    if (complete != NULL)
22289 +        *complete = true;
22290 +
22291 +    XMLHelper::serialize(m_assertion->marshall((DOMDocument *)NULL), str);
22292 +
22293 +    if (value != NULL)
22294 +        duplicateBuffer(str, value);
22295 +    if (display_value != NULL)
22296 +        duplicateBuffer(str, display_value);
22297 +
22298 +    *more = 0;
22299 +
22300 +    return true;
22301 +}
22302 +
22303 +gss_any_t
22304 +gss_eap_saml_assertion_provider::mapToAny(int authenticated,
22305 +                                          gss_buffer_t type_id GSSEAP_UNUSED) const
22306 +{
22307 +    if (authenticated && !m_authenticated)
22308 +        return (gss_any_t)NULL;
22309 +
22310 +    return (gss_any_t)m_assertion;
22311 +}
22312 +
22313 +void
22314 +gss_eap_saml_assertion_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED,
22315 +                                                       gss_any_t input) const
22316 +{
22317 +    delete ((saml2::Assertion *)input);
22318 +}
22319 +
22320 +const char *
22321 +gss_eap_saml_assertion_provider::prefix(void) const
22322 +{
22323 +    return "urn:ietf:params:gss-eap:saml-aaa-assertion";
22324 +}
22325 +
22326 +bool
22327 +gss_eap_saml_assertion_provider::init(void)
22328 +{
22329 +    bool ret = false;
22330 +
22331 +    try {
22332 +        ret = SAMLConfig::getConfig().init();
22333 +    } catch (exception &e) {
22334 +    }
22335 +
22336 +    if (ret)
22337 +        gss_eap_attr_ctx::registerProvider(ATTR_TYPE_SAML_ASSERTION, createAttrContext);
22338 +
22339 +    return ret;
22340 +}
22341 +
22342 +void
22343 +gss_eap_saml_assertion_provider::finalize(void)
22344 +{
22345 +    gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_SAML_ASSERTION);
22346 +}
22347 +
22348 +gss_eap_attr_provider *
22349 +gss_eap_saml_assertion_provider::createAttrContext(void)
22350 +{
22351 +    return new gss_eap_saml_assertion_provider;
22352 +}
22353 +
22354 +saml2::Assertion *
22355 +gss_eap_saml_assertion_provider::initAssertion(void)
22356 +{
22357 +    delete m_assertion;
22358 +    m_assertion = saml2::AssertionBuilder::buildAssertion();
22359 +    m_authenticated = false;
22360 +
22361 +    return m_assertion;
22362 +}
22363 +
22364 +/*
22365 + * gss_eap_saml_attr_provider is for retrieving the underlying attributes.
22366 + */
22367 +bool
22368 +gss_eap_saml_attr_provider::getAssertion(int *authenticated,
22369 +                                         saml2::Assertion **pAssertion,
22370 +                                         bool createIfAbsent) const
22371 +{
22372 +    gss_eap_saml_assertion_provider *saml;
22373 +
22374 +    if (authenticated != NULL)
22375 +        *authenticated = false;
22376 +    if (pAssertion != NULL)
22377 +        *pAssertion = NULL;
22378 +
22379 +    saml = static_cast<gss_eap_saml_assertion_provider *>
22380 +        (m_manager->getProvider(ATTR_TYPE_SAML_ASSERTION));
22381 +    if (saml == NULL)
22382 +        return false;
22383 +
22384 +    if (authenticated != NULL)
22385 +        *authenticated = saml->authenticated();
22386 +    if (pAssertion != NULL)
22387 +        *pAssertion = saml->getAssertion();
22388 +
22389 +    if (saml->getAssertion() == NULL) {
22390 +        if (createIfAbsent) {
22391 +            if (authenticated != NULL)
22392 +                *authenticated = false;
22393 +            if (pAssertion != NULL)
22394 +                *pAssertion = saml->initAssertion();
22395 +        } else
22396 +            return false;
22397 +    }
22398 +
22399 +    return true;
22400 +}
22401 +
22402 +bool
22403 +gss_eap_saml_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
22404 +                                              void *data) const
22405 +{
22406 +    saml2::Assertion *assertion;
22407 +    int authenticated;
22408 +
22409 +    if (!getAssertion(&authenticated, &assertion))
22410 +        return true;
22411 +
22412 +    /*
22413 +     * Note: the first prefix is added by the attribute provider manager
22414 +     *
22415 +     * From draft-hartman-gss-eap-naming-00:
22416 +     *
22417 +     *   Each attribute carried in the assertion SHOULD also be a GSS name
22418 +     *   attribute.  The name of this attribute has three parts, all separated
22419 +     *   by an ASCII space character.  The first part is
22420 +     *   urn:ietf:params:gss-eap:saml-attr.  The second part is the URI for
22421 +     *   the SAML attribute name format.  The final part is the name of the
22422 +     *   SAML attribute.  If the mechanism performs an additional attribute
22423 +     *   query, the retrieved attributes SHOULD be GSS-API name attributes
22424 +     *   using the same name syntax.
22425 +     */
22426 +    /* For each attribute statement, look for an attribute match */
22427 +    const vector <saml2::AttributeStatement *> &statements =
22428 +        const_cast<const saml2::Assertion *>(assertion)->getAttributeStatements();
22429 +
22430 +    for (vector<saml2::AttributeStatement *>::const_iterator s = statements.begin();
22431 +        s != statements.end();
22432 +        ++s) {
22433 +        const vector<saml2::Attribute*> &attrs =
22434 +            const_cast<const saml2::AttributeStatement*>(*s)->getAttributes();
22435 +
22436 +        for (vector<saml2::Attribute*>::const_iterator a = attrs.begin(); a != attrs.end(); ++a) {
22437 +            const XMLCh *attributeName, *attributeNameFormat;
22438 +            XMLCh space[2] = { ' ', 0 };
22439 +            gss_buffer_desc utf8;
22440 +
22441 +            attributeName = (*a)->getName();
22442 +            attributeNameFormat = (*a)->getNameFormat();
22443 +            if (attributeNameFormat == NULL || attributeNameFormat[0] == '\0')
22444 +                attributeNameFormat = saml2::Attribute::UNSPECIFIED;
22445 +
22446 +            XMLCh qualifiedName[XMLString::stringLen(attributeNameFormat) + 1 +
22447 +                                XMLString::stringLen(attributeName) + 1];
22448 +            XMLString::copyString(qualifiedName, attributeNameFormat);
22449 +            XMLString::catString(qualifiedName, space);
22450 +            XMLString::catString(qualifiedName, attributeName);
22451 +
22452 +            utf8.value = (void *)toUTF8(qualifiedName);
22453 +            utf8.length = strlen((char *)utf8.value);
22454 +
22455 +            if (!addAttribute(m_manager, this, &utf8, data))
22456 +                return false;
22457 +        }
22458 +    }
22459 +
22460 +    return true;
22461 +}
22462 +
22463 +static BaseRefVectorOf<XMLCh> *
22464 +decomposeAttributeName(const gss_buffer_t attr)
22465 +{
22466 +    BaseRefVectorOf<XMLCh> *components;
22467 +    string str((const char *)attr->value, attr->length);
22468 +    auto_ptr_XMLCh qualifiedAttr(str.c_str());
22469 +
22470 +    components = XMLString::tokenizeString(qualifiedAttr.get());
22471 +
22472 +    if (components->size() != 2) {
22473 +        delete components;
22474 +        components = NULL;
22475 +    }
22476 +
22477 +    return components;
22478 +}
22479 +
22480 +bool
22481 +gss_eap_saml_attr_provider::setAttribute(int complete GSSEAP_UNUSED,
22482 +                                         const gss_buffer_t attr,
22483 +                                         const gss_buffer_t value)
22484 +{
22485 +    saml2::Assertion *assertion;
22486 +    saml2::Attribute *attribute;
22487 +    saml2::AttributeValue *attributeValue;
22488 +    saml2::AttributeStatement *attributeStatement;
22489 +
22490 +    if (!getAssertion(NULL, &assertion, true))
22491 +        return false;
22492 +
22493 +    if (assertion->getAttributeStatements().size() != 0) {
22494 +        attributeStatement = assertion->getAttributeStatements().front();
22495 +    } else {
22496 +        attributeStatement = saml2::AttributeStatementBuilder::buildAttributeStatement();
22497 +        assertion->getAttributeStatements().push_back(attributeStatement);
22498 +    }
22499 +
22500 +    /* Check the attribute name consists of name format | whsp | name */
22501 +    BaseRefVectorOf<XMLCh> *components = decomposeAttributeName(attr);
22502 +    if (components == NULL)
22503 +        return false;
22504 +
22505 +    attribute = saml2::AttributeBuilder::buildAttribute();
22506 +    attribute->setNameFormat(components->elementAt(0));
22507 +    attribute->setName(components->elementAt(1));
22508 +
22509 +    attributeValue = saml2::AttributeValueBuilder::buildAttributeValue();
22510 +    auto_ptr_XMLCh unistr((char *)value->value, value->length);
22511 +    attributeValue->setTextContent(unistr.get());
22512 +
22513 +    attribute->getAttributeValues().push_back(attributeValue);
22514 +
22515 +    GSSEAP_ASSERT(attributeStatement != NULL);
22516 +    attributeStatement->getAttributes().push_back(attribute);
22517 +
22518 +    delete components;
22519 +
22520 +    return true;
22521 +}
22522 +
22523 +bool
22524 +gss_eap_saml_attr_provider::deleteAttribute(const gss_buffer_t attr)
22525 +{
22526 +    saml2::Assertion *assertion;
22527 +    bool ret = false;
22528 +
22529 +    if (!getAssertion(NULL, &assertion) ||
22530 +        assertion->getAttributeStatements().size() == 0)
22531 +        return false;
22532 +
22533 +    /* Check the attribute name consists of name format | whsp | name */
22534 +    BaseRefVectorOf<XMLCh> *components = decomposeAttributeName(attr);
22535 +    if (components == NULL)
22536 +        return false;
22537 +
22538 +    /* For each attribute statement, look for an attribute match */
22539 +    const vector<saml2::AttributeStatement *> &statements =
22540 +        const_cast<const saml2::Assertion *>(assertion)->getAttributeStatements();
22541 +
22542 +    for (vector<saml2::AttributeStatement *>::const_iterator s = statements.begin();
22543 +        s != statements.end();
22544 +        ++s) {
22545 +        const vector<saml2::Attribute *> &attrs =
22546 +            const_cast<const saml2::AttributeStatement *>(*s)->getAttributes();
22547 +        ssize_t index = -1, i = 0;
22548 +
22549 +        /* There's got to be an easier way to do this */
22550 +        for (vector<saml2::Attribute *>::const_iterator a = attrs.begin();
22551 +             a != attrs.end();
22552 +             ++a) {
22553 +            if (XMLString::equals((*a)->getNameFormat(), components->elementAt(0)) &&
22554 +                XMLString::equals((*a)->getName(), components->elementAt(1))) {
22555 +                index = i;
22556 +                break;
22557 +            }
22558 +            ++i;
22559 +        }
22560 +        if (index != -1) {
22561 +            (*s)->getAttributes().erase((*s)->getAttributes().begin() + index);
22562 +            ret = true;
22563 +        }
22564 +    }
22565 +
22566 +    delete components;
22567 +
22568 +    return ret;
22569 +}
22570 +
22571 +bool
22572 +gss_eap_saml_attr_provider::getAttribute(const gss_buffer_t attr,
22573 +                                         int *authenticated,
22574 +                                         int *complete,
22575 +                                         const saml2::Attribute **pAttribute) const
22576 +{
22577 +    saml2::Assertion *assertion;
22578 +
22579 +    if (authenticated != NULL)
22580 +        *authenticated = false;
22581 +    if (complete != NULL)
22582 +        *complete = true;
22583 +    *pAttribute = NULL;
22584 +
22585 +    if (!getAssertion(authenticated, &assertion) ||
22586 +        assertion->getAttributeStatements().size() == 0)
22587 +        return false;
22588 +
22589 +    /* Check the attribute name consists of name format | whsp | name */
22590 +    BaseRefVectorOf<XMLCh> *components = decomposeAttributeName(attr);
22591 +    if (components == NULL)
22592 +        return false;
22593 +
22594 +    /* For each attribute statement, look for an attribute match */
22595 +    const vector <saml2::AttributeStatement *> &statements =
22596 +        const_cast<const saml2::Assertion *>(assertion)->getAttributeStatements();
22597 +    const saml2::Attribute *ret = NULL;
22598 +
22599 +    for (vector<saml2::AttributeStatement *>::const_iterator s = statements.begin();
22600 +        s != statements.end();
22601 +        ++s) {
22602 +        const vector<saml2::Attribute *> &attrs =
22603 +            const_cast<const saml2::AttributeStatement*>(*s)->getAttributes();
22604 +
22605 +        for (vector<saml2::Attribute *>::const_iterator a = attrs.begin(); a != attrs.end(); ++a) {
22606 +            const XMLCh *attributeName, *attributeNameFormat;
22607 +
22608 +            attributeName = (*a)->getName();
22609 +            attributeNameFormat = (*a)->getNameFormat();
22610 +            if (attributeNameFormat == NULL || attributeNameFormat[0] == '\0')
22611 +                attributeNameFormat = saml2::Attribute::UNSPECIFIED;
22612 +
22613 +            if (XMLString::equals(attributeNameFormat, components->elementAt(0)) &&
22614 +                XMLString::equals(attributeName, components->elementAt(1))) {
22615 +                ret = *a;
22616 +                break;
22617 +            }
22618 +        }
22619 +
22620 +        if (ret != NULL)
22621 +            break;
22622 +    }
22623 +
22624 +    delete components;
22625 +
22626 +    *pAttribute = ret;
22627 +
22628 +    return (ret != NULL);
22629 +}
22630 +
22631 +static bool
22632 +isBase64EncodedAttributeValueP(const saml2::AttributeValue *av)
22633 +{
22634 +    const xmltooling::QName *type = av->getSchemaType();
22635 +
22636 +    if (type == NULL)
22637 +        return false;
22638 +
22639 +    if (!type->hasNamespaceURI() ||
22640 +        !XMLString::equals(type->getNamespaceURI(), xmlconstants::XSD_NS))
22641 +        return false;
22642 +
22643 +    if (!type->hasLocalPart() ||
22644 +        !XMLString::equals(type->getLocalPart(), base64Binary))
22645 +        return false;
22646 +
22647 +    return true;
22648 +}
22649 +
22650 +bool
22651 +gss_eap_saml_attr_provider::getAttribute(const gss_buffer_t attr,
22652 +                                         int *authenticated,
22653 +                                         int *complete,
22654 +                                         gss_buffer_t value,
22655 +                                         gss_buffer_t display_value,
22656 +                                         int *more) const
22657 +{
22658 +    const saml2::Attribute *a;
22659 +    const saml2::AttributeValue *av;
22660 +    int nvalues, i = *more;
22661 +
22662 +    *more = 0;
22663 +
22664 +    if (!getAttribute(attr, authenticated, complete, &a))
22665 +        return false;
22666 +
22667 +    nvalues = a->getAttributeValues().size();
22668 +
22669 +    if (i == -1)
22670 +        i = 0;
22671 +    if (i >= nvalues)
22672 +        return false;
22673 +#ifdef __APPLE__
22674 +    av = (const saml2::AttributeValue *)((void *)(a->getAttributeValues().at(i)));
22675 +#else
22676 +    av = dynamic_cast<const saml2::AttributeValue *>(a->getAttributeValues().at(i));
22677 +#endif
22678 +    if (av != NULL) {
22679 +        bool base64Encoded = isBase64EncodedAttributeValueP(av);
22680 +
22681 +        if (value != NULL) {
22682 +            char *stringValue = toUTF8(av->getTextContent(), true);
22683 +            size_t stringValueLen = strlen(stringValue);
22684 +
22685 +            if (base64Encoded) {
22686 +                ssize_t octetLen;
22687 +
22688 +                value->value = GSSEAP_MALLOC(stringValueLen);
22689 +                if (value->value == NULL) {
22690 +                    GSSEAP_FREE(stringValue);
22691 +                    throw new std::bad_alloc;
22692 +                }
22693 +
22694 +                octetLen = base64Decode(stringValue, value->value);
22695 +                if (octetLen < 0) {
22696 +                    GSSEAP_FREE(value->value);
22697 +                    GSSEAP_FREE(stringValue);
22698 +                    value->value = NULL;
22699 +                    return false;
22700 +                }
22701 +                value->length = octetLen;
22702 +                GSSEAP_FREE(stringValue);
22703 +            } else {
22704 +                value->value = stringValue;
22705 +                value->length = stringValueLen;
22706 +            }
22707 +        }
22708 +        if (display_value != NULL && base64Encoded == false) {
22709 +            display_value->value = toUTF8(av->getTextContent(), true);
22710 +            display_value->length = strlen((char *)value->value);
22711 +        }
22712 +    }
22713 +
22714 +    if (nvalues > ++i)
22715 +        *more = i;
22716 +
22717 +    return true;
22718 +}
22719 +
22720 +gss_any_t
22721 +gss_eap_saml_attr_provider::mapToAny(int authenticated GSSEAP_UNUSED,
22722 +                                     gss_buffer_t type_id GSSEAP_UNUSED) const
22723 +{
22724 +    return (gss_any_t)NULL;
22725 +}
22726 +
22727 +void
22728 +gss_eap_saml_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED,
22729 +                                                  gss_any_t input GSSEAP_UNUSED) const
22730 +{
22731 +}
22732 +
22733 +const char *
22734 +gss_eap_saml_attr_provider::prefix(void) const
22735 +{
22736 +    return "urn:ietf:params:gss-eap:saml-attr";
22737 +}
22738 +
22739 +bool
22740 +gss_eap_saml_attr_provider::init(void)
22741 +{
22742 +    gss_eap_attr_ctx::registerProvider(ATTR_TYPE_SAML, createAttrContext);
22743 +    return true;
22744 +}
22745 +
22746 +void
22747 +gss_eap_saml_attr_provider::finalize(void)
22748 +{
22749 +    gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_SAML);
22750 +}
22751 +
22752 +gss_eap_attr_provider *
22753 +gss_eap_saml_attr_provider::createAttrContext(void)
22754 +{
22755 +    return new gss_eap_saml_attr_provider;
22756 +}
22757 +
22758 +OM_uint32
22759 +gssEapSamlAttrProvidersInit(OM_uint32 *minor)
22760 +{
22761 +    if (!gss_eap_saml_assertion_provider::init() ||
22762 +        !gss_eap_saml_attr_provider::init()) {
22763 +        *minor = GSSEAP_SAML_INIT_FAILURE;
22764 +        return GSS_S_FAILURE;
22765 +    }
22766 +
22767 +    return GSS_S_COMPLETE;
22768 +}
22769 +
22770 +OM_uint32
22771 +gssEapSamlAttrProvidersFinalize(OM_uint32 *minor)
22772 +{
22773 +    gss_eap_saml_attr_provider::finalize();
22774 +    gss_eap_saml_assertion_provider::finalize();
22775 +
22776 +    *minor = 0;
22777 +    return GSS_S_COMPLETE;
22778 +}
22779 diff --git a/mech_eap/util_saml.h b/mech_eap/util_saml.h
22780 new file mode 100644
22781 index 0000000..9110ad4
22782 --- /dev/null
22783 +++ b/mech_eap/util_saml.h
22784 @@ -0,0 +1,176 @@
22785 +/*
22786 + * Copyright (c) 2011, JANET(UK)
22787 + * All rights reserved.
22788 + *
22789 + * Redistribution and use in source and binary forms, with or without
22790 + * modification, are permitted provided that the following conditions
22791 + * are met:
22792 + *
22793 + * 1. Redistributions of source code must retain the above copyright
22794 + *    notice, this list of conditions and the following disclaimer.
22795 + *
22796 + * 2. Redistributions in binary form must reproduce the above copyright
22797 + *    notice, this list of conditions and the following disclaimer in the
22798 + *    documentation and/or other materials provided with the distribution.
22799 + *
22800 + * 3. Neither the name of JANET(UK) nor the names of its contributors
22801 + *    may be used to endorse or promote products derived from this software
22802 + *    without specific prior written permission.
22803 + *
22804 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22805 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22806 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22807 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22808 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22809 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22810 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22811 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22812 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22813 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22814 + * SUCH DAMAGE.
22815 + */
22816 +
22817 +/*
22818 + * SAML attribute provider.
22819 + */
22820 +
22821 +#ifndef _UTIL_SAML_H_
22822 +#define _UTIL_SAML_H_ 1
22823 +
22824 +#ifdef __cplusplus
22825 +
22826 +namespace opensaml {
22827 +    namespace saml2 {
22828 +        class Attribute;
22829 +        class Assertion;
22830 +        class NameID;
22831 +    };
22832 +};
22833 +
22834 +struct gss_eap_saml_assertion_provider : gss_eap_attr_provider {
22835 +public:
22836 +    gss_eap_saml_assertion_provider(void);
22837 +    ~gss_eap_saml_assertion_provider(void);
22838 +
22839 +    bool initWithExistingContext(const gss_eap_attr_ctx *source,
22840 +                                 const gss_eap_attr_provider *ctx);
22841 +    bool initWithGssContext(const gss_eap_attr_ctx *source,
22842 +                            const gss_cred_id_t cred,
22843 +                            const gss_ctx_id_t ctx);
22844 +
22845 +    bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const;
22846 +    bool setAttribute(int complete,
22847 +                      const gss_buffer_t attr,
22848 +                      const gss_buffer_t value);
22849 +    bool deleteAttribute(const gss_buffer_t value);
22850 +    bool getAttribute(const gss_buffer_t attr,
22851 +                      int *authenticated,
22852 +                      int *complete,
22853 +                      gss_buffer_t value,
22854 +                      gss_buffer_t display_value,
22855 +                      int *more) const;
22856 +    gss_any_t mapToAny(int authenticated,
22857 +                       gss_buffer_t type_id) const;
22858 +    void releaseAnyNameMapping(gss_buffer_t type_id,
22859 +                               gss_any_t input) const;
22860 +
22861 +    const char *prefix(void) const;
22862 +    const char *name(void) const { return NULL; }
22863 +    bool initWithJsonObject(const gss_eap_attr_ctx *manager GSSEAP_UNUSED,
22864 +                           JSONObject &object GSSEAP_UNUSED) {
22865 +        return false;
22866 +    }
22867 +    JSONObject jsonRepresentation(void) const {
22868 +        return JSONObject::null();
22869 +    }
22870 +
22871 +    opensaml::saml2::Assertion *initAssertion(void);
22872 +
22873 +    opensaml::saml2::Assertion *getAssertion(void) const {
22874 +        return m_assertion;
22875 +    }
22876 +    bool authenticated(void) const {
22877 +        return m_authenticated;
22878 +    }
22879 +
22880 +    time_t getExpiryTime(void) const;
22881 +    OM_uint32 mapException(OM_uint32 *minor, std::exception &e) const;
22882 +
22883 +    static bool init(void);
22884 +    static void finalize(void);
22885 +
22886 +    static gss_eap_attr_provider *createAttrContext(void);
22887 +
22888 +private:
22889 +    static opensaml::saml2::Assertion *
22890 +        parseAssertion(const gss_buffer_t buffer);
22891 +
22892 +    void setAssertion(const opensaml::saml2::Assertion *assertion,
22893 +                      bool authenticated = false);
22894 +    void setAssertion(const gss_buffer_t buffer,
22895 +                      bool authenticated = false);
22896 +
22897 +    opensaml::saml2::Assertion *m_assertion;
22898 +    bool m_authenticated;
22899 +};
22900 +
22901 +struct gss_eap_saml_attr_provider : gss_eap_attr_provider {
22902 +public:
22903 +    gss_eap_saml_attr_provider(void) {}
22904 +    ~gss_eap_saml_attr_provider(void) {}
22905 +
22906 +    bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const;
22907 +    bool setAttribute(int complete,
22908 +                      const gss_buffer_t attr,
22909 +                      const gss_buffer_t value);
22910 +    bool deleteAttribute(const gss_buffer_t value);
22911 +    bool getAttribute(const gss_buffer_t attr,
22912 +                      int *authenticated,
22913 +                      int *complete,
22914 +                      gss_buffer_t value,
22915 +                      gss_buffer_t display_value,
22916 +                      int *more) const;
22917 +    gss_any_t mapToAny(int authenticated,
22918 +                       gss_buffer_t type_id) const;
22919 +    void releaseAnyNameMapping(gss_buffer_t type_id,
22920 +                               gss_any_t input) const;
22921 +
22922 +    const char *prefix(void) const;
22923 +    const char *name(void) const {
22924 +        return NULL;
22925 +    }
22926 +    bool initWithJsonObject(const gss_eap_attr_ctx *manager GSSEAP_UNUSED,
22927 +                            JSONObject &object GSSEAP_UNUSED) {
22928 +        return false;
22929 +    }
22930 +    JSONObject jsonRepresentation(void) const {
22931 +        return JSONObject::null();
22932 +    }
22933 +
22934 +    bool getAttribute(const gss_buffer_t attr,
22935 +                      int *authenticated,
22936 +                      int *complete,
22937 +                      const opensaml::saml2::Attribute **pAttribute) const;
22938 +    bool getAssertion(int *authenticated,
22939 +                      opensaml::saml2::Assertion **pAssertion,
22940 +                      bool createIfAbsent = false) const;
22941 +
22942 +    static bool init(void);
22943 +    static void finalize(void);
22944 +
22945 +    static gss_eap_attr_provider *createAttrContext(void);
22946 +
22947 +private:
22948 +};
22949 +
22950 +extern "C" {
22951 +#endif
22952 +
22953 +OM_uint32 gssEapSamlAttrProvidersInit(OM_uint32 *minor);
22954 +OM_uint32 gssEapSamlAttrProvidersFinalize(OM_uint32 *minor);
22955 +
22956 +#ifdef __cplusplus
22957 +}
22958 +#endif
22959 +
22960 +#endif /* _UTIL_SAML_H_ */
22961 diff --git a/mech_eap/util_shib.cpp b/mech_eap/util_shib.cpp
22962 new file mode 100644
22963 index 0000000..f8c702b
22964 --- /dev/null
22965 +++ b/mech_eap/util_shib.cpp
22966 @@ -0,0 +1,555 @@
22967 +/*
22968 + * Copyright (c) 2011, JANET(UK)
22969 + * All rights reserved.
22970 + *
22971 + * Redistribution and use in source and binary forms, with or without
22972 + * modification, are permitted provided that the following conditions
22973 + * are met:
22974 + *
22975 + * 1. Redistributions of source code must retain the above copyright
22976 + *    notice, this list of conditions and the following disclaimer.
22977 + *
22978 + * 2. Redistributions in binary form must reproduce the above copyright
22979 + *    notice, this list of conditions and the following disclaimer in the
22980 + *    documentation and/or other materials provided with the distribution.
22981 + *
22982 + * 3. Neither the name of JANET(UK) nor the names of its contributors
22983 + *    may be used to endorse or promote products derived from this software
22984 + *    without specific prior written permission.
22985 + *
22986 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22987 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22988 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22989 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22990 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22991 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22992 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22993 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22994 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22995 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22996 + * SUCH DAMAGE.
22997 + */
22998 +/*
22999 + * Copyright 2001-2009 Internet2
23000 + *
23001 + * Licensed under the Apache License, Version 2.0 (the "License");
23002 + * you may not use this file except in compliance with the License.
23003 + * You may obtain a copy of the License at
23004 + *
23005 + *     http://www.apache.org/licenses/LICENSE-2.0
23006 + *
23007 + * Unless required by applicable law or agreed to in writing, software
23008 + * distributed under the License is distributed on an "AS IS" BASIS,
23009 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23010 + * See the License for the specific language governing permissions and
23011 + * limitations under the License.
23012 + */
23013 +
23014 +/*
23015 + * Local attribute provider implementation.
23016 + */
23017 +
23018 +#include "gssapiP_eap.h"
23019 +
23020 +#include <xmltooling/XMLObject.h>
23021 +#ifndef HAVE_OPENSAML
23022 +#include <xmltooling/XMLToolingConfig.h>
23023 +#include <xmltooling/util/ParserPool.h>
23024 +#endif
23025 +
23026 +#include <saml/saml2/core/Assertions.h>
23027 +
23028 +#include <shibsp/exceptions.h>
23029 +#include <shibsp/attribute/SimpleAttribute.h>
23030 +#include <shibsp/attribute/BinaryAttribute.h>
23031 +#include <shibsp/attribute/ScopedAttribute.h>
23032 +#include <shibresolver/resolver.h>
23033 +
23034 +#include <sstream>
23035 +
23036 +using namespace shibsp;
23037 +using namespace shibresolver;
23038 +using namespace xmltooling;
23039 +using namespace std;
23040 +#ifdef HAVE_OPENSAML
23041 +using namespace opensaml::saml2md;
23042 +using namespace opensaml;
23043 +#else
23044 +using namespace xercesc;
23045 +#endif
23046 +
23047 +gss_eap_shib_attr_provider::gss_eap_shib_attr_provider(void)
23048 +{
23049 +    m_initialized = false;
23050 +    m_authenticated = false;
23051 +}
23052 +
23053 +gss_eap_shib_attr_provider::~gss_eap_shib_attr_provider(void)
23054 +{
23055 +    for_each(m_attributes.begin(),
23056 +             m_attributes.end(),
23057 +             xmltooling::cleanup<Attribute>())
23058 +        ;
23059 +}
23060 +
23061 +bool
23062 +gss_eap_shib_attr_provider::initWithExistingContext(const gss_eap_attr_ctx *manager,
23063 +                                                    const gss_eap_attr_provider *ctx)
23064 +{
23065 +    const gss_eap_shib_attr_provider *shib;
23066 +
23067 +    if (!gss_eap_attr_provider::initWithExistingContext(manager, ctx)) {
23068 +        return false;
23069 +    }
23070 +
23071 +    m_authenticated = false;
23072 +
23073 +    shib = static_cast<const gss_eap_shib_attr_provider *>(ctx);
23074 +    if (shib != NULL) {
23075 +        m_attributes = duplicateAttributes(shib->getAttributes());
23076 +        m_authenticated = shib->authenticated();
23077 +    }
23078 +
23079 +    m_initialized = true;
23080 +
23081 +    return true;
23082 +}
23083 +
23084 +bool
23085 +gss_eap_shib_attr_provider::initWithGssContext(const gss_eap_attr_ctx *manager,
23086 +                                               const gss_cred_id_t gssCred,
23087 +                                               const gss_ctx_id_t gssCtx)
23088 +{
23089 +    if (!gss_eap_attr_provider::initWithGssContext(manager, gssCred, gssCtx))
23090 +        return false;
23091 +
23092 +    auto_ptr<ShibbolethResolver> resolver(ShibbolethResolver::create());
23093 +
23094 +    /*
23095 +     * For now, leave ApplicationID defaulted.
23096 +     * Later on, we could allow this via config option to the mechanism
23097 +     * or rely on an SPRequest interface to pass in a URI identifying the
23098 +     * acceptor.
23099 +     */
23100 +#if 0
23101 +    gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
23102 +    if (gssCred != GSS_C_NO_CREDENTIAL &&
23103 +        gssEapDisplayName(&minor, gssCred->name, &nameBuf, NULL) == GSS_S_COMPLETE) {
23104 +        resolver->setApplicationID((const char *)nameBuf.value);
23105 +        gss_release_buffer(&minor, &nameBuf);
23106 +    }
23107 +#endif
23108 +
23109 +    gss_buffer_desc mechName = GSS_C_EMPTY_BUFFER;
23110 +    OM_uint32 major, minor;
23111 +
23112 +    major = gssEapExportNameInternal(&minor, gssCtx->initiatorName, &mechName,
23113 +                                     EXPORT_NAME_FLAG_OID |
23114 +                                     EXPORT_NAME_FLAG_COMPOSITE);
23115 +    if (major == GSS_S_COMPLETE) {
23116 +        resolver->addToken(&mechName);
23117 +        gss_release_buffer(&minor, &mechName);
23118 +    }
23119 +
23120 +#ifdef HAVE_OPENSAML
23121 +    const gss_eap_saml_assertion_provider *saml;
23122 +    saml = static_cast<const gss_eap_saml_assertion_provider *>
23123 +        (m_manager->getProvider(ATTR_TYPE_SAML_ASSERTION));
23124 +    if (saml != NULL && saml->getAssertion() != NULL) {
23125 +        resolver->addToken(saml->getAssertion());
23126 +    }
23127 +#else
23128 +    /* If no OpenSAML, parse the XML assertion explicitly */
23129 +    const gss_eap_radius_attr_provider *radius;
23130 +    int authenticated, complete;
23131 +    gss_buffer_desc value = GSS_C_EMPTY_BUFFER;
23132 +
23133 +    radius = static_cast<const gss_eap_radius_attr_provider *>
23134 +        (m_manager->getProvider(ATTR_TYPE_RADIUS));
23135 +    if (radius != NULL &&
23136 +        radius->getFragmentedAttribute(PW_SAML_AAA_ASSERTION,
23137 +                                       VENDORPEC_UKERNA,
23138 +                                       &authenticated, &complete, &value)) {
23139 +        string str((char *)value.value, value.length);
23140 +        istringstream istream(str);
23141 +        DOMDocument *doc = XMLToolingConfig::getConfig().getParser().parse(istream);
23142 +        const XMLObjectBuilder *b = XMLObjectBuilder::getBuilder(doc->getDocumentElement());
23143 +        resolver->addToken(b->buildFromDocument(doc));
23144 +        gss_release_buffer(&minor, &value);
23145 +    }
23146 +#endif /* HAVE_OPENSAML */
23147 +
23148 +    try {
23149 +        resolver->resolve();
23150 +        m_attributes = resolver->getResolvedAttributes();
23151 +        resolver->getResolvedAttributes().clear();
23152 +    } catch (exception &e) {
23153 +        return false;
23154 +    }
23155 +
23156 +    m_authenticated = true;
23157 +    m_initialized = true;
23158 +
23159 +    return true;
23160 +}
23161 +
23162 +ssize_t
23163 +gss_eap_shib_attr_provider::getAttributeIndex(const gss_buffer_t attr) const
23164 +{
23165 +    int i = 0;
23166 +
23167 +    GSSEAP_ASSERT(m_initialized);
23168 +
23169 +    for (vector<Attribute *>::const_iterator a = m_attributes.begin();
23170 +         a != m_attributes.end();
23171 +         ++a)
23172 +    {
23173 +        for (vector<string>::const_iterator s = (*a)->getAliases().begin();
23174 +             s != (*a)->getAliases().end();
23175 +             ++s) {
23176 +            if (attr->length == (*s).length() &&
23177 +                memcmp((*s).c_str(), attr->value, attr->length) == 0) {
23178 +                return i;
23179 +            }
23180 +        }
23181 +    }
23182 +
23183 +    return -1;
23184 +}
23185 +
23186 +bool
23187 +gss_eap_shib_attr_provider::setAttribute(int complete GSSEAP_UNUSED,
23188 +                                         const gss_buffer_t attr,
23189 +                                         const gss_buffer_t value)
23190 +{
23191 +    string attrStr((char *)attr->value, attr->length);
23192 +    vector <string> ids(1, attrStr);
23193 +    BinaryAttribute *a = new BinaryAttribute(ids);
23194 +
23195 +    GSSEAP_ASSERT(m_initialized);
23196 +
23197 +    if (value->length != 0) {
23198 +        string valueStr((char *)value->value, value->length);
23199 +
23200 +        a->getValues().push_back(valueStr);
23201 +    }
23202 +
23203 +    m_attributes.push_back(a);
23204 +    m_authenticated = false;
23205 +
23206 +    return true;
23207 +}
23208 +
23209 +bool
23210 +gss_eap_shib_attr_provider::deleteAttribute(const gss_buffer_t attr)
23211 +{
23212 +    int i;
23213 +
23214 +    GSSEAP_ASSERT(m_initialized);
23215 +
23216 +    i = getAttributeIndex(attr);
23217 +    if (i >= 0)
23218 +        m_attributes.erase(m_attributes.begin() + i);
23219 +
23220 +    m_authenticated = false;
23221 +
23222 +    return true;
23223 +}
23224 +
23225 +bool
23226 +gss_eap_shib_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute,
23227 +                                              void *data) const
23228 +{
23229 +    GSSEAP_ASSERT(m_initialized);
23230 +
23231 +    for (vector<Attribute*>::const_iterator a = m_attributes.begin();
23232 +        a != m_attributes.end();
23233 +        ++a)
23234 +    {
23235 +        gss_buffer_desc attribute;
23236 +
23237 +        attribute.value = (void *)((*a)->getId());
23238 +        attribute.length = strlen((char *)attribute.value);
23239 +
23240 +        if (!addAttribute(m_manager, this, &attribute, data))
23241 +            return false;
23242 +    }
23243 +
23244 +    return true;
23245 +}
23246 +
23247 +const Attribute *
23248 +gss_eap_shib_attr_provider::getAttribute(const gss_buffer_t attr) const
23249 +{
23250 +    const Attribute *ret = NULL;
23251 +
23252 +    GSSEAP_ASSERT(m_initialized);
23253 +
23254 +    for (vector<Attribute *>::const_iterator a = m_attributes.begin();
23255 +         a != m_attributes.end();
23256 +         ++a)
23257 +    {
23258 +        for (vector<string>::const_iterator s = (*a)->getAliases().begin();
23259 +             s != (*a)->getAliases().end();
23260 +             ++s) {
23261 +            if (attr->length == (*s).length() &&
23262 +                memcmp((*s).c_str(), attr->value, attr->length) == 0) {
23263 +                ret = *a;
23264 +                break;
23265 +            }
23266 +        }
23267 +        if (ret != NULL)
23268 +            break;
23269 +    }
23270 +
23271 +    return ret;
23272 +}
23273 +
23274 +bool
23275 +gss_eap_shib_attr_provider::getAttribute(const gss_buffer_t attr,
23276 +                                         int *authenticated,
23277 +                                         int *complete,
23278 +                                         gss_buffer_t value,
23279 +                                         gss_buffer_t display_value,
23280 +                                         int *more) const
23281 +{
23282 +    const Attribute *shibAttr = NULL;
23283 +    const BinaryAttribute *binaryAttr;
23284 +    gss_buffer_desc valueBuf = GSS_C_EMPTY_BUFFER;
23285 +    gss_buffer_desc displayValueBuf = GSS_C_EMPTY_BUFFER;
23286 +    int nvalues, i = *more;
23287 +
23288 +    GSSEAP_ASSERT(m_initialized);
23289 +
23290 +    *more = 0;
23291 +
23292 +    shibAttr = getAttribute(attr);
23293 +    if (shibAttr == NULL)
23294 +        return false;
23295 +
23296 +    nvalues = shibAttr->valueCount();
23297 +
23298 +    if (i == -1)
23299 +        i = 0;
23300 +    if (i >= nvalues)
23301 +        return false;
23302 +
23303 +    binaryAttr = dynamic_cast<const BinaryAttribute *>(shibAttr);
23304 +    if (binaryAttr != NULL) {
23305 +        std::string str = binaryAttr->getValues()[*more];
23306 +
23307 +        valueBuf.value = (void *)str.data();
23308 +        valueBuf.length = str.size();
23309 +    } else {
23310 +        std::string str = shibAttr->getSerializedValues()[*more];
23311 +
23312 +        valueBuf.value = (void *)str.c_str();
23313 +        valueBuf.length = str.length();
23314 +
23315 +        const SimpleAttribute *simpleAttr =
23316 +            dynamic_cast<const SimpleAttribute *>(shibAttr);
23317 +        const ScopedAttribute *scopedAttr =
23318 +            dynamic_cast<const ScopedAttribute *>(shibAttr);
23319 +        if (simpleAttr != NULL || scopedAttr != NULL)
23320 +            displayValueBuf = valueBuf;
23321 +    }
23322 +
23323 +    if (authenticated != NULL)
23324 +        *authenticated = m_authenticated;
23325 +    if (complete != NULL)
23326 +        *complete = true;
23327 +    if (value != NULL)
23328 +        duplicateBuffer(valueBuf, value);
23329 +    if (display_value != NULL)
23330 +        duplicateBuffer(displayValueBuf, display_value);
23331 +    if (nvalues > ++i)
23332 +        *more = i;
23333 +
23334 +    return true;
23335 +}
23336 +
23337 +gss_any_t
23338 +gss_eap_shib_attr_provider::mapToAny(int authenticated,
23339 +                                     gss_buffer_t type_id GSSEAP_UNUSED) const
23340 +{
23341 +    gss_any_t output;
23342 +
23343 +    GSSEAP_ASSERT(m_initialized);
23344 +
23345 +    if (authenticated && !m_authenticated)
23346 +        return (gss_any_t)NULL;
23347 +
23348 +    vector <Attribute *>v = duplicateAttributes(m_attributes);
23349 +
23350 +    output = (gss_any_t)new vector <Attribute *>(v);
23351 +
23352 +    return output;
23353 +}
23354 +
23355 +void
23356 +gss_eap_shib_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id GSSEAP_UNUSED,
23357 +                                                  gss_any_t input) const
23358 +{
23359 +    GSSEAP_ASSERT(m_initialized);
23360 +
23361 +    vector <Attribute *> *v = ((vector <Attribute *> *)input);
23362 +    delete v;
23363 +}
23364 +
23365 +const char *
23366 +gss_eap_shib_attr_provider::prefix(void) const
23367 +{
23368 +    return NULL;
23369 +}
23370 +
23371 +const char *
23372 +gss_eap_shib_attr_provider::name(void) const
23373 +{
23374 +    return "local";
23375 +}
23376 +
23377 +JSONObject
23378 +gss_eap_shib_attr_provider::jsonRepresentation(void) const
23379 +{
23380 +    JSONObject obj;
23381 +
23382 +    if (m_initialized == false)
23383 +        return obj; /* don't export incomplete context */
23384 +
23385 +    JSONObject jattrs = JSONObject::array();
23386 +
23387 +    for (vector<Attribute*>::const_iterator a = m_attributes.begin();
23388 +         a != m_attributes.end(); ++a) {
23389 +        DDF attr = (*a)->marshall();
23390 +        JSONObject jattr = JSONObject::ddf(attr);
23391 +        jattrs.append(jattr);
23392 +    }
23393 +
23394 +    obj.set("attributes", jattrs);
23395 +
23396 +    obj.set("authenticated", m_authenticated);
23397 +
23398 +    return obj;
23399 +}
23400 +
23401 +bool
23402 +gss_eap_shib_attr_provider::initWithJsonObject(const gss_eap_attr_ctx *ctx,
23403 +                                               JSONObject &obj)
23404 +{
23405 +    if (!gss_eap_attr_provider::initWithJsonObject(ctx, obj))
23406 +        return false;
23407 +
23408 +    GSSEAP_ASSERT(m_authenticated == false);
23409 +    GSSEAP_ASSERT(m_attributes.size() == 0);
23410 +
23411 +    JSONObject jattrs = obj["attributes"];
23412 +    size_t nelems = jattrs.size();
23413 +
23414 +    for (size_t i = 0; i < nelems; i++) {
23415 +        JSONObject jattr = jattrs.get(i);
23416 +
23417 +        DDF attr = jattr.ddf();
23418 +        Attribute *attribute = Attribute::unmarshall(attr);
23419 +        m_attributes.push_back(attribute);
23420 +    }
23421 +
23422 +    m_authenticated = obj["authenticated"].integer();
23423 +    m_initialized = true;
23424 +
23425 +    return true;
23426 +}
23427 +
23428 +bool
23429 +gss_eap_shib_attr_provider::init(void)
23430 +{
23431 +    bool ret = false;
23432 +
23433 +    try {
23434 +        ret = ShibbolethResolver::init();
23435 +    } catch (exception &e) {
23436 +    }
23437 +
23438 +    if (ret)
23439 +        gss_eap_attr_ctx::registerProvider(ATTR_TYPE_LOCAL, createAttrContext);
23440 +
23441 +    return ret;
23442 +}
23443 +
23444 +void
23445 +gss_eap_shib_attr_provider::finalize(void)
23446 +{
23447 +    gss_eap_attr_ctx::unregisterProvider(ATTR_TYPE_LOCAL);
23448 +    ShibbolethResolver::term();
23449 +}
23450 +
23451 +OM_uint32
23452 +gss_eap_shib_attr_provider::mapException(OM_uint32 *minor,
23453 +                                         std::exception &e) const
23454 +{
23455 +    if (typeid(e) == typeid(AttributeException))
23456 +        *minor = GSSEAP_SHIB_ATTR_FAILURE;
23457 +    else if (typeid(e) == typeid(AttributeExtractionException))
23458 +        *minor = GSSEAP_SHIB_ATTR_EXTRACT_FAILURE;
23459 +    else if (typeid(e) == typeid(AttributeFilteringException))
23460 +        *minor = GSSEAP_SHIB_ATTR_FILTER_FAILURE;
23461 +    else if (typeid(e) == typeid(AttributeResolutionException))
23462 +        *minor = GSSEAP_SHIB_ATTR_RESOLVE_FAILURE;
23463 +    else if (typeid(e) == typeid(ConfigurationException))
23464 +        *minor = GSSEAP_SHIB_CONFIG_FAILURE;
23465 +    else if (typeid(e) == typeid(ListenerException))
23466 +        *minor = GSSEAP_SHIB_LISTENER_FAILURE;
23467 +    else
23468 +        return GSS_S_CONTINUE_NEEDED;
23469 +
23470 +    gssEapSaveStatusInfo(*minor, "%s", e.what());
23471 +
23472 +    return GSS_S_FAILURE;
23473 +}
23474 +
23475 +gss_eap_attr_provider *
23476 +gss_eap_shib_attr_provider::createAttrContext(void)
23477 +{
23478 +    return new gss_eap_shib_attr_provider;
23479 +}
23480 +
23481 +Attribute *
23482 +gss_eap_shib_attr_provider::duplicateAttribute(const Attribute *src)
23483 +{
23484 +    DDF obj = src->marshall();
23485 +    Attribute *attribute = Attribute::unmarshall(obj);
23486 +    obj.destroy();
23487 +
23488 +    return attribute;
23489 +}
23490 +
23491 +vector <Attribute *>
23492 +gss_eap_shib_attr_provider::duplicateAttributes(const vector <Attribute *>src)
23493 +{
23494 +    vector <Attribute *> dst;
23495 +
23496 +    for (vector<Attribute *>::const_iterator a = src.begin();
23497 +         a != src.end();
23498 +         ++a)
23499 +        dst.push_back(duplicateAttribute(*a));
23500 +
23501 +    return dst;
23502 +}
23503 +
23504 +OM_uint32
23505 +gssEapLocalAttrProviderInit(OM_uint32 *minor)
23506 +{
23507 +    if (!gss_eap_shib_attr_provider::init()) {
23508 +        *minor = GSSEAP_SHIB_INIT_FAILURE;
23509 +        return GSS_S_FAILURE;
23510 +    }
23511 +    return GSS_S_COMPLETE;
23512 +}
23513 +
23514 +OM_uint32
23515 +gssEapLocalAttrProviderFinalize(OM_uint32 *minor)
23516 +{
23517 +    gss_eap_shib_attr_provider::finalize();
23518 +
23519 +    *minor = 0;
23520 +    return GSS_S_COMPLETE;
23521 +}
23522 diff --git a/mech_eap/util_shib.h b/mech_eap/util_shib.h
23523 new file mode 100644
23524 index 0000000..4cf7481
23525 --- /dev/null
23526 +++ b/mech_eap/util_shib.h
23527 @@ -0,0 +1,122 @@
23528 +/*
23529 + * Copyright (c) 2011, JANET(UK)
23530 + * All rights reserved.
23531 + *
23532 + * Redistribution and use in source and binary forms, with or without
23533 + * modification, are permitted provided that the following conditions
23534 + * are met:
23535 + *
23536 + * 1. Redistributions of source code must retain the above copyright
23537 + *    notice, this list of conditions and the following disclaimer.
23538 + *
23539 + * 2. Redistributions in binary form must reproduce the above copyright
23540 + *    notice, this list of conditions and the following disclaimer in the
23541 + *    documentation and/or other materials provided with the distribution.
23542 + *
23543 + * 3. Neither the name of JANET(UK) nor the names of its contributors
23544 + *    may be used to endorse or promote products derived from this software
23545 + *    without specific prior written permission.
23546 + *
23547 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23548 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23549 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23550 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23551 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23552 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23553 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23554 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23555 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23556 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23557 + * SUCH DAMAGE.
23558 + */
23559 +
23560 +/*
23561 + * Local attribute provider.
23562 + */
23563 +
23564 +#ifndef _UTIL_SHIB_H_
23565 +#define _UTIL_SHIB_H_ 1
23566 +
23567 +#ifdef __cplusplus
23568 +
23569 +#include <vector>
23570 +
23571 +namespace shibsp {
23572 +    class Attribute;
23573 +};
23574 +
23575 +namespace shibresolver {
23576 +    class ShibbolethResolver;
23577 +};
23578 +
23579 +struct gss_eap_shib_attr_provider : gss_eap_attr_provider {
23580 +public:
23581 +    gss_eap_shib_attr_provider(void);
23582 +    ~gss_eap_shib_attr_provider(void);
23583 +
23584 +    bool initWithExistingContext(const gss_eap_attr_ctx *source,
23585 +                                 const gss_eap_attr_provider *ctx);
23586 +    bool initWithGssContext(const gss_eap_attr_ctx *source,
23587 +                            const gss_cred_id_t cred,
23588 +                            const gss_ctx_id_t ctx);
23589 +
23590 +    bool setAttribute(int complete,
23591 +                      const gss_buffer_t attr,
23592 +                      const gss_buffer_t value);
23593 +    bool deleteAttribute(const gss_buffer_t value);
23594 +    bool getAttributeTypes(gss_eap_attr_enumeration_cb, void *data) const;
23595 +    bool getAttribute(const gss_buffer_t attr,
23596 +                      int *authenticated,
23597 +                      int *complete,
23598 +                      gss_buffer_t value,
23599 +                      gss_buffer_t display_value,
23600 +                      int *more) const;
23601 +    gss_any_t mapToAny(int authenticated,
23602 +                       gss_buffer_t type_id) const;
23603 +    void releaseAnyNameMapping(gss_buffer_t type_id,
23604 +                               gss_any_t input) const;
23605 +
23606 +    const char *prefix(void) const;
23607 +    const char *name(void) const;
23608 +    bool initWithJsonObject(const gss_eap_attr_ctx *manager,
23609 +                            JSONObject &obj);
23610 +    JSONObject jsonRepresentation(void) const;
23611 +
23612 +    static bool init(void);
23613 +    static void finalize(void);
23614 +
23615 +    OM_uint32 mapException(OM_uint32 *minor, std::exception &e) const;
23616 +
23617 +    static gss_eap_attr_provider *createAttrContext(void);
23618 +
23619 +    std::vector<shibsp::Attribute *> getAttributes(void) const {
23620 +        return m_attributes;
23621 +    }
23622 +
23623 +private:
23624 +    static shibsp::Attribute *
23625 +        duplicateAttribute(const shibsp::Attribute *src);
23626 +    static std::vector <shibsp::Attribute *>
23627 +        duplicateAttributes(const std::vector <shibsp::Attribute *>src);
23628 +
23629 +    ssize_t getAttributeIndex(const gss_buffer_t attr) const;
23630 +    const shibsp::Attribute *getAttribute(const gss_buffer_t attr) const;
23631 +
23632 +    bool authenticated(void) const { return m_authenticated; }
23633 +
23634 +    bool m_initialized;
23635 +    bool m_authenticated;
23636 +    std::vector<shibsp::Attribute *> m_attributes;
23637 +};
23638 +
23639 +extern "C" {
23640 +#endif
23641 +
23642 +OM_uint32 gssEapLocalAttrProviderInit(OM_uint32 *minor);
23643 +OM_uint32 gssEapLocalAttrProviderFinalize(OM_uint32 *minor);
23644 +
23645 +#ifdef __cplusplus
23646 +}
23647 +#endif
23648 +
23649 +#endif /* _UTIL_SHIB_H_ */
23650 diff --git a/mech_eap/util_sm.c b/mech_eap/util_sm.c
23651 new file mode 100644
23652 index 0000000..56248d8
23653 --- /dev/null
23654 +++ b/mech_eap/util_sm.c
23655 @@ -0,0 +1,372 @@
23656 +/*
23657 + * Copyright (c) 2011, JANET(UK)
23658 + * All rights reserved.
23659 + *
23660 + * Redistribution and use in source and binary forms, with or without
23661 + * modification, are permitted provided that the following conditions
23662 + * are met:
23663 + *
23664 + * 1. Redistributions of source code must retain the above copyright
23665 + *    notice, this list of conditions and the following disclaimer.
23666 + *
23667 + * 2. Redistributions in binary form must reproduce the above copyright
23668 + *    notice, this list of conditions and the following disclaimer in the
23669 + *    documentation and/or other materials provided with the distribution.
23670 + *
23671 + * 3. Neither the name of JANET(UK) nor the names of its contributors
23672 + *    may be used to endorse or promote products derived from this software
23673 + *    without specific prior written permission.
23674 + *
23675 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23676 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23677 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23678 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23679 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23680 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23681 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23682 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23683 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23684 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23685 + * SUCH DAMAGE.
23686 + */
23687 +
23688 +/*
23689 + * Context establishment state machine.
23690 + */
23691 +
23692 +#include "gssapiP_eap.h"
23693 +
23694 +/* private flags */
23695 +#define SM_FLAG_TRANSITED                   0x80000000
23696 +
23697 +#define SM_ASSERT_VALID(ctx, status)        do { \
23698 +        GSSEAP_ASSERT(GSS_ERROR((status)) || \
23699 +               ((status) == GSS_S_CONTINUE_NEEDED && ((ctx)->state > GSSEAP_STATE_INITIAL && (ctx)->state < GSSEAP_STATE_ESTABLISHED)) || \
23700 +               ((status) == GSS_S_COMPLETE && (ctx)->state == GSSEAP_STATE_ESTABLISHED)); \
23701 +    } while (0)
23702 +
23703 +#ifdef GSSEAP_DEBUG
23704 +static const char *
23705 +gssEapStateToString(enum gss_eap_state state)
23706 +{
23707 +    const char *s;
23708 +
23709 +    switch (state) {
23710 +    case GSSEAP_STATE_INITIAL:
23711 +        s = "INITIAL";
23712 +        break;
23713 +    case GSSEAP_STATE_AUTHENTICATE:
23714 +        s = "AUTHENTICATE";
23715 +        break;
23716 +    case GSSEAP_STATE_INITIATOR_EXTS:
23717 +        s = "INITIATOR_EXTS";
23718 +        break;
23719 +    case GSSEAP_STATE_ACCEPTOR_EXTS:
23720 +        s = "ACCEPTOR_EXTS";
23721 +        break;
23722 +#ifdef GSSEAP_ENABLE_REAUTH
23723 +    case GSSEAP_STATE_REAUTHENTICATE:
23724 +        s = "REAUTHENTICATE";
23725 +        break;
23726 +#endif
23727 +    case GSSEAP_STATE_ESTABLISHED:
23728 +        s = "ESTABLISHED";
23729 +        break;
23730 +    default:
23731 +        s = "INVALID";
23732 +        break;
23733 +    }
23734 +
23735 +    return s;
23736 +}
23737 +
23738 +void
23739 +gssEapSmTransition(gss_ctx_id_t ctx, enum gss_eap_state state)
23740 +{
23741 +    GSSEAP_ASSERT(state >= GSSEAP_STATE_INITIAL);
23742 +    GSSEAP_ASSERT(state <= GSSEAP_STATE_ESTABLISHED);
23743 +
23744 +    fprintf(stderr, "GSS-EAP: state transition %s->%s\n",
23745 +            gssEapStateToString(GSSEAP_SM_STATE(ctx)),
23746 +            gssEapStateToString(state));
23747 +
23748 +    ctx->state = state;
23749 +}
23750 +#endif /* GSSEAP_DEBUG */
23751 +
23752 +static OM_uint32
23753 +makeErrorToken(OM_uint32 *minor,
23754 +               OM_uint32 majorStatus,
23755 +               OM_uint32 minorStatus,
23756 +               struct gss_eap_token_buffer_set *token)
23757 +{
23758 +    OM_uint32 major, tmpMinor;
23759 +    unsigned char errorData[8];
23760 +    gss_buffer_desc errorBuffer;
23761 +
23762 +    GSSEAP_ASSERT(GSS_ERROR(majorStatus));
23763 +
23764 +    /*
23765 +     * Only return error codes that the initiator could have caused,
23766 +     * to avoid information leakage.
23767 +     */
23768 +    if (IS_RADIUS_ERROR(minorStatus)) {
23769 +        /* Squash RADIUS error codes */
23770 +        minorStatus = GSSEAP_RADIUS_PROT_FAILURE;
23771 +    } else if (!IS_WIRE_ERROR(minorStatus)) {
23772 +        /* Don't return non-wire error codes */
23773 +        return GSS_S_COMPLETE;
23774 +    }
23775 +
23776 +    minorStatus -= ERROR_TABLE_BASE_eapg;
23777 +
23778 +    store_uint32_be(majorStatus, &errorData[0]);
23779 +    store_uint32_be(minorStatus, &errorData[4]);
23780 +
23781 +    major = gssEapAllocInnerTokens(&tmpMinor, 1, token);
23782 +    if (GSS_ERROR(major)) {
23783 +        *minor = tmpMinor;
23784 +        return major;
23785 +    }
23786 +
23787 +    errorBuffer.length = sizeof(errorData);
23788 +    errorBuffer.value = errorData;
23789 +
23790 +    major = duplicateBuffer(&tmpMinor, &errorBuffer, &token->buffers.elements[0]);
23791 +    if (GSS_ERROR(major)) {
23792 +        gssEapReleaseInnerTokens(&tmpMinor, token, 1);
23793 +        *minor = tmpMinor;
23794 +        return major;
23795 +    }
23796 +
23797 +    token->buffers.count = 1;
23798 +    token->types[0] = ITOK_TYPE_CONTEXT_ERR | ITOK_FLAG_CRITICAL;
23799 +
23800 +    *minor = 0;
23801 +    return GSS_S_COMPLETE;
23802 +}
23803 +
23804 +OM_uint32
23805 +gssEapSmStep(OM_uint32 *minor,
23806 +             gss_cred_id_t cred,
23807 +             gss_ctx_id_t ctx,
23808 +             gss_name_t target,
23809 +             gss_OID mech,
23810 +             OM_uint32 reqFlags,
23811 +             OM_uint32 timeReq,
23812 +             gss_channel_bindings_t chanBindings,
23813 +             gss_buffer_t inputToken,
23814 +             gss_buffer_t outputToken,
23815 +             struct gss_eap_sm *sm, /* ordered by state */
23816 +             size_t smCount)
23817 +{
23818 +    OM_uint32 major, tmpMajor, tmpMinor;
23819 +    struct gss_eap_token_buffer_set inputTokens = { { 0, GSS_C_NO_BUFFER }, NULL };
23820 +    struct gss_eap_token_buffer_set outputTokens = { { 0, GSS_C_NO_BUFFER }, NULL };
23821 +    gss_buffer_desc unwrappedInputToken = GSS_C_EMPTY_BUFFER;
23822 +    gss_buffer_desc unwrappedOutputToken = GSS_C_EMPTY_BUFFER;
23823 +    unsigned int smFlags = 0;
23824 +    size_t i, j;
23825 +    int initialContextToken = 0;
23826 +    enum gss_eap_token_type tokType;
23827 +
23828 +    GSSEAP_ASSERT(smCount > 0);
23829 +
23830 +    *minor = 0;
23831 +
23832 +    outputToken->length = 0;
23833 +    outputToken->value = NULL;
23834 +
23835 +    if (inputToken != GSS_C_NO_BUFFER && inputToken->length != 0) {
23836 +        major = gssEapVerifyToken(minor, ctx, inputToken, &tokType,
23837 +                                  &unwrappedInputToken);
23838 +        if (GSS_ERROR(major))
23839 +            goto cleanup;
23840 +
23841 +        if (tokType != (CTX_IS_INITIATOR(ctx)
23842 +                    ? TOK_TYPE_ACCEPTOR_CONTEXT : TOK_TYPE_INITIATOR_CONTEXT)) {
23843 +            major = GSS_S_DEFECTIVE_TOKEN;
23844 +            *minor = GSSEAP_WRONG_TOK_ID;
23845 +            goto cleanup;
23846 +        }
23847 +    } else if (!CTX_IS_INITIATOR(ctx) || ctx->state != GSSEAP_STATE_INITIAL) {
23848 +        major = GSS_S_DEFECTIVE_TOKEN;
23849 +        *minor = GSSEAP_WRONG_SIZE;
23850 +        goto cleanup;
23851 +    } else {
23852 +        initialContextToken = 1;
23853 +    }
23854 +
23855 +    if (CTX_IS_ESTABLISHED(ctx)) {
23856 +        major = GSS_S_BAD_STATUS;
23857 +        *minor = GSSEAP_CONTEXT_ESTABLISHED;
23858 +        goto cleanup;
23859 +    }
23860 +
23861 +    GSSEAP_ASSERT(ctx->state < GSSEAP_STATE_ESTABLISHED);
23862 +
23863 +    major = gssEapDecodeInnerTokens(minor, &unwrappedInputToken, &inputTokens);
23864 +    if (GSS_ERROR(major))
23865 +        goto cleanup;
23866 +
23867 +    major = gssEapAllocInnerTokens(minor, smCount, &outputTokens);
23868 +    if (GSS_ERROR(major))
23869 +        goto cleanup;
23870 +
23871 +    ctx->inputTokens = &inputTokens;
23872 +    ctx->outputTokens = &outputTokens;
23873 +
23874 +    /* Process all the tokens that are valid for the current state. */
23875 +    for (i = 0; i < smCount; i++) {
23876 +        struct gss_eap_sm *smp = &sm[i];
23877 +        int processToken = 0;
23878 +        gss_buffer_t innerInputToken = GSS_C_NO_BUFFER;
23879 +        OM_uint32 *inputTokenType = NULL;
23880 +        gss_buffer_desc innerOutputToken = GSS_C_EMPTY_BUFFER;
23881 +
23882 +        if ((smp->validStates & ctx->state) == 0)
23883 +            continue;
23884 +
23885 +        /*
23886 +         * We special case the first call to gss_init_sec_context so that
23887 +         * all token providers have the opportunity to generate an initial
23888 +         * context token. Providers where inputTokenType is ITOK_TYPE_NONE
23889 +         * are always called and generally act on state transition boundaries,
23890 +         * for example to advance the state after a series of optional tokens
23891 +         * (as is the case with the extension token exchange) or to generate
23892 +         * a new token after the state was advanced by a provider which did
23893 +         * not emit a token.
23894 +         */
23895 +        if (smp->inputTokenType == ITOK_TYPE_NONE || initialContextToken) {
23896 +            processToken = 1;
23897 +        } else if ((smFlags & SM_FLAG_TRANSITED) == 0) {
23898 +            /* Don't regurgitate a token which belonds to a previous state. */
23899 +            for (j = 0; j < inputTokens.buffers.count; j++) {
23900 +                if ((inputTokens.types[j] & ITOK_TYPE_MASK) == smp->inputTokenType) {
23901 +                    if (processToken) {
23902 +                        /* Check for duplicate inner tokens */
23903 +                        major = GSS_S_DEFECTIVE_TOKEN;
23904 +                        *minor = GSSEAP_DUPLICATE_ITOK;
23905 +                        break;
23906 +                    }
23907 +                    processToken = 1;
23908 +                    innerInputToken = &inputTokens.buffers.elements[j];
23909 +                    inputTokenType = &inputTokens.types[j];
23910 +                }
23911 +            }
23912 +            if (GSS_ERROR(major))
23913 +                break;
23914 +        }
23915 +
23916 +        if (processToken) {
23917 +            enum gss_eap_state oldState = ctx->state;
23918 +
23919 +            smFlags = 0;
23920 +            if (inputTokenType != NULL && (*inputTokenType & ITOK_FLAG_CRITICAL))
23921 +                smFlags |= SM_FLAG_INPUT_TOKEN_CRITICAL;
23922 +
23923 +            major = smp->processToken(minor, cred, ctx, target, mech, reqFlags,
23924 +                                      timeReq, chanBindings, innerInputToken,
23925 +                                      &innerOutputToken, &smFlags);
23926 +            if (GSS_ERROR(major))
23927 +                break;
23928 +
23929 +            if (inputTokenType != NULL)
23930 +                *inputTokenType |= ITOK_FLAG_VERIFIED;
23931 +            if (ctx->state < oldState)
23932 +                i = 0; /* restart */
23933 +            else if (ctx->state != oldState)
23934 +                smFlags |= SM_FLAG_TRANSITED;
23935 +
23936 +            if (innerOutputToken.value != NULL) {
23937 +                outputTokens.buffers.elements[outputTokens.buffers.count] = innerOutputToken;
23938 +                GSSEAP_ASSERT(smp->outputTokenType != ITOK_TYPE_NONE);
23939 +                outputTokens.types[outputTokens.buffers.count] = smp->outputTokenType;
23940 +                if (smFlags & SM_FLAG_OUTPUT_TOKEN_CRITICAL)
23941 +                    outputTokens.types[outputTokens.buffers.count] |= ITOK_FLAG_CRITICAL;
23942 +                outputTokens.buffers.count++;
23943 +            }
23944 +            /*
23945 +             * Break out if we made a state transition and have some tokens to send.
23946 +             */
23947 +            if ((smFlags & SM_FLAG_TRANSITED) &&
23948 +                 ((smFlags & SM_FLAG_FORCE_SEND_TOKEN) || outputTokens.buffers.count != 0)) {
23949 +                SM_ASSERT_VALID(ctx, major);
23950 +                break;
23951 +            }
23952 +        } else if ((smp->itokFlags & SM_ITOK_FLAG_REQUIRED) &&
23953 +            smp->inputTokenType != ITOK_TYPE_NONE) {
23954 +            /* Check for required inner tokens */
23955 +            major = GSS_S_DEFECTIVE_TOKEN;
23956 +            *minor = GSSEAP_MISSING_REQUIRED_ITOK;
23957 +            break;
23958 +        }
23959 +    }
23960 +
23961 +    GSSEAP_ASSERT(outputTokens.buffers.count <= smCount);
23962 +
23963 +    /* Check we understood all critical tokens sent by peer */
23964 +    if (!GSS_ERROR(major)) {
23965 +        for (j = 0; j < inputTokens.buffers.count; j++) {
23966 +            if ((inputTokens.types[j] & ITOK_FLAG_CRITICAL) &&
23967 +                (inputTokens.types[j] & ITOK_FLAG_VERIFIED) == 0) {
23968 +                major = GSS_S_UNAVAILABLE;
23969 +                *minor = GSSEAP_CRIT_ITOK_UNAVAILABLE;
23970 +                goto cleanup;
23971 +            }
23972 +        }
23973 +    }
23974 +
23975 +    /* Optionaly emit an error token if we are the acceptor */
23976 +    if (GSS_ERROR(major)) {
23977 +        if (CTX_IS_INITIATOR(ctx))
23978 +            goto cleanup; /* return error directly to caller */
23979 +
23980 +        /* replace any emitted tokens with error token */
23981 +        gssEapReleaseInnerTokens(&tmpMinor, &outputTokens, 1);
23982 +
23983 +        tmpMajor = makeErrorToken(&tmpMinor, major, *minor, &outputTokens);
23984 +        if (GSS_ERROR(tmpMajor)) {
23985 +            major = tmpMajor;
23986 +            *minor = tmpMinor;
23987 +            goto cleanup;
23988 +        }
23989 +    }
23990 +
23991 +    /* Format output token from inner tokens */
23992 +    if (outputTokens.buffers.count != 0 ||            /* inner tokens to send */
23993 +        !CTX_IS_INITIATOR(ctx) ||                   /* any leg acceptor */
23994 +        !CTX_IS_ESTABLISHED(ctx)) {                 /* non-last leg initiator */
23995 +        tmpMajor = gssEapEncodeInnerTokens(&tmpMinor, &outputTokens, &unwrappedOutputToken);
23996 +        if (tmpMajor == GSS_S_COMPLETE) {
23997 +            if (CTX_IS_INITIATOR(ctx))
23998 +                tokType = TOK_TYPE_INITIATOR_CONTEXT;
23999 +            else
24000 +                tokType = TOK_TYPE_ACCEPTOR_CONTEXT;
24001 +
24002 +            tmpMajor = gssEapMakeToken(&tmpMinor, ctx, &unwrappedOutputToken,
24003 +                                       tokType, outputToken);
24004 +            if (GSS_ERROR(tmpMajor)) {
24005 +                major = tmpMajor;
24006 +                *minor = tmpMinor;
24007 +                goto cleanup;
24008 +            }
24009 +        }
24010 +    }
24011 +
24012 +    /* If the context is established, empty tokens only to be emitted by initiator */
24013 +    GSSEAP_ASSERT(!CTX_IS_ESTABLISHED(ctx) || ((outputToken->length == 0) == CTX_IS_INITIATOR(ctx)));
24014 +
24015 +    SM_ASSERT_VALID(ctx, major);
24016 +
24017 +cleanup:
24018 +    gssEapReleaseInnerTokens(&tmpMinor, &inputTokens, 0);
24019 +    gssEapReleaseInnerTokens(&tmpMinor, &inputTokens, 1);
24020 +
24021 +    gss_release_buffer(&tmpMinor, &unwrappedOutputToken);
24022 +
24023 +    ctx->inputTokens = NULL;
24024 +    ctx->outputTokens = NULL;
24025 +
24026 +    return major;
24027 +}
24028 diff --git a/mech_eap/util_tld.c b/mech_eap/util_tld.c
24029 new file mode 100644
24030 index 0000000..05bc3d1
24031 --- /dev/null
24032 +++ b/mech_eap/util_tld.c
24033 @@ -0,0 +1,167 @@
24034 +/*
24035 + * Copyright (c) 2011, JANET(UK)
24036 + * All rights reserved.
24037 + *
24038 + * Redistribution and use in source and binary forms, with or without
24039 + * modification, are permitted provided that the following conditions
24040 + * are met:
24041 + *
24042 + * 1. Redistributions of source code must retain the above copyright
24043 + *    notice, this list of conditions and the following disclaimer.
24044 + *
24045 + * 2. Redistributions in binary form must reproduce the above copyright
24046 + *    notice, this list of conditions and the following disclaimer in the
24047 + *    documentation and/or other materials provided with the distribution.
24048 + *
24049 + * 3. Neither the name of JANET(UK) nor the names of its contributors
24050 + *    may be used to endorse or promote products derived from this software
24051 + *    without specific prior written permission.
24052 + *
24053 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24054 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24055 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24056 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24057 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24058 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24059 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24060 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24061 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24062 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24063 + * SUCH DAMAGE.
24064 + */
24065 +
24066 +/*
24067 + * Thread local data abstraction, using pthreads on Unix and the TlsXXX
24068 + * APIs on Windows.
24069 + */
24070 +
24071 +#include "gssapiP_eap.h"
24072 +
24073 +/* Clean up thread-local data; called on thread detach */
24074 +static void
24075 +destroyThreadLocalData(struct gss_eap_thread_local_data *tld)
24076 +{
24077 +    if (tld->statusInfo != NULL)
24078 +        gssEapDestroyStatusInfo(tld->statusInfo);
24079 +    if (tld->krbContext != NULL)
24080 +        gssEapDestroyKrbContext(tld->krbContext);
24081 +    GSSEAP_FREE(tld);
24082 +}
24083 +
24084 +#ifdef WIN32
24085 +
24086 +/*
24087 + * This is the TLS index returned by TlsAlloc() on process init.
24088 + * Each thread, on thread attach in DllMain(), allocates its thread-local
24089 + * data and uses this index with TlsSetValue() to store it.
24090 + * It can then subsequently be retrieved with TlsGetValue().
24091 + */
24092 +static DWORD tlsIndex = TLS_OUT_OF_INDEXES;
24093 +
24094 +/* Access thread-local data */
24095 +struct gss_eap_thread_local_data *
24096 +gssEapGetThreadLocalData(void)
24097 +{
24098 +    struct gss_eap_thread_local_data *tlsData;
24099 +
24100 +    GSSEAP_ASSERT(tlsIndex != TLS_OUT_OF_INDEXES);
24101 +
24102 +    tlsData = TlsGetValue(tlsIndex);
24103 +    if (tlsData == NULL) {
24104 +        tlsData = GSSEAP_CALLOC(1, sizeof(*tlsData));
24105 +        TlsSetValue(tlsIndex, tlsData);
24106 +    }
24107 +
24108 +    return tlsData;
24109 +}
24110 +
24111 +BOOL WINAPI
24112 +DllMain(HINSTANCE hDLL,     /* DLL module handle */
24113 +        DWORD reason,       /* reason called */
24114 +        LPVOID reserved)    /* reserved */
24115 +{
24116 +    struct gss_eap_thread_local_data *tlsData;
24117 +    OM_uint32 major, minor;
24118 +
24119 +    switch (reason) {
24120 +        case DLL_PROCESS_ATTACH:
24121 +            /* Allocate a TLS index. */
24122 +            major = gssEapInitiatorInit(&minor);
24123 +            if (GSS_ERROR(major))
24124 +                return FALSE;
24125 +
24126 +            tlsIndex = TlsAlloc();
24127 +            if (tlsIndex == TLS_OUT_OF_INDEXES)
24128 +                return FALSE;
24129 +            /* No break: Initialize the index for first thread.*/
24130 +        case DLL_THREAD_ATTACH:
24131 +            /* Initialize the TLS index for this thread. */
24132 +            tlsData = GSSEAP_CALLOC(1, sizeof(*tlsData));
24133 +            if (tlsData == NULL)
24134 +                return FALSE;
24135 +            TlsSetValue(tlsIndex, tlsData);
24136 +            break;
24137 +        case DLL_THREAD_DETACH:
24138 +            /* Release the allocated memory for this thread. */
24139 +            tlsData = TlsGetValue(tlsIndex);
24140 +            if (tlsData != NULL) {
24141 +                destroyThreadLocalData(tlsData);
24142 +                TlsSetValue(tlsIndex, NULL);
24143 +            }
24144 +            break;
24145 +        case DLL_PROCESS_DETACH:
24146 +            /* Release the TLS index. */
24147 +            TlsFree(tlsIndex);
24148 +            gssEapFinalize();
24149 +            break;
24150 +        default:
24151 +            break;
24152 +    }
24153 +
24154 +    return TRUE;
24155 +    UNREFERENCED_PARAMETER(hDLL);
24156 +    UNREFERENCED_PARAMETER(reserved);
24157 +}
24158 +
24159 +#else /* WIN32 */
24160 +
24161 +/* pthreads implementation */
24162 +
24163 +static GSSEAP_THREAD_ONCE tldKeyOnce = GSSEAP_ONCE_INITIALIZER;
24164 +static GSSEAP_THREAD_KEY tldKey;
24165 +
24166 +static void
24167 +pthreadDestroyThreadLocalData(void *arg)
24168 +{
24169 +    struct gss_eap_thread_local_data* tld = arg;
24170 +
24171 +    if (tld != NULL)
24172 +        destroyThreadLocalData(tld);
24173 +}
24174 +
24175 +static void
24176 +createThreadLocalDataKey(void)
24177 +{
24178 +    GSSEAP_KEY_CREATE(&tldKey, pthreadDestroyThreadLocalData);
24179 +}
24180 +
24181 +struct gss_eap_thread_local_data *
24182 +gssEapGetThreadLocalData()
24183 +{
24184 +    struct gss_eap_thread_local_data *tld;
24185 +
24186 +    GSSEAP_ONCE(&tldKeyOnce, createThreadLocalDataKey);
24187 +
24188 +    tld = GSSEAP_GETSPECIFIC(tldKey);
24189 +    if (tld == NULL) {
24190 +        tld = GSSEAP_CALLOC(1, sizeof(*tld));
24191 +        if (tld == NULL)
24192 +            return NULL;
24193 +
24194 +        GSSEAP_SETSPECIFIC(tldKey, tld);
24195 +    }
24196 +
24197 +    return tld;
24198 +}
24199 +
24200 +#endif /* WIN32 */
24201 diff --git a/mech_eap/util_token.c b/mech_eap/util_token.c
24202 new file mode 100644
24203 index 0000000..a1aea0c
24204 --- /dev/null
24205 +++ b/mech_eap/util_token.c
24206 @@ -0,0 +1,493 @@
24207 +/*
24208 + * Copyright (c) 2011, JANET(UK)
24209 + * All rights reserved.
24210 + *
24211 + * Redistribution and use in source and binary forms, with or without
24212 + * modification, are permitted provided that the following conditions
24213 + * are met:
24214 + *
24215 + * 1. Redistributions of source code must retain the above copyright
24216 + *    notice, this list of conditions and the following disclaimer.
24217 + *
24218 + * 2. Redistributions in binary form must reproduce the above copyright
24219 + *    notice, this list of conditions and the following disclaimer in the
24220 + *    documentation and/or other materials provided with the distribution.
24221 + *
24222 + * 3. Neither the name of JANET(UK) nor the names of its contributors
24223 + *    may be used to endorse or promote products derived from this software
24224 + *    without specific prior written permission.
24225 + *
24226 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24227 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24228 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24229 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24230 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24231 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24232 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24233 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24234 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24235 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24236 + * SUCH DAMAGE.
24237 + */
24238 +/*
24239 + * Portions Copyright 1993 by OpenVision Technologies, Inc.
24240 + *
24241 + * Permission to use, copy, modify, distribute, and sell this software
24242 + * and its documentation for any purpose is hereby granted without fee,
24243 + * provided that the above copyright notice appears in all copies and
24244 + * that both that copyright notice and this permission notice appear in
24245 + * supporting documentation, and that the name of OpenVision not be used
24246 + * in advertising or publicity pertaining to distribution of the software
24247 + * without specific, written prior permission. OpenVision makes no
24248 + * representations about the suitability of this software for any
24249 + * purpose.  It is provided "as is" without express or implied warranty.
24250 + *
24251 + * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
24252 + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
24253 + * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
24254 + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
24255 + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
24256 + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
24257 + * PERFORMANCE OF THIS SOFTWARE.
24258 + */
24259 +
24260 +/*
24261 + * Utility routines for GSS tokens.
24262 + */
24263 +
24264 +#include "gssapiP_eap.h"
24265 +
24266 +OM_uint32
24267 +gssEapEncodeInnerTokens(OM_uint32 *minor,
24268 +                        struct gss_eap_token_buffer_set *tokens,
24269 +                        gss_buffer_t buffer)
24270 +{
24271 +    OM_uint32 major, tmpMinor;
24272 +    size_t required = 0, i;
24273 +    unsigned char *p;
24274 +
24275 +    buffer->value = NULL;
24276 +    buffer->length = 0;
24277 +
24278 +    for (i = 0; i < tokens->buffers.count; i++) {
24279 +        required += 8 + tokens->buffers.elements[i].length;
24280 +    }
24281 +
24282 +    /*
24283 +     * We must always return a non-NULL token otherwise the calling state
24284 +     * machine assumes we are finished. Hence care in case malloc(0) does
24285 +     * return NULL.
24286 +     */
24287 +    buffer->value = GSSEAP_MALLOC(required ? required : 1);
24288 +    if (buffer->value == NULL) {
24289 +        major = GSS_S_FAILURE;
24290 +        *minor = ENOMEM;
24291 +        goto cleanup;
24292 +    }
24293 +
24294 +    buffer->length = required;
24295 +    p = (unsigned char *)buffer->value;
24296 +
24297 +    for (i = 0; i < tokens->buffers.count; i++) {
24298 +        gss_buffer_t tokenBuffer = &tokens->buffers.elements[i];
24299 +
24300 +        GSSEAP_ASSERT((tokens->types[i] & ITOK_FLAG_VERIFIED) == 0); /* private flag */
24301 +
24302 +         /*
24303 +          * Extensions are encoded as type-length-value, where the upper
24304 +          * bit of the type indicates criticality.
24305 +          */
24306 +        store_uint32_be(tokens->types[i], &p[0]);
24307 +        store_uint32_be(tokenBuffer->length, &p[4]);
24308 +        memcpy(&p[8], tokenBuffer->value, tokenBuffer->length);
24309 +
24310 +        p += 8 + tokenBuffer->length;
24311 +    }
24312 +
24313 +    GSSEAP_ASSERT(p == (unsigned char *)buffer->value + required);
24314 +    GSSEAP_ASSERT(buffer->value != NULL);
24315 +
24316 +    major = GSS_S_COMPLETE;
24317 +    *minor = 0;
24318 +
24319 +cleanup:
24320 +    if (GSS_ERROR(major)) {
24321 +        gss_release_buffer(&tmpMinor, buffer);
24322 +    }
24323 +
24324 +    return major;
24325 +}
24326 +
24327 +OM_uint32
24328 +gssEapDecodeInnerTokens(OM_uint32 *minor,
24329 +                        const gss_buffer_t buffer,
24330 +                        struct gss_eap_token_buffer_set *tokens)
24331 +{
24332 +    OM_uint32 major, tmpMinor;
24333 +    unsigned char *p;
24334 +    size_t count = 0;
24335 +    size_t remain;
24336 +
24337 +    tokens->buffers.count = 0;
24338 +    tokens->buffers.elements = NULL;
24339 +    tokens->types = NULL;
24340 +
24341 +    if (buffer->length == 0) {
24342 +        major = GSS_S_COMPLETE;
24343 +        goto cleanup;
24344 +    }
24345 +
24346 +    p = (unsigned char *)buffer->value;
24347 +    remain = buffer->length;
24348 +
24349 +    do {
24350 +        OM_uint32 *ntypes;
24351 +        gss_buffer_desc tokenBuffer, *newTokenBuffers;
24352 +
24353 +        if (remain < 8) {
24354 +            major = GSS_S_DEFECTIVE_TOKEN;
24355 +            *minor = GSSEAP_TOK_TRUNC;
24356 +            goto cleanup;
24357 +        }
24358 +
24359 +        if (tokens->buffers.count <= count) {
24360 +            if (count == 0)
24361 +                count = 1;
24362 +            else
24363 +                count *= 2;
24364 +
24365 +            ntypes = GSSEAP_MALLOC(count * sizeof(OM_uint32));
24366 +            if (ntypes == NULL) {
24367 +                major = GSS_S_FAILURE;
24368 +                *minor = ENOMEM;
24369 +                goto cleanup;
24370 +            }
24371 +            if (tokens->types != NULL) {
24372 +                memcpy(ntypes, tokens->types, tokens->buffers.count * sizeof(OM_uint32));
24373 +                GSSEAP_FREE(tokens->types);
24374 +            }
24375 +            tokens->types = ntypes;
24376 +
24377 +            newTokenBuffers = GSSEAP_MALLOC(count * sizeof(gss_buffer_desc));
24378 +            if (newTokenBuffers == NULL) {
24379 +                major = GSS_S_FAILURE;
24380 +                *minor = ENOMEM;
24381 +                goto cleanup;
24382 +            }
24383 +            if (tokens->buffers.elements != NULL) {
24384 +                memcpy(newTokenBuffers, tokens->buffers.elements,
24385 +                       tokens->buffers.count * sizeof(gss_buffer_desc));
24386 +                GSSEAP_FREE(tokens->buffers.elements);
24387 +            }
24388 +            tokens->buffers.elements = newTokenBuffers;
24389 +        }
24390 +
24391 +        tokens->types[tokens->buffers.count] = load_uint32_be(&p[0]);
24392 +        tokenBuffer.length = load_uint32_be(&p[4]);
24393 +
24394 +        if (remain < 8 + tokenBuffer.length) {
24395 +            major = GSS_S_DEFECTIVE_TOKEN;
24396 +            *minor = GSSEAP_TOK_TRUNC;
24397 +            goto cleanup;
24398 +        }
24399 +        tokenBuffer.value = &p[8];
24400 +
24401 +        tokens->buffers.elements[tokens->buffers.count] = tokenBuffer;
24402 +        tokens->buffers.count++;
24403 +
24404 +        p      += 8 + tokenBuffer.length;
24405 +        remain -= 8 + tokenBuffer.length;
24406 +    } while (remain != 0);
24407 +
24408 +    major = GSS_S_COMPLETE;
24409 +    *minor = 0;
24410 +
24411 +cleanup:
24412 +    if (GSS_ERROR(major))
24413 +        gssEapReleaseInnerTokens(&tmpMinor, tokens, 0);
24414 +
24415 +    return major;
24416 +}
24417 +
24418 +/*
24419 + * $Id: util_token.c 23457 2009-12-08 00:04:48Z tlyu $
24420 + */
24421 +
24422 +/* XXXX this code currently makes the assumption that a mech oid will
24423 +   never be longer than 127 bytes.  This assumption is not inherent in
24424 +   the interfaces, so the code can be fixed if the OSI namespace
24425 +   balloons unexpectedly. */
24426 +
24427 +/*
24428 + * Each token looks like this:
24429 + * 0x60                 tag for APPLICATION 0, SEQUENCE
24430 + *                              (constructed, definite-length)
24431 + * <length>             possible multiple bytes, need to parse/generate
24432 + * 0x06                 tag for OBJECT IDENTIFIER
24433 + * <moid_length>        compile-time constant string (assume 1 byte)
24434 + * <moid_bytes>         compile-time constant string
24435 + * <inner_bytes>        the ANY containing the application token
24436 + * bytes 0,1 are the token type
24437 + * bytes 2,n are the token data
24438 + *
24439 + * Note that the token type field is a feature of RFC 1964 mechanisms and
24440 + * is not used by other GSSAPI mechanisms.  As such, a token type of -1
24441 + * is interpreted to mean that no token type should be expected or
24442 + * generated.
24443 + *
24444 + * For the purposes of this abstraction, the token "header" consists of
24445 + * the sequence tag and length octets, the mech OID DER encoding, and the
24446 + * first two inner bytes, which indicate the token type.  The token
24447 + * "body" consists of everything else.
24448 + */
24449 +
24450 +static size_t
24451 +der_length_size(size_t length)
24452 +{
24453 +    if (length < (1<<7))
24454 +        return 1;
24455 +    else if (length < (1<<8))
24456 +        return 2;
24457 +#if INT_MAX == 0x7fff
24458 +    else
24459 +        return 3;
24460 +#else
24461 +    else if (length < (1<<16))
24462 +        return 3;
24463 +    else if (length < (1<<24))
24464 +        return 4;
24465 +    else
24466 +        return 5;
24467 +#endif
24468 +}
24469 +
24470 +static void
24471 +der_write_length(unsigned char **buf, size_t length)
24472 +{
24473 +    if (length < (1<<7)) {
24474 +        *(*buf)++ = (unsigned char)length;
24475 +    } else {
24476 +        *(*buf)++ = (unsigned char)(der_length_size(length)+127);
24477 +#if INT_MAX > 0x7fff
24478 +        if (length >= (1<<24))
24479 +            *(*buf)++ = (unsigned char)(length>>24);
24480 +        if (length >= (1<<16))
24481 +            *(*buf)++ = (unsigned char)((length>>16)&0xff);
24482 +#endif
24483 +        if (length >= (1<<8))
24484 +            *(*buf)++ = (unsigned char)((length>>8)&0xff);
24485 +        *(*buf)++ = (unsigned char)(length&0xff);
24486 +    }
24487 +}
24488 +
24489 +/* returns decoded length, or < 0 on failure.  Advances buf and
24490 +   decrements bufsize */
24491 +
24492 +static int
24493 +der_read_length(unsigned char **buf, ssize_t *bufsize)
24494 +{
24495 +    unsigned char sf;
24496 +    int ret;
24497 +
24498 +    if (*bufsize < 1)
24499 +        return -1;
24500 +
24501 +    sf = *(*buf)++;
24502 +    (*bufsize)--;
24503 +    if (sf & 0x80) {
24504 +        if ((sf &= 0x7f) > ((*bufsize)-1))
24505 +            return -1;
24506 +        if (sf > sizeof(int))
24507 +            return -1;
24508 +        ret = 0;
24509 +        for (; sf; sf--) {
24510 +            ret = (ret<<8) + (*(*buf)++);
24511 +            (*bufsize)--;
24512 +        }
24513 +    } else {
24514 +        ret = sf;
24515 +    }
24516 +
24517 +    return ret;
24518 +}
24519 +
24520 +/* returns the length of a token, given the mech oid and the body size */
24521 +
24522 +size_t
24523 +tokenSize(const gss_OID_desc *mech, size_t body_size)
24524 +{
24525 +    GSSEAP_ASSERT(mech != GSS_C_NO_OID);
24526 +
24527 +    /* set body_size to sequence contents size */
24528 +    body_size += 4 + (size_t) mech->length;         /* NEED overflow check */
24529 +    return 1 + der_length_size(body_size) + body_size;
24530 +}
24531 +
24532 +/* fills in a buffer with the token header.  The buffer is assumed to
24533 +   be the right size.  buf is advanced past the token header */
24534 +
24535 +void
24536 +makeTokenHeader(
24537 +    const gss_OID_desc *mech,
24538 +    size_t body_size,
24539 +    unsigned char **buf,
24540 +    enum gss_eap_token_type tok_type)
24541 +{
24542 +    *(*buf)++ = 0x60;
24543 +    der_write_length(buf, (tok_type == -1) ?2:4 + mech->length + body_size);
24544 +    *(*buf)++ = 0x06;
24545 +    *(*buf)++ = (unsigned char)mech->length;
24546 +    memcpy(*buf, mech->elements, mech->length);
24547 +    *buf += mech->length;
24548 +    GSSEAP_ASSERT(tok_type != TOK_TYPE_NONE);
24549 +    *(*buf)++ = (unsigned char)((tok_type>>8) & 0xff);
24550 +    *(*buf)++ = (unsigned char)(tok_type & 0xff);
24551 +}
24552 +
24553 +/*
24554 + * Given a buffer containing a token, reads and verifies the token,
24555 + * leaving buf advanced past the token header, and setting body_size
24556 + * to the number of remaining bytes.  Returns 0 on success,
24557 + * G_BAD_TOK_HEADER for a variety of errors, and G_WRONG_MECH if the
24558 + * mechanism in the token does not match the mech argument.  buf and
24559 + * *body_size are left unmodified on error.
24560 + */
24561 +
24562 +OM_uint32
24563 +verifyTokenHeader(OM_uint32 *minor,
24564 +                  gss_OID mech,
24565 +                  size_t *body_size,
24566 +                  unsigned char **buf_in,
24567 +                  size_t toksize_in,
24568 +                  enum gss_eap_token_type *ret_tok_type)
24569 +{
24570 +    unsigned char *buf = *buf_in;
24571 +    ssize_t seqsize;
24572 +    gss_OID_desc toid;
24573 +    ssize_t toksize = (ssize_t)toksize_in;
24574 +
24575 +    *minor = GSSEAP_BAD_TOK_HEADER;
24576 +
24577 +    if (ret_tok_type != NULL)
24578 +        *ret_tok_type = TOK_TYPE_NONE;
24579 +
24580 +    if ((toksize -= 1) < 0)
24581 +        return GSS_S_DEFECTIVE_TOKEN;
24582 +
24583 +    if (*buf++ != 0x60)
24584 +        return GSS_S_DEFECTIVE_TOKEN;
24585 +
24586 +    seqsize = der_read_length(&buf, &toksize);
24587 +    if (seqsize < 0)
24588 +        return GSS_S_DEFECTIVE_TOKEN;
24589 +
24590 +    if (seqsize != toksize)
24591 +        return GSS_S_DEFECTIVE_TOKEN;
24592 +
24593 +    if ((toksize -= 1) < 0)
24594 +        return GSS_S_DEFECTIVE_TOKEN;
24595 +
24596 +    if (*buf++ != 0x06)
24597 +        return GSS_S_DEFECTIVE_TOKEN;
24598 +
24599 +    if ((toksize -= 1) < 0)
24600 +        return GSS_S_DEFECTIVE_TOKEN;
24601 +
24602 +    toid.length = *buf++;
24603 +
24604 +    if ((toksize -= toid.length) < 0)
24605 +        return GSS_S_DEFECTIVE_TOKEN;
24606 +
24607 +    toid.elements = buf;
24608 +    buf += toid.length;
24609 +
24610 +    if (mech->elements == NULL) {
24611 +        *mech = toid;
24612 +        if (toid.length == 0)
24613 +            return GSS_S_BAD_MECH;
24614 +    } else if (!oidEqual(&toid, mech)) {
24615 +        *minor = GSSEAP_WRONG_MECH;
24616 +        return GSS_S_BAD_MECH;
24617 +    }
24618 +
24619 +    if (ret_tok_type != NULL) {
24620 +        if ((toksize -= 2) < 0)
24621 +            return GSS_S_DEFECTIVE_TOKEN;
24622 +
24623 +        *ret_tok_type = load_uint16_be(buf);
24624 +        buf += 2;
24625 +    }
24626 +
24627 +    *buf_in = buf;
24628 +    *body_size = toksize;
24629 +
24630 +    *minor = 0;
24631 +    return GSS_S_COMPLETE;
24632 +}
24633 +
24634 +OM_uint32
24635 +gssEapAllocInnerTokens(OM_uint32 *minor,
24636 +                       size_t count,
24637 +                       struct gss_eap_token_buffer_set *tokens)
24638 +{
24639 +    OM_uint32 major;
24640 +
24641 +    tokens->buffers.count = 0;
24642 +    tokens->buffers.elements = (gss_buffer_desc *)GSSEAP_CALLOC(count, sizeof(gss_buffer_desc));
24643 +    if (tokens->buffers.elements == NULL) {
24644 +        major = GSS_S_FAILURE;
24645 +        *minor = ENOMEM;
24646 +        goto cleanup;
24647 +    }
24648 +
24649 +    tokens->types = (OM_uint32 *)GSSEAP_CALLOC(count, sizeof(OM_uint32));
24650 +    if (tokens->types == NULL) {
24651 +        major = GSS_S_FAILURE;
24652 +        *minor = ENOMEM;
24653 +        goto cleanup;
24654 +    }
24655 +
24656 +    major = GSS_S_COMPLETE;
24657 +    *minor = 0;
24658 +
24659 +cleanup:
24660 +    if (GSS_ERROR(major)) {
24661 +        if (tokens->buffers.elements != NULL) {
24662 +            GSSEAP_FREE(tokens->buffers.elements);
24663 +            tokens->buffers.elements = NULL;
24664 +        }
24665 +        if (tokens->types != NULL) {
24666 +            GSSEAP_FREE(tokens->types);
24667 +            tokens->types = NULL;
24668 +        }
24669 +    }
24670 +
24671 +    return major;
24672 +}
24673 +
24674 +OM_uint32
24675 +gssEapReleaseInnerTokens(OM_uint32 *minor,
24676 +                         struct gss_eap_token_buffer_set *tokens,
24677 +                         int freeBuffers)
24678 +{
24679 +    OM_uint32 tmpMinor;
24680 +    size_t i;
24681 +
24682 +    if (tokens->buffers.elements != NULL) {
24683 +        if (freeBuffers) {
24684 +            for (i = 0; i < tokens->buffers.count; i++)
24685 +                gss_release_buffer(&tmpMinor, &tokens->buffers.elements[i]);
24686 +        }
24687 +        GSSEAP_FREE(tokens->buffers.elements);
24688 +        tokens->buffers.elements = NULL;
24689 +    }
24690 +    tokens->buffers.count = 0;
24691 +
24692 +    if (tokens->types != NULL) {
24693 +        GSSEAP_FREE(tokens->types);
24694 +        tokens->types = NULL;
24695 +    }
24696 +
24697 +    *minor = 0;
24698 +    return GSS_S_COMPLETE;
24699 +}
24700 diff --git a/mech_eap/verify_mic.c b/mech_eap/verify_mic.c
24701 new file mode 100644
24702 index 0000000..c0829f5
24703 --- /dev/null
24704 +++ b/mech_eap/verify_mic.c
24705 @@ -0,0 +1,71 @@
24706 +/*
24707 + * Copyright (c) 2011, JANET(UK)
24708 + * All rights reserved.
24709 + *
24710 + * Redistribution and use in source and binary forms, with or without
24711 + * modification, are permitted provided that the following conditions
24712 + * are met:
24713 + *
24714 + * 1. Redistributions of source code must retain the above copyright
24715 + *    notice, this list of conditions and the following disclaimer.
24716 + *
24717 + * 2. Redistributions in binary form must reproduce the above copyright
24718 + *    notice, this list of conditions and the following disclaimer in the
24719 + *    documentation and/or other materials provided with the distribution.
24720 + *
24721 + * 3. Neither the name of JANET(UK) nor the names of its contributors
24722 + *    may be used to endorse or promote products derived from this software
24723 + *    without specific prior written permission.
24724 + *
24725 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24726 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24727 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24728 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24729 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24730 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24731 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24732 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24733 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24734 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24735 + * SUCH DAMAGE.
24736 + */
24737 +
24738 +/*
24739 + * Message protection services: verify a message integrity check.
24740 + */
24741 +
24742 +#include "gssapiP_eap.h"
24743 +
24744 +OM_uint32 GSSAPI_CALLCONV
24745 +gss_verify_mic(OM_uint32 *minor,
24746 +               gss_ctx_id_t ctx,
24747 +               gss_buffer_t message_buffer,
24748 +               gss_buffer_t message_token,
24749 +               gss_qop_t *qop_state)
24750 +{
24751 +    OM_uint32 major;
24752 +    gss_iov_buffer_desc iov[3];
24753 +    int conf_state;
24754 +
24755 +    if (message_token->length < 16) {
24756 +        *minor = GSSEAP_TOK_TRUNC;
24757 +        return GSS_S_BAD_SIG;
24758 +    }
24759 +
24760 +    *minor = 0;
24761 +
24762 +    iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
24763 +    iov[0].buffer = *message_buffer;
24764 +
24765 +    iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER;
24766 +    iov[1].buffer = *message_token;
24767 +
24768 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
24769 +
24770 +    major = gssEapUnwrapOrVerifyMIC(minor, ctx, &conf_state, qop_state,
24771 +                                    iov, 2, TOK_TYPE_MIC);
24772 +
24773 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
24774 +
24775 +    return major;
24776 +}
24777 diff --git a/mech_eap/wrap.c b/mech_eap/wrap.c
24778 new file mode 100644
24779 index 0000000..2e27fb3
24780 --- /dev/null
24781 +++ b/mech_eap/wrap.c
24782 @@ -0,0 +1,137 @@
24783 +/*
24784 + * Copyright (c) 2011, JANET(UK)
24785 + * All rights reserved.
24786 + *
24787 + * Redistribution and use in source and binary forms, with or without
24788 + * modification, are permitted provided that the following conditions
24789 + * are met:
24790 + *
24791 + * 1. Redistributions of source code must retain the above copyright
24792 + *    notice, this list of conditions and the following disclaimer.
24793 + *
24794 + * 2. Redistributions in binary form must reproduce the above copyright
24795 + *    notice, this list of conditions and the following disclaimer in the
24796 + *    documentation and/or other materials provided with the distribution.
24797 + *
24798 + * 3. Neither the name of JANET(UK) nor the names of its contributors
24799 + *    may be used to endorse or promote products derived from this software
24800 + *    without specific prior written permission.
24801 + *
24802 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24803 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24804 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24805 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24806 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24807 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24808 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24809 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24810 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24811 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24812 + * SUCH DAMAGE.
24813 + */
24814 +
24815 +/*
24816 + * Message protection services: wrap.
24817 + */
24818 +
24819 +#include "gssapiP_eap.h"
24820 +
24821 +OM_uint32 GSSAPI_CALLCONV
24822 +gss_wrap(OM_uint32 *minor,
24823 +         gss_ctx_id_t ctx,
24824 +         int conf_req_flag,
24825 +         gss_qop_t qop_req,
24826 +         gss_buffer_t input_message_buffer,
24827 +         int *conf_state,
24828 +         gss_buffer_t output_message_buffer)
24829 +{
24830 +    OM_uint32 major;
24831 +
24832 +    if (ctx == GSS_C_NO_CONTEXT) {
24833 +        *minor = EINVAL;
24834 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
24835 +    }
24836 +
24837 +    *minor = 0;
24838 +
24839 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
24840 +
24841 +    if (!CTX_IS_ESTABLISHED(ctx)) {
24842 +        major = GSS_S_NO_CONTEXT;
24843 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
24844 +        goto cleanup;
24845 +    }
24846 +
24847 +    major = gssEapWrap(minor, ctx, conf_req_flag, qop_req,
24848 +                       input_message_buffer,
24849 +                       conf_state, output_message_buffer);
24850 +    if (GSS_ERROR(major))
24851 +        goto cleanup;
24852 +
24853 +cleanup:
24854 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
24855 +
24856 +    return major;
24857 +}
24858 +
24859 +OM_uint32
24860 +gssEapWrap(OM_uint32 *minor,
24861 +           gss_ctx_id_t ctx,
24862 +           int conf_req_flag,
24863 +           gss_qop_t qop_req,
24864 +           gss_buffer_t input_message_buffer,
24865 +           int *conf_state,
24866 +           gss_buffer_t output_message_buffer)
24867 +{
24868 +    OM_uint32 major, tmpMinor;
24869 +    gss_iov_buffer_desc iov[4];
24870 +    unsigned char *p;
24871 +    int i;
24872 +
24873 +    iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
24874 +    iov[0].buffer.value = NULL;
24875 +    iov[0].buffer.length = 0;
24876 +
24877 +    iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
24878 +    iov[1].buffer = *input_message_buffer;
24879 +
24880 +    iov[2].type = GSS_IOV_BUFFER_TYPE_PADDING;
24881 +    iov[2].buffer.value = NULL;
24882 +    iov[2].buffer.length = 0;
24883 +
24884 +    iov[3].type = GSS_IOV_BUFFER_TYPE_TRAILER;
24885 +    iov[3].buffer.value = NULL;
24886 +    iov[3].buffer.length = 0;
24887 +
24888 +    major = gssEapWrapIovLength(minor, ctx, conf_req_flag, qop_req,
24889 +                                NULL, iov, 4);
24890 +    if (GSS_ERROR(major)) {
24891 +        return major;
24892 +    }
24893 +
24894 +    for (i = 0, output_message_buffer->length = 0; i < 4; i++) {
24895 +        output_message_buffer->length += iov[i].buffer.length;
24896 +    }
24897 +
24898 +    output_message_buffer->value = GSSEAP_MALLOC(output_message_buffer->length);
24899 +    if (output_message_buffer->value == NULL) {
24900 +        *minor = ENOMEM;
24901 +        return GSS_S_FAILURE;
24902 +    }
24903 +
24904 +    for (i = 0, p = output_message_buffer->value; i < 4; i++) {
24905 +        if (iov[i].type == GSS_IOV_BUFFER_TYPE_DATA) {
24906 +            memcpy(p, input_message_buffer->value, input_message_buffer->length);
24907 +        }
24908 +        iov[i].buffer.value = p;
24909 +        p += iov[i].buffer.length;
24910 +    }
24911 +
24912 +    major = gssEapWrapOrGetMIC(minor, ctx, conf_req_flag, conf_state,
24913 +                               iov, 4, TOK_TYPE_WRAP);
24914 +    if (GSS_ERROR(major)) {
24915 +        gss_release_buffer(&tmpMinor, output_message_buffer);
24916 +    }
24917 +
24918 +    return major;
24919 +}
24920 diff --git a/mech_eap/wrap_iov.c b/mech_eap/wrap_iov.c
24921 new file mode 100644
24922 index 0000000..be890b6
24923 --- /dev/null
24924 +++ b/mech_eap/wrap_iov.c
24925 @@ -0,0 +1,379 @@
24926 +/*
24927 + * Copyright (c) 2011, JANET(UK)
24928 + * All rights reserved.
24929 + *
24930 + * Redistribution and use in source and binary forms, with or without
24931 + * modification, are permitted provided that the following conditions
24932 + * are met:
24933 + *
24934 + * 1. Redistributions of source code must retain the above copyright
24935 + *    notice, this list of conditions and the following disclaimer.
24936 + *
24937 + * 2. Redistributions in binary form must reproduce the above copyright
24938 + *    notice, this list of conditions and the following disclaimer in the
24939 + *    documentation and/or other materials provided with the distribution.
24940 + *
24941 + * 3. Neither the name of JANET(UK) nor the names of its contributors
24942 + *    may be used to endorse or promote products derived from this software
24943 + *    without specific prior written permission.
24944 + *
24945 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24946 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24947 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24948 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24949 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24950 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24951 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24952 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24953 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24954 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24955 + * SUCH DAMAGE.
24956 + */
24957 +/*
24958 + * Copyright 2008 by the Massachusetts Institute of Technology.
24959 + * All Rights Reserved.
24960 + *
24961 + * Export of this software from the United States of America may
24962 + *   require a specific license from the United States Government.
24963 + *   It is the responsibility of any person or organization contemplating
24964 + *   export to obtain such a license before exporting.
24965 + *
24966 + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
24967 + * distribute this software and its documentation for any purpose and
24968 + * without fee is hereby granted, provided that the above copyright
24969 + * notice appear in all copies and that both that copyright notice and
24970 + * this permission notice appear in supporting documentation, and that
24971 + * the name of M.I.T. not be used in advertising or publicity pertaining
24972 + * to distribution of the software without specific, written prior
24973 + * permission.  Furthermore if you modify this software you must label
24974 + * your software as modified software and not distribute it in such a
24975 + * fashion that it might be confused with the original M.I.T. software.
24976 + * M.I.T. makes no representations about the suitability of
24977 + * this software for any purpose.  It is provided "as is" without express
24978 + * or implied warranty.
24979 + */
24980 +
24981 +/*
24982 + * Message protection services: wrap with scatter-gather API.
24983 + */
24984 +
24985 +#include "gssapiP_eap.h"
24986 +
24987 +unsigned char
24988 +rfc4121Flags(gss_ctx_id_t ctx, int receiving)
24989 +{
24990 +    unsigned char flags;
24991 +    int isAcceptor;
24992 +
24993 +    isAcceptor = !CTX_IS_INITIATOR(ctx);
24994 +    if (receiving)
24995 +        isAcceptor = !isAcceptor;
24996 +
24997 +    flags = 0;
24998 +    if (isAcceptor)
24999 +        flags |= TOK_FLAG_SENDER_IS_ACCEPTOR;
25000 +
25001 +    if ((ctx->flags & CTX_FLAG_KRB_REAUTH) &&
25002 +        (ctx->gssFlags & GSS_C_MUTUAL_FLAG))
25003 +        flags |= TOK_FLAG_ACCEPTOR_SUBKEY;
25004 +
25005 +    return flags;
25006 +}
25007 +
25008 +OM_uint32
25009 +gssEapWrapOrGetMIC(OM_uint32 *minor,
25010 +                   gss_ctx_id_t ctx,
25011 +                   int conf_req_flag,
25012 +                   int *conf_state,
25013 +                   gss_iov_buffer_desc *iov,
25014 +                   int iov_count,
25015 +                   enum gss_eap_token_type toktype)
25016 +{
25017 +    krb5_error_code code = 0;
25018 +    gss_iov_buffer_t header;
25019 +    gss_iov_buffer_t padding;
25020 +    gss_iov_buffer_t trailer;
25021 +    unsigned char flags;
25022 +    unsigned char *outbuf = NULL;
25023 +    unsigned char *tbuf = NULL;
25024 +    int keyUsage;
25025 +    size_t rrc = 0;
25026 +    size_t gssHeaderLen, gssTrailerLen;
25027 +    size_t dataLen, assocDataLen;
25028 +    krb5_context krbContext;
25029 +#ifdef HAVE_HEIMDAL_VERSION
25030 +    krb5_crypto krbCrypto = NULL;
25031 +#endif
25032 +
25033 +    if (ctx->encryptionType == ENCTYPE_NULL) {
25034 +        *minor = GSSEAP_KEY_UNAVAILABLE;
25035 +        return GSS_S_UNAVAILABLE;
25036 +    }
25037 +
25038 +    GSSEAP_KRB_INIT(&krbContext);
25039 +
25040 +    flags = rfc4121Flags(ctx, FALSE);
25041 +
25042 +    if (toktype == TOK_TYPE_WRAP) {
25043 +        keyUsage = CTX_IS_INITIATOR(ctx)
25044 +                   ? KEY_USAGE_INITIATOR_SEAL
25045 +                   : KEY_USAGE_ACCEPTOR_SEAL;
25046 +    } else {
25047 +        keyUsage = CTX_IS_INITIATOR(ctx)
25048 +                   ? KEY_USAGE_INITIATOR_SIGN
25049 +                   : KEY_USAGE_ACCEPTOR_SIGN;
25050 +    }
25051 +
25052 +    gssEapIovMessageLength(iov, iov_count, &dataLen, &assocDataLen);
25053 +
25054 +    header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
25055 +    if (header == NULL) {
25056 +        *minor = GSSEAP_MISSING_IOV;
25057 +        return GSS_S_FAILURE;
25058 +    }
25059 +
25060 +    padding = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
25061 +    if (padding != NULL)
25062 +        padding->buffer.length = 0;
25063 +
25064 +    trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
25065 +
25066 +#ifdef HAVE_HEIMDAL_VERSION
25067 +    code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, ETYPE_NULL, &krbCrypto);
25068 +    if (code != 0)
25069 +        goto cleanup;
25070 +#endif
25071 +
25072 +    if (toktype == TOK_TYPE_WRAP && conf_req_flag) {
25073 +        size_t krbHeaderLen, krbTrailerLen, krbPadLen;
25074 +        size_t ec = 0, confDataLen = dataLen - assocDataLen;
25075 +
25076 +        code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
25077 +                               KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen);
25078 +        if (code != 0)
25079 +            goto cleanup;
25080 +
25081 +        code = krbPaddingLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
25082 +                                confDataLen + 16 /* E(Header) */,
25083 +                                &krbPadLen);
25084 +        if (code != 0)
25085 +            goto cleanup;
25086 +
25087 +        if (krbPadLen == 0 && (ctx->gssFlags & GSS_C_DCE_STYLE)) {
25088 +            /* Windows rejects AEAD tokens with non-zero EC */
25089 +            code = krbBlockSize(krbContext, KRB_CRYPTO_CONTEXT(ctx), &ec);
25090 +            if (code != 0)
25091 +                goto cleanup;
25092 +        } else
25093 +            ec = krbPadLen;
25094 +
25095 +        code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
25096 +                               KRB5_CRYPTO_TYPE_TRAILER, &krbTrailerLen);
25097 +        if (code != 0)
25098 +            goto cleanup;
25099 +
25100 +        gssHeaderLen = 16 /* Header */ + krbHeaderLen;
25101 +        gssTrailerLen = ec + 16 /* E(Header) */ + krbTrailerLen;
25102 +
25103 +        if (trailer == NULL) {
25104 +            rrc = gssTrailerLen;
25105 +            /* Workaround for Windows bug where it rotates by EC + RRC */
25106 +            if (ctx->gssFlags & GSS_C_DCE_STYLE)
25107 +                rrc -= ec;
25108 +            gssHeaderLen += gssTrailerLen;
25109 +        }
25110 +
25111 +        if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
25112 +            code = gssEapAllocIov(header, (size_t)gssHeaderLen);
25113 +        } else if (header->buffer.length < gssHeaderLen)
25114 +            code = GSSEAP_WRONG_SIZE;
25115 +        if (code != 0)
25116 +            goto cleanup;
25117 +        outbuf = (unsigned char *)header->buffer.value;
25118 +        header->buffer.length = (size_t)gssHeaderLen;
25119 +
25120 +        if (trailer != NULL) {
25121 +            if (trailer->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
25122 +                code = gssEapAllocIov(trailer, (size_t)gssTrailerLen);
25123 +            else if (trailer->buffer.length < gssTrailerLen)
25124 +                code = GSSEAP_WRONG_SIZE;
25125 +            if (code != 0)
25126 +                goto cleanup;
25127 +            trailer->buffer.length = (size_t)gssTrailerLen;
25128 +        }
25129 +
25130 +        /* TOK_ID */
25131 +        store_uint16_be((uint16_t)toktype, outbuf);
25132 +        /* flags */
25133 +        outbuf[2] = flags
25134 +                     | (conf_req_flag ? TOK_FLAG_WRAP_CONFIDENTIAL : 0);
25135 +        /* filler */
25136 +        outbuf[3] = 0xFF;
25137 +        /* EC */
25138 +        store_uint16_be(ec, outbuf + 4);
25139 +        /* RRC */
25140 +        store_uint16_be(0, outbuf + 6);
25141 +        store_uint64_be(ctx->sendSeq, outbuf + 8);
25142 +
25143 +        /*
25144 +         * EC | copy of header to be encrypted, located in
25145 +         * (possibly rotated) trailer
25146 +         */
25147 +        if (trailer == NULL)
25148 +            tbuf = (unsigned char *)header->buffer.value + 16; /* Header */
25149 +        else
25150 +            tbuf = (unsigned char *)trailer->buffer.value;
25151 +
25152 +        memset(tbuf, 0xFF, ec);
25153 +        memcpy(tbuf + ec, header->buffer.value, 16);
25154 +
25155 +        code = gssEapEncrypt(krbContext,
25156 +                             ((ctx->gssFlags & GSS_C_DCE_STYLE) != 0),
25157 +                             ec, rrc, KRB_CRYPTO_CONTEXT(ctx),
25158 +                             keyUsage, iov, iov_count);
25159 +        if (code != 0)
25160 +            goto cleanup;
25161 +
25162 +        /* RRC */
25163 +        store_uint16_be(rrc, outbuf + 6);
25164 +
25165 +        ctx->sendSeq++;
25166 +    } else if (toktype == TOK_TYPE_WRAP && !conf_req_flag) {
25167 +    wrap_with_checksum:
25168 +
25169 +        gssHeaderLen = 16;
25170 +
25171 +        code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
25172 +                               KRB5_CRYPTO_TYPE_CHECKSUM, &gssTrailerLen);
25173 +        if (code != 0)
25174 +            goto cleanup;
25175 +
25176 +        GSSEAP_ASSERT(gssTrailerLen <= 0xFFFF);
25177 +
25178 +        if (trailer == NULL) {
25179 +            rrc = gssTrailerLen;
25180 +            gssHeaderLen += gssTrailerLen;
25181 +        }
25182 +
25183 +        if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
25184 +            code = gssEapAllocIov(header, (size_t)gssHeaderLen);
25185 +        else if (header->buffer.length < gssHeaderLen)
25186 +            code = GSSEAP_WRONG_SIZE;
25187 +        if (code != 0)
25188 +            goto cleanup;
25189 +        outbuf = (unsigned char *)header->buffer.value;
25190 +        header->buffer.length = (size_t)gssHeaderLen;
25191 +
25192 +        if (trailer != NULL) {
25193 +            if (trailer->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
25194 +                code = gssEapAllocIov(trailer, (size_t)gssTrailerLen);
25195 +            else if (trailer->buffer.length < gssTrailerLen)
25196 +                code = GSSEAP_WRONG_SIZE;
25197 +            if (code != 0)
25198 +                goto cleanup;
25199 +            trailer->buffer.length = (size_t)gssTrailerLen;
25200 +        }
25201 +
25202 +        /* TOK_ID */
25203 +        store_uint16_be((uint16_t)toktype, outbuf);
25204 +        /* flags */
25205 +        outbuf[2] = flags;
25206 +        /* filler */
25207 +        outbuf[3] = 0xFF;
25208 +        if (toktype == TOK_TYPE_WRAP) {
25209 +            /* Use 0 for checksum calculation, substitute
25210 +             * checksum length later.
25211 +             */
25212 +            /* EC */
25213 +            store_uint16_be(0, outbuf + 4);
25214 +            /* RRC */
25215 +            store_uint16_be(0, outbuf + 6);
25216 +        } else {
25217 +            /* MIC and DEL store 0xFF in EC and RRC */
25218 +            store_uint16_be(0xFFFF, outbuf + 4);
25219 +            store_uint16_be(0xFFFF, outbuf + 6);
25220 +        }
25221 +        store_uint64_be(ctx->sendSeq, outbuf + 8);
25222 +
25223 +        code = gssEapSign(krbContext, ctx->checksumType, rrc,
25224 +                          KRB_CRYPTO_CONTEXT(ctx), keyUsage,
25225 +                          iov, iov_count);
25226 +        if (code != 0)
25227 +            goto cleanup;
25228 +
25229 +        ctx->sendSeq++;
25230 +
25231 +        if (toktype == TOK_TYPE_WRAP) {
25232 +            /* Fix up EC field */
25233 +            store_uint16_be(gssTrailerLen, outbuf + 4);
25234 +            /* Fix up RRC field */
25235 +            store_uint16_be(rrc, outbuf + 6);
25236 +        }
25237 +    } else if (toktype == TOK_TYPE_MIC) {
25238 +        trailer = NULL;
25239 +        goto wrap_with_checksum;
25240 +    } else if (toktype == TOK_TYPE_DELETE_CONTEXT) {
25241 +        trailer = NULL;
25242 +        goto wrap_with_checksum;
25243 +    } else {
25244 +        abort();
25245 +    }
25246 +
25247 +    code = 0;
25248 +    if (conf_state != NULL)
25249 +        *conf_state = conf_req_flag;
25250 +
25251 +cleanup:
25252 +    if (code != 0)
25253 +        gssEapReleaseIov(iov, iov_count);
25254 +#ifdef HAVE_HEIMDAL_VERSION
25255 +    if (krbCrypto != NULL)
25256 +        krb5_crypto_destroy(krbContext, krbCrypto);
25257 +#endif
25258 +
25259 +    *minor = code;
25260 +
25261 +    return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
25262 +}
25263 +
25264 +OM_uint32 GSSAPI_CALLCONV
25265 +gss_wrap_iov(OM_uint32 *minor,
25266 +             gss_ctx_id_t ctx,
25267 +             int conf_req_flag,
25268 +             gss_qop_t qop_req,
25269 +             int *conf_state,
25270 +             gss_iov_buffer_desc *iov,
25271 +             int iov_count)
25272 +{
25273 +    OM_uint32 major;
25274 +
25275 +    if (ctx == GSS_C_NO_CONTEXT) {
25276 +        *minor = EINVAL;
25277 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
25278 +    }
25279 +
25280 +    if (qop_req != GSS_C_QOP_DEFAULT) {
25281 +        *minor = GSSEAP_UNKNOWN_QOP;
25282 +        return GSS_S_UNAVAILABLE;
25283 +    }
25284 +
25285 +    *minor = 0;
25286 +
25287 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
25288 +
25289 +    if (!CTX_IS_ESTABLISHED(ctx)) {
25290 +        major = GSS_S_NO_CONTEXT;
25291 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
25292 +        goto cleanup;
25293 +    }
25294 +
25295 +    major = gssEapWrapOrGetMIC(minor, ctx, conf_req_flag, conf_state,
25296 +                               iov, iov_count, TOK_TYPE_WRAP);
25297 +    if (GSS_ERROR(major))
25298 +        goto cleanup;
25299 +
25300 +cleanup:
25301 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
25302 +
25303 +    return major;
25304 +}
25305 diff --git a/mech_eap/wrap_iov_length.c b/mech_eap/wrap_iov_length.c
25306 new file mode 100644
25307 index 0000000..247b78d
25308 --- /dev/null
25309 +++ b/mech_eap/wrap_iov_length.c
25310 @@ -0,0 +1,234 @@
25311 +/*
25312 + * Copyright (c) 2011, JANET(UK)
25313 + * All rights reserved.
25314 + *
25315 + * Redistribution and use in source and binary forms, with or without
25316 + * modification, are permitted provided that the following conditions
25317 + * are met:
25318 + *
25319 + * 1. Redistributions of source code must retain the above copyright
25320 + *    notice, this list of conditions and the following disclaimer.
25321 + *
25322 + * 2. Redistributions in binary form must reproduce the above copyright
25323 + *    notice, this list of conditions and the following disclaimer in the
25324 + *    documentation and/or other materials provided with the distribution.
25325 + *
25326 + * 3. Neither the name of JANET(UK) nor the names of its contributors
25327 + *    may be used to endorse or promote products derived from this software
25328 + *    without specific prior written permission.
25329 + *
25330 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25331 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25332 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25333 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25334 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25335 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25336 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25337 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25338 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25339 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25340 + * SUCH DAMAGE.
25341 + */
25342 +/*
25343 + * Copyright 2008 by the Massachusetts Institute of Technology.
25344 + * All Rights Reserved.
25345 + *
25346 + * Export of this software from the United States of America may
25347 + *   require a specific license from the United States Government.
25348 + *   It is the responsibility of any person or organization contemplating
25349 + *   export to obtain such a license before exporting.
25350 + *
25351 + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
25352 + * distribute this software and its documentation for any purpose and
25353 + * without fee is hereby granted, provided that the above copyright
25354 + * notice appear in all copies and that both that copyright notice and
25355 + * this permission notice appear in supporting documentation, and that
25356 + * the name of M.I.T. not be used in advertising or publicity pertaining
25357 + * to distribution of the software without specific, written prior
25358 + * permission.  Furthermore if you modify this software you must label
25359 + * your software as modified software and not distribute it in such a
25360 + * fashion that it might be confused with the original M.I.T. software.
25361 + * M.I.T. makes no representations about the suitability of
25362 + * this software for any purpose.  It is provided "as is" without express
25363 + * or implied warranty.
25364 + */
25365 +
25366 +/*
25367 + * Message protection services: determine protected message size.
25368 + */
25369 +
25370 +#include "gssapiP_eap.h"
25371 +
25372 +#define INIT_IOV_DATA(_iov)     do { (_iov)->buffer.value = NULL;       \
25373 +        (_iov)->buffer.length = 0; }                                    \
25374 +    while (0)
25375 +
25376 +OM_uint32
25377 +gssEapWrapIovLength(OM_uint32 *minor,
25378 +                    gss_ctx_id_t ctx,
25379 +                    int conf_req_flag,
25380 +                    gss_qop_t qop_req,
25381 +                    int *conf_state,
25382 +                    gss_iov_buffer_desc *iov,
25383 +                    int iov_count)
25384 +{
25385 +    gss_iov_buffer_t header, trailer, padding;
25386 +    size_t dataLength, assocDataLength;
25387 +    size_t gssHeaderLen, gssPadLen, gssTrailerLen;
25388 +    size_t krbHeaderLen = 0, krbTrailerLen = 0, krbPadLen = 0;
25389 +    krb5_error_code code;
25390 +    krb5_context krbContext;
25391 +    int dce_style;
25392 +    size_t ec;
25393 +#ifdef HAVE_HEIMDAL_VERSION
25394 +    krb5_crypto krbCrypto = NULL;
25395 +#endif
25396 +
25397 +    if (qop_req != GSS_C_QOP_DEFAULT) {
25398 +        *minor = GSSEAP_UNKNOWN_QOP;
25399 +        return GSS_S_UNAVAILABLE;
25400 +    }
25401 +
25402 +    if (ctx->encryptionType == ENCTYPE_NULL) {
25403 +        *minor = GSSEAP_KEY_UNAVAILABLE;
25404 +        return GSS_S_UNAVAILABLE;
25405 +    }
25406 +
25407 +    GSSEAP_KRB_INIT(&krbContext);
25408 +
25409 +    header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
25410 +    if (header == NULL) {
25411 +        *minor = GSSEAP_MISSING_IOV;
25412 +        return GSS_S_FAILURE;
25413 +    }
25414 +    INIT_IOV_DATA(header);
25415 +
25416 +    trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
25417 +    if (trailer != NULL) {
25418 +        INIT_IOV_DATA(trailer);
25419 +    }
25420 +
25421 +    dce_style = ((ctx->gssFlags & GSS_C_DCE_STYLE) != 0);
25422 +
25423 +    /* For CFX, EC is used instead of padding, and is placed in header or trailer */
25424 +    padding = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
25425 +    if (padding != NULL) {
25426 +        INIT_IOV_DATA(padding);
25427 +    }
25428 +
25429 +    gssEapIovMessageLength(iov, iov_count, &dataLength, &assocDataLength);
25430 +
25431 +    if (conf_req_flag && gssEapIsIntegrityOnly(iov, iov_count))
25432 +        conf_req_flag = FALSE;
25433 +
25434 +    gssHeaderLen = gssPadLen = gssTrailerLen = 0;
25435 +
25436 +#ifdef HAVE_HEIMDAL_VERSION
25437 +    code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, ETYPE_NULL, &krbCrypto);
25438 +    if (code != 0)
25439 +        return code;
25440 +#endif
25441 +
25442 +    code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
25443 +                           conf_req_flag ?
25444 +                                KRB5_CRYPTO_TYPE_TRAILER : KRB5_CRYPTO_TYPE_CHECKSUM,
25445 +                           &krbTrailerLen);
25446 +    if (code != 0) {
25447 +        *minor = code;
25448 +        return GSS_S_FAILURE;
25449 +    }
25450 +
25451 +    if (conf_req_flag) {
25452 +        code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
25453 +                               KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen);
25454 +        if (code != 0) {
25455 +            *minor = code;
25456 +            return GSS_S_FAILURE;
25457 +        }
25458 +    }
25459 +
25460 +    gssHeaderLen = 16; /* Header */
25461 +    if (conf_req_flag) {
25462 +        gssHeaderLen += krbHeaderLen; /* Kerb-Header */
25463 +        gssTrailerLen = 16 /* E(Header) */ + krbTrailerLen; /* Kerb-Trailer */
25464 +
25465 +        code = krbPaddingLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
25466 +                                dataLength - assocDataLength + 16 /* E(Header) */,
25467 +                                &krbPadLen);
25468 +        if (code != 0) {
25469 +            *minor = code;
25470 +            return GSS_S_FAILURE;
25471 +        }
25472 +
25473 +        if (krbPadLen == 0 && dce_style) {
25474 +            /* Windows rejects AEAD tokens with non-zero EC */
25475 +            code = krbBlockSize(krbContext, KRB_CRYPTO_CONTEXT(ctx), &ec);
25476 +            if (code != 0) {
25477 +                *minor = code;
25478 +                return GSS_S_FAILURE;
25479 +            }
25480 +        } else
25481 +            ec = krbPadLen;
25482 +
25483 +        gssTrailerLen += ec;
25484 +    } else {
25485 +        gssTrailerLen = krbTrailerLen; /* Kerb-Checksum */
25486 +    }
25487 +
25488 +    dataLength += gssPadLen;
25489 +
25490 +    if (trailer == NULL)
25491 +        gssHeaderLen += gssTrailerLen;
25492 +    else
25493 +        trailer->buffer.length = gssTrailerLen;
25494 +
25495 +    GSSEAP_ASSERT(gssPadLen == 0 || padding != NULL);
25496 +
25497 +    if (padding != NULL)
25498 +        padding->buffer.length = gssPadLen;
25499 +
25500 +    header->buffer.length = gssHeaderLen;
25501 +
25502 +    if (conf_state != NULL)
25503 +        *conf_state = conf_req_flag;
25504 +
25505 +    *minor = 0;
25506 +    return GSS_S_COMPLETE;
25507 +}
25508 +
25509 +OM_uint32 GSSAPI_CALLCONV
25510 +gss_wrap_iov_length(OM_uint32 *minor,
25511 +                    gss_ctx_id_t ctx,
25512 +                    int conf_req_flag,
25513 +                    gss_qop_t qop_req,
25514 +                    int *conf_state,
25515 +                    gss_iov_buffer_desc *iov,
25516 +                    int iov_count)
25517 +{
25518 +    OM_uint32 major;
25519 +
25520 +    if (ctx == GSS_C_NO_CONTEXT) {
25521 +        *minor = EINVAL;
25522 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
25523 +    }
25524 +
25525 +    *minor = 0;
25526 +
25527 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
25528 +
25529 +    if (!CTX_IS_ESTABLISHED(ctx)) {
25530 +        major = GSS_S_NO_CONTEXT;
25531 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
25532 +        goto cleanup;
25533 +    }
25534 +
25535 +    major = gssEapWrapIovLength(minor, ctx, conf_req_flag, qop_req,
25536 +                                conf_state, iov, iov_count);
25537 +    if (GSS_ERROR(major))
25538 +        goto cleanup;
25539 +
25540 +cleanup:
25541 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
25542 +
25543 +    return major;
25544 +}
25545 diff --git a/mech_eap/wrap_size_limit.c b/mech_eap/wrap_size_limit.c
25546 new file mode 100644
25547 index 0000000..d11fd63
25548 --- /dev/null
25549 +++ b/mech_eap/wrap_size_limit.c
25550 @@ -0,0 +1,97 @@
25551 +/*
25552 + * Copyright (c) 2011, JANET(UK)
25553 + * All rights reserved.
25554 + *
25555 + * Redistribution and use in source and binary forms, with or without
25556 + * modification, are permitted provided that the following conditions
25557 + * are met:
25558 + *
25559 + * 1. Redistributions of source code must retain the above copyright
25560 + *    notice, this list of conditions and the following disclaimer.
25561 + *
25562 + * 2. Redistributions in binary form must reproduce the above copyright
25563 + *    notice, this list of conditions and the following disclaimer in the
25564 + *    documentation and/or other materials provided with the distribution.
25565 + *
25566 + * 3. Neither the name of JANET(UK) nor the names of its contributors
25567 + *    may be used to endorse or promote products derived from this software
25568 + *    without specific prior written permission.
25569 + *
25570 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25571 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25572 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25573 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25574 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25575 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25576 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25577 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25578 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25579 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25580 + * SUCH DAMAGE.
25581 + */
25582 +
25583 +/*
25584 + * Message protection services: determine maximum input size.
25585 + */
25586 +
25587 +#include "gssapiP_eap.h"
25588 +
25589 +OM_uint32 GSSAPI_CALLCONV
25590 +gss_wrap_size_limit(OM_uint32 *minor,
25591 +                    gss_ctx_id_t ctx,
25592 +                    int conf_req_flag,
25593 +                    gss_qop_t qop_req,
25594 +                    OM_uint32 req_output_size,
25595 +                    OM_uint32 *max_input_size)
25596 +{
25597 +    gss_iov_buffer_desc iov[4];
25598 +    OM_uint32 major, overhead;
25599 +
25600 +    if (ctx == GSS_C_NO_CONTEXT) {
25601 +        *minor = EINVAL;
25602 +        return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
25603 +    }
25604 +
25605 +    *minor = 0;
25606 +
25607 +    GSSEAP_MUTEX_LOCK(&ctx->mutex);
25608 +
25609 +    if (!CTX_IS_ESTABLISHED(ctx)) {
25610 +        major = GSS_S_NO_CONTEXT;
25611 +        *minor = GSSEAP_CONTEXT_INCOMPLETE;
25612 +        goto cleanup;
25613 +    }
25614 +
25615 +    iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
25616 +    iov[0].buffer.value = NULL;
25617 +    iov[0].buffer.length = 0;
25618 +
25619 +    iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
25620 +    iov[1].buffer.length = req_output_size;
25621 +    iov[1].buffer.value = NULL;
25622 +
25623 +    iov[2].type = GSS_IOV_BUFFER_TYPE_PADDING;
25624 +    iov[2].buffer.value = NULL;
25625 +    iov[2].buffer.length = 0;
25626 +
25627 +    iov[3].type = GSS_IOV_BUFFER_TYPE_TRAILER;
25628 +    iov[3].buffer.value = NULL;
25629 +    iov[3].buffer.length = 0;
25630 +
25631 +    major = gssEapWrapIovLength(minor, ctx, conf_req_flag, qop_req,
25632 +                                NULL, iov, 4);
25633 +    if (GSS_ERROR(major))
25634 +        goto cleanup;
25635 +
25636 +    overhead = iov[0].buffer.length + iov[3].buffer.length;
25637 +
25638 +    if (iov[2].buffer.length == 0 && overhead < req_output_size)
25639 +        *max_input_size = req_output_size - overhead;
25640 +    else
25641 +        *max_input_size = 0;
25642 +
25643 +cleanup:
25644 +    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
25645 +
25646 +    return major;
25647 +}
25648 -- 
25649 1.7.5.4
25650