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

📄 groupadd.c

📁 pwdutils是一套密码管理工具
💻 C
字号:
/* Copyright (C) 2003, 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 <utmp.h>#include <fcntl.h>#include <paths.h>#include <ctype.h>#include <errno.h>#include <stdio.h>#include <getopt.h>#include <unistd.h>#include <string.h>#include <signal.h>#include <libgen.h>#include <sys/resource.h>#ifdef HAVE_LIBNSCD_H#include <libnscd.h>#endif#ifdef USE_LDAP#include "libldap.h"#endif#include "i18n.h"#include "group.h"#include "public.h"#include "logging.h"#include "utf8conv.h"#include "logindefs.h"#include "read-files.h"#include "error_codes.h"static voidprint_usage (FILE *stream, const char *program){  fprintf (stream, _("Usage: %s [-D binddn] [-g gid [-o]] [-r] [-P path] [-p password] group\n"),	   program);}static voidprint_help (const char *program){  print_usage (stdout, program);  fprintf (stdout, _("%s - create a new group\n\n"), program);  fputs (_("  -D binddn      Use dn \"binddn\" to bind to the LDAP directory\n"), stdout);  fputs (_("  -g gid         Force the new groupid to be the given number\n"),	 stdout);  fputs (_("  -o             Allow duplicate (non-unique) UID\n"), stdout);  fputs (_("  -P path        Search passwd, shadow and group file in \"path\"\n"),	 stdout);  fputs (_("  -p password    Encrypted password as returned by crypt(3)\n"),	 stdout);  fputs (_("  -r, --system   Create a system account\n"), stdout);  fputs (_(" --service srv   Add account to nameservice 'srv'\n"), stdout);  fputs (_("      --help     Give this help list\n"), stdout);  fputs (_("      --usage    Give a short usage message\n"), stdout);  fputs (_("  -v, --version  Print program version\n"), stdout);  fputs (_("Valid services for --service are: files, ldap\n"), stdout);}static const char *program = "groupadd";static struct option long_options[] = {#ifdef USE_LDAP  {"binddn",      required_argument, NULL, 'D'},#endif  {"force",       no_argument,       NULL, 'f'},  {"gid",         required_argument, NULL, 'g'},  {"non-unique",  no_argument,       NULL, 'o'},  {"path",        required_argument, NULL, 'P'},  {"password",    required_argument, NULL, 'p'},  {"service",     required_argument, NULL, '\253'},  {"system",      no_argument,       NULL, 'r'},  {"version",     no_argument,       NULL, 'v'},  {"usage",       no_argument,       NULL, '\254'},  {"help",        no_argument,       NULL, '\255'},  {NULL, 0, NULL, '\0'}};static const char *short_options = "D:fg:oP:p:ru:v";static struct group *files_getgrent (void){  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_getgrent_r (&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 group *files_getgrnam (const char *name){  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_getgrnam_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 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;}/* find_free_gid - find the first, free available GID.  */static gid_tfind_free_gid (int is_system_account, int have_extrapath){  const struct group *grp;  gid_t groupid, gid_min, gid_max;  if (is_system_account)    {      /* Some special handling for LSB. LSB defines         the GID range as:         1 - 99: fix assigned system groups         100 - 499: dynamic assigned system groups         If we use -r, try to get a uid from the dynamic         assigned range.  */      gid_min = getlogindefs_unum ("SYSTEM_GID_MIN", 100);      gid_max = getlogindefs_unum ("SYSTEM_GID_MAX", 499);    }  else    {      gid_min = getlogindefs_unum ("GID_MIN", 500);      gid_max = getlogindefs_unum ("GID_MAX", 60000);    }  groupid = gid_min;  /* Search the entire group file, looking for the     largest unused value. If gid_max does already exists,     skip this.  */  if (getgrgid (gid_max) == NULL)    {      setgrent ();      while ((grp = getgrent ()))	{	  if (grp->gr_gid >= groupid)	    {	      if (grp->gr_gid > gid_max)		continue;	      groupid = grp->gr_gid + 1;	    }	}      if (have_extrapath && groupid != gid_max + 1)	{	  /* If the -P flag is given, not only search in the	     "official" database, but also in the extra one. */	  while ((grp = files_getgrent ()))	    {	      if (grp->gr_gid >= groupid)		{		  if (grp->gr_gid > gid_max)		    continue;		  groupid = grp->gr_gid + 1;		}	    }	}    }  else    groupid = gid_max + 1;	/* gid_max exists, so this will be				   the result of the above loop.  */  /* If the GID we found is equal to GID_MAX+1, we will step     through the whole GID_MIN - GID_MAX range and search for     the first free GID.  */  if (groupid == gid_max + 1)    {      for (groupid = gid_min; groupid < gid_max; groupid++)	if (getgrgid (groupid) == NULL)	  {	    if (have_extrapath)	      {		/* The GID is not used  in the normal database, now		   look in the extra one, too.  */		if (files_getgrgid (groupid) == NULL)		  break;	      }	    else	      break;	  }      if (groupid == gid_max)	{	  fprintf (stderr, _("%s: Can't get unique gid in range %u - %u.\n"),		   program, gid_min, gid_max);	  sec_log (program, MSG_NO_FREE_GID, gid_min, gid_max);	  exit (E_FAILURE);	}    }  return groupid;}intmain (int argc, char **argv){  char *use_service = NULL;#ifdef USE_LDAP  char *binddn = NULL;#endif  char *new_group = NULL;  char *new_password = NULL;  int know_gid = 0;  gid_t new_gid = 0;  int system_account = 0;  int non_unique = 0;  int have_extrapath = 0;  int force_add = 0;  setlocale (LC_ALL, "");  bindtextdomain (PACKAGE, LOCALEDIR);  textdomain (PACKAGE);  /* Before going any further, raise the ulimit and ignore     signals.  */  init_environment ();  while (1)    {      int c;      int option_index = 0;      c = getopt_long (argc, argv, short_options,		       long_options, &option_index);      if (c == (-1))	break;      switch (c)	{        case 'D':#ifdef USE_LDAP	  binddn = optarg;#endif          break;	case 'f':	  fprintf (stderr,		   _("%s: You are using an undocumented option (-f)!\n"),		   program);	  force_add = 1;	  break;	case 'g':	  if (strtoid (optarg, &new_gid) == -1)    /* invalid number */	    {	      fprintf (stderr,		       _("%s: Invalid numeric argument `%s' for Group ID.\n"),		       program, optarg);	      return E_BAD_ARG;	    }	  know_gid = 1;	  break;	case 'o':	  non_unique = 1;	  break;	case 'P':	  files_etc_dir = strdup (optarg);	  have_extrapath = 1;	  /* If -P option is used, set use_service to "files" if not	     already set through an option. If we don't limitate to	     service files, we can get trouble finding the right	     source.  */	  if (!use_service)	    use_service = "files";	  break;	case 'p':		/* set encrypted password */	  if (strcspn (optarg, ":\n") != strlen (optarg))	    {	      fprintf (stderr, _("%s: Invalid characters in password `%s'.\n"),		       program, optarg);	      return E_BAD_ARG;	    }	  new_password = optarg;	  break;	case 'r':	  system_account = 1;	  break;	case '\253':	  if (use_service != NULL)            {              print_usage (stderr, program);              return E_BAD_ARG;            }	  if (strcasecmp (optarg, "files") == 0)            use_service = "files";#ifdef USE_LDAP          else if (strcasecmp (optarg, "ldap") == 0)            use_service = "ldap";#endif          else            {              fprintf (stderr, _("Service `%s' not supported.\n"), optarg);              print_usage (stderr, program);              return E_BAD_ARG;            }	  break;	case '\255':	  print_help (program);	  return 0;	case 'v':	  print_version (program, "2005");	  return 0;	case '\254':	  print_usage (stdout, program);	  return 0;	default:	  print_error (program);	  return E_USAGE;	}    }  argc -= optind;  argv += optind;  if (argc > 1)    {      fprintf (stderr, _("%s: Too many arguments.\n"), program);      print_error (program);      return E_USAGE;    }  else if (argc == 0)    {      fprintf (stderr, _("%s: Too few arguments.\n"), program);      print_error (program);      return E_USAGE;    }  else if (force_add && non_unique)    {      fprintf (stderr, _("%s: You cannot use -f with -o.\n"), program);      print_usage (stderr, program);      return E_USAGE;    }  else    {      int buflen = 256;      char *buffer = alloca (buflen);      struct passwd resultbuf;      struct passwd *pw;      open_sec_log (program);      /* Determine our own user name for PAM authentication.  */      while (getpwuid_r (getuid (), &resultbuf, buffer, buflen, &pw) != 0	     && errno == ERANGE)	{	  errno = 0;	  buflen += 256;	  buffer = alloca (buflen);	}      if (!pw)	{	  sec_log (program, MSG_NO_ACCOUNT_FOUND, getuid ());	  fprintf (stderr, _("%s: Cannot determine your user name.\n"),		   program);	  return E_UNKNOWN_USER;	}      if (do_authentication ("shadow" /* XXX program */,			     pw->pw_name, NULL) != 0)	{	  sec_log (program, MSG_PERMISSION_DENIED, pw->pw_name,		   pw->pw_uid, getuid() );	  return E_NOPERM;	}    }  /* After this, we can start creating the new group.  */  if (know_gid && !non_unique)    {      if (getgrgid (new_gid) != NULL ||	  (have_extrapath && files_getgrgid (new_gid) != NULL))	{	  if (force_add)	    {	      /* If -f was given, reset -g option.  */	      fprintf (stderr,		       _("%s: GID %u is not unique, using another one.\n"),		       program, new_gid);	      know_gid = 0;	    }	  else	    {	      fprintf (stderr, _("%s: GID %u is not unique.\n"),		       program, new_gid);	      sec_log (program, MSG_GID_NOT_UNIQUE, new_gid, getuid ());	      return E_GID_IN_USE;	    }	}    }  new_group = locale_to_utf8 (argv[0]);  if (check_name (new_group) != 0)    {      fprintf (stderr, _("%s: Invalid group name `%s'.\n"),	       program, utf8_to_locale (new_group));      sec_log (program, MSG_GROUP_NAME_INVALID, new_group, getuid())      return E_BAD_ARG;    }  /* Lock group file, so that a concurrent useradd process will not     add the user a second time or a second user with the same uid.  */  if ((use_service == NULL || strcmp (use_service, "files") == 0) &&      lock_database () != 0)    {      fputs (_("Cannot lock group file: already locked.\n"), stderr);      sec_log (program, MSG_GROUP_FILE_ALREADY_LOCKED);      return E_PWDBUSY;    }  else if (getgrnam (new_group) != NULL ||	   (have_extrapath && files_getgrnam (new_group) != NULL))    {				/* Group does already exists.  */      fprintf (stderr, _("%s: Group `%s' already exists.\n"),	       program, utf8_to_locale (new_group));      sec_log (program, MSG_GROUP_ALREADY_EXISTS, new_group, getuid ());      return E_NAME_IN_USE;    }  else    {      int i;      group_t gr_data;      int retval = E_SUCCESS;      memset (&gr_data, 0, sizeof (gr_data));      if (use_service)	{	  if (strcmp (use_service, "files") == 0)	    gr_data.service = S_LOCAL;	  else if (strcmp (use_service, "ldap") == 0)	    gr_data.service = S_LDAP;	}      else	gr_data.service = S_LOCAL;      gr_data.todo = DO_CREATE;      gr_data.gr.gr_name = new_group;      if (new_password)	gr_data.gr.gr_passwd = new_password;      else	gr_data.gr.gr_passwd = "!";      gr_data.gr.gr_gid = know_gid ? new_gid : find_free_gid (system_account,							      have_extrapath);#ifdef USE_LDAP      if (gr_data.service == S_LDAP)	{	  if (binddn == NULL)	    {	      binddn = get_caller_dn ();	      if (binddn == NULL)		{		  fprintf (stderr, _("%s: Cannot add group to LDAP database without DN.\n"),			   program);		}	      else gr_data.binddn = strdup (binddn);	    }	  else	    gr_data.binddn = strdup (binddn);	  if (gr_data.oldclearpwd == NULL)	    {	      char *cp = get_ldap_password (gr_data.binddn);	      if (cp)		gr_data.oldclearpwd = strdup (cp);	      else		{		  fprintf (stderr,			   _("%s: Group not added to LDAP database.\n"),			   program);		  return E_FAILURE;		}	    }	}#endif      if (write_group_data (&gr_data, 1) != 0)	{	  sec_log (program, MSG_ERROR_ADDING_NEW_GROUP, gr_data.gr.gr_name,		   (unsigned int) gr_data.gr.gr_gid, getuid());	  return E_FAILURE;	}      else	{	  sec_log (program, MSG_NEW_GROUP_ADDED, gr_data.gr.gr_name,		   (unsigned int) gr_data.gr.gr_gid, getuid());	}#ifdef HAVE_NSCD_FLUSH_CACHE      /* flush NSCD cache.  */      nscd_flush_cache ("group");#endif      if (use_service == NULL || strcmp (use_service, "files") == 0)	ulckpwdf ();      i = call_script ("GROUPADD_CMD", gr_data.gr.gr_name,		       gr_data.gr.gr_gid, getuid (), NULL, program);      if (i != 0)	{	  fprintf (stderr, _("%s: GROUPADD_CMD fails with exit code %d.\n"),		   program, i);	  retval = E_FAILURE;	}      return retval;    }  return E_SUCCESS;}

⌨️ 快捷键说明

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