|
28 | 28 | #include <client_protocol.h> |
29 | 29 | #include <definitions.h> |
30 | 30 | #include <net.h> |
| 31 | +#include <stat_cache.h> |
31 | 32 | #include <string_lib.h> |
32 | 33 | #include <tls_generic.h> |
33 | 34 |
|
@@ -88,3 +89,122 @@ Seq *ProtocolOpenDir(AgentConnection *conn, const char *path) |
88 | 89 |
|
89 | 90 | return seq; |
90 | 91 | } |
| 92 | + |
| 93 | +bool ProtocolGet(AgentConnection *conn, const char *remote_path, |
| 94 | + const char *local_path, const uint32_t file_size, int perms) |
| 95 | +{ |
| 96 | + assert(conn != NULL); |
| 97 | + assert(remote_path != NULL); |
| 98 | + assert(local_path != NULL); |
| 99 | + assert(file_size != 0); |
| 100 | + |
| 101 | + perms = (perms == 0) ? CF_PERMS_DEFAULT : perms; |
| 102 | + |
| 103 | + unlink(local_path); |
| 104 | + FILE *file_ptr = safe_fopen_create_perms(local_path, "wx", perms); |
| 105 | + if (file_ptr == NULL) |
| 106 | + { |
| 107 | + Log(LOG_LEVEL_WARNING, "Failed to open file %s (fopen: %s)", |
| 108 | + local_path, GetErrorStr()); |
| 109 | + return false; |
| 110 | + } |
| 111 | + |
| 112 | + char buf[CF_MSGSIZE] = {0}; |
| 113 | + int to_send = snprintf(buf, CF_MSGSIZE, "GET %d %s", |
| 114 | + CF_MSGSIZE, remote_path); |
| 115 | + |
| 116 | + |
| 117 | + int ret = SendTransaction(conn->conn_info, buf, to_send, CF_DONE); |
| 118 | + if (ret == -1) |
| 119 | + { |
| 120 | + Log(LOG_LEVEL_WARNING, "Failed to send request for remote file %s:%s", |
| 121 | + conn->this_server, remote_path); |
| 122 | + unlink(local_path); |
| 123 | + fclose(file_ptr); |
| 124 | + return false; |
| 125 | + } |
| 126 | + |
| 127 | + char cfchangedstr[sizeof(CF_CHANGEDSTR1 CF_CHANGEDSTR2)]; |
| 128 | + snprintf(cfchangedstr, sizeof(cfchangedstr), "%s%s", |
| 129 | + CF_CHANGEDSTR1, CF_CHANGEDSTR2); |
| 130 | + |
| 131 | + bool success = true; |
| 132 | + uint32_t received_bytes = 0; |
| 133 | + while (received_bytes < file_size) |
| 134 | + { |
| 135 | + int len = TLSRecv(conn->conn_info->ssl, buf, CF_MSGSIZE); |
| 136 | + if (len == -1) |
| 137 | + { |
| 138 | + Log(LOG_LEVEL_WARNING, "Failed to GET file %s:%s", |
| 139 | + conn->this_server, remote_path); |
| 140 | + success = false; |
| 141 | + break; |
| 142 | + } |
| 143 | + else if (len > CF_MSGSIZE) |
| 144 | + { |
| 145 | + Log(LOG_LEVEL_WARNING, |
| 146 | + "Incorrect length of incoming packet " |
| 147 | + "while retrieving %s:%s, %d > %d", |
| 148 | + conn->this_server, remote_path, len, CF_MSGSIZE); |
| 149 | + success = false; |
| 150 | + break; |
| 151 | + } |
| 152 | + |
| 153 | + if (BadProtoReply(buf)) |
| 154 | + { |
| 155 | + Log(LOG_LEVEL_ERR, |
| 156 | + "Error from server while retrieving file %s:%s: %s", |
| 157 | + conn->this_server, remote_path, buf); |
| 158 | + success = false; |
| 159 | + break; |
| 160 | + } |
| 161 | + |
| 162 | + if (StringSafeEqualN(buf, cfchangedstr, sizeof(cfchangedstr) - 1)) |
| 163 | + { |
| 164 | + Log(LOG_LEVEL_ERR, |
| 165 | + "Remote file %s:%s changed during file transfer", |
| 166 | + conn->this_server, remote_path); |
| 167 | + success = false; |
| 168 | + break; |
| 169 | + } |
| 170 | + |
| 171 | + ret = fwrite(buf, sizeof(char), len, file_ptr); |
| 172 | + if (ret < 0) |
| 173 | + { |
| 174 | + Log(LOG_LEVEL_ERR, |
| 175 | + "Failed to write during retrieval of file %s:%s (fwrite: %s)", |
| 176 | + conn->this_server, remote_path, GetErrorStr()); |
| 177 | + success = false; |
| 178 | + break; |
| 179 | + } |
| 180 | + |
| 181 | + received_bytes += len; |
| 182 | + } |
| 183 | + |
| 184 | + if (!success) |
| 185 | + { |
| 186 | + unlink(local_path); |
| 187 | + } |
| 188 | + |
| 189 | + fclose(file_ptr); |
| 190 | + return success; |
| 191 | +} |
| 192 | + |
| 193 | +bool ProtocolStatGet(AgentConnection *conn, const char *remote_path, |
| 194 | + const char *local_path, int perms) |
| 195 | +{ |
| 196 | + assert(conn != NULL); |
| 197 | + assert(remote_path != NULL); |
| 198 | + |
| 199 | + struct stat sb; |
| 200 | + int ret = cf_remote_stat(conn, false, remote_path, &sb, "file"); |
| 201 | + if (ret == -1) |
| 202 | + { |
| 203 | + Log(LOG_LEVEL_ERR, |
| 204 | + "%s: Failed to stat remote file %s:%s", |
| 205 | + __func__, conn->this_server, remote_path); |
| 206 | + return false; |
| 207 | + } |
| 208 | + |
| 209 | + return ProtocolGet(conn, remote_path, local_path, sb.st_size, perms); |
| 210 | +} |
0 commit comments