1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 * Copyright 2015 Red Hat, Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person
6 * obtaining a copy of this software and associated documentation files
7 * (the "Software"), to deal in the Software without restriction,
8 * including without limitation the rights to use, copy, modify, merge,
9 * publish, distribute, sublicense, and/or sell copies of the Software,
10 * and to permit persons to whom the Software is furnished to do so,
11 * subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <assert.h>
30
31 #include "common.h"
32
33
34 /*
35 * Test program for inquiring about a security context, intended to be run from
36 * a Python test script. Partially establishes a context to test inquiring
37 * about an incomplete context, and then establishes full contexts and inquires
38 * them. Exits with status 0 if all operations are successful, or 1 if not.
39 *
40 * Usage: ./t_inq_ctx target_name
41 */
42
43 static void
check_inq_context(gss_ctx_id_t context,int incomplete,gss_OID expected_mech,OM_uint32 expected_flags,int expected_locally_init)44 check_inq_context(gss_ctx_id_t context, int incomplete, gss_OID expected_mech,
45 OM_uint32 expected_flags, int expected_locally_init)
46 {
47 OM_uint32 major, minor;
48 gss_name_t out_init_name, out_accept_name;
49 OM_uint32 out_lifetime;
50 gss_OID out_mech_type;
51 OM_uint32 out_flags;
52 int out_locally_init;
53 int out_open;
54
55 major = gss_inquire_context(&minor, context, &out_init_name,
56 &out_accept_name, &out_lifetime,
57 &out_mech_type, &out_flags, &out_locally_init,
58 &out_open);
59 check_gsserr("gss_inquire_context", major, minor);
60
61 assert(gss_oid_equal(out_mech_type, expected_mech));
62 assert(out_flags == expected_flags);
63 assert(out_locally_init == expected_locally_init);
64 if (incomplete) {
65 assert(!out_open);
66 assert(out_lifetime == 0);
67 assert(out_init_name == GSS_C_NO_NAME);
68 assert(out_accept_name == GSS_C_NO_NAME);
69 } else {
70 assert(out_open);
71 assert(out_lifetime > 0);
72 assert(out_init_name != GSS_C_NO_NAME);
73 assert(out_accept_name != GSS_C_NO_NAME);
74 }
75
76 (void)gss_release_name(&minor, &out_accept_name);
77 (void)gss_release_name(&minor, &out_init_name);
78 }
79
80 /* Call gss_init_sec_context() once to create an initiator context (which will
81 * be partial if flags includes GSS_C_MUTUAL_FLAG and the mech is krb5). */
82 static void
start_init_context(gss_OID mech,gss_cred_id_t cred,gss_name_t tname,OM_uint32 flags,gss_ctx_id_t * ctx)83 start_init_context(gss_OID mech, gss_cred_id_t cred, gss_name_t tname,
84 OM_uint32 flags, gss_ctx_id_t *ctx)
85 {
86 OM_uint32 major, minor;
87 gss_buffer_desc itok = GSS_C_EMPTY_BUFFER;
88
89 *ctx = GSS_C_NO_CONTEXT;
90 major = gss_init_sec_context(&minor, cred, ctx, tname, mech, flags,
91 GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS,
92 NULL, NULL, &itok, NULL, NULL);
93 check_gsserr("gss_init_sec_context", major, minor);
94 (void)gss_release_buffer(&minor, &itok);
95 }
96
97 /* Call gss_init_sec_context() and gss_accept_sec_context() once to create an
98 * acceptor context. */
99 static void
start_accept_context(gss_OID mech,gss_cred_id_t icred,gss_cred_id_t acred,gss_name_t tname,OM_uint32 flags,gss_ctx_id_t * ctx)100 start_accept_context(gss_OID mech, gss_cred_id_t icred, gss_cred_id_t acred,
101 gss_name_t tname, OM_uint32 flags, gss_ctx_id_t *ctx)
102 {
103 OM_uint32 major, minor;
104 gss_ctx_id_t ictx = GSS_C_NO_CONTEXT;
105 gss_buffer_desc itok = GSS_C_EMPTY_BUFFER, atok = GSS_C_EMPTY_BUFFER;
106
107 major = gss_init_sec_context(&minor, icred, &ictx, tname, mech, flags,
108 GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS,
109 NULL, NULL, &itok, NULL, NULL);
110 check_gsserr("gss_init_sec_context", major, minor);
111
112 *ctx = GSS_C_NO_CONTEXT;
113 major = gss_accept_sec_context(&minor, ctx, acred, &itok,
114 GSS_C_NO_CHANNEL_BINDINGS, NULL, NULL,
115 &atok, NULL, NULL, NULL);
116 check_gsserr("gss_accept_sec_context", major, minor);
117
118 (void)gss_release_buffer(&minor, &itok);
119 (void)gss_release_buffer(&minor, &atok);
120 (void)gss_delete_sec_context(&minor, &ictx, NULL);
121 }
122
123 static void
partial_iakerb_acceptor(const char * username,const char * password,gss_name_t tname,OM_uint32 flags,gss_ctx_id_t * ctx)124 partial_iakerb_acceptor(const char *username, const char *password,
125 gss_name_t tname, OM_uint32 flags, gss_ctx_id_t *ctx)
126 {
127 OM_uint32 major, minor;
128 gss_name_t name;
129 gss_buffer_desc ubuf, pwbuf;
130 gss_OID_set_desc mechlist;
131 gss_cred_id_t icred, acred;
132
133 mechlist.count = 1;
134 mechlist.elements = &mech_iakerb;
135
136 /* Import the username. */
137 ubuf.value = (void *)username;
138 ubuf.length = strlen(username);
139 major = gss_import_name(&minor, &ubuf, GSS_C_NT_USER_NAME, &name);
140 check_gsserr("gss_import_name", major, minor);
141
142 /* Create an IAKERB initiator cred with the username and password. */
143 pwbuf.value = (void *)password;
144 pwbuf.length = strlen(password);
145 major = gss_acquire_cred_with_password(&minor, name, &pwbuf, 0,
146 &mechlist, GSS_C_INITIATE, &icred,
147 NULL, NULL);
148 check_gsserr("gss_acquire_cred_with_password", major, minor);
149
150 /* Create an acceptor cred with support for IAKERB. */
151 major = gss_acquire_cred(&minor, GSS_C_NO_NAME, GSS_C_INDEFINITE,
152 &mechlist, GSS_C_ACCEPT, &acred, NULL, NULL);
153 check_gsserr("gss_acquire_cred", major, minor);
154
155 /* Begin context establishment to get a partial acceptor context. */
156 start_accept_context(&mech_iakerb, icred, acred, tname, flags, ctx);
157
158 (void)gss_release_name(&minor, &name);
159 (void)gss_release_cred(&minor, &icred);
160 (void)gss_release_cred(&minor, &acred);
161 }
162
163 /* Create a partially established SPNEGO acceptor. */
164 static void
partial_spnego_acceptor(gss_name_t tname,gss_ctx_id_t * ctx)165 partial_spnego_acceptor(gss_name_t tname, gss_ctx_id_t *ctx)
166 {
167 OM_uint32 major, minor;
168 gss_buffer_desc itok = GSS_C_EMPTY_BUFFER, atok;
169
170 /*
171 * We could construct a fixed SPNEGO initiator token which forces a
172 * renegotiation, but a simpler approach is to pass an empty token to
173 * gss_accept_sec_context(), taking advantage of our compatibility support
174 * for SPNEGO NegHints.
175 */
176 *ctx = GSS_C_NO_CONTEXT;
177 major = gss_accept_sec_context(&minor, ctx, GSS_C_NO_CREDENTIAL, &itok,
178 GSS_C_NO_CHANNEL_BINDINGS, NULL, NULL,
179 &atok, NULL, NULL, NULL);
180 check_gsserr("gss_accept_sec_context(neghints)", major, minor);
181
182 (void)gss_release_buffer(&minor, &atok);
183 }
184
185 int
main(int argc,char * argv[])186 main(int argc, char *argv[])
187 {
188 OM_uint32 minor, flags, dce_flags;
189 gss_name_t tname;
190 gss_ctx_id_t ictx, actx;
191 const char *username, *password;
192
193 if (argc != 4) {
194 fprintf(stderr, "Usage: %s username password targetname\n", argv[0]);
195 return 1;
196 }
197 username = argv[1];
198 password = argv[2];
199 tname = import_name(argv[3]);
200
201 flags = GSS_C_SEQUENCE_FLAG | GSS_C_MUTUAL_FLAG | GSS_C_CONF_FLAG |
202 GSS_C_INTEG_FLAG;
203 start_init_context(&mech_krb5, GSS_C_NO_CREDENTIAL, tname, flags, &ictx);
204 check_inq_context(ictx, 1, &mech_krb5, flags | GSS_C_TRANS_FLAG, 1);
205 (void)gss_delete_sec_context(&minor, &ictx, NULL);
206
207 start_init_context(&mech_iakerb, GSS_C_NO_CREDENTIAL, tname, flags, &ictx);
208 check_inq_context(ictx, 1, &mech_iakerb, flags, 1);
209 (void)gss_delete_sec_context(&minor, &ictx, NULL);
210
211 start_init_context(&mech_spnego, GSS_C_NO_CREDENTIAL, tname, flags, &ictx);
212 check_inq_context(ictx, 1, &mech_spnego, flags, 1);
213 (void)gss_delete_sec_context(&minor, &ictx, NULL);
214
215 dce_flags = flags | GSS_C_DCE_STYLE;
216 start_accept_context(&mech_krb5, GSS_C_NO_CREDENTIAL, GSS_C_NO_CREDENTIAL,
217 tname, dce_flags, &actx);
218 check_inq_context(actx, 1, &mech_krb5, dce_flags | GSS_C_TRANS_FLAG, 0);
219 (void)gss_delete_sec_context(&minor, &actx, NULL);
220
221 partial_iakerb_acceptor(username, password, tname, flags, &actx);
222 check_inq_context(actx, 1, &mech_iakerb, 0, 0);
223 (void)gss_delete_sec_context(&minor, &actx, NULL);
224
225 partial_spnego_acceptor(tname, &actx);
226 check_inq_context(actx, 1, &mech_spnego, 0, 0);
227 (void)gss_delete_sec_context(&minor, &actx, NULL);
228
229 establish_contexts(&mech_krb5, GSS_C_NO_CREDENTIAL, GSS_C_NO_CREDENTIAL,
230 tname, flags, &ictx, &actx, NULL, NULL, NULL);
231
232 check_inq_context(ictx, 0, &mech_krb5, flags | GSS_C_TRANS_FLAG, 1);
233 check_inq_context(actx, 0, &mech_krb5,
234 flags | GSS_C_TRANS_FLAG | GSS_C_PROT_READY_FLAG, 0);
235
236 (void)gss_delete_sec_context(&minor, &ictx, NULL);
237 (void)gss_delete_sec_context(&minor, &actx, NULL);
238
239 (void)gss_release_name(&minor, &tname);
240 return 0;
241 }
242