12 #define DECL_SSPI_FUNCTION(linkage, rettype, name, params) \
13 typedef rettype (WINAPI *t_##name) params; \
14 linkage t_##name p_##name
15 #define GET_SSPI_FUNCTION(module, name) \
16 p_##name = module ? (t_##name) GetProcAddress(module, #name) : NULL
18 DECL_SSPI_FUNCTION(static, SECURITY_STATUS
,
19 AcquireCredentialsHandleA
,
20 (SEC_CHAR
*, SEC_CHAR
*, ULONG
, PLUID
,
21 PVOID
, SEC_GET_KEY_FN
, PVOID
, PCredHandle
, PTimeStamp
));
22 DECL_SSPI_FUNCTION(static, SECURITY_STATUS
,
23 InitializeSecurityContextA
,
24 (PCredHandle
, PCtxtHandle
, SEC_CHAR
*, ULONG
, ULONG
,
25 ULONG
, PSecBufferDesc
, ULONG
, PCtxtHandle
,
26 PSecBufferDesc
, PULONG
, PTimeStamp
));
27 DECL_SSPI_FUNCTION(static, SECURITY_STATUS
,
30 DECL_SSPI_FUNCTION(static, SECURITY_STATUS
,
31 FreeCredentialsHandle
,
33 DECL_SSPI_FUNCTION(static, SECURITY_STATUS
,
34 DeleteSecurityContext
,
36 DECL_SSPI_FUNCTION(static, SECURITY_STATUS
,
37 QueryContextAttributesA
,
38 (PCtxtHandle
, ULONG
, PVOID
));
39 DECL_SSPI_FUNCTION(static, SECURITY_STATUS
,
41 (PCtxtHandle
, ULONG
, PSecBufferDesc
, ULONG
));
43 static HMODULE security_module
= NULL
;
45 typedef struct winSsh_gss_ctx
{
46 unsigned long maj_stat
;
47 unsigned long min_stat
;
48 CredHandle cred_handle
;
50 PCtxtHandle context_handle
;
55 const Ssh_gss_buf gss_mech_krb5
={9,"\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"};
57 int ssh_gss_init(void)
60 return 1; /* already initialised */
62 security_module
= LoadLibrary("secur32.dll");
63 if (security_module
) {
64 GET_SSPI_FUNCTION(security_module
, AcquireCredentialsHandleA
);
65 GET_SSPI_FUNCTION(security_module
, InitializeSecurityContextA
);
66 GET_SSPI_FUNCTION(security_module
, FreeContextBuffer
);
67 GET_SSPI_FUNCTION(security_module
, FreeCredentialsHandle
);
68 GET_SSPI_FUNCTION(security_module
, DeleteSecurityContext
);
69 GET_SSPI_FUNCTION(security_module
, QueryContextAttributesA
);
70 GET_SSPI_FUNCTION(security_module
, MakeSignature
);
76 Ssh_gss_stat
ssh_gss_indicate_mech(Ssh_gss_buf
*mech
)
78 *mech
= gss_mech_krb5
;
83 Ssh_gss_stat
ssh_gss_import_name(char *host
, Ssh_gss_name
*srv_name
)
88 if (host
== NULL
) return SSH_GSS_FAILURE
;
90 /* copy it into form host/FQDN */
91 pStr
= dupcat("host/", host
, NULL
);
93 *srv_name
= (Ssh_gss_name
) pStr
;
98 Ssh_gss_stat
ssh_gss_acquire_cred(Ssh_gss_ctx
*ctx
)
100 winSsh_gss_ctx
*winctx
= snew(winSsh_gss_ctx
);
101 memset(winctx
, 0, sizeof(winSsh_gss_ctx
));
103 /* prepare our "wrapper" structure */
104 winctx
->maj_stat
= winctx
->min_stat
= SEC_E_OK
;
105 winctx
->context_handle
= NULL
;
107 /* Specifying no principal name here means use the credentials of
108 the current logged-in user */
110 winctx
->maj_stat
= p_AcquireCredentialsHandleA(NULL
,
112 SECPKG_CRED_OUTBOUND
,
117 &winctx
->cred_handle
,
120 if (winctx
->maj_stat
!= SEC_E_OK
) return SSH_GSS_FAILURE
;
122 *ctx
= (Ssh_gss_ctx
) winctx
;
127 Ssh_gss_stat
ssh_gss_init_sec_context(Ssh_gss_ctx
*ctx
,
128 Ssh_gss_name srv_name
,
130 Ssh_gss_buf
*recv_tok
,
131 Ssh_gss_buf
*send_tok
)
133 winSsh_gss_ctx
*winctx
= (winSsh_gss_ctx
*) *ctx
;
134 SecBuffer wsend_tok
= {send_tok
->length
,SECBUFFER_TOKEN
,send_tok
->value
};
135 SecBuffer wrecv_tok
= {recv_tok
->length
,SECBUFFER_TOKEN
,recv_tok
->value
};
136 SecBufferDesc output_desc
={SECBUFFER_VERSION
,1,&wsend_tok
};
137 SecBufferDesc input_desc
={SECBUFFER_VERSION
,1,&wrecv_tok
};
138 unsigned long flags
=ISC_REQ_MUTUAL_AUTH
|ISC_REQ_REPLAY_DETECT
|
139 ISC_REQ_CONFIDENTIALITY
|ISC_REQ_ALLOCATE_MEMORY
;
140 unsigned long ret_flags
=0;
142 /* check if we have to delegate ... */
143 if (to_deleg
) flags
|= ISC_REQ_DELEGATE
;
144 winctx
->maj_stat
= p_InitializeSecurityContextA(&winctx
->cred_handle
,
145 winctx
->context_handle
,
149 SECURITY_NATIVE_DREP
,
157 /* prepare for the next round */
158 winctx
->context_handle
= &winctx
->context
;
159 send_tok
->value
= wsend_tok
.pvBuffer
;
160 send_tok
->length
= wsend_tok
.cbBuffer
;
162 /* check & return our status */
163 if (winctx
->maj_stat
==SEC_E_OK
) return SSH_GSS_S_COMPLETE
;
164 if (winctx
->maj_stat
==SEC_I_CONTINUE_NEEDED
) return SSH_GSS_S_CONTINUE_NEEDED
;
166 return SSH_GSS_FAILURE
;
169 Ssh_gss_stat
ssh_gss_free_tok(Ssh_gss_buf
*send_tok
)
172 if (send_tok
== NULL
) return SSH_GSS_FAILURE
;
174 /* free Windows buffer */
175 p_FreeContextBuffer(send_tok
->value
);
176 SSH_GSS_CLEAR_BUF(send_tok
);
181 Ssh_gss_stat
ssh_gss_release_cred(Ssh_gss_ctx
*ctx
)
183 winSsh_gss_ctx
*winctx
= (winSsh_gss_ctx
*) *ctx
;
186 if (winctx
== NULL
) return SSH_GSS_FAILURE
;
188 /* free Windows data */
189 p_FreeCredentialsHandle(&winctx
->cred_handle
);
190 p_DeleteSecurityContext(&winctx
->context
);
192 /* delete our "wrapper" structure */
194 *ctx
= (Ssh_gss_ctx
) NULL
;
200 Ssh_gss_stat
ssh_gss_release_name(Ssh_gss_name
*srv_name
)
202 char *pStr
= (char *) *srv_name
;
204 if (pStr
== NULL
) return SSH_GSS_FAILURE
;
206 *srv_name
= (Ssh_gss_name
) NULL
;
211 Ssh_gss_stat
ssh_gss_display_status(Ssh_gss_ctx ctx
, Ssh_gss_buf
*buf
)
213 winSsh_gss_ctx
*winctx
= (winSsh_gss_ctx
*) ctx
;
216 if (winctx
== NULL
) return SSH_GSS_FAILURE
;
218 /* decode the error code */
219 switch (winctx
->maj_stat
) {
220 case SEC_E_OK
: msg
="SSPI status OK"; break;
221 case SEC_E_INVALID_HANDLE
: msg
="The handle passed to the function"
224 case SEC_E_TARGET_UNKNOWN
: msg
="The target was not recognized."; break;
225 case SEC_E_LOGON_DENIED
: msg
="The logon failed."; break;
226 case SEC_E_INTERNAL_ERROR
: msg
="The Local Security Authority cannot"
229 case SEC_E_NO_CREDENTIALS
: msg
="No credentials are available in the"
230 " security package.";
232 case SEC_E_NO_AUTHENTICATING_AUTHORITY
:
233 msg
="No authority could be contacted for authentication."
234 "The domain name of the authenticating party could be wrong,"
235 " the domain could be unreachable, or there might have been"
236 " a trust relationship failure.";
238 case SEC_E_INSUFFICIENT_MEMORY
:
239 msg
="One or more of the SecBufferDesc structures passed as"
240 " an OUT parameter has a buffer that is too small.";
242 case SEC_E_INVALID_TOKEN
:
243 msg
="The error is due to a malformed input token, such as a"
244 " token corrupted in transit, a token"
245 " of incorrect size, or a token passed into the wrong"
246 " security package. Passing a token to"
247 " the wrong package can happen if client and server did not"
248 " negotiate the proper security package.";
251 msg
= "Internal SSPI error";
255 buf
->value
= dupstr(msg
);
256 buf
->length
= strlen(buf
->value
);
261 Ssh_gss_stat
ssh_gss_get_mic(Ssh_gss_ctx ctx
, Ssh_gss_buf
*buf
,
264 winSsh_gss_ctx
*winctx
= (winSsh_gss_ctx
*) ctx
;
265 SecPkgContext_Sizes ContextSizes
;
266 SecBufferDesc InputBufferDescriptor
;
267 SecBuffer InputSecurityToken
[2];
269 if (winctx
== NULL
) return SSH_GSS_FAILURE
;
271 winctx
->maj_stat
= 0;
273 memset(&ContextSizes
, 0, sizeof(ContextSizes
));
275 winctx
->maj_stat
= p_QueryContextAttributesA(&winctx
->context
,
279 if (winctx
->maj_stat
!= SEC_E_OK
||
280 ContextSizes
.cbMaxSignature
== 0)
281 return winctx
->maj_stat
;
283 InputBufferDescriptor
.cBuffers
= 2;
284 InputBufferDescriptor
.pBuffers
= InputSecurityToken
;
285 InputBufferDescriptor
.ulVersion
= SECBUFFER_VERSION
;
286 InputSecurityToken
[0].BufferType
= SECBUFFER_DATA
;
287 InputSecurityToken
[0].cbBuffer
= buf
->length
;
288 InputSecurityToken
[0].pvBuffer
= buf
->value
;
289 InputSecurityToken
[1].BufferType
= SECBUFFER_TOKEN
;
290 InputSecurityToken
[1].cbBuffer
= ContextSizes
.cbMaxSignature
;
291 InputSecurityToken
[1].pvBuffer
= snewn(ContextSizes
.cbMaxSignature
, char);
293 winctx
->maj_stat
= p_MakeSignature(&winctx
->context
,
295 &InputBufferDescriptor
,
298 if (winctx
->maj_stat
== SEC_E_OK
) {
299 hash
->length
= InputSecurityToken
[1].cbBuffer
;
300 hash
->value
= InputSecurityToken
[1].pvBuffer
;
303 return winctx
->maj_stat
;
306 Ssh_gss_stat
ssh_gss_free_mic(Ssh_gss_buf
*hash
)
314 /* Dummy function so this source file defines something if NO_GSSAPI
317 int ssh_gss_init(void)