Esempio n. 1
0
int guac_sftp_blob_handler(guac_client* client, guac_stream* stream,
        void* data, int length) {

    /* Pull file from stream */
    ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data;
    LIBSSH2_SFTP_HANDLE* file = (LIBSSH2_SFTP_HANDLE*) stream->data;

    /* Attempt write */
    if (libssh2_sftp_write(file, data, length) == length) {
        guac_protocol_send_ack(client->socket, stream, "SFTP: OK",
                GUAC_PROTOCOL_STATUS_SUCCESS);
        guac_socket_flush(client->socket);
    }

    /* Inform of any errors */
    else {
        guac_client_log_error(client, "Unable to write to file: %s",
                libssh2_sftp_last_error(client_data->sftp_session));
        guac_protocol_send_ack(client->socket, stream, "SFTP: Write failed",
                GUAC_PROTOCOL_STATUS_INTERNAL_ERROR);
        guac_socket_flush(client->socket);
    }

    return 0;

}
Esempio n. 2
0
int guac_rdp_upload_end_handler(guac_client* client, guac_stream* stream) {

    guac_rdp_stream* rdp_stream = (guac_rdp_stream*) stream->data;

    /* Get filesystem, return error if no filesystem */
    guac_rdp_fs* fs = ((rdp_guac_client_data*) client->data)->filesystem;
    if (fs == NULL) {
        guac_protocol_send_ack(client->socket, stream, "FAIL (NO FS)",
                GUAC_PROTOCOL_STATUS_SERVER_ERROR);
        guac_socket_flush(client->socket);
        return 0;
    }

    /* Close file */
    guac_rdp_fs_close(fs, rdp_stream->upload_status.file_id);

    /* Acknowledge stream end */
    guac_protocol_send_ack(client->socket, stream, "OK (STREAM END)",
            GUAC_PROTOCOL_STATUS_SUCCESS);
    guac_socket_flush(client->socket);

    free(rdp_stream);
    return 0;

}
Esempio n. 3
0
int guac_rdp_download_ack_handler(guac_client* client, guac_stream* stream,
        char* message, guac_protocol_status status) {

    guac_rdp_stream* rdp_stream = (guac_rdp_stream*) stream->data;

    /* Get filesystem, return error if no filesystem */
    guac_rdp_fs* fs = ((rdp_guac_client_data*) client->data)->filesystem;
    if (fs == NULL) {
        guac_protocol_send_ack(client->socket, stream, "FAIL (NO FS)",
                GUAC_PROTOCOL_STATUS_SERVER_ERROR);
        guac_socket_flush(client->socket);
        return 0;
    }

    /* If successful, read data */
    if (status == GUAC_PROTOCOL_STATUS_SUCCESS) {

        /* Attempt read into buffer */
        char buffer[4096];
        int bytes_read = guac_rdp_fs_read(fs,
                rdp_stream->download_status.file_id,
                rdp_stream->download_status.offset, buffer, sizeof(buffer));

        /* If bytes read, send as blob */
        if (bytes_read > 0) {
            rdp_stream->download_status.offset += bytes_read;
            guac_protocol_send_blob(client->socket, stream,
                    buffer, bytes_read);
        }

        /* If EOF, send end */
        else if (bytes_read == 0) {
            guac_protocol_send_end(client->socket, stream);
            guac_client_free_stream(client, stream);
            free(rdp_stream);
        }

        /* Otherwise, fail stream */
        else {
            guac_client_log(client, GUAC_LOG_ERROR,
                    "Error reading file for download");
            guac_protocol_send_end(client->socket, stream);
            guac_client_free_stream(client, stream);
            free(rdp_stream);
        }

        guac_socket_flush(client->socket);

    }

    /* Otherwise, return stream to client */
    else
        guac_client_free_stream(client, stream);

    return 0;

}
Esempio n. 4
0
static void __stream_read_callback(pa_stream* stream, size_t length,
        void* data) {

    guac_client* client = (guac_client*) data;
    vnc_guac_client_data* client_data = (vnc_guac_client_data*) client->data;
    guac_audio_stream* audio = client_data->audio;

    const void* buffer;

    /* Read data */
    pa_stream_peek(stream, &buffer, &length);

    /* Avoid sending silence unless data is waiting to be flushed */
    if (audio->pcm_bytes_written != 0 || !guac_pa_is_silence(buffer, length)) {

        /* Write data */
        guac_audio_stream_write_pcm(audio, buffer, length);

        /* Flush occasionally */
        if (audio->pcm_bytes_written > GUAC_VNC_PCM_WRITE_RATE) {
            guac_audio_stream_end(audio);
            guac_audio_stream_begin(client_data->audio,
                    GUAC_VNC_AUDIO_RATE,
                    GUAC_VNC_AUDIO_CHANNELS,
                    GUAC_VNC_AUDIO_BPS);
            guac_socket_flush(client->socket);
        }

    }

    /* Advance buffer */
    pa_stream_drop(stream);

}
Esempio n. 5
0
int guac_rdp_user_file_handler(guac_user* user, guac_stream* stream,
        char* mimetype, char* filename) {

    guac_rdp_client* rdp_client = (guac_rdp_client*) user->client->data;

#ifdef ENABLE_COMMON_SSH
    guac_rdp_settings* settings = rdp_client->settings;

    /* If SFTP is enabled, it should be used for default uploads only if RDPDR
     * is not enabled or its upload directory has been set */
    if (rdp_client->sftp_filesystem != NULL) {
        if (!settings->drive_enabled || settings->sftp_directory != NULL)
            return guac_rdp_sftp_file_handler(user, stream, mimetype, filename);
    }
#endif

    /* Default to using RDPDR uploads (if enabled) */
    if (rdp_client->filesystem != NULL)
        return guac_rdp_upload_file_handler(user, stream, mimetype, filename);

    /* File transfer not enabled */
    guac_protocol_send_ack(user->socket, stream, "File transfer disabled",
            GUAC_PROTOCOL_STATUS_UNSUPPORTED);
    guac_socket_flush(user->socket);

    return 0;
}
Esempio n. 6
0
int guac_rdp_svc_pipe_handler(guac_client* client, guac_stream* stream,
        char* mimetype, char* name) {

    guac_rdp_stream* rdp_stream;
    guac_rdp_svc* svc = guac_rdp_get_svc(client, name);

    /* Fail if no such SVC */
    if (svc == NULL) {
        guac_client_log(client, GUAC_LOG_ERROR,
                "Requested non-existent pipe: \"%s\".",
                name);
        guac_protocol_send_ack(client->socket, stream, "FAIL (NO SUCH PIPE)",
                GUAC_PROTOCOL_STATUS_CLIENT_BAD_REQUEST);
        guac_socket_flush(client->socket);
        return 0;
    }
    else
        guac_client_log(client, GUAC_LOG_ERROR,
                "Inbound half of channel \"%s\" connected.",
                name);

    /* Init stream data */
    stream->data = rdp_stream = malloc(sizeof(guac_rdp_stream));
    stream->blob_handler = guac_rdp_svc_blob_handler;
    rdp_stream->type = GUAC_RDP_INBOUND_SVC_STREAM;
    rdp_stream->svc = svc;
    svc->input_pipe = stream;

    return 0;

}
Esempio n. 7
0
guac_stream* guac_sftp_download_file(guac_client* client,
        char* filename) {

    ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data;
    guac_stream* stream;
    LIBSSH2_SFTP_HANDLE* file;

    /* Attempt to open file for reading */
    file = libssh2_sftp_open(client_data->sftp_session, filename,
            LIBSSH2_FXF_READ, 0);
    if (file == NULL) {
        guac_client_log_error(client, "Unable to read file \"%s\": %s",
                filename,
                libssh2_sftp_last_error(client_data->sftp_session));
        return NULL;
    }

    /* Allocate stream */
    stream = guac_client_alloc_stream(client);
    stream->ack_handler = guac_sftp_ack_handler;
    stream->data = file;

    /* Send stream start, strip name */
    filename = basename(filename);
    guac_protocol_send_file(client->socket, stream,
            "application/octet-stream", filename);
    guac_socket_flush(client->socket);

    return stream;

}
Esempio n. 8
0
int guac_vnc_user_join_handler(guac_user* user, int argc, char** argv) {

    guac_vnc_client* vnc_client = (guac_vnc_client*) user->client->data;

    /* Connect via VNC if owner */
    if (user->owner) {

        /* Parse arguments into client */
        guac_vnc_settings* settings = vnc_client->settings =
            guac_vnc_parse_args(user, argc, (const char**) argv);

        /* Fail if settings cannot be parsed */
        if (settings == NULL) {
            guac_user_log(user, GUAC_LOG_INFO,
                    "Badly formatted client arguments.");
            return 1;
        }

        /* Start client thread */
        if (pthread_create(&vnc_client->client_thread, NULL, guac_vnc_client_thread, user->client)) {
            guac_user_log(user, GUAC_LOG_ERROR, "Unable to start VNC client thread.");
            return 1;
        }

    }

    /* If not owner, synchronize with current state */
    else {

#ifdef ENABLE_PULSE
        /* Synchronize an audio stream */
        if (vnc_client->audio)
            guac_audio_stream_add_user(vnc_client->audio, user);
#endif

        /* Synchronize with current display */
        guac_common_display_dup(vnc_client->display, user, user->socket);
        guac_socket_flush(user->socket);

    }

    /* Only handle events if not read-only */
    if (vnc_client->settings->read_only == 0) {

        /* General mouse/keyboard/clipboard events */
        user->mouse_handler     = guac_vnc_user_mouse_handler;
        user->key_handler       = guac_vnc_user_key_handler;
        user->clipboard_handler = guac_vnc_clipboard_handler;

#ifdef ENABLE_COMMON_SSH
        /* Set generic (non-filesystem) file upload handler */
        user->file_handler = guac_vnc_sftp_file_handler;
#endif

    }

    return 0;

}
Esempio n. 9
0
int guac_rdp_upload_blob_handler(guac_client* client, guac_stream* stream,
        void* data, int length) {

    int bytes_written;
    guac_rdp_stream* rdp_stream = (guac_rdp_stream*) stream->data;

    /* Get filesystem, return error if no filesystem 0*/
    guac_rdp_fs* fs = ((rdp_guac_client_data*) client->data)->filesystem;
    if (fs == NULL) {
        guac_protocol_send_ack(client->socket, stream, "FAIL (NO FS)",
                GUAC_PROTOCOL_STATUS_SERVER_ERROR);
        guac_socket_flush(client->socket);
        return 0;
    }

    /* Write entire block */
    while (length > 0) {

        /* Attempt write */
        bytes_written = guac_rdp_fs_write(fs,
                rdp_stream->upload_status.file_id,
                rdp_stream->upload_status.offset,
                data, length);

        /* On error, abort */
        if (bytes_written < 0) {
            guac_protocol_send_ack(client->socket, stream,
                    "FAIL (BAD WRITE)",
                    GUAC_PROTOCOL_STATUS_CLIENT_FORBIDDEN);
            guac_socket_flush(client->socket);
            return 0;
        }

        /* Update counters */
        rdp_stream->upload_status.offset += bytes_written;
        data += bytes_written;
        length -= bytes_written;

    }

    guac_protocol_send_ack(client->socket, stream, "OK (DATA RECEIVED)",
            GUAC_PROTOCOL_STATUS_SUCCESS);
    guac_socket_flush(client->socket);
    return 0;

}
/**
 * Called periodically by guacd whenever the plugin should handle accumulated
 * data and render a frame.
 *
 * @param client
 *     The guac_client associated with the plugin that should render a frame.
 *
 * @return
 *     Non-zero if an error occurs, zero otherwise.
 */
