From: Jeffrey Altman Date: Tue, 7 Sep 2010 12:21:12 +0000 (-0400) Subject: Windows: Improve SMB detection of Local System account X-Git-Tag: openafs-devel-1_7_1~1598 X-Git-Url: https://git.openafs.org/?p=openafs.git;a=commitdiff_plain;h=19f50c13b4542cc84c33eaca4b2cc6ac0b75eb98 Windows: Improve SMB detection of Local System account Depending on the authentication method, the smb session authenticated name for the "local system" account may be the nul string. In this case it is impossible to use the name to determine if the authenticated entity is the "local system" account as required by smb_SetToken. To work around this problem, smb_AuthenticateUserExt() will now obtain the Security Identifier (SID) for the authenticated account. The string representation of the SID will be used in place of the name by smb_ReceiveV3SessionSetupX() when constructing the smb_user_t object. A new flag, SMB_USERNAMEFLAG_SID, indicates when the name is in fact a SID. smb_userIsLocalSystem() checks for the SMB_USERNAMEFLAG_SID flag and performs a SID comparison when it is set. smb_SetToken() will accept either MACHINE\user or a SID string as the smbname. It will obtain the SID if possible and create a SID-based smb_user_t. It is possible that a SYSTEM service will use an anonymous (S-1-5-7) SMB connection. In that case, we also check the RPC Impersonation SID to see if it is SYSTEM. If so, the RPC identity supercedes the SMB identity for SetToken. smb_IoctlRead, smb_IoctlV3Read and smb_IoctlRawRead are now all consistent with regards to name processing. Fixed a couple of comments as well. FIXES 128022 LICENSE MIT Change-Id: I8f9ccd4a4dddea52d151288855c7e129e2f31b28 Reviewed-on: http://gerrit.openafs.org/2709 Tested-by: Jeffrey Altman Reviewed-by: Jeffrey Altman --- diff --git a/src/WINNT/afsd/cm_ioctl.c b/src/WINNT/afsd/cm_ioctl.c index 9451a8f..b25cc0c 100644 --- a/src/WINNT/afsd/cm_ioctl.c +++ b/src/WINNT/afsd/cm_ioctl.c @@ -2718,7 +2718,7 @@ cm_IoctlGetToken(struct cm_ioctl *ioctlp, struct cm_user *userp) lock_ReleaseMutex(&userp->mx); - cm_RegisterNewTokenEvent(uuid, ucellp->sessionKey.data); + cm_RegisterNewTokenEvent(uuid, ucellp->sessionKey.data, NULL); return 0; } diff --git a/src/WINNT/afsd/cm_rpc.c b/src/WINNT/afsd/cm_rpc.c index fe49555..9655e49 100644 --- a/src/WINNT/afsd/cm_rpc.c +++ b/src/WINNT/afsd/cm_rpc.c @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -36,6 +37,7 @@ extern void afsi_log(char *pattern, ...); typedef struct tokenEvent { + clientchar_t *SidString; afs_uuid_t uuid; char sessionKey[8]; struct tokenEvent *next; @@ -52,9 +54,11 @@ EVENT_HANDLE rpc_ShutdownEvent = NULL; */ void cm_RegisterNewTokenEvent( afs_uuid_t uuid, - char sessionKey[8]) + char sessionKey[8], + clientchar_t *SidString) { tokenEvent_t *te = malloc(sizeof(tokenEvent_t)); + te->SidString = SidString; te->uuid = uuid; memcpy(te->sessionKey, sessionKey, sizeof(te->sessionKey)); lock_ObtainMutex(&tokenEventLock); @@ -69,7 +73,7 @@ void cm_RegisterNewTokenEvent( * * Return TRUE if found, FALSE if not found */ -BOOL cm_FindTokenEvent(afs_uuid_t uuid, char sessionKey[8]) +BOOL cm_FindTokenEvent(afs_uuid_t uuid, char sessionKey[8], clientchar_t **SidString) { RPC_STATUS status; tokenEvent_t *te; @@ -84,6 +88,10 @@ BOOL cm_FindTokenEvent(afs_uuid_t uuid, char sessionKey[8]) lock_ReleaseMutex(&tokenEventLock); memcpy(sessionKey, te->sessionKey, sizeof(te->sessionKey)); + if (SidString) + *SidString = te->SidString; + else + LocalFree(te->SidString); free(te); return TRUE; } @@ -102,7 +110,40 @@ long AFSRPC_SetToken( afs_uuid_t uuid, unsigned char __RPC_FAR sessionKey[8]) { - cm_RegisterNewTokenEvent(uuid, sessionKey); + clientchar_t *secSidString = 0; + + if (RpcImpersonateClient(0) == RPC_S_OK) { + HANDLE hToken = 0; + PSID pSid = 0; + DWORD gle = 0; + DWORD retlen; + TOKEN_STATISTICS tokenStats; + + if (!OpenThreadToken( GetCurrentThread(), TOKEN_READ, FALSE, &hToken)) { + gle = GetLastError(); + goto done; + } + + if (!GetTokenInformation( hToken, TokenStatistics, &tokenStats, sizeof(tokenStats), &retlen)) { + gle = GetLastError(); + goto done; + } + + if (!smb_GetUserSID( hToken, &pSid)) + goto done; + + if (!ConvertSidToStringSidW(pSid, &secSidString)) + goto done; + + done: + if (hToken) + CloseHandle( hToken); + + RpcRevertToSelf(); + } + + cm_RegisterNewTokenEvent(uuid, sessionKey, secSidString); + return 0; } @@ -112,7 +153,7 @@ long AFSRPC_GetToken( { BOOL found; - found = cm_FindTokenEvent(uuid, sessionKey); + found = cm_FindTokenEvent(uuid, sessionKey, NULL); if (!found) return 1; diff --git a/src/WINNT/afsd/cm_rpc.h b/src/WINNT/afsd/cm_rpc.h index a4cdbd4..6023e5c 100644 --- a/src/WINNT/afsd/cm_rpc.h +++ b/src/WINNT/afsd/cm_rpc.h @@ -12,8 +12,8 @@ #include "afsrpc.h" -void cm_RegisterNewTokenEvent(afs_uuid_t uuid, char sessionKey[8]); -BOOL cm_FindTokenEvent(afs_uuid_t uuid, char sessionKey[8]); +void cm_RegisterNewTokenEvent(afs_uuid_t uuid, char sessionKey[8], clientchar_t *); +BOOL cm_FindTokenEvent(afs_uuid_t uuid, char sessionKey[8], clientchar_t **); extern long RpcInit(void); extern void RpcShutdown(void); diff --git a/src/WINNT/afsd/smb.c b/src/WINNT/afsd/smb.c index 031bb2e..79b7885 100644 --- a/src/WINNT/afsd/smb.c +++ b/src/WINNT/afsd/smb.c @@ -1241,12 +1241,15 @@ afs_int32 smb_userIsLocalSystem(smb_user_t *uidp) DWORD gle; afs_int32 isSystem = 0; + if (uidp->unp->flags & SMB_USERNAMEFLAG_SID) { + isSystem = !cm_ClientStrCmp(NTSID_LOCAL_SYSTEM, uidp->unp->name); + return isSystem; + } + /* - * The input name is probably not a SID for the user which is how - * the user is now being identified as a result of the SMB - * extended authentication. See if we can obtain the SID for the - * specified name. If we can, use that instead of the name - * provided. + * The input name is not a SID for the user. See if we can + * obtain the SID for the specified name. If we can, use + * that instead of the name provided for the comparison. */ LookupAccountNameW( NULL /* System Name to begin Search */, diff --git a/src/WINNT/afsd/smb.h b/src/WINNT/afsd/smb.h index 6a26848..88e4d3e 100644 --- a/src/WINNT/afsd/smb.h +++ b/src/WINNT/afsd/smb.h @@ -306,6 +306,12 @@ typedef struct smb_username { #define SMB_USERNAMEFLAG_LOGOFF 2 +/* + * The SMB_USERNAMEFLAG_SID flag indicates that the name is not a username + * but a SID string. + */ +#define SMB_USERNAMEFLAG_SID 4 + #define SMB_MAX_USERNAME_LENGTH 256 /* one per tree-connect */ @@ -608,6 +614,8 @@ extern smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *mac extern cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags); +extern cm_user_t *smb_FindCMUserBySID(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags); + extern smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern); extern void smb_ReleaseUsername(smb_username_t *unp); diff --git a/src/WINNT/afsd/smb3.c b/src/WINNT/afsd/smb3.c index c88124f..522f58d 100644 --- a/src/WINNT/afsd/smb3.c +++ b/src/WINNT/afsd/smb3.c @@ -16,6 +16,7 @@ #include #define SECURITY_WIN32 #include +#include #include #pragma warning(pop) #include @@ -263,6 +264,149 @@ void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) { return; } +afs_uint32 +smb_GetLogonSID(HANDLE hToken, PSID *ppsid) +{ + BOOL bSuccess = FALSE; + DWORD dwIndex; + DWORD dwLength = 0; + PTOKEN_GROUPS ptg = NULL; + + // Verify the parameter passed in is not NULL. + if (NULL == ppsid) + goto Cleanup; + + // Get required buffer size and allocate the TOKEN_GROUPS buffer. + + if (!GetTokenInformation( hToken, // handle to the access token + TokenGroups, // get information about the token's groups + (LPVOID) ptg, // pointer to TOKEN_GROUPS buffer + 0, // size of buffer + &dwLength // receives required buffer size + )) + { + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + goto Cleanup; + + ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, dwLength); + + if (ptg == NULL) + goto Cleanup; + } + + // Get the token group information from the access token. + + if (!GetTokenInformation( hToken, // handle to the access token + TokenGroups, // get information about the token's groups + (LPVOID) ptg, // pointer to TOKEN_GROUPS buffer + dwLength, // size of buffer + &dwLength // receives required buffer size + )) + { + goto Cleanup; + } + + // Loop through the groups to find the logon SID. + for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++) { + if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID) + { + // Found the logon SID; make a copy of it. + + dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid); + *ppsid = (PSID) HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, dwLength); + if (*ppsid == NULL) + goto Cleanup; + if (!CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid)) + { + HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid); + goto Cleanup; + } + bSuccess = TRUE; + break; + } + } + + Cleanup: + + // Free the buffer for the token groups. + if (ptg != NULL) + HeapFree(GetProcessHeap(), 0, (LPVOID)ptg); + + return bSuccess; +} + +afs_uint32 +smb_GetUserSID(HANDLE hToken, PSID *ppsid) +{ + BOOL bSuccess = FALSE; + DWORD dwLength = 0; + PTOKEN_USER ptu = NULL; + + // Verify the parameter passed in is not NULL. + if (NULL == ppsid) + goto Cleanup; + + // Get required buffer size and allocate the TOKEN_USER buffer. + + if (!GetTokenInformation( hToken, // handle to the access token + TokenUser, // get information about the token's user + (LPVOID) ptu, // pointer to TOKEN_USER buffer + 0, // size of buffer + &dwLength // receives required buffer size + )) + { + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + goto Cleanup; + + ptu = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, dwLength); + + if (ptu == NULL) + goto Cleanup; + } + + // Get the token group information from the access token. + + if (!GetTokenInformation( hToken, // handle to the access token + TokenUser, // get information about the token's user + (LPVOID) ptu, // pointer to TOKEN_USER buffer + dwLength, // size of buffer + &dwLength // receives required buffer size + )) + { + goto Cleanup; + } + + // Found the user SID; make a copy of it. + dwLength = GetLengthSid(ptu->User.Sid); + *ppsid = (PSID) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength); + if (*ppsid == NULL) + goto Cleanup; + if (!CopySid(dwLength, *ppsid, ptu->User.Sid)) + { + HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid); + goto Cleanup; + } + bSuccess = TRUE; + + Cleanup: + + // Free the buffer for the token groups. + if (ptu != NULL) + HeapFree(GetProcessHeap(), 0, (LPVOID)ptu); + + return bSuccess; +} + +void +smb_FreeSID (PSID psid) +{ + HeapFree(GetProcessHeap(), 0, (LPVOID)psid); +} + + struct smb_ext_context { CredHandle creds; CtxtHandle ctx; @@ -272,7 +416,8 @@ struct smb_ext_context { long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern, char * secBlobIn, int secBlobInLength, - char ** secBlobOut, int * secBlobOutLength) { + char ** secBlobOut, int * secBlobOutLength, + wchar_t **secSidString) { SECURITY_STATUS status, istatus; CredHandle creds; TimeStamp expiry; @@ -292,6 +437,7 @@ long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern, *secBlobOut = NULL; *secBlobOutLength = 0; + *secSidString = NULL; if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) { secCtx = vcp->secCtx; @@ -427,6 +573,7 @@ long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern, if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) { /* woo hoo! */ + HANDLE hToken = 0; SecPkgContext_NamesW names; OutputDebugF(_C("Authentication completed")); @@ -442,6 +589,21 @@ long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern, OutputDebugF(_C("QueryContextAttributes Names failed [%x]"), GetLastError()); code = CM_ERROR_BADPASSWORD; } + + /* Obtain the user's SID */ + if (code == 0 && !QuerySecurityContextToken(((secCtx)?&ctx:NULL), &hToken)) { + PSID pSid = 0; + OutputDebugF(_C("Received hToken")); + + if (smb_GetUserSID(hToken, &pSid)) + ConvertSidToStringSidW(pSid, secSidString); + + if (pSid) + smb_FreeSID(pSid); + CloseHandle(hToken); + } else { + OutputDebugF(_C("QueryContextToken failed [%x]"), GetLastError()); + } } else if (!code) { switch ( status ) { case SEC_E_INVALID_TOKEN: @@ -679,8 +841,10 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t * clientchar_t *s1 = _C(" "); long code = 0; clientchar_t usern[SMB_MAX_USERNAME_LENGTH]; + int usernIsSID = 0; char *secBlobOut = NULL; int secBlobOutLength = 0; + wchar_t *secSidString = 0; int maxBufferSize = 0; int maxMpxCount = 0; int vcNumber = 0; @@ -729,7 +893,7 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t * secBlobInLength = smb_GetSMBParm(inp, 7); secBlobIn = smb_GetSMBData(inp, NULL); - code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength); + code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength, &secSidString); if (code == CM_ERROR_GSSCONTINUE) { size_t cb_data = 0; @@ -875,9 +1039,20 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t * early to avoid accidently stealing someone else's tokens. */ if (code) { + if (secSidString) + LocalFree(secSidString); return code; } + /* + * If the SidString for the user could be obtained, use that + * for the user id + */ + if (secSidString) { + cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, secSidString); + usernIsSID = 1; + } + OutputDebugF(_C("Received username=[%s]"), usern); /* On Windows 2000, this function appears to be called more often than @@ -909,6 +1084,8 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t * */ unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON; } + if (usernIsSID) + unp->flags |= SMB_USERNAMEFLAG_SID; lock_ReleaseMutex(&unp->mx); /* Create a new UID and cm_user_t structure */ @@ -986,6 +1163,8 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t * } } + if (secSidString) + LocalFree(secSidString); return 0; } @@ -9463,3 +9642,23 @@ cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_ return userp; } +cm_user_t *smb_FindCMUserBySID(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags) +{ + smb_username_t *unp; + cm_user_t * userp; + + unp = smb_FindUserByName(usern, machine, flags); + if (!unp->userp) { + lock_ObtainMutex(&unp->mx); + unp->flags |= SMB_USERNAMEFLAG_SID; + unp->userp = cm_NewUser(); + lock_ReleaseMutex(&unp->mx); + osi_Log2(smb_logp,"smb_FindCMUserBySID New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine)); + } else { + osi_Log2(smb_logp,"smb_FindCMUserBySID Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine)); + } + userp = unp->userp; + cm_HoldUser(userp); + smb_ReleaseUsername(unp); + return userp; +} diff --git a/src/WINNT/afsd/smb3.h b/src/WINNT/afsd/smb3.h index fa5ca6a..3f09b18 100644 --- a/src/WINNT/afsd/smb3.h +++ b/src/WINNT/afsd/smb3.h @@ -444,4 +444,9 @@ extern void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength); #define NO_REPARSETAG 0x0004 #define NO_SUBSTREAMS 0x0002 #define NO_EAS 0x0001 + +extern afs_uint32 smb_GetLogonSID(HANDLE hToken, PSID *ppsid); +extern afs_uint32 smb_GetUserSID(HANDLE hToken, PSID *ppsid); +extern void smb_FreeSID (PSID psid); + #endif /* __SMB3_H_ENV__ */ diff --git a/src/WINNT/afsd/smb_ioctl.c b/src/WINNT/afsd/smb_ioctl.c index 9f38eb8..d441fe9 100644 --- a/src/WINNT/afsd/smb_ioctl.c +++ b/src/WINNT/afsd/smb_ioctl.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -219,7 +220,18 @@ smb_IoctlRead(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o if (uidp) { isSystem = smb_userIsLocalSystem(uidp); userp = smb_GetUserFromUID(uidp); + if (uidp->unp) { + osi_Log3(afsd_logp, "smb_IoctlRead uid %d user %x name %s", + uidp->userID, userp, + osi_LogSaveClientString(afsd_logp, uidp->unp->name)); + } else { + osi_Log2(afsd_logp, "smb_IoctlRead uid %d user %x no name", + uidp->userID, userp); + } smb_ReleaseUID(uidp); + } else { + osi_Log1(afsd_logp, "smb_IoctlRead no uid user %x no name", userp); + return CM_ERROR_BADSMB; } if (!userp) { @@ -375,29 +387,37 @@ smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t char *op; cm_user_t *userp; smb_user_t *uidp; + int isSystem = 0; iop = fidp->ioctlp; count = smb_GetSMBParm(inp, 5); - + + /* Get the user and determine if it is the local machine account */ uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0); - if (!uidp) - return CM_ERROR_BADSMB; - userp = smb_GetUserFromUID(uidp); - osi_assertx(userp != NULL, "null cm_user_t"); - iop->uidp = uidp; - if (uidp && uidp->unp) { - osi_Log3(afsd_logp, "Ioctl uid %d user %x name %S", - uidp->userID, userp, - osi_LogSaveClientString(afsd_logp, uidp->unp->name)); - } else { - if (uidp) - osi_Log2(afsd_logp, "Ioctl uid %d user %x no name", - uidp->userID, userp); - else - osi_Log1(afsd_logp, "Ioctl no uid user %x no name", - userp); + if (uidp) { + isSystem = smb_userIsLocalSystem(uidp); + userp = smb_GetUserFromUID(uidp); + if (uidp->unp) { + osi_Log3(afsd_logp, "smb_IoctlV3Read uid %d user %x name %s", + uidp->userID, userp, + osi_LogSaveClientString(afsd_logp, uidp->unp->name)); + } else { + osi_Log2(afsd_logp, "smb_IoctlV3Read uid %d user %x no name", + uidp->userID, userp); + } + } else { + osi_Log0(afsd_logp, "smb_IoctlV3Read no uid"); + return CM_ERROR_BADSMB; + } + + if (!userp) { + userp = cm_rootUserp; + cm_HoldUser(userp); } + iop->uidp = uidp; + + code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &iop->tidPathp); if (code) { if (uidp) @@ -406,7 +426,7 @@ smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t return CM_ERROR_NOSUCHPATH; } - code = smb_IoctlPrepareRead(fidp, iop, userp, 0); + code = smb_IoctlPrepareRead(fidp, iop, userp, isSystem ? AFSCALL_FLAG_LOCAL_SYSTEM : 0); if (uidp) { iop->uidp = 0; smb_ReleaseUID(uidp); @@ -473,26 +493,32 @@ smb_IoctlReadRaw(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, afs_int32 code; cm_user_t *userp; smb_user_t *uidp; + int isSystem = 0; iop = fidp->ioctlp; - userp = smb_GetUserFromVCP(vcp, inp); - - /* Log the user */ + /* Get the user and determine if it is the local machine account */ uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0); - if (uidp && uidp->unp) { - osi_Log3(afsd_logp, "Ioctl uid %d user %x name %s", - uidp->userID, userp, - osi_LogSaveClientString(afsd_logp, uidp->unp->name)); - } else if (uidp) { - osi_Log2(afsd_logp, "Ioctl uid %d user %x no name", - uidp->userID, userp); + if (uidp) { + isSystem = smb_userIsLocalSystem(uidp); + userp = smb_GetUserFromUID(uidp); + if (uidp->unp) { + osi_Log3(afsd_logp, "smb_IoctlRawRead uid %d user %x name %s", + uidp->userID, userp, + osi_LogSaveClientString(afsd_logp, uidp->unp->name)); + } else { + osi_Log2(afsd_logp, "smb_IoctlRawRead uid %d user %x no name", + uidp->userID, userp); + } + smb_ReleaseUID(uidp); } else { - osi_Log1(afsd_logp, "Ioctl no uid user %x no name", - userp); + osi_Log0(afsd_logp, "smb_IoctlRawRead no uid"); + } + + if (!userp) { + userp = cm_rootUserp; + cm_HoldUser(userp); } - if (uidp) - smb_ReleaseUID(uidp); code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &iop->tidPathp); if (code) { @@ -500,7 +526,7 @@ smb_IoctlReadRaw(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, goto done; } - code = smb_IoctlPrepareRead(fidp, iop, userp, 0); + code = smb_IoctlPrepareRead(fidp, iop, userp, isSystem ? AFSCALL_FLAG_LOCAL_SYSTEM : 0); if (code) { goto done; } @@ -974,6 +1000,7 @@ smb_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pf clientchar_t *uname = NULL; clientchar_t *smbname = NULL; clientchar_t *wdir = NULL; + clientchar_t *rpc_sid = NULL; afs_int32 code = 0; saveDataPtr = ioctlp->ioctl.inDatap; @@ -1035,42 +1062,113 @@ smb_IoctlSetToken(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pf if (flags & PIOCTL_LOGON) { /* SMB user name with which to associate tokens */ smbname = cm_ParseIoctlStringAlloc(&ioctlp->ioctl, tp); - osi_Log2(smb_logp,"cm_IoctlSetToken for user [%S] smbname [%S]", + osi_Log2(smb_logp,"smb_IoctlSetToken for user [%S] smbname [%S]", osi_LogSaveClientString(smb_logp,uname), osi_LogSaveClientString(smb_logp,smbname)); fprintf(stderr, "SMB name = %S\n", smbname); tp += strlen(tp) + 1; } else { - osi_Log1(smb_logp,"cm_IoctlSetToken for user [%S]", + osi_Log1(smb_logp,"smb_IoctlSetToken for user [%S]", osi_LogSaveClientString(smb_logp, uname)); } /* uuid */ memcpy(&uuid, tp, sizeof(uuid)); - if (!cm_FindTokenEvent(uuid, sessionKey)) { + if (!cm_FindTokenEvent(uuid, sessionKey, &rpc_sid)) { code = CM_ERROR_INVAL; goto done; } + if (!(pflags & AFSCALL_FLAG_LOCAL_SYSTEM) && rpc_sid) { + osi_Log1(smb_logp,"smb_IoctlSetToken Rpc Sid [%S]", + osi_LogSaveClientString(smb_logp, rpc_sid)); + if (!cm_ClientStrCmp(NTSID_LOCAL_SYSTEM, rpc_sid)) + pflags |= AFSCALL_FLAG_LOCAL_SYSTEM; + } + if (!(pflags & AFSCALL_FLAG_LOCAL_SYSTEM) && (flags & PIOCTL_LOGON)) { code = CM_ERROR_NOACCESS; goto done; } } else { cellp = cm_data.rootCellp; - osi_Log0(smb_logp,"cm_IoctlSetToken - no name specified"); + osi_Log0(smb_logp,"smb_IoctlSetToken - no name specified"); } if ((pflags & AFSCALL_FLAG_LOCAL_SYSTEM) && (flags & PIOCTL_LOGON)) { - userp = smb_FindCMUserByName(smbname, ioctlp->fidp->vcp->rname, - SMB_FLAG_CREATE|SMB_FLAG_AFSLOGON); - release_userp = 1; + PSID pSid = NULL; + DWORD dwSize1 = 0, dwSize2 = 0; + wchar_t *pszRefDomain = NULL; + SID_NAME_USE snu = SidTypeGroup; + clientchar_t * secSidString = NULL; + DWORD gle; + + /* + * The specified smbname is may not be a SID for the user. + * See if we can obtain the SID for the specified name. + * If we can, use that instead of the name provided. + */ + + LookupAccountNameW( NULL /* System Name to begin Search */, + smbname, + NULL, &dwSize1, + NULL, &dwSize2, + &snu); + gle = GetLastError(); + if (gle == ERROR_INSUFFICIENT_BUFFER) { + pSid = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, dwSize1); + /* + * Although dwSize2 is supposed to include the terminating + * NUL character, on Win7 it does not. + */ + pszRefDomain = malloc((dwSize2 + 1) * sizeof(wchar_t)); + } + + if ( pSid && pszRefDomain ) { + if (LookupAccountNameW( NULL /* System Name to begin Search */, + smbname, + pSid, &dwSize1, + pszRefDomain, &dwSize2, + &snu)) + ConvertSidToStringSidW(pSid, &secSidString); + } + + if (secSidString) { + userp = smb_FindCMUserBySID( secSidString, ioctlp->fidp->vcp->rname, + SMB_FLAG_CREATE|SMB_FLAG_AFSLOGON); + LocalFree(secSidString); + } else { + /* Free the SID so we can reuse the variable */ + if (pSid) { + LocalFree(pSid); + pSid = NULL; + } + + /* + * If the SID for the name could not be found, + * perhaps it already is a SID + */ + if (!ConvertStringSidToSidW( smbname, &pSid)) { + userp = smb_FindCMUserBySID( smbname, ioctlp->fidp->vcp->rname, + SMB_FLAG_CREATE|SMB_FLAG_AFSLOGON); + } else { + userp = smb_FindCMUserByName( smbname, ioctlp->fidp->vcp->rname, + SMB_FLAG_CREATE|SMB_FLAG_AFSLOGON); + } + } + + if (pSid) + LocalFree(pSid); + if (pszRefDomain) + free(pszRefDomain); + + release_userp = 1; } /* store the token */ lock_ObtainMutex(&userp->mx); ucellp = cm_GetUCell(userp, cellp); - osi_Log1(smb_logp,"cm_IoctlSetToken ucellp %lx", ucellp); + osi_Log1(smb_logp,"smb_IoctlSetToken ucellp %lx", ucellp); ucellp->ticketLen = ticketLen; if (ucellp->ticketp) free(ucellp->ticketp); /* Discard old token if any */ @@ -1944,7 +2042,7 @@ smb_IoctlSetOwner(struct smb_ioctl *ioctlp, struct cm_user *userp, afs_uint32 pf } /* - * VIOC_GETOWNER + * VIOC_SETGROUP * * This pioctl requires the use of the cm_ioctlQueryOptions_t structure. *