/* * Unix SMB/CIFS implementation. * Copyright (C) Jeremy Allison 1995-1998 * Copyright (C) Tim Potter 2001 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 675 * Mass Ave, Cambridge, MA 02139, USA. */ #include "includes.h" #include void E_md4hash(const char *passwd, uchar p16[16]) { int len; smb_ucs2_t wpwd[129]; int i; /* Password must be converted to NT unicode - null terminated. */ len = strlen(passwd); #if 0 push_ucs2(NULL, wpwd, (const char *)passwd, 256, STR_UNICODE|STR_NOALIGN|STR_TERMINATE); #else for (i = 0; i < len; i++) { wpwd[i] = (unsigned char)passwd[i]; #if __BYTE_ORDER == __BIG_ENDIAN wpwd[i] <<= 8; // make mem layout like LITTLEENDIAN #endif } wpwd[i] = 0; // termination #endif /* Calculate length in bytes */ len = len /*strlen_w(wpwd)*/ * sizeof(int16); mdfour(p16, (unsigned char *)wpwd, len); ZERO_STRUCT(wpwd); } /** * Creates the DES forward-only Hash of the users password in DOS ASCII charset * @param passwd password in 'unix' charset. * @param p16 return password hashed with DES, caller allocated 16 byte buffer * @return False if password was > 14 characters, and therefore may be incorrect, otherwise True * @note p16 is filled in regardless */ BOOL E_deshash(const char *passwd, uchar p16[16]) { BOOL ret = True; char dospwd[256+2]; int i; int len; /* Password must be converted to DOS charset - null terminated, uppercase. */ // push_ascii(dospwd, passwd, sizeof(dospwd), STR_UPPER|STR_TERMINATE); len = strlen(passwd); for (i = 0; i < len; i++) { char c = passwd[i]; if (islower(c)) c = toupper(c); dospwd[i] = c; } dospwd[i] = 0; /* Only the fisrt 14 chars are considered, password need not be null terminated. */ E_P16((const unsigned char *)dospwd, p16); if (strlen(dospwd) > 14) { ret = False; } memset(dospwd, 0, sizeof(dospwd)); // ZERO_STRUCT(dospwd); return ret; } static void my_pdb_sethexpwd(char *p, const unsigned char *pwd) { if (pwd != NULL) { int i; for (i = 0; i < 16; i++) slprintf(&p[i*2], 3, "%02X", pwd[i]); } else { strncpy(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 32); } } static void crypt_password (const char *user_name, const char *new_passwd, char *new_lanman_p16, char *new_nt_p16) { /* Calculate the MD4 hash (NT compatible) of the password */ E_md4hash(new_passwd, new_nt_p16); if (!E_deshash(new_passwd, new_lanman_p16)) { /* E_deshash returns false for 'long' passwords (> 14 DOS chars). This allows us to match Win2k, which does not store a LM hash for these passwords (which would reduce the effective password length to 14 */ memset(new_lanman_p16, 0, LM_HASH_LEN); } } /* ftpuser:1000:8C6F5D02DEB21501AAD3B435B51404EE:E0FBA38268D0EC66EF1CB452D5885E53:[UX ]:LCT-00000000: */ /********************************************************* Start here. **********************************************************/ int main(int argc, char **argv) { char *passwd_filename = "/var/tmp/samba/private/smbpasswd"; char *cleartext_filename = "/var/tmp/smbpasswd.cleartext"; if (argc != 1) { fprintf(stderr, "use: smbpasswd\n"); fprintf(stderr, " file %s will be encrypted to %s\n", cleartext_filename, passwd_filename); return -9; } FILE *fp = fopen(passwd_filename, "w"); if (fp == NULL) { fprintf(stderr, "can't write %s\n", passwd_filename); return -10; } /* Make sure it is only rw by the owner */ chmod(passwd_filename, 0600); FILE *fp_in = fopen(cleartext_filename, "r"); if (!fp_in) { fprintf(stderr, "can't read %s\n", cleartext_filename); fclose(fp); return -11; } char line[512]; unsigned nusers = 0; while(line == fgets(line, sizeof(line)-1, fp_in)) { char *username, *passwd, *extra; unsigned uid; uchar new_lanman_p16[LM_HASH_LEN]; uchar new_nt_p16[NT_HASH_LEN]; char ascii_p16[32+1]; char *p; line[sizeof(line)-1] = '\0'; if (strlen(line)) { p = &line[strlen(line)-1]; while(p >= line) { if (*p != '\n' && *p != '\r') break; *p = '\0'; p--; } } p = line; char *p2 = strchr(p, '\t'); if (!p2) goto err; *p2 = 0; username = p; p = p2 + 1; p2 = strchr(p, '\t'); if (!p2) goto err; *p2 = 0; uid = atoi(p); p = p2 + 1; p2 = strchr(p, '\t'); if (!p2) goto err; *p2 = 0; passwd = p; extra = p2 + 1; fprintf(fp, "%s:%u:", username, uid); if ('\0' != passwd[0]) { crypt_password(username, passwd, new_lanman_p16, new_nt_p16); my_pdb_sethexpwd(ascii_p16, new_lanman_p16); ascii_p16[32] = '\0'; fprintf(fp, "%s:", ascii_p16); my_pdb_sethexpwd(ascii_p16, new_nt_p16); ascii_p16[32] = '\0'; fprintf(fp, "%s:", ascii_p16); } else { fprintf(fp, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX:"); fprintf(fp, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX:"); } fprintf(fp, "%s\n", extra); nusers++; } // while err: fclose(fp_in); fclose(fp); fprintf(stderr, "%u samba users written to %s\n", nusers, passwd_filename); return 0; }