Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

552 lines
11 KiB

/****************************************************************************
PROGRAM: homesvr.cxx
PURPOSE: NT database server for RPC client.
Author:
Joev Dubach
Purpose:
HOMESVR keeps a database of users and their home directories
edited using HOMEADM, the administrative Windows client
application. It currently uses a linked list structure for
storing this database, and it uses named pipes for its RPC
services.
****************************************************************************/
//
// Inclusions
//
extern "C"
{
#include <stdlib.h>
#include <windows.h>
#include <string.h>
#include <stdio.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <ctype.h>
#include <rpc.h> // RPC data structures and APIs
#include <winerror.h>
#include "home.h" // header file generated by MIDL compiler
#include "..\homedir.h" // Server/client error codes
}
#include "homesvr.hxx"
//
// Global variables
//
NODE Database; // The server database
//
// Function Prototypes
//
// C++ global operators
void *
::operator new(
size_t size
);
void
::operator delete(
void *p
);
// RPC Callables
MY_STATUS
RpcHomesvrAdd(
char PAPI *Name,
char PAPI *Directory
);
MY_STATUS
RpcHomesvrDel(
char PAPI *Name
);
MY_STATUS
RpcHomesvrGet(
char PAPI *Name,
char PAPI *ResultDirectory
);
void
RpcHomesvrShutdown(
void
);
// Main program
void
main(
int argc,
char **argv
);
// MIDL stuff
void *
MIDL_user_allocate(
size_t len
);
void
MIDL_user_free(
void * ptr
);
//
// Program Body
//
//
// C++ global operators
//
//
// The global operators new and delete supersede the standard C++ new and
// delete. This makes memory allocation checking unnecessary.
//
void *
::operator new(
size_t size
)
{
void *p = malloc(size);
if (p == NULL)
{
printf("Fatal error: out of memory.\n");
exit(1);
}
return p;
}
void
::operator delete(
void *p
)
{
free(p);
}
//
// NODE members
//
//
// NODE::NODE initializes the inside of a new NODE appropriately.
//
NODE::NODE(
)
{
Name = new char[STRINGSIZE];
Directory = new char[STRINGSIZE];
Name[0] = '\0';
Directory[0] = '\0';
Prev = NULL;
Next = NULL;
}
//
// NODE::~NODE deletes the pointers that have been allocated inside a NODE.
//
NODE::~NODE(
)
{
delete [] Name;
delete [] Directory;
}
//
// NODE::NewList initializes a new Database by giving it empty head and tail
// nodes important to my linked list implementation.
//
MY_STATUS
NODE::NewList(
)
{
Next = new NODE;
Next->Prev = this;
return HOMEDIR_S_OK;
}
//
// NODE::FindNode returns the first node with Name alphabetically >= SearchName.
// If SearchName > all the other nodes' Names, the tail node is naturally
// returned.
//
NODE PAPI *
NODE::FindNode(
char PAPI *SearchName
)
{
PNODE PCurrNode = this;
for (int CompareVal = 1; CompareVal > 0;)
{ // Find it further down
PCurrNode = PCurrNode->Next;
if ((PCurrNode->Name)[0] != '\0')
{
CompareVal = strcmp((const char *) SearchName,
(const char *) PCurrNode->Name);
}
else
{
CompareVal = 0;
}
}
return PCurrNode; // Note that this never returns NULL, as the tail node
// always has an empty Name.
}
//
// NODE::AddNode creates a new node with NewName and NewDirectory and puts
// it in the database.
//
MY_STATUS
NODE::AddNode(
char PAPI *NewName,
char PAPI *NewDirectory
)
{
PNODE PCurrNode = FindNode(NewName);
PNODE PNewNode;
if (strcmp((const char *) NewName,(const char *) PCurrNode->Name) == 0)
{
return HOMEDIR_S_ENTRY_ALREADY_EXISTS;
}
(PNewNode = new NODE)->Next = PCurrNode;
PNewNode->Prev = PCurrNode->Prev;
PNewNode->Prev->Next = PNewNode;
PCurrNode->Prev = PNewNode;
strcpy(PNewNode->Name, NewName);
strcpy(PNewNode->Directory, NewDirectory);
return HOMEDIR_S_OK;
}
//
// NODE::DelNode deletes the specified node.
//
MY_STATUS
NODE::DelNode(
char PAPI *OldName
)
{
PNODE PDeleteNode = FindNode(OldName);
if (strcmp((const char *) PDeleteNode->Name,(const char *) OldName) != 0)
{
return HOMEDIR_S_ENTRY_NOT_FOUND;
}
else
{
PDeleteNode->Prev->Next = PDeleteNode->Next;
PDeleteNode->Next->Prev = PDeleteNode->Prev;
delete PDeleteNode;
return HOMEDIR_S_OK;
}
}
//
// NODE::GetDir searches for ThisName in the database, and returns the
// corresponding directory in FoundDirectory.
//
MY_STATUS NODE::GetDir(char PAPI *ThisName, char PAPI *FoundDirectory)
{
PNODE PGetNode = FindNode(ThisName);
strcpy(FoundDirectory, FindNode(ThisName)->Directory);
if (strcmp(ThisName,PGetNode->Name) == 0)
{
strcpy(FoundDirectory, PGetNode->Directory);
return HOMEDIR_S_OK;
}
else
{
FoundDirectory[0] = '\0';
return HOMEDIR_S_ENTRY_NOT_FOUND;
}
}
//
// NODE::LoadData loads the information contained in C:\homesvr.dat into
// the space between the first node and last node created by NewList.
//
MY_STATUS
NODE::LoadData(
void
)
{
FILE *FilePtr;
NODE *ReadNode = new NODE;
NODE *PrevNode = this;
NODE *LastNode = Next;
FilePtr = fopen("C:\\homesvr.dat","rt");
if (FilePtr != NULL)
{
while (fscanf(FilePtr,
"%s\n%s\n",
ReadNode->Name,
ReadNode->Directory) != EOF)
{
ReadNode->Prev = PrevNode;
PrevNode->Next = ReadNode;
PrevNode = ReadNode;
ReadNode = new NODE;
}
PrevNode->Next = LastNode;
LastNode->Prev = PrevNode;
delete ReadNode;
fclose(FilePtr);
}
return HOMEDIR_S_OK;
}
//
// NODE::SaveData saves the database out to C:\homesvr.dat, with every two
// lines making up a database entry.
//
MY_STATUS
NODE::SaveData(
void
)
{
FILE *FilePtr;
NODE *CurrNode = Next;
FilePtr = fopen("C:\\homesvr.dat","wt");
if (FilePtr == NULL)
{
printf("Fatal error: cannot write to data file.\n");
exit(1);
}
while((CurrNode->Name)[0] != '\0')
{
if (fprintf(FilePtr,
"%s\n%s\n",
CurrNode->Name,
CurrNode->Directory) < 0)
{
printf("Fatal error: cannot write to data file.\n");
exit(1);
}
CurrNode = CurrNode->Next;
}
if (fclose(FilePtr)==EOF)
{
printf("Fatal error: cannot write to data file.\n");
exit(1);
}
return HOMEDIR_S_OK;
}
//
// NODE::ShowData prints out the database on the server side.
//
void
NODE::ShowData(
void
)
{
PNODE CurrNode = this;
int i = 1;
for (;CurrNode != NULL;CurrNode = CurrNode->Next)
{
printf("%i. Name = '%s', Directory = '%s'.\n",
i++,
CurrNode->Name,
CurrNode->Directory);
}
}
//
// RPC Callables; the C front ends for C++ NODE members
//
//
// RpcHomesvrAdd adds a new node to Database and saves the database.
//
MY_STATUS
RpcHomesvrAdd(
char PAPI *Name,
char PAPI *Directory
)
{
MY_STATUS status = Database.AddNode(_strlwr(Name),_strlwr(Directory));
if (status != HOMEDIR_S_ENTRY_ALREADY_EXISTS)
{
//Database.ShowData();
Database.SaveData();
}
return status;
}
//
// RpcHomesvrDel deletes a node from Database.
//
MY_STATUS
RpcHomesvrDel(
char PAPI *Name
)
{
MY_STATUS status = Database.DelNode(_strlwr(Name));
if (status != HOMEDIR_S_ENTRY_NOT_FOUND)
{
//Database.ShowData();
Database.SaveData();
}
return status;
}
//
// RpcHomesvrGet returns the directory of the node in Database with Name Name.
//
MY_STATUS
RpcHomesvrGet(
char PAPI *Name,
char PAPI *ResultDirectory
)
{
return(Database.GetDir(_strlwr(Name),ResultDirectory));
}
//
// RpcHomesvrShutdown shuts down the server and returns execution to main,
// ending the call to RpcServerListen.
//
void
RpcHomesvrShutdown(
void
)
{
RPC_STATUS status;
//printf("Calling RpcMgmtStopServerListening\n");
status = RpcMgmtStopServerListening(NULL);
//printf("RpcMgmtStopServerListening returned: 0x%x\n", status);
if (status)
{
exit(2);
}
//printf("Calling RpcServerUnregisterIf\n");
status = RpcServerUnregisterIf(NULL, NULL, FALSE);
//printf("RpcServerUnregisterIf returned 0x%x\n", status);
if (status)
{
exit(2);
}
}
//
// Main program
//
void
main(
int argc,
char **argv
)
{
RPC_STATUS status;
char * pszProtocolSequence = "ncacn_np";
char * pszEndpoint = "\\pipe\\home";
// RPC_BINDING_VECTOR PAPI * BindingVector;
status = RpcServerUseProtseqEp((unsigned char *) pszProtocolSequence,
1, // maximum concurrent calls
(unsigned char *) pszEndpoint,
0);
//printf("RpcServerUseProtseqEp returned 0x%x\n", status);
if (status)
{
exit(2);
}
// FUTURE ENHANCEMENT: use the locator to find the server.
/*
status = RpcServerInqBindings(&BindingVector);
//printf("RpcServerInqBindings returned 0x%x\n", status);
if (status)
{
exit(2);
}
status = RpcNsBindingExport(RPC_C_NS_SYNTAX_DEFAULT,
(unsigned char PAPI *) "/.:/Home",
home_ServerIfHandle,
BindingVector,
NULL);
//printf("RpcNsBindingExport returned 0x%x\n", status);
if (status)
{
exit(2);
}
*/
//
status = RpcServerRegisterIf(home_ServerIfHandle, 0, 0);
//printf("RpcServerRegisterIf returned 0x%x\n", status);
if (status)
{
exit(2);
}
//
Database.NewList();
Database.LoadData();
//printf("Calling RpcServerListen\n");
printf("Microsoft (R) RPC HomeDrive Server Vesion 1.0\n");
printf("Copyright (c) Microsoft Corp 1992. All rights reserved.\n");
printf("Server successfully initialized.\n");
status = RpcServerListen(1,
10,
0);
//printf("RpcServerListen returned: 0x%x\n", status);
if (status)
{
exit(2);
}
// In the future enhancement:
// I don't call RpcNsBindingUnexport. (It's meant for a permanent removal.)
// I should call RpcBindingVectorFree.
} /* end main() */
// ====================================================================
// MIDL allocate and free
// ====================================================================
void *
MIDL_user_allocate(
size_t len
)
{
return(malloc(len));
}
void
MIDL_user_free(
void * ptr
)
{
free(ptr);
}
/* end homesvr.cxx */