1/*
2
3Copyright 1988, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27*/
28
29/*
30 * xdm - display manager daemon
31 * Author:  Keith Packard, MIT X Consortium
32 *
33 * verify.c
34 *
35 * typical unix verification routine.
36 */
37
38#include	"dm.h"
39#include	"dm_error.h"
40
41#include	<pwd.h>
42
43#if defined(USE_PAM)
44# include	<stdlib.h>
45#elif defined(HAVE_GETSPNAM)
46# include	<shadow.h>
47# include	<errno.h>
48#elif defined(USE_BSDAUTH)
49# include	<login_cap.h>
50# include	<stdarg.h>
51# include	<bsd_auth.h>
52#endif
53
54#include	"greet.h"
55
56
57static const char *envvars[] = {
58    "TZ",
59    NULL
60};
61
62#ifdef KERBEROS
63# include <sys/param.h>
64# include <kerberosIV/krb.h>
65/* OpenBSD 2.8 needs this. */
66# if defined(OpenBSD) && (OpenBSD <= 200012)
67#  include <kerberosIV/kafs.h>
68# endif
69static char krbtkfile[MAXPATHLEN];
70#endif
71
72static char **
73userEnv (struct display *d, int useSystemPath, char *user, char *home, char *shell)
74{
75    char	**env;
76    const char	**envvar;
77    const char	*str;
78
79    env = defaultEnv ();
80    env = setEnv (env, "DISPLAY", d->name);
81    env = setEnv (env, "HOME", home);
82    env = setEnv (env, "LOGNAME", user); /* POSIX, System V */
83    env = setEnv (env, "USER", user);    /* BSD */
84    env = setEnv (env, "PATH", useSystemPath ? d->systemPath : d->userPath);
85    env = setEnv (env, "SHELL", shell);
86#ifdef KERBEROS
87    if (krbtkfile[0] != '\0')
88        env = setEnv (env, "KRBTKFILE", krbtkfile);
89#endif
90    for (envvar = envvars; *envvar; envvar++)
91    {
92	str = getenv(*envvar);
93	if (str)
94	    env = setEnv (env, *envvar, str);
95    }
96    return env;
97}
98
99#ifdef USE_BSDAUTH
100_X_INTERNAL
101int
102Verify (struct display *d, struct greet_info *greet, struct verify_info *verify)
103{
104	struct passwd	*p;
105	login_cap_t	*lc;
106	auth_session_t	*as;
107	char		*style, *shell, *home, *s, **argv;
108	char		path[MAXPATHLEN];
109	int		authok;
110
111	/* User may have specified an authentication style. */
112	if ((style = strchr(greet->name, ':')) != NULL)
113		*style++ = '\0';
114
115	Debug ("Verify %s, style %s ...\n", greet->name,
116	    style ? style : "default");
117
118	p = getpwnam (greet->name);
119	endpwent();
120
121	if (!p || strlen (greet->name) == 0) {
122		Debug("getpwnam() failed.\n");
123		bzero(greet->password, strlen(greet->password));
124		return 0;
125	}
126
127	if ((lc = login_getclass(p->pw_class)) == NULL) {
128		Debug("login_getclass() failed.\n");
129		bzero(greet->password, strlen(greet->password));
130		return 0;
131	}
132	if ((style = login_getstyle(lc, style, "xdm")) == NULL) {
133		Debug("login_getstyle() failed.\n");
134		bzero(greet->password, strlen(greet->password));
135		return 0;
136	}
137	if ((as = auth_open()) == NULL) {
138		Debug("auth_open() failed.\n");
139		login_close(lc);
140		bzero(greet->password, strlen(greet->password));
141		return 0;
142	}
143	if (auth_setoption(as, "login", "yes") == -1) {
144		Debug("auth_setoption() failed.\n");
145		login_close(lc);
146		bzero(greet->password, strlen(greet->password));
147		return 0;
148	}
149
150	/* Set up state for no challenge, just check a response. */
151	auth_setstate(as, 0);
152	auth_setdata(as, "", 1);
153	auth_setdata(as, greet->password, strlen(greet->password) + 1);
154
155	/* Build path of the auth script and call it */
156	snprintf(path, sizeof(path), _PATH_AUTHPROG "%s", style);
157	auth_call(as, path, style, "-s", "response", greet->name,
158		  lc->lc_class, (void *)NULL);
159	authok = auth_getstate(as);
160
161	if ((authok & AUTH_ALLOW) == 0) {
162		Debug("password verify failed\n");
163		bzero(greet->password, strlen(greet->password));
164		auth_close(as);
165		login_close(lc);
166		return 0;
167	}
168	/* Run the approval script */
169	if (!auth_approval(as, lc, greet->name, "auth-xdm")) {
170		Debug("login not approved\n");
171		bzero(greet->password, strlen(greet->password));
172		auth_close(as);
173		login_close(lc);
174		return 0;
175	}
176	auth_close(as);
177	login_close(lc);
178	/* Check empty passwords against allowNullPasswd */
179	if (!greet->allow_null_passwd && strlen(greet->password) == 0) {
180		Debug("empty password not allowed\n");
181		return 0;
182	}
183	/* Only accept root logins if allowRootLogin resource is set */
184	if (p->pw_uid == 0 && !greet->allow_root_login) {
185		Debug("root logins not allowed\n");
186		bzero(greet->password, strlen(greet->password));
187		return 0;
188	}
189
190	/*
191	 * Shell must be in /etc/shells
192	 */
193	for (;;) {
194		s = getusershell();
195		if (s == NULL) {
196			/* did not found the shell in /etc/shells
197			   -> failure */
198			Debug("shell not in /etc/shells\n");
199			bzero(greet->password, strlen(greet->password));
200			endusershell();
201			return 0;
202		}
203		if (strcmp(s, p->pw_shell) == 0) {
204			/* found the shell in /etc/shells */
205			endusershell();
206			break;
207		}
208	}
209#else /* !USE_BSDAUTH */
210_X_INTERNAL
211int
212Verify (struct display *d, struct greet_info *greet, struct verify_info *verify)
213{
214	struct passwd	*p;
215# ifndef USE_PAM
216#  ifdef HAVE_GETSPNAM
217	struct spwd	*sp;
218#  endif
219	char		*user_pass = NULL;
220	char		*crypted_pass = NULL;
221# endif
222# ifdef __OpenBSD__
223	char            *s;
224	struct timeval  tp;
225# endif
226	char		*shell, *home;
227	char		**argv;
228
229	Debug ("Verify %s ...\n", greet->name);
230
231	p = getpwnam (greet->name);
232	endpwent();
233
234	if (!p || strlen (greet->name) == 0) {
235		Debug ("getpwnam() failed.\n");
236		if (greet->password != NULL)
237		    bzero(greet->password, strlen(greet->password));
238		return 0;
239	}
240
241	/*
242	 * Only accept root logins if allowRootLogin resource is not false
243	 */
244	if ((p->pw_uid == 0) && !greet->allow_root_login) {
245		Debug("root logins not allowed\n");
246		if (greet->password != NULL)
247		    bzero(greet->password, strlen(greet->password));
248		return 0;
249	}
250
251# if defined(sun) && defined(SVR4)
252	/* Solaris: If CONSOLE is set to /dev/console in /etc/default/login,
253	   then root can only login on system console */
254
255#  define SOLARIS_LOGIN_DEFAULTS "/etc/default/login"
256
257	if (p->pw_uid == 0) {
258	    char *console = NULL, *tmp = NULL;
259	    FILE *fs;
260
261	    if ((fs= fopen(SOLARIS_LOGIN_DEFAULTS, "r")) != NULL)
262	    {
263		char str[120];
264		while (!feof(fs))
265		{
266		    fgets(str, 120, fs);
267		    if(str[0] == '#' || strlen(str) < 8)
268			continue;
269		    if((tmp = strstr(str, "CONSOLE=")) != NULL)
270			console = strdup((tmp+8));
271		}
272		fclose(fs);
273                if ( console != NULL &&
274		  (strncmp(console, "/dev/console", 12) == 0) &&
275		  (strncmp(d->name,":0",2) != 0) )
276		{
277                        Debug("Not on system console\n");
278			if (greet->password != NULL)
279			    bzero(greet->password, strlen(greet->password));
280			free(console);
281	                return 0;
282                }
283		free(console);
284	    }
285	    else
286	    {
287		Debug("Could not open %s\n", SOLARIS_LOGIN_DEFAULTS);
288	    }
289	}
290# endif
291
292# ifndef USE_PAM /* PAM authentication happened in GreetUser already */
293#  ifdef linux
294	if (!strcmp(p->pw_passwd, "!") || !strcmp(p->pw_passwd, "*")) {
295	    Debug ("The account is locked, no login allowed.\n");
296	    bzero(greet->password, strlen(greet->password));
297	    return 0;
298	}
299#  endif
300	user_pass = p->pw_passwd;
301#  ifdef KERBEROS
302	if(strcmp(greet->name, "root") != 0){
303		char name[ANAME_SZ];
304		char realm[REALM_SZ];
305		char *q;
306		int ret;
307
308		if(krb_get_lrealm(realm, 1)){
309			Debug ("Can't get Kerberos realm.\n");
310		} else {
311
312		    snprintf(krbtkfile, sizeof(krbktfile), "%s.%s",
313			     TKT_ROOT, d->name);
314		    krb_set_tkt_string(krbtkfile);
315		    unlink(krbtkfile);
316
317		    ret = krb_verify_user(greet->name, "", realm,
318				      greet->password, 1, "rcmd");
319
320		    if(ret == KSUCCESS){
321			    chown(krbtkfile, p->pw_uid, p->pw_gid);
322			    Debug("kerberos verify succeeded\n");
323			    if (k_hasafs()) {
324				    if (k_setpag() == -1)
325					    LogError ("setpag() failed for %s\n",
326						      greet->name);
327
328				    if((ret = k_afsklog(NULL, NULL)) != KSUCCESS)
329					    LogError("Warning %s\n",
330						     krb_get_err_text(ret));
331			    }
332			    goto done;
333		    } else if(ret != KDC_PR_UNKNOWN && ret != SKDC_CANT){
334			    /* failure */
335			    Debug("kerberos verify failure %d\n", ret);
336			    krbtkfile[0] = '\0';
337		    }
338		}
339	}
340#  endif
341#  ifdef HAVE_GETSPNAM
342	errno = 0;
343	sp = getspnam(greet->name);
344	if (sp == NULL) {
345	    Debug ("getspnam() failed: %s\n", _SysErrorMsg (errno));
346	} else {
347	    user_pass = sp->sp_pwdp;
348	}
349	endspent();
350#  endif /* HAVE_GETSPNAM */
351	crypted_pass = crypt (greet->password, user_pass);
352	if ((crypted_pass == NULL)
353	    || (strcmp (crypted_pass, user_pass)))
354	{
355		if(!greet->allow_null_passwd || strlen(p->pw_passwd) > 0) {
356			Debug ("password verify failed\n");
357			bzero(greet->password, strlen(greet->password));
358			return 0;
359		} /* else: null passwd okay */
360	}
361#  ifdef KERBEROS
362done:
363#  endif
364	/*
365	 * Only accept root logins if allowRootLogin resource is set
366	 */
367	if ((p->pw_uid == 0) && !greet->allow_root_login) {
368		Debug("root logins not allowed\n");
369		bzero(greet->password, strlen(greet->password));
370		return 0;
371	}
372#  ifdef __OpenBSD__
373	/*
374	 * Shell must be in /etc/shells
375	 */
376	for (;;) {
377		s = getusershell();
378		if (s == NULL) {
379			/* did not found the shell in /etc/shells
380			   -> failure */
381			Debug("shell not in /etc/shells\n");
382			bzero(greet->password, strlen(greet->password));
383			endusershell();
384			return 0;
385		}
386		if (strcmp(s, p->pw_shell) == 0) {
387			/* found the shell in /etc/shells */
388			endusershell();
389			break;
390		}
391	}
392	/*
393	 * Test for expired password
394	 */
395	if (p->pw_change || p->pw_expire)
396		(void)gettimeofday(&tp, (struct timezone *)NULL);
397	if (p->pw_change) {
398		if (tp.tv_sec >= p->pw_change) {
399			Debug("Password has expired.\n");
400			bzero(greet->password, strlen(greet->password));
401			return 0;
402		}
403	}
404	if (p->pw_expire) {
405		if (tp.tv_sec >= p->pw_expire) {
406			Debug("account has expired.\n");
407			bzero(greet->password, strlen(greet->password));
408			return 0;
409		}
410	}
411#  endif /* __OpenBSD__ */
412	bzero(user_pass, strlen(user_pass)); /* in case shadow password */
413
414# endif /* USE_PAM */
415#endif /* USE_BSDAUTH */
416
417	Debug ("verify succeeded\n");
418	/* The password is passed to StartClient() for use by user-based
419	   authorization schemes.  It is zeroed there. */
420	verify->uid = p->pw_uid;
421	verify->gid = p->pw_gid;
422	home = p->pw_dir;
423	shell = p->pw_shell;
424	argv = NULL;
425	if (d->session)
426		argv = parseArgs (argv, d->session);
427	if (greet->string)
428		argv = parseArgs (argv, greet->string);
429	if (!argv)
430		argv = parseArgs (argv, "xsession");
431	verify->argv = argv;
432	verify->userEnviron = userEnv (d, p->pw_uid == 0,
433				       greet->name, home, shell);
434	Debug ("user environment:\n");
435	printEnv (verify->userEnviron);
436	verify->systemEnviron = systemEnv (d, greet->name, home);
437	Debug ("system environment:\n");
438	printEnv (verify->systemEnviron);
439	Debug ("end of environments\n");
440	return 1;
441}
442