home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / Networking / SambaManager / samba-1.9.17p4 / source / smbpass.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-30  |  10.6 KB  |  419 lines

  1. #ifdef SMB_PASSWD
  2. /*
  3.  * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup
  4.  * Copyright (C) Andrew Tridgell 1992-1997 Modified by Jeremy Allison 1995.
  5.  * 
  6.  * This program is free software; you can redistribute it and/or modify it under
  7.  * the terms of the GNU General Public License as published by the Free
  8.  * Software Foundation; either version 2 of the License, or (at your option)
  9.  * any later version.
  10.  * 
  11.  * This program is distributed in the hope that it will be useful, but WITHOUT
  12.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  14.  * more details.
  15.  * 
  16.  * You should have received a copy of the GNU General Public License along with
  17.  * this program; if not, write to the Free Software Foundation, Inc., 675
  18.  * Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21. #include "includes.h"
  22.  
  23. extern int      DEBUGLEVEL;
  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.     int             ret;
  36. #ifndef BSD_LOCK
  37.     struct flock    lock;
  38.  
  39.     lock.l_type = type;
  40.     lock.l_whence = SEEK_SET;
  41.     lock.l_start = 0;
  42.     lock.l_len = 1;
  43.     lock.l_pid = 0;
  44. #endif
  45.  
  46.     gotalarm = 0;
  47.     signal(SIGALRM, SIGNAL_CAST gotalarm_sig);
  48.     alarm(5);
  49.  
  50. #ifdef BSD_LOCK
  51.       ret = flock(fd, (type==F_UNLCK)?LOCK_UN:LOCK_EX);
  52. #else
  53.     ret = fcntl(fd, F_SETLKW, &lock);
  54. #endif
  55.  
  56.     alarm(0);
  57.     signal(SIGALRM, SIGNAL_CAST SIG_DFL);
  58.  
  59.     if (gotalarm) {
  60.         DEBUG(0, ("do_pw_lock: failed to %s SMB passwd file.\n",
  61.               type == F_UNLCK ? "unlock" : "lock"));
  62.         return -1;
  63.     }
  64.     return ret;
  65. }
  66.  
  67. int pw_file_lock(char *name, int type, int secs)
  68. {
  69.     int fd = open(name, O_RDWR | O_CREAT, 0600);
  70.     if (fd < 0)
  71.         return (-1);
  72.     if (do_pw_lock(fd, secs, type)) {
  73.         close(fd);
  74.         return -1;
  75.     }
  76.     return fd;
  77. }
  78.  
  79. int pw_file_unlock(int fd)
  80. {
  81.     do_pw_lock(fd, 5, F_UNLCK);
  82.     return close(fd);
  83. }
  84.  
  85.  
  86. /*
  87.  * Routine to get the next 32 hex characters and turn them
  88.  * into a 16 byte array.
  89.  */
  90.  
  91. static int gethexpwd(char *p, char *pwd)
  92. {
  93.     int i;
  94.     unsigned char   lonybble, hinybble;
  95.     char           *hexchars = "0123456789ABCDEF";
  96.     char           *p1, *p2;
  97.  
  98.     for (i = 0; i < 32; i += 2) {
  99.         hinybble = toupper(p[i]);
  100.         lonybble = toupper(p[i + 1]);
  101.  
  102.         p1 = strchr(hexchars, hinybble);
  103.         p2 = strchr(hexchars, lonybble);
  104.         if (!p1 || !p2)
  105.             return (False);
  106.         hinybble = PTR_DIFF(p1, hexchars);
  107.         lonybble = PTR_DIFF(p2, hexchars);
  108.  
  109.         pwd[i / 2] = (hinybble << 4) | lonybble;
  110.     }
  111.     return (True);
  112. }
  113.  
  114. #ifdef USE_NETINFO
  115. /*
  116.  * The code to use when accesssing netinfo on NEXTSTEP/OPENSTEP
  117.  */
  118. #include "netinfo/ni_crypt.c"
  119. struct smb_passwd *get_smbpwnam_from_file(char *name);
  120.  
  121. struct smb_passwd *get_smbpwnam(char *name)
  122. {
  123.     /* Static buffers we will return. */
  124.     static struct smb_passwd pw_buf;
  125.     static pstring           user_name;
  126.     static unsigned char     smbpwd[16];
  127.     static unsigned char     smbntpwd[16];
  128.     char                     *pfile = lp_smb_passwd_file();
  129.  
  130.     ni_status        status;
  131.     ni_namelist    passwd, ntpasswd;
  132.     ni_id                ndir;
  133.     void                *handle;
  134.     char                *ldir;
  135.  
  136.     DEBUG(10, ("get_smbpwnam: opening netinfo for samba passwords for user %s.\n", name));
  137.  
  138.     /* Set the directory to get. */
  139.     ldir = (char *)malloc(sizeof(char)*(8+strlen(name)));
  140.     (void)strcpy(ldir, S_USERDIR);
  141.     (void)strcat(ldir, "/");
  142.     (void)strcat(ldir, name);
  143.     
  144.     /*
  145.      * Scan the NetInfo hierarchy, starting from the local level,
  146.      * until either an entry is found or we are past the top level.
  147.      */
  148.     handle = NULL;
  149.     status = ni_search_for_dir(ldir, ".", &handle, &ndir, 5, 0, 1);
  150.     free(ldir);
  151.  
  152.     if (status == NI_OK) {
  153.     
  154.         /* Do we have a samba password? */
  155.         status = ni_lookupprop(handle, &ndir, S_SMBPASSWD, &passwd);
  156.         if ((status == NI_OK)  && (passwd.ni_namelist_len)) {
  157.             /* If the password starts with 'X' or '*', the entry has been disabled. */
  158.             if ((*(passwd.ni_namelist_val[0]) == '*') || (*(passwd.ni_namelist_val[0]) == 'X')) {
  159.                 DEBUG(10, ("get_smbpwnam: entry invalidated for user %s\n", name));
  160.                 ni_namelist_free(&passwd);
  161.                 ni_free(handle);
  162.                 return NULL;
  163.             }
  164.         
  165.             if (!strncasecmp(passwd.ni_namelist_val[0], "NO PASSWORD", 11)) {
  166.                 pw_buf.smb_passwd = NULL;
  167.             } else {
  168.                 ni_decrypt(passwd.ni_namelist_val[0], (char *)smbpwd);
  169.                 pw_buf.smb_passwd = smbpwd;
  170.             }
  171.             ni_namelist_free(&passwd);
  172.             
  173.             /* User name must be identical to name passed. */
  174.             strcpy(user_name, name);
  175.             pw_buf.smb_name = user_name;
  176.  
  177.             
  178.             /* Get uid. */
  179.             status = ni_lookupprop(handle, &ndir, "uid", &passwd);
  180.             if ((status == NI_OK) && (passwd.ni_namelist_len)) {
  181.                 pw_buf.smb_userid = atoi(passwd.ni_namelist_val[0]);
  182.                 ni_namelist_free(&passwd);
  183.             } else {
  184.                 if (status == NI_OK)
  185.                     ni_namelist_free(&passwd);
  186.                 DEBUG(0, ("get_smbpwnam: could not read uid from NetInfo\n"));
  187.                 ni_free(handle);
  188.                 return NULL;
  189.             }
  190.             
  191.             pw_buf.smb_nt_passwd = NULL;
  192.             /* Do we have an NT password? */
  193.             status = ni_lookupprop(handle, &ndir, S_SMBNTPASSWD, &ntpasswd);
  194.             if (status == NI_OK) {
  195.                 if (ntpasswd.ni_namelist_len) {
  196.                     if (*(ntpasswd.ni_namelist_val[0]) != '*' && *(ntpasswd.ni_namelist_val[0]) != 'X') {
  197.                         ni_decrypt(ntpasswd.ni_namelist_val[0], (char *)smbntpwd);
  198.                             pw_buf.smb_nt_passwd = smbntpwd;
  199.                     }
  200.                 }
  201.                 ni_namelist_free(&ntpasswd);
  202.             }
  203.  
  204.             DEBUG(5, ("get_smbpwname: returning passwd entry for user %s, uid %d\n",
  205.                     user_name, pw_buf.smb_userid));
  206.             ni_free(handle);
  207.             return &pw_buf;
  208.  
  209.         } else if (status == NI_OK)
  210.                 ni_namelist_free(&passwd);
  211.   }
  212.     
  213.     DEBUG(0, ("get_smbpwnam: could not find %s in any NetInfo domain\n", ldir));
  214.     if (pfile && *pfile && strcmp("netinfo", pfile)) {
  215.         DEBUG(0, ("get_smbpwnam: trying flat file %s\n", ldir));
  216.         return get_smbpwnam_from_file(name);
  217.     }
  218.     return NULL;
  219. }
  220.  
  221. #define get_smbpwnam get_smbpwnam_from_file
  222. #endif /* USE_NETINFO */
  223.  
  224. /*
  225.  * Routine to search the smbpasswd file for an entry matching the username.
  226.  */
  227. struct smb_passwd *get_smbpwnam(char *name)
  228. {
  229.     /* Static buffers we will return. */
  230.     static struct smb_passwd pw_buf;
  231.     static pstring  user_name;
  232.     static unsigned char smbpwd[16];
  233.     static unsigned char smbntpwd[16];
  234.  
  235.     char            linebuf[256];
  236.     char            readbuf[16 * 1024];
  237.     unsigned char   c;
  238.     unsigned char  *p;
  239.     long            uidval;
  240.     long            linebuf_len;
  241.     FILE           *fp;
  242.     int             lockfd;
  243.     char           *pfile = lp_smb_passwd_file();
  244.  
  245.     if (!*pfile) {
  246.         DEBUG(0, ("No SMB password file set\n"));
  247.         return (NULL);
  248.     }
  249.     DEBUG(10, ("get_smbpwnam: opening file %s\n", pfile));
  250.  
  251.     fp = fopen(pfile, "r");
  252.  
  253.     if (fp == NULL) {
  254.         DEBUG(0, ("get_smbpwnam: unable to open file %s\n", pfile));
  255.         return NULL;
  256.     }
  257.     /* Set a 16k buffer to do more efficient reads */
  258.     setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf));
  259.  
  260.     if ((lockfd = pw_file_lock(pfile, F_RDLCK, 5)) < 0) {
  261.         DEBUG(0, ("get_smbpwnam: unable to lock file %s\n", pfile));
  262.         fclose(fp);
  263.         return NULL;
  264.     }
  265.     /* make sure it is only rw by the owner */
  266.     chmod(pfile, 0600);
  267.  
  268.     /* We have a read lock on the file. */
  269.     /*
  270.      * Scan the file, a line at a time and check if the name matches.
  271.      */
  272.     while (!feof(fp)) {
  273.         linebuf[0] = '\0';
  274.  
  275.         fgets(linebuf, 256, fp);
  276.         if (ferror(fp)) {
  277.             fclose(fp);
  278.             pw_file_unlock(lockfd);
  279.             return NULL;
  280.         }
  281.         /*
  282.          * Check if the string is terminated with a newline - if not
  283.          * then we must keep reading and discard until we get one.
  284.          */
  285.         linebuf_len = strlen(linebuf);
  286.         if (linebuf[linebuf_len - 1] != '\n') {
  287.             c = '\0';
  288.             while (!ferror(fp) && !feof(fp)) {
  289.                 c = fgetc(fp);
  290.                 if (c == '\n')
  291.                     break;
  292.             }
  293.         } else
  294.             linebuf[linebuf_len - 1] = '\0';
  295.  
  296. #ifdef DEBUG_PASSWORD
  297.         DEBUG(100, ("get_smbpwnam: got line |%s|\n", linebuf));
  298. #endif
  299.         if ((linebuf[0] == 0) && feof(fp)) {
  300.             DEBUG(4, ("get_smbpwnam: end of file reached\n"));
  301.             break;
  302.         }
  303.         /*
  304.          * The line we have should be of the form :-
  305.          * 
  306.          * username:uid:[32hex bytes]:....other flags presently
  307.          * ignored....
  308.          * 
  309.          * or,
  310.          *
  311.          * username:uid:[32hex bytes]:[32hex bytes]:....ignored....
  312.          *
  313.          * if Windows NT compatible passwords are also present.
  314.          */
  315.  
  316.         if (linebuf[0] == '#' || linebuf[0] == '\0') {
  317.             DEBUG(6, ("get_smbpwnam: skipping comment or blank line\n"));
  318.             continue;
  319.         }
  320.         p = (unsigned char *) strchr(linebuf, ':');
  321.         if (p == NULL) {
  322.             DEBUG(0, ("get_smbpwnam: malformed password entry (no :)\n"));
  323.             continue;
  324.         }
  325.         /*
  326.          * As 256 is shorter than a pstring we don't need to check
  327.          * length here - if this ever changes....
  328.          */
  329.         strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
  330.         user_name[PTR_DIFF(p, linebuf)] = '\0';
  331.         if (!strequal(user_name, name))
  332.             continue;
  333.  
  334.         /* User name matches - get uid and password */
  335.         p++;        /* Go past ':' */
  336.         if (!isdigit(*p)) {
  337.             DEBUG(0, ("get_smbpwnam: malformed password entry (uid not number)\n"));
  338.             fclose(fp);
  339.             pw_file_unlock(lockfd);
  340.             return NULL;
  341.         }
  342.         uidval = atoi((char *) p);
  343.         while (*p && isdigit(*p))
  344.             p++;
  345.         if (*p != ':') {
  346.             DEBUG(0, ("get_smbpwnam: malformed password entry (no : after uid)\n"));
  347.             fclose(fp);
  348.             pw_file_unlock(lockfd);
  349.             return NULL;
  350.         }
  351.         /*
  352.          * Now get the password value - this should be 32 hex digits
  353.          * which are the ascii representations of a 16 byte string.
  354.          * Get two at a time and put them into the password.
  355.          */
  356.         p++;
  357.         if (*p == '*' || *p == 'X') {
  358.             /* Password deliberately invalid - end here. */
  359.             DEBUG(10, ("get_smbpwnam: entry invalidated for user %s\n", user_name));
  360.             fclose(fp);
  361.             pw_file_unlock(lockfd);
  362.             return NULL;
  363.         }
  364.         if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) {
  365.             DEBUG(0, ("get_smbpwnam: malformed password entry (passwd too short)\n"));
  366.             fclose(fp);
  367.             pw_file_unlock(lockfd);
  368.             return (False);
  369.         }
  370.         if (p[32] != ':') {
  371.             DEBUG(0, ("get_smbpwnam: malformed password entry (no terminating :)\n"));
  372.             fclose(fp);
  373.             pw_file_unlock(lockfd);
  374.             return NULL;
  375.         }
  376.         if (!strncasecmp((char *) p, "NO PASSWORD", 11)) {
  377.             pw_buf.smb_passwd = NULL;
  378.         } else {
  379.             if(!gethexpwd((char *)p,(char *)smbpwd)) {
  380.                 DEBUG(0, ("Malformed Lanman password entry (non hex chars)\n"));
  381.                 fclose(fp);
  382.                 pw_file_unlock(lockfd);
  383.                 return NULL;
  384.             }
  385.             pw_buf.smb_passwd = smbpwd;
  386.         }
  387.         pw_buf.smb_name = user_name;
  388.         pw_buf.smb_userid = uidval;
  389.         pw_buf.smb_nt_passwd = NULL;
  390.  
  391.         /* Now check if the NT compatible password is
  392.             available. */
  393.         p += 33; /* Move to the first character of the line after
  394.                     the lanman password. */
  395.         if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) {
  396.             if (*p != '*' && *p != 'X') {
  397.                 if(gethexpwd((char *)p,(char *)smbntpwd))
  398.                     pw_buf.smb_nt_passwd = smbntpwd;
  399.             }
  400.         }
  401.  
  402.         fclose(fp);
  403.         pw_file_unlock(lockfd);
  404.         DEBUG(5, ("get_smbpwname: returning passwd entry for user %s, uid %d\n",
  405.               user_name, uidval));
  406.         return &pw_buf;
  407.     }
  408.  
  409.     fclose(fp);
  410.     pw_file_unlock(lockfd);
  411.  
  412.     return NULL;
  413. }
  414. #else
  415.  void smbpass_dummy(void)
  416. {
  417. }                /* To avoid compiler complaints */
  418. #endif
  419.