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