1 /**
2  * xrdp: A Remote Desktop Protocol server.
3  *
4  * Copyright (C) Jay Sorg 2004-2015
5  *
6  * BSD process grouping by:
7  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland.
8  * Copyright (c) 2000-2001 Markus Friedl.
9  * Copyright (c) 2011-2015 Koichiro Iwao, Kyushu Institute of Technology.
10  *
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  *     http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  */
23 
24 /**
25  *
26  * @file session.c
27  * @brief Session management code
28  * @author Jay Sorg, Simone Fedele
29  *
30  */
31 
32 #if defined(HAVE_CONFIG_H)
33 #include "config_ac.h"
34 #endif
35 
36 #ifdef HAVE_SYS_PRCTL_H
37 #include <sys/prctl.h>
38 #endif
39 
40 #include "sesman.h"
41 #include "libscp_types.h"
42 #include "xauth.h"
43 #include "xrdp_sockets.h"
44 #include "string_calls.h"
45 
46 #ifndef PR_SET_NO_NEW_PRIVS
47 #define PR_SET_NO_NEW_PRIVS 38
48 #endif
49 
50 extern unsigned char g_fixedkey[8];
51 extern struct config_sesman *g_cfg; /* in sesman.c */
52 extern int g_sck; /* in sesman.c */
53 struct session_chain *g_sessions;
54 int g_session_count;
55 
56 extern tbus g_term_event; /* in sesman.c */
57 
58 /**
59  * Creates a string consisting of all parameters that is hosted in the param list
60  * @param self
61  * @param outstr, allocate this buffer before you use this function
62  * @param len the allocated len for outstr
63  * @return
64  */
65 char *
dumpItemsToString(struct list * self,char * outstr,int len)66 dumpItemsToString(struct list *self, char *outstr, int len)
67 {
68     int index;
69     int totalLen = 0;
70 
71     g_memset(outstr, 0, len);
72     if (self->count == 0)
73     {
74         LOG_DEVEL(LOG_LEVEL_TRACE, "List is empty");
75     }
76 
77     for (index = 0; index < self->count; index++)
78     {
79         /* +1 = one space*/
80         totalLen = totalLen + g_strlen((char *)list_get_item(self, index)) + 1;
81 
82         if (len > totalLen)
83         {
84             g_strcat(outstr, (char *)list_get_item(self, index));
85             g_strcat(outstr, " ");
86         }
87     }
88 
89     return outstr ;
90 }
91 
92 
93 /******************************************************************************/
94 struct session_item *
session_get_bydata(const char * name,int width,int height,int bpp,int type,const char * client_ip)95 session_get_bydata(const char *name, int width, int height, int bpp, int type,
96                    const char *client_ip)
97 {
98     struct session_chain *tmp;
99     enum SESMAN_CFG_SESS_POLICY policy = g_cfg->sess.policy;
100 
101     tmp = g_sessions;
102 
103     /* convert from SCP_SESSION_TYPE namespace to SESMAN_SESSION_TYPE namespace */
104     switch (type)
105     {
106         case SCP_SESSION_TYPE_XVNC: /* 0 */
107             type = SESMAN_SESSION_TYPE_XVNC; /* 2 */
108             break;
109         case SCP_SESSION_TYPE_XRDP: /* 1 */
110             type = SESMAN_SESSION_TYPE_XRDP; /* 1 */
111             break;
112         case SCP_SESSION_TYPE_XORG:
113             type = SESMAN_SESSION_TYPE_XORG;
114             break;
115         default:
116             return 0;
117     }
118 
119     LOG(LOG_LEVEL_DEBUG,
120         "session_get_bydata: search policy %d U %s W %d H %d bpp %d T %d IP %s",
121         policy, name, width, height, bpp, type, client_ip);
122 
123     while (tmp != 0)
124     {
125         LOG(LOG_LEVEL_DEBUG,
126             "session_get_bydata: try %p U %s W %d H %d bpp %d T %d IP %s",
127             tmp->item,
128             tmp->item->name,
129             tmp->item->width, tmp->item->height,
130             tmp->item->bpp, tmp->item->type,
131             tmp->item->client_ip);
132 
133         if (g_strncmp(name, tmp->item->name, 255) == 0 &&
134                 (!(policy & SESMAN_CFG_SESS_POLICY_D) ||
135                  (tmp->item->width == width && tmp->item->height == height)) &&
136                 (!(policy & SESMAN_CFG_SESS_POLICY_I) ||
137                  (g_strncmp_d(client_ip, tmp->item->client_ip, ':', 255) == 0)) &&
138                 (!(policy & SESMAN_CFG_SESS_POLICY_C) ||
139                  (g_strncmp(client_ip, tmp->item->client_ip, 255) == 0)) &&
140                 tmp->item->bpp == bpp &&
141                 tmp->item->type == type)
142         {
143             return tmp->item;
144         }
145 
146         tmp = tmp->next;
147     }
148 
149     return 0;
150 }
151 
152 /******************************************************************************/
153 /**
154  *
155  * @brief checks if there's a server running on a display
156  * @param display the display to check
157  * @return 0 if there isn't a display running, nonzero otherwise
158  *
159  */
160 static int
x_server_running_check_ports(int display)161 x_server_running_check_ports(int display)
162 {
163     char text[256];
164     int x_running;
165     int sck;
166 
167     g_sprintf(text, "/tmp/.X11-unix/X%d", display);
168     x_running = g_file_exist(text);
169 
170     if (!x_running)
171     {
172         LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
173         g_sprintf(text, "/tmp/.X%d-lock", display);
174         x_running = g_file_exist(text);
175     }
176 
177     if (!x_running) /* check 59xx */
178     {
179         LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
180         if ((sck = g_tcp_socket()) != -1)
181         {
182             g_sprintf(text, "59%2.2d", display);
183             x_running = g_tcp_bind(sck, text);
184             g_tcp_close(sck);
185         }
186     }
187 
188     if (!x_running) /* check 60xx */
189     {
190         LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
191         if ((sck = g_tcp_socket()) != -1)
192         {
193             g_sprintf(text, "60%2.2d", display);
194             x_running = g_tcp_bind(sck, text);
195             g_tcp_close(sck);
196         }
197     }
198 
199     if (!x_running) /* check 62xx */
200     {
201         LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
202         if ((sck = g_tcp_socket()) != -1)
203         {
204             g_sprintf(text, "62%2.2d", display);
205             x_running = g_tcp_bind(sck, text);
206             g_tcp_close(sck);
207         }
208     }
209 
210     if (!x_running)
211     {
212         LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
213         g_sprintf(text, XRDP_CHANSRV_STR, display);
214         x_running = g_file_exist(text);
215     }
216 
217     if (!x_running)
218     {
219         LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
220         g_sprintf(text, CHANSRV_PORT_OUT_STR, display);
221         x_running = g_file_exist(text);
222     }
223 
224     if (!x_running)
225     {
226         LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
227         g_sprintf(text, CHANSRV_PORT_IN_STR, display);
228         x_running = g_file_exist(text);
229     }
230 
231     if (!x_running)
232     {
233         LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
234         g_sprintf(text, CHANSRV_API_STR, display);
235         x_running = g_file_exist(text);
236     }
237 
238     if (!x_running)
239     {
240         LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
241         g_sprintf(text, XRDP_X11RDP_STR, display);
242         x_running = g_file_exist(text);
243     }
244 
245     if (x_running)
246     {
247         LOG(LOG_LEVEL_INFO, "Found X server running at %s", text);
248     }
249 
250     return x_running;
251 }
252 
253 /******************************************************************************/
254 /**
255  *
256  * @brief checks if there's a server running on a display
257  * @param display the display to check
258  * @return 0 if there isn't a display running, nonzero otherwise
259  *
260  */
261 static int
x_server_running(int display)262 x_server_running(int display)
263 {
264     char text[256];
265     int x_running;
266 
267     g_sprintf(text, "/tmp/.X11-unix/X%d", display);
268     x_running = g_file_exist(text);
269 
270     if (!x_running)
271     {
272         LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
273         g_sprintf(text, "/tmp/.X%d-lock", display);
274         x_running = g_file_exist(text);
275     }
276 
277     if (x_running)
278     {
279         LOG(LOG_LEVEL_INFO, "Found X server running at %s", text);
280     }
281     else
282     {
283         LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
284     }
285 
286     return x_running;
287 }
288 
289 /******************************************************************************/
290 /* called with the main thread
291    returns boolean */
292 static int
session_is_display_in_chain(int display)293 session_is_display_in_chain(int display)
294 {
295     struct session_chain *chain;
296     struct session_item *item;
297 
298     chain = g_sessions;
299 
300     while (chain != 0)
301     {
302         item = chain->item;
303 
304         if (item->display == display)
305         {
306             return 1;
307         }
308 
309         chain = chain->next;
310     }
311 
312     return 0;
313 }
314 
315 /******************************************************************************/
316 /* called with the main thread */
317 static int
session_get_avail_display_from_chain(void)318 session_get_avail_display_from_chain(void)
319 {
320     int display;
321 
322     display = g_cfg->sess.x11_display_offset;
323 
324     while ((display - g_cfg->sess.x11_display_offset) <= g_cfg->sess.max_sessions)
325     {
326         if (!session_is_display_in_chain(display))
327         {
328             if (!x_server_running_check_ports(display))
329             {
330                 return display;
331             }
332         }
333 
334         display++;
335     }
336 
337     LOG(LOG_LEVEL_ERROR, "X server -- no display in range (%d to %d) is available",
338         g_cfg->sess.x11_display_offset,
339         g_cfg->sess.x11_display_offset + g_cfg->sess.max_sessions);
340     return 0;
341 }
342 
343 /******************************************************************************/
344 static int
wait_for_xserver(int display)345 wait_for_xserver(int display)
346 {
347     int i;
348 
349     /* give X a bit to start */
350     /* wait up to 10 secs for x server to start */
351     i = 0;
352 
353     LOG(LOG_LEVEL_DEBUG, "Waiting for X server to start on display %d", display);
354 
355     while (!x_server_running(display))
356     {
357         i++;
358 
359         if (i > 40)
360         {
361             LOG(LOG_LEVEL_WARNING,
362                 "Timed out waiting for X server on display %d to startup",
363                 display);
364             break;
365         }
366 
367         g_sleep(250);
368     }
369 
370     return 0;
371 }
372 
373 /******************************************************************************/
374 static int
session_start_chansrv(char * username,int display)375 session_start_chansrv(char *username, int display)
376 {
377     struct list *chansrv_params;
378     char exe_path[262];
379     int chansrv_pid;
380 
381     chansrv_pid = g_fork();
382     if (chansrv_pid == 0)
383     {
384         LOG(LOG_LEVEL_INFO,
385             "Starting the xrdp channel server for display %d", display);
386 
387         chansrv_params = list_create();
388         chansrv_params->auto_free = 1;
389 
390         /* building parameters */
391         g_snprintf(exe_path, sizeof(exe_path), "%s/xrdp-chansrv",
392                    XRDP_SBIN_PATH);
393 
394         list_add_item(chansrv_params, (intptr_t) g_strdup(exe_path));
395         list_add_item(chansrv_params, 0); /* mandatory */
396 
397         env_set_user(username, 0, display,
398                      g_cfg->env_names,
399                      g_cfg->env_values);
400 
401         /* executing chansrv */
402         g_execvp(exe_path, (char **) (chansrv_params->items));
403 
404         /* should not get here */
405         list_delete(chansrv_params);
406         g_exit(1);
407     }
408     return chansrv_pid;
409 }
410 
411 /******************************************************************************/
412 /* called with the main thread */
413 static int
session_start_fork(tbus data,tui8 type,struct SCP_CONNECTION * c,struct SCP_SESSION * s)414 session_start_fork(tbus data, tui8 type, struct SCP_CONNECTION *c,
415                    struct SCP_SESSION *s)
416 {
417     int display = 0;
418     int pid = 0;
419     char geometry[32];
420     char depth[32];
421     char screen[32]; /* display number */
422     char text[256];
423     char execvpparams[2048];
424     char *xserver = NULL; /* absolute/relative path to Xorg/X11rdp/Xvnc */
425     char *passwd_file;
426     char **pp1 = (char **)NULL;
427     struct session_chain *temp = (struct session_chain *)NULL;
428     struct list *xserver_params = (struct list *)NULL;
429     struct tm stime;
430     time_t ltime;
431     char authfile[256]; /* The filename for storing xauth informations */
432     int chansrv_pid;
433     int display_pid;
434     int window_manager_pid;
435 
436     /* initialize (zero out) local variables: */
437     g_memset(&ltime, 0, sizeof(time_t));
438     g_memset(&stime, 0, sizeof(struct tm));
439     g_memset(geometry, 0, sizeof(char) * 32);
440     g_memset(depth, 0, sizeof(char) * 32);
441     g_memset(screen, 0, sizeof(char) * 32);
442     g_memset(text, 0, sizeof(char) * 256);
443 
444     passwd_file = 0;
445 
446     /* check to limit concurrent sessions */
447     if (g_session_count >= g_cfg->sess.max_sessions)
448     {
449         LOG(LOG_LEVEL_ERROR, "max concurrent session limit "
450             "exceeded. login for user %s denied", s->username);
451         return 0;
452     }
453 
454     temp = (struct session_chain *)g_malloc(sizeof(struct session_chain), 0);
455 
456     if (temp == 0)
457     {
458         LOG(LOG_LEVEL_ERROR, "Out of memory error: cannot create new session "
459             "chain element - user %s", s->username);
460         return 0;
461     }
462 
463     temp->item = (struct session_item *)g_malloc(sizeof(struct session_item), 0);
464 
465     if (temp->item == 0)
466     {
467         g_free(temp);
468         LOG(LOG_LEVEL_ERROR, "Out of memory error: cannot create new session "
469             "item - user %s", s->username);
470         return 0;
471     }
472 
473     display = session_get_avail_display_from_chain();
474 
475     if (display == 0)
476     {
477         g_free(temp->item);
478         g_free(temp);
479         return 0;
480     }
481 
482     pid = g_fork(); /* parent is fork from tcp accept,
483                        child forks X and wm, then becomes scp */
484 
485     if (pid == -1)
486     {
487         LOG(LOG_LEVEL_ERROR,
488             "[session start] (display %d): Failed to fork for scp with "
489             "errno: %d, description: %s",
490             display, g_get_errno(), g_get_strerror());
491     }
492     else if (pid == 0)
493     {
494         LOG(LOG_LEVEL_INFO,
495             "[session start] (display %d): calling auth_start_session from pid %d",
496             display, g_getpid());
497         auth_start_session(data, display);
498         g_delete_wait_obj(g_term_event);
499         g_tcp_close(g_sck);
500         g_tcp_close(c->in_sck);
501         g_sprintf(geometry, "%dx%d", s->width, s->height);
502         g_sprintf(depth, "%d", s->bpp);
503         g_sprintf(screen, ":%d", display);
504 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
505         /*
506          * FreeBSD bug
507          * ports/157282: effective login name is not set by xrdp-sesman
508          * http://www.freebsd.org/cgi/query-pr.cgi?pr=157282
509          *
510          * from:
511          *  $OpenBSD: session.c,v 1.252 2010/03/07 11:57:13 dtucker Exp $
512          *  with some ideas about BSD process grouping to xrdp
513          */
514         pid_t bsdsespid = g_fork();
515 
516         if (bsdsespid == -1)
517         {
518         }
519         else if (bsdsespid == 0) /* BSD session leader */
520         {
521             /**
522              * Create a new session and process group since the 4.4BSD
523              * setlogin() affects the entire process group
524              */
525             if (g_setsid() < 0)
526             {
527                 LOG(LOG_LEVEL_WARNING,
528                     "[session start] (display %d): setsid failed - pid %d",
529                     display, g_getpid());
530             }
531 
532             if (g_setlogin(s->username) < 0)
533             {
534                 LOG(LOG_LEVEL_WARNING,
535                     "[session start] (display %d): setlogin failed for user %s - pid %d",
536                     display, s->username, g_getpid());
537             }
538         }
539 
540         g_waitpid(bsdsespid);
541 
542         if (bsdsespid > 0)
543         {
544             g_exit(0);
545             /*
546              * intermediate sesman should exit here after WM exits.
547              * do not execure the following codes.
548              */
549         }
550 #endif
551         window_manager_pid = g_fork(); /* parent becomes X,
552                              child forks wm, and waits, todo */
553         if (window_manager_pid == -1)
554         {
555             LOG(LOG_LEVEL_ERROR,
556                 "Failed to fork for the window manager on display %d", display);
557         }
558         else if (window_manager_pid == 0)
559         {
560             wait_for_xserver(display);
561             env_set_user(s->username,
562                          0,
563                          display,
564                          g_cfg->env_names,
565                          g_cfg->env_values);
566             if (x_server_running(display))
567             {
568                 auth_set_env(data);
569                 if (s->directory != 0)
570                 {
571                     if (s->directory[0] != 0)
572                     {
573                         g_set_current_dir(s->directory);
574                     }
575                 }
576                 if (s->program != 0 && s->program[0] != 0)
577                 {
578                     if (g_strchr(s->program, ' ') != 0 || g_strchr(s->program, '\t') != 0)
579                     {
580                         LOG(LOG_LEVEL_INFO,
581                             "Starting user requested window manager on "
582                             "display %d with embeded arguments using a shell: %s",
583                             display, s->program);
584                         const char *params[] = {"sh", "-c", s->program, NULL};
585                         g_execvp("/bin/sh", (char **)params);
586                     }
587                     else
588                     {
589                         LOG(LOG_LEVEL_INFO,
590                             "Starting user requested window manager on "
591                             "display %d: %s", display, s->program);
592                         g_execlp3(s->program, s->program, 0);
593                     }
594                 }
595                 else
596                 {
597                     LOG(LOG_LEVEL_DEBUG, "The user session on display %d did "
598                         "not request a specific window manager", display);
599                 }
600 
601                 /* try to execute user window manager if enabled */
602                 if (g_cfg->enable_user_wm)
603                 {
604                     g_sprintf(text, "%s/%s", g_getenv("HOME"), g_cfg->user_wm);
605                     if (g_file_exist(text))
606                     {
607                         LOG(LOG_LEVEL_INFO,
608                             "Starting window manager on display %d"
609                             "from user home directory: %s", display, text);
610                         g_execlp3(text, g_cfg->user_wm, 0);
611                     }
612                     else
613                     {
614                         LOG(LOG_LEVEL_DEBUG,
615                             "The user home directory window manager configuration "
616                             "is enabled but window manager program does not exist: %s",
617                             text);
618                     }
619                 }
620 
621                 LOG(LOG_LEVEL_INFO,
622                     "Starting the default window manager on display %d: %s",
623                     display, g_cfg->default_wm);
624                 g_execlp3(g_cfg->default_wm, g_cfg->default_wm, 0);
625 
626                 /* still a problem starting window manager just start xterm */
627                 LOG(LOG_LEVEL_WARNING,
628                     "No window manager on display %d started, "
629                     "so falling back to starting xterm for user debugging",
630                     display);
631                 g_execlp3("xterm", "xterm", 0);
632 
633                 /* should not get here */
634             }
635             else
636             {
637                 LOG(LOG_LEVEL_ERROR,
638                     "There is no X server active on display %d", display);
639             }
640 
641             LOG(LOG_LEVEL_ERROR, "A fatal error has occured attempting to start "
642                 "the window manager on display %d, aborting connection",
643                 display);
644             g_exit(0);
645         }
646         else
647         {
648             display_pid = g_fork(); /* parent becomes scp,
649                                 child becomes X */
650             if (display_pid == -1)
651             {
652                 LOG(LOG_LEVEL_ERROR,
653                     "Failed to fork for the X server on display %d", display);
654             }
655             else if (display_pid == 0) /* child */
656             {
657                 if (type == SESMAN_SESSION_TYPE_XVNC)
658                 {
659                     env_set_user(s->username,
660                                  &passwd_file,
661                                  display,
662                                  g_cfg->env_names,
663                                  g_cfg->env_values);
664                 }
665                 else
666                 {
667                     env_set_user(s->username,
668                                  0,
669                                  display,
670                                  g_cfg->env_names,
671                                  g_cfg->env_values);
672                 }
673 
674                 /* setting Xserver environment variables */
675                 g_snprintf(text, 255, "%d", g_cfg->sess.max_idle_time);
676                 g_setenv("XRDP_SESMAN_MAX_IDLE_TIME", text, 1);
677                 g_snprintf(text, 255, "%d", g_cfg->sess.max_disc_time);
678                 g_setenv("XRDP_SESMAN_MAX_DISC_TIME", text, 1);
679                 g_snprintf(text, 255, "%d", g_cfg->sess.kill_disconnected);
680                 g_setenv("XRDP_SESMAN_KILL_DISCONNECTED", text, 1);
681                 g_setenv("XRDP_SOCKET_PATH", XRDP_SOCKET_PATH, 1);
682 
683                 /* prepare the Xauthority stuff */
684                 if (g_getenv("XAUTHORITY") != NULL)
685                 {
686                     g_snprintf(authfile, 255, "%s", g_getenv("XAUTHORITY"));
687                 }
688                 else
689                 {
690                     g_snprintf(authfile, 255, "%s", ".Xauthority");
691                 }
692 
693                 /* Add the entry in XAUTHORITY file or exit if error */
694                 if (add_xauth_cookie(display, authfile) != 0)
695                 {
696                     LOG(LOG_LEVEL_ERROR,
697                         "Error setting the xauth cookie for display %d in file %s",
698                         display, authfile);
699 
700                     LOG(LOG_LEVEL_ERROR, "A fatal error has occured attempting to start "
701                         "the X server on display %d, aborting connection",
702                         display);
703                     g_exit(1);
704                 }
705 
706                 if (type == SESMAN_SESSION_TYPE_XORG)
707                 {
708 #ifdef HAVE_SYS_PRCTL_H
709                     /*
710                      * Make sure Xorg doesn't run setuid root. Root access is not
711                      * needed. Xorg can fail when run as root and the user has no
712                      * console permissions.
713                      * PR_SET_NO_NEW_PRIVS requires Linux kernel 3.5 and newer.
714                      */
715                     if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0)
716                     {
717                         LOG(LOG_LEVEL_WARNING,
718                             "[session start] (display %d): Failed to disable "
719                             "setuid on X server: %s",
720                             display, g_get_strerror());
721                     }
722 #endif
723 
724                     xserver_params = list_create();
725                     xserver_params->auto_free = 1;
726 
727                     /* get path of Xorg from config */
728                     xserver = g_strdup((const char *)list_get_item(g_cfg->xorg_params, 0));
729 
730                     /* these are the must have parameters */
731                     list_add_item(xserver_params, (tintptr) g_strdup(xserver));
732                     list_add_item(xserver_params, (tintptr) g_strdup(screen));
733                     list_add_item(xserver_params, (tintptr) g_strdup("-auth"));
734                     list_add_item(xserver_params, (tintptr) g_strdup(authfile));
735 
736                     /* additional parameters from sesman.ini file */
737                     list_append_list_strdup(g_cfg->xorg_params, xserver_params, 1);
738 
739                     /* make sure it ends with a zero */
740                     list_add_item(xserver_params, 0);
741 
742                     pp1 = (char **) xserver_params->items;
743 
744                     /* some args are passed via env vars */
745                     g_sprintf(geometry, "%d", s->width);
746                     g_setenv("XRDP_START_WIDTH", geometry, 1);
747 
748                     g_sprintf(geometry, "%d", s->height);
749                     g_setenv("XRDP_START_HEIGHT", geometry, 1);
750                 }
751                 else if (type == SESMAN_SESSION_TYPE_XVNC)
752                 {
753                     char guid_str[64];
754                     g_bytes_to_hexstr(s->guid, 16, guid_str, 64);
755                     env_check_password_file(passwd_file, guid_str);
756                     xserver_params = list_create();
757                     xserver_params->auto_free = 1;
758 
759                     /* get path of Xvnc from config */
760                     xserver = g_strdup((const char *)list_get_item(g_cfg->vnc_params, 0));
761 
762                     /* these are the must have parameters */
763                     list_add_item(xserver_params, (tintptr)g_strdup(xserver));
764                     list_add_item(xserver_params, (tintptr)g_strdup(screen));
765                     list_add_item(xserver_params, (tintptr)g_strdup("-auth"));
766                     list_add_item(xserver_params, (tintptr)g_strdup(authfile));
767                     list_add_item(xserver_params, (tintptr)g_strdup("-geometry"));
768                     list_add_item(xserver_params, (tintptr)g_strdup(geometry));
769                     list_add_item(xserver_params, (tintptr)g_strdup("-depth"));
770                     list_add_item(xserver_params, (tintptr)g_strdup(depth));
771                     list_add_item(xserver_params, (tintptr)g_strdup("-rfbauth"));
772                     list_add_item(xserver_params, (tintptr)g_strdup(passwd_file));
773 
774                     g_free(passwd_file);
775 
776                     /* additional parameters from sesman.ini file */
777                     //config_read_xserver_params(SESMAN_SESSION_TYPE_XVNC,
778                     //                           xserver_params);
779                     list_append_list_strdup(g_cfg->vnc_params, xserver_params, 1);
780 
781                     /* make sure it ends with a zero */
782                     list_add_item(xserver_params, 0);
783                     pp1 = (char **)xserver_params->items;
784                 }
785                 else if (type == SESMAN_SESSION_TYPE_XRDP)
786                 {
787                     xserver_params = list_create();
788                     xserver_params->auto_free = 1;
789 
790                     /* get path of X11rdp from config */
791                     xserver = g_strdup((const char *)list_get_item(g_cfg->rdp_params, 0));
792 
793                     /* these are the must have parameters */
794                     list_add_item(xserver_params, (tintptr)g_strdup(xserver));
795                     list_add_item(xserver_params, (tintptr)g_strdup(screen));
796                     list_add_item(xserver_params, (tintptr)g_strdup("-auth"));
797                     list_add_item(xserver_params, (tintptr)g_strdup(authfile));
798                     list_add_item(xserver_params, (tintptr)g_strdup("-geometry"));
799                     list_add_item(xserver_params, (tintptr)g_strdup(geometry));
800                     list_add_item(xserver_params, (tintptr)g_strdup("-depth"));
801                     list_add_item(xserver_params, (tintptr)g_strdup(depth));
802 
803                     /* additional parameters from sesman.ini file */
804                     //config_read_xserver_params(SESMAN_SESSION_TYPE_XRDP,
805                     //                           xserver_params);
806                     list_append_list_strdup(g_cfg->rdp_params, xserver_params, 1);
807 
808                     /* make sure it ends with a zero */
809                     list_add_item(xserver_params, 0);
810                     pp1 = (char **)xserver_params->items;
811                 }
812                 else
813                 {
814                     LOG(LOG_LEVEL_ERROR, "Unknown session type: %d", type);
815                     LOG(LOG_LEVEL_ERROR, "A fatal error has occured attempting "
816                         "to start the X server on display %d, aborting connection",
817                         display);
818                     g_exit(1);
819                 }
820 
821                 /* fire up X server */
822                 LOG(LOG_LEVEL_INFO, "Starting X server on display %d: %s",
823                     display, dumpItemsToString(xserver_params, execvpparams, 2048));
824                 g_execvp(xserver, pp1);
825 
826                 /* should not get here */
827                 LOG(LOG_LEVEL_ERROR,
828                     "Error starting X server on display %d", display);
829                 LOG(LOG_LEVEL_ERROR, "A fatal error has occured attempting "
830                     "to start the X server on display %d, aborting connection",
831                     display);
832 
833                 list_delete(xserver_params);
834                 g_exit(1);
835             }
836             else
837             {
838                 int wm_wait_time;
839                 struct exit_status wm_exit_status;
840                 struct exit_status xserver_exit_status;
841                 struct exit_status chansrv_exit_status;
842 
843                 wait_for_xserver(display);
844                 chansrv_pid = session_start_chansrv(s->username, display);
845 
846                 LOG(LOG_LEVEL_INFO,
847                     "Session started successfully for user %s on display %d",
848                     s->username, display);
849 
850                 /* Monitor the amount of time we wait for the
851                  * window manager. This is approximately how long the window
852                  * manager was running for */
853                 LOG(LOG_LEVEL_INFO, "Session in progress on display %d, waiting "
854                     "until the window manager (pid %d) exits to end the session",
855                     display, window_manager_pid);
856                 wm_wait_time = g_time1();
857                 wm_exit_status = g_waitpid_status(window_manager_pid);
858                 wm_wait_time = g_time1() - wm_wait_time;
859                 if (wm_exit_status.exit_code > 0)
860                 {
861                     LOG(LOG_LEVEL_WARNING, "Window manager (pid %d, display %d) "
862                         "exited with non-zero exit code %d and signal %d. This "
863                         "could indicate a window manager config problem",
864                         window_manager_pid, display, wm_exit_status.exit_code,
865                         wm_exit_status.signal_no);
866                 }
867                 if (wm_wait_time < 10)
868                 {
869                     /* This could be a config issue. Log a significant error */
870                     LOG(LOG_LEVEL_WARNING, "Window manager (pid %d, display %d) "
871                         "exited quickly (%d secs). This could indicate a window "
872                         "manager config problem",
873                         window_manager_pid, display, wm_wait_time);
874                 }
875                 else
876                 {
877                     LOG(LOG_LEVEL_DEBUG, "Window manager (pid %d, display %d) "
878                         "was running for %d seconds.",
879                         window_manager_pid, display, wm_wait_time);
880                 }
881                 LOG(LOG_LEVEL_INFO,
882                     "Calling auth_stop_session and auth_end from pid %d",
883                     g_getpid());
884                 auth_stop_session(data);
885                 auth_end(data);
886 
887                 LOG(LOG_LEVEL_INFO,
888                     "Terminating X server (pid %d) on display %d",
889                     display_pid, display);
890                 g_sigterm(display_pid);
891 
892                 LOG(LOG_LEVEL_INFO, "Terminating the xrdp channel server (pid %d) "
893                     "on display %d", chansrv_pid, display);
894                 g_sigterm(chansrv_pid);
895 
896                 /* make sure socket cleanup happen after child process exit */
897                 xserver_exit_status = g_waitpid_status(display_pid);
898                 LOG(LOG_LEVEL_INFO,
899                     "X server on display %d (pid %d) returned exit code %d "
900                     "and signal number %d",
901                     display, display_pid, xserver_exit_status.exit_code,
902                     xserver_exit_status.signal_no);
903 
904                 chansrv_exit_status = g_waitpid_status(chansrv_pid);
905                 LOG(LOG_LEVEL_INFO,
906                     "xrdp channel server for display %d (pid %d) "
907                     "exit code %d and signal number %d",
908                     display, chansrv_pid, chansrv_exit_status.exit_code,
909                     chansrv_exit_status.signal_no);
910 
911                 cleanup_sockets(display);
912                 g_deinit();
913                 g_exit(0);
914             }
915         }
916     }
917     else
918     {
919         LOG(LOG_LEVEL_INFO, "Starting session: session_pid %d, "
920             "display :%d.0, width %d, height %d, bpp %d, client ip %s, "
921             "user name %s",
922             pid, display, s->width, s->height, s->bpp, s->client_ip, s->username);
923         temp->item->pid = pid;
924         temp->item->display = display;
925         temp->item->width = s->width;
926         temp->item->height = s->height;
927         temp->item->bpp = s->bpp;
928         temp->item->data = data;
929         g_strncpy(temp->item->client_ip, s->client_ip, 255);   /* store client ip data */
930         g_strncpy(temp->item->name, s->username, 255);
931         g_memcpy(temp->item->guid, s->guid, 16);
932 
933         ltime = g_time1();
934         localtime_r(&ltime, &stime);
935         temp->item->connect_time.year = (tui16)(stime.tm_year + 1900);
936         temp->item->connect_time.month = (tui8)(stime.tm_mon + 1);
937         temp->item->connect_time.day = (tui8)stime.tm_mday;
938         temp->item->connect_time.hour = (tui8)stime.tm_hour;
939         temp->item->connect_time.minute = (tui8)stime.tm_min;
940         zero_time(&(temp->item->disconnect_time));
941         zero_time(&(temp->item->idle_time));
942 
943         temp->item->type = type;
944         temp->item->status = SESMAN_SESSION_STATUS_ACTIVE;
945 
946         temp->next = g_sessions;
947         g_sessions = temp;
948         g_session_count++;
949 
950         return display;
951     }
952 
953     g_free(temp->item);
954     g_free(temp);
955     return display;
956 }
957 
958 /******************************************************************************/
959 /* called with the main thread */
960 static int
session_reconnect_fork(int display,char * username,long data)961 session_reconnect_fork(int display, char *username, long data)
962 {
963     int pid;
964 
965     pid = g_fork();
966 
967     if (pid == -1)
968     {
969         LOG(LOG_LEVEL_ERROR, "Failed to fork for session reconnection script");
970     }
971     else if (pid == 0)
972     {
973         env_set_user(username,
974                      0,
975                      display,
976                      g_cfg->env_names,
977                      g_cfg->env_values);
978         auth_set_env(data);
979 
980         if (g_file_exist(g_cfg->reconnect_sh))
981         {
982             LOG(LOG_LEVEL_INFO,
983                 "Starting session reconnection script on display %d: %s",
984                 display, g_cfg->reconnect_sh);
985             g_execlp3(g_cfg->reconnect_sh, g_cfg->reconnect_sh, 0);
986 
987             /* should not get here */
988             LOG(LOG_LEVEL_ERROR,
989                 "Error starting session reconnection script on display %d: %s",
990                 display, g_cfg->reconnect_sh);
991         }
992         else
993         {
994             LOG(LOG_LEVEL_WARNING,
995                 "Session reconnection script file does not exist: %s",
996                 g_cfg->reconnect_sh);
997         }
998 
999         /* TODO: why is this existing with a success error code when the
1000             reconnect script failed to be executed? */
1001         g_exit(0);
1002     }
1003 
1004     return display;
1005 }
1006 
1007 /******************************************************************************/
1008 /* called by a worker thread, ask the main thread to call session_sync_start
1009    and wait till done */
1010 int
session_start(long data,tui8 type,struct SCP_CONNECTION * c,struct SCP_SESSION * s)1011 session_start(long data, tui8 type, struct SCP_CONNECTION *c,
1012               struct SCP_SESSION *s)
1013 {
1014     return session_start_fork(data, type, c, s);
1015 }
1016 
1017 /******************************************************************************/
1018 /* called by a worker thread, ask the main thread to call session_sync_start
1019    and wait till done */
1020 int
session_reconnect(int display,char * username,long data)1021 session_reconnect(int display, char *username, long data)
1022 {
1023     return session_reconnect_fork(display, username, data);
1024 }
1025 
1026 /******************************************************************************/
1027 int
session_kill(int pid)1028 session_kill(int pid)
1029 {
1030     struct session_chain *tmp;
1031     struct session_chain *prev;
1032 
1033     tmp = g_sessions;
1034     prev = 0;
1035 
1036     while (tmp != 0)
1037     {
1038         if (tmp->item == 0)
1039         {
1040             LOG(LOG_LEVEL_ERROR, "session descriptor for "
1041                 "pid %d is null!", pid);
1042 
1043             if (prev == 0)
1044             {
1045                 /* prev does no exist, so it's the first element - so we set
1046                    g_sessions */
1047                 g_sessions = tmp->next;
1048             }
1049             else
1050             {
1051                 prev->next = tmp->next;
1052             }
1053 
1054             return SESMAN_SESSION_KILL_NULLITEM;
1055         }
1056 
1057         if (tmp->item->pid == pid)
1058         {
1059             /* deleting the session */
1060             LOG(LOG_LEVEL_INFO,
1061                 "++ terminated session:  username %s, display :%d.0, session_pid %d, ip %s",
1062                 tmp->item->name, tmp->item->display, tmp->item->pid, tmp->item->client_ip);
1063             g_free(tmp->item);
1064 
1065             if (prev == 0)
1066             {
1067                 /* prev does no exist, so it's the first element - so we set
1068                    g_sessions */
1069                 g_sessions = tmp->next;
1070             }
1071             else
1072             {
1073                 prev->next = tmp->next;
1074             }
1075 
1076             g_free(tmp);
1077             g_session_count--;
1078             return SESMAN_SESSION_KILL_OK;
1079         }
1080 
1081         /* go on */
1082         prev = tmp;
1083         tmp = tmp->next;
1084     }
1085 
1086     return SESMAN_SESSION_KILL_NOTFOUND;
1087 }
1088 
1089 /******************************************************************************/
1090 void
session_sigkill_all(void)1091 session_sigkill_all(void)
1092 {
1093     struct session_chain *tmp;
1094 
1095     tmp = g_sessions;
1096 
1097     while (tmp != 0)
1098     {
1099         if (tmp->item == 0)
1100         {
1101             LOG(LOG_LEVEL_ERROR, "found null session descriptor!");
1102         }
1103         else
1104         {
1105             g_sigterm(tmp->item->pid);
1106         }
1107 
1108         /* go on */
1109         tmp = tmp->next;
1110     }
1111 }
1112 
1113 /******************************************************************************/
1114 struct session_item *
session_get_bypid(int pid)1115 session_get_bypid(int pid)
1116 {
1117     struct session_chain *tmp;
1118     struct session_item *dummy;
1119 
1120     dummy = g_new0(struct session_item, 1);
1121 
1122     if (0 == dummy)
1123     {
1124         LOG(LOG_LEVEL_ERROR, "session_get_bypid: out of memory");
1125         return 0;
1126     }
1127 
1128     tmp = g_sessions;
1129 
1130     while (tmp != 0)
1131     {
1132         if (tmp->item == 0)
1133         {
1134             LOG(LOG_LEVEL_ERROR, "session descriptor for pid %d is null!", pid);
1135             g_free(dummy);
1136             return 0;
1137         }
1138 
1139         if (tmp->item->pid == pid)
1140         {
1141             g_memcpy(dummy, tmp->item, sizeof(struct session_item));
1142             return dummy;
1143         }
1144 
1145         /* go on */
1146         tmp = tmp->next;
1147     }
1148 
1149     g_free(dummy);
1150     return 0;
1151 }
1152 
1153 /******************************************************************************/
1154 struct SCP_DISCONNECTED_SESSION *
session_get_byuser(const char * user,int * cnt,unsigned char flags)1155 session_get_byuser(const char *user, int *cnt, unsigned char flags)
1156 {
1157     struct session_chain *tmp;
1158     struct SCP_DISCONNECTED_SESSION *sess;
1159     int count;
1160     int index;
1161 
1162     count = 0;
1163 
1164     tmp = g_sessions;
1165 
1166     LOG(LOG_LEVEL_DEBUG, "searching for session by user: %s", user);
1167     while (tmp != 0)
1168     {
1169         if ((NULL == user) || (!g_strncasecmp(user, tmp->item->name, 256)))
1170         {
1171             LOG(LOG_LEVEL_DEBUG, "session_get_byuser: status=%d, flags=%d, "
1172                 "result=%d", (tmp->item->status), flags,
1173                 ((tmp->item->status) & flags));
1174 
1175             if ((tmp->item->status) & flags)
1176             {
1177                 count++;
1178             }
1179         }
1180 
1181         /* go on */
1182         tmp = tmp->next;
1183     }
1184 
1185     if (count == 0)
1186     {
1187         (*cnt) = 0;
1188         return 0;
1189     }
1190 
1191     /* malloc() an array of disconnected sessions */
1192     sess = g_new0(struct SCP_DISCONNECTED_SESSION, count);
1193 
1194     if (sess == 0)
1195     {
1196         (*cnt) = 0;
1197         return 0;
1198     }
1199 
1200     tmp = g_sessions;
1201     index = 0;
1202 
1203     while (tmp != 0)
1204     {
1205         /* #warning FIXME: we should get only disconnected sessions! */
1206         if ((NULL == user) || (!g_strncasecmp(user, tmp->item->name, 256)))
1207         {
1208             if ((tmp->item->status) & flags)
1209             {
1210                 (sess[index]).SID = tmp->item->pid;
1211                 (sess[index]).type = tmp->item->type;
1212                 (sess[index]).height = tmp->item->height;
1213                 (sess[index]).width = tmp->item->width;
1214                 (sess[index]).bpp = tmp->item->bpp;
1215                 /* #warning FIXME: setting idle times and such */
1216                 /*(sess[index]).connect_time.year = tmp->item->connect_time.year;
1217                 (sess[index]).connect_time.month = tmp->item->connect_time.month;
1218                 (sess[index]).connect_time.day = tmp->item->connect_time.day;
1219                 (sess[index]).connect_time.hour = tmp->item->connect_time.hour;
1220                 (sess[index]).connect_time.minute = tmp->item->connect_time.minute;
1221                 (sess[index]).disconnect_time.year = tmp->item->disconnect_time.year;
1222                 (sess[index]).disconnect_time.month = tmp->item->disconnect_time.month;
1223                 (sess[index]).disconnect_time.day = tmp->item->disconnect_time.day;
1224                 (sess[index]).disconnect_time.hour = tmp->item->disconnect_time.hour;
1225                 (sess[index]).disconnect_time.minute = tmp->item->disconnect_time.minute;
1226                 (sess[index]).idle_time.year = tmp->item->idle_time.year;
1227                 (sess[index]).idle_time.month = tmp->item->idle_time.month;
1228                 (sess[index]).idle_time.day = tmp->item->idle_time.day;
1229                 (sess[index]).idle_time.hour = tmp->item->idle_time.hour;
1230                 (sess[index]).idle_time.minute = tmp->item->idle_time.minute;*/
1231                 (sess[index]).conn_year = tmp->item->connect_time.year;
1232                 (sess[index]).conn_month = tmp->item->connect_time.month;
1233                 (sess[index]).conn_day = tmp->item->connect_time.day;
1234                 (sess[index]).conn_hour = tmp->item->connect_time.hour;
1235                 (sess[index]).conn_minute = tmp->item->connect_time.minute;
1236                 (sess[index]).idle_days = tmp->item->idle_time.day;
1237                 (sess[index]).idle_hours = tmp->item->idle_time.hour;
1238                 (sess[index]).idle_minutes = tmp->item->idle_time.minute;
1239 
1240                 index++;
1241             }
1242         }
1243 
1244         /* go on */
1245         tmp = tmp->next;
1246     }
1247 
1248     (*cnt) = count;
1249     return sess;
1250 }
1251 
1252 /******************************************************************************/
1253 int
cleanup_sockets(int display)1254 cleanup_sockets(int display)
1255 {
1256     LOG(LOG_LEVEL_INFO, "cleanup_sockets:");
1257     char file[256];
1258     int error;
1259 
1260     error = 0;
1261 
1262     g_snprintf(file, 255, CHANSRV_PORT_OUT_STR, display);
1263     if (g_file_exist(file))
1264     {
1265         LOG(LOG_LEVEL_DEBUG, "cleanup_sockets: deleting %s", file);
1266         if (g_file_delete(file) == 0)
1267         {
1268             LOG(LOG_LEVEL_WARNING,
1269                 "cleanup_sockets: failed to delete %s (%s)",
1270                 file, g_get_strerror());
1271             error++;
1272         }
1273     }
1274 
1275     g_snprintf(file, 255, CHANSRV_PORT_IN_STR, display);
1276     if (g_file_exist(file))
1277     {
1278         LOG(LOG_LEVEL_DEBUG, "cleanup_sockets: deleting %s", file);
1279         if (g_file_delete(file) == 0)
1280         {
1281             LOG(LOG_LEVEL_WARNING,
1282                 "cleanup_sockets: failed to delete %s (%s)",
1283                 file, g_get_strerror());
1284             error++;
1285         }
1286     }
1287 
1288     g_snprintf(file, 255, XRDP_CHANSRV_STR, display);
1289     if (g_file_exist(file))
1290     {
1291         LOG(LOG_LEVEL_DEBUG, "cleanup_sockets: deleting %s", file);
1292         if (g_file_delete(file) == 0)
1293         {
1294             LOG(LOG_LEVEL_WARNING,
1295                 "cleanup_sockets: failed to delete %s (%s)",
1296                 file, g_get_strerror());
1297             error++;
1298         }
1299     }
1300 
1301     g_snprintf(file, 255, CHANSRV_API_STR, display);
1302     if (g_file_exist(file))
1303     {
1304         LOG(LOG_LEVEL_DEBUG, "cleanup_sockets: deleting %s", file);
1305         if (g_file_delete(file) == 0)
1306         {
1307             LOG(LOG_LEVEL_WARNING,
1308                 "cleanup_sockets: failed to delete %s (%s)",
1309                 file, g_get_strerror());
1310             error++;
1311         }
1312     }
1313 
1314     /* the following files should be deleted by xorgxrdp
1315      * but just in case the deletion failed */
1316 
1317     g_snprintf(file, 255, XRDP_X11RDP_STR, display);
1318     if (g_file_exist(file))
1319     {
1320         LOG(LOG_LEVEL_DEBUG, "cleanup_sockets: deleting %s", file);
1321         if (g_file_delete(file) == 0)
1322         {
1323             LOG(LOG_LEVEL_WARNING,
1324                 "cleanup_sockets: failed to delete %s (%s)",
1325                 file, g_get_strerror());
1326             error++;
1327         }
1328     }
1329 
1330     g_snprintf(file, 255, XRDP_DISCONNECT_STR, display);
1331     if (g_file_exist(file))
1332     {
1333         LOG(LOG_LEVEL_DEBUG, "cleanup_sockets: deleting %s", file);
1334         if (g_file_delete(file) == 0)
1335         {
1336             LOG(LOG_LEVEL_WARNING,
1337                 "cleanup_sockets: failed to delete %s (%s)",
1338                 file, g_get_strerror());
1339             error++;
1340         }
1341     }
1342 
1343     return error;
1344 
1345 }
1346