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