home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Divers / samba-1.9.18p7.tar.gz / samba-1.9.18p7.tar / samba-1.9.18p7 / source / smbpass.c < prev    next >
C/C++ Source or Header  |  1998-05-12  |  21KB  |  881 lines

  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(void)
  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.         pw_buf.acct_ctrl = ACB_NORMAL;
  128.         pw_buf.smb_passwd = NULL;
  129.         pw_buf.smb_nt_passwd = NULL;
  130.  
  131.     if (!*pfile) {
  132.         DEBUG(0, ("No SMB password file set\n"));
  133.         return (NULL);
  134.     }
  135.     DEBUG(10, ("get_smbpwd_entry: opening file %s\n", pfile));
  136.  
  137.     if (name != NULL)
  138.     {
  139.         DEBUG(10, ("get_smbpwd_entry: search by name: %s\n", name));
  140.     }
  141.     else
  142.     {
  143.         DEBUG(10, ("get_smbpwd_entry: search by smb_userid: %x\n", smb_userid));
  144.     }
  145.  
  146.     fp = fopen(pfile, "r");
  147.  
  148.     if (fp == NULL) {
  149.         DEBUG(0, ("get_smbpwd_entry: unable to open file %s\n", pfile));
  150.         return NULL;
  151.     }
  152.     /* Set a 16k buffer to do more efficient reads */
  153.     setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
  154.  
  155.     if ((lockfd = pw_file_lock(pfile, F_RDLCK, 5)) < 0) {
  156.         DEBUG(0, ("get_smbpwd_entry: unable to lock file %s\n", pfile));
  157.         fclose(fp);
  158.         return NULL;
  159.     }
  160.     /* make sure it is only rw by the owner */
  161.     chmod(pfile, 0600);
  162.  
  163.     /* We have a read lock on the file. */
  164.     /*
  165.      * Scan the file, a line at a time and check if the name matches.
  166.      */
  167.     while (!feof(fp)) {
  168.         linebuf[0] = '\0';
  169.  
  170.         fgets(linebuf, 256, fp);
  171.         if (ferror(fp)) {
  172.             fclose(fp);
  173.             pw_file_unlock(lockfd);
  174.             return NULL;
  175.         }
  176.         /*
  177.          * Check if the string is terminated with a newline - if not
  178.          * then we must keep reading and discard until we get one.
  179.          */
  180.         linebuf_len = strlen(linebuf);
  181.         if (linebuf[linebuf_len - 1] != '\n') {
  182.             c = '\0';
  183.             while (!ferror(fp) && !feof(fp)) {
  184.                 c = fgetc(fp);
  185.                 if (c == '\n')
  186.                     break;
  187.             }
  188.         } else
  189.             linebuf[linebuf_len - 1] = '\0';
  190.  
  191. #ifdef DEBUG_PASSWORD
  192.         DEBUG(100, ("get_smbpwd_entry: got line |%s|\n", linebuf));
  193. #endif
  194.         if ((linebuf[0] == 0) && feof(fp)) {
  195.             DEBUG(4, ("get_smbpwd_entry: end of file reached\n"));
  196.             break;
  197.         }
  198.         /*
  199.          * The line we have should be of the form :-
  200.          * 
  201.          * username:uid:[32hex bytes]:....other flags presently
  202.          * ignored....
  203.          * 
  204.          * or,
  205.          *
  206.          * username:uid:[32hex bytes]:[32hex bytes]:....ignored....
  207.          *
  208.          * if Windows NT compatible passwords are also present.
  209.          */
  210.  
  211.         if (linebuf[0] == '#' || linebuf[0] == '\0') {
  212.             DEBUG(6, ("get_smbpwd_entry: skipping comment or blank line\n"));
  213.             continue;
  214.         }
  215.         p = (unsigned char *) strchr(linebuf, ':');
  216.         if (p == NULL) {
  217.             DEBUG(0, ("get_smbpwd_entry: malformed password entry (no :)\n"));
  218.             continue;
  219.         }
  220.         /*
  221.          * As 256 is shorter than a pstring we don't need to check
  222.          * length here - if this ever changes....
  223.          */
  224.         strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
  225.         user_name[PTR_DIFF(p, linebuf)] = '\0';
  226.  
  227.         /* get smb uid */
  228.  
  229.         p++;        /* Go past ':' */
  230.         if (!isdigit(*p)) {
  231.             DEBUG(0, ("get_smbpwd_entry: malformed password entry (uid not number)\n"));
  232.             continue;
  233.         }
  234.  
  235.         uidval = atoi((char *) p);
  236.  
  237.         while (*p && isdigit(*p))
  238.         {
  239.             p++;
  240.         }
  241.  
  242.         if (*p != ':')
  243.         {
  244.             DEBUG(0, ("get_smbpwd_entry: malformed password entry (no : after uid)\n"));
  245.             continue;
  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.                          * We set this so that the caller can tell
  302.                          * that there was no old password.
  303.                          */
  304.                         pw_buf.acct_ctrl |= ACB_PWNOTREQ;
  305.         }
  306.         else
  307.         {
  308.             if (!gethexpwd((char *)p, (char *)smbpwd))
  309.             {
  310.                 DEBUG(0, ("Malformed Lanman password entry (non hex chars)\n"));
  311.                 fclose(fp);
  312.                 pw_file_unlock(lockfd);
  313.                 return NULL;
  314.             }
  315.             pw_buf.smb_passwd = smbpwd;
  316.         }
  317.  
  318.         pw_buf.smb_name = user_name;
  319.         pw_buf.smb_userid = uidval;
  320.         pw_buf.smb_nt_passwd = NULL;
  321.  
  322.         /* Now check if the NT compatible password is
  323.             available. */
  324.         p += 33; /* Move to the first character of the line after
  325.                     the lanman password. */
  326.         if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
  327.             if (*p != '*' && *p != 'X') {
  328.                 if(gethexpwd((char *)p,(char *)smbntpwd))
  329.                     pw_buf.smb_nt_passwd = smbntpwd;
  330.             }
  331.         }
  332.  
  333.         fclose(fp);
  334.         pw_file_unlock(lockfd);
  335.         DEBUG(5, ("get_smbpwd_entry: returning passwd entry for user %s, uid %d\n",
  336.               user_name, uidval));
  337.         return &pw_buf;
  338.     }
  339.  
  340.     fclose(fp);
  341.     pw_file_unlock(lockfd);
  342.     return NULL;
  343. }
  344.  
  345. /*
  346.  * Routine to search the smbpasswd file for an entry matching the username.
  347.  */
  348. BOOL add_smbpwd_entry(struct smb_passwd* pwd)
  349. {
  350.     /* Static buffers we will return. */
  351.     static pstring  user_name;
  352.  
  353.     char            linebuf[256];
  354.     char            readbuf[16 * 1024];
  355.     unsigned char   c;
  356.     unsigned char  *p;
  357.     long            linebuf_len;
  358.     FILE           *fp;
  359.     int             lockfd;
  360.     char           *pfile = lp_smb_passwd_file();
  361.  
  362.     int i;
  363.     int wr_len;
  364.  
  365.     int fd;
  366.     int new_entry_length;
  367.     uchar *new_entry;
  368.     long offpos;
  369.  
  370.     if (!*pfile)
  371.     {
  372.         DEBUG(0, ("No SMB password file set\n"));
  373.         return False;
  374.     }
  375.     DEBUG(10, ("add_smbpwd_entry: opening file %s\n", pfile));
  376.  
  377.     fp = fopen(pfile, "r+");
  378.  
  379.     if (fp == NULL)
  380.     {
  381.         DEBUG(0, ("add_smbpwd_entry: unable to open file %s\n", pfile));
  382.         return False;
  383.     }
  384.     /* Set a 16k buffer to do more efficient reads */
  385.     setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
  386.  
  387.     if ((lockfd = pw_file_lock(pfile, F_WRLCK, 5)) < 0)
  388.     {
  389.         DEBUG(0, ("add_smbpwd_entry: unable to lock file %s\n", pfile));
  390.         fclose(fp);
  391.         return False;
  392.     }
  393.     /* make sure it is only rw by the owner */
  394.     chmod(pfile, 0600);
  395.  
  396.     /* We have a write lock on the file. */
  397.     /*
  398.     * Scan the file, a line at a time and check if the name matches.
  399.     */
  400.     while (!feof(fp))
  401.     {
  402.         linebuf[0] = '\0';
  403.  
  404.         fgets(linebuf, 256, fp);
  405.         if (ferror(fp))
  406.         {
  407.             fclose(fp);
  408.             pw_file_unlock(lockfd);
  409.             return False;
  410.         }
  411.  
  412.         /*
  413.          * Check if the string is terminated with a newline - if not
  414.          * then we must keep reading and discard until we get one.
  415.          */
  416.         linebuf_len = strlen(linebuf);
  417.         if (linebuf[linebuf_len - 1] != '\n')
  418.         {
  419.             c = '\0';
  420.             while (!ferror(fp) && !feof(fp))
  421.             {
  422.                 c = fgetc(fp);
  423.                 if (c == '\n')
  424.                 {
  425.                     break;
  426.                 }
  427.             }
  428.         }
  429.         else
  430.         {
  431.             linebuf[linebuf_len - 1] = '\0';
  432.         }
  433.  
  434. #ifdef DEBUG_PASSWORD
  435.         DEBUG(100, ("add_smbpwd_entry: got line |%s|\n", linebuf));
  436. #endif
  437.  
  438.         if ((linebuf[0] == 0) && feof(fp))
  439.         {
  440.             DEBUG(4, ("add_smbpwd_entry: end of file reached\n"));
  441.             break;
  442.         }
  443.  
  444.         /*
  445.         * The line we have should be of the form :-
  446.         * 
  447.         * username:uid:[32hex bytes]:....other flags presently
  448.         * ignored....
  449.         * 
  450.         * or,
  451.         *
  452.         * username:uid:[32hex bytes]:[32hex bytes]:....ignored....
  453.         *
  454.         * if Windows NT compatible passwords are also present.
  455.         */
  456.  
  457.         if (linebuf[0] == '#' || linebuf[0] == '\0')
  458.         {
  459.             DEBUG(6, ("add_smbpwd_entry: skipping comment or blank line\n"));
  460.             continue;
  461.         }
  462.  
  463.         p = (unsigned char *) strchr(linebuf, ':');
  464.  
  465.         if (p == NULL)
  466.         {
  467.             DEBUG(0, ("add_smbpwd_entry: malformed password entry (no :)\n"));
  468.             continue;
  469.         }
  470.  
  471.         /*
  472.          * As 256 is shorter than a pstring we don't need to check
  473.          * length here - if this ever changes....
  474.          */
  475.         strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
  476.         user_name[PTR_DIFF(p, linebuf)] = '\0';
  477.         if (strequal(user_name, pwd->smb_name))
  478.         {
  479.             DEBUG(6, ("add_smbpwd_entry: entry already exists\n"));
  480.             return False;
  481.         }
  482.     }
  483.  
  484.     /* ok - entry doesn't exist.  we can add it */
  485.  
  486.     /* Create a new smb passwd entry and set it to the given password. */
  487.     /* The add user write needs to be atomic - so get the fd from 
  488.        the fp and do a raw write() call.
  489.      */
  490.     fd = fileno(fp);
  491.  
  492.     if((offpos = lseek(fd, 0, SEEK_END)) == -1)
  493.     {
  494.         DEBUG(0, ("add_smbpwd_entry(lseek): Failed to add entry for user %s to file %s. \
  495. Error was %s\n", pwd->smb_name, pfile, strerror(errno)));
  496.  
  497.         fclose(fp);
  498.         pw_file_unlock(lockfd);
  499.         return False;
  500.     }
  501.  
  502.     new_entry_length = strlen(pwd->smb_name) + 1 + 15 + 1 + 32 + 1 + 32 + 1 + 2;
  503.  
  504.     if((new_entry = (uchar *)malloc( new_entry_length )) == 0)
  505.     {
  506.         DEBUG(0, ("add_smbpwd_entry(malloc): Failed to add entry for user %s to file %s. \
  507. Error was %s\n", 
  508.         pwd->smb_name, pfile, strerror(errno)));
  509.  
  510.         fclose(fp);
  511.         pw_file_unlock(lockfd);
  512.         return False;
  513.     }
  514.  
  515.     slprintf((char *)new_entry, new_entry_length - 1, "%s:%u:", pwd->smb_name, (unsigned)pwd->smb_userid);
  516.     p = (unsigned char *)&new_entry[strlen((char *)new_entry)];
  517.  
  518.     for( i = 0; i < 16; i++)
  519.     {
  520.         slprintf((char *)&p[i*2], new_entry_length - (p - new_entry) - 1,"%02X", pwd->smb_passwd[i]);
  521.     }
  522.     p += 32;
  523.  
  524.     *p++ = ':';
  525.  
  526.     for( i = 0; i < 16; i++)
  527.     {
  528.         slprintf((char *)&p[i*2], new_entry_length - (p - new_entry) - 1, "%02X", pwd->smb_nt_passwd[i]);
  529.     }
  530.     p += 32;
  531.  
  532.     *p++ = ':';
  533.     slprintf((char *)p, new_entry_length - (p - new_entry) - 1, "\n");
  534.  
  535. #ifdef DEBUG_PASSWORD
  536.         DEBUG(100, ("add_smbpwd_entry(%d): new_entry_len %d entry_len %d made line |%s|\n", 
  537.                      fd, new_entry_length, strlen(new_entry), new_entry));
  538. #endif
  539.  
  540.     if ((wr_len = write(fd, new_entry, strlen((char *)new_entry))) != strlen((char *)new_entry))
  541.     {
  542.         DEBUG(0, ("add_smbpwd_entry(write): %d Failed to add entry for user %s to file %s. \
  543. Error was %s\n", wr_len, pwd->smb_name, pfile, strerror(errno)));
  544.  
  545.         /* Remove the entry we just wrote. */
  546.         if(ftruncate(fd, offpos) == -1)
  547.         {
  548.             DEBUG(0, ("add_smbpwd_entry: ERROR failed to ftruncate file %s. \
  549. Error was %s. Password file may be corrupt ! Please examine by hand !\n", 
  550.             pwd->smb_name, strerror(errno)));
  551.         }
  552.  
  553.         fclose(fp);
  554.         pw_file_unlock(lockfd);
  555.         return False;
  556.     }
  557.  
  558.     fclose(fp);
  559.     pw_file_unlock(lockfd);
  560.     return True;
  561. }
  562. /*
  563.  * Routine to search the smbpasswd file for an entry matching the username.
  564.  * and then modify its password entry
  565.  * override = 0, normal
  566.  * override = 1, don't care about XXXXXXXX'd out password or NO PASS
  567.  */
  568.  
  569. BOOL mod_smbpwd_entry(struct smb_passwd* pwd, BOOL override)
  570. {
  571.     /* Static buffers we will return. */
  572.     static pstring  user_name;
  573.  
  574.     char            linebuf[256];
  575.     char            readbuf[16 * 1024];
  576.     unsigned char   c;
  577.     char            ascii_p16[66];
  578.     unsigned char  *p = NULL;
  579.     long            linebuf_len = 0;
  580.     FILE           *fp;
  581.     int             lockfd;
  582.     char           *pfile = lp_smb_passwd_file();
  583.     BOOL found_entry = False;
  584.  
  585.     long pwd_seekpos = 0;
  586.  
  587.     int i;
  588.     int wr_len;
  589.     int fd;
  590.  
  591.     if (!*pfile)
  592.     {
  593.         DEBUG(0, ("No SMB password file set\n"));
  594.         return False;
  595.     }
  596.     DEBUG(10, ("mod_smbpwd_entry: opening file %s\n", pfile));
  597.  
  598.     fp = fopen(pfile, "r+");
  599.  
  600.     if (fp == NULL)
  601.     {
  602.         DEBUG(0, ("mod_smbpwd_entry: unable to open file %s\n", pfile));
  603.         return False;
  604.     }
  605.     /* Set a 16k buffer to do more efficient reads */
  606.     setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
  607.  
  608.     if ((lockfd = pw_file_lock(pfile, F_WRLCK, 5)) < 0)
  609.     {
  610.         DEBUG(0, ("mod_smbpwd_entry: unable to lock file %s\n", pfile));
  611.         fclose(fp);
  612.         return False;
  613.     }
  614.     /* make sure it is only rw by the owner */
  615.     chmod(pfile, 0600);
  616.  
  617.     /* We have a write lock on the file. */
  618.     /*
  619.     * Scan the file, a line at a time and check if the name matches.
  620.     */
  621.     while (!feof(fp))
  622.     {
  623.         pwd_seekpos = ftell(fp);
  624.  
  625.         linebuf[0] = '\0';
  626.  
  627.         fgets(linebuf, 256, fp);
  628.         if (ferror(fp))
  629.         {
  630.             fclose(fp);
  631.             pw_file_unlock(lockfd);
  632.             return False;
  633.         }
  634.  
  635.         /*
  636.          * Check if the string is terminated with a newline - if not
  637.          * then we must keep reading and discard until we get one.
  638.          */
  639.         linebuf_len = strlen(linebuf);
  640.         if (linebuf[linebuf_len - 1] != '\n')
  641.         {
  642.             c = '\0';
  643.             while (!ferror(fp) && !feof(fp))
  644.             {
  645.                 c = fgetc(fp);
  646.                 if (c == '\n')
  647.                 {
  648.                     break;
  649.                 }
  650.             }
  651.         }
  652.         else
  653.         {
  654.             linebuf[linebuf_len - 1] = '\0';
  655.         }
  656.  
  657. #ifdef DEBUG_PASSWORD
  658.         DEBUG(100, ("mod_smbpwd_entry: got line |%s|\n", linebuf));
  659. #endif
  660.  
  661.         if ((linebuf[0] == 0) && feof(fp))
  662.         {
  663.             DEBUG(4, ("mod_smbpwd_entry: end of file reached\n"));
  664.             break;
  665.         }
  666.  
  667.         /*
  668.         * The line we have should be of the form :-
  669.         * 
  670.         * username:uid:[32hex bytes]:....other flags presently
  671.         * ignored....
  672.         * 
  673.         * or,
  674.         *
  675.         * username:uid:[32hex bytes]:[32hex bytes]:....ignored....
  676.         *
  677.         * if Windows NT compatible passwords are also present.
  678.         */
  679.  
  680.         if (linebuf[0] == '#' || linebuf[0] == '\0')
  681.         {
  682.             DEBUG(6, ("mod_smbpwd_entry: skipping comment or blank line\n"));
  683.             continue;
  684.         }
  685.  
  686.         p = (unsigned char *) strchr(linebuf, ':');
  687.  
  688.         if (p == NULL)
  689.         {
  690.             DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no :)\n"));
  691.             continue;
  692.         }
  693.  
  694.         /*
  695.          * As 256 is shorter than a pstring we don't need to check
  696.          * length here - if this ever changes....
  697.          */
  698.         strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
  699.         user_name[PTR_DIFF(p, linebuf)] = '\0';
  700.         if (strequal(user_name, pwd->smb_name))
  701.         {
  702.             found_entry = True;
  703.             break;
  704.         }
  705.     }
  706.  
  707.     if (!found_entry) return False;
  708.  
  709.     DEBUG(6, ("mod_smbpwd_entry: entry exists\n"));
  710.  
  711.     /* User name matches - get uid and password */
  712.     p++;        /* Go past ':' */
  713.  
  714.     if (!isdigit(*p))
  715.     {
  716.         DEBUG(0, ("mod_smbpwd_entry: malformed password entry (uid not number)\n"));
  717.         fclose(fp);
  718.         pw_file_unlock(lockfd);
  719.         return False;
  720.     }
  721.  
  722.     while (*p && isdigit(*p))
  723.         p++;
  724.     if (*p != ':')
  725.     {
  726.         DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no : after uid)\n"));
  727.         fclose(fp);
  728.         pw_file_unlock(lockfd);
  729.         return False;
  730.     }
  731.     /*
  732.      * Now get the password value - this should be 32 hex digits
  733.      * which are the ascii representations of a 16 byte string.
  734.      * Get two at a time and put them into the password.
  735.      */
  736.     p++;
  737.  
  738.     /* record exact password position */
  739.     pwd_seekpos += PTR_DIFF(p, linebuf);
  740.  
  741.     if (!override && (*p == '*' || *p == 'X'))
  742.     {
  743.         /* Password deliberately invalid - end here. */
  744.         DEBUG(10, ("get_smbpwd_entry: entry invalidated for user %s\n", user_name));
  745.         fclose(fp);
  746.         pw_file_unlock(lockfd);
  747.         return False;
  748.     }
  749.  
  750.     if (linebuf_len < (PTR_DIFF(p, linebuf) + 33))
  751.     {
  752.         DEBUG(0, ("mod_smbpwd_entry: malformed password entry (passwd too short)\n"));
  753.         fclose(fp);
  754.         pw_file_unlock(lockfd);
  755.         return (False);
  756.     }
  757.  
  758.     if (p[32] != ':')
  759.     {
  760.         DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no terminating :)\n"));
  761.         fclose(fp);
  762.         pw_file_unlock(lockfd);
  763.         return False;
  764.     }
  765.  
  766.     if (!override && (*p == '*' || *p == 'X'))
  767.     {
  768.         fclose(fp);
  769.         pw_file_unlock(lockfd);
  770.         return False;
  771.     }
  772.  
  773.     /* Now check if the NT compatible password is
  774.         available. */
  775.     p += 33; /* Move to the first character of the line after
  776.                 the lanman password. */
  777.     if (linebuf_len < (PTR_DIFF(p, linebuf) + 33))
  778.     {
  779.         DEBUG(0, ("mod_smbpwd_entry: malformed password entry (passwd too short)\n"));
  780.         fclose(fp);
  781.         pw_file_unlock(lockfd);
  782.         return (False);
  783.     }
  784.  
  785.     if (p[32] != ':')
  786.     {
  787.         DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no terminating :)\n"));
  788.         fclose(fp);
  789.         pw_file_unlock(lockfd);
  790.         return False;
  791.     }
  792.  
  793.         /* The following check is wrong - the NT hash is optional. */
  794. #if 0
  795.     if (*p == '*' || *p == 'X')
  796.     {
  797.         fclose(fp);
  798.         pw_file_unlock(lockfd);
  799.         return False;
  800.     }
  801. #endif
  802.  
  803.     /* whew.  entry is correctly formed. */
  804.  
  805.     /*
  806.      * Do an atomic write into the file at the position defined by
  807.      * seekpos.
  808.      */
  809.  
  810.     /* The mod user write needs to be atomic - so get the fd from 
  811.        the fp and do a raw write() call.
  812.      */
  813.  
  814.     fd = fileno(fp);
  815.  
  816.     if (lseek(fd, pwd_seekpos - 1, SEEK_SET) != pwd_seekpos - 1)
  817.     {
  818.         DEBUG(1, ("mod_smbpwd_entry: seek fail on file %s.\n", pfile));
  819.             fclose(fp);
  820.             pw_file_unlock(lockfd);
  821.             return False;
  822.     }
  823.  
  824.     /* Sanity check - ensure the character is a ':' */
  825.     if (read(fd, &c, 1) != 1)
  826.     {
  827.         DEBUG(1, ("mod_smbpwd_entry: read fail on file %s.\n", pfile));
  828.         fclose(fp);
  829.         pw_file_unlock(lockfd);
  830.         return False;
  831.     }
  832.  
  833.     if (c != ':')
  834.     {
  835.         DEBUG(1, ("mod_smbpwd_entry: check on passwd file %s failed.\n", pfile));
  836.         fclose(fp);
  837.         pw_file_unlock(lockfd);
  838.         return False;
  839.     }
  840.  
  841.     /* Create the 32 byte representation of the new p16 */
  842.     for (i = 0; i < 16; i++)
  843.     {
  844.         slprintf(&ascii_p16[i*2], sizeof(ascii_p16) - (i*2) - 1, 
  845.                         "%02X", (uchar) pwd->smb_passwd[i]);
  846.     }
  847.     /* Add on the NT md4 hash */
  848.     ascii_p16[32] = ':';
  849.     wr_len = 65;
  850.     if (pwd->smb_nt_passwd != NULL)
  851.     {
  852.         for (i = 0; i < 16; i++)
  853.         {
  854.             slprintf(&ascii_p16[(i*2)+33], sizeof(ascii_p16) - (i*2) - 32, 
  855.                                  "%02X", (uchar) pwd->smb_nt_passwd[i]);
  856.         }
  857.     }
  858.     else    
  859.     {
  860.         /* No NT hash - write out an 'invalid' string. */
  861.         fstrcpy(&ascii_p16[33], "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
  862.     }
  863.  
  864. #ifdef DEBUG_PASSWORD
  865.     DEBUG(100,("mod_smbpwd_entry: "));
  866.     dump_data(100, ascii_p16, wr_len);
  867. #endif
  868.  
  869.     if (write(fd, ascii_p16, wr_len) != wr_len)
  870.     {
  871.         DEBUG(1, ("mod_smbpwd_entry: write failed in passwd file %s\n", pfile));
  872.         fclose(fp);
  873.         pw_file_unlock(lockfd);
  874.         return False;
  875.     }
  876.  
  877.     fclose(fp);
  878.     pw_file_unlock(lockfd);
  879.     return True;
  880. }
  881.