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