GUACAMOLE-221: Clean up libguac, protocol changes, and documentation.
diff --git a/src/libguac/client.c b/src/libguac/client.c
index 4be0d4d..9738c0c 100644
--- a/src/libguac/client.c
+++ b/src/libguac/client.c
@@ -492,15 +492,17 @@
  *     passed on to the owner to continue the connection.
  * 
  * @return
- *     A pointer to an integer containing the return status of the send
- *     operation.
+ *     Zero if the operation succeeds or non-zero on failure, cast as a void*.
  */
 static void* guac_client_owner_send_required_callback(guac_user* user, void* data) {
     
     const char** required = (const char **) data;
     
     /* Send required parameters to owner. */
-    return (void*) ((intptr_t) guac_protocol_send_required(user->socket, required));
+    if (user != NULL)
+        return (void*) ((intptr_t) guac_protocol_send_required(user->socket, required));
+    
+    return (void*) ((intptr_t) -1);
     
 }
 
@@ -672,38 +674,30 @@
 /**
  * A callback function which is invoked by guac_client_owner_supports_required()
  * to determine if the owner of a client supports the "required" instruction,
- * updating the flag to indicate support.
+ * returning zero if the user does not support the instruction or non-zero if
+ * the user supports it.
  * 
  * @param user
  *     The guac_user that will be checked for "required" instruction support.
  * 
  * @param data
- *     A pointer to an int containing the status for support of the "required"
- *     instruction.  This will be 0 if the owner does not support this
- *     instruction, or 1 if the owner does support it.
+ *     Data provided to the callback. This value is never used within this
+ *     callback.
  * 
  * @return
- *     Always NULL.
+ *     A non-zero integer if the provided user who owns the connection supports
+ *     the "required" instruction, or zero if the user does not. The integer
+ *     is cast as a void*.
  */
 static void* guac_owner_supports_required_callback(guac_user* user, void* data) {
     
-    int* required_supported = (int *) data;
-    
-    /* Check if owner supports required */
-    if (*required_supported)
-        *required_supported = guac_user_supports_required(user);
-    
-    return NULL;
+    return (void*) ((intptr_t) guac_user_supports_required(user));
     
 }
 
 int guac_client_owner_supports_required(guac_client* client) {
     
-    int required_supported = 1;
-    
-    guac_client_for_owner(client, guac_owner_supports_required_callback, &required_supported);
-    
-    return required_supported;
+    return (int) ((intptr_t) guac_client_for_owner(client, guac_owner_supports_required_callback, NULL));
     
 }
 
