Esempio n. 1
0
/*
 * Generate a management command from user input and send it
 */
BOOL
ManagementCommandFromInput(connection_t *c, LPSTR fmt, HWND hDlg, int id)
{
    BOOL retval = FALSE;
    LPSTR input, cmd;
    int input_len, cmd_len;

    GetDlgItemTextUtf8(hDlg, id, &input, &input_len);

    cmd_len = input_len + strlen(fmt);
    cmd = malloc(cmd_len);
    if (cmd)
    {
        snprintf(cmd, cmd_len, fmt, input);
        retval = ManagementCommand(c, cmd, NULL, regular);
        free(cmd);
    }

    /* Clear buffers with potentially secret content */
    memset(input, 'x', input_len - 1);
    SetDlgItemTextA(hDlg, id, input);
    free(input);

    return retval;
}
Esempio n. 2
0
/*
 * Handle management socket events asynchronously
 */
void
OnManagement(SOCKET sk, LPARAM lParam)
{
    int res;
    char *pos = NULL;
    char data[MAX_LOG_LENGTH];
    connection_t *c = GetConnByManagement(sk);
    if (c == NULL)
        return;

    switch (WSAGETSELECTEVENT(lParam))
    {
    case FD_CONNECT:
        if (WSAGETSELECTERROR(lParam))
            SendMessage(c->hwndStatus, WM_CLOSE, 0, 0);
        break;

    case FD_READ:
        /* Check if there's a complete line to read */
        res = recv(c->manage.sk, data, sizeof(data), MSG_PEEK);
        if (res < 1)
            return;

        pos = memchr(data, (*c->manage.password ? ':' : '\n'), res);
        if (!pos)
            return;

        /* There is data available: read it */
        res = recv(c->manage.sk, data, pos - data + 1, 0);
        if (res != pos - data + 1)
            return;

        /* Reply to a management password request */
        if (*c->manage.password)
        {
            ManagementCommand(c, c->manage.password, NULL, regular);
            *c->manage.password = '******';
            return;
        }

        /* Handle regular management interface output */
        data[pos - data - 1] = '\0';
        if (data[0] == '>')
        {
            /* Real time notifications */
            pos = data + 1;
            if (strncmp(pos, "LOG:", 4) == 0)
            {
                if (rtmsg_handler[log])
                    rtmsg_handler[log](c, pos + 4);
            }
            else if (strncmp(pos, "STATE:", 6) == 0)
            {
                if (rtmsg_handler[state])
                    rtmsg_handler[state](c, pos + 6);
            }
            else if (strncmp(pos, "HOLD:", 5) == 0)
            {
                if (rtmsg_handler[hold])
                    rtmsg_handler[hold](c, pos + 5);
            }
            else if (strncmp(pos, "PASSWORD:"******"INFO:", 5) == 0)
            {
                /* delay until management interface accepts input */
                Sleep(100);
                if (rtmsg_handler[ready])
                    rtmsg_handler[ready](c, pos + 5);
            }
        }
        else if (c->manage.cmd_queue)
        {
            /* Response to commands */
            mgmt_cmd_t *cmd = c->manage.cmd_queue;
            if (strncmp(data, "SUCCESS:", 8) == 0)
            {
                if (cmd->handler)
                    cmd->handler(c, data + 9);
                UnqueueCommand(c);
            }
            else if (strncmp(data, "ERROR:", 6) == 0)
            {
                if (cmd->handler)
                    cmd->handler(c, NULL);
                UnqueueCommand(c);
            }
            else if (strcmp(data, "END") == 0)
            {
                UnqueueCommand(c);
            }
            else if (cmd->handler)
            {
                cmd->handler(c, data);
            }
        }
        break;

    case FD_WRITE:
        SendCommand(c);
        break;

    case FD_CLOSE:
        closesocket(c->manage.sk);
        c->manage.sk = INVALID_SOCKET;
        while (UnqueueCommand(c))
            ;
        WSACleanup();
        if (rtmsg_handler[stop])
            rtmsg_handler[stop](c, "");
        break;
    }
}
Esempio n. 3
0
/*
 * Handle the request to release a hold from the OpenVPN management interface
 */
void
OnHold(connection_t *c, UNUSED char *msg)
{
    ManagementCommand(c, "hold off", NULL, regular);
    ManagementCommand(c, "hold release", NULL, regular);
}
Esempio n. 4
0
/*
 * DialogProc for OpenVPN status dialog windows
 */
