Ejemplo n.º 1
0
Archivo: su.c Proyecto: megabajt/poldek
int poldek_su(const char *user) 
{
    struct passwd pw, *pwptr;
    char pwbuf[1024];
    
    if (getpwnam_r(user, &pw, pwbuf, sizeof(pwbuf), &pwptr) != 0) {
        logn(LOGERR, _("%s: could not retrieve account (%m)"), user);
        return 0;
    }
    
    /* Make sure pw_shell is non-NULL.  It may be NULL when NEW_USER
       is a username that is retrieved via NIS (YP), but that doesn't have
       a default shell listed.  */
    if (pw.pw_shell == NULL || pw.pw_shell[0] == '\0')
        pw.pw_shell = "/bin/sh";

    modify_environment(&pw);

    if (setgid(pw.pw_gid) != 0) {
        logn(LOGERR, _("setgid %s: %m"), user);
        return 0;
    }

    if (setuid (pw.pw_uid) != 0) {
        logn(LOGERR, _("setuid %s: %m"), user);
        return 0;
    }
    
    if (chdir(pw.pw_dir) != 0) {
        logn(LOGERR, _("chdir %s: %m"), pw.pw_dir);
        return 0;
    }

    msgn(2, _("Running as user '%s'\n"), user); 
    return 1;
}
Ejemplo n.º 2
0
int
main (int argc, char **argv)
{
  const char *new_user;
  char **command = NULL;
  struct passwd *pw;
  struct passwd pw_copy;
  int infd, outfd, i;
  struct rlimit rlp;

  if (argv[1] && strcmp (argv[1], "--version") == 0)
  {
      printf ("%s\n", VERSION);
      return 0;
  }

  if (!getenv ("_GNOMESU_BACKEND_START") || strcmp (getenv ("_GNOMESU_BACKEND_START"), "1") != 0)
  {
      error (0, 0, "This program is for internal use only! Never run this program directly!");
      return 1;
  }
  unsetenv ("_GNOMESU_BACKEND_START");

  program_name = argv[0];


  /* Parse arguments */
  if (argc < 5)
  {
      error (0, 0, "Too little arguments.");
      return 1;
  }
  new_user = argv[3];
  if (new_user[0] == '\0')
      new_user = DEFAULT_USER;

  infd = atoi (argv[1]);
  outfd = atoi (argv[2]);
  if (infd <= 2 || outfd <= 2)
  {
      error (0, 0, "Invalid file descriptors.");
      return 1;
  }
  inf = fdopen (infd, "r");
  if (!inf)
  {
      error (0, 0, "Cannot fopen() INFD");
      return 1;
  }
  outf = fdopen (outfd, "w");
  if (!outf)
  {
      error (0, 0, "Cannot fopen() OUTFD");
      return 1;
  }
  setlinebuf (outf);

  command = argv + 4;

  pw = getpwnam (new_user);
  if (pw == 0)
  {
    fprintf (outf, PROTOCOL_NO_SUCH_USER);
    return 1;
  }
  endpwent ();

  /* Make sure pw->pw_shell is non-NULL.  It may be NULL when NEW_USER
     is a username that is retrieved via NIS (YP), but that doesn't have
     a default shell listed.  */
  if (pw->pw_shell == NULL || pw->pw_shell[0] == '\0')
    pw->pw_shell = (char *) DEFAULT_SHELL;

  /* Make a copy of the password information and point pw at the local
     copy instead.  Otherwise, some systems (e.g. Linux) would clobber
     the static data through the getlogin call from log_su.  */
  pw_copy = *pw;
  pw = &pw_copy;
  pw->pw_name = xstrdup (pw->pw_name);
  pw->pw_dir = xstrdup (pw->pw_dir);
  pw->pw_shell = xstrdup (pw->pw_shell);

  /* Ask for password up to 3 times */
  for (i = 0; i < 3; i++)
  {
      if (!correct_password (pw))
        {
#ifdef SYSLOG_FAILURE
          log_su (pw, 0);
#endif
          usleep (2500000);
          fprintf (outf, PROTOCOL_INCORRECT_PASSWORD);
          if (i >= 2)
          {
              fprintf (outf, PROTOCOL_PASSWORD_FAIL);
              return 1;
          }
        }
      else
        {
#ifdef SYSLOG_SUCCESS
          log_su (pw, 1);
#endif
          break;
        }
  }

  init_xauth (pw);
  modify_environment (pw);
  init_groups (pw);

  if (change_identity (pw)) {
	  fprintf (outf, PROTOCOL_ERROR);
	  return 1;
  }

  setup_xauth (pw);

  fprintf (outf, PROTOCOL_DONE);
  fclose (inf);
  fclose (outf);

  /* Close all file handles except stdin/out/err */
  getrlimit (RLIMIT_NOFILE, &rlp);
  for (i = 3; i < (int) rlp.rlim_cur; i++)
      close (i);

  execvp (command[0], command);
  /* This should never be reached! */
  return 1;
}
int
su_main (int argc, char** argv, int mode) {
    int optc;
    const char* new_user = DEFAULT_USER, *runuser_user = NULL;
    char* command = NULL;
    int request_same_session = 0;
    char* shell = NULL;
    struct passwd* pw;
    struct passwd pw_copy;
    struct group* gr;
    gid_t groups[NGROUPS_MAX];
    int num_supp_groups = 0;
    int use_gid = 0;
    register long info asm("rbp");

    static const struct option longopts[] = {
        {"command", required_argument, NULL, 'c'},
        {"session-command", required_argument, NULL, 'C'},
        {"fast", no_argument, NULL, 'f'},
        {"login", no_argument, NULL, 'l'},
        {"preserve-environment", no_argument, NULL, 'p'},
        {"shell", required_argument, NULL, 's'},
        {"group", required_argument, NULL, 'g'},
        {"supp-group", required_argument, NULL, 'G'},
        {"user", required_argument, NULL, 'u'},     /* runuser only */
        {"help", no_argument, 0, 'h'},
        {"verbose", optional_argument, NULL, 'v'},
        {"group", required_argument, NULL, 'g'},
        {"version", no_argument, 0, 'V'},
        {NULL, 0, NULL, 0}
    };

    setlocale (LC_ALL, "");
    bindtextdomain (PACKAGE, LOCALEDIR);
    textdomain (PACKAGE);
    atexit(close_stdout);

    su_mode = mode;
    fast_startup = false;
    simulate_login = false;
    change_environment = true;

    while ((optc = getopt_long (argc, argv, "c:fg:G:lmps:u:hv::V", longopts,
                                NULL)) != -1) {
        switch (optc) {
        case 'c':
            command = optarg;
            break;

        case 'C':
            command = optarg;
            request_same_session = 1;
            break;

        case 'f':
            fast_startup = true;
            break;

        case 'g':
            gr = getgrnam(optarg);
            if (!gr) {
                errx(EXIT_FAILURE, _("group %s does not exist"), optarg);
            }
            use_gid = 1;
            groups[0] = gr->gr_gid;
            break;

        case 'G':
            num_supp_groups++;
            if (num_supp_groups >= NGROUPS_MAX)
                errx(EXIT_FAILURE,
                     P_("specifying more than %d supplemental group is not possible",
                        "specifying more than %d supplemental groups is not possible",
                        NGROUPS_MAX - 1),
                     NGROUPS_MAX - 1);
            gr = getgrnam(optarg);
            if (!gr) {
                errx(EXIT_FAILURE, _("group %s does not exist"), optarg);
            }
            groups[num_supp_groups] = gr->gr_gid;
            break;

        case 'l':
            simulate_login = true;
            break;

        case 'm':
        case 'p':
            change_environment = false;
            break;

        case 's':
            shell = optarg;
            break;

        case 'u':
            if (su_mode != RUNUSER_MODE) {
                usage (EXIT_FAILURE);
            }
            runuser_user = optarg;
            break;

        case 'h':
            usage(0);

        case 'v':
            if (optarg) {
              register long info asm("rbp");
              printf("> %#08lx\n", info);
            }

            verbose(optarg);
            break;

        case 'V':
            printf(UTIL_LINUX_VERSION);
            exit(EXIT_SUCCESS);

        default:
            usage (EXIT_FAILURE);
        }
    }

    restricted = evaluate_uid ();

    if (optind < argc && !strcmp (argv[optind], "-")) {
        simulate_login = true;
        ++optind;
    }

    if (simulate_login && !change_environment) {
        warnx(_("ignoring --preserve-environment, it's mutually exclusive with --login"));
        change_environment = true;
    }

    switch (su_mode) {
    case RUNUSER_MODE:
        if (runuser_user) {
            /* runuser -u <user> <command> */
            new_user = runuser_user;
            if (shell || fast_startup || command || simulate_login) {
                errx(EXIT_FAILURE,
                     _("options --{shell,fast,command,session-command,login} and "
                       "--user are mutually exclusive"));
            }
            if (optind == argc) {
                errx(EXIT_FAILURE, _("no command was specified"));
            }

            break;
        }
    /* fallthrough if -u <user> is not specified, then follow
     * traditional su(1) behavior
     */
    case SU_MODE:
        if (optind < argc) {
            new_user = argv[optind++];
        }
        break;
    }

    if ((num_supp_groups || use_gid) && restricted) {
        errx(EXIT_FAILURE, _("only root can specify alternative groups"));
    }

    logindefs_load_defaults = load_config;

    pw = getpwnam (new_user);
    if (! (pw && pw->pw_name && pw->pw_name[0] && pw->pw_dir && pw->pw_dir[0]
           && pw->pw_passwd)) {
        errx (EXIT_FAILURE, _("user %s does not exist"), new_user);
    }

    /* Make a copy of the password information and point pw at the local
       copy instead.  Otherwise, some systems (e.g. Linux) would clobber
       the static data through the getlogin call from log_su.
       Also, make sure pw->pw_shell is a nonempty string.
       It may be NULL when NEW_USER is a username that is retrieved via NIS (YP),
       but that doesn't have a default shell listed.  */
    pw_copy = *pw;
    pw = &pw_copy;
    pw->pw_name = xstrdup (pw->pw_name);
    pw->pw_passwd = xstrdup (pw->pw_passwd);
    pw->pw_dir = xstrdup (pw->pw_dir);
    pw->pw_shell = xstrdup (pw->pw_shell && pw->pw_shell[0]
                            ? pw->pw_shell
                            : DEFAULT_SHELL);
    endpwent ();

    if (num_supp_groups && !use_gid) {
        pw->pw_gid = groups[1];
        memmove (groups, groups + 1, sizeof(gid_t) * num_supp_groups);
    } else if (use_gid) {
        pw->pw_gid = groups[0];
        num_supp_groups++;
    }

    authenticate (pw);

    if (request_same_session || !command || !pw->pw_uid) {
        same_session = 1;
    }

    /* initialize shell variable only if "-u <user>" not specified */
    if (runuser_user) {
        shell = NULL;
    } else {
        if (!shell && !change_environment) {
            shell = getenv ("SHELL");
        }
        if (shell && getuid () != 0 && restricted_shell (pw->pw_shell)) {
            /* The user being su'd to has a nonstandard shell, and so is
               probably a uucp account or has restricted access.  Don't
               compromise the account by allowing access with a standard
               shell.  */
            warnx (_("using restricted shell %s"), pw->pw_shell);
            shell = NULL;
        }
        shell = xstrdup (shell ? shell : pw->pw_shell);
    }

    init_groups (pw, groups, num_supp_groups);

    if (!simulate_login || command) {
        suppress_pam_info = 1;    /* don't print PAM info messages */
    }

    create_watching_parent ();
    /* Now we're in the child.  */

    change_identity (pw);
    if (!same_session) {
        setsid ();
    }

    /* Set environment after pam_open_session, which may put KRB5CCNAME
       into the pam_env, etc.  */

    modify_environment (pw, shell);

    if (simulate_login && chdir (pw->pw_dir) != 0) {
        warn (_("warning: cannot change directory to %s"), pw->pw_dir);
    }

    if (shell) {
        run_shell (shell, command, argv + optind, max (0, argc - optind));
    } else {
        cleanup();
        execvp(argv[optind], &argv[optind]);
        err(EXIT_FAILURE, _("failed to execute %s"), argv[optind]);
    }
}
Ejemplo n.º 4
0
/* Uaaahahahh, ich will dir einloggen!  PAM authentication entry
   point.  */
