2 Unix SMB/Netbios implementation.
4 Samba utility functions
5 Copyright (C) Andrew Tridgell 1992-1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 /* fork a child process to exec passwd and write to its
23 * tty to change a users password. This is running as the
24 * user who is attempting to change the password.
28 * This code was copied/borrowed and stolen from various sources.
29 * The primary source was the poppasswd.c from the authors of POPMail. This software
30 * was included as a client to change passwords using the 'passwd' program
31 * on the remote machine.
33 * This routine is called by set_user_password() in password.c only if ALLOW_PASSWORD_CHANGE
34 * is defined in the compiler directives located in the Makefile.
36 * This code has been hacked by Bob Nance (nance@niehs.nih.gov) and Evan Patterson
37 * (patters2@niehs.nih.gov) at the National Institute of Environmental Health Sciences
38 * and rights to modify, distribute or incorporate this change to the CAP suite or
39 * using it for any other reason are granted, so long as this disclaimer is left intact.
43 This code was hacked considerably for inclusion in Samba, primarily
44 by Andrew.Tridgell@anu.edu.au. The biggest change was the addition
45 of the "password chat" option, which allows the easy runtime
46 specification of the expected sequence of events to change a
52 extern int DEBUGLEVEL;
54 #if ALLOW_CHANGE_PASSWORD
55 #define MINPASSWDLENGTH 5
58 static int findpty(char **slave)
64 struct dirent *dentry;
66 #endif /* !HAVE_GRANTPT */
68 #if defined(HAVE_GRANTPT)
69 if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 1) {
72 *slave = ptsname(master);
74 DEBUG(0,("findpty: Unable to create master/slave pty pair.\n"));
75 /* Stop fd leak on error. */
79 DEBUG(10, ("findpty: Allocated slave pty %s\n", *slave));
83 #else /* HAVE_GRANTPT */
84 fstrcpy( line, "/dev/ptyXX" );
86 dirp = opendir("/dev");
89 while ((dentry = readdir(dirp)) != NULL) {
90 dpname = dentry->d_name;
91 if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5) {
92 DEBUG(3,("pty: try to open %s, line was %s\n", dpname, line ) );
95 if ((master = sys_open(line, O_RDWR, 0)) >= 0) {
96 DEBUG(3,("pty: opened %s\n", line ) );
105 #endif /* HAVE_GRANTPT */
109 static int dochild(int master,char *slavedev, char *name, char *passwordprogram, BOOL as_root)
112 struct termios stermios;
113 const struct passwd *pass = Get_Pwnam(name,True);
118 DEBUG(0,("dochild: user name %s doesn't exist in the UNIX password database.\n",
125 #ifdef HAVE_SETRESUID
131 /* Start new session - gets rid of controlling terminal. */
133 DEBUG(3,("Weirdness, couldn't let go of controlling terminal\n"));
137 /* Open slave pty and acquire as new controlling terminal. */
138 if ((slave = sys_open(slavedev, O_RDWR, 0)) < 0) {
139 DEBUG(3,("More weirdness, could not open %s\n",
144 ioctl(slave, I_PUSH, "ptem");
145 ioctl(slave, I_PUSH, "ldterm");
146 #elif defined(TIOCSCTTY)
147 if (ioctl(slave,TIOCSCTTY,0) <0) {
148 DEBUG(3,("Error in ioctl call for slave pty\n"));
156 /* Make slave stdin/out/err of child. */
158 if (dup2(slave, STDIN_FILENO) != STDIN_FILENO) {
159 DEBUG(3,("Could not re-direct stdin\n"));
162 if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO) {
163 DEBUG(3,("Could not re-direct stdout\n"));
166 if (dup2(slave, STDERR_FILENO) != STDERR_FILENO) {
167 DEBUG(3,("Could not re-direct stderr\n"));
170 if (slave > 2) close(slave);
172 /* Set proper terminal attributes - no echo, canonical input processing,
173 no map NL to CR/NL on output. */
175 if (tcgetattr(0, &stermios) < 0) {
176 DEBUG(3,("could not read default terminal attributes on pty\n"));
179 stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
180 stermios.c_lflag |= ICANON;
181 stermios.c_oflag &= ~(ONLCR);
182 if (tcsetattr(0, TCSANOW, &stermios) < 0) {
183 DEBUG(3,("could not set attributes of pty\n"));
187 /* make us completely into the right uid */
189 #ifdef HAVE_SETRESUID
192 setresgid(gid,gid,gid);
193 setresuid(uid,uid,uid);
204 DEBUG(10, ("Invoking '%s' as password change program.\n", passwordprogram));
206 /* execl() password-change application */
207 if (execl("/bin/sh","sh","-c",passwordprogram,NULL) < 0) {
208 DEBUG(3,("Bad status returned from %s\n",passwordprogram));
214 static int expect(int master,char *expected,char *buf)
221 if (n >= BUFSIZE-1) {
225 /* allow 4 seconds for some output to appear */
226 m = read_with_timeout(master, buf+n, 1, BUFSIZE-1-n, 4000);
236 pstrcpy(s2,expected);
237 if (do_match(s1, s2, False))
243 static void pwd_sub(char *buf)
245 string_sub(buf,"\\n","\n");
246 string_sub(buf,"\\r","\r");
247 string_sub(buf,"\\s"," ");
248 string_sub(buf,"\\t","\t");
251 static void writestring(int fd,char *s)
260 static int talktochild(int master, char *chatsequence)
264 char *ptr=chatsequence;
270 while (next_token(&ptr,chatbuf,NULL,sizeof(chatbuf))) {
274 if (!strequal(chatbuf,"."))
275 ok = expect(master,chatbuf,buf);
277 if (lp_passwd_chat_debug())
278 DEBUG(100,("talktochild: chatbuf=[%s] responsebuf=[%s]\n",chatbuf,buf));
281 DEBUG(3,("response %d incorrect\n",count));
285 if (!next_token(&ptr,chatbuf,NULL,sizeof(chatbuf))) break;
287 if (!strequal(chatbuf,"."))
288 writestring(master,chatbuf);
290 if (lp_passwd_chat_debug())
291 DEBUG(100,("talktochild: sendbuf=[%s]\n",chatbuf));
294 if (count<1) return(False);
300 static BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequence, BOOL as_root)
308 /* allocate a pseudo-terminal device */
309 if ((master = findpty (&slavedev)) < 0) {
310 DEBUG(3,("Cannot Allocate pty for password change: %s\n",name));
314 if ((pid = fork()) < 0) {
315 DEBUG(3,("Cannot fork() child for password change: %s\n",name));
320 /* we now have a pty */
321 if (pid > 0){ /* This is the parent process */
322 if ((chstat = talktochild(master, chatsequence)) == False) {
323 DEBUG(3,("Child failed to change password: %s\n",name));
324 kill(pid, SIGKILL); /* be sure to end this process */
327 if ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) {
328 DEBUG(3,("The process is no longer waiting!\n\n"));
336 DEBUG(3,("We were waiting for the wrong process ID\n"));
339 if (WIFEXITED(wstat) == 0) {
340 DEBUG(3,("The process exited while we were waiting\n"));
343 if (WEXITSTATUS(wstat) != 0) {
344 DEBUG(3,("The status of the process exiting was %d\n", wstat));
352 * Lose any oplock capabilities.
354 set_process_capability(KERNEL_OPLOCK_CAPABILITY, False);
355 set_inherited_process_capability(KERNEL_OPLOCK_CAPABILITY, False);
357 /* make sure it doesn't freeze */
362 DEBUG(3,("Dochild for user %s (uid=%d,gid=%d)\n",name,(int)getuid(),(int)getgid()));
363 chstat = dochild(master, slavedev, name, passwordprogram, as_root);
366 unbecome_root(False);
370 DEBUG(3,("Password change %ssuccessful for user %s\n", (chstat?"":"un"), name));
375 BOOL chgpasswd(char *name,char *oldpass,char *newpass, BOOL as_root)
377 pstring passwordprogram;
378 pstring chatsequence;
383 DEBUG(3,("Password change for user: %s\n",name));
386 DEBUG(100,("Passwords: old=%s new=%s\n",oldpass,newpass));
389 /* Take the passed information and test it for minimum criteria */
390 /* Minimum password length */
391 if (strlen(newpass) < MINPASSWDLENGTH) /* too short, must be at least MINPASSWDLENGTH */
393 DEBUG(2,("Password Change: %s, New password is shorter than MINPASSWDLENGTH\n",name));
394 return (False); /* inform the user */
397 /* Password is same as old password */
398 if (strcmp(oldpass,newpass) == 0) /* don't allow same password */
400 DEBUG(2,("Password Change: %s, New password is same as old\n",name)); /* log the attempt */
401 return (False); /* inform the user */
404 pstrcpy(passwordprogram,lp_passwd_program());
405 pstrcpy(chatsequence,lp_passwd_chat());
407 if (!*chatsequence) {
408 DEBUG(2,("Null chat sequence - no password changing\n"));
412 if (!*passwordprogram) {
413 DEBUG(2,("Null password program - no password changing\n"));
418 * Check the old and new passwords don't contain any control
422 len = strlen(oldpass);
423 for(i = 0; i < len; i++) {
424 if (iscntrl((int)oldpass[i])) {
425 DEBUG(0,("chat_with_program: oldpass contains control characters (disallowed).\n"));
430 len = strlen(newpass);
431 for(i = 0; i < len; i++) {
432 if (iscntrl((int)newpass[i])) {
433 DEBUG(0,("chat_with_program: newpass contains control characters (disallowed).\n"));
438 string_sub(passwordprogram,"%u",name);
439 all_string_sub(passwordprogram,"%o",oldpass);
440 all_string_sub(passwordprogram,"%n",newpass);
442 string_sub(chatsequence,"%u",name);
443 all_string_sub(chatsequence,"%o",oldpass);
444 all_string_sub(chatsequence,"%n",newpass);
445 return(chat_with_program(passwordprogram,name,chatsequence, as_root));
448 #else /* ALLOW_CHANGE_PASSWORD */
449 BOOL chgpasswd(char *name,char *oldpass,char *newpass, BOOL as_root)
451 DEBUG(0,("Password changing not compiled in (user=%s)\n",name));
454 #endif /* ALLOW_CHANGE_PASSWORD */
456 /***********************************************************
457 Code to check the lanman hashed password.
458 ************************************************************/
460 BOOL check_lanman_password(char *user, uchar *pass1,
461 uchar *pass2, struct smb_passwd **psmbpw)
463 static uchar null_pw[16];
464 uchar unenc_new_pw[16];
465 uchar unenc_old_pw[16];
466 struct smb_passwd *smbpw;
471 smbpw = getsmbpwnam(user);
476 DEBUG(0,("check_lanman_password: getsmbpwnam returned NULL\n"));
480 if (smbpw->acct_ctrl & ACB_DISABLED)
482 DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
486 if ((smbpw->smb_passwd == NULL) && (smbpw->acct_ctrl & ACB_PWNOTREQ))
489 memset(no_pw, '\0', 14);
490 E_P16(no_pw, null_pw);
491 smbpw->smb_passwd = null_pw;
492 } else if (smbpw->smb_passwd == NULL) {
493 DEBUG(0,("check_lanman_password: no lanman password !\n"));
497 /* Get the new lanman hash. */
498 D_P16(smbpw->smb_passwd, pass2, unenc_new_pw);
500 /* Use this to get the old lanman hash. */
501 D_P16(unenc_new_pw, pass1, unenc_old_pw);
503 /* Check that the two old passwords match. */
504 if (memcmp(smbpw->smb_passwd, unenc_old_pw, 16))
506 DEBUG(0,("check_lanman_password: old password doesn't match.\n"));
514 /***********************************************************
515 Code to change the lanman hashed password.
516 It nulls out the NT hashed password as it will
518 ************************************************************/
520 BOOL change_lanman_password(struct smb_passwd *smbpw, uchar *pass1, uchar *pass2)
522 static uchar null_pw[16];
523 uchar unenc_new_pw[16];
528 DEBUG(0,("change_lanman_password: no smb password entry.\n"));
532 if (smbpw->acct_ctrl & ACB_DISABLED)
534 DEBUG(0,("change_lanman_password: account %s disabled.\n", smbpw->unix_name));
538 if ((smbpw->smb_passwd == NULL) && (smbpw->acct_ctrl & ACB_PWNOTREQ))
541 memset(no_pw, '\0', 14);
542 E_P16(no_pw, null_pw);
543 smbpw->smb_passwd = null_pw;
544 } else if (smbpw->smb_passwd == NULL) {
545 DEBUG(0,("change_lanman_password: no lanman password !\n"));
549 /* Get the new lanman hash. */
550 D_P16(smbpw->smb_passwd, pass2, unenc_new_pw);
552 smbpw->smb_passwd = unenc_new_pw;
553 smbpw->smb_nt_passwd = NULL; /* We lose the NT hash. Sorry. */
555 /* Now write it into the file. */
557 ret = mod_smbpwd_entry(smbpw,False);
563 /***********************************************************
564 Code to check and change the OEM hashed password.
565 ************************************************************/
566 BOOL pass_oem_change(char *user,
567 uchar *lmdata, uchar *lmhash,
568 uchar *ntdata, uchar *nthash)
571 struct smb_passwd *sampw;
572 BOOL ret = check_oem_password( user, lmdata, lmhash, ntdata, nthash,
574 new_passwd, sizeof(new_passwd));
576 /* now we check to see if we are actually allowed to change the
579 if (ret && (sampw->acct_ctrl & ACB_PWLOCK))
585 * At this point we have the new case-sensitive plaintext
586 * password in the fstring new_passwd. If we wanted to synchronise
587 * with UNIX passwords we would call a UNIX password changing
588 * function here. However it would have to be done as root
589 * as the plaintext of the old users password is not
593 if ( ret && lp_unix_password_sync())
595 ret = chgpasswd(user,"", new_passwd, True);
600 ret = change_oem_password( sampw, new_passwd, False );
603 memset(new_passwd, 0, sizeof(new_passwd));
608 /***********************************************************
609 Code to check the OEM hashed password.
611 this function ignores the 516 byte nt OEM hashed password
612 but does use the lm OEM password to check the nt hashed-hash.
614 ************************************************************/
615 BOOL check_oem_password(char *user,
616 uchar *lmdata, uchar *lmhash,
617 uchar *ntdata, uchar *nthash,
618 struct smb_passwd **psmbpw, char *new_passwd,
621 static uchar null_pw[16];
622 static uchar null_ntpw[16];
623 struct smb_passwd *smbpw = NULL;
625 uchar unenc_old_ntpw[16];
627 uchar unenc_old_pw[16];
631 BOOL nt_pass_set = (ntdata != NULL && nthash != NULL);
634 *psmbpw = smbpw = getsmbpwnam(user);
635 unbecome_root(False);
639 DEBUG(0,("check_oem_password: getsmbpwnam returned NULL\n"));
643 if (smbpw->acct_ctrl & ACB_DISABLED)
645 DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
649 /* construct a null password (in case one is needed */
652 nt_lm_owf_gen(no_pw, null_ntpw, null_pw);
654 /* check for null passwords */
655 if (smbpw->smb_passwd == NULL)
657 if (smbpw->acct_ctrl & ACB_PWNOTREQ)
659 smbpw->smb_passwd = null_pw;
663 DEBUG(0,("check_oem_password: no lanman password !\n"));
668 if (smbpw->smb_nt_passwd == NULL && nt_pass_set)
670 if (smbpw->acct_ctrl & ACB_PWNOTREQ)
672 smbpw->smb_nt_passwd = null_pw;
676 DEBUG(0,("check_oem_password: no ntlm password !\n"));
682 * Call the hash function to get the new password.
684 SamOEMhash( (uchar *)lmdata, (uchar *)smbpw->smb_passwd, True);
686 if (!decode_pw_buffer(lmdata, new_passwd, new_passwd_size, &len))
692 * To ensure we got the correct new password, hash it and
693 * use it as a key to test the passed old password.
696 nt_lm_owf_gen(new_passwd, new_ntp16, new_p16);
701 * Now use new_p16 as the key to see if the old
704 D_P16(new_p16 , lmhash, unenc_old_pw);
706 if (memcmp(smbpw->smb_passwd, unenc_old_pw, 16))
708 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
712 #ifdef DEBUG_PASSWORD
713 DEBUG(100,("check_oem_password: password %s ok\n", new_passwd));
719 * Now use new_p16 as the key to see if the old
722 D_P16(new_ntp16, lmhash, unenc_old_pw);
723 D_P16(new_ntp16, nthash, unenc_old_ntpw);
725 if (memcmp(smbpw->smb_passwd, unenc_old_pw, 16))
727 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
731 if (memcmp(smbpw->smb_nt_passwd, unenc_old_ntpw, 16))
733 DEBUG(0,("check_oem_password: old nt password doesn't match.\n"));
736 #ifdef DEBUG_PASSWORD
737 DEBUG(100,("check_oem_password: password %s ok\n", new_passwd));
742 /***********************************************************
743 Code to change the oem password. Changes both the lanman
745 override = False, normal
746 override = True, override XXXXXXXXXX'd password
747 ************************************************************/
749 BOOL change_oem_password(struct smb_passwd *smbpw, char *new_passwd, BOOL override)
752 uchar new_nt_p16[16];
755 nt_lm_owf_gen(new_passwd, new_nt_p16, new_p16);
757 smbpw->smb_passwd = new_p16;
758 smbpw->smb_nt_passwd = new_nt_p16;
760 /* Now write it into the file. */
762 ret = mod_smbpwd_entry(smbpw,override);
765 memset(new_passwd, '\0', strlen(new_passwd));