Ejemplo n.º 1
0
/* Return the default security context for the given username */
static security_context_t
ssh_selinux_getctxbyname(char *pwname)
{
	security_context_t sc = NULL;
	char *sename = NULL, *lvl = NULL;
	int r;

#ifdef HAVE_GETSEUSERBYNAME
	if (getseuserbyname(pwname, &sename, &lvl) != 0)
		return NULL;
#else
	sename = pwname;
	lvl = NULL;
#endif

#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL
	r = get_default_context_with_level(sename, lvl, NULL, &sc);
#else
	r = get_default_context(sename, NULL, &sc);
#endif

	if (r != 0) {
		switch (security_getenforce()) {
		case -1:
			fatal("%s: ssh_selinux_getctxbyname: "
			    "security_getenforce() failed", __func__);
		case 0:
			error("%s: Failed to get default SELinux security "
			    "context for %s", __func__, pwname);
			sc = NULL;
			break;
		default:
			fatal("%s: Failed to get default SELinux security "
			    "context for %s (in enforcing mode)",
			    __func__, pwname);
		}
	}

#ifdef HAVE_GETSEUSERBYNAME
	if (sename != NULL)
		xfree(sename);
	if (lvl != NULL)
		xfree(lvl);
#endif

	return sc;
}
Ejemplo n.º 2
0
static void initselinux(char *username, char *full_tty,
                        security_context_t *user_sid)
{
    security_context_t old_tty_sid, new_tty_sid;

    if (!is_selinux_enabled())
        return;

    if (get_default_context(username, NULL, user_sid)) {
        bb_error_msg_and_die("can't get SID for %s", username);
    }
    if (getfilecon(full_tty, &old_tty_sid) < 0) {
        bb_perror_msg_and_die("getfilecon(%s) failed", full_tty);
    }
    if (security_compute_relabel(*user_sid, old_tty_sid,
                                 SECCLASS_CHR_FILE, &new_tty_sid) != 0) {
        bb_perror_msg_and_die("security_change_sid(%s) failed", full_tty);
    }
    if (setfilecon(full_tty, new_tty_sid) != 0) {
        bb_perror_msg_and_die("chsid(%s, %s) failed", full_tty, new_tty_sid);
    }
}
Ejemplo n.º 3
0
/* selinux_prepare_fork - Initialize context switching
 *
 * Returns
 *  - 0 if everything is OK, 
 *  - +1 if the code should continue, even if SELinux wouldn't allow
 *       (for instance due to permissive mode)
 *  - -1 if the code should not continue
 */