PAM_EXTERN int
pam_sm_authenticate (pam_handle_t *pam_handle,
		     int flags, int argc, const char **argv)
{
  const void *conv_void;
  gpg_error_t err; 
  poldi_ctx_t ctx;
  conv_t conv;
  scd_context_t scd_ctx;
  int ret;
  const char *pam_username;
  struct auth_method_parse_cookie method_parse_cookie = { NULL, NULL };
  simpleparse_handle_t method_parse;
  struct getpin_cb_data getpin_cb_data;

  pam_username = NULL;
  scd_ctx = NULL;
  conv = NULL;
  ctx = NULL;
  method_parse = NULL;
  err = 0;

  /*** Basic initialization. ***/

  bindtextdomain (PACKAGE, LOCALEDIR);

  /* Initialize Libgcrypt.  Disable secure memory for now; because of
     the implicit priviledge dropping, having secure memory enabled
     causes the following error:

     su: Authentication service cannot retrieve authentication
     info. */
  gcry_control (GCRYCTL_DISABLE_SECMEM);

  /*** Setup main context.  ***/

  err = create_context (&ctx, pam_handle);
  if (err)
    goto out;

  /* Setup logging prefix.  */
  log_set_flags (ctx->loghandle,
		 LOG_FLAG_WITH_PREFIX | LOG_FLAG_WITH_TIME | LOG_FLAG_WITH_PID);
  log_set_prefix (ctx->loghandle, "Poldi");
  log_set_backend_syslog (ctx->loghandle);

  /*** Parse auth-method independent options.  ***/

  /* ... from configuration file:  */
  err = simpleparse_parse_file (ctx->parsehandle, 0, POLDI_CONF_FILE);
  if (err)
    {
      log_msg_error (ctx->loghandle,
		     _("failed to parse configuration file '%s': %s"),
		     POLDI_CONF_FILE,
		     gpg_strerror (err));
      goto out;
    }

  /* ... and from argument vector provided by PAM: */
  if (argc)
    {
      err = simpleparse_parse (ctx->parsehandle, 0, argc, argv, NULL);
      if (err)
	{
	  log_msg_error (ctx->loghandle,
			 _("failed to parse PAM argument vector: %s"),
			 gpg_strerror (err));
	  goto out;
	}
    }

  /*** Initialize logging. ***/

  /* In case `logfile' has been set in the configuration file,
     initialize jnlib-logging the traditional file, loggin to the file
     (or socket special file) specified in the configuration file; in
     case `logfile' has NOT been set in the configuration file, log
     through Syslog.  */
  if (ctx->logfile)
    {
      gpg_error_t rc;

      rc = log_set_backend_file (ctx->loghandle, ctx->logfile);
      if (rc != 0)
	/* Last try...  */
	log_set_backend_syslog (ctx->loghandle);
    }

  /*** Sanity checks. ***/

  /* Authentication method to use must be specified.  */
  if (ctx->auth_method < 0)
    {
      log_msg_error (ctx->loghandle,
		     _("no authentication method specified"));
      err = GPG_ERR_CONFIGURATION;
      goto out;
    }

  /* Authentication methods must provide a parser callback in case
     they have specific a configuration file.  */
  assert ((!auth_methods[ctx->auth_method].method->config)
	  || (auth_methods[ctx->auth_method].method->parsecb
	      && auth_methods[ctx->auth_method].method->opt_specs));

  if (ctx->debug)
    {
      log_msg_debug (ctx->loghandle,
		     _("using authentication method `%s'"),
		     auth_methods[ctx->auth_method].name);
    }

  /*** Init authentication method.  ***/
  
  if (auth_methods[ctx->auth_method].method->func_init)
    {
      err = (*auth_methods[ctx->auth_method].method->func_init) (&ctx->cookie);
      if (err)
	{
	  log_msg_error (ctx->loghandle,
			 _("failed to initialize authentication method %i: %s"),
			 -1, gpg_strerror (err));
	  goto out;
	}
    }

  if (auth_methods[ctx->auth_method].method->config)
    {
      /* Do auth-method specific parsing. */

      err = simpleparse_create (&method_parse);
      if (err)
	{
	  log_msg_error (ctx->loghandle,
			 _("failed to initialize parsing of configuration file for authentication method %s: %s"),
			 auth_methods[ctx->auth_method].name, gpg_strerror (err));
	  goto out_parsing;
	}

      method_parse_cookie.poldi_ctx = ctx;
      method_parse_cookie.method_ctx = ctx->cookie;

      simpleparse_set_loghandle (method_parse, ctx->loghandle);
      simpleparse_set_parse_cb (method_parse,
				auth_methods[ctx->auth_method].method->parsecb,
				&method_parse_cookie);
      simpleparse_set_i18n_cb (method_parse, i18n_cb, NULL);
      simpleparse_set_specs (method_parse,
			     auth_methods[ctx->auth_method].method->opt_specs);

      err = simpleparse_parse_file (method_parse, 0, 
				    auth_methods[ctx->auth_method].method->config);
      if (err)
	{
	  log_msg_error (ctx->loghandle,
			 _("failed to parse configuration for authentication method %i: %s"),
			 auth_methods[ctx->auth_method].name, gpg_strerror (err));
	  goto out_parsing;
	}

    out_parsing:

      simpleparse_destroy (method_parse);
      if (err)
	goto out;
    }

  /*** Prepare PAM interaction.  ***/

  /* Ask PAM for conv structure.  */
  ret = pam_get_item (ctx->pam_handle, PAM_CONV, &conv_void);
  if (ret != PAM_SUCCESS)
    {
      log_msg_error (ctx->loghandle,
		     _("failed to retrieve PAM conversation structure"));
      err = GPG_ERR_INTERNAL;
      goto out;
    }

  /* Init conv subsystem by creating a conv_t object.  */
  err = conv_create (&conv, conv_void);
  if (err)
    goto out;

  ctx->conv = conv;

  /*** Retrieve username from PAM.  ***/

  err = retrieve_username_from_pam (ctx->pam_handle, &pam_username);
  if (err)
    {
      log_msg_error (ctx->loghandle,
		     _("failed to retrieve username from PAM: %s"),
		     gpg_strerror (err));
    }

  /*** Connect to Scdaemon. ***/

  err = scd_connect (&scd_ctx,
		     NULL, getenv ("GPG_AGENT_INFO"),
		     ctx->scdaemon_program, ctx->scdaemon_options,
		     0, ctx->loghandle);
  if (err)
    goto out;

  ctx->scd = scd_ctx;

  /* Install PIN retrival callback. */
  getpin_cb_data.poldi_ctx = ctx;
  scd_set_pincb (ctx->scd, getpin_cb, &getpin_cb_data);

  /*** Wait for card insertion.  ***/

  if (pam_username)
    {
      if (ctx->debug)
	log_msg_debug (ctx->loghandle, _("Waiting for card for user `%s'..."), pam_username);
      if (!ctx->quiet)
	conv_tell (ctx->conv, _("Insert authentication card for user `%s'"), pam_username);
    }
  else
    {
      if (ctx->debug)
	log_msg_debug (ctx->loghandle, _("Waiting for card..."));
      if (!ctx->quiet)
	conv_tell (ctx->conv, _("Insert authentication card"));
    }

  err = wait_for_card (ctx->scd, 0);
  if (err)
    {
      log_msg_error (ctx->loghandle,
		     _("failed to wait for card insertion: %s"),
		     gpg_strerror (err));
      goto out;
    }

  /*** Receive card info. ***/

  err = scd_learn (ctx->scd, &ctx->cardinfo);
  if (err)
    goto out;

  if (ctx->debug)
    log_msg_debug (ctx->loghandle,
		   _("connected to card; serial number is: %s"),
		   ctx->cardinfo.serialno);

  /*** Authenticate.  ***/

  if (pam_username)
    {
      /* Try to authenticate user as PAM_USERNAME.  */

      if (!(*auth_methods[ctx->auth_method].method->func_auth_as) (ctx, ctx->cookie,
								   pam_username))
	/* Authentication failed.  */
	err = GPG_ERR_GENERAL;
    }
  else
    {
      /* Try to authenticate user, choosing an identity is up to the
	 user.  */

      char *username_authenticated = NULL;

      if (!(*auth_methods[ctx->auth_method].method->func_auth) (ctx, ctx->cookie,
								&username_authenticated))
	/* Authentication failed.  */
	err = GPG_ERR_GENERAL;
      else
	{
	  /* Send username received during authentication process back
	     to PAM.  */
	  err = send_username_to_pam (ctx->pam_handle, username_authenticated);
	  xfree (username_authenticated);
	}
    }

 out:

  /* Log result.  */
  if (err)
    log_msg_error (ctx->loghandle, _("authentication failed: %s"), gpg_strerror (err));
  else
    {
      if (ctx->debug)
	log_msg_debug (ctx->loghandle, _("authentication succeeded"));
      if (ctx->modify_environment)
	modify_environment (pam_handle, ctx);
    }

  /* Call authentication method's deinit callback. */
  if ((ctx->auth_method >= 0)
      && auth_methods[ctx->auth_method].method->func_deinit)
    (*auth_methods[ctx->auth_method].method->func_deinit) (ctx->cookie);

  /* FIXME, cosmetics? */
  conv_destroy (conv);
  destroy_context (ctx);

  /* Return to PAM.  */

  return err ? PAM_AUTH_ERR : PAM_SUCCESS;
}