diff --git a/src/libguac/guacamole/protocol-types.h b/src/libguac/guacamole/protocol-types.h
index d492fe7..51652d2 100644
--- a/src/libguac/guacamole/protocol-types.h
+++ b/src/libguac/guacamole/protocol-types.h
@@ -277,8 +277,8 @@
 } guac_line_join_style;
 
 /**
- * The set of protocol versions known to guacd to help negotiate features that
- * may not be supported by various versions of the client.
+ * The set of protocol versions known to guacd to handle negotiation or feature
+ * support between differing versions of Guacamole clients and guacd.
  */
 typedef enum guac_protocol_version {
     
diff --git a/src/libguac/guacamole/protocol.h b/src/libguac/guacamole/protocol.h
index c4c6f21..c6dbed2 100644
--- a/src/libguac/guacamole/protocol.h
+++ b/src/libguac/guacamole/protocol.h
@@ -797,7 +797,7 @@
 /**
  * Sends a "required" instruction over the given guac_socket connection.  This
  * instruction indicates to the client that one or more additional parameters
- * is needed to continue the connection.
+ * are needed to continue the connection.
  * 
  * @param socket
  *     The guac_socket connection to which to send the instruction.
@@ -1024,18 +1024,18 @@
 int guac_protocol_decode_base64(char* base64);
 
 /**
- * Given a string representation of a protocol version, search the mapping
- * to find the matching enum version, or GUAC_PROTOCOL_VERSION_UNKNOWN if no
- * match is found.
+ * Given a string representation of a protocol version, return the enum value of
+ * that protocol version, or GUAC_PROTOCOL_VERSION_UNKNOWN if the value is not a
+ * known version.
  * 
  * @param version_string
  *     The string representation of the protocol version.
  * 
  * @return 
  *     The enum value of the protocol version, or GUAC_PROTOCOL_VERSION_UNKNOWN
- *     if no match is found.
+ *     if the provided version is not known.
  */
-guac_protocol_version guac_protocol_string_to_version(char* version_string);
+guac_protocol_version guac_protocol_string_to_version(const char* version_string);
 
 /**
  * Given the enum value of the protocol version, return a pointer to the string
diff --git a/src/libguac/guacamole/string.h b/src/libguac/guacamole/string.h
index 5e56e33..a648c0c 100644
--- a/src/libguac/guacamole/string.h
+++ b/src/libguac/guacamole/string.h
@@ -110,6 +110,19 @@
 size_t guac_strlcat(char* restrict dest, const char* restrict src, size_t n);
 
 /**
+ * Simple wrapper for strdup() which behaves identically to standard strdup(),
+ * except that NULL will be returned if the provided string is NULL.
+ *
+ * @param str
+ *     The string to duplicate as a newly-allocated string.
+ *
+ * @return
+ *     A newly-allocated string containing identically the same content as the
+ *     given string, or NULL if the given string was NULL.
+ */
+char* guac_strdup(const char* str);
+
+/**
  * Concatenates each of the given strings, separated by the given delimiter,
  * storing the result within a destination buffer. The number of bytes written
  * will be no more than the given number of bytes, and the destination buffer
diff --git a/src/libguac/protocol.c b/src/libguac/protocol.c
index 8002c92..59a46d5 100644
--- a/src/libguac/protocol.c
+++ b/src/libguac/protocol.c
@@ -1302,7 +1302,7 @@
 
 }
 
-guac_protocol_version guac_protocol_string_to_version(char* version_string) {
+guac_protocol_version guac_protocol_string_to_version(const char* version_string) {
     
     guac_protocol_version_mapping* current = guac_protocol_version_table;
     while (current->version != GUAC_PROTOCOL_VERSION_UNKNOWN) {
@@ -1321,11 +1321,12 @@
 const char* guac_protocol_version_to_string(guac_protocol_version version) {
     
     guac_protocol_version_mapping* current = guac_protocol_version_table;
-    while (current->version) {
+    while (current->version != GUAC_PROTOCOL_VERSION_UNKNOWN) {
         
-        if (current->version == version) {
+        if (current->version == version)
             return (const char*) current->version_string;
-        }
+        
+        current++;
         
     }
     
diff --git a/src/libguac/string.c b/src/libguac/string.c
index f05c4c0..e75f7c1 100644
--- a/src/libguac/string.c
+++ b/src/libguac/string.c
@@ -81,6 +81,17 @@
 
 }
 
+char* guac_strdup(const char* str) {
+
+    /* Return NULL if no string provided */
+    if (str == NULL)
+        return NULL;
+
+    /* Otherwise just invoke strdup() */
+    return strdup(str);
+
+}
+
 size_t guac_strljoin(char* restrict dest, const char* restrict const* elements,
         int nmemb, const char* restrict delim, size_t n) {
 
diff --git a/src/libguac/tests/protocol/guac_protocol_version.c b/src/libguac/tests/protocol/guac_protocol_version.c
index 782b0aa..37f42e0 100644
--- a/src/libguac/tests/protocol/guac_protocol_version.c
+++ b/src/libguac/tests/protocol/guac_protocol_version.c
@@ -31,9 +31,9 @@
     guac_protocol_version version_b = GUAC_PROTOCOL_VERSION_1_0_0;
     guac_protocol_version version_c = GUAC_PROTOCOL_VERSION_UNKNOWN;
     
-    CU_ASSERT_STRING_EQUAL_FATAL(guac_protocol_version_to_string(version_a), "VERSION_1_3_0");
-    CU_ASSERT_STRING_EQUAL_FATAL(guac_protocol_version_to_string(version_b), "VERSION_1_0_0");
-    CU_ASSERT_PTR_NULL_FATAL(guac_protocol_version_to_string(version_c));
+    CU_ASSERT_STRING_EQUAL(guac_protocol_version_to_string(version_a), "VERSION_1_3_0");
+    CU_ASSERT_STRING_EQUAL(guac_protocol_version_to_string(version_b), "VERSION_1_0_0");
+    CU_ASSERT_PTR_NULL(guac_protocol_version_to_string(version_c));
     
 }
 
@@ -50,10 +50,10 @@
     char* str_version_c = "AVACADO";
     char* str_version_d = "VERSION_31_4_1";
     