static int streamtest_client_message_handler(guac_client* client) {

    /* Get stream state from client */
    streamtest_state* state = (streamtest_state*) client->data;

    int frame_start;
    int frame_duration;

    /* Record start of frame */
    frame_start = streamtest_utime();

    /* Read from stream and write as blob(s) */
    if (!state->paused) {

        /* Attempt to fill the available buffer space */
        int length = streamtest_fill_buffer(state->fd,
                state->frame_buffer, state->frame_bytes);

        /* Abort connection if we cannot read */
        if (length == -1) {
            guac_client_log(client, GUAC_LOG_ERROR,
                    "Unable to read from specified file: %s",
                    strerror(errno));
            return 1;
        }

        /* Write all data read as blobs */
        if (length > 0)
            streamtest_write_blobs(client->socket, state->stream,
                    state->frame_buffer, length);

        /* Disconnect on EOF */
        else {
            guac_client_log(client, GUAC_LOG_INFO, "Media streaming complete");
            guac_client_stop(client);
        }

    }

    /* Update progress bar */
    streamtest_render_progress(client);
    guac_socket_flush(client->socket);

    /* Sleep for remainder of frame */
    frame_duration = streamtest_utime() - frame_start;
    if (frame_duration < state->frame_duration)
        streamtest_usleep(state->frame_duration - frame_duration);

    /* Warn (at debug level) if frame takes too long */
    else
        guac_client_log(client, GUAC_LOG_DEBUG,
                "Frame took longer than requested duration: %i microseconds",
                frame_duration);

    /* Success */
    return 0;

}
Esempio n. 11
0
void* __guacd_client_output_thread(void* data) {

    guac_client* client = (guac_client*) data;
    guac_socket* socket = client->socket;

    /* Guacamole client output loop */
    while (client->state == GUAC_CLIENT_RUNNING) {

        /* Handle server messages */
        if (client->handle_messages) {

            /* Only handle messages if synced within threshold */
            if (client->last_sent_timestamp - client->last_received_timestamp
                    < GUACD_SYNC_THRESHOLD) {

                int retval = client->handle_messages(client);
                if (retval) {
                    guacd_client_log_guac_error(client,
                            "Error handling server messages");
                    guac_client_stop(client);
                    return NULL;
                }

                /* Send sync instruction */
                client->last_sent_timestamp = guac_timestamp_current();
                if (guac_protocol_send_sync(socket, client->last_sent_timestamp)) {
                    guacd_client_log_guac_error(client, 
                            "Error sending \"sync\" instruction");
                    guac_client_stop(client);
                    return NULL;
                }

                /* Flush */
                if (guac_socket_flush(socket)) {
                    guacd_client_log_guac_error(client,
                            "Error flushing output");
                    guac_client_stop(client);
                    return NULL;
                }

            }

            /* Do not spin while waiting for old sync */
            else
                __guacdd_sleep(GUACD_MESSAGE_HANDLE_FREQUENCY);

        }

        /* If no message handler, just sleep until next sync ping */
        else
            __guacdd_sleep(GUACD_SYNC_FREQUENCY);

    } /* End of output loop */

    guac_client_stop(client);
    return NULL;

}
Esempio n. 12
0
/**
 * Callback which is invoked by guac_client_foreach_user() to flush all
 * pending data on the given user's socket. If an error occurs while flushing
 * a user's socket, that user is signalled to stop with guac_user_stop().
 *
 * @param user
 *     The user whose socket should be flushed.
 *
 * @param data
 *     Arbitrary data passed to guac_client_foreach_user(). This is not needed
 *     by this callback, and should be left as NULL.
 *
 * @return
 *     Always NULL.
 */
