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