1/*-
2 * Copyright (c) 2005 Doug Rabson
3 * All rights reserved.
4 *
5 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include "mech_locl.h"
30#include <heim_threads.h>
31
32#ifdef __BLOCKS__
33#include <Block.h>
34#endif
35
36#ifdef __BLOCKS__
37
38static void
39complete_block(void *ctx, OM_uint32 maj_stat,
40	       gss_status_id_t status, gss_cred_id_t cred,
41	       gss_OID_set set, OM_uint32 min_time)
42{
43    gss_acquire_cred_complete complete = ctx;
44
45    complete(status, cred, set, min_time);
46    Block_release(complete);
47}
48
49OM_uint32 GSSAPI_LIB_FUNCTION
50gss_acquire_cred_ex(const gss_name_t desired_name,
51		    OM_uint32 flags,
52		    OM_uint32 time_req,
53		    gss_const_OID desired_mech,
54		    gss_cred_usage_t cred_usage,
55		    gss_auth_identity_t identity,
56		    gss_acquire_cred_complete complete)
57{
58    OM_uint32 ret;
59
60    complete = (gss_acquire_cred_complete)Block_copy(complete);
61
62    ret = gss_acquire_cred_ex_f(NULL,
63				desired_name,
64				flags,
65				time_req,
66				desired_mech,
67				cred_usage,
68				identity,
69				complete,
70				complete_block);
71    if (ret != GSS_S_COMPLETE)
72	Block_release(complete);
73    return ret;
74}
75#endif
76
77
78OM_uint32 GSSAPI_LIB_FUNCTION
79gss_acquire_cred_ex_f(gss_status_id_t status,
80		      gss_name_t desired_name,
81		      OM_uint32 flags,
82		      OM_uint32 time_req,
83		      gss_const_OID desired_mech,
84		      gss_cred_usage_t cred_usage,
85		      gss_auth_identity_t identity,
86		      void * userctx,
87		      void (*usercomplete)(void *, OM_uint32, gss_status_id_t, gss_cred_id_t, gss_OID_set, OM_uint32))
88{
89        OM_uint32 major_status, minor_status;
90	gss_name_t name = GSS_C_NO_NAME;
91	gss_cred_id_t cred;
92	OM_uint32 junk;
93	gss_buffer_desc buffer;
94
95	if (usercomplete == NULL)
96	    return GSS_S_CALL_INACCESSIBLE_READ;
97
98	/*
99	 * If no desired_name, make one up from the identity
100	 */
101	if (desired_name == GSS_C_NO_NAME) {
102	    char *str;
103	    if (identity->username == NULL)
104		return GSS_S_FAILURE;
105	    if (identity->realm)
106		asprintf(&str, "%s@%s", identity->username, identity->realm);
107	    else
108		str = strdup(identity->username);
109	    buffer.value = str;
110	    buffer.length = strlen(str);
111
112	    major_status = gss_import_name(&minor_status, &buffer, GSS_C_NT_USER_NAME, &name);
113	    free(str);
114	    if (major_status)
115		return major_status;
116
117	    desired_name = name;
118	}
119
120	/*
121	 * First make sure that at least one of the requested
122	 * mechanisms is one that we support.
123	 */
124	if (desired_mech) {
125		int t;
126		gss_test_oid_set_member(&junk, desired_mech, _gss_mech_oids, &t);
127		if (!t) {
128			if (name)
129				gss_release_name(&junk, &name);
130			return (GSS_S_BAD_MECH);
131		}
132	}
133
134	buffer.value = identity->password;
135	buffer.length = strlen(identity->password);
136
137	cred = GSS_C_NO_CREDENTIAL;
138
139	major_status = gss_acquire_cred_ext(&minor_status,
140					    desired_name,
141					    GSS_C_CRED_PASSWORD,
142					    &buffer,
143					    time_req,
144					    desired_mech,
145					    cred_usage,
146					    &cred);
147	if (name)
148		gss_release_name(&junk, &name);
149	if (major_status)
150		return major_status;
151
152	usercomplete(userctx, major_status, status,
153		     cred, GSS_C_NO_OID_SET, GSS_C_INDEFINITE);
154
155	return GSS_S_COMPLETE;
156}
157