1145b7b3cSmrg/* 2145b7b3cSmrg 3145b7b3cSmrgCopyright 1988, 1998 The Open Group 4145b7b3cSmrg 5145b7b3cSmrgPermission to use, copy, modify, distribute, and sell this software and its 6145b7b3cSmrgdocumentation for any purpose is hereby granted without fee, provided that 7145b7b3cSmrgthe above copyright notice appear in all copies and that both that 8145b7b3cSmrgcopyright notice and this permission notice appear in supporting 9145b7b3cSmrgdocumentation. 10145b7b3cSmrg 11145b7b3cSmrgThe above copyright notice and this permission notice shall be included 12145b7b3cSmrgin all copies or substantial portions of the Software. 13145b7b3cSmrg 14145b7b3cSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15145b7b3cSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16145b7b3cSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17145b7b3cSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 18145b7b3cSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19145b7b3cSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20145b7b3cSmrgOTHER DEALINGS IN THE SOFTWARE. 21145b7b3cSmrg 22145b7b3cSmrgExcept as contained in this notice, the name of The Open Group shall 23145b7b3cSmrgnot be used in advertising or otherwise to promote the sale, use or 24145b7b3cSmrgother dealings in this Software without prior written authorization 25145b7b3cSmrgfrom The Open Group. 26145b7b3cSmrg 27145b7b3cSmrg*/ 28145b7b3cSmrg 29145b7b3cSmrg/* 30145b7b3cSmrg * xdm - display manager daemon 31145b7b3cSmrg * Author: Keith Packard, MIT X Consortium 32145b7b3cSmrg * 33145b7b3cSmrg * verify.c 34145b7b3cSmrg * 35145b7b3cSmrg * typical unix verification routine. 36145b7b3cSmrg */ 37145b7b3cSmrg 38145b7b3cSmrg#include "dm.h" 39145b7b3cSmrg#include "dm_error.h" 40145b7b3cSmrg 41145b7b3cSmrg#include <pwd.h> 42145b7b3cSmrg 43145b7b3cSmrg#if defined(USE_PAM) 44145b7b3cSmrg# include <stdlib.h> 45629baa8cSmrg#elif defined(HAVE_GETSPNAM) 46145b7b3cSmrg# include <shadow.h> 47145b7b3cSmrg# include <errno.h> 48145b7b3cSmrg#elif defined(USE_BSDAUTH) 49145b7b3cSmrg# include <login_cap.h> 50b7d26471Smrg# include <stdarg.h> 51145b7b3cSmrg# include <bsd_auth.h> 52145b7b3cSmrg#endif 53145b7b3cSmrg 54578741aaSmrg#include "greet.h" 55145b7b3cSmrg 56145b7b3cSmrg 57b7d26471Smrgstatic const char *envvars[] = { 584901b09eSmrg "TZ", 59145b7b3cSmrg NULL 60145b7b3cSmrg}; 61145b7b3cSmrg 62145b7b3cSmrg#ifdef KERBEROS 63578741aaSmrg# include <sys/param.h> 64578741aaSmrg# include <kerberosIV/krb.h> 65145b7b3cSmrg/* OpenBSD 2.8 needs this. */ 66578741aaSmrg# if defined(OpenBSD) && (OpenBSD <= 200012) 67578741aaSmrg# include <kerberosIV/kafs.h> 68578741aaSmrg# endif 69145b7b3cSmrgstatic char krbtkfile[MAXPATHLEN]; 70145b7b3cSmrg#endif 71145b7b3cSmrg 72145b7b3cSmrgstatic char ** 73145b7b3cSmrguserEnv (struct display *d, int useSystemPath, char *user, char *home, char *shell) 74145b7b3cSmrg{ 75145b7b3cSmrg char **env; 76b7d26471Smrg const char **envvar; 77b7d26471Smrg const char *str; 78145b7b3cSmrg 79145b7b3cSmrg env = defaultEnv (); 80145b7b3cSmrg env = setEnv (env, "DISPLAY", d->name); 81145b7b3cSmrg env = setEnv (env, "HOME", home); 82145b7b3cSmrg env = setEnv (env, "LOGNAME", user); /* POSIX, System V */ 83145b7b3cSmrg env = setEnv (env, "USER", user); /* BSD */ 84145b7b3cSmrg env = setEnv (env, "PATH", useSystemPath ? d->systemPath : d->userPath); 85145b7b3cSmrg env = setEnv (env, "SHELL", shell); 86145b7b3cSmrg#ifdef KERBEROS 87145b7b3cSmrg if (krbtkfile[0] != '\0') 88145b7b3cSmrg env = setEnv (env, "KRBTKFILE", krbtkfile); 89145b7b3cSmrg#endif 90145b7b3cSmrg for (envvar = envvars; *envvar; envvar++) 91145b7b3cSmrg { 92145b7b3cSmrg str = getenv(*envvar); 93145b7b3cSmrg if (str) 94145b7b3cSmrg env = setEnv (env, *envvar, str); 95145b7b3cSmrg } 96145b7b3cSmrg return env; 97145b7b3cSmrg} 98145b7b3cSmrg 99145b7b3cSmrg#ifdef USE_BSDAUTH 100145b7b3cSmrg_X_INTERNAL 101145b7b3cSmrgint 102145b7b3cSmrgVerify (struct display *d, struct greet_info *greet, struct verify_info *verify) 103145b7b3cSmrg{ 104145b7b3cSmrg struct passwd *p; 105145b7b3cSmrg login_cap_t *lc; 106145b7b3cSmrg auth_session_t *as; 107145b7b3cSmrg char *style, *shell, *home, *s, **argv; 108145b7b3cSmrg char path[MAXPATHLEN]; 109145b7b3cSmrg int authok; 110145b7b3cSmrg 111145b7b3cSmrg /* User may have specified an authentication style. */ 112145b7b3cSmrg if ((style = strchr(greet->name, ':')) != NULL) 113145b7b3cSmrg *style++ = '\0'; 114145b7b3cSmrg 115145b7b3cSmrg Debug ("Verify %s, style %s ...\n", greet->name, 116145b7b3cSmrg style ? style : "default"); 117145b7b3cSmrg 118145b7b3cSmrg p = getpwnam (greet->name); 119145b7b3cSmrg endpwent(); 120145b7b3cSmrg 121145b7b3cSmrg if (!p || strlen (greet->name) == 0) { 122145b7b3cSmrg Debug("getpwnam() failed.\n"); 123145b7b3cSmrg bzero(greet->password, strlen(greet->password)); 124145b7b3cSmrg return 0; 125145b7b3cSmrg } 126145b7b3cSmrg 127145b7b3cSmrg if ((lc = login_getclass(p->pw_class)) == NULL) { 128145b7b3cSmrg Debug("login_getclass() failed.\n"); 129145b7b3cSmrg bzero(greet->password, strlen(greet->password)); 130145b7b3cSmrg return 0; 131145b7b3cSmrg } 132145b7b3cSmrg if ((style = login_getstyle(lc, style, "xdm")) == NULL) { 133145b7b3cSmrg Debug("login_getstyle() failed.\n"); 134145b7b3cSmrg bzero(greet->password, strlen(greet->password)); 135145b7b3cSmrg return 0; 136145b7b3cSmrg } 137145b7b3cSmrg if ((as = auth_open()) == NULL) { 138145b7b3cSmrg Debug("auth_open() failed.\n"); 139145b7b3cSmrg login_close(lc); 140145b7b3cSmrg bzero(greet->password, strlen(greet->password)); 141145b7b3cSmrg return 0; 142145b7b3cSmrg } 143145b7b3cSmrg if (auth_setoption(as, "login", "yes") == -1) { 144145b7b3cSmrg Debug("auth_setoption() failed.\n"); 145145b7b3cSmrg login_close(lc); 146145b7b3cSmrg bzero(greet->password, strlen(greet->password)); 147145b7b3cSmrg return 0; 148145b7b3cSmrg } 149145b7b3cSmrg 150145b7b3cSmrg /* Set up state for no challenge, just check a response. */ 151145b7b3cSmrg auth_setstate(as, 0); 152145b7b3cSmrg auth_setdata(as, "", 1); 153145b7b3cSmrg auth_setdata(as, greet->password, strlen(greet->password) + 1); 154145b7b3cSmrg 155145b7b3cSmrg /* Build path of the auth script and call it */ 156145b7b3cSmrg snprintf(path, sizeof(path), _PATH_AUTHPROG "%s", style); 157578741aaSmrg auth_call(as, path, style, "-s", "response", greet->name, 158145b7b3cSmrg lc->lc_class, (void *)NULL); 159145b7b3cSmrg authok = auth_getstate(as); 160145b7b3cSmrg 161145b7b3cSmrg if ((authok & AUTH_ALLOW) == 0) { 162145b7b3cSmrg Debug("password verify failed\n"); 163145b7b3cSmrg bzero(greet->password, strlen(greet->password)); 164145b7b3cSmrg auth_close(as); 165145b7b3cSmrg login_close(lc); 166145b7b3cSmrg return 0; 167145b7b3cSmrg } 168145b7b3cSmrg /* Run the approval script */ 169145b7b3cSmrg if (!auth_approval(as, lc, greet->name, "auth-xdm")) { 170145b7b3cSmrg Debug("login not approved\n"); 171145b7b3cSmrg bzero(greet->password, strlen(greet->password)); 172145b7b3cSmrg auth_close(as); 173145b7b3cSmrg login_close(lc); 174145b7b3cSmrg return 0; 175145b7b3cSmrg } 176145b7b3cSmrg auth_close(as); 177145b7b3cSmrg login_close(lc); 178145b7b3cSmrg /* Check empty passwords against allowNullPasswd */ 179145b7b3cSmrg if (!greet->allow_null_passwd && strlen(greet->password) == 0) { 180145b7b3cSmrg Debug("empty password not allowed\n"); 181145b7b3cSmrg return 0; 182145b7b3cSmrg } 183145b7b3cSmrg /* Only accept root logins if allowRootLogin resource is set */ 184145b7b3cSmrg if (p->pw_uid == 0 && !greet->allow_root_login) { 185145b7b3cSmrg Debug("root logins not allowed\n"); 186145b7b3cSmrg bzero(greet->password, strlen(greet->password)); 187145b7b3cSmrg return 0; 188145b7b3cSmrg } 189145b7b3cSmrg 190145b7b3cSmrg /* 191578741aaSmrg * Shell must be in /etc/shells 192145b7b3cSmrg */ 193145b7b3cSmrg for (;;) { 194145b7b3cSmrg s = getusershell(); 195145b7b3cSmrg if (s == NULL) { 196578741aaSmrg /* did not found the shell in /etc/shells 197145b7b3cSmrg -> failure */ 198145b7b3cSmrg Debug("shell not in /etc/shells\n"); 199145b7b3cSmrg bzero(greet->password, strlen(greet->password)); 200145b7b3cSmrg endusershell(); 201145b7b3cSmrg return 0; 202145b7b3cSmrg } 203145b7b3cSmrg if (strcmp(s, p->pw_shell) == 0) { 204145b7b3cSmrg /* found the shell in /etc/shells */ 205145b7b3cSmrg endusershell(); 206145b7b3cSmrg break; 207145b7b3cSmrg } 208578741aaSmrg } 209b7d26471Smrg#else /* !USE_BSDAUTH */ 210145b7b3cSmrg_X_INTERNAL 211145b7b3cSmrgint 212145b7b3cSmrgVerify (struct display *d, struct greet_info *greet, struct verify_info *verify) 213145b7b3cSmrg{ 214145b7b3cSmrg struct passwd *p; 215578741aaSmrg# ifndef USE_PAM 216629baa8cSmrg# ifdef HAVE_GETSPNAM 217145b7b3cSmrg struct spwd *sp; 218578741aaSmrg# endif 219145b7b3cSmrg char *user_pass = NULL; 220b7d26471Smrg char *crypted_pass = NULL; 221578741aaSmrg# endif 222578741aaSmrg# ifdef __OpenBSD__ 223145b7b3cSmrg char *s; 224145b7b3cSmrg struct timeval tp; 225578741aaSmrg# endif 226145b7b3cSmrg char *shell, *home; 227145b7b3cSmrg char **argv; 228145b7b3cSmrg 229145b7b3cSmrg Debug ("Verify %s ...\n", greet->name); 230145b7b3cSmrg 231145b7b3cSmrg p = getpwnam (greet->name); 232145b7b3cSmrg endpwent(); 233145b7b3cSmrg 234145b7b3cSmrg if (!p || strlen (greet->name) == 0) { 235145b7b3cSmrg Debug ("getpwnam() failed.\n"); 236145b7b3cSmrg if (greet->password != NULL) 237145b7b3cSmrg bzero(greet->password, strlen(greet->password)); 238145b7b3cSmrg return 0; 239145b7b3cSmrg } 240145b7b3cSmrg 241629baa8cSmrg /* 242629baa8cSmrg * Only accept root logins if allowRootLogin resource is not false 243629baa8cSmrg */ 244629baa8cSmrg if ((p->pw_uid == 0) && !greet->allow_root_login) { 245629baa8cSmrg Debug("root logins not allowed\n"); 246629baa8cSmrg if (greet->password != NULL) 247629baa8cSmrg bzero(greet->password, strlen(greet->password)); 248629baa8cSmrg return 0; 249629baa8cSmrg } 250629baa8cSmrg 251578741aaSmrg# if defined(sun) && defined(SVR4) 252578741aaSmrg /* Solaris: If CONSOLE is set to /dev/console in /etc/default/login, 253145b7b3cSmrg then root can only login on system console */ 254145b7b3cSmrg 255578741aaSmrg# define SOLARIS_LOGIN_DEFAULTS "/etc/default/login" 256145b7b3cSmrg 257145b7b3cSmrg if (p->pw_uid == 0) { 258145b7b3cSmrg char *console = NULL, *tmp = NULL; 259145b7b3cSmrg FILE *fs; 260145b7b3cSmrg 261145b7b3cSmrg if ((fs= fopen(SOLARIS_LOGIN_DEFAULTS, "r")) != NULL) 262578741aaSmrg { 263145b7b3cSmrg char str[120]; 264145b7b3cSmrg while (!feof(fs)) 265145b7b3cSmrg { 266145b7b3cSmrg fgets(str, 120, fs); 267145b7b3cSmrg if(str[0] == '#' || strlen(str) < 8) 268145b7b3cSmrg continue; 269145b7b3cSmrg if((tmp = strstr(str, "CONSOLE=")) != NULL) 270145b7b3cSmrg console = strdup((tmp+8)); 271145b7b3cSmrg } 272145b7b3cSmrg fclose(fs); 273578741aaSmrg if ( console != NULL && 274578741aaSmrg (strncmp(console, "/dev/console", 12) == 0) && 275145b7b3cSmrg (strncmp(d->name,":0",2) != 0) ) 276145b7b3cSmrg { 277145b7b3cSmrg Debug("Not on system console\n"); 278145b7b3cSmrg if (greet->password != NULL) 279145b7b3cSmrg bzero(greet->password, strlen(greet->password)); 280629baa8cSmrg free(console); 281145b7b3cSmrg return 0; 282145b7b3cSmrg } 283145b7b3cSmrg free(console); 284145b7b3cSmrg } 285145b7b3cSmrg else 286145b7b3cSmrg { 287145b7b3cSmrg Debug("Could not open %s\n", SOLARIS_LOGIN_DEFAULTS); 288578741aaSmrg } 289145b7b3cSmrg } 290578741aaSmrg# endif 291145b7b3cSmrg 292578741aaSmrg# ifndef USE_PAM /* PAM authentication happened in GreetUser already */ 293578741aaSmrg# ifdef linux 294145b7b3cSmrg if (!strcmp(p->pw_passwd, "!") || !strcmp(p->pw_passwd, "*")) { 295145b7b3cSmrg Debug ("The account is locked, no login allowed.\n"); 296145b7b3cSmrg bzero(greet->password, strlen(greet->password)); 297145b7b3cSmrg return 0; 298145b7b3cSmrg } 299578741aaSmrg# endif 300145b7b3cSmrg user_pass = p->pw_passwd; 301578741aaSmrg# ifdef KERBEROS 302145b7b3cSmrg if(strcmp(greet->name, "root") != 0){ 303145b7b3cSmrg char name[ANAME_SZ]; 304145b7b3cSmrg char realm[REALM_SZ]; 305145b7b3cSmrg char *q; 306145b7b3cSmrg int ret; 307578741aaSmrg 308145b7b3cSmrg if(krb_get_lrealm(realm, 1)){ 309145b7b3cSmrg Debug ("Can't get Kerberos realm.\n"); 310145b7b3cSmrg } else { 311145b7b3cSmrg 312578741aaSmrg snprintf(krbtkfile, sizeof(krbktfile), "%s.%s", 313578741aaSmrg TKT_ROOT, d->name); 314145b7b3cSmrg krb_set_tkt_string(krbtkfile); 315145b7b3cSmrg unlink(krbtkfile); 316578741aaSmrg 317578741aaSmrg ret = krb_verify_user(greet->name, "", realm, 318145b7b3cSmrg greet->password, 1, "rcmd"); 319578741aaSmrg 320145b7b3cSmrg if(ret == KSUCCESS){ 321145b7b3cSmrg chown(krbtkfile, p->pw_uid, p->pw_gid); 322145b7b3cSmrg Debug("kerberos verify succeeded\n"); 323145b7b3cSmrg if (k_hasafs()) { 324145b7b3cSmrg if (k_setpag() == -1) 325145b7b3cSmrg LogError ("setpag() failed for %s\n", 326145b7b3cSmrg greet->name); 327578741aaSmrg 328145b7b3cSmrg if((ret = k_afsklog(NULL, NULL)) != KSUCCESS) 329578741aaSmrg LogError("Warning %s\n", 330145b7b3cSmrg krb_get_err_text(ret)); 331145b7b3cSmrg } 332145b7b3cSmrg goto done; 333145b7b3cSmrg } else if(ret != KDC_PR_UNKNOWN && ret != SKDC_CANT){ 334145b7b3cSmrg /* failure */ 335145b7b3cSmrg Debug("kerberos verify failure %d\n", ret); 336145b7b3cSmrg krbtkfile[0] = '\0'; 337145b7b3cSmrg } 338145b7b3cSmrg } 339145b7b3cSmrg } 340578741aaSmrg# endif 341629baa8cSmrg# ifdef HAVE_GETSPNAM 342145b7b3cSmrg errno = 0; 343145b7b3cSmrg sp = getspnam(greet->name); 344145b7b3cSmrg if (sp == NULL) { 345578741aaSmrg Debug ("getspnam() failed: %s\n", _SysErrorMsg (errno)); 346145b7b3cSmrg } else { 347145b7b3cSmrg user_pass = sp->sp_pwdp; 348145b7b3cSmrg } 349145b7b3cSmrg endspent(); 350629baa8cSmrg# endif /* HAVE_GETSPNAM */ 351b7d26471Smrg crypted_pass = crypt (greet->password, user_pass); 352b7d26471Smrg if ((crypted_pass == NULL) 353b7d26471Smrg || (strcmp (crypted_pass, user_pass))) 354145b7b3cSmrg { 355145b7b3cSmrg if(!greet->allow_null_passwd || strlen(p->pw_passwd) > 0) { 356145b7b3cSmrg Debug ("password verify failed\n"); 357145b7b3cSmrg bzero(greet->password, strlen(greet->password)); 358145b7b3cSmrg return 0; 359145b7b3cSmrg } /* else: null passwd okay */ 360145b7b3cSmrg } 361578741aaSmrg# ifdef KERBEROS 362145b7b3cSmrgdone: 363578741aaSmrg# endif 364145b7b3cSmrg /* 365145b7b3cSmrg * Only accept root logins if allowRootLogin resource is set 366145b7b3cSmrg */ 367145b7b3cSmrg if ((p->pw_uid == 0) && !greet->allow_root_login) { 368145b7b3cSmrg Debug("root logins not allowed\n"); 369145b7b3cSmrg bzero(greet->password, strlen(greet->password)); 370145b7b3cSmrg return 0; 371145b7b3cSmrg } 372629baa8cSmrg# ifdef __OpenBSD__ 373145b7b3cSmrg /* 374578741aaSmrg * Shell must be in /etc/shells 375145b7b3cSmrg */ 376145b7b3cSmrg for (;;) { 377145b7b3cSmrg s = getusershell(); 378145b7b3cSmrg if (s == NULL) { 379578741aaSmrg /* did not found the shell in /etc/shells 380145b7b3cSmrg -> failure */ 381145b7b3cSmrg Debug("shell not in /etc/shells\n"); 382145b7b3cSmrg bzero(greet->password, strlen(greet->password)); 383145b7b3cSmrg endusershell(); 384145b7b3cSmrg return 0; 385145b7b3cSmrg } 386145b7b3cSmrg if (strcmp(s, p->pw_shell) == 0) { 387145b7b3cSmrg /* found the shell in /etc/shells */ 388145b7b3cSmrg endusershell(); 389145b7b3cSmrg break; 390145b7b3cSmrg } 391578741aaSmrg } 392145b7b3cSmrg /* 393145b7b3cSmrg * Test for expired password 394145b7b3cSmrg */ 395145b7b3cSmrg if (p->pw_change || p->pw_expire) 396145b7b3cSmrg (void)gettimeofday(&tp, (struct timezone *)NULL); 397145b7b3cSmrg if (p->pw_change) { 398145b7b3cSmrg if (tp.tv_sec >= p->pw_change) { 399145b7b3cSmrg Debug("Password has expired.\n"); 400145b7b3cSmrg bzero(greet->password, strlen(greet->password)); 401145b7b3cSmrg return 0; 402145b7b3cSmrg } 403145b7b3cSmrg } 404145b7b3cSmrg if (p->pw_expire) { 405145b7b3cSmrg if (tp.tv_sec >= p->pw_expire) { 406145b7b3cSmrg Debug("account has expired.\n"); 407145b7b3cSmrg bzero(greet->password, strlen(greet->password)); 408145b7b3cSmrg return 0; 409578741aaSmrg } 410145b7b3cSmrg } 411578741aaSmrg# endif /* __OpenBSD__ */ 412145b7b3cSmrg bzero(user_pass, strlen(user_pass)); /* in case shadow password */ 413145b7b3cSmrg 414578741aaSmrg# endif /* USE_PAM */ 415145b7b3cSmrg#endif /* USE_BSDAUTH */ 416145b7b3cSmrg 417145b7b3cSmrg Debug ("verify succeeded\n"); 418145b7b3cSmrg /* The password is passed to StartClient() for use by user-based 419145b7b3cSmrg authorization schemes. It is zeroed there. */ 420145b7b3cSmrg verify->uid = p->pw_uid; 421145b7b3cSmrg verify->gid = p->pw_gid; 422145b7b3cSmrg home = p->pw_dir; 423145b7b3cSmrg shell = p->pw_shell; 424145b7b3cSmrg argv = NULL; 425145b7b3cSmrg if (d->session) 426145b7b3cSmrg argv = parseArgs (argv, d->session); 427145b7b3cSmrg if (greet->string) 428145b7b3cSmrg argv = parseArgs (argv, greet->string); 429145b7b3cSmrg if (!argv) 430145b7b3cSmrg argv = parseArgs (argv, "xsession"); 431145b7b3cSmrg verify->argv = argv; 432145b7b3cSmrg verify->userEnviron = userEnv (d, p->pw_uid == 0, 433145b7b3cSmrg greet->name, home, shell); 434145b7b3cSmrg Debug ("user environment:\n"); 435145b7b3cSmrg printEnv (verify->userEnviron); 436145b7b3cSmrg verify->systemEnviron = systemEnv (d, greet->name, home); 437145b7b3cSmrg Debug ("system environment:\n"); 438145b7b3cSmrg printEnv (verify->systemEnviron); 439145b7b3cSmrg Debug ("end of environments\n"); 440145b7b3cSmrg return 1; 441145b7b3cSmrg} 442