/* File: user.c Handles routemon options to get and set RAS user properties. */ #include "precomp.h" #define NT40_BUILD_NUMBER 1381 const WCHAR pszBuildNumPath[] = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"; const WCHAR pszBuildVal[] = L"CurrentBuildNumber"; // // Defines a macro to perform string copies to // unicode strings regardless of the UNICODE setting. // #if defined( UNICODE ) || defined( _UNICODE ) #define UserStrcpy(dst, src) wcscpy((dst), (src)); #else #define UserStrcpy(dst, src) mbstowcs((dst), (src), strlen((src))); #endif // // Defines structure of parameters that can be sent to // a User api's. // typedef struct _USER_PARAMS { PWCHAR pszMachine; // Given machine DWORD dwToken; // Token designating the desired command WCHAR pszAccount[1024]; // The account in question BOOL bPolicySpecified; // Whether policy given on cmd line DWORD dwTokenPolicy; // Specifies the token for the callback policy RAS_USER_0 UserInfo; // Buffer to hold user info } USER_PARAMS, * PUSER_PARAMS; // // Determines the role of the given computer (NTW, NTS, NTS DC, etc.) // DWORD UserGetMachineRole( IN PWCHAR pszMachine, OUT DSROLE_MACHINE_ROLE * peRole) { PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pGlobalDomainInfo = NULL; DWORD dwErr; if (!peRole) return ERROR_INVALID_PARAMETER; // // Get the name of the domain this machine is a member of // __try { dwErr = DsRoleGetPrimaryDomainInformation( pszMachine, DsRolePrimaryDomainInfoBasic, (LPBYTE *)&pGlobalDomainInfo ); if (dwErr != NO_ERROR) return dwErr; *peRole = pGlobalDomainInfo->MachineRole; } __finally { if (pGlobalDomainInfo) DsRoleFreeMemory (pGlobalDomainInfo); } return NO_ERROR; } // // Determines the build number of a given machine // DWORD UserGetNtosBuildNumber( IN PWCHAR pszMachine, OUT LPDWORD lpdwBuild) { WCHAR pszComputer[1024], pszBuf[64]; HKEY hkBuild = NULL, hkMachine = NULL; DWORD dwErr, dwType = REG_SZ, dwSize = sizeof(pszBuf); __try { if (pszMachine) { if (*pszMachine != L'\\') wsprintfW(pszComputer, L"\\\\%s", pszMachine); else wcscpy(pszComputer, pszMachine); dwErr = RegConnectRegistryW (pszComputer, HKEY_LOCAL_MACHINE, &hkMachine); if (dwErr != ERROR_SUCCESS) return dwErr; } else hkMachine = HKEY_LOCAL_MACHINE; // Open the build number key dwErr = RegOpenKeyExW ( hkMachine, pszBuildNumPath, 0, KEY_READ, &hkBuild); if (dwErr != ERROR_SUCCESS) return dwErr; // Get the value dwErr = RegQueryValueExW ( hkBuild, pszBuildVal, NULL, &dwType, (LPBYTE)pszBuf, &dwSize); if (dwErr != ERROR_SUCCESS) return dwErr; *lpdwBuild = (DWORD) _wtoi(pszBuf); } __finally { if (hkMachine && pszMachine) RegCloseKey(hkMachine); if (hkBuild) RegCloseKey(hkBuild); } return NO_ERROR; } // // Returns a static error message // PWCHAR UserError (DWORD dwErr) { static WCHAR pszRet[512]; ZeroMemory(pszRet, sizeof(pszRet)); FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr, 0, pszRet, sizeof(pszRet) / sizeof(WCHAR), NULL); return pszRet; } // // Displays usage and returns a generic error. // DWORD UserUsage( IN HINSTANCE hInst, IN PROUTEMON_PARAMS pRmParams, IN PROUTEMON_UTILS pUtils) { pUtils->put_msg (hInst, MSG_USER_HELP, pRmParams->pszProgramName); return ERROR_CAN_NOT_COMPLETE; } // // Parses the register command line and fills // the parameters accordingly. // DWORD UserParse ( IN int argc, IN TCHAR *argv[], IN PROUTEMON_PARAMS pRmParams, IN PROUTEMON_UTILS pUtils, IN BOOL bLoad, OUT USER_PARAMS * pParams) { DWORD dwSize, dwErr; BOOL bValidCmd = FALSE; HINSTANCE hInst = GetModuleHandle(NULL); TCHAR buf[MAX_TOKEN]; // Initialize the return val ZeroMemory(pParams, sizeof(USER_PARAMS)); // Parse out the name of the computer if (pRmParams->wszRouterName[0]) pParams->pszMachine = (PWCHAR)&(pRmParams->wszRouterName[0]); // Make sure some command was issued if (argc == 0) return UserUsage(hInst, pRmParams, pUtils); // Parse out the command if (_tcsicmp(argv[0], GetString (hInst, TOKEN_ENABLE, buf))==0) { pParams->dwToken = TOKEN_ENABLE; if (argc == 1) return UserUsage(hInst, pRmParams, pUtils); UserStrcpy(pParams->pszAccount, argv[1]); // Optional setting of callback policy and number if (argc > 2) { pParams->bPolicySpecified = TRUE; if (_tcsicmp(argv[2], GetString (hInst, TOKEN_NONE, buf))==0) pParams->dwTokenPolicy = TOKEN_NONE; else if (_tcsicmp(argv[2], GetString (hInst, TOKEN_CALLER, buf))==0) pParams->dwTokenPolicy = TOKEN_CALLER; else if (_tcsicmp(argv[2], GetString (hInst, TOKEN_ADMIN, buf))==0) pParams->dwTokenPolicy = TOKEN_ADMIN; if ((pParams->dwTokenPolicy == TOKEN_ADMIN) && (argc < 3)) { return UserUsage(hInst, pRmParams, pUtils); } else if (pParams->dwTokenPolicy == TOKEN_ADMIN) { UserStrcpy(pParams->UserInfo.wszPhoneNumber, argv[3]); } } } else if (_tcsicmp(argv[0], GetString (hInst, TOKEN_DISABLE, buf))==0) { pParams->dwToken = TOKEN_DISABLE; if (argc == 1) return UserUsage(hInst, pRmParams, pUtils); UserStrcpy(pParams->pszAccount, argv[1]); } else if (_tcsicmp(argv[0], GetString (hInst, TOKEN_SHOW, buf))==0) { pParams->dwToken = TOKEN_SHOW; if (argc == 1) return UserUsage(hInst, pRmParams, pUtils); UserStrcpy(pParams->pszAccount, argv[1]); } else if (_tcsicmp(argv[0], GetString (hInst, TOKEN_UPGRADE, buf))==0) { pParams->dwToken = TOKEN_UPGRADE; } else return UserUsage(hInst, pRmParams, pUtils); return NO_ERROR; } // // Cleans up any User parameters // DWORD UserCleanup ( IN PUSER_PARAMS pParams) { if (pParams->pszMachine) free(pParams->pszMachine); return NO_ERROR; } // // Gets user info // DWORD UserGetInfo ( IN PWCHAR lpszServer, IN PWCHAR lpszUser, IN DWORD dwLevel, OUT LPBYTE lpbBuffer) { DWORD dwErr, dwBuild; // Find out the OS of the given machine. dwErr = UserGetNtosBuildNumber( lpszServer, &dwBuild); if (dwErr != NO_ERROR) return dwErr; // If the target machine is nt4, use nt4 userparms if (dwBuild <= NT40_BUILD_NUMBER) { return MprAdminUserGetInfo( lpszServer, lpszUser, dwLevel, lpbBuffer); } // Otherwise, use SDO's else { HANDLE hServer, hUser; dwErr = MprAdminUserServerConnect( lpszServer, TRUE, &hServer); if (dwErr != NO_ERROR) return dwErr; dwErr = MprAdminUserOpen( hServer, lpszUser, &hUser); if (dwErr != NO_ERROR) { MprAdminUserServerDisconnect(hServer); return dwErr; } dwErr = MprAdminUserRead( hUser, dwLevel, lpbBuffer); if (dwErr != NO_ERROR) { MprAdminUserClose(hUser); MprAdminUserServerDisconnect(hServer); return dwErr; } MprAdminUserClose(hUser); MprAdminUserServerDisconnect(hServer); } return NO_ERROR; } // // Sets user info // DWORD UserSetInfo ( IN PWCHAR lpszServer, IN PWCHAR lpszUser, IN DWORD dwLevel, OUT LPBYTE lpbBuffer) { DWORD dwErr, dwBuild; // Find out the OS of the given machine. dwErr = UserGetNtosBuildNumber( lpszServer, &dwBuild); if (dwErr != NO_ERROR) return dwErr; // If the target machine is nt4, use nt4 userparms if (dwBuild <= NT40_BUILD_NUMBER) { return MprAdminUserSetInfo( lpszServer, lpszUser, dwLevel, lpbBuffer); } // Otherwise, use SDO's else { HANDLE hServer, hUser; dwErr = MprAdminUserServerConnect( lpszServer, TRUE, &hServer); if (dwErr != NO_ERROR) return dwErr; dwErr = MprAdminUserOpen( hServer, lpszUser, &hUser); if (dwErr != NO_ERROR) { MprAdminUserServerDisconnect(hServer); return dwErr; } dwErr = MprAdminUserWrite( hUser, dwLevel, lpbBuffer); if (dwErr != NO_ERROR) { MprAdminUserClose(hUser); MprAdminUserServerDisconnect(hServer); return dwErr; } MprAdminUserClose(hUser); MprAdminUserServerDisconnect(hServer); } return NO_ERROR; } // // Enables or disables a user // DWORD UserEnableDisable( IN PROUTEMON_PARAMS pRmParams, IN PROUTEMON_UTILS pUtils, IN PUSER_PARAMS pParams) { DWORD dwErr; // Read in the old user properties if all the options // weren't specified on the command line. if (pParams->dwTokenPolicy != TOKEN_ADMIN) { dwErr = UserGetInfo( pParams->pszMachine, pParams->pszAccount, 0, (LPBYTE)&(pParams->UserInfo)); if (dwErr != NO_ERROR) return dwErr; } // Set the dialin policy if (pParams->dwToken == TOKEN_ENABLE) pParams->UserInfo.bfPrivilege |= RASPRIV_DialinPrivilege; else pParams->UserInfo.bfPrivilege &= ~RASPRIV_DialinPrivilege; // Set the callback policy. The callback number will already // be set through the parsing. if (pParams->bPolicySpecified) { // Initialize pParams->UserInfo.bfPrivilege &= ~RASPRIV_NoCallback; pParams->UserInfo.bfPrivilege &= ~RASPRIV_CallerSetCallback; pParams->UserInfo.bfPrivilege &= ~RASPRIV_AdminSetCallback; // Set if (pParams->dwTokenPolicy == TOKEN_NONE) pParams->UserInfo.bfPrivilege |= RASPRIV_NoCallback; else if (pParams->dwTokenPolicy == TOKEN_CALLER) pParams->UserInfo.bfPrivilege |= RASPRIV_CallerSetCallback; else pParams->UserInfo.bfPrivilege |= RASPRIV_AdminSetCallback; } // Otherwise, initialize the display token else { if (pParams->UserInfo.bfPrivilege & RASPRIV_NoCallback) pParams->dwTokenPolicy = TOKEN_NONE; else if (pParams->UserInfo.bfPrivilege & RASPRIV_CallerSetCallback) pParams->dwTokenPolicy = TOKEN_CALLER; else pParams->dwTokenPolicy = TOKEN_ADMIN; } // Commit the changes to the system dwErr = UserSetInfo( pParams->pszMachine, pParams->pszAccount, 0, (LPBYTE)&(pParams->UserInfo)); if (dwErr != NO_ERROR) return dwErr; // Print out the results { HINSTANCE hInst = GetModuleHandle(NULL); TCHAR buf1[MAX_TOKEN], buf2[MAX_TOKEN]; DWORD dwYesNo; dwYesNo = (pParams->dwToken == TOKEN_ENABLE) ? VAL_YES : VAL_NO; pUtils->put_msg( hInst, MSG_USER_ENABLEDISABLE_SUCCESS, pParams->pszAccount, GetString (hInst, dwYesNo, buf1), GetString (hInst, pParams->dwTokenPolicy, buf2), pParams->UserInfo.wszPhoneNumber ); } return NO_ERROR; } // // Shows a user // DWORD UserShow( IN PROUTEMON_PARAMS pRmParams, IN PROUTEMON_UTILS pUtils, IN PUSER_PARAMS pParams) { DWORD dwErr; dwErr = UserGetInfo( pParams->pszMachine, pParams->pszAccount, 0, (LPBYTE)&(pParams->UserInfo)); if (dwErr != NO_ERROR) return dwErr; // Print out the results { HINSTANCE hInst = GetModuleHandle(NULL); TCHAR buf1[MAX_TOKEN], buf2[MAX_TOKEN]; DWORD dwTknEnable, dwTknPolicy; dwTknEnable = (pParams->UserInfo.bfPrivilege & RASPRIV_DialinPrivilege) ? VAL_YES : VAL_NO; if (pParams->UserInfo.bfPrivilege & RASPRIV_NoCallback) dwTknPolicy = TOKEN_NONE; else if (pParams->UserInfo.bfPrivilege & RASPRIV_CallerSetCallback) dwTknPolicy = TOKEN_CALLER; else dwTknPolicy = TOKEN_ADMIN; pUtils->put_msg( hInst, MSG_USER_SHOW_SUCCESS, pParams->pszAccount, GetString (hInst, dwTknEnable, buf1), GetString (hInst, dwTknPolicy, buf2), pParams->UserInfo.wszPhoneNumber ); } return NO_ERROR; } // // Upgrades a user // DWORD UserUpgrade( IN PROUTEMON_PARAMS pRmParams, IN PROUTEMON_UTILS pUtils, IN PUSER_PARAMS pParams) { BOOL bLocal = FALSE; DWORD dwErr, dwBuild; DSROLE_MACHINE_ROLE eRole; // Determine whether this should be local or // domain upgrade. dwErr = UserGetNtosBuildNumber(pParams->pszMachine, &dwBuild); if (dwErr != NO_ERROR) return dwErr; // You can upgrade nt4->nt4 if (dwBuild <= NT40_BUILD_NUMBER) return ERROR_CAN_NOT_COMPLETE; // Find out the role of the machine dwErr = UserGetMachineRole(pParams->pszMachine, &eRole); if (dwErr != NO_ERROR) return dwErr; // Now we know whether we're local bLocal = ((eRole != DsRole_RoleBackupDomainController) && (eRole != DsRole_RolePrimaryDomainController)); // Upgrade the users dwErr = MprAdminUpgradeUsers(pParams->pszMachine, bLocal); if (dwErr != NO_ERROR) return dwErr; // Print out the results { HINSTANCE hInst = GetModuleHandle(NULL); TCHAR buf[MAX_TOKEN]; DWORD dwToken; dwToken = (bLocal) ? VAL_LOCAL : VAL_DOMAIN; pUtils->put_msg( hInst, MSG_USER_UPGRADE_SUCCESS, GetString(hInst, dwToken, buf) ); } return NO_ERROR; } // // The User functionality engine // DWORD UserEngine ( IN PROUTEMON_PARAMS pRmParams, IN PROUTEMON_UTILS pUtils, IN PUSER_PARAMS pParams) { DWORD dwErr; HINSTANCE hInst = GetModuleHandle(NULL); switch (pParams->dwToken) { case TOKEN_ENABLE: case TOKEN_DISABLE: return UserEnableDisable(pRmParams, pUtils, pParams); case TOKEN_SHOW: return UserShow(pRmParams, pUtils, pParams); case TOKEN_UPGRADE: return UserUpgrade(pRmParams, pUtils, pParams); } return NO_ERROR; } // // Handles requests register a ras server in a domain // or to deregister a ras server in a domain or to query // whether a given ras server is registered in a given domain. // DWORD APIENTRY UserMonitor ( IN int argc, IN TCHAR *argv[], IN PROUTEMON_PARAMS params, IN PROUTEMON_UTILS utils ) { DWORD dwErr; USER_PARAMS UserParams; dwErr = UserParse ( argc, argv, params, utils, TRUE, &UserParams); if (dwErr != NO_ERROR) return NO_ERROR; dwErr = UserEngine (params, utils, &UserParams); UserCleanup(&UserParams); return dwErr; }