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