source: branches/samba-3.2.x/source/passdb/pdb_smbpasswd.c

Last change on this file was 232, checked in by Herwig Bauernfeind, 16 years ago

Update 3.2 branch to 3.2.8

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