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

📄 useradd.c

📁 pwdutils是一套密码管理工具
💻 C
📖 第 1 页 / 共 3 页
字号:
/* 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 "logindefs.h"#include "read-files.h"#include "error_codes.h"static voidprint_usage (FILE *stream, const char *program){  fprintf (stream, _("Usage: %s ...\n"), program);}static voidprint_help (const char *program){  print_usage (stdout, program);  fprintf (stdout, _("%s - create a new user\n\n"), program);  fputs (_("  -c comment     Set the GECOS field for the new account\n"),	 stdout);  fputs (_(" --show-defaults Print default values\n"), stdout);  fputs (_(" --save-defaults Save modified default values\n"), stdout);  fputs (_("  -D binddn      Use dn \"binddn\" to bind to the LDAP directory\n"), stdout);  fputs (_("  -d homedir     Home directory for the new user\n"), stdout);  fputs (_("  -e expire      Date on which the new account will be disabled\n"),	 stdout);  fputs (_("  -f inactive    Days after a password expires until account is \disabled\n"), stdout);  fputs (_("  -G group,...   List of supplementary groups\n"), stdout);  fputs (_("  -g gid         Name/number of the users primary group\n"),	 stdout);  fputs (_("  -k skeldir     Specify an alternative skel directory\n"),	 stdout);  fputs (_("  -m             Create home directory for the new user\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 (_("  -u uid         Force the new userid to be the given number\n"),	 stdout);  fputs (_("  -r, --system   Create a system account\n"), stdout);  fputs (_("  -s shell       Name of the user's login shell\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 = "useradd";static const char *useradd_default_file = "/etc/default/useradd";static struct option long_options_all[] = {  {"comment",     required_argument, NULL, 'c'},  {"gecos",       required_argument, NULL, 'c'},#ifdef USE_LDAP  {"binddn",      required_argument, NULL, 'D'},#endif  {"home",        required_argument, NULL, 'd'},  {"expire",      required_argument, NULL, 'e'},  {"inactive",    required_argument, NULL, 'f'},  {"groups",      required_argument, NULL, 'G'},  {"gid",         required_argument, NULL, 'g'},  {"skel",        required_argument, NULL, 'k'},  {"create-home", no_argument, NULL, 'm'},  {"non-unique",  no_argument, NULL, 'o'},  {"path",        required_argument, NULL, 'P'},  {"password",    required_argument, NULL, 'p'},  {"save-defaults", no_argument,     NULL, '\251'},  {"show-defaults", no_argument,     NULL, '\252'},  {"service",     required_argument, NULL, '\253'},  {"system",      no_argument,       NULL, 'r'},  {"shell",       required_argument, NULL, 's'},  {"uid",         required_argument, NULL, 'u'},  {"version",     no_argument,       NULL, 'v'},  {"usage",       no_argument,       NULL, '\254'},  {"help",        no_argument,       NULL, '\255'},  {NULL, 0, NULL, '\0'}};static const char *short_options_all = "c:D:d:e:f:G:g:k:MmoP:p:rs:u:v";static struct option long_options_D[] = {  {"home", required_argument, NULL, 'b'},#ifdef  USE_LDAP  {"binddn", required_argument, NULL, '\250'},#endif  {"home", required_argument, NULL, 'd'},  {"expire", required_argument, NULL, 'e'},  {"inactive", required_argument, NULL, 'f'},  {"groups", required_argument, NULL, 'G'},  {"gid", required_argument, NULL, 'g'},  {"skel", required_argument, NULL, 'k'},  {"shell", required_argument, NULL, 's'},  {"version", no_argument, NULL, 'v'},  {"save-defaults", no_argument,       NULL, '\251'},  {"show-defaults", no_argument,       NULL, '\252'},  {"service",       required_argument, NULL, '\253'},  {"usage",         no_argument,       NULL, '\254'},  {"help",          no_argument,       NULL, '\255'},  {NULL, 0, NULL, '\0'}};static const char *short_options_D = "b:Dd:e:f:G:g:k:s:v";struct default_t{  gid_t group;  char *home;  long int inactive;  long int expire;  char *shell;  char *skel;  unsigned int groupscnt;  char **groups;  int create_mail_spool;};/* This function converts a comma seperated list of groups   (a group can be a groupname or a group id) into a table   of group ids. It returns 0 on success.  */static intconvert_grpopt_to_name (const char *arg, char **grouplist, gid_t *groupid,			const char *use_service){  group_t *gr_data;  if (isdigit (*arg))    {      gid_t gid;      int err = strtoid (arg, &gid);      if (err == -1)		/* invalid number */	{	  fprintf (stderr,		   _("%s: Invalid numeric argument `%s' for group ID.\n"),		   program, arg);	  return E_BAD_ARG;	}      gr_data = find_group_data (NULL, gid, use_service);      if (gr_data == NULL || gr_data->service == S_NONE)	{	  if (use_service)	    {	      fprintf (stderr, _("%s: Group `%u' not found in service `%s'.\n"),		       program, gid, use_service);	      return E_NOTFOUND;	    }	  else	    {	      fprintf (stderr, _("%s: Unknown group `%u'.\n"), program, gid);	      return E_BAD_ARG;	    }	}    }  else    {      gr_data = find_group_data (arg, 0, use_service);      if (gr_data == NULL || gr_data->service == S_NONE)	{	  if (use_service)	    {	      fprintf (stderr, _("%s: Group `%s' not found in service `%s'.\n"),		       program, arg, use_service);	      return E_NOTFOUND;	    }	  else	    {	      fprintf (stderr, _("%s: Unknown group `%s'.\n"), program, arg);	      return E_BAD_ARG;	    }	}    }  if (grouplist)    *grouplist = strdup (gr_data->gr.gr_name);  if (groupid)    *groupid = gr_data->gr.gr_gid;  return 0;}/* Load the config file (/etc/default/useradd)  */static intload_defaults (const char *configfile, struct default_t *data){  FILE *fp;  char *buf = NULL;  size_t buflen = 0;  int errors = 0;  fp = fopen (configfile, "r");  if (NULL == fp)    return -1;  while (!feof (fp))    {      char *tmp, *cp;#if defined(HAVE_GETLINE)      ssize_t n = getline (&buf, &buflen, fp);#elif defined (HAVE_GETDELIM)      ssize_t n = getdelim (&buf, &buflen, '\n', fp);#else      ssize_t n;      if (buf == NULL)	{	  buflen = 8096;	  buf = malloc (buflen);	}      buf[0] = '\0';      fgets (buf, buflen - 1, fp);      if (buf != NULL)	n = strlen (buf);      else	n = 0;#endif /* HAVE_GETLINE / HAVE_GETDELIM */      cp = buf;      if (n < 1)	break;      tmp = strchr (cp, '#');	/* remove comments */      if (tmp)	*tmp = '\0';      while (isspace ((int) *cp))	/* remove spaces and tabs */	++cp;      if (*cp == '\0')		/* ignore empty lines */	continue;      if (cp[strlen (cp) - 1] == '\n')	cp[strlen (cp) - 1] = '\0';      if (strncasecmp (cp, "GROUP=", 6) == 0)	{	  struct group *grp;	  gid_t grpid;	  if (cp[6] != '\0' && strtoid (&cp[6], &grpid) == 0)	    /* GID in numeric form */	    data->group = grpid;	  else if ((grp = getgrnam (&cp[6])) != NULL)	    data->group = grp->gr_gid;	  else	    {	      ++errors;	      fprintf (stderr, _("%s: Unknown group `%s' in %s.\n"),		       program, cp, configfile);	    }	  continue;	}      else if (strncasecmp (cp, "HOME=", 5) == 0)	{	  char *home;	  home = &cp[5];	  if (strcspn (home, ":\n") != strlen (home) || *home != '/')	    {	      ++errors;	      fprintf (stderr, _("%s: Invalid home directory `%s' in %s.\n"),		       program, home, configfile);	    }	  else	    data->home = strdup (home);	  continue;	}      else if (strncasecmp (cp, "INACTIVE=", 9) == 0)	{	  long int inactive;	  char *ep;	  inactive = strtol (&cp[9], &ep, 10);	  if (*ep != '\0' ||	      ((inactive == LONG_MAX || inactive == LONG_MIN)	       && errno == ERANGE))	/* invalid number */	    {	      ++errors;	      fprintf (stderr, _("%s: Invalid numeric argument `%s' for `INACTIVE' in %s.\n"),		       program, &cp[9], configfile);	    }	  else	    data->inactive = inactive;	  continue;	}      else if (strncasecmp (cp, "EXPIRE=", 7) == 0)	{	  if (cp[7] == '\0' || strcmp (&cp[7], "1969-12-31") == 0)	    data->expire = -1;	  else	    {	      long int expire;	      char *ep;	      expire = str2date (&cp[7]);	      if (expire == -1)		{		  if (((expire = strtol (&cp[7], &ep, 10)) == 0 && *ep) ||		      expire < -1)		    {		      fprintf (stderr,			       _("%s: Expiredate `%s' is no date and no integer value >= -1 in %s.\n"),			       program, &cp[7], configfile);		      ++errors;		    }		}	      else		data->expire = expire;	    }	  continue;	}      else if (strncasecmp (cp, "SHELL=", 6) == 0)	{	  if (strcspn (&cp[6], ",=\":*\n") != strlen (&cp[6]) ||	      *&cp[6] != '/')	    {	      ++errors;	      fprintf (stderr, _("%s: Invalid shell `%s' in %s.\n"),		       program, &cp[6], configfile);	    }	  else	    data->shell = strdup (&cp[6]);	  continue;	}      else if (strncasecmp (cp, "SKEL=", 5) == 0)	{	  if (access (&cp[5], F_OK) != 0)	    {	      ++errors;	      fprintf (stderr,		       _("%s: Skel directory \"%s\" in %s does not exist.\n"),		       program, &cp[5], configfile);	    }	  else	    data->skel = strdup (&cp[5]);	  continue;	}      else if (strncasecmp (cp, "GROUPS=", 7) == 0)	{	  char *arg = strdupa (&cp[7]);	  unsigned int err = 0, i, j;	  j = 1;	  for (i = 0; i < strlen (arg); i++)	    if (arg[i] == ',')	      ++j;	  data->groups = malloc (sizeof (char *) * j);	  data->groupscnt = 0;	  do	    {	      char *c = strchr (arg, ',');	      if (c)		*c++ = '\0';	      if (arg && *arg)		{		  if (convert_grpopt_to_name (arg,					      &data->groups[data->groupscnt],					      NULL, NULL) != 0)		    ++err;		  else		    {		      data->groupscnt++;		      if (data->groupscnt > j)			abort ();		    }		}	      arg = c;	    }	  while (arg);	  if (err)	    {	      data->groupscnt = 0;	      free (data->groups);	      data->groups = NULL;	      ++errors;	    }	  continue;        }      else if (strncasecmp (cp, "CREATE_MAIL_SPOOL=", 18) == 0)        {	  if (strcasecmp (&cp[18], "yes") == 0)            data->create_mail_spool = 1;          else if (strcasecmp (&cp[18], "no") == 0)            data->create_mail_spool = 0;          else            {              ++errors;              fprintf (stderr, _("%s: Invalid value `%s' for option CREATE_MAIL_SPOOL in %s.\n"),                       program, &cp[18], configfile);            }          continue;        }    }  fclose (fp);  if (buf)    free (buf);  return errors;}static voidprint_defaults (const struct default_t *data){  unsigned int i;  printf ("GROUP=%u\n", (unsigned int) data->group);  printf ("HOME=%s\n", data->home);  printf ("INACTIVE=%li\n", data->inactive);  if (data->expire == -1)    fputs ("EXPIRE=\n", stdout);  else    printf ("EXPIRE=%s\n", date2str (data->expire * SCALE));  printf ("SHELL=%s\n", data->shell);  printf ("SKEL=%s\n", data->skel);  printf ("GROUPS=");  for (i = 0; i < data->groupscnt; i++)    {      if (i != 0)	printf (",");      printf ("%s", data->groups[i]);    }  printf ("\n");  printf ("CREATE_MAIL_SPOOL=%s\n", data->create_mail_spool?"yes":"no");}/* Write the config file (/etc/default/useradd)  */static intwrite_defaults (const char *configfile, struct default_t *data){  const char *tmpsuffix = ".tmpXXXXXX";  FILE *fp, *new_fp;  char *buf = NULL, *cp;  size_t buflen = 0;  char tmpname[strlen (configfile) + strlen (tmpsuffix) + 1];  struct stat oldmode;  int new_fd, ret;  int group_written = 0, home_written = 0, inactive_written = 0;  int expire_written = 0, shell_written = 0, groups_written = 0;  int skel_written = 0, create_mail_spool_written = 0;  fp = fopen (configfile, "r");  if (NULL == fp)    return -1;  cp = stpcpy (tmpname, configfile);  strcpy (cp, tmpsuffix);  if (fstat (fileno (fp), &oldmode) < 0)    {      fprintf (stderr, _("Can't stat `%s': %m\n"), configfile);      fclose (fp);      return -1;    }  /* Open a temp file */  new_fd = mkstemp (tmpname);  if (new_fd == -1)    {      fprintf (stderr, _("Can't create `%s': %m\n"), tmpname);      fclose (fp);      return -1;    }  if (fchmod (new_fd, oldmode.st_mode) < 0)    {      fprintf (stderr,	       _("Cannot change permissions for `%s': %s\n"),	       tmpname, strerror (errno));      fclose (fp);      close (new_fd);      unlink (tmpname);      return -1;    }  if (fchown (new_fd, oldmode.st_uid, oldmode.st_gid) < 0)    {      fprintf (stderr,	       _("Cannot change owner/group for `%s': %s\n"),	       tmpname, strerror (errno));      fclose (fp);      close (new_fd);      unlink (tmpname);      return -1;    }  if (copy_xattr (configfile, tmpname) != 0)    {      fclose (fp);      close (new_fd);      unlink (tmpname);      return -1;    }  new_fp = fdopen (new_fd, "w+");  if (new_fp == NULL)    {      fprintf (stderr, _("Can't open `%s': %m\n"), configfile);      fclose (fp);      close (new_fd);      unlink (tmpname);      return -1;    }  while (!feof (fp))    {      char *tmp;#if defined(HAVE_GETLINE)      ssize_t n = getline (&buf, &buflen, fp);#elif defined (HAVE_GETDELIM)      ssize_t n = getdelim (&buf, &buflen, '\n', fp);#else      ssize_t n;      if (buf == NULL)	{	  buflen = 8096;	  buf = malloc (buflen);	}      buf[0] = '\0';      fgets (buf, buflen - 1, fp);      if (buf != NULL)	n = strlen (buf);      else	n = 0;#endif /* HAVE_GETLINE / HAVE_GETDELIM */      if (n < 1)	break;      cp = strdupa (buf);      tmp = strchr (cp, '#');	/* remove comments */      if (tmp)	*tmp = '\0';      while (isspace ((int) *cp))	/* remove spaces and tabs */	++cp;      if (*cp == '\0')		/* ignore empty lines */	{	  fputs (buf, new_fp);	  continue;	}      if (cp[strlen (cp) - 1] == '\n')	cp[strlen (cp) - 1] = '\0';      if (strncasecmp (cp, "GROUP=", 6) == 0)	{	  fprintf (new_fp, "GROUP=%u\n", data->group);	  group_written = 1;	  continue;	}      else if (strncasecmp (cp, "HOME=", 5) == 0)	{	  fprintf (new_fp, "HOME=%s\n", data->home);	  home_written = 1;

⌨️ 快捷键说明

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