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

📄 usermod.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 "public.h"#include "group.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 ...\n"), program);}static voidprint_help (const char *program){  print_usage (stdout, program);  fprintf (stdout, _("%s - modify a user account\n\n"), program);  fputs (_("  -c comment     Set the GECOS field for the new account\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 (_("  -l login       Change login name.\n"), stdout);  fputs (_("  -m             Move home directory to the new path\n"), stdout);  fputs (_("  -o             Allow duplicate (non-unique) UID\n"), stdout);  fputs (_("  -A group,...   List of groups the user should be added to\n"),	 stdout);  fputs (_("  -R group,...   List of groups the user should be removed from\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 (_("  -s shell       Name of the user's login shell\n"), stdout);  fputs (_("  -u uid         Change the userid to the given number\n"),	 stdout);  fputs (_("  --service srv  Use nameservice 'srv'\n"), stdout);  fputs (_("  -L             Locks the password entry for \"user\"\n"),	 stdout);  fputs (_("  -U             Try to unlock the password entry for \"user\"\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 are: files, ldap\n"), stdout);}static const char *program = "usermod";static struct option long_options[] = {  {"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'},  {"add-to-groups", required_argument, NULL, 'A'},  {"remove-from-groups", required_argument, NULL, 'R'},  {"gid", required_argument, NULL, 'g'},  {"login", required_argument, NULL, 'l'},  {"lock", required_argument, NULL, 'L'},  {"move-home", no_argument, NULL, 'm'},  {"non-unique", no_argument, NULL, 'o'},  {"path", required_argument, NULL, 'P'},  {"password", required_argument, NULL, 'p'},  {"shell", required_argument, NULL, 's'},  {"uid", required_argument, NULL, 'u'},  {"unlock", required_argument, NULL, 'U'},  {"version", no_argument, NULL, 'v'},  {"service", required_argument, NULL, '\253'},  {"usage", no_argument, NULL, '\254'},  {"help", no_argument, NULL, '\255'},  {NULL, 0, NULL, '\0'}};static const char *short_options = "A:c:D:d:e:f:G:g:l:LmoP:p:R:s:u:Uv";/* 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;      if (strtoid (arg, &gid) == -1)	/* invalid number */	{	  fprintf (stderr, _("%s: Invalid numeric argument `%s'.\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, utf8_to_locale (arg), use_service);	      return E_NOTFOUND;	    }	  else	    {	      fprintf (stderr, _("%s: Unknown group `%s'.\n"), program,		       utf8_to_locale (arg));	      return E_BAD_ARG;	    }	}    }  if (grouplist)    *grouplist = strdup (gr_data->gr.gr_name);  if (groupid)    *groupid = gr_data->gr.gr_gid;  return 0;}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 struct passwd *files_getpwuid (uid_t uid){  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_getpwuid_r (uid, &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_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 char **add_gr_mem (const char *name, char **gr_mem){  char **groups;  unsigned int i;  int already_added = 0;  i = 0;  while (gr_mem[i])    {      if (strcmp (gr_mem[i], name) == 0)	already_added = 1;      ++i;    }  ++i;				/* for trailing NULL pointer */  if (!already_added)    ++i;  groups = malloc (i * sizeof (char *));  i = 0;  while (gr_mem[i])    {      groups[i] = strdup (gr_mem[i]);      ++i;    }  if (!already_added)    {      groups[i] = strdup (name);      ++i;    }  groups[i] = NULL;  return groups;}static char **rename_gr_mem (const char *name, char **gr_mem, const char *new_name){  char **groups;  unsigned int i;  for (i = 0; gr_mem[i]; i++) ;  ++i;                          /* for trailing NULL pointer */  groups = malloc ((i + 1) * sizeof (char *));  if (groups == NULL)    return NULL;  for (i = 0; gr_mem[i]; i++)    {      if (strcmp (name, gr_mem[i]) != 0)	groups[i] = strdup (gr_mem[i]);      else	groups[i] = strdup (new_name);    }  groups[i] = NULL;  return groups;}static intrename_in_secondary_groups (user_t *pw_data, int have_extrapath){  struct item_t {    char *value;    struct item_t *next;  } *list = NULL, *item;  struct group *gr;  int retval = E_SUCCESS;  if (have_extrapath)    {      while ((gr = files_getgrent ()))        {          unsigned int i;          for (i = 0; gr->gr_mem[i]; i++)            {              if (strcmp (gr->gr_mem[i], pw_data->pw.pw_name) == 0)                {                  item = malloc (sizeof (*item));                  item->value = strdup (gr->gr_name);                  item->next = list;                  list = item;                }            }        }    }  else    {      setgrent ();      while ((gr = getgrent ()))        {          unsigned int i;          for (i = 0; gr->gr_mem[i]; i++)            {              if (strcmp (gr->gr_mem[i], pw_data->pw.pw_name) == 0)                {                  item = malloc (sizeof (*item));                  item->value = strdup (gr->gr_name);                  item->next = list;                  list = item;                }            }        }      endgrent ();    }  item = list;  while (item != NULL)    {      group_t *gr_data = find_group_data (item->value, 0, NULL);      if (gr_data == NULL || gr_data->service == S_NONE)        {          fprintf (stderr,                   _("%s: ERROR: Cannot find group `%s' anymore!\n"),                   program, utf8_to_locale (item->value));          if (retval == E_SUCCESS)            retval = E_NOTFOUND;        }      else        {          gr_data->todo = DO_MODIFY;#ifdef USE_LDAP          if (gr_data->service == S_LDAP)            {              if (pw_data->binddn == NULL)                {		  sec_log (program, MSG_ERROR_RENAME_USER_IN_GROUP,			   pw_data->pw.pw_name, pw_data->pw.pw_uid,			   gr_data->gr.gr_name,			   gr_data->gr.gr_gid, getuid ());                  fprintf (stderr,                           _("%s: User not renamed in LDAP group `%s'.\n"),                           program, utf8_to_locale (gr_data->gr.gr_name));                  item = item->next;                  free_group_t (gr_data);                  retval = E_GRP_UPDATE;                  continue;                }              gr_data->binddn = strdup (pw_data->binddn);              if (pw_data->oldclearpwd == NULL)                {		  sec_log (program, MSG_ERROR_RENAME_USER_IN_GROUP,			   pw_data->pw.pw_name,			   pw_data->pw.pw_uid, gr_data->gr.gr_name,			   gr_data->gr.gr_gid, getuid ());		  fprintf (stderr,			   _("%s: User not renamed from LDAP group `%s'.\n"),			   program, utf8_to_locale (gr_data->gr.gr_name));		  item = item->next;		  free_group_t (gr_data);		  retval = E_GRP_UPDATE;		  continue;		}            }#endif          if (pw_data->oldclearpwd)            gr_data->oldclearpwd = strdup (pw_data->oldclearpwd);          gr_data->new_gr_mem = rename_gr_mem (pw_data->pw.pw_name,                                               gr_data->gr.gr_mem,					       pw_data->new_name);          if (write_group_data (gr_data, 1) != 0)            {	      sec_log (program, MSG_ERROR_RENAME_USER_IN_GROUP,		       pw_data->pw.pw_name,		       pw_data->pw.pw_uid, gr_data->gr.gr_name,		       gr_data->gr.gr_gid, getuid ());              fprintf (stderr,                       _("%s: User not renamed in group `%s'.\n"),                       program, utf8_to_locale (gr_data->gr.gr_name));              retval = E_GRP_UPDATE;            }	  else	    {	      sec_log (program, MSG_USER_RENAMED_IN_GROUP,		       pw_data->new_name, pw_data->pw.pw_name,		       pw_data->pw.pw_uid, gr_data->gr.gr_name,		       gr_data->gr.gr_gid, getuid ());	    }          item = item->next;        }      free_group_t (gr_data);    }  return retval;}/* Move the users home directory to new location.  */static intmove_home_directory (const char *oldhome, const char *newhome){  struct stat st;  if (oldhome == NULL || *oldhome == '\0' ||      newhome == NULL || *newhome == '\0')    return E_HOMEDIR;  /* Does the old directory exist?  */  if (stat (oldhome, &st) < 0)    return 0; /* No old homedirectory, but no error, too.  */  /* Don't try to move it if it is not a directory.     Some admins have the bad idea to use a file as home     directory.  */  if (!S_ISDIR (st.st_mode))    return E_HOMEDIR;  if (access (newhome, F_OK) == 0)    return E_HOMEDIR;  else    {      char path[strlen (newhome) + 2];      char *bhome, *cp;      path[0] = '\0';      bhome = strdup (newhome);      ++bhome;      /* Check for every part of the path, if the directory         exists. If not, create it with permissions 755 and         owner root:root.  */      cp = strtok (bhome, "/");      while (cp)	{	  strcat (path, "/");	  strcat (path, cp);	  if (access (path, F_OK) != 0)	    {	      if (mkdir (path, 0) != 0)		{		  fprintf (stderr,			   _("%s: Cannot create directory `%s'.\n"),			   program, path);		  return E_HOMEDIR;		}              if (chown (path, 0, 0) < 0)                fprintf (stderr, _("%s: Warning: chown on `%s' failed: %m\n"),                         program, path);              if (chmod (path, 0755) < 0)                fprintf (stderr, _("%s: Warning: chmod on `%s' failed: %m\n"),                         program, path);	    }	  cp = strtok (NULL, "/");	}      /* we have this created to much, remove it again.  */      rmdir (newhome);    }  if (rename (oldhome, newhome) == -1)    {      if (errno == EXDEV)	{	  if (mkdir (newhome, st.st_mode & 0777))	    {	      fprintf (stderr, _("Can't create `%s': %m\n"),		       newhome);	      return E_HOMEDIR;	    }	  if (chown (newhome, st.st_uid, st.st_gid))	    {	      fprintf (stderr, _("%s: Warning: chown on `%s' failed: %m\n"),		       program, newhome);	      rmdir (newhome);	      return E_HOMEDIR;	    }	  if (copy_dir_rec (oldhome, newhome, 1, 0, 0) == 0)	    remove_dir_rec (oldhome); /* only remove if no error occured. */	  else	    {	      fprintf (stderr, _("%s: Cannot copy directory %s to %s.\n"),		       program, oldhome, newhome);	      return E_HOMEDIR;	    }	}      else	{	  fprintf (stderr, _("%s: Cannot rename directory %s to %s.\n"),		   program, oldhome, newhome);	  return E_HOMEDIR;	}    }  return 0;}/* XXX Make this generic and put it into libpwdutils.  */static intremove_from_secondary_groups (user_t *pw_data, int have_extrapath,			      const char *name){  struct item_t {    char *value;    struct item_t *next;  } *list = NULL, *item;  struct group *gr;  int retval = E_SUCCESS;  if (have_extrapath)    {      while ((gr = files_getgrent ()))        {          unsigned int i;

⌨️ 快捷键说明

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