static void* __flush_callback(guac_user* user, void* data) {

    /* Attempt flush, disconnect on failure */
    if (guac_socket_flush(user->socket))
        guac_user_stop(user);

    return NULL;

}
Esempio n. 13
0
int guac_rdp_upload_file_handler(guac_client* client, guac_stream* stream,
        char* mimetype, char* filename) {

    int file_id;
    guac_rdp_stream* rdp_stream;
    char file_path[GUAC_RDP_FS_MAX_PATH];

    /* Get filesystem, return error if no filesystem */
    guac_rdp_fs* fs = ((rdp_guac_client_data*) client->data)->filesystem;
    if (fs == NULL) {
        guac_protocol_send_ack(client->socket, stream, "FAIL (NO FS)",
                GUAC_PROTOCOL_STATUS_SERVER_ERROR);
        guac_socket_flush(client->socket);
        return 0;
    }

    /* Translate name */
    __generate_upload_path(filename, file_path);

    /* Open file */
    file_id = guac_rdp_fs_open(fs, file_path, ACCESS_GENERIC_WRITE, 0,
            DISP_FILE_OVERWRITE_IF, 0);
    if (file_id < 0) {
        guac_protocol_send_ack(client->socket, stream, "FAIL (CANNOT OPEN)",
                GUAC_PROTOCOL_STATUS_CLIENT_FORBIDDEN);
        guac_socket_flush(client->socket);
        return 0;
    }

    /* Init upload status */
    rdp_stream = malloc(sizeof(guac_rdp_stream));
    rdp_stream->type = GUAC_RDP_UPLOAD_STREAM;
    rdp_stream->upload_status.offset = 0;
    rdp_stream->upload_status.file_id = file_id;
    stream->data = rdp_stream;
    stream->blob_handler = guac_rdp_upload_blob_handler;
    stream->end_handler = guac_rdp_upload_end_handler;

    guac_protocol_send_ack(client->socket, stream, "OK (STREAM BEGIN)",
            GUAC_PROTOCOL_STATUS_SUCCESS);
    guac_socket_flush(client->socket);
    return 0;

}
Esempio n. 14
0
int guac_sftp_end_handler(guac_client* client, guac_stream* stream) {

    /* Pull file from stream */
    LIBSSH2_SFTP_HANDLE* file = (LIBSSH2_SFTP_HANDLE*) stream->data;

    /* Attempt to close file */
    if (libssh2_sftp_close(file) == 0) {
        guac_protocol_send_ack(client->socket, stream, "SFTP: OK", GUAC_PROTOCOL_STATUS_SUCCESS);
        guac_socket_flush(client->socket);
    }
    else {
        guac_client_log_error(client, "Unable to close file");
        guac_protocol_send_ack(client->socket, stream, "SFTP: Close failed", GUAC_PROTOCOL_STATUS_SERVER_ERROR);
        guac_socket_flush(client->socket);
    }

    return 0;

}
Esempio n. 15
0
int guac_rdp_user_join_handler(guac_user* user, int argc, char** argv) {

    guac_rdp_client* rdp_client = (guac_rdp_client*) user->client->data;

    /* Connect via RDP if owner */
    if (user->owner) {

        /* Parse arguments into client */
        guac_rdp_settings* settings = rdp_client->settings =
            guac_rdp_parse_args(user, argc, (const char**) argv);

        /* Fail if settings cannot be parsed */
        if (settings == NULL) {
            guac_user_log(user, GUAC_LOG_INFO,
                    "Badly formatted client arguments.");
            return 1;
        }

        /* Start client thread */
        if (pthread_create(&rdp_client->client_thread, NULL,
                    guac_rdp_client_thread, user->client)) {
            guac_user_log(user, GUAC_LOG_ERROR,
                    "Unable to start VNC client thread.");
            return 1;
        }

    }

    /* If not owner, synchronize with current state */
    else {

        /* Synchronize any audio stream */
        if (rdp_client->audio)
            guac_audio_stream_add_user(rdp_client->audio, user);

        /* Bring user up to date with any registered static channels */
        guac_rdp_svc_send_pipes(user);

        /* Synchronize with current display */
        guac_common_display_dup(rdp_client->display, user, user->socket);
        guac_socket_flush(user->socket);

    }

    user->file_handler = guac_rdp_user_file_handler;
    user->mouse_handler = guac_rdp_user_mouse_handler;
    user->key_handler = guac_rdp_user_key_handler;
    user->size_handler = guac_rdp_user_size_handler;
    user->pipe_handler = guac_rdp_svc_pipe_handler;
    user->clipboard_handler = guac_rdp_clipboard_handler;

    return 0;

}
Esempio n. 16
0
int guac_rdp_upload_put_handler(guac_client* client, guac_object* object,
        guac_stream* stream, char* mimetype, char* name) {

    /* Get filesystem, return error if no filesystem */
    guac_rdp_fs* fs = ((rdp_guac_client_data*) client->data)->filesystem;
    if (fs == NULL) {
        guac_protocol_send_ack(client->socket, stream, "FAIL (NO FS)",
                GUAC_PROTOCOL_STATUS_SERVER_ERROR);
        guac_socket_flush(client->socket);
        return 0;
    }

    /* Open file */
    int file_id = guac_rdp_fs_open(fs, name, ACCESS_GENERIC_WRITE, 0,
            DISP_FILE_OVERWRITE_IF, 0);

    /* Abort on failure */
    if (file_id < 0) {
        guac_protocol_send_ack(client->socket, stream, "FAIL (CANNOT OPEN)",
                GUAC_PROTOCOL_STATUS_CLIENT_FORBIDDEN);
        guac_socket_flush(client->socket);
        return 0;
    }

    /* Init upload stream data */
    guac_rdp_stream* rdp_stream = malloc(sizeof(guac_rdp_stream));
    rdp_stream->type = GUAC_RDP_UPLOAD_STREAM;
    rdp_stream->upload_status.offset = 0;
    rdp_stream->upload_status.file_id = file_id;

    /* Allocate stream, init for file upload */
    stream->data = rdp_stream;
    stream->blob_handler = guac_rdp_upload_blob_handler;
    stream->end_handler = guac_rdp_upload_end_handler;

    /* Acknowledge stream creation */
    guac_protocol_send_ack(client->socket, stream, "OK (STREAM BEGIN)",
            GUAC_PROTOCOL_STATUS_SUCCESS);
    guac_socket_flush(client->socket);
    return 0;
}
Esempio n. 17
0
void guac_terminal_select_end(guac_terminal* terminal) {

    guac_client* client = terminal->client;
    guac_socket* socket = client->socket;

    /* If no text is selected, nothing to do */
    if (!terminal->text_selected)
        return;

    /* Selection is now committed */
    terminal->selection_committed = true;

    /* Reset current clipboard contents */
    guac_common_clipboard_reset(terminal->clipboard, "text/plain");

    int start_row, start_col;
    int end_row, end_col;

    /* Ensure proper ordering of start and end coords */
    guac_terminal_select_normalized_range(terminal,
            &start_row, &start_col, &end_row, &end_col);

    /* If only one row, simply copy */
    if (end_row == start_row)
        guac_terminal_clipboard_append_row(terminal, start_row, start_col, end_col);

    /* Otherwise, copy multiple rows */
    else {

        /* Store first row */
        guac_terminal_clipboard_append_row(terminal, start_row, start_col, -1);

        /* Store all middle rows */
        for (int row = start_row + 1; row < end_row; row++) {
            guac_common_clipboard_append(terminal->clipboard, "\n", 1);
            guac_terminal_clipboard_append_row(terminal, row, 0, -1);
        }

        /* Store last row */
        guac_common_clipboard_append(terminal->clipboard, "\n", 1);
        guac_terminal_clipboard_append_row(terminal, end_row, 0, end_col);

    }

    /* Send data */
    if (!terminal->disable_copy) {
        guac_common_clipboard_send(terminal->clipboard, client);
        guac_socket_flush(socket);
    }

    guac_terminal_notify(terminal);

}
Esempio n. 18
0
int guac_rdp_svc_blob_handler(guac_client* client, guac_stream* stream,
        void* data, int length) {

    guac_rdp_stream* rdp_stream = (guac_rdp_stream*) stream->data;

    /* Write blob data to SVC directly */
    guac_rdp_svc_write(rdp_stream->svc, data, length);

    guac_protocol_send_ack(client->socket, stream, "OK (DATA RECEIVED)",
            GUAC_PROTOCOL_STATUS_SUCCESS);
    guac_socket_flush(client->socket);
    return 0;

}
Esempio n. 19
0
void guac_rdpdr_start_download(guac_rdpdr_device* device, const char* path) {

    /* Get client and stream */
    guac_client* client = device->rdpdr->client;

    int file_id = guac_rdp_fs_open((guac_rdp_fs*) device->data, path,
            ACCESS_FILE_READ_DATA, 0, DISP_FILE_OPEN, 0);

    /* If file opened successfully, start stream */
    if (file_id >= 0) {

        guac_rdp_stream* rdp_stream;
        const char* basename;

        int i;
        char c;

        /* Associate stream with transfer status */
        guac_stream* stream = guac_client_alloc_stream(client);
        stream->data = rdp_stream = malloc(sizeof(guac_rdp_stream));
        stream->ack_handler = guac_rdp_download_ack_handler;
        rdp_stream->type = GUAC_RDP_DOWNLOAD_STREAM;
        rdp_stream->download_status.file_id = file_id;
        rdp_stream->download_status.offset = 0;

        /* Get basename from absolute path */
        i=0;
        basename = path;
        do {

            c = path[i];
            if (c == '/' || c == '\\')
                basename = &(path[i+1]);

            i++;

        } while (c != '\0');

        GUAC_RDP_DEBUG(2, "Initiating download of \"%s\"", path);

        /* Begin stream */
        guac_protocol_send_file(client->socket, stream,
                "application/octet-stream", basename);
        guac_socket_flush(client->socket);

    }
    else
        guac_client_log(client, GUAC_LOG_ERROR, "Unable to download \"%s\"", path);

}
Esempio n. 20
0
int guac_ssh_user_join_handler(guac_user* user, int argc, char** argv) {

    guac_client* client = user->client;
    guac_ssh_client* ssh_client = (guac_ssh_client*) client->data;

    /* Connect via SSH if owner */
    if (user->owner) {

        /* Parse arguments into client */
        guac_ssh_settings* settings = ssh_client->settings =
            guac_ssh_parse_args(user, argc, (const char**) argv);

        /* Fail if settings cannot be parsed */
        if (settings == NULL) {
            guac_user_log(user, GUAC_LOG_INFO,
                    "Badly formatted client arguments.");
            return 1;
        }

        /* Start client thread */
        if (pthread_create(&(ssh_client->client_thread), NULL,
                    ssh_client_thread, (void*) client)) {
            guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
                    "Unable to start SSH client thread");
            return 1;
        }

    }

    /* If not owner, synchronize with current display */
    else {
        guac_terminal_dup(ssh_client->term, user, user->socket);
        guac_socket_flush(user->socket);
    }

    /* Set per-user event handlers */
    user->key_handler       = guac_ssh_user_key_handler;
    user->mouse_handler     = guac_ssh_user_mouse_handler;
    user->size_handler      = guac_ssh_user_size_handler;
    user->clipboard_handler = guac_ssh_clipboard_handler;

    /* Set generic (non-filesystem) file upload handler */
    user->file_handler = guac_sftp_file_handler;

    return 0;

}
Esempio n. 21
0
/**
 * Clears the currently-selected region, removing the highlight.
 */
