/*++ Copyright (c) 1991 Microsoft Corporation Module Name: ApiWksta.c Abstract: This module contains individual API handlers for the NetWksta APIs. SUPPORTED : NetWkstaGetInfo, NetWkstaSetInfo. UNSUPPORTED : NetWkstaSetUid. SEE ALSO : NetWkstaUserLogon, NetWkstaUserLogoff - in ApiLogon.c. Author: Shanku Niyogi (w-shanku) 25-Feb-1991 Revision History: --*/ #include "XactSrvP.h" // // Declaration of descriptor strings. // STATIC const LPDESC Desc16_wksta_info_0 = REM16_wksta_info_0; STATIC const LPDESC Desc16_wksta_info_1 = REM16_wksta_info_1; STATIC const LPDESC Desc16_wksta_info_10 = REM16_wksta_info_10; // // The size of the heuristics is actually 55 chars but we add one // for padding. // #define SIZE_HEURISTICS 56 NTSTATUS XsNetWkstaGetInfo ( API_HANDLER_PARAMETERS ) /*++ Routine Description: This routine sets up a call to NetWkstaGetInfo. Because of the differences between 16- and 32-bit structures, this routine does not use the normal conversion process. Arguments: API_HANDLER_PARAMETERS - information about the API call. See XsTypes.h for details. Return Value: NTSTATUS - STATUS_SUCCESS or reason for failure. --*/ { NET_API_STATUS status; PXS_NET_WKSTA_GET_INFO parameters = Parameters; LPWKSTA_INFO_100 wksta_100 = NULL; // Native parameters LPWKSTA_INFO_101 wksta_101 = NULL; LPWKSTA_INFO_502 wksta_502 = NULL; LPBYTE stringLocation = NULL; // Conversion variables DWORD bytesRequired = 0; BOOL varWrite; LPWKSTA_16_INFO_1 entry1; LPWKSTA_16_INFO_10 entry10; TCHAR heuristics[SIZE_HEURISTICS]; DWORD i; USHORT level; WCHAR lanroot[PATHLEN+1]; API_HANDLER_PARAMETERS_REFERENCE; // Avoid warnings IF_DEBUG(WKSTA) { NetpKdPrint(( "XsNetWkstaGetInfo: header at %lx, " "params at %lx, level %ld\n", Header, parameters, SmbGetUshort( ¶meters->Level ) )); } try { // // Check for errors. // level = SmbGetUshort( ¶meters->Level ); if ( (level != 0) && (level != 1) && (level != 10) ) { Header->Status = ERROR_INVALID_LEVEL; goto cleanup; } // // we return the system directory as the lanroot // *lanroot = 0; GetSystemDirectory(lanroot, sizeof(lanroot)/sizeof(*lanroot)); // // Gather the requested data by making local GetInfo calls. // switch ( level ) { case 10: status = NetWkstaGetInfo( NULL, (DWORD)100, (LPBYTE *)&wksta_100 ); if ( !XsApiSuccess ( status )) { IF_DEBUG(API_ERRORS) { NetpKdPrint(( "XsWkstaGetInfo: WkstaGetInfo (level 100) " "failed: %X\n", status)); } Header->Status = (WORD) status; goto cleanup; } break; case 0: case 1: status = NetWkstaGetInfo( NULL, (DWORD)101, (LPBYTE *)&wksta_101 ); if ( !XsApiSuccess( status )) { IF_DEBUG(API_ERRORS) { NetpKdPrint(( "XsWkstaGetInfo: WkstaGetInfo (level 101) " "failed: %X\n", status)); } Header->Status = (WORD) status; goto cleanup; } status = NetWkstaGetInfo( NULL, (DWORD)502, (LPBYTE *)&wksta_502 ); if ( !XsApiSuccess( status )) { IF_DEBUG(API_ERRORS) { NetpKdPrint(( "XsWkstaGetInfo: WkstaGetInfo (level 502) " "failed: %X\n", status)); } Header->Status = (WORD) status; goto cleanup; } break; } // // Calculate the amount of space required to hold the fixed and // variable data. Since this is the only place where we get one // case for each valid level, we will also get the source structure // descriptor here. // switch ( level ) { case 0: StructureDesc = Desc16_wksta_info_0; bytesRequired = sizeof( WKSTA_16_INFO_0 ) + NetpUnicodeToDBCSLen( lanroot ) + NetpUnicodeToDBCSLen( wksta_101->wki101_computername ) + NetpUnicodeToDBCSLen( DEF16_wk_username ) + NetpUnicodeToDBCSLen( wksta_101->wki101_langroup ) + NetpUnicodeToDBCSLen( DEF16_wk_logon_server ) + SIZE_HEURISTICS + 6; // for terminating nulls break; case 1: StructureDesc = Desc16_wksta_info_1; bytesRequired = sizeof( WKSTA_16_INFO_1 ) + NetpUnicodeToDBCSLen( lanroot ) + NetpUnicodeToDBCSLen( wksta_101->wki101_computername ) + NetpUnicodeToDBCSLen( DEF16_wk_username ) + NetpUnicodeToDBCSLen( wksta_101->wki101_langroup ) + NetpUnicodeToDBCSLen( DEF16_wk_logon_server ) + SIZE_HEURISTICS + NetpUnicodeToDBCSLen( DEF16_wk_logon_domain ) + NetpUnicodeToDBCSLen( DEF16_wk_oth_domains ) + 8; // for terminating nulls break; case 10: StructureDesc = Desc16_wksta_info_10; bytesRequired = sizeof( WKSTA_16_INFO_10 ) + NetpUnicodeToDBCSLen( DEF16_wk_username ) + NetpUnicodeToDBCSLen( DEF16_wk_logon_domain ) + NetpUnicodeToDBCSLen( wksta_100->wki100_computername ) + NetpUnicodeToDBCSLen( wksta_100->wki100_langroup ) + NetpUnicodeToDBCSLen( DEF16_wk_oth_domains ) + 5; // for terminating nulls break; } // // If there isn't enough room in the buffer for this, don't write any // variable data. // varWrite = ( (DWORD)SmbGetUshort( ¶meters->BufLen ) >= bytesRequired ) ? TRUE : FALSE; stringLocation = (LPBYTE)( XsSmbGetPointer( ¶meters->Buffer ) + RapStructureSize( StructureDesc, Response, FALSE )); // // Return NERR_BufTooSmall if fixed structure will not fit. // if ( !XsCheckBufferSize( SmbGetUshort( ¶meters->BufLen ), StructureDesc, FALSE // not in native format )) { IF_DEBUG(ERRORS) { NetpKdPrint(( "XsNetWkstaGetInfo: Buffer too small.\n" )); } Header->Status = NERR_BufTooSmall; SmbPutUshort( ¶meters->TotalAvail, (WORD)bytesRequired ); goto cleanup; } // // Based on the level, fill the appropriate information directly into // 16-bit buffer. // entry1 = (LPWKSTA_16_INFO_1) XsSmbGetPointer( ¶meters->Buffer ); entry10 = (LPWKSTA_16_INFO_10) entry1; switch ( level ) { case 1: if ( varWrite ) { XsAddVarString( stringLocation, DEF16_wk_logon_domain, &entry1->wki1_logon_domain, entry1 ); XsAddVarString( stringLocation, DEF16_wk_oth_domains, &entry1->wki1_oth_domains, entry1 ); } SmbPutUshort( &entry1->wki1_numdgrambuf, DEF16_wk_numdgrambuf ); // // Fill the rest of the level 1 structure just like a // level 0 structure. // case 0: // // Zero the reserved words. // SmbPutUshort( &entry1->wki1_reserved_1, (WORD) 0 ); SmbPutUlong( &entry1->wki1_reserved_2, (DWORD) 0 ); SmbPutUlong( &entry1->wki1_reserved_3, (DWORD) 0 ); SmbPutUshort( &entry1->wki1_reserved_4, (WORD) 0 ); SmbPutUshort( &entry1->wki1_reserved_5, (WORD) 0 ); SmbPutUshort( &entry1->wki1_reserved_6, (WORD) 0 ); // // Fill in the fields which have analogues in NT. // if ( varWrite ) { XsAddVarString( stringLocation, lanroot, &entry1->wki1_root, entry1 ); XsAddVarString( stringLocation, wksta_101->wki101_computername, &entry1->wki1_computername, entry1 ); XsAddVarString( stringLocation, wksta_101->wki101_langroup, &entry1->wki1_langroup, entry1 ); } entry1->wki1_ver_major = (BYTE) wksta_101->wki101_ver_major; entry1->wki1_ver_minor = (BYTE) wksta_101->wki101_ver_minor; SmbPutUshort( &entry1->wki1_charwait, XsDwordToWord( wksta_502->wki502_char_wait ) ); SmbPutUlong( &entry1->wki1_chartime, (DWORD) wksta_502->wki502_collection_time ); SmbPutUshort( &entry1->wki1_charcount, XsDwordToWord( wksta_502-> wki502_maximum_collection_count ) ); SmbPutUshort( &entry1->wki1_keepconn, XsDwordToWord( wksta_502->wki502_keep_conn ) ); SmbPutUshort( &entry1->wki1_maxthreads, XsDwordToWord( wksta_502->wki502_max_threads ) ); SmbPutUshort( &entry1->wki1_maxcmds, XsDwordToWord( wksta_502->wki502_max_cmds ) ); SmbPutUshort( &entry1->wki1_sesstimeout, XsDwordToWord( wksta_502->wki502_sess_timeout ) ); // // Construct the heuristics string. // // Request opportunistic locking of files. heuristics[0] = MAKE_TCHAR(XsBoolToDigit( wksta_502->wki502_use_opportunistic_locking )); // Optimize performance for command files. heuristics[1] = MAKE_TCHAR('1'); // Unlock and WriteUnlock asynchronously. heuristics[2] = MAKE_TCHAR('1'); // default // Close and WriteClose asynchronously. heuristics[3] = MAKE_TCHAR('1'); // default // Buffer named pipes and communication devices. heuristics[4] = MAKE_TCHAR(XsBoolToDigit( wksta_502->wki502_buf_named_pipes )); // LockRead and WriteUnlock. heuristics[5] = MAKE_TCHAR(XsBoolToDigit( wksta_502->wki502_use_lock_read_unlock )); // Use Open and Read. heuristics[6] = MAKE_TCHAR('0'); // Read-ahead to sector boundary. heuristics[7] = MAKE_TCHAR('1'); // Use the "chain send" NetBIOS NCB. heuristics[8] = MAKE_TCHAR('2'); // Buffer small read/write requests. heuristics[9] = MAKE_TCHAR('1'); // Use buffer mode. heuristics[10] = MAKE_TCHAR('3'); // Use raw data transfer read/write server message block protocols. heuristics[11] = MAKE_TCHAR('1'); // Use large RAW read-ahead buffer. heuristics[12] = MAKE_TCHAR('1'); // Use large RAW write-behind buffer. heuristics[13] = MAKE_TCHAR('1'); // Use read multiplex SMB protocols. heuristics[14] = MAKE_TCHAR('0'); // Use write multiplex SMB protocols. heuristics[15] = MAKE_TCHAR('0'); // Use big buffer for large core reads. heuristics[16] = MAKE_TCHAR('1'); // Set the read-ahead size. heuristics[17] = MAKE_TCHAR('0'); // Set the write-behind size. heuristics[18] = MAKE_TCHAR('0'); // Force 512-byte maximum transfers to and from core servers. heuristics[19] = MAKE_TCHAR(XsBoolToDigit( wksta_502->wki502_use_512_byte_max_transfer )); // Flush pipes and devices on DosBufReset or DosClose. heuristics[20] = MAKE_TCHAR('0'); // Use encryption if the server supports it. heuristics[21] = MAKE_TCHAR(XsBoolToDigit( wksta_502->wki502_use_encryption )); // Control log entries for multiple occurences of an error. heuristics[22] = MAKE_TCHAR('1'); // Buffer all files opened with "deny write" rights. heuristics[23] = MAKE_TCHAR(XsBoolToDigit( wksta_502->wki502_buf_files_deny_write )); // Buffer all files opened with R attribute. heuristics[24] = MAKE_TCHAR(XsBoolToDigit( wksta_502->wki502_buf_read_only_files )); // Read ahead when opening a file for execution. heuristics[25] = MAKE_TCHAR('0'); // Handle Ctrl-C. heuristics[26] = MAKE_TCHAR('2'); // Force correct open mode when creating files on a core server. heuristics[27] = MAKE_TCHAR(XsBoolToDigit( wksta_502->wki502_force_core_create_mode )); // Use NetBIOS NoAck mode. heuristics[28] = MAKE_TCHAR('0'); // Send data along with SMB write-block-RAW requests. heuristics[29] = MAKE_TCHAR('1'); // Send a popup when the workstation logs an error. heuristics[30] = MAKE_TCHAR('1'); // Close the print job, causing the remote spooler to print if no // activity occurs on the printer for the time specified. heuristics[31] = MAKE_TCHAR('0'); // Controls BufReset and SMBFlush behavior for the MS-DOS // compatibility box. heuristics[32] = MAKE_TCHAR('2'); // Controls the time-out value for performing logon validation from a // domain controller. heuristics[33] = MAKE_TCHAR('0'); for ( i = 34; i <= 54; i++ ) { heuristics[i] = MAKE_TCHAR('0'); } heuristics[SIZE_HEURISTICS-1] = MAKE_TCHAR('\0'); if ( varWrite ) { XsAddVarString( stringLocation, heuristics, &entry1->wki1_wrkheuristics, entry1 ); } // // Put default values in the fields that are meaningless in NT. // if ( varWrite ) { XsAddVarString( stringLocation, DEF16_wk_logon_server, &entry1->wki1_logon_server, entry1 ); XsAddVarString( stringLocation, DEF16_wk_username, &entry1->wki1_username, entry1 ); } SmbPutUshort( &entry1->wki1_keepsearch, (WORD) DEF16_wk_keepsearch ); SmbPutUshort( &entry1->wki1_numworkbuf, (WORD) DEF16_wk_numworkbuf ); SmbPutUshort( &entry1->wki1_sizworkbuf, (WORD) DEF16_wk_sizeworkbuf ); SmbPutUshort( &entry1->wki1_maxwrkcache, (WORD) DEF16_wk_maxwrkcache ); SmbPutUshort( &entry1->wki1_sizerror, (WORD) DEF16_wk_sizerror ); SmbPutUshort( &entry1->wki1_numalerts, (WORD) DEF16_wk_numalerts ); SmbPutUshort( &entry1->wki1_numservices, (WORD) DEF16_wk_numservices ); SmbPutUshort( &entry1->wki1_errlogsz, (WORD) DEF16_wk_errlogsz ); SmbPutUshort( &entry1->wki1_printbuftime, (WORD) DEF16_wk_printbuftime ); SmbPutUshort( &entry1->wki1_numcharbuf, (WORD) DEF16_wk_numcharbuf ); SmbPutUshort( &entry1->wki1_sizcharbuf, (WORD) DEF16_wk_sizcharbuf ); SmbPutUshort( &entry1->wki1_mailslots, (WORD) DEF16_wk_mailslots ); break; case 10: // // Fill in the fields which have analogues in NT. // if ( varWrite ) { XsAddVarString( stringLocation, wksta_100->wki100_computername, &entry10->wki10_computername, entry10 ); XsAddVarString( stringLocation, wksta_100->wki100_langroup, &entry10->wki10_langroup, entry10 ); } entry10->wki10_ver_major = XsDwordToByte( wksta_100->wki100_ver_major ); entry10->wki10_ver_minor = XsDwordToByte( wksta_100->wki100_ver_minor ); // // Put default values in the fields that are meaningless in NT. // if ( varWrite ) { XsAddVarString( stringLocation, DEF16_wk_username, &entry10->wki10_username, entry10 ); XsAddVarString( stringLocation, DEF16_wk_logon_domain, &entry10->wki10_logon_domain, entry10 ); XsAddVarString( stringLocation, DEF16_wk_oth_domains, &entry10->wki10_oth_domains, entry10 ); } break; } SmbPutUshort( ¶meters->TotalAvail, (WORD)bytesRequired ); if ( varWrite == 0 ) { Header->Status = ERROR_MORE_DATA; } else { Header->Status = NERR_Success; Header->Converter = 0; } cleanup: ; } except( EXCEPTION_EXECUTE_HANDLER ) { Header->Status = (WORD)RtlNtStatusToDosError( GetExceptionCode() ); } if ( wksta_100 != NULL ) { NetApiBufferFree( wksta_100 ); } if ( wksta_101 != NULL ) { NetApiBufferFree( wksta_101 ); } if ( wksta_502 != NULL ) { NetApiBufferFree( wksta_502 ); } // // Determine return buffer size. // XsSetDataCount( ¶meters->BufLen, StructureDesc, Header->Converter, 1, Header->Status ); return STATUS_SUCCESS; } // XsNetWkstaGetInfo NTSTATUS XsNetWkstaSetInfo ( API_HANDLER_PARAMETERS ) /*++ Routine Description: This routine handles a call to NetWkstaSetInfo. Arguments: API_HANDLER_PARAMETERS - information about the API call. See XsTypes.h for details. Return Value: NTSTATUS - STATUS_SUCCESS or reason for failure. --*/ { NET_API_STATUS status; PXS_NET_WKSTA_SET_INFO parameters = Parameters; DWORD data; BOOL flag; DWORD nativeParmNum; LPVOID buffer = NULL; // Conversion variables DWORD bufferSize; LPWKSTA_16_INFO_1 entry1; LPWKSTA_16_INFO_10 entry10; BOOL error; DWORD parmNum; API_HANDLER_PARAMETERS_REFERENCE; // Avoid warnings try { // // Check for errors. We will filter out wrong levels now. // parmNum = SmbGetUshort( ¶meters->ParmNum ); switch ( SmbGetUshort( ¶meters->Level )) { case 0: StructureDesc = Desc16_wksta_info_0; if ( parmNum == WKSTA_OTH_DOMAINS_PARMNUM ) { Header->Status = ERROR_INVALID_LEVEL; goto cleanup; } break; case 1: StructureDesc = Desc16_wksta_info_1; break; case 10: StructureDesc = Desc16_wksta_info_10; if ( parmNum == WKSTA_CHARWAIT_PARMNUM || parmNum == WKSTA_CHARTIME_PARMNUM || parmNum == WKSTA_CHARCOUNT_PARMNUM || parmNum == WKSTA_ERRLOGSZ_PARMNUM || parmNum == WKSTA_PRINTBUFTIME_PARMNUM || parmNum == WKSTA_WRKHEURISTICS_PARMNUM ) { Header->Status = ERROR_INVALID_LEVEL; goto cleanup; } break; default: Header->Status = ERROR_INVALID_LEVEL; goto cleanup; break; } // // Check input buffer size if parmnum is PARMNUM_ALL. // if ( parmNum == PARMNUM_ALL ) { if ( !XsCheckBufferSize( SmbGetUshort( ¶meters->BufLen ), StructureDesc, FALSE // not in native format )) { Header->Status = NERR_BufTooSmall; goto cleanup; } } buffer = (LPVOID)XsSmbGetPointer( ¶meters->Buffer ); bufferSize = (DWORD)SmbGetUshort( ¶meters->BufLen ); entry1 = (LPWKSTA_16_INFO_1)buffer; entry10 = (LPWKSTA_16_INFO_10)buffer; // // Processing of this API depends on the value of the ParmNum // parameter. Because of all the discrepancies between NT and downlevel // info structures, we will handle each instance by hand. // error = TRUE; // // charwait - source data is in a WORD - convert to DWORD // if ( parmNum == PARMNUM_ALL || parmNum == WKSTA_CHARWAIT_PARMNUM ) { if ( bufferSize < sizeof(WORD) ) { Header->Status = NERR_BufTooSmall; goto cleanup; } data = ( parmNum == PARMNUM_ALL ) ? (DWORD)SmbGetUshort( &entry1->wki1_charwait ) : (DWORD)SmbGetUshort( (LPWORD)buffer ); status = NetWkstaSetInfo( NULL, PARMNUM_BASE_INFOLEVEL + WKSTA_CHARWAIT_PARMNUM, (LPBYTE)&data, NULL ); if ( status != NERR_Success ) { IF_DEBUG(ERRORS) { NetpKdPrint(( "XsNetWkstaSetInfo : SetInfo of charwait failed" "%X\n", status )); } Header->Status = (WORD)status; goto cleanup; } error = FALSE; } // // chartime - source data is in a DWORD - convert to DWORD // if ( parmNum == PARMNUM_ALL || parmNum == WKSTA_CHARTIME_PARMNUM ) { if ( bufferSize < sizeof(DWORD) ) { Header->Status = NERR_BufTooSmall; goto cleanup; } data = ( parmNum == PARMNUM_ALL ) ? SmbGetUlong( &entry1->wki1_chartime ) : SmbGetUlong( (LPDWORD)buffer ); status = NetWkstaSetInfo( NULL, PARMNUM_BASE_INFOLEVEL + WKSTA_CHARTIME_PARMNUM, (LPBYTE)&data, NULL ); if ( status != NERR_Success ) { IF_DEBUG(ERRORS) { NetpKdPrint(( "XsNetWkstaSetInfo : SetInfo of chartime failed" "%X\n", status )); } Header->Status = (WORD)status; goto cleanup; } error = FALSE; } // // charcount - source data is in a WORD - convert to DWORD // if ( parmNum == PARMNUM_ALL || parmNum == WKSTA_CHARCOUNT_PARMNUM ) { if ( bufferSize < sizeof(WORD) ) { Header->Status = NERR_BufTooSmall; goto cleanup; } data = ( parmNum == PARMNUM_ALL ) ? (DWORD)SmbGetUshort( &entry1->wki1_charcount ) : (DWORD)SmbGetUshort( (LPWORD)buffer ); status = NetWkstaSetInfo( NULL, PARMNUM_BASE_INFOLEVEL + WKSTA_CHARCOUNT_PARMNUM, (LPBYTE)&data, NULL ); if ( status != NERR_Success ) { IF_DEBUG(ERRORS) { NetpKdPrint(( "XsNetWkstaSetInfo : SetInfo of charcount failed" "%X\n", status )); } Header->Status = (WORD)status; goto cleanup; } error = FALSE; } // // errlogsz, printbuftime - source data is in a WORD. // // We can't set this, but downlevel can, so indicate success, // as long as something was sent. // if ( parmNum == PARMNUM_ALL || parmNum == WKSTA_ERRLOGSZ_PARMNUM || parmNum == WKSTA_PRINTBUFTIME_PARMNUM ) { if ( bufferSize < sizeof(WORD) ) { Header->Status = NERR_BufTooSmall; goto cleanup; } error = FALSE; } // // othdomains - source data is a string. // // We can't set this, but downlevel can, so indicate success, // as long as something was sent. // if ( parmNum == PARMNUM_ALL || parmNum == WKSTA_OTH_DOMAINS_PARMNUM ) { if ( bufferSize == 0 ) { Header->Status = NERR_BufTooSmall; goto cleanup; } error = FALSE; } // // wrkheuristics - source data is in a string. // // There are some elements of this that we can set. We go through a loop, // setting these. // if ( parmNum == PARMNUM_ALL || parmNum == WKSTA_WRKHEURISTICS_PARMNUM ) { LPBYTE heuristics; DWORD i; if ( bufferSize < 54 ) { Header->Status = NERR_BufTooSmall; goto cleanup; } heuristics = ( parmNum == PARMNUM_ALL ) ? (LPBYTE)XsSmbGetPointer( &entry1->wki1_wrkheuristics ) : (LPBYTE)buffer; // // Nothing to be changed // if ( heuristics == NULL ) { goto cleanup; } // // Make sure we have the right size of string. // if ( strlen( heuristics ) != 54 ) { Header->Status = ERROR_INVALID_PARAMETER; goto cleanup; } for ( i = 0; i < 54; i++ ) { // // Make sure heuristics string is valid. // if ( !isdigit( heuristics[i] )) { Header->Status = ERROR_INVALID_PARAMETER; goto cleanup; } // // Check if we can set this field. // switch ( i ) { case 0: nativeParmNum = WKSTA_USEOPPORTUNISTICLOCKING_PARMNUM; break; case 4: nativeParmNum = WKSTA_BUFFERNAMEDPIPES_PARMNUM; break; case 5: nativeParmNum = WKSTA_USELOCKANDREADANDUNLOCK_PARMNUM; break; case 19: nativeParmNum = WKSTA_USE512BYTESMAXTRANSFER_PARMNUM; break; case 21: nativeParmNum = WKSTA_USEENCRYPTION_PARMNUM; break; case 23: nativeParmNum = WKSTA_BUFFILESWITHDENYWRITE_PARMNUM; break; case 24: nativeParmNum = WKSTA_BUFFERREADONLYFILES_PARMNUM; break; case 27: nativeParmNum = WKSTA_FORCECORECREATEMODE_PARMNUM; break; default: nativeParmNum = 0; break; } // // If we can set the field, set it. // if ( nativeParmNum != 0 ) { if ( heuristics[i] != '0' && heuristics[i] != '1' ) { Header->Status = ERROR_INVALID_PARAMETER; goto cleanup; } flag = XsDigitToBool( heuristics[i] ); status = NetWkstaSetInfo( NULL, PARMNUM_BASE_INFOLEVEL + nativeParmNum, (LPBYTE)&flag, NULL ); if ( status != NERR_Success ) { IF_DEBUG(ERRORS) { NetpKdPrint(( "XsNetWkstaSetInfo : SetInfo of a " "heuristic failed: %X\n", status )); } Header->Status = (WORD)status; goto cleanup; } } } error = FALSE; } // // Tried all possible parmnums. If error is still set, we have an // invalid parmnum on our hands. // if ( error ) { Header->Status = ERROR_INVALID_PARAMETER; } // // No return information for this API. // cleanup: ; } except( EXCEPTION_EXECUTE_HANDLER ) { Header->Status = (WORD)RtlNtStatusToDosError( GetExceptionCode() ); } return STATUS_SUCCESS; } // XsNetWkstaSetInfo NTSTATUS XsNetWkstaSetUID ( API_HANDLER_PARAMETERS ) /*++ Routine Description: This temporary routine just returns STATUS_NOT_IMPLEMENTED. Arguments: API_HANDLER_PARAMETERS - information about the API call. See XsTypes.h for details. Return Value: NTSTATUS - STATUS_SUCCESS or reason for failure. --*/ { API_HANDLER_PARAMETERS_REFERENCE; // Avoid warnings Header->Status = (WORD)NERR_InvalidAPI; return STATUS_SUCCESS; } // XsNetWkstaSetUID