INT_PTR CALLBACK
StatusDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    connection_t *c;

    switch (msg)
    {
    case WM_MANAGEMENT:
        /* Management interface related event */
        OnManagement(wParam, lParam);
        return TRUE;

    case WM_INITDIALOG:
        c = (connection_t *) lParam;

        /* Set window icon "disconnected" */
        SetStatusWinIcon(hwndDlg, ID_ICO_CONNECTING);

        /* Set connection for this dialog */
        SetProp(hwndDlg, cfgProp, (HANDLE) c);

        /* Create log window */
        HWND hLogWnd = CreateWindowEx(0, RICHEDIT_CLASS, NULL,
            WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL|ES_SUNKEN|ES_LEFT|
            ES_MULTILINE|ES_READONLY|ES_AUTOHSCROLL|ES_AUTOVSCROLL,
            20, 25, 350, 160, hwndDlg, (HMENU) ID_EDT_LOG, o.hInstance, NULL);
        if (!hLogWnd)
        {
            ShowLocalizedMsg(IDS_ERR_CREATE_EDIT_LOGWINDOW);
            return FALSE;
        }

        /* Set font and fontsize of the log window */
        CHARFORMAT cfm = {
            .cbSize = sizeof(CHARFORMAT),
            .dwMask = CFM_SIZE|CFM_FACE|CFM_BOLD,
            .szFaceName = _T("Microsoft Sans Serif"),
            .dwEffects = 0,
            .yHeight = 160
        };
        if (SendMessage(hLogWnd, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfm) == 0)
            ShowLocalizedMsg(IDS_ERR_SET_SIZE);

        /* Set size and position of controls */
        RECT rect;
        GetClientRect(hwndDlg, &rect);
        MoveWindow(hLogWnd, 20, 25, rect.right - 40, rect.bottom - 70, TRUE);
        MoveWindow(GetDlgItem(hwndDlg, ID_TXT_STATUS), 20, 5, rect.right - 25, 15, TRUE);
        MoveWindow(GetDlgItem(hwndDlg, ID_DISCONNECT), 20, rect.bottom - 30, 110, 23, TRUE);
        MoveWindow(GetDlgItem(hwndDlg, ID_RESTART), 145, rect.bottom - 30, 110, 23, TRUE);
        MoveWindow(GetDlgItem(hwndDlg, ID_HIDE), rect.right - 130, rect.bottom - 30, 110, 23, TRUE);

        /* Set focus on the LogWindow so it scrolls automatically */
        SetFocus(hLogWnd);
        return FALSE;

    case WM_SIZE:
        MoveWindow(GetDlgItem(hwndDlg, ID_EDT_LOG), 20, 25, LOWORD(lParam) - 40, HIWORD(lParam) - 70, TRUE);
        MoveWindow(GetDlgItem(hwndDlg, ID_DISCONNECT), 20, HIWORD(lParam) - 30, 110, 23, TRUE);
        MoveWindow(GetDlgItem(hwndDlg, ID_RESTART), 145, HIWORD(lParam) - 30, 110, 23, TRUE);
        MoveWindow(GetDlgItem(hwndDlg, ID_HIDE), LOWORD(lParam) - 130, HIWORD(lParam) - 30, 110, 23, TRUE);
        MoveWindow(GetDlgItem(hwndDlg, ID_TXT_STATUS), 20, 5, LOWORD(lParam) - 25, 15, TRUE);
        InvalidateRect(hwndDlg, NULL, TRUE);
        return TRUE;

    case WM_COMMAND:
        c = (connection_t *) GetProp(hwndDlg, cfgProp);
        switch (LOWORD(wParam))
        {
        case ID_DISCONNECT:
            SetFocus(GetDlgItem(c->hwndStatus, ID_EDT_LOG));
            StopOpenVPN(c);
            return TRUE;

        case ID_HIDE:
            if (c->state != disconnected)
                ShowWindow(hwndDlg, SW_HIDE);
            else
                DestroyWindow(hwndDlg);
            return TRUE;

        case ID_RESTART:
            c->state = reconnecting;
            SetFocus(GetDlgItem(c->hwndStatus, ID_EDT_LOG));
            ManagementCommand(c, "signal SIGHUP", NULL, regular);
            return TRUE;
        }
        break;

    case WM_SHOWWINDOW:
        if (wParam == TRUE)
        {
            c = (connection_t *) GetProp(hwndDlg, cfgProp);
            if (c->hwndStatus)
                SetFocus(GetDlgItem(c->hwndStatus, ID_EDT_LOG));
        }
        return FALSE;

    case WM_CLOSE:
        c = (connection_t *) GetProp(hwndDlg, cfgProp);
        if (c->state != disconnected)
            ShowWindow(hwndDlg, SW_HIDE);
        else
            DestroyWindow(hwndDlg);
        return TRUE;

    case WM_NCDESTROY:
        RemoveProp(hwndDlg, cfgProp);
        break;

    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    case WM_OVPN_STOP:
        c = (connection_t *) GetProp(hwndDlg, cfgProp);
        c->state = disconnecting;
        RunDisconnectScript(c, false);
        EnableWindow(GetDlgItem(c->hwndStatus, ID_DISCONNECT), FALSE);
        EnableWindow(GetDlgItem(c->hwndStatus, ID_RESTART), FALSE);
        SetMenuStatus(c, disconnecting);
        SetDlgItemText(c->hwndStatus, ID_TXT_STATUS, LoadLocalizedString(IDS_NFO_STATE_WAIT_TERM));
        SetEvent(c->exit_event);
        SetTimer(hwndDlg, IDT_STOP_TIMER, 3000, NULL);
        break;

    case WM_OVPN_SUSPEND:
        c = (connection_t *) GetProp(hwndDlg, cfgProp);
        c->state = suspending;
        EnableWindow(GetDlgItem(c->hwndStatus, ID_DISCONNECT), FALSE);
        EnableWindow(GetDlgItem(c->hwndStatus, ID_RESTART), FALSE);
        SetMenuStatus(c, disconnecting);
        SetDlgItemText(c->hwndStatus, ID_TXT_STATUS, LoadLocalizedString(IDS_NFO_STATE_WAIT_TERM));
        SetEvent(c->exit_event);
        SetTimer(hwndDlg, IDT_STOP_TIMER, 3000, NULL);
        break;

    case WM_TIMER:
        PrintDebug(L"WM_TIMER message with wParam = %lu", wParam);
        c = (connection_t *) GetProp(hwndDlg, cfgProp);
        if (wParam == IDT_STOP_TIMER)
        {
            /* openvpn failed to respond to stop signal -- terminate */
            TerminateOpenVPN(c);
            KillTimer (hwndDlg, IDT_STOP_TIMER);
        }
        break;
    }
    return FALSE;
}

