static bool DoCreateUser(const char *puser, User u, enum cfopaction action, EvalContext *ctx, const Attributes *a, const Promise *pp) { char cmd[CF_BUFSIZE]; if (puser == NULL || !strcmp (puser, "")) { return false; } strcpy (cmd, USERADD); if (u.uid != NULL && strcmp (u.uid, "")) { StringAppend(cmd, " -u \"", sizeof(cmd)); StringAppend(cmd, u.uid, sizeof(cmd)); StringAppend(cmd, "\"", sizeof(cmd)); } if (u.description != NULL) { StringAppend(cmd, " -c \"", sizeof(cmd)); StringAppend(cmd, u.description, sizeof(cmd)); StringAppend(cmd, "\"", sizeof(cmd)); } if (u.group_primary != NULL && strcmp (u.group_primary, "")) { // TODO: Should check that group exists StringAppend(cmd, " -g \"", sizeof(cmd)); StringAppend(cmd, u.group_primary, sizeof(cmd)); StringAppend(cmd, "\"", sizeof(cmd)); } if (u.groups_secondary != NULL) { // TODO: Should check that groups exist StringAppend(cmd, " -G \"", sizeof(cmd)); char sep[2] = { '\0', '\0' }; for (Rlist *i = u.groups_secondary; i; i = i->next) { if (strcmp(RvalScalarValue(i->val), CF_NULL_VALUE) != 0) { StringAppend(cmd, sep, sizeof(cmd)); StringAppend(cmd, RvalScalarValue(i->val), sizeof(cmd)); sep[0] = ','; } } StringAppend(cmd, "\"", sizeof(cmd)); } if (u.home_dir != NULL && strcmp (u.home_dir, "")) { StringAppend(cmd, " -d \"", sizeof(cmd)); StringAppend(cmd, u.home_dir, sizeof(cmd)); StringAppend(cmd, "\"", sizeof(cmd)); } if (u.shell != NULL && strcmp (u.shell, "")) { StringAppend(cmd, " -s \"", sizeof(cmd)); StringAppend(cmd, u.shell, sizeof(cmd)); StringAppend(cmd, "\"", sizeof(cmd)); } if (SupportsOption(USERADD, "-M")) { // Prevents creation of home_dir. // We want home_bundle to do that. StringAppend(cmd, " -M", sizeof(cmd)); } StringAppend(cmd, " ", sizeof(cmd)); StringAppend(cmd, puser, sizeof(cmd)); if (action == cfa_warn || DONTDO) { Log(LOG_LEVEL_NOTICE, "Need to create user '%s'.", puser); return false; } else { if (!ExecuteUserCommand(puser, cmd, sizeof(cmd), "creating", "Creating")) { return false; } // Initially, "useradd" may set the password to '!', which confuses our detection for // locked accounts. So reset it to 'x' hash instead, which will never match anything. if (!ChangePassword(puser, "x", PASSWORD_FORMAT_HASH)) { return false; } if (u.policy == USER_STATE_LOCKED) { if (!SetAccountLocked(puser, "", true)) { return false; } } if (a->havebundle) { const Constraint *method_attrib = PromiseGetConstraint(pp, "home_bundle"); VerifyMethod(ctx, method_attrib->rval, *a, pp); } if (u.policy != USER_STATE_LOCKED && u.password != NULL && strcmp (u.password, "")) { if (!ChangePassword(puser, u.password, u.password_format)) { return false; } } } return true; }
static bool DoCreateUser(const char *puser, User u, enum cfopaction action, EvalContext *ctx, const Attributes *a, const Promise *pp) { char cmd[CF_BUFSIZE]; if (puser == NULL || !strcmp (puser, "")) { return false; } strcpy (cmd, USERADD); if (u.uid != NULL && strcmp (u.uid, "")) { StringAppend(cmd, " -u \"", sizeof(cmd)); StringAppend(cmd, u.uid, sizeof(cmd)); StringAppend(cmd, "\"", sizeof(cmd)); } if (u.description != NULL) { StringAppend(cmd, " -c \"", sizeof(cmd)); StringAppend(cmd, u.description, sizeof(cmd)); StringAppend(cmd, "\"", sizeof(cmd)); } if (u.group_primary != NULL && strcmp (u.group_primary, "")) { // TODO: Should check that group exists StringAppend(cmd, " -g \"", sizeof(cmd)); StringAppend(cmd, u.group_primary, sizeof(cmd)); StringAppend(cmd, "\"", sizeof(cmd)); } if (u.groups_secondary != NULL) { // TODO: Should check that groups exist StringAppend(cmd, " -G \"", sizeof(cmd)); char sep[2] = { '\0', '\0' }; for (Rlist *i = u.groups_secondary; i; i = i->next) { if (strcmp(RvalScalarValue(i->val), CF_NULL_VALUE) != 0) { StringAppend(cmd, sep, sizeof(cmd)); StringAppend(cmd, RvalScalarValue(i->val), sizeof(cmd)); sep[0] = ','; } } StringAppend(cmd, "\"", sizeof(cmd)); } if (u.home_dir != NULL && strcmp (u.home_dir, "")) { StringAppend(cmd, " -d \"", sizeof(cmd)); StringAppend(cmd, u.home_dir, sizeof(cmd)); StringAppend(cmd, "\"", sizeof(cmd)); } if (u.shell != NULL && strcmp (u.shell, "")) { StringAppend(cmd, " -s \"", sizeof(cmd)); StringAppend(cmd, u.shell, sizeof(cmd)); StringAppend(cmd, "\"", sizeof(cmd)); } StringAppend(cmd, " ", sizeof(cmd)); StringAppend(cmd, puser, sizeof(cmd)); if (action == cfa_warn || DONTDO) { Log(LOG_LEVEL_NOTICE, "Need to create user '%s'.", puser); return false; } else { if (strlen(cmd) >= sizeof(cmd) - 1) { // Instead of checking every string call above, assume that a maxed out // string length overflowed the string. Log(LOG_LEVEL_ERR, "Command line too long while creating user '%s'", puser); return false; } Log(LOG_LEVEL_VERBOSE, "Creating user '%s'. (command: '%s')", puser, cmd); int status; status = system(cmd); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { Log(LOG_LEVEL_ERR, "Command returned error while creating user '%s'. (Command line: '%s')", puser, cmd); return false; } // Initially, "useradd" may set the password to '!', which confuses our detection for // locked accounts. So reset it to 'x' hash instead, which will never match anything. if (!ChangePassword(puser, "x", PASSWORD_FORMAT_HASH)) { return false; } if (u.policy == USER_STATE_LOCKED) { if (!SetAccountLocked(puser, "", true)) { return false; } } if (a->havebundle) { const Constraint *method_attrib = PromiseGetConstraint(pp, "home_bundle"); VerifyMethod(ctx, method_attrib->rval, *a, pp); EvalContextVariableRemoveSpecial(ctx, SPECIAL_SCOPE_THIS, "promiser"); } if (u.policy != USER_STATE_LOCKED && u.password != NULL && strcmp (u.password, "")) { if (!ChangePassword(puser, u.password, u.password_format)) { return false; } } } return true; }
static bool DoModifyUser (const char *puser, User u, const struct passwd *passwd_info, uint32_t changemap, enum cfopaction action) { char cmd[CF_BUFSIZE]; strcpy (cmd, USERMOD); if (CFUSR_CHECKBIT (changemap, i_uid) != 0) { StringAppend(cmd, " -u \"", sizeof(cmd)); StringAppend(cmd, u.uid, sizeof(cmd)); StringAppend(cmd, "\"", sizeof(cmd)); } if (CFUSR_CHECKBIT (changemap, i_comment) != 0) { StringAppend(cmd, " -c \"", sizeof(cmd)); StringAppend(cmd, u.description, sizeof(cmd)); StringAppend(cmd, "\"", sizeof(cmd)); } if (CFUSR_CHECKBIT (changemap, i_group) != 0) { StringAppend(cmd, " -g \"", sizeof(cmd)); StringAppend(cmd, u.group_primary, sizeof(cmd)); StringAppend(cmd, "\"", sizeof(cmd)); } if (CFUSR_CHECKBIT (changemap, i_groups) != 0) { /* Work around bug on SUSE. If secondary groups contain a group that is the same group as the primary group, the secondary group is not set. This happens even if the primary group is changed in the same call. Therefore, set an empty group list first, and then set it to the real list later. */ StringAppend(cmd, " -G \"\"", sizeof(cmd)); } if (CFUSR_CHECKBIT (changemap, i_home) != 0) { StringAppend(cmd, " -d \"", sizeof(cmd)); StringAppend(cmd, u.home_dir, sizeof(cmd)); StringAppend(cmd, "\"", sizeof(cmd)); } if (CFUSR_CHECKBIT (changemap, i_shell) != 0) { StringAppend(cmd, " -s \"", sizeof(cmd)); StringAppend(cmd, u.shell, sizeof(cmd)); StringAppend(cmd, "\"", sizeof(cmd)); } StringAppend(cmd, " ", sizeof(cmd)); StringAppend(cmd, puser, sizeof(cmd)); if (CFUSR_CHECKBIT (changemap, i_password) != 0) { if (action == cfa_warn || DONTDO) { Log(LOG_LEVEL_NOTICE, "Need to change password for user '%s'.", puser); return false; } else { if (!ChangePassword(puser, u.password, u.password_format)) { return false; } } } if (CFUSR_CHECKBIT (changemap, i_locked) != 0) { if (action == cfa_warn || DONTDO) { Log(LOG_LEVEL_NOTICE, "Need to %s account for user '%s'.", (u.policy == USER_STATE_LOCKED) ? "lock" : "unlock", puser); return false; } else { const char *hash; if (!GetPasswordHash(puser, passwd_info, &hash)) { return false; } if (!SetAccountLocked(puser, hash, (u.policy == USER_STATE_LOCKED))) { return false; } } } // If password and locking were the only things changed, don't run the command. CFUSR_CLEARBIT(changemap, i_password); CFUSR_CLEARBIT(changemap, i_locked); if (action == cfa_warn || DONTDO) { Log(LOG_LEVEL_NOTICE, "Need to update user attributes (command '%s').", cmd); return false; } else if (changemap != 0) { if (!ExecuteUserCommand(puser, cmd, sizeof(cmd), "modifying", "Modifying")) { return false; } if (CFUSR_CHECKBIT (changemap, i_groups) != 0) { // Set real group list (see -G comment earlier). strcpy(cmd, USERMOD); StringAppend(cmd, " -G \"", sizeof(cmd)); char sep[2] = { '\0', '\0' }; for (Rlist *i = u.groups_secondary; i; i = i->next) { if (strcmp(RvalScalarValue(i->val), CF_NULL_VALUE) != 0) { StringAppend(cmd, sep, sizeof(cmd)); StringAppend(cmd, RvalScalarValue(i->val), sizeof(cmd)); sep[0] = ','; } } StringAppend(cmd, "\" ", sizeof(cmd)); StringAppend(cmd, puser, sizeof(cmd)); if (!ExecuteUserCommand(puser, cmd, sizeof(cmd), "modifying", "Modifying")) { return false; } } } return true; }