*/
#include "includes.h"
-
-extern struct passdb_ops pdb_ops;
+#include "../libcli/auth/libcli_auth.h"
static NTSTATUS check_oem_password(const char *user,
uchar password_encrypted_with_lm_hash[516],
const uchar old_lm_hash_encrypted[16],
uchar password_encrypted_with_nt_hash[516],
const uchar old_nt_hash_encrypted[16],
- struct samu **hnd,
+ struct samu *sampass,
char **pp_new_passwd);
#if ALLOW_CHANGE_PASSWORD
static int findpty(char **slave)
{
- int master;
- static fstring line;
- SMB_STRUCT_DIR *dirp;
+ int master = -1;
+ char *line = NULL;
+ SMB_STRUCT_DIR *dirp = NULL;
const char *dpname;
+ *slave = NULL;
+
#if defined(HAVE_GRANTPT)
/* Try to open /dev/ptmx. If that fails, fall through to old method. */
- if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 0)
- {
+ if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 0) {
grantpt(master);
unlockpt(master);
- *slave = (char *)ptsname(master);
- if (*slave == NULL)
- {
+ line = (char *)ptsname(master);
+ if (line) {
+ *slave = SMB_STRDUP(line);
+ }
+
+ if (*slave == NULL) {
DEBUG(0,
("findpty: Unable to create master/slave pty pair.\n"));
/* Stop fd leak on error. */
close(master);
return -1;
- }
- else
- {
+ } else {
DEBUG(10,
("findpty: Allocated slave pty %s\n", *slave));
return (master);
}
#endif /* HAVE_GRANTPT */
- fstrcpy(line, "/dev/ptyXX");
+ line = SMB_STRDUP("/dev/ptyXX");
+ if (!line) {
+ return (-1);
+ }
dirp = sys_opendir("/dev");
- if (!dirp)
+ if (!dirp) {
+ SAFE_FREE(line);
return (-1);
- while ((dpname = readdirname(dirp)) != NULL)
- {
- if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5)
- {
+ }
+
+ while ((dpname = readdirname(dirp)) != NULL) {
+ if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5) {
DEBUG(3,
("pty: try to open %s, line was %s\n", dpname,
line));
line[8] = dpname[3];
line[9] = dpname[4];
- if ((master = sys_open(line, O_RDWR, 0)) >= 0)
- {
+ if ((master = sys_open(line, O_RDWR, 0)) >= 0) {
DEBUG(3, ("pty: opened %s\n", line));
line[5] = 't';
*slave = line;
}
}
sys_closedir(dirp);
+ SAFE_FREE(line);
return (-1);
}
struct termios stermios;
gid_t gid;
uid_t uid;
+ char * const eptrs[1] = { NULL };
if (pass == NULL)
{
DEBUG(3, ("More weirdness, could not open %s\n", slavedev));
return (False);
}
-#if defined(I_PUSH) && defined(I_FIND)
+#if defined(TIOCSCTTY) && !defined(SUNOS5)
+ /*
+ * On patched Solaris 10 TIOCSCTTY is defined but seems not to work,
+ * see the discussion under
+ * https://bugzilla.samba.org/show_bug.cgi?id=5366.
+ */
+ if (ioctl(slave, TIOCSCTTY, 0) < 0)
+ {
+ DEBUG(3, ("Error in ioctl call for slave pty\n"));
+ /* return(False); */
+ }
+#elif defined(I_PUSH) && defined(I_FIND)
if (ioctl(slave, I_FIND, "ptem") == 0) {
ioctl(slave, I_PUSH, "ptem");
}
if (ioctl(slave, I_FIND, "ldterm") == 0) {
ioctl(slave, I_PUSH, "ldterm");
}
-#elif defined(TIOCSCTTY)
- if (ioctl(slave, TIOCSCTTY, 0) < 0)
- {
- DEBUG(3, ("Error in ioctl call for slave pty\n"));
- /* return(False); */
- }
#endif
/* Close master. */
/* Make slave stdin/out/err of child. */
- if (sys_dup2(slave, STDIN_FILENO) != STDIN_FILENO)
+ if (dup2(slave, STDIN_FILENO) != STDIN_FILENO)
{
DEBUG(3, ("Could not re-direct stdin\n"));
return (False);
}
- if (sys_dup2(slave, STDOUT_FILENO) != STDOUT_FILENO)
+ if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO)
{
DEBUG(3, ("Could not re-direct stdout\n"));
return (False);
}
- if (sys_dup2(slave, STDERR_FILENO) != STDERR_FILENO)
+ if (dup2(slave, STDERR_FILENO) != STDERR_FILENO)
{
DEBUG(3, ("Could not re-direct stderr\n"));
return (False);
passwordprogram));
/* execl() password-change application */
- if (execl("/bin/sh", "sh", "-c", passwordprogram, NULL) < 0)
+ if (execle("/bin/sh", "sh", "-c", passwordprogram, NULL, eptrs) < 0)
{
DEBUG(3, ("Bad status returned from %s\n", passwordprogram));
return (False);
static int expect(int master, char *issue, char *expected)
{
char buffer[1024];
- int attempts, timeout, nread, len;
+ int attempts, timeout, nread;
+ size_t len;
bool match = False;
for (attempts = 0; attempts < 2; attempts++) {
+ NTSTATUS status;
if (!strequal(issue, ".")) {
if (lp_passwd_chat_debug())
DEBUG(100, ("expect: sending [%s]\n", issue));
if ((len = sys_write(master, issue, strlen(issue))) != strlen(issue)) {
- DEBUG(2,("expect: (short) write returned %d\n", len ));
+ DEBUG(2,("expect: (short) write returned %d\n",
+ (int)len ));
return False;
}
}
nread = 0;
buffer[nread] = 0;
- while ((len = read_socket_with_timeout(master, buffer + nread, 1,
- sizeof(buffer) - nread - 1,
- timeout, NULL)) > 0) {
+ while (True) {
+ status = read_fd_with_timeout(
+ master, buffer + nread, 1,
+ sizeof(buffer) - nread - 1,
+ timeout, &len);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ break;
+ }
nread += len;
buffer[nread] = 0;
if (match)
break;
- if (len < 0) {
- DEBUG(2, ("expect: %s\n", strerror(errno)));
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(2, ("expect: %s\n", nt_errstr(status)));
return False;
}
}
static int talktochild(int master, const char *seq)
{
+ TALLOC_CTX *frame = talloc_stackframe();
int count = 0;
- fstring issue, expected;
+ char *issue;
+ char *expected;
- fstrcpy(issue, ".");
+ issue = talloc_strdup(frame, ".");
+ if (!issue) {
+ TALLOC_FREE(frame);
+ return false;
+ }
- while (next_token(&seq, expected, NULL, sizeof(expected)))
- {
+ while (next_token_talloc(frame, &seq, &expected, NULL)) {
pwd_sub(expected);
count++;
- if (!expect(master, issue, expected))
- {
+ if (!expect(master, issue, expected)) {
DEBUG(3, ("Response %d incorrect\n", count));
- return False;
+ TALLOC_FREE(frame);
+ return false;
}
- if (!next_token(&seq, issue, NULL, sizeof(issue)))
- fstrcpy(issue, ".");
-
+ if (!next_token_talloc(frame, &seq, &issue, NULL)) {
+ issue = talloc_strdup(frame, ".");
+ if (!issue) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+ }
pwd_sub(issue);
}
+
if (!strequal(issue, ".")) {
/* we have one final issue to send */
- fstrcpy(expected, ".");
- if (!expect(master, issue, expected))
+ expected = talloc_strdup(frame, ".");
+ if (!expected) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+ if (!expect(master, issue, expected)) {
+ TALLOC_FREE(frame);
return False;
+ }
}
-
+ TALLOC_FREE(frame);
return (count > 0);
}
static bool chat_with_program(char *passwordprogram, const struct passwd *pass,
char *chatsequence, bool as_root)
{
- char *slavedev;
+ char *slavedev = NULL;
int master;
pid_t pid, wpid;
int wstat;
if ((pid = sys_fork()) < 0) {
DEBUG(3, ("chat_with_program: Cannot fork() child for password change: %s\n", pass->pw_name));
+ SAFE_FREE(slavedev);
close(master);
CatchChild();
return (False);
/* we now have a pty */
if (pid > 0) { /* This is the parent process */
+ /* Don't need this anymore in parent. */
+ SAFE_FREE(slavedev);
+
if ((chstat = talktochild(master, chatsequence)) == False) {
DEBUG(3, ("chat_with_program: Child failed to change password: %s\n", pass->pw_name));
kill(pid, SIGKILL); /* be sure to end this process */
#ifdef WITH_PAM
if (lp_pam_password_change()) {
bool ret;
+#ifdef HAVE_SETLOCALE
+ const char *prevlocale = setlocale(LC_ALL, "C");
+#endif
if (as_root)
become_root();
if (as_root)
unbecome_root();
+#ifdef HAVE_SETLOCALE
+ setlocale(LC_ALL, prevlocale);
+#endif
+
return ret;
}
#endif
bool change_lanman_password(struct samu *sampass, uchar *pass2)
{
- static uchar null_pw[16];
+ uchar null_pw[16];
uchar unenc_new_pw[16];
bool ret;
uint32 acct_ctrl;
if (pwd == NULL) {
if (acct_ctrl & ACB_PWNOTREQ) {
uchar no_pw[14];
- memset(no_pw, '\0', 14);
+
+ ZERO_STRUCT(no_pw);
+
E_P16(no_pw, null_pw);
- /* Get the new lanman hash. */
- D_P16(null_pw, pass2, unenc_new_pw);
+ pwd = null_pw;
} else {
DEBUG(0,("change_lanman_password: no lanman password !\n"));
return False;
}
- } else {
- /* Get the new lanman hash. */
- D_P16(pwd, pass2, unenc_new_pw);
}
+ /* Get the new lanman hash. */
+ D_P16(pwd, pass2, unenc_new_pw);
+
if (!pdb_set_lanman_passwd(sampass, unenc_new_pw, PDB_CHANGED)) {
return False;
}
const uchar old_lm_hash_encrypted[16],
uchar password_encrypted_with_nt_hash[516],
const uchar old_nt_hash_encrypted[16],
- uint32 *reject_reason)
+ enum samPwdChangeReason *reject_reason)
{
char *new_passwd = NULL;
struct samu *sampass = NULL;
- NTSTATUS nt_status = check_oem_password(user,
- password_encrypted_with_lm_hash,
- old_lm_hash_encrypted,
- password_encrypted_with_nt_hash,
- old_nt_hash_encrypted,
- &sampass,
- &new_passwd);
+ NTSTATUS nt_status;
+ bool ret = false;
+
+ if (!(sampass = samu_new(NULL))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ become_root();
+ ret = pdb_getsampwnam(sampass, user);
+ unbecome_root();
+
+ if (ret == false) {
+ DEBUG(0,("pass_oem_change: getsmbpwnam returned NULL\n"));
+ TALLOC_FREE(sampass);
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ nt_status = check_oem_password(user,
+ password_encrypted_with_lm_hash,
+ old_lm_hash_encrypted,
+ password_encrypted_with_nt_hash,
+ old_nt_hash_encrypted,
+ sampass,
+ &new_passwd);
if (!NT_STATUS_IS_OK(nt_status)) {
+ TALLOC_FREE(sampass);
return nt_status;
}
const uchar old_lm_hash_encrypted[16],
uchar password_encrypted_with_nt_hash[516],
const uchar old_nt_hash_encrypted[16],
- struct samu **hnd,
+ struct samu *sampass,
char **pp_new_passwd)
{
- static uchar null_pw[16];
- static uchar null_ntpw[16];
- struct samu *sampass = NULL;
+ uchar null_pw[16];
+ uchar null_ntpw[16];
uint8 *password_encrypted;
const uint8 *encryption_key;
const uint8 *lanman_pw, *nt_pw;
uint32 acct_ctrl;
- uint32 new_pw_len;
+ size_t new_pw_len;
uchar new_nt_hash[16];
uchar new_lm_hash[16];
uchar verifier[16];
char no_pw[2];
- bool ret;
bool nt_pass_set = (password_encrypted_with_nt_hash && old_nt_hash_encrypted);
bool lm_pass_set = (password_encrypted_with_lm_hash && old_lm_hash_encrypted);
- *hnd = NULL;
-
- if ( !(sampass = samu_new( NULL )) ) {
- return NT_STATUS_NO_MEMORY;
- }
-
- become_root();
- ret = pdb_getsampwnam(sampass, user);
- unbecome_root();
-
- if (ret == False) {
- DEBUG(0, ("check_oem_password: getsmbpwnam returned NULL\n"));
- TALLOC_FREE(sampass);
- return NT_STATUS_NO_SUCH_USER;
- }
-
acct_ctrl = pdb_get_acct_ctrl(sampass);
+#if 0
+ /* I am convinced this check here is wrong, it is valid to
+ * change a password of a user that has a disabled account - gd */
if (acct_ctrl & ACB_DISABLED) {
DEBUG(2,("check_lanman_password: account %s disabled.\n", user));
- TALLOC_FREE(sampass);
return NT_STATUS_ACCOUNT_DISABLED;
}
-
+#endif
if ((acct_ctrl & ACB_PWNOTREQ) && lp_null_passwords()) {
/* construct a null password (in case one is needed */
no_pw[0] = 0;
} else if (nt_pass_set) {
DEBUG(1, ("NT password change supplied for user %s, but we have no NT password to check it with\n",
user));
- TALLOC_FREE(sampass);
return NT_STATUS_WRONG_PASSWORD;
} else if (lm_pass_set) {
if (lp_lanman_auth()) {
DEBUG(1, ("LM password change supplied for user %s, but we have disabled LanMan authentication\n",
user));
}
- TALLOC_FREE(sampass);
return NT_STATUS_WRONG_PASSWORD;
} else {
DEBUG(1, ("password change requested for user %s, but no password supplied!\n",
user));
- TALLOC_FREE(sampass);
return NT_STATUS_WRONG_PASSWORD;
}
/*
* Decrypt the password with the key
*/
- SamOEMhash( password_encrypted, encryption_key, 516);
+ arcfour_crypt( password_encrypted, encryption_key, 516);
if (!decode_pw_buffer(talloc_tos(),
password_encrypted,
pp_new_passwd,
&new_pw_len,
- nt_pass_set ? STR_UNICODE : STR_ASCII)) {
- TALLOC_FREE(sampass);
+ nt_pass_set ? CH_UTF16 : CH_DOS)) {
return NT_STATUS_WRONG_PASSWORD;
}
E_old_pw_hash(new_nt_hash, nt_pw, verifier);
if (memcmp(verifier, old_nt_hash_encrypted, 16)) {
DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
- TALLOC_FREE(sampass);
return NT_STATUS_WRONG_PASSWORD;
}
DEBUG(100,
("check_oem_password: password %s ok\n", *pp_new_passwd));
#endif
- *hnd = sampass;
return NT_STATUS_OK;
}
E_old_pw_hash(new_nt_hash, lanman_pw, verifier);
if (memcmp(verifier, old_lm_hash_encrypted, 16)) {
DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
- TALLOC_FREE(sampass);
return NT_STATUS_WRONG_PASSWORD;
}
#ifdef DEBUG_PASSWORD
DEBUG(100,
("check_oem_password: password %s ok\n", *pp_new_passwd));
#endif
- *hnd = sampass;
return NT_STATUS_OK;
}
}
E_old_pw_hash(new_lm_hash, lanman_pw, verifier);
if (memcmp(verifier, old_lm_hash_encrypted, 16)) {
DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
- TALLOC_FREE(sampass);
return NT_STATUS_WRONG_PASSWORD;
}
DEBUG(100,
("check_oem_password: password %s ok\n", *pp_new_passwd));
#endif
- *hnd = sampass;
return NT_STATUS_OK;
}
/* should not be reached */
- TALLOC_FREE(sampass);
return NT_STATUS_WRONG_PASSWORD;
}
int i;
uint32 pwHisLen, curr_pwHisLen;
- pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHisLen);
+ pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHisLen);
if (pwHisLen == 0) {
return False;
}
return found;
}
+/***********************************************************
+************************************************************/
+
+NTSTATUS check_password_complexity(const char *username,
+ const char *password,
+ enum samPwdChangeReason *samr_reject_reason)
+{
+ TALLOC_CTX *tosctx = talloc_tos();
+
+ /* Use external script to check password complexity */
+ if (lp_check_password_script() && *(lp_check_password_script())) {
+ int check_ret;
+ char *cmd;
+
+ cmd = talloc_string_sub(tosctx, lp_check_password_script(), "%u", username);
+ if (!cmd) {
+ return NT_STATUS_PASSWORD_RESTRICTION;
+ }
+
+ check_ret = smbrunsecret(cmd, password);
+ DEBUG(5,("check_password_complexity: check password script (%s) returned [%d]\n",
+ cmd, check_ret));
+ TALLOC_FREE(cmd);
+
+ if (check_ret != 0) {
+ DEBUG(1,("check_password_complexity: "
+ "check password script said new password is not good enough!\n"));
+ if (samr_reject_reason) {
+ *samr_reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
+ }
+ return NT_STATUS_PASSWORD_RESTRICTION;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
/***********************************************************
Code to change the oem password. Changes both the lanman
and NT hashes. Old_passwd is almost always NULL.
is correct before calling. JRA.
************************************************************/
-NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passwd, bool as_root, uint32 *samr_reject_reason)
+NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passwd, bool as_root, enum samPwdChangeReason *samr_reject_reason)
{
uint32 min_len;
uint32 refuse;
+ TALLOC_CTX *tosctx = talloc_tos();
struct passwd *pass = NULL;
const char *username = pdb_get_username(hnd);
time_t can_change_time = pdb_get_pass_can_change_time(hnd);
+ NTSTATUS status;
if (samr_reject_reason) {
- *samr_reject_reason = Undefined;
+ *samr_reject_reason = SAM_PWD_CHANGE_NO_ERROR;
}
/* check to see if the secdesc has previously been set to disallow */
if (!pdb_get_pass_can_change(hnd)) {
DEBUG(1, ("user %s does not have permissions to change password\n", username));
if (samr_reject_reason) {
- *samr_reject_reason = REJECT_REASON_OTHER;
+ *samr_reject_reason = SAM_PWD_CHANGE_NO_ERROR;
}
return NT_STATUS_ACCOUNT_RESTRICTION;
}
* denies machines to change the password. *
* Should we deny also SRVTRUST and/or DOMSTRUST ? .SSS. */
if (pdb_get_acct_ctrl(hnd) & ACB_WSTRUST) {
- if (pdb_get_account_policy(AP_REFUSE_MACHINE_PW_CHANGE, &refuse) && refuse) {
+ if (pdb_get_account_policy(PDB_POLICY_REFUSE_MACHINE_PW_CHANGE, &refuse) && refuse) {
DEBUG(1, ("Machine %s cannot change password now, "
"denied by Refuse Machine Password Change policy\n",
username));
if (samr_reject_reason) {
- *samr_reject_reason = REJECT_REASON_OTHER;
+ *samr_reject_reason = SAM_PWD_CHANGE_NO_ERROR;
}
return NT_STATUS_ACCOUNT_RESTRICTION;
}
if ((can_change_time != 0) && (time(NULL) < can_change_time)) {
DEBUG(1, ("user %s cannot change password now, must "
"wait until %s\n", username,
- http_timestring(can_change_time)));
+ http_timestring(tosctx, can_change_time)));
if (samr_reject_reason) {
- *samr_reject_reason = REJECT_REASON_OTHER;
+ *samr_reject_reason = SAM_PWD_CHANGE_NO_ERROR;
}
return NT_STATUS_ACCOUNT_RESTRICTION;
}
- if (pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &min_len) && (str_charnum(new_passwd) < min_len)) {
+ if (pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_LEN, &min_len) && (str_charnum(new_passwd) < min_len)) {
DEBUG(1, ("user %s cannot change password - password too short\n",
username));
DEBUGADD(1, (" account policy min password len = %d\n", min_len));
if (samr_reject_reason) {
- *samr_reject_reason = REJECT_REASON_TOO_SHORT;
+ *samr_reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
}
return NT_STATUS_PASSWORD_RESTRICTION;
/* return NT_STATUS_PWD_TOO_SHORT; */
if (check_passwd_history(hnd,new_passwd)) {
if (samr_reject_reason) {
- *samr_reject_reason = REJECT_REASON_IN_HISTORY;
+ *samr_reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
}
return NT_STATUS_PASSWORD_RESTRICTION;
}
- pass = Get_Pwnam(username);
+ pass = Get_Pwnam_alloc(tosctx, username);
if (!pass) {
DEBUG(1, ("change_oem_password: Username %s does not exist in system !?!\n", username));
return NT_STATUS_ACCESS_DENIED;
}
- /* Use external script to check password complexity */
- if (lp_check_password_script() && *(lp_check_password_script())) {
- int check_ret;
-
- check_ret = smbrunsecret(lp_check_password_script(), new_passwd);
- DEBUG(5, ("change_oem_password: check password script (%s) returned [%d]\n", lp_check_password_script(), check_ret));
-
- if (check_ret != 0) {
- DEBUG(1, ("change_oem_password: check password script said new password is not good enough!\n"));
- if (samr_reject_reason) {
- *samr_reject_reason = REJECT_REASON_NOT_COMPLEX;
- }
- return NT_STATUS_PASSWORD_RESTRICTION;
- }
+ status = check_password_complexity(username, new_passwd, samr_reject_reason);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(pass);
+ return status;
}
/*
if(lp_unix_password_sync() &&
!chgpasswd(username, pass, old_passwd, new_passwd, as_root)) {
+ TALLOC_FREE(pass);
return NT_STATUS_ACCESS_DENIED;
}
+ TALLOC_FREE(pass);
+
if (!pdb_set_plaintext_passwd (hnd, new_passwd)) {
return NT_STATUS_ACCESS_DENIED;
}