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