~stefanor/ubuntu/maverick/samba/ntlm-auth-623342

« back to all changes in this revision

Viewing changes to source/smbd/chgpasswd.c

  • Committer: Bazaar Package Importer
  • Author(s): Chuck Short
  • Date: 2009-07-08 07:02:37 UTC
  • mfrom: (0.27.6 upstream) (0.28.6 sid)
  • Revision ID: james.westby@ubuntu.com-20090708070237-o5wxq1shz5tabuw2
Tags: 2:3.4.0-1ubuntu1
* Merge from debian unstable, remaining changes:
  + debian/patches/VERSION.patch:
    - set SAMBA_VERSION_SUFFIX to Ubuntu.
  + debian/smb.conf:
    - Add "(Samaba, Ubuntu)" to server string.
    - Comment out the default [homes] share, and add a comment 
      about "valid users = $s" to show users how to restrict access
      to \\server\username to only username.
    - Set 'usershare allow guests' so that usershare admins are
      allowed to create public shares to authenticated ones.
    - Add 'map to gues = Bad user', maps bad username to guest access.
  + debian/samba-common.conf:
    - Do not change priority to hight if dhclient3 is installed.
    - Use priority medium  instead of high for the workgroup question.
  + debian/samba-common.postinst: Add more informative error message for the case
    where smb.conf was manually deleted. (LP: #312449)
  + debian/mksambapasswd.awk: Do not add user with UID less than 1000 to smbpasswd.
  + debian/control:
    - Make libwbclient0 replace/conflict with hardy's likewise-open.
    - Don't build against ctdb.
    - Add suggests keyutils for smbfs. (LP: #300221)
  + debian/rules:
    - enable "native" PIE hardening.
    - remove --with-ctdb and --with-cluster-support=yes
  + Add ufw integration:
    - Created debian/samba.ufw profile.
    - debian/rules, debian/samba.dirs, debian/samba.files: install profile
    - debian/control: have samba suffest ufw
  + Dropped:
    - debian/patches/fix-password-expiry-calculation.patch: Already upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
 
50
 
extern struct passdb_ops pdb_ops;
51
 
 
52
 
static NTSTATUS check_oem_password(const char *user,
53
 
                                   uchar password_encrypted_with_lm_hash[516],
54
 
                                   const uchar old_lm_hash_encrypted[16],
55
 
                                   uchar password_encrypted_with_nt_hash[516],
56
 
                                   const uchar old_nt_hash_encrypted[16],
57
 
                                   struct samu **hnd,
58
 
                                   char **pp_new_passwd);
59
 
 
60
 
#if ALLOW_CHANGE_PASSWORD
61
 
 
62
 
static int findpty(char **slave)
63
 
{
64
 
        int master = -1;
65
 
        char *line = NULL;
66
 
        SMB_STRUCT_DIR *dirp = NULL;
67
 
        const char *dpname;
68
 
 
69
 
        *slave = NULL;
70
 
 
71
 
#if defined(HAVE_GRANTPT)
72
 
        /* Try to open /dev/ptmx. If that fails, fall through to old method. */
73
 
        if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 0) {
74
 
                grantpt(master);
75
 
                unlockpt(master);
76
 
                line = (char *)ptsname(master);
77
 
                if (line) {
78
 
                        *slave = SMB_STRDUP(line);
79
 
                }
80
 
 
81
 
                if (*slave == NULL) {
82
 
                        DEBUG(0,
83
 
                              ("findpty: Unable to create master/slave pty pair.\n"));
84
 
                        /* Stop fd leak on error. */
85
 
                        close(master);
86
 
                        return -1;
87
 
                } else {
88
 
                        DEBUG(10,
89
 
                              ("findpty: Allocated slave pty %s\n", *slave));
90
 
                        return (master);
91
 
                }
92
 
        }
93
 
#endif /* HAVE_GRANTPT */
94
 
 
95
 
        line = SMB_STRDUP("/dev/ptyXX");
96
 
        if (!line) {
97
 
                return (-1);
98
 
        }
99
 
 
100
 
        dirp = sys_opendir("/dev");
101
 
        if (!dirp) {
102
 
                SAFE_FREE(line);
103
 
                return (-1);
104
 
        }
105
 
 
106
 
        while ((dpname = readdirname(dirp)) != NULL) {
107
 
                if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5) {
108
 
                        DEBUG(3,
109
 
                              ("pty: try to open %s, line was %s\n", dpname,
110
 
                               line));
111
 
                        line[8] = dpname[3];
112
 
                        line[9] = dpname[4];
113
 
                        if ((master = sys_open(line, O_RDWR, 0)) >= 0) {
114
 
                                DEBUG(3, ("pty: opened %s\n", line));
115
 
                                line[5] = 't';
116
 
                                *slave = line;
117
 
                                sys_closedir(dirp);
118
 
                                return (master);
119
 
                        }
120
 
                }
121
 
        }
122
 
        sys_closedir(dirp);
123
 
        SAFE_FREE(line);
124
 
        return (-1);
125
 
}
126
 
 
127
 
static int dochild(int master, const char *slavedev, const struct passwd *pass,
128
 
                   const char *passwordprogram, bool as_root)
129
 