/*
 * ThreadProc for OpenVPN status dialog windows
 */
static DWORD WINAPI
ThreadOpenVPNStatus(void *p)
{
    connection_t *c = p;
    TCHAR conn_name[200];
    MSG msg;
    HANDLE wait_event;

    CLEAR (msg);

    /* Cut of extention from config filename. */
    _tcsncpy(conn_name, c->config_file, _countof(conn_name));
    conn_name[_tcslen(conn_name) - _tcslen(o.ext_string) - 1] = _T('\0');

    c->state = (c->state == suspended ? resuming : connecting);

    /* Create and Show Status Dialog */
    c->hwndStatus = CreateLocalizedDialogParam(ID_DLG_STATUS, StatusDialogFunc, (LPARAM) c);
    if (!c->hwndStatus)
        return 1;

    CheckAndSetTrayIcon();
    SetMenuStatus(c, connecting);
    SetDlgItemText(c->hwndStatus, ID_TXT_STATUS, LoadLocalizedString(IDS_NFO_STATE_CONNECTING));
    SetWindowText(c->hwndStatus, LoadLocalizedString(IDS_NFO_CONNECTION_XXX, conn_name));

    if (!OpenManagement(c))
        PostMessage(c->hwndStatus, WM_CLOSE, 0, 0);

    /* Start the async read loop for service and set it as the wait event */
    if (c->iserv.hEvent)
    {
        HandleServiceIO (0, 0, (LPOVERLAPPED) &c->iserv);
        wait_event = c->iserv.hEvent;
    }
    else
        wait_event = c->hProcess;

    if (o.silent_connection == 0)
        ShowWindow(c->hwndStatus, SW_SHOW);

    /* Run the message loop for the status window */
    while (WM_QUIT != msg.message)
    {
        DWORD res;
        if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            if ((res = MsgWaitForMultipleObjectsEx (1, &wait_event, INFINITE, QS_ALLINPUT,
                                         MWMO_ALERTABLE)) == WAIT_OBJECT_0)
            {
                if (wait_event == c->hProcess)
                    OnProcess (c, NULL);
                else if (wait_event == c->iserv.hEvent)
                    OnService (c, NULL);
            }
            continue;
        }

        if (IsDialogMessage(c->hwndStatus, &msg) == 0)
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    /* release handles etc.*/
    Cleanup (c);
    c->hwndStatus = NULL;
    return 0;
}
Esempio n. 5
0
/*
 * Receive banner on connection to management interface
 * Format: <BANNER>
 */