-    CU_ASSERT_EQUAL_FATAL(guac_protocol_string_to_version(str_version_a), GUAC_PROTOCOL_VERSION_1_3_0);
-    CU_ASSERT_EQUAL_FATAL(guac_protocol_string_to_version(str_version_b), GUAC_PROTOCOL_VERSION_1_1_0);
-    CU_ASSERT_EQUAL_FATAL(guac_protocol_string_to_version(str_version_c), GUAC_PROTOCOL_VERSION_UNKNOWN);
-    CU_ASSERT_EQUAL_FATAL(guac_protocol_string_to_version(str_version_d), GUAC_PROTOCOL_VERSION_UNKNOWN);
+    CU_ASSERT_EQUAL(guac_protocol_string_to_version(str_version_a), GUAC_PROTOCOL_VERSION_1_3_0);
+    CU_ASSERT_EQUAL(guac_protocol_string_to_version(str_version_b), GUAC_PROTOCOL_VERSION_1_1_0);
+    CU_ASSERT_EQUAL(guac_protocol_string_to_version(str_version_c), GUAC_PROTOCOL_VERSION_UNKNOWN);
+    CU_ASSERT_EQUAL(guac_protocol_string_to_version(str_version_d), GUAC_PROTOCOL_VERSION_UNKNOWN);
     
 }
 
@@ -63,7 +63,7 @@
  */
 void test_gauc_protocol__version_comparison() {
     
-    CU_ASSERT_TRUE_FATAL(GUAC_PROTOCOL_VERSION_1_3_0 > GUAC_PROTOCOL_VERSION_1_0_0);
-    CU_ASSERT_TRUE_FATAL(GUAC_PROTOCOL_VERSION_UNKNOWN < GUAC_PROTOCOL_VERSION_1_1_0);
+    CU_ASSERT_TRUE(GUAC_PROTOCOL_VERSION_1_3_0 > GUAC_PROTOCOL_VERSION_1_0_0);
+    CU_ASSERT_TRUE(GUAC_PROTOCOL_VERSION_UNKNOWN < GUAC_PROTOCOL_VERSION_1_1_0);
     
 }
\ No newline at end of file
diff --git a/src/protocols/rdp/rdp.c b/src/protocols/rdp/rdp.c
index 8bf1f22..6c80abc 100644
--- a/src/protocols/rdp/rdp.c
+++ b/src/protocols/rdp/rdp.c
@@ -43,6 +43,7 @@
 #include "pointer.h"
 #include "print-job.h"
 #include "rdp.h"
+#include "settings.h"
 
 #ifdef ENABLE_COMMON_SSH
 #include "common-ssh/sftp.h"
@@ -70,6 +71,7 @@
 #include <guacamole/client.h>
 #include <guacamole/protocol.h>
 #include <guacamole/socket.h>
+#include <guacamole/string.h>
 #include <guacamole/timestamp.h>
 #include <guacamole/wol.h>
 #include <winpr/error.h>
@@ -236,7 +238,7 @@
     guac_client* client = ((rdp_freerdp_context*) context)->client;
     guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
     guac_rdp_settings* settings = rdp_client->settings;
-    char* params[4] = {};
+    char* params[4] = {NULL};
     int i = 0;
     
     /* If the client does not support the "required" instruction, warn and
@@ -275,15 +277,17 @@
     
     if (i > 0) {
         
-        /* Send required parameters to the owner. */
+        /* Send required parameters to the owner and wait for the response. */
         guac_client_owner_send_required(client, (const char**) params);
-        
         guac_argv_await((const char**) params);
         
-        /* Get new values from settings. */
-        *username = settings->username;
-        *password = settings->password;
-        *domain = settings->domain;
+        /* Free old values and get new values from settings. */
+        free(*username);
+        free(*password);
+        free(*domain);
+        *username = guac_strdup(settings->username);
+        *password = guac_strdup(settings->password);
+        *domain = guac_strdup(settings->domain);
         
     }
     
diff --git a/src/protocols/rdp/settings.c b/src/protocols/rdp/settings.c
index bac8af0..57760d9 100644
--- a/src/protocols/rdp/settings.c
+++ b/src/protocols/rdp/settings.c
@@ -1267,47 +1267,25 @@
 
 }
 
