/* * close_files - close all of the files that were opened * * close_files() closes all of the files that were opened for this new * group. This causes any modified entries to be written out. */ static void close_files (void) { /* First, write the changes in the regular group database */ if (gr_close () == 0) { fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, gr_dbname ()); exit (E_GRP_UPDATE); } #ifdef WITH_AUDIT audit_logger (AUDIT_ADD_GROUP, Prog, "adding group to /etc/group", group_name, (unsigned int) group_id, SHADOW_AUDIT_SUCCESS); #endif SYSLOG ((LOG_INFO, "group added to %s: name=%s, GID=%u", gr_dbname (), group_name, (unsigned int) group_id)); del_cleanup (cleanup_report_add_group_group); cleanup_unlock_group (NULL); del_cleanup (cleanup_unlock_group); /* Now, write the changes in the shadow database */ #ifdef SHADOWGRP if (is_shadow_grp) { if (sgr_close () == 0) { fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, sgr_dbname ()); exit (E_GRP_UPDATE); } #ifdef WITH_AUDIT audit_logger (AUDIT_ADD_GROUP, Prog, "adding group to /etc/gshadow", group_name, (unsigned int) group_id, SHADOW_AUDIT_SUCCESS); #endif SYSLOG ((LOG_INFO, "group added to %s: name=%s", sgr_dbname (), group_name)); del_cleanup (cleanup_report_add_group_gshadow); cleanup_unlock_gshadow (NULL); del_cleanup (cleanup_unlock_gshadow); } #endif /* SHADOWGRP */ /* Report success at the system level */ #ifdef WITH_AUDIT audit_logger (AUDIT_ADD_GROUP, Prog, "", group_name, (unsigned int) group_id, SHADOW_AUDIT_SUCCESS); #endif SYSLOG ((LOG_INFO, "new group: name=%s, GID=%u", group_name, (unsigned int) group_id)); del_cleanup (cleanup_report_add_group); }
/* * fail_exit - do some cleanup and exit with the given error code */ static /*@noreturn@*/void fail_exit (int code) { if (spw_locked) { if (spw_unlock () == 0) { fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, spw_dbname ()); SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ())); /* continue */ } } if (pw_locked) { if (pw_unlock () == 0) { fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, pw_dbname ()); SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ())); /* continue */ } } closelog (); #ifdef WITH_AUDIT if (E_SUCCESS != code) { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change age", user_name, (unsigned int) user_uid, 0); } #endif exit (code); }
/* * fail_exit - exit with a failure code after unlocking the files */ static void fail_exit (int code) { if (pw_locked) { if (pw_unlock () == 0) { fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, pw_dbname ()); SYSLOG ((LOG_ERR, "failed to unlock %s", pw_dbname ())); /* continue */ } } if (gr_locked) { if (gr_unlock () == 0) { fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, gr_dbname ()); SYSLOG ((LOG_ERR, "failed to unlock %s", gr_dbname ())); /* continue */ } } if (spw_locked) { if (spw_unlock () == 0) { fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, spw_dbname ()); SYSLOG ((LOG_ERR, "failed to unlock %s", spw_dbname ())); /* continue */ } } #ifdef SHADOWGRP if (sgr_locked) { if (sgr_unlock () == 0) { fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sgr_dbname ()); SYSLOG ((LOG_ERR, "failed to unlock %s", sgr_dbname ())); /* continue */ } } #endif /* SHADOWGRP */ #ifdef ENABLE_SUBIDS if (sub_uid_locked) { if (sub_uid_unlock () == 0) { fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_uid_dbname ()); SYSLOG ((LOG_ERR, "failed to unlock %s", sub_uid_dbname ())); /* continue */ } } if (sub_gid_locked) { if (sub_gid_unlock () == 0) { fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_gid_dbname ()); SYSLOG ((LOG_ERR, "failed to unlock %s", sub_gid_dbname ())); /* continue */ } } #endif /* ENABLE_SUBIDS */ #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "deleting user", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ exit (code); }
static void update_one (/*@null@*/const struct passwd *pw) { off_t offset; struct lastlog ll; int err; if (NULL == pw) { return; } offset = (off_t) pw->pw_uid * sizeof (ll); /* fseeko errors are not really relevant for us. */ err = fseeko (lastlogfile, offset, SEEK_SET); assert (0 == err); memzero (&ll, sizeof (ll)); if (Sflg) { ll.ll_time = NOW; #ifdef HAVE_LL_HOST strcpy (ll.ll_host, "localhost"); #endif strcpy (ll.ll_line, "lastlog"); #ifdef WITH_AUDIT audit_logger (AUDIT_ACCT_UNLOCK, Prog, "clearing-lastlog", pw->pw_name, (unsigned int) pw->pw_uid, SHADOW_AUDIT_SUCCESS); #endif } #ifdef WITH_AUDIT else { audit_logger (AUDIT_ACCT_UNLOCK, Prog, "refreshing-lastlog", pw->pw_name, (unsigned int) pw->pw_uid, SHADOW_AUDIT_SUCCESS); } #endif if (fwrite (&ll, sizeof(ll), 1, lastlogfile) != 1) { fprintf (stderr, _("%s: Failed to update the entry for UID %lu\n"), Prog, (unsigned long int)pw->pw_uid); exit (EXIT_FAILURE); } }
/* * update encrypted password string (for both shadow and non-shadow * passwords) */ static char *new_pw_passwd (char *pw_pass, const char *pw_name) { if (Lflg && pw_pass[0] != '!') { char *buf = xmalloc (strlen (pw_pass) + 2); #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "updating passwd", user_newname, user_newid, 0); #endif SYSLOG ((LOG_INFO, "lock user `%s' password", pw_name)); strcpy (buf, "!"); strcat (buf, pw_pass); pw_pass = buf; } else if (Uflg && pw_pass[0] == '!') { char *s; #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "updating password", user_newname, user_newid, 0); #endif SYSLOG ((LOG_INFO, "unlock user `%s' password", pw_name)); s = pw_pass; while (*s) { *s = *(s + 1); s++; } } else if (pflg) { #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing password", user_newname, user_newid, 1); #endif SYSLOG ((LOG_INFO, "change user `%s' password", pw_name)); pw_pass = xstrdup (user_pass); } return pw_pass; }
/* * fail_exit - exit with an error code after unlocking files */ static void fail_exit (int code) { (void) gr_unlock (); #ifdef SHADOWGRP if (is_shadow_grp) sgr_unlock (); #endif if (is_shadow_pwd) spw_unlock (); (void) pw_unlock (); #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "modifying account", user_name, -1, 0); #endif exit (code); }
/* * update_user - delete the user entries * * update_user() deletes the password file entries for this user * and will update the group entries as required. */ static void update_user (void) { if (pw_remove (user_name) == 0) { fprintf (stderr, _("%s: cannot remove entry '%s' from %s\n"), Prog, user_name, pw_dbname ()); fail_exit (E_PW_UPDATE); } if ( is_shadow_pwd && (spw_locate (user_name) != NULL) && (spw_remove (user_name) == 0)) { fprintf (stderr, _("%s: cannot remove entry '%s' from %s\n"), Prog, user_name, spw_dbname ()); fail_exit (E_PW_UPDATE); } #ifdef ENABLE_SUBIDS if (is_sub_uid && sub_uid_remove(user_name, 0, ULONG_MAX) == 0) { fprintf (stderr, _("%s: cannot remove entry %lu from %s\n"), Prog, (unsigned long)user_id, sub_uid_dbname ()); fail_exit (E_SUB_UID_UPDATE); } if (is_sub_gid && sub_gid_remove(user_name, 0, ULONG_MAX) == 0) { fprintf (stderr, _("%s: cannot remove entry %lu from %s\n"), Prog, (unsigned long)user_id, sub_gid_dbname ()); fail_exit (E_SUB_GID_UPDATE); } #endif /* ENABLE_SUBIDS */ #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "deleting user entries", user_name, (unsigned int) user_id, SHADOW_AUDIT_SUCCESS); #endif /* WITH_AUDIT */ SYSLOG ((LOG_INFO, "delete user '%s'\n", user_name)); }
/* * update_user - delete the user entries * * update_user() deletes the password file entries for this user * and will update the group entries as required. */ static void update_user (void) { if (pw_remove (user_name) == 0) { fprintf (stderr, _("%s: cannot remove entry '%s' from %s\n"), Prog, user_name, pw_dbname ()); fail_exit (E_PW_UPDATE); } if ( is_shadow_pwd && (spw_locate (user_name) != NULL) && (spw_remove (user_name) == 0)) { fprintf (stderr, _("%s: cannot remove entry '%s' from %s\n"), Prog, user_name, spw_dbname ()); fail_exit (E_PW_UPDATE); } #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "deleting user entries", user_name, (unsigned int) user_id, SHADOW_AUDIT_SUCCESS); #endif SYSLOG ((LOG_INFO, "delete user '%s'\n", user_name)); }
static void log_gpasswd_failure (const char *suffix) { #ifdef WITH_AUDIT char buf[1024]; #endif if (aflg) { SYSLOG ((LOG_ERR, "%s failed to add user %s to group %s%s", myname, user, group, suffix)); #ifdef WITH_AUDIT snprintf (buf, 1023, "%s failed to add user %s to group %s%s", myname, user, group, suffix); buf[1023] = '\0'; audit_logger (AUDIT_USER_ACCT, Prog, buf, group, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE); #endif } else if (dflg) { SYSLOG ((LOG_ERR, "%s failed to remove user %s from group %s%s", myname, user, group, suffix)); #ifdef WITH_AUDIT snprintf (buf, 1023, "%s failed to remove user %s from group %s%s", myname, user, group, suffix); buf[1023] = '\0'; audit_logger (AUDIT_USER_ACCT, Prog, buf, group, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE); #endif } else if (rflg) { SYSLOG ((LOG_ERR, "%s failed to remove password of group %s%s", myname, group, suffix)); #ifdef WITH_AUDIT snprintf (buf, 1023, "%s failed to remove password of group %s%s", myname, group, suffix); buf[1023] = '\0'; audit_logger (AUDIT_USER_CHAUTHTOK, Prog, buf, group, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE); #endif } else if (Rflg) { SYSLOG ((LOG_ERR, "%s failed to restrict access to group %s%s", myname, group, suffix)); #ifdef WITH_AUDIT snprintf (buf, 1023, "%s failed to restrict access to group %s%s", myname, group, suffix); buf[1023] = '\0'; audit_logger (AUDIT_USER_CHAUTHTOK, Prog, buf, group, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE); #endif } else if (Aflg || Mflg) { #ifdef SHADOWGRP if (Aflg) { SYSLOG ((LOG_ERR, "%s failed to set the administrators of group %s to %s%s", myname, group, admins, suffix)); #ifdef WITH_AUDIT snprintf (buf, 1023, "%s failed to set the administrators of group %s to %s%s", myname, group, admins, suffix); buf[1023] = '\0'; audit_logger (AUDIT_USER_ACCT, Prog, buf, group, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE); #endif } #endif /* SHADOWGRP */ if (Mflg) { SYSLOG ((LOG_ERR, "%s failed to set the members of group %s to %s%s", myname, group, members, suffix)); #ifdef WITH_AUDIT snprintf (buf, 1023, "%s failed to set the members of group %s to %s%s", myname, group, members, suffix); buf[1023] = '\0'; audit_logger (AUDIT_USER_ACCT, Prog, buf, group, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE); #endif } } else { SYSLOG ((LOG_ERR, "%s failed to change password of group %s%s", myname, group, suffix)); #ifdef WITH_AUDIT snprintf (buf, 1023, "%s failed to change password of group %s%s", myname, group, suffix); buf[1023] = '\0'; audit_logger (AUDIT_USER_CHAUTHTOK, Prog, buf, group, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE); #endif } }
int main (int argc, char **argv) { const struct spwd *sp; uid_t ruid; gid_t rgid; const struct passwd *pw; /* * Get the program name so that error messages can use it. */ Prog = Basename (argv[0]); sanitize_env (); (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); process_root_flag ("-R", argc, argv); #ifdef WITH_AUDIT audit_help_open (); #endif OPENLOG ("chage"); ruid = getuid (); rgid = getgid (); amroot = (ruid == 0); #ifdef WITH_SELINUX if (amroot && (is_selinux_enabled () > 0)) { amroot = (selinux_check_passwd_access (PASSWD__ROOTOK) == 0); } #endif process_flags (argc, argv); check_perms (); if (!spw_file_present ()) { fprintf (stderr, _("%s: the shadow password file is not present\n"), Prog); SYSLOG ((LOG_WARN, "can't find the shadow password file")); closelog (); exit (E_SHADOW_NOTFOUND); } open_files (lflg); /* Drop privileges */ if (lflg && ( (setregid (rgid, rgid) != 0) || (setreuid (ruid, ruid) != 0))) { fprintf (stderr, _("%s: failed to drop privileges (%s)\n"), Prog, strerror (errno)); fail_exit (E_NOPERM); } pw = pw_locate (argv[optind]); if (NULL == pw) { fprintf (stderr, _("%s: user '%s' does not exist in %s\n"), Prog, argv[optind], pw_dbname ()); closelog (); fail_exit (E_NOPERM); } STRFCPY (user_name, pw->pw_name); #ifdef WITH_TCB if (shadowtcb_set_user (pw->pw_name) == SHADOWTCB_FAILURE) { fail_exit (E_NOPERM); } #endif user_uid = pw->pw_uid; sp = spw_locate (argv[optind]); get_defaults (sp); /* * Print out the expiration fields if the user has requested the * list option. */ if (lflg) { if (!amroot && (ruid != user_uid)) { fprintf (stderr, _("%s: Permission denied.\n"), Prog); fail_exit (E_NOPERM); } #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "display aging info", user_name, (unsigned int) user_uid, 1); #endif list_fields (); fail_exit (E_SUCCESS); } /* * If none of the fields were changed from the command line, let the * user interactively change them. */ if (!mflg && !Mflg && !dflg && !Wflg && !Iflg && !Eflg) { printf (_("Changing the aging information for %s\n"), user_name); if (new_fields () == 0) { fprintf (stderr, _("%s: error changing fields\n"), Prog); fail_exit (E_NOPERM); } #ifdef WITH_AUDIT else { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change all aging information", user_name, (unsigned int) user_uid, 1); } #endif } else { #ifdef WITH_AUDIT if (Mflg) { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change max age", user_name, (unsigned int) user_uid, 1); } if (mflg) { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change min age", user_name, (unsigned int) user_uid, 1); } if (dflg) { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change last change date", user_name, (unsigned int) user_uid, 1); } if (Wflg) { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change passwd warning", user_name, (unsigned int) user_uid, 1); } if (Iflg) { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change inactive days", user_name, (unsigned int) user_uid, 1); } if (Eflg) { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "change passwd expiration", user_name, (unsigned int) user_uid, 1); } #endif } update_age (sp, pw); close_files (); SYSLOG ((LOG_INFO, "changed password expiry for %s", user_name)); closelog (); exit (E_SUCCESS); }
/* * update_groups - delete user from secondary group set * * update_groups() takes the user name that was given and searches * the group files for membership in any group. * * we also check to see if they have any groups they own (the same * name is their user name) and delete them too (only if USERGROUPS_ENAB * is enabled). */ static void update_groups (void) { const struct group *grp; struct group *ngrp; #ifdef SHADOWGRP const struct sgrp *sgrp; struct sgrp *nsgrp; #endif /* SHADOWGRP */ /* * Scan through the entire group file looking for the groups that * the user is a member of. */ for (gr_rewind (), grp = gr_next (); NULL != grp; grp = gr_next ()) { /* * See if the user specified this group as one of their * concurrent groups. */ if (!is_on_list (grp->gr_mem, user_name)) { continue; } /* * Delete the username from the list of group members and * update the group entry to reflect the change. */ ngrp = __gr_dup (grp); if (NULL == ngrp) { fprintf (stderr, _("%s: Out of memory. Cannot update %s.\n"), Prog, gr_dbname ()); exit (13); /* XXX */ } ngrp->gr_mem = del_list (ngrp->gr_mem, user_name); if (gr_update (ngrp) == 0) { fprintf (stderr, _("%s: failed to prepare the new %s entry '%s'\n"), Prog, gr_dbname (), ngrp->gr_name); exit (E_GRP_UPDATE); } /* * Update the DBM group file with the new entry as well. */ #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "deleting user from group", user_name, (unsigned int) user_id, SHADOW_AUDIT_SUCCESS); #endif /* WITH_AUDIT */ SYSLOG ((LOG_INFO, "delete '%s' from group '%s'\n", user_name, ngrp->gr_name)); } if (getdef_bool ("USERGROUPS_ENAB")) { remove_usergroup (); } #ifdef SHADOWGRP if (!is_shadow_grp) { return; } /* * Scan through the entire shadow group file looking for the groups * that the user is a member of. Both the administrative list and * the ordinary membership list is checked. */ for (sgr_rewind (), sgrp = sgr_next (); NULL != sgrp; sgrp = sgr_next ()) { bool was_member, was_admin; /* * See if the user specified this group as one of their * concurrent groups. */ was_member = is_on_list (sgrp->sg_mem, user_name); was_admin = is_on_list (sgrp->sg_adm, user_name); if (!was_member && !was_admin) { continue; } nsgrp = __sgr_dup (sgrp); if (NULL == nsgrp) { fprintf (stderr, _("%s: Out of memory. Cannot update %s.\n"), Prog, sgr_dbname ()); exit (13); /* XXX */ } if (was_member) { nsgrp->sg_mem = del_list (nsgrp->sg_mem, user_name); } if (was_admin) { nsgrp->sg_adm = del_list (nsgrp->sg_adm, user_name); } if (sgr_update (nsgrp) == 0) { fprintf (stderr, _("%s: failed to prepare the new %s entry '%s'\n"), Prog, sgr_dbname (), nsgrp->sg_name); exit (E_GRP_UPDATE); } #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "deleting user from shadow group", user_name, (unsigned int) user_id, SHADOW_AUDIT_SUCCESS); #endif /* WITH_AUDIT */ SYSLOG ((LOG_INFO, "delete '%s' from shadow group '%s'\n", user_name, nsgrp->sg_name)); } #endif /* SHADOWGRP */ }
/* * process_flags - perform command line argument setting * * process_flags() interprets the command line arguments and sets the * values that the user will be created with accordingly. The values * are checked for sanity. */ static void process_flags (int argc, char **argv) { const struct group *grp; const struct passwd *pwd; const struct spwd *spwd = NULL; int anyflag = 0; int arg; if (argc == 1 || argv[argc - 1][0] == '-') usage (); if (!(pwd = getpwnam (argv[argc - 1]))) { fprintf (stderr, _("%s: user %s does not exist\n"), Prog, argv[argc - 1]); exit (E_NOTFOUND); } user_name = argv[argc - 1]; user_id = pwd->pw_uid; user_gid = pwd->pw_gid; user_comment = xstrdup (pwd->pw_gecos); user_home = xstrdup (pwd->pw_dir); user_shell = xstrdup (pwd->pw_shell); #ifdef WITH_AUDIT user_newname = user_name; user_newid = user_id; user_newgid = user_gid; user_newcomment = user_comment; user_newhome = user_home; user_newshell = user_shell; #endif #ifdef USE_NIS /* * Now make sure it isn't an NIS user. */ if (__ispwNIS ()) { char *nis_domain; char *nis_master; fprintf (stderr, _("%s: user %s is a NIS user\n"), Prog, user_name); if (!yp_get_default_domain (&nis_domain) && !yp_master (nis_domain, "passwd.byname", &nis_master)) { fprintf (stderr, _("%s: %s is the NIS master\n"), Prog, nis_master); } exit (E_NOTFOUND); } #endif if (is_shadow_pwd && (spwd = getspnam (user_name))) { user_expire = spwd->sp_expire; user_inactive = spwd->sp_inact; #ifdef WITH_AUDIT user_newexpire = user_expire; user_newinactive = user_inactive; #endif } { /* * Parse the command line options. */ int c; static struct option long_options[] = { {"append", required_argument, NULL, 'a'}, {"comment", required_argument, NULL, 'c'}, {"home", required_argument, NULL, 'd'}, {"expiredate", required_argument, NULL, 'e'}, {"inactive", required_argument, NULL, 'f'}, {"gid", required_argument, NULL, 'g'}, {"groups", required_argument, NULL, 'G'}, {"help", no_argument, NULL, 'h'}, {"login", required_argument, NULL, 'l'}, {"lock", no_argument, NULL, 'L'}, {"move-home", no_argument, NULL, 'm'}, {"non-unique", no_argument, NULL, 'o'}, {"password", required_argument, NULL, 'p'}, {"shell", required_argument, NULL, 's'}, {"uid", required_argument, NULL, 'u'}, {"unlock", no_argument, NULL, 'U'}, {NULL, 0, NULL, '\0'} }; while ((c = getopt_long (argc, argv, "ac:d:e:f:g:G:l:Lmop:s:u:U", long_options, NULL)) != -1) { switch (c) { case 'a': aflg++; break; case 'c': if (!VALID (optarg)) { fprintf (stderr, _("%s: invalid field `%s'\n"), Prog, optarg); exit (E_BAD_ARG); } #ifdef WITH_AUDIT user_newcomment = optarg; #else user_comment = optarg; #endif cflg++; break; case 'd': if (!VALID (optarg)) { fprintf (stderr, _("%s: invalid field `%s'\n"), Prog, optarg); exit (E_BAD_ARG); } dflg++; user_newhome = optarg; break; case 'e': if (*optarg) { #ifdef WITH_AUDIT user_newexpire = strtoday (optarg); if (user_newexpire == -1) { #else user_expire = strtoday (optarg); if (user_expire == -1) { #endif fprintf (stderr, _ ("%s: invalid date `%s'\n"), Prog, optarg); exit (E_BAD_ARG); } #ifdef WITH_AUDIT user_newexpire *= DAY / SCALE; #else user_expire *= DAY / SCALE; #endif } else #ifdef WITH_AUDIT user_newexpire = -1; #else user_expire = -1; #endif eflg++; break; case 'f': #ifdef WITH_AUDIT user_newinactive = get_number (optarg); #else user_inactive = get_number (optarg); #endif fflg++; break; case 'g': grp = getgr_nam_gid (optarg); if (!grp) { fprintf (stderr, _("%s: unknown group %s\n"), Prog, optarg); exit (E_NOTFOUND); } user_newgid = grp->gr_gid; gflg++; break; case 'G': if (get_groups (optarg)) exit (E_NOTFOUND); Gflg++; break; case 'l': if (!check_user_name (optarg)) { fprintf (stderr, _("%s: invalid field `%s'\n"), Prog, optarg); exit (E_BAD_ARG); } /* * If the name does not really change, we mustn't * set the flag as this will cause rather serious * problems later! */ if (strcmp (user_name, optarg)) lflg++; user_newname = optarg; break; case 'L': if (Uflg || pflg) usage (); Lflg++; break; case 'm': if (!dflg) usage (); mflg++; break; case 'o': if (!uflg) usage (); oflg++; break; case 'p': if (Lflg || Uflg) usage (); user_pass = optarg; pflg++; break; case 's': if (!VALID (optarg)) { fprintf (stderr, _("%s: invalid field `%s'\n"), Prog, optarg); exit (E_BAD_ARG); } #ifdef WITH_AUDIT user_newshell = optarg; #else user_shell = optarg; #endif sflg++; break; case 'u': user_newid = get_id (optarg); uflg++; break; case 'U': if (Lflg && pflg) usage (); Uflg++; break; default: usage (); } anyflag++; } } if (anyflag == 0) { fprintf (stderr, _("%s: no flags given\n"), Prog); exit (E_USAGE); } if (!is_shadow_pwd && (eflg || fflg)) { fprintf (stderr, _ ("%s: shadow passwords required for -e and -f\n"), Prog); exit (E_USAGE); } if (optind != argc - 1) usage (); if (aflg && (!Gflg)) { fprintf (stderr, _("%s: -a flag is ONLY allowed with the -G flag\n"), Prog); usage (); exit (E_USAGE); } if (dflg && strcmp (user_home, user_newhome) == 0) dflg = mflg = 0; if (uflg && user_id == user_newid) uflg = oflg = 0; if (lflg && getpwnam (user_newname)) { fprintf (stderr, _("%s: user %s exists\n"), Prog, user_newname); exit (E_NAME_IN_USE); } if (uflg && !oflg && getpwuid (user_newid)) { fprintf (stderr, _("%s: uid %lu is not unique\n"), Prog, (unsigned long) user_newid); exit (E_UID_IN_USE); } } /* * close_files - close all of the files that were opened * * close_files() closes all of the files that were opened for this new * user. This causes any modified entries to be written out. */ static void close_files (void) { if (!pw_close ()) { fprintf (stderr, _("%s: cannot rewrite password file\n"), Prog); fail_exit (E_PW_UPDATE); } if (is_shadow_pwd && !spw_close ()) { fprintf (stderr, _("%s: cannot rewrite shadow password file\n"), Prog); fail_exit (E_PW_UPDATE); } if (is_shadow_pwd) spw_unlock (); (void) pw_unlock (); /* * Close the DBM and/or flat files */ endpwent (); endspent (); endgrent (); #ifdef SHADOWGRP endsgent (); #endif } /* * open_files - lock and open the password files * * open_files() opens the two password files. */ static void open_files (void) { if (!pw_lock ()) { fprintf (stderr, _("%s: unable to lock password file\n"), Prog); exit (E_PW_UPDATE); } if (!pw_open (O_RDWR)) { fprintf (stderr, _("%s: unable to open password file\n"), Prog); fail_exit (E_PW_UPDATE); } if (is_shadow_pwd && !spw_lock ()) { fprintf (stderr, _("%s: cannot lock shadow password file\n"), Prog); fail_exit (E_PW_UPDATE); } if (is_shadow_pwd && !spw_open (O_RDWR)) { fprintf (stderr, _("%s: cannot open shadow password file\n"), Prog); fail_exit (E_PW_UPDATE); } } /* * usr_update - create the user entries * * usr_update() creates the password file entries for this user and * will update the group entries if required. */ static void usr_update (void) { struct passwd pwent; const struct passwd *pwd; struct spwd spent; const struct spwd *spwd = NULL; /* * Locate the entry in /etc/passwd, which MUST exist. */ pwd = pw_locate (user_name); if (!pwd) { fprintf (stderr, _("%s: %s not found in /etc/passwd\n"), Prog, user_name); fail_exit (E_NOTFOUND); } pwent = *pwd; new_pwent (&pwent); /* * Locate the entry in /etc/shadow. It doesn't have to exist, and * won't be created if it doesn't. */ if (is_shadow_pwd && (spwd = spw_locate (user_name))) { spent = *spwd; new_spent (&spent); } if (lflg || uflg || gflg || cflg || dflg || sflg || pflg || Lflg || Uflg) { if (!pw_update (&pwent)) { fprintf (stderr, _("%s: error changing password entry\n"), Prog); fail_exit (E_PW_UPDATE); } if (lflg && !pw_remove (user_name)) { fprintf (stderr, _("%s: error removing password entry\n"), Prog); fail_exit (E_PW_UPDATE); } } if (spwd && (lflg || eflg || fflg || pflg || Lflg || Uflg)) { if (!spw_update (&spent)) { fprintf (stderr, _ ("%s: error adding new shadow password entry\n"), Prog); fail_exit (E_PW_UPDATE); } if (lflg && !spw_remove (user_name)) { fprintf (stderr, _ ("%s: error removing shadow password entry\n"), Prog); fail_exit (E_PW_UPDATE); } } } /* * move_home - move the user's home directory * * move_home() moves the user's home directory to a new location. The * files will be copied if the directory cannot simply be renamed. */ static void move_home (void) { struct stat sb; if (mflg && stat (user_home, &sb) == 0) { /* * Don't try to move it if it is not a directory * (but /dev/null for example). --marekm */ if (!S_ISDIR (sb.st_mode)) return; if (access (user_newhome, F_OK) == 0) { fprintf (stderr, _("%s: directory %s exists\n"), Prog, user_newhome); fail_exit (E_HOMEDIR); } else if (rename (user_home, user_newhome)) { if (errno == EXDEV) { if (mkdir (user_newhome, sb.st_mode & 0777)) { fprintf (stderr, _ ("%s: can't create %s\n"), Prog, user_newhome); } if (chown (user_newhome, sb.st_uid, sb.st_gid)) { fprintf (stderr, _("%s: can't chown %s\n"), Prog, user_newhome); rmdir (user_newhome); fail_exit (E_HOMEDIR); } if (copy_tree (user_home, user_newhome, uflg ? user_newid : -1, gflg ? user_newgid : -1) == 0) { if (remove_tree (user_home) != 0 || rmdir (user_home) != 0) fprintf (stderr, _ ("%s: warning: failed to completely remove old home directory %s"), Prog, user_home); #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "moving home directory", user_newname, user_newid, 1); #endif return; } (void) remove_tree (user_newhome); (void) rmdir (user_newhome); } fprintf (stderr, _ ("%s: cannot rename directory %s to %s\n"), Prog, user_home, user_newhome); fail_exit (E_HOMEDIR); } #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "moving home directory", user_newname, user_newid, 1); #endif } if (uflg || gflg) { #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing home directory owner", user_newname, user_newid, 1); #endif chown (dflg ? user_newhome : user_home, uflg ? user_newid : user_id, gflg ? user_newgid : user_gid); } } /* * update_files - update the lastlog and faillog files */ static void update_files (void) { struct lastlog ll; struct faillog fl; int fd; /* * Relocate the "lastlog" entries for the user. The old entry is * left alone in case the UID was shared. It doesn't hurt anything * to just leave it be. */ if ((fd = open (LASTLOG_FILE, O_RDWR)) != -1) { lseek (fd, (off_t) user_id * sizeof ll, SEEK_SET); if (read (fd, (char *) &ll, sizeof ll) == sizeof ll) { lseek (fd, (off_t) user_newid * sizeof ll, SEEK_SET); write (fd, (char *) &ll, sizeof ll); } close (fd); } /* * Relocate the "faillog" entries in the same manner. */ if ((fd = open (FAILLOG_FILE, O_RDWR)) != -1) { lseek (fd, (off_t) user_id * sizeof fl, SEEK_SET); if (read (fd, (char *) &fl, sizeof fl) == sizeof fl) { lseek (fd, (off_t) user_newid * sizeof fl, SEEK_SET); write (fd, (char *) &fl, sizeof fl); } close (fd); } } #ifndef NO_MOVE_MAILBOX /* * This is the new and improved code to carefully chown/rename the user's * mailbox. Maybe I am too paranoid but the mail spool dir sometimes * happens to be mode 1777 (this makes mail user agents work without * being setgid mail, but is NOT recommended; they all should be fixed * to use movemail). --marekm */ static void move_mailbox (void) { const char *maildir; char mailfile[1024], newmailfile[1024]; int fd; struct stat st; maildir = getdef_str ("MAIL_DIR"); #ifdef MAIL_SPOOL_DIR if (!maildir && !getdef_str ("MAIL_FILE")) maildir = MAIL_SPOOL_DIR; #endif if (!maildir) return; /* * O_NONBLOCK is to make sure open won't hang on mandatory locks. * We do fstat/fchown to make sure there are no races (someone * replacing /var/spool/mail/luser with a hard link to /etc/passwd * between stat and chown). --marekm */ snprintf (mailfile, sizeof mailfile, "%s/%s", maildir, user_name); fd = open (mailfile, O_RDONLY | O_NONBLOCK, 0); if (fd < 0) { /* no need for warnings if the mailbox doesn't exist */ if (errno != ENOENT) perror (mailfile); return; } if (fstat (fd, &st) < 0) { perror ("fstat"); close (fd); return; } if (st.st_uid != user_id) { /* better leave it alone */ fprintf (stderr, _("%s: warning: %s not owned by %s\n"), Prog, mailfile, user_name); close (fd); return; } if (uflg) { if (fchown (fd, user_newid, (gid_t) - 1) < 0) { perror (_("failed to change mailbox owner")); } #ifdef WITH_AUDIT else { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing mail file owner", user_newname, user_newid, 1); } #endif } close (fd); if (lflg) { snprintf (newmailfile, sizeof newmailfile, "%s/%s", maildir, user_newname); if (link (mailfile, newmailfile) || unlink (mailfile)) { perror (_("failed to rename mailbox")); } #ifdef WITH_AUDIT else { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing mail file name", user_newname, user_newid, 1); } #endif } } #endif /* * main - usermod command */ int main (int argc, char **argv) { int grp_err = 0; #ifdef USE_PAM pam_handle_t *pamh = NULL; struct passwd *pampw; int retval; #endif #ifdef WITH_AUDIT audit_help_open (); #endif /* * Get my name so that I can use it to report errors. */ Prog = Basename (argv[0]); setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); sys_ngroups = sysconf (_SC_NGROUPS_MAX); user_groups = malloc ((1 + sys_ngroups) * sizeof (char *)); user_groups[0] = (char *) 0; OPENLOG ("usermod"); is_shadow_pwd = spw_file_present (); #ifdef SHADOWGRP is_shadow_grp = sgr_file_present (); #endif process_flags (argc, argv); #ifdef USE_PAM retval = PAM_SUCCESS; pampw = getpwuid (getuid ()); if (pampw == NULL) { retval = PAM_USER_UNKNOWN; } if (retval == PAM_SUCCESS) { retval = pam_start ("usermod", pampw->pw_name, &conv, &pamh); } if (retval == PAM_SUCCESS) { retval = pam_authenticate (pamh, 0); if (retval != PAM_SUCCESS) { pam_end (pamh, retval); } } if (retval == PAM_SUCCESS) { retval = pam_acct_mgmt (pamh, 0); if (retval != PAM_SUCCESS) { pam_end (pamh, retval); } } if (retval != PAM_SUCCESS) { fprintf (stderr, _("%s: PAM authentication failed\n"), Prog); exit (1); } #endif /* USE_PAM */ /* * Do the hard stuff - open the files, change the user entries, * change the home directory, then close and update the files. */ open_files (); usr_update (); nscd_flush_cache ("passwd"); nscd_flush_cache ("group"); close_files (); if (Gflg || lflg) grp_err = grp_update (); if (mflg) move_home (); #ifndef NO_MOVE_MAILBOX if (lflg || uflg) move_mailbox (); #endif if (uflg) { update_files (); /* * Change the UID on all of the files owned by `user_id' to * `user_newid' in the user's home directory. */ chown_tree (dflg ? user_newhome : user_home, user_id, user_newid, user_gid, gflg ? user_newgid : user_gid); } if (grp_err) exit (E_GRP_UPDATE); #ifdef USE_PAM if (retval == PAM_SUCCESS) pam_end (pamh, PAM_SUCCESS); #endif /* USE_PAM */ exit (E_SUCCESS); /* NOT REACHED */ }
static int update_gshadow (void) { int is_member; int was_member; int was_admin; int changed; const struct sgrp *sgrp; struct sgrp *nsgrp; if (!sgr_lock ()) { fprintf (stderr, _("%s: error locking shadow group file\n"), Prog); SYSLOG ((LOG_ERR, "error locking shadow group file")); return -1; } if (!sgr_open (O_RDWR)) { fprintf (stderr, _("%s: error opening shadow group file\n"), Prog); SYSLOG ((LOG_ERR, "error opening shadow group file")); sgr_unlock (); return -1; } changed = 0; /* * Scan through the entire shadow group file looking for the groups * that the user is a member of. */ while ((sgrp = sgr_next ())) { /* * See if the user was a member of this group */ was_member = is_on_list (sgrp->sg_mem, user_name); /* * See if the user was an administrator of this group */ was_admin = is_on_list (sgrp->sg_adm, user_name); /* * See if the user specified this group as one of their * concurrent groups. */ is_member = Gflg && is_on_list (user_groups, sgrp->sg_name); if (!was_member && !was_admin && !is_member) continue; nsgrp = __sgr_dup (sgrp); if (!nsgrp) { fprintf (stderr, _ ("%s: out of memory in update_gshadow\n"), Prog); sgr_unlock (); return -1; } if (was_admin && lflg) { nsgrp->sg_adm = del_list (nsgrp->sg_adm, user_name); nsgrp->sg_adm = add_list (nsgrp->sg_adm, user_newname); changed = 1; #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing admin name in shadow group", user_name, -1, 1); #endif SYSLOG ((LOG_INFO, "change admin `%s' to `%s' in shadow group `%s'", user_name, user_newname, nsgrp->sg_name)); } if (was_member && (!Gflg || is_member)) { if (lflg) { nsgrp->sg_mem = del_list (nsgrp->sg_mem, user_name); nsgrp->sg_mem = add_list (nsgrp->sg_mem, user_newname); changed = 1; #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing member in shadow group", user_name, -1, 1); #endif SYSLOG ((LOG_INFO, "change `%s' to `%s' in shadow group `%s'", user_name, user_newname, nsgrp->sg_name)); } } else if (was_member && !aflg && Gflg && !is_member) { nsgrp->sg_mem = del_list (nsgrp->sg_mem, user_name); changed = 1; #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "removing user from shadow group", user_name, -1, 1); #endif SYSLOG ((LOG_INFO, "delete `%s' from shadow group `%s'", user_name, nsgrp->sg_name)); } else if (!was_member && Gflg && is_member) { nsgrp->sg_mem = add_list (nsgrp->sg_mem, lflg ? user_newname : user_name); changed = 1; #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "adding user to shadow group", user_newname, -1, 1); #endif SYSLOG ((LOG_INFO, "add `%s' to shadow group `%s'", lflg ? user_newname : user_name, nsgrp->sg_name)); } if (!changed) continue; changed = 0; /* * Update the group entry to reflect the changes. */ if (!sgr_update (nsgrp)) { fprintf (stderr, _("%s: error adding new group entry\n"), Prog); SYSLOG ((LOG_ERR, "error adding shadow group entry")); sgr_unlock (); return -1; } } if (!sgr_close ()) { fprintf (stderr, _("%s: cannot rewrite shadow group file\n"), Prog); sgr_unlock (); return -1; } sgr_unlock (); return 0; }
static int update_group (void) { int is_member; int was_member; int changed; const struct group *grp; struct group *ngrp; /* * Lock and open the group file. This will load all of the group * entries. */ if (!gr_lock ()) { fprintf (stderr, _("%s: error locking group file\n"), Prog); SYSLOG ((LOG_ERR, "error locking group file")); return -1; } if (!gr_open (O_RDWR)) { fprintf (stderr, _("%s: error opening group file\n"), Prog); SYSLOG ((LOG_ERR, "error opening group file")); gr_unlock (); return -1; } changed = 0; /* * Scan through the entire group file looking for the groups that * the user is a member of. */ while ((grp = gr_next ())) { /* * See if the user specified this group as one of their * concurrent groups. */ was_member = is_on_list (grp->gr_mem, user_name); is_member = Gflg && is_on_list (user_groups, grp->gr_name); if (!was_member && !is_member) continue; ngrp = __gr_dup (grp); if (!ngrp) { fprintf (stderr, _("%s: out of memory in update_group\n"), Prog); gr_unlock (); return -1; } if (was_member && (!Gflg || is_member)) { if (lflg) { ngrp->gr_mem = del_list (ngrp->gr_mem, user_name); ngrp->gr_mem = add_list (ngrp->gr_mem, user_newname); changed = 1; #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing group member", user_newname, -1, 1); #endif SYSLOG ((LOG_INFO, "change `%s' to `%s' in group `%s'", user_name, user_newname, ngrp->gr_name)); } } else if (was_member && !aflg && Gflg && !is_member) { ngrp->gr_mem = del_list (ngrp->gr_mem, user_name); changed = 1; #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "removing group member", user_name, -1, 1); #endif SYSLOG ((LOG_INFO, "delete `%s' from group `%s'", user_name, ngrp->gr_name)); } else if (!was_member && Gflg && is_member) { ngrp->gr_mem = add_list (ngrp->gr_mem, lflg ? user_newname : user_name); changed = 1; #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "adding user to group", user_name, -1, 1); #endif SYSLOG ((LOG_INFO, "add `%s' to group `%s'", lflg ? user_newname : user_name, ngrp->gr_name)); } if (!changed) continue; changed = 0; if (!gr_update (ngrp)) { fprintf (stderr, _("%s: error adding new group entry\n"), Prog); SYSLOG ((LOG_ERR, "error adding group entry")); gr_unlock (); return -1; } } if (!gr_close ()) { fprintf (stderr, _("%s: cannot rewrite group file\n"), Prog); gr_unlock (); return -1; } gr_unlock (); return 0; }
/* * new_spent - initialize the values in a shadow password file entry * * new_spent() takes all of the values that have been entered and fills * in a (struct spwd) with them. */ static void new_spent (struct spwd *spent) { if (lflg) spent->sp_namp = xstrdup (user_newname); if (fflg) { #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing inactive days", user_newname, user_newid, 1); SYSLOG ((LOG_INFO, "change user `%s' inactive from `%ld' to `%ld'", spent->sp_namp, spent->sp_inact, user_newinactive)); spent->sp_inact = user_newinactive; #else SYSLOG ((LOG_INFO, "change user `%s' inactive from `%ld' to `%ld'", spent->sp_namp, spent->sp_inact, user_inactive)); spent->sp_inact = user_inactive; #endif } if (eflg) { /* XXX - dates might be better than numbers of days. --marekm */ #ifdef WITH_AUDIT if (audit_fd >= 0) { time_t exp_t; struct tm *exp_tm; char new_exp[16], old_exp[16]; if (user_newexpire == -1) new_exp[0] = '\0'; else { exp_t = user_newexpire * DAY; exp_tm = gmtime (&exp_t); #ifdef HAVE_STRFTIME strftime (new_exp, sizeof (new_exp), "%Y-%m-%d", exp_tm); #else memset (new_exp, 0, sizeof (new_exp)); snprintf (new_exp, sizeof (new_exp) - 1, "%04i-%02i-%02i", exp_tm->tm_year + 1900, exp_tm->tm_mon + 1, exp_tm->tm_mday); #endif } if (user_expire == -1) old_exp[0] = '\0'; else { exp_t = user_expire * DAY; exp_tm = gmtime (&exp_t); #ifdef HAVE_STRFTIME strftime (old_exp, sizeof (old_exp), "%Y-%m-%d", exp_tm); #else memset (old_exp, 0, sizeof (old_exp)); snprintf (old_exp, sizeof (old_exp) - 1, "%04i-%02i-%02i", exp_tm->tm_year + 1900, exp_tm->tm_mon + 1, exp_tm->tm_mday); #endif } audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing expiration date", user_newname, user_newid, 1); } SYSLOG ((LOG_INFO, "change user `%s' expiration from `%ld' to `%ld'", spent->sp_namp, spent->sp_expire, user_newexpire)); spent->sp_expire = user_newexpire; #else SYSLOG ((LOG_INFO, "change user `%s' expiration from `%ld' to `%ld'", spent->sp_namp, spent->sp_expire, user_expire)); spent->sp_expire = user_expire; #endif } spent->sp_pwdp = new_pw_passwd (spent->sp_pwdp, spent->sp_namp); if (pflg) spent->sp_lstchg = time ((time_t *) 0) / SCALE; }
/* * new_pwent - initialize the values in a password file entry * * new_pwent() takes all of the values that have been entered and fills * in a (struct passwd) with them. */ static void new_pwent (struct passwd *pwent) { if (lflg) { #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing name", user_newname, user_newid, 1); #endif SYSLOG ((LOG_INFO, "change user name `%s' to `%s'", pwent->pw_name, user_newname)); pwent->pw_name = xstrdup (user_newname); } if (!is_shadow_pwd) pwent->pw_passwd = new_pw_passwd (pwent->pw_passwd, pwent->pw_name); if (uflg) { #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing uid", user_newname, user_newid, 1); #endif SYSLOG ((LOG_INFO, "change user `%s' UID from `%d' to `%d'", pwent->pw_name, pwent->pw_uid, user_newid)); pwent->pw_uid = user_newid; } if (gflg) { #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing primary group", user_newname, user_newid, 1); #endif SYSLOG ((LOG_INFO, "change user `%s' GID from `%d' to `%d'", pwent->pw_name, pwent->pw_gid, user_newgid)); pwent->pw_gid = user_newgid; } if (cflg) { #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing comment", user_newname, user_newid, 1); pwent->pw_gecos = user_newcomment; #else pwent->pw_gecos = user_comment; #endif } if (dflg) { #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing home directory", user_newname, user_newid, 1); #endif SYSLOG ((LOG_INFO, "change user `%s' home from `%s' to `%s'", pwent->pw_name, pwent->pw_dir, user_newhome)); pwent->pw_dir = user_newhome; } if (sflg) { #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing user shell", user_newname, user_newid, 1); SYSLOG ((LOG_INFO, "change user `%s' shell from `%s' to `%s'", pwent->pw_name, pwent->pw_shell, user_newshell)); pwent->pw_shell = user_newshell; #else SYSLOG ((LOG_INFO, "change user `%s' shell from `%s' to `%s'", pwent->pw_name, pwent->pw_shell, user_shell)); pwent->pw_shell = user_shell; #endif } }
/* * close_files - close all of the files that were opened * * close_files() closes all of the files that were opened for this new * group. This causes any modified entries to be written out. */ static void close_files (void) { if (gr_close () == 0) { fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, gr_dbname ()); exit (E_GRP_UPDATE); } #ifdef WITH_AUDIT audit_logger (AUDIT_USER_ACCT, Prog, info_group.audit_msg, group_name, AUDIT_NO_ID, SHADOW_AUDIT_SUCCESS); #endif SYSLOG ((LOG_INFO, "group changed in %s (%s)", gr_dbname (), info_group.action)); del_cleanup (cleanup_report_mod_group); cleanup_unlock_group (NULL); del_cleanup (cleanup_unlock_group); #ifdef SHADOWGRP if ( is_shadow_grp && (pflg || nflg)) { if (sgr_close () == 0) { fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, sgr_dbname ()); exit (E_GRP_UPDATE); } #ifdef WITH_AUDIT audit_logger (AUDIT_USER_ACCT, Prog, info_gshadow.audit_msg, group_name, AUDIT_NO_ID, SHADOW_AUDIT_SUCCESS); #endif SYSLOG ((LOG_INFO, "group changed in %s (%s)", sgr_dbname (), info_gshadow.action)); del_cleanup (cleanup_report_mod_gshadow); cleanup_unlock_gshadow (NULL); del_cleanup (cleanup_unlock_gshadow); } #endif /* SHADOWGRP */ if (gflg) { if (pw_close () == 0) { fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, pw_dbname ()); exit (E_GRP_UPDATE); } #ifdef WITH_AUDIT audit_logger (AUDIT_USER_ACCT, Prog, info_passwd.audit_msg, group_name, AUDIT_NO_ID, SHADOW_AUDIT_SUCCESS); #endif SYSLOG ((LOG_INFO, "group changed in %s (%s)", pw_dbname (), info_passwd.action)); del_cleanup (cleanup_report_mod_passwd); cleanup_unlock_passwd (NULL); del_cleanup (cleanup_unlock_passwd); } #ifdef WITH_AUDIT audit_logger (AUDIT_USER_ACCT, Prog, "modifying group", group_name, AUDIT_NO_ID, SHADOW_AUDIT_SUCCESS); #endif }
/* * remove_usergroup - delete the user's group if it is a usergroup * * An usergroup is removed if * + it has the same name as the user * + it is the primary group of the user * + it has no other members * + it is not the primary group of any other user */ static void remove_usergroup (void) { const struct group *grp; const struct passwd *pwd = NULL; grp = gr_locate (user_name); if (NULL == grp) { /* This user has no usergroup. */ return; } if (grp->gr_gid != user_gid) { fprintf (stderr, _("%s: group %s not removed because it is not the primary group of user %s.\n"), Prog, grp->gr_name, user_name); return; } if (NULL != grp->gr_mem[0]) { /* The usergroup has other members. */ fprintf (stderr, _("%s: group %s not removed because it has other members.\n"), Prog, grp->gr_name); return; } if (!fflg) { /* * Scan the passwd file to check if this group is still * used as a primary group. */ setpwent (); while ((pwd = getpwent ()) != NULL) { if (strcmp (pwd->pw_name, user_name) == 0) { continue; } if (pwd->pw_gid == grp->gr_gid) { fprintf (stderr, _("%s: group %s is the primary group of another user and is not removed.\n"), Prog, grp->gr_name); break; } } endpwent (); } if (NULL == pwd) { /* * We can remove this group, it is not the primary * group of any remaining user. */ if (gr_remove (user_name) == 0) { fprintf (stderr, _("%s: cannot remove entry '%s' from %s\n"), Prog, user_name, gr_dbname ()); fail_exit (E_GRP_UPDATE); } #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_GROUP, Prog, "deleting group", user_name, AUDIT_NO_ID, SHADOW_AUDIT_SUCCESS); #endif /* WITH_AUDIT */ SYSLOG ((LOG_INFO, "removed group '%s' owned by '%s'\n", user_name, user_name)); #ifdef SHADOWGRP if (sgr_locate (user_name) != NULL) { if (sgr_remove (user_name) == 0) { fprintf (stderr, _("%s: cannot remove entry '%s' from %s\n"), Prog, user_name, sgr_dbname ()); fail_exit (E_GRP_UPDATE); } #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_GROUP, Prog, "deleting shadow group", user_name, AUDIT_NO_ID, SHADOW_AUDIT_SUCCESS); #endif /* WITH_AUDIT */ SYSLOG ((LOG_INFO, "removed shadow group '%s' owned by '%s'\n", user_name, user_name)); } #endif /* SHADOWGRP */ } }
/* * main - userdel command */ int main (int argc, char **argv) { int errors = 0; /* Error in the removal of the home directory */ #ifdef ACCT_TOOLS_SETUID #ifdef USE_PAM pam_handle_t *pamh = NULL; int retval; #endif /* USE_PAM */ #endif /* ACCT_TOOLS_SETUID */ /* * Get my name so that I can use it to report errors. */ Prog = Basename (argv[0]); (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); process_root_flag ("-R", argc, argv); OPENLOG ("userdel"); #ifdef WITH_AUDIT audit_help_open (); #endif /* WITH_AUDIT */ { /* * Parse the command line options. */ int c; static struct option long_options[] = { {"force", no_argument, NULL, 'f'}, {"help", no_argument, NULL, 'h'}, {"remove", no_argument, NULL, 'r'}, {"root", required_argument, NULL, 'R'}, #ifdef WITH_SELINUX {"selinux-user", no_argument, NULL, 'Z'}, #endif /* WITH_SELINUX */ {NULL, 0, NULL, '\0'} }; while ((c = getopt_long (argc, argv, #ifdef WITH_SELINUX "fhrR:Z", #else /* !WITH_SELINUX */ "fhrR:", #endif /* !WITH_SELINUX */ long_options, NULL)) != -1) { switch (c) { case 'f': /* force remove even if not owned by user */ fflg = true; break; case 'h': usage (E_SUCCESS); break; case 'r': /* remove home dir and mailbox */ rflg = true; break; case 'R': /* no-op, handled in process_root_flag () */ break; #ifdef WITH_SELINUX case 'Z': if (is_selinux_enabled () > 0) { Zflg = true; } else { fprintf (stderr, _("%s: -Z requires SELinux enabled kernel\n"), Prog); exit (E_BAD_ARG); } break; #endif /* WITH_SELINUX */ default: usage (E_USAGE); } } } if ((optind + 1) != argc) { usage (E_USAGE); } #ifdef ACCT_TOOLS_SETUID #ifdef USE_PAM { struct passwd *pampw; pampw = getpwuid (getuid ()); /* local, no need for xgetpwuid */ if (pampw == NULL) { fprintf (stderr, _("%s: Cannot determine your user name.\n"), Prog); exit (E_PW_UPDATE); } retval = pam_start ("userdel", pampw->pw_name, &conv, &pamh); } if (PAM_SUCCESS == retval) { retval = pam_authenticate (pamh, 0); } if (PAM_SUCCESS == retval) { retval = pam_acct_mgmt (pamh, 0); } if (PAM_SUCCESS != retval) { fprintf (stderr, _("%s: PAM: %s\n"), Prog, pam_strerror (pamh, retval)); SYSLOG((LOG_ERR, "%s", pam_strerror (pamh, retval))); if (NULL != pamh) { (void) pam_end (pamh, retval); } exit (E_PW_UPDATE); } (void) pam_end (pamh, retval); #endif /* USE_PAM */ #endif /* ACCT_TOOLS_SETUID */ is_shadow_pwd = spw_file_present (); #ifdef SHADOWGRP is_shadow_grp = sgr_file_present (); #endif /* SHADOWGRP */ #ifdef ENABLE_SUBIDS is_sub_uid = sub_uid_file_present (); is_sub_gid = sub_gid_file_present (); #endif /* ENABLE_SUBIDS */ /* * Start with a quick check to see if the user exists. */ user_name = argv[argc - 1]; { struct passwd *pwd; pwd = getpwnam (user_name); /* local, no need for xgetpwnam */ if (NULL == pwd) { fprintf (stderr, _("%s: user '%s' does not exist\n"), Prog, user_name); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "deleting user not found", user_name, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ exit (E_NOTFOUND); } user_id = pwd->pw_uid; user_gid = pwd->pw_gid; user_home = xstrdup (pwd->pw_dir); } #ifdef WITH_TCB if (shadowtcb_set_user (user_name) == SHADOWTCB_FAILURE) { exit (E_NOTFOUND); } #endif /* WITH_TCB */ #ifdef USE_NIS /* * Now make sure it isn't an NIS user. */ if (__ispwNIS ()) { char *nis_domain; char *nis_master; fprintf (stderr, _("%s: user %s is a NIS user\n"), Prog, user_name); if ( !yp_get_default_domain (&nis_domain) && !yp_master (nis_domain, "passwd.byname", &nis_master)) { fprintf (stderr, _("%s: %s is the NIS master\n"), Prog, nis_master); } exit (E_NOTFOUND); } #endif /* USE_NIS */ /* * Check to make certain the user isn't logged in. * Note: This is a best effort basis. The user may log in between, * a cron job may be started on her behalf, etc. */ if (user_busy (user_name, user_id) != 0) { if (!fflg) { #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "deleting user logged in", user_name, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ exit (E_USER_BUSY); } } /* * Do the hard stuff - open the files, create the user entries, * create the home directory, then close and update the files. */ open_files (); update_user (); update_groups (); if (rflg) { errors += remove_mailbox (); } if (rflg) { int home_owned = is_owner (user_id, user_home); if (-1 == home_owned) { fprintf (stderr, _("%s: %s home directory (%s) not found\n"), Prog, user_name, user_home); rflg = 0; } else if ((0 == home_owned) && !fflg) { fprintf (stderr, _("%s: %s not owned by %s, not removing\n"), Prog, user_home, user_name); rflg = 0; errors++; /* continue */ } } #ifdef EXTRA_CHECK_HOME_DIR /* This may be slow, the above should be good enough. */ if (rflg && !fflg) { struct passwd *pwd; /* * For safety, refuse to remove the home directory if it * would result in removing some other user's home * directory. Still not perfect so be careful, but should * prevent accidents if someone has /home or / as home * directory... --marekm */ setpwent (); while ((pwd = getpwent ())) { if (strcmp (pwd->pw_name, user_name) == 0) { continue; } if (path_prefix (user_home, pwd->pw_dir)) { fprintf (stderr, _("%s: not removing directory %s (would remove home of user %s)\n"), Prog, user_home, pwd->pw_name); rflg = false; errors++; /* continue */ break; } } endpwent (); } #endif /* EXTRA_CHECK_HOME_DIR */ if (rflg) { if (remove_tree (user_home, true) != 0) { fprintf (stderr, _("%s: error removing directory %s\n"), Prog, user_home); errors++; /* continue */ } #ifdef WITH_AUDIT else { audit_logger (AUDIT_DEL_USER, Prog, "deleting home directory", user_name, (unsigned int) user_id, SHADOW_AUDIT_SUCCESS); } #endif /* WITH_AUDIT */ } #ifdef WITH_AUDIT if (0 != errors) { audit_logger (AUDIT_DEL_USER, Prog, "deleting home directory", user_name, AUDIT_NO_ID, SHADOW_AUDIT_FAILURE); } #endif /* WITH_AUDIT */ #ifdef WITH_SELINUX if (Zflg) { if (del_seuser (user_name) != 0) { fprintf (stderr, _("%s: warning: the user name %s to SELinux user mapping removal failed.\n"), Prog, user_name); #ifdef WITH_AUDIT audit_logger (AUDIT_ADD_USER, Prog, "removing SELinux user mapping", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_SE_UPDATE); } } #endif /* WITH_SELINUX */ /* * Cancel any crontabs or at jobs. Have to do this before we remove * the entry from /etc/passwd. */ user_cancel (user_name); close_files (); #ifdef WITH_TCB errors += remove_tcbdir (user_name, user_id); #endif /* WITH_TCB */ nscd_flush_cache ("passwd"); nscd_flush_cache ("group"); return ((0 != errors) ? E_HOMEDIR : E_SUCCESS); }
static int remove_mailbox (void) { const char *maildir; char mailfile[1024]; int i; int errors = 0; maildir = getdef_str ("MAIL_DIR"); #ifdef MAIL_SPOOL_DIR if ((NULL == maildir) && (getdef_str ("MAIL_FILE") == NULL)) { maildir = MAIL_SPOOL_DIR; } #endif /* MAIL_SPOOL_DIR */ if (NULL == maildir) { return 0; } snprintf (mailfile, sizeof mailfile, "%s/%s", maildir, user_name); if (access (mailfile, F_OK) != 0) { if (ENOENT == errno) { fprintf (stderr, _("%s: %s mail spool (%s) not found\n"), Prog, user_name, mailfile); return 0; } else { fprintf (stderr, _("%s: warning: can't remove %s: %s\n"), Prog, mailfile, strerror (errno)); SYSLOG ((LOG_ERR, "Cannot remove %s: %s", mailfile, strerror (errno))); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "deleting mail file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ return -1; } } if (fflg) { if (unlink (mailfile) != 0) { fprintf (stderr, _("%s: warning: can't remove %s: %s\n"), Prog, mailfile, strerror (errno)); SYSLOG ((LOG_ERR, "Cannot remove %s: %s", mailfile, strerror (errno))); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "deleting mail file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ errors = 1; /* continue */ } #ifdef WITH_AUDIT else { audit_logger (AUDIT_DEL_USER, Prog, "deleting mail file", user_name, (unsigned int) user_id, SHADOW_AUDIT_SUCCESS); } #endif /* WITH_AUDIT */ return errors; } i = is_owner (user_id, mailfile); if (i == 0) { fprintf (stderr, _("%s: %s not owned by %s, not removing\n"), Prog, mailfile, user_name); SYSLOG ((LOG_ERR, "%s not owned by %s, not removed", mailfile, strerror (errno))); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "deleting mail file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ return 1; } else if (i == -1) { return 0; /* mailbox doesn't exist */ } if (unlink (mailfile) != 0) { fprintf (stderr, _("%s: warning: can't remove %s: %s\n"), Prog, mailfile, strerror (errno)); SYSLOG ((LOG_ERR, "Cannot remove %s: %s", mailfile, strerror (errno))); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "deleting mail file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ errors = 1; /* continue */ } #ifdef WITH_AUDIT else { audit_logger (AUDIT_DEL_USER, Prog, "deleting mail file", user_name, (unsigned int) user_id, SHADOW_AUDIT_SUCCESS); } #endif /* WITH_AUDIT */ return errors; }
static void log_gpasswd_success (const char *suffix) { #ifdef WITH_AUDIT char buf[1024]; #endif if (aflg) { SYSLOG ((LOG_INFO, "user %s added by %s to group %s%s", user, myname, group, suffix)); #ifdef WITH_AUDIT snprintf (buf, 1023, "user %s added by %s to group %s%s", user, myname, group, suffix); buf[1023] = '\0'; audit_logger (AUDIT_USER_ACCT, Prog, buf, group, AUDIT_NO_ID, SHADOW_AUDIT_SUCCESS); #endif } else if (dflg) { SYSLOG ((LOG_INFO, "user %s removed by %s from group %s%s", user, myname, group, suffix)); #ifdef WITH_AUDIT snprintf (buf, 1023, "user %s removed by %s from group %s%s", user, myname, group, suffix); buf[1023] = '\0'; audit_logger (AUDIT_USER_ACCT, Prog, buf, group, AUDIT_NO_ID, SHADOW_AUDIT_SUCCESS); #endif } else if (rflg) { SYSLOG ((LOG_INFO, "password of group %s removed by %s%s", group, myname, suffix)); #ifdef WITH_AUDIT snprintf (buf, 1023, "password of group %s removed by %s%s", group, myname, suffix); buf[1023] = '\0'; audit_logger (AUDIT_USER_CHAUTHTOK, Prog, buf, group, AUDIT_NO_ID, SHADOW_AUDIT_SUCCESS); #endif } else if (Rflg) { SYSLOG ((LOG_INFO, "access to group %s restricted by %s%s", group, myname, suffix)); #ifdef WITH_AUDIT snprintf (buf, 1023, "access to group %s restricted by %s%s", group, myname, suffix); buf[1023] = '\0'; audit_logger (AUDIT_USER_CHAUTHTOK, Prog, buf, group, AUDIT_NO_ID, SHADOW_AUDIT_SUCCESS); #endif } else if (Aflg || Mflg) { #ifdef SHADOWGRP if (Aflg) { SYSLOG ((LOG_INFO, "administrators of group %s set by %s to %s%s", group, myname, admins, suffix)); #ifdef WITH_AUDIT snprintf (buf, 1023, "administrators of group %s set by %s to %s%s", group, myname, admins, suffix); buf[1023] = '\0'; audit_logger (AUDIT_USER_ACCT, Prog, buf, group, AUDIT_NO_ID, SHADOW_AUDIT_SUCCESS); #endif } #endif /* SHADOWGRP */ if (Mflg) { SYSLOG ((LOG_INFO, "members of group %s set by %s to %s%s", group, myname, members, suffix)); #ifdef WITH_AUDIT snprintf (buf, 1023, "members of group %s set by %s to %s%s", group, myname, members, suffix); buf[1023] = '\0'; audit_logger (AUDIT_USER_ACCT, Prog, buf, group, AUDIT_NO_ID, SHADOW_AUDIT_SUCCESS); #endif } } else { SYSLOG ((LOG_INFO, "password of group %s changed by %s%s", group, myname, suffix)); #ifdef WITH_AUDIT snprintf (buf, 1023, "password of group %s changed by %s%s", group, myname, suffix); buf[1023] = '\0'; audit_logger (AUDIT_USER_CHAUTHTOK, Prog, buf, group, AUDIT_NO_ID, SHADOW_AUDIT_SUCCESS); #endif } }
/* * update_groups - delete user from secondary group set * * update_groups() takes the user name that was given and searches * the group files for membership in any group. * * we also check to see if they have any groups they own (the same * name is their user name) and delete them too (only if USERGROUPS_ENAB * is enabled). */ static void update_groups (void) { const struct group *grp; struct group *ngrp; struct passwd *pwd; #ifdef SHADOWGRP bool deleted_user_group = false; const struct sgrp *sgrp; struct sgrp *nsgrp; #endif /* SHADOWGRP */ /* * Scan through the entire group file looking for the groups that * the user is a member of. */ for (gr_rewind (), grp = gr_next (); NULL != grp; grp = gr_next ()) { /* * See if the user specified this group as one of their * concurrent groups. */ if (!is_on_list (grp->gr_mem, user_name)) { continue; } /* * Delete the username from the list of group members and * update the group entry to reflect the change. */ ngrp = __gr_dup (grp); if (NULL == ngrp) { fprintf (stderr, _("%s: Out of memory. Cannot update %s.\n"), Prog, gr_dbname ()); exit (13); /* XXX */ } ngrp->gr_mem = del_list (ngrp->gr_mem, user_name); if (gr_update (ngrp) == 0) { fprintf (stderr, _("%s: failed to prepare the new %s entry '%s'\n"), Prog, gr_dbname (), ngrp->gr_name); exit (E_GRP_UPDATE); } /* * Update the DBM group file with the new entry as well. */ #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "deleting user from group", user_name, (unsigned int) user_id, SHADOW_AUDIT_SUCCESS); #endif SYSLOG ((LOG_INFO, "delete '%s' from group '%s'\n", user_name, ngrp->gr_name)); } /* * we've removed their name from all the groups above, so * now if they have a group with the same name as their * user name, with no members, we delete it. * FIXME: below, the check for grp->gr_mem[0] is not sufficient. * We should retrieve the group with gr_locate and check * that gr_mem is empty. */ grp = xgetgrnam (user_name); if ( (NULL != grp) && getdef_bool ("USERGROUPS_ENAB") && ( (NULL == grp->gr_mem[0]) || ( (NULL == grp->gr_mem[1]) && (strcmp (grp->gr_mem[0], user_name) == 0)))) { pwd = NULL; if (!fflg) { /* * Scan the passwd file to check if this group is still * used as a primary group. */ setpwent (); while ((pwd = getpwent ()) != NULL) { if (strcmp (pwd->pw_name, user_name) == 0) { continue; } if (pwd->pw_gid == grp->gr_gid) { fprintf (stderr, _("%s: group %s is the primary group of another user and is not removed.\n"), Prog, grp->gr_name); break; } } endpwent (); } if (NULL == pwd) { /* * We can remove this group, it is not the primary * group of any remaining user. */ if (gr_remove (grp->gr_name) == 0) { fprintf (stderr, _("%s: cannot remove entry '%s' from %s\n"), Prog, grp->gr_name, gr_dbname ()); fail_exit (E_GRP_UPDATE); } #ifdef SHADOWGRP deleted_user_group = true; #endif #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_GROUP, Prog, "deleting group", grp->gr_name, AUDIT_NO_ID, SHADOW_AUDIT_SUCCESS); #endif SYSLOG ((LOG_INFO, "removed group '%s' owned by '%s'\n", grp->gr_name, user_name)); } } #ifdef SHADOWGRP if (!is_shadow_grp) { return; } /* * Scan through the entire shadow group file looking for the groups * that the user is a member of. Both the administrative list and * the ordinary membership list is checked. */ for (sgr_rewind (), sgrp = sgr_next (); NULL != sgrp; sgrp = sgr_next ()) { bool was_member, was_admin; /* * See if the user specified this group as one of their * concurrent groups. */ was_member = is_on_list (sgrp->sg_mem, user_name); was_admin = is_on_list (sgrp->sg_adm, user_name); if (!was_member && !was_admin) { continue; } nsgrp = __sgr_dup (sgrp); if (NULL == nsgrp) { fprintf (stderr, _("%s: Out of memory. Cannot update %s.\n"), Prog, sgr_dbname ()); exit (13); /* XXX */ } if (was_member) { nsgrp->sg_mem = del_list (nsgrp->sg_mem, user_name); } if (was_admin) { nsgrp->sg_adm = del_list (nsgrp->sg_adm, user_name); } if (sgr_update (nsgrp) == 0) { fprintf (stderr, _("%s: failed to prepare the new %s entry '%s'\n"), Prog, sgr_dbname (), nsgrp->sg_name); exit (E_GRP_UPDATE); } #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "deleting user from shadow group", user_name, (unsigned int) user_id, SHADOW_AUDIT_SUCCESS); #endif SYSLOG ((LOG_INFO, "delete '%s' from shadow group '%s'\n", user_name, nsgrp->sg_name)); } if ( deleted_user_group && (sgr_locate (user_name) != NULL)) { if (sgr_remove (user_name) == 0) { fprintf (stderr, _("%s: cannot remove entry '%s' from %s\n"), Prog, user_name, sgr_dbname ()); fail_exit (E_GRP_UPDATE); } } #endif /* SHADOWGRP */ }
static void open_files (void) { if (pw_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, pw_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "locking password file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_PW_UPDATE); } pw_locked = true; if (pw_open (O_CREAT | O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, pw_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "opening password file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_PW_UPDATE); } if (is_shadow_pwd) { if (spw_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, spw_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "locking shadow password file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_PW_UPDATE); } spw_locked = true; if (spw_open (O_CREAT | O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, spw_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "opening shadow password file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_PW_UPDATE); } } if (gr_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, gr_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "locking group file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_GRP_UPDATE); } gr_locked = true; if (gr_open (O_CREAT | O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, gr_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "opening group file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_GRP_UPDATE); } #ifdef SHADOWGRP if (is_shadow_grp) { if (sgr_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, sgr_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "locking shadow group file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_GRP_UPDATE); } sgr_locked= true; if (sgr_open (O_CREAT | O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, sgr_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "opening shadow group file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_GRP_UPDATE); } } #endif /* SHADOWGRP */ #ifdef ENABLE_SUBIDS if (is_sub_uid) { if (sub_uid_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, sub_uid_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "locking subordinate user file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_SUB_UID_UPDATE); } sub_uid_locked = true; if (sub_uid_open (O_CREAT | O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, sub_uid_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "opening subordinate user file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_SUB_UID_UPDATE); } } if (is_sub_gid) { if (sub_gid_lock () == 0) { fprintf (stderr, _("%s: cannot lock %s; try again later.\n"), Prog, sub_gid_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "locking subordinate group file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_SUB_GID_UPDATE); } sub_gid_locked = true; if (sub_gid_open (O_CREAT | O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, sub_gid_dbname ()); #ifdef WITH_AUDIT audit_logger (AUDIT_DEL_USER, Prog, "opening subordinate group file", user_name, (unsigned int) user_id, SHADOW_AUDIT_FAILURE); #endif /* WITH_AUDIT */ fail_exit (E_SUB_GID_UPDATE); } } #endif /* ENABLE_SUBIDS */ }