⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pwck.c

📁 pwdutils是一套密码管理工具
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Copyright (C) 2004, 2005 Thorsten Kukuk   Author: Thorsten Kukuk <kukuk@suse.de>   This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License version 2 as   published by the Free Software Foundation.   This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.   You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software Foundation,   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */#ifdef HAVE_CONFIG_H#include <config.h>#endif#define _GNU_SOURCE#include <time.h>#include <errno.h>#include <stdio.h>#include <string.h>#include <unistd.h>#include <getopt.h>#include <sys/types.h>#include <sys/stat.h>#include "i18n.h"#include "yesno.h"#include "public.h"#include "read-files.h"#define E_SUCCESS 0#define E_USAGE 1#define E_BAD_ENTRY 2#define E_NO_FILE 3#define E_PWDBUSY 4#define E_FAILURE 5#define SCALE DAYchar *files_etc_dir = "/etc";int readonly = 0;static voidprint_usage (FILE *stream, const char *program){  fprintf (stream, _("Usage: %s [-P path] [-q|-r|-s]\n"),           program);}static voidprint_help (const char *program){  print_usage (stdout, program);  fprintf (stdout, _("%s - check integrity of password files\n\n"), program);  fputs (_("  -P path        Search passwd, shadow and group file in \"path\"\n"),         stdout);  fputs (_("  -q, --quiet    Don't print warnings, only errors\n"), stdout);  fputs (_("  -r, --read-only Run in read-only mode, don't make changes\n"),	 stdout);  fputs (_("  -s, --sort     Sort the password file, no checks are done\n"),	 stdout);  fputs (_("      --help     Give this help list\n"), stdout);  fputs (_("  -u, --usage    Give a short usage message\n"), stdout);  fputs (_("  -v, --version  Print program version\n"), stdout);}static intanswer_yes (void){  if (readonly)    {      printf (_("No\n"));      return 0;    }  else    return yesno ();}#define BLACKLIST_INITIAL_SIZE 512#define BLACKLIST_INCREMENT 256struct blacklist_t{  char *data;  int current;  int size;};/* returns TRUE if ent->blacklist contains name, else FALSE */static bool_tin_blacklist (const char *name, int namelen, struct blacklist_t *ent){  char buf[namelen + 3];  char *cp;  if (ent->data == NULL)    return FALSE;  buf[0] = '|';  cp = stpcpy (&buf[1], name);  *cp++ = '|';  *cp = '\0';  return strstr (ent->data, buf) != NULL;}/* Support routines for remembering login names. The names are stored   in a single string with `|' as separator. */static voidblacklist_store_name (const char *name, struct blacklist_t *ent){  int namelen = strlen (name);  char *tmp;  /* first call, setup cache */  if (ent->size == 0)    {      ent->size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen);      ent->data = malloc (ent->size);      if (ent->data == NULL)        return;      ent->data[0] = '|';      ent->data[1] = '\0';      ent->current = 1;    }  else    {      if (in_blacklist (name, namelen, ent))        return;                 /* no duplicates */      if (ent->current + namelen + 1 >= ent->size)        {          ent->size += MAX (BLACKLIST_INCREMENT, 2 * namelen);          tmp = realloc (ent->data, ent->size);          if (tmp == NULL)            {              free (ent->data);              ent->size = 0;              return;            }          ent->data = tmp;        }    }  tmp = stpcpy (ent->data + ent->current, name);  *tmp++ = '|';  *tmp = '\0';  ent->current += namelen + 1;  return;}/* XXX move into the library.  */static struct group *files_getgrgid (gid_t gid){  enum nss_status status;  static int buflen = 256;  static char *buffer = NULL;  static struct group resultbuf;  if (buffer == NULL)    buffer = malloc (buflen);  while ((status = files_getgrgid_r (gid, &resultbuf, buffer, buflen, &errno))         == NSS_STATUS_TRYAGAIN && errno == ERANGE)    {      errno = 0;      buflen += 256;      buffer = realloc (buffer, buflen);    }  if (status == NSS_STATUS_SUCCESS)    return &resultbuf;  else    return NULL;}static struct passwd *files_getpwnam (const char *name){  enum nss_status status;  static int buflen = 256;  static char *buffer = NULL;  static struct passwd resultbuf;  if (buffer == NULL)    buffer = malloc (buflen);  while ((status =          files_getpwnam_r (name, &resultbuf, buffer, buflen,                            &errno)) == NSS_STATUS_TRYAGAIN         && errno == ERANGE)    {      errno = 0;      buflen += 256;      buffer = realloc (buffer, buflen);    }  if (status == NSS_STATUS_SUCCESS)    return &resultbuf;  else    return NULL;}static intloop_over_passwd_file (int quiet){  struct stat passwd_stat;  FILE *input, *output;  int output_fd;  char *buf = NULL;  size_t buflen = 0;  struct passwd res;  int result = 0;  struct blacklist_t blacklist = {NULL, 0, 0};  int modified = 0;  char *inputname = alloca (strlen (files_etc_dir) + 8);  char *outputname = alloca (strlen (files_etc_dir) + 20);  strcpy (inputname, files_etc_dir);  strcat (inputname, "/passwd");  strcpy (outputname, files_etc_dir);  strcat (outputname, "/passwd.tmpXXXXXX");  if (!quiet)    printf (_("Checking `%s'\n"), inputname);  input = fopen (inputname, "r");  if (input == NULL)    {      fprintf (stderr, _("Can't open `%s': %m\n"), inputname);      return E_NO_FILE;    }  if (fstat (fileno (input), &passwd_stat) < 0)    {      fprintf (stderr, _("Can't stat `%s': %m\n"), inputname);      fclose (input);      return E_NO_FILE;    }#ifdef WITH_SELINUX  security_context_t prev_context;  if (set_default_context (inputname, &prev_context) < 0)    {      fclose (input);      return E_NO_FILE;    }#endif  /* Open a temp passwd file */  output_fd = mkstemp (outputname);#ifdef WITH_SELINUX  if (restore_default_context (prev_context) < 0)    {      if (output_fd >= 0)	close (output_fd);      fclose (input);      return E_FAILURE;    }#endif  if (output_fd == -1)    {      fprintf (stderr, _("Can't create `%s': %m\n"),	       inputname);      fclose (input);      return E_NO_FILE;    }  if (fchmod (output_fd, passwd_stat.st_mode) < 0)    {      fprintf (stderr,	       _("Cannot change permissions for `%s': %s\n"),	       outputname, strerror (errno));      fclose (input);      close (output_fd);      unlink (outputname);      return E_NO_FILE;    }  if (fchown (output_fd, passwd_stat.st_uid, passwd_stat.st_gid) < 0)    {      fprintf (stderr,	       _("Cannot change owner/group for `%s': %s\n"),	       outputname, strerror (errno));      fclose (input);      close (output_fd);      unlink (outputname);      return E_NO_FILE;    }  if (copy_xattr (inputname, outputname) != 0)    {      fclose (input);      close (output_fd);      unlink (outputname);      return E_NO_FILE;    }  output = fdopen (output_fd, "w+");  if (output == NULL)    {      fprintf (stderr, _("Can't open `%s': %m\n"), outputname);      fclose (input);      close (output_fd);      unlink (outputname);      return E_NO_FILE;    }  while (!feof (input))    {      char *cp;#if defined(HAVE_GETLINE)      ssize_t n = getline (&buf, &buflen, input);#elif defined (HAVE_GETDELIM)      ssize_t n = getdelim (&buf, &buflen, '\n', input);#else      ssize_t n;      if (buf == NULL)        {          buflen = 8096;          buf = malloc (buflen);        }      buf[0] = '\0';      fgets (buf, buflen - 1, input);      if (buf != NULL)        n = strlen (buf);      else        n = 0;#endif /* HAVE_GETLINE / HAVE_GETDELIM */      if (buf)	cp = strdup (buf);      else	cp = strdup ("");      if (n < 1)	{	  if (feof (input))	    continue;	  result = E_BAD_ENTRY;	  printf (_("Invalid password entry.\n"));	  printf (_("Delete empty line? "));	  if (answer_yes ())	    {	      free (cp);	      modified = 1;	      continue;	    }	  else	    goto write_pw;	}      /* Remove trailing '\n'.  */      if (cp[strlen (cp) - 1] == '\n')	cp[strlen (cp) - 1] = '\0';      if (*cp == '+' || *cp == '-')	goto write_pw;      /* Comments are not allowed in /etc/passwd.  */      if (strchr (cp, '#') != NULL)	{	  result = E_BAD_ENTRY;	  printf (_("Invalid password entry with comment.\n"));	  printf (_("Delete line `%s'? "), cp);	  if (answer_yes ())	    {	      modified = 1;	      free (cp);	      continue;	    }	  else	    goto write_pw;	}      /* Parse string in strict mode and report error.  */      if (parse_pwent (buf, &res, 1) != 1)	{	  result = E_BAD_ENTRY;	  printf (_("Invalid password entry.\n"));	  printf (_("Delete line `%s'? "), cp);	  if (answer_yes ())	    {	      modified = 1;	      free (cp);	      continue;	    }	  else	    goto write_pw;	}      /* Check for invalid characters in username.  */      if (check_name (res.pw_name) < 0)	{	  result = E_BAD_ENTRY;	  printf (_("Invalid account name `%s'.\n"), res.pw_name);	  printf (_("Delete line `%s'? "), cp);	  if (answer_yes ())	    {	      modified = 1;	      free (cp);	      continue;	    }	  else	    goto write_pw;	}      /* Check, if we saw this user name already.  */      if (in_blacklist (res.pw_name, strlen (res.pw_name), &blacklist))	{	  result = E_BAD_ENTRY;	  printf (_("Duplicate password entry\n"));	  printf (_("Delete line `%s'? "), cp);	  if (answer_yes ())	    {	      modified = 1;	      free (cp);	      continue;	    }	  else	    goto write_pw;	}      /* Mark the username as seen, but after checking for duplicate!  */      blacklist_store_name (res.pw_name, &blacklist);      /* Check, if primary group exists.  */      if (!quiet && getgrgid (res.pw_gid) == NULL &&	  files_getgrgid (res.pw_gid) == NULL)	{	  result = E_BAD_ENTRY;	  printf (_("User `%s': unknown group `%u'\n"),		  res.pw_name, res.pw_gid);	}      /* Check, if the home directory exists.  */      if (!quiet && access (res.pw_dir, F_OK))	{	  result = E_BAD_ENTRY;	  printf (_("User `%s': directory `%s' does not exist.\n"),		  res.pw_name, res.pw_dir);	}      /* Check, if shell is executable.  */      if (!quiet && res.pw_shell[0]	  && access (res.pw_shell, X_OK))	{	  result = E_BAD_ENTRY;	  printf (_("User `%s': shell `%s' is not executeable.\n"),		  res.pw_name, res.pw_shell);	}    write_pw:      fprintf (output, "%s\n", cp);      free (cp);    }  fclose (input);  fclose (output);  if (modified)    {      char *oldname = alloca (strlen (files_etc_dir) + 20);      strcpy (oldname, files_etc_dir);      strcat (oldname, "/passwd.old");      unlink (oldname);      if (link (inputname, oldname) < 0)	fprintf (stderr,		 _("Warning: cannot create backup file `%s': %m\n"),                 oldname);      rename (outputname, inputname);    }  else    unlink (outputname);  return result;}static intloop_over_shadow_file (int quiet){  struct stat shadow_stat;  FILE *input, *output;  int output_fd;  char *buf = NULL;  size_t buflen = 0;  struct spwd res;  int result = 0;  struct blacklist_t blacklist = {NULL, 0, 0};  int modified = 0;  char *inputname = alloca (strlen (files_etc_dir) + 8);  char *outputname = alloca (strlen (files_etc_dir) + 20);  strcpy (inputname, files_etc_dir);  strcat (inputname, "/shadow");  strcpy (outputname, files_etc_dir);  strcat (outputname, "/shadow.tmpXXXXXX");  input = fopen (inputname, "r");  if (input == NULL)    {      /* fprintf (stderr, _("Can't open `%s': %m\n"), inputname); */      return E_NO_FILE;    }  if (!quiet)    printf (_("Checking `%s'.\n"), inputname);  if (fstat (fileno (input), &shadow_stat) < 0)    {      fprintf (stderr, _("Can't stat `%s': %m\n"), inputname);      fclose (input);      return E_NO_FILE;    }#ifdef WITH_SELINUX  security_context_t prev_context;  if (set_default_context (inputname, &prev_context) < 0)    {      fclose (input);      return E_NO_FILE;    }#endif  /* Open a temp shadow file */  output_fd = mkstemp (outputname);#ifdef WITH_SELINUX  if (restore_default_context (prev_context) < 0)    {      if (output_fd >= 0)	close (output_fd);      fclose (input);      return E_FAILURE;    }#endif  if (output_fd == -1)    {      fprintf (stderr, _("Can't create `%s': %m\n"),	       inputname);      fclose (input);      return E_NO_FILE;    }  if (fchmod (output_fd, shadow_stat.st_mode) < 0)    {      fprintf (stderr,	       _("Cannot change permissions for `%s': %s\n"),	       outputname, strerror (errno));      fclose (input);      close (output_fd);      unlink (outputname);      return E_NO_FILE;    }  if (fchown (output_fd, shadow_stat.st_uid, shadow_stat.st_gid) < 0)    {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -