1 /*
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,2003
7  * Modified by Andrew Bartlett         2002.
8  *
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 3 of the License, or (at your option)
12  * any later version.
13  *
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
17  * more details.
18  *
19  * You should have received a copy of the GNU General Public License along with
20  * this program; if not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include "includes.h"
24 #include "passdb.h"
25 #include "system/passwd.h"
26 #include "system/filesys.h"
27 #include "../librpc/gen_ndr/samr.h"
28 #include "../libcli/security/security.h"
29 #include "passdb/pdb_smbpasswd.h"
30 
31 #undef DBGC_CLASS
32 #define DBGC_CLASS DBGC_PASSDB
33 
34 /*
35    smb_passwd is analogous to sam_passwd used everywhere
36    else.  However, smb_passwd is limited to the information
37    stored by an smbpasswd entry
38  */
39 
40 struct smb_passwd
41 {
42         uint32_t smb_userid;      /* this is actually the unix uid_t */
43         const char *smb_name;     /* username string */
44 
45         const unsigned char *smb_passwd;    /* Null if no password */
46         const unsigned char *smb_nt_passwd; /* Null if no password */
47 
48         uint16_t acct_ctrl;             /* account info (ACB_xxxx bit-mask) */
49         time_t pass_last_set_time;    /* password last set time */
50 };
51 
52 struct smbpasswd_privates
53 {
54 	/* used for maintain locks on the smbpasswd file */
55 	int 	pw_file_lock_depth;
56 
57 	/* Global File pointer */
58 	FILE 	*pw_file;
59 
60 	/* formerly static variables */
61 	struct smb_passwd pw_buf;
62 	fstring user_name;
63 	unsigned char smbpwd[16];
64 	unsigned char smbntpwd[16];
65 
66 	/* retrieve-once info */
67 	const char *smbpasswd_file;
68 };
69 
70 enum pwf_access_type { PWF_READ, PWF_UPDATE, PWF_CREATE };
71 
72 static SIG_ATOMIC_T gotalarm;
73 
74 /***************************************************************
75  Signal function to tell us we timed out.
76 ****************************************************************/
77 
gotalarm_sig(int signum)78 static void gotalarm_sig(int signum)
79 {
80 	gotalarm = 1;
81 }
82 
83 /***************************************************************
84  Lock or unlock a fd for a known lock type. Abandon after waitsecs
85  seconds.
86 ****************************************************************/
87 
do_file_lock(int fd,int waitsecs,int type)88 static bool do_file_lock(int fd, int waitsecs, int type)
89 {
90 	struct flock lock;
91 	int             ret;
92 	void (*oldsig_handler)(int);
93 
94 	gotalarm = 0;
95 	oldsig_handler = CatchSignal(SIGALRM, gotalarm_sig);
96 
97 	lock.l_type = type;
98 	lock.l_whence = SEEK_SET;
99 	lock.l_start = 0;
100 	lock.l_len = 1;
101 	lock.l_pid = 0;
102 
103 	alarm(waitsecs);
104 	/* Note we must *NOT* use sys_fcntl here ! JRA */
105 	ret = fcntl(fd, F_SETLKW, &lock);
106 	alarm(0);
107 	CatchSignal(SIGALRM, oldsig_handler);
108 
109 	if (gotalarm && ret == -1) {
110 		DEBUG(0, ("do_file_lock: failed to %s file.\n",
111 			type == F_UNLCK ? "unlock" : "lock"));
112 		return False;
113 	}
114 
115 	return (ret == 0);
116 }
117 
118 /***************************************************************
119  Lock an fd. Abandon after waitsecs seconds.
120 ****************************************************************/
121 
pw_file_lock(int fd,int type,int secs,int * plock_depth)122 static bool pw_file_lock(int fd, int type, int secs, int *plock_depth)
123 {
124 	if (fd < 0) {
125 		return False;
126 	}
127 
128 	if(*plock_depth == 0) {
129 		if (!do_file_lock(fd, secs, type)) {
130 			DEBUG(10,("pw_file_lock: locking file failed, error = %s.\n",
131 				strerror(errno)));
132 			return False;
133 		}
134 	}
135 
136 	(*plock_depth)++;
137 
138 	return True;
139 }
140 
141 /***************************************************************
142  Unlock an fd. Abandon after waitsecs seconds.
143 ****************************************************************/
144 
pw_file_unlock(int fd,int * plock_depth)145 static bool pw_file_unlock(int fd, int *plock_depth)
146 {
147 	bool ret=True;
148 
149 	if (fd == 0 || *plock_depth == 0) {
150 		return True;
151 	}
152 
153 	if(*plock_depth == 1) {
154 		ret = do_file_lock(fd, 5, F_UNLCK);
155 	}
156 
157 	if (*plock_depth > 0) {
158 		(*plock_depth)--;
159 	}
160 
161 	if(!ret) {
162 		DEBUG(10,("pw_file_unlock: unlocking file failed, error = %s.\n",
163 			strerror(errno)));
164 	}
165 	return ret;
166 }
167 
168 /**************************************************************
169  Intialize a smb_passwd struct
170  *************************************************************/
171 
pdb_init_smb(struct smb_passwd * user)172 static void pdb_init_smb(struct smb_passwd *user)
173 {
174 	if (user == NULL)
175 		return;
176 	ZERO_STRUCTP (user);
177 
178 	user->pass_last_set_time = (time_t)0;
179 }
180 
181 /***************************************************************
182  Internal fn to enumerate the smbpasswd list. Returns a void pointer
183  to ensure no modification outside this module. Checks for atomic
184  rename of smbpasswd file on update or create once the lock has
185  been granted to prevent race conditions. JRA.
186 ****************************************************************/
187 
startsmbfilepwent(const char * pfile,enum pwf_access_type type,int * lock_depth)188 static FILE *startsmbfilepwent(const char *pfile, enum pwf_access_type type, int *lock_depth)
189 {
190 	FILE *fp = NULL;
191 	const char *open_mode = NULL;
192 	int race_loop = 0;
193 	int lock_type = F_RDLCK;
194 
195 	if (!*pfile) {
196 		DEBUG(0, ("startsmbfilepwent: No SMB password file set\n"));
197 		return (NULL);
198 	}
199 
200 	switch(type) {
201 		case PWF_READ:
202 			open_mode = "rb";
203 			lock_type = F_RDLCK;
204 			break;
205 		case PWF_UPDATE:
206 			open_mode = "r+b";
207 			lock_type = F_WRLCK;
208 			break;
209 		case PWF_CREATE:
210 			/*
211 			 * Ensure atomic file creation.
212 			 */
213 			{
214 				int i, fd = -1;
215 
216 				for(i = 0; i < 5; i++) {
217 					if((fd = open(pfile, O_CREAT|O_TRUNC|O_EXCL|O_RDWR, 0600))!=-1) {
218 						break;
219 					}
220 					usleep(200); /* Spin, spin... */
221 				}
222 				if(fd == -1) {
223 					DEBUG(0,("startsmbfilepwent_internal: too many race conditions \
224 creating file %s\n", pfile));
225 					return NULL;
226 				}
227 				close(fd);
228 				open_mode = "r+b";
229 				lock_type = F_WRLCK;
230 				break;
231 			}
232 		default:
233 			DEBUG(10, ("Invalid open mode: %d\n", type));
234 			return NULL;
235 	}
236 
237 	for(race_loop = 0; race_loop < 5; race_loop++) {
238 		DEBUG(10, ("startsmbfilepwent_internal: opening file %s\n", pfile));
239 
240 		if((fp = fopen(pfile, open_mode)) == NULL) {
241 
242 			/*
243 			 * If smbpasswd file doesn't exist, then create new one. This helps to avoid
244 			 * confusing error msg when adding user account first time.
245 			 */
246 			if (errno == ENOENT) {
247 				if ((fp = fopen(pfile, "a+")) != NULL) {
248 					DEBUG(0, ("startsmbfilepwent_internal: file %s did not \
249 exist. File successfully created.\n", pfile));
250 				} else {
251 					DEBUG(0, ("startsmbfilepwent_internal: file %s did not \
252 exist. Couldn't create new one. Error was: %s",
253 					pfile, strerror(errno)));
254 					return NULL;
255 				}
256 			} else {
257 				DEBUG(0, ("startsmbfilepwent_internal: unable to open file %s. \
258 Error was: %s\n", pfile, strerror(errno)));
259 				return NULL;
260 			}
261 		}
262 
263 		if (!pw_file_lock(fileno(fp), lock_type, 5, lock_depth)) {
264 			DEBUG(0, ("startsmbfilepwent_internal: unable to lock file %s. \
265 Error was %s\n", pfile, strerror(errno) ));
266 			fclose(fp);
267 			return NULL;
268 		}
269 
270 		/*
271 		 * Only check for replacement races on update or create.
272 		 * For read we don't mind if the data is one record out of date.
273 		 */
274 
275 		if(type == PWF_READ) {
276 			break;
277 		} else {
278 			SMB_STRUCT_STAT sbuf1, sbuf2;
279 
280 			/*
281 			 * Avoid the potential race condition between the open and the lock
282 			 * by doing a stat on the filename and an fstat on the fd. If the
283 			 * two inodes differ then someone did a rename between the open and
284 			 * the lock. Back off and try the open again. Only do this 5 times to
285 			 * prevent infinate loops. JRA.
286 			 */
287 
288 			if (sys_stat(pfile, &sbuf1, false) != 0) {
289 				DEBUG(0, ("startsmbfilepwent_internal: unable to stat file %s. \
290 Error was %s\n", pfile, strerror(errno)));
291 				pw_file_unlock(fileno(fp), lock_depth);
292 				fclose(fp);
293 				return NULL;
294 			}
295 
296 			if (sys_fstat(fileno(fp), &sbuf2, false) != 0) {
297 				DEBUG(0, ("startsmbfilepwent_internal: unable to fstat file %s. \
298 Error was %s\n", pfile, strerror(errno)));
299 				pw_file_unlock(fileno(fp), lock_depth);
300 				fclose(fp);
301 				return NULL;
302 			}
303 
304 			if( sbuf1.st_ex_ino == sbuf2.st_ex_ino) {
305 				/* No race. */
306 				break;
307 			}
308 
309 			/*
310 			 * Race occurred - back off and try again...
311 			 */
312 
313 			pw_file_unlock(fileno(fp), lock_depth);
314 			fclose(fp);
315 		}
316 	}
317 
318 	if(race_loop == 5) {
319 		DEBUG(0, ("startsmbfilepwent_internal: too many race conditions opening file %s\n", pfile));
320 		return NULL;
321 	}
322 
323 	/* Set a buffer to do more efficient reads */
324 	setvbuf(fp, (char *)NULL, _IOFBF, 1024);
325 
326 	/* Make sure it is only rw by the owner */
327 #ifdef HAVE_FCHMOD
328 	if(fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) {
329 #else
330 	if(chmod(pfile, S_IRUSR|S_IWUSR) == -1) {
331 #endif
332 		DEBUG(0, ("startsmbfilepwent_internal: failed to set 0600 permissions on password file %s. \
333 Error was %s\n.", pfile, strerror(errno) ));
334 		pw_file_unlock(fileno(fp), lock_depth);
335 		fclose(fp);
336 		return NULL;
337 	}
338 
339 	/* We have a lock on the file. */
340 	return fp;
341 }
342 
343 /***************************************************************
344  End enumeration of the smbpasswd list.
345 ****************************************************************/
346 
347 static void endsmbfilepwent(FILE *fp, int *lock_depth)
348 {
349 	if (!fp) {
350 		return;
351 	}
352 
353 	pw_file_unlock(fileno(fp), lock_depth);
354 	fclose(fp);
355 	DEBUG(7, ("endsmbfilepwent_internal: closed password file.\n"));
356 }
357 
358 /*************************************************************************
359  Routine to return the next entry in the smbpasswd list.
360  *************************************************************************/
361 
362 static struct smb_passwd *getsmbfilepwent(struct smbpasswd_privates *smbpasswd_state, FILE *fp)
363 {
364 	/* Static buffers we will return. */
365 	struct smb_passwd *pw_buf = &smbpasswd_state->pw_buf;
366 	char  *user_name = smbpasswd_state->user_name;
367 	unsigned char *smbpwd = smbpasswd_state->smbpwd;
368 	unsigned char *smbntpwd = smbpasswd_state->smbntpwd;
369 	char linebuf[256];
370 	unsigned char *p;
371 	long uidval;
372 	size_t linebuf_len;
373 	char *status;
374 
375 	if(fp == NULL) {
376 		DEBUG(0,("getsmbfilepwent: Bad password file pointer.\n"));
377 		return NULL;
378 	}
379 
380 	pdb_init_smb(pw_buf);
381 	pw_buf->acct_ctrl = ACB_NORMAL;
382 
383 	/*
384 	 * Scan the file, a line at a time and check if the name matches.
385 	 */
386 	status = linebuf;
387 	while (status && !feof(fp)) {
388 		linebuf[0] = '\0';
389 
390 		status = fgets(linebuf, 256, fp);
391 		if (status == NULL && ferror(fp)) {
392 			return NULL;
393 		}
394 
395 		/*
396 		 * Check if the string is terminated with a newline - if not
397 		 * then we must keep reading and discard until we get one.
398 		 */
399 		if ((linebuf_len = strlen(linebuf)) == 0) {
400 			continue;
401 		}
402 
403 		if (linebuf[linebuf_len - 1] != '\n') {
404 			while (!ferror(fp) && !feof(fp)) {
405 				int c;
406 				c = fgetc(fp);
407 				if (c == '\n') {
408 					break;
409 				}
410 			}
411 		} else {
412 			linebuf[linebuf_len - 1] = '\0';
413 		}
414 
415 #ifdef DEBUG_PASSWORD
416 		DEBUG(100, ("getsmbfilepwent: got line |%s|\n", linebuf));
417 #endif
418 		if ((linebuf[0] == 0) && feof(fp)) {
419 			DEBUG(4, ("getsmbfilepwent: end of file reached\n"));
420 			break;
421 		}
422 
423 		/*
424 		 * The line we have should be of the form :-
425 		 *
426 		 * username:uid:32hex bytes:[Account type]:LCT-12345678....other flags presently
427 		 * ignored....
428 		 *
429 		 * or,
430 		 *
431 		 * username:uid:32hex bytes:32hex bytes:[Account type]:LCT-12345678....ignored....
432 		 *
433 		 * if Windows NT compatible passwords are also present.
434 		 * [Account type] is an ascii encoding of the type of account.
435 		 * LCT-(8 hex digits) is the time_t value of the last change time.
436 		 */
437 
438 		if (linebuf[0] == '#' || linebuf[0] == '\0') {
439 			DEBUG(6, ("getsmbfilepwent: skipping comment or blank line\n"));
440 			continue;
441 		}
442 		p = (unsigned char *) strchr_m(linebuf, ':');
443 		if (p == NULL) {
444 			DEBUG(0, ("getsmbfilepwent: malformed password entry (no :)\n"));
445 			continue;
446 		}
447 
448 		strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
449 		user_name[PTR_DIFF(p, linebuf)] = '\0';
450 
451 		/* Get smb uid. */
452 
453 		p++; /* Go past ':' */
454 
455 		if(*p == '-') {
456 			DEBUG(0, ("getsmbfilepwent: user name %s has a negative uid.\n", user_name));
457 			continue;
458 		}
459 
460 		if (!isdigit(*p)) {
461 			DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (uid not number)\n",
462 				user_name));
463 			continue;
464 		}
465 
466 		uidval = atoi((char *) p);
467 
468 		while (*p && isdigit(*p)) {
469 			p++;
470 		}
471 
472 		if (*p != ':') {
473 			DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (no : after uid)\n",
474 				user_name));
475 			continue;
476 		}
477 
478 		pw_buf->smb_name = user_name;
479 		pw_buf->smb_userid = uidval;
480 
481 		/*
482 		 * Now get the password value - this should be 32 hex digits
483 		 * which are the ascii representations of a 16 byte string.
484 		 * Get two at a time and put them into the password.
485 		 */
486 
487 		/* Skip the ':' */
488 		p++;
489 
490 		if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
491 			DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (passwd too short)\n",
492 				user_name ));
493 			continue;
494 		}
495 
496 		if (p[32] != ':') {
497 			DEBUG(0, ("getsmbfilepwent: malformed password entry for user %s (no terminating :)\n",
498 				user_name));
499 			continue;
500 		}
501 
502 		if (strnequal((char *) p, "NO PASSWORD", 11)) {
503 			pw_buf->smb_passwd = NULL;
504 			pw_buf->acct_ctrl |= ACB_PWNOTREQ;
505 		} else {
506 			if (*p == '*' || *p == 'X') {
507 				/* NULL LM password */
508 				pw_buf->smb_passwd = NULL;
509 				DEBUG(10, ("getsmbfilepwent: LM password for user %s invalidated\n", user_name));
510 			} else if (pdb_gethexpwd((char *)p, smbpwd)) {
511 				pw_buf->smb_passwd = smbpwd;
512 			} else {
513 				pw_buf->smb_passwd = NULL;
514 				DEBUG(0, ("getsmbfilepwent: Malformed Lanman password entry for user %s \
515 (non hex chars)\n", user_name));
516 			}
517 		}
518 
519 		/*
520 		 * Now check if the NT compatible password is
521 		 * available.
522 		 */
523 		pw_buf->smb_nt_passwd = NULL;
524 		p += 33; /* Move to the first character of the line after the lanman password. */
525 		if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
526 			if (*p != '*' && *p != 'X') {
527 				if(pdb_gethexpwd((char *)p,smbntpwd)) {
528 					pw_buf->smb_nt_passwd = smbntpwd;
529 				}
530 			}
531 			p += 33; /* Move to the first character of the line after the NT password. */
532 		}
533 
534 		DEBUG(5,("getsmbfilepwent: returning passwd entry for user %s, uid %ld\n",
535 			user_name, uidval));
536 
537 		if (*p == '[') {
538 			unsigned char *end_p = (unsigned char *)strchr_m((char *)p, ']');
539 			pw_buf->acct_ctrl = pdb_decode_acct_ctrl((char*)p);
540 
541 			/* Must have some account type set. */
542 			if(pw_buf->acct_ctrl == 0) {
543 				pw_buf->acct_ctrl = ACB_NORMAL;
544 			}
545 
546 			/* Now try and get the last change time. */
547 			if(end_p) {
548 				p = end_p + 1;
549 			}
550 			if(*p == ':') {
551 				p++;
552 				if(*p && (strncasecmp_m((char *)p, "LCT-", 4)==0)) {
553 					int i;
554 					p += 4;
555 					for(i = 0; i < 8; i++) {
556 						if(p[i] == '\0' || !isxdigit(p[i])) {
557 							break;
558 						}
559 					}
560 					if(i == 8) {
561 						/*
562 						 * p points at 8 characters of hex digits -
563 						 * read into a time_t as the seconds since
564 						 * 1970 that the password was last changed.
565 						 */
566 						pw_buf->pass_last_set_time = (time_t)strtol((char *)p, NULL, 16);
567 					}
568 				}
569 			}
570 		} else {
571 			/* 'Old' style file. Fake up based on user name. */
572 			/*
573 			 * Currently trust accounts are kept in the same
574 			 * password file as 'normal accounts'. If this changes
575 			 * we will have to fix this code. JRA.
576 			 */
577 			if(pw_buf->smb_name[strlen(pw_buf->smb_name) - 1] == '$') {
578 				pw_buf->acct_ctrl &= ~ACB_NORMAL;
579 				pw_buf->acct_ctrl |= ACB_WSTRUST;
580 			}
581 		}
582 
583 		return pw_buf;
584 	}
585 
586 	DEBUG(5,("getsmbfilepwent: end of file reached.\n"));
587 	return NULL;
588 }
589 
590 /************************************************************************
591  Create a new smbpasswd entry - malloced space returned.
592 *************************************************************************/
593 
594 static char *format_new_smbpasswd_entry(const struct smb_passwd *newpwd)
595 {
596 	int new_entry_length;
597 	char *new_entry;
598 	char *p;
599 
600 	new_entry_length = strlen(newpwd->smb_name) + 1 + 15 + 1 + 32 + 1 + 32 + 1 +
601 				NEW_PW_FORMAT_SPACE_PADDED_LEN + 1 + 13 + 2;
602 
603 	if((new_entry = (char *)SMB_MALLOC( new_entry_length )) == NULL) {
604 		DEBUG(0, ("format_new_smbpasswd_entry: Malloc failed adding entry for user %s.\n",
605 			newpwd->smb_name ));
606 		return NULL;
607 	}
608 
609 	slprintf(new_entry, new_entry_length - 1, "%s:%u:", newpwd->smb_name, (unsigned)newpwd->smb_userid);
610 
611 	p = new_entry+strlen(new_entry);
612 	pdb_sethexpwd(p, newpwd->smb_passwd, newpwd->acct_ctrl);
613 	p+=strlen(p);
614 	*p = ':';
615 	p++;
616 
617 	pdb_sethexpwd(p, newpwd->smb_nt_passwd, newpwd->acct_ctrl);
618 	p+=strlen(p);
619 	*p = ':';
620 	p++;
621 
622 	/* Add the account encoding and the last change time. */
623 	slprintf((char *)p, new_entry_length - 1 - (p - new_entry),  "%s:LCT-%08X:\n",
624 		pdb_encode_acct_ctrl(newpwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN),
625 		(uint32_t)newpwd->pass_last_set_time);
626 
627 	return new_entry;
628 }
629 
630 /************************************************************************
631  Routine to add an entry to the smbpasswd file.
632 *************************************************************************/
633 
634 static NTSTATUS add_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state,
635 				     struct smb_passwd *newpwd)
636 {
637 	const char *pfile = smbpasswd_state->smbpasswd_file;
638 	struct smb_passwd *pwd = NULL;
639 	FILE *fp = NULL;
640 	int wr_len;
641 	int fd;
642 	size_t new_entry_length;
643 	char *new_entry;
644 	off_t offpos;
645 
646 	/* Open the smbpassword file - for update. */
647 	fp = startsmbfilepwent(pfile, PWF_UPDATE, &smbpasswd_state->pw_file_lock_depth);
648 
649 	if (fp == NULL && errno == ENOENT) {
650 		/* Try again - create. */
651 		fp = startsmbfilepwent(pfile, PWF_CREATE, &smbpasswd_state->pw_file_lock_depth);
652 	}
653 
654 	if (fp == NULL) {
655 		DEBUG(0, ("add_smbfilepwd_entry: unable to open file.\n"));
656 		return map_nt_error_from_unix(errno);
657 	}
658 
659 	/*
660 	 * Scan the file, a line at a time and check if the name matches.
661 	 */
662 
663 	while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) {
664 		if (strequal(newpwd->smb_name, pwd->smb_name)) {
665 			DEBUG(0, ("add_smbfilepwd_entry: entry with name %s already exists\n", pwd->smb_name));
666 			endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
667 			return NT_STATUS_USER_EXISTS;
668 		}
669 	}
670 
671 	/* Ok - entry doesn't exist. We can add it */
672 
673 	/* Create a new smb passwd entry and set it to the given password. */
674 	/*
675 	 * The add user write needs to be atomic - so get the fd from
676 	 * the fp and do a raw write() call.
677 	 */
678 	fd = fileno(fp);
679 
680 	if((offpos = lseek(fd, 0, SEEK_END)) == -1) {
681 		NTSTATUS result = map_nt_error_from_unix(errno);
682 		DEBUG(0, ("add_smbfilepwd_entry(lseek): Failed to add entry for user %s to file %s. \
683 Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
684 		endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
685 		return result;
686 	}
687 
688 	if((new_entry = format_new_smbpasswd_entry(newpwd)) == NULL) {
689 		DEBUG(0, ("add_smbfilepwd_entry(malloc): Failed to add entry for user %s to file %s. \
690 Error was %s\n", newpwd->smb_name, pfile, strerror(errno)));
691 		endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
692 		return NT_STATUS_NO_MEMORY;
693 	}
694 
695 	new_entry_length = strlen(new_entry);
696 
697 #ifdef DEBUG_PASSWORD
698 	DEBUG(100, ("add_smbfilepwd_entry(%d): new_entry_len %d made line |%s|",
699 			fd, (int)new_entry_length, new_entry));
700 #endif
701 
702 	if ((wr_len = write(fd, new_entry, new_entry_length)) != new_entry_length) {
703 		NTSTATUS result = map_nt_error_from_unix(errno);
704 		DEBUG(0, ("add_smbfilepwd_entry(write): %d Failed to add entry for user %s to file %s. \
705 Error was %s\n", wr_len, newpwd->smb_name, pfile, strerror(errno)));
706 
707 		/* Remove the entry we just wrote. */
708 		if(ftruncate(fd, offpos) == -1) {
709 			DEBUG(0, ("add_smbfilepwd_entry: ERROR failed to ftruncate file %s. \
710 Error was %s. Password file may be corrupt ! Please examine by hand !\n",
711 				newpwd->smb_name, strerror(errno)));
712 		}
713 
714 		endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
715 		free(new_entry);
716 		return result;
717 	}
718 
719 	free(new_entry);
720 	endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
721 	return NT_STATUS_OK;
722 }
723 
724 /************************************************************************
725  Routine to search the smbpasswd file for an entry matching the username.
726  and then modify its password entry. We can't use the startsmbpwent()/
727  getsmbpwent()/endsmbpwent() interfaces here as we depend on looking
728  in the actual file to decide how much room we have to write data.
729  override = False, normal
730  override = True, override XXXXXXXX'd out password or NO PASS
731 ************************************************************************/
732 
733 static bool mod_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, const struct smb_passwd* pwd)
734 {
735 	/* Static buffers we will return. */
736 	fstring user_name;
737 
738 	char *status;
739 #define LINEBUF_SIZE 255
740 	char linebuf[LINEBUF_SIZE + 1];
741 	char readbuf[1024];
742 	char ascii_p16[FSTRING_LEN + 20];
743 	fstring encode_bits;
744 	unsigned char *p = NULL;
745 	size_t linebuf_len = 0;
746 	FILE *fp;
747 	int lockfd;
748 	const char *pfile = smbpasswd_state->smbpasswd_file;
749 	bool found_entry = False;
750 	bool got_pass_last_set_time = False;
751 
752 	off_t pwd_seekpos = 0;
753 
754 	int i;
755 	int wr_len;
756 	int fd;
757 
758 	if (!*pfile) {
759 		DEBUG(0, ("No SMB password file set\n"));
760 		return False;
761 	}
762 	DEBUG(10, ("mod_smbfilepwd_entry: opening file %s\n", pfile));
763 
764 	fp = fopen(pfile, "r+");
765 
766 	if (fp == NULL) {
767 		DEBUG(0, ("mod_smbfilepwd_entry: unable to open file %s\n", pfile));
768 		return False;
769 	}
770 	/* Set a buffer to do more efficient reads */
771 	setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
772 
773 	lockfd = fileno(fp);
774 
775 	if (!pw_file_lock(lockfd, F_WRLCK, 5, &smbpasswd_state->pw_file_lock_depth)) {
776 		DEBUG(0, ("mod_smbfilepwd_entry: unable to lock file %s\n", pfile));
777 		fclose(fp);
778 		return False;
779 	}
780 
781 	/* Make sure it is only rw by the owner */
782 	chmod(pfile, 0600);
783 
784 	/* We have a write lock on the file. */
785 	/*
786 	 * Scan the file, a line at a time and check if the name matches.
787 	 */
788 	status = linebuf;
789 	while (status && !feof(fp)) {
790 		pwd_seekpos = ftell(fp);
791 
792 		linebuf[0] = '\0';
793 
794 		status = fgets(linebuf, LINEBUF_SIZE, fp);
795 		if (status == NULL && ferror(fp)) {
796 			pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth);
797 			fclose(fp);
798 			return False;
799 		}
800 
801 		/*
802 		 * Check if the string is terminated with a newline - if not
803 		 * then we must keep reading and discard until we get one.
804 		 */
805 		linebuf_len = strlen(linebuf);
806 		if (linebuf[linebuf_len - 1] != '\n') {
807 			while (!ferror(fp) && !feof(fp)) {
808 				int c;
809 				c = fgetc(fp);
810 				if (c == '\n') {
811 					break;
812 				}
813 			}
814 		} else {
815 			linebuf[linebuf_len - 1] = '\0';
816 		}
817 
818 #ifdef DEBUG_PASSWORD
819 		DEBUG(100, ("mod_smbfilepwd_entry: got line |%s|\n", linebuf));
820 #endif
821 
822 		if ((linebuf[0] == 0) && feof(fp)) {
823 			DEBUG(4, ("mod_smbfilepwd_entry: end of file reached\n"));
824 			break;
825 		}
826 
827 		/*
828 		 * The line we have should be of the form :-
829 		 *
830 		 * username:uid:[32hex bytes]:....other flags presently
831 		 * ignored....
832 		 *
833 		 * or,
834 		 *
835 		 * username:uid:[32hex bytes]:[32hex bytes]:[attributes]:LCT-XXXXXXXX:...ignored.
836 		 *
837 		 * if Windows NT compatible passwords are also present.
838 		 */
839 
840 		if (linebuf[0] == '#' || linebuf[0] == '\0') {
841 			DEBUG(6, ("mod_smbfilepwd_entry: skipping comment or blank line\n"));
842 			continue;
843 		}
844 
845 		p = (unsigned char *) strchr_m(linebuf, ':');
846 
847 		if (p == NULL) {
848 			DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry (no :)\n"));
849 			continue;
850 		}
851 
852 		strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
853 		user_name[PTR_DIFF(p, linebuf)] = '\0';
854 		if (strequal(user_name, pwd->smb_name)) {
855 			found_entry = True;
856 			break;
857 		}
858 	}
859 
860 	if (!found_entry) {
861 		pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth);
862 		fclose(fp);
863 
864 		DEBUG(2, ("Cannot update entry for user %s, as they don't exist in the smbpasswd file!\n",
865 			pwd->smb_name));
866 		return False;
867 	}
868 
869 	DEBUG(6, ("mod_smbfilepwd_entry: entry exists for user %s\n", pwd->smb_name));
870 
871 	/* User name matches - get uid and password */
872 	p++; /* Go past ':' */
873 
874 	if (!isdigit(*p)) {
875 		DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (uid not number)\n",
876 			pwd->smb_name));
877 		pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth);
878 		fclose(fp);
879 		return False;
880 	}
881 
882 	while (*p && isdigit(*p)) {
883 		p++;
884 	}
885 	if (*p != ':') {
886 		DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no : after uid)\n",
887 			pwd->smb_name));
888 		pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth);
889 		fclose(fp);
890 		return False;
891 	}
892 
893 	/*
894 	 * Now get the password value - this should be 32 hex digits
895 	 * which are the ascii representations of a 16 byte string.
896 	 * Get two at a time and put them into the password.
897 	 */
898 	p++;
899 
900 	/* Record exact password position */
901 	pwd_seekpos += PTR_DIFF(p, linebuf);
902 
903 	if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
904 		DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (passwd too short)\n",
905 			pwd->smb_name));
906 		pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
907 		fclose(fp);
908 		return (False);
909 	}
910 
911 	if (p[32] != ':') {
912 		DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no terminating :)\n",
913 			pwd->smb_name));
914 		pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
915 		fclose(fp);
916 		return False;
917 	}
918 
919 	/* Now check if the NT compatible password is available. */
920 	p += 33; /* Move to the first character of the line after the lanman password. */
921 	if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
922 		DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (passwd too short)\n",
923 			pwd->smb_name));
924 		pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
925 		fclose(fp);
926 		return (False);
927 	}
928 
929 	if (p[32] != ':') {
930 		DEBUG(0, ("mod_smbfilepwd_entry: malformed password entry for user %s (no terminating :)\n",
931 			pwd->smb_name));
932 		pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
933 		fclose(fp);
934 		return False;
935 	}
936 
937 	/*
938 	 * Now check if the account info and the password last
939 	 * change time is available.
940 	 */
941 	p += 33; /* Move to the first character of the line after the NT password. */
942 
943 	if (*p == '[') {
944 		i = 0;
945 		encode_bits[i++] = *p++;
946 		while((linebuf_len > PTR_DIFF(p, linebuf)) && (*p != ']')) {
947 			encode_bits[i++] = *p++;
948 		}
949 
950 		encode_bits[i++] = ']';
951 		encode_bits[i++] = '\0';
952 
953 		if(i == NEW_PW_FORMAT_SPACE_PADDED_LEN) {
954 			/*
955 			 * We are using a new format, space padded
956 			 * acct ctrl field. Encode the given acct ctrl
957 			 * bits into it.
958 			 */
959 			fstrcpy(encode_bits, pdb_encode_acct_ctrl(pwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN));
960 		} else {
961 			DEBUG(0,("mod_smbfilepwd_entry:  Using old smbpasswd format for user %s. \
962 This is no longer supported.!\n", pwd->smb_name));
963 			DEBUG(0,("mod_smbfilepwd_entry:  No changes made, failing.!\n"));
964 			pw_file_unlock(lockfd, &smbpasswd_state->pw_file_lock_depth);
965 			fclose(fp);
966 			return False;
967 		}
968 
969 		/* Go past the ']' */
970 		if(linebuf_len > PTR_DIFF(p, linebuf)) {
971 			p++;
972 		}
973 
974 		if((linebuf_len > PTR_DIFF(p, linebuf)) && (*p == ':')) {
975 			p++;
976 
977 			/* We should be pointing at the LCT entry. */
978 			if((linebuf_len > (PTR_DIFF(p, linebuf) + 13)) && (strncasecmp_m((char *)p, "LCT-", 4) == 0)) {
979 				p += 4;
980 				for(i = 0; i < 8; i++) {
981 					if(p[i] == '\0' || !isxdigit(p[i])) {
982 						break;
983 					}
984 				}
985 				if(i == 8) {
986 					/*
987 					 * p points at 8 characters of hex digits -
988 					 * read into a time_t as the seconds since
989 					 * 1970 that the password was last changed.
990 					 */
991 					got_pass_last_set_time = True;
992 				} /* i == 8 */
993 			} /* *p && strncasecmp_m() */
994 		} /* p == ':' */
995 	} /* p == '[' */
996 
997 	/* Entry is correctly formed. */
998 
999 	/* Create the 32 byte representation of the new p16 */
1000 	pdb_sethexpwd(ascii_p16, pwd->smb_passwd, pwd->acct_ctrl);
1001 
1002 	/* Add on the NT md4 hash */
1003 	ascii_p16[32] = ':';
1004 	wr_len = 66;
1005 	pdb_sethexpwd(ascii_p16+33, pwd->smb_nt_passwd, pwd->acct_ctrl);
1006 	ascii_p16[65] = ':';
1007 	ascii_p16[66] = '\0'; /* null-terminate the string so that strlen works */
1008 
1009 	/* Add on the account info bits and the time of last password change. */
1010 	if(got_pass_last_set_time) {
1011 		slprintf(&ascii_p16[strlen(ascii_p16)],
1012 			sizeof(ascii_p16)-(strlen(ascii_p16)+1),
1013 			"%s:LCT-%08X:",
1014 			encode_bits, (uint32_t)pwd->pass_last_set_time );
1015 		wr_len = strlen(ascii_p16);
1016 	}
1017 
1018 #ifdef DEBUG_PASSWORD
1019 	DEBUG(100,("mod_smbfilepwd_entry: "));
1020 	dump_data(100, (uint8_t *)ascii_p16, wr_len);
1021 #endif
1022 
1023 	if(wr_len > LINEBUF_SIZE) {
1024 		DEBUG(0, ("mod_smbfilepwd_entry: line to write (%d) is too long.\n", wr_len+1));
1025 		pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
1026 		fclose(fp);
1027 		return (False);
1028 	}
1029 
1030 	/*
1031 	 * Do an atomic write into the file at the position defined by
1032 	 * seekpos.
1033 	 */
1034 
1035 	/* The mod user write needs to be atomic - so get the fd from
1036 		the fp and do a raw write() call.
1037 	 */
1038 
1039 	fd = fileno(fp);
1040 
1041 	if (lseek(fd, pwd_seekpos - 1, SEEK_SET) != pwd_seekpos - 1) {
1042 		DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
1043 		pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
1044 		fclose(fp);
1045 		return False;
1046 	}
1047 
1048 	/* Sanity check - ensure the areas we are writing are framed by ':' */
1049 	if (read(fd, linebuf, wr_len+1) != wr_len+1) {
1050 		DEBUG(0, ("mod_smbfilepwd_entry: read fail on file %s.\n", pfile));
1051 		pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
1052 		fclose(fp);
1053 		return False;
1054 	}
1055 
1056 	if ((linebuf[0] != ':') || (linebuf[wr_len] != ':'))	{
1057 		DEBUG(0, ("mod_smbfilepwd_entry: check on passwd file %s failed.\n", pfile));
1058 		pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
1059 		fclose(fp);
1060 		return False;
1061 	}
1062 
1063 	if (lseek(fd, pwd_seekpos, SEEK_SET) != pwd_seekpos) {
1064 		DEBUG(0, ("mod_smbfilepwd_entry: seek fail on file %s.\n", pfile));
1065 		pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
1066 		fclose(fp);
1067 		return False;
1068 	}
1069 
1070 	if (write(fd, ascii_p16, wr_len) != wr_len) {
1071 		DEBUG(0, ("mod_smbfilepwd_entry: write failed in passwd file %s\n", pfile));
1072 		pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
1073 		fclose(fp);
1074 		return False;
1075 	}
1076 
1077 	pw_file_unlock(lockfd,&smbpasswd_state->pw_file_lock_depth);
1078 	fclose(fp);
1079 	return True;
1080 }
1081 
1082 /************************************************************************
1083  Routine to delete an entry in the smbpasswd file by name.
1084 *************************************************************************/
1085 
1086 static bool del_smbfilepwd_entry(struct smbpasswd_privates *smbpasswd_state, const char *name)
1087 {
1088 	const char *pfile = smbpasswd_state->smbpasswd_file;
1089 	char *pfile2 = NULL;
1090 	struct smb_passwd *pwd = NULL;
1091 	FILE *fp = NULL;
1092 	FILE *fp_write = NULL;
1093 	int pfile2_lockdepth = 0;
1094 
1095 	pfile2 = talloc_asprintf(talloc_tos(),
1096 			"%s.%u",
1097 			pfile, (unsigned)getpid());
1098 	if (!pfile2) {
1099 		return false;
1100 	}
1101 
1102 	/*
1103 	 * Open the smbpassword file - for update. It needs to be update
1104 	 * as we need any other processes to wait until we have replaced
1105 	 * it.
1106 	 */
1107 
1108 	if((fp = startsmbfilepwent(pfile, PWF_UPDATE, &smbpasswd_state->pw_file_lock_depth)) == NULL) {
1109 		DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
1110 		return False;
1111 	}
1112 
1113 	/*
1114 	 * Create the replacement password file.
1115 	 */
1116 	if((fp_write = startsmbfilepwent(pfile2, PWF_CREATE, &pfile2_lockdepth)) == NULL) {
1117 		DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile));
1118 		endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
1119 		return False;
1120 	}
1121 
1122 	/*
1123 	 * Scan the file, a line at a time and check if the name matches.
1124 	 */
1125 
1126 	while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) {
1127 		char *new_entry;
1128 		size_t new_entry_length;
1129 
1130 		if (strequal(name, pwd->smb_name)) {
1131 			DEBUG(10, ("del_smbfilepwd_entry: found entry with "
1132 				   "name %s - deleting it.\n", name));
1133 			continue;
1134 		}
1135 
1136 		/*
1137 		 * We need to copy the entry out into the second file.
1138 		 */
1139 
1140 		if((new_entry = format_new_smbpasswd_entry(pwd)) == NULL) {
1141 			DEBUG(0, ("del_smbfilepwd_entry(malloc): Failed to copy entry for user %s to file %s. \
1142 Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
1143 			unlink(pfile2);
1144 			endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
1145 			endsmbfilepwent(fp_write, &pfile2_lockdepth);
1146 			return False;
1147 		}
1148 
1149 		new_entry_length = strlen(new_entry);
1150 
1151 		if(fwrite(new_entry, 1, new_entry_length, fp_write) != new_entry_length) {
1152 			DEBUG(0, ("del_smbfilepwd_entry(write): Failed to copy entry for user %s to file %s. \
1153 Error was %s\n", pwd->smb_name, pfile2, strerror(errno)));
1154 			unlink(pfile2);
1155 			endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
1156 			endsmbfilepwent(fp_write, &pfile2_lockdepth);
1157 			free(new_entry);
1158 			return False;
1159 		}
1160 
1161 		free(new_entry);
1162 	}
1163 
1164 	/*
1165 	 * Ensure pfile2 is flushed before rename.
1166 	 */
1167 
1168 	if(fflush(fp_write) != 0) {
1169 		DEBUG(0, ("del_smbfilepwd_entry: Failed to flush file %s. Error was %s\n", pfile2, strerror(errno)));
1170 		endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
1171 		endsmbfilepwent(fp_write,&pfile2_lockdepth);
1172 		return False;
1173 	}
1174 
1175 	/*
1176 	 * Do an atomic rename - then release the locks.
1177 	 */
1178 
1179 	if(rename(pfile2,pfile) != 0) {
1180 		unlink(pfile2);
1181 	}
1182 
1183 	endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
1184 	endsmbfilepwent(fp_write,&pfile2_lockdepth);
1185 	return True;
1186 }
1187 
1188 /*********************************************************************
1189  Create a smb_passwd struct from a struct samu.
1190  We will not allocate any new memory.  The smb_passwd struct
1191  should only stay around as long as the struct samu does.
1192  ********************************************************************/
1193 
1194 static bool build_smb_pass (struct smb_passwd *smb_pw, const struct samu *sampass)
1195 {
1196 	uint32_t rid;
1197 
1198 	if (sampass == NULL)
1199 		return False;
1200 	ZERO_STRUCTP(smb_pw);
1201 
1202 	if (!IS_SAM_DEFAULT(sampass, PDB_USERSID)) {
1203 		rid = pdb_get_user_rid(sampass);
1204 
1205 		/* If the user specified a RID, make sure its able to be both stored and retreived */
1206 		if (rid == DOMAIN_RID_GUEST) {
1207 			struct passwd *passwd = Get_Pwnam_alloc(NULL, lp_guest_account());
1208 			if (!passwd) {
1209 				DEBUG(0, ("Could not find guest account via Get_Pwnam_alloc()! (%s)\n", lp_guest_account()));
1210 				return False;
1211 			}
1212 			smb_pw->smb_userid=passwd->pw_uid;
1213 			TALLOC_FREE(passwd);
1214 		} else if (algorithmic_pdb_rid_is_user(rid)) {
1215 			smb_pw->smb_userid=algorithmic_pdb_user_rid_to_uid(rid);
1216 		} else {
1217 			DEBUG(0,("build_sam_pass: Failing attempt to store user with non-uid based user RID. \n"));
1218 			return False;
1219 		}
1220 	}
1221 
1222 	smb_pw->smb_name=(const char*)pdb_get_username(sampass);
1223 
1224 	smb_pw->smb_passwd=pdb_get_lanman_passwd(sampass);
1225 	smb_pw->smb_nt_passwd=pdb_get_nt_passwd(sampass);
1226 
1227 	smb_pw->acct_ctrl=pdb_get_acct_ctrl(sampass);
1228 	smb_pw->pass_last_set_time=pdb_get_pass_last_set_time(sampass);
1229 
1230 	return True;
1231 }
1232 
1233 /*********************************************************************
1234  Create a struct samu from a smb_passwd struct
1235  ********************************************************************/
1236 
1237 static bool build_sam_account(struct smbpasswd_privates *smbpasswd_state,
1238 			      struct samu *sam_pass, const struct smb_passwd *pw_buf)
1239 {
1240 	struct passwd *pwfile;
1241 
1242 	if ( !sam_pass ) {
1243 		DEBUG(5,("build_sam_account: struct samu is NULL\n"));
1244 		return False;
1245 	}
1246 
1247 	/* verify the user account exists */
1248 
1249 	if ( !(pwfile = Get_Pwnam_alloc(NULL, pw_buf->smb_name )) ) {
1250 		DEBUG(0,("build_sam_account: smbpasswd database is corrupt!  username %s with uid "
1251 		"%u is not in unix passwd database!\n", pw_buf->smb_name, pw_buf->smb_userid));
1252 			return False;
1253 	}
1254 
1255 	if ( !NT_STATUS_IS_OK( samu_set_unix(sam_pass, pwfile )) )
1256 		return False;
1257 
1258 	TALLOC_FREE(pwfile);
1259 
1260 	/* set remaining fields */
1261 
1262 	if (!pdb_set_nt_passwd (sam_pass, pw_buf->smb_nt_passwd, PDB_SET))
1263 		return False;
1264 	if (!pdb_set_lanman_passwd (sam_pass, pw_buf->smb_passwd, PDB_SET))
1265 		return False;
1266 	pdb_set_acct_ctrl (sam_pass, pw_buf->acct_ctrl, PDB_SET);
1267 	pdb_set_pass_last_set_time (sam_pass, pw_buf->pass_last_set_time, PDB_SET);
1268 	pdb_set_pass_can_change_time (sam_pass, pw_buf->pass_last_set_time, PDB_SET);
1269 
1270 	return True;
1271 }
1272 
1273 /*****************************************************************
1274  Functions to be implemented by the new passdb API
1275  ****************************************************************/
1276 
1277 /****************************************************************
1278  Search smbpasswd file by iterating over the entries.  Do not
1279  call getpwnam() for unix account information until we have found
1280  the correct entry
1281  ***************************************************************/
1282 
1283 static NTSTATUS smbpasswd_getsampwnam(struct pdb_methods *my_methods,
1284 				  struct samu *sam_acct, const char *username)
1285 {
1286 	NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1287 	struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
1288 	struct smb_passwd *smb_pw;
1289 	FILE *fp = NULL;
1290 
1291 	DEBUG(10, ("getsampwnam (smbpasswd): search by name: %s\n", username));
1292 
1293 	/* startsmbfilepwent() is used here as we don't want to lookup
1294 	   the UNIX account in the local system password file until
1295 	   we have a match.  */
1296 	fp = startsmbfilepwent(smbpasswd_state->smbpasswd_file, PWF_READ, &(smbpasswd_state->pw_file_lock_depth));
1297 
1298 	if (fp == NULL) {
1299 		DEBUG(0, ("Unable to open passdb database.\n"));
1300 		return nt_status;
1301 	}
1302 
1303 	while ( ((smb_pw=getsmbfilepwent(smbpasswd_state, fp)) != NULL)&& (!strequal(smb_pw->smb_name, username)) )
1304 		/* do nothing....another loop */ ;
1305 
1306 	endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
1307 
1308 
1309 	/* did we locate the username in smbpasswd  */
1310 	if (smb_pw == NULL)
1311 		return nt_status;
1312 
1313 	DEBUG(10, ("getsampwnam (smbpasswd): found by name: %s\n", smb_pw->smb_name));
1314 
1315 	if (!sam_acct) {
1316 		DEBUG(10,("getsampwnam (smbpasswd): struct samu is NULL\n"));
1317 		return nt_status;
1318 	}
1319 
1320 	/* now build the struct samu */
1321 	if (!build_sam_account(smbpasswd_state, sam_acct, smb_pw))
1322 		return nt_status;
1323 
1324 	/* success */
1325 	return NT_STATUS_OK;
1326 }
1327 
1328 static NTSTATUS smbpasswd_getsampwsid(struct pdb_methods *my_methods, struct samu *sam_acct, const struct dom_sid *sid)
1329 {
1330 	NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1331 	struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
1332 	struct smb_passwd *smb_pw;
1333 	struct dom_sid_buf buf;
1334 	FILE *fp = NULL;
1335 	uint32_t rid;
1336 
1337 	DEBUG(10, ("smbpasswd_getsampwrid: search by sid: %s\n",
1338 		   dom_sid_str_buf(sid, &buf)));
1339 
1340 	if (!sid_peek_check_rid(get_global_sam_sid(), sid, &rid))
1341 		return NT_STATUS_UNSUCCESSFUL;
1342 
1343 	/* More special case 'guest account' hacks... */
1344 	if (rid == DOMAIN_RID_GUEST) {
1345 		const char *guest_account = lp_guest_account();
1346 		if (!(guest_account && *guest_account)) {
1347 			DEBUG(1, ("Guest account not specified!\n"));
1348 			return nt_status;
1349 		}
1350 		return smbpasswd_getsampwnam(my_methods, sam_acct, guest_account);
1351 	}
1352 
1353 	/* Open the sam password file - not for update. */
1354 	fp = startsmbfilepwent(smbpasswd_state->smbpasswd_file, PWF_READ, &(smbpasswd_state->pw_file_lock_depth));
1355 
1356 	if (fp == NULL) {
1357 		DEBUG(0, ("Unable to open passdb database.\n"));
1358 		return nt_status;
1359 	}
1360 
1361 	while ( ((smb_pw=getsmbfilepwent(smbpasswd_state, fp)) != NULL) && (algorithmic_pdb_uid_to_user_rid(smb_pw->smb_userid) != rid) )
1362       		/* do nothing */ ;
1363 
1364 	endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
1365 
1366 
1367 	/* did we locate the username in smbpasswd  */
1368 	if (smb_pw == NULL)
1369 		return nt_status;
1370 
1371 	DEBUG(10, ("getsampwrid (smbpasswd): found by name: %s\n", smb_pw->smb_name));
1372 
1373 	if (!sam_acct) {
1374 		DEBUG(10,("getsampwrid: (smbpasswd) struct samu is NULL\n"));
1375 		return nt_status;
1376 	}
1377 
1378 	/* now build the struct samu */
1379 	if (!build_sam_account (smbpasswd_state, sam_acct, smb_pw))
1380 		return nt_status;
1381 
1382 	/* build_sam_account might change the SID on us, if the name was for the guest account */
1383 	if (NT_STATUS_IS_OK(nt_status) && !dom_sid_equal(pdb_get_user_sid(sam_acct), sid)) {
1384 		struct dom_sid_buf buf1, buf2;
1385 		DEBUG(1, ("looking for user with sid %s instead returned %s "
1386 			  "for account %s!?!\n",
1387 			  dom_sid_str_buf(sid, &buf1),
1388 			  dom_sid_str_buf(pdb_get_user_sid(sam_acct), &buf2),
1389 			  pdb_get_username(sam_acct)));
1390 		return NT_STATUS_NO_SUCH_USER;
1391 	}
1392 
1393 	/* success */
1394 	return NT_STATUS_OK;
1395 }
1396 
1397 static NTSTATUS smbpasswd_add_sam_account(struct pdb_methods *my_methods, struct samu *sampass)
1398 {
1399 	struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
1400 	struct smb_passwd smb_pw;
1401 
1402 	/* convert the struct samu */
1403 	if (!build_smb_pass(&smb_pw, sampass)) {
1404 		return NT_STATUS_UNSUCCESSFUL;
1405 	}
1406 
1407 	/* add the entry */
1408 	return add_smbfilepwd_entry(smbpasswd_state, &smb_pw);
1409 }
1410 
1411 static NTSTATUS smbpasswd_update_sam_account(struct pdb_methods *my_methods, struct samu *sampass)
1412 {
1413 	struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
1414 	struct smb_passwd smb_pw;
1415 
1416 	/* convert the struct samu */
1417 	if (!build_smb_pass(&smb_pw, sampass)) {
1418 		DEBUG(0, ("smbpasswd_update_sam_account: build_smb_pass failed!\n"));
1419 		return NT_STATUS_UNSUCCESSFUL;
1420 	}
1421 
1422 	/* update the entry */
1423 	if(!mod_smbfilepwd_entry(smbpasswd_state, &smb_pw)) {
1424 		DEBUG(0, ("smbpasswd_update_sam_account: mod_smbfilepwd_entry failed!\n"));
1425 		return NT_STATUS_UNSUCCESSFUL;
1426 	}
1427 
1428 	return NT_STATUS_OK;
1429 }
1430 
1431 static NTSTATUS smbpasswd_delete_sam_account (struct pdb_methods *my_methods, struct samu *sampass)
1432 {
1433 	struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
1434 
1435 	const char *username = pdb_get_username(sampass);
1436 
1437 	if (del_smbfilepwd_entry(smbpasswd_state, username))
1438 		return NT_STATUS_OK;
1439 
1440 	return NT_STATUS_UNSUCCESSFUL;
1441 }
1442 
1443 static NTSTATUS smbpasswd_rename_sam_account (struct pdb_methods *my_methods,
1444 					      struct samu *old_acct,
1445 					      const char *newname)
1446 {
1447 	const struct loadparm_substitution *lp_sub =
1448 		loadparm_s3_global_substitution();
1449 	char *rename_script = NULL;
1450 	struct samu *new_acct = NULL;
1451 	bool interim_account = False;
1452 	TALLOC_CTX *ctx = talloc_tos();
1453 	NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
1454 
1455 	if (!*(lp_rename_user_script(talloc_tos(), lp_sub)))
1456 		goto done;
1457 
1458 	if ( !(new_acct = samu_new( NULL )) ) {
1459 		return NT_STATUS_NO_MEMORY;
1460 	}
1461 
1462 	if ( !pdb_copy_sam_account( new_acct, old_acct )
1463 		|| !pdb_set_username(new_acct, newname, PDB_CHANGED))
1464 	{
1465 		goto done;
1466 	}
1467 
1468 	ret = smbpasswd_add_sam_account(my_methods, new_acct);
1469 	if (!NT_STATUS_IS_OK(ret))
1470 		goto done;
1471 
1472 	interim_account = True;
1473 
1474 	/* rename the posix user */
1475 	rename_script = lp_rename_user_script(ctx, lp_sub);
1476 	if (!rename_script) {
1477 		ret = NT_STATUS_NO_MEMORY;
1478 		goto done;
1479 	}
1480 
1481 	if (*rename_script) {
1482 	        int rename_ret;
1483 
1484 		rename_script = talloc_string_sub2(ctx,
1485 					rename_script,
1486 					"%unew",
1487 					newname,
1488 					true,
1489 					false,
1490 					true);
1491 		if (!rename_script) {
1492 			ret = NT_STATUS_NO_MEMORY;
1493 			goto done;
1494 		}
1495 		rename_script = talloc_string_sub2(ctx,
1496 					rename_script,
1497 					"%uold",
1498 					pdb_get_username(old_acct),
1499 					true,
1500 					false,
1501 					true);
1502 		if (!rename_script) {
1503 			ret = NT_STATUS_NO_MEMORY;
1504 			goto done;
1505 		}
1506 
1507 		rename_ret = smbrun(rename_script, NULL, NULL);
1508 
1509 		DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n", rename_script, rename_ret));
1510 
1511 		if (rename_ret == 0) {
1512 			smb_nscd_flush_user_cache();
1513 		}
1514 
1515 		if (rename_ret)
1516 			goto done;
1517         } else {
1518 		goto done;
1519 	}
1520 
1521 	smbpasswd_delete_sam_account(my_methods, old_acct);
1522 	interim_account = False;
1523 
1524 done:
1525 	/* cleanup */
1526 	if (interim_account)
1527 		smbpasswd_delete_sam_account(my_methods, new_acct);
1528 
1529 	if (new_acct)
1530 		TALLOC_FREE(new_acct);
1531 
1532 	return (ret);
1533 }
1534 
1535 static uint32_t smbpasswd_capabilities(struct pdb_methods *methods)
1536 {
1537 	return 0;
1538 }
1539 
1540 static void free_private_data(void **vp)
1541 {
1542 	struct smbpasswd_privates **privates = (struct smbpasswd_privates**)vp;
1543 
1544 	endsmbfilepwent((*privates)->pw_file, &((*privates)->pw_file_lock_depth));
1545 
1546 	*privates = NULL;
1547 	/* No need to free any further, as it is talloc()ed */
1548 }
1549 
1550 struct smbpasswd_search_state {
1551 	uint32_t acct_flags;
1552 
1553 	struct samr_displayentry *entries;
1554 	uint32_t num_entries;
1555 	ssize_t array_size;
1556 	uint32_t current;
1557 };
1558 
1559 static void smbpasswd_search_end(struct pdb_search *search)
1560 {
1561 	struct smbpasswd_search_state *state = talloc_get_type_abort(
1562 		search->private_data, struct smbpasswd_search_state);
1563 	TALLOC_FREE(state);
1564 }
1565 
1566 static bool smbpasswd_search_next_entry(struct pdb_search *search,
1567 					struct samr_displayentry *entry)
1568 {
1569 	struct smbpasswd_search_state *state = talloc_get_type_abort(
1570 		search->private_data, struct smbpasswd_search_state);
1571 
1572 	if (state->current == state->num_entries) {
1573 		return false;
1574 	}
1575 
1576 	entry->idx = state->entries[state->current].idx;
1577 	entry->rid = state->entries[state->current].rid;
1578 	entry->acct_flags = state->entries[state->current].acct_flags;
1579 
1580 	entry->account_name = talloc_strdup(
1581 		search, state->entries[state->current].account_name);
1582 	entry->fullname = talloc_strdup(
1583 		search, state->entries[state->current].fullname);
1584 	entry->description = talloc_strdup(
1585 		search, state->entries[state->current].description);
1586 
1587 	if ((entry->account_name == NULL) || (entry->fullname == NULL)
1588 	    || (entry->description == NULL)) {
1589 		DEBUG(0, ("talloc_strdup failed\n"));
1590 		return false;
1591 	}
1592 
1593 	state->current += 1;
1594 	return true;
1595 }
1596 
1597 static bool smbpasswd_search_users(struct pdb_methods *methods,
1598 				   struct pdb_search *search,
1599 				   uint32_t acct_flags)
1600 {
1601 	struct smbpasswd_privates *smbpasswd_state =
1602 		(struct smbpasswd_privates*)methods->private_data;
1603 
1604 	struct smbpasswd_search_state *search_state;
1605 	struct smb_passwd *pwd;
1606 	FILE *fp;
1607 
1608 	search_state = talloc_zero(search, struct smbpasswd_search_state);
1609 	if (search_state == NULL) {
1610 		DEBUG(0, ("talloc failed\n"));
1611 		return false;
1612 	}
1613 	search_state->acct_flags = acct_flags;
1614 
1615 	fp = startsmbfilepwent(smbpasswd_state->smbpasswd_file, PWF_READ,
1616 			       &smbpasswd_state->pw_file_lock_depth);
1617 
1618 	if (fp == NULL) {
1619 		DEBUG(10, ("Unable to open smbpasswd file.\n"));
1620 		TALLOC_FREE(search_state);
1621 		return false;
1622 	}
1623 
1624 	while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) {
1625 		struct samr_displayentry entry;
1626 		struct samu *user;
1627 
1628 		if ((acct_flags != 0)
1629 		    && ((acct_flags & pwd->acct_ctrl) == 0)) {
1630 			continue;
1631 		}
1632 
1633 		user = samu_new(talloc_tos());
1634 		if (user == NULL) {
1635 			DEBUG(0, ("samu_new failed\n"));
1636 			break;
1637 		}
1638 
1639 		if (!build_sam_account(smbpasswd_state, user, pwd)) {
1640 			/* Already got debug msgs... */
1641 			break;
1642 		}
1643 
1644 		ZERO_STRUCT(entry);
1645 
1646 		entry.acct_flags = pdb_get_acct_ctrl(user);
1647 		sid_peek_rid(pdb_get_user_sid(user), &entry.rid);
1648 		entry.account_name = talloc_strdup(
1649 			search_state, pdb_get_username(user));
1650 		entry.fullname = talloc_strdup(
1651 			search_state, pdb_get_fullname(user));
1652 		entry.description = talloc_strdup(
1653 			search_state, pdb_get_acct_desc(user));
1654 
1655 		TALLOC_FREE(user);
1656 
1657 		if ((entry.account_name == NULL) || (entry.fullname == NULL)
1658 		    || (entry.description == NULL)) {
1659 			DEBUG(0, ("talloc_strdup failed\n"));
1660 			break;
1661 		}
1662 
1663 		ADD_TO_LARGE_ARRAY(search_state, struct samr_displayentry,
1664 				   entry, &search_state->entries,
1665 				   &search_state->num_entries,
1666 				   &search_state->array_size);
1667 	}
1668 
1669 	endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
1670 
1671 	search->private_data = search_state;
1672 	search->next_entry = smbpasswd_search_next_entry;
1673 	search->search_end = smbpasswd_search_end;
1674 
1675 	return true;
1676 }
1677 
1678 static NTSTATUS pdb_init_smbpasswd( struct pdb_methods **pdb_method, const char *location )
1679 {
1680 	NTSTATUS nt_status;
1681 	struct smbpasswd_privates *privates;
1682 
1683 	if ( !NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method )) ) {
1684 		return nt_status;
1685 	}
1686 
1687 	(*pdb_method)->name = "smbpasswd";
1688 
1689 	(*pdb_method)->getsampwnam = smbpasswd_getsampwnam;
1690 	(*pdb_method)->getsampwsid = smbpasswd_getsampwsid;
1691 	(*pdb_method)->add_sam_account = smbpasswd_add_sam_account;
1692 	(*pdb_method)->update_sam_account = smbpasswd_update_sam_account;
1693 	(*pdb_method)->delete_sam_account = smbpasswd_delete_sam_account;
1694 	(*pdb_method)->rename_sam_account = smbpasswd_rename_sam_account;
1695 	(*pdb_method)->search_users = smbpasswd_search_users;
1696 
1697 	(*pdb_method)->capabilities = smbpasswd_capabilities;
1698 
1699 	/* Setup private data and free function */
1700 
1701 	if ( !(privates = talloc_zero( *pdb_method, struct smbpasswd_privates )) ) {
1702 		DEBUG(0, ("talloc() failed for smbpasswd private_data!\n"));
1703 		return NT_STATUS_NO_MEMORY;
1704 	}
1705 
1706 	/* Store some config details */
1707 
1708 	if (location) {
1709 		privates->smbpasswd_file = talloc_strdup(*pdb_method, location);
1710 	} else {
1711 		privates->smbpasswd_file = talloc_strdup(*pdb_method, lp_smb_passwd_file());
1712 	}
1713 
1714 	if (!privates->smbpasswd_file) {
1715 		DEBUG(0, ("talloc_strdp() failed for storing smbpasswd location!\n"));
1716 		return NT_STATUS_NO_MEMORY;
1717 	}
1718 
1719 	(*pdb_method)->private_data = privates;
1720 
1721 	(*pdb_method)->free_private_data = free_private_data;
1722 
1723 	return NT_STATUS_OK;
1724 }
1725 
1726 NTSTATUS pdb_smbpasswd_init(TALLOC_CTX *ctx)
1727 {
1728 	return smb_register_passdb(PASSDB_INTERFACE_VERSION, "smbpasswd", pdb_init_smbpasswd);
1729 }
1730