void
OnReady(connection_t *c, UNUSED char *msg)
{
    ManagementCommand(c, "state on", NULL, regular);
    ManagementCommand(c, "log all on", OnLogLine, combined);
}
Esempio n. 6
0
/*
 * DialogProc for OpenVPN status dialog windows
 */
INT_PTR CALLBACK
StatusDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    connection_t *c;

    switch (msg)
    {
    case WM_MANAGEMENT:
        /* Management interface related event */
        OnManagement(wParam, lParam);
        return TRUE;

    case WM_INITDIALOG:
        c = (connection_t *) lParam;

        /* Set window icon "disconnected" */
        SetStatusWinIcon(hwndDlg, ID_ICO_CONNECTING);

        /* Set connection for this dialog */
        SetProp(hwndDlg, cfgProp, (HANDLE) c);

        /* Create log window */
        HWND hLogWnd = CreateWindowEx(0, RICHEDIT_CLASS, NULL,
            WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL|ES_SUNKEN|ES_LEFT|
            ES_MULTILINE|ES_READONLY|ES_AUTOHSCROLL|ES_AUTOVSCROLL,
            20, 25, 350, 160, hwndDlg, (HMENU) ID_EDT_LOG, o.hInstance, NULL);
        if (!hLogWnd)
        {
            ShowLocalizedMsg(IDS_ERR_CREATE_EDIT_LOGWINDOW);
            return FALSE;
        }

        /* Set font and fontsize of the log window */
        CHARFORMAT cfm = {
            .cbSize = sizeof(CHARFORMAT),
            .dwMask = CFM_SIZE|CFM_FACE|CFM_BOLD,
            .szFaceName = _T("Microsoft Sans Serif"),
            .dwEffects = 0,
            .yHeight = 160
        };
        if (SendMessage(hLogWnd, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfm) == 0)
            ShowLocalizedMsg(IDS_ERR_SET_SIZE);

        /* Set size and position of controls */
        RECT rect;
        GetClientRect(hwndDlg, &rect);
        MoveWindow(hLogWnd, 20, 25, rect.right - 40, rect.bottom - 70, TRUE);
        MoveWindow(GetDlgItem(hwndDlg, ID_TXT_STATUS), 20, 5, rect.right - 25, 15, TRUE);
        MoveWindow(GetDlgItem(hwndDlg, ID_DISCONNECT), 20, rect.bottom - 30, 110, 23, TRUE);
        MoveWindow(GetDlgItem(hwndDlg, ID_RESTART), 145, rect.bottom - 30, 110, 23, TRUE);
        MoveWindow(GetDlgItem(hwndDlg, ID_HIDE), rect.right - 130, rect.bottom - 30, 110, 23, TRUE);

        /* Set focus on the LogWindow so it scrolls automatically */
        SetFocus(hLogWnd);
        return FALSE;

    case WM_SIZE:
        MoveWindow(GetDlgItem(hwndDlg, ID_EDT_LOG), 20, 25, LOWORD(lParam) - 40, HIWORD(lParam) - 70, TRUE);
        MoveWindow(GetDlgItem(hwndDlg, ID_DISCONNECT), 20, HIWORD(lParam) - 30, 110, 23, TRUE);
        MoveWindow(GetDlgItem(hwndDlg, ID_RESTART), 145, HIWORD(lParam) - 30, 110, 23, TRUE);
        MoveWindow(GetDlgItem(hwndDlg, ID_HIDE), LOWORD(lParam) - 130, HIWORD(lParam) - 30, 110, 23, TRUE);
        MoveWindow(GetDlgItem(hwndDlg, ID_TXT_STATUS), 20, 5, LOWORD(lParam) - 25, 15, TRUE);
        InvalidateRect(hwndDlg, NULL, TRUE);
        return TRUE;

    case WM_COMMAND:
        c = (connection_t *) GetProp(hwndDlg, cfgProp);
        switch (LOWORD(wParam))
        {
        case ID_DISCONNECT:
            SetFocus(GetDlgItem(c->hwndStatus, ID_EDT_LOG));
            StopOpenVPN(c);
            return TRUE;

        case ID_HIDE:
            if (c->state != disconnected)
                ShowWindow(hwndDlg, SW_HIDE);
            else
                DestroyWindow(hwndDlg);
            return TRUE;

        case ID_RESTART:
            c->state = reconnecting;
            SetFocus(GetDlgItem(c->hwndStatus, ID_EDT_LOG));
            ManagementCommand(c, "signal SIGHUP", NULL, regular);
            return TRUE;
        }
        break;

    case WM_SHOWWINDOW:
        if (wParam == TRUE)
        {
            c = (connection_t *) GetProp(hwndDlg, cfgProp);
            if (c->hwndStatus)
                SetFocus(GetDlgItem(c->hwndStatus, ID_EDT_LOG));
        }
        return FALSE;

    case WM_CLOSE:
        c = (connection_t *) GetProp(hwndDlg, cfgProp);
        if (c->state != disconnected)
            ShowWindow(hwndDlg, SW_HIDE);
        else
            DestroyWindow(hwndDlg);
        return TRUE;

    case WM_NCDESTROY:
        RemoveProp(hwndDlg, cfgProp);
        break;

    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    }
    return FALSE;
}


