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