This is *not* a big change (although it looks like one).
[ira/wip.git] / source3 / passdb / smbpass.c
1 /*
2  * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup
3  * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
4  * 
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License as published by the Free
7  * Software Foundation; either version 2 of the License, or (at your option)
8  * any later version.
9  * 
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  * 
15  * You should have received a copy of the GNU General Public License along with
16  * this program; if not, write to the Free Software Foundation, Inc., 675
17  * Mass Ave, Cambridge, MA 02139, USA.
18  */
19
20 #include "includes.h"
21
22 extern int      DEBUGLEVEL;
23
24 int             gotalarm;
25
26 void 
27 gotalarm_sig()
28 {
29         gotalarm = 1;
30 }
31
32 int 
33 do_pw_lock(int fd, int waitsecs, int type)
34 {
35         struct flock    lock;
36         int             ret;
37
38         gotalarm = 0;
39         signal(SIGALRM, SIGNAL_CAST gotalarm_sig);
40
41         lock.l_type = type;
42         lock.l_whence = SEEK_SET;
43         lock.l_start = 0;
44         lock.l_len = 1;
45         lock.l_pid = 0;
46
47         alarm(5);
48         ret = fcntl(fd, F_SETLKW, &lock);
49         alarm(0);
50         signal(SIGALRM, SIGNAL_CAST SIG_DFL);
51
52         if (gotalarm) {
53                 DEBUG(0, ("do_pw_lock: failed to %s SMB passwd file.\n",
54                           type == F_UNLCK ? "unlock" : "lock"));
55                 return -1;
56         }
57         return ret;
58 }
59
60 int pw_file_lock(char *name, int type, int secs)
61 {
62         int fd = open(name, O_RDWR | O_CREAT, 0600);
63         if (fd < 0)
64                 return (-1);
65         if (do_pw_lock(fd, secs, type)) {
66                 close(fd);
67                 return -1;
68         }
69         return fd;
70 }
71
72 int pw_file_unlock(int fd)
73 {
74         do_pw_lock(fd, 5, F_UNLCK);
75         return close(fd);
76 }
77
78 /*
79  * Routine to get the next 32 hex characters and turn them
80  * into a 16 byte array.
81  */
82
83 static int gethexpwd(char *p, char *pwd)
84 {
85         int i;
86         unsigned char   lonybble, hinybble;
87         char           *hexchars = "0123456789ABCDEF";
88         char           *p1, *p2;
89
90         for (i = 0; i < 32; i += 2) {
91                 hinybble = toupper(p[i]);
92                 lonybble = toupper(p[i + 1]);
93  
94                 p1 = strchr(hexchars, hinybble);
95                 p2 = strchr(hexchars, lonybble);
96                 if (!p1 || !p2)
97                         return (False);
98                 hinybble = PTR_DIFF(p1, hexchars);
99                 lonybble = PTR_DIFF(p2, hexchars);
100  
101                 pwd[i / 2] = (hinybble << 4) | lonybble;
102         }
103         return (True);
104 }
105
106 /*************************************************************************
107  Routine to search the smbpasswd file for an entry matching the username
108  or user id.  if the name is NULL, then the smb_uid is used instead.
109  *************************************************************************/
110 struct smb_passwd *get_smbpwd_entry(char *name, int smb_userid)
111 {
112         /* Static buffers we will return. */
113         static struct smb_passwd pw_buf;
114         static pstring  user_name;
115         static unsigned char smbpwd[16];
116         static unsigned char smbntpwd[16];
117         char            linebuf[256];
118         char            readbuf[16 * 1024];
119         unsigned char   c;
120         unsigned char  *p;
121         long            uidval;
122         long            linebuf_len;
123         FILE           *fp;
124         int             lockfd;
125         char           *pfile = lp_smb_passwd_file();
126
127         if (!*pfile) {
128                 DEBUG(0, ("No SMB password file set\n"));
129                 return (NULL);
130         }
131         DEBUG(10, ("get_smbpwd_entry: opening file %s\n", pfile));
132
133         if (name != NULL)
134         {
135                 DEBUG(10, ("get_smbpwd_entry: search by name: %s\n", name));
136         }
137         else
138         {
139                 DEBUG(10, ("get_smbpwd_entry: search by smb_userid: %x\n", smb_userid));
140         }
141
142         fp = fopen(pfile, "r");
143
144         if (fp == NULL) {
145                 DEBUG(0, ("get_smbpwd_entry: unable to open file %s\n", pfile));
146                 return NULL;
147         }
148         /* Set a 16k buffer to do more efficient reads */
149         setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
150
151         if ((lockfd = pw_file_lock(pfile, F_RDLCK, 5)) < 0) {
152                 DEBUG(0, ("get_smbpwd_entry: unable to lock file %s\n", pfile));
153                 fclose(fp);
154                 return NULL;
155         }
156         /* make sure it is only rw by the owner */
157         chmod(pfile, 0600);
158
159         /* We have a read lock on the file. */
160         /*
161          * Scan the file, a line at a time and check if the name matches.
162          */
163         while (!feof(fp)) {
164                 linebuf[0] = '\0';
165
166                 fgets(linebuf, 256, fp);
167                 if (ferror(fp)) {
168                         fclose(fp);
169                         pw_file_unlock(lockfd);
170                         return NULL;
171                 }
172                 /*
173                  * Check if the string is terminated with a newline - if not
174                  * then we must keep reading and discard until we get one.
175                  */
176                 linebuf_len = strlen(linebuf);
177                 if (linebuf[linebuf_len - 1] != '\n') {
178                         c = '\0';
179                         while (!ferror(fp) && !feof(fp)) {
180                                 c = fgetc(fp);
181                                 if (c == '\n')
182                                         break;
183                         }
184                 } else
185                         linebuf[linebuf_len - 1] = '\0';
186
187 #ifdef DEBUG_PASSWORD
188                 DEBUG(100, ("get_smbpwd_entry: got line |%s|\n", linebuf));
189 #endif
190                 if ((linebuf[0] == 0) && feof(fp)) {
191                         DEBUG(4, ("get_smbpwd_entry: end of file reached\n"));
192                         break;
193                 }
194                 /*
195                  * The line we have should be of the form :-
196                  * 
197                  * username:uid:[32hex bytes]:....other flags presently
198                  * ignored....
199                  * 
200                  * or,
201                  *
202                  * username:uid:[32hex bytes]:[32hex bytes]:....ignored....
203                  *
204                  * if Windows NT compatible passwords are also present.
205                  */
206
207                 if (linebuf[0] == '#' || linebuf[0] == '\0') {
208                         DEBUG(6, ("get_smbpwd_entry: skipping comment or blank line\n"));
209                         continue;
210                 }
211                 p = (unsigned char *) strchr(linebuf, ':');
212                 if (p == NULL) {
213                         DEBUG(0, ("get_smbpwd_entry: malformed password entry (no :)\n"));
214                         continue;
215                 }
216                 /*
217                  * As 256 is shorter than a pstring we don't need to check
218                  * length here - if this ever changes....
219                  */
220                 strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
221                 user_name[PTR_DIFF(p, linebuf)] = '\0';
222
223                 /* get smb uid */
224
225                 p++;            /* Go past ':' */
226                 if (!isdigit(*p)) {
227                         DEBUG(0, ("get_smbpwd_entry: malformed password entry (uid not number)\n"));
228                         fclose(fp);
229                         pw_file_unlock(lockfd);
230                         return NULL;
231                 }
232
233                 uidval = atoi((char *) p);
234
235                 while (*p && isdigit(*p))
236                 {
237                         p++;
238                 }
239
240                 if (*p != ':')
241                 {
242                         DEBUG(0, ("get_smbpwd_entry: malformed password entry (no : after uid)\n"));
243                         fclose(fp);
244                         pw_file_unlock(lockfd);
245                         return NULL;
246                 }
247
248                 if (name != NULL)
249                 {
250                         /* search is by user name */
251                         if (!strequal(user_name, name)) continue;
252                         DEBUG(10, ("get_smbpwd_entry: found by name: %s\n", user_name));
253                 }
254                 else
255                 {
256                         /* search is by user id */
257                         if (uidval != smb_userid) continue;
258                         DEBUG(10, ("get_smbpwd_entry: found by smb_userid: %x\n", uidval));
259                 }
260
261                 /* if we're here, the entry has been found (either by name or uid) */
262
263                 /*
264                  * Now get the password value - this should be 32 hex digits
265                  * which are the ascii representations of a 16 byte string.
266                  * Get two at a time and put them into the password.
267                  */
268
269                 /* skip the ':' */
270                 p++;
271
272                 if (*p == '*' || *p == 'X')
273                 {
274                         /* Password deliberately invalid - end here. */
275                         DEBUG(10, ("get_smbpwd_entry: entry invalidated for user %s\n", user_name));
276                         fclose(fp);
277                         pw_file_unlock(lockfd);
278                         return NULL;
279                 }
280
281                 if (linebuf_len < (PTR_DIFF(p, linebuf) + 33))
282                 {
283                         DEBUG(0, ("get_smbpwd_entry: malformed password entry (passwd too short)\n"));
284                         fclose(fp);
285                         pw_file_unlock(lockfd);
286                         return (False);
287                 }
288
289                 if (p[32] != ':')
290                 {
291                         DEBUG(0, ("get_smbpwd_entry: malformed password entry (no terminating :)\n"));
292                         fclose(fp);
293                         pw_file_unlock(lockfd);
294                         return NULL;
295                 }
296
297                 if (!strncasecmp((char *) p, "NO PASSWORD", 11))
298                 {
299                         pw_buf.smb_passwd = NULL;
300                 }
301                 else
302                 {
303                         if (!gethexpwd((char *)p, (char *)smbpwd))
304                         {
305                                 DEBUG(0, ("Malformed Lanman password entry (non hex chars)\n"));
306                                 fclose(fp);
307                                 pw_file_unlock(lockfd);
308                                 return NULL;
309                         }
310                         pw_buf.smb_passwd = smbpwd;
311                 }
312
313                 pw_buf.smb_name = user_name;
314                 pw_buf.smb_userid = uidval;
315                 pw_buf.smb_nt_passwd = NULL;
316
317                 /* Now check if the NT compatible password is
318                         available. */
319                 p += 33; /* Move to the first character of the line after
320                                         the lanman password. */
321                 if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
322                         if (*p != '*' && *p != 'X') {
323                                 if(gethexpwd((char *)p,(char *)smbntpwd))
324                                         pw_buf.smb_nt_passwd = smbntpwd;
325                         }
326                 }
327
328                 fclose(fp);
329                 pw_file_unlock(lockfd);
330                 DEBUG(5, ("get_smbpwd_entrye: returning passwd entry for user %s, uid %d\n",
331                           user_name, uidval));
332                 return &pw_buf;
333         }
334
335         fclose(fp);
336         pw_file_unlock(lockfd);
337         return NULL;
338 }
339
340 /*
341  * Routine to search the smbpasswd file for an entry matching the username.
342  */
343 BOOL add_smbpwd_entry(struct smb_passwd* pwd)
344 {
345         /* Static buffers we will return. */
346         static pstring  user_name;
347
348         char            linebuf[256];
349         char            readbuf[16 * 1024];
350         unsigned char   c;
351         unsigned char  *p;
352         long            linebuf_len;
353         FILE           *fp;
354         int             lockfd;
355         char           *pfile = lp_smb_passwd_file();
356
357         int i;
358         int wr_len;
359
360         int fd;
361         int new_entry_length;
362         char *new_entry;
363         long offpos;
364
365         if (!*pfile)
366         {
367                 DEBUG(0, ("No SMB password file set\n"));
368                 return False;
369         }
370         DEBUG(10, ("add_smbpwd_entry: opening file %s\n", pfile));
371
372         fp = fopen(pfile, "r+");
373
374         if (fp == NULL)
375         {
376                 DEBUG(0, ("add_smbpwd_entry: unable to open file %s\n", pfile));
377                 return False;
378         }
379         /* Set a 16k buffer to do more efficient reads */
380         setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
381
382         if ((lockfd = pw_file_lock(pfile, F_RDLCK | F_WRLCK, 5)) < 0)
383         {
384                 DEBUG(0, ("add_smbpwd_entry: unable to lock file %s\n", pfile));
385                 fclose(fp);
386                 return False;
387         }
388         /* make sure it is only rw by the owner */
389         chmod(pfile, 0600);
390
391         /* We have a write lock on the file. */
392         /*
393         * Scan the file, a line at a time and check if the name matches.
394         */
395         while (!feof(fp))
396         {
397                 linebuf[0] = '\0';
398
399                 fgets(linebuf, 256, fp);
400                 if (ferror(fp))
401                 {
402                         fclose(fp);
403                         pw_file_unlock(lockfd);
404                         return False;
405                 }
406
407                 /*
408                  * Check if the string is terminated with a newline - if not
409                  * then we must keep reading and discard until we get one.
410                  */
411                 linebuf_len = strlen(linebuf);
412                 if (linebuf[linebuf_len - 1] != '\n')
413                 {
414                         c = '\0';
415                         while (!ferror(fp) && !feof(fp))
416                         {
417                                 c = fgetc(fp);
418                                 if (c == '\n')
419                                 {
420                                         break;
421                                 }
422                         }
423                 }
424                 else
425                 {
426                         linebuf[linebuf_len - 1] = '\0';
427                 }
428
429 #ifdef DEBUG_PASSWORD
430                 DEBUG(100, ("add_smbpwd_entry: got line |%s|\n", linebuf));
431 #endif
432
433                 if ((linebuf[0] == 0) && feof(fp))
434                 {
435                         DEBUG(4, ("add_smbpwd_entry: end of file reached\n"));
436                         break;
437                 }
438
439                 /*
440                 * The line we have should be of the form :-
441                 * 
442                 * username:uid:[32hex bytes]:....other flags presently
443                 * ignored....
444                 * 
445                 * or,
446                 *
447                 * username:uid:[32hex bytes]:[32hex bytes]:....ignored....
448                 *
449                 * if Windows NT compatible passwords are also present.
450                 */
451
452                 if (linebuf[0] == '#' || linebuf[0] == '\0')
453                 {
454                         DEBUG(6, ("add_smbpwd_entry: skipping comment or blank line\n"));
455                         continue;
456                 }
457
458                 p = (unsigned char *) strchr(linebuf, ':');
459
460                 if (p == NULL)
461                 {
462                         DEBUG(0, ("add_smbpwd_entry: malformed password entry (no :)\n"));
463                         continue;
464                 }
465
466                 /*
467                  * As 256 is shorter than a pstring we don't need to check
468                  * length here - if this ever changes....
469                  */
470                 strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
471                 user_name[PTR_DIFF(p, linebuf)] = '\0';
472                 if (strequal(user_name, pwd->smb_name))
473                 {
474                         DEBUG(6, ("add_smbpwd_entry: entry already exists\n"));
475                         return False;
476                 }
477         }
478
479         /* ok - entry doesn't exist.  we can add it */
480
481         /* Create a new smb passwd entry and set it to the given password. */
482         /* The add user write needs to be atomic - so get the fd from 
483            the fp and do a raw write() call.
484          */
485         fd = fileno(fp);
486
487         if((offpos = lseek(fd, 0, SEEK_END)) == -1)
488         {
489                 DEBUG(0, ("add_smbpwd_entry(lseek): Failed to add entry for user %s to file %s. \
490 Error was %s\n", pwd->smb_name, pfile, strerror(errno)));
491
492                 fclose(fp);
493                 pw_file_unlock(lockfd);
494                 return False;
495         }
496
497         new_entry_length = strlen(pwd->smb_name) + 1 + 15 + 1 + 32 + 1 + 32 + 1 + 2;
498
499         if((new_entry = (char *)malloc( new_entry_length )) == 0)
500         {
501                 DEBUG(0, ("add_smbpwd_entry(malloc): Failed to add entry for user %s to file %s. \
502 Error was %s\n", 
503                 pwd->smb_name, pfile, strerror(errno)));
504
505                 fclose(fp);
506                 pw_file_unlock(lockfd);
507                 return False;
508         }
509
510         sprintf(new_entry, "%s:%u:", pwd->smb_name, (unsigned)pwd->smb_userid);
511         p = (unsigned char *)&new_entry[strlen(new_entry)];
512
513         for( i = 0; i < 16; i++)
514         {
515                 sprintf((char *)&p[i*2], "%02X", pwd->smb_passwd[i]);
516         }
517         p += 32;
518
519         *p++ = ':';
520
521         for( i = 0; i < 16; i++)
522         {
523                 sprintf((char *)&p[i*2], "%02X", pwd->smb_nt_passwd[i]);
524         }
525         p += 32;
526
527         *p++ = ':';
528         sprintf((char *)p,"\n");
529
530 #ifdef DEBUG_PASSWORD
531                 DEBUG(100, ("add_smbpwd_entry(%d): new_entry_len %d entry_len %d made line |%s|\n", 
532                              fd, new_entry_length, strlen(new_entry), new_entry));
533 #endif
534
535         if ((wr_len = write(fd, new_entry, strlen(new_entry))) != strlen(new_entry))
536         {
537                 DEBUG(0, ("add_smbpwd_entry(write): %d Failed to add entry for user %s to file %s. \
538 Error was %s\n", wr_len, pwd->smb_name, pfile, strerror(errno)));
539
540                 /* Remove the entry we just wrote. */
541                 if(ftruncate(fd, offpos) == -1)
542                 {
543                         DEBUG(0, ("add_smbpwd_entry: ERROR failed to ftruncate file %s. \
544 Error was %s. Password file may be corrupt ! Please examine by hand !\n", 
545                         pwd->smb_name, strerror(errno)));
546                 }
547
548                 fclose(fp);
549                 pw_file_unlock(lockfd);
550                 return False;
551         }
552
553         fclose(fp);
554         pw_file_unlock(lockfd);
555         return True;
556 }
557 /*
558  * Routine to search the smbpasswd file for an entry matching the username.
559  * and then modify its password entry
560  */
561 BOOL mod_smbpwd_entry(struct smb_passwd* pwd)
562 {
563         /* Static buffers we will return. */
564         static pstring  user_name;
565
566         char            linebuf[256];
567         char            readbuf[16 * 1024];
568         unsigned char   c;
569         char            ascii_p16[66];
570         unsigned char  *p = NULL;
571         long            linebuf_len = 0;
572         FILE           *fp;
573         int             lockfd;
574         char           *pfile = lp_smb_passwd_file();
575         BOOL found_entry = False;
576
577         long pwd_seekpos = 0;
578
579         int i;
580         int wr_len;
581         int fd;
582
583         if (!*pfile)
584         {
585                 DEBUG(0, ("No SMB password file set\n"));
586                 return False;
587         }
588         DEBUG(10, ("mod_smbpwd_entry: opening file %s\n", pfile));
589
590         fp = fopen(pfile, "r+");
591
592         if (fp == NULL)
593         {
594                 DEBUG(0, ("mod_smbpwd_entry: unable to open file %s\n", pfile));
595                 return False;
596         }
597         /* Set a 16k buffer to do more efficient reads */
598         setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
599
600         if ((lockfd = pw_file_lock(pfile, F_RDLCK | F_WRLCK, 5)) < 0)
601         {
602                 DEBUG(0, ("mod_smbpwd_entry: unable to lock file %s\n", pfile));
603                 fclose(fp);
604                 return False;
605         }
606         /* make sure it is only rw by the owner */
607         chmod(pfile, 0600);
608
609         /* We have a write lock on the file. */
610         /*
611         * Scan the file, a line at a time and check if the name matches.
612         */
613         while (!feof(fp))
614         {
615                 pwd_seekpos = ftell(fp);
616
617                 linebuf[0] = '\0';
618
619                 fgets(linebuf, 256, fp);
620                 if (ferror(fp))
621                 {
622                         fclose(fp);
623                         pw_file_unlock(lockfd);
624                         return False;
625                 }
626
627                 /*
628                  * Check if the string is terminated with a newline - if not
629                  * then we must keep reading and discard until we get one.
630                  */
631                 linebuf_len = strlen(linebuf);
632                 if (linebuf[linebuf_len - 1] != '\n')
633                 {
634                         c = '\0';
635                         while (!ferror(fp) && !feof(fp))
636                         {
637                                 c = fgetc(fp);
638                                 if (c == '\n')
639                                 {
640                                         break;
641                                 }
642                         }
643                 }
644                 else
645                 {
646                         linebuf[linebuf_len - 1] = '\0';
647                 }
648
649 #ifdef DEBUG_PASSWORD
650                 DEBUG(100, ("mod_smbpwd_entry: got line |%s|\n", linebuf));
651 #endif
652
653                 if ((linebuf[0] == 0) && feof(fp))
654                 {
655                         DEBUG(4, ("mod_smbpwd_entry: end of file reached\n"));
656                         break;
657                 }
658
659                 /*
660                 * The line we have should be of the form :-
661                 * 
662                 * username:uid:[32hex bytes]:....other flags presently
663                 * ignored....
664                 * 
665                 * or,
666                 *
667                 * username:uid:[32hex bytes]:[32hex bytes]:....ignored....
668                 *
669                 * if Windows NT compatible passwords are also present.
670                 */
671
672                 if (linebuf[0] == '#' || linebuf[0] == '\0')
673                 {
674                         DEBUG(6, ("mod_smbpwd_entry: skipping comment or blank line\n"));
675                         continue;
676                 }
677
678                 p = (unsigned char *) strchr(linebuf, ':');
679
680                 if (p == NULL)
681                 {
682                         DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no :)\n"));
683                         continue;
684                 }
685
686                 /*
687                  * As 256 is shorter than a pstring we don't need to check
688                  * length here - if this ever changes....
689                  */
690                 strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
691                 user_name[PTR_DIFF(p, linebuf)] = '\0';
692                 if (strequal(user_name, pwd->smb_name))
693                 {
694                         found_entry = True;
695                         break;
696                 }
697         }
698
699         if (!found_entry) return False;
700
701         DEBUG(6, ("mod_smbpwd_entry: entry exists\n"));
702
703         /* User name matches - get uid and password */
704         p++;            /* Go past ':' */
705
706         if (!isdigit(*p))
707         {
708                 DEBUG(0, ("mod_smbpwd_entry: malformed password entry (uid not number)\n"));
709                 fclose(fp);
710                 pw_file_unlock(lockfd);
711                 return False;
712         }
713
714         while (*p && isdigit(*p))
715                 p++;
716         if (*p != ':')
717         {
718                 DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no : after uid)\n"));
719                 fclose(fp);
720                 pw_file_unlock(lockfd);
721                 return False;
722         }
723         /*
724          * Now get the password value - this should be 32 hex digits
725          * which are the ascii representations of a 16 byte string.
726          * Get two at a time and put them into the password.
727          */
728         p++;
729
730         /* record exact password position */
731         pwd_seekpos += PTR_DIFF(p, linebuf);
732
733         if (*p == '*' || *p == 'X')
734         {
735                 /* Password deliberately invalid - end here. */
736                 DEBUG(10, ("get_smbpwd_entry: entry invalidated for user %s\n", user_name));
737                 fclose(fp);
738                 pw_file_unlock(lockfd);
739                 return False;
740         }
741
742         if (linebuf_len < (PTR_DIFF(p, linebuf) + 33))
743         {
744                 DEBUG(0, ("mod_smbpwd_entry: malformed password entry (passwd too short)\n"));
745                 fclose(fp);
746                 pw_file_unlock(lockfd);
747                 return (False);
748         }
749
750         if (p[32] != ':')
751         {
752                 DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no terminating :)\n"));
753                 fclose(fp);
754                 pw_file_unlock(lockfd);
755                 return False;
756         }
757
758         if (*p == '*' || *p == 'X')
759         {
760                 fclose(fp);
761                 pw_file_unlock(lockfd);
762                 return False;
763         }
764         if (!strncasecmp((char *) p, "NO PASSWORD", 11))
765         {
766                 fclose(fp);
767                 pw_file_unlock(lockfd);
768                 return False;
769         }
770
771         /* Now check if the NT compatible password is
772                 available. */
773         p += 33; /* Move to the first character of the line after
774                                 the lanman password. */
775         if (linebuf_len < (PTR_DIFF(p, linebuf) + 33))
776         {
777                 DEBUG(0, ("mod_smbpwd_entry: malformed password entry (passwd too short)\n"));
778                 fclose(fp);
779                 pw_file_unlock(lockfd);
780                 return (False);
781         }
782
783         if (p[32] != ':')
784         {
785                 DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no terminating :)\n"));
786                 fclose(fp);
787                 pw_file_unlock(lockfd);
788                 return False;
789         }
790
791         /* The following check is wrong - the NT hash is optional. */
792 #if 0
793         if (*p == '*' || *p == 'X')
794         {
795                 fclose(fp);
796                 pw_file_unlock(lockfd);
797                 return False;
798         }
799 #endif
800
801         /* whew.  entry is correctly formed. */
802
803         /*
804          * Do an atomic write into the file at the position defined by
805          * seekpos.
806          */
807
808         /* The mod user write needs to be atomic - so get the fd from 
809            the fp and do a raw write() call.
810          */
811
812         fd = fileno(fp);
813
814         if (lseek(fd, pwd_seekpos - 1, SEEK_SET) != pwd_seekpos - 1)
815         {
816                 DEBUG(1, ("mod_smbpwd_entry: seek fail on file %s.\n", pfile));
817                         fclose(fp);
818                         pw_file_unlock(lockfd);
819                         return False;
820         }
821
822         /* Sanity check - ensure the character is a ':' */
823         if (read(fd, &c, 1) != 1)
824         {
825                 DEBUG(1, ("mod_smbpwd_entry: read fail on file %s.\n", pfile));
826                 fclose(fp);
827                 pw_file_unlock(lockfd);
828                 return False;
829         }
830
831         if (c != ':')
832         {
833                 DEBUG(1, ("mod_smbpwd_entry: check on passwd file %s failed.\n", pfile));
834                 fclose(fp);
835                 pw_file_unlock(lockfd);
836                 return False;
837         }
838  
839         /* Create the 32 byte representation of the new p16 */
840         for (i = 0; i < 16; i++)
841         {
842                 sprintf(&ascii_p16[i*2], "%02X", (uchar) pwd->smb_passwd[i]);
843         }
844         /* Add on the NT md4 hash */
845         ascii_p16[32] = ':';
846         wr_len = 65;
847         if (pwd->smb_nt_passwd != NULL)
848         {
849                 for (i = 0; i < 16; i++)
850                 {
851                         sprintf(&ascii_p16[(i*2)+33], "%02X", (uchar) pwd->smb_nt_passwd[i]);
852                 }
853         }
854         else    
855         {
856                 /* No NT hash - write out an 'invalid' string. */
857                 strcpy(&ascii_p16[33], "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
858         }
859
860 #ifdef DEBUG_PASSWORD
861         DEBUG(100,("mod_smbpwd_entry: "));
862         dump_data(100, ascii_p16, wr_len);
863 #endif
864
865         if (write(fd, ascii_p16, wr_len) != wr_len)
866         {
867                 DEBUG(1, ("mod_smbpwd_entry: write failed in passwd file %s\n", pfile));
868                 fclose(fp);
869                 pw_file_unlock(lockfd);
870                 return False;
871         }
872
873         fclose(fp);
874         pw_file_unlock(lockfd);
875         return True;
876 }