/*
 * ThreadProc for OpenVPN status dialog windows
 */
static DWORD WINAPI
ThreadOpenVPNStatus(void *p)
{
    connection_t *c = p;
    TCHAR conn_name[200];
    MSG msg;

    /* Cut of extention from config filename. */
    _tcsncpy(conn_name, c->config_file, _countof(conn_name));
    conn_name[_tcslen(conn_name) - _tcslen(o.ext_string) - 1] = _T('\0');

    c->state = (c->state == suspended ? resuming : connecting);

    /* Create and Show Status Dialog */
    c->hwndStatus = CreateLocalizedDialogParam(ID_DLG_STATUS, StatusDialogFunc, (LPARAM) c);
    if (!c->hwndStatus)
        return 1;

    CheckAndSetTrayIcon();
    SetMenuStatus(c, connecting);
    SetDlgItemText(c->hwndStatus, ID_TXT_STATUS, LoadLocalizedString(IDS_NFO_STATE_CONNECTING));
    SetWindowText(c->hwndStatus, LoadLocalizedString(IDS_NFO_CONNECTION_XXX, conn_name));

    if (!OpenManagement(c))
        PostMessage(c->hwndStatus, WM_CLOSE, 0, 0);

    if (o.silent_connection[0] == '0')
        ShowWindow(c->hwndStatus, SW_SHOW);

    /* Run the message loop for the status window */
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (msg.hwnd == NULL)
        {
            switch (msg.message)
            {
            case WM_OVPN_STOP:
                c->state = disconnecting;
                RunDisconnectScript(c, false);
                EnableWindow(GetDlgItem(c->hwndStatus, ID_DISCONNECT), FALSE);
                EnableWindow(GetDlgItem(c->hwndStatus, ID_RESTART), FALSE);
                SetMenuStatus(c, disconnecting);
                SetDlgItemText(c->hwndStatus, ID_TXT_STATUS, LoadLocalizedString(IDS_NFO_STATE_WAIT_TERM));
                SetEvent(c->exit_event);
                break;

            case WM_OVPN_SUSPEND:
                c->state = suspending;
                EnableWindow(GetDlgItem(c->hwndStatus, ID_DISCONNECT), FALSE);
                EnableWindow(GetDlgItem(c->hwndStatus, ID_RESTART), FALSE);
                SetMenuStatus(&o.conn[config], disconnecting);
                SetDlgItemText(c->hwndStatus, ID_TXT_STATUS, LoadLocalizedString(IDS_NFO_STATE_WAIT_TERM));
                SetEvent(c->exit_event);
                break;
            }
        }
        else if (IsDialogMessage(c->hwndStatus, &msg) == 0)
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return 0;
}
Esempio n. 7
0
/*
 * Handle a state change notification from the OpenVPN management interface
 * Format <TIMESTAMP>,<STATE>,[<MESSAGE>],[<LOCAL_IP>][,<REMOTE_IP>]
 */
