source: branches/samba-3.5.x/source3/passdb/pdb_smbpasswd.c

Last change on this file was 596, checked in by Herwig Bauernfeind, 14 years ago

Samba 3.5: Update trunk to 3.5.8

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