/******************************************************************************* * config.c * * Published Terminal Server APIs * * - user configuration routines * * Copyright 1998, Citrix Systems Inc. * Copyright (C) 1997-1999 Microsoft Corp. /******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #if(WINVER >= 0x0500) #include #include #else #include #include #endif #include #include #include #include // for NetGet[Any]DCName KLB 10-07-97 #include // for NERR_Success KLB 10-07-97 #include // for NetApiBufferFree KLB 10-07-97 #include /*============================================================================= == External procedures defined =============================================================================*/ BOOL WINAPI WTSQueryUserConfigW( LPWSTR, LPWSTR, WTS_CONFIG_CLASS, LPWSTR *, DWORD *); BOOL WINAPI WTSQueryUserConfigA( LPSTR, LPSTR, WTS_CONFIG_CLASS, LPSTR *, DWORD *); BOOL WINAPI WTSSetUserConfigW( LPWSTR, LPWSTR, WTS_CONFIG_CLASS, LPWSTR, DWORD); BOOL WINAPI WTSSetUserConfigA( LPSTR, LPSTR, WTS_CONFIG_CLASS, LPSTR, DWORD); /*============================================================================= == Internal procedures defined =============================================================================*/ #ifdef NETWARE //This should be defined in the wtsapi32.h typedef struct _WTS_USER_CONFIG_SET_NWSERVERW { LPWSTR pNWServerName; LPWSTR pNWDomainAdminName; LPWSTR pNWDomainAdminPassword; } WTS_USER_CONFIG_SET_NWSERVERW, * PWTS_USER_CONFIG_SET_NWSERVERW; BOOL SetNWAuthenticationServer(PWTS_USER_CONFIG_SET_NWSERVERW pInput, LPWSTR pServerNameW, LPWSTR pUserNameW, PUSERCONFIGW pUserConfigW ); #endif /*============================================================================= == Procedures used =============================================================================*/ BOOL _CopyData( PVOID, ULONG, LPWSTR *, DWORD * ); BOOL _CopyStringW( LPWSTR, LPWSTR *, DWORD * ); BOOL _CopyStringA( LPSTR, LPWSTR *, DWORD * ); BOOL _CopyStringWtoA( LPWSTR, LPSTR *, DWORD * ); BOOL ValidateCopyAnsiToUnicode(LPSTR, DWORD, LPWSTR); BOOL ValidateCopyUnicodeToUnicode(LPWSTR, DWORD, LPWSTR); VOID UnicodeToAnsi( CHAR *, ULONG, WCHAR * ); VOID AnsiToUnicode( WCHAR *, ULONG, CHAR * ); /*============================================================================= == Local Data =============================================================================*/ /**************************************************************************** * * WTSQueryUserConfigW (UNICODE) * * Query information from the SAM for the specified user * * ENTRY: * pServerName (input) * Name of server to access (NULL for current machine). * pUserName (input) * User name to query * WTSConfigClass (input) * Specifies the type of information to retrieve about the specified user * ppBuffer (output) * Points to the address of a variable to receive information about * the specified session. The format and contents of the data * depend on the specified information class being queried. The * buffer is allocated within this API and is disposed of using * WTSFreeMemory. * pBytesReturned (output) * An optional parameter that if specified, receives the number of * bytes returned. * * EXIT: * * TRUE -- The query operation succeeded. * * FALSE -- The operation failed. Extended error status is available * using GetLastError. * * HISTORY: * Created KLB 10-06-97 * ****************************************************************************/ BOOL WINAPI WTSQueryUserConfigW( IN LPWSTR pServerName, IN LPWSTR pUserName, IN WTS_CONFIG_CLASS WTSConfigClass, OUT LPWSTR * ppBuffer, OUT DWORD * pBytesReturned ) { USERCONFIGW UserConfigW; ULONG ulReturnLength; LONG rc; BOOL fSuccess = FALSE; DWORD dwfInheritInitialProgram; DWORD dwReturnValue; PUSER_INFO_0 pUserInfo = NULL; WCHAR netServerName[DOMAIN_LENGTH + 3]; /* * Check the null buffer */ if (!ppBuffer || !pBytesReturned) { SetLastError (ERROR_INVALID_PARAMETER); fSuccess = FALSE; goto done; } /* * First, we want to make sure the user actually exists on the specified * machine. */ rc = NetUserGetInfo( pServerName, // server name (can be NULL) pUserName, // user name 0, // level to query (0 = just name) (LPBYTE *)&pUserInfo );// buffer to return data to (they alloc, we free) /* * append the "\\" in front of server name to check the user name existence again */ if ( rc != NERR_Success && pServerName) { lstrcpyW(netServerName, L"\\\\"); lstrcatW(netServerName, pServerName); rc = NetUserGetInfo( netServerName, // server name (can be NULL) pUserName, // user name 0, // level to query (0 = user name) (LPBYTE *)&pUserInfo );// buffer to return data to (they alloc, we free) if ( rc != NERR_Success ) { SetLastError( ERROR_NO_SUCH_USER ); goto done; // exit with fSuccess = FALSE } } /* * Query the user. If the user config doesn't exist for the user, then * we query the default values. */ rc = RegUserConfigQuery( pServerName, // server name pUserName, // user name &UserConfigW, // returned user config (ULONG)sizeof(UserConfigW),// user config length &ulReturnLength ); // #bytes returned if ( rc != ERROR_SUCCESS ) { rc = RegDefaultUserConfigQuery( pServerName, // server name &UserConfigW, // returned user config (ULONG)sizeof(UserConfigW),// user config length &ulReturnLength ); // #bytes returned } /* * Now, process the results. Note that in each case, we're allocating a * new buffer which the caller must free * (WTSUserConfigfInheritInitialProgram is just a boolean, but we allocate * a DWORD to send it back). */ if ( rc == ERROR_SUCCESS ) { switch ( WTSConfigClass ) { case WTSUserConfigInitialProgram: fSuccess = _CopyStringW( UserConfigW.InitialProgram, ppBuffer, pBytesReturned ); break; case WTSUserConfigWorkingDirectory: fSuccess = _CopyStringW( UserConfigW.WorkDirectory, ppBuffer, pBytesReturned ); break; case WTSUserConfigfInheritInitialProgram: dwReturnValue = UserConfigW.fInheritInitialProgram; fSuccess = _CopyData( &dwReturnValue, sizeof(DWORD), ppBuffer, pBytesReturned ); break; case WTSUserConfigfAllowLogonTerminalServer: //DWORD returned/expected dwReturnValue = !(UserConfigW.fLogonDisabled); fSuccess = _CopyData( &dwReturnValue, sizeof(DWORD), ppBuffer, pBytesReturned ); break; //Timeout settings case WTSUserConfigTimeoutSettingsConnections: dwReturnValue = UserConfigW.MaxConnectionTime; fSuccess = _CopyData( &dwReturnValue, sizeof(DWORD), ppBuffer, pBytesReturned ); break; case WTSUserConfigTimeoutSettingsDisconnections: //DWORD dwReturnValue = UserConfigW.MaxDisconnectionTime; fSuccess = _CopyData( &dwReturnValue, sizeof(DWORD), ppBuffer, pBytesReturned ); break; case WTSUserConfigTimeoutSettingsIdle: //DWORD dwReturnValue = UserConfigW.MaxIdleTime; fSuccess = _CopyData( &dwReturnValue, sizeof(DWORD), ppBuffer, pBytesReturned ); break; case WTSUserConfigfDeviceClientDrives: //DWORD dwReturnValue = UserConfigW.fAutoClientDrives; fSuccess = _CopyData( &dwReturnValue, sizeof(DWORD), ppBuffer, pBytesReturned ); break; case WTSUserConfigfDeviceClientPrinters: //DWORD dwReturnValue = UserConfigW.fAutoClientLpts; fSuccess = _CopyData( &dwReturnValue, sizeof(DWORD), ppBuffer, pBytesReturned ); break; case WTSUserConfigfDeviceClientDefaultPrinter: //DWORD dwReturnValue = UserConfigW.fForceClientLptDef; fSuccess = _CopyData( &dwReturnValue, sizeof(DWORD), ppBuffer, pBytesReturned ); break; //Connection settings case WTSUserConfigBrokenTimeoutSettings: //DWORD dwReturnValue = UserConfigW.fResetBroken; fSuccess = _CopyData( &dwReturnValue, sizeof(DWORD), ppBuffer, pBytesReturned ); break; case WTSUserConfigReconnectSettings: dwReturnValue = UserConfigW.fReconnectSame; fSuccess = _CopyData( &dwReturnValue, sizeof(DWORD), ppBuffer, pBytesReturned ); break; //Modem settings case WTSUserConfigModemCallbackSettings: //DWORD dwReturnValue = UserConfigW.Callback; fSuccess = _CopyData( &dwReturnValue, sizeof(DWORD), ppBuffer, pBytesReturned ); break; case WTSUserConfigModemCallbackPhoneNumber: fSuccess = _CopyStringW(UserConfigW.CallbackNumber, ppBuffer, pBytesReturned ); break; case WTSUserConfigShadowingSettings: //DWORD dwReturnValue = UserConfigW.Shadow; fSuccess = _CopyData( &dwReturnValue, sizeof(DWORD), ppBuffer, pBytesReturned ); break; #ifdef NETWARE case WTSUserConfigNWServerName: // string fSuccess = _CopyStringW(UserConfigW.NWLogonServer, ppBuffer, pBytesReturned ); break; #endif case WTSUserConfigTerminalServerProfilePath: // string fSuccess = _CopyStringW(UserConfigW.WFProfilePath, ppBuffer, pBytesReturned ); break; case WTSUserConfigTerminalServerHomeDir: // string fSuccess = _CopyStringW(UserConfigW.WFHomeDir, ppBuffer, pBytesReturned ); break; case WTSUserConfigTerminalServerHomeDirDrive: // string fSuccess = _CopyStringW(UserConfigW.WFHomeDirDrive, ppBuffer, pBytesReturned ); break; case WTSUserConfigfTerminalServerRemoteHomeDir: // DWORD 0:LOCAL 1:REMOTE if (wcslen(UserConfigW.WFHomeDirDrive) > 0 ) { dwReturnValue = 1; } else { dwReturnValue = 0; } fSuccess = _CopyData( &dwReturnValue, sizeof(DWORD), ppBuffer, pBytesReturned ); break; #ifdef NETWARE case WTSUserConfigfNWMapRoot: dwReturnValue = UserConfigW.fHomeDirectoryMapRoot; fSuccess = _CopyData( &dwReturnValue, sizeof(DWORD), ppBuffer, pBytesReturned ); break; #endif } // switch() } //if (rc == ERROR_SUCCESS) done: if ( pUserInfo ) { NetApiBufferFree( pUserInfo ); } return( fSuccess ); } /**************************************************************************** * * WTSQueryUserConfigA (ANSI) * * Query information from the SAM for the specified user * * ENTRY: * * see WTSQueryUserConfigW * * EXIT: * * TRUE -- The query operation succeeded. * * FALSE -- The operation failed. Extended error status is available * using GetLastError. * * HISTORY: * Created KLB 10-06-97 * ****************************************************************************/ BOOL WINAPI WTSQueryUserConfigA( IN LPSTR pServerName, IN LPSTR pUserName, IN WTS_CONFIG_CLASS WTSConfigClass, OUT LPSTR * ppBuffer, OUT DWORD * pBytesReturned ) { LPWSTR lpBufferW = NULL; BOOL fSuccess; LONG rc; LPWSTR pUserNameW = NULL; LPWSTR pServerNameW = NULL; if (!ppBuffer || !pBytesReturned) { SetLastError (ERROR_INVALID_PARAMETER); fSuccess = FALSE; goto done; } fSuccess = _CopyStringA( pUserName, &pUserNameW, NULL ); if ( fSuccess ) { fSuccess = _CopyStringA( pServerName, &pServerNameW, NULL ); } if ( fSuccess ) { fSuccess = WTSQueryUserConfigW( pServerNameW, pUserNameW, WTSConfigClass, &lpBufferW, pBytesReturned ); LocalFree( pUserNameW ); } // Now, process the results. if ( fSuccess ) switch ( WTSConfigClass ) { case WTSUserConfigInitialProgram: case WTSUserConfigWorkingDirectory: case WTSUserConfigModemCallbackPhoneNumber: #ifdef NETWARE case WTSUserConfigNWServerName: // string returned/expected #endif case WTSUserConfigTerminalServerProfilePath: // string returned/expected case WTSUserConfigTerminalServerHomeDir: // string returned/expected case WTSUserConfigTerminalServerHomeDirDrive: // string returned/expected /* * String Data - Convert to ANSI */ fSuccess = _CopyStringWtoA( lpBufferW, ppBuffer, pBytesReturned ); LocalFree( lpBufferW ); break; default: /* * Just a DWORD, point buffer at the one returned (caller is * responsible for freeing, so this is cool). */ *ppBuffer = (LPSTR)lpBufferW; break; } // switch() done: return( fSuccess ); } /**************************************************************************** * * WTSSetUserConfigW (UNICODE) * * Set information in the SAM for the specified user * * ENTRY: * pServerName (input) * Name of server to access (NULL for current machine). * pUserName (input) * User name to query * WTSConfigClass (input) * Specifies the type of information to change for the specified user * pBuffer (input) * Pointer to the data used to modify the specified user's information. * DataLength (input) * The length of the data provided. * * EXIT: * * TRUE -- The query operation succeeded. * * FALSE -- The operation failed. Extended error status is available * using GetLastError. * * HISTORY: * Created KLB 10-06-97 * ****************************************************************************/ BOOL WINAPI WTSSetUserConfigW( IN LPWSTR pServerName, IN LPWSTR pUserName, IN WTS_CONFIG_CLASS WTSConfigClass, IN LPWSTR pBuffer, IN DWORD DataLength ) { USERCONFIGW UserConfigW; ULONG ulReturnLength; LONG rc; BOOL fSuccess = FALSE; BOOL fUserConfig = TRUE; //TRUE - We use RegUserConfigSet //FALSE - Use NetUserSetInfo DWORD dwfInheritInitialProgram; PDWORD pdwValue = (DWORD *) pBuffer; PUSER_INFO_0 pUserInfo = NULL; DWORD dwParam = 0; WCHAR netServerName[DOMAIN_LENGTH + 3]; if (!pBuffer || DataLength == 0) { SetLastError (ERROR_INVALID_PARAMETER); goto done; // exit with fSuccess = FALSE } /* * First, we want to make sure the user actually exists on the specified * machine. */ rc = NetUserGetInfo( pServerName, // server name (can be NULL) pUserName, // user name 0, // level to query (0 = just name) (LPBYTE *)&pUserInfo );// buffer to return data to (they alloc, we free) if ( rc != NERR_Success ) { if (pServerName != NULL) { lstrcpyW(netServerName, L"\\\\"); lstrcatW(netServerName, pServerName); rc = NetUserGetInfo( netServerName, // server name (can be NULL) pUserName, // user name 3, // level to query (3 = ust name) (LPBYTE *)&pUserInfo );// buffer to return data to (they alloc, we free) } else { rc = NetUserGetInfo( NULL, // server name is NULL pUserName, // user name 3, // level to query (3 = ust name) (LPBYTE *)&pUserInfo );// buffer to return data to (they alloc, we free) } if ( rc != NERR_Success ) { SetLastError( ERROR_NO_SUCH_USER ); goto done; // exit with fSuccess = FALSE } } /* * Query the user. If the user config doesn't exist for the user, then * we query the default values. */ rc = RegUserConfigQuery( pServerName, // server name pUserName, // user name &UserConfigW, // returned user config (ULONG)sizeof(UserConfigW),// user config length &ulReturnLength ); // #bytes returned if ( rc != ERROR_SUCCESS ) { rc = RegDefaultUserConfigQuery( pServerName, // server name &UserConfigW, // returned user config (ULONG)sizeof(UserConfigW),// user config length &ulReturnLength ); // #bytes returned } if ( rc != ERROR_SUCCESS ) { goto done; } /* * Now, we plug in the part we want to change. */ switch ( WTSConfigClass ) { case WTSUserConfigInitialProgram: if (!(fSuccess = ValidateCopyUnicodeToUnicode((LPWSTR)pBuffer, INITIALPROGRAM_LENGTH, UserConfigW.InitialProgram)) ) { SetLastError(ERROR_INVALID_DATA); goto done; } break; case WTSUserConfigWorkingDirectory: if (!(fSuccess = ValidateCopyUnicodeToUnicode((LPWSTR)pBuffer, DIRECTORY_LENGTH, UserConfigW.WorkDirectory)) ) { SetLastError(ERROR_INVALID_DATA); goto done; } break; case WTSUserConfigfInheritInitialProgram: /* * We have to point a DWORD pointer at the data, then assign it * from the DWORD, as that's how it's defined (and this will * ensure that it works okay on non-Intel architectures). */ UserConfigW.fInheritInitialProgram = *pdwValue; fSuccess = TRUE; break; case WTSUserConfigfAllowLogonTerminalServer: if (*pdwValue) { UserConfigW.fLogonDisabled = FALSE; } else { UserConfigW.fLogonDisabled = TRUE; } fSuccess = TRUE; break; case WTSUserConfigTimeoutSettingsConnections: UserConfigW.MaxConnectionTime = *pdwValue; fSuccess = TRUE; break; case WTSUserConfigTimeoutSettingsDisconnections: //DWORD UserConfigW.MaxDisconnectionTime = *pdwValue; fSuccess = TRUE; break; case WTSUserConfigTimeoutSettingsIdle: //DWORD UserConfigW.MaxIdleTime = *pdwValue; fSuccess = TRUE; break; case WTSUserConfigfDeviceClientDrives: //DWORD UserConfigW.fAutoClientDrives = *pdwValue; fSuccess = TRUE; break; case WTSUserConfigfDeviceClientPrinters: //DWORD UserConfigW.fAutoClientLpts = *pdwValue; fSuccess = TRUE; break; case WTSUserConfigfDeviceClientDefaultPrinter: //DWORD UserConfigW.fForceClientLptDef = *pdwValue; fSuccess = TRUE; break; case WTSUserConfigBrokenTimeoutSettings: //DWORD UserConfigW.fResetBroken= *pdwValue; fSuccess = TRUE; break; case WTSUserConfigReconnectSettings: UserConfigW.fReconnectSame = *pdwValue; fSuccess = TRUE; break; //Modem settings case WTSUserConfigModemCallbackSettings: //DWORD UserConfigW.Callback = *pdwValue; fSuccess = TRUE; break; case WTSUserConfigModemCallbackPhoneNumber: if (!(fSuccess = ValidateCopyUnicodeToUnicode((LPWSTR)pBuffer, sizeof(UserConfigW.CallbackNumber) - 1, UserConfigW.CallbackNumber)) ) { SetLastError(ERROR_INVALID_DATA); goto done; } break; case WTSUserConfigShadowingSettings: //DWORD UserConfigW.Shadow = *pdwValue; fSuccess = TRUE; break; #ifdef NETWARE case WTSUserConfigNWServerName: // WTS_USER_CONFIG_SET_NWSERVERW // Make sure the data structure is correct // if (DataLength < sizeof (WTS_USER_CONFIG_SET_NWSERVERW)) { fSuccess = FALSE; SetLastError(ERROR_INVALID_PARAMETER); goto done; } fSuccess = SetNWAuthenticationServer((PWTS_USER_CONFIG_SET_NWSERVERW)pBuffer, pServerName, pUserName, pBuffer, &UserConfigW); goto done; break; #endif case WTSUserConfigTerminalServerProfilePath: // string if (!(fSuccess = ValidateCopyUnicodeToUnicode((LPWSTR)pBuffer, sizeof(UserConfigW.WFProfilePath) - 1, UserConfigW.WFProfilePath)) ) { SetLastError(ERROR_INVALID_DATA); goto done; } break; case WTSUserConfigTerminalServerHomeDir: // string if (!(fSuccess = ValidateCopyUnicodeToUnicode((LPWSTR)pBuffer, sizeof(UserConfigW.WFHomeDir) - 1, UserConfigW.WFHomeDir)) ) { SetLastError(ERROR_INVALID_DATA); goto done; } break; case WTSUserConfigTerminalServerHomeDirDrive: // string if (!(fSuccess = ValidateCopyUnicodeToUnicode((LPWSTR)pBuffer, sizeof(UserConfigW.WFHomeDirDrive) - 1, UserConfigW.WFHomeDirDrive)) ) { SetLastError(ERROR_INVALID_DATA); goto done; } break; case WTSUserConfigfTerminalServerRemoteHomeDir: // DWORD 0:LOCAL 1:REMOTE fSuccess = FALSE; SetLastError (ERROR_INVALID_PARAMETER); // We don't set this parameter goto done; break; #ifdef NETWARE case WTSUserConfigfNWMapRoot: UserConfigW.fHomeDirectoryMapRoot = *pdwValue; fSuccess = TRUE; break; #endif default: fSuccess = FALSE; SetLastError (ERROR_INVALID_PARAMETER); goto done; } if ( fSuccess ) { if (fUserConfig) { /* * Only in here if we successfully changed the data in UserConfigW. * So, we can now write it out to the SAM. */ rc = RegUserConfigSet( pServerName, // server name pUserName, // user name &UserConfigW, // returned user config (ULONG)sizeof(UserConfigW));// user config length } fSuccess = (ERROR_SUCCESS == rc); if ( !fSuccess ) { SetLastError( rc ); } } done: if ( pUserInfo ) { NetApiBufferFree( pUserInfo ); } return(fSuccess); } /**************************************************************************** * * WTSSetUserConfigA (ANSI) * * Set information in the SAM for the specified user * * ENTRY: * * see WTSSetUserConfigW * * EXIT: * * TRUE -- The query operation succeeded. * * FALSE -- The operation failed. Extended error status is available * using GetLastError. * * HISTORY: * Created KLB 10-06-97 * ****************************************************************************/ BOOL WINAPI WTSSetUserConfigA( IN LPSTR pServerName, IN LPSTR pUserName, IN WTS_CONFIG_CLASS WTSConfigClass, IN LPSTR pBuffer, IN DWORD DataLength ) { BOOL fSuccess = FALSE; BOOL fFreepBufferW = TRUE; LPWSTR pUserNameW = NULL; LPWSTR pServerNameW = NULL; LPWSTR pBufferW = NULL; DWORD dwDataLength; if (!pBuffer || DataLength == 0) { SetLastError (ERROR_INVALID_PARAMETER); goto done; // exit with fSuccess = FALSE } /* * We're going to call WTSSetUserConfigW() to do the actual work. We need * to convert all ANSI strings to Unicode before calling. These are the * user name, and the pBuffer data if it's the initial program or the * working directory; if it's the flag for inherit initial program, it'll * be a DWORD in either case, so no conversion is necessary. */ fSuccess = _CopyStringA( pUserName, &pUserNameW, NULL ); if ( fSuccess ) { fSuccess = _CopyStringA( pServerName, &pServerNameW, NULL ); } if ( fSuccess ) switch ( WTSConfigClass ) { case WTSUserConfigInitialProgram: case WTSUserConfigWorkingDirectory: case WTSUserConfigModemCallbackPhoneNumber: case WTSUserConfigTerminalServerProfilePath: // string returned/expected case WTSUserConfigTerminalServerHomeDir: // string returned/expected case WTSUserConfigTerminalServerHomeDirDrive: // string returned/expected /* * String Data - Convert to Unicode (_CopyStringA() allocates * pBufferW for us) */ fSuccess = _CopyStringA( pBuffer, &pBufferW, &dwDataLength ); break; #ifdef NETWARE case WTSUserConfigNWServerName: // string returned/expected { //Need to convert the data structure from ASCII to UNICODE PWTS_USER_CONFIG_SET_NWSERVERW pSetNWServerParamW = LocalAlloc(LPTR, sizeof(WTS_USER_CONFIG_SET_NWSERVERW)); PWTS_USER_CONFIG_SET_NWSERVERA pSetNWServerParamA = (PWTS_USER_CONFIG_SET_NWSERVERA)pBuffer; DWORD dwLen = 0; if (pSetNWServerParamW == NULL) { fSuccess = FALSE; break; } pBufferW = pSetNWServerParamW; //----------------------------------------// // Allocate the buffer to hold the // // required unicode string // //----------------------------------------// dwLen = strlen(pSetNWServerParamA -> pNWServerName); if (fSuccess = _CopyStringA(pSetNWServerParamA -> pNWServerName, &pSetNWServerParamW -> pNWServerName, &dwLen)) { dwLen = strlen(pSetNWServerParamA -> pNWDomainAdminName); if (fSuccess = _CopyStringA(pSetNWServerParamA -> pNWDomainAdminName, &pSetNWServerParamW -> pNWDomainAdminName, &dwLen)) { dwLen = strlen(pSetNWServerParamA -> pNWDomainAdminPassword); fSuccess = _CopyStringA(pSetNWServerParamA -> pNWDomainAdminPassword, &pSetNWServerParamW -> pNWDomainAdminPassword, &dwLen); } } //-----------------------------------------// // Call the UNICODE function // //-----------------------------------------// if (fSuccess) { fSuccess = WTSSetUserConfigW( pServerNameW, pUserNameW, WTSConfigClass, pBufferW, dwDataLength ); } //----------------------------------------------// // Free the storage for the specific function // //----------------------------------------------// if (pSetNWServerParamW -> pNWServerName) { LocalFree( pSetNWServerParamW -> pNWServerName ); } if (pSetNWServerParamW -> pNWDomainAdminName) { LocalFree( pSetNWServerParamW -> pNWDomainAdminName ); } if (pSetNWServerParamW -> pNWDomainAdminPassword) { LocalFree( pSetNWServerParamW -> pNWDomainAdminPassword ); } goto done; break; } #endif default: /* * Just a DWORD, point our wide buffer at the narrow buffer passed * in to us and set the data length variable we'll pass down. * NOTE: WE DON'T WANT TO FREE THE BUFFER, since we're re-using * the buffer sent in and the caller expects to free it. We'll * use a BOOL to decide, rather than allocating an extra buffer * here (performance, memory fragmentation, etc.). KLB 10-08-97 */ pBufferW = (LPWSTR) pBuffer; dwDataLength = sizeof(DWORD); fFreepBufferW = FALSE; break; } // switch() /* * Now, if fSuccess is TRUE, we've copied all the strings we need. So, we * can now call WTSSetUserConfigW(). */ if ( fSuccess ) { fSuccess = WTSSetUserConfigW( pServerNameW, pUserNameW, WTSConfigClass, pBufferW, dwDataLength ); } done: if ( pUserNameW ) { LocalFree( pUserNameW ); } if ( fFreepBufferW && pBufferW ) { LocalFree( pBufferW ); } return(fSuccess); } #ifdef NETWARE BOOL SetNWAuthenticationServer(PWTS_USER_CONFIG_SET_NWSERVERW pInput, LPWSTR pServerNameW, LPWSTR pUserNameW, PUSERCONFIGW pUserConfigW ) { BOOL bStatus = TRUE; PWKSTA_INFO_100 pWkstaInfo = NULL; NWLOGONADMIN nwLogonAdmin; HANDLE hServer; DWORD dwStatus; //----------------------------------// // Get a Server handle //----------------------------------// hServer = RegOpenServer(pServerNameW); if (!hServer) { SetLastError(GetLastError()); bStatus = FALSE; goto done; } //---------------------------------- //find the domain name //------------------------------------ dwStatus = NetWkstaGetInfo( pServerNameW, 100, &pWkstaInfo ); if (dwStatus != ERROR_SUCCESS) { SetLastError(dwStatus); goto done; } //----------------------------------------------------- //Copy the parameter to the NWLOGONADMIN structure //----------------------------------------------------- bStatus = ValidateCopyUnicodeToUnicode(pInput -> pNWDomainAdminName, sizeof(nwLogonAdmin.Username)-1, nwLogonAdmin.Username); if (!bStatus) { goto done; } bStatus = ValidateCopyUnicodeToUnicode(pInput -> pNWDomainAdminPassword, sizeof(nwLogonAdmin.Password)-1, nwLogonAdmin.Password); if (!bStatus) { goto done; } bStatus = ValidateCopyUnicodeToUnicode(pWkstaInfo -> wki100_langroup, sizeof(nwLogonAdmin.Domain)-1, nwLogonAdmin.Domain); if (!bStatus) { goto done; } //------------------------------------------// // Set the admin // //-----------------------------------------// bStatus = _NWLogonSetAdmin(hServer, &nwLogonAdmin, sizeof(nwLogonAdmin)); if (!bStatus) { SetLastError(GetLastError()); goto done; } done: if (pWkstaInfo) { NetApiBufferFree(pWkstaInfo); } return bStatus; } #endif