From bd529d7a83c35be233baca09bc79aa911ad443ce Mon Sep 17 00:00:00 2001 From: Luke Leighton Date: Thu, 6 Nov 1997 23:03:58 +0000 Subject: following a cvs error, i am rewriting this monster-commit. with bad grace. Modified Files: --------------- Makefile: adding extra files ipc.c : send_trans_reply() - alignment issue. this makes the alignment the same as that in NT. this should be looked at by people who understand the SMB stuff better than i. api_fd_commands[] - added samr and wkssvc pipes. loadparm.c : lp_domain_controller() changed to mean "samba is a domain controller". it's a "yes/no" parameter, now. no, it isn't used _anywhere_. namedbwork.c nameelect.c : if "domain controller = yes" then add SV_TYPE_DOMAIN_CTRL to the host _and_ workgroup announcements. yes, you must do both: nt does. namelogon.c : important NETLOGON bug in SAMLOGON request parsing, which may be the source of some people's problems with logging on to the Samba PDC. password.c : get_smbpwnam() renamed to get_smbpwd_entry(). pipes.c : added samr and wkssvc pipes. proto.h : usual. can we actually _remove_ proto.h from the cvs tree, and have it as one of the Makefile dependencies, or something? reply.c : get_smbpwnam() renamed to get_smbpwd_entry() - also changed response error code when logging in from a WORKSTATION$ account. yes, paul is right: we need to know when to return the right error code, and why. server.c : added call to reset_chain_pnum(). #ifdef NTDOMAIN added call to init_lsa_policy_hnd() #endif. jeremy, you'd be proud: i did a compile without NTDOMAIN, and caught a link error for this function. smb.h : defines and structures for samr and wkssvc pipes. smbpass.c : modified get_smbpwnam() to get_smbpwd_entry() and it now takes two arguments. one for the name; if this is null, it looks up by smb_userid instead. oh, by the way, smb_userids are actually domain relative ids (RIDs). concatenate a RID with the domain SID, and you have an internet globally unique way of identifying a user. we're using RIDs in the wrong way.... added mod_smbpwnam() function. this was based on code in smbpasswd.c rpc_pipes/lsaparse.c : added enum trusted domain parsing. this is incomplete: i need a packet trace to write it properly. rpc_pipes/pipe_hnd.c : added reset_chain_pnum() function. rpc_pipes/pipenetlog.c : get_smbpwnam() function renamed to get_smbpwd_entry(). arcfour() issues. removed capability of get_md4pw() function to automatically add workstation accounts. this should either be done using smbpasswd -add MACHINE$, or by using \PIPE\samr. rpc_pipes/pipe_util.c : create_pol_hnd() - creates a unique LSA Policy Handle. overkill function: uses a 64 bit sequence number; current unix time and the smbd pid. rpc_pipes/smbparse.c : arcfour() issues. smb_io_unistr2() should advance by uni_str_len not uni_max_len. smb_io_smb_hdr_rb() - request bind uses uint16 for the context id, and uint8 for the num_syntaxes. oops, i put these both as uint32s. Added Files: ------------ rpc_pipes/lsa_hnd.c : on the samr pipe, allocate and associate an LSA Policy Handle with a SID. you receive queries with the LSA Policy Handle, and have to turn this back into a SID in order to answer the query... rpc_pipes/pipesamr.c rpc_pipes/samrparse.c \PIPE\samr processing. samr i presume is the SAM Replication pipe. rpc_pipes/pipewkssvc.c rpc_pipes/wksparse.c \PIPE\wkssvc processing. the Workstation Service pipe? holy cow. (This used to be commit 1bd084b3e690eb26a1006d616075e53d711ecd2f) --- source3/passdb/smbpass.c | 442 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 401 insertions(+), 41 deletions(-) (limited to 'source3/passdb') diff --git a/source3/passdb/smbpass.c b/source3/passdb/smbpass.c index daa1064750..2c533f16f9 100644 --- a/source3/passdb/smbpass.c +++ b/source3/passdb/smbpass.c @@ -103,10 +103,11 @@ static int gethexpwd(char *p, char *pwd) return (True); } -/* - * Routine to search the smbpasswd file for an entry matching the username. - */ -struct smb_passwd *get_smbpwnam(char *name) +/************************************************************************* + 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 struct smb_passwd pw_buf; @@ -127,19 +128,28 @@ struct smb_passwd *get_smbpwnam(char *name) DEBUG(0, ("No SMB password file set\n")); return (NULL); } - DEBUG(10, ("get_smbpwnam: opening file %s\n", pfile)); + 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_smbpwnam: unable to open file %s\n", pfile)); + 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_smbpwnam: unable to lock file %s\n", pfile)); + DEBUG(0, ("get_smbpwd_entry: unable to lock file %s\n", pfile)); fclose(fp); return NULL; } @@ -175,10 +185,10 @@ struct smb_passwd *get_smbpwnam(char *name) linebuf[linebuf_len - 1] = '\0'; #ifdef DEBUG_PASSWORD - DEBUG(100, ("get_smbpwnam: got line |%s|\n", linebuf)); + DEBUG(100, ("get_smbpwd_entry: got line |%s|\n", linebuf)); #endif if ((linebuf[0] == 0) && feof(fp)) { - DEBUG(4, ("get_smbpwnam: end of file reached\n")); + DEBUG(4, ("get_smbpwd_entry: end of file reached\n")); break; } /* @@ -195,12 +205,12 @@ struct smb_passwd *get_smbpwnam(char *name) */ if (linebuf[0] == '#' || linebuf[0] == '\0') { - DEBUG(6, ("get_smbpwnam: skipping comment or blank line\n")); + DEBUG(6, ("get_smbpwd_entry: skipping comment or blank line\n")); continue; } p = (unsigned char *) strchr(linebuf, ':'); if (p == NULL) { - DEBUG(0, ("get_smbpwnam: malformed password entry (no :)\n")); + DEBUG(0, ("get_smbpwd_entry: malformed password entry (no :)\n")); continue; } /* @@ -209,55 +219,89 @@ struct smb_passwd *get_smbpwnam(char *name) */ strncpy(user_name, linebuf, PTR_DIFF(p, linebuf)); user_name[PTR_DIFF(p, linebuf)] = '\0'; - if (!strequal(user_name, name)) - continue; - /* User name matches - get uid and password */ + /* get smb uid */ + p++; /* Go past ':' */ if (!isdigit(*p)) { - DEBUG(0, ("get_smbpwnam: malformed password entry (uid not number)\n")); + DEBUG(0, ("get_smbpwd_entry: malformed password entry (uid not number)\n")); fclose(fp); pw_file_unlock(lockfd); return NULL; } + uidval = atoi((char *) p); + while (*p && isdigit(*p)) + { p++; - if (*p != ':') { - DEBUG(0, ("get_smbpwnam: malformed password entry (no : after uid)\n")); + } + + if (*p != ':') + { + DEBUG(0, ("get_smbpwd_entry: malformed password entry (no : after uid)\n")); fclose(fp); pw_file_unlock(lockfd); return NULL; } + + 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') { + + if (*p == '*' || *p == 'X') + { /* Password deliberately invalid - end here. */ - DEBUG(10, ("get_smbpwnam: entry invalidated for user %s\n", user_name)); + 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_smbpwnam: malformed password entry (passwd too short)\n")); + + 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_smbpwnam: malformed password entry (no terminating :)\n")); + + 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)) { + + if (!strncasecmp((char *) p, "NO PASSWORD", 11)) + { pw_buf.smb_passwd = NULL; - } else { - if(!gethexpwd((char *)p,(char *)smbpwd)) { + } + else + { + if (!gethexpwd((char *)p, (char *)smbpwd)) + { DEBUG(0, ("Malformed Lanman password entry (non hex chars)\n")); fclose(fp); pw_file_unlock(lockfd); @@ -265,6 +309,7 @@ struct smb_passwd *get_smbpwnam(char *name) } pw_buf.smb_passwd = smbpwd; } + pw_buf.smb_name = user_name; pw_buf.smb_userid = uidval; pw_buf.smb_nt_passwd = NULL; @@ -282,7 +327,7 @@ struct smb_passwd *get_smbpwnam(char *name) fclose(fp); pw_file_unlock(lockfd); - DEBUG(5, ("get_smbpwname: returning passwd entry for user %s, uid %d\n", + DEBUG(5, ("get_smbpwd_entrye: returning passwd entry for user %s, uid %d\n", user_name, uidval)); return &pw_buf; } @@ -291,10 +336,11 @@ struct smb_passwd *get_smbpwnam(char *name) pw_file_unlock(lockfd); return NULL; } + /* * Routine to search the smbpasswd file for an entry matching the username. */ -BOOL add_smbpwnam(struct smb_passwd* pwd) +BOOL add_smbpwd_entry(struct smb_passwd* pwd) { /* Static buffers we will return. */ static pstring user_name; @@ -321,13 +367,13 @@ BOOL add_smbpwnam(struct smb_passwd* pwd) DEBUG(0, ("No SMB password file set\n")); return False; } - DEBUG(10, ("add_smbpwnam: opening file %s\n", pfile)); + DEBUG(10, ("add_smbpwd_entry: opening file %s\n", pfile)); fp = fopen(pfile, "r+"); if (fp == NULL) { - DEBUG(0, ("add_smbpwnam: unable to open file %s\n", pfile)); + DEBUG(0, ("add_smbpwd_entry: unable to open file %s\n", pfile)); return False; } /* Set a 16k buffer to do more efficient reads */ @@ -335,7 +381,7 @@ BOOL add_smbpwnam(struct smb_passwd* pwd) if ((lockfd = pw_file_lock(pfile, F_RDLCK | F_WRLCK, 5)) < 0) { - DEBUG(0, ("add_smbpwnam: unable to lock file %s\n", pfile)); + DEBUG(0, ("add_smbpwd_entry: unable to lock file %s\n", pfile)); fclose(fp); return False; } @@ -381,12 +427,12 @@ BOOL add_smbpwnam(struct smb_passwd* pwd) } #ifdef DEBUG_PASSWORD - DEBUG(100, ("add_smbpwnam: got line |%s|\n", linebuf)); + DEBUG(100, ("add_smbpwd_entry: got line |%s|\n", linebuf)); #endif if ((linebuf[0] == 0) && feof(fp)) { - DEBUG(4, ("add_smbpwnam: end of file reached\n")); + DEBUG(4, ("add_smbpwd_entry: end of file reached\n")); break; } @@ -405,7 +451,7 @@ BOOL add_smbpwnam(struct smb_passwd* pwd) if (linebuf[0] == '#' || linebuf[0] == '\0') { - DEBUG(6, ("add_smbpwnam: skipping comment or blank line\n")); + DEBUG(6, ("add_smbpwd_entry: skipping comment or blank line\n")); continue; } @@ -413,7 +459,7 @@ BOOL add_smbpwnam(struct smb_passwd* pwd) if (p == NULL) { - DEBUG(0, ("add_smbpwnam: malformed password entry (no :)\n")); + DEBUG(0, ("add_smbpwd_entry: malformed password entry (no :)\n")); continue; } @@ -425,7 +471,7 @@ BOOL add_smbpwnam(struct smb_passwd* pwd) user_name[PTR_DIFF(p, linebuf)] = '\0'; if (strequal(user_name, pwd->smb_name)) { - DEBUG(6, ("add_smbpwnam: entry already exists\n")); + DEBUG(6, ("add_smbpwd_entry: entry already exists\n")); return False; } } @@ -440,7 +486,7 @@ BOOL add_smbpwnam(struct smb_passwd* pwd) if((offpos = lseek(fd, 0, SEEK_END)) == -1) { - DEBUG(0, ("add_smbpwnam(lseek): Failed to add entry for user %s to file %s. \ + 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))); fclose(fp); @@ -452,7 +498,7 @@ Error was %s\n", pwd->smb_name, pfile, strerror(errno))); if((new_entry = (char *)malloc( new_entry_length )) == 0) { - DEBUG(0, ("add_smbpwnam(malloc): Failed to add entry for user %s to file %s. \ + 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))); @@ -482,19 +528,19 @@ Error was %s\n", sprintf(p,"\n"); #ifdef DEBUG_PASSWORD - DEBUG(100, ("add_smbpwnam(%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_smbpwnam(write): %d Failed to add entry for user %s to file %s. \ + 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_smbpwnam: ERROR failed to ftruncate file %s. \ + 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))); } @@ -508,3 +554,317 @@ Error was %s. Password file may be corrupt ! Please examine by hand !\n", pw_file_unlock(lockfd); return True; } +/* + * Routine to search the smbpasswd file for an entry matching the username. + * and then modify its password entry + */ +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; + long linebuf_len; + FILE *fp; + int lockfd; + char *pfile = lp_smb_passwd_file(); + + BOOL found_entry = True; + 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, ("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)) + { + 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, ("add_smbpwd_entry: got line |%s|\n", linebuf)); +#endif + + 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")); + found_entry = True; + break; + } + + /* 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; + } + + if (*p == '*' || *p == 'X') + { + fclose(fp); + pw_file_unlock(lockfd); + return False; + } + + /* whew. entry is correctly formed. */ + break; + } + + /* + * 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; + } + + /* 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]); + } + if (pwd->smb_nt_passwd != NULL) + { + /* Add on the NT md4 hash */ + ascii_p16[32] = ':'; + for (i = 0; i < 16; i++) + { + sprintf(&ascii_p16[(i*2)+33], "%02X", (uchar) pwd->smb_nt_passwd[i]); + } + wr_len = 65; + } + else + { + wr_len = 32; + } + +#ifdef DEBUG_PASSWORD + 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; +} -- cgit