/************************************************************ * ACCESS_QueryGuestDisplayInformation * * Creates a buffer with information for the Guest User */ static void ACCESS_QueryGuestDisplayInformation(PNET_DISPLAY_USER *buf, PDWORD pdwSize) { static const WCHAR sGuestUserName[] = { 'G','u','e','s','t',0 }; /* sizes of the field buffers in WCHARS */ int name_sz, comment_sz, full_name_sz; PNET_DISPLAY_USER usr; /* set up buffer */ name_sz = lstrlenW(sGuestUserName) + 1; comment_sz = 1; full_name_sz = 1; *pdwSize = sizeof(NET_DISPLAY_USER); *pdwSize += (name_sz + comment_sz + full_name_sz) * sizeof(WCHAR); NetApiBufferAllocate(*pdwSize, (LPVOID *) buf); usr = *buf; usr->usri1_name = (LPWSTR) ((PBYTE) usr + sizeof(NET_DISPLAY_USER)); usr->usri1_comment = (LPWSTR) ( ((PBYTE) usr->usri1_name) + name_sz * sizeof(WCHAR)); usr->usri1_full_name = (LPWSTR) ( ((PBYTE) usr->usri1_comment) + comment_sz * sizeof(WCHAR)); /* set data */ lstrcpyW(usr->usri1_name, sGuestUserName); usr->usri1_comment[0] = 0; usr->usri1_flags = UF_ACCOUNTDISABLE | UF_SCRIPT | UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD; usr->usri1_full_name[0] = 0; usr->usri1_user_id = DOMAIN_USER_RID_GUEST; usr->usri1_next_index = 0; }
/************************************************************ * NetLocalGroupGetInfo (NETAPI32.@) */ NET_API_STATUS WINAPI NetLocalGroupGetInfo( LPCWSTR servername, LPCWSTR groupname, DWORD level, LPBYTE* bufptr) { static const WCHAR commentW[]={'N','o',' ','c','o','m','m','e','n','t',0}; LOCALGROUP_INFO_1* info; DWORD size; FIXME("(%s %s %d %p) semi-stub!\n", debugstr_w(servername), debugstr_w(groupname), level, bufptr); size = sizeof(*info) + sizeof(WCHAR) * (lstrlenW(groupname)+1) + sizeof(commentW); NetApiBufferAllocate(size, (LPVOID*)&info); info->lgrpi1_name = (LPWSTR)(info + 1); lstrcpyW(info->lgrpi1_name, groupname); info->lgrpi1_comment = info->lgrpi1_name + lstrlenW(groupname) + 1; lstrcpyW(info->lgrpi1_comment, commentW); *bufptr = (LPBYTE)info; return NERR_Success; }
NET_API_STATUS NET_API_FUNCTION NetapipBufferAllocate ( IN DWORD ByteCount, OUT LPVOID * Buffer ) /*++ Routine Description: NetapipBufferAllocate is an old internal function that allocates buffers which the APIs will return to the application. All calls to this routine should eventually be replaced by calls to NetApiBufferAllocate. Arguments: (Same as NetApiBufferAllocate.) Return Value: (Same as NetApiBufferAllocate.) --*/ { return (NetApiBufferAllocate( ByteCount, Buffer )); } // NetapipBufferAllocate
/************************************************************ * NetServerGetInfo (NETAPI32.@) */ NET_API_STATUS WINAPI NetServerGetInfo(LMSTR servername, DWORD level, LPBYTE* bufptr) { NET_API_STATUS ret; TRACE("%s %d %p\n", debugstr_w( servername ), level, bufptr ); if (servername) { if (!NETAPI_IsLocalComputer(servername)) { FIXME("remote computers not supported\n"); return ERROR_INVALID_LEVEL; } } if (!bufptr) return ERROR_INVALID_PARAMETER; switch (level) { case 100: case 101: { DWORD computerNameLen, size; WCHAR computerName[MAX_COMPUTERNAME_LENGTH + 1]; computerNameLen = MAX_COMPUTERNAME_LENGTH + 1; GetComputerNameW(computerName, &computerNameLen); computerNameLen++; /* include NULL terminator */ size = sizeof(SERVER_INFO_101) + computerNameLen * sizeof(WCHAR); ret = NetApiBufferAllocate(size, (LPVOID *)bufptr); if (ret == NERR_Success) { /* INFO_100 structure is a subset of INFO_101 */ PSERVER_INFO_101 info = (PSERVER_INFO_101)*bufptr; OSVERSIONINFOW verInfo; info->sv101_platform_id = PLATFORM_ID_NT; info->sv101_name = (LMSTR)(*bufptr + sizeof(SERVER_INFO_101)); memcpy(info->sv101_name, computerName, computerNameLen * sizeof(WCHAR)); verInfo.dwOSVersionInfoSize = sizeof(verInfo); GetVersionExW(&verInfo); info->sv101_version_major = verInfo.dwMajorVersion; info->sv101_version_minor = verInfo.dwMinorVersion; /* Use generic type as no wine equivalent of DC / Server */ info->sv101_type = SV_TYPE_NT; info->sv101_comment = NULL; } break; } default: FIXME("level %d unimplemented\n", level); ret = ERROR_INVALID_LEVEL; } return ret; }
/************************************************************ * NetLocalGroupGetMembers (NETAPI32.@) */ NET_API_STATUS WINAPI NetLocalGroupGetMembers( LPCWSTR servername, LPCWSTR localgroupname, DWORD level, LPBYTE* bufptr, DWORD prefmaxlen, LPDWORD entriesread, LPDWORD totalentries, PDWORD_PTR resumehandle) { FIXME("(%s %s %d %p %d, %p %p %p) stub!\n", debugstr_w(servername), debugstr_w(localgroupname), level, bufptr, prefmaxlen, entriesread, totalentries, resumehandle); if (level == 3) { WCHAR userName[MAX_COMPUTERNAME_LENGTH + 1]; DWORD userNameLen; DWORD len,needlen; PLOCALGROUP_MEMBERS_INFO_3 ptr; /* still a stub, current user is belonging to all groups */ *totalentries = 1; *entriesread = 0; userNameLen = MAX_COMPUTERNAME_LENGTH + 1; GetUserNameW(userName,&userNameLen); needlen = sizeof(LOCALGROUP_MEMBERS_INFO_3) + (userNameLen+2) * sizeof(WCHAR); if (prefmaxlen != MAX_PREFERRED_LENGTH) len = min(prefmaxlen,needlen); else len = needlen; NetApiBufferAllocate(len, (LPVOID *) bufptr); if (len < needlen) return ERROR_MORE_DATA; ptr = (PLOCALGROUP_MEMBERS_INFO_3)*bufptr; ptr->lgrmi3_domainandname = (LPWSTR)(*bufptr+sizeof(LOCALGROUP_MEMBERS_INFO_3)); lstrcpyW(ptr->lgrmi3_domainandname,userName); *entriesread = 1; } return NERR_Success; }
WERROR NetGetAnyDCName_r(struct libnetapi_ctx *ctx, struct NetGetAnyDCName *r) { NTSTATUS status; WERROR werr; struct dcerpc_binding_handle *b; const char *dcname; void *buffer; werr = libnetapi_get_binding_handle(ctx, r->in.server_name, &ndr_table_netlogon, &b); if (!W_ERROR_IS_OK(werr)) { goto done; } status = dcerpc_netr_GetAnyDCName(b, talloc_tos(), r->in.server_name, r->in.domain_name, &dcname, &werr); if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto done; } if (!W_ERROR_IS_OK(werr)) { goto done; } if (NetApiBufferAllocate(strlen_m_term(dcname), &buffer)) { werr = WERR_NOT_ENOUGH_MEMORY; goto done; } memcpy(buffer, dcname, strlen_m_term(dcname)); *r->out.buffer = buffer; done: return werr; }
NET_API_STATUS RxNetServiceInstall ( IN LPTSTR UncServerName, IN LPTSTR Service, IN DWORD ArgC, IN LPTSTR ArgV[], OUT LPBYTE *BufPtr ) { NET_API_STATUS ApiStatus; DWORD ArgIndex; // Index into array of strings. LPSTR CmdArgs; // ptr to alloc'ed ASCII list of strings. DWORD CmdArgsIndex; // Char index into CmdArgs. DWORD CmdArgsLen = 0; // Number of chars in CmdArgs (incl null). const DWORD Level = 2; // Implied by this API. LPVOID OldInfo; // Info structure in downlevel format. DWORD OldTotalSize; // Size of struct in old (downlevel) format. NET_API_STATUS TempStatus; LPSERVICE_INFO_2 serviceInfo2; NetpAssert(UncServerName != NULL); NetpAssert(*UncServerName != '\0'); // // Compute how much memory we'll need for single CmdArgs array. // for (ArgIndex = 0; ArgIndex < ArgC; ++ArgIndex) { #if defined(DBCS) && defined(UNICODE) // RxNetServiceInstall () CmdArgsLen += NetpUnicodeToDBCSLen(ArgV[ArgIndex]) + 1; // string and null. #else CmdArgsLen += STRLEN(ArgV[ArgIndex]) + 1; // string and null. #endif // defined(DBCS) && defined(UNICODE) } ++CmdArgsLen; // include a null char at end of array. // // Allocate the array. This is in ASCII, so we don't need to // add sizeof(some_char_type). // TempStatus = NetApiBufferAllocate( CmdArgsLen, (LPVOID *) & CmdArgs ); if (TempStatus != NERR_Success) { return (TempStatus); } NetpAssert(CmdArgs != NULL); // // Build ASCII version of CmdArgs. // CmdArgsIndex = 0; // start for (ArgIndex=0; ArgIndex<ArgC; ++ArgIndex) { NetpAssert( ArgV[ArgIndex] != NULL ); #if defined(DBCS) && defined(UNICODE) // RxNetServiceInstall () NetpCopyWStrToStrDBCS( & CmdArgs[CmdArgsIndex], // dest ArgV[ArgIndex] ); // src CmdArgsIndex += strlen(&CmdArgs[CmdArgsIndex])+1; //str and null #else NetpCopyTStrToStr( & CmdArgs[CmdArgsIndex], // dest ArgV[ArgIndex]); // src CmdArgsIndex += STRLEN(ArgV[ArgIndex]) + 1; // str and null. #endif // defined(DBCS) && defined(UNICODE) } CmdArgs[CmdArgsIndex] = '\0'; // null char to end list. IF_DEBUG(SERVICE) { NetpKdPrint(( PREFIX_NETAPI "RxNetServiceInstall: cmd args (partial):\n" )); NetpDbgHexDump( (LPBYTE) (LPVOID) CmdArgs, NetpDbgReasonable(CmdArgsLen) ); } // // Find out about the downlevel version of this data structure. // Allocate space for it. (See note below as to why we have to do this // here rather than in RxRemoteApi.) // TempStatus = NetpServiceStructureInfo ( Level, PARMNUM_ALL, // want entire structure FALSE, // Want downlevel size. NULL, // don't need DataDesc16 here NULL, // don't need DataDesc32 here NULL, // don't need DataDescSmb here & OldTotalSize, // max size (downlevel version) NULL, // don't care about fixed size NULL); // don't care about string size NetpAssert(TempStatus == NERR_Success); TempStatus = NetApiBufferAllocate( OldTotalSize, (LPVOID *) & OldInfo ); if (TempStatus != NERR_Success) { (void) NetApiBufferFree(CmdArgs); return (TempStatus); } // // Remote the API. // // Note that this is strange because there should be descriptors for two // things: the cmd buffer we're sending, and the structure we're expecting // back. The downlevel system is only expecting a descriptor for the // cmd args, so RxRemoteApi won't be able to convert the structure into // native format for us. So we'll have to convert it later. // // Also, the following comment (from the LM 2.x svc_inst.c) explains // why we're passing something besides the expected value for cbBuffer: // /* Now for a slightly unclean fix for an oversight in the * parameters spec'ed for this call. The command arg buf is * the variable length buffer while the outbuf is actually * a fixed length structure (no var. length ptrs) yet the * parameters to the API give only the outbuflen. In order * to transport the API remotely the outbuflen (which has * already been length verified) is used to transport the * ca_len, and will be reset to sizeof(struct service_info_2) * by a remote only entry point to the API. */ ApiStatus = RxRemoteApi( API_WServiceInstall, // API number UncServerName, REMSmb_NetServiceInstall_P, // parm desc REM16_service_cmd_args, // send cmd desc, NOT DataDesc16 REM16_service_cmd_args, // send cmd desc, NOT DataDesc32 REMSmb_service_cmd_args, // send cmd desc, NOT DataDescSmb NULL, // no aux desc 16 NULL, // no aux desc 32 NULL, // no aux desc SMB 0, // flags: nothing special // rest of API's arguments, in 32-bit LM2.x format: Service, CmdArgs, // ASCII version of cmd args. OldInfo, // pbBuffer CmdArgsLen); // cbBuffer (not OldTotalSize; see // comment above). IF_DEBUG(SERVICE) { NetpKdPrint(( PREFIX_NETAPI "RxNetServiceInstall: OldInfo=" FORMAT_LPVOID ".\n", (LPVOID) OldInfo )); if (OldInfo) { NetpKdPrint(( PREFIX_NETAPI "RxNetServiceInstall: *OldInfo=" FORMAT_LPVOID ".\n", *(LPVOID *) OldInfo )); } } NetpAssert( ApiStatus != ERROR_MORE_DATA ); if (ApiStatus == NERR_Success) { DWORD BytesRequired = 0; // 0 bytes used so far. LPDESC DataDesc16, DataDesc32; LPVOID NewInfo; DWORD NewTotalSize; LPBYTE StringLocation; // // Set up to do conversion to native format. // TempStatus = NetpServiceStructureInfo ( Level, PARMNUM_ALL, // want entire structure TRUE, // want native size. & DataDesc16, & DataDesc32, NULL, // don't need data desc SMB & NewTotalSize, // max size (downlevel version) NULL, // don't care about fixed size NULL); // don't care about string size NetpAssert(TempStatus == NERR_Success); // Level can't be wrong. TempStatus = NetApiBufferAllocate( NewTotalSize, (LPVOID *) & NewInfo ); if (TempStatus != NERR_Success) { (void) NetApiBufferFree(OldInfo); (void) NetApiBufferFree(CmdArgs); return (TempStatus); } StringLocation = (LPVOID) NetpPointerPlusSomeBytes( NewInfo, NewTotalSize ); // // Convert info structure to native format. // IF_DEBUG(SERVICE) { NetpKdPrint(( PREFIX_NETAPI "RxNetServiceInstall: Unconverted info at " FORMAT_LPVOID "\n", (LPVOID) OldInfo )); NetpDbgHexDump( OldInfo, OldTotalSize ); } TempStatus = RapConvertSingleEntry ( OldInfo, // in structure DataDesc16, // in structure desc TRUE, // meaningless input ptrs NewInfo, // output buffer start NewInfo, // output buffer DataDesc32, // output structure desc FALSE, // don't set offsets (want ptrs) & StringLocation, // where to start strs (updated) & BytesRequired, // bytes used (will be updated) Both, // transmission mode RapToNative); // conversion mode NetpAssert( TempStatus == NERR_Success ); IF_DEBUG(SERVICE) { NetpKdPrint(( PREFIX_NETAPI "RxNetServiceInstall: Converted info at " FORMAT_LPVOID "\n", (LPVOID) NewInfo )); NetpDbgHexDump( NewInfo, NewTotalSize ); } NetpAssert( BytesRequired <= NewTotalSize ); *BufPtr = (LPBYTE) NewInfo; if ((! RxpFatalErrorCode(ApiStatus)) && (Level == 2)) { serviceInfo2 = (LPSERVICE_INFO_2)*BufPtr; if (serviceInfo2 != NULL) { DWORD installState; serviceInfo2->svci2_display_name = serviceInfo2->svci2_name; // // if INSTALL or UNINSTALL is PENDING, then force the upper // bits to 0. This is to prevent the upper bits of the wait // hint from getting accidentally set. Downlevel should never // use more than FF for waithint. // installState = serviceInfo2->svci2_status & SERVICE_INSTALL_STATE; if ((installState == SERVICE_INSTALL_PENDING) || (installState == SERVICE_UNINSTALL_PENDING)) { serviceInfo2->svci2_code &= SERVICE_RESRV_MASK; } } } } else {
NET_API_STATUS RxNetConfigGet ( IN LPTSTR UncServerName, IN LPTSTR Component, IN LPTSTR Parameter, OUT LPBYTE *BufPtr ) /*++ Routine Description: RxNetConfigGet performs the same function as NetConfigGet, except that the server name is known to refer to a downlevel server. Arguments: (Same as NetConfigGet, except UncServerName must not be null, and must not refer to the local computer.) Return Value: (Same as NetConfigGet.) --*/ { const DWORD BufSize = 65535; NET_API_STATUS Status; DWORD TotalAvail; IF_DEBUG(CONFIG) { NetpKdPrint(( PREFIX_NETAPI "RxNetConfigGet: starting, server=" FORMAT_LPTSTR ", component=" FORMAT_LPTSTR ", parm=" FORMAT_LPTSTR ".\n", UncServerName, Component, Parameter )); } // // Error check DLL stub and the app. // NetpAssert(UncServerName != NULL); if (BufPtr == NULL) { return (ERROR_INVALID_PARAMETER); } *BufPtr = NULL; // assume error; it makes error handlers easy to code. // This also forces possible GP fault before we allocate memory. // // Actually remote the API, which will get back the // data in native format. // Status = RxRemoteApi( API_WConfigGet2, // API number UncServerName, // Required, with \\name. REMSmb_NetConfigGet_P, // parm desc REM16_configget_info, // data desc 16 REM32_configget_info, // data desc 32 REMSmb_configget_info, // data desc SMB NULL, // no aux data desc 16 NULL, // no aux data desc 32 NULL, // no aux data desc SMB ALLOCATE_RESPONSE, // Flags: alloc mem for us. // rest of API's arguments, in 32-bit LM 2.x format: NULL, // reserved (must be null pointer) Component, Parameter, BufPtr, // pbBuffer (will be set) BufSize, // cbBuffer & TotalAvail); // total size (meaningless!) NetpAssert( Status != ERROR_MORE_DATA ); NetpAssert( Status != NERR_BufTooSmall ); if (Status == NERR_Success) { #ifdef UNICODE DWORD SrcByteCount = strlen((LPSTR) *BufPtr)+1; // Bytes for 8-bit str. LPVOID TempBuff = *BufPtr; // non-UNICODE version of string. LPVOID UnicodeBuff; // // Allocate space for UNICODE version of string. // Status = NetApiBufferAllocate( SrcByteCount * sizeof(TCHAR), & UnicodeBuff); if (Status != NERR_Success) { return (Status); } NetpAssert(UnicodeBuff != NULL); // // Translate result string to Unicode. // NetpCopyStrToTStr( UnicodeBuff, // dest (in UNICODE) TempBuff); // src string (in codepage) (void) NetApiBufferFree( TempBuff ); *BufPtr = UnicodeBuff; #else // not UNICODE // BufPtr should already point at non-UNICODE string. NetpAssert( *BufPtr != NULL); #endif // not UNICODE } else { *BufPtr = NULL; } return (Status); } // RxNetConfigGet
NET_API_STATUS RxNetFileGetInfo ( IN LPTSTR UncServerName, IN DWORD FileId, IN DWORD Level, OUT LPBYTE *BufPtr ) /*++ Routine Description: RxNetFileGetInfo performs the same function as NetFileGetInfo, except that the server name is known to refer to a downlevel server. Arguments: (Same as NetFileGetInfo, except UncServerName must not be null, and must not refer to the local computer.) Return Value: (Same as NetFileGetInfo.) --*/ { LPDESC DataDesc16, DataDesc32, DataDescSmb; LPBYTE ApiBuffer32; // Buffer to be returned to caller. DWORD ApiBufferSize32; NET_API_STATUS Status; DWORD TotalAvail; IF_DEBUG(FILE) { NetpKdPrint(("RxNetFileGetInfo: starting, server=" FORMAT_LPTSTR ", lvl=" FORMAT_DWORD ".\n", UncServerName, Level)); } // // Error check DLL stub and the app. // NetpAssert(UncServerName != NULL); if ( (Level != 2) && (Level != 3) ) { return (ERROR_INVALID_LEVEL); } if (BufPtr == NULL) { return (ERROR_INVALID_PARAMETER); } *BufPtr = NULL; // assume error; it makes error handlers easy to code. // This also forces possible GP fault before we allocate memory. // // Learn about info level. // Status = NetpFileStructureInfo ( Level, // level to learn about PARMNUM_ALL, // No parmnum with this. TRUE, // Need native sizes. & DataDesc16, & DataDesc32, & DataDescSmb, & ApiBufferSize32, // max buffer size (native) NULL, // don't need fixed size. NULL // don't need string size. ); if (Status != NERR_Success) { return (Status); } // // Allocate memory for 32-bit version of info, which we'll use to get // data from the remote computer. // Status = NetApiBufferAllocate( ApiBufferSize32, (LPVOID *) & ApiBuffer32); if (Status != NERR_Success) { return (Status); } IF_DEBUG(FILE) { NetpKdPrint(( "RxNetFileGetInfo: allocated buffer at " FORMAT_LPVOID "\n", (LPVOID) ApiBuffer32 )); } // // Actually remote the API, which will get back the // data in native format. // Status = RxRemoteApi( API_WFileGetInfo, // API number UncServerName, // Required, with \\name. REMSmb_NetFileGetInfo_P, // parm desc DataDesc16, DataDesc32, DataDescSmb, NULL, // no aux data desc 16 NULL, // no aux data desc 32 NULL, // no aux data desc SMB FALSE, // not a null session API // rest of API's arguments, in 32-bit LM 2.x format: FileId, Level, ApiBuffer32, ApiBufferSize32, & TotalAvail); // total size (BUGBUG meaningless?) NetpAssert( Status != ERROR_MORE_DATA ); NetpAssert( Status != NERR_BufTooSmall ); if (Status == NERR_Success) { *BufPtr = ApiBuffer32; } else { (void) NetApiBufferFree( ApiBuffer32 ); } return (Status); } // RxNetFileGetInfo
BOOL CShowActiveDirUsers::GetFullUserName(LPTSTR szUser, LPTSTR szDomain, LPTSTR szFullUserName, LPTSTR szDescription) { BOOL bResult = FALSE; LPWSTR pServer = NULL; BOOL bLocal = FALSE; TCHAR szComputerName[_MAX_PATH]; TCHAR szDomainName[_MAX_PATH]; TCHAR szServer[_MAX_PATH]; TCHAR szPDC[_MAX_PATH]; DWORD dwLevel = 10; LPUSER_INFO_10 pUserInfoBuffer = NULL; // init ZeroMemory(szComputerName, _MAX_PATH); ZeroMemory(szDomainName, _MAX_PATH); ZeroMemory(szServer, _MAX_PATH); ZeroMemory(szPDC, _MAX_PATH); GetLocalComputerName(szComputerName); if (_tcsicmp(szComputerName, szDomain) == 0) bLocal = TRUE; // for active directory native, szUser comes in as [email protected] if (!bLocal) { GetDCName(szPDC, szDomain); if (_tcschr(szUser, _T('@')) ) { GetUserAndDomainNameFromUPN(szUser, szFullUserName, szDomainName); _tcscpy(szUser, szFullUserName); _tcscpy(szDomain, szDomainName); } } else { NetApiBufferAllocate(_MAX_PATH, (LPVOID*)&pServer); ZeroMemory(pServer, _MAX_PATH); _tcscpy(pServer, _T("\\\\")); _tcscat(pServer, szComputerName); } // grab the details of the user account, // may fail if AD=native & user not in proper security group if (NERR_Success == NetUserGetInfo(szPDC, szUser, dwLevel, (LPBYTE*)&pUserInfoBuffer)) { if (pUserInfoBuffer) { _tcscpy(szFullUserName, pUserInfoBuffer->usri10_full_name); _tcscpy(szDescription, pUserInfoBuffer->usri10_comment); bResult = TRUE; } } if (pUserInfoBuffer) NetApiBufferFree(pUserInfoBuffer); if (pServer) NetApiBufferFree(pServer); return bResult; }
int main(int argc, const char **argv) { NET_API_STATUS status; struct libnetapi_ctx *ctx = NULL; const char *hostname = NULL; const char *groupname = NULL; struct LOCALGROUP_MEMBERS_INFO_0 *g0; struct LOCALGROUP_MEMBERS_INFO_3 *g3; uint32_t total_entries = 0; uint8_t *buffer = NULL; uint32_t level = 3; const char **names = NULL; int i = 0; poptContext pc; int opt; struct poptOption long_options[] = { POPT_AUTOHELP POPT_COMMON_LIBNETAPI_EXAMPLES POPT_TABLEEND }; status = libnetapi_init(&ctx); if (status != 0) { return status; } pc = poptGetContext("localgroup_addmembers", argc, argv, long_options, 0); poptSetOtherOptionHelp(pc, "hostname groupname member1 member2 ..."); while((opt = poptGetNextOpt(pc)) != -1) { } if (!poptPeekArg(pc)) { poptPrintHelp(pc, stderr, 0); goto out; } hostname = poptGetArg(pc); if (!poptPeekArg(pc)) { poptPrintHelp(pc, stderr, 0); goto out; } groupname = poptGetArg(pc); if (!poptPeekArg(pc)) { poptPrintHelp(pc, stderr, 0); goto out; } names = poptGetArgs(pc); for (i=0; names[i] != NULL; i++) { total_entries++; } switch (level) { case 0: status = NetApiBufferAllocate(sizeof(struct LOCALGROUP_MEMBERS_INFO_0) * total_entries, (void **)&g0); if (status) { printf("NetApiBufferAllocate failed with: %s\n", libnetapi_get_error_string(ctx, status)); goto out; } for (i=0; i<total_entries; i++) { if (!ConvertStringSidToSid(names[i], &g0[i].lgrmi0_sid)) { printf("could not convert sid\n"); goto out; } } buffer = (uint8_t *)g0; break; case 3: status = NetApiBufferAllocate(sizeof(struct LOCALGROUP_MEMBERS_INFO_3) * total_entries, (void **)&g3); if (status) { printf("NetApiBufferAllocate failed with: %s\n", libnetapi_get_error_string(ctx, status)); goto out; } for (i=0; i<total_entries; i++) { g3[i].lgrmi3_domainandname = names[i]; } buffer = (uint8_t *)g3; break; default: break; } /* NetLocalGroupAddMembers */ status = NetLocalGroupAddMembers(hostname, groupname, level, buffer, total_entries); if (status != 0) { printf("NetLocalGroupAddMembers failed with: %s\n", libnetapi_get_error_string(ctx, status)); } out: libnetapi_free(ctx); poptFreeContext(pc); return status; }
NET_API_STATUS RxNetServiceGetInfo ( IN LPTSTR UncServerName, IN LPTSTR Service, IN DWORD Level, OUT LPBYTE *BufPtr ) /*++ Routine Description: RxNetServiceGetInfo performs the same function as NetServiceGetInfo, except that the server name is known to refer to a downlevel server. Arguments: (Same as NetServiceGetInfo, except UncServerName must not be null, and must not refer to the local computer.) Return Value: (Same as NetServiceGetInfo.) --*/ { LPDESC DataDesc16, DataDesc32, DataDescSmb; LPBYTE ApiBuffer32; // Buffer to be returned to caller. DWORD ApiBufferSize32; NET_API_STATUS Status; DWORD TotalAvail; LPSERVICE_INFO_2 serviceInfo2; IF_DEBUG(SERVICE) { NetpKdPrint(("RxNetServiceGetInfo: starting, server=" FORMAT_LPTSTR ", lvl=" FORMAT_DWORD ".\n", UncServerName, Level)); } // // Error check DLL stub and the app. // NetpAssert(UncServerName != NULL); if (BufPtr == NULL) { return (ERROR_INVALID_PARAMETER); } *BufPtr = NULL; // assume error; it makes error handlers easy to code. // This also forces possible GP fault before we allocate memory. // // Learn about info level. // Status = NetpServiceStructureInfo ( Level, // level to learn about PARMNUM_ALL, // No parmnum with this. TRUE, // Need native sizes. & DataDesc16, & DataDesc32, & DataDescSmb, & ApiBufferSize32, // max buffer size (native) NULL, // don't need fixed size. NULL // don't need string size. ); if (Status != NERR_Success) { return (Status); } // // Allocate memory for 32-bit version of info, which we'll use to get // data from the remote computer. // Status = NetApiBufferAllocate( ApiBufferSize32, (LPVOID *) & ApiBuffer32); if (Status != NERR_Success) { return (Status); } IF_DEBUG(SERVICE) { NetpKdPrint(( "RxNetServiceGetInfo: allocated buffer at " FORMAT_LPVOID "\n", (LPVOID) ApiBuffer32 )); } // // Actually remote the API, which will get back the // data in native format. // Status = RxRemoteApi( API_WServiceGetInfo, // API number UncServerName, // Required, with \\name. REMSmb_NetServiceGetInfo_P, // parm desc DataDesc16, DataDesc32, DataDescSmb, NULL, // no aux data desc 16 NULL, // no aux data desc 32 NULL, // no aux data desc SMB FALSE, // not a null session API // rest of API's arguments, in 32-bit LM 2.x format: Service, Level, ApiBuffer32, ApiBufferSize32, & TotalAvail); // total size (BUGBUG meaningless?) NetpAssert( Status != ERROR_MORE_DATA ); NetpAssert( Status != NERR_BufTooSmall ); if (Status == NERR_Success) { *BufPtr = ApiBuffer32; if ((! RxpFatalErrorCode(Status)) && ((Level == 2) || (Level==1 ))) { serviceInfo2 = (LPSERVICE_INFO_2)*BufPtr; if (serviceInfo2 != NULL) { DWORD installState; if (Level == 2) { serviceInfo2->svci2_display_name = serviceInfo2->svci2_name; } // // if INSTALL or UNINSTALL is PENDING, then force the upper // bits to 0. This is to prevent the upper bits of the wait // hint from getting accidentally set. Downlevel should never // use more than FF for waithint. // installState = serviceInfo2->svci2_status & SERVICE_INSTALL_STATE; if ((installState == SERVICE_INSTALL_PENDING) || (installState == SERVICE_UNINSTALL_PENDING)) { serviceInfo2->svci2_code &= SERVICE_RESRV_MASK; } } } } else { (void) NetApiBufferFree( ApiBuffer32 ); } return (Status); } // RxNetServiceGetInfo
/****************************************************************************** * NetUserModalsGet (NETAPI32.@) * * Retrieves global information for all users and global groups in the security * database. * * PARAMS * szServer [I] Specifies the DNS or the NetBIOS name of the remote server * on which the function is to execute. * level [I] Information level of the data. * 0 Return global passwords parameters. bufptr points to a * USER_MODALS_INFO_0 struct. * 1 Return logon server and domain controller information. bufptr * points to a USER_MODALS_INFO_1 struct. * 2 Return domain name and identifier. bufptr points to a * USER_MODALS_INFO_2 struct. * 3 Return lockout information. bufptr points to a USER_MODALS_INFO_3 * struct. * pbuffer [I] Buffer that receives the data. * * RETURNS * Success: NERR_Success. * Failure: * ERROR_ACCESS_DENIED - the user does not have access to the info. * NERR_InvalidComputer - computer name is invalid. */ NET_API_STATUS WINAPI NetUserModalsGet( LPCWSTR szServer, DWORD level, LPBYTE *pbuffer) { TRACE("(%s %d %p)\n", debugstr_w(szServer), level, pbuffer); switch (level) { case 0: /* return global passwords parameters */ FIXME("level 0 not implemented!\n"); *pbuffer = NULL; return NERR_InternalError; case 1: /* return logon server and domain controller info */ FIXME("level 1 not implemented!\n"); *pbuffer = NULL; return NERR_InternalError; case 2: { /* return domain name and identifier */ PUSER_MODALS_INFO_2 umi; LSA_HANDLE policyHandle; LSA_OBJECT_ATTRIBUTES objectAttributes; PPOLICY_ACCOUNT_DOMAIN_INFO domainInfo; NTSTATUS ntStatus; PSID domainIdentifier = NULL; int domainNameLen, domainIdLen; ZeroMemory(&objectAttributes, sizeof(objectAttributes)); objectAttributes.Length = sizeof(objectAttributes); ntStatus = LsaOpenPolicy(NULL, &objectAttributes, POLICY_VIEW_LOCAL_INFORMATION, &policyHandle); if (ntStatus != STATUS_SUCCESS) { WARN("LsaOpenPolicy failed with NT status %x\n", LsaNtStatusToWinError(ntStatus)); return ntStatus; } ntStatus = LsaQueryInformationPolicy(policyHandle, PolicyAccountDomainInformation, (PVOID *)&domainInfo); if (ntStatus != STATUS_SUCCESS) { WARN("LsaQueryInformationPolicy failed with NT status %x\n", LsaNtStatusToWinError(ntStatus)); LsaClose(policyHandle); return ntStatus; } domainIdentifier = domainInfo->DomainSid; domainIdLen = (domainIdentifier) ? GetLengthSid(domainIdentifier) : 0; domainNameLen = lstrlenW(domainInfo->DomainName.Buffer) + 1; LsaClose(policyHandle); ntStatus = NetApiBufferAllocate(sizeof(USER_MODALS_INFO_2) + domainIdLen + domainNameLen * sizeof(WCHAR), (LPVOID *)pbuffer); if (ntStatus != NERR_Success) { WARN("NetApiBufferAllocate() failed\n"); LsaFreeMemory(domainInfo); return ntStatus; } umi = (USER_MODALS_INFO_2 *) *pbuffer; umi->usrmod2_domain_id = (domainIdLen > 0) ? (*pbuffer + sizeof(USER_MODALS_INFO_2)) : NULL; umi->usrmod2_domain_name = (LPWSTR)(*pbuffer + sizeof(USER_MODALS_INFO_2) + domainIdLen); lstrcpynW(umi->usrmod2_domain_name, domainInfo->DomainName.Buffer, domainNameLen); if (domainIdLen > 0) CopySid(GetLengthSid(domainIdentifier), umi->usrmod2_domain_id, domainIdentifier); LsaFreeMemory(domainInfo); break; } case 3: /* return lockout information */ FIXME("level 3 not implemented!\n"); *pbuffer = NULL; return NERR_InternalError; default: TRACE("Invalid level %d is specified\n", level); *pbuffer = NULL; return ERROR_INVALID_LEVEL; } return NERR_Success; }
NET_API_STATUS RxNetCharDevGetInfo( IN LPTSTR ServerName, IN LPTSTR DeviceName, IN DWORD Level, OUT LPBYTE* Buffer ) /*++ Routine Description: Returns an information structure detailing a particular shared comms device at a down-level server Arguments: ServerName - Where to run the remoted API DeviceName - Name of device for which to get info Level - Of info required - 0 or 1 Buffer - Pointer to returned pointer to buffer containing info Return Value: NET_API_STATUS Success - NERR_Success Failure - ERROR_INVALID_PARAMETER DeviceName too long ERROR_INVALID_LEVEL Level parameter not allowed (return code from remoted API) --*/ { DWORD buflen, total_avail; LPDESC pDesc16, pDesc32, pDescSmb; LPBYTE bufptr; NET_API_STATUS rc; // // test out the caller supplied arguments. This should be done at the outer // level // *Buffer = NULL; if (STRLEN(DeviceName) > LM20_DEVLEN) { return ERROR_INVALID_PARAMETER; } switch (Level) { case 0: pDesc16 = REM16_chardev_info_0; pDesc32 = REM32_chardev_info_0; pDescSmb = REMSmb_chardev_info_0; buflen = sizeof(CHARDEV_INFO_0) + STRING_SPACE_REQD(DEVLEN + 1); break; case 1: pDesc16 = REM16_chardev_info_1; pDesc32 = REM32_chardev_info_1; pDescSmb = REMSmb_chardev_info_1; buflen = sizeof(CHARDEV_INFO_1) + STRING_SPACE_REQD(DEVLEN + 1) + STRING_SPACE_REQD(UNLEN + 1); break; default: return ERROR_INVALID_LEVEL; } // // In the GetInfo case we are content to pre-allocate the return buffer // because we know how large it should be (although we actually allocate // the maximum size for a particular GetInfo structure level) // if (rc = NetApiBufferAllocate(buflen, (LPVOID *) &bufptr)) { return rc; } rc = RxRemoteApi(API_NetCharDevGetInfo, // API # ServerName, // where to remote it REMSmb_NetCharDevGetInfo_P, // parameter descriptor pDesc16, pDesc32, pDescSmb, // primary structure descriptors NULL, NULL, NULL, // no aux data structures FALSE, // can't use NULL session DeviceName, // API parameters start here... Level, bufptr, buflen, // supplied by us &total_avail // not used by 32-bit API ); if (rc) { (void) NetApiBufferFree(bufptr); } else { *Buffer = bufptr; } return rc; }
NET_API_STATUS NetrReplExportDirEnum ( IN LPTSTR UncServerName OPTIONAL, // IN DWORD Level, IN OUT LPEXPORT_ENUM_STRUCT EnumContainer, // OUT LPEXPORT_CONTAINER BufPtr, // RPC container (union) IN DWORD PrefMaxSize, // OUT LPDWORD EntriesRead, OUT LPDWORD TotalEntries, IN OUT LPDWORD ResumeHandle OPTIONAL ) /*++ Routine Description: Same as NetReplExportDirEnum. Arguments: Same as NetReplExportDirEnum. Return Value: Same as NetReplExportDirEnum. --*/ { LPVOID ApiArray; LPVOID ApiEntry; NET_API_STATUS ApiStatus; BOOL ConfigLocked = FALSE; DWORD EntryCount; DWORD FixedSize; DWORD Level; BOOL ListLocked = FALSE; LPMASTER_LIST_REC MasterRecord; DWORD OutputSize; LPVOID StringLocation; #define SET_ENTRIES_READ( value ) \ { \ /* Pretend level 0, to make life easy. */ \ EnumContainer->ExportInfo.Level0->EntriesRead = (value); \ } #define SET_BUFFER_POINTER( value ) \ { \ /* Pretend level 0, to make life easy. */ \ EnumContainer->ExportInfo.Level0->Buffer = (value); \ } UNREFERENCED_PARAMETER(PrefMaxSize); // // Check for caller errors. // Level = EnumContainer->Level; // // Compute size of output area (and check caller's Level too). // ApiStatus = NetpReplExportDirStructureInfo ( Level, PARMNUM_ALL, TRUE, // want native sizes NULL, // don't need DataDesc16 NULL, // don't need DataDesc32 NULL, // don't need DataDescSmb & OutputSize, // need max size of structure & FixedSize, NULL); // don't need StringSize if (ApiStatus != NO_ERROR) { return (ApiStatus); } NetpAssert( OutputSize > sizeof( REPL_EDIR_INFO_0 ) ); NetpAssert( OutputSize > FixedSize ); NetpAssert( FixedSize != 0 ); NetpAssert( EnumContainer != NULL ); NetpAssert( EnumContainer->ExportInfo.Level0 != NULL ); // Don't confuse caller about possible alloc'ed data. SET_BUFFER_POINTER( NULL ); if (TotalEntries == NULL) { return (ERROR_INVALID_PARAMETER); } // Test for memory faults before we lock anything. SET_ENTRIES_READ( 0 ); *TotalEntries = 0; // This version only supports 1 call to enumerate, so resume handle // should never be set to nonzero. But let's check, so caller finds out // they have a buggy program. if (ResumeHandle != NULL) { if (*ResumeHandle != 0) { return (ERROR_INVALID_PARAMETER); } } // // We'll need shared lock on config data, so we can find out if export half // is actually running. // ACQUIRE_LOCK_SHARED( ReplConfigLock ); ConfigLocked = TRUE; // // Handle call using registry only, if export half is not running now. // if ( !ReplRoleIncludesExport( ReplConfigRole ) ) { ApiStatus = ExportDirEnumApiRecords( UncServerName, Level, (LPBYTE *) (LPVOID) &ApiArray, PrefMaxSize, & EntryCount, TotalEntries ); goto Cleanup; } // // Get read-only lock on master list. // ACQUIRE_LOCK_SHARED( RMGlobalListLock ); ListLocked = TRUE; // // Find out how many entries there are. // EntryCount = RMGlobalMasterListCount; if (EntryCount > 0) { NetpAssert( RMGlobalMasterListHeader != NULL ); // // Allocate the output area. // ApiStatus = NetApiBufferAllocate( OutputSize * EntryCount, (LPVOID *) & ApiArray); if (ApiStatus != NO_ERROR) { // ApiStatus is already set to return error to caller. // Don't forget to release lock... } else { #if DBG DWORD EntriesFound = 0; #endif IF_DEBUG( EXPAPI ) { NetpKdPrint(( PREFIX_REPL_MASTER "NetrReplExportDirEnum: alloc'ed " FORMAT_DWORD " bytes at " FORMAT_LPVOID ".\n", OutputSize * EntryCount, (LPVOID) ApiArray )); } NetpAssert( ApiArray != NULL ); // // Loop for each entry in master list. // ApiEntry = ApiArray; MasterRecord = RMGlobalMasterListHeader; StringLocation = NetpPointerPlusSomeBytes( ApiArray, OutputSize * EntryCount ); while (MasterRecord != NULL) { // // Build an array entry for this master record. // ApiStatus = ExportDirBuildApiRecord ( Level, MasterRecord->dir_name, MasterRecord->integrity, MasterRecord->extent, MasterRecord->lockcount, MasterRecord->time_of_first_lock, // secs since 1970 ApiEntry, (LPBYTE *) (LPVOID) & StringLocation); NetpAssert( ApiStatus == NO_ERROR ); // We checked all parms. MasterRecord = MasterRecord->next_p; ApiEntry = NetpPointerPlusSomeBytes( ApiEntry, FixedSize ); #if DBG ++EntriesFound; #endif } #if DBG NetpAssert( EntriesFound == EntryCount ); #endif } // Don't forget to release lock... } else {
NET_API_STATUS NetrReplImportDirEnum ( IN LPTSTR UncServerName OPTIONAL, // IN DWORD Level, IN OUT LPIMPORT_ENUM_STRUCT EnumContainer, // OUT LPIMPORT_CONTAINER BufPtr, // RPC container (union) IN DWORD PrefMaxSize, // OUT LPDWORD EntriesRead, OUT LPDWORD TotalEntries, IN OUT LPDWORD ResumeHandle OPTIONAL ) /*++ Routine Description: Same as NetReplImportDirEnum. Arguments: Same as NetReplImportDirEnum. Return Value: Same as NetReplImportDirEnum. --*/ { LPVOID ApiArray = NULL; LPVOID ApiEntry; NET_API_STATUS ApiStatus; LPCLIENT_LIST_REC ClientRecord; DWORD EntryCount = 0; DWORD FixedSize; DWORD Level; BOOL LockedClientList = FALSE; BOOL LockedConfigData = FALSE; DWORD OutputSize; LPVOID StringLocation; UNREFERENCED_PARAMETER(PrefMaxSize); UNREFERENCED_PARAMETER(UncServerName); #define SET_ENTRIES_READ( value ) \ { \ /* Pretend level 0, to make life easy. */ \ EnumContainer->ImportInfo.Level0->EntriesRead = (value); \ } #define SET_BUFFER_POINTER( value ) \ { \ /* Pretend level 0, to make life easy. */ \ EnumContainer->ImportInfo.Level0->Buffer = (value); \ } // // Check for caller errors. // NetpAssert( EnumContainer != NULL ); NetpAssert( EnumContainer->ImportInfo.Level0 != NULL ); Level = EnumContainer->Level; SET_BUFFER_POINTER( NULL ); // Don't confuse caller about possible alloc. if (TotalEntries == NULL) { return (ERROR_INVALID_PARAMETER); } // Test for memory faults before we lock anything. SET_ENTRIES_READ( 0 ); * TotalEntries = 0; // This version only supports 1 call to enumerate, so resume handle // should never be set to nonzero. But let's check, so caller finds out // they have a buggy program. if (ResumeHandle != NULL) { if (*ResumeHandle != 0) { return (ERROR_INVALID_PARAMETER); } } // // Check role and handle call if import half of service is not running. // ACQUIRE_LOCK_SHARED( ReplConfigLock ); LockedConfigData = TRUE; if ( !ReplRoleIncludesImport( ReplConfigRole ) ) { ApiStatus = ImportDirEnumApiRecords( UncServerName, Level, (LPBYTE *) (LPVOID) &ApiArray, PrefMaxSize, & EntryCount, TotalEntries ); goto Cleanup; } // // Import side of service is running... // Compute size of output area (and check caller's Level too). // ApiStatus = NetpReplImportDirStructureInfo ( Level, PARMNUM_ALL, TRUE, // want native sizes NULL, // don't need DataDesc16 NULL, // don't need DataDesc32 NULL, // don't need DataDescSmb & OutputSize, // need max size of structure & FixedSize, NULL); // don't need StringSize if (ApiStatus != NO_ERROR) { goto Cleanup; // don't forget to unlock... } // // Get read-only lock on client list. // ACQUIRE_LOCK_SHARED( RCGlobalClientListLock ); LockedClientList = TRUE; // // Find out how many entries there are. // EntryCount = RCGlobalClientListCount; IF_DEBUG( IMPAPI ) { NetpKdPrint(( "NetrReplImportDirEnum: there are " FORMAT_DWORD " client records.\n", EntryCount )); } if (EntryCount > 0) { // // Allocate the output area. // ApiStatus = NetApiBufferAllocate( OutputSize * EntryCount, (LPVOID *) & ApiArray); if (ApiStatus != NO_ERROR) { // ApiStatus is already set to return error to caller. // Don't forget to release lock... } else { NetpAssert( ApiArray != NULL ); // // Loop for each entry in client list. // ApiEntry = ApiArray; ClientRecord = RCGlobalClientListHeader; StringLocation = NetpPointerPlusSomeBytes( ApiArray, OutputSize * EntryCount ); while (ClientRecord != NULL) { // // Build an array entry for this client record. // ApiStatus = ImportDirBuildApiRecord ( Level, ClientRecord->dir_name, ClientRecord->state, ClientRecord->master, ClientRecord->timestamp, // Last update, secs since '70. ClientRecord->lockcount, ClientRecord->time_of_first_lock, // Seconds since 1970. ApiEntry, (LPBYTE *) (LPVOID) & StringLocation); IF_DEBUG( IMPAPI ) { NetpKdPrint(( "NetrReplImportDirEnum: build status is " FORMAT_API_STATUS ".\n", ApiStatus )); } NetpAssert( ApiStatus == NO_ERROR ); // We checked all parms. ClientRecord = ClientRecord->next_p; ApiEntry = NetpPointerPlusSomeBytes( ApiEntry, FixedSize ); } } // Don't forget to release lock... } else {
/************************************************************ * NetQueryDisplayInformation (NETAPI32.@) * * The buffer structure: * - array of fixed size record of the level type * - strings, referenced by the record of the level type */ NET_API_STATUS WINAPI NetQueryDisplayInformation( LPCWSTR ServerName, DWORD Level, DWORD Index, DWORD EntriesRequested, DWORD PreferredMaximumLength, LPDWORD ReturnedEntryCount, PVOID *SortedBuffer) { TRACE("(%s, %d, %d, %d, %d, %p, %p)\n", debugstr_w(ServerName), Level, Index, EntriesRequested, PreferredMaximumLength, ReturnedEntryCount, SortedBuffer); if(!NETAPI_IsLocalComputer(ServerName)) { FIXME("Only implemented on local computer, but requested for " "remote server %s\n", debugstr_w(ServerName)); return ERROR_ACCESS_DENIED; } switch (Level) { case 1: { /* current record */ PNET_DISPLAY_USER inf; /* current available strings buffer */ LPWSTR str; PNET_DISPLAY_USER admin, guest; DWORD admin_size, guest_size; LPWSTR name = NULL; DWORD dwSize; /* sizes of the field buffers in WCHARS */ int name_sz, comment_sz, full_name_sz; /* number of the records, returned in SortedBuffer 3 - for current user, Administrator and Guest users */ int records = 3; FIXME("Level %d partially implemented\n", Level); *ReturnedEntryCount = records; comment_sz = 1; full_name_sz = 1; /* get data */ dwSize = UNLEN + 1; NetApiBufferAllocate(dwSize * sizeof(WCHAR), (LPVOID *) &name); if (!GetUserNameW(name, &dwSize)) { NetApiBufferFree(name); return ERROR_ACCESS_DENIED; } name_sz = dwSize; ACCESS_QueryAdminDisplayInformation(&admin, &admin_size); ACCESS_QueryGuestDisplayInformation(&guest, &guest_size); /* set up buffer */ dwSize = sizeof(NET_DISPLAY_USER) * records; dwSize += (name_sz + comment_sz + full_name_sz) * sizeof(WCHAR); NetApiBufferAllocate(dwSize + admin_size - sizeof(NET_DISPLAY_USER) + guest_size - sizeof(NET_DISPLAY_USER), SortedBuffer); inf = *SortedBuffer; str = (LPWSTR) ((PBYTE) inf + sizeof(NET_DISPLAY_USER) * records); inf->usri1_name = str; str = (LPWSTR) ( ((PBYTE) str) + name_sz * sizeof(WCHAR)); inf->usri1_comment = str; str = (LPWSTR) ( ((PBYTE) str) + comment_sz * sizeof(WCHAR)); inf->usri1_full_name = str; str = (LPWSTR) ( ((PBYTE) str) + full_name_sz * sizeof(WCHAR)); /* set data */ lstrcpyW(inf->usri1_name, name); NetApiBufferFree(name); inf->usri1_comment[0] = 0; inf->usri1_flags = UF_SCRIPT | UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD; inf->usri1_full_name[0] = 0; inf->usri1_user_id = 0; inf->usri1_next_index = 0; inf++; ACCESS_CopyDisplayUser(admin, &str, inf); NetApiBufferFree(admin); inf++; ACCESS_CopyDisplayUser(guest, &str, inf); NetApiBufferFree(guest); break; } case 2: case 3: { FIXME("Level %d is not implemented\n", Level); break; } default: TRACE("Invalid level %d is specified\n", Level); return ERROR_INVALID_LEVEL; } return NERR_Success; }
NET_API_STATUS RxpCopyAndConvertSessions( IN LPSESSION_SUPERSET_INFO InStructureArray, IN DWORD InEntryCount, IN DWORD LevelWanted, IN LPTSTR ClientName OPTIONAL, IN LPTSTR UserName OPTIONAL, OUT LPVOID * OutStructureArrayPtr, // alloc'ed by this routine OUT LPDWORD OutEntryCountPtr OPTIONAL ) { LPSESSION_SUPERSET_INFO InEntry = InStructureArray; DWORD InEntriesLeft; const DWORD InFixedSize = sizeof(SESSION_SUPERSET_INFO); LPVOID OutEntry; // Buffer to be returned to caller. DWORD OutEntryCount; LPBYTE OutFixedDataEnd; DWORD OutFixedSize; DWORD OutMaxSize; LPTSTR OutStringLocation; DWORD OutStringSize; LPVOID OutStructureArray; BOOL AnyMatchFound = FALSE; // not yet. NET_API_STATUS Status; NetpAssert( InEntryCount > 0 ); NetpAssert( InStructureArray != NULL ); *OutStructureArrayPtr = NULL; NetpSetOptionalArg(OutEntryCountPtr, 0); IF_DEBUG(SESSION) { NetpKdPrint(( "RxpCopyAndConvertSessions: starting...\n" )); NetpDbgDisplaySessionArray( SESSION_SUPERSET_LEVEL, (LPVOID) InStructureArray, InEntryCount); } // // Learn about info level that caller wants. // Status = NetpSessionStructureInfo ( LevelWanted, // level to learn about PARMNUM_ALL, // No parmnum with this. TRUE, // Need native sizes. NULL, // don't need data desc 16 NULL, // don't need data desc 32 NULL, // don't need data desc SMB & OutMaxSize, // max buffer size (native) & OutFixedSize, // fixed size. & OutStringSize // string size. ); if (Status != NERR_Success) { return (Status); } // // Allocate memory for 32-bit version of caller's info level. // BUGBUG: Optimize by scanning input array first. // Status = NetApiBufferAllocate( InEntryCount * OutMaxSize, & OutStructureArray); if (Status != NERR_Success) { return (Status); } OutEntry = OutStructureArray; IF_DEBUG(SESSION) { NetpKdPrint(( "RxpCopyAndConvertSessions: allocated output buffer at " FORMAT_LPVOID "\n", (LPVOID) OutStructureArray )); } OutEntryCount = 0; OutStringLocation = (LPTSTR) NetpPointerPlusSomeBytes( OutStructureArray, InEntryCount * OutMaxSize); for (InEntriesLeft=InEntryCount; InEntriesLeft > 0; --InEntriesLeft) { OutFixedDataEnd = NetpPointerPlusSomeBytes( OutEntry, OutFixedSize); if (RxpSessionMatches( (LPSESSION_SUPERSET_INFO) InEntry, // candidate structure ClientName, UserName)) { // Match! AnyMatchFound = TRUE; ++OutEntryCount; RxpConvertSessionInfo ( InEntry, LevelWanted, OutEntry, OutFixedDataEnd, & OutStringLocation); // string area top (updated) OutEntry = (LPVOID) NetpPointerPlusSomeBytes(OutEntry,OutFixedSize); } InEntry = (LPVOID) NetpPointerPlusSomeBytes(InEntry, InFixedSize); } if (AnyMatchFound == FALSE) { (void) NetApiBufferFree( OutStructureArray ); OutStructureArray = NULL; Status = RxpSessionMissingErrorCode( ClientName, UserName); } else { Status = NERR_Success; IF_DEBUG(SESSION) { NetpKdPrint(( "RxpCopyAndConvertSessions: ending...\n" )); NetpDbgDisplaySessionArray( LevelWanted, (LPVOID) OutStructureArray, OutEntryCount); } } // // Tell caller how things went. // *OutStructureArrayPtr = OutStructureArray; NetpSetOptionalArg(OutEntryCountPtr, OutEntryCount); return (Status); }
NET_API_STATUS RxpConvertAuditArray( IN LPVOID InputArray, IN DWORD InputByteCount, OUT LPBYTE * OutputArrayPtr, // will be alloc'ed (free w/ NetApiBufferFree). OUT LPDWORD OutputByteCountPtr ) { DWORD EntryType; const LPBYTE InputArrayEndPtr = (LPVOID) ( ((LPBYTE)InputArray) + InputByteCount ); LPBYTE InputBytePtr; DWORD InputDataOffset; DWORD InputTotalEntrySize; LPBYTE InputFixedPtr; LPBYTE InputVariablePtr; DWORD InputVariableSize; LPVOID OutputArray; DWORD OutputArraySize; DWORD OutputBytesUsed = 0; DWORD OutputEntrySizeSoFar; LPAUDIT_ENTRY OutputFixedPtr; DWORD OutputVariableSize; LPBYTE OutputVariablePtr; NET_API_STATUS Status; // // Error check caller's parameters. // Set output parameters to make error handling easier below. // (Also check for memory faults while we're at it.) // if (OutputArrayPtr != NULL) { *OutputArrayPtr = NULL; } if (OutputByteCountPtr != NULL) { *OutputByteCountPtr = 0; } if ( (OutputArrayPtr == NULL) || (OutputByteCountPtr == NULL) ) { return (ERROR_INVALID_PARAMETER); } if ( (InputArray == NULL) || (InputByteCount == 0) ) { return (ERROR_INVALID_PARAMETER); } // // Compute size needed for output buffer, taking into account: // per field expansion, // per entry expansion, // and alignment. // Status = RxpEstimateLogSize( DOWNLEVEL_AUDIT_FIXED_ENTRY_SIZE, InputByteCount, // input (downlevel) array size in bytes. FALSE, // no, we're not doing error log & OutputArraySize); // set estimated array size in bytes. if (Status != NO_ERROR) { return (Status); // (output vars are already set.) } NetpAssert( OutputArraySize > 0 ); NetpAssert( OutputArraySize > InputByteCount ); *OutputByteCountPtr = OutputArraySize; // // Allocate oversize area for output; we'll realloc it to shrink it. // Status = NetApiBufferAllocate( OutputArraySize, (LPVOID *) & OutputArray ); if (Status != NERR_Success) { return (Status); // (output vars are already set.) } NetpAssert( OutputArray != NULL ); NetpAssert( POINTER_IS_ALIGNED( OutputArray, ALIGN_WORST ) ); // // Loop for each entry in the input area. // OutputFixedPtr = OutputArray; for (InputBytePtr = InputArray; InputBytePtr < InputArrayEndPtr; ) { InputFixedPtr = InputBytePtr; NetpAssert( POINTER_IS_ALIGNED( OutputFixedPtr, ALIGN_WORST ) ); IF_DEBUG(AUDIT) { NetpKdPrint(( PREFIX_NETLIB "RxpConvertAuditArray: doing input entry at " FORMAT_LPVOID ", out entry at " FORMAT_LPVOID ".\n", (LPVOID) InputFixedPtr, (LPVOID) OutputFixedPtr )); } // // Process each field in input fixed entry. // InputTotalEntrySize = (DWORD) SmbGetUshort( (LPWORD) InputBytePtr ); if (InputTotalEntrySize < MIN_DOWNLEVEL_ENTRY_SIZE) { goto FileCorrupt; } { LPBYTE EndPos = InputBytePtr + InputTotalEntrySize; if (EndPos > InputArrayEndPtr) { goto FileCorrupt; } EndPos -= sizeof(WORD); // the last ae_len2 if (SmbGetUshort( (LPWORD) EndPos ) != InputTotalEntrySize) { goto FileCorrupt; } } InputBytePtr += sizeof(WORD); // skip ae_len. OutputFixedPtr->ae_reserved = (DWORD) SmbGetUshort( (LPWORD) InputBytePtr ); InputBytePtr += sizeof(WORD); // skip ae_reserved { DWORD LocalTime = (DWORD) SmbGetUlong( (LPDWORD) InputBytePtr ); DWORD GmtTime; NetpLocalTimeToGmtTime( LocalTime, & GmtTime ); OutputFixedPtr->ae_time = GmtTime; InputBytePtr += sizeof(DWORD); } EntryType = (DWORD) SmbGetUshort( (LPWORD) InputBytePtr ); OutputFixedPtr->ae_type = EntryType; InputBytePtr += sizeof(WORD); InputDataOffset = (DWORD) SmbGetUshort( (LPWORD) InputBytePtr ); NetpAssert( InputDataOffset >= DOWNLEVEL_AUDIT_FIXED_ENTRY_SIZE ); InputBytePtr += sizeof(WORD); OutputEntrySizeSoFar = sizeof(AUDIT_ENTRY); // // Process variable portion (if any): // InputVariablePtr = (LPVOID) ( ((LPBYTE) InputFixedPtr) + InputDataOffset ); InputVariableSize = (InputTotalEntrySize - InputDataOffset) - sizeof(WORD); // don't include ae_len2. OutputVariablePtr = (LPVOID) ( ((LPBYTE) OutputFixedPtr) + sizeof(AUDIT_ENTRY) ); // Align variable part. OutputVariablePtr = ROUND_UP_POINTER( OutputVariablePtr, ALIGN_WORST ); OutputEntrySizeSoFar = ROUND_UP_COUNT( OutputEntrySizeSoFar, ALIGN_WORST ); OutputFixedPtr->ae_data_offset = OutputEntrySizeSoFar; // Copy and convert the variable part. RxpConvertAuditEntryVariableData( EntryType, InputVariablePtr, OutputVariablePtr, InputVariableSize, & OutputVariableSize); #ifdef REVISED_AUDIT_ENTRY_STRUCT OutputFixedPtr->ae_data_size = OutputVariableSize; #endif // Account for variable area and ae_len2 in total length. OutputEntrySizeSoFar += (OutputVariableSize + sizeof(DWORD)); // Round size up so next entry (if any) is worst-case aligned. OutputEntrySizeSoFar = ROUND_UP_COUNT( OutputEntrySizeSoFar, ALIGN_WORST ); #define OutputEntrySize OutputEntrySizeSoFar OutputFixedPtr->ae_len = OutputEntrySize; { LPDWORD EndSizePtr = (LPVOID) ( ((LPBYTE)OutputFixedPtr) + OutputEntrySize - sizeof(DWORD) ); *EndSizePtr = OutputEntrySize; // set ae_len2. } // // Update for next loop iteration. // InputBytePtr = (LPVOID) ( ((LPBYTE) InputFixedPtr) + InputTotalEntrySize); OutputFixedPtr = (LPVOID) ( ((LPBYTE) OutputFixedPtr) + OutputEntrySize ); OutputBytesUsed += OutputEntrySize; NetpAssert( OutputBytesUsed <= OutputArraySize ); } NetpAssert(OutputBytesUsed > 0); NetpAssert( OutputBytesUsed <= OutputArraySize ); // BUGBUG: realloc OutputArray to OutputBytesUsed *OutputArrayPtr = OutputArray; *OutputByteCountPtr = OutputBytesUsed; return (NERR_Success); FileCorrupt: NetpKdPrint(( PREFIX_NETAPI "RxpConvertAuditArray: corrupt audit log!\n" )); if (OutputArray != NULL) { (VOID) NetApiBufferFree( OutputArray ); } if (OutputArrayPtr != NULL) { *OutputArrayPtr = NULL; } if (OutputByteCountPtr != NULL) { *OutputByteCountPtr = 0; } return (NERR_LogFileCorrupt); }
NET_API_STATUS RxNetConfigGetAll ( IN LPTSTR UncServerName, IN LPTSTR Component, OUT LPBYTE *BufPtr ) /*++ Routine Description: RxNetConfigGetAll performs the same function as NetConfigGetAll, except that the server name is known to refer to a downlevel server. Arguments: (Same as NetConfigGetAll, except UncServerName must not be null, and must not refer to the local computer.) Return Value: (Same as NetConfigGetAll.) --*/ { const DWORD BufSize = 65535; DWORD EntriesRead; NET_API_STATUS Status; DWORD TotalEntries; // Make sure caller didn't mess up. NetpAssert(UncServerName != NULL); if (BufPtr == NULL) { return (ERROR_INVALID_PARAMETER); } // Assume something might go wrong, and make error paths easier to // code. Also, check for bad pointers before we do anything. *BufPtr = NULL; // // Remote the API, which will allocate the array for us. // Status = RxRemoteApi( API_WConfigGetAll2, // api number UncServerName, // \\servername REMSmb_NetConfigGetAll_P, // parm desc (SMB version) REM16_configgetall_info, REM32_configgetall_info, REMSmb_configgetall_info, NULL, // no aux desc 16 NULL, // no aux desc 32 NULL, // no aux desc SMB ALLOCATE_RESPONSE, // flags: allocate buffer for us // rest of API's arguments in 32-bit LM 2.x format: NULL, // pszReserved Component, // pszComponent BufPtr, // Buffer: array (alloc for us) BufSize, // Buffer: array size in bytes & EntriesRead, // pcbEntriesRead & TotalEntries); // pcbTotalAvail NetpAssert( Status != ERROR_MORE_DATA ); if (Status == NERR_Success) { #ifdef UNICODE DWORD SrcByteCount = NetpStrArraySize((LPSTR) *BufPtr); LPVOID TempBuff = *BufPtr; // non-UNICODE version of array. LPVOID UnicodeBuff; // // Allocate space for UNICODE version of array. // Status = NetApiBufferAllocate( SrcByteCount * sizeof(TCHAR), & UnicodeBuff); if (Status != NERR_Success) { return (Status); } NetpAssert(UnicodeBuff != NULL); // // Translate result array to Unicode. // NetpCopyStrArrayToTStrArray( UnicodeBuff, // dest (in UNICODE) TempBuff); // src array (in codepage) (void) NetApiBufferFree( TempBuff ); *BufPtr = UnicodeBuff; #else // not UNICODE // BufPtr should already point at non-UNICODE array. NetpAssert( *BufPtr != NULL); #endif // not UNICODE } else { *BufPtr = NULL; } return (Status); } // RxNetConfigGetAll
static NET_API_STATUS test_netgroupsetusers(const char *hostname, const char *groupname, uint32_t level, size_t num_entries, const char **names) { NET_API_STATUS status; uint8_t *buffer = NULL; int i = 0; size_t buf_size = 0; struct GROUP_USERS_INFO_0 *g0 = NULL; struct GROUP_USERS_INFO_1 *g1 = NULL; printf("testing NetGroupSetUsers level %d\n", level); switch (level) { case 0: buf_size = sizeof(struct GROUP_USERS_INFO_0) * num_entries; status = NetApiBufferAllocate(buf_size, (void **)&g0); if (status) { goto out; } for (i=0; i<num_entries; i++) { g0[i].grui0_name = names[i]; } buffer = (uint8_t *)g0; break; case 1: buf_size = sizeof(struct GROUP_USERS_INFO_1) * num_entries; status = NetApiBufferAllocate(buf_size, (void **)&g1); if (status) { goto out; } for (i=0; i<num_entries; i++) { g1[i].grui1_name = names[i]; } buffer = (uint8_t *)g1; break; default: break; } /* NetGroupSetUsers */ status = NetGroupSetUsers(hostname, groupname, level, buffer, num_entries); if (status) { goto out; } out: NetApiBufferFree(buffer); return status; }
NET_API_STATUS RxNetSessionGetInfo ( IN LPTSTR UncServerName, IN LPTSTR UncClientName, IN LPTSTR UserName, IN DWORD LevelWanted, OUT LPBYTE *BufPtr ) /*++ Routine Description: RxNetSessionGetInfo performs the same function as NetSessionGetInfo, except that the server name is known to refer to a downlevel server. Arguments: (Same as NetSessionGetInfo, except UncServerName must not be null, and must not refer to the local computer.) Return Value: (Same as NetSessionGetInfo.) --*/ { NET_API_STATUS ApiStatus; LPBYTE TempBuffer; // Buffer we'll use. DWORD TempBufferSize; LPDESC TempDataDesc16, TempDataDesc32, TempDataDescSmb; NET_API_STATUS TempStatus; DWORD TotalAvail; IF_DEBUG(SESSION) { NetpKdPrint(("RxNetSessionGetInfo: starting, server=" FORMAT_LPTSTR ", lvl=" FORMAT_DWORD ".\n", UncServerName, LevelWanted)); } // // Update pointers if they point to null chars. // ChangeNullCharToNullPtr( UncClientName ); ChangeNullCharToNullPtr( UserName ); // // Error check DLL stub and the app. // NetpAssert(UncServerName != NULL); if (BufPtr == NULL) { return (ERROR_INVALID_PARAMETER); } *BufPtr = NULL; // assume error; it makes error handlers easy to code. // This also forces possible GP fault before we allocate memory. if ( (UncClientName == NULL) || (UserName == NULL) ) { return (ERROR_INVALID_PARAMETER); } // // Learn about temp info level (max superset of all levels). // TempStatus = NetpSessionStructureInfo ( SESSION_SUPERSET_LEVEL, // level to learn about PARMNUM_ALL, // No parmnum with this. TRUE, // Need native sizes. & TempDataDesc16, & TempDataDesc32, & TempDataDescSmb, & TempBufferSize, // max buffer size (native) NULL, // don't need fixed size. NULL // don't need string size. ); NetpAssert(TempStatus == NERR_Success); // // Allocate memory for 32-bit version of superset info level. // TempStatus = NetApiBufferAllocate( TempBufferSize, (LPVOID *) & TempBuffer); if (TempStatus != NERR_Success) { return (TempStatus); } IF_DEBUG(SESSION) { NetpKdPrint(( "RxNetSessionGetInfo: allocated temp buffer at " FORMAT_LPVOID "\n", (LPVOID) TempBuffer )); } // // Actually remote the API, which will get back the superset // data in native format. // ApiStatus = RxRemoteApi( API_WSessionGetInfo, // API number UncServerName, // Required, with \\name. REMSmb_NetSessionGetInfo_P, // parm desc TempDataDesc16, TempDataDesc32, TempDataDescSmb, NULL, // no aux data desc 16 NULL, // no aux data desc 32 NULL, // no aux data desc SMB 0, // Flags: normal // rest of API's arguments, in 32-bit LM 2.x format: UncClientName, SESSION_SUPERSET_LEVEL, // level with all possible fields TempBuffer, TempBufferSize, & TotalAvail); // total size (BUGBUG meaningless?) NetpAssert( ApiStatus != ERROR_MORE_DATA ); NetpAssert( ApiStatus != NERR_BufTooSmall ); if (ApiStatus == NERR_Success) { DWORD EntriesSelected; // // Copy and convert from temp info level to level the caller wants. // Check for match on UncClientName and UserName first. // TempStatus = RxpCopyAndConvertSessions( (LPSESSION_SUPERSET_INFO) TempBuffer, // input "array" 1, // only one "entry" this time LevelWanted, UncClientName, UserName, (LPVOID *) BufPtr, // alloc'ed (may be NULL if no match) & EntriesSelected); // output entry count NetpAssert(TempStatus == NERR_Success); if (EntriesSelected == 0) { ApiStatus = RxpSessionMissingErrorCode( UncClientName, UserName ); NetpAssert( ApiStatus != NERR_Success ); } } (void) NetApiBufferFree( TempBuffer ); return (ApiStatus); } // RxNetSessionGetInfo