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