📄 useradd.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 "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 + -