{
130
 
        int slave;
131
 
        struct termios stermios;
132
 
        gid_t gid;
133
 
        uid_t uid;
134
 
        char * const eptrs[1] = { NULL };
135
 
 
136
 
        if (pass == NULL)
137
 
        {
138
 
                DEBUG(0,
139
 
                      ("dochild: user doesn't exist in the UNIX password database.\n"));
140
 
                return False;
141
 
        }
142
 
 
143
 
        gid = pass->pw_gid;
144
 
        uid = pass->pw_uid;
145
 
 
146
 
        gain_root_privilege();
147
 
 
148
 
        /* Start new session - gets rid of controlling terminal. */
149
 
        if (setsid() < 0)
150
 
        {
151
 
                DEBUG(3,
152
 
                      ("Weirdness, couldn't let go of controlling terminal\n"));
153
 
                return (False);
154
 
        }
155
 
 
156
 
        /* Open slave pty and acquire as new controlling terminal. */
157
 
        if ((slave = sys_open(slavedev, O_RDWR, 0)) < 0)
158
 
        {
159
 
                DEBUG(3, ("More weirdness, could not open %s\n", slavedev));
160
 
                return (False);
161
 
        }
162
 
#if defined(TIOCSCTTY) && !defined(SUNOS5)
163
 
        /*
164
 
         * On patched Solaris 10 TIOCSCTTY is defined but seems not to work,
165
 
         * see the discussion under
166
 
         * https://bugzilla.samba.org/show_bug.cgi?id=5366.
167
 
         */
168
 
        if (ioctl(slave, TIOCSCTTY, 0) < 0)
169
 
        {
170
 
                DEBUG(3, ("Error in ioctl call for slave pty\n"));
171
 
                /* return(False); */
172
 
        }
173
 
#elif defined(I_PUSH) && defined(I_FIND)
174
 
        if (ioctl(slave, I_FIND, "ptem") == 0) {
175
 
                ioctl(slave, I_PUSH, "ptem");
176
 
        }
177
 
        if (ioctl(slave, I_FIND, "ldterm") == 0) {
178
 
                ioctl(slave, I_PUSH, "ldterm");
179
 
        }
180
 
#endif
181
 
 
182
 
        /* Close master. */
183
 
        close(master);
184
 
 
185
 
        /* Make slave stdin/out/err of child. */
186
 
 
187
 
        if (sys_dup2(slave, STDIN_FILENO) != STDIN_FILENO)
188
 
        {
189
 
                DEBUG(3, ("Could not re-direct stdin\n"));
190
 
                return (False);
191
 
        }
192
 
        if (sys_dup2(slave, STDOUT_FILENO) != STDOUT_FILENO)
193
 
        {
194
 
                DEBUG(3, ("Could not re-direct stdout\n"));
195
 
                return (False);
196
 
        }
197
 
        if (sys_dup2(slave, STDERR_FILENO) != STDERR_FILENO)
198
 
        {
199
 
                DEBUG(3, ("Could not re-direct stderr\n"));
200
 
                return (False);
201
 
        }
202
 
        if (slave > 2)
203
 
                close(slave);
204
 
 
205
 
        /* Set proper terminal attributes - no echo, canonical input processing,
206
 
           no map NL to CR/NL on output. */
207
 
 
208
 
        if (tcgetattr(0, &stermios) < 0)
209
 
        {
210
 
                DEBUG(3,
211
 
                      ("could not read default terminal attributes on pty\n"));
212
 
                return (False);
213
 
        }
214
 
        stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
215
 
        stermios.c_lflag |= ICANON;
216
 
#ifdef ONLCR
217
 
        stermios.c_oflag &= ~(ONLCR);
218
 
#endif
219
 
        if (tcsetattr(0, TCSANOW, &stermios) < 0)
220
 
        {
221
 
                DEBUG(3, ("could not set attributes of pty\n"));
222
 
                return (False);
223
 
        }
224
 
 
225
 
        /* make us completely into the right uid */
226
 
        if (!as_root)
227
 
        {
228
 
                become_user_permanently(uid, gid);
229
 
        }
230
 
 
231
 
        DEBUG(10,
232
 
              ("Invoking '%s' as password change program.\n",
233
 
               passwordprogram));
234
 
 
235
 
        /* execl() password-change application */
236
 
        if (execle("/bin/sh", "sh", "-c", passwordprogram, NULL, eptrs) < 0)
237
 
        {
238
 
                DEBUG(3, ("Bad status returned from %s\n", passwordprogram));
239
 
                return (False);
240
 
        }
241
 
        return (True);
242
 
}
243
 
 
244
 
static int expect(int master, char *issue, char *expected)
245
 
{
246
 
        char buffer[1024];
247
 
        int attempts, timeout, nread;
248
 
        size_t len;
249
 
        bool match = False;
250
 
 
251
 
        for (attempts = 0; attempts < 2; attempts++) {
252
 
                NTSTATUS status;
253
 
                if (!strequal(issue, ".")) {
254
 
                        if (lp_passwd_chat_debug())
255
 
                                DEBUG(100, ("expect: sending [%s]\n", issue));
256
 
 
257
 
                        if ((len = sys_write(master, issue, strlen(issue))) != strlen(issue)) {
258
 
                                DEBUG(2,("expect: (short) write returned %d\n",
259
 
                                         (int)len ));
260
 
                                return False;
261
 
                        }
262
 
                }
263
 
 
264
 
                if (strequal(expected, "."))
265
 
                        return True;
266
 
 
267
 
                /* Initial timeout. */
268
 
                timeout = lp_passwd_chat_timeout() * 1000;
269
 
                nread = 0;
270
 
                buffer[nread] = 0;
271
 
 
272
 
                while (True) {
273
 
                        status = read_socket_with_timeout(
274
 
                                master, buffer + nread, 1,
275
 
                                sizeof(buffer) - nread - 1,
276
 
                                timeout, &len);
277
 
 
278
 
                        if (!NT_STATUS_IS_OK(status)) {
279
 
                                break;
280
 
                        }
281
 
                        nread += len;
282
 
                        buffer[nread] = 0;
283
 
 
284
 
                        {
285
 
                                /* Eat leading/trailing whitespace before match. */
286
 
                                char *str = SMB_STRDUP(buffer);
287
 
                                if (!str) {
288
 
                                        DEBUG(2,("expect: ENOMEM\n"));
289
 
                                        return False;
290
 
                                }
291
 
                                trim_char(str, ' ', ' ');
292
 
 
293
 
                                if ((match = unix_wild_match(expected, str)) == True) {
294
 
                                        /* Now data has started to return, lower timeout. */
295
 
                                        timeout = lp_passwd_chat_timeout() * 100;
296
 
                                }
297
 
                                SAFE_FREE(str);
298
 
                        }
299
 
                }
300
 
 
301
 
                if (lp_passwd_chat_debug())
302
 
                        DEBUG(100, ("expect: expected [%s] received [%s] match %s\n",
303
 
                                    expected, buffer, match ? "yes" : "no" ));
304
 
 
305
 
                if (match)
306
 
                        break;
307
 
 
308
 
                if (!NT_STATUS_IS_OK(status)) {
309
 
                        DEBUG(2, ("expect: %s\n", nt_errstr(status)));
310
 
                        return False;
311
 
                }
312
 
        }
313
 
 
314
 
        DEBUG(10,("expect: returning %s\n", match ? "True" : "False" ));
315
 
        return match;
316
 
}
317
 
 
318
 
static void pwd_sub(char *buf)
319
 
{
320
 
        all_string_sub(buf, "\\n", "\n", 0);
321
 
        all_string_sub(buf, "\\r", "\r", 0);
322
 
        all_string_sub(buf, "\\s", " ", 0);
323
 
        all_string_sub(buf, "\\t", "\t", 0);
324
 
}
325
 
 
326
 
