Windows: remove extraneous "pingCount" format param
[openafs.git] / src / WINNT / afsd / logon_ad.cpp
1 /*
2
3 Copyright 2004 by the Massachusetts Institute of Technology
4
5 All rights reserved.
6
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the name of the Massachusetts
12 Institute of Technology (M.I.T.) not be used in advertising or publicity
13 pertaining to distribution of the software without specific, written
14 prior permission.
15
16 M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
17 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
18 M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
19 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
22 SOFTWARE.
23
24 */
25
26
27 #include <afsconfig.h>
28 #include <afs/param.h>
29 #include <roken.h>
30
31
32 //#pragma keyword("interface",on)
33 //#define interface struct
34 #define SECURITY_WIN32
35 #if (_WIN32_WINNT < 0x0500)
36 #error _WIN32_WINNT < 0x0500
37 #endif
38
39 /**/
40 #include <security.h>
41 #include <winioctl.h>
42 #include <sddl.h>
43 #include <unknwn.h>
44 #include <oaidl.h>
45 #include <Iads.h>
46 #include <adshlp.h>
47 /**/
48
49 #include "afslogon.h"
50
51 #include "..\afsrdr\common\AFSUserDefines.h"
52 #include "..\afsrdr\common\AFSUserIoctl.h"
53 #include "..\afsrdr\common\AFSUserStructs.h"
54 #include "..\afsrdr\common\AFSProvider.h"
55
56 #define SEC_ERR_VALUE(v) if (status==v) return #v
57
58 char * _get_sec_err_text(SECURITY_STATUS status) {
59     SEC_ERR_VALUE(SEC_E_OK);
60     SEC_ERR_VALUE(SEC_I_CONTINUE_NEEDED);
61     SEC_ERR_VALUE(SEC_I_COMPLETE_NEEDED);
62     SEC_ERR_VALUE(SEC_I_COMPLETE_AND_CONTINUE);
63     SEC_ERR_VALUE(SEC_E_INCOMPLETE_MESSAGE);
64     SEC_ERR_VALUE(SEC_I_INCOMPLETE_CREDENTIALS);
65     SEC_ERR_VALUE(SEC_E_INVALID_HANDLE);
66     SEC_ERR_VALUE(SEC_E_TARGET_UNKNOWN);
67     SEC_ERR_VALUE(SEC_E_LOGON_DENIED);
68     SEC_ERR_VALUE(SEC_E_INTERNAL_ERROR);
69     SEC_ERR_VALUE(SEC_E_NO_CREDENTIALS);
70     SEC_ERR_VALUE(SEC_E_NO_AUTHENTICATING_AUTHORITY);
71     SEC_ERR_VALUE(SEC_E_INSUFFICIENT_MEMORY);
72     SEC_ERR_VALUE(SEC_E_INVALID_TOKEN);
73     SEC_ERR_VALUE(SEC_E_UNSUPPORTED_FUNCTION);
74     SEC_ERR_VALUE(SEC_E_WRONG_PRINCIPAL);
75     return "Unknown";
76 }
77
78 #undef SEC_ERR_VALUE
79
80 DWORD
81 LogonSSP(PLUID lpLogonId, PCtxtHandle outCtx) {
82     DWORD code = 1;
83     SECURITY_STATUS status;
84     CredHandle creds;
85     CtxtHandle ctxclient,ctxserver;
86     TimeStamp expiry;
87     BOOL cont = TRUE;
88     BOOL first = TRUE;
89     SecBufferDesc sdescc,sdescs;
90     SecBuffer stokc,stoks;
91     ULONG cattrs,sattrs;
92     int iters = 10;
93
94     outCtx->dwLower = 0;
95     outCtx->dwUpper = 0;
96
97     cattrs = 0;
98     sattrs = 0;
99
100     status = AcquireCredentialsHandle( NULL,
101                                        "Negotiate",
102                                        SECPKG_CRED_BOTH,
103                                        lpLogonId,
104                                        NULL,
105                                        NULL,
106                                        NULL,
107                                        &creds,
108                                        &expiry);
109
110     if (status != SEC_E_OK) {
111         DebugEvent("AcquireCredentialsHandle failed: %lX", status);
112         goto ghp_0;
113     }
114
115     sdescc.cBuffers = 1;
116     sdescc.pBuffers = &stokc;
117     sdescc.ulVersion = SECBUFFER_VERSION;
118
119     stokc.BufferType = SECBUFFER_TOKEN;
120     stokc.cbBuffer = 0;
121     stokc.pvBuffer = NULL;
122
123     sdescs.cBuffers = 1;
124     sdescs.pBuffers = &stoks;
125     sdescs.ulVersion = SECBUFFER_VERSION;
126
127     stoks.BufferType = SECBUFFER_TOKEN;
128     stoks.cbBuffer = 0;
129     stoks.pvBuffer = NULL;
130
131     do {
132         status = InitializeSecurityContext( &creds,
133                                             ((first)? NULL:&ctxclient),
134                                             NULL,
135                                             ISC_REQ_DELEGATE | ISC_REQ_ALLOCATE_MEMORY,
136                                             0,
137                                             SECURITY_NATIVE_DREP,
138                                             ((first)?NULL:&sdescs),
139                                             0,
140                                             &ctxclient,
141                                             &sdescc,
142                                             &cattrs,
143                                             &expiry
144                                             );
145
146         DebugEvent("InitializeSecurityContext returns status[%lX](%s)",status,_get_sec_err_text(status));
147
148         if (!first) FreeContextBuffer(stoks.pvBuffer);
149
150         if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
151             CompleteAuthToken(&ctxclient, &sdescc);
152         }
153
154         if (status != SEC_I_CONTINUE_NEEDED && status != SEC_I_COMPLETE_AND_CONTINUE) {
155             cont = FALSE;
156         }
157
158         if (!stokc.cbBuffer && !cont) {
159             DebugEvent("Breaking out after InitializeSecurityContext");
160             break;
161         }
162
163         status = AcceptSecurityContext( &creds,
164                                         ((first)?NULL:&ctxserver),
165                                         &sdescc,
166                                         ASC_REQ_DELEGATE | ASC_REQ_ALLOCATE_MEMORY,
167                                         SECURITY_NATIVE_DREP,
168                                         &ctxserver,
169                                         &sdescs,
170                                         &sattrs,
171                                         &expiry);
172
173         DebugEvent("AcceptSecurityContext returns status[%lX](%s)", status, _get_sec_err_text(status));
174
175         FreeContextBuffer(stokc.pvBuffer);
176
177         if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
178             CompleteAuthToken(&ctxserver,&sdescs);
179         }
180
181         if (status == SEC_I_CONTINUE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
182             cont = TRUE;
183         }
184
185         if (!cont)
186             FreeContextBuffer(stoks.pvBuffer);
187
188         first = FALSE;
189         iters--; /* just in case, hard limit on loop */
190     } while (cont && iters);
191
192     if (sattrs & ASC_RET_DELEGATE) {
193         DebugEvent("Received delegate context");
194         *outCtx = ctxserver;
195         code = 0;
196     } else {
197         DebugEvent("Didn't receive delegate context");
198         outCtx->dwLower = 0;
199         outCtx->dwUpper = 0;
200         DeleteSecurityContext(&ctxserver);
201     }
202
203     DeleteSecurityContext(&ctxclient);
204     FreeCredentialsHandle(&creds);
205   ghp_0:
206     return code;
207 }
208
209 DWORD
210 QueryAdHomePathFromSid(char * homePath, size_t homePathLen, PSID psid, PWSTR domain) {
211     DWORD code = 1; /* default is failure */
212     NTSTATUS rv = 0;
213     HRESULT hr = S_OK;
214     LPWSTR p = NULL;
215     WCHAR adsPath[MAX_PATH] = L"";
216     BOOL coInitialized = FALSE;
217     CHAR ansidomain[256], *a;
218
219     homePath[0] = '\0';
220
221     /* I trust this is an ASCII domain name */
222     for ( p=domain, a=ansidomain; *a = (CHAR)*p; p++, a++);
223     DebugEvent("Domain: %s", ansidomain);
224
225     if (ConvertSidToStringSidW(psid,&p)) {
226         IADsNameTranslate *pNto;
227
228         DebugEvent("Got SID string [%S]", p);
229
230         hr = CoInitialize(NULL);
231         if (SUCCEEDED(hr))
232             coInitialized = TRUE;
233
234         hr = CoCreateInstance( CLSID_NameTranslate,
235                                NULL,
236                                CLSCTX_INPROC_SERVER,
237                                IID_IADsNameTranslate,
238                                (void**)&pNto);
239
240         if (FAILED(hr)) {
241             DebugEvent("Can't create nametranslate object");
242         }
243         else {
244             hr = pNto->Init(ADS_NAME_INITTYPE_GC,L"");
245             if (FAILED(hr)) {
246                 DebugEvent("NameTranslate Init GC failed [%ld]", hr);
247                 if ( domain ) {
248                     hr = pNto->Init(ADS_NAME_INITTYPE_DOMAIN,domain);
249                     if (FAILED(hr)) {
250                         DebugEvent("NameTranslate Init Domain failed [%ld]", hr);
251                     }
252                 }
253             }
254
255             if (!FAILED(hr)) {
256                 hr = pNto->Set(ADS_NAME_TYPE_SID_OR_SID_HISTORY_NAME, p);
257                 if (FAILED(hr)) {
258                     DebugEvent("Can't set sid string");
259                 }
260                 else {
261                     BSTR bstr;
262
263                     hr = pNto->Get(ADS_NAME_TYPE_1779, &bstr);
264                     if(SUCCEEDED(hr)) {
265                         hr = StringCchCopyW(adsPath, MAX_PATH, bstr);
266                         if(FAILED(hr)) {
267                             DebugEvent("Overflow while copying ADS path");
268                             adsPath[0] = L'\0';
269                         }
270
271                         SysFreeString(bstr);
272                     }
273                 }
274             }
275             pNto->Release();
276         }
277
278         LocalFree(p);
279     } else {
280         DebugEvent("Can't convert sid to string");
281     }
282
283     if (adsPath[0]) {
284         WCHAR fAdsPath[MAX_PATH];
285         IADsUser *pAdsUser;
286         BSTR bstHomeDir = NULL;
287
288         hr = StringCchPrintfW(fAdsPath, MAX_PATH, L"LDAP://%s", adsPath);
289         if (hr != S_OK) {
290             DebugEvent("Can't format full adspath");
291             goto cleanup;
292         }
293
294         DebugEvent("Trying adsPath=[%S]", fAdsPath);
295
296         hr = ADsGetObject( fAdsPath, IID_IADsUser, (LPVOID *) &pAdsUser);
297         if (hr != S_OK) {
298             DebugEvent("Can't open IADs object");
299             goto cleanup;
300         }
301
302         hr = pAdsUser->get_Profile(&bstHomeDir);
303         if (hr != S_OK) {
304             DebugEvent("Can't get profile directory");
305             goto cleanup_homedir_section;
306         }
307
308         wcstombs(homePath, bstHomeDir, homePathLen);
309
310         DebugEvent("Got homepath [%s]", homePath);
311
312         SysFreeString(bstHomeDir);
313
314         code = 0;
315
316       cleanup_homedir_section:
317         pAdsUser->Release();
318     }
319
320   cleanup:
321     if (coInitialized)
322         CoUninitialize();
323
324     return code;
325 }
326
327 /* Try to determine the user's AD home path.  *homePath is assumed to be at least MAXPATH bytes.
328    If successful, opt.flags is updated with LOGON_FLAG_AD_REALM to indicate that we are dealing with
329    an AD realm. */
330 DWORD
331 GetAdHomePath(char * homePath, size_t homePathLen, PLUID lpLogonId, LogonOptions_t * opt) {
332     CtxtHandle ctx;
333     DWORD code = 0;
334     SECURITY_STATUS status;
335
336     homePath[0] = '\0';
337
338     if (LogonSSP(lpLogonId,&ctx)) {
339         DebugEvent("Failed LogonSSP");
340         return 1;
341     }
342
343     status = ImpersonateSecurityContext(&ctx);
344     if (status == SEC_E_OK) {
345         PSECURITY_LOGON_SESSION_DATA plsd;
346         NTSTATUS rv;
347
348         rv = LsaGetLogonSessionData(lpLogonId, &plsd);
349         if (rv == 0) {
350             PWSTR domain;
351
352             domain = (PWSTR)malloc(sizeof(WCHAR) * (plsd->LogonDomain.Length+1));
353             memcpy(domain, plsd->LogonDomain.Buffer, sizeof(WCHAR) * (plsd->LogonDomain.Length));
354             domain[plsd->LogonDomain.Length] = 0;
355
356             if (!QueryAdHomePathFromSid(homePath,homePathLen,plsd->Sid,domain)) {
357                 DebugEvent("Returned home path [%s]",homePath);
358                 opt->flags |= LOGON_FLAG_AD_REALM;
359             }
360             free(domain);
361             LsaFreeReturnBuffer(plsd);
362         } else {
363             DebugEvent("LsaGetLogonSessionData failed [%lX]", rv);
364         }
365         RevertSecurityContext(&ctx);
366     } else {
367         DebugEvent("Can't impersonate context [%lX]",status);
368         code = 1;
369     }
370
371     DeleteSecurityContext(&ctx);
372     return code;
373 }
374
375 BOOL
376 GetLocalShortDomain(PWSTR Domain, DWORD cbDomain)
377 {
378     HRESULT hr;
379     IADsADSystemInfo *pADsys;
380     BOOL coInitialized = FALSE;
381     BOOL retval = FALSE;
382
383     hr = CoInitialize(NULL);
384     if (SUCCEEDED(hr))
385         coInitialized = TRUE;
386
387     hr = CoCreateInstance( CLSID_ADSystemInfo,
388                            NULL,
389                            CLSCTX_INPROC_SERVER,
390                            IID_IADsADSystemInfo,
391                            (void**)&pADsys);
392     if ( !FAILED(hr) ) {
393         BSTR bstr;
394
395         hr = pADsys->get_DomainShortName(&bstr);
396         if ( !FAILED(hr) ) {
397             hr = StringCbCopyW( Domain, cbDomain, bstr );
398             if(SUCCEEDED(hr)) {
399                 retval = TRUE;
400             }
401             SysFreeString(bstr);
402         }
403         pADsys->Release();
404     }
405
406     if (coInitialized)
407         CoUninitialize();
408
409     return retval;
410 }
411
412 static HANDLE
413 OpenRedirector(void)
414 {
415     HANDLE hControlDevice = NULL;
416
417     hControlDevice = CreateFileW( AFS_SYMLINK_W,
418                                  GENERIC_READ | GENERIC_WRITE,
419                                  FILE_SHARE_READ | FILE_SHARE_WRITE,
420                                  NULL,
421                                  OPEN_EXISTING,
422                                  0,
423                                  NULL );
424
425     if( hControlDevice == INVALID_HANDLE_VALUE)
426     {
427         hControlDevice = NULL;
428         DebugEvent("OpenRedirector Failed to open control device error: %d",
429                     GetLastError());
430     }
431
432     return hControlDevice;
433 }
434
435 void
436 AFSCreatePAG(PLUID lpLogonId)
437 {
438     BOOLEAN             bRet = FALSE;
439     HANDLE              hControlDevice = NULL;
440     DWORD               dwCopyBytes = 0;
441     AFSAuthGroupRequestCB *pAuthGroup = NULL;
442     WCHAR *             pwchSIDString = NULL;
443     CtxtHandle          ctx;
444     SECURITY_STATUS     status;
445     PSECURITY_LOGON_SESSION_DATA plsd = NULL;
446     NTSTATUS            rv;
447     BOOLEAN             bImpersonated = FALSE;
448
449     GUID stAuthGroup;
450     unsigned char *pchGUID = NULL;
451     DWORD bytesReturned;
452
453     if (LogonSSP(lpLogonId, &ctx)) {
454         DebugEvent("AFSCreatePAG unable to obtain LogonSSP context");
455         return;
456     }
457
458     status = ImpersonateSecurityContext(&ctx);
459     if (status == SEC_E_OK)
460     {
461         bImpersonated = TRUE;
462
463         rv = LsaGetLogonSessionData(lpLogonId, &plsd);
464         if (rv == 0)
465         {
466             if( !ConvertSidToStringSidW( plsd->Sid,
467                                          &pwchSIDString))
468             {
469                 DebugEvent("AFSCreatePAG Failed to convert sid to string Error %08X", GetLastError());
470                 goto cleanup;
471             }
472
473             pAuthGroup = (AFSAuthGroupRequestCB *)LocalAlloc( LPTR, 0x1000);
474
475             if( pAuthGroup == NULL)
476             {
477                 DebugEvent0("AFSCreatePAG Failed auth group allocation");
478                 goto cleanup;
479             }
480
481             memset( pAuthGroup, 0, 0x1000);
482
483             pAuthGroup->SIDLength = (USHORT) (wcslen( pwchSIDString) * sizeof( WCHAR));
484             pAuthGroup->SessionId = plsd->Session;
485
486             memcpy( pAuthGroup->SIDString,
487                     pwchSIDString,
488                     pAuthGroup->SIDLength);
489
490             RevertSecurityContext(&ctx);
491
492             bImpersonated = FALSE;
493
494             hControlDevice = OpenRedirector();
495
496             if( hControlDevice == NULL)
497             {
498                 DebugEvent0("AFSCreatePAG Failed to open redirector");
499                 goto cleanup;
500             }
501
502             bRet = DeviceIoControl( hControlDevice,
503                                    IOCTL_AFS_AUTHGROUP_SID_QUERY,
504                                    NULL,
505                                    0,
506                                    &stAuthGroup,
507                                    sizeof( GUID),
508                                    &bytesReturned,
509                                    NULL);
510
511             if( bRet == FALSE)
512             {
513                 DebugEvent("AFSCreatePAG Failed IOCTL_AFS_AUTHGROUP_SID_QUERY Error 0x%08X", GetLastError());
514             }
515             else
516             {
517                 if( UuidToString( (UUID *)&stAuthGroup,
518                                   &pchGUID) == RPC_S_OK)
519                 {
520                     DebugEvent("AFSCreatePAG Initial AuthGroup %s\n", pchGUID);
521                     RpcStringFree( &pchGUID);
522                 }
523                 else
524                 {
525                     DebugEvent0("AFSCreatePAG Failed to convert GUID to string\n");
526                 }
527             }
528
529             ImpersonateSecurityContext(&ctx); bImpersonated = TRUE;
530
531             bRet = DeviceIoControl( hControlDevice,
532                                     IOCTL_AFS_AUTHGROUP_SID_QUERY,
533                                     NULL,
534                                     0,
535                                     &stAuthGroup,
536                                     sizeof( GUID),
537                                     &bytesReturned,
538                                     NULL);
539
540             if( bRet == FALSE)
541             {
542                 DebugEvent("AFSCreatePAG Failed IOCTL_AFS_AUTHGROUP_SID_QUERY Impersonation Error 0x%08X", GetLastError());
543             }
544             else
545             {
546                 if( UuidToString( (UUID *)&stAuthGroup,
547                                   &pchGUID) == RPC_S_OK)
548                 {
549                     DebugEvent("AFSCreatePAG Initial Impersonation AuthGroup %s\n", pchGUID);
550                     RpcStringFree( &pchGUID);
551                 }
552                 else
553                 {
554                     DebugEvent0("AFSCreatePAG Failed to convert GUID to string\n");
555                 }
556             }
557
558             RevertSecurityContext(&ctx); bImpersonated = FALSE;
559
560
561             bRet = DeviceIoControl( hControlDevice,
562                                     IOCTL_AFS_AUTHGROUP_LOGON_CREATE,
563                                     pAuthGroup,
564                                     sizeof( AFSAuthGroupRequestCB) + pAuthGroup->SIDLength - 1,
565                                     NULL,
566                                     0,
567                                     &dwCopyBytes,
568                                     NULL);
569
570             if( bRet == FALSE)
571             {
572                 DebugEvent("AFSCreatePAG Failed IOCTL_AFS_AUTHGROUP_SID_CREATE Error 0x%08X", GetLastError());
573             }
574             else
575             {
576                 bRet = DeviceIoControl( hControlDevice,
577                                         IOCTL_AFS_AUTHGROUP_SID_QUERY,
578                                         NULL,
579                                         0,
580                                         &stAuthGroup,
581                                         sizeof( GUID),
582                                         &bytesReturned,
583                                         NULL);
584
585                 if( bRet == FALSE)
586                 {
587                     DebugEvent("AFSCreatePAG Failed IOCTL_AFS_AUTHGROUP_SID_QUERY Error 0x%08X", GetLastError());
588                 }
589                 else
590                 {
591                     if( UuidToString( (UUID *)&stAuthGroup,
592                                       &pchGUID) == RPC_S_OK)
593                     {
594                         DebugEvent("AFSCreatePAG New AuthGroup %s\n", pchGUID);
595                         RpcStringFree( &pchGUID);
596                     }
597                     else
598                     {
599                         DebugEvent0("AFSCreatePAG Failed to convert GUID to string\n");
600                     }
601                 }
602             }
603
604             ImpersonateSecurityContext(&ctx);
605
606             bRet = DeviceIoControl( hControlDevice,
607                                     IOCTL_AFS_AUTHGROUP_SID_QUERY,
608                                     NULL,
609                                     0,
610                                     &stAuthGroup,
611                                     sizeof( GUID),
612                                     &bytesReturned,
613                                     NULL);
614
615             if( bRet == FALSE)
616             {
617                 DebugEvent("AFSCreatePAG Failed IOCTL_AFS_AUTHGROUP_SID_QUERY Impersonation Error 0x%08X", GetLastError());
618             }
619             else
620             {
621                 if( UuidToString( (UUID *)&stAuthGroup,
622                                   &pchGUID) == RPC_S_OK)
623                 {
624                     DebugEvent("AFSCreatePAG New Impersonation AuthGroup %s\n", pchGUID);
625                     RpcStringFree( &pchGUID);
626                 }
627                 else
628                 {
629                     DebugEvent0("AFSCreatePAG Failed to convert GUID to string\n");
630                 }
631             }
632
633             RevertSecurityContext(&ctx);
634         }
635         else
636         {
637             DebugEvent("AFSCreatePAG LsaGetLogonSessionData failed [%lX]", rv);
638         }
639
640     }
641     else
642     {
643         DebugEvent("AFSCreatePAG cannot impersonate context [%lX]", status);
644     }
645
646
647   cleanup:
648
649     if (bImpersonated)
650         RevertSecurityContext(&ctx);
651
652     DeleteSecurityContext(&ctx);
653
654     if (plsd != NULL)
655         LsaFreeReturnBuffer(plsd);
656
657     if ( hControlDevice != NULL)
658         CloseHandle( hControlDevice);
659
660     if( pwchSIDString != NULL)
661         LocalFree( pwchSIDString);
662 }