static void __guac_terminal_display_clear_select(guac_terminal_display* display) {

    guac_socket* socket = display->client->socket;
    guac_layer* select_layer = display->select_layer;

    guac_protocol_send_rect(socket, select_layer, 0, 0, 1, 1);
    guac_protocol_send_cfill(socket, GUAC_COMP_SRC, select_layer,
            0x00, 0x00, 0x00, 0x00);

    guac_client_end_frame(display->client);
    guac_socket_flush(socket);

    /* Text is no longer selected */
    display->text_selected =
    display->selection_committed = false;

}
Esempio n. 22
0
void vguac_client_abort(guac_client* client, guac_protocol_status status,
        const char* format, va_list ap) {

    /* Only relevant if client is running */
    if (client->state == GUAC_CLIENT_RUNNING) {

        /* Log detail of error */
        vguac_client_log_error(client, format, ap);

        /* Send error immediately, limit information given */
        guac_protocol_send_error(client->socket, "Aborted. See logs.", status);
        guac_socket_flush(client->socket);

        /* Stop client */
        guac_client_stop(client);

    }

}
Esempio n. 23
0
int guac_sftp_ack_handler(guac_client* client, guac_stream* stream,
        char* message, guac_protocol_status status) {

    ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data;
    LIBSSH2_SFTP_HANDLE* file = (LIBSSH2_SFTP_HANDLE*) stream->data;

    /* If successful, read data */
    if (status == GUAC_PROTOCOL_STATUS_SUCCESS) {

        /* Attempt read into buffer */
        char buffer[4096];
        int bytes_read = libssh2_sftp_read(file, buffer, sizeof(buffer)); 

        /* If bytes read, send as blob */
        if (bytes_read > 0)
            guac_protocol_send_blob(client->socket, stream,
                    buffer, bytes_read);

        /* If EOF, send end */
        else if (bytes_read == 0) {
            guac_protocol_send_end(client->socket, stream);
            guac_client_free_stream(client, stream);
        }

        /* Otherwise, fail stream */
        else {
            guac_client_log_error(client, "Error reading file: %s",
                    libssh2_sftp_last_error(client_data->sftp_session));
            guac_protocol_send_end(client->socket, stream);
            guac_client_free_stream(client, stream);
        }

        guac_socket_flush(client->socket);

    }

    /* Otherwise, return stream to client */
    else
        guac_client_free_stream(client, stream);

    return 0;
}
Esempio n. 24
0
int ssh_guac_client_size_handler(guac_client* client, int width, int height) {

    /* Get terminal */
    ssh_guac_client_data* guac_client_data = (ssh_guac_client_data*) client->data;
    guac_terminal* terminal = guac_client_data->term;

    /* Calculate dimensions */
    int rows    = height / terminal->display->char_height;
    int columns = width  / terminal->display->char_width;

    pthread_mutex_lock(&(terminal->lock));

    /* If size has changed */
    if (columns != terminal->term_width || rows != terminal->term_height) {

        /* Resize terminal */
        guac_terminal_resize(terminal, columns, rows);

        /* Update cursor */
        guac_terminal_commit_cursor(terminal);

        /* Update SSH pty size if connected */
        if (guac_client_data->term_channel != NULL)
            libssh2_channel_request_pty_size(guac_client_data->term_channel,
                    terminal->term_width, terminal->term_height);

        /* Reset scroll region */
        terminal->scroll_end = rows - 1;

        guac_terminal_display_flush(terminal->display);
        guac_protocol_send_sync(terminal->client->socket,
                client->last_sent_timestamp);
        guac_socket_flush(terminal->client->socket);
    }

    pthread_mutex_unlock(&(terminal->lock));

    return 0;
}
Esempio n. 25
0
boolean rdp_freerdp_post_connect(freerdp* instance) {

    rdpContext* context = instance->context;
    guac_client* client = ((rdp_freerdp_context*) context)->client;
    rdpChannels* channels = instance->context->channels;

    /* Init channels (post-connect) */
    if (freerdp_channels_post_connect(channels, instance)) {
        guac_protocol_send_error(client->socket, "Error initializing RDP client channel manager");
        guac_socket_flush(client->socket);
        return false;
    }

    /* Client handlers */
    client->free_handler = rdp_guac_client_free_handler;
    client->handle_messages = rdp_guac_client_handle_messages;
    client->mouse_handler = rdp_guac_client_mouse_handler;
    client->key_handler = rdp_guac_client_key_handler;
    client->clipboard_handler = rdp_guac_client_clipboard_handler;

    return true;

}
void guac_svc_process_receive(rdpSvcPlugin* plugin,
        wStream* input_stream) {

    /* Get corresponding guac_rdp_svc */
    guac_svcPlugin* svc_plugin = (guac_svcPlugin*) plugin;
    guac_rdp_svc* svc = svc_plugin->svc;

    /* Fail if output not created */
    if (svc->output_pipe == NULL) {
        guac_client_log(svc->client, GUAC_LOG_ERROR,
                "Output for channel \"%s\" dropped.",
                svc->name);
        return;
    }

    /* Send blob */
    guac_protocol_send_blob(svc->client->socket, svc->output_pipe,
            Stream_Buffer(input_stream),
            Stream_Length(input_stream));

    guac_socket_flush(svc->client->socket);

}
Esempio n. 27
0
int guac_sftp_file_handler(guac_client* client, guac_stream* stream,
        char* mimetype, char* filename) {

    ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data;
    char fullpath[GUAC_SFTP_MAX_PATH];
    LIBSSH2_SFTP_HANDLE* file;
    int i;

    /* Ensure filename is a valid filename and not a path */
    if (!__ssh_guac_valid_filename(filename)) {
        guac_protocol_send_ack(client->socket, stream, "SFTP: Illegal filename",
                GUAC_PROTOCOL_STATUS_CLIENT_BAD_REQUEST);
        guac_socket_flush(client->socket);
        return 0;
    }

    /* Copy upload path, append trailing slash */
    for (i=0; i<GUAC_SFTP_MAX_PATH; i++) {
        char c = client_data->sftp_upload_path[i];
        if (c == '\0') {
            fullpath[i++] = '/';
            break;
        }

        fullpath[i] = c;
    }

    /* Append filename */
    for (; i<GUAC_SFTP_MAX_PATH; i++) {
        char c = *(filename++);
        if (c == '\0')
            break;

        fullpath[i] = c;
    }

    /* If path + filename exceeds max length, abort */
    if (i == GUAC_SFTP_MAX_PATH) {
        guac_protocol_send_ack(client->socket, stream, "SFTP: Name too long", GUAC_PROTOCOL_STATUS_CLIENT_OVERRUN);
        guac_socket_flush(client->socket);
        return 0;
    }

    /* Terminate path string */
    fullpath[i] = '\0';

    /* Open file via SFTP */
    file = libssh2_sftp_open(client_data->sftp_session, fullpath,
            LIBSSH2_FXF_WRITE | LIBSSH2_FXF_CREAT | LIBSSH2_FXF_TRUNC,
            S_IRUSR | S_IWUSR);

    /* Inform of status */
    if (file != NULL) {
        guac_protocol_send_ack(client->socket, stream, "SFTP: File opened", GUAC_PROTOCOL_STATUS_SUCCESS);
        guac_socket_flush(client->socket);
    }
    else {
        guac_client_log_error(client, "Unable to open file \"%s\": %s",
                fullpath, libssh2_sftp_last_error(client_data->sftp_session));
        guac_protocol_send_ack(client->socket, stream, "SFTP: Open failed", GUAC_PROTOCOL_STATUS_RESOURCE_NOT_FOUND);
        guac_socket_flush(client->socket);
    }

    /* Set handlers for file stream */
    stream->blob_handler = guac_sftp_blob_handler;
    stream->end_handler = guac_sftp_end_handler;

    /* Store file within stream */
    stream->data = file;
    return 0;

}
Esempio n. 28
0
/**
 * Creates a new guac_client for the connection on the given socket, adding
 * it to the client map based on its ID.
 */
