1 /* Copyright (C) 2018-2021 Greenbone Networks GmbH
2  *
3  * SPDX-License-Identifier: AGPL-3.0-or-later
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Affero General Public License as
7  * published by the Free Software Foundation, either version 3 of the
8  * License, or (at your option) any later version.
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 Affero General Public License for more details.
14  *
15  * You should have received a copy of the GNU Affero General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /**
20  * @file gmp_base.c
21  * @brief GVM GMP layer: Base facilities.
22  *
23  * GMP base facilities used by all modules, but not exported for users of the GMP
24  * layer (i.e. gmpd.c).
25  */
26 
27 #include "gmp_base.h"
28 #include "manage.h"
29 
30 #include <stdlib.h>
31 #include <string.h>
32 
33 #include <gvm/base/strings.h>
34 
35 #undef G_LOG_DOMAIN
36 /**
37  * @brief GLib log domain.
38  */
39 #define G_LOG_DOMAIN "md    gmp"
40 
41 /**
42  * @brief Find an attribute in a parser callback list of attributes.
43  *
44  * @param[in]   attribute_names   List of names.
45  * @param[in]   attribute_values  List of values.
46  * @param[in]   attribute_name    Name of sought attribute.
47  * @param[out]  attribute_value   Attribute value return.
48  *
49  * @return 1 if found, else 0.
50  */
51 int
find_attribute(const gchar ** attribute_names,const gchar ** attribute_values,const char * attribute_name,const gchar ** attribute_value)52 find_attribute (const gchar **attribute_names,
53                 const gchar **attribute_values,
54                 const char *attribute_name,
55                 const gchar **attribute_value)
56 {
57   while (*attribute_names && *attribute_values)
58     if (strcmp (*attribute_names, attribute_name))
59       attribute_names++, attribute_values++;
60     else
61       {
62         *attribute_value = *attribute_values;
63         return 1;
64       }
65   return 0;
66 }
67 
68 /**
69  * @brief Find an attribute in a parser callback list of attributes and append
70  * @brief it to a string using gvm_append_string.
71  *
72  * @param[in]   attribute_names   List of names.
73  * @param[in]   attribute_values  List of values.
74  * @param[in]   attribute_name    Name of sought attribute.
75  * @param[out]  string            String to append attribute value to, if
76  *                                found.
77  *
78  * @return 1 if found and appended, else 0.
79  */
80 int
append_attribute(const gchar ** attribute_names,const gchar ** attribute_values,const char * attribute_name,gchar ** string)81 append_attribute (const gchar **attribute_names,
82                   const gchar **attribute_values,
83                   const char *attribute_name,
84                   gchar **string)
85 {
86   const gchar* attribute;
87   if (find_attribute (attribute_names, attribute_values, attribute_name,
88                       &attribute))
89     {
90       gvm_append_string (string, attribute);
91       return 1;
92     }
93   return 0;
94 }
95 
96 /**
97  * @brief Format XML into a buffer.
98  *
99  * @param[in]  buffer  Buffer.
100  * @param[in]  format  Format string for XML.
101  * @param[in]  ...     Arguments for format string.
102  */
103 void
buffer_xml_append_printf(GString * buffer,const char * format,...)104 buffer_xml_append_printf (GString *buffer, const char *format, ...)
105 {
106   va_list args;
107   gchar *msg;
108   va_start (args, format);
109   msg = g_markup_vprintf_escaped (format, args);
110   va_end (args);
111   g_string_append (buffer, msg);
112   g_free (msg);
113 }
114 
115 
116 /* Communication. */
117 
118 /**
119  * @brief Send a response message to the client.
120  *
121  * @param[in]  msg                       The message, a string.
122  * @param[in]  user_send_to_client       Function to send to client.
123  * @param[in]  user_send_to_client_data  Argument to \p user_send_to_client.
124  *
125  * @return TRUE if send to client failed, else FALSE.
126  */
127 gboolean
send_to_client(const char * msg,int (* user_send_to_client)(const char *,void *),void * user_send_to_client_data)128 send_to_client (const char* msg,
129                 int (*user_send_to_client) (const char*, void*),
130                 void* user_send_to_client_data)
131 {
132   if (user_send_to_client && msg)
133     return user_send_to_client (msg, user_send_to_client_data);
134   return FALSE;
135 }
136 
137 /**
138  * @brief Send an XML find error response message to the client.
139  *
140  * @param[in]  command      Command name.
141  * @param[in]  type         Resource type.
142  * @param[in]  id           Resource ID.
143  * @param[in]  gmp_parser   GMP Parser.
144  *
145  * @return TRUE if out of space in to_client, else FALSE.
146  */
147 gboolean
send_find_error_to_client(const char * command,const char * type,const char * id,gmp_parser_t * gmp_parser)148 send_find_error_to_client (const char* command, const char* type,
149                            const char* id, gmp_parser_t *gmp_parser)
150 {
151   gchar *msg;
152   gboolean ret;
153 
154   msg = g_markup_printf_escaped ("<%s_response status=\""
155                                  STATUS_ERROR_MISSING
156                                  "\" status_text=\"Failed to find %s '%s'\"/>",
157                                  command, type, id);
158   ret = send_to_client (msg, gmp_parser->client_writer,
159                         gmp_parser->client_writer_data);
160   g_free (msg);
161   return ret;
162 }
163 
164 /**
165  * @brief Set an out of space parse error on a GError.
166  *
167  * @param [out]  error  The error.
168  */
169 void
error_send_to_client(GError ** error)170 error_send_to_client (GError** error)
171 {
172   g_debug ("   send_to_client out of space in to_client");
173   g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
174                "Manager out of space for reply to client.");
175 }
176 
177 /**
178  * @brief Set an internal error on a GError.
179  *
180  * @param [out]  error  The error.
181  */
182 void
internal_error_send_to_client(GError ** error)183 internal_error_send_to_client (GError** error)
184 {
185   g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
186                "Internal Error.");
187 }
188 
189 /**
190  * @brief Creates a log event entry for a resource action.
191  *
192  * @param[in]   type        Resource type.
193  * @param[in]   type_name   Resource type name.
194  * @param[in]   id          Resource id.
195  * @param[in]   action      Action done.
196  * @param[in]   fail        Whether it is a fail event.
197  */
198 static void
log_event_internal(const char * type,const char * type_name,const char * id,const char * action,int fail)199 log_event_internal (const char *type, const char *type_name, const char *id,
200                     const char *action, int fail)
201 {
202   gchar *domain;
203 
204   domain = g_strdup_printf ("event %s", type);
205 
206   if (id)
207     {
208       char *name;
209 
210       if (manage_resource_name (type, id, &name))
211         name = NULL;
212       else if ((name == NULL)
213                && manage_trash_resource_name (type, id, &name))
214         name = NULL;
215 
216       if (name)
217         g_log (domain, G_LOG_LEVEL_MESSAGE,
218                "%s %s (%s) %s %s by %s",
219                type_name, name, id,
220                fail ? "could not be" : "has been",
221                action,
222                current_credentials.username);
223       else
224         g_log (domain, G_LOG_LEVEL_MESSAGE,
225                "%s %s %s %s by %s",
226                type_name, id,
227                fail ? "could not be" : "has been",
228                action,
229                current_credentials.username);
230 
231       free (name);
232     }
233   else
234     g_log (domain, G_LOG_LEVEL_MESSAGE,
235            "%s %s %s by %s",
236            type_name,
237            fail ? "could not be" : "has been",
238            action,
239            current_credentials.username);
240 
241   g_free (domain);
242 }
243 
244 /**
245  * @brief Creates a log event entry for a resource action.
246  *
247  * @param[in]   type        Resource type.
248  * @param[in]   type_name   Resource type name.
249  * @param[in]   id          Resource id.
250  * @param[in]   action      Action done.
251  */
252 void
log_event(const char * type,const char * type_name,const char * id,const char * action)253 log_event (const char *type, const char *type_name, const char *id,
254            const char *action)
255 {
256   log_event_internal (type, type_name, id, action, 0);
257 }
258 
259 /**
260  * @brief Creates a log event failure entry for a resource action.
261  *
262  * @param[in]   type        Resource type.
263  * @param[in]   type_name   Resource type name.
264  * @param[in]   id          Resource id.
265  * @param[in]   action      Action done.
266  */
267 void
log_event_fail(const char * type,const char * type_name,const char * id,const char * action)268 log_event_fail (const char *type, const char *type_name, const char *id,
269                 const char *action)
270 {
271   log_event_internal (type, type_name, id, action, 1);
272 }
273