int selinux_prepare_fork(char * name) {
#ifndef SELINUX
  return 0;
#else
  char * newcon = 0;
  char * curcon = 0;
  struct av_decision avd;
  int rc;
  int permissive = 0;
  int dom_permissive = 0;

  char * sename = 0;
  char * selevel = 0;

  /*
   * See if SELinux is enabled.
   * If not, then we can immediately tell the code
   * that everything is OK.
   */
  rc = is_selinux_enabled();
  if (rc == 0) {
    out(DEBUG, "SELinux is not enabled.\n");
    return 0;
  } else if (rc == -1) {
    out(WARN, "Could not check SELinux state (is_selinux_enabled() failed)\n");
    return 1;
  };
  out(DEBUG, "SELinux is enabled.\n");

  /*
   * See if SELinux is in enforcing mode
   * or permissive mode
   */
  rc = security_getenforce();
  if (rc == 0) {
    permissive = 1;
  } else if (rc == 1) {
    permissive = 0;
  } else {
    out(WARN, "Could not check SELinux mode (security_getenforce() failed)\n");
  }
  out(DEBUG, "SELinux mode is %s\n", permissive ? "permissive" : "enforcing");

  /*
   * Get the current SELinux context of the process.
   * Always interesting to log this for end users
   * trying to debug a possible issue.
   */
  rc = getcon(&curcon);
  if (rc) {
    out(WARN, "Could not get current SELinux context (getcon() failed)\n");
    if (permissive)
      return +1;
    else
      return -1;
  };
  out(DEBUG, "Currently in SELinux context \"%s\"\n", (char *) curcon);
 
  /*
   * Get the SELinux user given the Linux user
   * name passed on to this function.
   */
  rc = getseuserbyname(name, &sename, &selevel);
  if (rc) {
    out(WARN, "Could not find SELinux user for Linux user \"%s\" (getseuserbyname() failed)\n", name);
    freecon(curcon);
    if (permissive)
      return +1;
    else
      return -1;
  };
  out(DEBUG, "SELinux user for Linux user \"%s\" is \"%s\"\n", name, sename);

  /*
   * Find out what the context is that this process should transition
   * to.
   */
  rc = get_default_context(sename, NULL, &newcon);
  if (rc) {
    out(WARN, "Could not deduce default context for SELinux user \"%s\" given our current context (\"%s\")\n", sename, (char *) curcon);
    freecon(curcon);
    if (permissive)
      return +1;
    else
      return -1;
  };
  out(DEBUG, "SELinux context to transition to is \"%s\"\n", (char *) newcon);

  /*
   * Now let's look if we are allowed to transition to the new context.
   * We currently only check the transition access for the process class. However,
   * transitioning is a bit more complex (execute rights on target context, 
   * entrypoint of that context for the new domain, no constraints like target
   * domain not being a valid one, MLS constraints, etc.).
   */
  rc = security_compute_av_flags(curcon, newcon, SECCLASS_PROCESS, PROCESS__TRANSITION, &avd);
  if (rc) {
    out(WARN, "Could not deduce rights for transitioning \"%s\" -> \"%s\" (security_compute_av_flags() failed)\n", (char *) curcon, (char *) newcon);
    freecon(curcon);
    freecon(newcon);
    if (permissive)
      return +1;
    else
      return -1;
  };
  /* Validate the response 
   *
   * We are interested in two things:
   * - Is the transition allowed, but also
   * - Is the permissive flag set
   *
   * If the permissive flag is set, then we
   * know the current domain is permissive
   * (even if the rest of the system is in
   * enforcing mode).
   */
  if (avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE) {
    out(DEBUG, "The SELINUX_AVD_FLAGS_PERMISSIVE flag is set, so domain is permissive.\n");
    dom_permissive = 1;
  };
  if (!(avd.allowed & PROCESS__TRANSITION)) {
    // The transition is denied
    if (permissive) {
      out(DEBUG, "Transition is not allowed by SELinux, but permissive mode is enabled. Continuing.\n");
    };
    if (dom_permissive) {
      out(DEBUG, "Transition is not allowed by SELinux, but domain is in permissive mode. Continuing.\n");
    };
    if ((permissive == 0) && (dom_permissive == 0)) {
      out(WARN, "The domain transition is not allowed and we are not in permissive mode.\n");
      freecon(curcon);
      freecon(newcon);
      return -1;
    };
  };


  /*
   * Set the context for the fork (process execution).
   */
  rc = setexeccon(newcon);
  if (rc) {
    out(WARN, "Could not set execution context (setexeccon() failed)\n");
    freecon(curcon);
    freecon(newcon);
    if ((permissive) || (dom_permissive))
      return +1;
    else
      return -1;
  };

  freecon(newcon);
  freecon(curcon);

  return 0;
#endif
};
Ejemplo n.º 4
0
static Bool StartClient(struct verify_info *verify, struct display *d, int *pidp, char *name, char *passwd
#ifdef WITH_CONSOLE_KIT
						, char *ck_session_cookie
#endif
	)
{
	char **f;
	const char *home;
	char *failsafeArgv[2];
	int pid;
#ifdef HAS_SETUSERCONTEXT
	struct passwd *pwd;
#endif
#ifdef USE_PAM
	pam_handle_t *pamh = thepamh();
#endif

	if (verify->argv) {
		WDMDebug("StartSession %s: ", verify->argv[0]);
		for (f = verify->argv; *f; f++)
			WDMDebug("%s ", *f);
		WDMDebug("; ");
	}
	if (verify->userEnviron) {
		for (f = verify->userEnviron; *f; f++)
			WDMDebug("%s ", *f);
		WDMDebug("\n");
	}

	/* Do system-dependent login setup here */

	if (setgid(verify->gid) < 0) {
		WDMError("setgid %d (user \"%s\") failed, errno=%d\n", verify->gid, name, errno);
		return (0);
	}
#if defined(BSD) && (BSD >= 199103)
	if (setlogin(name) < 0) {
		WDMError("setlogin for \"%s\" failed, errno=%d", name, errno);
		return (0);
	}
#endif
	if (initgroups(name, verify->gid) < 0) {
		WDMError("initgroups for \"%s\" failed, errno=%d\n", name, errno);
		return (0);
	}
#ifdef USE_PAM
	if (pamh) {
		if (pam_setcred(pamh, PAM_ESTABLISH_CRED) != PAM_SUCCESS) {
			WDMError("pam_setcred failed, errno=%d\n", errno);
			log_to_audit_system(0);
			pam_end(pamh, PAM_SUCCESS);
			pamh = NULL;
			return 0;
		}

		pam_open_session(pamh, 0);
		log_to_audit_system(1);

		/* pass in environment variables set by libpam and modules it called */
		{
			long i;
			char **pam_env = pam_getenvlist(pamh);
			for (i = 0; pam_env && pam_env[i]; i++) {
				verify->userEnviron = WDMPutEnv(verify->userEnviron, pam_env[i]);
			}
		}
	}
#endif
	switch (pid = fork()) {
	case 0:
		CleanUpChild();
#ifdef XDMCP
		/* The chooser socket is not closed by CleanUpChild() */
		DestroyWellKnownSockets();
#endif

		if (setuid(verify->uid) < 0) {
			WDMError("setuid %d (user \"%s\") failed, errno=%d\n", verify->uid, name, errno);
			return (0);
		}

		/*
		 * for Security Enhanced Linux,
		 * set the default security context for this user.
		 */
#ifdef WITH_SELINUX
		if (is_selinux_enabled()) {
			security_context_t scontext;
			if (get_default_context(name, NULL, &scontext))
				WDMError("Failed to get default security context" " for %s.", name);
			WDMDebug("setting security context to %s", scontext);
			if (setexeccon(scontext)) {
				freecon(scontext);
				WDMError("Failed to set exec security context %s " "for %s.", scontext, name);
			}
			freecon(scontext);
		}
#endif
		/*
		 * for user-based authorization schemes,
		 * use the password to get the user's credentials.
		 */
		bzero(passwd, strlen(passwd));
#ifdef WITH_CONSOLE_KIT
		if (ck_session_cookie != NULL) {
			verify->userEnviron = WDMSetEnv(verify->userEnviron, "XDG_SESSION_COOKIE", ck_session_cookie);
		}
#endif
		SetUserAuthorization(d, verify);
		home = WDMGetEnv(verify->userEnviron, "HOME");
		if (home)
			if (chdir(home) == -1) {
				WDMError("user \"%s\": cannot chdir to home \"%s\" (err %d), using \"/\"\n",
						 WDMGetEnv(verify->userEnviron, "USER"), home, errno);
				chdir("/");
				verify->userEnviron = WDMSetEnv(verify->userEnviron, "HOME", "/");
			}
		if (verify->argv) {
			WDMDebug("executing session %s\n", verify->argv[0]);
			execute(verify->argv, verify->userEnviron);
			WDMError("Session \"%s\" execution failed (err %d)\n", verify->argv[0], errno);
		} else {
			WDMError("Session has no command/arguments\n");
		}
		failsafeArgv[0] = d->failsafeClient;
		failsafeArgv[1] = 0;
		execute(failsafeArgv, verify->userEnviron);
		exit(1);
	case -1:
		bzero(passwd, strlen(passwd));
		WDMDebug("StartSession, fork failed\n");
		WDMError("can't start session on \"%s\", fork failed, errno=%d\n", d->name, errno);
		return 0;
	default:
		bzero(passwd, strlen(passwd));
		WDMDebug("StartSession, fork succeeded %d\n", pid);
		*pidp = pid;
		return 1;
	}
}
Ejemplo n.º 5
0
int login_main(int argc, char **argv)
{
	char tty[BUFSIZ];
	char full_tty[200];
	char fromhost[512];
	char username[USERNAME_SIZE];
	const char *tmp;
	int amroot;
	int flag;
	int failed;
	int count=0;
	struct passwd *pw, pw_copy;
#ifdef CONFIG_WHEEL_GROUP
	struct group *grp;
#endif
	int opt_preserve = 0;
	int opt_fflag = 0;
	char *opt_host = 0;
	int alarmstarted = 0;
#ifdef CONFIG_SELINUX
	security_context_t stat_sid = NULL, sid = NULL, old_tty_sid=NULL, new_tty_sid=NULL;
#endif

	username[0]=0;
	amroot = ( getuid ( ) == 0 );
	signal ( SIGALRM, alarm_handler );
	alarm ( TIMEOUT );
	alarmstarted = 1;

	while (( flag = getopt(argc, argv, "f:h:p")) != EOF ) {
		switch ( flag ) {
		case 'p':
			opt_preserve = 1;
			break;
		case 'f':
			/*
			 * username must be a separate token
			 * (-f root, *NOT* -froot). --marekm
			 */
			if ( optarg != argv[optind-1] )
				bb_show_usage( );

			if ( !amroot )		/* Auth bypass only if real UID is zero */
				bb_error_msg_and_die ( "-f permission denied" );

			safe_strncpy(username, optarg, USERNAME_SIZE);
			opt_fflag = 1;
			break;
		case 'h':
			opt_host = optarg;
			break;
		default:
			bb_show_usage( );
		}
	}

	if (optind < argc)             // user from command line (getty)
		safe_strncpy(username, argv[optind], USERNAME_SIZE);

	if ( !isatty ( 0 ) || !isatty ( 1 ) || !isatty ( 2 ))
		return EXIT_FAILURE;		/* Must be a terminal */

#ifdef CONFIG_FEATURE_UTMP
	checkutmp ( !amroot );
#endif

	tmp = ttyname ( 0 );
	if ( tmp && ( strncmp ( tmp, "/dev/", 5 ) == 0 ))
		safe_strncpy ( tty, tmp + 5, sizeof( tty ));
	else if ( tmp && *tmp == '/' )
		safe_strncpy ( tty, tmp, sizeof( tty ));
	else
		safe_strncpy ( tty, "UNKNOWN", sizeof( tty ));

#ifdef CONFIG_FEATURE_UTMP
	if ( amroot )
		memset ( utent.ut_host, 0, sizeof utent.ut_host );
#endif

	if ( opt_host ) {
#ifdef CONFIG_FEATURE_UTMP
		safe_strncpy ( utent.ut_host, opt_host, sizeof( utent. ut_host ));
#endif
		snprintf ( fromhost, sizeof( fromhost ) - 1, " on `%.100s' from `%.200s'", tty, opt_host );
	}
	else
		snprintf ( fromhost, sizeof( fromhost ) - 1, " on `%.100s'", tty );

	setpgrp();

	openlog ( "login", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH );

	while ( 1 ) {
		failed = 0;

		if ( !username[0] )
			if(!login_prompt ( username ))
				return EXIT_FAILURE;

		if ( !alarmstarted && ( TIMEOUT > 0 )) {
			alarm ( TIMEOUT );
			alarmstarted = 1;
		}

		if (!( pw = getpwnam ( username ))) {
			pw_copy.pw_name   = "UNKNOWN";
			pw_copy.pw_passwd = "!";
			opt_fflag = 0;
			failed = 1;
		} else
			pw_copy = *pw;

		pw = &pw_copy;

		if (( pw-> pw_passwd [0] == '!' ) || ( pw-> pw_passwd[0] == '*' ))
			failed = 1;

		if ( opt_fflag ) {
			opt_fflag = 0;
			goto auth_ok;
		}

		if (!failed && ( pw-> pw_uid == 0 ) && ( !check_tty ( tty )))
			failed = 1;

		/* Don't check the password if password entry is empty (!) */
		if ( !pw-> pw_passwd[0] )
			goto auth_ok;

		/* authorization takes place here */
		if ( correct_password ( pw ))
			goto auth_ok;

		failed = 1;

auth_ok:
		if ( !failed)
			break;

		bb_do_delay(FAIL_DELAY);
		puts("Login incorrect");
		username[0] = 0;
		if ( ++count == 3 ) {
			syslog ( LOG_WARNING, "invalid password for `%s'%s\n", pw->pw_name, fromhost);
			return EXIT_FAILURE;
	}
	}

	alarm ( 0 );
	if ( check_nologin ( pw-> pw_uid == 0 ))
		return EXIT_FAILURE;

#ifdef CONFIG_FEATURE_UTMP
	setutmp ( username, tty );
#endif

	if ( *tty != '/' )
		snprintf ( full_tty, sizeof( full_tty ) - 1, "/dev/%s", tty);
	else
		safe_strncpy ( full_tty, tty, sizeof( full_tty ) - 1 );

#ifdef CONFIG_SELINUX
	if (is_selinux_enabled())
	{
		struct stat st;
		int rc;

		if (get_default_context(username, NULL, &sid))
		{
			fprintf(stderr, "Unable to get SID for %s\n", username);
			exit(1);
		}
		rc = getfilecon(full_tty,&stat_sid);
		freecon(stat_sid);
		if ((rc<0) || (stat(full_tty, &st)<0))
		{
			fprintf(stderr, "stat_secure(%.100s) failed: %.100s\n", full_tty, strerror(errno));
			return EXIT_FAILURE;
		}
		if (security_compute_relabel (sid, old_tty_sid, SECCLASS_CHR_FILE, &new_tty_sid) != 0)
		{
			fprintf(stderr, "security_change_sid(%.100s) failed: %.100s\n", full_tty, strerror(errno));
			return EXIT_FAILURE;
		}
		if(setfilecon(full_tty, new_tty_sid) != 0)
		{
			fprintf(stderr, "chsid(%.100s, %s) failed: %.100s\n", full_tty, new_tty_sid, strerror(errno));
			return EXIT_FAILURE;
		}
		freecon(sid);
		freecon(old_tty_sid);
		freecon(new_tty_sid);
	}
#endif
	if ( !is_my_tty ( full_tty ))
		syslog ( LOG_ERR, "unable to determine TTY name, got %s\n", full_tty );

	/* Try these, but don't complain if they fail
	 * (for example when the root fs is read only) */
	chown ( full_tty, pw-> pw_uid, pw-> pw_gid );
	chmod ( full_tty, 0600 );

	change_identity ( pw );
	tmp = pw-> pw_shell;
	if(!tmp || !*tmp)
		tmp = DEFAULT_SHELL;
	setup_environment ( tmp, 1, !opt_preserve, pw );

	motd ( );
	signal ( SIGALRM, SIG_DFL );	/* default alarm signal */

	if ( pw-> pw_uid == 0 )
		syslog ( LOG_INFO, "root login %s\n", fromhost );
#ifdef CONFIG_SELINUX
	set_current_security_context(sid);
#endif
	run_shell ( tmp, 1, 0, 0);	/* exec the shell finally. */

	return EXIT_FAILURE;
}