diff options
Diffstat (limited to 'source3/passdb/smbpass.c')
-rw-r--r-- | source3/passdb/smbpass.c | 1558 |
1 files changed, 774 insertions, 784 deletions
diff --git a/source3/passdb/smbpass.c b/source3/passdb/smbpass.c index fbda8949bc..b51f675306 100644 --- a/source3/passdb/smbpass.c +++ b/source3/passdb/smbpass.c @@ -19,854 +19,844 @@ #include "includes.h" -extern int DEBUGLEVEL; +extern int DEBUGLEVEL; -int gotalarm; +static int gotalarm; +static char s_readbuf[16 * 1024]; -void -gotalarm_sig() +/*************************************************************** + Signal function to tell us we timed out. +****************************************************************/ + +static void gotalarm_sig() { - gotalarm = 1; + gotalarm = 1; } -int -do_pw_lock(int fd, int waitsecs, int type) +/*************************************************************** + Lock or unlock a fd for a known lock type. Abandon after waitsecs + seconds. +****************************************************************/ + +static int do_pw_lock(int fd, int waitsecs, int type) { - struct flock lock; - int ret; - - gotalarm = 0; - signal(SIGALRM, SIGNAL_CAST gotalarm_sig); - - lock.l_type = type; - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 1; - lock.l_pid = 0; - - alarm(5); - ret = fcntl(fd, F_SETLKW, &lock); - alarm(0); - signal(SIGALRM, SIGNAL_CAST SIG_DFL); - - if (gotalarm) { - DEBUG(0, ("do_pw_lock: failed to %s SMB passwd file.\n", - type == F_UNLCK ? "unlock" : "lock")); - return -1; - } - return ret; + struct flock lock; + int ret; + + gotalarm = 0; + signal(SIGALRM, SIGNAL_CAST gotalarm_sig); + + lock.l_type = type; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 1; + lock.l_pid = 0; + + alarm(5); + ret = fcntl(fd, F_SETLKW, &lock); + alarm(0); + signal(SIGALRM, SIGNAL_CAST SIG_DFL); + + if (gotalarm) { + DEBUG(0, ("do_pw_lock: failed to %s SMB passwd file.\n", + type == F_UNLCK ? "unlock" : "lock")); + return -1; + } + return ret; } -int pw_file_lock(char *name, int type, int secs) +/*************************************************************** + Lock an fd. Abandon after waitsecs seconds. +****************************************************************/ + +int pw_file_lock(int fd, int type, int secs) { - int fd = open(name, O_RDWR | O_CREAT, 0600); - if (fd < 0) - return (-1); - if (do_pw_lock(fd, secs, type)) { - close(fd); - return -1; - } - return fd; + if (fd < 0) + return (-1); + if (do_pw_lock(fd, secs, type)) { + return -1; + } + return fd; } +/*************************************************************** + Unlock an fd. Abandon after waitsecs seconds. +****************************************************************/ + int pw_file_unlock(int fd) { - do_pw_lock(fd, 5, F_UNLCK); - return close(fd); + return do_pw_lock(fd, 5, F_UNLCK); } -/* - * Routine to get the next 32 hex characters and turn them - * into a 16 byte array. - */ +/*************************************************************** + Open the smbpasswd file - get ready to enumerate it. +****************************************************************/ + +FILE *startsmbpwent(BOOL update) +{ + FILE *fp = NULL; + char *pfile = lp_smb_passwd_file(); + + if (!*pfile) { + DEBUG(0, ("startsmbpwent: No SMB password file set\n")); + return (NULL); + } + DEBUG(10, ("startsmbpwent: opening file %s\n", pfile)); + + fp = fopen(pfile, update ? "r+b" : "rb"); + + if (fp == NULL) { + DEBUG(0, ("startsmbpwent: unable to open file %s\n", pfile)); + return NULL; + } + + /* Set a 16k buffer to do more efficient reads */ + setvbuf(fp, s_readbuf, _IOFBF, sizeof(s_readbuf)); + + if ((pw_file_lock(fileno(fp), F_RDLCK | (update ? F_WRLCK : 0), 5)) < 0) { + DEBUG(0, ("startsmbpwent: unable to lock file %s\n", pfile)); + fclose(fp); + return NULL; + } + + /* Make sure it is only rw by the owner */ + chmod(pfile, 0600); + + /* We have a lock on the file. */ + return fp; +} + +/*************************************************************** + Close the smbpasswd file - end enumeration. +****************************************************************/ + +void endsmbpwent(FILE *fp) +{ + pw_file_unlock(fileno(fp)); + fclose(fp); + DEBUG(7, ("endsmbpwent: closed password file.\n")); +} + +/************************************************************* + Routine to get the next 32 hex characters and turn them + into a 16 byte array. +**************************************************************/ static int gethexpwd(char *p, char *pwd) { - int i; - unsigned char lonybble, hinybble; - char *hexchars = "0123456789ABCDEF"; - char *p1, *p2; - - for (i = 0; i < 32; i += 2) { - hinybble = toupper(p[i]); - lonybble = toupper(p[i + 1]); + int i; + unsigned char lonybble, hinybble; + char *hexchars = "0123456789ABCDEF"; + char *p1, *p2; + + for (i = 0; i < 32; i += 2) { + hinybble = toupper(p[i]); + lonybble = toupper(p[i + 1]); - p1 = strchr(hexchars, hinybble); - p2 = strchr(hexchars, lonybble); - if (!p1 || !p2) - return (False); - hinybble = PTR_DIFF(p1, hexchars); - lonybble = PTR_DIFF(p2, hexchars); + p1 = strchr(hexchars, hinybble); + p2 = strchr(hexchars, lonybble); + if (!p1 || !p2) + return (False); + hinybble = PTR_DIFF(p1, hexchars); + lonybble = PTR_DIFF(p2, hexchars); - pwd[i / 2] = (hinybble << 4) | lonybble; - } - return (True); + pwd[i / 2] = (hinybble << 4) | lonybble; + } + return (True); } /************************************************************************* - Routine to search the smbpasswd file for an entry matching the username - or user id. if the name is NULL, then the smb_uid is used instead. + Routine to return the next entry in the smbpasswd file. *************************************************************************/ -struct smb_passwd *get_smbpwd_entry(char *name, int smb_userid) + +struct smb_passwd *getsmbpwent(FILE *fp) { - /* Static buffers we will return. */ - static struct smb_passwd pw_buf; - static pstring user_name; - static unsigned char smbpwd[16]; - static unsigned char smbntpwd[16]; - char linebuf[256]; - char readbuf[16 * 1024]; - unsigned char c; - unsigned char *p; - long uidval; - long linebuf_len; - FILE *fp; - int lockfd; - char *pfile = lp_smb_passwd_file(); - - if (!*pfile) { - DEBUG(0, ("No SMB password file set\n")); - return (NULL); - } - DEBUG(10, ("get_smbpwd_entry: opening file %s\n", pfile)); - - if (name != NULL) - { - DEBUG(10, ("get_smbpwd_entry: search by name: %s\n", name)); - } - else - { - DEBUG(10, ("get_smbpwd_entry: search by smb_userid: %x\n", smb_userid)); - } - - fp = fopen(pfile, "r"); - - if (fp == NULL) { - DEBUG(0, ("get_smbpwd_entry: unable to open file %s\n", pfile)); - return NULL; - } - /* Set a 16k buffer to do more efficient reads */ - setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf)); - - if ((lockfd = pw_file_lock(pfile, F_RDLCK, 5)) < 0) { - DEBUG(0, ("get_smbpwd_entry: unable to lock file %s\n", pfile)); - fclose(fp); - return NULL; - } - /* make sure it is only rw by the owner */ - chmod(pfile, 0600); - - /* We have a read lock on the file. */ - /* - * Scan the file, a line at a time and check if the name matches. - */ - while (!feof(fp)) { - linebuf[0] = '\0'; - - fgets(linebuf, 256, fp); - if (ferror(fp)) { - fclose(fp); - pw_file_unlock(lockfd); - return NULL; - } - /* - * Check if the string is terminated with a newline - if not - * then we must keep reading and discard until we get one. - */ - linebuf_len = strlen(linebuf); - if (linebuf[linebuf_len - 1] != '\n') { - c = '\0'; - while (!ferror(fp) && !feof(fp)) { - c = fgetc(fp); - if (c == '\n') - break; - } - } else - linebuf[linebuf_len - 1] = '\0'; + /* Static buffers we will return. */ + static struct smb_passwd pw_buf; + static pstring user_name; + static unsigned char smbpwd[16]; + static unsigned char smbntpwd[16]; + char linebuf[256]; + unsigned char c; + unsigned char *p; + long uidval; + long linebuf_len; + + if(fp == NULL) { + DEBUG(0,("getsmbpwent: Bad password file pointer.\n")); + return NULL; + } + + /* + * Scan the file, a line at a time and check if the name matches. + */ + while (!feof(fp)) { + linebuf[0] = '\0'; + + fgets(linebuf, 256, fp); + if (ferror(fp)) { + return NULL; + } + + /* + * Check if the string is terminated with a newline - if not + * then we must keep reading and discard until we get one. + */ + linebuf_len = strlen(linebuf); + if (linebuf[linebuf_len - 1] != '\n') { + c = '\0'; + while (!ferror(fp) && !feof(fp)) { + c = fgetc(fp); + if (c == '\n') + break; + } + } else + linebuf[linebuf_len - 1] = '\0'; #ifdef DEBUG_PASSWORD - DEBUG(100, ("get_smbpwd_entry: got line |%s|\n", linebuf)); + DEBUG(100, ("getsmbpwent: got line |%s|\n", linebuf)); #endif - if ((linebuf[0] == 0) && feof(fp)) { - DEBUG(4, ("get_smbpwd_entry: end of file reached\n")); - break; - } - /* - * The line we have should be of the form :- - * - * username:uid:[32hex bytes]:....other flags presently - * ignored.... - * - * or, - * - * username:uid:[32hex bytes]:[32hex bytes]:....ignored.... - * - * if Windows NT compatible passwords are also present. - */ - - if (linebuf[0] == '#' || linebuf[0] == '\0') { - DEBUG(6, ("get_smbpwd_entry: skipping comment or blank line\n")); - continue; - } - p = (unsigned char *) strchr(linebuf, ':'); - if (p == NULL) { - DEBUG(0, ("get_smbpwd_entry: malformed password entry (no :)\n")); - continue; - } - /* - * As 256 is shorter than a pstring we don't need to check - * length here - if this ever changes.... - */ - strncpy(user_name, linebuf, PTR_DIFF(p, linebuf)); - user_name[PTR_DIFF(p, linebuf)] = '\0'; - - /* get smb uid */ - - p++; /* Go past ':' */ - if (!isdigit(*p)) { - DEBUG(0, ("get_smbpwd_entry: malformed password entry (uid not number)\n")); - continue; - } - - uidval = atoi((char *) p); - - while (*p && isdigit(*p)) - { - p++; - } - - if (*p != ':') - { - DEBUG(0, ("get_smbpwd_entry: malformed password entry (no : after uid)\n")); - continue; - } - - if (name != NULL) - { - /* search is by user name */ - if (!strequal(user_name, name)) continue; - DEBUG(10, ("get_smbpwd_entry: found by name: %s\n", user_name)); - } - else - { - /* search is by user id */ - if (uidval != smb_userid) continue; - DEBUG(10, ("get_smbpwd_entry: found by smb_userid: %x\n", uidval)); - } - - /* if we're here, the entry has been found (either by name or uid) */ - - /* - * Now get the password value - this should be 32 hex digits - * which are the ascii representations of a 16 byte string. - * Get two at a time and put them into the password. - */ - - /* skip the ':' */ - p++; - - if (*p == '*' || *p == 'X') - { - /* Password deliberately invalid - end here. */ - DEBUG(10, ("get_smbpwd_entry: entry invalidated for user %s\n", user_name)); - fclose(fp); - pw_file_unlock(lockfd); - return NULL; - } - - if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) - { - DEBUG(0, ("get_smbpwd_entry: malformed password entry (passwd too short)\n")); - fclose(fp); - pw_file_unlock(lockfd); - return (False); - } - - if (p[32] != ':') - { - DEBUG(0, ("get_smbpwd_entry: malformed password entry (no terminating :)\n")); - fclose(fp); - pw_file_unlock(lockfd); - return NULL; - } - - if (!strncasecmp((char *) p, "NO PASSWORD", 11)) - { - pw_buf.smb_passwd = NULL; - } - else - { - if (!gethexpwd((char *)p, (char *)smbpwd)) - { - DEBUG(0, ("Malformed Lanman password entry (non hex chars)\n")); - fclose(fp); - pw_file_unlock(lockfd); - return NULL; - } - pw_buf.smb_passwd = smbpwd; - } - - pw_buf.smb_name = user_name; - pw_buf.smb_userid = uidval; - pw_buf.smb_nt_passwd = NULL; - - /* Now check if the NT compatible password is - available. */ - p += 33; /* Move to the first character of the line after - the lanman password. */ - if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) { - if (*p != '*' && *p != 'X') { - if(gethexpwd((char *)p,(char *)smbntpwd)) - pw_buf.smb_nt_passwd = smbntpwd; - } - } - - fclose(fp); - pw_file_unlock(lockfd); - DEBUG(5, ("get_smbpwd_entrye: returning passwd entry for user %s, uid %d\n", + if ((linebuf[0] == 0) && feof(fp)) { + DEBUG(4, ("getsmbpwent: end of file reached\n")); + break; + } + /* + * The line we have should be of the form :- + * + * username:uid:[32hex bytes]:....other flags presently + * ignored.... + * + * or, + * + * username:uid:[32hex bytes]:[32hex bytes]:....ignored.... + * + * if Windows NT compatible passwords are also present. + */ + + if (linebuf[0] == '#' || linebuf[0] == '\0') { + DEBUG(6, ("getsmbpwent: skipping comment or blank line\n")); + continue; + } + p = (unsigned char *) strchr(linebuf, ':'); + if (p == NULL) { + DEBUG(0, ("getsmbpwent: malformed password entry (no :)\n")); + continue; + } + /* + * As 256 is shorter than a pstring we don't need to check + * length here - if this ever changes.... + */ + strncpy(user_name, linebuf, PTR_DIFF(p, linebuf)); + user_name[PTR_DIFF(p, linebuf)] = '\0'; + + /* Get smb uid. */ + + p++; /* Go past ':' */ + if (!isdigit(*p)) { + DEBUG(0, ("getsmbpwent: malformed password entry (uid not number)\n")); + continue; + } + + uidval = atoi((char *) p); + + while (*p && isdigit(*p)) + p++; + + if (*p != ':') { + DEBUG(0, ("getsmbpwent: malformed password entry (no : after uid)\n")); + continue; + } + + pw_buf.smb_name = user_name; + pw_buf.smb_userid = uidval; + + /* + * Now get the password value - this should be 32 hex digits + * which are the ascii representations of a 16 byte string. + * Get two at a time and put them into the password. + */ + + /* Skip the ':' */ + p++; + + if (*p == '*' || *p == 'X') { + /* Password deliberately invalid - end here. */ + DEBUG(10, ("getsmbpwent: entry invalidated for user %s\n", user_name)); + pw_buf.smb_nt_passwd = NULL; + pw_buf.smb_passwd = NULL; + pw_buf.acct_ctrl |= ACB_DISABLED; + return &pw_buf; + } + + if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) { + DEBUG(0, ("getsmbpwent: malformed password entry (passwd too short)\n")); + continue; + } + + if (p[32] != ':') { + DEBUG(0, ("getsmbpwent: malformed password entry (no terminating :)\n")); + continue; + } + + if (!strncasecmp((char *) p, "NO PASSWORD", 11)) { + pw_buf.smb_passwd = NULL; + pw_buf.acct_ctrl |= ACB_PWNOTREQ; + } else { + if (!gethexpwd((char *)p, (char *)smbpwd)) { + DEBUG(0, ("getsmbpwent: Malformed Lanman password entry (non hex chars)\n")); + continue; + } + pw_buf.smb_passwd = smbpwd; + } + + /* + * Now check if the NT compatible password is + * available. + */ + pw_buf.smb_nt_passwd = NULL; + + p += 33; /* Move to the first character of the line after + the lanman password. */ + if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':')) { + if (*p != '*' && *p != 'X') { + if(gethexpwd((char *)p,(char *)smbntpwd)) + pw_buf.smb_nt_passwd = smbntpwd; + } + p += 33; /* Move to the first character of the line after + the NT password. */ + } + + DEBUG(5, ("getsmbpwent: returning passwd entry for user %s, uid %d\n", user_name, uidval)); - return &pw_buf; - } - fclose(fp); - pw_file_unlock(lockfd); - return NULL; + /* + * Check if the account type bits have been encoded after the + * NT password (in the form [NDHTUWSLXI]). + */ + + if (*p == '[') { + BOOL finished = False; + + pw_buf.acct_ctrl = 0; + + for(p++;*p && !finished; p++) { + switch (*p) { + case 'N': + /* 'N'o password. */ + pw_buf.acct_ctrl |= ACB_PWNOTREQ; + break; + case 'D': + /* 'D'isabled. */ + pw_buf.acct_ctrl |= ACB_DISABLED; + break; + case 'H': + /* 'H'omedir required. */ + pw_buf.acct_ctrl |= ACB_HOMDIRREQ; + break; + case 'T': + /* 'T'emp account. */ + pw_buf.acct_ctrl |= ACB_TEMPDUP; + break; + case 'U': + /* 'U'ser account (normal). */ + pw_buf.acct_ctrl |= ACB_NORMAL; + break; + case 'M': + /* 'M'NS logon user account. What is this ? */ + pw_buf.acct_ctrl |= ACB_MNS; + break; + case 'W': + /* 'W'orkstation account. */ + pw_buf.acct_ctrl |= ACB_WSTRUST; + break; + case 'S': + /* 'S'erver account. */ + pw_buf.acct_ctrl |= ACB_SVRTRUST; + break; + case 'L': + /* 'L'ocked account. */ + pw_buf.acct_ctrl |= ACB_AUTOLOCK; + break; + case 'X': + /* No 'X'piry. */ + pw_buf.acct_ctrl |= ACB_PWNOEXP; + break; + case 'I': + /* 'I'nterdomain trust account. */ + pw_buf.acct_ctrl |= ACB_DOMTRUST; + break; + + case ':': + case '\n': + case '\0': + case ']': + default: + finished = True; + } + } + + /* Must have some account type set. */ + if(pw_buf.acct_ctrl == 0) + pw_buf.acct_ctrl = ACB_NORMAL; + + } else { + /* 'Old' style file. Fake up based on user name. */ + /* + * Currently machine accounts are kept in the same + * password file as 'normal accounts'. If this changes + * we will have to fix this code. JRA. + */ + if(pw_buf.smb_name[strlen(pw_buf.smb_name) - 1] == '$') + pw_buf.acct_ctrl = ACB_WSTRUST; + else + pw_buf.acct_ctrl = ACB_NORMAL; + } + + return &pw_buf; + } + + DEBUG(5,("getsmbpwent: end of file reached.\n")); + return NULL; } -/* - * Routine to search the smbpasswd file for an entry matching the username. - */ -BOOL add_smbpwd_entry(struct smb_passwd* pwd) +/************************************************************************* + Routine to search the smbpasswd file for an entry matching the username + or user id. if the name is NULL, then the smb_uid is used instead. + *************************************************************************/ + +struct smb_passwd *get_smbpwd_entry(char *name, int smb_userid) { - /* Static buffers we will return. */ - static pstring user_name; - - char linebuf[256]; - char readbuf[16 * 1024]; - unsigned char c; - unsigned char *p; - long linebuf_len; - FILE *fp; - int lockfd; - char *pfile = lp_smb_passwd_file(); - - int i; - int wr_len; - - int fd; - int new_entry_length; - char *new_entry; - long offpos; - - if (!*pfile) - { - DEBUG(0, ("No SMB password file set\n")); - return False; - } - DEBUG(10, ("add_smbpwd_entry: opening file %s\n", pfile)); - - fp = fopen(pfile, "r+"); - - if (fp == NULL) - { - DEBUG(0, ("add_smbpwd_entry: unable to open file %s\n", pfile)); - return False; - } - /* Set a 16k buffer to do more efficient reads */ - setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf)); - - if ((lockfd = pw_file_lock(pfile, F_RDLCK | F_WRLCK, 5)) < 0) - { - DEBUG(0, ("add_smbpwd_entry: unable to lock file %s\n", pfile)); - fclose(fp); - return False; - } - /* make sure it is only rw by the owner */ - chmod(pfile, 0600); - - /* We have a write lock on the file. */ - /* - * Scan the file, a line at a time and check if the name matches. - */ - while (!feof(fp)) - { - linebuf[0] = '\0'; - - fgets(linebuf, 256, fp); - if (ferror(fp)) - { - fclose(fp); - pw_file_unlock(lockfd); - return False; - } - - /* - * Check if the string is terminated with a newline - if not - * then we must keep reading and discard until we get one. - */ - linebuf_len = strlen(linebuf); - if (linebuf[linebuf_len - 1] != '\n') - { - c = '\0'; - while (!ferror(fp) && !feof(fp)) - { - c = fgetc(fp); - if (c == '\n') - { - break; - } - } - } - else - { - linebuf[linebuf_len - 1] = '\0'; - } + struct smb_passwd *pwd = NULL; + FILE *fp = NULL; + + if (name != NULL) { + DEBUG(10, ("get_smbpwd_entry: search by name: %s\n", name)); + } else { + DEBUG(10, ("get_smbpwd_entry: search by smb_userid: %x\n", smb_userid)); + } + + /* Open the smbpassword file - not for update. */ + fp = startsmbpwent(False); + + if (fp == NULL) { + DEBUG(0, ("get_smbpwd_entry: unable to open password file.\n")); + return NULL; + } + + /* + * Scan the file, a line at a time and check if the name + * or uid matches. + */ + + while ((pwd = getsmbpwent(fp)) != NULL) { + if (name != NULL) { + /* Search is by user name */ + if (!strequal(pwd->smb_name, name)) + continue; + DEBUG(10, ("get_smbpwd_entry: found by name: %s\n", name)); + break; + } else { + /* Search is by user id */ + if (pwd->smb_userid != smb_userid) + continue; + DEBUG(10, ("get_smbpwd_entry: found by smb_userid: %x\n", smb_userid)); + break; + } + } + + endsmbpwent(fp); + return pwd; +} -#ifdef DEBUG_PASSWORD - DEBUG(100, ("add_smbpwd_entry: got line |%s|\n", linebuf)); -#endif +/************************************************************************ + Routine to add an entry to the smbpasswd file. +*************************************************************************/ - if ((linebuf[0] == 0) && feof(fp)) - { - DEBUG(4, ("add_smbpwd_entry: end of file reached\n")); - break; - } - - /* - * The line we have should be of the form :- - * - * username:uid:[32hex bytes]:....other flags presently - * ignored.... - * - * or, - * - * username:uid:[32hex bytes]:[32hex bytes]:....ignored.... - * - * if Windows NT compatible passwords are also present. - */ - - if (linebuf[0] == '#' || linebuf[0] == '\0') - { - DEBUG(6, ("add_smbpwd_entry: skipping comment or blank line\n")); - continue; - } - - p = (unsigned char *) strchr(linebuf, ':'); - - if (p == NULL) - { - DEBUG(0, ("add_smbpwd_entry: malformed password entry (no :)\n")); - continue; - } - - /* - * As 256 is shorter than a pstring we don't need to check - * length here - if this ever changes.... - */ - strncpy(user_name, linebuf, PTR_DIFF(p, linebuf)); - user_name[PTR_DIFF(p, linebuf)] = '\0'; - if (strequal(user_name, pwd->smb_name)) - { - DEBUG(6, ("add_smbpwd_entry: entry already exists\n")); - return False; - } - } - - /* ok - entry doesn't exist. we can add it */ - - /* Create a new smb passwd entry and set it to the given password. */ - /* The add user write needs to be atomic - so get the fd from - the fp and do a raw write() call. - */ - fd = fileno(fp); - - if((offpos = lseek(fd, 0, SEEK_END)) == -1) - { - DEBUG(0, ("add_smbpwd_entry(lseek): Failed to add entry for user %s to file %s. \ +BOOL add_smbpwd_entry(struct smb_passwd *newpwd) +{ + char *pfile = lp_smb_passwd_file(); + struct smb_passwd *pwd = NULL; + FILE *fp = NULL; + + int i; + int wr_len; + + int fd; + int new_entry_length; + char *new_entry; + long offpos; + unsigned char *p; + + /* Open the smbpassword file - for update. */ + fp = startsmbpwent(True); + + if (fp == NULL) { + DEBUG(0, ("add_smbpwd_entry: unable to open file.\n")); + return False; + } + + /* + * Scan the file, a line at a time and check if the name matches. + */ + + while ((pwd = getsmbpwent(fp)) != NULL) { + if (strequal(newpwd->smb_name, pwd->smb_name)) { + DEBUG(0, ("add_smbpwd_entry: entry with name %s already exists\n", pwd->smb_name)); + endsmbpwent(fp); + return False; + } + } + + /* Ok - entry doesn't exist. We can add it */ + + /* Create a new smb passwd entry and set it to the given password. */ + /* + * The add user write needs to be atomic - so get the fd from + * the fp and do a raw write() call. + */ + fd = fileno(fp); + + if((offpos = lseek(fd, 0, SEEK_END)) == -1) { + DEBUG(0, ("add_smbpwd_entry(lseek): Failed to add entry for user %s to file %s. \ Error was %s\n", pwd->smb_name, pfile, strerror(errno))); + endsmbpwent(fp); + return False; + } - fclose(fp); - pw_file_unlock(lockfd); - return False; - } - - new_entry_length = strlen(pwd->smb_name) + 1 + 15 + 1 + 32 + 1 + 32 + 1 + 2; + new_entry_length = strlen(pwd->smb_name) + 1 + 15 + 1 + 32 + 1 + 32 + 1 + 2; - if((new_entry = (char *)malloc( new_entry_length )) == 0) - { - DEBUG(0, ("add_smbpwd_entry(malloc): Failed to add entry for user %s to file %s. \ -Error was %s\n", - pwd->smb_name, pfile, strerror(errno))); + if((new_entry = (char *)malloc( new_entry_length )) == NULL) { + DEBUG(0, ("add_smbpwd_entry(malloc): Failed to add entry for user %s to file %s. \ +Error was %s\n", pwd->smb_name, pfile, strerror(errno))); + endsmbpwent(fp); + return False; + } - fclose(fp); - pw_file_unlock(lockfd); - return False; - } + sprintf(new_entry, "%s:%u:", pwd->smb_name, (unsigned)pwd->smb_userid); + p = (unsigned char *)&new_entry[strlen(new_entry)]; - sprintf(new_entry, "%s:%u:", pwd->smb_name, (unsigned)pwd->smb_userid); - p = (unsigned char *)&new_entry[strlen(new_entry)]; + for( i = 0; i < 16; i++) { + sprintf((char *)&p[i*2], "%02X", pwd->smb_passwd[i]); + } - for( i = 0; i < 16; i++) - { - sprintf((char *)&p[i*2], "%02X", pwd->smb_passwd[i]); - } - p += 32; + p += 32; - *p++ = ':'; + *p++ = ':'; - for( i = 0; i < 16; i++) - { - sprintf((char *)&p[i*2], "%02X", pwd->smb_nt_passwd[i]); - } - p += 32; + for( i = 0; i < 16; i++) { + sprintf((char *)&p[i*2], "%02X", pwd->smb_nt_passwd[i]); + } + p += 32; - *p++ = ':'; - sprintf((char *)p,"\n"); + *p++ = ':'; + sprintf((char *)p,"\n"); #ifdef DEBUG_PASSWORD - DEBUG(100, ("add_smbpwd_entry(%d): new_entry_len %d entry_len %d made line |%s|\n", + DEBUG(100, ("add_smbpwd_entry(%d): new_entry_len %d entry_len %d made line |%s|\n", fd, new_entry_length, strlen(new_entry), new_entry)); #endif - if ((wr_len = write(fd, new_entry, strlen(new_entry))) != strlen(new_entry)) - { - DEBUG(0, ("add_smbpwd_entry(write): %d Failed to add entry for user %s to file %s. \ + if ((wr_len = write(fd, new_entry, strlen(new_entry))) != strlen(new_entry)) { + DEBUG(0, ("add_smbpwd_entry(write): %d Failed to add entry for user %s to file %s. \ Error was %s\n", wr_len, pwd->smb_name, pfile, strerror(errno))); - /* Remove the entry we just wrote. */ - if(ftruncate(fd, offpos) == -1) - { - DEBUG(0, ("add_smbpwd_entry: ERROR failed to ftruncate file %s. \ + /* Remove the entry we just wrote. */ + if(ftruncate(fd, offpos) == -1) { + DEBUG(0, ("add_smbpwd_entry: ERROR failed to ftruncate file %s. \ Error was %s. Password file may be corrupt ! Please examine by hand !\n", - pwd->smb_name, strerror(errno))); - } + pwd->smb_name, strerror(errno))); + } - fclose(fp); - pw_file_unlock(lockfd); - return False; - } + endsmbpwent(fp); + return False; + } - fclose(fp); - pw_file_unlock(lockfd); - return True; + endsmbpwent(fp); + return True; } -/* - * Routine to search the smbpasswd file for an entry matching the username. - * and then modify its password entry - */ + +/************************************************************************ + Routine to search the smbpasswd file for an entry matching the username. + and then modify its password entry. We can't use the startsmbpwent()/ + getsmbpwent()/endsmbpwent() interfaces here as we depend on looking + in the actual file to decide how much room we have to write data. +************************************************************************/ + BOOL mod_smbpwd_entry(struct smb_passwd* pwd) { - /* Static buffers we will return. */ - static pstring user_name; - - char linebuf[256]; - char readbuf[16 * 1024]; - unsigned char c; - char ascii_p16[66]; - unsigned char *p = NULL; - long linebuf_len = 0; - FILE *fp; - int lockfd; - char *pfile = lp_smb_passwd_file(); - BOOL found_entry = False; - - long pwd_seekpos = 0; - - int i; - int wr_len; - int fd; - - if (!*pfile) - { - DEBUG(0, ("No SMB password file set\n")); - return False; - } - DEBUG(10, ("mod_smbpwd_entry: opening file %s\n", pfile)); - - fp = fopen(pfile, "r+"); - - if (fp == NULL) - { - DEBUG(0, ("mod_smbpwd_entry: unable to open file %s\n", pfile)); - return False; - } - /* Set a 16k buffer to do more efficient reads */ - setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf)); - - if ((lockfd = pw_file_lock(pfile, F_RDLCK | F_WRLCK, 5)) < 0) - { - DEBUG(0, ("mod_smbpwd_entry: unable to lock file %s\n", pfile)); - fclose(fp); - return False; - } - /* make sure it is only rw by the owner */ - chmod(pfile, 0600); - - /* We have a write lock on the file. */ - /* - * Scan the file, a line at a time and check if the name matches. - */ - while (!feof(fp)) - { - pwd_seekpos = ftell(fp); - - linebuf[0] = '\0'; - - fgets(linebuf, 256, fp); - if (ferror(fp)) - { - fclose(fp); - pw_file_unlock(lockfd); - return False; - } - - /* - * Check if the string is terminated with a newline - if not - * then we must keep reading and discard until we get one. - */ - linebuf_len = strlen(linebuf); - if (linebuf[linebuf_len - 1] != '\n') - { - c = '\0'; - while (!ferror(fp) && !feof(fp)) - { - c = fgetc(fp); - if (c == '\n') - { - break; - } - } - } - else - { - linebuf[linebuf_len - 1] = '\0'; - } + /* Static buffers we will return. */ + static pstring user_name; + + char linebuf[256]; + char readbuf[16 * 1024]; + unsigned char c; + char ascii_p16[66]; + unsigned char *p = NULL; + long linebuf_len = 0; + FILE *fp; + int lockfd; + char *pfile = lp_smb_passwd_file(); + BOOL found_entry = False; + + long pwd_seekpos = 0; + + int i; + int wr_len; + int fd; + + if (!*pfile) { + DEBUG(0, ("No SMB password file set\n")); + return False; + } + DEBUG(10, ("mod_smbpwd_entry: opening file %s\n", pfile)); + + fp = fopen(pfile, "r+"); + + if (fp == NULL) { + DEBUG(0, ("mod_smbpwd_entry: unable to open file %s\n", pfile)); + return False; + } + /* Set a 16k buffer to do more efficient reads */ + setvbuf(fp, readbuf, _IOFBF, sizeof(readbuf)); + + if ((lockfd = pw_file_lock(fileno(fp), F_RDLCK | F_WRLCK, 5)) < 0) { + DEBUG(0, ("mod_smbpwd_entry: unable to lock file %s\n", pfile)); + fclose(fp); + return False; + } + + /* Make sure it is only rw by the owner */ + chmod(pfile, 0600); + + /* We have a write lock on the file. */ + /* + * Scan the file, a line at a time and check if the name matches. + */ + while (!feof(fp)) { + pwd_seekpos = ftell(fp); + + linebuf[0] = '\0'; + + fgets(linebuf, 256, fp); + if (ferror(fp)) { + fclose(fp); + pw_file_unlock(lockfd); + return False; + } + + /* + * Check if the string is terminated with a newline - if not + * then we must keep reading and discard until we get one. + */ + linebuf_len = strlen(linebuf); + if (linebuf[linebuf_len - 1] != '\n') { + c = '\0'; + while (!ferror(fp) && !feof(fp)) { + c = fgetc(fp); + if (c == '\n') { + break; + } + } + } else { + linebuf[linebuf_len - 1] = '\0'; + } #ifdef DEBUG_PASSWORD - DEBUG(100, ("mod_smbpwd_entry: got line |%s|\n", linebuf)); + DEBUG(100, ("mod_smbpwd_entry: got line |%s|\n", linebuf)); #endif - if ((linebuf[0] == 0) && feof(fp)) - { - DEBUG(4, ("mod_smbpwd_entry: end of file reached\n")); - break; - } - - /* - * The line we have should be of the form :- - * - * username:uid:[32hex bytes]:....other flags presently - * ignored.... - * - * or, - * - * username:uid:[32hex bytes]:[32hex bytes]:....ignored.... - * - * if Windows NT compatible passwords are also present. - */ - - if (linebuf[0] == '#' || linebuf[0] == '\0') - { - DEBUG(6, ("mod_smbpwd_entry: skipping comment or blank line\n")); - continue; - } - - p = (unsigned char *) strchr(linebuf, ':'); - - if (p == NULL) - { - DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no :)\n")); - continue; - } - - /* - * As 256 is shorter than a pstring we don't need to check - * length here - if this ever changes.... - */ - strncpy(user_name, linebuf, PTR_DIFF(p, linebuf)); - user_name[PTR_DIFF(p, linebuf)] = '\0'; - if (strequal(user_name, pwd->smb_name)) - { - found_entry = True; - break; - } - } - - if (!found_entry) return False; - - DEBUG(6, ("mod_smbpwd_entry: entry exists\n")); - - /* User name matches - get uid and password */ - p++; /* Go past ':' */ - - if (!isdigit(*p)) - { - DEBUG(0, ("mod_smbpwd_entry: malformed password entry (uid not number)\n")); - fclose(fp); - pw_file_unlock(lockfd); - return False; - } - - while (*p && isdigit(*p)) - p++; - if (*p != ':') - { - DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no : after uid)\n")); - fclose(fp); - pw_file_unlock(lockfd); - return False; - } - /* - * Now get the password value - this should be 32 hex digits - * which are the ascii representations of a 16 byte string. - * Get two at a time and put them into the password. - */ - p++; - - /* record exact password position */ - pwd_seekpos += PTR_DIFF(p, linebuf); - - if (*p == '*' || *p == 'X') - { - /* Password deliberately invalid - end here. */ - DEBUG(10, ("get_smbpwd_entry: entry invalidated for user %s\n", user_name)); - fclose(fp); - pw_file_unlock(lockfd); - return False; - } - - if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) - { - DEBUG(0, ("mod_smbpwd_entry: malformed password entry (passwd too short)\n")); - fclose(fp); - pw_file_unlock(lockfd); - return (False); - } - - if (p[32] != ':') - { - DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no terminating :)\n")); - fclose(fp); - pw_file_unlock(lockfd); - return False; - } - - if (*p == '*' || *p == 'X') - { - fclose(fp); - pw_file_unlock(lockfd); - return False; - } - if (!strncasecmp((char *) p, "NO PASSWORD", 11)) - { - fclose(fp); - pw_file_unlock(lockfd); - return False; - } - - /* Now check if the NT compatible password is - available. */ - p += 33; /* Move to the first character of the line after - the lanman password. */ - if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) - { - DEBUG(0, ("mod_smbpwd_entry: malformed password entry (passwd too short)\n")); - fclose(fp); - pw_file_unlock(lockfd); - return (False); - } - - if (p[32] != ':') - { - DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no terminating :)\n")); - fclose(fp); - pw_file_unlock(lockfd); - return False; - } - - /* The following check is wrong - the NT hash is optional. */ -#if 0 - if (*p == '*' || *p == 'X') - { - fclose(fp); - pw_file_unlock(lockfd); - return False; - } -#endif - - /* whew. entry is correctly formed. */ - - /* - * Do an atomic write into the file at the position defined by - * seekpos. - */ - - /* The mod user write needs to be atomic - so get the fd from - the fp and do a raw write() call. - */ - - fd = fileno(fp); - - if (lseek(fd, pwd_seekpos - 1, SEEK_SET) != pwd_seekpos - 1) - { - DEBUG(1, ("mod_smbpwd_entry: seek fail on file %s.\n", pfile)); - fclose(fp); - pw_file_unlock(lockfd); - return False; - } - - /* Sanity check - ensure the character is a ':' */ - if (read(fd, &c, 1) != 1) - { - DEBUG(1, ("mod_smbpwd_entry: read fail on file %s.\n", pfile)); - fclose(fp); - pw_file_unlock(lockfd); - return False; - } - - if (c != ':') - { - DEBUG(1, ("mod_smbpwd_entry: check on passwd file %s failed.\n", pfile)); - fclose(fp); - pw_file_unlock(lockfd); - return False; - } + if ((linebuf[0] == 0) && feof(fp)) { + DEBUG(4, ("mod_smbpwd_entry: end of file reached\n")); + break; + } + + /* + * The line we have should be of the form :- + * + * username:uid:[32hex bytes]:....other flags presently + * ignored.... + * + * or, + * + * username:uid:[32hex bytes]:[32hex bytes]:....ignored.... + * + * if Windows NT compatible passwords are also present. + */ + + if (linebuf[0] == '#' || linebuf[0] == '\0') { + DEBUG(6, ("mod_smbpwd_entry: skipping comment or blank line\n")); + continue; + } + + p = (unsigned char *) strchr(linebuf, ':'); + + if (p == NULL) { + DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no :)\n")); + continue; + } + + /* + * As 256 is shorter than a pstring we don't need to check + * length here - if this ever changes.... + */ + strncpy(user_name, linebuf, PTR_DIFF(p, linebuf)); + user_name[PTR_DIFF(p, linebuf)] = '\0'; + if (strequal(user_name, pwd->smb_name)) { + found_entry = True; + break; + } + } + + if (!found_entry) return False; + + DEBUG(6, ("mod_smbpwd_entry: entry exists\n")); + + /* User name matches - get uid and password */ + p++; /* Go past ':' */ + + if (!isdigit(*p)) { + DEBUG(0, ("mod_smbpwd_entry: malformed password entry (uid not number)\n")); + fclose(fp); + pw_file_unlock(lockfd); + return False; + } + + while (*p && isdigit(*p)) + p++; + if (*p != ':') { + DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no : after uid)\n")); + fclose(fp); + pw_file_unlock(lockfd); + return False; + } + + /* + * Now get the password value - this should be 32 hex digits + * which are the ascii representations of a 16 byte string. + * Get two at a time and put them into the password. + */ + p++; + + /* Record exact password position */ + pwd_seekpos += PTR_DIFF(p, linebuf); + + if (*p == '*' || *p == 'X') { + /* Password deliberately invalid - end here. */ + DEBUG(10, ("get_smbpwd_entry: entry invalidated for user %s\n", user_name)); + fclose(fp); + pw_file_unlock(lockfd); + return False; + } + + if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) { + DEBUG(0, ("mod_smbpwd_entry: malformed password entry (passwd too short)\n")); + fclose(fp); + pw_file_unlock(lockfd); + return (False); + } + + if (p[32] != ':') { + DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no terminating :)\n")); + fclose(fp); + pw_file_unlock(lockfd); + return False; + } + + if (*p == '*' || *p == 'X') { + fclose(fp); + pw_file_unlock(lockfd); + return False; + } + + if (!strncasecmp((char *) p, "NO PASSWORD", 11)) { + fclose(fp); + pw_file_unlock(lockfd); + return False; + } + + /* Now check if the NT compatible password is + available. */ + p += 33; /* Move to the first character of the line after + the lanman password. */ + if (linebuf_len < (PTR_DIFF(p, linebuf) + 33)) { + DEBUG(0, ("mod_smbpwd_entry: malformed password entry (passwd too short)\n")); + fclose(fp); + pw_file_unlock(lockfd); + return (False); + } + + if (p[32] != ':') { + DEBUG(0, ("mod_smbpwd_entry: malformed password entry (no terminating :)\n")); + fclose(fp); + pw_file_unlock(lockfd); + return False; + } + + /* Entry is correctly formed. */ + + /* + * Do an atomic write into the file at the position defined by + * seekpos. + */ + + /* The mod user write needs to be atomic - so get the fd from + the fp and do a raw write() call. + */ + + fd = fileno(fp); + + if (lseek(fd, pwd_seekpos - 1, SEEK_SET) != pwd_seekpos - 1) { + DEBUG(0, ("mod_smbpwd_entry: seek fail on file %s.\n", pfile)); + fclose(fp); + pw_file_unlock(lockfd); + return False; + } + + /* Sanity check - ensure the character is a ':' */ + if (read(fd, &c, 1) != 1) { + DEBUG(0, ("mod_smbpwd_entry: read fail on file %s.\n", pfile)); + fclose(fp); + pw_file_unlock(lockfd); + return False; + } + + if (c != ':') { + DEBUG(0, ("mod_smbpwd_entry: check on passwd file %s failed.\n", pfile)); + fclose(fp); + pw_file_unlock(lockfd); + return False; + } - /* Create the 32 byte representation of the new p16 */ - for (i = 0; i < 16; i++) - { - sprintf(&ascii_p16[i*2], "%02X", (uchar) pwd->smb_passwd[i]); - } - /* Add on the NT md4 hash */ - ascii_p16[32] = ':'; - wr_len = 65; - if (pwd->smb_nt_passwd != NULL) - { - for (i = 0; i < 16; i++) - { - sprintf(&ascii_p16[(i*2)+33], "%02X", (uchar) pwd->smb_nt_passwd[i]); - } - } - else - { - /* No NT hash - write out an 'invalid' string. */ - strcpy(&ascii_p16[33], "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); - } + /* Create the 32 byte representation of the new p16 */ + for (i = 0; i < 16; i++) { + sprintf(&ascii_p16[i*2], "%02X", (uchar) pwd->smb_passwd[i]); + } + + /* Add on the NT md4 hash */ + ascii_p16[32] = ':'; + wr_len = 65; + if (pwd->smb_nt_passwd != NULL) { + for (i = 0; i < 16; i++) { + sprintf(&ascii_p16[(i*2)+33], "%02X", (uchar) pwd->smb_nt_passwd[i]); + } + } else { + /* No NT hash - write out an 'invalid' string. */ + strcpy(&ascii_p16[33], "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); + } #ifdef DEBUG_PASSWORD - DEBUG(100,("mod_smbpwd_entry: ")); - dump_data(100, ascii_p16, wr_len); + DEBUG(100,("mod_smbpwd_entry: ")); + dump_data(100, ascii_p16, wr_len); #endif - if (write(fd, ascii_p16, wr_len) != wr_len) - { - DEBUG(1, ("mod_smbpwd_entry: write failed in passwd file %s\n", pfile)); - fclose(fp); - pw_file_unlock(lockfd); - return False; - } - - fclose(fp); - pw_file_unlock(lockfd); - return True; + if (write(fd, ascii_p16, wr_len) != wr_len) { + DEBUG(0, ("mod_smbpwd_entry: write failed in passwd file %s\n", pfile)); + fclose(fp); + pw_file_unlock(lockfd); + return False; + } + + fclose(fp); + pw_file_unlock(lockfd); + return True; } |