1 /* $Xorg: verify.c,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $ */
2 /*
3 
4 Copyright 1988, 1998  The Open Group
5 
6 Permission to use, copy, modify, distribute, and sell this software and its
7 documentation for any purpose is hereby granted without fee, provided that
8 the above copyright notice appear in all copies and that both that
9 copyright notice and this permission notice appear in supporting
10 documentation.
11 
12 The above copyright notice and this permission notice shall be included
13 in all copies or substantial portions of the Software.
14 
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 OTHER DEALINGS IN THE SOFTWARE.
22 
23 Except as contained in this notice, the name of The Open Group shall
24 not be used in advertising or otherwise to promote the sale, use or
25 other dealings in this Software without prior written authorization
26 from The Open Group.
27 
28 */
29 /* $XFree86: xc/programs/xdm/greeter/verify.c,v 3.21 2001/12/14 20:01:29 dawes Exp $ */
30 
31 /*
32  * xdm - display manager daemon
33  * Author:  Keith Packard, MIT X Consortium
34  *
35  * verify.c
36  *
37  * typical unix verification routine.
38  */
39 
40 #include	<dm.h>
41 
42 #include	<pwd.h>
43 #ifdef USE_PAM
44 # include	<security/pam_appl.h>
45 # include	<stdlib.h>
46 #else
47 # ifdef HAVE_SHADOW_H
48 #  include	<shadow.h>
49 #  include	<errno.h>
50 # endif
51 #endif
52 
53 # include	<greet.h>
54 
55 #include <wdmlib.h>
56 
57 #ifdef QNX4
58 extern char *crypt(const char *, const char *);
59 #endif
60 
61 static char *envvars[] = {
62     "TZ",			/* SYSV and SVR4, but never hurts */
63 #if defined(sony) && !defined(SYSTYPE_SYSV) && !defined(_SYSTYPE_SYSV)
64     "bootdev",
65     "boothowto",
66     "cputype",
67     "ioptype",
68     "machine",
69     "model",
70     "CONSDEVTYPE",
71     "SYS_LANGUAGE",
72     "SYS_CODE",
73 #endif
74 #if (defined(SVR4) || defined(SYSV)) && defined(i386) && !defined(sun)
75     "XLOCAL",
76 #endif
77     NULL
78 };
79 
80 #ifdef KERBEROS
81 #include <sys/param.h>
82 #include <kerberosIV/krb.h>
83 #include <kerberosIV/kafs.h>
84 static char krbtkfile[MAXPATHLEN];
85 #endif
86 
87 static char **
userEnv(struct display * d,int useSystemPath,char * user,char * home,char * shell)88 userEnv (struct display *d, int useSystemPath, char *user, char *home, char *shell)
89 {
90     char	**env;
91     char	**envvar;
92     char	*str;
93 
94     env = defaultEnv ();
95     env = WDMSetEnv(env, "DISPLAY", d->name);
96     env = WDMSetEnv(env, "HOME", home);
97     env = WDMSetEnv(env, "LOGNAME", user); /* POSIX, System V */
98     env = WDMSetEnv(env, "USER", user);    /* BSD */
99     env = WDMSetEnv(env, "PATH", useSystemPath ? d->systemPath : d->userPath);
100     env = WDMSetEnv(env, "SHELL", shell);
101 #ifdef KERBEROS
102     if (krbtkfile[0] != '\0')
103         env = WDMSetEnv(env, "KRBTKFILE", krbtkfile);
104 #endif
105     for (envvar = envvars; *envvar; envvar++)
106     {
107 	str = getenv(*envvar);
108 	if (str)
109 	    env = WDMSetEnv(env, *envvar, str);
110     }
111     return env;
112 }
113 
114 #ifdef USE_PAM
115 static char *PAM_password;
116 static int pam_error;
117 
PAM_conv(int num_msg,struct pam_message ** msg,struct pam_response ** resp,void * appdata_ptr)118 static int PAM_conv (int num_msg,
119 #ifdef sun
120 		     struct pam_message **msg,
121 #else
122 		     const struct pam_message **msg,
123 #endif
124 		     struct pam_response **resp,
125 		     void *appdata_ptr) {
126 	int count = 0, replies = 0;
127 	struct pam_response *reply = NULL;
128 
129 #define PAM_RESPONSE_SIZE	sizeof(struct pam_response)
130 	size_t size = PAM_RESPONSE_SIZE;
131 
132 #define COPY_STRING(s) (s) ? strdup(s) : (char*)NULL
133 
134 	for (count = 0; count < num_msg; count++) {
135 		switch (msg[count]->msg_style) {
136 		case PAM_PROMPT_ECHO_ON:
137 			/* user name given to PAM already */
138 			return PAM_CONV_ERR;
139 		case PAM_PROMPT_ECHO_OFF:
140 			/* wants password */
141 			if (reply) {
142 				reply = realloc(reply, size);
143 				bzero(reply + size - PAM_RESPONSE_SIZE, PAM_RESPONSE_SIZE);
144 			} else {
145 				reply = (struct pam_response*)malloc(size);
146 				bzero(reply, size);
147 			}
148 
149 			if (!reply)
150 				return PAM_CONV_ERR;
151 
152 			size += PAM_RESPONSE_SIZE;
153 
154 			reply[replies].resp_retcode = PAM_SUCCESS;
155 			reply[replies].resp = COPY_STRING(PAM_password);
156 			/* PAM frees resp */
157 			break;
158 		case PAM_TEXT_INFO:
159 			/* ignore the informational mesage */
160 			break;
161 		default:
162 			/* unknown or PAM_ERROR_MSG */
163 			if (reply) free (reply);
164 			return PAM_CONV_ERR;
165 		}
166 	}
167 
168 #undef COPY_STRING
169 	if (reply) *resp = reply;
170 	return PAM_SUCCESS;
171 }
172 
173 static struct pam_conv PAM_conversation = {
174 	PAM_conv,
175 	NULL
176 };
177 #endif /* USE_PAM */
178 
179 #ifdef USE_BSDAUTH
180 int
Verify(struct display * d,struct greet_info * greet,struct verify_info * verify)181 Verify (struct display *d, struct greet_info *greet, struct verify_info *verify)
182 {
183 	struct passwd	*p;
184 	login_cap_t	*lc;
185 	auth_session_t	*as;
186 	char		*style, *shell, *home, *s, **argv;
187 	char		path[MAXPATHLEN];
188 	int		authok;
189 
190 	/* User may have specified an authentication style. */
191 	if ((style = strchr(greet->name, ':')) != NULL)
192 		*style++ = '\0';
193 
194 	Debug ("Verify %s, style %s ...\n", greet->name,
195 	    style ? style : "default");
196 
197 	p = getpwnam (greet->name);
198 	endpwent();
199 
200 	if (!p || strlen (greet->name) == 0) {
201 		Debug("getpwnam() failed.\n");
202 		bzero(greet->password, strlen(greet->password));
203 		return 0;
204 	}
205 
206 	if ((lc = login_getclass(p->pw_class)) == NULL) {
207 		Debug("login_getclass() failed.\n");
208 		bzero(greet->password, strlen(greet->password));
209 		return 0;
210 	}
211 	if ((style = login_getstyle(lc, style, "xdm")) == NULL) {
212 		Debug("login_getstyle() failed.\n");
213 		bzero(greet->password, strlen(greet->password));
214 		return 0;
215 	}
216 	if ((as = auth_open()) == NULL) {
217 		Debug("auth_open() failed.\n");
218 		login_close(lc);
219 		bzero(greet->password, strlen(greet->password));
220 		return 0;
221 	}
222 	if (auth_setoption(as, "login", "yes") == -1) {
223 		Debug("auth_setoption() failed.\n");
224 		login_close(lc);
225 		bzero(greet->password, strlen(greet->password));
226 		return 0;
227 	}
228 
229 	/* Set up state for no challenge, just check a response. */
230 	auth_setstate(as, 0);
231 	auth_setdata(as, "", 1);
232 	auth_setdata(as, greet->password, strlen(greet->password) + 1);
233 
234 	/* Build path of the auth script and call it */
235 	snprintf(path, sizeof(path), _PATH_AUTHPROG "%s", style);
236 	auth_call(as, path, style, "-s", "response", greet->name, NULL);
237 	authok = auth_getstate(as);
238 
239 	if ((authok & AUTH_ALLOW) == 0) {
240 		Debug("password verify failed\n");
241 		bzero(greet->password, strlen(greet->password));
242 		auth_close(as);
243 		login_close(lc);
244 		return 0;
245 	}
246 	/* Run the approval script */
247 	if (!auth_approval(as, lc, greet->name, "auth-xdm")) {
248 		Debug("login not approved\n");
249 		bzero(greet->password, strlen(greet->password));
250 		auth_close(as);
251 		login_close(lc);
252 		return 0;
253 	}
254 	auth_close(as);
255 	login_close(lc);
256 	/* Check empty passwords against allowNullPasswd */
257 	if (!greet->allow_null_passwd && strlen(greet->password) == 0) {
258 		Debug("empty password not allowed\n");
259 		return 0;
260 	}
261 	/* Only accept root logins if allowRootLogin resource is set */
262 	if (p->pw_uid == 0 && !greet->allow_root_login) {
263 		Debug("root logins not allowed\n");
264 		bzero(greet->password, strlen(greet->password));
265 		return 0;
266 	}
267 
268 	/*
269 	 * Shell must be in /etc/shells
270 	 */
271 	for (;;) {
272 		s = getusershell();
273 		if (s == NULL) {
274 			/* did not found the shell in /etc/shells
275 			   -> failure */
276 			Debug("shell not in /etc/shells\n");
277 			bzero(greet->password, strlen(greet->password));
278 			endusershell();
279 			return 0;
280 		}
281 		if (strcmp(s, p->pw_shell) == 0) {
282 			/* found the shell in /etc/shells */
283 			endusershell();
284 			break;
285 		}
286 	}
287 #else /* !USE_BSDAUTH */
288 int
289 Verify (struct display *d, struct greet_info *greet, struct verify_info *verify)
290 {
291 	struct passwd	*p;
292 #ifdef USE_PAM
293 	pam_handle_t **pamhp = thepamhp();
294 #else
295 #ifdef HAVE_SHADOW_H
296 	struct spwd	*sp;
297 #endif
298 	char		*user_pass = NULL;
299 #endif
300 #ifdef __OpenBSD__
301 	char            *s;
302 	struct timeval  tp;
303 #endif
304 	char		*shell, *home;
305 	char		**argv;
306 
307 	WDMDebug("Verify %s ...\n", greet->name);
308 #ifndef USE_PAM
309 	p = getpwnam (greet->name);
310 	endpwent();
311 
312 	if (!p || strlen (greet->name) == 0) {
313 		WDMDebug("getpwnam() failed.\n");
314 		bzero(greet->password, strlen(greet->password));
315 		return 0;
316 	} else {
317 #ifdef linux
318 	    if (!strcmp(p->pw_passwd, "!") || !strcmp(p->pw_passwd, "*")) {
319 		WDMDebug("The account is locked, no login allowed.\n");
320 		bzero(greet->password, strlen(greet->password));
321 		return 0;
322 	    }
323 #endif
324 	    user_pass = p->pw_passwd;
325 	}
326 #endif
327 #ifdef KERBEROS
328 	if(strcmp(greet->name, "root") != 0){
329 		char name[ANAME_SZ];
330 		char realm[REALM_SZ];
331 		char *q;
332 		int ret;
333 
334 		if(krb_get_lrealm(realm, 1)){
335 			WDMDebug("Can't get Kerberos realm.\n");
336 		} else {
337 
338 		    sprintf(krbtkfile, "%s.%s", TKT_ROOT, d->name);
339 		    krb_set_tkt_string(krbtkfile);
340 		    unlink(krbtkfile);
341 
342 		    ret = krb_verify_user(greet->name, "", realm,
343 				      greet->password, 1, "rcmd");
344 
345 		    if(ret == KSUCCESS){
346 			    chown(krbtkfile, p->pw_uid, p->pw_gid);
347 			    WDMDebug("kerberos verify succeeded\n");
348 			    if (k_hasafs()) {
349 				    if (k_setpag() == -1)
350 					    WDMError("setpag() failed for %s\n",
351 						      greet->name);
352 
353 				    if((ret = k_afsklog(NULL, NULL)) != KSUCCESS)
354 					    WDMError("Warning %s\n",
355 						     krb_get_err_text(ret));
356 			    }
357 			    goto done;
358 		    } else if(ret != KDC_PR_UNKNOWN && ret != SKDC_CANT){
359 			    /* failure */
360 			    WDMDebug("kerberos verify failure %d\n", ret);
361 			    krbtkfile[0] = '\0';
362 		    }
363 		}
364 	}
365 #endif
366 #ifndef USE_PAM
367 #ifdef HAVE_SHADOW_H
368 	errno = 0;
369 	sp = getspnam(greet->name);
370 	if (sp == NULL) {
371 	    WDMDebug("getspnam() failed, errno=%d.  Are you root?\n", errno);
372 	} else {
373 	    user_pass = sp->sp_pwdp;
374 	}
375 #ifndef QNX4
376 	endspent();
377 #endif  /* QNX4 doesn't need endspent() to end shadow passwd ops */
378 #endif
379 #if defined(ultrix) || defined(__ultrix__)
380 	if (authenticate_user(p, greet->password, NULL) < 0)
381 #else
382 	if (strcmp (crypt (greet->password, user_pass), user_pass))
383 #endif
384 	{
385 		if(!greet->allow_null_passwd || strlen(p->pw_passwd) > 0) {
386 			WDMDebug("password verify failed\n");
387 			bzero(greet->password, strlen(greet->password));
388 			return 0;
389 		} /* else: null passwd okay */
390 	}
391 #ifdef KERBEROS
392 done:
393 #endif
394 #ifdef __OpenBSD__
395 	/*
396 	 * Only accept root logins if allowRootLogin resource is set
397 	 */
398 	if ((p->pw_uid == 0) && !greet->allow_root_login) {
399 		WDMDebug("root logins not allowed\n");
400 		bzero(greet->password, strlen(greet->password));
401 		return 0;
402 	}
403 	/*
404 	 * Shell must be in /etc/shells
405 	 */
406 	for (;;) {
407 		s = getusershell();
408 		if (s == NULL) {
409 			/* did not found the shell in /etc/shells
410 			   -> failure */
411 			WDMDebug("shell not in /etc/shells\n");
412 			bzero(greet->password, strlen(greet->password));
413 			endusershell();
414 			return 0;
415 		}
416 		if (strcmp(s, p->pw_shell) == 0) {
417 			/* found the shell in /etc/shells */
418 			endusershell();
419 			break;
420 		}
421 	}
422 	/*
423 	 * Test for expired password
424 	 */
425 	if (p->pw_change || p->pw_expire)
426 		(void)gettimeofday(&tp, (struct timezone *)NULL);
427 	if (p->pw_change) {
428 		if (tp.tv_sec >= p->pw_change) {
429 			WDMDebug("Password has expired.\n");
430 			bzero(greet->password, strlen(greet->password));
431 			return 0;
432 		}
433 	}
434 	if (p->pw_expire) {
435 		if (tp.tv_sec >= p->pw_expire) {
436 			WDMDebug("account has expired.\n");
437 			bzero(greet->password, strlen(greet->password));
438 			return 0;
439 		}
440 	}
441 #endif /* __OpenBSD__ */
442 	bzero(user_pass, strlen(user_pass)); /* in case shadow password */
443 
444 #else /* USE_PAM */
445 #define PAM_BAIL	\
446 	if (pam_error != PAM_SUCCESS) goto pam_failed;
447 
448 	PAM_password = greet->password;
449 	pam_error = pam_start("wdm", greet->name, &PAM_conversation, pamhp);
450 	PAM_BAIL;
451 	pam_error = pam_set_item(*pamhp, PAM_TTY, d->name);
452 	PAM_BAIL;
453 	pam_error = pam_set_item(*pamhp, PAM_RHOST, "");
454 	PAM_BAIL;
455 	pam_error = pam_authenticate(*pamhp, 0);
456 	PAM_BAIL;
457 	pam_error = pam_acct_mgmt(*pamhp, 0);
458 	/* really should do password changing, but it doesn't fit well */
459 	PAM_BAIL;
460 	pam_error = pam_setcred(*pamhp, 0);
461 	PAM_BAIL;
462 	p = getpwnam (greet->name);
463 	endpwent();
464 
465 	if (!p || strlen (greet->name) == 0) {
466 		WDMDebug("getpwnam() failed.\n");
467 		bzero(greet->password, strlen(greet->password));
468 		return 0;
469 	}
470 
471 	if (pam_error != PAM_SUCCESS) {
472 	pam_failed:
473 		pam_end(*pamhp, PAM_SUCCESS);
474 		*pamhp = NULL;
475 		return 0;
476 	}
477 #undef PAM_BAIL
478 #endif /* USE_PAM */
479 #endif /* USE_BSDAUTH */
480 
481 	WDMDebug("verify succeeded\n");
482 	/* The password is passed to StartClient() for use by user-based
483 	   authorization schemes.  It is zeroed there. */
484 	verify->uid = p->pw_uid;
485 	verify->gid = p->pw_gid;
486 	home = p->pw_dir;
487 	shell = p->pw_shell;
488 	argv = 0;
489 	if (d->session)
490 		argv = parseArgs (argv, d->session);
491 	if (greet->string)
492 		argv = parseArgs (argv, greet->string);
493 	if (!argv)
494 		argv = parseArgs (argv, "xsession");
495 	verify->argv = argv;
496 	verify->userEnviron = userEnv (d, p->pw_uid == 0,
497 				       greet->name, home, shell);
498 	WDMDebug("user environment:\n");
499 	WDMPrintEnv (verify->userEnviron);
500 	verify->systemEnviron = systemEnv (d, greet->name, home);
501 	WDMDebug("system environment:\n");
502 	WDMPrintEnv (verify->systemEnviron);
503 	WDMDebug("end of environments\n");
504 	return 1;
505 }
506