void
OnStateChange(connection_t *c, char *data)
{
    char *pos, *state, *message;

    pos = strchr(data, ',');
    if (pos == NULL)
        return;
    *pos = '\0';

    state = pos + 1;
    pos = strchr(state, ',');
    if (pos == NULL)
        return;
    *pos = '\0';

    message = pos + 1;
    pos = strchr(message, ',');
    if (pos == NULL)
        return;
    *pos = '\0';

    if (strcmp(state, "CONNECTED") == 0)
    {
        /* Run Connect Script */
        if (c->state == connecting || c->state == resuming)
            RunConnectScript(c, false);

        /* Save the local IP address if available */
        char *local_ip = pos + 1;
        pos = strchr(local_ip, ',');
        if (pos != NULL)
            *pos = '\0';

        /* Convert the IP address to Unicode */
        MultiByteToWideChar(CP_ACP, 0, local_ip, -1, c->ip, _countof(c->ip));

        /* Show connection tray balloon */
        if ((c->state == connecting   && o.show_balloon[0] != '0')
        ||  (c->state == resuming     && o.show_balloon[0] != '0')
        ||  (c->state == reconnecting && o.show_balloon[0] == '2'))
        {
            TCHAR msg[256];
            LoadLocalizedStringBuf(msg, _countof(msg), IDS_NFO_NOW_CONNECTED, c->config_name);
            ShowTrayBalloon(msg, (_tcslen(c->ip) ? LoadLocalizedString(IDS_NFO_ASSIGN_IP, c->ip) : _T("")));
        }

        /* Save time when we got connected. */
        c->connected_since = atoi(data);
        c->failed_psw_attempts = 0;
        c->state = connected;

        SetMenuStatus(c, connected);
        SetTrayIcon(connected);

        SetDlgItemText(c->hwndStatus, ID_TXT_STATUS, LoadLocalizedString(IDS_NFO_STATE_CONNECTED));
        SetStatusWinIcon(c->hwndStatus, ID_ICO_CONNECTED);

        /* Hide Status Window */
        ShowWindow(c->hwndStatus, SW_HIDE);
    }
    else if (strcmp(state, "RECONNECTING") == 0)
    {
        if (strcmp(message, "auth-failure") == 0
        ||  strcmp(message, "private-key-password-failure") == 0)
            c->failed_psw_attempts++;

        if (c->failed_psw_attempts >= o.psw_attempts - 1)
            ManagementCommand(c, "auth-retry none", NULL, regular);

        c->state = reconnecting;
        CheckAndSetTrayIcon();

        SetDlgItemText(c->hwndStatus, ID_TXT_STATUS, LoadLocalizedString(IDS_NFO_STATE_RECONNECTING));
        SetStatusWinIcon(c->hwndStatus, ID_ICO_CONNECTING);
    }
}
Esempio n. 8
0
/*
 * Handle management socket events asynchronously
 */
