2 * Unix SMB/CIFS implementation.
3 * SMB parameters and setup
4 * Copyright (C) Andrew Tridgell 1992-1998
5 * Modified by Jeremy Allison 1995.
6 * Modified by Gerald (Jerry) Carter 2000-2001
7 * Modified by Andrew Bartlett 2002.
9 * This program is free software; you can redistribute it and/or modify it under
10 * the terms of the GNU General Public License as published by the Free
11 * Software Foundation; either version 2 of the License, or (at your option)
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * You should have received a copy of the GNU General Public License along with
20 * this program; if not, write to the Free Software Foundation, Inc., 675
21 * Mass Ave, Cambridge, MA 02139, USA.
27 #define DBGC_CLASS DBGC_PASSDB
30 smb_passwd is analogous to sam_passwd used everywhere
31 else. However, smb_passwd is limited to the information
32 stored by an smbpasswd entry
37 BOOL smb_userid_set; /* this is actually the unix uid_t */
38 uint32 smb_userid; /* this is actually the unix uid_t */
39 const char *smb_name; /* username string */
41 const unsigned char *smb_passwd; /* Null if no password */
42 const unsigned char *smb_nt_passwd; /* Null if no password */
44 uint16 acct_ctrl; /* account info (ACB_xxxx bit-mask) */
45 time_t pass_last_set_time; /* password last set time */
48 struct smbpasswd_privates
50 /* used for maintain locks on the smbpasswd file */
51 int pw_file_lock_depth;
53 /* Global File pointer */
56 /* formerly static variables */
57 struct smb_passwd pw_buf;
59 unsigned char smbpwd[16];
60 unsigned char smbntpwd[16];
62 /* retrive-once info */
63 const char *smbpasswd_file;
65 BOOL permit_non_unix_accounts;
67 uint32 low_nua_userid;
68 uint32 high_nua_userid;
72 enum pwf_access_type { PWF_READ, PWF_UPDATE, PWF_CREATE };
74 /***************************************************************
75 Lock an fd. Abandon after waitsecs seconds.
76 ****************************************************************/
78 static BOOL pw_file_lock(int fd, int type, int secs, int *plock_depth)
83 if(*plock_depth == 0) {
84 if (!do_file_lock(fd, secs, type)) {
85 DEBUG(10,("pw_file_lock: locking file failed, error = %s.\n",
96 /***************************************************************
97 Unlock an fd. Abandon after waitsecs seconds.
98 ****************************************************************/
100 static BOOL pw_file_unlock(int fd, int *plock_depth)
104 if(*plock_depth == 1)
105 ret = do_file_lock(fd, 5, F_UNLCK);
107 if (*plock_depth > 0)
111 DEBUG(10,("pw_file_unlock: unlocking file failed, error = %s.\n",
117 /**************************************************************
118 Intialize a smb_passwd struct
119 *************************************************************/
121 static void pdb_init_smb(struct smb_passwd *user)
127 user->pass_last_set_time = (time_t)0;
130 /***************************************************************
131 Internal fn to enumerate the smbpasswd list. Returns a void pointer
132 to ensure no modification outside this module. Checks for atomic
133 rename of smbpasswd file on update or create once the lock has
134 been granted to prevent race conditions. JRA.
135 ****************************************************************/
137 static FILE *startsmbfilepwent(const char *pfile, enum pwf_access_type type, int *lock_depth)
140 const char *open_mode = NULL;
142 int lock_type = F_RDLCK;
145 DEBUG(0, ("startsmbfilepwent: No SMB password file set\n"));
160 * Ensure atomic file creation.
165 for(i = 0; i < 5; i++) {
166 if((fd = sys_open(pfile, O_CREAT|O_TRUNC|O_EXCL|O_RDWR, 0600))!=-1)
168 sys_usleep(200); /* Spin, spin... */
171 DEBUG(0,("startsmbfilepwent_internal: too many race conditions creating file %s\n", pfile));
181 for(race_loop = 0; race_loop < 5; race_loop++) {
182 DEBUG(10, ("startsmbfilepwent_internal: opening file %s\n", pfile));
184 if((fp = sys_fopen(pfile, open_mode)) == NULL) {
185 DEBUG(0, ("startsmbfilepwent_internal: unable to open file %s. Error was %s\n", pfile, strerror(errno) ));
189 if (!pw_file_lock(fileno(fp), lock_type, 5, lock_depth)) {
190 DEBUG(0, ("startsmbfilepwent_internal: unable to lock file %s. Error was %s\n", pfile, strerror(errno) ));
196 * Only check for replacement races on update or create.
197 * For read we don't mind if the data is one record out of date.
200 if(type == PWF_READ) {
203 SMB_STRUCT_STAT sbuf1, sbuf2;
206 * Avoid the potential race condition between the open and the lock
207 * by doing a stat on the filename and an fstat on the fd. If the
208 * two inodes differ then someone did a rename between the open and
209 * the lock. Back off and try the open again. Only do this 5 times to
210 * prevent infinate loops. JRA.
213 if (sys_stat(pfile,&sbuf1) != 0) {
214 DEBUG(0, ("startsmbfilepwent_internal: unable to stat file %s. Error was %s\n", pfile, strerror(errno)));
215 pw_file_unlock(fileno(fp), lock_depth);
220 if (sys_fstat(fileno(fp),&sbuf2) != 0) {
221 DEBUG(0, ("startsmbfilepwent_internal: unable to fstat file %s. Error was %s\n", pfile, strerror(errno)));
222 pw_file_unlock(fileno(fp), lock_depth);
227 if( sbuf1.st_ino == sbuf2.st_ino) {
233 * Race occurred - back off and try again...
236 pw_file_unlock(fileno(fp), lock_depth);
242 DEBUG(0, ("startsmbfilepwent_internal: too many race conditions opening file %s\n", pfile));
246 /* Set a buffer to do more efficient reads */
247 setvbuf(fp, (char *)NULL, _IOFBF, 1024);
249 /* Make sure it is only rw by the owner */
250 if(fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) {
251 DEBUG(0, ("startsmbfilepwent_internal: failed to set 0600 permissions on password file %s. \
252 Error was %s\n.", pfile, strerror(errno) ));
253 pw_file_unlock(fileno(fp), lock_depth);
258 /* We have a lock on the file. */
262 /***************************************************************
263 End enumeration of the smbpasswd list.
264 ****************************************************************/
265 static void endsmbfilepwent(FILE *fp, int *lock_depth)
268 pw_file_unlock(fileno(fp), lock_depth);
270 DEBUG(7, ("endsmbfilepwent_internal: closed password file.\n"));
273 /*************************************************************************
274 Routine to return the next entry in the smbpasswd list.
275 *************************************************************************/
277 static struct smb_passwd *getsmbfilepwent(struct smbpasswd_privates *smbpasswd_state, FILE *fp)
279 /* Static buffers we will return. */
280 struct smb_passwd *pw_buf = &smbpasswd_state->pw_buf;
281 char *user_name = smbpasswd_state->user_name;
282 unsigned char *smbpwd = smbpasswd_state->smbpwd;
283 unsigned char *smbntpwd = smbpasswd_state->smbntpwd;
291 DEBUG(0,("getsmbfilepwent: Bad password file pointer.\n"));
295 pdb_init_smb(pw_buf);
297 pw_buf->acct_ctrl = ACB_NORMAL;
300 * Scan the file, a line at a time and check if the name matches.
305 fgets(linebuf, 256, fp);
311 * Check if the string is terminated with a newline - if not
312 * then we must keep reading and discard until we get one.
314 if ((linebuf_len = strlen(linebuf)) == 0)
317 if (linebuf[linebuf_len - 1] != '\n') {
319 while (!ferror(fp) && !feof(fp)) {
325 linebuf[linebuf_len - 1] = '\0';
327 #ifdef DEBUG_PASSWORD
328 DEBUG(100, ("getsmbfilepwent: got line |%s|\n", linebuf));
330 if ((linebuf[0] == 0) && feof(fp)) {
331 DEBUG(4, ("getsmbfilepwent: end of file reached\n"));
335 * The line we have should be of the form :-
337 * username:uid:32hex bytes:[Account type]:LCT-12345678....other flags presently
342 * username:uid:32hex bytes:32hex bytes:[Account type]:LCT-12345678....ignored....
344 * if Windows NT compatible passwords are also present.
345 * [Account type] is an ascii encoding of the type of account.
346 * LCT-(8 hex digits) is the time_t value of the last change time.
349 if (linebuf[0] == '#' || linebuf[0] == '\0') {
350 DEBUG(6, ("getsmbfilepwent: skipping comment or blank line\n"));
353 p = (unsigned char *) strchr_m(linebuf, ':');
355 DEBUG(0, ("getsmbfilepwent: malformed password entry (no :)\n"));
359 * As 256 is shorter than a pstring we don't need to check
360 * length here - if this ever changes....
362 SMB_ASSERT(sizeof(pstring) > sizeof(linebuf));
364 strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
365 user_name[PTR_DIFF(p, linebuf)] = '\0';
369 p++; /* Go past ':' */
372 DEBUG(0, ("getsmbfilepwent: uids in the smbpasswd file must not be negative.\n"));
377 DEBUG(0, ("getsmbfilepwent: malformed password entry (uid not number)\n"));
381 uidval = atoi((char *) p);
383 while (*p && isdigit(*p))
387 DEBUG(0, ("getsmbfilepwent: malformed password entry (no : after uid)\n"));
391 pw_buf->smb_name = user_name;
392 pw_buf->smb_userid = uidval;
395 * Now get the password value - this should be 32 hex digits
396 * which are the ascii representations of a 16 byte string.
397 * Get two at a time and put them into the password.
403 if (*p == '*' || *p == 'X') {
404 /* Password deliberately invalid - end here. */
405 DEBUG(10, ("getsmbfilepwent: entry invalidated for user %s\n", user_name));
406 pw_buf->smb_nt_passwd = NULL;
407 pw_buf->smb_passwd = NULL;
408 pw_buf->acct_ctrl |= ACB_DISABLED;
412 if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
413 DEBUG(0, ("getsmbfilepwent: malformed password entry (passwd too short)\n"));
418 DEBUG(0, ("getsmbfilepwent: malformed password entry (no terminating :)\n"));
422 if (!strncasecmp((char *) p, "NO PASSWORD", 11)) {
423 pw_buf->smb_passwd = NULL;
424 pw_buf->acct_ctrl |= ACB_PWNOTREQ;
426 if (!pdb_gethexpwd((char *)p, smbpwd)) {
427 DEBUG(0, ("getsmbfilepwent: Malformed Lanman password entry (non hex chars)\n"));
430 pw_buf->smb_passwd = smbpwd;
434 * Now check if the NT compatible password is
437 pw_buf->smb_nt_passwd = NULL;
439 p += 33; /* Move to the first character of the line after
440 the lanman password. */
441 if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
442 if (*p != '*' && *p != 'X') {
443 if(pdb_gethexpwd((char *)p,smbntpwd))
444 pw_buf->smb_nt_passwd = smbntpwd;
446 p += 33; /* Move to the first character of the line after
450 DEBUG(5,("getsmbfilepwent: returning passwd entry for user %s, uid %ld\n",
455 unsigned char *end_p = (unsigned char *)strchr_m((char *)p, ']');
456 pw_buf->acct_ctrl = pdb_decode_acct_ctrl((char*)p);
458 /* Must have some account type set. */
459 if(pw_buf->acct_ctrl == 0)
460 pw_buf->acct_ctrl = ACB_NORMAL;
462 /* Now try and get the last change time. */
467 if(*p && (StrnCaseCmp((char *)p, "LCT-", 4)==0)) {
470 for(i = 0; i < 8; i++) {
471 if(p[i] == '\0' || !isxdigit(p[i]))
476 * p points at 8 characters of hex digits -
477 * read into a time_t as the seconds since
478 * 1970 that the password was last changed.
480 pw_buf->pass_last_set_time = (time_t)strtol((char *)p, NULL, 16);
485 /* 'Old' style file. Fake up based on user name. */
487 * Currently trust accounts are kept in the same
488 * password file as 'normal accounts'. If this changes
489 * we will have to fix this code. JRA.
491 if(pw_buf->smb_name[strlen(pw_buf->smb_name) - 1] == '$') {
492 pw_buf->acct_ctrl &= ~ACB_NORMAL;
493 pw_buf->acct_ctrl |= ACB_WSTRUST;
500 DEBUG(5,("getsmbfilepwent: end of file reached.\n"));
504 /************************************************************************
505 Create a new smbpasswd entry - malloced space returned.
506 *************************************************************************/
508 static char *format_new_smbpasswd_entry(const struct smb_passwd *newpwd)
510 int new_entry_length;
515 new_entry_length = strlen(newpwd->smb_name) + 1 + 15 + 1 + 32 + 1 + 32 + 1 + NEW_PW_FORMAT_SPACE_PADDED_LEN + 1 + 13 + 2;
517 if((new_entry = (char *)malloc( new_entry_length )) == NULL) {
518 DEBUG(0, ("format_new_smbpasswd_entry: Malloc failed adding entry for user %s.\n", newpwd->smb_name ));
522 slprintf(new_entry, new_entry_length - 1, "%s:%u:", newpwd->smb_name, (unsigned)newpwd->smb_userid);
523 p = &new_entry[strlen(new_entry)];
525 if(newpwd->smb_passwd != NULL) {
526 for( i = 0; i < 16; i++) {
527 slprintf((char *)&p[i*2], new_entry_length - (p - new_entry) - 1, "%02X", newpwd->smb_passwd[i]);
531 if(newpwd->acct_ctrl & ACB_PWNOTREQ)
532 safe_strcpy((char *)p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
534 safe_strcpy((char *)p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
541 if(newpwd->smb_nt_passwd != NULL) {
542 for( i = 0; i < 16; i++) {
543 slprintf((char *)&p[i*2], new_entry_length - 1 - (p - new_entry), "%02X", newpwd->smb_nt_passwd[i]);
546 if(newpwd->acct_ctrl & ACB_PWNOTREQ)
547 safe_strcpy((char *)p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
549 safe_strcpy((char *)p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry));
556 /* Add the account encoding and the last change time. */
557 slprintf((char *)p, new_entry_length - 1 - (p - new_entry), "%s:LCT-%08X:\n",
558 pdb_encode_acct_ctrl(newpwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN),
559 (uint32)newpwd->pass_last_set_time);
564 /************************************************************************
565 Routine to add an entry to the smbpasswd file.
566 *************************************************************************/
568 static BOOL add_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, struct smb_passwd *newpwd)
570 const char *pfile = smbpasswd_state->smbpasswd_file;
571 struct smb_passwd *pwd = NULL;
575 size_t new_entry_length;
578 uint32 max_found_uid = 0;
580 /* Open the smbpassword file - for update. */
581 fp = startsmbfilepwent(pfile, PWF_UPDATE, &(smbpasswd_state->pw_file_lock_depth));
583 if (fp == NULL && errno == ENOENT) {
584 /* Try again - create. */
585 fp = startsmbfilepwent(pfile, PWF_CREATE, &(smbpasswd_state->pw_file_lock_depth));
589 DEBUG(0, ("add_smbfilepwd_entry: unable to open file.\n"));
594 * Scan the file, a line at a time and check if the name matches.
597 while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL)
599 if (strequal(newpwd->smb_name, pwd->smb_name))
601 DEBUG(0, ("add_smbfilepwd_entry: entry with name %s already exists\n", pwd->smb_name));
602 endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
606 /* Look for a free uid for use in non-unix accounts */
607 if (pwd->smb_userid > max_found_uid) {
608 max_found_uid = pwd->smb_userid;
612 /* Ok - entry doesn't exist. We can add it */
614 /* Account not in /etc/passwd hack!!! */
615 if (!newpwd->smb_userid_set) {
616 if (!smbpasswd_state->permit_non_unix_accounts) {
617 DEBUG(0, ("add_smbfilepwd_entry: cannot add account %s without unix identity\n", newpwd->smb_name));
618 endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
622 if (max_found_uid < smbpasswd_state->low_nua_userid) {
623 newpwd->smb_userid = smbpasswd_state->low_nua_userid;
624 newpwd->smb_userid_set = True;
625 } else if (max_found_uid >= smbpasswd_state->high_nua_userid) {
626 DEBUG(0, ("add_smbfilepwd_entry: cannot add machine %s, no uids are free! \n", newpwd->smb_name));
627 endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
630 newpwd->smb_userid = max_found_uid + 1;
631 newpwd->smb_userid_set = True;
636 /* Create a new smb passwd entry and set it to the given password. */
638 * The add user write needs to be atomic - so get the fd from
639 * the fp and do a raw write() call.
643 if((offpos = sys_lseek(fd, 0, SEEK_END)) == -1)
645 DEBUG(0, ("add_smbfilepwd_entry(sys_lseek): Failed to add entry for user %s to file %s. \
646 Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
647 endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
651 if((new_entry = format_new_smbpasswd_entry(newpwd)) == NULL)
653 DEBUG(0, ("add_smbfilepwd_entry(malloc): Failed to add entry for user %s to file %s. \
654 Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
655 endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
659 new_entry_length = strlen(new_entry);
661 #ifdef DEBUG_PASSWORD
662 DEBUG(100, ("add_smbfilepwd_entry(%d): new_entry_len %d made line |%s|",
663 fd, new_entry_length, new_entry));
666 if ((wr_len = write(fd, new_entry, new_entry_length)) != new_entry_length)
668 DEBUG(0, ("add_smbfilepwd_entry(write): %d Failed to add entry for user %s to file %s. \
669 Error was %s\n", wr_len, newpwd->smb_name, pfile, strerror(errno)));
671 /* Remove the entry we just wrote. */
672 if(sys_ftruncate(fd, offpos) == -1)
674 DEBUG(0, ("add_smbfilepwd_entry: ERROR failed to ftruncate file %s. \
675 Error was %s. Password file may be corrupt ! Please examine by hand !\n",
676 newpwd->smb_name, strerror(errno)));
679 endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
685 endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
689 /************************************************************************
690 Routine to search the smbpasswd file for an entry matching the username.
691 and then modify its password entry. We can't use the startsmbpwent()/
692 getsmbpwent()/endsmbpwent() interfaces here as we depend on looking
693 in the actual file to decide how much room we have to write data.
694 override = False, normal
695 override = True, override XXXXXXXX'd out password or NO PASS
696 ************************************************************************/
698 static BOOL mod_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, const struct smb_passwd* pwd)
700 /* Static buffers we will return. */
708 unsigned char *p = NULL;
709 size_t linebuf_len = 0;
712 const char *pfile = smbpasswd_state->smbpasswd_file;
713 BOOL found_entry = False;
714 BOOL got_pass_last_set_time = False;
716 SMB_OFF_T pwd_seekpos = 0;
723 DEBUG(0, ("No SMB password file set\n"));
726 DEBUG(10, ("mod_smbfilepwd_entry: opening file %s\n", pfile));
728 fp = sys_fopen(pfile, "r+");
731 DEBUG(0, ("mod_smbfilepwd_entry: unable to open file %s\n", pfile));
734 /* Set a buffer to do more efficient reads */
735 setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
739 if (!pw_file_lock(lockfd, F_WRLCK, 5, &(smbpasswd_state->pw_file_lock_depth))) {
740 DEBUG(0, ("mod_smbfilepwd_entry: unable to lock file %s\n", pfile));
745 /* Make sure it is only rw by the owner */
748 /* We have a write lock on the file. */
750 * Scan the file, a line at a time and check if the name matches.
753 pwd_seekpos = sys_ftell(fp);
757 fgets(linebuf, sizeof(linebuf), fp);
759 pw_file_unlock(lockfd, &(smbpasswd_state->pw_file_lock_depth));
765 * Check if the string is terminated with a newline - if not
766 * then we must keep reading and discard until we get one.
768 linebuf_len = strlen(linebuf);
769 if (linebuf[linebuf_len - 1] != '\n') {
771 while (!ferror(fp) && !feof(fp)) {
778 linebuf[linebuf_len - 1] = '\0';
781 #ifdef DEBUG_PASSWORD
782 DEBUG(100, ("mod_smbfilepwd_entry: got line |%s|\n", linebuf));
785 if ((linebuf[0] == 0) && feof(fp)) {
786 DEBUG(4, ("mod_smbfilepwd_entry: end of file reached\n"));
791 * The line we have should be of the form :-
793 * username:uid:[32hex bytes]:....other flags presently
798 * username:uid:[32hex bytes]:[32hex bytes]:[attributes]:LCT-XXXXXXXX:...ignored.
800 * if Windows NT compatible passwords are also present.
803 if (linebuf[0] == '#' || linebuf[0] == '\0') {
804 DEBUG(6, ("mod_smbfilepwd_entry: skipping comment or blank line\n"));
808 p = (unsigned char *) strchr_m(linebuf, ':');
811 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no :)\n"));
816 * As 256 is shorter than a pstring we don't need to check
817 * length here - if this ever changes....
820 SMB_ASSERT(sizeof(user_name) > sizeof(linebuf));
822 strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
823 user_name[PTR_DIFF(p, linebuf)] = '\0';
824 if (strequal(user_name, pwd->smb_name)) {
831 pw_file_unlock(lockfd, &(smbpasswd_state->pw_file_lock_depth));
834 DEBUG(2, ("Cannot update entry for user %s, as they don't exist in the smbpasswd file!\n",
839 DEBUG(6, ("mod_smbfilepwd_entry: entry exists\n"));
841 /* User name matches - get uid and password */
842 p++; /* Go past ':' */
845 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (uid not number)\n"));
846 pw_file_unlock(lockfd, &(smbpasswd_state->pw_file_lock_depth));
851 while (*p && isdigit(*p))
854 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no : after uid)\n"));
855 pw_file_unlock(lockfd, &(smbpasswd_state->pw_file_lock_depth));
861 * Now get the password value - this should be 32 hex digits
862 * which are the ascii representations of a 16 byte string.
863 * Get two at a time and put them into the password.
867 /* Record exact password position */
868 pwd_seekpos += PTR_DIFF(p, linebuf);
870 if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
871 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (passwd too short)\n"));
872 pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
878 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no terminating :)\n"));
879 pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
884 /* Now check if the NT compatible password is
886 p += 33; /* Move to the first character of the line after
887 the lanman password. */
888 if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
889 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (passwd too short)\n"));
890 pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
896 DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no terminating :)\n"));
897 pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
903 * Now check if the account info and the password last
904 * change time is available.
906 p += 33; /* Move to the first character of the line after
912 encode_bits[i++] = *p++;
913 while((linebuf_len > PTR_DIFF(p, linebuf)) && (*p != ']'))
914 encode_bits[i++] = *p++;
916 encode_bits[i++] = ']';
917 encode_bits[i++] = '\0';
919 if(i == NEW_PW_FORMAT_SPACE_PADDED_LEN) {
921 * We are using a new format, space padded
922 * acct ctrl field. Encode the given acct ctrl
925 fstrcpy(encode_bits, pdb_encode_acct_ctrl(pwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN));
927 DEBUG(0,("mod_smbfilepwd_entry: Using old smbpasswd format. This is no longer supported.!\n"));
928 DEBUG(0,("mod_smbfilepwd_entry: No changes made, failing.!\n"));
932 /* Go past the ']' */
933 if(linebuf_len > PTR_DIFF(p, linebuf))
936 if((linebuf_len > PTR_DIFF(p, linebuf)) && (*p == ':')) {
939 /* We should be pointing at the LCT entry. */
940 if((linebuf_len > (PTR_DIFF(p, linebuf) + 13)) && (StrnCaseCmp((char *)p, "LCT-", 4) == 0)) {
943 for(i = 0; i < 8; i++) {
944 if(p[i] == '\0' || !isxdigit(p[i]))
949 * p points at 8 characters of hex digits -
950 * read into a time_t as the seconds since
951 * 1970 that the password was last changed.
953 got_pass_last_set_time = True;
955 } /* *p && StrnCaseCmp() */
959 /* Entry is correctly formed. */
961 /* Create the 32 byte representation of the new p16 */
962 if(pwd->smb_passwd != NULL) {
963 for (i = 0; i < 16; i++) {
964 slprintf(&ascii_p16[i*2], sizeof(fstring) - 1, "%02X", (uchar) pwd->smb_passwd[i]);
967 if(pwd->acct_ctrl & ACB_PWNOTREQ)
968 fstrcpy(ascii_p16, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
970 fstrcpy(ascii_p16, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
973 /* Add on the NT md4 hash */
976 if (pwd->smb_nt_passwd != NULL) {
977 for (i = 0; i < 16; i++) {
978 slprintf(&ascii_p16[(i*2)+33], sizeof(fstring) - 1, "%02X", (uchar) pwd->smb_nt_passwd[i]);
981 if(pwd->acct_ctrl & ACB_PWNOTREQ)
982 fstrcpy(&ascii_p16[33], "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
984 fstrcpy(&ascii_p16[33], "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
987 ascii_p16[66] = '\0'; /* null-terminate the string so that strlen works */
989 /* Add on the account info bits and the time of last
992 if(got_pass_last_set_time) {
993 slprintf(&ascii_p16[strlen(ascii_p16)],
994 sizeof(ascii_p16)-(strlen(ascii_p16)+1),
996 encode_bits, (uint32)pwd->pass_last_set_time );
997 wr_len = strlen(ascii_p16);
1000 #ifdef DEBUG_PASSWORD
1001 DEBUG(100,("mod_smbfilepwd_entry: "));
1002 dump_data(100, ascii_p16, wr_len);
1005 if(wr_len > sizeof(linebuf)) {
1006 DEBUG(0, ("mod_smbfilepwd_entry: line to write (%d) is too long.\n", wr_len+1));
1007 pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
1013 * Do an atomic write into the file at the position defined by
1017 /* The mod user write needs to be atomic - so get the fd from
1018 the fp and do a raw write() call.
1023 if (sys_lseek(fd, pwd_seekpos - 1, SEEK_SET) != pwd_seekpos - 1) {
1024 DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
1025 pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
1030 /* Sanity check - ensure the areas we are writing are framed by ':' */
1031 if (read(fd, linebuf, wr_len+1) != wr_len+1) {
1032 DEBUG(0, ("mod_smbfilepwd_entry: read fail on file %s.\n", pfile));
1033 pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
1038 if ((linebuf[0] != ':') || (linebuf[wr_len] != ':')) {
1039 DEBUG(0, ("mod_smbfilepwd_entry: check on passwd file %s failed.\n", pfile));
1040 pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
1045 if (sys_lseek(fd, pwd_seekpos, SEEK_SET) != pwd_seekpos) {
1046 DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
1047 pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
1052 if (write(fd, ascii_p16, wr_len) != wr_len) {
1053 DEBUG(0, ("mod_smbfilepwd_entry: write failed in passwd file %s\n", pfile));
1054 pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
1059 pw_file_unlock(lockfd,&(smbpasswd_state->pw_file_lock_depth));
1064 /************************************************************************
1065 Routine to delete an entry in the smbpasswd file by name.
1066 *************************************************************************/
1068 static BOOL del_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, const char *name)
1070 const char *pfile = smbpasswd_state->smbpasswd_file;
1072 struct smb_passwd *pwd = NULL;
1074 FILE *fp_write = NULL;
1075 int pfile2_lockdepth = 0;
1077 slprintf(pfile2, sizeof(pfile2)-1, "%s.%u", pfile, (unsigned)sys_getpid() );
1080 * Open the smbpassword file - for update. It needs to be update
1081 * as we need any other processes to wait until we have replaced
1085 if((fp = startsmbfilepwent(pfile, PWF_UPDATE, &(smbpasswd_state->pw_file_lock_depth))) == NULL) {
1086 DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
1091 * Create the replacement password file.
1093 if((fp_write = startsmbfilepwent(pfile2, PWF_CREATE, &pfile2_lockdepth)) == NULL) {
1094 DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
1095 endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
1100 * Scan the file, a line at a time and check if the name matches.
1103 while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) {
1105 size_t new_entry_length;
1107 if (strequal(name, pwd->smb_name)) {
1108 DEBUG(10, ("add_smbfilepwd_entry: found entry with name %s - deleting it.\n", name));
1113 * We need to copy the entry out into the second file.
1116 if((new_entry = format_new_smbpasswd_entry(pwd)) == NULL)
1118 DEBUG(0, ("del_smbfilepwd_entry(malloc): Failed to copy entry for user %s to file %s. \
1119 Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
1121 endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
1122 endsmbfilepwent(fp_write, &pfile2_lockdepth);
1126 new_entry_length = strlen(new_entry);
1128 if(fwrite(new_entry, 1, new_entry_length, fp_write) != new_entry_length)
1130 DEBUG(0, ("del_smbfilepwd_entry(write): Failed to copy entry for user %s to file %s. \
1131 Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
1133 endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
1134 endsmbfilepwent(fp_write, &pfile2_lockdepth);
1143 * Ensure pfile2 is flushed before rename.
1146 if(fflush(fp_write) != 0)
1148 DEBUG(0, ("del_smbfilepwd_entry: Failed to flush file %s. Error was %s\n", pfile2, strerror(errno)));
1149 endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
1150 endsmbfilepwent(fp_write,&pfile2_lockdepth);
1155 * Do an atomic rename - then release the locks.
1158 if(rename(pfile2,pfile) != 0) {
1162 endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
1163 endsmbfilepwent(fp_write,&pfile2_lockdepth);
1167 /*********************************************************************
1168 Create a smb_passwd struct from a SAM_ACCOUNT.
1169 We will not allocate any new memory. The smb_passwd struct
1170 should only stay around as long as the SAM_ACCOUNT does.
1171 ********************************************************************/
1172 static BOOL build_smb_pass (struct smb_passwd *smb_pw, const SAM_ACCOUNT *sampass)
1176 if (sampass == NULL)
1179 ZERO_STRUCTP(smb_pw);
1181 if (!IS_SAM_UNIX_USER(sampass)) {
1182 smb_pw->smb_userid_set = False;
1183 DEBUG(5,("build_smb_pass: storing user without a UNIX uid or gid. \n"));
1185 uint32 rid = pdb_get_user_rid(sampass);
1186 smb_pw->smb_userid_set = True;
1187 uid = pdb_get_uid(sampass);
1189 /* If the user specified a RID, make sure its able to be both stored and retreived */
1190 if (rid && uid != fallback_pdb_user_rid_to_uid(rid)) {
1191 DEBUG(0,("build_sam_pass: Failing attempt to store user with non-uid based user RID. \n"));
1195 smb_pw->smb_userid=uid;
1198 smb_pw->smb_name=(const char*)pdb_get_username(sampass);
1200 smb_pw->smb_passwd=pdb_get_lanman_passwd(sampass);
1201 smb_pw->smb_nt_passwd=pdb_get_nt_passwd(sampass);
1203 smb_pw->acct_ctrl=pdb_get_acct_ctrl(sampass);
1204 smb_pw->pass_last_set_time=pdb_get_pass_last_set_time(sampass);
1208 * ifdef'out by JFM on 11/29/2001.
1209 * this assertion is no longer valid
1210 * and I don't understand the goal
1211 * and doing the same thing with the group mapping code
1214 * We just have the RID, in which SID is it valid ?
1215 * our domain SID ? well known SID ? local SID ?
1218 if (gid != pdb_group_rid_to_gid(pdb_get_group_rid(sampass))) {
1219 DEBUG(0,("build_sam_pass: Failing attempt to store user with non-gid based primary group RID. \n"));
1220 DEBUG(0,("build_sam_pass: %d %d %d. \n", *gid, pdb_group_rid_to_gid(pdb_get_group_rid(sampass)), pdb_get_group_rid(sampass)));
1228 /*********************************************************************
1229 Create a SAM_ACCOUNT from a smb_passwd struct
1230 ********************************************************************/
1231 static BOOL build_sam_account(struct smbpasswd_privates *smbpasswd_state,
1232 SAM_ACCOUNT *sam_pass, const struct smb_passwd *pw_buf)
1234 struct passwd *pwfile;
1236 if (sam_pass==NULL) {
1237 DEBUG(5,("build_sam_account: SAM_ACCOUNT is NULL\n"));
1241 if ((smbpasswd_state->permit_non_unix_accounts)
1242 && (pw_buf->smb_userid >= smbpasswd_state->low_nua_userid)
1243 && (pw_buf->smb_userid <= smbpasswd_state->high_nua_userid)) {
1245 pdb_set_user_rid(sam_pass, fallback_pdb_uid_to_user_rid (pw_buf->smb_userid));
1247 /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here.
1249 This was down the bottom for machines, but it looks pretty good as
1250 a general default for non-unix users. --abartlet 2002-01-08
1252 pdb_set_group_rid (sam_pass, DOMAIN_GROUP_RID_USERS);
1253 pdb_set_username (sam_pass, pw_buf->smb_name);
1254 pdb_set_domain (sam_pass, lp_workgroup());
1257 pwfile = getpwnam_alloc(pw_buf->smb_name);
1258 if (pwfile == NULL) {
1259 DEBUG(0,("build_sam_account: smbpasswd database is corrupt! username %s with uid %u is not in unix passwd database!\n", pw_buf->smb_name, pw_buf->smb_userid));
1263 if (!NT_STATUS_IS_OK(pdb_fill_sam_pw(sam_pass, pwfile))) {
1267 passwd_free(&pwfile);
1270 pdb_set_nt_passwd (sam_pass, pw_buf->smb_nt_passwd);
1271 pdb_set_lanman_passwd (sam_pass, pw_buf->smb_passwd);
1272 pdb_set_acct_ctrl (sam_pass, pw_buf->acct_ctrl);
1273 pdb_set_pass_last_set_time (sam_pass, pw_buf->pass_last_set_time);
1274 pdb_set_pass_can_change_time (sam_pass, pw_buf->pass_last_set_time, True);
1277 /* the smbpasswd format doesn't have a must change time field, so
1278 we can't get this right. The best we can do is to set this to
1279 some time in the future. 21 days seems as reasonable as any other value :)
1281 pdb_set_pass_must_change_time (sam_pass, pw_buf->pass_last_set_time + MAX_PASSWORD_AGE);
1286 /*****************************************************************
1287 Functions to be implemented by the new passdb API
1288 ****************************************************************/
1289 static BOOL smbpasswd_setsampwent (struct pdb_methods *my_methods, BOOL update)
1291 struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
1293 smbpasswd_state->pw_file = startsmbfilepwent(smbpasswd_state->smbpasswd_file,
1294 update ? PWF_UPDATE : PWF_READ,
1295 &(smbpasswd_state->pw_file_lock_depth));
1297 /* did we fail? Should we try to create it? */
1298 if (!smbpasswd_state->pw_file && update && errno == ENOENT)
1301 /* slprintf(msg_str,msg_str_len-1,
1302 "smbpasswd file did not exist - attempting to create it.\n"); */
1303 DEBUG(0,("smbpasswd file did not exist - attempting to create it.\n"));
1304 fp = sys_fopen(smbpasswd_state->smbpasswd_file, "w");
1307 fprintf(fp, "# Samba SMB password file\n");
1311 smbpasswd_state->pw_file = startsmbfilepwent(smbpasswd_state->smbpasswd_file,
1312 update ? PWF_UPDATE : PWF_READ,
1313 &(smbpasswd_state->pw_file_lock_depth));
1316 return (smbpasswd_state->pw_file != NULL);
1319 static void smbpasswd_endsampwent (struct pdb_methods *my_methods)
1321 struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
1322 endsmbfilepwent(smbpasswd_state->pw_file, &(smbpasswd_state->pw_file_lock_depth));
1325 /*****************************************************************
1326 ****************************************************************/
1327 static BOOL smbpasswd_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUNT *user)
1329 struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
1330 struct smb_passwd *pw_buf=NULL;
1332 DEBUG(5,("pdb_getsampwent\n"));
1335 DEBUG(5,("pdb_getsampwent (smbpasswd): user is NULL\n"));
1337 smb_panic("NULL pointer passed to getsampwent (smbpasswd)\n");
1344 /* do we have an entry? */
1345 pw_buf = getsmbfilepwent(smbpasswd_state, smbpasswd_state->pw_file);
1349 /* build the SAM_ACCOUNT entry from the smb_passwd struct.
1350 We loop in case the user in the pdb does not exist in
1351 the local system password file */
1352 if (build_sam_account(smbpasswd_state, user, pw_buf))
1356 DEBUG(5,("getsampwent (smbpasswd): done\n"));
1363 /****************************************************************
1364 Search smbpasswd file by iterating over the entries. Do not
1365 call getpwnam() for unix account information until we have found
1367 ***************************************************************/
1368 static BOOL smbpasswd_getsampwnam(struct pdb_methods *my_methods, SAM_ACCOUNT *sam_acct, const char *username)
1370 struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
1371 struct smb_passwd *smb_pw;
1374 DEBUG(10, ("getsampwnam (smbpasswd): search by name: %s\n", username));
1376 /* startsmbfilepwent() is used here as we don't want to lookup
1377 the UNIX account in the local system password file until
1379 fp = startsmbfilepwent(smbpasswd_state->smbpasswd_file, PWF_READ, &(smbpasswd_state->pw_file_lock_depth));
1382 DEBUG(0, ("unable to open passdb database.\n"));
1386 while ( ((smb_pw=getsmbfilepwent(smbpasswd_state, fp)) != NULL)&& (!strequal(smb_pw->smb_name, username)) )
1387 /* do nothing....another loop */ ;
1389 endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
1392 /* did we locate the username in smbpasswd */
1396 DEBUG(10, ("getsampwnam (smbpasswd): found by name: %s\n", smb_pw->smb_name));
1399 DEBUG(10,("getsampwnam (smbpasswd): SAM_ACCOUNT is NULL\n"));
1401 smb_panic("NULL pointer passed to pdb_getsampwnam\n");
1406 /* now build the SAM_ACCOUNT */
1407 if (!build_sam_account(smbpasswd_state, sam_acct, smb_pw))
1414 static BOOL smbpasswd_getsampwrid(struct pdb_methods *my_methods, SAM_ACCOUNT *sam_acct,uint32 rid)
1416 struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
1417 struct smb_passwd *smb_pw;
1420 DEBUG(10, ("pdb_getsampwrid: search by rid: %d\n", rid));
1422 /* Open the sam password file - not for update. */
1423 fp = startsmbfilepwent(smbpasswd_state->smbpasswd_file, PWF_READ, &(smbpasswd_state->pw_file_lock_depth));
1426 DEBUG(0, ("unable to open passdb database.\n"));
1430 while ( ((smb_pw=getsmbfilepwent(smbpasswd_state, fp)) != NULL) && (fallback_pdb_uid_to_user_rid(smb_pw->smb_userid) != rid) )
1433 endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
1436 /* did we locate the username in smbpasswd */
1440 DEBUG(10, ("getsampwrid (smbpasswd): found by name: %s\n", smb_pw->smb_name));
1443 DEBUG(10,("getsampwrid: (smbpasswd) SAM_ACCOUNT is NULL\n"));
1445 smb_panic("NULL pointer passed to pdb_getsampwrid\n");
1450 /* now build the SAM_ACCOUNT */
1451 if (!build_sam_account (smbpasswd_state, sam_acct, smb_pw))
1458 static BOOL smbpasswd_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUNT * user, DOM_SID *sid)
1461 sid_peek_rid(sid, &rid);
1462 return smbpasswd_getsampwrid(my_methods, user, rid);
1465 static BOOL smbpasswd_add_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT *sampass)
1467 struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
1468 struct smb_passwd smb_pw;
1470 /* convert the SAM_ACCOUNT */
1471 if (!build_smb_pass(&smb_pw, sampass)) {
1476 if(!add_smbfilepwd_entry(smbpasswd_state, &smb_pw)) {
1483 static BOOL smbpasswd_update_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT *sampass)
1485 struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
1486 struct smb_passwd smb_pw;
1488 /* convert the SAM_ACCOUNT */
1489 if (!build_smb_pass(&smb_pw, sampass)) {
1490 DEBUG(0, ("smbpasswd_update_sam_account: build_smb_pass failed!\n"));
1494 /* update the entry */
1495 if(!mod_smbfilepwd_entry(smbpasswd_state, &smb_pw)) {
1496 DEBUG(0, ("smbpasswd_update_sam_account: mod_smbfilepwd_entry failed!\n"));
1503 static BOOL smbpasswd_delete_sam_account (struct pdb_methods *my_methods, SAM_ACCOUNT *sampass)
1505 struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
1507 const char *username = pdb_get_username(sampass);
1509 return del_smbfilepwd_entry(smbpasswd_state, username);
1512 static void free_private_data(void **vp)
1514 struct smbpasswd_privates **privates = (struct smbpasswd_privates**)vp;
1516 endsmbfilepwent((*privates)->pw_file, &((*privates)->pw_file_lock_depth));
1519 /* No need to free any further, as it is talloc()ed */
1523 NTSTATUS pdb_init_smbpasswd(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
1526 struct smbpasswd_privates *privates;
1528 if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) {
1532 (*pdb_method)->name = "smbpasswd";
1534 (*pdb_method)->setsampwent = smbpasswd_setsampwent;
1535 (*pdb_method)->endsampwent = smbpasswd_endsampwent;
1536 (*pdb_method)->getsampwent = smbpasswd_getsampwent;
1537 (*pdb_method)->getsampwnam = smbpasswd_getsampwnam;
1538 (*pdb_method)->getsampwsid = smbpasswd_getsampwsid;
1539 (*pdb_method)->add_sam_account = smbpasswd_add_sam_account;
1540 (*pdb_method)->update_sam_account = smbpasswd_update_sam_account;
1541 (*pdb_method)->delete_sam_account = smbpasswd_delete_sam_account;
1543 /* Setup private data and free function */
1545 privates = talloc_zero(pdb_context->mem_ctx, sizeof(struct smbpasswd_privates));
1548 DEBUG(0, ("talloc() failed for smbpasswd private_data!\n"));
1549 return NT_STATUS_NO_MEMORY;
1552 /* Store some config details */
1555 privates->smbpasswd_file = talloc_strdup(pdb_context->mem_ctx, location);
1557 privates->smbpasswd_file = talloc_strdup(pdb_context->mem_ctx, lp_smb_passwd_file());
1560 if (!privates->smbpasswd_file) {
1561 DEBUG(0, ("talloc_strdp() failed for storing smbpasswd location!\n"));
1562 return NT_STATUS_NO_MEMORY;
1565 (*pdb_method)->private_data = privates;
1567 (*pdb_method)->free_private_data = free_private_data;
1569 return NT_STATUS_OK;
1572 NTSTATUS pdb_init_smbpasswd_nua(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
1575 struct smbpasswd_privates *privates;
1577 if (!NT_STATUS_IS_OK(nt_status = pdb_init_smbpasswd(pdb_context, pdb_method, location))) {
1581 (*pdb_method)->name = "smbpasswd_nua";
1583 privates = (*pdb_method)->private_data;
1585 privates->permit_non_unix_accounts = True;
1587 if (!lp_non_unix_account_range(&privates->low_nua_userid, &privates->high_nua_userid)) {
1588 DEBUG(0, ("cannot use smbpasswd_nua without 'non unix account range' in smb.conf!\n"));
1589 return NT_STATUS_UNSUCCESSFUL;
1592 return NT_STATUS_OK;