LCOV - code coverage report
Current view: top level - source3/rpc_server/samr - srv_samr_chgpasswd.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 170 633 26.9 %
Date: 2024-04-21 15:09:00 Functions: 6 14 42.9 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Samba utility functions
       4             :    Copyright (C) Andrew Tridgell 1992-1998
       5             :    Copyright (C) Andrew Bartlett 2001-2004
       6             : 
       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 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      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.
      16             : 
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : /* These comments regard the code to change the user's unix password: */
      22             : 
      23             : /* fork a child process to exec passwd and write to its
      24             :  * tty to change a users password. This is running as the
      25             :  * user who is attempting to change the password.
      26             :  */
      27             : 
      28             : /*
      29             :  * This code was copied/borrowed and stolen from various sources.
      30             :  * The primary source was the poppasswd.c from the authors of POPMail. This software
      31             :  * was included as a client to change passwords using the 'passwd' program
      32             :  * on the remote machine.
      33             :  *
      34             :  * This code has been hacked by Bob Nance (nance@niehs.nih.gov) and Evan Patterson
      35             :  * (patters2@niehs.nih.gov) at the National Institute of Environmental Health Sciences
      36             :  * and rights to modify, distribute or incorporate this change to the CAP suite or
      37             :  * using it for any other reason are granted, so long as this disclaimer is left intact.
      38             :  */
      39             : 
      40             : /*
      41             :    This code was hacked considerably for inclusion in Samba, primarily
      42             :    by Andrew.Tridgell@anu.edu.au. The biggest change was the addition
      43             :    of the "password chat" option, which allows the easy runtime
      44             :    specification of the expected sequence of events to change a
      45             :    password.
      46             :    */
      47             : 
      48             : #include "includes.h"
      49             : #include "system/terminal.h"
      50             : #include "system/passwd.h"
      51             : #include "system/filesys.h"
      52             : #include "../libcli/auth/libcli_auth.h"
      53             : #include "rpc_server/samr/srv_samr_util.h"
      54             : #include "passdb.h"
      55             : #include "auth.h"
      56             : #include "lib/util/sys_rw.h"
      57             : #include "librpc/rpc/dcerpc_samr.h"
      58             : 
      59             : #include "lib/crypto/gnutls_helpers.h"
      60             : #include <gnutls/gnutls.h>
      61             : #include <gnutls/crypto.h>
      62             : 
      63             : #undef DBGC_CLASS
      64             : #define DBGC_CLASS DBGC_RPC_SRV
      65             : 
      66             : #ifndef ALLOW_CHANGE_PASSWORD
      67             : #if (defined(HAVE_TERMIOS_H) && defined(HAVE_DUP2) && defined(HAVE_SETSID))
      68             : #define ALLOW_CHANGE_PASSWORD 1
      69             : #endif
      70             : #endif
      71             : 
      72             : #if ALLOW_CHANGE_PASSWORD
      73             : 
      74           0 : static int findpty(char **slave)
      75             : {
      76           0 :         int master = -1;
      77           0 :         char *line = NULL;
      78           0 :         DIR *dirp = NULL;
      79           0 :         const char *dpname;
      80             : 
      81           0 :         *slave = NULL;
      82             : 
      83             : #if defined(HAVE_GRANTPT)
      84             : #if defined(HAVE_POSIX_OPENPT)
      85           0 :         master = posix_openpt(O_RDWR|O_NOCTTY);
      86             : #else
      87             :         /* Try to open /dev/ptmx. If that fails, fall through to old method. */
      88             :         master = open("/dev/ptmx", O_RDWR, 0);
      89             : #endif
      90           0 :         if (master >= 0) {
      91           0 :                 grantpt(master);
      92           0 :                 unlockpt(master);
      93           0 :                 line = (char *)ptsname(master);
      94           0 :                 if (line) {
      95           0 :                         *slave = SMB_STRDUP(line);
      96             :                 }
      97             : 
      98           0 :                 if (*slave == NULL) {
      99           0 :                         DEBUG(0,
     100             :                               ("findpty: Unable to create master/slave pty pair.\n"));
     101             :                         /* Stop fd leak on error. */
     102           0 :                         close(master);
     103           0 :                         return -1;
     104             :                 } else {
     105           0 :                         DEBUG(10,
     106             :                               ("findpty: Allocated slave pty %s\n", *slave));
     107           0 :                         return (master);
     108             :                 }
     109             :         }
     110             : #endif /* HAVE_GRANTPT */
     111             : 
     112           0 :         line = SMB_STRDUP("/dev/ptyXX");
     113           0 :         if (!line) {
     114           0 :                 return (-1);
     115             :         }
     116             : 
     117           0 :         dirp = opendir("/dev");
     118           0 :         if (!dirp) {
     119           0 :                 SAFE_FREE(line);
     120           0 :                 return (-1);
     121             :         }
     122             : 
     123           0 :         while ((dpname = readdirname(dirp)) != NULL) {
     124           0 :                 if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5) {
     125           0 :                         DEBUG(3,
     126             :                               ("pty: try to open %s, line was %s\n", dpname,
     127             :                                line));
     128           0 :                         line[8] = dpname[3];
     129           0 :                         line[9] = dpname[4];
     130           0 :                         if ((master = open(line, O_RDWR, 0)) >= 0) {
     131           0 :                                 DEBUG(3, ("pty: opened %s\n", line));
     132           0 :                                 line[5] = 't';
     133           0 :                                 *slave = line;
     134           0 :                                 closedir(dirp);
     135           0 :                                 return (master);
     136             :                         }
     137             :                 }
     138             :         }
     139           0 :         closedir(dirp);
     140           0 :         SAFE_FREE(line);
     141           0 :         return (-1);
     142             : }
     143             : 
     144           0 : static int dochild(int master, const char *slavedev, const struct passwd *pass,
     145             :                    const char *passwordprogram, bool as_root)
     146             : {
     147           0 :         int slave;
     148           0 :         struct termios stermios;
     149           0 :         gid_t gid;
     150           0 :         uid_t uid;
     151           0 :         char * const eptrs[1] = { NULL };
     152             : 
     153           0 :         if (pass == NULL)
     154             :         {
     155           0 :                 DEBUG(0,
     156             :                       ("dochild: user doesn't exist in the UNIX password database.\n"));
     157           0 :                 return False;
     158             :         }
     159             : 
     160           0 :         gid = pass->pw_gid;
     161           0 :         uid = pass->pw_uid;
     162             : 
     163           0 :         gain_root_privilege();
     164             : 
     165             :         /* Start new session - gets rid of controlling terminal. */
     166           0 :         if (setsid() < 0)
     167             :         {
     168           0 :                 DEBUG(3,
     169             :                       ("Weirdness, couldn't let go of controlling terminal\n"));
     170           0 :                 return (False);
     171             :         }
     172             : 
     173             :         /* Open slave pty and acquire as new controlling terminal. */
     174           0 :         if ((slave = open(slavedev, O_RDWR, 0)) < 0)
     175             :         {
     176           0 :                 DEBUG(3, ("More weirdness, could not open %s\n", slavedev));
     177           0 :                 return (False);
     178             :         }
     179             : #if defined(TIOCSCTTY) && !defined(SUNOS5)
     180             :         /*
     181             :          * On patched Solaris 10 TIOCSCTTY is defined but seems not to work,
     182             :          * see the discussion under
     183             :          * https://bugzilla.samba.org/show_bug.cgi?id=5366.
     184             :          */
     185           0 :         if (ioctl(slave, TIOCSCTTY, 0) < 0)
     186             :         {
     187           0 :                 DEBUG(3, ("Error in ioctl call for slave pty\n"));
     188             :                 /* return(False); */
     189             :         }
     190             : #elif defined(I_PUSH) && defined(I_FIND)
     191             :         if (ioctl(slave, I_FIND, "ptem") == 0) {
     192             :                 ioctl(slave, I_PUSH, "ptem");
     193             :         }
     194             :         if (ioctl(slave, I_FIND, "ldterm") == 0) {
     195             :                 ioctl(slave, I_PUSH, "ldterm");
     196             :         }
     197             : #endif
     198             : 
     199             :         /* Close master. */
     200           0 :         close(master);
     201             : 
     202             :         /* Make slave stdin/out/err of child. */
     203             : 
     204           0 :         if (dup2(slave, STDIN_FILENO) != STDIN_FILENO)
     205             :         {
     206           0 :                 DEBUG(3, ("Could not re-direct stdin\n"));
     207           0 :                 return (False);
     208             :         }
     209           0 :         if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO)
     210             :         {
     211           0 :                 DEBUG(3, ("Could not re-direct stdout\n"));
     212           0 :                 return (False);
     213             :         }
     214           0 :         if (dup2(slave, STDERR_FILENO) != STDERR_FILENO)
     215             :         {
     216           0 :                 DEBUG(3, ("Could not re-direct stderr\n"));
     217           0 :                 return (False);
     218             :         }
     219           0 :         if (slave > 2)
     220           0 :                 close(slave);
     221             : 
     222             :         /* Set proper terminal attributes - no echo, canonical input processing,
     223             :            no map NL to CR/NL on output. */
     224             : 
     225           0 :         if (tcgetattr(0, &stermios) < 0)
     226             :         {
     227           0 :                 DEBUG(3,
     228             :                       ("could not read default terminal attributes on pty\n"));
     229           0 :                 return (False);
     230             :         }
     231           0 :         stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
     232           0 :         stermios.c_lflag |= ICANON;
     233             : #ifdef ONLCR
     234           0 :         stermios.c_oflag &= ~(ONLCR);
     235             : #endif
     236           0 :         if (tcsetattr(0, TCSANOW, &stermios) < 0)
     237             :         {
     238           0 :                 DEBUG(3, ("could not set attributes of pty\n"));
     239           0 :                 return (False);
     240             :         }
     241             : 
     242             :         /* make us completely into the right uid */
     243           0 :         if (!as_root)
     244             :         {
     245           0 :                 become_user_permanently(uid, gid);
     246             :         }
     247             : 
     248           0 :         DEBUG(10,
     249             :               ("Invoking '%s' as password change program.\n",
     250             :                passwordprogram));
     251             : 
     252             :         /* execl() password-change application */
     253           0 :         if (execle("/bin/sh", "sh", "-c", passwordprogram, NULL, eptrs) < 0)
     254             :         {
     255           0 :                 DEBUG(3, ("Bad status returned from %s\n", passwordprogram));
     256           0 :                 return (False);
     257             :         }
     258           0 :         return (True);
     259             : }
     260             : 
     261           0 : static int expect(int master, char *issue, char *expected)
     262             : {
     263           0 :         char buffer[1024];
     264           0 :         int attempts, timeout, nread;
     265           0 :         size_t len;
     266           0 :         bool match = False;
     267             : 
     268           0 :         for (attempts = 0; attempts < 2; attempts++) {
     269           0 :                 NTSTATUS status;
     270           0 :                 if (!strequal(issue, ".")) {
     271           0 :                         if (lp_passwd_chat_debug())
     272           0 :                                 DEBUG(100, ("expect: sending [%s]\n", issue));
     273             : 
     274           0 :                         if ((len = sys_write(master, issue, strlen(issue))) != strlen(issue)) {
     275           0 :                                 DEBUG(2,("expect: (short) write returned %d\n",
     276             :                                          (int)len ));
     277           0 :                                 return False;
     278             :                         }
     279             :                 }
     280             : 
     281           0 :                 if (strequal(expected, "."))
     282           0 :                         return True;
     283             : 
     284             :                 /* Initial timeout. */
     285           0 :                 timeout = lp_passwd_chat_timeout() * 1000;
     286           0 :                 nread = 0;
     287           0 :                 buffer[nread] = 0;
     288             : 
     289           0 :                 while (True) {
     290           0 :                         status = read_fd_with_timeout(
     291             :                                 master, buffer + nread, 1,
     292             :                                 sizeof(buffer) - nread - 1,
     293             :                                 timeout, &len);
     294             : 
     295           0 :                         if (!NT_STATUS_IS_OK(status)) {
     296           0 :                                 DEBUG(2, ("expect: read error %s\n",
     297             :                                           nt_errstr(status)));
     298           0 :                                 break;
     299             :                         }
     300           0 :                         nread += len;
     301           0 :                         buffer[nread] = 0;
     302             : 
     303             :                         {
     304             :                                 /* Eat leading/trailing whitespace before match. */
     305           0 :                                 char *str = SMB_STRDUP(buffer);
     306           0 :                                 if (!str) {
     307           0 :                                         DEBUG(2,("expect: ENOMEM\n"));
     308           0 :                                         return False;
     309             :                                 }
     310           0 :                                 trim_char(str, ' ', ' ');
     311             : 
     312           0 :                                 if ((match = unix_wild_match(expected, str)) == True) {
     313             :                                         /* Now data has started to return, lower timeout. */
     314           0 :                                         timeout = lp_passwd_chat_timeout() * 100;
     315             :                                 }
     316           0 :                                 SAFE_FREE(str);
     317             :                         }
     318             :                 }
     319             : 
     320           0 :                 if (lp_passwd_chat_debug())
     321           0 :                         DEBUG(100, ("expect: expected [%s] received [%s] match %s\n",
     322             :                                     expected, buffer, match ? "yes" : "no" ));
     323             : 
     324           0 :                 if (match)
     325           0 :                         break;
     326             : 
     327           0 :                 if (!NT_STATUS_IS_OK(status)) {
     328           0 :                         DEBUG(2, ("expect: %s\n", nt_errstr(status)));
     329           0 :                         return False;
     330             :                 }
     331             :         }
     332             : 
     333           0 :         DEBUG(10,("expect: returning %s\n", match ? "True" : "False" ));
     334           0 :         return match;
     335             : }
     336             : 
     337           0 : static void pwd_sub(char *buf)
     338             : {
     339           0 :         all_string_sub(buf, "\\n", "\n", 0);
     340           0 :         all_string_sub(buf, "\\r", "\r", 0);
     341           0 :         all_string_sub(buf, "\\s", " ", 0);
     342           0 :         all_string_sub(buf, "\\t", "\t", 0);
     343           0 : }
     344             : 
     345           0 : static int talktochild(int master, const char *seq)
     346             : {
     347           0 :         TALLOC_CTX *frame = talloc_stackframe();
     348           0 :         int count = 0;
     349           0 :         char *issue;
     350           0 :         char *expected;
     351             : 
     352           0 :         issue = talloc_strdup(frame, ".");
     353           0 :         if (!issue) {
     354           0 :                 TALLOC_FREE(frame);
     355           0 :                 return false;
     356             :         }
     357             : 
     358           0 :         while (next_token_talloc(frame, &seq, &expected, NULL)) {
     359           0 :                 pwd_sub(expected);
     360           0 :                 count++;
     361             : 
     362           0 :                 if (!expect(master, issue, expected)) {
     363           0 :                         DEBUG(3, ("Response %d incorrect\n", count));
     364           0 :                         TALLOC_FREE(frame);
     365           0 :                         return false;
     366             :                 }
     367             : 
     368           0 :                 if (!next_token_talloc(frame, &seq, &issue, NULL)) {
     369           0 :                         issue = talloc_strdup(frame, ".");
     370           0 :                         if (!issue) {
     371           0 :                                 TALLOC_FREE(frame);
     372           0 :                                 return false;
     373             :                         }
     374             :                 }
     375           0 :                 pwd_sub(issue);
     376             :         }
     377             : 
     378           0 :         if (!strequal(issue, ".")) {
     379             :                 /* we have one final issue to send */
     380           0 :                 expected = talloc_strdup(frame, ".");
     381           0 :                 if (!expected) {
     382           0 :                         TALLOC_FREE(frame);
     383           0 :                         return false;
     384             :                 }
     385           0 :                 if (!expect(master, issue, expected)) {
     386           0 :                         TALLOC_FREE(frame);
     387           0 :                         return False;
     388             :                 }
     389             :         }
     390           0 :         TALLOC_FREE(frame);
     391           0 :         return (count > 0);
     392             : }
     393             : 
     394           0 : static bool chat_with_program(char *passwordprogram, const struct passwd *pass,
     395             :                               char *chatsequence, bool as_root)
     396             : {
     397           0 :         char *slavedev = NULL;
     398           0 :         int master;
     399           0 :         pid_t pid, wpid;
     400           0 :         int wstat;
     401           0 :         bool chstat = False;
     402           0 :         void (*saved_handler)(int);
     403             : 
     404           0 :         if (pass == NULL) {
     405           0 :                 DEBUG(0, ("chat_with_program: user doesn't exist in the UNIX password database.\n"));
     406           0 :                 return False;
     407             :         }
     408             : 
     409             :         /* allocate a pseudo-terminal device */
     410           0 :         if ((master = findpty(&slavedev)) < 0) {
     411           0 :                 DEBUG(3, ("chat_with_program: Cannot Allocate pty for password change: %s\n", pass->pw_name));
     412           0 :                 return (False);
     413             :         }
     414             : 
     415             :         /*
     416             :          * We need to temporarily stop CatchChild from eating
     417             :          * SIGCLD signals as it also eats the exit status code. JRA.
     418             :          */
     419             : 
     420           0 :         saved_handler = CatchChildLeaveStatus();
     421             : 
     422           0 :         if ((pid = fork()) < 0) {
     423           0 :                 DEBUG(3, ("chat_with_program: Cannot fork() child for password change: %s\n", pass->pw_name));
     424           0 :                 SAFE_FREE(slavedev);
     425           0 :                 close(master);
     426           0 :                 (void)CatchSignal(SIGCLD, saved_handler);
     427           0 :                 return (False);
     428             :         }
     429             : 
     430             :         /* we now have a pty */
     431           0 :         if (pid > 0) {                       /* This is the parent process */
     432             :                 /* Don't need this anymore in parent. */
     433           0 :                 SAFE_FREE(slavedev);
     434             : 
     435           0 :                 if ((chstat = talktochild(master, chatsequence)) == False) {
     436           0 :                         DEBUG(3, ("chat_with_program: Child failed to change password: %s\n", pass->pw_name));
     437           0 :                         kill(pid, SIGKILL);     /* be sure to end this process */
     438             :                 }
     439             : 
     440           0 :                 while ((wpid = waitpid(pid, &wstat, 0)) < 0) {
     441           0 :                         if (errno == EINTR) {
     442           0 :                                 errno = 0;
     443           0 :                                 continue;
     444             :                         }
     445           0 :                         break;
     446             :                 }
     447             : 
     448           0 :                 if (wpid < 0) {
     449           0 :                         DEBUG(3, ("chat_with_program: The process is no longer waiting!\n\n"));
     450           0 :                         close(master);
     451           0 :                         (void)CatchSignal(SIGCLD, saved_handler);
     452           0 :                         return (False);
     453             :                 }
     454             : 
     455             :                 /*
     456             :                  * Go back to ignoring children.
     457             :                  */
     458           0 :                 (void)CatchSignal(SIGCLD, saved_handler);
     459             : 
     460           0 :                 close(master);
     461             : 
     462           0 :                 if (pid != wpid) {
     463           0 :                         DEBUG(3, ("chat_with_program: We were waiting for the wrong process ID\n"));
     464           0 :                         return (False);
     465             :                 }
     466           0 :                 if (WIFEXITED(wstat) && (WEXITSTATUS(wstat) != 0)) {
     467           0 :                         DEBUG(3, ("chat_with_program: The process exited with status %d \
     468             : while we were waiting\n", WEXITSTATUS(wstat)));
     469           0 :                         return (False);
     470             :                 }
     471             : #if defined(WIFSIGNALLED) && defined(WTERMSIG)
     472             :                 else if (WIFSIGNALLED(wstat)) {
     473             :                         DEBUG(3, ("chat_with_program: The process was killed by signal %d \
     474             : while we were waiting\n", WTERMSIG(wstat)));
     475             :                         return (False);
     476             :                 }
     477             : #endif
     478             :         } else {
     479             :                 /* CHILD */
     480             : 
     481             :                 /*
     482             :                  * Lose any elevated privileges.
     483             :                  */
     484           0 :                 drop_effective_capability(KERNEL_OPLOCK_CAPABILITY);
     485           0 :                 drop_effective_capability(DMAPI_ACCESS_CAPABILITY);
     486             : 
     487             :                 /* make sure it doesn't freeze */
     488           0 :                 alarm(20);
     489             : 
     490           0 :                 if (as_root)
     491           0 :                         become_root();
     492             : 
     493           0 :                 DEBUG(3, ("chat_with_program: Dochild for user %s (uid=%d,gid=%d) (as_root = %s)\n", pass->pw_name,
     494             :                        (int)getuid(), (int)getgid(), BOOLSTR(as_root) ));
     495           0 :                 chstat = dochild(master, slavedev, pass, passwordprogram, as_root);
     496             : 
     497           0 :                 if (as_root)
     498           0 :                         unbecome_root();
     499             : 
     500             :                 /*
     501             :                  * The child should never return from dochild() ....
     502             :                  */
     503             : 
     504           0 :                 DEBUG(0, ("chat_with_program: Error: dochild() returned %d\n", chstat));
     505           0 :                 exit(1);
     506             :         }
     507             : 
     508           0 :         if (chstat)
     509           0 :                 DEBUG(3, ("chat_with_program: Password change %ssuccessful for user %s\n",
     510             :                        (chstat ? "" : "un"), pass->pw_name));
     511           0 :         return (chstat);
     512             : }
     513             : 
     514           0 : bool chgpasswd(const char *name, const char *rhost, const struct passwd *pass,
     515             :                const char *oldpass, const char *newpass, bool as_root)
     516             : {
     517           0 :         const struct loadparm_substitution *lp_sub =
     518           0 :                 loadparm_s3_global_substitution();
     519           0 :         char *passwordprogram = NULL;
     520           0 :         char *chatsequence = NULL;
     521           0 :         size_t i;
     522           0 :         size_t len;
     523           0 :         TALLOC_CTX *ctx = talloc_tos();
     524             : 
     525           0 :         if (!oldpass) {
     526           0 :                 oldpass = "";
     527             :         }
     528             : 
     529           0 :         DEBUG(3, ("chgpasswd: Password change (as_root=%s) for user: %s\n", BOOLSTR(as_root), name));
     530             : 
     531             : #ifdef DEBUG_PASSWORD
     532           0 :         DEBUG(100, ("chgpasswd: Passwords: old=%s new=%s\n", oldpass, newpass));
     533             : #endif
     534             : 
     535             :         /* Take the passed information and test it for minimum criteria */
     536             : 
     537             :         /* Password is same as old password */
     538           0 :         if (strcmp(oldpass, newpass) == 0) {
     539             :                 /* don't allow same password */
     540           0 :                 DEBUG(2, ("chgpasswd: Password Change: %s, New password is same as old\n", name));    /* log the attempt */
     541           0 :                 return (False); /* inform the user */
     542             :         }
     543             : 
     544             :         /*
     545             :          * Check the old and new passwords don't contain any control
     546             :          * characters.
     547             :          */
     548             : 
     549           0 :         len = strlen(oldpass);
     550           0 :         for (i = 0; i < len; i++) {
     551           0 :                 if (iscntrl((int)oldpass[i])) {
     552           0 :                         DEBUG(0, ("chgpasswd: oldpass contains control characters (disallowed).\n"));
     553           0 :                         return False;
     554             :                 }
     555             :         }
     556             : 
     557           0 :         len = strlen(newpass);
     558           0 :         for (i = 0; i < len; i++) {
     559           0 :                 if (iscntrl((int)newpass[i])) {
     560           0 :                         DEBUG(0, ("chgpasswd: newpass contains control characters (disallowed).\n"));
     561           0 :                         return False;
     562             :                 }
     563             :         }
     564             : 
     565             : #ifdef WITH_PAM
     566           0 :         if (lp_pam_password_change()) {
     567           0 :                 bool ret;
     568             : #ifdef HAVE_SETLOCALE
     569           0 :                 const char *prevlocale = setlocale(LC_ALL, "C");
     570             : #endif
     571             : 
     572           0 :                 if (as_root)
     573           0 :                         become_root();
     574             : 
     575           0 :                 if (pass) {
     576           0 :                         ret = smb_pam_passchange(pass->pw_name, rhost,
     577             :                                                  oldpass, newpass);
     578             :                 } else {
     579           0 :                         ret = smb_pam_passchange(name, rhost, oldpass,
     580             :                                                  newpass);
     581             :                 }
     582             : 
     583           0 :                 if (as_root)
     584           0 :                         unbecome_root();
     585             : 
     586             : #ifdef HAVE_SETLOCALE
     587           0 :                 setlocale(LC_ALL, prevlocale);
     588             : #endif
     589             : 
     590           0 :                 return ret;
     591             :         }
     592             : #endif
     593             : 
     594             :         /* A non-PAM password change just doesn't make sense without a valid local user */
     595             : 
     596           0 :         if (pass == NULL) {
     597           0 :                 DEBUG(0, ("chgpasswd: user %s doesn't exist in the UNIX password database.\n", name));
     598           0 :                 return false;
     599             :         }
     600             : 
     601           0 :         passwordprogram = lp_passwd_program(ctx, lp_sub);
     602           0 :         if (!passwordprogram || !*passwordprogram) {
     603           0 :                 DEBUG(2, ("chgpasswd: Null password program - no password changing\n"));
     604           0 :                 return false;
     605             :         }
     606           0 :         chatsequence = lp_passwd_chat(ctx, lp_sub);
     607           0 :         if (!chatsequence || !*chatsequence) {
     608           0 :                 DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n"));
     609           0 :                 return false;
     610             :         }
     611             : 
     612           0 :         if (as_root) {
     613             :                 /* The password program *must* contain the user name to work. Fail if not. */
     614           0 :                 if (strstr_m(passwordprogram, "%u") == NULL) {
     615           0 :                         DEBUG(0,("chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \
     616             : the string %%u, and the given string %s does not.\n", passwordprogram ));
     617           0 :                         return false;
     618             :                 }
     619             :         }
     620             : 
     621           0 :         passwordprogram = talloc_string_sub(ctx, passwordprogram, "%u", name);
     622           0 :         if (!passwordprogram) {
     623           0 :                 return false;
     624             :         }
     625             : 
     626             :         /* note that we do NOT substitute the %o and %n in the password program
     627             :            as this would open up a security hole where the user could use
     628             :            a new password containing shell escape characters */
     629             : 
     630           0 :         chatsequence = talloc_string_sub(ctx, chatsequence, "%u", name);
     631           0 :         if (!chatsequence) {
     632           0 :                 return false;
     633             :         }
     634           0 :         chatsequence = talloc_all_string_sub(ctx,
     635             :                                         chatsequence,
     636             :                                         "%o",
     637             :                                         oldpass);
     638           0 :         if (!chatsequence) {
     639           0 :                 return false;
     640             :         }
     641           0 :         chatsequence = talloc_all_string_sub(ctx,
     642             :                                         chatsequence,
     643             :                                         "%n",
     644             :                                         newpass);
     645           0 :         if (chatsequence == NULL) {
     646           0 :                 return false;
     647             :         }
     648           0 :         return chat_with_program(passwordprogram,
     649             :                                 pass,
     650             :                                 chatsequence,
     651             :                                 as_root);
     652             : }
     653             : 
     654             : #else /* ALLOW_CHANGE_PASSWORD */
     655             : 
     656             : bool chgpasswd(const char *name, const struct passwd *pass,
     657             :                const char *oldpass, const char *newpass, bool as_root)
     658             : {
     659             :         DEBUG(0, ("chgpasswd: Unix Password changing not compiled in (user=%s)\n", name));
     660             :         return (False);
     661             : }
     662             : #endif /* ALLOW_CHANGE_PASSWORD */
     663             : 
     664             : /***********************************************************
     665             :  Decrypt and verify a user password change.
     666             : 
     667             :  The 516 byte long buffers are encrypted with the old NT and
     668             :  old LM passwords, and if the NT passwords are present, both
     669             :  buffers contain a unicode string.
     670             : 
     671             :  After decrypting the buffers, check the password is correct by
     672             :  matching the old hashed passwords with the passwords in the passdb.
     673             : 
     674             : ************************************************************/
     675             : 
     676         180 : static NTSTATUS check_oem_password(const char *user,
     677             :                                    uchar password_encrypted_with_lm_hash[516],
     678             :                                    const uchar old_lm_hash_encrypted[16],
     679             :                                    uchar password_encrypted_with_nt_hash[516],
     680             :                                    const uchar old_nt_hash_encrypted[16],
     681             :                                    struct samu *sampass,
     682             :                                    char **pp_new_passwd)
     683             : {
     684           0 :         uchar null_pw[16];
     685           0 :         uchar null_ntpw[16];
     686           0 :         uint8_t *password_encrypted;
     687           0 :         const uint8_t *encryption_key;
     688           0 :         const uint8_t *lanman_pw, *nt_pw;
     689           0 :         uint32_t acct_ctrl;
     690           0 :         size_t new_pw_len;
     691           0 :         uchar new_nt_hash[16];
     692           0 :         uchar new_lm_hash[16];
     693           0 :         uchar verifier[16];
     694           0 :         char no_pw[2];
     695             : 
     696         180 :         bool nt_pass_set = (password_encrypted_with_nt_hash && old_nt_hash_encrypted);
     697         180 :         bool lm_pass_set = (password_encrypted_with_lm_hash && old_lm_hash_encrypted);
     698         180 :         enum ntlm_auth_level ntlm_auth_level = lp_ntlm_auth();
     699             : 
     700         180 :         gnutls_cipher_hd_t cipher_hnd = NULL;
     701           0 :         gnutls_datum_t enc_key;
     702           0 :         int rc;
     703             : 
     704             :         /* this call should be disabled without NTLM auth */
     705         180 :         if (ntlm_auth_level == NTLM_AUTH_DISABLED) {
     706           2 :                 DBG_WARNING("NTLM password changes not"
     707             :                             "permitted by configuration.\n");
     708           2 :                 return NT_STATUS_NTLM_BLOCKED;
     709             :         }
     710             : 
     711         178 :         acct_ctrl = pdb_get_acct_ctrl(sampass);
     712             : #if 0
     713             :         /* I am convinced this check here is wrong, it is valid to
     714             :          * change a password of a user that has a disabled account - gd */
     715             : 
     716             :         if (acct_ctrl & ACB_DISABLED) {
     717             :                 DEBUG(2,("check_lanman_password: account %s disabled.\n", user));
     718             :                 return NT_STATUS_ACCOUNT_DISABLED;
     719             :         }
     720             : #endif
     721         178 :         if ((acct_ctrl & ACB_PWNOTREQ) && lp_null_passwords()) {
     722             :                 /* construct a null password (in case one is needed */
     723           0 :                 no_pw[0] = 0;
     724           0 :                 no_pw[1] = 0;
     725           0 :                 nt_lm_owf_gen(no_pw, null_ntpw, null_pw);
     726           0 :                 lanman_pw = null_pw;
     727           0 :                 nt_pw = null_pw;
     728             : 
     729             :         } else {
     730             :                 /* save pointers to passwords so we don't have to keep looking them up */
     731         178 :                 if (lp_lanman_auth()) {
     732         176 :                         lanman_pw = pdb_get_lanman_passwd(sampass);
     733             :                 } else {
     734           2 :                         lanman_pw = NULL;
     735             :                 }
     736         178 :                 nt_pw = pdb_get_nt_passwd(sampass);
     737             :         }
     738             : 
     739         178 :         if (nt_pw && nt_pass_set) {
     740             :                 /* IDEAL Case: passwords are in unicode, and we can
     741             :                  * read use the password encrypted with the NT hash
     742             :                  */
     743         162 :                 password_encrypted = password_encrypted_with_nt_hash;
     744         162 :                 encryption_key = nt_pw;
     745          16 :         } else if (lanman_pw && lm_pass_set) {
     746             :                 /* password may still be in unicode, but use LM hash version */
     747          14 :                 password_encrypted = password_encrypted_with_lm_hash;
     748          14 :                 encryption_key = lanman_pw;
     749           2 :         } else if (nt_pass_set) {
     750           0 :                 DEBUG(1, ("NT password change supplied for user %s, but we have no NT password to check it with\n",
     751             :                           user));
     752           0 :                 return NT_STATUS_WRONG_PASSWORD;
     753           2 :         } else if (lm_pass_set) {
     754           0 :                 if (lp_lanman_auth()) {
     755           0 :                         DEBUG(1, ("LM password change supplied for user %s, but we have no LanMan password to check it with\n",
     756             :                                   user));
     757             :                 } else {
     758           0 :                         DEBUG(1, ("LM password change supplied for user %s, but we have disabled LanMan authentication\n",
     759             :                                   user));
     760             :                 }
     761           0 :                 return NT_STATUS_WRONG_PASSWORD;
     762             :         } else {
     763           2 :                 DEBUG(1, ("password change requested for user %s, but no password supplied!\n",
     764             :                           user));
     765           2 :                 return NT_STATUS_WRONG_PASSWORD;
     766             :         }
     767             : 
     768             :         /*
     769             :          * Decrypt the password with the key
     770             :          */
     771         176 :         enc_key = (gnutls_datum_t) {
     772             :                 .data = discard_const_p(unsigned char, encryption_key),
     773             :                 .size = 16,
     774             :         };
     775             : 
     776         176 :         GNUTLS_FIPS140_SET_LAX_MODE();
     777         176 :         rc = gnutls_cipher_init(&cipher_hnd,
     778             :                                 GNUTLS_CIPHER_ARCFOUR_128,
     779             :                                 &enc_key,
     780             :                                 NULL);
     781         176 :         if (rc < 0) {
     782           0 :                 GNUTLS_FIPS140_SET_STRICT_MODE();
     783           0 :                 return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
     784             :         }
     785             : 
     786         176 :         rc = gnutls_cipher_decrypt(cipher_hnd,
     787             :                                    password_encrypted,
     788             :                                    516);
     789         176 :         gnutls_cipher_deinit(cipher_hnd);
     790         176 :         GNUTLS_FIPS140_SET_STRICT_MODE();
     791         176 :         if (rc < 0) {
     792           0 :                 return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
     793             :         }
     794             : 
     795         176 :         if (!decode_pw_buffer(talloc_tos(),
     796             :                                 password_encrypted,
     797             :                                 pp_new_passwd,
     798             :                                 &new_pw_len,
     799             :                                 nt_pass_set ? CH_UTF16 : CH_DOS)) {
     800          56 :                 return NT_STATUS_WRONG_PASSWORD;
     801             :         }
     802             : 
     803             :         /*
     804             :          * To ensure we got the correct new password, hash it and
     805             :          * use it as a key to test the passed old password.
     806             :          */
     807             : 
     808         120 :         if (nt_pass_set) {
     809             :                 /* NT passwords, verify the NT hash. */
     810             : 
     811             :                 /* Calculate the MD4 hash (NT compatible) of the password */
     812         110 :                 memset(new_nt_hash, '\0', 16);
     813         110 :                 E_md4hash(*pp_new_passwd, new_nt_hash);
     814             : 
     815         110 :                 if (nt_pw) {
     816             :                         /*
     817             :                          * check the NT verifier
     818             :                          */
     819         110 :                         rc = E_old_pw_hash(new_nt_hash, nt_pw, verifier);
     820         110 :                         if (rc != 0) {
     821           0 :                                 NTSTATUS status = NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER;
     822           0 :                                 return gnutls_error_to_ntstatus(rc, status);
     823             :                         }
     824         110 :                         if (!mem_equal_const_time(verifier, old_nt_hash_encrypted, 16)) {
     825          52 :                                 DEBUG(0, ("check_oem_password: old nt "
     826             :                                           "password doesn't match.\n"));
     827          52 :                                 return NT_STATUS_WRONG_PASSWORD;
     828             :                         }
     829             : 
     830             :                         /* We could check the LM password here, but there is
     831             :                          * little point, we already know the password is
     832             :                          * correct, and the LM password might not even be
     833             :                          * present. */
     834             : 
     835             :                         /* Further, LM hash generation algorithms
     836             :                          * differ with charset, so we could
     837             :                          * incorrectly fail a perfectly valid password
     838             :                          * change */
     839             : #ifdef DEBUG_PASSWORD
     840          58 :                         DEBUG(100,
     841             :                               ("check_oem_password: password %s ok\n", *pp_new_passwd));
     842             : #endif
     843          58 :                         return NT_STATUS_OK;
     844             :                 }
     845             : 
     846           0 :                 if (lanman_pw) {
     847             :                         /*
     848             :                          * check the lm verifier
     849             :                          */
     850           0 :                         rc = E_old_pw_hash(new_nt_hash, lanman_pw, verifier);
     851           0 :                         if (rc != 0) {
     852           0 :                                 NTSTATUS status = NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER;
     853           0 :                                 return gnutls_error_to_ntstatus(rc, status);
     854             :                         }
     855           0 :                         if (!mem_equal_const_time(verifier, old_lm_hash_encrypted, 16)) {
     856           0 :                                 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
     857           0 :                                 return NT_STATUS_WRONG_PASSWORD;
     858             :                         }
     859             : #ifdef DEBUG_PASSWORD
     860           0 :                         DEBUG(100,
     861             :                               ("check_oem_password: password %s ok\n", *pp_new_passwd));
     862             : #endif
     863           0 :                         return NT_STATUS_OK;
     864             :                 }
     865             :         }
     866             : 
     867          10 :         if (lanman_pw && lm_pass_set) {
     868             : 
     869          10 :                 E_deshash(*pp_new_passwd, new_lm_hash);
     870             : 
     871             :                 /*
     872             :                  * check the lm verifier
     873             :                  */
     874          10 :                 rc = E_old_pw_hash(new_lm_hash, lanman_pw, verifier);
     875          10 :                 if (rc != 0) {
     876           0 :                         NTSTATUS status = NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER;
     877           0 :                         return gnutls_error_to_ntstatus(rc, status);
     878             :                 }
     879          10 :                 if (!mem_equal_const_time(verifier, old_lm_hash_encrypted, 16)) {
     880           4 :                         DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
     881           4 :                         return NT_STATUS_WRONG_PASSWORD;
     882             :                 }
     883             : 
     884             : #ifdef DEBUG_PASSWORD
     885           6 :                 DEBUG(100,
     886             :                       ("check_oem_password: password %s ok\n", *pp_new_passwd));
     887             : #endif
     888           6 :                 return NT_STATUS_OK;
     889             :         }
     890             : 
     891             :         /* should not be reached */
     892           0 :         return NT_STATUS_WRONG_PASSWORD;
     893             : }
     894             : 
     895           0 : static bool password_in_history(uint8_t nt_pw[NT_HASH_LEN],
     896             :                                 uint32_t pw_history_len,
     897             :                                 const uint8_t *pw_history)
     898             : {
     899           0 :         int i;
     900             : 
     901           0 :         dump_data(100, nt_pw, NT_HASH_LEN);
     902           0 :         dump_data(100, pw_history, PW_HISTORY_ENTRY_LEN * pw_history_len);
     903             : 
     904           0 :         for (i=0; i<pw_history_len; i++) {
     905           0 :                 uint8_t new_nt_pw_salted_md5_hash[SALTED_MD5_HASH_LEN];
     906           0 :                 const uint8_t *current_salt;
     907           0 :                 const uint8_t *old_nt_pw_salted_md5_hash;
     908             : 
     909           0 :                 current_salt = &pw_history[i*PW_HISTORY_ENTRY_LEN];
     910           0 :                 old_nt_pw_salted_md5_hash = current_salt + PW_HISTORY_SALT_LEN;
     911             : 
     912           0 :                 if (all_zero(old_nt_pw_salted_md5_hash, SALTED_MD5_HASH_LEN)) {
     913             :                         /* Ignore zero valued entries. */
     914           0 :                         continue;
     915             :                 }
     916             : 
     917           0 :                 if (all_zero(current_salt, PW_HISTORY_SALT_LEN)) {
     918             :                         /*
     919             :                          * New format: zero salt and then plain nt hash.
     920             :                          * Directly compare the hashes.
     921             :                          */
     922           0 :                         if (mem_equal_const_time(nt_pw, old_nt_pw_salted_md5_hash,
     923             :                                                  SALTED_MD5_HASH_LEN))
     924             :                         {
     925           0 :                                 return true;
     926             :                         }
     927             :                 } else {
     928           0 :                         gnutls_hash_hd_t hash_hnd = NULL;
     929           0 :                         int rc;
     930             : 
     931             :                         /*
     932             :                          * Old format: md5sum of salted nt hash.
     933             :                          * Create salted version of new pw to compare.
     934             :                          */
     935           0 :                         rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
     936           0 :                         if (rc < 0) {
     937           0 :                                 return false;
     938             :                         }
     939             : 
     940           0 :                         rc = gnutls_hash(hash_hnd, current_salt, 16);
     941           0 :                         if (rc < 0) {
     942           0 :                                 gnutls_hash_deinit(hash_hnd, NULL);
     943           0 :                                 return false;
     944             :                         }
     945           0 :                         rc = gnutls_hash(hash_hnd, nt_pw, 16);
     946           0 :                         if (rc < 0) {
     947           0 :                                 gnutls_hash_deinit(hash_hnd, NULL);
     948           0 :                                 return false;
     949             :                         }
     950           0 :                         gnutls_hash_deinit(hash_hnd, new_nt_pw_salted_md5_hash);
     951             : 
     952           0 :                         if (mem_equal_const_time(new_nt_pw_salted_md5_hash,
     953             :                                                  old_nt_pw_salted_md5_hash,
     954             :                                                  SALTED_MD5_HASH_LEN)) {
     955           0 :                                 return true;
     956             :                         }
     957             :                 }
     958             :         }
     959           0 :         return false;
     960             : }
     961             : 
     962             : /***********************************************************
     963             :  This routine takes the given password and checks it against
     964             :  the password history. Returns True if this password has been
     965             :  found in the history list.
     966             : ************************************************************/
     967             : 
     968          70 : static bool check_passwd_history(struct samu *sampass, const char *plaintext)
     969             : {
     970           0 :         uchar new_nt_p16[NT_HASH_LEN];
     971           0 :         const uint8_t *nt_pw;
     972           0 :         const uint8_t *pwhistory;
     973           0 :         uint32_t pwHisLen, curr_pwHisLen;
     974             : 
     975          70 :         pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHisLen);
     976          70 :         if (pwHisLen == 0) {
     977          70 :                 return False;
     978             :         }
     979             : 
     980           0 :         pwhistory = pdb_get_pw_history(sampass, &curr_pwHisLen);
     981           0 :         if (!pwhistory || curr_pwHisLen == 0) {
     982           0 :                 return False;
     983             :         }
     984             : 
     985             :         /* Only examine the minimum of the current history len and
     986             :            the stored history len. Avoids race conditions. */
     987           0 :         pwHisLen = MIN(pwHisLen,curr_pwHisLen);
     988             : 
     989           0 :         nt_pw = pdb_get_nt_passwd(sampass);
     990             : 
     991           0 :         E_md4hash(plaintext, new_nt_p16);
     992             : 
     993           0 :         if (mem_equal_const_time(nt_pw, new_nt_p16, NT_HASH_LEN)) {
     994           0 :                 DEBUG(10,("check_passwd_history: proposed new password for user %s is the same as the current password !\n",
     995             :                         pdb_get_username(sampass) ));
     996           0 :                 return True;
     997             :         }
     998             : 
     999           0 :         if (password_in_history(new_nt_p16, pwHisLen, pwhistory)) {
    1000           0 :                 DEBUG(1,("check_passwd_history: proposed new password for "
    1001             :                          "user %s found in history list !\n",
    1002             :                          pdb_get_username(sampass) ));
    1003           0 :                 return true;
    1004             :         }
    1005           0 :         return false;
    1006             : }
    1007             : 
    1008             : /***********************************************************
    1009             : ************************************************************/
    1010             : 
    1011          70 : NTSTATUS check_password_complexity(const char *username,
    1012             :                                    const char *fullname,
    1013             :                                    const char *password,
    1014             :                                    enum samPwdChangeReason *samr_reject_reason)
    1015             : {
    1016          70 :         TALLOC_CTX *tosctx = talloc_tos();
    1017           0 :         const struct loadparm_substitution *lp_sub =
    1018          70 :                 loadparm_s3_global_substitution();
    1019           0 :         int check_ret;
    1020           0 :         char *cmd;
    1021             : 
    1022             :         /* Use external script to check password complexity */
    1023          70 :         if ((lp_check_password_script(tosctx, lp_sub) == NULL)
    1024          70 :             || (*(lp_check_password_script(tosctx, lp_sub)) == '\0')){
    1025          70 :                 return NT_STATUS_OK;
    1026             :         }
    1027             : 
    1028           0 :         cmd = talloc_string_sub(tosctx, lp_check_password_script(tosctx, lp_sub), "%u",
    1029             :                                 username);
    1030           0 :         if (!cmd) {
    1031           0 :                 return NT_STATUS_PASSWORD_RESTRICTION;
    1032             :         }
    1033             : 
    1034           0 :         check_ret = setenv("SAMBA_CPS_ACCOUNT_NAME", username, 1);
    1035           0 :         if (check_ret != 0) {
    1036           0 :                 return map_nt_error_from_unix_common(errno);
    1037             :         }
    1038           0 :         unsetenv("SAMBA_CPS_USER_PRINCIPAL_NAME");
    1039           0 :         if (fullname != NULL) {
    1040           0 :                 check_ret = setenv("SAMBA_CPS_FULL_NAME", fullname, 1);
    1041             :         } else {
    1042           0 :                 unsetenv("SAMBA_CPS_FULL_NAME");
    1043             :         }
    1044           0 :         if (check_ret != 0) {
    1045           0 :                 return map_nt_error_from_unix_common(errno);
    1046             :         }
    1047           0 :         check_ret = smbrunsecret(cmd, password);
    1048           0 :         unsetenv("SAMBA_CPS_ACCOUNT_NAME");
    1049           0 :         unsetenv("SAMBA_CPS_USER_PRINCIPAL_NAME");
    1050           0 :         unsetenv("SAMBA_CPS_FULL_NAME");
    1051           0 :         DEBUG(5,("check_password_complexity: check password script (%s) "
    1052             :                  "returned [%d]\n", cmd, check_ret));
    1053           0 :         TALLOC_FREE(cmd);
    1054             : 
    1055           0 :         if (check_ret != 0) {
    1056           0 :                 DEBUG(1,("check_password_complexity: "
    1057             :                          "check password script said new password is not good "
    1058             :                          "enough!\n"));
    1059           0 :                 if (samr_reject_reason) {
    1060           0 :                         *samr_reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
    1061             :                 }
    1062           0 :                 return NT_STATUS_PASSWORD_RESTRICTION;
    1063             :         }
    1064             : 
    1065           0 :         return NT_STATUS_OK;
    1066             : }
    1067             : 
    1068             : /***********************************************************
    1069             :  Code to change the oem password. Changes both the lanman
    1070             :  and NT hashes.  Old_passwd is almost always NULL.
    1071             :  NOTE this function is designed to be called as root. Check the old password
    1072             :  is correct before calling. JRA.
    1073             : ************************************************************/
    1074             : 
    1075          74 : NTSTATUS change_oem_password(struct samu *hnd, const char *rhost,
    1076             :                              char *old_passwd, char *new_passwd,
    1077             :                              bool as_root,
    1078             :                              enum samPwdChangeReason *samr_reject_reason)
    1079             : {
    1080           0 :         uint32_t min_len;
    1081           0 :         uint32_t refuse;
    1082          74 :         TALLOC_CTX *tosctx = talloc_tos();
    1083          74 :         struct passwd *pass = NULL;
    1084          74 :         const char *username = pdb_get_username(hnd);
    1085          74 :         const char *fullname = pdb_get_fullname(hnd);
    1086          74 :         time_t can_change_time = pdb_get_pass_can_change_time(hnd);
    1087           0 :         NTSTATUS status;
    1088             : 
    1089          74 :         if (samr_reject_reason) {
    1090          52 :                 *samr_reject_reason = SAM_PWD_CHANGE_NO_ERROR;
    1091             :         }
    1092             : 
    1093             :         /* check to see if the secdesc has previously been set to disallow */
    1094          74 :         if (!pdb_get_pass_can_change(hnd)) {
    1095           0 :                 DEBUG(1, ("user %s does not have permissions to change password\n", username));
    1096           0 :                 if (samr_reject_reason) {
    1097           0 :                         *samr_reject_reason = SAM_PWD_CHANGE_NO_ERROR;
    1098             :                 }
    1099           0 :                 return NT_STATUS_ACCOUNT_RESTRICTION;
    1100             :         }
    1101             : 
    1102             :         /* check to see if it is a Machine account and if the policy
    1103             :          * denies machines to change the password. *
    1104             :          * Should we deny also SRVTRUST and/or DOMSTRUST ? .SSS. */
    1105          74 :         if (pdb_get_acct_ctrl(hnd) & ACB_WSTRUST) {
    1106           0 :                 if (pdb_get_account_policy(PDB_POLICY_REFUSE_MACHINE_PW_CHANGE, &refuse) && refuse) {
    1107           0 :                         DEBUG(1, ("Machine %s cannot change password now, "
    1108             :                                   "denied by Refuse Machine Password Change policy\n",
    1109             :                                   username));
    1110           0 :                         if (samr_reject_reason) {
    1111           0 :                                 *samr_reject_reason = SAM_PWD_CHANGE_NO_ERROR;
    1112             :                         }
    1113           0 :                         return NT_STATUS_ACCOUNT_RESTRICTION;
    1114             :                 }
    1115             :         }
    1116             : 
    1117             :         /* removed calculation here, because passdb now calculates
    1118             :            based on policy.  jmcd */
    1119          74 :         if ((can_change_time != 0) && (time(NULL) < can_change_time)) {
    1120           0 :                 DEBUG(1, ("user %s cannot change password now, must "
    1121             :                           "wait until %s\n", username,
    1122             :                           http_timestring(tosctx, can_change_time)));
    1123           0 :                 if (samr_reject_reason) {
    1124           0 :                         *samr_reject_reason = SAM_PWD_CHANGE_NO_ERROR;
    1125             :                 }
    1126           0 :                 return NT_STATUS_ACCOUNT_RESTRICTION;
    1127             :         }
    1128             : 
    1129          74 :         if (pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_LEN, &min_len) && (str_charnum(new_passwd) < min_len)) {
    1130           4 :                 DBG_WARNING("user %s cannot change password - "
    1131             :                             "password too short\n"
    1132             :                             " account policy min password len = %"PRIu32"\n",
    1133             :                             username,
    1134             :                             min_len);
    1135           4 :                 if (samr_reject_reason) {
    1136           4 :                         *samr_reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
    1137             :                 }
    1138           4 :                 return NT_STATUS_PASSWORD_RESTRICTION;
    1139             : /*              return NT_STATUS_PWD_TOO_SHORT; */
    1140             :         }
    1141             : 
    1142          70 :         if (check_passwd_history(hnd,new_passwd)) {
    1143           0 :                 if (samr_reject_reason) {
    1144           0 :                         *samr_reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
    1145             :                 }
    1146           0 :                 return NT_STATUS_PASSWORD_RESTRICTION;
    1147             :         }
    1148             : 
    1149          70 :         pass = Get_Pwnam_alloc(tosctx, username);
    1150          70 :         if (!pass) {
    1151           0 :                 DEBUG(1, ("change_oem_password: Username %s does not exist in system !?!\n", username));
    1152           0 :                 return NT_STATUS_ACCESS_DENIED;
    1153             :         }
    1154             : 
    1155          70 :         status = check_password_complexity(username,
    1156             :                                            fullname,
    1157             :                                            new_passwd,
    1158             :                                            samr_reject_reason);
    1159          70 :         if (!NT_STATUS_IS_OK(status)) {
    1160           0 :                 TALLOC_FREE(pass);
    1161           0 :                 return status;
    1162             :         }
    1163             : 
    1164             :         /*
    1165             :          * If unix password sync was requested, attempt to change
    1166             :          * the /etc/passwd database first. Return failure if this cannot
    1167             :          * be done.
    1168             :          *
    1169             :          * This occurs before the oem change, because we don't want to
    1170             :          * update it if chgpasswd failed.
    1171             :          *
    1172             :          * Conditional on lp_unix_password_sync() because we don't want
    1173             :          * to touch the unix db unless we have admin permission.
    1174             :          */
    1175             : 
    1176          70 :         if(lp_unix_password_sync() &&
    1177           0 :            !chgpasswd(username, rhost, pass, old_passwd, new_passwd,
    1178             :                       as_root)) {
    1179           0 :                 TALLOC_FREE(pass);
    1180           0 :                 return NT_STATUS_ACCESS_DENIED;
    1181             :         }
    1182             : 
    1183          70 :         TALLOC_FREE(pass);
    1184             : 
    1185          70 :         if (!pdb_set_plaintext_passwd (hnd, new_passwd)) {
    1186           0 :                 return NT_STATUS_ACCESS_DENIED;
    1187             :         }
    1188             : 
    1189             :         /* Now write it into the file. */
    1190          70 :         return pdb_update_sam_account (hnd);
    1191             : }
    1192             : 
    1193             : /***********************************************************
    1194             :  Code to check and change the OEM hashed password.
    1195             : ************************************************************/
    1196             : 
    1197         240 : NTSTATUS pass_oem_change(char *user, const char *rhost,
    1198             :                          uchar password_encrypted_with_lm_hash[516],
    1199             :                          const uchar old_lm_hash_encrypted[16],
    1200             :                          uchar password_encrypted_with_nt_hash[516],
    1201             :                          const uchar old_nt_hash_encrypted[16],
    1202             :                          enum samPwdChangeReason *reject_reason)
    1203             : {
    1204         240 :         char *new_passwd = NULL;
    1205         240 :         struct samu *sampass = NULL;
    1206           0 :         NTSTATUS nt_status;
    1207         240 :         bool ret = false;
    1208         240 :         bool updated_badpw = false;
    1209           0 :         NTSTATUS update_login_attempts_status;
    1210         240 :         char *mutex_name_by_user = NULL;
    1211         240 :         struct named_mutex *mtx = NULL;
    1212             : 
    1213         240 :         if (!(sampass = samu_new(NULL))) {
    1214           0 :                 return NT_STATUS_NO_MEMORY;
    1215             :         }
    1216             : 
    1217         240 :         become_root();
    1218         240 :         ret = pdb_getsampwnam(sampass, user);
    1219         240 :         unbecome_root();
    1220             : 
    1221         240 :         if (ret == false) {
    1222          56 :                 DEBUG(0,("pass_oem_change: getsmbpwnam returned NULL\n"));
    1223          56 :                 nt_status = NT_STATUS_NO_SUCH_USER;
    1224          56 :                 goto done;
    1225             :         }
    1226             : 
    1227             :         /* Quit if the account was locked out. */
    1228         184 :         if (pdb_get_acct_ctrl(sampass) & ACB_AUTOLOCK) {
    1229           4 :                 DEBUG(3,("check_sam_security: Account for user %s was locked out.\n", user));
    1230           4 :                 nt_status = NT_STATUS_ACCOUNT_LOCKED_OUT;
    1231           4 :                 goto done;
    1232             :         }
    1233             : 
    1234         180 :         nt_status = check_oem_password(user,
    1235             :                                        password_encrypted_with_lm_hash,
    1236             :                                        old_lm_hash_encrypted,
    1237             :                                        password_encrypted_with_nt_hash,
    1238             :                                        old_nt_hash_encrypted,
    1239             :                                        sampass,
    1240             :                                        &new_passwd);
    1241             : 
    1242             :         /*
    1243             :          * We must re-load the sam account information under a mutex
    1244             :          * lock to ensure we don't miss any concurrent account lockout
    1245             :          * changes.
    1246             :          */
    1247             : 
    1248             :         /* Clear out old sampass info. */
    1249         180 :         TALLOC_FREE(sampass);
    1250             : 
    1251         180 :         sampass = samu_new(NULL);
    1252         180 :         if (sampass == NULL) {
    1253           0 :                 return NT_STATUS_NO_MEMORY;
    1254             :         }
    1255             : 
    1256         180 :         mutex_name_by_user = talloc_asprintf(NULL,
    1257             :                                              "check_sam_security_mutex_%s",
    1258             :                                              user);
    1259         180 :         if (mutex_name_by_user == NULL) {
    1260           0 :                 nt_status = NT_STATUS_NO_MEMORY;
    1261           0 :                 goto done;
    1262             :         }
    1263             : 
    1264             :         /* Grab the named mutex under root with 30 second timeout. */
    1265         180 :         become_root();
    1266         180 :         mtx = grab_named_mutex(NULL, mutex_name_by_user, 30);
    1267         180 :         if (mtx != NULL) {
    1268             :                 /* Re-load the account information if we got the mutex. */
    1269         180 :                 ret = pdb_getsampwnam(sampass, user);
    1270             :         }
    1271         180 :         unbecome_root();
    1272             : 
    1273             :         /* Everything from here on until mtx is freed is done under the mutex.*/
    1274             : 
    1275         180 :         if (mtx == NULL) {
    1276           0 :                 DBG_ERR("Acquisition of mutex %s failed "
    1277             :                         "for user %s\n",
    1278             :                         mutex_name_by_user,
    1279             :                         user);
    1280           0 :                 nt_status = NT_STATUS_INTERNAL_ERROR;
    1281           0 :                 goto done;
    1282             :         }
    1283             : 
    1284         180 :         if (!ret) {
    1285             :                 /*
    1286             :                  * Re-load of account failed. This could only happen if the
    1287             :                  * user was deleted in the meantime.
    1288             :                  */
    1289           0 :                 DBG_NOTICE("reload of user '%s' in passdb failed.\n",
    1290             :                            user);
    1291           0 :                 nt_status = NT_STATUS_NO_SUCH_USER;
    1292           0 :                 goto done;
    1293             :         }
    1294             : 
    1295             :         /*
    1296             :          * Check if the account is now locked out - now under the mutex.
    1297             :          * This can happen if the server is under
    1298             :          * a password guess attack and the ACB_AUTOLOCK is set by
    1299             :          * another process.
    1300             :          */
    1301         180 :         if (pdb_get_acct_ctrl(sampass) & ACB_AUTOLOCK) {
    1302           0 :                 DBG_NOTICE("Account for user %s was locked out.\n", user);
    1303           0 :                 nt_status = NT_STATUS_ACCOUNT_LOCKED_OUT;
    1304           0 :                 goto done;
    1305             :         }
    1306             : 
    1307             :         /*
    1308             :          * Notify passdb backend of login success/failure. If not
    1309             :          * NT_STATUS_OK the backend doesn't like the login
    1310             :          */
    1311         180 :         update_login_attempts_status = pdb_update_login_attempts(sampass,
    1312         180 :                                                 NT_STATUS_IS_OK(nt_status));
    1313             : 
    1314         180 :         if (!NT_STATUS_IS_OK(nt_status)) {
    1315         116 :                 bool increment_bad_pw_count = false;
    1316             : 
    1317         116 :                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) &&
    1318         114 :                     (pdb_get_acct_ctrl(sampass) & ACB_NORMAL) &&
    1319         114 :                     NT_STATUS_IS_OK(update_login_attempts_status))
    1320             :                 {
    1321         114 :                         increment_bad_pw_count = true;
    1322             :                 }
    1323             : 
    1324         116 :                 if (increment_bad_pw_count) {
    1325         114 :                         pdb_increment_bad_password_count(sampass);
    1326         114 :                         updated_badpw = true;
    1327             :                 } else {
    1328           2 :                         pdb_update_bad_password_count(sampass,
    1329             :                                                       &updated_badpw);
    1330             :                 }
    1331             :         } else {
    1332             : 
    1333         128 :                 if ((pdb_get_acct_ctrl(sampass) & ACB_NORMAL) &&
    1334          64 :                     (pdb_get_bad_password_count(sampass) > 0)){
    1335           0 :                         pdb_set_bad_password_count(sampass, 0, PDB_CHANGED);
    1336           0 :                         pdb_set_bad_password_time(sampass, 0, PDB_CHANGED);
    1337           0 :                         updated_badpw = true;
    1338             :                 }
    1339             :         }
    1340             : 
    1341         180 :         if (updated_badpw) {
    1342           0 :                 NTSTATUS update_status;
    1343         114 :                 become_root();
    1344         114 :                 update_status = pdb_update_sam_account(sampass);
    1345         114 :                 unbecome_root();
    1346             : 
    1347         114 :                 if (!NT_STATUS_IS_OK(update_status)) {
    1348           0 :                         DEBUG(1, ("Failed to modify entry: %s\n",
    1349             :                                   nt_errstr(update_status)));
    1350             :                 }
    1351             :         }
    1352             : 
    1353         180 :         if (!NT_STATUS_IS_OK(nt_status)) {
    1354         116 :                 goto done;
    1355             :         }
    1356             : 
    1357             :         /* We've already checked the old password here.... */
    1358          64 :         become_root();
    1359          64 :         nt_status = change_oem_password(sampass, rhost, NULL, new_passwd,
    1360             :                                         True, reject_reason);
    1361          64 :         unbecome_root();
    1362             : 
    1363          64 :         BURN_STR(new_passwd);
    1364             : 
    1365           0 : done:
    1366         240 :         TALLOC_FREE(sampass);
    1367         240 :         TALLOC_FREE(mutex_name_by_user);
    1368         240 :         TALLOC_FREE(mtx);
    1369             : 
    1370         240 :         return nt_status;
    1371             : }
    1372             : 
    1373          10 : NTSTATUS samr_set_password_aes(TALLOC_CTX *mem_ctx,
    1374             :                                const DATA_BLOB *cdk,
    1375             :                                struct samr_EncryptedPasswordAES *pwbuf,
    1376             :                                char **new_password_str)
    1377             : {
    1378          10 :         DATA_BLOB pw_data = data_blob_null;
    1379          10 :         DATA_BLOB new_password = data_blob_null;
    1380           0 :         const DATA_BLOB ciphertext =
    1381          10 :                 data_blob_const(pwbuf->cipher, pwbuf->cipher_len);
    1382          10 :         DATA_BLOB iv = data_blob_const(pwbuf->salt, sizeof(pwbuf->salt));
    1383           0 :         NTSTATUS status;
    1384           0 :         bool ok;
    1385             : 
    1386          10 :         *new_password_str = NULL;
    1387             : 
    1388          10 :         status = samba_gnutls_aead_aes_256_cbc_hmac_sha512_decrypt(
    1389             :                 mem_ctx,
    1390             :                 &ciphertext,
    1391             :                 cdk,
    1392             :                 &samr_aes256_enc_key_salt,
    1393             :                 &samr_aes256_mac_key_salt,
    1394             :                 &iv,
    1395          10 :                 pwbuf->auth_data,
    1396             :                 &pw_data);
    1397          10 :         if (!NT_STATUS_IS_OK(status)) {
    1398           0 :                 return NT_STATUS_WRONG_PASSWORD;
    1399             :         }
    1400             : 
    1401          10 :         ok = decode_pwd_string_from_buffer514(mem_ctx,
    1402          10 :                                               pw_data.data,
    1403             :                                               CH_UTF16,
    1404             :                                               &new_password);
    1405          10 :         TALLOC_FREE(pw_data.data);
    1406          10 :         if (!ok) {
    1407           0 :                 DBG_NOTICE("samr: failed to decode password buffer\n");
    1408           0 :                 return NT_STATUS_WRONG_PASSWORD;
    1409             :         }
    1410             : 
    1411          20 :         *new_password_str = talloc_strndup(mem_ctx,
    1412          10 :                                            (char *)new_password.data,
    1413             :                                            new_password.length);
    1414          10 :         TALLOC_FREE(new_password.data);
    1415          10 :         if (*new_password_str == NULL) {
    1416           0 :                 return NT_STATUS_NO_MEMORY;
    1417             :         }
    1418          10 :         talloc_keep_secret(*new_password_str);
    1419             : 
    1420          10 :         return NT_STATUS_OK;
    1421             : }

Generated by: LCOV version 1.14