10 #define DECL_SSPI_FUNCTION(linkage, rettype, name, params) \
11 typedef rettype (WINAPI *t_##name) params; \
12 linkage t_##name p_##name
13 #define GET_SSPI_FUNCTION(module, name) \
14 p_##name = module ? (t_##name) GetProcAddress(module, #name) : NULL
16 DECL_SSPI_FUNCTION(static, SECURITY_STATUS
,
17 AcquireCredentialsHandleA
,
18 (SEC_CHAR
*, SEC_CHAR
*, ULONG
, PLUID
,
19 PVOID
, SEC_GET_KEY_FN
, PVOID
, PCredHandle
, PTimeStamp
));
20 DECL_SSPI_FUNCTION(static, SECURITY_STATUS
,
21 InitializeSecurityContextA
,
22 (PCredHandle
, PCtxtHandle
, SEC_CHAR
*, ULONG
, ULONG
,
23 ULONG
, PSecBufferDesc
, ULONG
, PCtxtHandle
,
24 PSecBufferDesc
, PULONG
, PTimeStamp
));
25 DECL_SSPI_FUNCTION(static, SECURITY_STATUS
,
28 DECL_SSPI_FUNCTION(static, SECURITY_STATUS
,
29 FreeCredentialsHandle
,
31 DECL_SSPI_FUNCTION(static, SECURITY_STATUS
,
32 DeleteSecurityContext
,
34 DECL_SSPI_FUNCTION(static, SECURITY_STATUS
,
35 QueryContextAttributesA
,
36 (PCtxtHandle
, ULONG
, PVOID
));
37 DECL_SSPI_FUNCTION(static, SECURITY_STATUS
,
39 (PCtxtHandle
, ULONG
, PSecBufferDesc
, ULONG
));
41 static HMODULE security_module
= NULL
;
43 typedef struct winSsh_gss_ctx
{
44 unsigned long maj_stat
;
45 unsigned long min_stat
;
46 CredHandle cred_handle
;
48 PCtxtHandle context_handle
;
53 const Ssh_gss_buf gss_mech_krb5
={9,"\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"};
55 int ssh_gss_init(void)
58 return 1; /* already initialised */
60 security_module
= LoadLibrary("secur32.dll");
61 if (security_module
) {
62 GET_SSPI_FUNCTION(security_module
, AcquireCredentialsHandleA
);
63 GET_SSPI_FUNCTION(security_module
, InitializeSecurityContextA
);
64 GET_SSPI_FUNCTION(security_module
, FreeContextBuffer
);
65 GET_SSPI_FUNCTION(security_module
, FreeCredentialsHandle
);
66 GET_SSPI_FUNCTION(security_module
, DeleteSecurityContext
);
67 GET_SSPI_FUNCTION(security_module
, QueryContextAttributesA
);
68 GET_SSPI_FUNCTION(security_module
, MakeSignature
);
74 Ssh_gss_stat
ssh_gss_indicate_mech(Ssh_gss_buf
*mech
)
76 *mech
= gss_mech_krb5
;
81 Ssh_gss_stat
ssh_gss_import_name(char *host
, Ssh_gss_name
*srv_name
)
86 if (host
== NULL
) return SSH_GSS_FAILURE
;
88 /* copy it into form host/FQDN */
89 pStr
= dupcat("host/", host
, NULL
);
91 *srv_name
= (Ssh_gss_name
) pStr
;
96 Ssh_gss_stat
ssh_gss_acquire_cred(Ssh_gss_ctx
*ctx
)
98 winSsh_gss_ctx
*winctx
= snew(winSsh_gss_ctx
);
99 memset(winctx
, 0, sizeof(winSsh_gss_ctx
));
101 /* prepare our "wrapper" structure */
102 winctx
->maj_stat
= winctx
->min_stat
= SEC_E_OK
;
103 winctx
->context_handle
= NULL
;
105 /* Specifying no principal name here means use the credentials of
106 the current logged-in user */
108 winctx
->maj_stat
= p_AcquireCredentialsHandleA(NULL
,
110 SECPKG_CRED_OUTBOUND
,
115 &winctx
->cred_handle
,
118 if (winctx
->maj_stat
!= SEC_E_OK
) return SSH_GSS_FAILURE
;
120 *ctx
= (Ssh_gss_ctx
) winctx
;
125 Ssh_gss_stat
ssh_gss_init_sec_context(Ssh_gss_ctx
*ctx
,
126 Ssh_gss_name srv_name
,
128 Ssh_gss_buf
*recv_tok
,
129 Ssh_gss_buf
*send_tok
)
131 winSsh_gss_ctx
*winctx
= (winSsh_gss_ctx
*) *ctx
;
132 SecBuffer wsend_tok
= {send_tok
->length
,SECBUFFER_TOKEN
,send_tok
->value
};
133 SecBuffer wrecv_tok
= {recv_tok
->length
,SECBUFFER_TOKEN
,recv_tok
->value
};
134 SecBufferDesc output_desc
={SECBUFFER_VERSION
,1,&wsend_tok
};
135 SecBufferDesc input_desc
={SECBUFFER_VERSION
,1,&wrecv_tok
};
136 unsigned long flags
=ISC_REQ_MUTUAL_AUTH
|ISC_REQ_REPLAY_DETECT
|
137 ISC_REQ_CONFIDENTIALITY
|ISC_REQ_ALLOCATE_MEMORY
;
138 unsigned long ret_flags
=0;
140 /* check if we have to delegate ... */
141 if (to_deleg
) flags
|= ISC_REQ_DELEGATE
;
142 winctx
->maj_stat
= p_InitializeSecurityContextA(&winctx
->cred_handle
,
143 winctx
->context_handle
,
147 SECURITY_NATIVE_DREP
,
155 /* prepare for the next round */
156 winctx
->context_handle
= &winctx
->context
;
157 send_tok
->value
= wsend_tok
.pvBuffer
;
158 send_tok
->length
= wsend_tok
.cbBuffer
;
160 /* check & return our status */
161 if (winctx
->maj_stat
==SEC_E_OK
) return SSH_GSS_S_COMPLETE
;
162 if (winctx
->maj_stat
==SEC_I_CONTINUE_NEEDED
) return SSH_GSS_S_CONTINUE_NEEDED
;
164 return SSH_GSS_FAILURE
;
167 Ssh_gss_stat
ssh_gss_free_tok(Ssh_gss_buf
*send_tok
)
170 if (send_tok
== NULL
) return SSH_GSS_FAILURE
;
172 /* free Windows buffer */
173 p_FreeContextBuffer(send_tok
->value
);
174 SSH_GSS_CLEAR_BUF(send_tok
);
179 Ssh_gss_stat
ssh_gss_release_cred(Ssh_gss_ctx
*ctx
)
181 winSsh_gss_ctx
*winctx
= (winSsh_gss_ctx
*) *ctx
;
184 if (winctx
== NULL
) return SSH_GSS_FAILURE
;
186 /* free Windows data */
187 p_FreeCredentialsHandle(&winctx
->cred_handle
);
188 p_DeleteSecurityContext(&winctx
->context
);
190 /* delete our "wrapper" structure */
192 *ctx
= (Ssh_gss_ctx
) NULL
;
198 Ssh_gss_stat
ssh_gss_release_name(Ssh_gss_name
*srv_name
)
200 char *pStr
= (char *) *srv_name
;
202 if (pStr
== NULL
) return SSH_GSS_FAILURE
;
204 *srv_name
= (Ssh_gss_name
) NULL
;
209 Ssh_gss_stat
ssh_gss_display_status(Ssh_gss_ctx ctx
, Ssh_gss_buf
*buf
)
211 winSsh_gss_ctx
*winctx
= (winSsh_gss_ctx
*) ctx
;
214 if (winctx
== NULL
) return SSH_GSS_FAILURE
;
216 /* decode the error code */
217 switch (winctx
->maj_stat
) {
218 case SEC_E_OK
: msg
="SSPI status OK"; break;
219 case SEC_E_INVALID_HANDLE
: msg
="The handle passed to the function"
222 case SEC_E_TARGET_UNKNOWN
: msg
="The target was not recognized."; break;
223 case SEC_E_LOGON_DENIED
: msg
="The logon failed."; break;
224 case SEC_E_INTERNAL_ERROR
: msg
="The Local Security Authority cannot"
227 case SEC_E_NO_CREDENTIALS
: msg
="No credentials are available in the"
228 " security package.";
230 case SEC_E_NO_AUTHENTICATING_AUTHORITY
:
231 msg
="No authority could be contacted for authentication."
232 "The domain name of the authenticating party could be wrong,"
233 " the domain could be unreachable, or there might have been"
234 " a trust relationship failure.";
236 case SEC_E_INSUFFICIENT_MEMORY
:
237 msg
="One or more of the SecBufferDesc structures passed as"
238 " an OUT parameter has a buffer that is too small.";
240 case SEC_E_INVALID_TOKEN
:
241 msg
="The error is due to a malformed input token, such as a"
242 " token corrupted in transit, a token"
243 " of incorrect size, or a token passed into the wrong"
244 " security package. Passing a token to"
245 " the wrong package can happen if client and server did not"
246 " negotiate the proper security package.";
249 msg
= "Internal SSPI error";
253 buf
->value
= dupstr(msg
);
254 buf
->length
= strlen(buf
->length
);
259 Ssh_gss_stat
ssh_gss_get_mic(Ssh_gss_ctx ctx
, Ssh_gss_buf
*buf
,
262 winSsh_gss_ctx
*winctx
= (winSsh_gss_ctx
*) ctx
;
263 SecPkgContext_Sizes ContextSizes
;
264 SecBufferDesc InputBufferDescriptor
;
265 SecBuffer InputSecurityToken
[2];
267 if (winctx
== NULL
) return SSH_GSS_FAILURE
;
269 winctx
->maj_stat
= 0;
271 memset(&ContextSizes
, 0, sizeof(ContextSizes
));
273 winctx
->maj_stat
= p_QueryContextAttributesA(&winctx
->context
,
277 if (winctx
->maj_stat
!= SEC_E_OK
||
278 ContextSizes
.cbMaxSignature
== 0)
279 return winctx
->maj_stat
;
281 InputBufferDescriptor
.cBuffers
= 2;
282 InputBufferDescriptor
.pBuffers
= InputSecurityToken
;
283 InputBufferDescriptor
.ulVersion
= SECBUFFER_VERSION
;
284 InputSecurityToken
[0].BufferType
= SECBUFFER_DATA
;
285 InputSecurityToken
[0].cbBuffer
= buf
->length
;
286 InputSecurityToken
[0].pvBuffer
= buf
->value
;
287 InputSecurityToken
[1].BufferType
= SECBUFFER_TOKEN
;
288 InputSecurityToken
[1].cbBuffer
= ContextSizes
.cbMaxSignature
;
289 InputSecurityToken
[1].pvBuffer
= snewn(ContextSizes
.cbMaxSignature
, char);
291 winctx
->maj_stat
= p_MakeSignature(&winctx
->context
,
293 &InputBufferDescriptor
,
296 if (winctx
->maj_stat
== SEC_E_OK
) {
297 hash
->length
= InputSecurityToken
[1].cbBuffer
;
298 hash
->value
= InputSecurityToken
[1].pvBuffer
;
301 return winctx
->maj_stat
;
304 Ssh_gss_stat
ssh_gss_free_mic(Ssh_gss_buf
*hash
)
312 /* Dummy function so this source file defines something if NO_GSSAPI
315 int ssh_gss_init(void)