示例#1
0
/*
**  Execute a command, blocking during its execution.
*/
static STATUS
execute( char *cmd )
{
CL_ERR_DESC err_code;
SECURITY_ATTRIBUTES sa;
STARTUPINFO     st;
PROCESS_INFORMATION pi;
HANDLE hProcess = 0;
HANDLE hFile = 0;
OSVERSIONINFO lpvers;
bool status = FALSE;
BOOL on_w95 = FALSE;
PHANDLER_ROUTINE pHandler = NULL;

    lpvers.dwOSVersionInfoSize= sizeof(OSVERSIONINFO);
    GetVersionEx(&lpvers);
    on_w95=(lpvers.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)? TRUE: FALSE;

    if (on_w95)
        pHandler = (PHANDLER_ROUTINE)HandlerRoutine;

    iimksec(&sa);
    /* Set up the STARTUPINFO structure for spawning the command. */
    st.cb = sizeof(st);
    st.lpReserved = NULL;
    st.lpReserved2 = NULL;
    st.cbReserved2 = 0;
    st.lpDesktop = NULL;
    st.lpTitle = NULL;
    st.dwX = st.dwY = 20;
    st.dwXSize = st.dwYSize = 40;
    st.dwFlags = STARTF_USESHOWWINDOW;  /* Start app according to */
    st.wShowWindow = SW_SHOWMINIMIZED;  /* wShowWindow setting */
    status = CreateProcess( NULL,
                            cmd,
                            &sa,
                            &sa,
                            TRUE,
                            NORMAL_PRIORITY_CLASS,
                            (LPVOID) NULL,
                            NULL,
                            &st,
                            &pi);

    SetConsoleCtrlHandler(pHandler,TRUE);   /* Turns off ctrl-c handling in  */
                                            /* this process                  */
    if(status == TRUE)
    {
        hProcess = pi.hProcess;
        WaitForSingleObject(pi.hProcess,INFINITE);
        CloseHandle(pi.hProcess);
        hProcess = 0;
    }
    return((status != TRUE) ? GetLastError(): 0);
}
示例#2
0
/*
** Name: PCexec_suid - Execute a command as the ingres user.
**
** Description:
**	This procedure works with the Ingres service to run the given
**	command as the ingres user. It mimicks the "setuid" bit in UNIX.
**
** Inputs:
**	cmdbuf - command to execute as the ingres user
**
** Outputs:
**	none
**
** Returns:
**	OK
**	FAIL
**
** Side Effects:
**	none
**
** History:
**	08-jan-1998 (somsa01)
**	    Created.
**	19-feb-1998 (somsa01)
**	    We need to pass to the service the current working directory
**	    as well.  (Bug #89006)
**	25-feb-1998 (somsa01)
**	    We now have an input file for the process' stdin which
**	    runs through the OpenIngres service.
**	19-jun-1998 (somsa01)
**	    Use SYSTEM_PRODUCT_NAME for the name of the service.
**	10-jul-1998 (kitch01)
**		Bug 91362. If user is 'system' run through OpenIngres service
**		despite having access to server shared memory 'system' does not
**		have required privilege to access semaphores/mutexes.
**	11-jun-1999 (somsa01)
**	    If the command is a startup command, then it is always run through
**	    the Ingres service.
**	03-nov-1999 (somsa01)
**	    A failure from ControlService() should be treated as a severe
**	    error which should not let us continue.
** 	22-jan-2000 (somsa01)
**	    Return the exit code of the spawned process. Also, if the
**	    files exist, truncate them. The service name is now keyed off
**	    of II_INSTALLATION.
**	05-jun-2000 (somsa01)
**	    The Ingres installation may be started as the SYSTEM account,
**	    in which the 'ingres' user will not automatically have access
**	    to the shared memory segments. Therefore, even if the real
**	    user is 'ingres', check to see if he has access.
**	24-oct-2000 (somsa01)
**	    Removed the check on shared memory access. Access to the shared
**	    memory segment does not necessarily mean that the user running
**	    the process does not need to run the specified process as the
**	    Ingres owner. Also, generalized the check of the user with
**	    IDname_service().
**	18-dec-2000 (somsa01)
**	    Modified the cases to run the command "as is" without the Ingres
**	    service.
**	20-mar-2002 (somsa01)
**	    If all is well, return the exit code of the child process that
**	    was executed.
**	29-mar-2002 (somsa01)
**	    Properly return the child process exit code.
**	11-apr-2003 (somsa01)
**	    While waiting for "pending" to not be set, give some CPU back
**	    to the OS.
**      29-Jul-2005 (drivi01)
**	    Allow user to run the command if he/she owns a shared
**	    segment and ingres is not running as a service.
**	06-Dec-2006 (drivi01)
**	    Adding support for Vista, Vista requires "Global\" prefix for
**	    shared objects as well.  Replacing calls to GVosvers with 
**	    GVshobj which returns the prefix to shared objects.
**	    Added PCadjust_SeDebugPrivilege to allow quering of 
**	    System processes.
**	25-Jul-2007 (drivi01)
**		On Vista, PCexec_suid is unable to use SE_DEBUG Privilege
**	    to query process status and retireve its exit code.
**		The routine for monitoring a process and retrieving 
**	    its exit code has been moved to Ingres Service.
**	05-Nov-2009 (wanfr01) b122847
**	    Don't do a PCsleep unless you are waiting for more input
*/
STATUS
PCexec_suid(char *cmdbuf)
{
    EX_CONTEXT		context;
    SERVICE_STATUS	ssServiceStatus;
    LPSERVICE_STATUS	lpssServiceStatus = &ssServiceStatus;
    struct SETUID	setuid;
    DWORD		ProcID;
    HANDLE		SaveStdout;
    SECURITY_ATTRIBUTES	sa;
    CHAR		szRealUserID[25] = "";
    CHAR		*pszRealUserID = szRealUserID;
    CHAR		szServiceUserID[25] = "";
    CHAR		*pszServiceUserID = szServiceUserID;
    DWORD		BytesWritten, BytesRead = 0;
    CHAR		*inst_id;
    CHAR		SetuidShmName[64];
    CHAR		*temp_loc;
    CHAR		InBuf[256], OutBuf[256];
    static CHAR		SetuidPipeName[32];
    CL_ERR_DESC		err_code;
    CHAR		ServiceName[255];
    DWORD		ExitCode = 0;
    CHAR		tchII_INSTALLATION[3];
    BOOL		SetuidDbCmd = FALSE, ServiceCommand = FALSE;
    int			i, cmdlen;
    char		*ObjectPrefix;
	u_i4		drType;
    SC_HANDLE		schSCManager, OpIngSvcHandle;
    BOOL		bServiceStarted = FALSE;

    if (EXdeclare(ex_handler, &context) != OK)
    {
	EXdelete();
	PCexit(FAIL);
    }
    NMgtAt("II_INSTALLATION", &inst_id);
    STcopy(inst_id, tchII_INSTALLATION);

    /*
    ** See if this is a command that MUST be run through the Ingres
    ** service.
    */
    cmdlen = (i4)STlength(cmdbuf);
    for (i = 0; ServiceCommands[i] ; i++)
    {
	if (STbcompare( cmdbuf, cmdlen, ServiceCommands[i],
			(i4)STlength(ServiceCommands[i]), FALSE ) == 0)
	{
	    ServiceCommand = TRUE;
	    break;
	}
    }

    /*
    ** If the user is the same as the user who started the Ingres
    ** service, just spawn the command.
    */
    if (!ServiceCommand)
    {
	IDname(&pszRealUserID);
	if (!IDname_service(&pszServiceUserID) &&
	    STcompare(pszServiceUserID, pszRealUserID) == 0 && 
		PCisAdmin())
	{
	    /*
	    ** Attempt to just execute the command.
	    */
	    return( PCcmdline( (LOCATION *) NULL, cmdbuf, PC_WAIT,
		    (LOCATION *) NULL, &err_code) );
	}
	else
	{
	    /*
	    ** If current user is not the same as service user and ingres is not
	    ** running as a service, check if shared memory segment is owned
	    ** by current user, if user has access to shared segment allow him
	    ** to run the command.
	    */
	    PTR	shmem;
	    SIZE_TYPE	allocated_pages=0;
	    STATUS status;

	    if((status = MEget_pages(ME_MSHARED_MASK, 1, "lglkdata.mem",
	                 &shmem, &allocated_pages, &err_code)) == OK)
	    {
	        STprintf(ServiceName, "%s_Database_%s", SYSTEM_SERVICE_NAME, 
		tchII_INSTALLATION);
	        if ((schSCManager = OpenSCManager(NULL, NULL, 
					SC_MANAGER_CONNECT)) != NULL)
	        {
		    if ((OpIngSvcHandle = OpenService(schSCManager, ServiceName,
					SERVICE_QUERY_STATUS)) != NULL)
		    {
		       if (QueryServiceStatus(OpIngSvcHandle,lpssServiceStatus))
		       {
		    	if (ssServiceStatus.dwCurrentState != SERVICE_STOPPED)
			     bServiceStarted = TRUE;
		        }
		    }
	        }	
	        if (!bServiceStarted)
		    return(PCcmdline( (LOCATION *) NULL, cmdbuf, PC_WAIT,
			(LOCATION *) NULL, &err_code) );
	    }

	}

	/*
	** See if this command is an Ingres command which needs to interact
	** with at least one database.
	*/
	for (i = 0; validSetuidDbCmds[i] ; i++)
	{
	    if (STbcompare( cmdbuf, cmdlen, validSetuidDbCmds[i],
			    (i4)STlength(validSetuidDbCmds[i]), FALSE ) == 0)
	    {
		SetuidDbCmd = TRUE;
		break;
	    }
	}

	/*
	** If the user has access to the Ingres shared memory segment,
	** just spawn the command provided that it is not in the
	** validSetuidDbCmds list.
	*/
	if (!SetuidDbCmd)
	{
	    PTR	shmem;
	    SIZE_TYPE	allocated_pages=0;
	    STATUS	status;

	    if (((status = MEget_pages(ME_MSHARED_MASK, 1, "lglkdata.mem",
		&shmem,
		&allocated_pages, &err_code)) == OK) ||
		(status == ME_NO_SUCH_SEGMENT))
	    {
		if (status != ME_NO_SUCH_SEGMENT)
		    MEfree_pages(shmem, allocated_pages, &err_code);
		
		return( PCcmdline( (LOCATION *) NULL, cmdbuf, PC_WAIT,
			(LOCATION *) NULL, &err_code) );
	    }
	}
    }

    /*
    ** We must run the command through the Ingres service.
    */

    if ( STstrindex(cmdbuf, "-silent", 0, FALSE ) )
	SilentMode = TRUE;

    iimksec(&sa);


	GVshobj(&ObjectPrefix);
	STprintf(SetuidShmName, "%s%sSetuidShm", ObjectPrefix, tchII_INSTALLATION);

    if ( (SetuidShmHandle = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE,
					    FALSE,
					    SetuidShmName)) == NULL )
    {
	error_exit(GetLastError());
	return(FAIL);
    }
    if ( (SetuidShmPtr = MapViewOfFile(SetuidShmHandle,
				       FILE_MAP_WRITE | FILE_MAP_READ,
				       0,
				       0,
				       sizeof(struct SETUID_SHM))) == NULL )
    {
	error_exit(GetLastError());
	return(FAIL);
    }

    /* Set up the information to send to the service. */
    STcopy(cmdbuf, setuid.cmdline);
    GetCurrentDirectory(sizeof(setuid.WorkingDirectory),
			setuid.WorkingDirectory);
	NMgtAt("II_TEMPORARY", &temp_loc);
	drType = GetDriveType(NULL);
	if (drType == DRIVE_REMOTE)
	{
		STcopy(temp_loc, setuid.WorkingDirectory);
	}
    SaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);
    CVla(GetCurrentProcessId(), setuid.ClientProcID);
    STprintf(SetuidPipeName, "\\\\.\\PIPE\\INGRES\\%s\\SETUID", inst_id);

    /* Set up the stdout file for the command. */
    STprintf(OutfileName, "%s\\%sstdout.tmp", temp_loc, setuid.ClientProcID);
    if ( (OutFile = CreateFile(OutfileName,
			       GENERIC_READ | GENERIC_WRITE,
			       FILE_SHARE_READ | FILE_SHARE_WRITE,
			       &sa,
			       CREATE_ALWAYS,
			       FILE_ATTRIBUTE_NORMAL,
			       NULL)) == INVALID_HANDLE_VALUE )
    {
	error_exit(GetLastError());
	return(FAIL);
    }

    /* Set up the stdin file for the command. */
    STprintf(InfileName, "%s\\%sstdin.tmp", temp_loc, setuid.ClientProcID);
    if ( (InFile = CreateFile(InfileName,
			      GENERIC_READ | GENERIC_WRITE,
			      FILE_SHARE_READ | FILE_SHARE_WRITE,
			      &sa,
			      CREATE_ALWAYS,
			      FILE_FLAG_WRITE_THROUGH,
			      NULL)) == INVALID_HANDLE_VALUE )
    {
	error_exit(GetLastError());
	return(FAIL);
    }

    /* Wait until the service is ready to process our request. */
    while (SetuidShmPtr->pending == TRUE)
	PCsleep(100);
    SetuidShmPtr->pending = TRUE;

    /* Trigger the "setuid" event of the service. */
    if ( (schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)) == NULL)
    {
	error_exit(GetLastError());
	return(FAIL);
    }

    STprintf(ServiceName, "%s_Database_%s", SYSTEM_SERVICE_NAME,
	     tchII_INSTALLATION );
	OpIngSvcHandle = OpenService(schSCManager, ServiceName,
						SERVICE_USER_DEFINED_CONTROL);
	if (OpIngSvcHandle == NULL)
	{
		STprintf(ServiceName, "%s_DBATools_%s", SYSTEM_SERVICE_NAME,
	     tchII_INSTALLATION );
		OpIngSvcHandle = OpenService(schSCManager, ServiceName,
						SERVICE_USER_DEFINED_CONTROL);
	}
    if ( OpIngSvcHandle == NULL)
    {
	error_exit(GetLastError());
	return(FAIL);
    }
    if (!ControlService(OpIngSvcHandle, RUN_COMMAND_AS_INGRES,
			lpssServiceStatus))
    {
	error_exit(GetLastError());
	CloseServiceHandle(schSCManager);
	return(FAIL);
    }

    WaitNamedPipe(SetuidPipeName, NMPWAIT_WAIT_FOREVER);

    /* Send the information to the service. */
    if ( (Setuid_Handle = CreateFile(SetuidPipeName,
				     GENERIC_READ|GENERIC_WRITE,
				     FILE_SHARE_READ|FILE_SHARE_WRITE,
				     &sa,
				     OPEN_EXISTING,
				     FILE_ATTRIBUTE_NORMAL,
				     NULL)) == INVALID_HANDLE_VALUE )
    {
	error_exit(GetLastError());
	return(FAIL);
    }
    if (!WriteFile(Setuid_Handle, &setuid, sizeof(struct SETUID),
		   &BytesWritten, NULL))
    {
	error_exit(GetLastError());
	return(FAIL);
    }

    /*
    ** Retrieve information back from the service, and then
    ** disconnect from the pipe.
    */
    if (!ReadFile(Setuid_Handle, &setuid, sizeof(struct SETUID),
		  &BytesRead, NULL))
    {
	error_exit(GetLastError());
	return(FAIL);
    }

    ProcID = setuid.CreatedProcID;
    SetuidShmPtr->pending = FALSE;

    UnmapViewOfFile(SetuidShmPtr);
    SetuidShmPtr = NULL;
    CloseHandle(SetuidShmHandle);

    if ( (ProcID != -1) && (ProcID != -2) )
    {
	/*
	** Wait for the "spawned" process to exit, reading its output
	** from the stdout file.
	*/
	for (;;)
	{
	    if ( ((!ReadFile(OutFile, OutBuf, sizeof(OutBuf), &BytesRead, NULL)
		  || (BytesRead == 0)) && setuid.ExitCode != STILL_ACTIVE ))
		break;

	    if ( BytesRead &&
		 (!WriteFile(SaveStdout, OutBuf, BytesRead, &BytesWritten,
		  NULL)) && setuid.ExitCode != STILL_ACTIVE)
		break;
	    else if (BytesRead < sizeof(OutBuf))
		PCsleep(200);

	    /*
	    ** Currently, the only DBA program which can require
	    ** user input is verifydb. Therefore, when it spits out
	    ** the appropriate messages asking for user input, get
	    ** it from the end user and pass it along to the spawned
	    ** process.
	    */
	    if ( (STrstrindex(OutBuf, "S_DU04FF_CONTINUE_PROMPT", 0, FALSE)
			!= NULL) ||
		 (STrstrindex(OutBuf, "S_DU0300_PROMPT", 0, FALSE) != NULL) )
	    {
		SIflush(stdout);
		MEfill(sizeof(OutBuf), ' ', &OutBuf);
		MEfill(sizeof(InBuf), ' ', &InBuf);
		SIgetrec(InBuf, 255, 0);
		WriteFile(InFile, InBuf, sizeof(OutBuf), &BytesWritten, NULL);
	    }
	}

	ExitCode = setuid.ExitCode;
	CloseHandle(Setuid_Handle);
	CloseHandle(InFile);
	DeleteFile(InfileName);
	CloseHandle(OutFile);
	DeleteFile(OutfileName);
	CloseServiceHandle(OpIngSvcHandle);
	CloseServiceHandle(schSCManager);
        return(ExitCode);
    }
    else
    {
	error_exit(GetLastError());
	return(FAIL);
    }
}
示例#3
0
/*
** Name: GClanman_async_thread
** Description:
**	This thread handles all the asynchronous I/O for a protocol driver.
** 	It will be woken up when GClanman() places a request on it's input
**	Q.  Then, this thread will move the request from the input Q to its
**	processing Q and continue to process the request until complete.
**	When complete, the request is finally moved to the completion
**	Q.
** History:
**	04-Nov-93 (edg)
**	    Written.
**	29-jun-2000 (somsa01)
**	    Use GCc_listen_port for the server ncb_name. Also, make sure
**	    that we update GCc_client_name if we need a unique one.
**      06-Aug-2009 (Bruce Lunsford) Sir 122426
**	    Since _beginthreadex() is now used to start this thread,
**	    use _endthreadex() to end it.
*/
VOID
GClanman_async_thread( VOID * parms)
{
	int             status = OK;
	char            callname[NCBNAMSZ+1];
	DWORD		wait_stat;
	HANDLE		hSave;
	int		processing_requests = 0;
	int		pending_requests = 0;
	QUEUE		*q;
	SECURITY_ATTRIBUTES sa;

	iimksec (&sa);

	GCTRACE(4)("LMAN THREAD: started.\n");
top:
	/*
	** Wait for a request to come in from the primary gcc thread....
	*/

	GCTRACE(4)("LMAN THREAD: waiting for event ... \n");

	wait_stat = WaitForSingleObject( hEventThreadInQ, INFINITE );

	GCTRACE(3)("LMAN THREAD: wait returned %d, handle = %d\n", 
		    wait_stat, hEventThreadInQ );

	/*
	** If wait failed, chances are it's a major hosure.  Continue on any
	** way -- there's a possibility that something useful may get done.
	*/
	if (wait_stat == WAIT_FAILED)
	{
	    GCTRACE(1)("LMAN THREAD: wait failed %d\n", 
	    		GetLastError() );
	}

	/*
	** Now get get the incoming requests and add up how many requests
	** we're processing.
	*/
	processing_requests = GCget_incoming_reqs( Tptr, hMutexThreadInQ );

	GCTRACE(2)("LMAN THREAD: Got %d new requests to process\n",
		    processing_requests);

	/*
	** Loop until there's no more requests being processed.
	*/
	while( processing_requests )
	{
            pending_requests = 0;
	    /*
	    ** Now loop thru the inprocess request list.
	    */
	    for ( q = Tptr->process_head.q_next;
	    	  q != &Tptr->process_head;
		  q = q->q_next )
	    {
	        REQUEST_Q *rq = (REQUEST_Q *)q;
		GCC_P_PLIST *parm_list = rq->plist;
		PCB *pcb = (PCB *)parm_list->pcb;

		parm_list->generic_status = OK;
		CLEAR_ERR(&parm_list->system_status);

		switch (parm_list->function_invoked) 
		{

		    /******************************************************
		    ** Handle CONNECT
		    *******************************************************/
		    case GCC_CONNECT:

		    GCTRACE(4)("LMAN THREAD: process CONNECT\n");
		    if ( pcb == NULL || pcb->state.conn == INITIAL )
		    {
		        GCTRACE(3)("LMAN THREAD: initial CONNECT\n");
		        /*
			** Allocate the protocol control block.
			*/
		  	pcb = (PCB *) malloc( sizeof(PCB) );
		    	parm_list->pcb = (char *)pcb;
			if (pcb == NULL) 
			{
			    status = errno;
			    SETWIN32ERR(&parm_list->system_status, status, ER_alloc);
			    pcb->state.conn = COMPLETED;
			    parm_list->generic_status = GC_CONNECT_FAIL;
			    break;
		   	}
			memset( pcb, 0, sizeof( *pcb ) );
		        GCTRACE(3)("LMAN THREAD: CONNECT allocated pcb\n");
			/*
			** Create send/recv event handles for ncb.
			*/
    			if ((pcb->s_ncb.ncb_event = 
				CreateEvent( &sa, TRUE, FALSE, NULL ))== NULL)
    			{
        		    status = GetLastError();
			    pcb->state.conn = COMPLETED;
			    SETWIN32ERR(&parm_list->system_status, status, ER_create);
			    parm_list->generic_status = GC_CONNECT_FAIL;
			    break;
    		        }
       		 	if ((pcb->r_ncb.ncb_event = 
				CreateEvent( &sa, TRUE, FALSE, NULL ))== NULL)
    			{
        		    status = GetLastError();
			    CloseHandle( pcb->s_ncb.ncb_event );
			    pcb->state.conn = COMPLETED;
			    SETWIN32ERR(&parm_list->system_status, status, ER_create);
			    parm_list->generic_status = GC_CONNECT_FAIL;
			    break;
    			}
		        GCTRACE(3)("LMAN THREAD: CONNECT created events\n");

			pcb->state.conn = INITIAL;

		    } /* end if pcb NULL */

		    /*
		    ** If the PCB state is not INITIAL, just break because
		    ** we're just waiting for connect to complete.
		    */
		    if ( pcb->state.conn != INITIAL )
		        break;

		    /*
		    ** Use the send ncb in pcb for the connect -- add name.
		    */
		    pcb->s_ncb.ncb_command = NCBADDNAME;
		    pcb->s_ncb.ncb_buffer = Dummy_Buf;
		    pcb->s_ncb.ncb_length = sizeof(Dummy_Buf);
		    pcb->s_ncb.ncb_lana_num = lana_num;

		    for (;;)
		    {
			STprintf( GCc_client_name, "%s%-d", 
				  MyName, GCc_client_count++ );
			STcopy( GCc_client_name, pcb->s_ncb.ncb_name );

			GCTRACE(3)("LMAN THREAD: CONNECT doing ADDNAME %s\n",
				   pcb->s_ncb.ncb_name );

			/*
			** Copy to local NCB struct -- Netbios seems to fark
			** up if we don't.
			*/
			memcpy( &Name_Ncb, &pcb->s_ncb, sizeof( Name_Ncb ) );

			Netbios( &Name_Ncb );

			if (Name_Ncb.ncb_retcode == NRC_GOODRET)
			    break;
			else if (Name_Ncb.ncb_retcode == NRC_DUPNAME)
			    continue;
			else
			{
			    status = (STATUS)Name_Ncb.ncb_retcode;
			    CloseHandle( Name_Ncb.ncb_event );
			    pcb->s_ncb.ncb_event = NULL;
			    CloseHandle( pcb->r_ncb.ncb_event );
			    pcb->r_ncb.ncb_event = NULL;
			    pcb->state.conn = COMPLETED;
			    SETWIN32ERR(&parm_list->system_status, status,
					ER_netbios);
			    parm_list->generic_status = GC_CONNECT_FAIL;
			    break;
			}
		    }

		    if (parm_list->generic_status == GC_CONNECT_FAIL)
			break;

		    /*
		    ** just in case ...
		    */
		    ResetEvent( pcb->s_ncb.ncb_event );

		    /*
		    ** OK, now make the call
		    */
		    hSave = pcb->s_ncb.ncb_event;    /* save handle */
		    memset( &pcb->s_ncb, 0, sizeof(NCB) );
		    pcb->s_ncb.ncb_event = hSave;    /* restore handle */
		    pcb->s_ncb.ncb_buffer = parm_list->buffer_ptr;    
		    pcb->s_ncb.ncb_length = (WORD)parm_list->buffer_lng;    
		    pcb->s_ncb.ncb_command = NCBCALL | ASYNCH;
		    pcb->s_ncb.ncb_lana_num = lana_num;
		    STcopy( GCc_client_name, pcb->s_ncb.ncb_name );
		    STpolycat( 3, parm_list->function_parms.connect.node_id,
		    	       "_", parm_list->function_parms.connect.port_id,
			       callname );
		    CVupper( callname );

		    
		    /*
		    ** Loopback check to prevent mangling the name (?)
		    */
		    if ( STcompare( parm_list->function_parms.connect.port_id,
		    		    GCc_listen_port ) == 0 )
		    {
		        STcopy( GCc_listen_port, pcb->s_ncb.ncb_callname );
		    }
		    else
		    {
		        STcopy( callname, pcb->s_ncb.ncb_callname );
		    }

		    GCTRACE(3)("LMAN THREAD: CONNECT doing CALL to %s\n",
		    		pcb->s_ncb.ncb_callname );

		    if ( Netbios( &pcb->s_ncb ) != NRC_GOODRET )
		    {
		        status = (STATUS)pcb->s_ncb.ncb_retcode;
			CloseHandle( pcb->s_ncb.ncb_event );
			pcb->s_ncb.ncb_event = NULL;
			CloseHandle( pcb->r_ncb.ncb_event );
			pcb->r_ncb.ncb_event = NULL;
			pcb->state.conn = COMPLETED;
			SETWIN32ERR(&parm_list->system_status, status, ER_netbios);
			parm_list->generic_status = GC_CONNECT_FAIL;
			break;
		    }

		    GCTRACE(3)("LMAN THREAD: Async CALL OK\n" );

		    pcb->state.conn = COMPLETING;

		    break;


		    /*******************************************************
		    ** Handle SEND
		    *******************************************************/
		    case GCC_SEND:

		    GCTRACE(4)("LMAN THREAD: process SEND\n");

		    if ( pcb->state.send != INITIAL )
		    {
		        break;
		    }
		    pcb->s_ncb.ncb_buffer = parm_list->buffer_ptr;    
		    pcb->s_ncb.ncb_length = (WORD)parm_list->buffer_lng;    
		    pcb->s_ncb.ncb_lana_num = lana_num;
		    pcb->s_ncb.ncb_command = NCBSEND | ASYNCH;
		    if ( Netbios( &pcb->s_ncb ) != NRC_GOODRET )
		    {
		        status = (STATUS)pcb->s_ncb.ncb_retcode;
			pcb->state.send = COMPLETED;
			SETWIN32ERR(&parm_list->system_status, status, ER_netbios);
			parm_list->generic_status = GC_SEND_FAIL;
		    }

		    pcb->state.send = COMPLETING;

		    break;


		    /*******************************************************
		    ** Handle RECEIVE
		    *******************************************************/
		    case GCC_RECEIVE:

		    GCTRACE(4)("LMAN THREAD: process RECEIVE\n");

		    if ( pcb->state.recv != INITIAL )
		    {
                        pending_requests++;
		        break;
		    }
		    pcb->r_ncb.ncb_buffer = parm_list->buffer_ptr;    
		    pcb->r_ncb.ncb_length = (WORD)parm_list->buffer_lng;    
		    pcb->r_ncb.ncb_lana_num = lana_num;
		    pcb->r_ncb.ncb_command = NCBRECV | ASYNCH;

		    if ( Netbios( &pcb->r_ncb ) != NRC_GOODRET )
		    {
		        status = (STATUS)pcb->r_ncb.ncb_retcode;
			pcb->state.recv = COMPLETED;
			SETWIN32ERR(&parm_list->system_status, status, ER_netbios);
			parm_list->generic_status = GC_RECEIVE_FAIL;
		    }

		    pcb->state.recv = COMPLETING;

		    break;

		    /*******************************************************
		    ** Handle DISCONNECT
		    *******************************************************/
		    case GCC_DISCONNECT:

		    GCTRACE(4)("LMAN THREAD: process DISCONNECT\n");

		    if ( pcb && pcb->state.disc == INITIAL ) 
		    {
		        pcb->s_ncb.ncb_buffer = parm_list->buffer_ptr;    
		        pcb->s_ncb.ncb_length = (WORD)parm_list->buffer_lng;    
		        pcb->s_ncb.ncb_command = NCBHANGUP | ASYNCH;
		    	pcb->s_ncb.ncb_lana_num = lana_num;
			if ( pcb->s_ncb.ncb_lsn == 0 )
			    pcb->s_ncb.ncb_lsn = pcb->r_ncb.ncb_lsn;
		        if ( Netbios( &pcb->s_ncb ) != NRC_GOODRET )
		        {
		            status = (STATUS)pcb->s_ncb.ncb_retcode;
		    	    pcb->state.disc = COMPLETED;
			    SETWIN32ERR(&parm_list->system_status, status, ER_netbios);
			    parm_list->generic_status = GC_DISCONNECT_FAIL;
			    break;
		        }
		        pcb->state.disc = COMPLETING;
		    }

		    break;

		} /* end switch */

	    } /* end for process q loop */

	    /*
	    ** Now go thru the inprocess Q and look for any requests that
	    ** have been completed.  This will be indicated by one of:
	    ** parm_list->pcb == NULL (bad connect or after disconnect) or
	    ** pcb->state == COMPLETED, or WaitForSingleObject indicates
	    ** completion.
	    */

	    GCTRACE(4)("LMAN THREAD: processing completed. . . \n");

	    q = Tptr->process_head.q_next;
	    while( q != &Tptr->process_head )
	    {
	        REQUEST_Q *rq = (REQUEST_Q *)q;
	        GCC_P_PLIST *pl = rq->plist;
		PCB *pcb = (PCB *)pl->pcb;
		bool completed = FALSE;

		switch ( pl->function_invoked )
		{
		    case GCC_CONNECT:
		        if ( pcb == NULL || pcb->state.conn == COMPLETED || 
			     WaitForSingleObject( pcb->s_ncb.ncb_event, 0) ==
			         WAIT_OBJECT_0 )
			{
			    if (pcb) 
			    {
			        ResetEvent( pcb->s_ncb.ncb_event );
			        pcb->r_ncb.ncb_lsn = pcb->s_ncb.ncb_lsn;
				if ( pcb->s_ncb.ncb_lsn == 0 ||
				     pcb->s_ncb.ncb_retcode != NRC_GOODRET )
				{
				    pl->generic_status = GC_CONNECT_FAIL;
				    status = (STATUS)pcb->s_ncb.ncb_retcode;
				    SETWIN32ERR( &pl->system_status, status , ER_revent);
				    CloseHandle( pcb->s_ncb.ncb_event );
				    CloseHandle( pcb->r_ncb.ncb_event );
				    free( pcb );
				    pl->pcb = NULL;
				}
			    }

			    completed = TRUE;
			}
		        break;
		    case GCC_SEND:
		        if ( pcb == NULL || pcb->state.send == COMPLETED || 
			     WaitForSingleObject( pcb->s_ncb.ncb_event, 0) ==
			         WAIT_OBJECT_0 )
			{
			    ResetEvent( pcb->s_ncb.ncb_event );
			    if ( pcb->s_ncb.ncb_lsn == 0 ||
			         pcb->s_ncb.ncb_retcode != NRC_GOODRET )
			    {
				    pl->generic_status = GC_SEND_FAIL;
				    status = (STATUS)pcb->s_ncb.ncb_retcode;
				    SETWIN32ERR( &pl->system_status, status , ER_revent);
			    }
			    else
			    {
			        GCTRACE(2)(
				"LMAN THREAD: Send COMP pl len %d pcb len %d\n",
			            pl->buffer_lng, pcb->s_ncb.ncb_length);
					
			        pl->buffer_lng = pcb->s_ncb.ncb_length;
			    }
			    completed = TRUE;
			}
		        break;
		    case GCC_RECEIVE:
		        if ( pcb == NULL || pcb->state.recv == COMPLETED || 
			     WaitForSingleObject( pcb->r_ncb.ncb_event, 0) ==
			         WAIT_OBJECT_0 )
			{
			    ResetEvent( pcb->r_ncb.ncb_event );
			    if ( pcb->s_ncb.ncb_lsn == 0 ||
			         pcb->r_ncb.ncb_retcode != NRC_GOODRET )
			    {
				    pl->generic_status = GC_RECEIVE_FAIL;
				    status = (STATUS)pcb->r_ncb.ncb_retcode;
				    SETWIN32ERR( &pl->system_status, status , ER_revent);
			    }
			    else
			    {
			        pl->buffer_lng = pcb->r_ncb.ncb_length;
			    }
			    completed = TRUE;
			}
		        break;
		    case GCC_DISCONNECT:
		        if ( pcb == NULL || pcb->state.disc == COMPLETED || 
			     WaitForSingleObject( pcb->s_ncb.ncb_event, 0) ==
			         WAIT_OBJECT_0 )
			{
			    if (pcb) 
			    {
				if ( pcb->s_ncb.ncb_lsn == 0 ||
				     pcb->s_ncb.ncb_retcode != NRC_GOODRET )
				{
				    pl->generic_status = GC_DISCONNECT_FAIL;
				    status = (STATUS)pcb->s_ncb.ncb_retcode;
				    SETWIN32ERR( &pl->system_status, status , ER_revent);
				}
				pcb->s_ncb.ncb_command = NCBDELNAME;
				Netbios( &pcb->s_ncb );
				CloseHandle( pcb->s_ncb.ncb_event );
				CloseHandle( pcb->r_ncb.ncb_event );
				free( pcb );
				pl->pcb = NULL;
			    }
			    completed = TRUE;
			}
		        break;
		} /* end switch */

		if ( completed )
		{
		    QUEUE *nq = q->q_next;

	    	    GCTRACE(3)("LMAN THREAD:  Complete! PCB = %x PARM = %x \n",
		    		pcb, pl);

		    GCcomplete_request( q );

		    q = nq;
		    processing_requests--;

	    	    GCTRACE(3)("LMAN THREAD: processed completed \n");
	    	    GCTRACE(3)("                 : total now = %d \n",
		    		processing_requests);

		} /* end if req completed */
		else
		{
		    q = q->q_next;
		}

	    } /* end for -- look for complete req */

	    /*
	    ** Do a quick, non-blocking check to see if any new requests
	    ** came in during processing.
	    */
	    GCTRACE(4)("LMAN THREAD: quick look for new reqs \n");
	    if ( WaitForSingleObject( hEventThreadInQ, 0 ) == WAIT_OBJECT_0 )
	    {
		processing_requests += GCget_incoming_reqs( Tptr, 
					   hMutexThreadInQ );
	    }
	    GCTRACE(4)("LMAN THREAD: process reqs now = %d\n",
	    		processing_requests);

            if (processing_requests && pending_requests == processing_requests)
            {
                i4 Sleeptime = 1;
                Sleep(Sleeptime);
            }

	} /* end while processing requests */

	if (In_Shutdown)
	{
		_endthreadex(0);
		return;
	}

	/*
	** we're done for now, go back to the top and sleep.
	*/
	GCTRACE(3)("LMAN THREAD: No more reqs, going back to top\n" );
	goto top;
}
示例#4
0
/*
** Name: GClanman_listen
** Description:
**	This is the listen thread for lanman.  It runs a syncronous accept()
**	on the listen socket.  When complete it Q's the completetion to
**	the completed event Q.  When accept completes, this thread returns.
**	A new one will be created when GClanman() gets the request to
**	repost the listen.
** History:
**	11-nov-93 (edg)
**	    created.
**	29-jun-2000 (somsa01)
**	    Use GCc_listen_port for the ncb_name.
**	16-mar-2001 (somsa01)
**	    Set node_id to ncb_callname.
**      06-Aug-2009 (Bruce Lunsford) Sir 122426
**          Convert GCC completion queue mutex to a critical section
**          to improve performance (less overhead).
**	    Since _beginthreadex() is now used to start this thread,
**	    use _endthreadex() to end it.
*/
VOID
GClanman_listen( VOID *parms )
{
    GCC_P_PLIST		*parm_list = (GCC_P_PLIST *)parms;
    PCB			*pcb;
    STATUS		status = OK;
    REQUEST_Q		*rq;
    SECURITY_ATTRIBUTES	sa;

    iimksec (&sa);

    /*
    ** Initialize the listen node_id to NULL.
    */
    parm_list->function_parms.listen.node_id = NULL;

    /*
    ** Initialize fields of the Listen_Ncb
    */
    memset( &Listen_Ncb, 0, sizeof(NCB) );
    Listen_Ncb.ncb_buffer = parm_list->buffer_ptr;
    Listen_Ncb.ncb_length = (USHORT)parm_list->buffer_lng;
    Listen_Ncb.ncb_command = NCBLISTEN;
    Listen_Ncb.ncb_lana_num = lana_num;
    *Listen_Ncb.ncb_callname = (unsigned char)NULL;
    STmove( "*", ' ', NCBNAMSZ, Listen_Ncb.ncb_callname );
    *Listen_Ncb.ncb_name = (unsigned char)NULL;
    STcopy( GCc_listen_port, Listen_Ncb.ncb_name );


    /*
    ** Now we can do the NCBLISTEN request.  Block until it completes.
    */
    Netbios( &Listen_Ncb );
    if ( Listen_Ncb.ncb_retcode != NRC_GOODRET )
    {
	status = (int)Listen_Ncb.ncb_retcode;
	goto sys_err;
    }

    /*
    ** Allocate Protcol Control Block specific to this driver and put into
    ** parm list
    */
    pcb = (PCB *) malloc( sizeof(PCB) );
    if (pcb == NULL) 
    {
	status = errno;
	goto sys_err;
    }
    memset( pcb, 0, sizeof( *pcb ) );
    parm_list->pcb = (char *)pcb;

    /*
    ** Set node_id to the node name of the partner.
    */
    parm_list->function_parms.listen.node_id = STalloc(Listen_Ncb.ncb_callname);

    /*
    ** Now assign the pcb's send and receive NCB's the local session number
    ** returned by listen for further communications.
    */
    pcb->s_ncb.ncb_lsn = pcb->r_ncb.ncb_lsn = Listen_Ncb.ncb_lsn;

    /*
    ** Now create handles for the read and write event handles in the
    ** NCB.  These are created with manual reset as cautioned by the 
    ** programmer's guide so a ResetEvent MUST be done on them.
    */
    if ((pcb->s_ncb.ncb_event = CreateEvent( &sa, TRUE, FALSE, NULL ))== NULL)
    {
        status = GetLastError();
	goto sys_err;
    }
    if ((pcb->r_ncb.ncb_event = CreateEvent( &sa, TRUE, FALSE, NULL ))== NULL)
    {
        status = GetLastError();
	CloseHandle( pcb->s_ncb.ncb_event );
	pcb->s_ncb.ncb_event = NULL;
	goto sys_err;
    }

sys_err:
    if (status != OK) 
    {
        SETWIN32ERR(&parm_list->system_status, status, ER_create);
	parm_list->generic_status = GC_LISTEN_FAIL;
    }

    /*
    ** Now allocate a request q structure, stick it into complete q, and
    ** raise the GCC_COMPLETE event.
    */
    if ( (rq = (REQUEST_Q *)MEreqmem(0, sizeof(*rq), TRUE, NULL ) ) != NULL )
    {
        rq->plist = parm_list;
	/*
	** Get critical section for completion Q.
	*/
	EnterCriticalSection( &GccCompleteQCritSect );

	/*
	** Now insert the completed request into the completed Q.
	*/
	QUinsert( &rq->req_q, &IIGCc_proto_threads.completed_head );

	/*
	** Exit/leave critical section for completion Q
	*/
	LeaveCriticalSection( &GccCompleteQCritSect );

	/*
	** raise the completion event to wake up GCexec.
	*/
	if ( !SetEvent( hAsyncEvents[GCC_COMPLETE] ) )
	{
	   /*
	   ** ruh roh.  We're screwed if this event can't be signaled.
	   */
	   status = GetLastError();
	   GCTRACE(1)("GClanman_listen, SetEvent error = %d\n", status );
	}

    }
    else
    {
        /*
	** ruh-roh.  MEreqmem failed.  Selious tlouble.  Not sure what to
	** do about it at this point since if it failed we can't notify
	** the completion routine.  For now, just return (exit thread)
	** which will probably have the effect of blocking all incoming
	** connections.
	*/
    }
    _endthreadex(0);
}
示例#5
0
/*
** Name: GClanman
** Description:
**	Main entry point for the window's NT lan manager protocol driver.  This
** 	driver is essentially just a dispatcher -- it runs in the primary
**	GCC thread and mostly just Q's things to do to the constantly running
**	aynchronous request thread.  It may also start a listen thread if
**	it is a LISTEN request.
**
**	The following functions are handled:
**	    GCC_OPEN	- call GClanman_open
**	    GCC_LISTEN  - start listen thread
**	    GCC_SEND    - Q request for asynch thread
**	    GCC_RECEIVE - Q request for asynch thread
**	    GCC_CONNECT - Q request for asynch thread
**	    GCC_DISCONN - Q request for asynch thread
** History:
**	11-Nov-93 (edg)
**	    Original.
**      06-Aug-2009 (Bruce Lunsford) Sir 122426
**          Remove mutexing around calls to GCA service completion routine
**          as it is no longer necessary, since GCA is thread-safe...removes
**          calls to GCwaitCompletion + GCrestart. Should improve peformance.
**	    Convert CreateThread() to _beginthreadex() which is recommended
**	    when using C runtime.
*/
STATUS
GClanman( i4 function_code, GCC_P_PLIST * parm_list)
{
	STATUS          generror = 0;
	int             status = 0;
	int             tid;
	HANDLE          hThread;
    	REQUEST_Q 	*rq;
	SECURITY_ATTRIBUTES sa;

	iimksec (&sa);

	CLEAR_ERR(&parm_list->system_status);

	/*
	** set error based on function code and determine whether we got a
	** valid function.
	*/
	switch (function_code) {
	case GCC_OPEN:
		is_comm_svr = TRUE;
		GCTRACE(2) ("GClanman: Function = OPEN\n" );
		return GClanman_open( parm_list );

	case GCC_LISTEN:
		GCTRACE(2) ("GClanman: Function = LISTEN\n" );
		generror = GC_LISTEN_FAIL;
                /*
                ** For Lanman, the peer is always remote.
                */
                parm_list->options = 0;

		/*
		** Spawn off a thread to handle the listen request
		*/
		hThread = (HANDLE)_beginthreadex(&sa,
			       GC_STACK_SIZE,
			       (LPTHREAD_START_ROUTINE) GClanman_listen,
			       parm_list,
			       (unsigned long)NULL,
			       &tid);
		if (hThread) 
		{
			CloseHandle(hThread);
			return (OK);
		}
		status = errno;
		SETWIN32ERR(&parm_list->system_status, status, ER_create);
		goto err_exit;
		break;

	case GCC_CONNECT:
	    GCTRACE(2) ("GClanman: Function = CONNECT\n" );
	    generror = GC_CONNECT_FAIL;
	    break;
	case GCC_SEND:
	    GCTRACE(2) ("GClanman: Function = SEND\n" );
	    generror = GC_SEND_FAIL;
	    break;
	case GCC_RECEIVE:
	    GCTRACE(2) ("GClanman: Function = RECEIVE\n" );
	    generror = GC_RECEIVE_FAIL;
	    break;
	case GCC_DISCONNECT:
	    GCTRACE(2) ("GClanman: Function = DISCONNECT\n" );
	    generror = GC_DISCONNECT_FAIL;
	    break;

	default:
	    return FAIL;
	}			/* end switch */
	/*
	** CONNECT, SEND, RECEIVE and DISCONNECT are all dispatched
	** to the asynch thread.
   	** Now allocate a request q structure, stick it into incoming q,
   	** and raise the INCOMING REQUEST event.
   	*/
	GCTRACE(2)("GClanman: Q'ing request ...\n");

    	if ( (rq = (REQUEST_Q *)MEreqmem(0, sizeof(*rq), TRUE, NULL ) ) != NULL )
    	{
            rq->plist = parm_list;
	    /*
	    ** get mutex for completion Q
	    */
	    GCTRACE(2)("GClanman: wait for input mutex ...\n");
	    WaitForSingleObject( hMutexThreadInQ, INFINITE );

	    /*
	    ** Now insert the completed request into the inconming Q.
	    */
	    GCTRACE(2)("GClanman: inserting incoming req ...\n");
	    QUinsert( &rq->req_q, &Tptr->incoming_head );

	    /*
	    ** release mutex for completion Q
	    */
	    GCTRACE(2)("GClanman: releasing Mutex incoming req ...\n");
	    ReleaseMutex( hMutexThreadInQ );

	    /*
	    ** raise the incoming event to wake up the thread.
	    */
	    GCTRACE(2)("GClanman: Setting event ...\n");
	    if ( !SetEvent( hEventThreadInQ ) )
	    {
	   	    status = GetLastError();
		    SETWIN32ERR(&parm_list->system_status, status, ER_sevent);
	   	    GCTRACE(1)("GClanman, SetEvent error = %d\n", 
		    		status );
	    }

	    return OK;

   	}
    	else
    	{
	        /*
		** MEreqmem failed
		*/
		SETWIN32ERR(&parm_list->system_status, errno, ER_alloc);
    	}

	/*
	 * * Drive the completion routine on error
	 */
err_exit:
	parm_list->generic_status = generror;
	(*parm_list->compl_exit) (parm_list->compl_id);
	return OK;
}
示例#6
0
/*
** Name: GClanman_init
** Description:
**	LANMAN inititialization function.  This routine is called from
**	GCpinit() -- the routine GCC calls to initialize protocol drivers.
**
**	This function does initialization specific to the protocol:
**	    Creates Events and Mutex's for the protocol
**	    Finds and saves a pointer to it's input event Q.
**	    Fires up the thread which will do asynch I/O
** History:
**	11-Nov-93 (edg)
**	    created.
**      15-jul-95 (emmag)
**          Use a NULL Discretionary Access Control List (DACL) for
**          security, to give implicit access to everyone.
**	23-Feb-1998 (thaal01)
**	    Make space for port_id, stops gcc crashing on startup, sometimes.
**	13-may-2004 (somsa01)
**	    Updated config.dat string used to retrieve port information such
**	    that we do not rely specifically on the GCC port.
**	06-Aug-2009 (Bruce Lunsford)  Sir 122426
**	    Change arglist pointer in _beginthreadex for async_thread from
**	    uninitialized "dummy" to NULL to eliminate compiler warning
**	    and possible startup problem.
*/
STATUS
GClanman_init(GCC_PCE * pptr)
{

	char            *ptr, *host, *server_id, *port_id;
	char		config_string[256];
	char            buffer[MAX_COMPUTERNAME_LENGTH + 1];
	int 		real_name_size = MAX_COMPUTERNAME_LENGTH + 1;
	i4		i;
	int		tid;
	HANDLE		hThread;
	int		status;
	SECURITY_ATTRIBUTES sa;
	char		port_id_buf[8];

	port_id = port_id_buf;

	iimksec (&sa);

	/*
	** Look for trace variable.
	*/
	NMgtAt( "II_LANMAN_TRACE", &ptr );
	if ( !(ptr && *ptr) && PMget("!.lanman_trace_level", &ptr) != OK )
	{
	    GCLANMAN_trace = 0;
	}
	else
	{
	    GCLANMAN_trace = atoi( ptr );
	}

	/*
	** Create MUTEX and EVENT for the input queue of this protocol
	** driver.
	*/
	if ( ( hMutexThreadInQ = CreateMutex(&sa, FALSE, NULL) ) == NULL )
	{
	    return FAIL;
	}

	GCTRACE(3)( "GClanman_init: MutexInQ Handle = %d\n", hMutexThreadInQ );

	if ( ( hEventThreadInQ = CreateEvent(&sa, FALSE, FALSE, NULL)) == NULL )
	{
	    CloseHandle( hMutexThreadInQ );
	    return FAIL;
	}

	GCTRACE(3)( "GClanman_init: EventInQ Handle = %d\n", hEventThreadInQ );
	

	GCTRACE(4)( "Start GClanman_init\n" );

        /*
        ** Get set up for the PMget call.
        */
        PMinit();
        if( PMload( NULL, (PM_ERR_FUNC *)NULL ) != OK )
                PCexit( FAIL );

	/*
	** Construct the network port identifier. 
	*/

        host = PMhost();
	server_id = PMgetDefault(3);
 	if (!server_id)
 		server_id = "*" ;
        STprintf( config_string, ERx("!.lanman.port"),
                  SystemCfgPrefix, host, server_id);

	/*
	** Search config.dat for a match on the string we just built.
	** If we don't find it, then use the value for II_INSTALLATION 
	** failing that, default to II.
	*/
        PMget( config_string, &port_id );
	if (port_id == NULL )
	{
		NMgtAt("II_INSTALLATION", &ptr);
		if (ptr != NULL && *ptr != '\0')
		{
			STcopy(ptr, port_id);
		}
		else 
		{ 
			STcopy(SystemVarPrefix, port_id);
		}
	}

	NMgtAt( "II_NETBIOS_NODE", &ptr );
	if ( !ptr || !*ptr  )
	{
	    /*
	    ** Get Computer Name into buffer.
	    */
	    *buffer = (char)NULL;
	    GetComputerName( buffer, &real_name_size );
	    if ( !*buffer )
	        STcopy( "NONAME", buffer );
	    ptr = buffer;
	}
	/*
	** MyName holds ID for outgoing connections.
	*/
	STpolycat( 2, ptr, "_", MyName );
	/*
	** Create listen port ID.
	*/
	STpolycat( 3, ptr, "_", port_id, GCc_listen_port );
	CVupper( MyName );
	CVupper( GCc_listen_port );
	STcopy( GCc_listen_port, pptr->pce_port );

	GCTRACE(2)("GClanman_init: port = %s\n", pptr->pce_port );

	/*
	** Go thru the the protocol threads event list and find the index
	** of the lanman thread.  Set the Global Tptr for easy reference
	** to the event q's for this protocols thread.
	*/
	for ( i = 0; i < IIGCc_proto_threads.no_threads; i++ )
	{
	     THREAD_EVENTS *p = &IIGCc_proto_threads.thread[i];

	     if ( !STcompare( LANMAN_ID, p->thread_name ) )
	     {
	         Tptr = p;
	         break;
	     }
	}
	if ( Tptr == NULL )
	{
	    CloseHandle( hEventThreadInQ );
	    CloseHandle( hMutexThreadInQ );
	    return FAIL;
	}

	/*
	** Finally we start the asynchronous I/O thread
	*/

	hThread = (HANDLE)_beginthreadex(&sa,
		       GC_STACK_SIZE,
		       (LPTHREAD_START_ROUTINE) GClanman_async_thread,
		       NULL,
		       (unsigned long)NULL,
		       &tid);
	if (hThread) 
	{
		CloseHandle(hThread);
	}
	else
	{
	    status = errno;
	    GCTRACE(1)("GClanman_init: Couldn't create thread errno = %d '%s'\n",
	    		status, strerror(status) );
	    return FAIL;
	}

	return OK;
}