void
OnManagement(SOCKET sk, LPARAM lParam)
{
    int res;
    char *data;
    ULONG data_size, offset;

    connection_t *c = GetConnByManagement(sk);
    if (c == NULL)
        return;

    switch (WSAGETSELECTEVENT(lParam))
    {
    case FD_CONNECT:
        if (WSAGETSELECTERROR(lParam))
        {
            if (time(NULL) < c->manage.timeout)
                connect(c->manage.sk, (SOCKADDR *)&c->manage.skaddr, sizeof(c->manage.skaddr));
            else
            {
                /* Connection to MI timed out. */
                c->state = timedout;
                rtmsg_handler[stop](c, "");
            }
        }
        break;

    case FD_READ:
        if (ioctlsocket(c->manage.sk, FIONREAD, &data_size) != 0
        ||  data_size == 0)
            return;

        data = malloc(c->manage.saved_size + data_size);
        if (data == NULL)
            return;

        res = recv(c->manage.sk, data + c->manage.saved_size, data_size, 0);
        if (res != (int) data_size)
        {
            free(data);
            return;
        }

        /* Copy previously saved management data */
        if (c->manage.saved_size)
        {
            memcpy(data, c->manage.saved_data, c->manage.saved_size);
            data_size += c->manage.saved_size;
            free(c->manage.saved_data);
            c->manage.saved_data = NULL;
            c->manage.saved_size = 0;
        }

        offset = 0;
        while (offset < data_size)
        {
            char *pos;
            char *line = data + offset;
            size_t line_size = data_size - offset;

            pos = memchr(line, (*c->manage.password ? ':' : '\n'), line_size);
            if (pos == NULL)
            {
                c->manage.saved_data = malloc(line_size);
                if (c->manage.saved_data)
                {
                    c->manage.saved_size = line_size;
                    memcpy(c->manage.saved_data, line, c->manage.saved_size);
                }
                break;
            }

            offset += (pos - line) + 1;

            /* Reply to a management password request */
            if (*c->manage.password)
            {
                ManagementCommand(c, c->manage.password, NULL, regular);
                *c->manage.password = '******';
                continue;
            }

            /* Handle regular management interface output */
            line[pos - line - 1] = '\0';
            if (line[0] == '>')
            {
                /* Real time notifications */
                pos = line + 1;
                if (strncmp(pos, "LOG:", 4) == 0)
                {
                    if (rtmsg_handler[log])
                        rtmsg_handler[log](c, pos + 4);
                }
                else if (strncmp(pos, "STATE:", 6) == 0)
                {
                    if (rtmsg_handler[state])
                        rtmsg_handler[state](c, pos + 6);
                }
                else if (strncmp(pos, "HOLD:", 5) == 0)
                {
                    if (rtmsg_handler[hold])
                        rtmsg_handler[hold](c, pos + 5);
                }
                else if (strncmp(pos, "PASSWORD:"******"PROXY:", 6) == 0)
                {
                    if (rtmsg_handler[proxy])
                        rtmsg_handler[proxy](c, pos + 6);
                }
                else if (strncmp(pos, "INFO:", 5) == 0)
                {
                    /* delay until management interface accepts input */
                    Sleep(100);
                    if (rtmsg_handler[ready])
                        rtmsg_handler[ready](c, pos + 5);
                }
            }
            else if (c->manage.cmd_queue)
            {
                /* Response to commands */
                mgmt_cmd_t *cmd = c->manage.cmd_queue;
                if (strncmp(line, "SUCCESS:", 8) == 0)
                {
                    if (cmd->handler)
                        cmd->handler(c, line + 9);
                    UnqueueCommand(c);
                }
                else if (strncmp(line, "ERROR:", 6) == 0)
                {
                    if (cmd->handler)
                        cmd->handler(c, NULL);
                    UnqueueCommand(c);
                }
                else if (strcmp(line, "END") == 0)
                {
                    UnqueueCommand(c);
                }
                else if (cmd->handler)
                {
                    cmd->handler(c, line);
                }
            }
        }
        free(data);
        break;

    case FD_WRITE:
        SendCommand(c);
        break;

    case FD_CLOSE:
        if (c->manage.saved_size)
        {
            free(c->manage.saved_data);
            c->manage.saved_data = NULL;
            c->manage.saved_size = 0;
        }
        closesocket(c->manage.sk);
        c->manage.sk = INVALID_SOCKET;
        while (UnqueueCommand(c))
            ;
        WSACleanup();
        if (rtmsg_handler[stop])
            rtmsg_handler[stop](c, "");
        break;
    }
}
Esempio n. 9
0
static LPWSTR
QueryWindowsProxySettings(const url_scheme scheme, LPCSTR host)
{
    LPWSTR proxy = NULL;
    BOOL auto_detect = TRUE;
    LPWSTR auto_config_url = NULL;
    WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxy_config;

    if (WinHttpGetIEProxyConfigForCurrentUser(&proxy_config))
    {
        proxy = proxy_config.lpszProxy;
        auto_detect = proxy_config.fAutoDetect;
        auto_config_url = proxy_config.lpszAutoConfigUrl;
        GlobalFree(proxy_config.lpszProxyBypass);
    }

    if (auto_detect)
    {
        LPWSTR old_url = auto_config_url;
        DWORD flags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
        if (WinHttpDetectAutoProxyConfigUrl(flags, &auto_config_url))
            GlobalFree(old_url);
    }

    if (auto_config_url)
    {
        HINTERNET session = WinHttpOpen(NULL, WINHTTP_ACCESS_TYPE_NO_PROXY,
            WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
        if (session)
        {
            int size = _snwprintf(NULL, 0, L"%s://%S", UrlSchemeStr(scheme), host) + 1;
            LPWSTR url = malloc(size * sizeof(WCHAR));
            if (url)
            {
                _snwprintf(url, size, L"%s://%S", UrlSchemeStr(scheme), host);

                LPWSTR old_proxy = proxy;
                WINHTTP_PROXY_INFO proxy_info;
                WINHTTP_AUTOPROXY_OPTIONS options = {
                    .fAutoLogonIfChallenged = TRUE,
                    .dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL,
                    .lpszAutoConfigUrl = auto_config_url,
                    .dwAutoDetectFlags = 0,
                    .lpvReserved = NULL,
                    .dwReserved = 0
                };

                if (WinHttpGetProxyForUrl(session, url, &options, &proxy_info))
                {
                    GlobalFree(old_proxy);
                    GlobalFree(proxy_info.lpszProxyBypass);
                    proxy = proxy_info.lpszProxy;
                }
                free(url);
            }
            WinHttpCloseHandle(session);
        }
        GlobalFree(auto_config_url);
    }

    return proxy;
}


static VOID
ParseProxyString(LPWSTR proxy_str, url_scheme scheme,
                 LPCSTR *type, LPCWSTR *host, LPCWSTR *port)
{
    if (proxy_str == NULL)
        return;

    LPCWSTR delim = L"; ";
    LPWSTR token = wcstok(proxy_str, delim);

    LPCWSTR scheme_str = UrlSchemeStr(scheme);
    LPCWSTR socks_str = UrlSchemeStr(SOCKS_URL);

    /* Token format: [<scheme>=][<scheme>"://"]<server>[":"<port>] */
    while (token)
    {
        BOOL match = FALSE;
        LPWSTR eq = wcschr(token, '=');
        LPWSTR css = wcsstr(token, L"://");

        /*
         * If the token has a <scheme>, test for the one we're looking for.
         * If we're looking for a https proxy, socks will also do.
         * If it's a proxy without a <scheme> it's only good for https.
         */
        if (eq || css)
        {
            if (wcsbegins(token, scheme_str))
            {
                match = TRUE;
            }
            else if (scheme == HTTPS_URL && wcsbegins(token, socks_str))
            {
                match = TRUE;
                scheme = SOCKS_URL;
            }
        }
        else if (scheme == HTTPS_URL)
        {
            match = TRUE;
        }

        if (match)
        {
            LPWSTR server = token;
            if (css)
                server = css + 3;
            else if (eq)
                server = eq + 1;

            /* IPv6 addresses are surrounded by brackets */
            LPWSTR port_delim;
            if (server[0] == '[')
            {
                server += 1;
                LPWSTR end = wcschr(server, ']');
                if (end == NULL)
                    continue;
                *end++ = '\0';

                port_delim = (*end == ':' ? end : NULL);
            }
            else
            {
                port_delim = wcsrchr(server, ':');
                if (port_delim)
                    *port_delim = '\0';
            }

            *type = (scheme == HTTPS_URL ? "HTTP" : "SOCKS");
            *host = server;
            if (port_delim)
                *port = port_delim + 1;
            else
                *port = (scheme == HTTPS_URL ? L"80": L"1080");

            break;
        }
        token = wcstok(NULL, delim);
    }
}


/*
 * Respond to management interface PROXY notifications
 * Input format: REMOTE_NO,PROTOCOL,HOST
 */
void
OnProxy(connection_t *c, char *line)
{
    LPSTR proto, host;
    char *pos = strchr(line, ',');
    if (pos == NULL)
        return;

    proto = ++pos;
    pos = strchr(pos, ',');
    if (pos == NULL)
        return;

    *pos = '\0';
    host = ++pos;
    if (host[0] == '\0')
        return;

    LPCSTR type = "NONE";
    LPCWSTR addr = L"", port = L"";
    LPWSTR proxy_str = NULL;

    if (o.proxy_source == manual)
    {
        if (o.proxy_type == http && streq(proto, "TCP"))
        {
            type = "HTTP";
            addr = o.proxy_http_address;
            port = o.proxy_http_port;
        }
        else if (o.proxy_type == socks)
        {
            type = "SOCKS";
            addr = o.proxy_socks_address;
            port = o.proxy_socks_port;
        }
    }
    else if (o.proxy_source == windows)
    {
        url_scheme scheme = (streq(proto, "TCP") ? HTTPS_URL : SOCKS_URL);
        proxy_str = QueryWindowsProxySettings(scheme, host);
        ParseProxyString(proxy_str, scheme, &type, &addr, &port);
    }

    char cmd[128];
    snprintf(cmd, sizeof(cmd), "proxy %s %S %S", type, addr, port);
    cmd[sizeof(cmd) - 1] = '\0';
    ManagementCommand(c, cmd, NULL, regular);

    GlobalFree(proxy_str);
}