Blame login/programs/pt_chown.c

Packit Service 82fcde
/* pt_chmod - helper program for `grantpt'.
Packit Service 82fcde
   Copyright (C) 1998-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
   Contributed by C. Scott Ananian <cananian@alumni.princeton.edu>, 1998.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <argp.h>
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <error.h>
Packit Service 82fcde
#include <grp.h>
Packit Service 82fcde
#include <libintl.h>
Packit Service 82fcde
#include <locale.h>
Packit Service 82fcde
#include <signal.h>
Packit Service 82fcde
#include <stdio.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include <sys/stat.h>
Packit Service 82fcde
#include <unistd.h>
Packit Service 82fcde
#ifdef HAVE_LIBCAP
Packit Service 82fcde
# include <sys/capability.h>
Packit Service 82fcde
# include <sys/prctl.h>
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#include "pty-private.h"
Packit Service 82fcde
Packit Service 82fcde
/* Get libc version number.  */
Packit Service 82fcde
#include "../version.h"
Packit Service 82fcde
Packit Service 82fcde
#define PACKAGE _libc_intl_domainname
Packit Service 82fcde
Packit Service 82fcde
/* Name and version of program.  */
Packit Service 82fcde
static void print_version (FILE *stream, struct argp_state *state);
Packit Service 82fcde
void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
Packit Service 82fcde
Packit Service 82fcde
/* Function to print some extra text in the help message.  */
Packit Service 82fcde
static char *more_help (int key, const char *text, void *input);
Packit Service 82fcde
Packit Service 82fcde
/* Data structure to communicate with argp functions.  */
Packit Service 82fcde
static struct argp argp =
Packit Service 82fcde
{
Packit Service 82fcde
  NULL, NULL, NULL, NULL, NULL, more_help
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Print the version information.  */
Packit Service 82fcde
static void
Packit Service 82fcde
print_version (FILE *stream, struct argp_state *state)
Packit Service 82fcde
{
Packit Service 82fcde
  fprintf (stream, "pt_chown %s%s\n", PKGVERSION, VERSION);
Packit Service 82fcde
  fprintf (stream, gettext ("\
Packit Service 82fcde
Copyright (C) %s Free Software Foundation, Inc.\n\
Packit Service 82fcde
This is free software; see the source for copying conditions.  There is NO\n\
Packit Service 82fcde
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
Packit Service 82fcde
"), "2018");
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static char *
Packit Service 82fcde
more_help (int key, const char *text, void *input)
Packit Service 82fcde
{
Packit Service 82fcde
  char *cp;
Packit Service 82fcde
  char *tp;
Packit Service 82fcde
Packit Service 82fcde
  switch (key)
Packit Service 82fcde
    {
Packit Service 82fcde
    case ARGP_KEY_HELP_PRE_DOC:
Packit Service 82fcde
      asprintf (&cp, gettext ("\
Packit Service 82fcde
Set the owner, group and access permission of the slave pseudo\
Packit Service 82fcde
 terminal corresponding to the master pseudo terminal passed on\
Packit Service 82fcde
 file descriptor `%d'.  This is the helper program for the\
Packit Service 82fcde
 `grantpt' function.  It is not intended to be run directly from\
Packit Service 82fcde
 the command line.\n"),
Packit Service 82fcde
		PTY_FILENO);
Packit Service 82fcde
      return cp;
Packit Service 82fcde
    case ARGP_KEY_HELP_EXTRA:
Packit Service 82fcde
      /* We print some extra information.  */
Packit Service 82fcde
      if (asprintf (&tp, gettext ("\
Packit Service 82fcde
For bug reporting instructions, please see:\n\
Packit Service 82fcde
%s.\n"), REPORT_BUGS_TO) < 0)
Packit Service 82fcde
	return NULL;
Packit Service 82fcde
      if (asprintf (&cp, gettext ("\
Packit Service 82fcde
The owner is set to the current user, the group is set to `%s',\
Packit Service 82fcde
 and the access permission is set to `%o'.\n\n\
Packit Service 82fcde
%s"),
Packit Service 82fcde
		    TTY_GROUP, S_IRUSR|S_IWUSR|S_IWGRP, tp) < 0)
Packit Service 82fcde
	{
Packit Service 82fcde
	  free (tp);
Packit Service 82fcde
	  return NULL;
Packit Service 82fcde
	}
Packit Service 82fcde
      return cp;
Packit Service 82fcde
    default:
Packit Service 82fcde
      break;
Packit Service 82fcde
    }
Packit Service 82fcde
  return (char *) text;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
do_pt_chown (void)
Packit Service 82fcde
{
Packit Service 82fcde
  char *pty;
Packit Service 82fcde
  struct stat64 st;
Packit Service 82fcde
  struct group *p;
Packit Service 82fcde
  gid_t gid;
Packit Service 82fcde
Packit Service 82fcde
  /* Check that PTY_FILENO is a valid master pseudo terminal.  */
Packit Service 82fcde
  pty = ptsname (PTY_FILENO);
Packit Service 82fcde
  if (pty == NULL)
Packit Service 82fcde
    return errno == EBADF ? FAIL_EBADF : FAIL_EINVAL;
Packit Service 82fcde
Packit Service 82fcde
  /* Check that the returned slave pseudo terminal is a
Packit Service 82fcde
     character device.  */
Packit Service 82fcde
  if (stat64 (pty, &st) < 0 || !S_ISCHR (st.st_mode))
Packit Service 82fcde
    return FAIL_EINVAL;
Packit Service 82fcde
Packit Service 82fcde
  /* Get the group ID of the special `tty' group.  */
Packit Service 82fcde
  p = getgrnam (TTY_GROUP);
Packit Service 82fcde
  gid = p ? p->gr_gid : getgid ();
Packit Service 82fcde
Packit Service 82fcde
  /* Set the owner to the real user ID, and the group to that special
Packit Service 82fcde
     group ID.  */
Packit Service 82fcde
  if (chown (pty, getuid (), gid) < 0)
Packit Service 82fcde
    return FAIL_EACCES;
Packit Service 82fcde
Packit Service 82fcde
  /* Set the permission mode to readable and writable by the owner,
Packit Service 82fcde
     and writable by the group.  */
Packit Service 82fcde
  if ((st.st_mode & ACCESSPERMS) != (S_IRUSR|S_IWUSR|S_IWGRP)
Packit Service 82fcde
      && chmod (pty, S_IRUSR|S_IWUSR|S_IWGRP) < 0)
Packit Service 82fcde
    return FAIL_EACCES;
Packit Service 82fcde
Packit Service 82fcde
  return 0;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
main (int argc, char *argv[])
Packit Service 82fcde
{
Packit Service 82fcde
  uid_t euid = geteuid ();
Packit Service 82fcde
  uid_t uid = getuid ();
Packit Service 82fcde
  int remaining;
Packit Service 82fcde
  sigset_t signalset;
Packit Service 82fcde
Packit Service 82fcde
  /* Clear any signal mask from the parent process.  */
Packit Service 82fcde
  sigemptyset (&signalset);
Packit Service 82fcde
  sigprocmask (SIG_SETMASK, &signalset, NULL);
Packit Service 82fcde
Packit Service 82fcde
  if (argc == 1 && euid == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
#ifdef HAVE_LIBCAP
Packit Service 82fcde
  /* Drop privileges.  */
Packit Service 82fcde
      if (uid != euid)
Packit Service 82fcde
	{
Packit Service 82fcde
	  static const cap_value_t cap_list[] =
Packit Service 82fcde
	    { CAP_CHOWN, CAP_FOWNER	};
Packit Service 82fcde
# define ncap_list (sizeof (cap_list) / sizeof (cap_list[0]))
Packit Service 82fcde
	  cap_t caps = cap_init ();
Packit Service 82fcde
	  if (caps == NULL)
Packit Service 82fcde
	    return FAIL_ENOMEM;
Packit Service 82fcde
Packit Service 82fcde
	  /* There is no reason why these should not work.  */
Packit Service 82fcde
	  cap_set_flag (caps, CAP_PERMITTED, ncap_list, cap_list, CAP_SET);
Packit Service 82fcde
	  cap_set_flag (caps, CAP_EFFECTIVE, ncap_list, cap_list, CAP_SET);
Packit Service 82fcde
Packit Service 82fcde
	  int res = cap_set_proc (caps);
Packit Service 82fcde
Packit Service 82fcde
	  cap_free (caps);
Packit Service 82fcde
Packit Service 82fcde
	  if (__glibc_unlikely (res != 0))
Packit Service 82fcde
	    return FAIL_EXEC;
Packit Service 82fcde
	}
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
      /* Normal invocation of this program is with no arguments and
Packit Service 82fcde
	 with privileges.  */
Packit Service 82fcde
      return do_pt_chown ();
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* We aren't going to be using privileges, so drop them right now. */
Packit Service 82fcde
  setuid (uid);
Packit Service 82fcde
Packit Service 82fcde
  /* Set locale via LC_ALL.  */
Packit Service 82fcde
  setlocale (LC_ALL, "");
Packit Service 82fcde
Packit Service 82fcde
  /* Set the text message domain.  */
Packit Service 82fcde
  textdomain (PACKAGE);
Packit Service 82fcde
Packit Service 82fcde
  /* parse and process arguments.  */
Packit Service 82fcde
  argp_parse (&argp, argc, argv, 0, &remaining, NULL);
Packit Service 82fcde
Packit Service 82fcde
  if (remaining < argc)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* We should not be called with any non-option parameters.  */
Packit Service 82fcde
      error (0, 0, gettext ("too many arguments"));
Packit Service 82fcde
      argp_help (&argp, stdout, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR,
Packit Service 82fcde
		 program_invocation_short_name);
Packit Service 82fcde
      return EXIT_FAILURE;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Check if we are properly installed.  */
Packit Service 82fcde
  if (euid != 0)
Packit Service 82fcde
    error (FAIL_EXEC, 0, gettext ("needs to be installed setuid `root'"));
Packit Service 82fcde
Packit Service 82fcde
  return EXIT_SUCCESS;
Packit Service 82fcde
}