static void guacd_handle_connection(guacd_client_map* map, guac_socket* socket) {

    guac_client* client;
    guac_client_plugin* plugin;
    guac_instruction* select;
    guac_instruction* size;
    guac_instruction* audio;
    guac_instruction* video;
    guac_instruction* connect;
    int init_result;

    /* Reset guac_error */
    guac_error = GUAC_STATUS_SUCCESS;
    guac_error_message = NULL;

    /* Get protocol from select instruction */
    select = guac_instruction_expect(
            socket, GUACD_USEC_TIMEOUT, "select");
    if (select == NULL) {

        /* Log error */
        guacd_log_guac_error("Error reading \"select\"");

        /* Free resources */
        guac_socket_free(socket);
        return;
    }

    /* Validate args to select */
    if (select->argc != 1) {

        /* Log error */
        guacd_log_error("Bad number of arguments to \"select\" (%i)",
                select->argc);

        /* Free resources */
        guac_socket_free(socket);
        return;
    }

    guacd_log_info("Protocol \"%s\" selected", select->argv[0]);

    /* Get plugin from protocol in select */
    plugin = guac_client_plugin_open(select->argv[0]);
    guac_instruction_free(select);

    if (plugin == NULL) {

        /* Log error */
        guacd_log_guac_error("Error loading client plugin");

        /* Free resources */
        guac_socket_free(socket);
        return;
    }

    /* Send args response */
    if (guac_protocol_send_args(socket, plugin->args)
            || guac_socket_flush(socket)) {

        /* Log error */
        guacd_log_guac_error("Error sending \"args\"");

        if (guac_client_plugin_close(plugin))
            guacd_log_guac_error("Error closing client plugin");

        guac_socket_free(socket);
        return;
    }

    /* Get optimal screen size */
    size = guac_instruction_expect(
            socket, GUACD_USEC_TIMEOUT, "size");
    if (size == NULL) {

        /* Log error */
        guacd_log_guac_error("Error reading \"size\"");

        /* Free resources */
        guac_socket_free(socket);
        return;
    }

    /* Get supported audio formats */
    audio = guac_instruction_expect(
            socket, GUACD_USEC_TIMEOUT, "audio");
    if (audio == NULL) {

        /* Log error */
        guacd_log_guac_error("Error reading \"audio\"");

        /* Free resources */
        guac_socket_free(socket);
        return;
    }

    /* Get supported video formats */
    video = guac_instruction_expect(
            socket, GUACD_USEC_TIMEOUT, "video");
    if (video == NULL) {

        /* Log error */
        guacd_log_guac_error("Error reading \"video\"");

        /* Free resources */
        guac_socket_free(socket);
        return;
    }

    /* Get args from connect instruction */
    connect = guac_instruction_expect(
            socket, GUACD_USEC_TIMEOUT, "connect");
    if (connect == NULL) {

        /* Log error */
        guacd_log_guac_error("Error reading \"connect\"");

        if (guac_client_plugin_close(plugin))
            guacd_log_guac_error("Error closing client plugin");

        guac_socket_free(socket);
        return;
    }

    /* Get client */
    client = guac_client_alloc();
    if (client == NULL) {
        guacd_log_guac_error("Client could not be allocated");
        guac_socket_free(socket);
        return;
    }

    client->socket = socket;
    client->log_info_handler = guacd_client_log_info;
    client->log_error_handler = guacd_client_log_error;

    /* Parse optimal screen dimensions from size instruction */
    client->info.optimal_width  = atoi(size->argv[0]);
    client->info.optimal_height = atoi(size->argv[1]);

    /* If DPI given, set the client resolution */
    if (size->argc >= 3)
        client->info.optimal_resolution = atoi(size->argv[2]);

    /* Otherwise, use a safe default for rough backwards compatibility */
    else
        client->info.optimal_resolution = 96;

    /* Store audio mimetypes */
    client->info.audio_mimetypes = malloc(sizeof(char*) * (audio->argc+1));
    memcpy(client->info.audio_mimetypes, audio->argv,
            sizeof(char*) * audio->argc);
    client->info.audio_mimetypes[audio->argc] = NULL;

    /* Store video mimetypes */
    client->info.video_mimetypes = malloc(sizeof(char*) * (video->argc+1));
    memcpy(client->info.video_mimetypes, video->argv,
            sizeof(char*) * video->argc);
    client->info.video_mimetypes[video->argc] = NULL;

    /* Store client */
    if (guacd_client_map_add(map, client))
        guacd_log_error("Unable to add client. Internal client storage has failed");

    /* Send connection ID */
    guacd_log_info("Connection ID is \"%s\"", client->connection_id);
    guac_protocol_send_ready(socket, client->connection_id);

    /* Init client */
    init_result = guac_client_plugin_init_client(plugin,
                client, connect->argc, connect->argv);

    guac_instruction_free(connect);

    /* If client could not be started, free everything and fail */
    if (init_result) {

        guac_client_free(client);

        guacd_log_guac_error("Error instantiating client");

        if (guac_client_plugin_close(plugin))
            guacd_log_guac_error("Error closing client plugin");

        guac_socket_free(socket);
        return;
    }

    /* Start client threads */
    guacd_log_info("Starting client");
    if (guacd_client_start(client))
        guacd_log_error("Client finished abnormally");
    else
        guacd_log_info("Client finished normally");

    /* Remove client */
    if (guacd_client_map_remove(map, client->connection_id) == NULL)
        guacd_log_error("Unable to remove client. Internal client storage has failed");

    /* Free mimetype lists */
    free(client->info.audio_mimetypes);
    free(client->info.video_mimetypes);

    /* Free remaining instructions */
    guac_instruction_free(audio);
    guac_instruction_free(video);
    guac_instruction_free(size);

    /* Clean up */
    guac_client_free(client);
    if (guac_client_plugin_close(plugin))
        guacd_log_error("Error closing client plugin");

    /* Close socket */
    guac_socket_free(socket);

}
Esempio n. 29
0
int guac_client_init(guac_client* client, int argc, char** argv) {

    guac_socket* socket = client->socket;

    guac_telnet_client_data* client_data = malloc(sizeof(guac_telnet_client_data));

    /* Init client data */
    client->data = client_data;
    client_data->telnet = NULL;
    client_data->socket_fd = -1;
    client_data->naws_enabled = 0;
    client_data->echo_enabled = 1;

    if (argc != TELNET_ARGS_COUNT) {
        guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Wrong number of arguments");
        return -1;
    }

    /* Read parameters */
    strcpy(client_data->hostname,  argv[IDX_HOSTNAME]);

    /* Read port */
    if (argv[IDX_PORT][0] != 0)
        strcpy(client_data->port, argv[IDX_PORT]);
    else
        strcpy(client_data->port, GUAC_TELNET_DEFAULT_PORT);

    /* Read font name */
    if (argv[IDX_FONT_NAME][0] != 0)
        strcpy(client_data->font_name, argv[IDX_FONT_NAME]);
    else
        strcpy(client_data->font_name, GUAC_TELNET_DEFAULT_FONT_NAME );

    /* Read font size */
    if (argv[IDX_FONT_SIZE][0] != 0)
        client_data->font_size = atoi(argv[IDX_FONT_SIZE]);
    else
        client_data->font_size = GUAC_TELNET_DEFAULT_FONT_SIZE;

    /* Create terminal */
    client_data->term = guac_terminal_create(client,
            client_data->font_name, client_data->font_size,
            client->info.optimal_resolution,
            client->info.optimal_width, client->info.optimal_height);

    /* Fail if terminal init failed */
    if (client_data->term == NULL) {
        guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Terminal initialization failed");
        return -1;
    }

    /* Send initial name */
    guac_protocol_send_name(socket, client_data->hostname);

    guac_socket_flush(socket);

    /* Set basic handlers */
    client->handle_messages   = guac_telnet_client_handle_messages;
    client->key_handler       = guac_telnet_client_key_handler;
    client->mouse_handler     = guac_telnet_client_mouse_handler;
    client->size_handler      = guac_telnet_client_size_handler;
    client->free_handler      = guac_telnet_client_free_handler;
    client->clipboard_handler = guac_telnet_clipboard_handler;

    /* Start client thread */
    if (pthread_create(&(client_data->client_thread), NULL, guac_telnet_client_thread, (void*) client)) {
        guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Unable to start telnet client thread");
        return -1;
    }

    /* Success */
    return 0;

}
Esempio n. 30
0
void guac_rdp_client_abort(guac_client* client) {

    /*
     * NOTE: The RDP status codes translated here are documented within
     * [MS-RDPBCGR], section 2.2.5.1.1: "Set Error Info PDU Data", in the
     * description of the "errorInfo" field.
     *
     * https://msdn.microsoft.com/en-us/library/cc240544.aspx
     */

    guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
    freerdp* rdp_inst = rdp_client->rdp_inst;

    guac_protocol_status status;
    const char* message;

    /* Read disconnect reason code from connection */
    int error_info = freerdp_error_info(rdp_inst);

    /* Translate reason code into Guacamole protocol status */
    switch (error_info) {

        /* Normal disconnect */
        case 0x0: /* ERRINFO_SUCCESS */
            status = GUAC_PROTOCOL_STATUS_SUCCESS;
            message = "Disconnected.";
            break;

        /* Forced disconnect (possibly by admin) */
        case 0x1: /* ERRINFO_RPC_INITIATED_DISCONNECT */
            status = GUAC_PROTOCOL_STATUS_SESSION_CLOSED;
            message = "Forcibly disconnected.";
            break;

        /* The user was logged off (possibly by admin) */
        case 0x2: /* ERRINFO_RPC_INITIATED_LOGOFF */
            status = GUAC_PROTOCOL_STATUS_SESSION_CLOSED;
            message = "Logged off.";
            break;

        /* The user was idle long enough that the RDP server disconnected */
        case 0x3: /* ERRINFO_IDLE_TIMEOUT */
            status = GUAC_PROTOCOL_STATUS_SESSION_TIMEOUT;
            message = "Idle session time limit exceeded.";
            break;

        /* The user's session has been active for too long */
        case 0x4: /* ERRINFO_LOGON_TIMEOUT */
            status = GUAC_PROTOCOL_STATUS_SESSION_CLOSED;
            message = "Active session time limit exceeded.";
            break;

        /* Another user logged on, disconnecting this user */
        case 0x5: /* ERRINFO_DISCONNECTED_BY_OTHER_CONNECTION */
            status = GUAC_PROTOCOL_STATUS_SESSION_CONFLICT;
            message = "Disconnected by other connection.";
            break;

        /* The RDP server is refusing to service the connection */
        case 0x6: /* ERRINFO_OUT_OF_MEMORY */
        case 0x7: /* ERRINFO_SERVER_DENIED_CONNECTION */
            status = GUAC_PROTOCOL_STATUS_UPSTREAM_UNAVAILABLE;
            message = "Server refused connection.";
            break;

        /* The user does not have permission to connect */
        case 0x9: /* ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES */
            status = GUAC_PROTOCOL_STATUS_CLIENT_FORBIDDEN;
            message = "Insufficient privileges.";
            break;

        /* The user's credentials have expired */
        case 0xA: /* ERRINFO_SERVER_FRESH_CREDENTIALS_REQUIRED */
            status = GUAC_PROTOCOL_STATUS_CLIENT_FORBIDDEN;
            message = "Credentials expired.";
            break;

        /* The user manually disconnected using an administrative tool within
         * the session */
        case 0xB: /* ERRINFO_RPC_INITIATED_DISCONNECT_BYUSER */
            status = GUAC_PROTOCOL_STATUS_SUCCESS;
            message = "Manually disconnected.";
            break;

        /* The user manually logged off */
        case 0xC: /* ERRINFO_LOGOFF_BY_USER */
            status = GUAC_PROTOCOL_STATUS_SUCCESS;
            message = "Manually logged off.";
            break;

        /* Unimplemented/unknown disconnect reason code */
        default:
            status = GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR;
            message = "Upstream error.";

    }

    /* Send error code if an error occurred */
    if (status != GUAC_PROTOCOL_STATUS_SUCCESS) {
        guac_protocol_send_error(client->socket, message, status);
        guac_socket_flush(client->socket);
    }

    /* Log human-readable description of disconnect at info level */
    guac_client_log(client, GUAC_LOG_INFO, "RDP server closed connection: %s",
            message);

    /* Log internal disconnect reason code at debug level */
    if (error_info)
        guac_client_log(client, GUAC_LOG_DEBUG, "Disconnect reason "
                "code: 0x%X.", error_info);

    /* Abort connection */
    guac_client_stop(client);

}