static int talktochild(int master, const char *seq)
327
 
{
328
 
        TALLOC_CTX *frame = talloc_stackframe();
329
 
        int count = 0;
330
 
        char *issue;
331
 
        char *expected;
332
 
 
333
 
        issue = talloc_strdup(frame, ".");
334
 
        if (!issue) {
335
 
                TALLOC_FREE(frame);
336
 
                return false;
337
 
        }
338
 
 
339
 
        while (next_token_talloc(frame, &seq, &expected, NULL)) {
340
 
                pwd_sub(expected);
341
 
                count++;
342
 
 
343
 
                if (!expect(master, issue, expected)) {
344
 
                        DEBUG(3, ("Response %d incorrect\n", count));
345
 
                        TALLOC_FREE(frame);
346
 
                        return false;
347
 
                }
348
 
 
349
 
                if (!next_token_talloc(frame, &seq, &issue, NULL)) {
350
 
                        issue = talloc_strdup(frame, ".");
351
 
                        if (!issue) {
352
 
                                TALLOC_FREE(frame);
353
 
                                return false;
354
 
                        }
355
 
                }
356
 
                pwd_sub(issue);
357
 
        }
358
 
 
359
 
        if (!strequal(issue, ".")) {
360
 
                /* we have one final issue to send */
361
 
                expected = talloc_strdup(frame, ".");
362
 
                if (!expected) {
363
 
                        TALLOC_FREE(frame);
364
 
                        return false;
365
 
                }
366
 
                if (!expect(master, issue, expected)) {
367
 
                        TALLOC_FREE(frame);
368
 
                        return False;
369
 
                }
370
 
        }
371
 
        TALLOC_FREE(frame);
372
 
        return (count > 0);
373
 
}
374
 
 
375
 
static bool chat_with_program(char *passwordprogram, const struct passwd *pass,
376
 
                              char *chatsequence, bool as_root)
377
 