-/**
- * Simple wrapper for strdup() which behaves identically to standard strdup(),
- * execpt that NULL will be returned if the provided string is NULL.
- *
- * @param str
- *     The string to duplicate as a newly-allocated string.
- *
- * @return
- *     A newly-allocated string containing identically the same content as the
- *     given string, or NULL if the given string was NULL.
- */
-static char* guac_rdp_strdup(const char* str) {
-
-    /* Return NULL if no string provided */
-    if (str == NULL)
-        return NULL;
-
-    /* Otherwise just invoke strdup() */
-    return strdup(str);
-
-}
-
 void guac_rdp_push_settings(guac_client* client,
         guac_rdp_settings* guac_settings, freerdp* rdp) {
 
     rdpSettings* rdp_settings = rdp->settings;
 
     /* Authentication */
-    rdp_settings->Domain = guac_rdp_strdup(guac_settings->domain);
-    rdp_settings->Username = guac_rdp_strdup(guac_settings->username);
-    rdp_settings->Password = guac_rdp_strdup(guac_settings->password);
+    rdp_settings->Domain = guac_strdup(guac_settings->domain);
+    rdp_settings->Username = guac_strdup(guac_settings->username);
+    rdp_settings->Password = guac_strdup(guac_settings->password);
 
     /* Connection */
-    rdp_settings->ServerHostname = guac_rdp_strdup(guac_settings->hostname);
+    rdp_settings->ServerHostname = guac_strdup(guac_settings->hostname);
     rdp_settings->ServerPort = guac_settings->port;
 
     /* Session */
     rdp_settings->ColorDepth = guac_settings->color_depth;
     rdp_settings->DesktopWidth = guac_settings->width;
     rdp_settings->DesktopHeight = guac_settings->height;
-    rdp_settings->AlternateShell = guac_rdp_strdup(guac_settings->initial_program);
+    rdp_settings->AlternateShell = guac_strdup(guac_settings->initial_program);
     rdp_settings->KeyboardLayout = guac_settings->server_layout->freerdp_keyboard_layout;
 
     /* Performance flags */
@@ -1425,9 +1403,9 @@
         rdp_settings->Workarea = TRUE;
         rdp_settings->RemoteApplicationMode = TRUE;
         rdp_settings->RemoteAppLanguageBarSupported = TRUE;
-        rdp_settings->RemoteApplicationProgram = guac_rdp_strdup(guac_settings->remote_app);
-        rdp_settings->ShellWorkingDirectory = guac_rdp_strdup(guac_settings->remote_app_dir);
-        rdp_settings->RemoteApplicationCmdLine = guac_rdp_strdup(guac_settings->remote_app_args);
+        rdp_settings->RemoteApplicationProgram = guac_strdup(guac_settings->remote_app);
+        rdp_settings->ShellWorkingDirectory = guac_strdup(guac_settings->remote_app_dir);
+        rdp_settings->RemoteApplicationCmdLine = guac_strdup(guac_settings->remote_app_args);
     }
 
     /* Preconnection ID */
@@ -1441,7 +1419,7 @@
     if (guac_settings->preconnection_blob != NULL) {
         rdp_settings->NegotiateSecurityLayer = FALSE;
         rdp_settings->SendPreconnectionPdu = TRUE;
-        rdp_settings->PreconnectionBlob = guac_rdp_strdup(guac_settings->preconnection_blob);
+        rdp_settings->PreconnectionBlob = guac_strdup(guac_settings->preconnection_blob);
     }
 
     /* Enable use of RD gateway if a gateway hostname is provided */
@@ -1451,20 +1429,20 @@
         rdp_settings->GatewayEnabled = TRUE;
 
         /* RD gateway connection details */
-        rdp_settings->GatewayHostname = guac_rdp_strdup(guac_settings->gateway_hostname);
+        rdp_settings->GatewayHostname = guac_strdup(guac_settings->gateway_hostname);
         rdp_settings->GatewayPort = guac_settings->gateway_port;
 
         /* RD gateway credentials */
         rdp_settings->GatewayUseSameCredentials = FALSE;
-        rdp_settings->GatewayDomain = guac_rdp_strdup(guac_settings->gateway_domain);
-        rdp_settings->GatewayUsername = guac_rdp_strdup(guac_settings->gateway_username);
-        rdp_settings->GatewayPassword = guac_rdp_strdup(guac_settings->gateway_password);
+        rdp_settings->GatewayDomain = guac_strdup(guac_settings->gateway_domain);
+        rdp_settings->GatewayUsername = guac_strdup(guac_settings->gateway_username);
+        rdp_settings->GatewayPassword = guac_strdup(guac_settings->gateway_password);
 
     }
 
     /* Store load balance info (and calculate length) if provided */
     if (guac_settings->load_balance_info != NULL) {
-        rdp_settings->LoadBalanceInfo = (BYTE*) guac_rdp_strdup(guac_settings->load_balance_info);
+        rdp_settings->LoadBalanceInfo = (BYTE*) guac_strdup(guac_settings->load_balance_info);
         rdp_settings->LoadBalanceInfoLength = strlen(guac_settings->load_balance_info);
     }
 
diff --git a/src/protocols/rdp/user.c b/src/protocols/rdp/user.c
index e7a91d7..351c67e 100644
--- a/src/protocols/rdp/user.c
+++ b/src/protocols/rdp/user.c
@@ -118,8 +118,9 @@
         /* Inbound arbitrary named pipes */
         user->pipe_handler = guac_rdp_pipe_svc_pipe_handler;
         
