1 /**
2  * xrdp: A Remote Desktop Protocol server.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * This file implements the interface in chansrv_config.h
17  */
18 #if defined(HAVE_CONFIG_H)
19 #include <config_ac.h>
20 #endif
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25 
26 #include "arch.h"
27 
28 #include "list.h"
29 #include "log.h"
30 #include "file.h"
31 #include "os_calls.h"
32 
33 #include "chansrv_config.h"
34 #include "string_calls.h"
35 
36 /* Default settings */
37 #define DEFAULT_USE_UNIX_SOCKET             0
38 #define DEFAULT_RESTRICT_OUTBOUND_CLIPBOARD 0
39 #define DEFAULT_ENABLE_FUSE_MOUNT           1
40 #define DEFAULT_FUSE_MOUNT_NAME             "xrdp-client"
41 #define DEFAULT_FILE_UMASK                  077
42 
43 /**
44  * Type used for passing a logging function about
45  */
46 typedef
47 printflike(2, 3)
48 enum logReturns (*log_func_t)(const enum logLevels lvl,
49                               const char *msg, ...);
50 
51 /***************************************************************************//**
52  * @brief Error logging function to use to log to stdout
53  *
54  * Has the same signature as the log_message() function
55  */
56 static enum logReturns
log_to_stdout(const enum logLevels lvl,const char * msg,...)57 log_to_stdout(const enum logLevels lvl, const char *msg, ...)
58 {
59     char buff[256];
60     va_list ap;
61 
62     va_start(ap, msg);
63     vsnprintf(buff, sizeof(buff), msg, ap);
64     va_end(ap);
65     g_writeln("%s", buff);
66 
67     return LOG_STARTUP_OK;
68 }
69 
70 /***************************************************************************//**
71  * Reads the config values we need from the [Globals] section
72  *
73  * @param logmsg Function to use to log messages
74  * @param names List of definitions in the section
75  * @params values List of corresponding values for the names
76  * @params cfg Pointer to structure we're filling in
77  *
78  * @return 0 for success
79  */
80 static int
read_config_globals(log_func_t logmsg,struct list * names,struct list * values,struct config_chansrv * cfg)81 read_config_globals(log_func_t logmsg,
82                     struct list *names, struct list *values,
83                     struct config_chansrv *cfg)
84 {
85     int error = 0;
86     int index;
87 
88     for (index = 0; index < names->count; ++index)
89     {
90         const char *name = (const char *)list_get_item(names, index);
91         const char *value = (const char *)list_get_item(values, index);
92 
93         if (g_strcasecmp(name, "ListenAddress") == 0)
94         {
95             if (g_strcasecmp(value, "127.0.0.1") == 0)
96             {
97                 cfg->use_unix_socket = 1;
98             }
99         }
100     }
101 
102     return error;
103 }
104 
105 /***************************************************************************//**
106  * Reads the config values we need from the [Security] section
107  *
108  * @param logmsg Function to use to log messages
109  * @param names List of definitions in the section
110  * @params values List of corresponding values for the names
111  * @params cfg Pointer to structure we're filling in
112  *
113  * @return 0 for success
114  */
115 static int
read_config_security(log_func_t logmsg,struct list * names,struct list * values,struct config_chansrv * cfg)116 read_config_security(log_func_t logmsg,
117                      struct list *names, struct list *values,
118                      struct config_chansrv *cfg)
119 {
120     int error = 0;
121     int index;
122 
123     for (index = 0; index < names->count; ++index)
124     {
125         const char *name = (const char *)list_get_item(names, index);
126         const char *value = (const char *)list_get_item(values, index);
127 
128         if (g_strcasecmp(name, "RestrictOutboundClipboard") == 0)
129         {
130             cfg->restrict_outbound_clipboard = g_text2bool(value);
131         }
132     }
133 
134     return error;
135 }
136 
137 /***************************************************************************//**
138  * Reads the config values we need from the [Chansrv] section
139  *
140  * @param logmsg Function to use to log messages
141  * @param names List of definitions in the section
142  * @params values List of corresponding values for the names
143  * @params cfg Pointer to structure we're filling in
144  *
145  * @return 0 for success
146  */
147 static int
read_config_chansrv(log_func_t logmsg,struct list * names,struct list * values,struct config_chansrv * cfg)148 read_config_chansrv(log_func_t logmsg,
149                     struct list *names, struct list *values,
150                     struct config_chansrv *cfg)
151 {
152     int error = 0;
153     int index;
154 
155     for (index = 0; index < names->count; ++index)
156     {
157         const char *name = (const char *)list_get_item(names, index);
158         const char *value = (const char *)list_get_item(values, index);
159 
160         if (g_strcasecmp(name, "EnableFuseMount") == 0)
161         {
162             cfg->enable_fuse_mount = g_text2bool(value);
163         }
164         if (g_strcasecmp(name, "FuseMountName") == 0)
165         {
166             g_free(cfg->fuse_mount_name);
167             cfg->fuse_mount_name = g_strdup(value);
168             if (cfg->fuse_mount_name == NULL)
169             {
170                 logmsg(LOG_LEVEL_ERROR, "Can't alloc FuseMountName");
171                 error = 1;
172                 break;
173             }
174         }
175         else if (g_strcasecmp(name, "FileUmask") == 0)
176         {
177             cfg->file_umask = strtol(value, NULL, 0);
178         }
179     }
180 
181     return error;
182 }
183 
184 /***************************************************************************//**
185  * @brief returns a config block with default values
186  *
187  * @return Block, or NULL for no memory
188  */
189 static struct config_chansrv *
new_config(void)190 new_config(void)
191 {
192     /* Do all the allocations at the beginning, then check them together */
193     struct config_chansrv *cfg = g_new0(struct config_chansrv, 1);
194     char *fuse_mount_name = g_strdup(DEFAULT_FUSE_MOUNT_NAME);
195     if (cfg == NULL || fuse_mount_name == NULL)
196     {
197         /* At least one memory allocation failed */
198         g_free(fuse_mount_name);
199         g_free(cfg);
200         cfg = NULL;
201     }
202     else
203     {
204         cfg->use_unix_socket = DEFAULT_USE_UNIX_SOCKET;
205         cfg->enable_fuse_mount = DEFAULT_ENABLE_FUSE_MOUNT;
206         cfg->restrict_outbound_clipboard = DEFAULT_RESTRICT_OUTBOUND_CLIPBOARD;
207         cfg->fuse_mount_name = fuse_mount_name;
208         cfg->file_umask = DEFAULT_FILE_UMASK;
209     }
210 
211     return cfg;
212 }
213 
214 /******************************************************************************/
215 struct config_chansrv *
config_read(int use_logger,const char * sesman_ini)216 config_read(int use_logger, const char *sesman_ini)
217 {
218     int error = 0;
219     struct config_chansrv *cfg = NULL;
220     log_func_t logmsg = (use_logger) ? log_message : log_to_stdout;
221     int fd;
222 
223     fd = g_file_open_ex(sesman_ini, 1, 0, 0, 0);
224     if (fd < 0)
225     {
226         logmsg(LOG_LEVEL_ERROR, "Can't open config file %s", sesman_ini);
227         error = 1;
228     }
229     else
230     {
231         if ((cfg = new_config()) == NULL)
232         {
233             logmsg(LOG_LEVEL_ERROR, "Can't alloc config block");
234             error = 1;
235         }
236         else
237         {
238             struct list *names = list_create();
239             struct list *values = list_create();
240 
241             names->auto_free = 1;
242             values->auto_free = 1;
243 
244             if (!error && file_read_section(fd, "Globals", names, values) == 0)
245             {
246                 error = read_config_globals(logmsg, names, values, cfg);
247             }
248 
249 
250             if (!error && file_read_section(fd, "Security", names, values) == 0)
251             {
252                 error = read_config_security(logmsg, names, values, cfg);
253             }
254 
255             if (!error && file_read_section(fd, "Chansrv", names, values) == 0)
256             {
257                 error = read_config_chansrv(logmsg, names, values, cfg);
258             }
259 
260             list_delete(names);
261             list_delete(values);
262         }
263 
264         g_file_close(fd);
265     }
266 
267     if (error)
268     {
269         config_free(cfg);
270         cfg = NULL;
271     }
272 
273     return cfg;
274 }
275 
276 /******************************************************************************/
277 void
config_dump(struct config_chansrv * config)278 config_dump(struct config_chansrv *config)
279 {
280     g_writeln("Global configuration:");
281     g_writeln("    UseUnixSocket (derived):   %s",
282               g_bool2text(config->use_unix_socket));
283 
284     g_writeln("\nSecurity configuration:");
285     g_writeln("    RestrictOutboundClipboard: %s",
286               g_bool2text(config->restrict_outbound_clipboard));
287 
288     g_writeln("\nChansrv configuration:");
289     g_writeln("    EnableFuseMount            %s",
290               g_bool2text(config->enable_fuse_mount));
291     g_writeln("    FuseMountName:             %s", config->fuse_mount_name);
292     g_writeln("    FileMask:                  0%o", config->file_umask);
293 }
294 
295 /******************************************************************************/
296 void
config_free(struct config_chansrv * cc)297 config_free(struct config_chansrv *cc)
298 {
299     if (cc != NULL)
300     {
301         g_free(cc->fuse_mount_name);
302         g_free(cc);
303     }
304 }
305