Repository: incubator-guacamole-server Updated Branches: refs/heads/staging/0.9.12-incubating a808a6b17 -> 3ff832315
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d371f2d9/src/common-ssh/guac_ssh_buffer.c ---------------------------------------------------------------------- diff --git a/src/common-ssh/guac_ssh_buffer.c b/src/common-ssh/guac_ssh_buffer.c deleted file mode 100644 index b3d8d57..0000000 --- a/src/common-ssh/guac_ssh_buffer.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "config.h" - -#include <openssl/bn.h> -#include <openssl/ossl_typ.h> - -#include <stdint.h> -#include <string.h> -#include <stdlib.h> - -void guac_common_ssh_buffer_write_byte(char** buffer, uint8_t value) { - - uint8_t* data = (uint8_t*) *buffer; - *data = value; - - (*buffer)++; - -} - -void guac_common_ssh_buffer_write_uint32(char** buffer, uint32_t value) { - - uint8_t* data = (uint8_t*) *buffer; - - data[0] = (value & 0xFF000000) >> 24; - data[1] = (value & 0x00FF0000) >> 16; - data[2] = (value & 0x0000FF00) >> 8; - data[3] = value & 0x000000FF; - - *buffer += 4; - -} - -void guac_common_ssh_buffer_write_data(char** buffer, const char* data, - int length) { - memcpy(*buffer, data, length); - *buffer += length; -} - -void guac_common_ssh_buffer_write_bignum(char** buffer, BIGNUM* value) { - - unsigned char* bn_buffer; - int length; - - /* If zero, just write zero length */ - if (BN_is_zero(value)) { - guac_common_ssh_buffer_write_uint32(buffer, 0); - return; - } - - /* Allocate output buffer, add padding byte */ - length = BN_num_bytes(value); - bn_buffer = malloc(length); - - /* Convert BIGNUM */ - BN_bn2bin(value, bn_buffer); - - /* If first byte has high bit set, write padding byte */ - if (bn_buffer[0] & 0x80) { - guac_common_ssh_buffer_write_uint32(buffer, length+1); - guac_common_ssh_buffer_write_byte(buffer, 0); - } - else - guac_common_ssh_buffer_write_uint32(buffer, length); - - /* Write data */ - memcpy(*buffer, bn_buffer, length); - *buffer += length; - - free(bn_buffer); - -} - -void guac_common_ssh_buffer_write_string(char** buffer, const char* string, - int length) { - guac_common_ssh_buffer_write_uint32(buffer, length); - guac_common_ssh_buffer_write_data(buffer, string, length); -} - -uint8_t guac_common_ssh_buffer_read_byte(char** buffer) { - - uint8_t* data = (uint8_t*) *buffer; - uint8_t value = *data; - - (*buffer)++; - - return value; - -} - -uint32_t guac_common_ssh_buffer_read_uint32(char** buffer) { - - uint8_t* data = (uint8_t*) *buffer; - uint32_t value = - (data[0] << 24) - | (data[1] << 16) - | (data[2] << 8) - | data[3]; - - *buffer += 4; - - return value; - -} - -char* guac_common_ssh_buffer_read_string(char** buffer, int* length) { - - char* value; - - *length = guac_common_ssh_buffer_read_uint32(buffer); - value = *buffer; - - *buffer += *length; - - return value; - -} - http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d371f2d9/src/common-ssh/guac_ssh_buffer.h ---------------------------------------------------------------------- diff --git a/src/common-ssh/guac_ssh_buffer.h b/src/common-ssh/guac_ssh_buffer.h deleted file mode 100644 index b42a2ac..0000000 --- a/src/common-ssh/guac_ssh_buffer.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef GUAC_COMMON_SSH_BUFFER_H -#define GUAC_COMMON_SSH_BUFFER_H - -#include "config.h" - -#include <openssl/bn.h> -#include <stdint.h> - -/** - * Writes the given byte to the given buffer, advancing the buffer pointer by - * one byte. - * - * @param buffer - * The buffer to write to. - * - * @param value - * The value to write. - */ -void guac_common_ssh_buffer_write_byte(char** buffer, uint8_t value); - -/** - * Writes the given integer to the given buffer, advancing the buffer pointer - * four bytes. - * - * @param buffer - * The buffer to write to. - * - * @param value - * The value to write. - */ -void guac_common_ssh_buffer_write_uint32(char** buffer, uint32_t value); - -/** - * Writes the given string and its length to the given buffer, advancing the - * buffer pointer by the size of the length (four bytes) and the size of the - * string. - * - * @param buffer - * The buffer to write to. - * - * @param string - * The string value to write. - * - * @param length - * The length of the string to write, in bytes. - */ -void guac_common_ssh_buffer_write_string(char** buffer, const char* string, - int length); - -/** - * Writes the given BIGNUM the given buffer, advancing the buffer pointer by - * the size of the length (four bytes) and the size of the BIGNUM. - * - * @param buffer - * The buffer to write to. - * - * @param value - * The value to write. - */ -void guac_common_ssh_buffer_write_bignum(char** buffer, BIGNUM* value); - -/** - * Writes the given data the given buffer, advancing the buffer pointer by the - * given length. - * - * @param data - * The arbitrary data to write. - * - * @param length - * The length of data to write, in bytes. - */ -void guac_common_ssh_buffer_write_data(char** buffer, const char* data, int length); - -/** - * Reads a single byte from the given buffer, advancing the buffer by one byte. - * - * @param buffer - * The buffer to read from. - * - * @return - * The value read from the buffer. - */ -uint8_t guac_common_ssh_buffer_read_byte(char** buffer); - -/** - * Reads an integer from the given buffer, advancing the buffer by four bytes. - * - * @param buffer - * The buffer to read from. - * - * @return - * The value read from the buffer. - */ -uint32_t guac_common_ssh_buffer_read_uint32(char** buffer); - -/** - * Reads a string and its length from the given buffer, advancing the buffer - * by the size of the length (four bytes) and the size of the string, and - * returning a pointer to the buffer. The length of the string is stored in - * the given int. - * - * @param buffer - * The buffer to read from. - * - * @param length - * A pointer to an integer into which the length of the read string will - * be stored. - * - * @return - * A pointer to the value within the buffer. - */ -char* guac_common_ssh_buffer_read_string(char** buffer, int* length); - -#endif - http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d371f2d9/src/common-ssh/guac_ssh_key.c ---------------------------------------------------------------------- diff --git a/src/common-ssh/guac_ssh_key.c b/src/common-ssh/guac_ssh_key.c deleted file mode 100644 index 7594b84..0000000 --- a/src/common-ssh/guac_ssh_key.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "config.h" - -#include "guac_ssh_buffer.h" -#include "guac_ssh_key.h" - -#include <openssl/bio.h> -#include <openssl/bn.h> -#include <openssl/dsa.h> -#include <openssl/err.h> -#include <openssl/evp.h> -#include <openssl/obj_mac.h> -#include <openssl/pem.h> -#include <openssl/rsa.h> - -#include <stdlib.h> -#include <string.h> - -guac_common_ssh_key* guac_common_ssh_key_alloc(char* data, int length, - char* passphrase) { - - guac_common_ssh_key* key; - BIO* key_bio; - - char* public_key; - char* pos; - - /* Create BIO for reading key from memory */ - key_bio = BIO_new_mem_buf(data, length); - - /* If RSA key, load RSA */ - if (length > sizeof(SSH_RSA_KEY_HEADER)-1 - && memcmp(SSH_RSA_KEY_HEADER, data, - sizeof(SSH_RSA_KEY_HEADER)-1) == 0) { - - RSA* rsa_key; - - /* Read key */ - rsa_key = PEM_read_bio_RSAPrivateKey(key_bio, NULL, NULL, passphrase); - if (rsa_key == NULL) - return NULL; - - /* Allocate key */ - key = malloc(sizeof(guac_common_ssh_key)); - key->rsa = rsa_key; - - /* Set type */ - key->type = SSH_KEY_RSA; - - /* Allocate space for public key */ - public_key = malloc(4096); - pos = public_key; - - /* Derive public key */ - guac_common_ssh_buffer_write_string(&pos, "ssh-rsa", sizeof("ssh-rsa")-1); - guac_common_ssh_buffer_write_bignum(&pos, rsa_key->e); - guac_common_ssh_buffer_write_bignum(&pos, rsa_key->n); - - /* Save public key to structure */ - key->public_key = public_key; - key->public_key_length = pos - public_key; - - } - - /* If DSA key, load DSA */ - else if (length > sizeof(SSH_DSA_KEY_HEADER)-1 - && memcmp(SSH_DSA_KEY_HEADER, data, - sizeof(SSH_DSA_KEY_HEADER)-1) == 0) { - - DSA* dsa_key; - - /* Read key */ - dsa_key = PEM_read_bio_DSAPrivateKey(key_bio, NULL, NULL, passphrase); - if (dsa_key == NULL) - return NULL; - - /* Allocate key */ - key = malloc(sizeof(guac_common_ssh_key)); - key->dsa = dsa_key; - - /* Set type */ - key->type = SSH_KEY_DSA; - - /* Allocate space for public key */ - public_key = malloc(4096); - pos = public_key; - - /* Derive public key */ - guac_common_ssh_buffer_write_string(&pos, "ssh-dss", sizeof("ssh-dss")-1); - guac_common_ssh_buffer_write_bignum(&pos, dsa_key->p); - guac_common_ssh_buffer_write_bignum(&pos, dsa_key->q); - guac_common_ssh_buffer_write_bignum(&pos, dsa_key->g); - guac_common_ssh_buffer_write_bignum(&pos, dsa_key->pub_key); - - /* Save public key to structure */ - key->public_key = public_key; - key->public_key_length = pos - public_key; - - } - - /* Otherwise, unsupported type */ - else { - BIO_free(key_bio); - return NULL; - } - - /* Copy private key to structure */ - key->private_key_length = length; - key->private_key = malloc(length); - memcpy(key->private_key, data, length); - - BIO_free(key_bio); - return key; - -} - -const char* guac_common_ssh_key_error() { - - /* Return static error string */ - return ERR_reason_error_string(ERR_get_error()); - -} - -void guac_common_ssh_key_free(guac_common_ssh_key* key) { - - /* Free key-specific data */ - if (key->type == SSH_KEY_RSA) - RSA_free(key->rsa); - else if (key->type == SSH_KEY_DSA) - DSA_free(key->dsa); - - free(key->private_key); - free(key->public_key); - free(key); -} - -int guac_common_ssh_key_sign(guac_common_ssh_key* key, const char* data, - int length, unsigned char* sig) { - - const EVP_MD* md; - EVP_MD_CTX md_ctx; - - unsigned char digest[EVP_MAX_MD_SIZE]; - unsigned int dlen, len; - - /* Get SHA1 digest */ - if ((md = EVP_get_digestbynid(NID_sha1)) == NULL) - return -1; - - /* Digest data */ - EVP_DigestInit(&md_ctx, md); - EVP_DigestUpdate(&md_ctx, data, length); - EVP_DigestFinal(&md_ctx, digest, &dlen); - - /* Sign with key */ - switch (key->type) { - - case SSH_KEY_RSA: - if (RSA_sign(NID_sha1, digest, dlen, sig, &len, key->rsa) == 1) - return len; - break; - - case SSH_KEY_DSA: { - - DSA_SIG* dsa_sig = DSA_do_sign(digest, dlen, key->dsa); - if (dsa_sig != NULL) { - - /* Compute size of each half of signature */ - int rlen = BN_num_bytes(dsa_sig->r); - int slen = BN_num_bytes(dsa_sig->s); - - /* Ensure each number is within the required size */ - if (rlen > DSA_SIG_NUMBER_SIZE || slen > DSA_SIG_NUMBER_SIZE) - return -1; - - /* Init to all zeroes */ - memset(sig, 0, DSA_SIG_SIZE); - - /* Add R at the end of the first block of the signature */ - BN_bn2bin(dsa_sig->r, sig + DSA_SIG_SIZE - - DSA_SIG_NUMBER_SIZE - rlen); - - /* Add S at the end of the second block of the signature */ - BN_bn2bin(dsa_sig->s, sig + DSA_SIG_SIZE - slen); - - /* Done */ - DSA_SIG_free(dsa_sig); - return DSA_SIG_SIZE; - - } - - } - - } - - return -1; - -} - http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d371f2d9/src/common-ssh/guac_ssh_key.h ---------------------------------------------------------------------- diff --git a/src/common-ssh/guac_ssh_key.h b/src/common-ssh/guac_ssh_key.h deleted file mode 100644 index 1754dea..0000000 --- a/src/common-ssh/guac_ssh_key.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef GUAC_COMMON_SSH_KEY_H -#define GUAC_COMMON_SSH_KEY_H - -#include "config.h" - -#include <openssl/ossl_typ.h> - -/** - * The expected header of RSA private keys. - */ -#define SSH_RSA_KEY_HEADER "-----BEGIN RSA PRIVATE KEY-----" - -/** - * The expected header of DSA private keys. - */ -#define SSH_DSA_KEY_HEADER "-----BEGIN DSA PRIVATE KEY-----" - -/** - * The size of single number within a DSA signature, in bytes. - */ -#define DSA_SIG_NUMBER_SIZE 20 - -/** - * The size of a DSA signature, in bytes. - */ -#define DSA_SIG_SIZE DSA_SIG_NUMBER_SIZE*2 - -/** - * The type of an SSH key. - */ -typedef enum guac_common_ssh_key_type { - - /** - * RSA key. - */ - SSH_KEY_RSA, - - /** - * DSA key. - */ - SSH_KEY_DSA - -} guac_common_ssh_key_type; - -/** - * Abstraction of a key used for SSH authentication. - */ -typedef struct guac_common_ssh_key { - - /** - * The type of this key. - */ - guac_common_ssh_key_type type; - - /** - * Underlying RSA private key, if any. - */ - RSA* rsa; - - /** - * Underlying DSA private key, if any. - */ - DSA* dsa; - - /** - * The associated public key, encoded as necessary for SSH. - */ - char* public_key; - - /** - * The length of the public key, in bytes. - */ - int public_key_length; - - /** - * The private key, encoded as necessary for SSH. - */ - char* private_key; - - /** - * The length of the private key, in bytes. - */ - int private_key_length; - -} guac_common_ssh_key; - -/** - * Allocates a new key containing the given private key data and specified - * passphrase. If unable to read the key, NULL is returned. - * - * @param data - * The base64-encoded data to decode when reading the key. - * - * @param length - * The length of the provided data, in bytes. - * - * @param passphrase - * The passphrase to use when decrypting the key, if any, or an empty - * string or NULL if no passphrase is needed. - * - * @return - * The decoded, decrypted private key, or NULL if the key could not be - * decoded. - */ -guac_common_ssh_key* guac_common_ssh_key_alloc(char* data, int length, - char* passphrase); - -/** - * Returns a statically-allocated string describing the most recent SSH key - * error. - * - * @return - * A statically-allocated string describing the most recent SSH key error. - */ -const char* guac_common_ssh_key_error(); - -/** - * Frees all memory associated with the given key. - * - * @param key - * The key to free. - */ -void guac_common_ssh_key_free(guac_common_ssh_key* key); - -/** - * Signs the given data using the given key, returning the length of the - * signature in bytes, or a value less than zero on error. - * - * @param key - * The key to use when signing the given data. - * - * @param data - * The arbitrary data to sign. - * - * @param length - * The length of the arbitrary data being signed, in bytes. - * - * @param sig - * The buffer into which the signature should be written. The buffer must - * be at least DSA_SIG_SIZE for DSA keys. For RSA keys, the signature size - * is dependent only on key size, and is equal to the length of the - * modulus, in bytes. - * - * @return - * The number of bytes in the resulting signature. - */ -int guac_common_ssh_key_sign(guac_common_ssh_key* key, const char* data, - int length, unsigned char* sig); - -#endif - http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d371f2d9/src/common-ssh/guac_ssh_user.c ---------------------------------------------------------------------- diff --git a/src/common-ssh/guac_ssh_user.c b/src/common-ssh/guac_ssh_user.c deleted file mode 100644 index 73319c0..0000000 --- a/src/common-ssh/guac_ssh_user.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "guac_ssh_key.h" -#include "guac_ssh_user.h" - -#include <stdlib.h> -#include <string.h> - -guac_common_ssh_user* guac_common_ssh_create_user(const char* username) { - - guac_common_ssh_user* user = malloc(sizeof(guac_common_ssh_user)); - - /* Init user */ - user->username = strdup(username); - user->password = NULL; - user->private_key = NULL; - - return user; - -} - -void guac_common_ssh_destroy_user(guac_common_ssh_user* user) { - - /* Free private key, if present */ - if (user->private_key != NULL) - guac_common_ssh_key_free(user->private_key); - - /* Free all other data */ - free(user->password); - free(user->username); - free(user); - -} - -void guac_common_ssh_user_set_password(guac_common_ssh_user* user, - const char* password) { - - /* Replace current password with given value */ - free(user->password); - user->password = strdup(password); - -} - -int guac_common_ssh_user_import_key(guac_common_ssh_user* user, - char* private_key, char* passphrase) { - - /* Free existing private key, if present */ - if (user->private_key != NULL) - guac_common_ssh_key_free(user->private_key); - - /* Attempt to read key without passphrase if none given */ - if (passphrase == NULL) - user->private_key = guac_common_ssh_key_alloc(private_key, - strlen(private_key), ""); - - /* Otherwise, use provided passphrase */ - else - user->private_key = guac_common_ssh_key_alloc(private_key, - strlen(private_key), passphrase); - - /* Fail if key could not be read */ - return user->private_key == NULL; - -} - http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d371f2d9/src/common-ssh/guac_ssh_user.h ---------------------------------------------------------------------- diff --git a/src/common-ssh/guac_ssh_user.h b/src/common-ssh/guac_ssh_user.h deleted file mode 100644 index eeaa460..0000000 --- a/src/common-ssh/guac_ssh_user.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef GUAC_COMMON_SSH_USER_H -#define GUAC_COMMON_SSH_USER_H - -#include "guac_ssh_key.h" - -/** - * Data describing an SSH user, including their credentials. - */ -typedef struct guac_common_ssh_user { - - /** - * The username of this user. - */ - char* username; - - /** - * The password which should be used to authenticate this user, if any, or - * NULL if a private key will be used instead. - */ - char* password; - - /** - * The private key which should be used to authenticate this user, if any, - * or NULL if a password will be used instead. - */ - guac_common_ssh_key* private_key; - -} guac_common_ssh_user; - -/** - * Creates a new SSH user with the given username. When additionally populated - * with a password or private key, this user can then be used for - * authentication. - * - * @param username - * The username of the user being created. - * - * @return - * A new SSH user having the given username, but no associated password - * or private key. - */ -guac_common_ssh_user* guac_common_ssh_create_user(const char* username); - -/** - * Destroys the given user object, releasing all associated resources. - * - * @param user - * The user to destroy. - */ -void guac_common_ssh_destroy_user(guac_common_ssh_user* user); - -/** - * Associates the given user with the given password, such that that password - * is used for future authentication attempts. - * - * @param user - * The user to associate with the given password. - * - * @param password - * The password to associate with the given user. - */ -void guac_common_ssh_user_set_password(guac_common_ssh_user* user, - const char* password); - -/** - * Imports the given private key, associating that key with the given user. If - * necessary to decrypt the key, a passphrase may be specified. The private key - * must be provided in base64 form. If the private key is imported - * successfully, it will be used for future authentication attempts. - * - * @param user - * The user to associate with the given private key. - * - * @param private_key - * The base64-encoded private key to import. - * - * @param passphrase - * The passphrase to use to decrypt the given private key, or NULL if no - * passphrase should be used. - * - * @return - * Zero if the private key is successfully imported, or non-zero if the - * private key could not be imported due to an error. - */ -int guac_common_ssh_user_import_key(guac_common_ssh_user* user, - char* private_key, char* passphrase); - -#endif - http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d371f2d9/src/common-ssh/key.c ---------------------------------------------------------------------- diff --git a/src/common-ssh/key.c b/src/common-ssh/key.c new file mode 100644 index 0000000..82a3252 --- /dev/null +++ b/src/common-ssh/key.c @@ -0,0 +1,217 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "config.h" + +#include "common-ssh/buffer.h" +#include "common-ssh/key.h" + +#include <openssl/bio.h> +#include <openssl/bn.h> +#include <openssl/dsa.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/obj_mac.h> +#include <openssl/pem.h> +#include <openssl/rsa.h> + +#include <stdlib.h> +#include <string.h> + +guac_common_ssh_key* guac_common_ssh_key_alloc(char* data, int length, + char* passphrase) { + + guac_common_ssh_key* key; + BIO* key_bio; + + char* public_key; + char* pos; + + /* Create BIO for reading key from memory */ + key_bio = BIO_new_mem_buf(data, length); + + /* If RSA key, load RSA */ + if (length > sizeof(SSH_RSA_KEY_HEADER)-1 + && memcmp(SSH_RSA_KEY_HEADER, data, + sizeof(SSH_RSA_KEY_HEADER)-1) == 0) { + + RSA* rsa_key; + + /* Read key */ + rsa_key = PEM_read_bio_RSAPrivateKey(key_bio, NULL, NULL, passphrase); + if (rsa_key == NULL) + return NULL; + + /* Allocate key */ + key = malloc(sizeof(guac_common_ssh_key)); + key->rsa = rsa_key; + + /* Set type */ + key->type = SSH_KEY_RSA; + + /* Allocate space for public key */ + public_key = malloc(4096); + pos = public_key; + + /* Derive public key */ + guac_common_ssh_buffer_write_string(&pos, "ssh-rsa", sizeof("ssh-rsa")-1); + guac_common_ssh_buffer_write_bignum(&pos, rsa_key->e); + guac_common_ssh_buffer_write_bignum(&pos, rsa_key->n); + + /* Save public key to structure */ + key->public_key = public_key; + key->public_key_length = pos - public_key; + + } + + /* If DSA key, load DSA */ + else if (length > sizeof(SSH_DSA_KEY_HEADER)-1 + && memcmp(SSH_DSA_KEY_HEADER, data, + sizeof(SSH_DSA_KEY_HEADER)-1) == 0) { + + DSA* dsa_key; + + /* Read key */ + dsa_key = PEM_read_bio_DSAPrivateKey(key_bio, NULL, NULL, passphrase); + if (dsa_key == NULL) + return NULL; + + /* Allocate key */ + key = malloc(sizeof(guac_common_ssh_key)); + key->dsa = dsa_key; + + /* Set type */ + key->type = SSH_KEY_DSA; + + /* Allocate space for public key */ + public_key = malloc(4096); + pos = public_key; + + /* Derive public key */ + guac_common_ssh_buffer_write_string(&pos, "ssh-dss", sizeof("ssh-dss")-1); + guac_common_ssh_buffer_write_bignum(&pos, dsa_key->p); + guac_common_ssh_buffer_write_bignum(&pos, dsa_key->q); + guac_common_ssh_buffer_write_bignum(&pos, dsa_key->g); + guac_common_ssh_buffer_write_bignum(&pos, dsa_key->pub_key); + + /* Save public key to structure */ + key->public_key = public_key; + key->public_key_length = pos - public_key; + + } + + /* Otherwise, unsupported type */ + else { + BIO_free(key_bio); + return NULL; + } + + /* Copy private key to structure */ + key->private_key_length = length; + key->private_key = malloc(length); + memcpy(key->private_key, data, length); + + BIO_free(key_bio); + return key; + +} + +const char* guac_common_ssh_key_error() { + + /* Return static error string */ + return ERR_reason_error_string(ERR_get_error()); + +} + +void guac_common_ssh_key_free(guac_common_ssh_key* key) { + + /* Free key-specific data */ + if (key->type == SSH_KEY_RSA) + RSA_free(key->rsa); + else if (key->type == SSH_KEY_DSA) + DSA_free(key->dsa); + + free(key->private_key); + free(key->public_key); + free(key); +} + +int guac_common_ssh_key_sign(guac_common_ssh_key* key, const char* data, + int length, unsigned char* sig) { + + const EVP_MD* md; + EVP_MD_CTX md_ctx; + + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int dlen, len; + + /* Get SHA1 digest */ + if ((md = EVP_get_digestbynid(NID_sha1)) == NULL) + return -1; + + /* Digest data */ + EVP_DigestInit(&md_ctx, md); + EVP_DigestUpdate(&md_ctx, data, length); + EVP_DigestFinal(&md_ctx, digest, &dlen); + + /* Sign with key */ + switch (key->type) { + + case SSH_KEY_RSA: + if (RSA_sign(NID_sha1, digest, dlen, sig, &len, key->rsa) == 1) + return len; + break; + + case SSH_KEY_DSA: { + + DSA_SIG* dsa_sig = DSA_do_sign(digest, dlen, key->dsa); + if (dsa_sig != NULL) { + + /* Compute size of each half of signature */ + int rlen = BN_num_bytes(dsa_sig->r); + int slen = BN_num_bytes(dsa_sig->s); + + /* Ensure each number is within the required size */ + if (rlen > DSA_SIG_NUMBER_SIZE || slen > DSA_SIG_NUMBER_SIZE) + return -1; + + /* Init to all zeroes */ + memset(sig, 0, DSA_SIG_SIZE); + + /* Add R at the end of the first block of the signature */ + BN_bn2bin(dsa_sig->r, sig + DSA_SIG_SIZE + - DSA_SIG_NUMBER_SIZE - rlen); + + /* Add S at the end of the second block of the signature */ + BN_bn2bin(dsa_sig->s, sig + DSA_SIG_SIZE - slen); + + /* Done */ + DSA_SIG_free(dsa_sig); + return DSA_SIG_SIZE; + + } + + } + + } + + return -1; + +} + http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d371f2d9/src/common-ssh/sftp.c ---------------------------------------------------------------------- diff --git a/src/common-ssh/sftp.c b/src/common-ssh/sftp.c new file mode 100644 index 0000000..79db35e --- /dev/null +++ b/src/common-ssh/sftp.c @@ -0,0 +1,783 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "common-ssh/sftp.h" +#include "common-ssh/ssh.h" + +#include <guacamole/client.h> +#include <guacamole/object.h> +#include <guacamole/protocol.h> +#include <guacamole/socket.h> +#include <guacamole/user.h> +#include <libssh2.h> + +#include <fcntl.h> +#include <libgen.h> +#include <stdlib.h> +#include <string.h> + +/** + * Translates the last error message received by the SFTP layer of an SSH + * session into a Guacamole protocol status code. + * + * @param filesystem + * The object (not guac_object) defining the filesystem associated with the + * SFTP and SSH sessions. + * + * @return + * The Guacamole protocol status code corresponding to the last reported + * error of the SFTP layer, if nay, or GUAC_PROTOCOL_STATUS_SUCCESS if no + * error has occurred. + */ +static guac_protocol_status guac_sftp_get_status( + guac_common_ssh_sftp_filesystem* filesystem) { + + /* Get libssh2 objects */ + LIBSSH2_SFTP* sftp = filesystem->sftp_session; + LIBSSH2_SESSION* session = filesystem->ssh_session->session; + + /* Return success code if no error occurred */ + if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_SFTP_PROTOCOL) + return GUAC_PROTOCOL_STATUS_SUCCESS; + + /* Translate SFTP error codes defined by + * https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02 (the most + * commonly-implemented standard) */ + switch (libssh2_sftp_last_error(sftp)) { + + /* SSH_FX_OK (not an error) */ + case 0: + return GUAC_PROTOCOL_STATUS_SUCCESS; + + /* SSH_FX_EOF (technically not an error) */ + case 1: + return GUAC_PROTOCOL_STATUS_SUCCESS; + + /* SSH_FX_NO_SUCH_FILE */ + case 2: + return GUAC_PROTOCOL_STATUS_RESOURCE_NOT_FOUND; + + /* SSH_FX_PERMISSION_DENIED */ + case 3: + return GUAC_PROTOCOL_STATUS_CLIENT_FORBIDDEN; + + /* SSH_FX_FAILURE */ + case 4: + return GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR; + + /* SSH_FX_BAD_MESSAGE */ + case 5: + return GUAC_PROTOCOL_STATUS_SERVER_ERROR; + + /* SSH_FX_NO_CONNECTION / SSH_FX_CONNECTION_LOST */ + case 6: + case 7: + return GUAC_PROTOCOL_STATUS_UPSTREAM_TIMEOUT; + + /* SSH_FX_OP_UNSUPPORTED */ + case 8: + return GUAC_PROTOCOL_STATUS_UNSUPPORTED; + + /* Return generic error if cause unknown */ + default: + return GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR; + + } + +} + +/** + * Concatenates the given filename with the given path, separating the two + * with a single forward slash. The full result must be no more than + * GUAC_COMMON_SSH_SFTP_MAX_PATH bytes long, counting null terminator. + * + * @param fullpath + * The buffer to store the result within. This buffer must be at least + * GUAC_COMMON_SSH_SFTP_MAX_PATH bytes long. + * + * @param path + * The path to append the filename to. + * + * @param filename + * The filename to append to the path. + * + * @return + * Non-zero if the filename is valid and was successfully appended to the + * path, zero otherwise. + */ +static int guac_ssh_append_filename(char* fullpath, const char* path, + const char* filename) { + + int i; + + /* Disallow "." as a filename */ + if (strcmp(filename, ".") == 0) + return 0; + + /* Disallow ".." as a filename */ + if (strcmp(filename, "..") == 0) + return 0; + + /* Copy path, append trailing slash */ + for (i=0; i<GUAC_COMMON_SSH_SFTP_MAX_PATH; i++) { + + /* + * Append trailing slash only if: + * 1) Trailing slash is not already present + * 2) Path is non-empty + */ + + char c = path[i]; + if (c == '\0') { + if (i > 0 && path[i-1] != '/') + fullpath[i++] = '/'; + break; + } + + /* Copy character if not end of string */ + fullpath[i] = c; + + } + + /* Append filename */ + for (; i<GUAC_COMMON_SSH_SFTP_MAX_PATH; i++) { + + char c = *(filename++); + if (c == '\0') + break; + + /* Filenames may not contain slashes */ + if (c == '\\' || c == '/') + return 0; + + /* Append each character within filename */ + fullpath[i] = c; + + } + + /* Verify path length is within maximum */ + if (i == GUAC_COMMON_SSH_SFTP_MAX_PATH) + return 0; + + /* Terminate path string */ + fullpath[i] = '\0'; + + /* Append was successful */ + return 1; + +} + +/** + * Handler for blob messages which continue an inbound SFTP data transfer + * (upload). The data associated with the given stream is expected to be a + * pointer to an open LIBSSH2_SFTP_HANDLE for the file to which the data + * should be written. + * + * @param user + * The user receiving the blob message. + * + * @param stream + * The Guacamole protocol stream associated with the received blob message. + * + * @param data + * The data received within the blob. + * + * @param length + * The length of the received data, in bytes. + * + * @return + * Zero if the blob is handled successfully, or non-zero on error. + */ +static int guac_common_ssh_sftp_blob_handler(guac_user* user, + guac_stream* stream, void* data, int length) { + + /* Pull file from stream */ + LIBSSH2_SFTP_HANDLE* file = (LIBSSH2_SFTP_HANDLE*) stream->data; + + /* Attempt write */ + if (libssh2_sftp_write(file, data, length) == length) { + guac_user_log(user, GUAC_LOG_DEBUG, "%i bytes written", length); + guac_protocol_send_ack(user->socket, stream, "SFTP: OK", + GUAC_PROTOCOL_STATUS_SUCCESS); + guac_socket_flush(user->socket); + } + + /* Inform of any errors */ + else { + guac_user_log(user, GUAC_LOG_INFO, "Unable to write to file"); + guac_protocol_send_ack(user->socket, stream, "SFTP: Write failed", + GUAC_PROTOCOL_STATUS_SERVER_ERROR); + guac_socket_flush(user->socket); + } + + return 0; + +} + +/** + * Handler for end messages which terminate an inbound SFTP data transfer + * (upload). The data associated with the given stream is expected to be a + * pointer to an open LIBSSH2_SFTP_HANDLE for the file to which the data + * has been written and which should now be closed. + * + * @param user + * The user receiving the end message. + * + * @param stream + * The Guacamole protocol stream associated with the received end message. + * + * @return + * Zero if the file is closed successfully, or non-zero on error. + */ +static int guac_common_ssh_sftp_end_handler(guac_user* user, + 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_user_log(user, GUAC_LOG_DEBUG, "File closed"); + guac_protocol_send_ack(user->socket, stream, "SFTP: OK", + GUAC_PROTOCOL_STATUS_SUCCESS); + guac_socket_flush(user->socket); + } + else { + guac_user_log(user, GUAC_LOG_INFO, "Unable to close file"); + guac_protocol_send_ack(user->socket, stream, "SFTP: Close failed", + GUAC_PROTOCOL_STATUS_SERVER_ERROR); + guac_socket_flush(user->socket); + } + + return 0; + +} + +int guac_common_ssh_sftp_handle_file_stream( + guac_common_ssh_sftp_filesystem* filesystem, guac_user* user, + guac_stream* stream, char* mimetype, char* filename) { + + char fullpath[GUAC_COMMON_SSH_SFTP_MAX_PATH]; + LIBSSH2_SFTP_HANDLE* file; + + /* Concatenate filename with path */ + if (!guac_ssh_append_filename(fullpath, filesystem->upload_path, + filename)) { + + guac_user_log(user, GUAC_LOG_DEBUG, + "Filename \"%s\" is invalid or resulting path is too long", + filename); + + /* Abort transfer - invalid filename */ + guac_protocol_send_ack(user->socket, stream, + "SFTP: Illegal filename", + GUAC_PROTOCOL_STATUS_CLIENT_BAD_REQUEST); + + guac_socket_flush(user->socket); + return 0; + } + + /* Open file via SFTP */ + file = libssh2_sftp_open(filesystem->sftp_session, fullpath, + LIBSSH2_FXF_WRITE | LIBSSH2_FXF_CREAT | LIBSSH2_FXF_TRUNC, + S_IRUSR | S_IWUSR); + + /* Inform of status */ + if (file != NULL) { + + guac_user_log(user, GUAC_LOG_DEBUG, + "File \"%s\" opened", + fullpath); + + guac_protocol_send_ack(user->socket, stream, "SFTP: File opened", + GUAC_PROTOCOL_STATUS_SUCCESS); + guac_socket_flush(user->socket); + } + else { + guac_user_log(user, GUAC_LOG_INFO, + "Unable to open file \"%s\"", fullpath); + guac_protocol_send_ack(user->socket, stream, "SFTP: Open failed", + guac_sftp_get_status(filesystem)); + guac_socket_flush(user->socket); + } + + /* Set handlers for file stream */ + stream->blob_handler = guac_common_ssh_sftp_blob_handler; + stream->end_handler = guac_common_ssh_sftp_end_handler; + + /* Store file within stream */ + stream->data = file; + return 0; + +} + +/** + * Handler for ack messages which continue an outbound SFTP data transfer + * (download), signalling the current status and requesting additional data. + * The data associated with the given stream is expected to be a pointer to an + * open LIBSSH2_SFTP_HANDLE for the file from which the data is to be read. + * + * @param user + * The user receiving the ack message. + * + * @param stream + * The Guacamole protocol stream associated with the received ack message. + * + * @param message + * An arbitrary human-readable message describing the nature of the + * success or failure denoted by the ack message. + * + * @param status + * The status code associated with the ack message, which may indicate + * success or an error. + * + * @return + * Zero if the file is read from successfully, or non-zero on error. + */ +static int guac_common_ssh_sftp_ack_handler(guac_user* user, + guac_stream* stream, char* message, guac_protocol_status status) { + + /* Pull file from stream */ + 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(user->socket, stream, + buffer, bytes_read); + + guac_user_log(user, GUAC_LOG_DEBUG, "%i bytes sent to user", + bytes_read); + + } + + /* If EOF, send end */ + else if (bytes_read == 0) { + guac_user_log(user, GUAC_LOG_DEBUG, "File sent"); + guac_protocol_send_end(user->socket, stream); + guac_user_free_stream(user, stream); + } + + /* Otherwise, fail stream */ + else { + guac_user_log(user, GUAC_LOG_INFO, "Error reading file"); + guac_protocol_send_end(user->socket, stream); + guac_user_free_stream(user, stream); + } + + guac_socket_flush(user->socket); + + } + + /* Otherwise, return stream to user */ + else + guac_user_free_stream(user, stream); + + return 0; +} + +guac_stream* guac_common_ssh_sftp_download_file( + guac_common_ssh_sftp_filesystem* filesystem, guac_user* user, + char* filename) { + + guac_stream* stream; + LIBSSH2_SFTP_HANDLE* file; + + /* Attempt to open file for reading */ + file = libssh2_sftp_open(filesystem->sftp_session, filename, + LIBSSH2_FXF_READ, 0); + if (file == NULL) { + guac_user_log(user, GUAC_LOG_INFO, + "Unable to read file \"%s\"", filename); + return NULL; + } + + /* Allocate stream */ + stream = guac_user_alloc_stream(user); + stream->ack_handler = guac_common_ssh_sftp_ack_handler; + stream->data = file; + + /* Send stream start, strip name */ + filename = basename(filename); + guac_protocol_send_file(user->socket, stream, + "application/octet-stream", filename); + guac_socket_flush(user->socket); + + guac_user_log(user, GUAC_LOG_DEBUG, "Sending file \"%s\"", filename); + return stream; + +} + +void guac_common_ssh_sftp_set_upload_path( + guac_common_ssh_sftp_filesystem* filesystem, const char* path) { + + guac_client* client = filesystem->ssh_session->client; + + /* Ignore requests which exceed maximum-allowed path */ + int length = strnlen(path, GUAC_COMMON_SSH_SFTP_MAX_PATH)+1; + if (length > GUAC_COMMON_SSH_SFTP_MAX_PATH) { + guac_client_log(client, GUAC_LOG_ERROR, + "Submitted path exceeds limit of %i bytes", + GUAC_COMMON_SSH_SFTP_MAX_PATH); + return; + } + + /* Copy path */ + memcpy(filesystem->upload_path, path, length); + guac_client_log(client, GUAC_LOG_DEBUG, "Upload path set to \"%s\"", path); + +} + +/** + * Handler for ack messages received due to receipt of a "body" or "blob" + * instruction associated with a SFTP directory list operation. + * + * @param user + * The user receiving the ack message. + * + * @param stream + * The Guacamole protocol stream associated with the received ack message. + * + * @param message + * An arbitrary human-readable message describing the nature of the + * success or failure denoted by this ack message. + * + * @param status + * The status code associated with this ack message, which may indicate + * success or an error. + * + * @return + * Zero on success, non-zero on error. + */ +static int guac_common_ssh_sftp_ls_ack_handler(guac_user* user, + guac_stream* stream, char* message, guac_protocol_status status) { + + int bytes_read; + int blob_written = 0; + + char filename[GUAC_COMMON_SSH_SFTP_MAX_PATH]; + LIBSSH2_SFTP_ATTRIBUTES attributes; + + guac_common_ssh_sftp_ls_state* list_state = + (guac_common_ssh_sftp_ls_state*) stream->data; + + guac_common_ssh_sftp_filesystem* filesystem = list_state->filesystem; + + LIBSSH2_SFTP* sftp = filesystem->sftp_session; + + /* If unsuccessful, free stream and abort */ + if (status != GUAC_PROTOCOL_STATUS_SUCCESS) { + libssh2_sftp_closedir(list_state->directory); + guac_user_free_stream(user, stream); + free(list_state); + return 0; + } + + /* While directory entries remain */ + while ((bytes_read = libssh2_sftp_readdir(list_state->directory, + filename, sizeof(filename), &attributes)) > 0 + && !blob_written) { + + char absolute_path[GUAC_COMMON_SSH_SFTP_MAX_PATH]; + + /* Skip current and parent directory entries */ + if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0) + continue; + + /* Concatenate into absolute path - skip if invalid */ + if (!guac_ssh_append_filename(absolute_path, + list_state->directory_name, filename)) { + + guac_user_log(user, GUAC_LOG_DEBUG, + "Skipping filename \"%s\" - filename is invalid or " + "resulting path is too long", filename); + + continue; + } + + /* Stat explicitly if symbolic link (might point to directory) */ + if (LIBSSH2_SFTP_S_ISLNK(attributes.permissions)) + libssh2_sftp_stat(sftp, absolute_path, &attributes); + + /* Determine mimetype */ + const char* mimetype; + if (LIBSSH2_SFTP_S_ISDIR(attributes.permissions)) + mimetype = GUAC_USER_STREAM_INDEX_MIMETYPE; + else + mimetype = "application/octet-stream"; + + /* Write entry */ + blob_written |= guac_common_json_write_property(user, stream, + &list_state->json_state, absolute_path, mimetype); + + } + + /* Complete JSON and cleanup at end of directory */ + if (bytes_read <= 0) { + + /* Complete JSON object */ + guac_common_json_end_object(user, stream, &list_state->json_state); + guac_common_json_flush(user, stream, &list_state->json_state); + + /* Clean up resources */ + libssh2_sftp_closedir(list_state->directory); + free(list_state); + + /* Signal of stream */ + guac_protocol_send_end(user->socket, stream); + guac_user_free_stream(user, stream); + + } + + guac_socket_flush(user->socket); + return 0; + +} + +/** + * Handler for get messages. In context of SFTP and the filesystem exposed via + * the Guacamole protocol, get messages request the body of a file within the + * filesystem. + * + * @param user + * The user who sent the get message. + * + * @param object + * The Guacamole protocol object associated with the get request itself. + * + * @param name + * The name of the input stream (file) being requested. + * + * @return + * Zero on success, non-zero on error. + */ +static int guac_common_ssh_sftp_get_handler(guac_user* user, + guac_object* object, char* name) { + + guac_common_ssh_sftp_filesystem* filesystem = + (guac_common_ssh_sftp_filesystem*) object->data; + + LIBSSH2_SFTP* sftp = filesystem->sftp_session; + LIBSSH2_SFTP_ATTRIBUTES attributes; + + /* Attempt to read file information */ + if (libssh2_sftp_stat(sftp, name, &attributes)) { + guac_user_log(user, GUAC_LOG_INFO, "Unable to read file \"%s\"", + name); + return 0; + } + + /* If directory, send contents of directory */ + if (LIBSSH2_SFTP_S_ISDIR(attributes.permissions)) { + + /* Open as directory */ + LIBSSH2_SFTP_HANDLE* dir = libssh2_sftp_opendir(sftp, name); + if (dir == NULL) { + guac_user_log(user, GUAC_LOG_INFO, + "Unable to read directory \"%s\"", name); + return 0; + } + + /* Init directory listing state */ + guac_common_ssh_sftp_ls_state* list_state = + malloc(sizeof(guac_common_ssh_sftp_ls_state)); + + list_state->directory = dir; + list_state->filesystem = filesystem; + strncpy(list_state->directory_name, name, + sizeof(list_state->directory_name) - 1); + + /* Allocate stream for body */ + guac_stream* stream = guac_user_alloc_stream(user); + stream->ack_handler = guac_common_ssh_sftp_ls_ack_handler; + stream->data = list_state; + + /* Init JSON object state */ + guac_common_json_begin_object(user, stream, &list_state->json_state); + + /* Associate new stream with get request */ + guac_protocol_send_body(user->socket, object, stream, + GUAC_USER_STREAM_INDEX_MIMETYPE, name); + + } + + /* Otherwise, send file contents */ + else { + + /* Open as normal file */ + LIBSSH2_SFTP_HANDLE* file = libssh2_sftp_open(sftp, name, + LIBSSH2_FXF_READ, 0); + if (file == NULL) { + guac_user_log(user, GUAC_LOG_INFO, + "Unable to read file \"%s\"", name); + return 0; + } + + /* Allocate stream for body */ + guac_stream* stream = guac_user_alloc_stream(user); + stream->ack_handler = guac_common_ssh_sftp_ack_handler; + stream->data = file; + + /* Associate new stream with get request */ + guac_protocol_send_body(user->socket, object, stream, + "application/octet-stream", name); + + } + + guac_socket_flush(user->socket); + return 0; +} + +/** + * Handler for put messages. In context of SFTP and the filesystem exposed via + * the Guacamole protocol, put messages request write access to a file within + * the filesystem. + * + * @param user + * The user who sent the put message. + * + * @param object + * The Guacamole protocol object associated with the put request itself. + * + * @param stream + * The Guacamole protocol stream along which the user will be sending + * file data. + * + * @param mimetype + * The mimetype of the data being send along the stream. + * + * @param name + * The name of the input stream (file) being requested. + * + * @return + * Zero on success, non-zero on error. + */ +static int guac_common_ssh_sftp_put_handler(guac_user* user, + guac_object* object, guac_stream* stream, char* mimetype, char* name) { + + guac_common_ssh_sftp_filesystem* filesystem = + (guac_common_ssh_sftp_filesystem*) object->data; + + LIBSSH2_SFTP* sftp = filesystem->sftp_session; + + /* Open file via SFTP */ + LIBSSH2_SFTP_HANDLE* file = libssh2_sftp_open(sftp, name, + LIBSSH2_FXF_WRITE | LIBSSH2_FXF_CREAT | LIBSSH2_FXF_TRUNC, + S_IRUSR | S_IWUSR); + + /* Acknowledge stream if successful */ + if (file != NULL) { + guac_user_log(user, GUAC_LOG_DEBUG, "File \"%s\" opened", name); + guac_protocol_send_ack(user->socket, stream, "SFTP: File opened", + GUAC_PROTOCOL_STATUS_SUCCESS); + } + + /* Abort on failure */ + else { + guac_user_log(user, GUAC_LOG_INFO, + "Unable to open file \"%s\"", name); + guac_protocol_send_ack(user->socket, stream, "SFTP: Open failed", + guac_sftp_get_status(filesystem)); + } + + /* Set handlers for file stream */ + stream->blob_handler = guac_common_ssh_sftp_blob_handler; + stream->end_handler = guac_common_ssh_sftp_end_handler; + + /* Store file within stream */ + stream->data = file; + + guac_socket_flush(user->socket); + return 0; +} + +void* guac_common_ssh_expose_sftp_filesystem(guac_user* user, void* data) { + + guac_common_ssh_sftp_filesystem* filesystem = + (guac_common_ssh_sftp_filesystem*) data; + + /* No need to expose if there is no filesystem or the user has left */ + if (user == NULL || filesystem == NULL) + return NULL; + + /* Allocate and expose filesystem object for user */ + return guac_common_ssh_alloc_sftp_filesystem_object(filesystem, user); + +} + +guac_object* guac_common_ssh_alloc_sftp_filesystem_object( + guac_common_ssh_sftp_filesystem* filesystem, guac_user* user) { + + /* Init filesystem */ + guac_object* fs_object = guac_user_alloc_object(user); + fs_object->get_handler = guac_common_ssh_sftp_get_handler; + fs_object->put_handler = guac_common_ssh_sftp_put_handler; + fs_object->data = filesystem; + + /* Send filesystem to user */ + guac_protocol_send_filesystem(user->socket, fs_object, filesystem->name); + guac_socket_flush(user->socket); + + return fs_object; + +} + +guac_common_ssh_sftp_filesystem* guac_common_ssh_create_sftp_filesystem( + guac_common_ssh_session* session, const char* name) { + + /* Request SFTP */ + LIBSSH2_SFTP* sftp_session = libssh2_sftp_init(session->session); + if (sftp_session == NULL) + return NULL; + + /* Allocate data for SFTP session */ + guac_common_ssh_sftp_filesystem* filesystem = + malloc(sizeof(guac_common_ssh_sftp_filesystem)); + + /* Associate SSH session with SFTP data and user */ + filesystem->name = strdup(name); + filesystem->ssh_session = session; + filesystem->sftp_session = sftp_session; + + /* Initially upload files to current directory */ + strcpy(filesystem->upload_path, "."); + + /* Return allocated filesystem */ + return filesystem; + +} + +void guac_common_ssh_destroy_sftp_filesystem( + guac_common_ssh_sftp_filesystem* filesystem) { + + /* Shutdown SFTP session */ + libssh2_sftp_shutdown(filesystem->sftp_session); + + /* Free associated memory */ + free(filesystem->name); + free(filesystem); + +} + http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d371f2d9/src/common-ssh/ssh.c ---------------------------------------------------------------------- diff --git a/src/common-ssh/ssh.c b/src/common-ssh/ssh.c new file mode 100644 index 0000000..9d3de19 --- /dev/null +++ b/src/common-ssh/ssh.c @@ -0,0 +1,544 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "common-ssh/key.h" +#include "common-ssh/ssh.h" +#include "common-ssh/user.h" + +#include <guacamole/client.h> +#include <libssh2.h> + +#ifdef LIBSSH2_USES_GCRYPT +#include <gcrypt.h> +#endif + +#include <openssl/err.h> +#include <openssl/ssl.h> + +#include <errno.h> +#include <netdb.h> +#include <netinet/in.h> +#include <pthread.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <unistd.h> + +#ifdef LIBSSH2_USES_GCRYPT +GCRY_THREAD_OPTION_PTHREAD_IMPL; +#endif + +/** + * Array of mutexes, used by OpenSSL. + */ +static pthread_mutex_t* guac_common_ssh_openssl_locks = NULL; + +/** + * Called by OpenSSL when locking or unlocking the Nth mutex. + * + * @param mode + * A bitmask denoting the action to be taken on the Nth lock, such as + * CRYPTO_LOCK or CRYPTO_UNLOCK. + * + * @param n + * The index of the lock to lock or unlock. + * + * @param file + * The filename of the function setting the lock, for debugging purposes. + * + * @param line + * The line number of the function setting the lock, for debugging + * purposes. + */ +static void guac_common_ssh_openssl_locking_callback(int mode, int n, + const char* file, int line){ + + /* Lock given mutex upon request */ + if (mode & CRYPTO_LOCK) + pthread_mutex_lock(&(guac_common_ssh_openssl_locks[n])); + + /* Unlock given mutex upon request */ + else if (mode & CRYPTO_UNLOCK) + pthread_mutex_unlock(&(guac_common_ssh_openssl_locks[n])); + +} + +/** + * Called by OpenSSL when determining the current thread ID. + * + * @return + * An ID which uniquely identifies the current thread. + */ +static unsigned long guac_common_ssh_openssl_id_callback() { + return (unsigned long) pthread_self(); +} + +/** + * Creates the given number of mutexes, such that OpenSSL will have at least + * this number of mutexes at its disposal. + * + * @param count + * The number of mutexes (locks) to create. + */ +static void guac_common_ssh_openssl_init_locks(int count) { + + int i; + + /* Allocate required number of locks */ + guac_common_ssh_openssl_locks = + malloc(sizeof(pthread_mutex_t) * count); + + /* Initialize each lock */ + for (i=0; i < count; i++) + pthread_mutex_init(&(guac_common_ssh_openssl_locks[i]), NULL); + +} + +/** + * Frees the given number of mutexes. + * + * @param count + * The number of mutexes (locks) to free. + */ +static void guac_common_ssh_openssl_free_locks(int count) { + + int i; + + /* SSL lock array was not initialized */ + if (guac_common_ssh_openssl_locks == NULL) + return; + + /* Free all locks */ + for (i=0; i < count; i++) + pthread_mutex_destroy(&(guac_common_ssh_openssl_locks[i])); + + /* Free lock array */ + free(guac_common_ssh_openssl_locks); + +} + +int guac_common_ssh_init(guac_client* client) { + +#ifdef LIBSSH2_USES_GCRYPT + /* Init threadsafety in libgcrypt */ + gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); + if (!gcry_check_version(GCRYPT_VERSION)) { + guac_client_log(client, GUAC_LOG_ERROR, "libgcrypt version mismatch."); + return 1; + } +#endif + + /* Init threadsafety in OpenSSL */ + guac_common_ssh_openssl_init_locks(CRYPTO_num_locks()); + CRYPTO_set_id_callback(guac_common_ssh_openssl_id_callback); + CRYPTO_set_locking_callback(guac_common_ssh_openssl_locking_callback); + + /* Init OpenSSL */ + SSL_library_init(); + ERR_load_crypto_strings(); + + /* Init libssh2 */ + libssh2_init(0); + + /* Success */ + return 0; + +} + +void guac_common_ssh_uninit() { + guac_common_ssh_openssl_free_locks(CRYPTO_num_locks()); +} + +/** + * Callback invoked by libssh2 when libssh2_userauth_publickkey() is invoked. + * This callback must sign the given data, returning the signature as newly- + * allocated buffer space. + * + * @param session + * The SSH session for which the signature is being generated. + * + * @param sig + * A pointer to the buffer space containing the signature. This callback + * MUST allocate and assign this space. + * + * @param sig_len + * The length of the signature within the allocated buffer space, in bytes. + * This value must be set to the size of the signature after the signing + * operation completes. + * + * @param data + * The arbitrary data that must be signed. + * + * @param data_len + * The length of the arbitrary data to be signed, in bytes. + * + * @param abstract + * The value of the abstract parameter provided with the corresponding call + * to libssh2_userauth_publickey(). + * + * @return + * Zero on success, non-zero if the signing operation failed. + */ +static int guac_common_ssh_sign_callback(LIBSSH2_SESSION* session, + unsigned char** sig, size_t* sig_len, + const unsigned char* data, size_t data_len, void **abstract) { + + guac_common_ssh_key* key = (guac_common_ssh_key*) abstract; + int length; + + /* Allocate space for signature */ + *sig = malloc(4096); + + /* Sign with key */ + length = guac_common_ssh_key_sign(key, (const char*) data, data_len, *sig); + if (length < 0) + return 1; + + *sig_len = length; + return 0; +} + +/** + * Callback for the keyboard-interactive authentication method. Currently + * supports just one prompt for the password. This callback is invoked as + * needed to fullfill a call to libssh2_userauth_keyboard_interactive(). + * + * @param name + * An arbitrary name which should be printed to the terminal for the + * benefit of the user. This is currently ignored. + * + * @param name_len + * The length of the name string, in bytes. + * + * @param instruction + * Arbitrary instructions which should be printed to the terminal for the + * benefit of the user. This is currently ignored. + * + * @param instruction_len + * The length of the instruction string, in bytes. + * + * @param num_prompts + * The number of keyboard-interactive prompts for which responses are + * requested. This callback currently only supports one prompt, and assumes + * that this prompt is requesting the password. + * + * @param prompts + * An array of all keyboard-interactive prompts for which responses are + * requested. + * + * @param responses + * A parallel array into which all prompt responses should be stored. Each + * entry within this array corresponds to the entry in the prompts array + * with the same index. + * + * @param abstract + * The value of the abstract parameter provided when the SSH session was + * created with libssh2_session_init_ex(). + */ +static void guac_common_ssh_kbd_callback(const char *name, int name_len, + const char *instruction, int instruction_len, int num_prompts, + const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, + LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, + void **abstract) { + + guac_common_ssh_session* common_session = + (guac_common_ssh_session*) *abstract; + + guac_client* client = common_session->client; + + /* Send password if only one prompt */ + if (num_prompts == 1) { + char* password = common_session->user->password; + responses[0].text = strdup(password); + responses[0].length = strlen(password); + } + + /* If more than one prompt, a single password is not enough */ + else + guac_client_log(client, GUAC_LOG_WARNING, + "Unsupported number of keyboard-interactive prompts: %i", + num_prompts); + +} + +/** + * Authenticates the user associated with the given session over SSH. All + * required credentials must already be present within the user object + * associated with the given session. + * + * @param session + * The session associated with the user to be authenticated. + * + * @return + * Zero if authentication succeeds, or non-zero if authentication has + * failed. + */ +static int guac_common_ssh_authenticate(guac_common_ssh_session* common_session) { + + guac_client* client = common_session->client; + guac_common_ssh_user* user = common_session->user; + LIBSSH2_SESSION* session = common_session->session; + + /* Get user credentials */ + char* username = user->username; + char* password = user->password; + guac_common_ssh_key* key = user->private_key; + + /* Validate username provided */ + if (username == NULL) { + guac_client_abort(client, GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED, + "SSH authentication requires a username."); + return 1; + } + + /* Get list of supported authentication methods */ + char* user_authlist = libssh2_userauth_list(session, username, + strlen(username)); + guac_client_log(client, GUAC_LOG_DEBUG, + "Supported authentication methods: %s", user_authlist); + + /* Authenticate with private key, if provided */ + if (key != NULL) { + + /* Check if public key auth is supported on the server */ + if (strstr(user_authlist, "publickey") == NULL) { + guac_client_abort(client, GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED, + "Public key authentication is not supported by " + "the SSH server"); + return 1; + } + + /* Attempt public key auth */ + if (libssh2_userauth_publickey(session, username, + (unsigned char*) key->public_key, key->public_key_length, + guac_common_ssh_sign_callback, (void**) key)) { + + /* Abort on failure */ + char* error_message; + libssh2_session_last_error(session, &error_message, NULL, 0); + guac_client_abort(client, GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED, + "Public key authentication failed: %s", error_message); + + return 1; + + } + + /* Private key authentication succeeded */ + return 0; + + } + + /* Authenticate with password, if provided */ + else if (password != NULL) { + + /* Check if password auth is supported on the server */ + if (strstr(user_authlist, "password") != NULL) { + + /* Attempt password authentication */ + if (libssh2_userauth_password(session, username, password)) { + + /* Abort on failure */ + char* error_message; + libssh2_session_last_error(session, &error_message, NULL, 0); + guac_client_abort(client, + GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED, + "Password authentication failed: %s", error_message); + + return 1; + } + + /* Password authentication succeeded */ + return 0; + + } + + /* Check if keyboard-interactive auth is supported on the server */ + if (strstr(user_authlist, "keyboard-interactive") != NULL) { + + /* Attempt keyboard-interactive auth using provided password */ + if (libssh2_userauth_keyboard_interactive(session, username, + &guac_common_ssh_kbd_callback)) { + + /* Abort on failure */ + char* error_message; + libssh2_session_last_error(session, &error_message, NULL, 0); + guac_client_abort(client, + GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED, + "Keyboard-interactive authentication failed: %s", + error_message); + + return 1; + } + + /* Keyboard-interactive authentication succeeded */ + return 0; + + } + + /* No known authentication types available */ + guac_client_abort(client, GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED, + "Password and keyboard-interactive authentication are not " + "supported by the SSH server"); + return 1; + + } + + /* No credentials provided */ + guac_client_abort(client, GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED, + "SSH authentication requires either a private key or a password."); + return 1; + +} + +guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client, + const char* hostname, const char* port, guac_common_ssh_user* user) { + + int retval; + + int fd; + struct addrinfo* addresses; + struct addrinfo* current_address; + + char connected_address[1024]; + char connected_port[64]; + + struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM, + .ai_protocol = IPPROTO_TCP + }; + + /* Get socket */ + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, + "Unable to create socket: %s", strerror(errno)); + return NULL; + } + + /* Get addresses connection */ + if ((retval = getaddrinfo(hostname, port, &hints, &addresses))) { + guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, + "Error parsing given address or port: %s", + gai_strerror(retval)); + close(fd); + return NULL; + } + + /* Attempt connection to each address until success */ + current_address = addresses; + while (current_address != NULL) { + + /* Resolve hostname */ + if ((retval = getnameinfo(current_address->ai_addr, + current_address->ai_addrlen, + connected_address, sizeof(connected_address), + connected_port, sizeof(connected_port), + NI_NUMERICHOST | NI_NUMERICSERV))) + guac_client_log(client, GUAC_LOG_DEBUG, + "Unable to resolve host: %s", gai_strerror(retval)); + + /* Connect */ + if (connect(fd, current_address->ai_addr, + current_address->ai_addrlen) == 0) { + + guac_client_log(client, GUAC_LOG_DEBUG, + "Successfully connected to host %s, port %s", + connected_address, connected_port); + + /* Done if successful connect */ + break; + + } + + /* Otherwise log information regarding bind failure */ + else + guac_client_log(client, GUAC_LOG_DEBUG, "Unable to connect to " + "host %s, port %s: %s", + connected_address, connected_port, strerror(errno)); + + current_address = current_address->ai_next; + + } + + /* Free addrinfo */ + freeaddrinfo(addresses); + + /* If unable to connect to anything, fail */ + if (current_address == NULL) { + guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, + "Unable to connect to any addresses."); + close(fd); + return NULL; + } + + /* Allocate new session */ + guac_common_ssh_session* common_session = + malloc(sizeof(guac_common_ssh_session)); + + /* Open SSH session */ + LIBSSH2_SESSION* session = libssh2_session_init_ex(NULL, NULL, + NULL, common_session); + if (session == NULL) { + guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, + "Session allocation failed."); + free(common_session); + close(fd); + return NULL; + } + + /* Perform handshake */ + if (libssh2_session_handshake(session, fd)) { + guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, + "SSH handshake failed."); + free(common_session); + close(fd); + return NULL; + } + + /* Store basic session data */ + common_session->client = client; + common_session->user = user; + common_session->session = session; + common_session->fd = fd; + + /* Attempt authentication */ + if (guac_common_ssh_authenticate(common_session)) { + free(common_session); + close(fd); + return NULL; + } + + /* Return created session */ + return common_session; + +} + +void guac_common_ssh_destroy_session(guac_common_ssh_session* session) { + + /* Disconnect and clean up libssh2 */ + libssh2_session_disconnect(session->session, "Bye"); + libssh2_session_free(session->session); + + /* Free all other data */ + free(session); + +} + http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d371f2d9/src/common-ssh/user.c ---------------------------------------------------------------------- diff --git a/src/common-ssh/user.c b/src/common-ssh/user.c new file mode 100644 index 0000000..92c8d96 --- /dev/null +++ b/src/common-ssh/user.c @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "common-ssh/key.h" +#include "common-ssh/user.h" + +#include <stdlib.h> +#include <string.h> + +guac_common_ssh_user* guac_common_ssh_create_user(const char* username) { + + guac_common_ssh_user* user = malloc(sizeof(guac_common_ssh_user)); + + /* Init user */ + user->username = strdup(username); + user->password = NULL; + user->private_key = NULL; + + return user; + +} + +void guac_common_ssh_destroy_user(guac_common_ssh_user* user) { + + /* Free private key, if present */ + if (user->private_key != NULL) + guac_common_ssh_key_free(user->private_key); + + /* Free all other data */ + free(user->password); + free(user->username); + free(user); + +} + +void guac_common_ssh_user_set_password(guac_common_ssh_user* user, + const char* password) { + + /* Replace current password with given value */ + free(user->password); + user->password = strdup(password); + +} + +int guac_common_ssh_user_import_key(guac_common_ssh_user* user, + char* private_key, char* passphrase) { + + /* Free existing private key, if present */ + if (user->private_key != NULL) + guac_common_ssh_key_free(user->private_key); + + /* Attempt to read key without passphrase if none given */ + if (passphrase == NULL) + user->private_key = guac_common_ssh_key_alloc(private_key, + strlen(private_key), ""); + + /* Otherwise, use provided passphrase */ + else + user->private_key = guac_common_ssh_key_alloc(private_key, + strlen(private_key), passphrase); + + /* Fail if key could not be read */ + return user->private_key == NULL; + +} + http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d371f2d9/src/protocols/rdp/client.c ---------------------------------------------------------------------- diff --git a/src/protocols/rdp/client.c b/src/protocols/rdp/client.c index 2dcb401..d12efba 100644 --- a/src/protocols/rdp/client.c +++ b/src/protocols/rdp/client.c @@ -27,9 +27,9 @@ #include "user.h" #ifdef ENABLE_COMMON_SSH -#include <guac_sftp.h> -#include <guac_ssh.h> -#include <guac_ssh_user.h> +#include "common-ssh/sftp.h" +#include "common-ssh/ssh.h" +#include "common-ssh/user.h" #endif #include <freerdp/cache/cache.h> http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d371f2d9/src/protocols/rdp/rdp.c ---------------------------------------------------------------------- diff --git a/src/protocols/rdp/rdp.c b/src/protocols/rdp/rdp.c index a48230a..8d49c83 100644 --- a/src/protocols/rdp/rdp.c +++ b/src/protocols/rdp/rdp.c @@ -40,9 +40,9 @@ #include "rdp_svc.h" #ifdef ENABLE_COMMON_SSH -#include <guac_sftp.h> -#include <guac_ssh.h> -#include <guac_ssh_user.h> +#include "common-ssh/sftp.h" +#include "common-ssh/ssh.h" +#include "common-ssh/user.h" #endif #include <freerdp/cache/bitmap.h> http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d371f2d9/src/protocols/rdp/rdp.h ---------------------------------------------------------------------- diff --git a/src/protocols/rdp/rdp.h b/src/protocols/rdp/rdp.h index e3e3311..943155d 100644 --- a/src/protocols/rdp/rdp.h +++ b/src/protocols/rdp/rdp.h @@ -39,9 +39,9 @@ #include <guacamole/client.h> #ifdef ENABLE_COMMON_SSH -#include "guac_sftp.h" -#include "guac_ssh.h" -#include "guac_ssh_user.h" +#include "common-ssh/sftp.h" +#include "common-ssh/ssh.h" +#include "common-ssh/user.h" #endif #include <pthread.h> http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d371f2d9/src/protocols/rdp/sftp.c ---------------------------------------------------------------------- diff --git a/src/protocols/rdp/sftp.c b/src/protocols/rdp/sftp.c index efda47d..ecfe35f 100644 --- a/src/protocols/rdp/sftp.c +++ b/src/protocols/rdp/sftp.c @@ -19,7 +19,7 @@ #include "config.h" -#include "guac_sftp.h" +#include "common-ssh/sftp.h" #include "rdp.h" #include "sftp.h" http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d371f2d9/src/protocols/ssh/client.c ---------------------------------------------------------------------- diff --git a/src/protocols/ssh/client.c b/src/protocols/ssh/client.c index 13dd1c8..2110ba9 100644 --- a/src/protocols/ssh/client.c +++ b/src/protocols/ssh/client.c @@ -20,7 +20,7 @@ #include "config.h" #include "client.h" -#include "guac_sftp.h" +#include "common-ssh/sftp.h" #include "ssh.h" #include "terminal.h" #include "user.h" http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d371f2d9/src/protocols/ssh/sftp.c ---------------------------------------------------------------------- diff --git a/src/protocols/ssh/sftp.c b/src/protocols/ssh/sftp.c index 9fddc30..f4173a6 100644 --- a/src/protocols/ssh/sftp.c +++ b/src/protocols/ssh/sftp.c @@ -19,7 +19,7 @@ #include "config.h" -#include "guac_sftp.h" +#include "common-ssh/sftp.h" #include "sftp.h" #include "ssh.h" http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d371f2d9/src/protocols/ssh/ssh.c ---------------------------------------------------------------------- diff --git a/src/protocols/ssh/ssh.c b/src/protocols/ssh/ssh.c index 53835c8..dd0a30f 100644 --- a/src/protocols/ssh/ssh.c +++ b/src/protocols/ssh/ssh.c @@ -20,8 +20,8 @@ #include "config.h" #include "common/recording.h" -#include "guac_sftp.h" -#include "guac_ssh.h" +#include "common-ssh/sftp.h" +#include "common-ssh/ssh.h" #include "settings.h" #include "sftp.h" #include "ssh.h" http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d371f2d9/src/protocols/ssh/ssh.h ---------------------------------------------------------------------- diff --git a/src/protocols/ssh/ssh.h b/src/protocols/ssh/ssh.h index 44027ee..d6dbdaf 100644 --- a/src/protocols/ssh/ssh.h +++ b/src/protocols/ssh/ssh.h @@ -22,9 +22,9 @@ #include "config.h" -#include "guac_sftp.h" -#include "guac_ssh.h" -#include "guac_ssh_user.h" +#include "common-ssh/sftp.h" +#include "common-ssh/ssh.h" +#include "common-ssh/user.h" #include "settings.h" #include "terminal.h" http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d371f2d9/src/protocols/vnc/client.c ---------------------------------------------------------------------- diff --git a/src/protocols/vnc/client.c b/src/protocols/vnc/client.c index 516d93f..00b9015 100644 --- a/src/protocols/vnc/client.c +++ b/src/protocols/vnc/client.c @@ -24,9 +24,9 @@ #include "vnc.h" #ifdef ENABLE_COMMON_SSH -#include "guac_sftp.h" -#include "guac_ssh.h" -#include "sftp.h" +#include "common-ssh/sftp.h" +#include "common-ssh/ssh.h" +#include "common-ssh/user.h" #endif #ifdef ENABLE_PULSE http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d371f2d9/src/protocols/vnc/sftp.c ---------------------------------------------------------------------- diff --git a/src/protocols/vnc/sftp.c b/src/protocols/vnc/sftp.c index fc90668..e5e768a 100644 --- a/src/protocols/vnc/sftp.c +++ b/src/protocols/vnc/sftp.c @@ -19,7 +19,7 @@ #include "config.h" -#include "guac_sftp.h" +#include "common-ssh/sftp.h" #include "sftp.h" #include "vnc.h" http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d371f2d9/src/protocols/vnc/vnc.c ---------------------------------------------------------------------- diff --git a/src/protocols/vnc/vnc.c b/src/protocols/vnc/vnc.c index 9b0bd76..710372f 100644 --- a/src/protocols/vnc/vnc.c +++ b/src/protocols/vnc/vnc.c @@ -37,8 +37,8 @@ #endif #ifdef ENABLE_COMMON_SSH -#include "guac_sftp.h" -#include "guac_ssh.h" +#include "common-ssh/sftp.h" +#include "common-ssh/ssh.h" #include "sftp.h" #endif http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/d371f2d9/src/protocols/vnc/vnc.h ---------------------------------------------------------------------- diff --git a/src/protocols/vnc/vnc.h b/src/protocols/vnc/vnc.h index 7ae8b72..0edbcd4 100644 --- a/src/protocols/vnc/vnc.h +++ b/src/protocols/vnc/vnc.h @@ -37,9 +37,9 @@ #endif #ifdef ENABLE_COMMON_SSH -#include "guac_sftp.h" -#include "guac_ssh.h" -#include "guac_ssh_user.h" +#include "common-ssh/sftp.h" +#include "common-ssh/ssh.h" +#include "common-ssh/user.h" #endif #include <pthread.h>
