source: trunk-3.0/source/passdb/pdb_smbpasswd.c@ 101

Last change on this file since 101 was 72, checked in by Paul Smedley, 18 years ago

Fix for smbpasswd -x - addressed part of Ticket #29

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