1 /* 2 Copyright 2021 Northern.tech AS 3 4 This file is part of CFEngine 3 - written and maintained by Northern.tech AS. 5 6 This program is free software; you can redistribute it and/or modify it 7 under the terms of the GNU General Public License as published by the 8 Free Software Foundation; version 3. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 18 19 To the extent this program is licensed as part of the Enterprise 20 versions of CFEngine, the applicable Commercial Open Source License 21 (COSL) may apply to this file if you as a licensee so wish it. See 22 included file COSL.txt. 23 */ 24 25 #ifndef CFENGINE_PROTOCOL_H 26 #define CFENGINE_PROTOCOL_H 27 28 #include <cfnet.h> 29 #include <sequence.h> 30 #include <protocol_version.h> // ProtocolVersion 31 32 /** 33 * Receives a directory listing from a remote host. 34 * 35 * The server will use "/var/cfengine" as working directory if absolute path 36 * is not specified. The server sends the directory entries as a string 37 * separated by NUL-bytes, and ending with the magic string CFD_TERMINATOR. 38 * 39 * The function shall fail if connection is not established, or if the server 40 * gives a bad response (denoted by a message preceded by "BAD"). 41 * 42 * @param [in] conn The connection to use 43 * @param [in] path Path on remote host 44 * @return A sequence of filenames in the requested directory on success, NULL 45 * on failure. 46 * 47 * Example (for printing each directory entry): 48 * @code 49 * AgentConnection *conn = ServerConnection("127.0.0.1", "666", ...); 50 * Seq *dir = ProtocolOpenDir(conn, "masterfiles"); 51 * for (int i = 0; i < SeqLength(dir); i++) 52 * { 53 * char *entry = SeqAt(i); 54 * printf("%s\n", entry); 55 * } 56 * @endcode 57 * 58 * In the protocol, this will look like this on the server side: 59 * Received: OPENDIR masterfiles 60 * Translated to: OPENDIR /var/cfengine/masterfiles 61 * Sends string: 62 * ".\0..\0cfe_internal\0cf_promises_release_id\0... 63 * ...templates\0update.cf\0" CFD_TERMINATOR 64 */ 65 Seq *ProtocolOpenDir(AgentConnection *conn, const char *path); 66 67 /** 68 * Receives a file from a remote host. 69 * 70 * The server will use "/var/cfengine" as working directory if absolute path 71 * is not specified. The client will send a request that looks like this: 72 * `GET <buf_size> <remote_path>` 73 * 74 * `buf_size` is the local buffer size: how much of the file to receive in 75 * each transaction. It should be aligned to block size (which is usually 76 * 4096), but currently the protocol only allows _exactly_ 4095 bytes per 77 * transaction. 78 * 79 * The function shall fail if connection is not established, or if the server 80 * gives a bad response (denoted by a message preceded by "BAD"). 81 * 82 * @param [in] conn The connection to use 83 * @param [in] remote_path Path on remote host 84 * @param [in] local_path Path of received file 85 * @param [in] file_size Size of file to get 86 * @param [in] perms Permissions of local file 87 * @return True if file was successfully transferred, false otherwise 88 * 89 * Example (for printing each directory entry): 90 * @code 91 * AgentConnection *conn = ServerConnection("127.0.0.1", "666", ...); 92 * bool got_file = ProtocolGet(conn, "masterfiles/update.cf", 93 * "update.cf", CF_MSGSIZE, 0644); 94 * if (got_file) 95 * { 96 * struct stat sb; 97 * stat("update.cf", &sb); 98 * printf("This file is %ld big!\n", sb.st_size); 99 * } 100 * @endcode 101 * 102 * In the protocol, this will look like this on the server side: 103 * Received: GET masterfiles/update.cf 104 * Translated to: GET /var/cfengine/masterfiles/update.cf 105 */ 106 bool ProtocolGet(AgentConnection *conn, const char *remote_path, 107 const char *local_path, const uint32_t file_size, int perms); 108 109 110 /** 111 * Receives a file from a remote host, see documentation for #ProtocolGet 112 * 113 * This funtion will first stat the remote path before attempting to receive 114 * it. 115 */ 116 bool ProtocolStatGet(AgentConnection *conn, const char *remote_path, 117 const char *local_path, int perms); 118 119 /** 120 * Receives statistics about a remote file. 121 * 122 * This is a cacheless version of #cf_remote_stat from stat_cache.c. This 123 * only supports sending with the latest cfnet protocol. 124 * 125 * When the `STAT` request is sent, it is sent together with the current time 126 * since the Epoch given by the `time` syscall denoted by `SYNCH <tloc>`. If 127 * the server is set to deny bad clocks (which is default), it will reject 128 * `STAT` requests from hosts where the clocks differ too much. 129 * 130 * When the server accepts the `STAT` request, it will send each field of the 131 * `Stat` struct from `stat_cache.h` as numbers delimited by spaces in a 132 * single string. Since the `Stat` struct is not cached, its fields are 133 * transferred to the \p stat_buf parameter. 134 * 135 * Example 136 * @code 137 * AgentConnection *conn = ServerConnection("127.0.0.1", "666", ...); 138 * struct stat stat_buf; 139 * ProtocolStat(conn, "masterfiles/update.cf", &stat_buf); 140 * assert((stat_buf.st_mode & S_IFMT) == S_IFREG); 141 * @endcode 142 * 143 * This is how the above example looks on the server side: 144 * Received: SYNCH 12356789 STAT masterfiles/update.cf 145 * Translated to: STAT /var/cfengine/masterfiles/update.cf 146 * Sends string: 147 * "OK: 0 33188 0 ..." etc. 148 * 149 * @param [in] conn The connection to use 150 * @param [in] remote_path Path on remote host 151 * @param [out] stat_buf Where to store statistics 152 * @return true on success, false on failure. 153 */ 154 bool ProtocolStat(AgentConnection *conn, const char *remote_path, 155 struct stat *stat_buf); 156 157 #endif 158