Merging upstream version 0.5.3 (Closes: #805659 CVE-2015-8308).
[debian/lxdm.git] / src / lxdm.c
CommitLineData
9931e273
DB
1/*
2 * lxdm.c - main entry of lxdm
3 *
4 * Copyright 2009 dgod <dgod.osa@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21
22#define _GNU_SOURCE
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
9931e273
DB
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <stdarg.h>
32#include <ctype.h>
33#include <stdint.h>
34#include <unistd.h>
35#include <stdarg.h>
36#include <fcntl.h>
37#include <pwd.h>
38#include <grp.h>
39#include <shadow.h>
40#include <errno.h>
41#include <signal.h>
42#include <time.h>
43#include <dirent.h>
44#include <sys/wait.h>
45#include <glib.h>
46#include <glib/gstdio.h>
47
48#include <sys/vt.h>
49#include <sys/ioctl.h>
50#include <sys/stat.h>
51
52#include <execinfo.h>
53
54#ifdef HAVE_UTMPX_H
55#include <utmpx.h>
56#endif
57
9931e273
DB
58#if HAVE_LIBCK_CONNECTOR
59#include <ck-connector.h>
60#endif
61
d6ba7c28
AG
62#ifndef HAVE_LIBPAM
63#ifdef USE_PAM
64#define HAVE_LIBPAM 1
65#else
66#define HAVE_LIBPAM 0
67#endif
68#endif
69
70#if HAVE_LIBPAM
71#include <security/pam_appl.h>
72#endif
73
9931e273
DB
74#include "lxdm.h"
75#include "lxcom.h"
76#include "xconn.h"
d6ba7c28
AG
77#include "lxcommon.h"
78#include "auth.h"
9931e273
DB
79
80#define LOGFILE "/var/log/lxdm.log"
81
82typedef struct{
83 gboolean idle;
84 gboolean greeter;
85 int tty;
86 pid_t server;
87 pid_t child;
88 uid_t user;
89 int display;
90 char *option; /* hold option in config file */
91 xconn_t dpy; /* hold this, or X crack */
d6ba7c28 92 LXDM_AUTH auth;
9931e273
DB
93#if HAVE_LIBCK_CONNECTOR
94 CkConnector *ckc;
95#endif
96#ifndef DISABLE_XAUTH
97 char mcookie[16];
98#endif
99 char **env;
100}LXSession;
101
102GKeyFile *config;
103static int old_tty=1,def_tty = 7,nr_tty=0;
d6ba7c28 104static int def_display=0;
9931e273
DB
105static GSList *session_list;
106
107static void lxdm_startx(LXSession *s);
108
109static int get_active_vt(void)
110{
111 int console_fd;
112 struct vt_stat console_state = { 0 };
113
114 console_fd = open("/dev/console", O_RDONLY | O_NOCTTY);
115
116 if( console_fd < 0 )
117 goto out;
118
119 if( ioctl(console_fd, VT_GETSTATE, &console_state) < 0 )
120 goto out;
121
122out:
123 if( console_fd >= 0 )
124 close(console_fd);
125
126 return console_state.v_active;
127}
128
129static void set_active_vt(int vt)
130{
131 int fd;
132
133 fd = open("/dev/console", O_RDWR);
134 if( fd < 0 )
135 fd = 0;
136 ioctl(fd, VT_ACTIVATE, vt);
d6ba7c28 137 if(fd!=0)
9931e273
DB
138 close(fd);
139}
140
141void stop_pid(int pid)
142{
143 if( pid <= 0 ) return;
144 lxcom_del_child_watch(pid);
145 if( killpg(pid, SIGTERM) < 0 )
146 killpg(pid, SIGKILL);
147 if( kill(pid, 0) == 0 )
148 {
149 if( kill(pid, SIGTERM) )
150 kill(pid, SIGKILL);
9931e273 151 }
d6ba7c28
AG
152 while( 1 )
153 {
154 int wpid, status;
155 wpid = waitpid(pid,&status,0);
156 if(pid == wpid)
157 break;
158 if(wpid<0 && errno!=EINTR)
159 break;
160 }
9931e273 161
d6ba7c28 162 while( waitpid(-1, 0, WNOHANG) > 0 ) ;
9931e273 163}
9931e273
DB
164
165static LXSession *lxsession_find_greeter(void)
166{
167 GSList *p;
168 for(p=session_list;p!=NULL;p=p->next)
169 {
170 LXSession *s=p->data;
171 if(s->greeter) return s;
172 }
173 return NULL;
174}
175
176static LXSession *lxsession_find_idle(void)
177{
178 GSList *p;
179 for(p=session_list;p!=NULL;p=p->next)
180 {
181 LXSession *s=p->data;
182 if(s->idle) return s;
183 }
184 return NULL;
185}
186
187static LXSession *lxsession_find_user(uid_t user)
188{
189 GSList *p;
190 for(p=session_list;p!=NULL;p=p->next)
191 {
192 LXSession *s=p->data;
193 if(s->greeter) continue;
194 if(s->user==user) return s;
195 }
196 return NULL;
197}
198
199LXSession *lxsession_find_tty(int tty)
200{
201 GSList *p;
202 for(p=session_list;p!=NULL;p=p->next)
203 {
204 LXSession *s=p->data;
205 if(s->tty==tty) return s;
206 }
207 return NULL;
208}
209
210static gboolean lxsession_get_active(void)
211{
212 GSList *p;
213 for(p=session_list;p!=NULL;p=p->next)
214 {
215 LXSession *s=p->data;
216 if(s->greeter || s->idle)
217 continue;
218 return TRUE;
219 }
220 return FALSE;
221}
222
223static void lxsession_set_active(LXSession *s)
224{
225 if(!s || s->tty<=0) return;
226 if(get_active_vt()==s->tty)
227 return;
228 set_active_vt(s->tty);
229}
230
231static gboolean tty_is_used(int tty)
232{
233 GSList *p;
234 for(p=session_list;p!=NULL;p=p->next)
235 {
236 LXSession *s=p->data;
237 if(s->tty==tty)
238 return TRUE;
239 }
240 return FALSE;
241}
242
243static gboolean display_is_used(int display)
244{
245 GSList *p;
246 for(p=session_list;p!=NULL;p=p->next)
247 {
248 LXSession *s=p->data;
249 if(s->display==display)
250 return TRUE;
251 }
252 return FALSE;
253}
254
255static int lxsession_alloc_tty(void)
256{
257 int i;
258 if(!tty_is_used(def_tty))
259 return def_tty;
260 for(i=7;i<13;i++)
261 {
262 if(!tty_is_used(i))
263 return i;
264 }
265 return 0;
266}
267
268static int lxsession_alloc_display(void)
269{
270 int i;
d6ba7c28 271 for(i=def_display;i<11;i++)
9931e273
DB
272 {
273 if(!display_is_used(i))
274 return i;
275 }
276 return -1;
277}
278
279static LXSession *lxsession_add(void)
280{
281 LXSession *s;
282
283 s=lxsession_find_idle();
284 if(s) return s;
285 if(g_slist_length(session_list)>=4)
286 return NULL;
287 s=g_new0(LXSession,1);
288 s->greeter=FALSE;
289 s->tty=lxsession_alloc_tty();
290 s->display=lxsession_alloc_display();
291 s->idle=TRUE;
292 if(!s->tty || s->display<0)
293 {
294 g_message("alloc tty s->tty, display %d fail\n",s->display);
295 g_free(s);
296 return NULL;
297 }
298 s->env=NULL;
d6ba7c28 299 lxdm_auth_init(&s->auth);
9931e273
DB
300 session_list=g_slist_prepend(session_list,s);
301 lxdm_startx(s);
302 return s;
303}
304
305static LXSession *lxsession_greeter(void)
306{
37f5420c 307 char temp[128];
9931e273
DB
308 LXSession *s;
309 s=lxsession_find_greeter();
310 if(s)
311 {
312 g_message("find prev greeter\n");
313 lxsession_set_active(s);
314 return s;
315 }
316 g_message("find greeter %p\n",s);
317 s=lxsession_find_idle();
318 g_message("find idle %p\n",s);
319 if(!s) s=lxsession_add();
320 g_message("add %p\n",s);
321 if(!s)
322 {
323 g_warning("add new fail\n");
324 return NULL;
325 }
326 s->greeter=TRUE;
327 s->idle=FALSE;
328 sprintf(temp,":%d",s->display);
329 setenv("DISPLAY",temp,1);
37f5420c
AG
330 #ifndef DISABLE_XAUTH
331 sprintf(temp,"/var/run/lxdm/lxdm-:%d.auth",s->display);
332 setenv("XAUTHORITY",temp,1);
333 #endif
9931e273
DB
334 g_message("prepare greeter on %s\n",temp);
335 ui_prepare();
336 lxsession_set_active(s);
337 g_message("start greeter on %s\n",temp);
37f5420c
AG
338 #ifndef DISABLE_XAUTH
339 unsetenv("XAUTHORITY");
340 #endif
9931e273
DB
341 return s;
342}
343
344static void lxsession_stop(LXSession *s)
345{
346 if(s->greeter)
347 {
348 ui_drop();
349 s->greeter=FALSE;
350 }
351 if(s->child>0)
352 {
353 lxcom_del_child_watch(s->child);
354 killpg(s->child, SIGHUP);
355 stop_pid(s->child);
356 s->child = -1;
357 }
358 if( s->server > 0 )
359 {
360 xconn_clean(s->dpy);
361 }
d6ba7c28 362 lxdm_auth_session_end(&s->auth);
9931e273
DB
363#if HAVE_LIBCK_CONNECTOR
364 if( s->ckc != NULL )
365 {
366 DBusError error;
367 dbus_error_init(&error);
368 ck_connector_close_session(s->ckc, &error);
369 if(dbus_error_is_set(&error))
370 {
371 dbus_error_free(&error);
372 }
373 ck_connector_unref(s->ckc);
374 s->ckc=NULL;
375 }
376#endif
377 s->idle=TRUE;
378}
379
380static void lxsession_free(LXSession *s)
381{
382 if(!s)
383 return;
384 session_list=g_slist_remove(session_list,s);
385 lxsession_stop(s);
386 if(s->server)
387 {
388 if(s->dpy)
389 {
390 xconn_close(s->dpy);
391 s->dpy=NULL;
392 }
393 stop_pid(s->server);
394 s->server=0;
395 }
396 g_free(s->option);
397 g_strfreev(s->env);
398 g_free(s);
399}
400
401static gboolean plymouth_is_running(void)
402{
403 int status;
404 gboolean res;
405
406 res=g_spawn_command_line_sync ("/bin/plymouth --ping",NULL,NULL,&status,NULL);
407 if(!res) return FALSE;
408 return WIFEXITED (status) && WEXITSTATUS (status) == 0;
409}
410
411static void plymouth_quit_with_transition(void)
412{
413 g_spawn_command_line_sync("/bin/plymouth quit --retain-splash",NULL,NULL,NULL,NULL);
414}
415
416static void plymouth_quit_without_transition(void)
417{
418 g_spawn_command_line_sync("/bin/plymouth quit",NULL,NULL,NULL,NULL);
419}
420
421static void plymouth_prepare_transition(void)
422{
423 g_spawn_command_line_sync ("/bin/plymouth deactivate",NULL,NULL,NULL,NULL);
424}
425
426static char *lxsession_xserver_command(LXSession *s)
427{
428 char *p;
429 int arc;
430 char **arg;
431 int i;
d6ba7c28 432 int novtswitch=0;
9931e273
DB
433
434 if(s->option)
435 {
436 p=g_key_file_get_string(config,s->option,"xarg",0);
437 if(p) return p;
438 }
439
440 p=g_key_file_get_string(config, "server", "arg", 0);
441 if(!p) p=g_strdup("/usr/bin/X");
442 g_shell_parse_argv(p, &arc, &arg, 0);
443 g_free(p);
444 for(i=1;i<arc;)
445 {
446 p = arg[i];
447 if(!strncmp(p, "vt", 2) && isdigit(p[2]) &&
448 ( !p[3] || (isdigit(p[3]) && !p[4]) ) )
449 {
450 g_free(arg[i]);
451 arc--;memcpy(arg+i,arg+i+1,(arc-i)*sizeof(char*));
452 }
453 else if(!strcmp(p,"-background"))
454 {
455 g_free(arg[i]);
456 arc--;memcpy(arg+i,arg+i+1,(arc-i)*sizeof(char*));
457 if(i<arc && !strcmp(arg[i],"none"))
458 {
459 g_free(arg[i]);
460 arc--;memcpy(arg+i,arg+i+1,(arc-i)*sizeof(char*));
461 }
462 }
463 else if(!strcmp(p,"-nr"))
464 {
465 g_free(arg[i]);
466 arc--;memcpy(arg+i,arg+i+1,(arc-i)*sizeof(char*));
467 }
d6ba7c28
AG
468 else if(!strcmp(p,"-novtswitch"))
469 {
470 novtswitch=1;
471 }
9931e273
DB
472 else
473 {
474 i++;
475 }
476 }
d6ba7c28 477
37f5420c 478 arg = g_renew(char *, arg, arc + 15);
9931e273
DB
479 if(nr_tty)
480 {
481 arg[arc++] = g_strdup("-background");
482 arg[arc++] = g_strdup("none");
483 }
484 arg[arc++] = g_strdup_printf(":%d",s->display);
485 if(s->tty>0)
486 arg[arc++] = g_strdup_printf("vt%02d", s->tty);
d6ba7c28
AG
487 if(g_key_file_get_integer(config,"server","tcp_listen",0)!=1)
488 {
489 arg[arc++] = g_strdup("-nolisten");
490 arg[arc++] = g_strdup("tcp");
491 }
492 if(!novtswitch)
493 {
494 arg[arc++] = g_strdup("-novtswitch");
495 }
37f5420c
AG
496#ifndef DISABLE_XAUTH
497 arg[arc++] = g_strdup("-auth");
498 arg[arc++] = g_strdup_printf("/var/run/lxdm/lxdm-:%d.auth",s->display);
499#endif
9931e273
DB
500 arg[arc] = NULL;
501 p=g_strjoinv(" ", arg);
502 g_strfreev(arg);
503 return p;
504}
505
506void lxdm_get_tty(void)
507{
508 char *s = g_key_file_get_string(config, "server", "arg", 0);
509 int arc;
510 char **arg;
511 int len;
512 int gotvtarg = 0;
513 gboolean plymouth;
514
515 plymouth=plymouth_is_running();
516 if(plymouth)
517 {
518 g_message("found plymouth running\n");
519 plymouth_prepare_transition();
520 }
521
522 old_tty=get_active_vt();
523 if( !s ) s = g_strdup("/usr/bin/X");
524 g_shell_parse_argv(s, &arc, &arg, 0);
525 g_free(s);
526 for( len = 0; arg && arg[len]; len++ )
527 {
528 char *p = arg[len];
529 if( !strncmp(p, "vt", 2) && isdigit(p[2]) &&
530 ( !p[3] || (isdigit(p[3]) && !p[4]) ) )
531 {
532 def_tty = atoi(p + 2);
533 gotvtarg = 1;
534 }
535 else if(!strcmp(p,"-background") || !strcmp(p,"-nr"))
536 {
537 nr_tty=1;
538 }
d6ba7c28
AG
539 else if(p[0]==':' && isdigit(p[1]))
540 {
541 def_display=atoi(p+1);
542 }
9931e273
DB
543 }
544 if(!gotvtarg)
545 {
546 /* support plymouth */
d6ba7c28 547 if(g_key_file_get_integer(config, "server", "active_vt", 0) )
9931e273
DB
548 /* use the active vt */
549 def_tty = old_tty;
9931e273
DB
550 if(plymouth)
551 {
552 nr_tty=1;
553 plymouth_quit_with_transition();
554 }
555 }
556 else
557 {
558 if(plymouth) /* set tty and plymouth running */
559 plymouth_quit_without_transition();
560 }
561 g_strfreev(arg);
562}
563
564void lxdm_quit_self(int code)
565{
566 g_message("quit code %d\n",code);
567 exit(code);
568}
569
570static void log_init(void)
571{
572 int fd_log;
9931e273
DB
573 g_unlink(LOGFILE ".old");
574 g_rename(LOGFILE, LOGFILE ".old");
575 fd_log = open(LOGFILE, O_CREAT|O_APPEND|O_TRUNC|O_WRONLY|O_EXCL, 0640);
576 if(fd_log == -1) return;
577 dup2(fd_log, 1);
578 dup2(fd_log, 2);
d6ba7c28 579 close(fd_log);
9931e273
DB
580}
581
582static void log_ignore(const gchar *log_domain, GLogLevelFlags log_level,
583 const gchar *message, gpointer user_data)
584{
585}
d6ba7c28 586#if 0
9931e273
DB
587GSList *do_scan_xsessions(void)
588{
589 GSList *xsessions = NULL;
590 GDir *d;
591 const char *basename;
592 GKeyFile *f;
593
594 d = g_dir_open(XSESSIONS_DIR, 0, NULL);
595 if( !d )
596 return NULL;
597
598 f = g_key_file_new();
599 while( ( basename = g_dir_read_name(d) ) != NULL )
600 {
601 char *file_path;
602 gboolean loaded;
603
604 if(!g_str_has_suffix(basename, ".desktop"))
605 continue;
606
607 file_path = g_build_filename(XSESSIONS_DIR, basename, NULL);
608 loaded = g_key_file_load_from_file(f, file_path, G_KEY_FILE_NONE, NULL);
609 g_free(file_path);
610
611 if( loaded )
612 {
613 char *name = g_key_file_get_locale_string(f, "Desktop Entry", "Name", NULL, NULL);
614 if( name )
615 {
616 char *exec = g_key_file_get_string(f, "Desktop Entry", "Exec", NULL);
617 if(exec)
618 {
619 Session* sess = g_new( Session, 1 );
620 sess->name = name;
621 sess->exec = exec;
622 sess->desktop_file = g_strdup(basename);
623 if( !strcmp(name, "LXDE") )
624 xsessions = g_slist_prepend(xsessions, sess);
625 else
626 xsessions = g_slist_append(xsessions, sess);
627 continue; /* load next file */
628 g_free(exec);
629 }
630 g_free(name);
631 }
632 }
633 }
634 g_dir_close(d);
635 g_key_file_free(f);
636 return xsessions;
637}
638
639void free_xsessions(GSList *l)
640{
641 GSList *p;
642 Session *sess;
643
644 for( p = l; p; p = p->next )
645 {
646 sess = p->data;
647 g_free(sess->name);
648 g_free(sess->exec);
649 g_free(sess);
650 }
651 g_slist_free(l);
652}
d6ba7c28 653#endif
9931e273
DB
654
655#ifndef DISABLE_XAUTH
656
657static inline void xauth_write_uint16(int fd,uint16_t data)
658{
659 uint8_t t;
660 t=data>>8;
661 write(fd,&t,1);
662 t=data&0xff;
663 write(fd,&t,1);
664}
665
666static inline void xauth_write_string(int fd,const char *s)
667{
668 size_t len=strlen(s);
669 xauth_write_uint16(fd,(uint16_t)len);
670 write(fd,s,len);
671}
672
37f5420c 673static int xauth_write_file(const char *file,int dpy,char data[16])
9931e273
DB
674{
675 int fd;
d6ba7c28
AG
676 char addr[128];
677 char buf[16];
678
679 sprintf(buf,"%d",dpy);
680 gethostname(addr,sizeof(addr));
9931e273
DB
681
682 fd=open(file,O_CREAT|O_TRUNC|O_WRONLY,0600);
37f5420c 683 if(fd==-1) return -1;
d6ba7c28
AG
684 xauth_write_uint16(fd,256); //FamilyLocalHost
685 xauth_write_string(fd,addr);
686 xauth_write_string(fd,buf);
9931e273
DB
687 xauth_write_string(fd,"MIT-MAGIC-COOKIE-1");
688 xauth_write_uint16(fd,16);
689 write(fd,data,16);
690 close(fd);
37f5420c 691 return 0;
9931e273
DB
692}
693
694static void create_server_auth(LXSession *s)
695{
696 GRand *h;
697 int i;
698 char *authfile;
37f5420c 699 struct passwd *pw;
9931e273
DB
700
701 h = g_rand_new();
702 for( i = 0; i < 16; i++ )
703 {
704 s->mcookie[i] = g_rand_int(h)&0xff;
705 }
706 g_rand_free(h);
707
708 authfile = g_strdup_printf("/var/run/lxdm/lxdm-:%d.auth",s->display);
709
37f5420c 710 setenv("XAUTHORITY",authfile,1);
9931e273 711 remove(authfile);
d6ba7c28 712 xauth_write_file(authfile,s->display,s->mcookie);
37f5420c
AG
713 pw=getpwnam("lxdm");endpwent();
714 if(pw!=NULL)
715 {
716 chown(authfile,pw->pw_uid,pw->pw_gid);
717 }
9931e273
DB
718 g_free(authfile);
719}
720
d6ba7c28 721static char ** create_client_auth(struct passwd *pw,char **env)
9931e273
DB
722{
723 LXSession *s;
724 char *authfile;
9931e273 725
d6ba7c28 726 s=lxsession_find_user(pw->pw_uid);
9931e273 727 if(!s)
d6ba7c28
AG
728 return env;
729
730 /* pam_mktemp may provide XAUTHORITY to DM, just use it */
731 if((authfile=(char*)g_environ_getenv(env,"XAUTHORITY"))!=NULL)
9931e273 732 {
d6ba7c28 733 authfile=g_strdup(authfile);
9931e273
DB
734 }
735 else
736 {
d6ba7c28
AG
737 char *path;
738 path=g_key_file_get_string(config,"base","xauth_path",NULL);
739 if(path)
740 {
741 authfile = g_strdup_printf("%s/.Xauth%d", path,pw->pw_uid);
742 g_free(path);
743 }
744 else
745 {
746 authfile = g_strdup_printf("%s/.Xauthority", pw->pw_dir);
747 }
9931e273
DB
748 }
749 remove(authfile);
37f5420c
AG
750 if(xauth_write_file(authfile,s->display,s->mcookie)==-1)
751 {
752 g_free(authfile);
753 authfile = g_strdup_printf("/var/run/lxdm/.Xauth%d",pw->pw_uid);
754 remove(authfile);
755 xauth_write_file(authfile,s->display,s->mcookie);
756 }
d6ba7c28
AG
757 env=g_environ_setenv(env,"XAUTHORITY",authfile,TRUE);
758 chown(authfile,pw->pw_uid,pw->pw_gid);
9931e273 759 g_free(authfile);
d6ba7c28
AG
760
761 return env;
9931e273
DB
762}
763#endif
764
d6ba7c28 765int lxdm_auth_user(int type,char *user, char *pass, struct passwd **ppw)
9931e273 766{
9931e273 767 LXSession *s;
d6ba7c28 768 int ret;
9931e273
DB
769 s=lxsession_find_greeter();
770 if(!s) s=lxsession_find_idle();
771 if(!s) s=lxsession_add();
772 if(!s)
773 {
774 g_critical("lxsession_add fail\n");
775 exit(0);
776 }
d6ba7c28
AG
777 ret=lxdm_auth_user_authenticate(&s->auth,user,pass,type);
778 if(ret==AUTH_SUCCESS)
779 *ppw=&s->auth.pw;
780 return ret;
9931e273
DB
781}
782
9931e273
DB
783static void close_left_fds(void)
784{
785 struct dirent **list;
786 char path[256];
787 int n;
788
789 snprintf(path,sizeof(path),"/proc/%d/fd",getpid());
790 n=scandir(path,&list,0,0);
791 if(n<0) return;
792 while(n--)
793 {
794 int fd=atoi(list[n]->d_name);
795 free(list[n]);
796 if(fd<=STDERR_FILENO)
797 continue;
798 close(fd);
799 }
800 free(list);
d6ba7c28
AG
801
802 int fd = open("/dev/null", O_WRONLY);
803 if(fd == -1) return;
804 dup2(fd, 1);
805 dup2(fd, 2);
806 close(fd);
9931e273
DB
807}
808
d6ba7c28 809void switch_user(struct passwd *pw, const char *run, char **env)
9931e273 810{
d6ba7c28 811 int fd;
9931e273 812
d6ba7c28
AG
813 setenv("USER",pw->pw_name,1);
814 setenv("LOGNAME",pw->pw_name,1);
815 setenv("SHELL",pw->pw_shell,1);
816 setenv("HOME",pw->pw_dir,1);
817
818 g_spawn_command_line_sync ("/etc/lxdm/PreLogin",NULL,NULL,NULL,NULL);
819
820 if( !pw || initgroups(pw->pw_name, pw->pw_gid) ||
821 setgid(pw->pw_gid) || setuid(pw->pw_uid) || setsid() == -1 )
822 exit(EXIT_FAILURE);
823 chdir(pw->pw_dir);
824 fd=open(".xsession-errors",O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR);
825 if(fd!=-1)
826 {
827 dup2(fd,STDERR_FILENO);
828 close(fd);
829 }
9931e273
DB
830
831 /* reset signal */
832 signal(SIGCHLD, SIG_DFL);
833 signal(SIGTERM, SIG_DFL);
834 signal(SIGPIPE, SIG_DFL);
835 signal(SIGALRM, SIG_DFL);
836 signal(SIGHUP, SIG_DFL);
c8e553a1
AG
837 signal(SIGTTIN, SIG_DFL);
838 signal(SIGTTOU, SIG_DFL);
839 signal(SIGUSR1, SIG_DFL);
9931e273
DB
840 close_left_fds();
841
842 g_spawn_command_line_async ("/etc/lxdm/PostLogin",NULL);
843 execle("/etc/lxdm/Xsession", "/etc/lxdm/Xsession", run, NULL, env);
844 exit(EXIT_FAILURE);
845}
846
847static void get_lock(void)
848{
d6ba7c28
AG
849 FILE *fp;
850 char *lockfile;
9931e273 851
d6ba7c28
AG
852 lockfile = g_key_file_get_string(config, "base", "lock", 0);
853 if( !lockfile ) lockfile = g_strdup("/var/run/lxdm.pid");
9931e273 854
d6ba7c28
AG
855 fp = fopen(lockfile, "r");
856 if( fp )
857 {
858 int pid;
859 int ret;
860 ret = fscanf(fp, "%d", &pid);
861 fclose(fp);
862 if(ret == 1 && pid!=getpid())
9931e273 863 {
d6ba7c28
AG
864 if(kill(pid, 0) == 0 || (ret == -1 && errno == EPERM))
865 {
866 /* we should only quit if the pid running is lxdm */
9931e273 867#ifdef __linux__
d6ba7c28
AG
868 char path[64],buf[128];
869 sprintf(path,"/proc/%d/exe",pid);
870 ret=readlink(path,buf,128);
871 if(ret<128 && ret>0 && strstr(buf,"lxdm-binary"))
9931e273 872 lxdm_quit_self(1);
d6ba7c28
AG
873#else
874 lxdm_quit_self(1);
9931e273 875#endif
d6ba7c28 876 }
9931e273 877 }
d6ba7c28
AG
878 }
879 fp = fopen(lockfile, "w");
880 if( !fp )
881 {
882 g_critical("open lock file %s fail\n",lockfile);
883 lxdm_quit_self(0);
884 }
885 fprintf( fp, "%d", getpid() );
886 fclose(fp);
887 g_free(lockfile);
9931e273
DB
888}
889
890static void put_lock(void)
891{
892 FILE *fp;
893 char *lockfile;
894
895 lockfile = g_key_file_get_string(config, "base", "lock", 0);
896 if( !lockfile ) lockfile = g_strdup("/var/run/lxdm.pid");
897 fp = fopen(lockfile, "r");
898 if( fp )
899 {
900 int pid;
901 int ret;
902 ret = fscanf(fp, "%d", &pid);
903 fclose(fp);
904 if( ret == 1 && pid == getpid() )
905 remove(lockfile);
906 }
907 g_free(lockfile);
908}
909
37f5420c
AG
910static int get_run_level(void)
911{
912#if defined(HAVE_UTMPX_H) && defined(RUN_LVL)
913 int res;
914 struct utmpx *ut,tmp;
915
916 setutxent();
917 tmp.ut_type=RUN_LVL;
918 ut=getutxid(&tmp);
919 if(!ut)
920 {
921 endutxent();
922 return '5';
923 }
924 res=ut->ut_pid & 0xff;
925 endutxent();
926 //g_message("runlevel %c\n",res);
927 return res;
928#else
929 return '5';
930#endif
931}
932
9931e273
DB
933static void on_xserver_stop(void *data,int pid, int status)
934{
935 LXSession *s=data;
936 LXSession *greeter;
37f5420c 937 int level;
9931e273
DB
938
939 stop_pid(pid);
940 s->server = -1;
941 lxsession_stop(s);
37f5420c
AG
942
943 level=get_run_level();
944 if(level=='6' || level=='0')
945 {
946 return;
947 }
948
949 g_message("xserver stop, restart. return status %x\n",status);
950
9931e273
DB
951 greeter=lxsession_find_greeter();
952 if(s->greeter || !greeter)
953 {
954 s->greeter=TRUE;
955 xconn_close(s->dpy);
956 s->dpy=NULL;
9931e273 957 ui_drop();
37f5420c 958 lxdm_startx(s);
9931e273 959 ui_prepare();
37f5420c 960 lxsession_set_active(s);
9931e273
DB
961 }
962 else
963 {
964 lxsession_free(s);
965 lxsession_set_active(greeter);
966 }
967}
968
37f5420c 969static void lxdm_startx(LXSession *s)
9931e273
DB
970{
971 char *arg;
972 char **args;
973 int i;
974 char display[16];
975
d6ba7c28
AG
976 lxsession_set_active(s);
977
9931e273
DB
978 sprintf(display,":%d",s->display);
979 setenv("DISPLAY",display,1);
980
981 #ifndef DISABLE_XAUTH
982 create_server_auth(s);
983 #endif
984
985 arg = lxsession_xserver_command(s);
986 args = g_strsplit(arg, " ", -1);
987 g_free(arg);
988
989 s->server = vfork();
990
991 switch( s->server )
992 {
993 case 0:
994 execvp(args[0], args);
995 g_critical("exec %s fail\n",args[0]);
996 lxdm_quit_self(0);
997 break;
998 case -1:
999 /* fatal error, should not restart self */
1000 g_critical("fork proc fail\n");
1001 lxdm_quit_self(0);
1002 break;
1003 default:
1004 break;
1005 }
1006 g_strfreev(args);
1007 lxcom_add_child_watch(s->server, on_xserver_stop, s);
1008
d6ba7c28 1009 g_message("%ld: add xserver watch\n",time(NULL));
9931e273
DB
1010 for( i = 0; i < 100; i++ )
1011 {
1012 if(lxcom_last_sig==SIGINT || lxcom_last_sig==SIGTERM)
1013 break;
1014 if((s->dpy=xconn_open(display))!=NULL)
1015 break;
1016 g_usleep(50 * 1000);
1017 //g_message("retry %d\n",i);
1018 }
d6ba7c28 1019 g_message("%ld: start xserver in %d retry",time(NULL),i);
9931e273
DB
1020 if(s->dpy==NULL)
1021 exit(EXIT_FAILURE);
1022
1023 if(s->option && g_key_file_has_key(config,s->option,"numlock",NULL))
1024 {
1025 i=g_key_file_get_integer(config,s->option,"numlock",0);
1026 arg=g_strdup_printf("%s %d",LXDM_NUMLOCK_PATH,i);
1027 g_spawn_command_line_async(arg,NULL);
1028 g_free(arg);
1029
1030 }
1031 else if(g_key_file_has_key(config,"base","numlock",NULL))
1032 {
1033 i=g_key_file_get_integer(config,"base","numlock",0);
1034 arg=g_strdup_printf("%s %d",LXDM_NUMLOCK_PATH,i);
1035 g_spawn_command_line_async(arg,NULL);
1036 g_free(arg);
1037 }
37f5420c
AG
1038 #ifndef DISABLE_XAUTH
1039 unsetenv("XAUTHORITY");
1040 #endif
9931e273
DB
1041}
1042
1043static void exit_cb(void)
1044{
1045 g_message("exit cb\n");
1046 ui_drop();
1047 while(session_list)
1048 lxsession_free(session_list->data);
1049 g_message("free session\n");
1050 put_lock();
1051 set_active_vt(old_tty);
1052 g_key_file_free(config);
1053}
1054
37f5420c 1055static gboolean delayed_restart_greeter(LXSession *s)
9931e273 1056{
37f5420c
AG
1057 int level;
1058
1059 level=get_run_level();
1060 if(level=='0' || level=='6')
9931e273 1061 {
37f5420c
AG
1062 if(level=='0')
1063 g_spawn_command_line_sync("/etc/lxdm/PreShutdown",0,0,0,0);
1064 else
1065 g_spawn_command_line_sync("/etc/lxdm/PreReboot",0,0,0,0);
1066 g_message("run level %c\n",level);
1067 lxdm_quit_self(0);
1068 return FALSE;
9931e273 1069 }
37f5420c
AG
1070
1071 if(s && s!=lxsession_greeter())
1072 {
1073 lxsession_free(s);
1074 }
1075 else if(!s)
1076 {
1077 lxsession_greeter();
1078 }
1079
1080 return FALSE;
9931e273
DB
1081}
1082
1083static void on_session_stop(void *data,int pid, int status)
1084{
1085 int level;
1086 LXSession *s=data;
1087
c8e553a1
AG
1088 gchar *argv[] = { "/etc/lxdm/PostLogout", NULL };
1089 g_spawn_async(NULL, argv, s->env, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL);
1090
1091 if(g_key_file_get_integer(config,"server","reset",NULL)!=1)
1092 {
1093 lxsession_stop(s);
1094 }
1095 else
1096 {
1097 lxsession_free(s);
1098 s=NULL;
1099 }
9931e273
DB
1100
1101 level=get_run_level();
1102 if(level=='0' || level=='6')
1103 {
1104 if(level=='0')
1105 g_spawn_command_line_sync("/etc/lxdm/PreShutdown",0,0,0,0);
1106 else
1107 g_spawn_command_line_sync("/etc/lxdm/PreReboot",0,0,0,0);
1108 g_message("run level %c\n",level);
1109 lxdm_quit_self(0);
37f5420c 1110 return;
9931e273 1111 }
37f5420c 1112 g_timeout_add(300,(GSourceFunc)delayed_restart_greeter,s);
9931e273
DB
1113}
1114
c8e553a1 1115gboolean lxdm_get_session_info(const char *session,char **pname,char **pexec,char **pdesktop_names)
9931e273 1116{
c8e553a1 1117 char *name=NULL,*exec=NULL,**names=NULL,*desktop_names=NULL;
9931e273
DB
1118 if(!session || !session[0])
1119 {
1120 name=g_key_file_get_string(config, "base", "session", 0);
1121 if(!name && getenv("PREFERRED"))
1122 name = g_strdup(getenv("PREFERRED"));
d6ba7c28 1123 if(!name && getenv("DESKTOP"))
9931e273
DB
1124 name = g_strdup(getenv("DESKTOP"));
1125 if(!name) name=g_strdup("LXDE");
1126 }
1127 else
1128 {
1129 char *p=strrchr(session,'.');
1130 if(p && !strcmp(p,".desktop"))
1131 {
1132 GKeyFile *cfg=g_key_file_new();
1133 if(!g_key_file_load_from_file(cfg,session,G_KEY_FILE_NONE,NULL))
1134 {
1135 g_key_file_free(cfg);
1136 return FALSE;
1137 }
1138 name=g_key_file_get_string(cfg,"Desktop Entry","Name",NULL);
1139 exec=g_key_file_get_string(cfg,"Desktop Entry","Exec",NULL);
c8e553a1
AG
1140 names = g_key_file_get_string_list (cfg, "Desktop Entry", "DesktopNames", NULL, NULL);
1141 if (names != NULL) {
1142 desktop_names = g_strjoinv (":", names);
1143 g_strfreev (names);
1144 }
9931e273
DB
1145 g_key_file_free(cfg);
1146 if(!name || !exec)
1147 {
1148 g_free(name);
1149 g_free(exec);
1150 return FALSE;
1151 }
1152 }
1153 else
1154 {
1155 GKeyFile *f;
1156 char *file_path;
1157 gboolean loaded;
1158
1159 f = g_key_file_new();
1160 char *desktop_name = g_strconcat(session, ".desktop", NULL);
1161 file_path = g_build_filename(XSESSIONS_DIR, desktop_name, NULL);
1162 loaded = g_key_file_load_from_file(f, file_path, G_KEY_FILE_NONE, NULL);
1163 g_free(file_path);
1164 g_free(desktop_name);
1165
1166 if ( loaded )
1167 {
1168 name = g_key_file_get_locale_string(f, "Desktop Entry", "Name", NULL, NULL);
1169 exec = g_key_file_get_string(f, "Desktop Entry", "Exec", NULL);
c8e553a1
AG
1170 names = g_key_file_get_string_list (f, "Desktop Entry", "DesktopNames", NULL, NULL);
1171 if (names != NULL) {
1172 desktop_names = g_strjoinv (":", names);
1173 g_strfreev (names);
1174 }
9931e273
DB
1175 }
1176 else
1177 {
1178 name=g_strdup(session);
1179 }
1180 g_key_file_free(f);
1181 }
1182 }
1183 if(name && !exec)
1184 {
1185 if(!strcasecmp(name,"LXDE"))
1186 exec = g_strdup("startlxde");
1187 else if( !strcasecmp(name, "GNOME") )
1188 exec = g_strdup("gnome-session");
1189 else if( !strcasecmp(name, "KDE") )
1190 exec = g_strdup("startkde");
1191 else if( !strcasecmp(name, "XFCE") || !strcasecmp(name, "xfce4"))
1192 exec = g_strdup("startxfce4");
1193 else
1194 exec=g_strdup(name);
1195 }
1196 if(pname) *pname=name;
1197 if(pexec) *pexec=exec;
c8e553a1 1198 if(pdesktop_names) *pdesktop_names=desktop_names;
9931e273
DB
1199 return TRUE;
1200}
1201
1202static void lxdm_save_login(char *session,char *lang)
1203{
1204 char *old;
1205 GKeyFile *var;
1206 int dirty=0;
1207 if(!session || !session[0])
1208 session="__default__";
1209 if(!lang)
1210 lang="";
1211 var=g_key_file_new();
1212 g_key_file_set_list_separator(var, ' ');
d6ba7c28 1213 g_key_file_load_from_file(var,VCONFIG_FILE,0,NULL);
9931e273
DB
1214 old=g_key_file_get_string(var,"base","last_session",0);
1215 if(0!=g_strcmp0(old,session))
1216 {
1217 g_key_file_set_string(var,"base","last_session",session);
1218 dirty++;
1219 }
1220 g_free(old);
1221 old=g_key_file_get_string(var,"base","last_lang",0);
1222 if(0!=g_strcmp0(old,lang))
1223 {
1224 g_key_file_set_string(var,"base","last_lang",lang);
1225 dirty++;
1226 }
1227 g_free(old);
1228 if(lang[0])
1229 {
1230 char **list;
1231 gsize len;
1232 list=g_key_file_get_string_list(var,"base","last_langs",&len,NULL);
1233 if(!list)
1234 {
1235 list=g_new0(char*,2);
1236 list[0]=g_strdup(lang);
1237 g_key_file_set_string_list(var,"base","last_langs",(void*)list,1);
1238 g_strfreev(list);
1239 dirty++;
1240 }
1241 else
1242 {
1243 int i;
1244 for(i=0;i<len;i++)
1245 {
1246 if(!strcmp(list[i],lang)) break;
1247 }
1248 if(i==len)
1249 {
1250 list=g_renew(char*,list,len+2);
1251 list[len]=g_strdup(lang);
1252 list[len+1]=NULL;
1253 g_key_file_set_string_list(var,"base","last_langs",(void*)list,len+1);
1254 dirty++;
1255 }
1256 g_strfreev(list);
1257 }
1258 }
1259 if(dirty)
1260 {
1261 gsize len;
1262 char* data = g_key_file_to_data(var, &len, NULL);
1263 mkdir("/var/lib/lxdm",0755);
1264 chmod("/var/lib/lxdm",0755);
d6ba7c28 1265 g_file_set_contents(VCONFIG_FILE, data, len, NULL);
9931e273
DB
1266 g_free(data);
1267 }
1268 g_key_file_free(var);
1269}
1270
1271void lxdm_do_login(struct passwd *pw, char *session, char *lang, char *option)
1272{
c8e553a1 1273 char *session_name=0,*session_exec=0,*session_desktop_names=0;
9931e273
DB
1274 gboolean alloc_session=FALSE,alloc_lang=FALSE;
1275 int pid;
1276 LXSession *s,*prev;
1277
1278 lxdm_save_login(session,lang);
d6ba7c28
AG
1279 if(!strcmp(session,"__default__"))
1280 session=NULL;
9931e273
DB
1281
1282 if(!session ||!session[0] || !lang || !lang[0])
1283 {
1284 char *path=g_strdup_printf("%s/.dmrc",pw->pw_dir);
1285 GKeyFile *dmrc=g_key_file_new();
1286 g_key_file_load_from_file(dmrc,path,G_KEY_FILE_NONE,0);
1287 g_free(path);
1288 if(!session || !session[0])
1289 {
1290 session=g_key_file_get_string(dmrc,"Desktop","Session",NULL);
1291 alloc_session=TRUE;
1292 }
1293 if(!lang || !lang[0])
1294 {
1295 lang=g_key_file_get_string(dmrc,"Desktop","Language",NULL);
1296 alloc_lang=TRUE;
1297 }
1298 g_key_file_free(dmrc);
1299 }
1300
c8e553a1 1301 if(!lxdm_get_session_info(session,&session_name,&session_exec,&session_desktop_names))
9931e273
DB
1302 {
1303 if(alloc_session)
1304 g_free(session);
1305 if(alloc_lang)
1306 g_free(lang);
1307 ui_prepare();
1308 g_debug("get session %s info fail\n",session);
1309 return;
1310 }
1311
1312 g_debug("login user %s session %s lang %s\n",pw->pw_name,session_exec,lang);
1313
1314 if( pw->pw_shell[0] == '\0' )
1315 {
1316 setusershell();
1317 strcpy(pw->pw_shell, getusershell());
1318 endusershell();
1319 }
1320 prev=lxsession_find_user(pw->pw_uid);
1321 s=lxsession_find_greeter();
d6ba7c28 1322 if(prev && prev->child>0)
9931e273
DB
1323 {
1324 if(s) lxsession_free(s);
1325 lxsession_set_active(prev);
37f5420c
AG
1326 g_free(session_name);
1327 g_free(session_exec);
1328 g_free(session_desktop_names);
9931e273
DB
1329 return;
1330 }
1331 if(!s) s=lxsession_find_idle();
1332 if(!s) s=lxsession_add();
1333 if(!s)
1334 {
1335 g_critical("lxsession_add fail\n");
1336 exit(0);
1337 }
1338 s->greeter=FALSE;
1339 s->idle=FALSE;
1340 s->user=pw->pw_uid;
1341 if(option)
1342 s->option=g_strdup(option);
1343#if HAVE_LIBCK_CONNECTOR
1344 if(s->ckc)
1345 {
1346 ck_connector_unref(s->ckc);
1347 s->ckc=NULL;
1348 }
1349#endif
d6ba7c28 1350 lxdm_auth_session_begin(&s->auth,session_name,s->tty,s->display,s->mcookie);
9931e273
DB
1351#if HAVE_LIBCK_CONNECTOR
1352#if HAVE_LIBPAM
d6ba7c28 1353 if(!s->ckc && (!s->auth.handle || !pam_getenv(s->auth.handle,"XDG_SESSION_COOKIE")))
9931e273
DB
1354#else
1355 if(!s->ckc)
1356#endif
1357 {
1358 s->ckc = ck_connector_new();
1359 }
1360 if( s->ckc != NULL )
1361 {
1362 DBusError error;
1363 char x[256], *d, *n;
1364 gboolean is_local=TRUE;
1365 sprintf(x, "/dev/tty%d", s->tty);
1366 dbus_error_init(&error);
1367 d = x; n = getenv("DISPLAY");
1368 if( ck_connector_open_session_with_parameters(s->ckc, &error,
1369 "unix-user", &pw->pw_uid,
1370 // disable this, follow the gdm way
1371 //"display-device", &d,
1372 "x11-display-device", &d,
1373 "x11-display", &n,
1374 "is-local",&is_local,
1375 NULL))
d6ba7c28
AG
1376 {
1377 setenv("XDG_SESSION_COOKIE", ck_connector_get_cookie(s->ckc), 1);
1378 }
1379 else
1380 {
1381 g_message("create ConsoleKit session fail\n");
1382 }
1383 }
1384 else
1385 {
1386 g_message("create ConsoleKit connector fail\n");
9931e273
DB
1387 }
1388#endif
d6ba7c28
AG
1389 char **env, *path;
1390 env=g_get_environ();
1391
1392 env=g_environ_setenv(env, "HOME", pw->pw_dir, TRUE);
1393 env=g_environ_setenv(env, "SHELL", pw->pw_shell, TRUE);
1394 env=g_environ_setenv(env, "USER", pw->pw_name, TRUE);
1395 env=g_environ_setenv(env, "LOGNAME", pw->pw_name, TRUE);
9931e273
DB
1396
1397 /* override $PATH if needed */
1398 path = g_key_file_get_string(config, "base", "path", 0);
1399 if( G_UNLIKELY(path) && path[0] ) /* if PATH is specified in config file */
d6ba7c28 1400 env=g_environ_setenv(env, "PATH", path, TRUE); /* override current $PATH with config value */
9931e273 1401 else /* don't use the global env, they are bad for user */
d6ba7c28 1402 env=g_environ_setenv(env, "PATH", "/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin", TRUE); /* set proper default */
9931e273
DB
1403 g_free(path);
1404 /* optionally override $LANG, $LC_MESSAGES, and $LANGUAGE */
1405 if( lang && lang[0] )
1406 {
d6ba7c28
AG
1407 env=g_environ_setenv(env, "LANG", lang, TRUE);
1408 env=g_environ_setenv(env, "LC_MESSAGES", lang, TRUE);
1409 env=g_environ_setenv(env, "LANGUAGE", lang, TRUE);
9931e273 1410 }
c8e553a1
AG
1411
1412 if( session_desktop_names && session_desktop_names[0] )
1413 env=g_environ_setenv(env, "XDG_CURRENT_DESKTOP", session_desktop_names, TRUE);
d6ba7c28 1414
37f5420c 1415 env=lxdm_auth_append_env(&s->auth,env);
d6ba7c28
AG
1416#ifndef DISABLE_XAUTH
1417 env=create_client_auth(pw,env);
1418#endif
9931e273
DB
1419 s->env = env;
1420
d6ba7c28 1421 /*s->child = pid = fork();
9931e273
DB
1422 if(s->child==0)
1423 {
d6ba7c28
AG
1424 env=lxdm_auth_append_env(&s->auth,env);
1425 lxdm_auth_clean_for_child(&s->auth);
9931e273
DB
1426 switch_user(pw, session_exec, env);
1427 lxdm_quit_self(4);
d6ba7c28
AG
1428 }*/
1429
1430 s->child = pid = lxdm_auth_session_run(&s->auth,session_exec,env);
1431
9931e273
DB
1432 g_free(session_name);
1433 g_free(session_exec);
c8e553a1 1434 g_free(session_desktop_names);
9931e273
DB
1435 if(alloc_session)
1436 g_free(session);
1437 if(alloc_lang)
1438 g_free(lang);
1439 lxcom_add_child_watch(pid, on_session_stop, s);
1440}
1441
1442void lxdm_do_reboot(void)
1443{
1444 char *cmd;
1445 cmd = g_key_file_get_string(config, "cmd", "reboot", 0);
1446 if( !cmd ) cmd = g_strdup("reboot");
1447 g_spawn_command_line_sync("/etc/lxdm/PreReboot",0,0,0,0);
1448 g_spawn_command_line_async(cmd,0);
1449 g_free(cmd);
1450 lxdm_quit_self(0);
1451}
1452
1453void lxdm_do_shutdown(void)
1454{
1455 char *cmd;
1456 cmd = g_key_file_get_string(config, "cmd", "shutdown", 0);
1457 if( !cmd ) cmd = g_strdup("shutdown -h now");
d6ba7c28 1458 g_spawn_command_line_sync("/etc/lxdm/PreShutdown",0,0,0,0);
9931e273
DB
1459 g_spawn_command_line_async(cmd,0);
1460 g_free(cmd);
1461 lxdm_quit_self(0);
1462}
1463
1464static gboolean auto_login_future(void)
1465{
1466 return g_key_file_get_integer(config,"base","timeout",NULL)>=5;
1467}
1468
1469int lxdm_do_auto_login(void)
1470{
1471 struct passwd *pw;
1472 char *p,**users;
1473 char *pass=NULL;
1474 int i,count,ret;
1475 int success=0;
1476
1477 p = g_key_file_get_string(config, "base", "autologin", 0);
1478 if(!p) return 0;
1479 users=g_strsplit(p," ",8);
1480 g_free(p);
1481 count=g_strv_length(users);
1482
1483 #ifdef ENABLE_PASSWORD
1484 if(count==1)
1485 pass = g_key_file_get_string(config, "base", "password", 0);
1486 #endif
d6ba7c28
AG
1487
1488 /* get defaults from last login */
1489 GKeyFile *var_config = g_key_file_new();
1490 g_key_file_set_list_separator(var_config, ' ');
1491 g_key_file_load_from_file(var_config,VCONFIG_FILE,G_KEY_FILE_KEEP_COMMENTS, NULL);
1492
1493 char* last_session = g_key_file_get_string(var_config, "base", "last_session", NULL);
1494 if(last_session != NULL && last_session[0] == 0)
1495 {
1496 g_free(last_session);
1497 last_session = NULL;
1498 }
1499
1500 char* last_lang = g_key_file_get_string(var_config, "base", "last_lang", NULL);
1501
1502 g_key_file_free(var_config);
1503
9931e273
DB
1504 for(i=0;i<count;i++)
1505 {
1506 char *user,*session=NULL,*lang=NULL,*option=NULL;
1507 p=users[i];
d6ba7c28
AG
1508 /* autologin users starting with '@' get own config section with
1509 * user=, session= and lang= entry
1510 */
9931e273
DB
1511 if(p[0]=='@')
1512 {
1513 option=p+1;
1514 user=g_key_file_get_string(config,option,"user",NULL);
1515 session=g_key_file_get_string(config,option,"session",0);
1516 lang=g_key_file_get_string(config,option,"lang",0);
1517 }
d6ba7c28
AG
1518 /* autologin users not starting with '@' get user, session, lang section
1519 * from last login
1520 */
9931e273
DB
1521 else
1522 {
1523 user=g_strdup(p);
d6ba7c28
AG
1524 session=g_strdup(last_session);
1525 lang=g_strdup(last_lang);
9931e273 1526 }
d6ba7c28 1527 ret=lxdm_auth_user(AUTH_TYPE_AUTO_LOGIN, user, pass, &pw);
9931e273
DB
1528 if(ret==AUTH_SUCCESS)
1529 {
1530 lxdm_do_login(pw,session,lang,option);
1531 success=1;
1532 }
1533 g_free(user);g_free(session);g_free(lang);
1534 }
d6ba7c28
AG
1535 g_free(last_lang);
1536 g_free(last_session);
9931e273
DB
1537 g_strfreev(users);
1538 g_free(pass);
d6ba7c28 1539 return success;
9931e273
DB
1540}
1541
1542static void log_sigsegv(void)
1543{
1544 void *array[40];
1545 size_t size;
1546 char **bt_strs;
1547 size_t i;
1548
1549 size=backtrace(array,40);
1550 bt_strs=backtrace_symbols(array, size);
1551
1552 for (i=0; i<size; i++)
1553 fprintf(stderr, "%s\n", bt_strs[i]);
1554
1555 free(bt_strs);
1556}
1557
1558static void sigsegv_handler(int sig)
1559{
1560 switch(sig){
1561 case SIGSEGV:
1562 log_sigsegv();
1563 lxdm_quit_self(0);
1564 break;
1565 default:
1566 break;
1567 }
1568}
1569
1570static void lxdm_signal_handler(void *data,int sig)
1571{
1572 switch(sig){
1573 case SIGTERM:
1574 case SIGINT:
37f5420c 1575 g_critical("QUIT BY SIGNAL %d\n",sig);
9931e273
DB
1576 lxdm_quit_self(0);
1577 break;
1578 default:
1579 break;
1580 }
1581}
1582
1583static gboolean strv_find(char **strv,const char *p)
1584{
1585 int i;
1586 if(!strv || !p) return FALSE;
1587 for(i=0;strv[i]!=NULL;i++)
1588 {
1589 if(!strcmp(strv[i],p))
1590 return TRUE;
1591 }
1592 return FALSE;
1593}
1594
1595static char *lxdm_get_user_face(struct passwd *pw)
1596{
1597 GKeyFile *kf;
1598 char *face;
1599 char *file;
1600 face=g_strdup_printf("%s/.face",pw->pw_dir);
1601 if(!access(face,R_OK))
1602 return face;
1603 g_free(face);
1604 kf=g_key_file_new();
1605 file=g_build_filename ("/var/lib/AccountsService/users/", pw->pw_name, NULL);
1606 g_key_file_load_from_file (kf, file, 0, NULL);
1607 g_free(file);
1608 face=g_key_file_get_string(kf,"User","Icon",NULL);
1609 g_key_file_free(kf);
1610 if(face && !access(face,R_OK))
1611 return face;
1612 g_free(face);
1613 return NULL;
1614}
1615
1616GKeyFile *lxdm_user_list(void)
1617{
1618 struct passwd *pw;
1619 GKeyFile *kf;
1620 char *face;
1621 char **black=NULL;
1622 char **white=NULL;
1623
1624 // load black list
1625 face=g_key_file_get_string(config,"userlist","black",NULL);
1626 if(face)
1627 {
1628 black=g_strsplit(face," ",-1);
1629 g_free(face);
1630 }
1631 //load white list
1632 face=g_key_file_get_string(config,"userlist","white",NULL);
1633 if(face)
1634 {
1635 white=g_strsplit(face," ",-1);
1636 g_free(face);
1637 }
1638
1639 kf=g_key_file_new();
1640 g_key_file_set_comment(kf,NULL,NULL,"lxdm user list",NULL);
1641 while((pw=getpwent())!=NULL)
1642 {
d6ba7c28
AG
1643 char *valid_shell;
1644 gboolean ret;
1645
9931e273
DB
1646 if(strstr(pw->pw_shell, "nologin"))
1647 continue;
d6ba7c28
AG
1648
1649 ret = FALSE;
1650 setusershell();
1651 while ((valid_shell = getusershell()) != NULL) {
1652 if (g_strcmp0 (pw->pw_shell, valid_shell) != 0)
1653 continue;
1654 ret = TRUE;
1655 }
1656 endusershell();
1657 if(!ret)
1658 continue;
1659
9931e273
DB
1660 if(strncmp(pw->pw_dir,"/home/",6))
1661 {
1662 if(!strv_find(white,pw->pw_name))
1663 continue;
1664 }
1665 else
1666 {
1667 if(strv_find(black,pw->pw_name))
1668 continue;
1669 }
1670
1671 g_key_file_set_string(kf,pw->pw_name,"name",pw->pw_name);
1672 if(pw->pw_gecos && pw->pw_gecos[0] && strcmp(pw->pw_name,pw->pw_gecos))
1673 g_key_file_set_string(kf,pw->pw_name,"gecos",pw->pw_gecos);
1674 if(lxsession_find_user(pw->pw_uid))
1675 g_key_file_set_boolean(kf,pw->pw_name,"login",TRUE);
1676 face=lxdm_get_user_face(pw);
1677 if(face)
1678 g_key_file_set_string(kf,pw->pw_name,"face",face);
1679 g_free(face);
1680 }
1681 endpwent();
1682 if(black) g_strfreev(black);
1683 if(white) g_strfreev(white);
1684 return kf;
1685}
1686
1687static GString *lxdm_user_cmd(void *data,int user,int arc,char **arg)
1688{
1689 LXSession *s=NULL;
1690 GString *res=NULL;
1691 s=lxsession_find_user(user);
1692 if(!s && user==ui_greeter_user())
1693 s=lxsession_find_greeter();
1694 g_message("greeter %d session %p\n",ui_greeter_user(),lxsession_find_greeter());
1695 g_message("user %d session %p cmd %s\n",user,s,arg[0]);
1696 if(user!=0 && s==NULL)
1697 return NULL;
1698 if(!strcmp(arg[0],"USER_SWITCH"))
1699 {
1700 g_message("start greeter\n");
1701 lxsession_greeter();
1702 }
1703 else if(!strcmp(arg[0],"USER_LIST"))
1704 {
1705 GKeyFile *kf=lxdm_user_list();
1706 gsize len;
1707 char *p=g_key_file_to_data(kf,&len,NULL);
1708 if(p)
1709 {
1710 res=g_string_new_len(p,len);
37f5420c 1711 g_free(p);
9931e273
DB
1712 }
1713 g_key_file_free(kf);
1714 }
1715 return res;
1716}
1717
1718void set_signal(void)
1719{
1720 lxcom_set_signal_handler(SIGQUIT,lxdm_signal_handler,0);
1721 lxcom_set_signal_handler(SIGTERM,lxdm_signal_handler,0);
1722 lxcom_set_signal_handler(SIGINT,lxdm_signal_handler,0);
1723 lxcom_set_signal_handler(SIGHUP,lxdm_signal_handler,0);
1724 lxcom_set_signal_handler(SIGPIPE,lxdm_signal_handler,0);
1725 lxcom_set_signal_handler(SIGALRM,lxdm_signal_handler,0);
1726 signal(SIGTTIN,SIG_IGN);
1727 signal(SIGTTOU,SIG_IGN);
1728 signal(SIGUSR1,SIG_IGN);
1729 signal(SIGSEGV, sigsegv_handler);
1730}
1731
1732int main(int arc, char *arg[])
1733{
1734 int daemonmode = 0;
1735 gboolean debugmode = FALSE;
1736 int i;
1737
1738
1739 for(i=1;i<arc;i++)
1740 {
1741 if(!strcmp(arg[i],"-d"))
1742 {
1743 daemonmode=1;
1744 }
1745 else if(!strcmp(arg[i],"-D"))
1746 {
1747 debugmode=TRUE;
1748 }
1749 else if(!strcmp(arg[i],"-c") && i+1<arc)
1750 {
1751 return lxcom_send("/var/run/lxdm/lxdm.sock",arg[i+1],NULL)?0:-1;
1752 }
1753 else if(!strcmp(arg[i],"-w") && i+1<arc)
1754 {
1755 char *res=NULL;
1756 lxcom_send("/var/run/lxdm/lxdm.sock",arg[i+1],&res);
1757 if(res) printf("%s\n",res);
1758 g_free(res);
1759 return res?0:-1;
1760 }
1761 }
d6ba7c28 1762 if(getuid() != 0)
9931e273
DB
1763 {
1764 fprintf(stderr, "only root is allowed to use this program\n");
1765 exit(EXIT_FAILURE);
1766 }
1767
d6ba7c28 1768 if(daemonmode)
9931e273
DB
1769 {
1770 (void)daemon(1, 1);
1771 }
1772 log_init();
1773
d6ba7c28 1774 if(!debugmode)
9931e273 1775 {
d6ba7c28 1776 /* turn off debug output */
9931e273
DB
1777 g_log_set_handler(NULL, G_LOG_LEVEL_DEBUG, log_ignore, NULL);
1778 }
1779
1780 config = g_key_file_new();
1781 g_key_file_load_from_file(config, CONFIG_FILE, G_KEY_FILE_NONE, NULL);
1782
1783 get_lock();
1784
1785 if(0!=mkdir("/var/run/lxdm",0755))
1786 {
1787 if(errno==EEXIST)
1788 {
1789 chmod("/var/run/lxdm",0755);
1790 }
1791 else
1792 {
1793 g_critical("mkdir /var/run/lxdm fail\n");
1794 exit(-1);
1795 }
1796 }
1797 lxcom_init("/var/run/lxdm/lxdm.sock");
1798 atexit(exit_cb);
1799
1800 set_signal();
1801 lxdm_get_tty();
1802
1803 if(!auto_login_future())
1804 lxdm_do_auto_login();
1805 if(!lxsession_get_active())
1806 lxsession_greeter();
1807
1808 lxcom_add_cmd_handler(-1,lxdm_user_cmd,NULL);
1809
1810 ui_main();
1811
1812 return 0;
1813}
d6ba7c28 1814