summaryrefslogtreecommitdiff
path: root/app/xdm/greeter/verify.c
diff options
context:
space:
mode:
authorMatthieu Herrb <matthieu@cvs.openbsd.org>2006-11-25 20:39:09 +0000
committerMatthieu Herrb <matthieu@cvs.openbsd.org>2006-11-25 20:39:09 +0000
commit2387c426e6dfc2b0a2d0aa5585dbeb580f5ea91e (patch)
tree12721540663213a17c4c6a294f8f9473621fd503 /app/xdm/greeter/verify.c
parentdc4a2107be04f29ad06d6e60e102370bf68739cd (diff)
Importing from X.Org 7.2RC2
Diffstat (limited to 'app/xdm/greeter/verify.c')
-rw-r--r--app/xdm/greeter/verify.c652
1 files changed, 652 insertions, 0 deletions
diff --git a/app/xdm/greeter/verify.c b/app/xdm/greeter/verify.c
new file mode 100644
index 000000000..a5fae5c7f
--- /dev/null
+++ b/app/xdm/greeter/verify.c
@@ -0,0 +1,652 @@
+/* $Xorg: verify.c,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $ */
+/* $XdotOrg: app/xdm/greeter/verify.c,v 1.8 2006/04/14 20:17:31 alanc Exp $ */
+/*
+
+Copyright 1988, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+*/
+/* $XFree86: xc/programs/xdm/greeter/verify.c,v 3.26 2003/11/19 04:44:00 dawes Exp $ */
+
+/*
+ * xdm - display manager daemon
+ * Author: Keith Packard, MIT X Consortium
+ *
+ * verify.c
+ *
+ * typical unix verification routine.
+ */
+
+#include "dm.h"
+#include "dm_error.h"
+
+#include <pwd.h>
+
+#if defined(USE_PAM)
+# include <security/pam_appl.h>
+# include <stdlib.h>
+#elif defined(USESHADOW)
+# include <shadow.h>
+# include <errno.h>
+#elif defined(USE_BSDAUTH)
+# include <login_cap.h>
+# include <varargs.h>
+# include <bsd_auth.h>
+#elif defined(USESECUREWARE)
+# include <sys/types.h>
+# include <prot.h>
+#endif
+
+# include "greet.h"
+
+#ifdef QNX4
+extern char *crypt(const char *, const char *);
+#endif
+
+static char *envvars[] = {
+ "TZ", /* SYSV and SVR4, but never hurts */
+#if defined(sony) && !defined(SYSTYPE_SYSV) && !defined(_SYSTYPE_SYSV)
+ "bootdev",
+ "boothowto",
+ "cputype",
+ "ioptype",
+ "machine",
+ "model",
+ "CONSDEVTYPE",
+ "SYS_LANGUAGE",
+ "SYS_CODE",
+#endif
+#if (defined(SVR4) || defined(SYSV)) && defined(i386) && !defined(sun)
+ "XLOCAL",
+#endif
+ NULL
+};
+
+#ifdef KERBEROS
+#include <sys/param.h>
+#include <kerberosIV/krb.h>
+/* OpenBSD 2.8 needs this. */
+#if defined(OpenBSD) && (OpenBSD <= 200012)
+#include <kerberosIV/kafs.h>
+#endif
+static char krbtkfile[MAXPATHLEN];
+#endif
+
+static char **
+userEnv (struct display *d, int useSystemPath, char *user, char *home, char *shell)
+{
+ char **env;
+ char **envvar;
+ char *str;
+
+ env = defaultEnv ();
+ env = setEnv (env, "DISPLAY", d->name);
+ env = setEnv (env, "HOME", home);
+ env = setEnv (env, "LOGNAME", user); /* POSIX, System V */
+ env = setEnv (env, "USER", user); /* BSD */
+ env = setEnv (env, "PATH", useSystemPath ? d->systemPath : d->userPath);
+ env = setEnv (env, "SHELL", shell);
+#ifdef KERBEROS
+ if (krbtkfile[0] != '\0')
+ env = setEnv (env, "KRBTKFILE", krbtkfile);
+#endif
+ for (envvar = envvars; *envvar; envvar++)
+ {
+ str = getenv(*envvar);
+ if (str)
+ env = setEnv (env, *envvar, str);
+ }
+ return env;
+}
+
+#ifdef USE_PAM
+static char *PAM_password;
+static int pam_error;
+
+static int PAM_conv (int num_msg,
+#ifdef sun
+ struct pam_message **msg,
+#else
+ const struct pam_message **msg,
+#endif
+ struct pam_response **resp,
+ void *appdata_ptr) {
+ int count = 0, replies = 0;
+ struct pam_response *reply = NULL;
+
+#define PAM_RESPONSE_SIZE sizeof(struct pam_response)
+ size_t size = PAM_RESPONSE_SIZE;
+
+#define COPY_STRING(s) (s) ? strdup(s) : (char*)NULL
+
+ for (count = 0; count < num_msg; count++) {
+ switch (msg[count]->msg_style) {
+ case PAM_PROMPT_ECHO_ON:
+ /* user name given to PAM already */
+ return PAM_CONV_ERR;
+ case PAM_PROMPT_ECHO_OFF:
+ /* wants password */
+ if (reply) {
+ void *r2 = reply;
+ if (! (reply = realloc(reply, size))) {
+ free (r2);
+ return PAM_CONV_ERR;
+ }
+ bzero(reply + size - PAM_RESPONSE_SIZE, PAM_RESPONSE_SIZE);
+ } else {
+ if (! (reply = (struct pam_response*)malloc(size)))
+ return PAM_CONV_ERR;
+ bzero(reply, size);
+ }
+
+ if (!reply)
+ return PAM_CONV_ERR;
+
+ size += PAM_RESPONSE_SIZE;
+
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ reply[replies].resp = COPY_STRING(PAM_password);
+ /* PAM frees resp */
+ break;
+ case PAM_TEXT_INFO:
+ /* ignore the informational mesage */
+ break;
+ default:
+ /* unknown or PAM_ERROR_MSG */
+ if (reply) free (reply);
+ return PAM_CONV_ERR;
+ }
+ }
+
+#undef COPY_STRING
+ if (reply) *resp = reply;
+ return PAM_SUCCESS;
+}
+
+static struct pam_conv PAM_conversation = {
+ PAM_conv,
+ NULL
+};
+#endif /* USE_PAM */
+
+#ifdef USE_BSDAUTH
+int
+Verify (struct display *d, struct greet_info *greet, struct verify_info *verify)
+{
+ struct passwd *p;
+ login_cap_t *lc;
+ auth_session_t *as;
+ char *style, *shell, *home, *s, **argv;
+ char path[MAXPATHLEN];
+ int authok;
+
+ /* User may have specified an authentication style. */
+ if ((style = strchr(greet->name, ':')) != NULL)
+ *style++ = '\0';
+
+ Debug ("Verify %s, style %s ...\n", greet->name,
+ style ? style : "default");
+
+ p = getpwnam (greet->name);
+ endpwent();
+
+ if (!p || strlen (greet->name) == 0) {
+ Debug("getpwnam() failed.\n");
+ bzero(greet->password, strlen(greet->password));
+ return 0;
+ }
+
+ if ((lc = login_getclass(p->pw_class)) == NULL) {
+ Debug("login_getclass() failed.\n");
+ bzero(greet->password, strlen(greet->password));
+ return 0;
+ }
+ if ((style = login_getstyle(lc, style, "xdm")) == NULL) {
+ Debug("login_getstyle() failed.\n");
+ bzero(greet->password, strlen(greet->password));
+ return 0;
+ }
+ if ((as = auth_open()) == NULL) {
+ Debug("auth_open() failed.\n");
+ login_close(lc);
+ bzero(greet->password, strlen(greet->password));
+ return 0;
+ }
+ if (auth_setoption(as, "login", "yes") == -1) {
+ Debug("auth_setoption() failed.\n");
+ login_close(lc);
+ bzero(greet->password, strlen(greet->password));
+ return 0;
+ }
+
+ /* Set up state for no challenge, just check a response. */
+ auth_setstate(as, 0);
+ auth_setdata(as, "", 1);
+ auth_setdata(as, greet->password, strlen(greet->password) + 1);
+
+ /* Build path of the auth script and call it */
+ snprintf(path, sizeof(path), _PATH_AUTHPROG "%s", style);
+ auth_call(as, path, style, "-s", "response", greet->name,
+ lc->lc_class, (void *)NULL);
+ authok = auth_getstate(as);
+
+ if ((authok & AUTH_ALLOW) == 0) {
+ Debug("password verify failed\n");
+ bzero(greet->password, strlen(greet->password));
+ auth_close(as);
+ login_close(lc);
+ return 0;
+ }
+ /* Run the approval script */
+ if (!auth_approval(as, lc, greet->name, "auth-xdm")) {
+ Debug("login not approved\n");
+ bzero(greet->password, strlen(greet->password));
+ auth_close(as);
+ login_close(lc);
+ return 0;
+ }
+ auth_close(as);
+ login_close(lc);
+ /* Check empty passwords against allowNullPasswd */
+ if (!greet->allow_null_passwd && strlen(greet->password) == 0) {
+ Debug("empty password not allowed\n");
+ return 0;
+ }
+ /* Only accept root logins if allowRootLogin resource is set */
+ if (p->pw_uid == 0 && !greet->allow_root_login) {
+ Debug("root logins not allowed\n");
+ bzero(greet->password, strlen(greet->password));
+ return 0;
+ }
+
+ /*
+ * Shell must be in /etc/shells
+ */
+ for (;;) {
+ s = getusershell();
+ if (s == NULL) {
+ /* did not found the shell in /etc/shells
+ -> failure */
+ Debug("shell not in /etc/shells\n");
+ bzero(greet->password, strlen(greet->password));
+ endusershell();
+ return 0;
+ }
+ if (strcmp(s, p->pw_shell) == 0) {
+ /* found the shell in /etc/shells */
+ endusershell();
+ break;
+ }
+ }
+#elif defined(USESECUREWARE) /* !USE_BSDAUTH */
+/*
+ * This is a global variable and will be referenced in at least session.c
+ */
+struct smp_user_info *userp = 0;
+
+int
+Verify (struct display *d, struct greet_info *greet, struct verify_info *verify)
+{
+ int ret, pwtries = 0, nis, delay;
+ char *reason = 0;
+ struct passwd *p;
+ char *shell, *home, **argv;
+
+ Debug ("Verify %s ...\n", greet->name);
+
+ p = getpwnam (greet->name);
+ endpwent();
+
+ if (!p || strlen (greet->name) == 0) {
+ LogError ("getpwnam() failed.\n");
+ bzero(greet->password, strlen(greet->password));
+ return 0;
+ }
+
+ ret = smp_check_user (SMP_LOGIN, greet->name, 0, 0, &userp, &pwtries,
+ &reason, &nis, &delay);
+ if (ret != SMP_RETIRED && userp->retired)
+ ret = userp->result = SMP_RETIRED;
+ Debug ("smp_check_user returns %d\n", ret);
+
+ switch (ret) {
+ case SMP_FAIL:
+ Debug ("Out of memory in smp_check_user\n");
+ goto smp_fail;
+ case SMP_EXTFAIL:
+ Debug ("SMP_EXTFAIL: %s", reason);
+ goto smp_fail;
+ case SMP_NOTAUTH:
+ Debug ("Not authorized\n");
+ goto smp_fail;
+ case SMP_TERMLOCK:
+ Debug ("Terminal is locked!\n");
+ goto smp_fail;
+ case SMP_ACCTLOCK:
+ Debug ("Account is locked\n");
+ goto smp_fail;
+ case SMP_RETIRED:
+ Debug ("Account is retired\n");
+ goto smp_fail;
+ case SMP_OVERRIDE:
+ Debug ("On override device ... proceeding\n");
+ break;
+ case SMP_NULLPW:
+ Debug ("NULL password entry\n");
+ if (!greet->allow_null_passwd) {
+ goto smp_fail;
+ }
+ break;
+ case SMP_BADUSER:
+ Debug ("User not found in protected password database\n");
+ goto smp_fail;
+ case SMP_PWREQ:
+ Debug ("Password change required\n");
+ goto smp_fail;
+ case SMP_HASPW:
+ break;
+ default:
+ Debug ("Unhandled smp_check_user return %d\n", ret);
+smp_fail:
+ sleep(delay);
+ smp_audit_fail (userp, 0);
+ bzero(greet->password, strlen(greet->password));
+ return 0;
+ break;
+ }
+
+ if (ret != SMP_NULLPW) {
+ /*
+ * If we require a password, check it.
+ */
+ ret = smp_check_pw (greet->password, userp, &reason);
+ switch (ret) {
+ case SMP_CANCHANGE:
+ case SMP_CANTCHANGE:
+ case SMP_OVERRIDE:
+ break;
+ default:
+ goto smp_fail;
+ }
+ }
+#else /* !USE_BSDAUTH && !USESECUREWARE */
+int
+Verify (struct display *d, struct greet_info *greet, struct verify_info *verify)
+{
+ struct passwd *p;
+#ifdef USE_PAM
+ pam_handle_t **pamhp = thepamhp();
+#else
+#ifdef USESHADOW
+ struct spwd *sp;
+#endif
+ char *user_pass = NULL;
+#endif
+#ifdef __OpenBSD__
+ char *s;
+ struct timeval tp;
+#endif
+ char *shell, *home;
+ char **argv;
+
+ Debug ("Verify %s ...\n", greet->name);
+
+ p = getpwnam (greet->name);
+ endpwent();
+
+ if (!p || strlen (greet->name) == 0) {
+ Debug ("getpwnam() failed.\n");
+ bzero(greet->password, strlen(greet->password));
+ return 0;
+ }
+
+#if defined(sun) && defined(SVR4)
+ /* Solaris: If CONSOLE is set to /dev/console in /etc/default/login,
+ then root can only login on system console */
+
+# define SOLARIS_LOGIN_DEFAULTS "/etc/default/login"
+
+ if (p->pw_uid == 0) {
+ char *console = NULL, *tmp = NULL;
+ FILE *fs;
+
+ if ((fs= fopen(SOLARIS_LOGIN_DEFAULTS, "r")) != NULL)
+ {
+ char str[120];
+ while (!feof(fs))
+ {
+ fgets(str, 120, fs);
+ if(str[0] == '#' || strlen(str) < 8)
+ continue;
+ if((tmp = strstr(str, "CONSOLE=")) != NULL)
+ console = strdup((tmp+8));
+ }
+ fclose(fs);
+ if ( console != NULL &&
+ (strncmp(console, "/dev/console", 12) == 0) &&
+ (strncmp(d->name,":0",2) != 0) )
+ {
+ Debug("Not on system console\n");
+ bzero(greet->password, strlen(greet->password));
+ XFree(console);
+ return 0;
+ }
+ XFree(console);
+ }
+ else
+ {
+ Debug("Could not open %s\n", SOLARIS_LOGIN_DEFAULTS);
+ }
+ }
+#endif
+
+#ifndef USE_PAM
+#ifdef linux
+ if (!strcmp(p->pw_passwd, "!") || !strcmp(p->pw_passwd, "*")) {
+ Debug ("The account is locked, no login allowed.\n");
+ bzero(greet->password, strlen(greet->password));
+ return 0;
+ }
+#endif
+ user_pass = p->pw_passwd;
+#endif
+#ifdef KERBEROS
+ if(strcmp(greet->name, "root") != 0){
+ char name[ANAME_SZ];
+ char realm[REALM_SZ];
+ char *q;
+ int ret;
+
+ if(krb_get_lrealm(realm, 1)){
+ Debug ("Can't get Kerberos realm.\n");
+ } else {
+
+ sprintf(krbtkfile, "%s.%s", TKT_ROOT, d->name);
+ krb_set_tkt_string(krbtkfile);
+ unlink(krbtkfile);
+
+ ret = krb_verify_user(greet->name, "", realm,
+ greet->password, 1, "rcmd");
+
+ if(ret == KSUCCESS){
+ chown(krbtkfile, p->pw_uid, p->pw_gid);
+ Debug("kerberos verify succeeded\n");
+ if (k_hasafs()) {
+ if (k_setpag() == -1)
+ LogError ("setpag() failed for %s\n",
+ greet->name);
+
+ if((ret = k_afsklog(NULL, NULL)) != KSUCCESS)
+ LogError("Warning %s\n",
+ krb_get_err_text(ret));
+ }
+ goto done;
+ } else if(ret != KDC_PR_UNKNOWN && ret != SKDC_CANT){
+ /* failure */
+ Debug("kerberos verify failure %d\n", ret);
+ krbtkfile[0] = '\0';
+ }
+ }
+ }
+#endif
+#ifndef USE_PAM
+#ifdef USESHADOW
+ errno = 0;
+ sp = getspnam(greet->name);
+ if (sp == NULL) {
+ Debug ("getspnam() failed, errno=%d. Are you root?\n", errno);
+ } else {
+ user_pass = sp->sp_pwdp;
+ }
+#ifndef QNX4
+ endspent();
+#endif /* QNX4 doesn't need endspent() to end shadow passwd ops */
+#endif
+#if defined(ultrix) || defined(__ultrix__)
+ if (authenticate_user(p, greet->password, NULL) < 0)
+#else
+ if (strcmp (crypt (greet->password, user_pass), user_pass))
+#endif
+ {
+ if(!greet->allow_null_passwd || strlen(p->pw_passwd) > 0) {
+ Debug ("password verify failed\n");
+ bzero(greet->password, strlen(greet->password));
+ return 0;
+ } /* else: null passwd okay */
+ }
+#ifdef KERBEROS
+done:
+#endif
+#ifdef __OpenBSD__
+ /*
+ * Only accept root logins if allowRootLogin resource is set
+ */
+ if ((p->pw_uid == 0) && !greet->allow_root_login) {
+ Debug("root logins not allowed\n");
+ bzero(greet->password, strlen(greet->password));
+ return 0;
+ }
+ /*
+ * Shell must be in /etc/shells
+ */
+ for (;;) {
+ s = getusershell();
+ if (s == NULL) {
+ /* did not found the shell in /etc/shells
+ -> failure */
+ Debug("shell not in /etc/shells\n");
+ bzero(greet->password, strlen(greet->password));
+ endusershell();
+ return 0;
+ }
+ if (strcmp(s, p->pw_shell) == 0) {
+ /* found the shell in /etc/shells */
+ endusershell();
+ break;
+ }
+ }
+ /*
+ * Test for expired password
+ */
+ if (p->pw_change || p->pw_expire)
+ (void)gettimeofday(&tp, (struct timezone *)NULL);
+ if (p->pw_change) {
+ if (tp.tv_sec >= p->pw_change) {
+ Debug("Password has expired.\n");
+ bzero(greet->password, strlen(greet->password));
+ return 0;
+ }
+ }
+ if (p->pw_expire) {
+ if (tp.tv_sec >= p->pw_expire) {
+ Debug("account has expired.\n");
+ bzero(greet->password, strlen(greet->password));
+ return 0;
+ }
+ }
+#endif /* __OpenBSD__ */
+ bzero(user_pass, strlen(user_pass)); /* in case shadow password */
+
+#else /* USE_PAM */
+#define PAM_BAIL \
+ if (pam_error != PAM_SUCCESS) goto pam_failed;
+
+ PAM_password = greet->password;
+ pam_error = pam_start("xdm", greet->name, &PAM_conversation, pamhp);
+ PAM_BAIL;
+ pam_error = pam_set_item(*pamhp, PAM_TTY, d->name);
+ PAM_BAIL;
+ pam_error = pam_set_item(*pamhp, PAM_RHOST, "");
+ PAM_BAIL;
+ pam_error = pam_authenticate(*pamhp, 0);
+ PAM_BAIL;
+ pam_error = pam_acct_mgmt(*pamhp, 0);
+ /* really should do password changing, but it doesn't fit well */
+ PAM_BAIL;
+ pam_error = pam_setcred(*pamhp, 0);
+ PAM_BAIL;
+ p = getpwnam (greet->name);
+ endpwent();
+
+ if (!p || strlen (greet->name) == 0) {
+ Debug ("getpwnam() failed.\n");
+ bzero(greet->password, strlen(greet->password));
+ return 0;
+ }
+
+ if (pam_error != PAM_SUCCESS) {
+ pam_failed:
+ pam_end(*pamhp, PAM_SUCCESS);
+ *pamhp = NULL;
+ return 0;
+ }
+#undef PAM_BAIL
+#endif /* USE_PAM */
+#endif /* USE_BSDAUTH */
+
+ Debug ("verify succeeded\n");
+ /* The password is passed to StartClient() for use by user-based
+ authorization schemes. It is zeroed there. */
+ verify->uid = p->pw_uid;
+ verify->gid = p->pw_gid;
+ home = p->pw_dir;
+ shell = p->pw_shell;
+ argv = 0;
+ if (d->session)
+ argv = parseArgs (argv, d->session);
+ if (greet->string)
+ argv = parseArgs (argv, greet->string);
+ if (!argv)
+ argv = parseArgs (argv, "xsession");
+ verify->argv = argv;
+ verify->userEnviron = userEnv (d, p->pw_uid == 0,
+ greet->name, home, shell);
+ Debug ("user environment:\n");
+ printEnv (verify->userEnviron);
+ verify->systemEnviron = systemEnv (d, greet->name, home);
+ Debug ("system environment:\n");
+ printEnv (verify->systemEnviron);
+ Debug ("end of environments\n");
+ return 1;
+}