Merging upstream version 0.5.3 (Closes: #805659 CVE-2015-8308).
[debian/lxdm.git] / src / auth.c
CommitLineData
d6ba7c28
AG
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#ifdef USE_PAM
29#define HAVE_LIBPAM 1
30#else
31#define HAVE_LIBPAM 0
32#endif
33#endif
34
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <stdarg.h>
39
40#include <pwd.h>
41#include <grp.h>
42#include <shadow.h>
43#include <unistd.h>
44#include <errno.h>
45
46#include <glib.h>
47
48#include "lxdm.h"
49#include "auth.h"
50
51#if HAVE_LIBPAM
52
53#define PAM_MP 1
54
55#endif
56
57void switch_user(struct passwd *pw, const char *run, char **env);
58
59static void passwd_clean(struct passwd *pw)
60{
61 g_free(pw->pw_name);
62 g_free(pw->pw_gecos);
63 g_free(pw->pw_dir);
64 g_free(pw->pw_shell);
65 memset(pw,0,sizeof(*pw));
66}
67
68#if !PAM_MP
69static void passwd_copy(struct passwd *dst,struct passwd *src)
70{
71 dst->pw_name=g_strdup(src->pw_name);
72 dst->pw_uid=src->pw_uid;
73 dst->pw_gid=src->pw_gid;
74 if(src->pw_gecos)
75 dst->pw_gecos=g_strdup(src->pw_gecos);
76 dst->pw_dir=g_strdup(src->pw_dir);
77 dst->pw_shell=g_strdup(src->pw_shell);
78}
79#endif
80
81#if !HAVE_LIBPAM
82
83
84int lxdm_auth_init(LXDM_AUTH *a)
85{
86 memset(a,0,sizeof(*a));
87 return 0;
88}
89
90int lxdm_auth_cleanup(LXDM_AUTH *a)
91{
92 passwd_clean(&a->pw);
93 return 0;
94}
95
96int lxdm_auth_user_authenticate(LXDM_AUTH *a,const char *user,const char *pass,int type)
97{
98 struct passwd *pw;
99 struct spwd *sp;
100 char *real;
101 char *enc;
102 if(!user || !user[0])
103 {
104 g_debug("user==NULL\n");
105 return AUTH_ERROR;
106 }
107 pw = getpwnam(user);
108 endpwent();
109 if(!pw)
110 {
111 g_debug("user %s not found\n",user);
112 return AUTH_BAD_USER;
113 }
114 if(strstr(pw->pw_shell, "nologin"))
115 {
116 g_debug("user %s have nologin shell\n",user);
117 return AUTH_PRIV;
118 }
119 if(type==AUTH_TYPE_AUTO_LOGIN && !pass)
120 {
121 goto out;
122 }
123 sp = getspnam(user);
124 if( !sp )
125 {
126 return AUTH_FAIL;
127 }
128 endspent();
129 real = sp->sp_pwdp;
130 if( !real || !real[0] )
131 {
132 if( !pass || !pass[0] )
133 {
134 passwd_copy(&a->pw,pw);
135 g_debug("user %s auth with no password ok\n",user);
136 return AUTH_SUCCESS;
137 }
138 else
139 {
140 g_debug("user %s password not match\n",user);
141 return AUTH_FAIL;
142 }
143 }
144 enc = crypt(pass, real);
145 if( strcmp(real, enc) )
146 {
147 g_debug("user %s password not match\n",user);
148 return AUTH_FAIL;
149 }
150out:
151 g_debug("user %s auth ok\n",pw->pw_name);
152 passwd_copy(&a->pw,pw);
153 return AUTH_SUCCESS;
154}
155
156int lxdm_auth_session_begin(LXDM_AUTH *a,const char *name,int tty,int display,char mcookie[16])
157{
158 return 0;
159}
160
161int lxdm_auth_session_end(LXDM_AUTH *a)
162{
163 return 0;
164}
165
166int lxdm_auth_clean_for_child(LXDM_AUTH *a)
167{
168 return 0;
169}
170
171char **lxdm_auth_append_env(LXDM_AUTH *a,char **env)
172{
173 return env;
174}
175
176int lxdm_auth_session_run(LXDM_AUTH *a,const char *session_exec,char **env)
177{
178 int pid;
179 pid = fork();
180 if(pid==0)
181 {
37f5420c 182 //env=lxdm_auth_append_env(a,env);
d6ba7c28
AG
183 lxdm_auth_clean_for_child(a);
184 switch_user(&a->pw, session_exec, env);
185 lxdm_quit_self(4);
186 }
187 return pid;
188}
189
190#elif !PAM_MP
191
192#include <security/pam_appl.h>
193
194static char *user_pass[2];
195
196static int do_conv(int num, const struct pam_message **msg,struct pam_response **resp, void *arg)
197{
198 int result = PAM_SUCCESS;
199 int i;
200 *resp = (struct pam_response *) calloc(num, sizeof(struct pam_response));
201 for(i=0;i<num;i++)
202 {
203 //printf("MSG: %d %s\n",msg[i]->msg_style,msg[i]->msg);
204 switch(msg[i]->msg_style){
205 case PAM_PROMPT_ECHO_ON:
206 resp[i]->resp=strdup(user_pass[0]?user_pass[0]:"");
207 break;
208 case PAM_PROMPT_ECHO_OFF:
209 //resp[i]->resp=strdup(user_pass[1]?user_pass[1]:"");
210 resp[i]->resp=user_pass[1]?strdup(user_pass[1]):NULL;
211 break;
212 case PAM_ERROR_MSG:
213 case PAM_TEXT_INFO:
214 //printf("PAM: %s\n",msg[i]->msg);
215 break;
216 default:
217 break;
218 }
219 }
220 return result;
221}
222
223static struct pam_conv conv={.conv=do_conv,.appdata_ptr=user_pass};
224
225int lxdm_auth_init(LXDM_AUTH *a)
226{
227 memset(a,0,sizeof(*a));
228 return 0;
229}
230
231int lxdm_auth_cleanup(LXDM_AUTH *a)
232{
233 passwd_clean(&a->pw);
234 return 0;
235}
236
237int lxdm_auth_user_authenticate(LXDM_AUTH *a,const char *user,const char *pass,int type)
238{
239 struct passwd *pw;
240 if(!user || !user[0])
241 {
242 g_debug("user==NULL\n");
243 return AUTH_ERROR;
244 }
245 pw = getpwnam(user);
246 endpwent();
247 if(!pw)
248 {
249 g_debug("user %s not found\n",user);
250 return AUTH_BAD_USER;
251 }
252 if(strstr(pw->pw_shell, "nologin"))
253 {
254 g_debug("user %s have nologin shell\n",user);
255 return AUTH_PRIV;
256 }
257 if(a->handle) pam_end(a->handle,0);
258 if(PAM_SUCCESS != pam_start("lxdm", pw->pw_name, &conv, (pam_handle_t**)&a->handle))
259 {
260 a->handle=NULL;
261 g_debug("user %s start pam fail\n",user);
262 return AUTH_FAIL;
263 }
264 else
265 {
266 int ret;
267 if(type==AUTH_TYPE_AUTO_LOGIN && !pass)
268 goto out;
269 user_pass[0]=(char*)user;user_pass[1]=(char*)pass;
270 ret=pam_authenticate(a->handle,PAM_SILENT);
271 user_pass[0]=0;user_pass[1]=0;
272 if(ret!=PAM_SUCCESS)
273 {
274 g_debug("user %s auth fail with %d\n",user,ret);
275 return AUTH_FAIL;
276 }
277 ret=pam_acct_mgmt(a->handle,PAM_SILENT);
278 if(ret!=PAM_SUCCESS)
279 {
280 g_debug("user %s acct mgmt fail with %d\n",user,ret);
281 return AUTH_FAIL;
282 }
283 }
284out:
285 passwd_copy(&a->pw,pw);
286 return AUTH_SUCCESS;
287}
288
289int lxdm_auth_session_begin(LXDM_AUTH *a,const char *name,int tty,int display,char mcookie[16])
290{
291 int err;
292 char x[256];
293
294 if(!a->handle)
295 {
296 g_message("begin session without auth\n");
297 return -1;
298 }
299 sprintf(x, "tty%d", tty);
300 pam_set_item(a->handle, PAM_TTY, x);
301#ifdef PAM_XDISPLAY
302 sprintf(x,":%d",display);
303 pam_set_item(a->handle, PAM_XDISPLAY, x);
304#endif
305#if !defined(DISABLE_XAUTH) && defined(PAM_XAUTHDATA)
306 struct pam_xauth_data value;
307 value.name="MIT-MAGIC-COOKIE-1";
308 value.namelen=18;
309 value.data=mcookie;
310 value.datalen=16;
311 pam_set_item (a->handle, PAM_XAUTHDATA, &value);
312#endif
313 if(name && name[0])
314 {
315 char *env;
316 env = g_strdup_printf ("DESKTOP_SESSION=%s", name);
317 pam_putenv (a->handle, env);
318 g_free (env);
319 }
320 err = pam_open_session(a->handle, 0); /* FIXME pam session failed */
321 if( err != PAM_SUCCESS )
322 g_warning( "pam open session error \"%s\"\n", pam_strerror(a->handle, err));
323 else
324 a->in_session=1;
325 return 0;
326}
327
328int lxdm_auth_session_end(LXDM_AUTH *a)
329{
330 int err;
331 if(!a->handle)
332 return 0;
333 if(a->in_session)
334 {
335 err = pam_close_session(a->handle, 0);
336 a->in_session=0;
337 }
338 pam_end(a->handle, err);
339 a->handle = NULL;
340 passwd_clean(&a->pw);
341 return 0;
342}
343
344int lxdm_auth_clean_for_child(LXDM_AUTH *a)
345{
346 pam_end(a->handle,0);
347 return 0;
348}
349
350char **lxdm_auth_append_env(LXDM_AUTH *a,char **env)
351{
352 int i,j,n,pa;
353 char **penv;
354 if(!a->handle) return env;
355 penv=pam_getenvlist(a->handle);
356 if(!penv) return env;
357 pa=g_strv_length(penv);
358 if(pa==0)
359 {
360 free(penv);
361 return env;
362 }
363 env=g_renew(char *,env,g_strv_length(env)+1+pa+10);
364 for(i=0;penv[i]!=NULL;i++)
365 {
366 fprintf(stderr,"PAM %s\n",penv[i]);
367 n=strcspn(penv[i],"=")+1;
368 for(j=0;env[j]!=NULL;j++)
369 {
370 if(!strncmp(penv[i],env[j],n))
371 break;
372 if(env[j+1]==NULL)
373 {
374 env[j+1]=g_strdup(penv[i]);
375 env[j+2]=NULL;
376 break;
377 }
378 }
379 free(penv[i]);
380 }
381 free(penv);
382 return env;
383}
384
385int lxdm_auth_session_run(LXDM_AUTH *a,const char *session_exec,char **env)
386{
387 int pid;
388 pid = fork();
389 if(pid==0)
390 {
37f5420c 391 //env=lxdm_auth_append_env(a,env);
d6ba7c28
AG
392 lxdm_auth_clean_for_child(a);
393 switch_user(&a->pw, session_exec, env);
394 lxdm_quit_self(4);
395 }
396 return pid;
397}
398
399#else
400
401static void xwrite(int fd,const void *buf,size_t size)
402{
403 int ret;
404 do{
405 ret=write(fd,buf,size);
406 }while(ret==-1 && errno==EINTR);
407}
408
409static int xreadline(int fd,char *buf,size_t size)
410{
411 int i;
412 for(i=0;i<size-1;i++)
413 {
414 int ret;
415 do{
416 ret=read(fd,buf+i,1);
417 }while(ret==-1 && errno==EINTR);
418 if(buf[i]==-1 || buf[i]=='\n')
419 break;
420 }
421 buf[i]=0;
422 return i;
423}
424
425int lxdm_auth_init(LXDM_AUTH *a)
426{
427 memset(a,0,sizeof(*a));
428 a->pipe[0]=a->pipe[1]=-1;
429 return 0;
430}
431
432int lxdm_auth_cleanup(LXDM_AUTH *a)
433{
434 passwd_clean(&a->pw);
435 if(a->pipe[0]!=-1)
436 {
437 close(a->pipe[0]);
438 a->pipe[0]=-1;
439 }
440 if(a->pipe[1]!=-1)
441 {
442 close(a->pipe[1]);
443 a->pipe[1]=-1;
444 }
445 return 0;
446}
447
448//#undef LXDM_SESSION_PATH
449//#define LXDM_SESSION_PATH "./lxdm-session"
450static int check_child(LXDM_AUTH *a)
451{
452 if(a->pipe[0]!=-1)
453 return 0;
454 char *argv[3]={LXDM_SESSION_PATH,NULL,NULL};
455 GPid pid;
456 gboolean ret;
457 ret = g_spawn_async_with_pipes(NULL, argv, NULL,
458 G_SPAWN_DO_NOT_REAP_CHILD, NULL,NULL,
459 &pid, a->pipe + 0, a->pipe + 1, NULL, NULL);
460 if(ret==FALSE)
461 {
462 g_message("spawn lxdm-session fail\n");
463 return -1;
464 }
465 a->child=(int)pid;
466 return 0;
467}
468
469int lxdm_auth_user_authenticate(LXDM_AUTH *a,const char *user,const char *pass,int type)
470{
471 char temp[128];
472 char res[8];
473 int ret;
474 if(check_child(a)!=0)
475 {
476 printf("check child fail\n");
477 return -1;
478 }
479 if(type==AUTH_TYPE_AUTO_LOGIN && pass)
480 type=AUTH_TYPE_NORMAL;
481 else if(type==AUTH_TYPE_NORMAL && !pass)
482 type=AUTH_TYPE_NULL_PASS;
483 xwrite(a->pipe[0],"auth\n",5);
484 ret=sprintf(temp,"%d\n",type);
485 xwrite(a->pipe[0],temp,ret);
486 ret=sprintf(temp,"%s\n",user);
487 xwrite(a->pipe[0],temp,ret);
488 if(pass!=NULL)
489 ret=sprintf(temp,"%s\n",pass);
490 xwrite(a->pipe[0],temp,ret);
491 ret=xreadline(a->pipe[1],res,sizeof(res));
492 if(ret<=0)
493 {
494 g_message("read user auth result fail\n");
495 return -1;
496 }
497 ret=atoi(res);
498 if(ret==AUTH_SUCCESS)
499 {
500 passwd_clean(&a->pw);
501 a->pw.pw_name=g_strdup(user);
502 ret=xreadline(a->pipe[1],temp,sizeof(temp));
503 if(ret==-1) return -1;
504 a->pw.pw_uid=atoi(temp);
505 ret=xreadline(a->pipe[1],temp,sizeof(temp));
506 if(ret==-1) return -1;
507 a->pw.pw_gid=atoi(temp);
508 ret=xreadline(a->pipe[1],temp,sizeof(temp));
509 if(ret==-1) return -1;
510 a->pw.pw_gecos=g_strdup(temp);
511 ret=xreadline(a->pipe[1],temp,sizeof(temp));
512 if(ret==-1) return -1;
513 a->pw.pw_dir=g_strdup(temp);
514 ret=xreadline(a->pipe[1],temp,sizeof(temp));
515 if(ret==-1) return -1;
516 a->pw.pw_shell=g_strdup(temp);
517 }
518 return atoi(res);
519}
520#include <assert.h>
521int lxdm_auth_session_begin(LXDM_AUTH *a,const char *name,int tty,int display,char mcookie[16])
522{
523 char temp[256];
524 char res[8];
525 gchar *b64;
526 int ret;
527
528 if(check_child(a)!=0)
529 return -1;
530 xwrite(a->pipe[0],"begin\n",6);
531 ret=sprintf(temp,"%s\n",name?:"");
532 xwrite(a->pipe[0],temp,ret);
533 ret=sprintf(temp,"%d\n",tty);
534 xwrite(a->pipe[0],temp,ret);
535 ret=sprintf(temp,"%d\n",display);
536 xwrite(a->pipe[0],temp,ret);
537 b64=g_base64_encode((const guchar*)mcookie,16);
538 assert(b64!=NULL);
539 ret=sprintf(temp,"%s\n",b64);
540 g_free(b64);
541 xwrite(a->pipe[0],temp,ret);
542 ret=xreadline(a->pipe[1],res,sizeof(res));
543 if(ret<=0)
544 {
545 g_message("pam session begin fail\n");
546 return -1;
547 }
548 ret=atoi(res);
549 return ret;
550}
551
552int lxdm_auth_session_end(LXDM_AUTH *a)
553{
554 passwd_clean(&a->pw);
555 if(a->pipe[0]!=-1)
556 {
557 xwrite(a->pipe[0],"exit\n",5);
558 close(a->pipe[0]);
559 a->pipe[0]=-1;
560 }
561 if(a->pipe[1]!=-1)
562 {
563 close(a->pipe[1]);
564 a->pipe[1]=-1;
565 }
566 return 0;
567}
568
569int lxdm_auth_clean_for_child(LXDM_AUTH *a)
570{
571 return 0;
572}
573
574char **lxdm_auth_append_env(LXDM_AUTH *a,char **env)
575{
576 int i,j,n,pa;
577 char temp[1024];
578 int ret;
579 char **penv;
580
581 if(check_child(a)!=0)
582 return env;
583 xwrite(a->pipe[0],"env\n",4);
584 ret=xreadline(a->pipe[1],temp,sizeof(temp));
585 if(ret<=0) return env;
586 penv=g_strsplit(temp," ",-1);
587 pa=g_strv_length(penv);
588 if(pa==0)
589 {
590 g_strfreev(penv);
591 return env;
592 }
593 env=g_renew(char *,env,g_strv_length(env)+1+pa+10);
594 for(i=0;penv[i]!=NULL;i++)
595 {
596 g_debug("PAM %s\n",penv[i]);
597 n=strcspn(penv[i],"=")+1;
598 for(j=0;env[j]!=NULL;j++)
599 {
600 if(!strncmp(penv[i],env[j],n))
601 break;
602 if(env[j+1]==NULL)
603 {
604 env[j+1]=g_strdup(penv[i]);
605 env[j+2]=NULL;
606 break;
607 }
608 }
609 }
610 g_strfreev(penv);
611 return env;
612}
613
614int lxdm_auth_session_run(LXDM_AUTH *a,const char *session_exec,char **env)
615{
616 int fd;
617 if(check_child(a)!=0)
618 return -1;
619 fd=a->pipe[0];
620 if(env!=NULL)
621 {
622 int i;
623 xwrite(fd,"putenv\n",7);
624 for(i=0;env[i]!=NULL;i++)
625 {
626 xwrite(fd,env[i],strlen(env[i]));
627 xwrite(fd,"\n",1);
628 }
629 xwrite(a->pipe[0],"\n",1);
630 }
631 xwrite(fd,"exec\n",5);
632 xwrite(fd,session_exec,strlen(session_exec));
633 xwrite(fd,"\n",1);
634 return a->child;
635}
636
637#endif
638