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

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

Import Samba 3.3 branch at 3.0.0 level (psmedley's port)

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 DEBUG(0, ("startsmbfilepwent_internal: failed to set 0600 permissions on password file %s. \
327Error was %s\n.", pfile, strerror(errno) ));
328 pw_file_unlock(fileno(fp), lock_depth);
329 fclose(fp);
330 return NULL;
331 }
332#endif
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
1180 if(rename(pfile2,pfile) != 0) {
1181 unlink(pfile2);
1182 }
1183
1184#ifndef __OS2__
1185 endsmbfilepwent(fp, &smbpasswd_state->pw_file_lock_depth);
1186 endsmbfilepwent(fp_write,&pfile2_lockdepth);
1187#endif
1188 return True;
1189}
1190
1191/*********************************************************************
1192 Create a smb_passwd struct from a struct samu.
1193 We will not allocate any new memory. The smb_passwd struct
1194 should only stay around as long as the struct samu does.
1195 ********************************************************************/
1196
1197static bool build_smb_pass (struct smb_passwd *smb_pw, const struct samu *sampass)
1198{
1199 uint32 rid;
1200
1201 if (sampass == NULL)
1202 return False;
1203 ZERO_STRUCTP(smb_pw);
1204
1205 if (!IS_SAM_DEFAULT(sampass, PDB_USERSID)) {
1206 rid = pdb_get_user_rid(sampass);
1207
1208 /* If the user specified a RID, make sure its able to be both stored and retreived */
1209 if (rid == DOMAIN_USER_RID_GUEST) {
1210 struct passwd *passwd = getpwnam_alloc(NULL, lp_guestaccount());
1211 if (!passwd) {
1212 DEBUG(0, ("Could not find guest account via getpwnam()! (%s)\n", lp_guestaccount()));
1213 return False;
1214 }
1215 smb_pw->smb_userid=passwd->pw_uid;
1216 TALLOC_FREE(passwd);
1217 } else if (algorithmic_pdb_rid_is_user(rid)) {
1218 smb_pw->smb_userid=algorithmic_pdb_user_rid_to_uid(rid);
1219 } else {
1220 DEBUG(0,("build_sam_pass: Failing attempt to store user with non-uid based user RID. \n"));
1221 return False;
1222 }
1223 }
1224
1225 smb_pw->smb_name=(const char*)pdb_get_username(sampass);
1226
1227 smb_pw->smb_passwd=pdb_get_lanman_passwd(sampass);
1228 smb_pw->smb_nt_passwd=pdb_get_nt_passwd(sampass);
1229
1230 smb_pw->acct_ctrl=pdb_get_acct_ctrl(sampass);
1231 smb_pw->pass_last_set_time=pdb_get_pass_last_set_time(sampass);
1232
1233 return True;
1234}
1235
1236/*********************************************************************
1237 Create a struct samu from a smb_passwd struct
1238 ********************************************************************/
1239
1240static bool build_sam_account(struct smbpasswd_privates *smbpasswd_state,
1241 struct samu *sam_pass, const struct smb_passwd *pw_buf)
1242{
1243 struct passwd *pwfile;
1244
1245 if ( !sam_pass ) {
1246 DEBUG(5,("build_sam_account: struct samu is NULL\n"));
1247 return False;
1248 }
1249
1250 /* verify the user account exists */
1251
1252 if ( !(pwfile = Get_Pwnam_alloc(NULL, pw_buf->smb_name )) ) {
1253 DEBUG(0,("build_sam_account: smbpasswd database is corrupt! username %s with uid "
1254 "%u is not in unix passwd database!\n", pw_buf->smb_name, pw_buf->smb_userid));
1255 return False;
1256 }
1257
1258 if ( !NT_STATUS_IS_OK( samu_set_unix(sam_pass, pwfile )) )
1259 return False;
1260
1261 TALLOC_FREE(pwfile);
1262
1263 /* set remaining fields */
1264
1265 if (!pdb_set_nt_passwd (sam_pass, pw_buf->smb_nt_passwd, PDB_SET))
1266 return False;
1267 if (!pdb_set_lanman_passwd (sam_pass, pw_buf->smb_passwd, PDB_SET))
1268 return False;
1269 pdb_set_acct_ctrl (sam_pass, pw_buf->acct_ctrl, PDB_SET);
1270 pdb_set_pass_last_set_time (sam_pass, pw_buf->pass_last_set_time, PDB_SET);
1271 pdb_set_pass_can_change_time (sam_pass, pw_buf->pass_last_set_time, PDB_SET);
1272
1273 return True;
1274}
1275
1276/*****************************************************************
1277 Functions to be implemented by the new passdb API
1278 ****************************************************************/
1279
1280/****************************************************************
1281 Search smbpasswd file by iterating over the entries. Do not
1282 call getpwnam() for unix account information until we have found
1283 the correct entry
1284 ***************************************************************/
1285
1286static NTSTATUS smbpasswd_getsampwnam(struct pdb_methods *my_methods,
1287 struct samu *sam_acct, const char *username)
1288{
1289 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1290 struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
1291 struct smb_passwd *smb_pw;
1292 FILE *fp = NULL;
1293
1294 DEBUG(10, ("getsampwnam (smbpasswd): search by name: %s\n", username));
1295
1296 /* startsmbfilepwent() is used here as we don't want to lookup
1297 the UNIX account in the local system password file until
1298 we have a match. */
1299 fp = startsmbfilepwent(smbpasswd_state->smbpasswd_file, PWF_READ, &(smbpasswd_state->pw_file_lock_depth));
1300
1301 if (fp == NULL) {
1302 DEBUG(0, ("Unable to open passdb database.\n"));
1303 return nt_status;
1304 }
1305
1306 while ( ((smb_pw=getsmbfilepwent(smbpasswd_state, fp)) != NULL)&& (!strequal(smb_pw->smb_name, username)) )
1307 /* do nothing....another loop */ ;
1308
1309 endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
1310
1311
1312 /* did we locate the username in smbpasswd */
1313 if (smb_pw == NULL)
1314 return nt_status;
1315
1316 DEBUG(10, ("getsampwnam (smbpasswd): found by name: %s\n", smb_pw->smb_name));
1317
1318 if (!sam_acct) {
1319 DEBUG(10,("getsampwnam (smbpasswd): struct samu is NULL\n"));
1320 return nt_status;
1321 }
1322
1323 /* now build the struct samu */
1324 if (!build_sam_account(smbpasswd_state, sam_acct, smb_pw))
1325 return nt_status;
1326
1327 /* success */
1328 return NT_STATUS_OK;
1329}
1330
1331static NTSTATUS smbpasswd_getsampwsid(struct pdb_methods *my_methods, struct samu *sam_acct, const DOM_SID *sid)
1332{
1333 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1334 struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
1335 struct smb_passwd *smb_pw;
1336 FILE *fp = NULL;
1337 uint32 rid;
1338
1339 DEBUG(10, ("smbpasswd_getsampwrid: search by sid: %s\n",
1340 sid_string_dbg(sid)));
1341
1342 if (!sid_peek_check_rid(get_global_sam_sid(), sid, &rid))
1343 return NT_STATUS_UNSUCCESSFUL;
1344
1345 /* More special case 'guest account' hacks... */
1346 if (rid == DOMAIN_USER_RID_GUEST) {
1347 const char *guest_account = lp_guestaccount();
1348 if (!(guest_account && *guest_account)) {
1349 DEBUG(1, ("Guest account not specfied!\n"));
1350 return nt_status;
1351 }
1352 return smbpasswd_getsampwnam(my_methods, sam_acct, guest_account);
1353 }
1354
1355 /* Open the sam password file - not for update. */
1356 fp = startsmbfilepwent(smbpasswd_state->smbpasswd_file, PWF_READ, &(smbpasswd_state->pw_file_lock_depth));
1357
1358 if (fp == NULL) {
1359 DEBUG(0, ("Unable to open passdb database.\n"));
1360 return nt_status;
1361 }
1362
1363 while ( ((smb_pw=getsmbfilepwent(smbpasswd_state, fp)) != NULL) && (algorithmic_pdb_uid_to_user_rid(smb_pw->smb_userid) != rid) )
1364 /* do nothing */ ;
1365
1366 endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
1367
1368
1369 /* did we locate the username in smbpasswd */
1370 if (smb_pw == NULL)
1371 return nt_status;
1372
1373 DEBUG(10, ("getsampwrid (smbpasswd): found by name: %s\n", smb_pw->smb_name));
1374
1375 if (!sam_acct) {
1376 DEBUG(10,("getsampwrid: (smbpasswd) struct samu is NULL\n"));
1377 return nt_status;
1378 }
1379
1380 /* now build the struct samu */
1381 if (!build_sam_account (smbpasswd_state, sam_acct, smb_pw))
1382 return nt_status;
1383
1384 /* build_sam_account might change the SID on us, if the name was for the guest account */
1385 if (NT_STATUS_IS_OK(nt_status) && !sid_equal(pdb_get_user_sid(sam_acct), sid)) {
1386 DEBUG(1, ("looking for user with sid %s instead returned %s "
1387 "for account %s!?!\n", sid_string_dbg(sid),
1388 sid_string_dbg(pdb_get_user_sid(sam_acct)),
1389 pdb_get_username(sam_acct)));
1390 return NT_STATUS_NO_SUCH_USER;
1391 }
1392
1393 /* success */
1394 return NT_STATUS_OK;
1395}
1396
1397static NTSTATUS smbpasswd_add_sam_account(struct pdb_methods *my_methods, struct samu *sampass)
1398{
1399 struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
1400 struct smb_passwd smb_pw;
1401
1402 /* convert the struct samu */
1403 if (!build_smb_pass(&smb_pw, sampass)) {
1404 return NT_STATUS_UNSUCCESSFUL;
1405 }
1406
1407 /* add the entry */
1408 return add_smbfilepwd_entry(smbpasswd_state, &smb_pw);
1409}
1410
1411static NTSTATUS smbpasswd_update_sam_account(struct pdb_methods *my_methods, struct samu *sampass)
1412{
1413 struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
1414 struct smb_passwd smb_pw;
1415
1416 /* convert the struct samu */
1417 if (!build_smb_pass(&smb_pw, sampass)) {
1418 DEBUG(0, ("smbpasswd_update_sam_account: build_smb_pass failed!\n"));
1419 return NT_STATUS_UNSUCCESSFUL;
1420 }
1421
1422 /* update the entry */
1423 if(!mod_smbfilepwd_entry(smbpasswd_state, &smb_pw)) {
1424 DEBUG(0, ("smbpasswd_update_sam_account: mod_smbfilepwd_entry failed!\n"));
1425 return NT_STATUS_UNSUCCESSFUL;
1426 }
1427
1428 return NT_STATUS_OK;
1429}
1430
1431static NTSTATUS smbpasswd_delete_sam_account (struct pdb_methods *my_methods, struct samu *sampass)
1432{
1433 struct smbpasswd_privates *smbpasswd_state = (struct smbpasswd_privates*)my_methods->private_data;
1434
1435 const char *username = pdb_get_username(sampass);
1436
1437 if (del_smbfilepwd_entry(smbpasswd_state, username))
1438 return NT_STATUS_OK;
1439
1440 return NT_STATUS_UNSUCCESSFUL;
1441}
1442
1443static NTSTATUS smbpasswd_rename_sam_account (struct pdb_methods *my_methods,
1444 struct samu *old_acct,
1445 const char *newname)
1446{
1447 char *rename_script = NULL;
1448 struct samu *new_acct = NULL;
1449 bool interim_account = False;
1450 TALLOC_CTX *ctx = talloc_tos();
1451 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
1452
1453 if (!*(lp_renameuser_script()))
1454 goto done;
1455
1456 if ( !(new_acct = samu_new( NULL )) ) {
1457 return NT_STATUS_NO_MEMORY;
1458 }
1459
1460 if ( !pdb_copy_sam_account( new_acct, old_acct )
1461 || !pdb_set_username(new_acct, newname, PDB_CHANGED))
1462 {
1463 goto done;
1464 }
1465
1466 ret = smbpasswd_add_sam_account(my_methods, new_acct);
1467 if (!NT_STATUS_IS_OK(ret))
1468 goto done;
1469
1470 interim_account = True;
1471
1472 /* rename the posix user */
1473 rename_script = talloc_strdup(ctx,
1474 lp_renameuser_script());
1475 if (!rename_script) {
1476 ret = NT_STATUS_NO_MEMORY;
1477 goto done;
1478 }
1479
1480 if (*rename_script) {
1481 int rename_ret;
1482
1483 rename_script = talloc_string_sub2(ctx,
1484 rename_script,
1485 "%unew",
1486 newname,
1487 true,
1488 false,
1489 true);
1490 if (!rename_script) {
1491 ret = NT_STATUS_NO_MEMORY;
1492 goto done;
1493 }
1494 rename_script = talloc_string_sub2(ctx,
1495 rename_script,
1496 "%uold",
1497 pdb_get_username(old_acct),
1498 true,
1499 false,
1500 true);
1501 if (!rename_script) {
1502 ret = NT_STATUS_NO_MEMORY;
1503 goto done;
1504 }
1505
1506 rename_ret = smbrun(rename_script, NULL);
1507
1508 DEBUG(rename_ret ? 0 : 3,("Running the command `%s' gave %d\n", rename_script, rename_ret));
1509
1510 if (rename_ret == 0) {
1511 smb_nscd_flush_user_cache();
1512 }
1513
1514 if (rename_ret)
1515 goto done;
1516 } else {
1517 goto done;
1518 }
1519
1520 smbpasswd_delete_sam_account(my_methods, old_acct);
1521 interim_account = False;
1522
1523done:
1524 /* cleanup */
1525 if (interim_account)
1526 smbpasswd_delete_sam_account(my_methods, new_acct);
1527
1528 if (new_acct)
1529 TALLOC_FREE(new_acct);
1530
1531 return (ret);
1532}
1533
1534static bool smbpasswd_rid_algorithm(struct pdb_methods *methods)
1535{
1536 return True;
1537}
1538
1539static void free_private_data(void **vp)
1540{
1541 struct smbpasswd_privates **privates = (struct smbpasswd_privates**)vp;
1542
1543 endsmbfilepwent((*privates)->pw_file, &((*privates)->pw_file_lock_depth));
1544
1545 *privates = NULL;
1546 /* No need to free any further, as it is talloc()ed */
1547}
1548
1549struct smbpasswd_search_state {
1550 uint32_t acct_flags;
1551
1552 struct samr_displayentry *entries;
1553 uint32_t num_entries;
1554 ssize_t array_size;
1555 uint32_t current;
1556};
1557
1558static void smbpasswd_search_end(struct pdb_search *search)
1559{
1560 struct smbpasswd_search_state *state = talloc_get_type_abort(
1561 search->private_data, struct smbpasswd_search_state);
1562 TALLOC_FREE(state);
1563}
1564
1565static bool smbpasswd_search_next_entry(struct pdb_search *search,
1566 struct samr_displayentry *entry)
1567{
1568 struct smbpasswd_search_state *state = talloc_get_type_abort(
1569 search->private_data, struct smbpasswd_search_state);
1570
1571 if (state->current == state->num_entries) {
1572 return false;
1573 }
1574
1575 entry->idx = state->entries[state->current].idx;
1576 entry->rid = state->entries[state->current].rid;
1577 entry->acct_flags = state->entries[state->current].acct_flags;
1578
1579 entry->account_name = talloc_strdup(
1580 search->mem_ctx, state->entries[state->current].account_name);
1581 entry->fullname = talloc_strdup(
1582 search->mem_ctx, state->entries[state->current].fullname);
1583 entry->description = talloc_strdup(
1584 search->mem_ctx, state->entries[state->current].description);
1585
1586 if ((entry->account_name == NULL) || (entry->fullname == NULL)
1587 || (entry->description == NULL)) {
1588 DEBUG(0, ("talloc_strdup failed\n"));
1589 return false;
1590 }
1591
1592 state->current += 1;
1593 return true;
1594}
1595
1596static bool smbpasswd_search_users(struct pdb_methods *methods,
1597 struct pdb_search *search,
1598 uint32_t acct_flags)
1599{
1600 struct smbpasswd_privates *smbpasswd_state =
1601 (struct smbpasswd_privates*)methods->private_data;
1602
1603 struct smbpasswd_search_state *search_state;
1604 struct smb_passwd *pwd;
1605 FILE *fp;
1606
1607 search_state = TALLOC_ZERO_P(search->mem_ctx,
1608 struct smbpasswd_search_state);
1609 if (search_state == NULL) {
1610 DEBUG(0, ("talloc failed\n"));
1611 return false;
1612 }
1613 search_state->acct_flags = acct_flags;
1614
1615 fp = startsmbfilepwent(smbpasswd_state->smbpasswd_file, PWF_READ,
1616 &smbpasswd_state->pw_file_lock_depth);
1617
1618 if (fp == NULL) {
1619 DEBUG(10, ("Unable to open smbpasswd file.\n"));
1620 TALLOC_FREE(search_state);
1621 return false;
1622 }
1623
1624 while ((pwd = getsmbfilepwent(smbpasswd_state, fp)) != NULL) {
1625 struct samr_displayentry entry;
1626 struct samu *user;
1627
1628 if ((acct_flags != 0)
1629 && ((acct_flags & pwd->acct_ctrl) == 0)) {
1630 continue;
1631 }
1632
1633 user = samu_new(talloc_tos());
1634 if (user == NULL) {
1635 DEBUG(0, ("samu_new failed\n"));
1636 break;
1637 }
1638
1639 if (!build_sam_account(smbpasswd_state, user, pwd)) {
1640 /* Already got debug msgs... */
1641 break;
1642 }
1643
1644 ZERO_STRUCT(entry);
1645
1646 entry.acct_flags = pdb_get_acct_ctrl(user);
1647 sid_peek_rid(pdb_get_user_sid(user), &entry.rid);
1648 entry.account_name = talloc_strdup(
1649 search_state, pdb_get_username(user));
1650 entry.fullname = talloc_strdup(
1651 search_state, pdb_get_fullname(user));
1652 entry.description = talloc_strdup(
1653 search_state, pdb_get_acct_desc(user));
1654
1655 TALLOC_FREE(user);
1656
1657 if ((entry.account_name == NULL) || (entry.fullname == NULL)
1658 || (entry.description == NULL)) {
1659 DEBUG(0, ("talloc_strdup failed\n"));
1660 break;
1661 }
1662
1663 ADD_TO_LARGE_ARRAY(search_state, struct samr_displayentry,
1664 entry, &search_state->entries,
1665 &search_state->num_entries,
1666 &search_state->array_size);
1667 }
1668
1669 endsmbfilepwent(fp, &(smbpasswd_state->pw_file_lock_depth));
1670
1671 search->private_data = search_state;
1672 search->next_entry = smbpasswd_search_next_entry;
1673 search->search_end = smbpasswd_search_end;
1674
1675 return true;
1676}
1677
1678static NTSTATUS pdb_init_smbpasswd( struct pdb_methods **pdb_method, const char *location )
1679{
1680 NTSTATUS nt_status;
1681 struct smbpasswd_privates *privates;
1682
1683 if ( !NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method )) ) {
1684 return nt_status;
1685 }
1686
1687 (*pdb_method)->name = "smbpasswd";
1688
1689 (*pdb_method)->getsampwnam = smbpasswd_getsampwnam;
1690 (*pdb_method)->getsampwsid = smbpasswd_getsampwsid;
1691 (*pdb_method)->add_sam_account = smbpasswd_add_sam_account;
1692 (*pdb_method)->update_sam_account = smbpasswd_update_sam_account;
1693 (*pdb_method)->delete_sam_account = smbpasswd_delete_sam_account;
1694 (*pdb_method)->rename_sam_account = smbpasswd_rename_sam_account;
1695 (*pdb_method)->search_users = smbpasswd_search_users;
1696
1697 (*pdb_method)->rid_algorithm = smbpasswd_rid_algorithm;
1698
1699 /* Setup private data and free function */
1700
1701 if ( !(privates = TALLOC_ZERO_P( *pdb_method, struct smbpasswd_privates )) ) {
1702 DEBUG(0, ("talloc() failed for smbpasswd private_data!\n"));
1703 return NT_STATUS_NO_MEMORY;
1704 }
1705
1706 /* Store some config details */
1707
1708 if (location) {
1709 privates->smbpasswd_file = talloc_strdup(*pdb_method, location);
1710 } else {
1711 privates->smbpasswd_file = talloc_strdup(*pdb_method, lp_smb_passwd_file());
1712 }
1713
1714 if (!privates->smbpasswd_file) {
1715 DEBUG(0, ("talloc_strdp() failed for storing smbpasswd location!\n"));
1716 return NT_STATUS_NO_MEMORY;
1717 }
1718
1719 (*pdb_method)->private_data = privates;
1720
1721 (*pdb_method)->free_private_data = free_private_data;
1722
1723 return NT_STATUS_OK;
1724}
1725
1726NTSTATUS pdb_smbpasswd_init(void)
1727{
1728 return smb_register_passdb(PASSDB_INTERFACE_VERSION, "smbpasswd", pdb_init_smbpasswd);
1729}
Note: See TracBrowser for help on using the repository browser.