Quell more warnings and, perhaps, avoid alignment faults on 64-bit Windows.
[u/mdw/putty] / windows / wingss.c
CommitLineData
42af6a67 1#ifndef NO_GSSAPI
2
a638600c 3#include "putty.h"
4
42af6a67 5#define SECURITY_WIN32
6#include <security.h>
a638600c 7
42af6a67 8#include "sshgss.h"
9#include "misc.h"
10
11#define NOTHING
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
17
18DECL_SSPI_FUNCTION(static, SECURITY_STATUS,
19 AcquireCredentialsHandleA,
20 (SEC_CHAR *, SEC_CHAR *, ULONG, PLUID,
21 PVOID, SEC_GET_KEY_FN, PVOID, PCredHandle, PTimeStamp));
22DECL_SSPI_FUNCTION(static, SECURITY_STATUS,
23 InitializeSecurityContextA,
24 (PCredHandle, PCtxtHandle, SEC_CHAR *, ULONG, ULONG,
25 ULONG, PSecBufferDesc, ULONG, PCtxtHandle,
26 PSecBufferDesc, PULONG, PTimeStamp));
27DECL_SSPI_FUNCTION(static, SECURITY_STATUS,
28 FreeContextBuffer,
29 (PVOID));
30DECL_SSPI_FUNCTION(static, SECURITY_STATUS,
31 FreeCredentialsHandle,
32 (PCredHandle));
33DECL_SSPI_FUNCTION(static, SECURITY_STATUS,
34 DeleteSecurityContext,
35 (PCtxtHandle));
36DECL_SSPI_FUNCTION(static, SECURITY_STATUS,
37 QueryContextAttributesA,
38 (PCtxtHandle, ULONG, PVOID));
39DECL_SSPI_FUNCTION(static, SECURITY_STATUS,
40 MakeSignature,
41 (PCtxtHandle, ULONG, PSecBufferDesc, ULONG));
42
43static HMODULE security_module = NULL;
44
45typedef struct winSsh_gss_ctx {
46 unsigned long maj_stat;
47 unsigned long min_stat;
48 CredHandle cred_handle;
49 CtxtHandle context;
50 PCtxtHandle context_handle;
51 TimeStamp expiry;
52} winSsh_gss_ctx;
53
54
55const Ssh_gss_buf gss_mech_krb5={9,"\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"};
56
57int ssh_gss_init(void)
58{
59 if (security_module)
60 return 1; /* already initialised */
61
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);
71 return 1;
72 }
73 return 0;
74}
75
76Ssh_gss_stat ssh_gss_indicate_mech(Ssh_gss_buf *mech)
77{
78 *mech = gss_mech_krb5;
79 return SSH_GSS_OK;
80}
81
82
83Ssh_gss_stat ssh_gss_import_name(char *host, Ssh_gss_name *srv_name)
84{
85 char *pStr;
86
87 /* Check hostname */
88 if (host == NULL) return SSH_GSS_FAILURE;
89
90 /* copy it into form host/FQDN */
91 pStr = dupcat("host/", host, NULL);
92
93 *srv_name = (Ssh_gss_name) pStr;
94
95 return SSH_GSS_OK;
96}
97
98Ssh_gss_stat ssh_gss_acquire_cred(Ssh_gss_ctx *ctx)
99{
100 winSsh_gss_ctx *winctx = snew(winSsh_gss_ctx);
94fe9122 101 memset(winctx, 0, sizeof(winSsh_gss_ctx));
42af6a67 102
103 /* prepare our "wrapper" structure */
104 winctx->maj_stat = winctx->min_stat = SEC_E_OK;
105 winctx->context_handle = NULL;
106
107 /* Specifying no principal name here means use the credentials of
108 the current logged-in user */
109
110 winctx->maj_stat = p_AcquireCredentialsHandleA(NULL,
111 "Kerberos",
112 SECPKG_CRED_OUTBOUND,
113 NULL,
114 NULL,
115 NULL,
116 NULL,
117 &winctx->cred_handle,
118 &winctx->expiry);
119
120 if (winctx->maj_stat != SEC_E_OK) return SSH_GSS_FAILURE;
121
122 *ctx = (Ssh_gss_ctx) winctx;
123 return SSH_GSS_OK;
124}
125
126
127Ssh_gss_stat ssh_gss_init_sec_context(Ssh_gss_ctx *ctx,
128 Ssh_gss_name srv_name,
129 int to_deleg,
130 Ssh_gss_buf *recv_tok,
131 Ssh_gss_buf *send_tok)
132{
133 winSsh_gss_ctx *winctx = (winSsh_gss_ctx *) *ctx;
86557057 134 SecBuffer wsend_tok = {send_tok->length,SECBUFFER_TOKEN,send_tok->value};
135 SecBuffer wrecv_tok = {recv_tok->length,SECBUFFER_TOKEN,recv_tok->value};
42af6a67 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;
141
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,
146 (char*) srv_name,
147 flags,
148 0, /* reserved */
149 SECURITY_NATIVE_DREP,
150 &input_desc,
151 0, /* reserved */
152 &winctx->context,
153 &output_desc,
154 &ret_flags,
155 &winctx->expiry);
156
157 /* prepare for the next round */
158 winctx->context_handle = &winctx->context;
86557057 159 send_tok->value = wsend_tok.pvBuffer;
160 send_tok->length = wsend_tok.cbBuffer;
42af6a67 161
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;
165
166 return SSH_GSS_FAILURE;
167}
168
169Ssh_gss_stat ssh_gss_free_tok(Ssh_gss_buf *send_tok)
170{
171 /* check input */
172 if (send_tok == NULL) return SSH_GSS_FAILURE;
173
174 /* free Windows buffer */
86557057 175 p_FreeContextBuffer(send_tok->value);
176 SSH_GSS_CLEAR_BUF(send_tok);
42af6a67 177
178 return SSH_GSS_OK;
179}
180
181Ssh_gss_stat ssh_gss_release_cred(Ssh_gss_ctx *ctx)
182{
183 winSsh_gss_ctx *winctx= (winSsh_gss_ctx *) *ctx;
184
185 /* check input */
186 if (winctx == NULL) return SSH_GSS_FAILURE;
187
188 /* free Windows data */
189 p_FreeCredentialsHandle(&winctx->cred_handle);
190 p_DeleteSecurityContext(&winctx->context);
191
192 /* delete our "wrapper" structure */
193 sfree(winctx);
194 *ctx = (Ssh_gss_ctx) NULL;
195
196 return SSH_GSS_OK;
197}
198
199
200Ssh_gss_stat ssh_gss_release_name(Ssh_gss_name *srv_name)
201{
202 char *pStr= (char *) *srv_name;
203
204 if (pStr == NULL) return SSH_GSS_FAILURE;
205 sfree(pStr);
206 *srv_name = (Ssh_gss_name) NULL;
207
208 return SSH_GSS_OK;
209}
210
211Ssh_gss_stat ssh_gss_display_status(Ssh_gss_ctx ctx, Ssh_gss_buf *buf)
212{
213 winSsh_gss_ctx *winctx = (winSsh_gss_ctx *) ctx;
214 char *msg;
215
216 if (winctx == NULL) return SSH_GSS_FAILURE;
217
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"
222 " is invalid.";
223 break;
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"
227 " be contacted.";
228 break;
229 case SEC_E_NO_CREDENTIALS: msg="No credentials are available in the"
230 " security package.";
231 break;
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.";
237 break;
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.";
241 break;
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.";
249 break;
250 default:
251 msg = "Internal SSPI error";
252 break;
253 }
254
86557057 255 buf->value = dupstr(msg);
2c19a01f 256 buf->length = strlen(buf->value);
42af6a67 257
258 return SSH_GSS_OK;
259}
260
261Ssh_gss_stat ssh_gss_get_mic(Ssh_gss_ctx ctx, Ssh_gss_buf *buf,
262 Ssh_gss_buf *hash)
263{
264 winSsh_gss_ctx *winctx= (winSsh_gss_ctx *) ctx;
265 SecPkgContext_Sizes ContextSizes;
266 SecBufferDesc InputBufferDescriptor;
267 SecBuffer InputSecurityToken[2];
268
269 if (winctx == NULL) return SSH_GSS_FAILURE;
270
271 winctx->maj_stat = 0;
272
273 memset(&ContextSizes, 0, sizeof(ContextSizes));
274
275 winctx->maj_stat = p_QueryContextAttributesA(&winctx->context,
276 SECPKG_ATTR_SIZES,
277 &ContextSizes);
278
279 if (winctx->maj_stat != SEC_E_OK ||
280 ContextSizes.cbMaxSignature == 0)
281 return winctx->maj_stat;
282
283 InputBufferDescriptor.cBuffers = 2;
284 InputBufferDescriptor.pBuffers = InputSecurityToken;
285 InputBufferDescriptor.ulVersion = SECBUFFER_VERSION;
286 InputSecurityToken[0].BufferType = SECBUFFER_DATA;
86557057 287 InputSecurityToken[0].cbBuffer = buf->length;
288 InputSecurityToken[0].pvBuffer = buf->value;
42af6a67 289 InputSecurityToken[1].BufferType = SECBUFFER_TOKEN;
290 InputSecurityToken[1].cbBuffer = ContextSizes.cbMaxSignature;
291 InputSecurityToken[1].pvBuffer = snewn(ContextSizes.cbMaxSignature, char);
292
293 winctx->maj_stat = p_MakeSignature(&winctx->context,
294 0,
295 &InputBufferDescriptor,
296 0);
297
298 if (winctx->maj_stat == SEC_E_OK) {
86557057 299 hash->length = InputSecurityToken[1].cbBuffer;
300 hash->value = InputSecurityToken[1].pvBuffer;
42af6a67 301 }
302
303 return winctx->maj_stat;
304}
305
306Ssh_gss_stat ssh_gss_free_mic(Ssh_gss_buf *hash)
307{
86557057 308 sfree(hash->value);
42af6a67 309 return SSH_GSS_OK;
310}
311
312#else
313
314/* Dummy function so this source file defines something if NO_GSSAPI
315 is defined. */
316
317int ssh_gss_init(void)
318{
319 return 0;
320}
321
322#endif