{
378
 
        char *slavedev = NULL;
379
 
        int master;
380
 
        pid_t pid, wpid;
381
 
        int wstat;
382
 
        bool chstat = False;
383
 
 
384
 
        if (pass == NULL) {
385
 
                DEBUG(0, ("chat_with_program: user doesn't exist in the UNIX password database.\n"));
386
 
                return False;
387
 
        }
388
 
 
389
 
        /* allocate a pseudo-terminal device */
390
 
        if ((master = findpty(&slavedev)) < 0) {
391
 
                DEBUG(3, ("chat_with_program: Cannot Allocate pty for password change: %s\n", pass->pw_name));
392
 
                return (False);
393
 
        }
394
 
 
395
 
        /*
396
 
         * We need to temporarily stop CatchChild from eating
397
 
         * SIGCLD signals as it also eats the exit status code. JRA.
398
 
         */
399
 
 
400
 
        CatchChildLeaveStatus();
401
 
 
402
 
        if ((pid = sys_fork()) < 0) {
403
 
                DEBUG(3, ("chat_with_program: Cannot fork() child for password change: %s\n", pass->pw_name));
404
 
                SAFE_FREE(slavedev);
405
 
                close(master);
406
 
                CatchChild();
407
 
                return (False);
408
 
        }
409
 
 
410
 
        /* we now have a pty */
411
 
        if (pid > 0) {                  /* This is the parent process */
412
 
                /* Don't need this anymore in parent. */
413
 
                SAFE_FREE(slavedev);
414
 
 
415
 
                if ((chstat = talktochild(master, chatsequence)) == False) {
416
 
                        DEBUG(3, ("chat_with_program: Child failed to change password: %s\n", pass->pw_name));
417
 
                        kill(pid, SIGKILL);     /* be sure to end this process */
418
 
                }
419
 
 
420
 
                while ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) {
421
 
                        if (errno == EINTR) {
422
 
                                errno = 0;
423
 
                                continue;
424
 
                        }
425
 
                        break;
426
 
                }
427
 
 
428
 
                if (wpid < 0) {
429
 
                        DEBUG(3, ("chat_with_program: The process is no longer waiting!\n\n"));
430
 
                        close(master);
431
 
                        CatchChild();
432
 
                        return (False);
433
 
                }
434
 
 
435
 
                /*
436
 
                 * Go back to ignoring children.
437
 
                 */
438
 
                CatchChild();
439
 
 
440
 
                close(master);
441
 
 
442
 
                if (pid != wpid) {
443
 
                        DEBUG(3, ("chat_with_program: We were waiting for the wrong process ID\n"));
444
 
                        return (False);
445
 
                }
446
 
                if (WIFEXITED(wstat) && (WEXITSTATUS(wstat) != 0)) {
447
 
                        DEBUG(3, ("chat_with_program: The process exited with status %d \
448
 
while we were waiting\n", WEXITSTATUS(wstat)));
449
 
                        return (False);
450
 
                }
451
 
#if defined(WIFSIGNALLED) && defined(WTERMSIG)
452
 
                else if (WIFSIGNALLED(wstat)) {
453
 
                        DEBUG(3, ("chat_with_program: The process was killed by signal %d \
454
 
while we were waiting\n", WTERMSIG(wstat)));
455
 
                        return (False);
456
 
                }
457
 
#endif
458
 
        } else {
459
 
                /* CHILD */
460
 
 
461
 
                /*
462
 
                 * Lose any elevated privileges.
463
 
                 */
464
 
                drop_effective_capability(KERNEL_OPLOCK_CAPABILITY);
465
 
                drop_effective_capability(DMAPI_ACCESS_CAPABILITY);
466
 
 
467
 
                /* make sure it doesn't freeze */
468
 
                alarm(20);
469
 
 
470
 
                if (as_root)
471
 
                        become_root();
472
 
 
473
 
                DEBUG(3, ("chat_with_program: Dochild for user %s (uid=%d,gid=%d) (as_root = %s)\n", pass->pw_name,
474
 
                       (int)getuid(), (int)getgid(), BOOLSTR(as_root) ));
475
 
                chstat = dochild(master, slavedev, pass, passwordprogram, as_root);
476
 
 
477
 
                if (as_root)
478
 
                        unbecome_root();
479
 
 
480
 
                /*
481
 
                 * The child should never return from dochild() ....
482
 
                 */
483
 
 
484
 
                DEBUG(0, ("chat_with_program: Error: dochild() returned %d\n", chstat));
485
 
                exit(1);
486
 
        }
487
 
 
488
 
        if (chstat)
489
 
                DEBUG(3, ("chat_with_program: Password change %ssuccessful for user %s\n",
490
 
                       (chstat ? "" : "un"), pass->pw_name));
491
 
        return (chstat);
492
 
}
493
 
 
494
 
bool chgpasswd(const char *name, const struct passwd *pass,
495
 
               const char *oldpass, const char *newpass, bool as_root)
496
 
{
497
 
        char *passwordprogram = NULL;
498
 
        char *chatsequence = NULL;
499
 
        size_t i;
500
 
        size_t len;
501
 
        TALLOC_CTX *ctx = talloc_tos();
502
 
 
503
 
        if (!oldpass) {
504
 
                oldpass = "";
505
 
        }
506
 
 
507
 
        DEBUG(3, ("chgpasswd: Password change (as_root=%s) for user: %s\n", BOOLSTR(as_root), name));
508
 
 
509
 
#ifdef DEBUG_PASSWORD
510
 
        DEBUG(100, ("chgpasswd: Passwords: old=%s new=%s\n", oldpass, newpass));
511
 
#endif
512
 
 
513
 
        /* Take the passed information and test it for minimum criteria */
514
 
 
515
 
        /* Password is same as old password */
516
 
        if (strcmp(oldpass, newpass) == 0) {
517
 
                /* don't allow same password */
518
 
                DEBUG(2, ("chgpasswd: Password Change: %s, New password is same as old\n", name));      /* log the attempt */
519
 
                return (False); /* inform the user */
520
 
        }
521
 
 
522
 
        /*
523
 
         * Check the old and new passwords don't contain any control
524
 
         * characters.
525
 
         */
526
 
 
527
 
        len = strlen(oldpass);
528
 
        for (i = 0; i < len; i++) {
529
 
                if (iscntrl((int)oldpass[i])) {
530
 
                        DEBUG(0, ("chgpasswd: oldpass contains control characters (disallowed).\n"));
531
 
                        return False;
532
 
                }
533
 
        }
534
 
 
535
 
        len = strlen(newpass);
536
 
        for (i = 0; i < len; i++) {
537
 
                if (iscntrl((int)newpass[i])) {
538
 
                        DEBUG(0, ("chgpasswd: newpass contains control characters (disallowed).\n"));
539
 
                        return False;
540
 
                }
541
 
        }
542
 
 
543
 
#ifdef WITH_PAM
544
 
        if (lp_pam_password_change()) {
545
 
                bool ret;
546
 
#ifdef HAVE_SETLOCALE
547
 
                const char *prevlocale = setlocale(LC_ALL, "C");
548
 
#endif
549
 
 
550
 
                if (as_root)
551
 
                        become_root();
552
 
 
553
 
                if (pass) {
554
 
                        ret = smb_pam_passchange(pass->pw_name, oldpass, newpass);
555
 
                } else {
556
 
                        ret = smb_pam_passchange(name, oldpass, newpass);
557
 
                }
558
 
 
559
 
                if (as_root)
560
 
                        unbecome_root();
561
 
 
562
 
#ifdef HAVE_SETLOCALE
563
 
                setlocale(LC_ALL, prevlocale);
564
 
#endif
565
 
 
566
 
                return ret;
567
 
        }
568
 
#endif
569
 
 
570
 
        /* A non-PAM password change just doen't make sense without a valid local user */
571
 
 
572
 
        if (pass == NULL) {
573
 
                DEBUG(0, ("chgpasswd: user %s doesn't exist in the UNIX password database.\n", name));
574
 
                return false;
575
 
        }
576
 
 
577
 
        passwordprogram = talloc_strdup(ctx, lp_passwd_program());
578
 
        if (!passwordprogram || !*passwordprogram) {
579
 
                DEBUG(2, ("chgpasswd: Null password program - no password changing\n"));
580
 
                return false;
581
 
        }
582
 
        chatsequence = talloc_strdup(ctx, lp_passwd_chat());
583
 
        if (!chatsequence || !*chatsequence) {
584
 
                DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n"));
585
 
                return false;
586
 
        }
587
 
 
588
 
        if (as_root) {
589
 
                /* The password program *must* contain the user name to work. Fail if not. */
590
 
                if (strstr_m(passwordprogram, "%u") == NULL) {
591
 
                        DEBUG(0,("chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \
592
 
the string %%u, and the given string %s does not.\n", passwordprogram ));
593
 
                        return false;
594
 
                }
595
 
        }
596
 
 
597
 
        passwordprogram = talloc_string_sub(ctx, passwordprogram, "%u", name);
598
 
        if (!passwordprogram) {
599
 
                return false;
600
 
        }
601
 
 
602
 
        /* note that we do NOT substitute the %o and %n in the password program
603
 
           as this would open up a security hole where the user could use
604
 
           a new password containing shell escape characters */
605
 
 
606
 
        chatsequence = talloc_string_sub(ctx, chatsequence, "%u", name);
607
 
        if (!chatsequence) {
608
 
                return false;
609
 
        }
610
 
        chatsequence = talloc_all_string_sub(ctx,
611
 
                                        chatsequence,
612
 
                                        "%o",
613
 
                                        oldpass);
614
 
        if (!chatsequence) {
615
 
                return false;
616
 
        }
617
 
        chatsequence = talloc_all_string_sub(ctx,
618
 
                                        chatsequence,
619
 
                                        "%n",
620
 
                                        newpass);
621
 
        return chat_with_program(passwordprogram,
622
 
                                pass,
623
 
                                chatsequence,
624
 
                                as_root);
625
 
}
626
 
 
627
 
#else /* ALLOW_CHANGE_PASSWORD */
628
 
 
629
 
bool chgpasswd(const char *name, const struct passwd *pass, 
630
 
               const char *oldpass, const char *newpass, bool as_root)
631
 
{
632
 
        DEBUG(0, ("chgpasswd: Unix Password changing not compiled in (user=%s)\n", name));
633
 
        return (False);
634
 
}
635
 
#endif /* ALLOW_CHANGE_PASSWORD */
636
 
 
637
 
/***********************************************************
638
 
 Code to check the lanman hashed password.
639
 
************************************************************/
640
 
 
641
 
bool check_lanman_password(char *user, uchar * pass1,
642
 
                           uchar * pass2, struct samu **hnd)
643
 
{
644
 
        uchar unenc_new_pw[16];
645
 
        uchar unenc_old_pw[16];
646
 
        struct samu *sampass = NULL;
647
 
        uint32 acct_ctrl;
648
 
        const uint8 *lanman_pw;
649
 
        bool ret;
650
 
 
651
 
        if ( !(sampass = samu_new(NULL)) ) {
652
 
                DEBUG(0, ("samu_new() failed!\n"));
653
 
                return False;
654
 
        }
655
 
        
656
 
        become_root();
657
 
        ret = pdb_getsampwnam(sampass, user);
658
 
        unbecome_root();
659
 
 
660
 
        if (ret == False) {
661
 
                DEBUG(0,("check_lanman_password: getsampwnam returned NULL\n"));
662
 
                TALLOC_FREE(sampass);
663
 
                return False;
664
 
        }
665
 
        
666
 
        acct_ctrl = pdb_get_acct_ctrl     (sampass);
667
 
        lanman_pw = pdb_get_lanman_passwd (sampass);
668
 
 
669
 
        if (acct_ctrl & ACB_DISABLED) {
670
 
                DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
671
 
                TALLOC_FREE(sampass);
672
 
                return False;
673
 
        }
674
 
 
675
 
        if (lanman_pw == NULL) {
676
 
                if (acct_ctrl & ACB_PWNOTREQ) {
677
 
                        /* this saves the pointer for the caller */
678
 
                        *hnd = sampass;
679
 
                        return True;
680
 
                } else {
681
 
                        DEBUG(0, ("check_lanman_password: no lanman password !\n"));
682
 
                        TALLOC_FREE(sampass);
683
 
                        return False;
684
 
                }
685
 
        }
686
 
 
687
 
        /* Get the new lanman hash. */
688
 
        D_P16(lanman_pw, pass2, unenc_new_pw);
689
 
 
690
 
        /* Use this to get the old lanman hash. */
691
 
        D_P16(unenc_new_pw, pass1, unenc_old_pw);
692
 
 
693
 
        /* Check that the two old passwords match. */
694
 
        if (memcmp(lanman_pw, unenc_old_pw, 16)) {
695
 
                DEBUG(0,("check_lanman_password: old password doesn't match.\n"));
696
 
                TALLOC_FREE(sampass);
697
 
                return False;
698
 
        }
699
 
 
700
 
        /* this saves the pointer for the caller */
701
 
        *hnd = sampass;
702
 
        return True;
703
 
}
704
 
 
705
 
/***********************************************************
706
 
 Code to change the lanman hashed password.
707
 
 It nulls out the NT hashed password as it will
708
 
 no longer be valid.
709
 
 NOTE this function is designed to be called as root. Check the old password
710
 
 is correct before calling. JRA.
711
 
************************************************************/
712
 
 
713
 
bool change_lanman_password(struct samu *sampass, uchar *pass2)
714
 
{
715
 
        static uchar null_pw[16];
716
 
        uchar unenc_new_pw[16];
717
 
        bool ret;
718
 
        uint32 acct_ctrl;
719
 
        const uint8 *pwd;
720
 
 
721
 
        if (sampass == NULL) {
722
 
                DEBUG(0,("change_lanman_password: no smb password entry.\n"));
723
 
                return False;
724
 
        }
725
 
        
726
 
        acct_ctrl = pdb_get_acct_ctrl(sampass);
727
 
        pwd = pdb_get_lanman_passwd(sampass);
728
 
 
729
 
        if (acct_ctrl & ACB_DISABLED) {
730
 
                DEBUG(0,("change_lanman_password: account %s disabled.\n",
731
 
                       pdb_get_username(sampass)));
732
 
                return False;
733
 
        }
734
 
 
735
 
        if (pwd == NULL) { 
736
 
                if (acct_ctrl & ACB_PWNOTREQ) {
737
 
                        uchar no_pw[14];
738
 
                        memset(no_pw, '\0', 14);
739
 
                        E_P16(no_pw, null_pw);
740
 
 
741
 
                        /* Get the new lanman hash. */
742
 
                        D_P16(null_pw, pass2, unenc_new_pw);
743
 
                } else {
744
 
                        DEBUG(0,("change_lanman_password: no lanman password !\n"));
745
 
                        return False;
746
 
                }
747
 
        } else {
748
 
                /* Get the new lanman hash. */
749
 
                D_P16(pwd, pass2, unenc_new_pw);
750
 
        }
751
 
 
752
 
        if (!pdb_set_lanman_passwd(sampass, unenc_new_pw, PDB_CHANGED)) {
753
 
                return False;
754
 
        }
755
 
 
756
 
        if (!pdb_set_nt_passwd    (sampass, NULL, PDB_CHANGED)) {
757
 
                return False;   /* We lose the NT hash. Sorry. */
758
 
        }
759
 
 
760
 
        if (!pdb_set_pass_last_set_time  (sampass, time(NULL), PDB_CHANGED)) {
761
 
                TALLOC_FREE(sampass);
762
 
                /* Not quite sure what this one qualifies as, but this will do */
763
 
                return False;
764
 
        }
765
 
 
766
 
        /* Now flush the sam_passwd struct to persistent storage */
767
 
        ret = NT_STATUS_IS_OK(pdb_update_sam_account (sampass));
768
 
 
769
 
        return ret;
770
 
}
771
 
 
772
 
/***********************************************************
773
 
 Code to check and change the OEM hashed password.
774
 
************************************************************/
775
 
 
776
 
NTSTATUS pass_oem_change(char *user,
777
 
                         uchar password_encrypted_with_lm_hash[516],
778
 
                         const uchar old_lm_hash_encrypted[16],
779
 
                         uchar password_encrypted_with_nt_hash[516],
780
 
                         const uchar old_nt_hash_encrypted[16],
781
 
                         uint32 *reject_reason)
782
 
{
783
 
        char *new_passwd = NULL;
784
 
        struct samu *sampass = NULL;
785
 
        NTSTATUS nt_status = check_oem_password(user,
786
 
                                                password_encrypted_with_lm_hash,
787
 
                                                old_lm_hash_encrypted,
788
 
                                                password_encrypted_with_nt_hash,
789
 
                                                old_nt_hash_encrypted,
790
 
                                                &sampass,
791
 
                                                &new_passwd);
792
 
 
793
 
        if (!NT_STATUS_IS_OK(nt_status)) {
794
 
                return nt_status;
795
 
        }
796
 
 
797
 
        /* We've already checked the old password here.... */
798
 
        become_root();
799
 
        nt_status = change_oem_password(sampass, NULL, new_passwd, True, reject_reason);
800
 
        unbecome_root();
801
 
 
802
 
        memset(new_passwd, 0, strlen(new_passwd));
803
 
 
804
 
        TALLOC_FREE(sampass);
805
 
 
806
 
        return nt_status;
807
 
}
808
 
 
809
 
/***********************************************************
810
 
 Decrypt and verify a user password change.
811
 
 
812
 
 The 516 byte long buffers are encrypted with the old NT and
813
 
 old LM passwords, and if the NT passwords are present, both
814
 
 buffers contain a unicode string.
815
 
 
816
 
 After decrypting the buffers, check the password is correct by
817
 
 matching the old hashed passwords with the passwords in the passdb.
818
 
 
819
 
************************************************************/
820
 
 
821
 
static NTSTATUS check_oem_password(const char *user,
822
 
                                   uchar password_encrypted_with_lm_hash[516],
823
 
                                   const uchar old_lm_hash_encrypted[16],
824
 
                                   uchar password_encrypted_with_nt_hash[516],
825
 
                                   const uchar old_nt_hash_encrypted[16],
826
 
                                   struct samu **hnd,
827
 
                                   char **pp_new_passwd)
828
 
{
829
 
        static uchar null_pw[16];
830
 
        static uchar null_ntpw[16];
831
 
        struct samu *sampass = NULL;
832
 
        uint8 *password_encrypted;
833
 
        const uint8 *encryption_key;
834
 
        const uint8 *lanman_pw, *nt_pw;
835
 
        uint32 acct_ctrl;
836
 
        uint32 new_pw_len;
837
 
        uchar new_nt_hash[16];
838
 
        uchar new_lm_hash[16];
839
 
        uchar verifier[16];
840
 
        char no_pw[2];
841
 
        bool ret;
842
 
 
843
 
        bool nt_pass_set = (password_encrypted_with_nt_hash && old_nt_hash_encrypted);
844
 
        bool lm_pass_set = (password_encrypted_with_lm_hash && old_lm_hash_encrypted);
845
 
 
846
 
        *hnd = NULL;
847
 
 
848
 
        if ( !(sampass = samu_new( NULL )) ) {
849
 
                return NT_STATUS_NO_MEMORY;
850
 
        }
851
 
 
852
 
        become_root();
853
 
        ret = pdb_getsampwnam(sampass, user);
854
 
        unbecome_root();
855
 
 
856
 
        if (ret == False) {
857
 
                DEBUG(0, ("check_oem_password: getsmbpwnam returned NULL\n"));
858
 
                TALLOC_FREE(sampass);
859
 
                return NT_STATUS_NO_SUCH_USER;
860
 
        }
861
 
 
862
 
        acct_ctrl = pdb_get_acct_ctrl(sampass);
863
 
 
864
 
        if (acct_ctrl & ACB_DISABLED) {
865
 
                DEBUG(2,("check_lanman_password: account %s disabled.\n", user));
866
 
                TALLOC_FREE(sampass);
867
 
                return NT_STATUS_ACCOUNT_DISABLED;
868
 
        }
869
 
 
870
 
        if ((acct_ctrl & ACB_PWNOTREQ) && lp_null_passwords()) {
871
 
                /* construct a null password (in case one is needed */
872
 
                no_pw[0] = 0;
873
 
                no_pw[1] = 0;
874
 
                nt_lm_owf_gen(no_pw, null_ntpw, null_pw);
875
 
                lanman_pw = null_pw;
876
 
                nt_pw = null_pw;
877
 
 
878
 
        } else {
879
 
                /* save pointers to passwords so we don't have to keep looking them up */
880
 
                if (lp_lanman_auth()) {
881
 
                        lanman_pw = pdb_get_lanman_passwd(sampass);
882
 
                } else {
883
 
                        lanman_pw = NULL;
884
 
                }
885
 
                nt_pw = pdb_get_nt_passwd(sampass);
886
 
        }
887
 
 
888
 
        if (nt_pw && nt_pass_set) {
889
 
                /* IDEAL Case: passwords are in unicode, and we can
890
 
                 * read use the password encrypted with the NT hash
891
 
                 */
892
 
                password_encrypted = password_encrypted_with_nt_hash;
893
 
                encryption_key = nt_pw;
894
 
        } else if (lanman_pw && lm_pass_set) {
895
 
                /* password may still be in unicode, but use LM hash version */
896
 
                password_encrypted = password_encrypted_with_lm_hash;
897
 
                encryption_key = lanman_pw;
898
 
        } else if (nt_pass_set) {
899
 
                DEBUG(1, ("NT password change supplied for user %s, but we have no NT password to check it with\n", 
900
 
                          user));
901
 
                TALLOC_FREE(sampass);
902
 
                return NT_STATUS_WRONG_PASSWORD;
903
 
        } else if (lm_pass_set) {
904
 
                if (lp_lanman_auth()) {
905
 
                        DEBUG(1, ("LM password change supplied for user %s, but we have no LanMan password to check it with\n", 
906
 
                                  user));
907
 
                } else {
908
 
                        DEBUG(1, ("LM password change supplied for user %s, but we have disabled LanMan authentication\n", 
909
 
                                  user));
910
 
                }
911
 
                TALLOC_FREE(sampass);
912
 
                return NT_STATUS_WRONG_PASSWORD;
913
 
        } else {
914
 
                DEBUG(1, ("password change requested for user %s, but no password supplied!\n", 
915
 
                          user));
916
 
                TALLOC_FREE(sampass);
917
 
                return NT_STATUS_WRONG_PASSWORD;
918
 
        }
919
 
 
920
 
        /*
921
 
         * Decrypt the password with the key
922
 
         */
923
 
        SamOEMhash( password_encrypted, encryption_key, 516);
924
 
 
925
 
        if (!decode_pw_buffer(talloc_tos(),
926
 
                                password_encrypted,
927
 
                                pp_new_passwd,
928
 
                                &new_pw_len,
929
 
                                nt_pass_set ? STR_UNICODE : STR_ASCII)) {
930
 
                TALLOC_FREE(sampass);
931
 
                return NT_STATUS_WRONG_PASSWORD;
932
 
        }
933
 
 
934
 
        /*
935
 
         * To ensure we got the correct new password, hash it and
936
 
         * use it as a key to test the passed old password.
937
 
         */
938
 
 
939
 
        if (nt_pass_set) {
940
 
                /* NT passwords, verify the NT hash. */
941
 
 
942
 
                /* Calculate the MD4 hash (NT compatible) of the password */
943
 
                memset(new_nt_hash, '\0', 16);
944
 
                E_md4hash(*pp_new_passwd, new_nt_hash);
945
 
 
946
 
                if (nt_pw) {
947
 
                        /*
948
 
                         * check the NT verifier
949
 
                         */
950
 
                        E_old_pw_hash(new_nt_hash, nt_pw, verifier);
951
 
                        if (memcmp(verifier, old_nt_hash_encrypted, 16)) {
952
 
                                DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
953
 
                                TALLOC_FREE(sampass);
954
 
                                return NT_STATUS_WRONG_PASSWORD;
955
 
                        }
956
 
 
957
 
                        /* We could check the LM password here, but there is
958
 
                         * little point, we already know the password is
959
 
                         * correct, and the LM password might not even be
960
 
                         * present. */
961
 
 
962
 
                        /* Further, LM hash generation algorithms
963
 
                         * differ with charset, so we could
964
 
                         * incorrectly fail a perfectly valid password
965
 
                         * change */
966
 
#ifdef DEBUG_PASSWORD
967
 
                        DEBUG(100,
968
 
                              ("check_oem_password: password %s ok\n", *pp_new_passwd));
969
 
#endif
970
 
                        *hnd = sampass;
971
 
                        return NT_STATUS_OK;
972
 
                }
973
 
 
974
 
                if (lanman_pw) {
975
 
                        /*
976
 
                         * check the lm verifier
977
 
                         */
978
 
                        E_old_pw_hash(new_nt_hash, lanman_pw, verifier);
979
 
                        if (memcmp(verifier, old_lm_hash_encrypted, 16)) {
980
 
                                DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
981
 
                                TALLOC_FREE(sampass);
982
 
                                return NT_STATUS_WRONG_PASSWORD;
983
 
                        }
984
 
#ifdef DEBUG_PASSWORD
985
 
                        DEBUG(100,
986
 
                              ("check_oem_password: password %s ok\n", *pp_new_passwd));
987
 
#endif
988
 
                        *hnd = sampass;
989
 
                        return NT_STATUS_OK;
990
 
                }
991
 
        }
992
 
 
993
 
        if (lanman_pw && lm_pass_set) {
994
 
 
995
 
                E_deshash(*pp_new_passwd, new_lm_hash);
996
 
 
997
 
                /*
998
 
                 * check the lm verifier
999
 
                 */
1000
 
                E_old_pw_hash(new_lm_hash, lanman_pw, verifier);
1001
 
                if (memcmp(verifier, old_lm_hash_encrypted, 16)) {
1002
 
                        DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
1003
 
                        TALLOC_FREE(sampass);
1004
 
                        return NT_STATUS_WRONG_PASSWORD;
1005
 
                }
1006
 
 
1007
 
#ifdef DEBUG_PASSWORD
1008
 
                DEBUG(100,
1009
 
                      ("check_oem_password: password %s ok\n", *pp_new_passwd));
1010
 
#endif
1011
 
                *hnd = sampass;
1012
 
                return NT_STATUS_OK;
1013
 
        }
1014
 
 
1015
 
        /* should not be reached */
1016
 
        TALLOC_FREE(sampass);
1017
 
        return NT_STATUS_WRONG_PASSWORD;
1018
 
}
1019
 
 
1020
 
/***********************************************************
1021
 
 This routine takes the given password and checks it against
1022
 
 the password history. Returns True if this password has been
1023
 
 found in the history list.
1024
 
************************************************************/
1025
 
 
1026
 
static bool check_passwd_history(struct samu *sampass, const char *plaintext)
1027
 
{
1028
 
        uchar new_nt_p16[NT_HASH_LEN];
1029
 
        uchar zero_md5_nt_pw[SALTED_MD5_HASH_LEN];
1030
 
        const uint8 *nt_pw;
1031
 
        const uint8 *pwhistory;
1032
 
        bool found = False;
1033
 
        int i;
1034
 
        uint32 pwHisLen, curr_pwHisLen;
1035
 
 
1036
 
        pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHisLen);
1037
 
        if (pwHisLen == 0) {
1038
 
                return False;
1039
 
        }
1040
 
 
1041
 
        pwhistory = pdb_get_pw_history(sampass, &curr_pwHisLen);
1042
 
        if (!pwhistory || curr_pwHisLen == 0) {
1043
 
                return False;
1044
 
        }
1045
 
 
1046
 
        /* Only examine the minimum of the current history len and
1047
 
           the stored history len. Avoids race conditions. */
1048
 
        pwHisLen = MIN(pwHisLen,curr_pwHisLen);
1049
 
 
1050
 
        nt_pw = pdb_get_nt_passwd(sampass);
1051
 
 
1052
 
        E_md4hash(plaintext, new_nt_p16);
1053
 
 
1054
 
        if (!memcmp(nt_pw, new_nt_p16, NT_HASH_LEN)) {
1055
 
                DEBUG(10,("check_passwd_history: proposed new password for user %s is the same as the current password !\n",
1056
 
                        pdb_get_username(sampass) ));
1057
 
                return True;
1058
 
        }
1059
 
 
1060
 
        dump_data(100, new_nt_p16, NT_HASH_LEN);
1061
 
        dump_data(100, pwhistory, PW_HISTORY_ENTRY_LEN*pwHisLen);
1062
 
 
1063
 
        memset(zero_md5_nt_pw, '\0', SALTED_MD5_HASH_LEN);
1064
 
        for (i=0; i<pwHisLen; i++) {
1065
 
                uchar new_nt_pw_salted_md5_hash[SALTED_MD5_HASH_LEN];
1066
 
                const uchar *current_salt = &pwhistory[i*PW_HISTORY_ENTRY_LEN];
1067
 
                const uchar *old_nt_pw_salted_md5_hash = &pwhistory[(i*PW_HISTORY_ENTRY_LEN)+
1068
 
                                                        PW_HISTORY_SALT_LEN];
1069
 
                if (!memcmp(zero_md5_nt_pw, old_nt_pw_salted_md5_hash, SALTED_MD5_HASH_LEN)) {
1070
 
                        /* Ignore zero valued entries. */
1071
 
                        continue;
1072
 
                }
1073
 
                /* Create salted versions of new to compare. */
1074
 
                E_md5hash(current_salt, new_nt_p16, new_nt_pw_salted_md5_hash);
1075
 
 
1076
 
                if (!memcmp(new_nt_pw_salted_md5_hash, old_nt_pw_salted_md5_hash, SALTED_MD5_HASH_LEN)) {
1077
 
                        DEBUG(1,("check_passwd_history: proposed new password for user %s found in history list !\n",
1078
 
                                pdb_get_username(sampass) ));
1079
 
                        found = True;
1080
 
                        break;
1081
 
                }
1082
 
        }
1083
 
        return found;
1084
 
}
1085
 
 
1086
 
/***********************************************************
1087
 
 Code to change the oem password. Changes both the lanman
1088
 
 and NT hashes.  Old_passwd is almost always NULL.
1089
 
 NOTE this function is designed to be called as root. Check the old password
1090
 
 is correct before calling. JRA.
1091
 
************************************************************/
1092
 
 
1093
 
NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passwd, bool as_root, uint32 *samr_reject_reason)
1094
 
{
1095
 
        uint32 min_len;
1096
 
        uint32 refuse;
1097
 
        struct passwd *pass = NULL;
1098
 
        const char *username = pdb_get_username(hnd);
1099
 
        time_t can_change_time = pdb_get_pass_can_change_time(hnd);
1100
 
 
1101
 
        if (samr_reject_reason) {
1102
 
                *samr_reject_reason = Undefined;
1103
 
        }
1104
 
 
1105
 
        /* check to see if the secdesc has previously been set to disallow */
1106
 
        if (!pdb_get_pass_can_change(hnd)) {
1107
 
                DEBUG(1, ("user %s does not have permissions to change password\n", username));
1108
 
                if (samr_reject_reason) {
1109
 
                        *samr_reject_reason = SAMR_REJECT_OTHER;
1110
 
                }
1111
 
                return NT_STATUS_ACCOUNT_RESTRICTION;
1112
 
        }
1113
 
 
1114
 
        /* check to see if it is a Machine account and if the policy
1115
 
         * denies machines to change the password. *
1116
 
         * Should we deny also SRVTRUST and/or DOMSTRUST ? .SSS. */
1117
 
        if (pdb_get_acct_ctrl(hnd) & ACB_WSTRUST) {
1118
 
                if (pdb_get_account_policy(AP_REFUSE_MACHINE_PW_CHANGE, &refuse) && refuse) {
1119
 
                        DEBUG(1, ("Machine %s cannot change password now, "
1120
 
                                  "denied by Refuse Machine Password Change policy\n",
1121
 
                                  username));
1122
 
                        if (samr_reject_reason) {
1123
 
                                *samr_reject_reason = SAMR_REJECT_OTHER;
1124
 
                        }
1125
 
                        return NT_STATUS_ACCOUNT_RESTRICTION;
1126
 
                }
1127
 
        }
1128
 
 
1129
 
        /* removed calculation here, becuase passdb now calculates
1130
 
           based on policy.  jmcd */
1131
 
        if ((can_change_time != 0) && (time(NULL) < can_change_time)) {
1132
 
                DEBUG(1, ("user %s cannot change password now, must "
1133
 
                          "wait until %s\n", username,
1134
 
                          http_timestring(can_change_time)));
1135
 
                if (samr_reject_reason) {
1136
 
                        *samr_reject_reason = SAMR_REJECT_OTHER;
1137
 
                }
1138
 
                return NT_STATUS_ACCOUNT_RESTRICTION;
1139
 
        }
1140
 
 
1141
 
        if (pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &min_len) && (str_charnum(new_passwd) < min_len)) {
1142
 
                DEBUG(1, ("user %s cannot change password - password too short\n", 
1143
 
                          username));
1144
 
                DEBUGADD(1, (" account policy min password len = %d\n", min_len));
1145
 
                if (samr_reject_reason) {
1146
 
                        *samr_reject_reason = SAMR_REJECT_TOO_SHORT;
1147
 
                }
1148
 
                return NT_STATUS_PASSWORD_RESTRICTION;
1149
 
/*              return NT_STATUS_PWD_TOO_SHORT; */
1150
 
        }
1151
 
 
1152
 
        if (check_passwd_history(hnd,new_passwd)) {
1153
 
                if (samr_reject_reason) {
1154
 
                        *samr_reject_reason = SAMR_REJECT_IN_HISTORY;
1155
 
                }
1156
 
                return NT_STATUS_PASSWORD_RESTRICTION;
1157
 
        }
1158
 
 
1159
 
        pass = Get_Pwnam_alloc(talloc_tos(), username);
1160
 
        if (!pass) {
1161
 
                DEBUG(1, ("change_oem_password: Username %s does not exist in system !?!\n", username));
1162
 
                return NT_STATUS_ACCESS_DENIED;
1163
 
        }
1164
 
 
1165
 
        /* Use external script to check password complexity */
1166
 
        if (lp_check_password_script() && *(lp_check_password_script())) {
1167
 
                int check_ret;
1168
 
 
1169
 
                check_ret = smbrunsecret(lp_check_password_script(), new_passwd);
1170
 
                DEBUG(5, ("change_oem_password: check password script (%s) returned [%d]\n", lp_check_password_script(), check_ret));
1171
 
 
1172
 
                if (check_ret != 0) {
1173
 
                        DEBUG(1, ("change_oem_password: check password script said new password is not good enough!\n"));
1174
 
                        if (samr_reject_reason) {
1175
 
                                *samr_reject_reason = SAMR_REJECT_COMPLEXITY;
1176
 
                        }
1177
 
                        TALLOC_FREE(pass);
1178
 
                        return NT_STATUS_PASSWORD_RESTRICTION;
1179
 
                }
1180
 
        }
1181
 
 
1182
 
        /*
1183
 
         * If unix password sync was requested, attempt to change
1184
 
         * the /etc/passwd database first. Return failure if this cannot
1185
 
         * be done.
1186
 
         *
1187
 
         * This occurs before the oem change, because we don't want to
1188
 
         * update it if chgpasswd failed.
1189
 
         *
1190
 
         * Conditional on lp_unix_password_sync() because we don't want
1191
 
         * to touch the unix db unless we have admin permission.
1192
 
         */
1193
 
        
1194
 
        if(lp_unix_password_sync() &&
1195
 
                !chgpasswd(username, pass, old_passwd, new_passwd, as_root)) {
1196
 
                TALLOC_FREE(pass);
1197
 
                return NT_STATUS_ACCESS_DENIED;
1198
 
        }
1199
 
 
1200
 
        TALLOC_FREE(pass);
1201
 
 
1202
 
        if (!pdb_set_plaintext_passwd (hnd, new_passwd)) {
1203
 
                return NT_STATUS_ACCESS_DENIED;
1204
 
        }
1205
 
 
1206
 
        /* Now write it into the file. */
1207
 
        return pdb_update_sam_account (hnd);
1208
 
}