-        /* Handler for updating parameters during connection. */
-        user->argv_handler = guac_argv_handler;
+        /* If we own it, register handler for updating parameters during connection. */
+        if (user->owner)
+            user->argv_handler = guac_argv_handler;
 
     }
 
diff --git a/src/protocols/vnc/auth.c b/src/protocols/vnc/auth.c
index 12f8361..b5a74b1 100644
--- a/src/protocols/vnc/auth.c
+++ b/src/protocols/vnc/auth.c
@@ -63,6 +63,7 @@
 }
 
 rfbCredential* guac_vnc_get_credentials(rfbClient* client, int credentialType) {
+    
     guac_client* gc = rfbClientGetClientData(client, GUAC_VNC_CLIENT_KEY);
     guac_vnc_client* vnc_client = ((guac_vnc_client*) gc->data);
     guac_vnc_settings* settings = vnc_client->settings;
@@ -71,43 +72,46 @@
     if (credentialType == rfbCredentialTypeUser) {
         rfbCredential *creds = malloc(sizeof(rfbCredential));
         
-        /* If the client does not support the "required" instruction, just return
-           the parameters already configured. */
-        if (!guac_client_owner_supports_required(gc)) {
-            creds->userCredential.username = settings->username;
-            creds->userCredential.password = settings->password;
-            return creds;
+        /* If the client supports the "required" instruction, prompt for and
+           update those. */
+        if (guac_client_owner_supports_required(gc)) {
+            char* params[3] = {NULL};
+            int i = 0;
+
+            /* Check if username is null or empty. */
+            if (settings->username == NULL) {
+                guac_argv_register(GUAC_VNC_ARGV_USERNAME, guac_vnc_argv_callback, NULL, 0);
+                params[i] = GUAC_VNC_ARGV_USERNAME;
+                i++;
+            }
+
+            /* Check if password is null or empty. */
+            if (settings->password == NULL) {
+                guac_argv_register(GUAC_VNC_ARGV_PASSWORD, guac_vnc_argv_callback, NULL, 0);
+                params[i] = GUAC_VNC_ARGV_PASSWORD;
+                i++;
+            }
+
+            params[i] = NULL;
+
+            /* If we have empty parameters, request them. */
+            if (i > 0) {
+
+                /* Send required parameters to owner. */
+                guac_client_owner_send_required(gc, (const char**) params);
+
+                /* Wait for the parameters to be returned. */
+                guac_argv_await((const char**) params);
+
+                return creds;
+
+            }
         }
         
-        char* params[2] = {NULL};
-        int i = 0;
-        
-        /* Check if username is null or empty. */
-        if (settings->username == NULL) {
-            guac_argv_register(GUAC_VNC_ARGV_USERNAME, guac_vnc_argv_callback, NULL, 0);
-            params[i] = GUAC_VNC_ARGV_USERNAME;
-            i++;
-        }
-        
-        /* Check if password is null or empty. */
-        if (settings->password == NULL) {
-            guac_argv_register(GUAC_VNC_ARGV_PASSWORD, guac_vnc_argv_callback, NULL, 0);
-            params[i] = GUAC_VNC_ARGV_PASSWORD;
-            i++;
-        }
-        
-        /* If we have empty parameters, request them. */
-        if (i > 0) {
-            
-            /* Send required parameters to owner. */
-            guac_client_owner_send_required(gc, (const char**) params);
-            
-            /* Wait for the parameters to be returned. */
-            guac_argv_await((const char**) params);
-            
-            return creds;
-            
-        }
+        /* Copy the values and return the credential set. */
+        creds->userCredential.username = strdup(settings->username);
+        creds->userCredential.password = strdup(settings->password);
+        return creds;
         
     }
 
diff --git a/src/protocols/vnc/user.c b/src/protocols/vnc/user.c
index 807cd0e..4e6f473 100644
--- a/src/protocols/vnc/user.c
+++ b/src/protocols/vnc/user.c
@@ -100,8 +100,9 @@
         if (!settings->disable_paste)
             user->clipboard_handler = guac_vnc_clipboard_handler;
         
-        /* Updates to connection parameters */
-        user->argv_handler = guac_argv_handler;
+        /* Updates to connection parameters if we own the connection */
+        if (user->owner)
+            user->argv_handler = guac_argv_handler;
 
 #ifdef ENABLE_COMMON_SSH
         /* Set generic (non-filesystem) file upload handler */