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