From 0f1eee5c7ac4031cd2a97524b1f65a24d0d618c2 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 25 Feb 2000 22:25:25 +0000 Subject: client/client.c: libsmb/clientgen.c: Fixes for Win2k smbclient browsing. Other fixes implement smbpasswd -x user to delete users. Also allows swat to do the same. Jeremy. (This used to be commit 9f6ad046761adecafba59040baa3abc9f0959e65) --- source3/client/client.c | 7 +- source3/include/proto.h | 7 +- source3/include/smb.h | 12 ++ source3/libsmb/clientgen.c | 10 +- source3/passdb/ldap.c | 6 + source3/passdb/nispass.c | 6 + source3/passdb/passdb.c | 9 ++ source3/passdb/smbpass.c | 358 +++++++++++++++++++++++++++++++++-------- source3/passdb/smbpasschange.c | 70 ++++---- source3/utils/smbpasswd.c | 96 +++++------ source3/web/swat.c | 40 +++-- 11 files changed, 453 insertions(+), 168 deletions(-) diff --git a/source3/client/client.c b/source3/client/client.c index 6beff70c9b..ea029d4df7 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -1560,10 +1560,15 @@ try and browse available connections on a host ****************************************************************************/ static BOOL browse_host(BOOL sort) { + int ret; + printf("\n\tSharename Type Comment\n"); printf("\t--------- ---- -------\n"); - return cli_RNetShareEnum(cli, browse_fn); + if((ret = cli_RNetShareEnum(cli, browse_fn)) == -1) + printf("Error returning browse list: %s\n", cli_errstr(cli)); + + return (ret != -1); } /**************************************************************************** diff --git a/source3/include/proto.h b/source3/include/proto.h index 934ec5a4c8..830e7bc5b1 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -573,7 +573,7 @@ BOOL cli_api(struct cli_state *cli, char **rparam, int *rprcnt, char **rdata, int *rdrcnt); BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation); -BOOL cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *)); +int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *)); BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype, void (*fn)(const char *, uint32, const char *)); BOOL cli_session_setup(struct cli_state *cli, @@ -1426,6 +1426,7 @@ void endsmbpwent(void *vp); struct smb_passwd *getsmbpwent(void *vp); BOOL add_smbpwd_entry(struct smb_passwd *newpwd); BOOL mod_smbpwd_entry(struct smb_passwd* pwd, BOOL override); +BOOL del_smbpwd_entry(const char *name); struct smb_passwd *getsmbpwnam(char *name); struct smb_passwd *getsmbpwrid(uint32 user_rid); struct smb_passwd *getsmbpwuid(uid_t smb_userid); @@ -1464,12 +1465,12 @@ BOOL lookup_local_name(char *domain, char *user, DOM_SID *psid, uint8 *psid_name /*The following definitions come from passdb/smbpass.c */ +char *format_new_smbpasswd_entry(struct smb_passwd *newpwd); struct passdb_ops *file_initialize_password_db(void); /*The following definitions come from passdb/smbpasschange.c */ -BOOL local_password_change(char *user_name, BOOL trust_account, BOOL add_user, - BOOL enable_user, BOOL disable_user, BOOL set_no_password, +BOOL local_password_change(char *user_name, int local_flags, char *new_passwd, char *err_str, size_t err_str_len, char *msg_str, size_t msg_str_len); diff --git a/source3/include/smb.h b/source3/include/smb.h index 18b2cb1542..54fb4d5cc7 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -747,6 +747,7 @@ struct passdb_ops { */ BOOL (*add_smbpwd_entry)(struct smb_passwd *); BOOL (*mod_smbpwd_entry)(struct smb_passwd *, BOOL); + BOOL (*del_smbpwd_entry)(const char *); /* * Functions that manupulate a struct sam_passwd. @@ -783,6 +784,17 @@ struct passdb_ops { #endif }; +/* + * Flags for local user manipulation. + */ + +#define LOCAL_ADD_USER 0x1 +#define LOCAL_DELETE_USER 0x2 +#define LOCAL_DISABLE_USER 0x4 +#define LOCAL_ENABLE_USER 0x8 +#define LOCAL_TRUST_ACCOUNT 0x10 +#define LOCAL_SET_NO_PASSWORD 0x20 + /* key and data in the connections database - used in smbstatus and smbd */ struct connections_key { pid_t pid; diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index df3df0b4ba..8d7dbec859 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -600,7 +600,7 @@ BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation) /**************************************************************************** call a NetShareEnum - try and browse available connections on a host ****************************************************************************/ -BOOL cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *)) +int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *)) { char *rparam = NULL; char *rdata = NULL; @@ -618,12 +618,16 @@ BOOL cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, c pstrcpy(p,"B13BWz"); p = skip_string(p,1); SSVAL(p,0,1); - SSVAL(p,2,0xFFFF); + /* + * Win2k needs a *smaller* buffer than 0xFFFF here - + * it returns "out of server memory" with 0xFFFF !!! JRA. + */ + SSVAL(p,2,0xFFE0); p += 4; if (cli_api(cli, param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */ - NULL, 0, 0xFFFF, /* data, length, maxlen */ + NULL, 0, 0xFFE0, /* data, length, maxlen - Win2k needs a small buffer here too ! */ &rparam, &rprcnt, /* return params, length */ &rdata, &rdrcnt)) /* return data, length */ { diff --git a/source3/passdb/ldap.c b/source3/passdb/ldap.c index 43fea00a64..54566e454b 100644 --- a/source3/passdb/ldap.c +++ b/source3/passdb/ldap.c @@ -970,6 +970,11 @@ static BOOL mod_ldappwd_entry(struct smb_passwd* pwd, BOOL override) return mod_ldap21pwd_entry(pdb_smb_to_sam(pwd), override); } +static BOOL del_ldappwd_entry(const char *name) +{ + return False; /* Dummy... */ +} + static struct sam_disp_info *getldapdispnam(char *name) { return pdb_sam_to_dispinfo(getldap21pwnam(name)); @@ -1002,6 +1007,7 @@ static struct passdb_ops ldap_ops = getldappwent, add_ldappwd_entry, mod_ldappwd_entry, + del_ldappwd_entry, getldap21pwent, iterate_getsam21pwnam, /* From passdb.c */ iterate_getsam21pwuid, /* From passdb.c */ diff --git a/source3/passdb/nispass.c b/source3/passdb/nispass.c index 27409eca4c..4b4e281c29 100644 --- a/source3/passdb/nispass.c +++ b/source3/passdb/nispass.c @@ -1005,6 +1005,11 @@ static BOOL mod_nisppwd_entry(struct smb_passwd* pwd, BOOL override) return mod_nisp21pwd_entry(pdb_smb_to_sam(pwd), override); } +static BOOL del_nisppwd_entry(const char *name) +{ + return False; /* Dummy. */ +} + static struct smb_passwd *getnisppwnam(char *name) { return pdb_sam_to_smb(getnisp21pwnam(name)); @@ -1051,6 +1056,7 @@ static struct passdb_ops nispasswd_ops = { getnisppwent, add_nisppwd_entry, mod_nisppwd_entry, + del_nisppwd_entry, getnisp21pwent, getnisp21pwnam, getnisp21pwuid, diff --git a/source3/passdb/passdb.c b/source3/passdb/passdb.c index f6502c238c..30ea1d9bd6 100644 --- a/source3/passdb/passdb.c +++ b/source3/passdb/passdb.c @@ -225,6 +225,15 @@ BOOL mod_smbpwd_entry(struct smb_passwd* pwd, BOOL override) return pdb_ops->mod_smbpwd_entry(pwd, override); } +/************************************************************************ + Routine to delete an entry from the smb passwd file. +*************************************************************************/ + +BOOL del_smbpwd_entry(const char *name) +{ + return pdb_ops->del_smbpwd_entry(name); +} + /************************************************************************ Routine to search smb passwd by name. *************************************************************************/ diff --git a/source3/passdb/smbpass.c b/source3/passdb/smbpass.c index 4cfac6d948..4ca37a9296 100644 --- a/source3/passdb/smbpass.c +++ b/source3/passdb/smbpass.c @@ -28,39 +28,127 @@ extern BOOL sam_logon_in_ssb; static char s_readbuf[1024]; static int pw_file_lock_depth; +enum pwf_access_type { PWF_READ, PWF_UPDATE, PWF_CREATE }; + /*************************************************************** - Start to enumerate the smbpasswd list. Returns a void pointer - to ensure no modification outside this module. + Internal fn to enumerate the smbpasswd list. Returns a void pointer + to ensure no modification outside this module. Checks for atomic + rename of smbpasswd file on update or create once the lock has + been granted to prevent race conditions. JRA. ****************************************************************/ -static void *startsmbfilepwent(BOOL update) +static void *startsmbfilepwent_internal(const char *pfile, enum pwf_access_type type, int *lock_depth) { FILE *fp = NULL; - char *pfile = lp_smb_passwd_file(); + const char *open_mode = NULL; + int race_loop = 0; + int lock_type; if (!*pfile) { DEBUG(0, ("startsmbfilepwent: No SMB password file set\n")); return (NULL); } - DEBUG(10, ("startsmbfilepwent: opening file %s\n", pfile)); - fp = sys_fopen(pfile, update ? "r+b" : "rb"); + switch(type) { + case PWF_READ: + open_mode = "rb"; + lock_type = F_RDLCK; + break; + case PWF_UPDATE: + open_mode = "r+b"; + lock_type = F_WRLCK; + break; + case PWF_CREATE: + /* + * Ensure atomic file creation. + */ + { + int i, fd = -1; - if (fp == NULL) { - DEBUG(0, ("startsmbfilepwent: unable to open file %s\n", pfile)); - return NULL; + for(i = 0; i < 5; i++) { + if((fd = sys_open(pfile, O_CREAT|O_TRUNC|O_EXCL|O_RDWR, 0600))!=-1) + break; + sys_usleep(200); /* Spin, spin... */ + } + if(fd == -1) { + DEBUG(0,("startsmbfilepwent_internal: too many race conditions creating file %s\n", pfile)); + return NULL; + } + close(fd); + open_mode = "r+b"; + lock_type = F_WRLCK; + break; + } } + + for(race_loop = 0; race_loop < 5; race_loop++) { + DEBUG(10, ("startsmbfilepwent_internal: opening file %s\n", pfile)); - /* Set a buffer to do more efficient reads */ - setvbuf(fp, s_readbuf, _IOFBF, sizeof(s_readbuf)); + if((fp = sys_fopen(pfile, open_mode)) == NULL) { + DEBUG(0, ("startsmbfilepwent_internal: unable to open file %s. Error was %s\n", pfile, strerror(errno) )); + return NULL; + } - if (!pw_file_lock(fileno(fp), (update ? F_WRLCK : F_RDLCK), 5, &pw_file_lock_depth)) - { - DEBUG(0, ("startsmbfilepwent: unable to lock file %s\n", pfile)); - fclose(fp); + if (!pw_file_lock(fileno(fp), lock_type, 5, lock_depth)) { + DEBUG(0, ("startsmbfilepwent_internal: unable to lock file %s. Error was %s\n", pfile, strerror(errno) )); + fclose(fp); + return NULL; + } + + /* + * Only check for replacement races on update or create. + * For read we don't mind if the data is one record out of date. + */ + + if(type == PWF_READ) { + break; + } else { + SMB_STRUCT_STAT sbuf1, sbuf2; + + /* + * Avoid the potential race condition between the open and the lock + * by doing a stat on the filename and an fstat on the fd. If the + * two inodes differ then someone did a rename between the open and + * the lock. Back off and try the open again. Only do this 5 times to + * prevent infinate loops. JRA. + */ + + if (sys_stat(pfile,&sbuf1) != 0) { + DEBUG(0, ("startsmbfilepwent_internal: unable to stat file %s. Error was %s\n", pfile, strerror(errno))); + pw_file_unlock(fileno(fp), lock_depth); + fclose(fp); + return False; + } + + if (sys_fstat(fileno(fp),&sbuf2) != 0) { + DEBUG(0, ("startsmbfilepwent_internal: unable to fstat file %s. Error was %s\n", pfile, strerror(errno))); + pw_file_unlock(fileno(fp), lock_depth); + fclose(fp); + return False; + } + + if( sbuf1.st_ino == sbuf2.st_ino) { + /* No race. */ + break; + } + + /* + * Race occurred - back off and try again... + */ + + pw_file_unlock(fileno(fp), lock_depth); + fclose(fp); + } + } + + if(race_loop == 5) { + DEBUG(0, ("startsmbfilepwent_internal: too many race conditions opening file %s\n", pfile)); return NULL; } + /* Set a buffer to do more efficient reads */ + setvbuf(fp, s_readbuf, _IOFBF, sizeof(s_readbuf)); + /* Make sure it is only rw by the owner */ chmod(pfile, 0600); @@ -68,22 +156,43 @@ static void *startsmbfilepwent(BOOL update) return (void *)fp; } +/*************************************************************** + Start to enumerate the smbpasswd list. Returns a void pointer + to ensure no modification outside this module. +****************************************************************/ + +static void *startsmbfilepwent(BOOL update) +{ + return startsmbfilepwent_internal(lp_smb_passwd_file(), update ? PWF_UPDATE : PWF_READ, &pw_file_lock_depth); +} + /*************************************************************** End enumeration of the smbpasswd list. ****************************************************************/ -static void endsmbfilepwent(void *vp) +static void endsmbfilepwent_internal(void *vp, int *lock_depth) { FILE *fp = (FILE *)vp; - pw_file_unlock(fileno(fp), &pw_file_lock_depth); + pw_file_unlock(fileno(fp), lock_depth); fclose(fp); - DEBUG(7, ("endsmbfilepwent: closed password file.\n")); + DEBUG(7, ("endsmbfilepwent_internal: closed password file.\n")); +} + +/*************************************************************** + End enumeration of the smbpasswd list - operate on the default + lock_depth. +****************************************************************/ + +static void endsmbfilepwent(void *vp) +{ + endsmbfilepwent_internal(vp, &pw_file_lock_depth); } /************************************************************************* Routine to return the next entry in the smbpasswd list. *************************************************************************/ + static struct smb_passwd *getsmbfilepwent(void *vp) { /* Static buffers we will return. */ @@ -431,6 +540,65 @@ static BOOL setsmbfilepwpos(void *vp, SMB_BIG_UINT tok) return !sys_fseek((FILE *)vp, (SMB_OFF_T)tok, SEEK_SET); } +/************************************************************************ + Create a new smbpasswd entry - malloced space returned. +*************************************************************************/ + +char *format_new_smbpasswd_entry(struct smb_passwd *newpwd) +{ + int new_entry_length; + char *new_entry; + char *p; + int i; + + new_entry_length = strlen(newpwd->smb_name) + 1 + 15 + 1 + 32 + 1 + 32 + 1 + NEW_PW_FORMAT_SPACE_PADDED_LEN + 1 + 13 + 2; + + if((new_entry = (char *)malloc( new_entry_length )) == NULL) { + DEBUG(0, ("format_new_smbpasswd_entry: Malloc failed adding entry for user %s.\n", newpwd->smb_name )); + return NULL; + } + + slprintf(new_entry, new_entry_length - 1, "%s:%u:", newpwd->smb_name, (unsigned)newpwd->smb_userid); + p = &new_entry[strlen(new_entry)]; + + if(newpwd->smb_passwd != NULL) { + for( i = 0; i < 16; i++) { + slprintf((char *)&p[i*2], new_entry_length - (p - new_entry) - 1, "%02X", newpwd->smb_passwd[i]); + } + } else { + i=0; + if(newpwd->acct_ctrl & ACB_PWNOTREQ) + safe_strcpy((char *)p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry)); + else + safe_strcpy((char *)p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry)); + } + + p += 32; + + *p++ = ':'; + + if(newpwd->smb_nt_passwd != NULL) { + for( i = 0; i < 16; i++) { + slprintf((char *)&p[i*2], new_entry_length - 1 - (p - new_entry), "%02X", newpwd->smb_nt_passwd[i]); + } + } else { + if(newpwd->acct_ctrl & ACB_PWNOTREQ) + safe_strcpy((char *)p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry)); + else + safe_strcpy((char *)p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry)); + } + + p += 32; + + *p++ = ':'; + + /* Add the account encoding and the last change time. */ + slprintf((char *)p, new_entry_length - 1 - (p - new_entry), "%s:LCT-%08X:\n", + pdb_encode_acct_ctrl(newpwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN), (uint32)time(NULL)); + + return new_entry; +} + /************************************************************************ Routine to add an entry to the smbpasswd file. *************************************************************************/ @@ -440,15 +608,11 @@ static BOOL add_smbfilepwd_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; + size_t new_entry_length; char *new_entry; SMB_OFF_T offpos; - char *p; /* Open the smbpassword file - for update. */ fp = startsmbfilepwent(True); @@ -486,59 +650,21 @@ Error was %s\n", newpwd->smb_name, pfile, strerror(errno))); return False; } - new_entry_length = strlen(newpwd->smb_name) + 1 + 15 + 1 + 32 + 1 + 32 + 1 + NEW_PW_FORMAT_SPACE_PADDED_LEN + 1 + 13 + 2; - - if((new_entry = (char *)malloc( new_entry_length )) == NULL) { + if((new_entry = format_new_smbpasswd_entry(newpwd)) == NULL) { DEBUG(0, ("add_smbfilepwd_entry(malloc): Failed to add entry for user %s to file %s. \ Error was %s\n", newpwd->smb_name, pfile, strerror(errno))); endsmbfilepwent(fp); return False; } - slprintf(new_entry, new_entry_length - 1, "%s:%u:", newpwd->smb_name, (unsigned)newpwd->smb_userid); - p = &new_entry[strlen(new_entry)]; - - if(newpwd->smb_passwd != NULL) { - for( i = 0; i < 16; i++) { - slprintf((char *)&p[i*2], new_entry_length - (p - new_entry) - 1, "%02X", newpwd->smb_passwd[i]); - } - } else { - i=0; - if(newpwd->acct_ctrl & ACB_PWNOTREQ) - safe_strcpy((char *)p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry)); - else - safe_strcpy((char *)p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry)); - } - - p += 32; - - *p++ = ':'; - - if(newpwd->smb_nt_passwd != NULL) { - for( i = 0; i < 16; i++) { - slprintf((char *)&p[i*2], new_entry_length - 1 - (p - new_entry), "%02X", newpwd->smb_nt_passwd[i]); - } - } else { - if(newpwd->acct_ctrl & ACB_PWNOTREQ) - safe_strcpy((char *)p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry)); - else - safe_strcpy((char *)p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", new_entry_length - 1 - (p - new_entry)); - } - - p += 32; - - *p++ = ':'; - - /* Add the account encoding and the last change time. */ - slprintf((char *)p, new_entry_length - 1 - (p - new_entry), "%s:LCT-%08X:\n", - pdb_encode_acct_ctrl(newpwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN), (uint32)time(NULL)); + new_entry_length = strlen(new_entry); #ifdef DEBUG_PASSWORD - DEBUG(100, ("add_smbfilepwd_entry(%d): new_entry_len %d entry_len %d made line |%s|", - fd, new_entry_length, strlen(new_entry), new_entry)); + DEBUG(100, ("add_smbfilepwd_entry(%d): new_entry_len %d made line |%s|", + fd, new_entry_length, new_entry)); #endif - if ((wr_len = write(fd, new_entry, strlen(new_entry))) != strlen(new_entry)) { + if ((wr_len = write(fd, new_entry, new_entry_length)) != new_entry_length) { DEBUG(0, ("add_smbfilepwd_entry(write): %d Failed to add entry for user %s to file %s. \ Error was %s\n", wr_len, newpwd->smb_name, pfile, strerror(errno))); @@ -960,6 +1086,105 @@ static BOOL mod_smbfilepwd_entry(struct smb_passwd* pwd, BOOL override) return True; } +/************************************************************************ + Routine to delete an entry in the smbpasswd file by name. +*************************************************************************/ + +static BOOL del_smbfilepwd_entry(const char *name) +{ + char *pfile = lp_smb_passwd_file(); + pstring pfile2; + struct smb_passwd *pwd = NULL; + FILE *fp = NULL; + FILE *fp_write = NULL; + int pfile2_lockdepth = 0; + + slprintf(pfile2, sizeof(pfile2)-1, "%s.%u", pfile, (unsigned)getpid() ); + + /* + * Open the smbpassword file - for update. It needs to be update + * as we need any other processes to wait until we have replaced + * it. + */ + + if((fp = startsmbfilepwent(True)) == NULL) { + DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile)); + return False; + } + + /* + * Create the replacement password file. + */ + if((fp_write = startsmbfilepwent_internal(pfile2, PWF_CREATE, &pfile2_lockdepth)) == NULL) { + DEBUG(0, ("del_smbfilepwd_entry: unable to open file %s.\n", pfile)); + endsmbfilepwent(fp); + return False; + } + + /* + * Scan the file, a line at a time and check if the name matches. + */ + + while ((pwd = getsmbfilepwent(fp)) != NULL) { + char *new_entry; + size_t new_entry_length; + + if (strequal(name, pwd->smb_name)) { + DEBUG(10, ("add_smbfilepwd_entry: found entry with name %s - deleting it.\n", name)); + continue; + } + + /* + * We need to copy the entry out into the second file. + */ + + if((new_entry = format_new_smbpasswd_entry(pwd)) == NULL) { + DEBUG(0, ("del_smbfilepwd_entry(malloc): Failed to copy entry for user %s to file %s. \ +Error was %s\n", pwd->smb_name, pfile2, strerror(errno))); + unlink(pfile2); + endsmbfilepwent(fp); + endsmbfilepwent_internal(fp_write,&pfile2_lockdepth); + return False; + } + + new_entry_length = strlen(new_entry); + + if(fwrite(new_entry, 1, new_entry_length, fp_write) != new_entry_length) { + DEBUG(0, ("del_smbfilepwd_entry(write): Failed to copy entry for user %s to file %s. \ +Error was %s\n", pwd->smb_name, pfile2, strerror(errno))); + unlink(pfile2); + endsmbfilepwent(fp); + endsmbfilepwent_internal(fp_write,&pfile2_lockdepth); + free(new_entry); + return False; + } + + free(new_entry); + } + + /* + * Ensure pfile2 is flushed before rename. + */ + + if(fflush(fp_write) != 0) { + DEBUG(0, ("del_smbfilepwd_entry: Failed to flush file %s. Error was %s\n", pfile2, strerror(errno))); + endsmbfilepwent(fp); + endsmbfilepwent_internal(fp_write,&pfile2_lockdepth); + return False; + } + + /* + * Do an atomic rename - then release the locks. + */ + + if(rename(pfile2,pfile) != 0) { + unlink(pfile2); + } + endsmbfilepwent(fp); + endsmbfilepwent_internal(fp_write,&pfile2_lockdepth); + return True; +} + /* * Stub functions - implemented in terms of others. */ @@ -1000,6 +1225,7 @@ static struct passdb_ops file_ops = { getsmbfilepwent, add_smbfilepwd_entry, mod_smbfilepwd_entry, + del_smbfilepwd_entry, getsmbfile21pwent, iterate_getsam21pwnam, iterate_getsam21pwuid, diff --git a/source3/passdb/smbpasschange.c b/source3/passdb/smbpasschange.c index 9d0aecf8b8..0348a2b97b 100644 --- a/source3/passdb/smbpasschange.c +++ b/source3/passdb/smbpasschange.c @@ -25,8 +25,8 @@ /************************************************************* add a new user to the local smbpasswd file *************************************************************/ -static BOOL add_new_user(char *user_name, uid_t uid, BOOL trust_account, - BOOL disable_user, BOOL set_no_password, + +static BOOL add_new_user(char *user_name, uid_t uid, int local_flags, uchar *new_p16, uchar *new_nt_p16) { struct smb_passwd new_smb_pwent; @@ -36,16 +36,17 @@ static BOOL add_new_user(char *user_name, uid_t uid, BOOL trust_account, new_smb_pwent.smb_name = user_name; new_smb_pwent.smb_passwd = NULL; new_smb_pwent.smb_nt_passwd = NULL; - new_smb_pwent.acct_ctrl = (trust_account ? ACB_WSTRUST : ACB_NORMAL); + new_smb_pwent.acct_ctrl = ((local_flags & LOCAL_TRUST_ACCOUNT) ? ACB_WSTRUST : ACB_NORMAL); - if(disable_user) { + if(local_flags & LOCAL_DISABLE_USER) { new_smb_pwent.acct_ctrl |= ACB_DISABLED; - } else if (set_no_password) { + } else if (local_flags & LOCAL_SET_NO_PASSWORD) { new_smb_pwent.acct_ctrl |= ACB_PWNOTREQ; } else { new_smb_pwent.smb_passwd = new_p16; new_smb_pwent.smb_nt_passwd = new_nt_p16; } + return add_smbpwd_entry(&new_smb_pwent); } @@ -55,13 +56,12 @@ static BOOL add_new_user(char *user_name, uid_t uid, BOOL trust_account, change a password entry in the local smbpasswd file *************************************************************/ -BOOL local_password_change(char *user_name, BOOL trust_account, BOOL add_user, - BOOL enable_user, BOOL disable_user, BOOL set_no_password, +BOOL local_password_change(char *user_name, int local_flags, char *new_passwd, char *err_str, size_t err_str_len, char *msg_str, size_t msg_str_len) { - struct passwd *pwd; + struct passwd *pwd = NULL; void *vp; struct smb_passwd *smb_pwent; uchar new_p16[16]; @@ -70,17 +70,18 @@ BOOL local_password_change(char *user_name, BOOL trust_account, BOOL add_user, *err_str = '\0'; *msg_str = '\0'; - pwd = sys_getpwnam(user_name); + if (local_flags & LOCAL_ADD_USER) { - /* - * Check for a local account. - */ + /* + * Check for a local account - if we're adding only. + */ - if(!pwd) { - slprintf(err_str, err_str_len - 1, "User %s does not \ + if(!(pwd = sys_getpwnam(user_name))) { + slprintf(err_str, err_str_len - 1, "User %s does not \ exist in system password file (usually /etc/passwd). Cannot add \ account without a valid local system user.\n", user_name); - return False; + return False; + } } /* Calculate the MD4 hash (NT compatible) of the new password. */ @@ -111,15 +112,14 @@ account without a valid local system user.\n", user_name); /* Get the smb passwd entry for this user */ smb_pwent = getsmbpwnam(user_name); if (smb_pwent == NULL) { - if(add_user == False) { + if(!(local_flags & LOCAL_ADD_USER)) { slprintf(err_str, err_str_len-1, - "Failed to find entry for user %s.\n", pwd->pw_name); + "Failed to find entry for user %s.\n", user_name); endsmbpwent(vp); return False; } - if (add_new_user(user_name, pwd->pw_uid, trust_account, disable_user, - set_no_password, new_p16, new_nt_p16)) { + if (add_new_user(user_name, pwd->pw_uid, local_flags, new_p16, new_nt_p16)) { slprintf(msg_str, msg_str_len-1, "Added user %s.\n", user_name); endsmbpwent(vp); return True; @@ -130,7 +130,7 @@ account without a valid local system user.\n", user_name); } } else { /* the entry already existed */ - add_user = False; + local_flags &= ~LOCAL_ADD_USER; } /* @@ -138,15 +138,15 @@ account without a valid local system user.\n", user_name); * and the valid last change time. */ - if(disable_user) { + if(local_flags & LOCAL_DISABLE_USER) { smb_pwent->acct_ctrl |= ACB_DISABLED; - } else if (enable_user) { + } else if (local_flags & LOCAL_ENABLE_USER) { if(smb_pwent->smb_passwd == NULL) { smb_pwent->smb_passwd = new_p16; smb_pwent->smb_nt_passwd = new_nt_p16; } smb_pwent->acct_ctrl &= ~ACB_DISABLED; - } else if (set_no_password) { + } else if (local_flags & LOCAL_SET_NO_PASSWORD) { smb_pwent->acct_ctrl |= ACB_PWNOTREQ; /* This is needed to preserve ACB_PWNOTREQ in mod_smbfilepwd_entry */ smb_pwent->smb_passwd = NULL; @@ -168,11 +168,25 @@ account without a valid local system user.\n", user_name); smb_pwent->smb_nt_passwd = new_nt_p16; } - if(mod_smbpwd_entry(smb_pwent,True) == False) { - slprintf(err_str, err_str_len-1, "Failed to modify entry for user %s.\n", - pwd->pw_name); - endsmbpwent(vp); - return False; + if(local_flags & LOCAL_DELETE_USER) { + if (del_smbpwd_entry(user_name)==False) { + slprintf(err_str,err_str_len-1, "Failed to delete entry for user %s.\n", user_name); + endsmbpwent(vp); + return False; + } + slprintf(msg_str, msg_str_len-1, "Deleted user %s.\n", user_name); + } else { + if(mod_smbpwd_entry(smb_pwent,True) == False) { + slprintf(err_str, err_str_len-1, "Failed to modify entry for user %s.\n", user_name); + endsmbpwent(vp); + return False; + } + if(local_flags & LOCAL_DISABLE_USER) + slprintf(msg_str, msg_str_len-1, "Disabled user %s.\n", user_name); + else if (local_flags & LOCAL_ENABLE_USER) + slprintf(msg_str, msg_str_len-1, "Enabled user %s.\n", user_name); + else if (local_flags & LOCAL_SET_NO_PASSWORD) + slprintf(msg_str, msg_str_len-1, "User %s password set to none.\n", user_name); } endsmbpwent(vp); diff --git a/source3/utils/smbpasswd.c b/source3/utils/smbpasswd.c index ec6ce15f07..dcfafaa8b9 100644 --- a/source3/utils/smbpasswd.c +++ b/source3/utils/smbpasswd.c @@ -63,6 +63,7 @@ static void usage(void) printf(" -R ORDER name resolve order\n"); printf(" -j DOMAIN join domain name\n"); printf(" -a add user\n"); + printf(" -x delete user\n"); printf(" -d disable user\n"); printf(" -e enable user\n"); printf(" -n set no password\n"); @@ -218,20 +219,19 @@ static char *prompt_for_new_password(BOOL stdin_get) /************************************************************* -change a password either locally or remotely + Change a password either locally or remotely. *************************************************************/ + static BOOL password_change(const char *remote_machine, char *user_name, - char *old_passwd, char *new_passwd, - BOOL add_user, BOOL enable_user, - BOOL disable_user, BOOL set_no_password, - BOOL trust_account) + char *old_passwd, char *new_passwd, int local_flags) { BOOL ret; pstring err_str; pstring msg_str; if (remote_machine != NULL) { - if (add_user || enable_user || disable_user || set_no_password || trust_account) { + if (local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER|LOCAL_DISABLE_USER|LOCAL_ENABLE_USER| + LOCAL_TRUST_ACCOUNT|LOCAL_SET_NO_PASSWORD)) { /* these things can't be done remotely yet */ return False; } @@ -242,8 +242,7 @@ static BOOL password_change(const char *remote_machine, char *user_name, return ret; } - ret = local_password_change(user_name, trust_account, add_user, enable_user, - disable_user, set_no_password, new_passwd, + ret = local_password_change(user_name, local_flags, new_passwd, err_str, sizeof(err_str), msg_str, sizeof(msg_str)); if(*msg_str) @@ -256,18 +255,15 @@ static BOOL password_change(const char *remote_machine, char *user_name, /************************************************************* -handle password changing for root + Handle password changing for root. *************************************************************/ + static int process_root(int argc, char *argv[]) { struct passwd *pwd; int ch; BOOL joining_domain = False; - BOOL trust_account = False; - BOOL add_user = False; - BOOL disable_user = False; - BOOL enable_user = False; - BOOL set_no_password = False; + int local_flags = 0; BOOL stdin_passwd_get = False; char *user_name = NULL; char *new_domain = NULL; @@ -275,24 +271,37 @@ static int process_root(int argc, char *argv[]) char *old_passwd = NULL; char *remote_machine = NULL; - while ((ch = getopt(argc, argv, "adehmnj:r:sR:D:U:")) != EOF) { + while ((ch = getopt(argc, argv, "a:x:d:e:mnj:r:sR:D:U:")) != EOF) { switch(ch) { case 'a': - add_user = True; + local_flags |= LOCAL_ADD_USER; + user_name = optarg; + break; + case 'x': + local_flags |= LOCAL_DELETE_USER; + user_name = optarg; + new_passwd = "XXXXXX"; break; case 'd': - disable_user = True; + local_flags |= LOCAL_DISABLE_USER; + user_name = optarg; new_passwd = "XXXXXX"; break; case 'e': - enable_user = True; + local_flags |= LOCAL_ENABLE_USER; + user_name = optarg; break; - case 'D': - DEBUGLEVEL = atoi(optarg); + case 'm': + local_flags |= LOCAL_TRUST_ACCOUNT; break; case 'n': - set_no_password = True; + local_flags |= LOCAL_SET_NO_PASSWORD; new_passwd = "NO PASSWORD"; + case 'j': + new_domain = optarg; + strupper(new_domain); + joining_domain = True; + break; case 'r': remote_machine = optarg; break; @@ -305,13 +314,8 @@ static int process_root(int argc, char *argv[]) case 'R': lp_set_name_resolve_order(optarg); break; - case 'm': - trust_account = True; - break; - case 'j': - new_domain = optarg; - strupper(new_domain); - joining_domain = True; + case 'D': + DEBUGLEVEL = atoi(optarg); break; case 'U': user_name = optarg; @@ -326,15 +330,16 @@ static int process_root(int argc, char *argv[]) /* - * Ensure add_user and either remote machine or join domain are + * Ensure add/delete user and either remote machine or join domain are * not both set. */ - if(add_user && ((remote_machine != NULL) || joining_domain)) { + if((local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER)) && ((remote_machine != NULL) || joining_domain)) { usage(); } if(joining_domain) { - if (argc != 0) usage(); + if (argc != 0) + usage(); return join_domain(new_domain, remote_machine); } @@ -365,7 +370,7 @@ static int process_root(int argc, char *argv[]) exit(1); } - if (trust_account) { + if (local_flags & LOCAL_TRUST_ACCOUNT) { /* add the $ automatically */ static fstring buf; @@ -378,7 +383,7 @@ static int process_root(int argc, char *argv[]) user_name[strlen(user_name)-1] = 0; } - if (add_user) { + if (local_flags & LOCAL_ADD_USER) { new_passwd = xstrdup(user_name); strlower(new_passwd); } @@ -392,12 +397,6 @@ static int process_root(int argc, char *argv[]) user_name = buf; } - if (!remote_machine && !Get_Pwnam(user_name, True)) { - fprintf(stderr, "User \"%s\" was not found in system password file.\n", - user_name); - exit(1); - } - if (remote_machine != NULL) { old_passwd = get_pass("Old SMB password:",stdin_passwd_get); } @@ -413,7 +412,7 @@ static int process_root(int argc, char *argv[]) * smbpasswd file) then we need to prompt for a new password. */ - if(enable_user) { + if(local_flags & LOCAL_ENABLE_USER) { struct smb_passwd *smb_pass = getsmbpwnam(user_name); if((smb_pass != NULL) && (smb_pass->smb_passwd != NULL)) { new_passwd = "XXXX"; /* Don't care. */ @@ -429,20 +428,12 @@ static int process_root(int argc, char *argv[]) } } - if (!password_change(remote_machine, user_name, old_passwd, new_passwd, - add_user, enable_user, disable_user, set_no_password, - trust_account)) { - fprintf(stderr,"Failed to change password entry for %s\n", user_name); + if (!password_change(remote_machine, user_name, old_passwd, new_passwd, local_flags)) { + fprintf(stderr,"Failed to modify password entry for user %s\n", user_name); return 1; } - if(disable_user) { - printf("User %s disabled.\n", user_name); - } else if(enable_user) { - printf("User %s enabled.\n", user_name); - } else if (set_no_password) { - printf("User %s - set to no password.\n", user_name); - } else { + if(!(local_flags & (LOCAL_ADD_USER|LOCAL_DISABLE_USER|LOCAL_ENABLE_USER|LOCAL_DELETE_USER|LOCAL_SET_NO_PASSWORD))) { struct smb_passwd *smb_pass = getsmbpwnam(user_name); printf("Password changed for user %s.", user_name ); if((smb_pass != NULL) && (smb_pass->acct_ctrl & ACB_DISABLED )) @@ -534,8 +525,7 @@ static int process_nonroot(int argc, char *argv[]) exit(1); } - if (!password_change(remote_machine, user_name, old_passwd, new_passwd, - False, False, False, False, False)) { + if (!password_change(remote_machine, user_name, old_passwd, new_passwd, 0)) { fprintf(stderr,"Failed to change password for %s\n", user_name); return 1; } diff --git a/source3/web/swat.c b/source3/web/swat.c index 48c3ae07e2..3c9858a3d3 100644 --- a/source3/web/swat.c +++ b/source3/web/swat.c @@ -44,6 +44,7 @@ static int iNumNonAutoPrintServices = 0; #define CHG_S_PASSWD_FLAG "chg_s_passwd_flag" #define CHG_R_PASSWD_FLAG "chg_r_passwd_flag" #define ADD_USER_FLAG "add_user_flag" +#define DELETE_USER_FLAG "delete_user_flag" #define DISABLE_USER_FLAG "disable_user_flag" #define ENABLE_USER_FLAG "enable_user_flag" #define RHOST "remote_host" @@ -617,7 +618,7 @@ change a password either locally or remotely *************************************************************/ static BOOL change_password(const char *remote_machine, char *user_name, char *old_passwd, char *new_passwd, - BOOL add_user, BOOL enable_user, BOOL disable_user) + int local_flags) { BOOL ret = False; pstring err_str; @@ -641,8 +642,7 @@ static BOOL change_password(const char *remote_machine, char *user_name, return False; } - ret = local_password_change(user_name, False, add_user, enable_user, - disable_user, False, new_passwd, err_str, sizeof(err_str), + ret = local_password_change(user_name, local_flags, new_passwd, err_str, sizeof(err_str), msg_str, sizeof(msg_str)); if(*msg_str) @@ -660,6 +660,7 @@ static void chg_passwd(void) { char *host; BOOL rslt; + int local_flags = 0; /* Make sure users name has been specified */ if (strlen(cgi_variable(SWAT_USER)) == 0) { @@ -668,10 +669,10 @@ static void chg_passwd(void) } /* - * smbpasswd doesn't require anything but the users name to disable or enable the user, + * smbpasswd doesn't require anything but the users name to delete, disable or enable the user, * so if that's what we're doing, skip the rest of the checks */ - if (!cgi_variable(DISABLE_USER_FLAG) && !cgi_variable(ENABLE_USER_FLAG)) { + if (!cgi_variable(DISABLE_USER_FLAG) && !cgi_variable(ENABLE_USER_FLAG) && !cgi_variable(DELETE_USER_FLAG)) { /* * If current user is not root, make sure old password has been specified @@ -710,18 +711,27 @@ static void chg_passwd(void) } else { host = "127.0.0.1"; } + + /* + * Set up the local flags. + */ + + local_flags |= (cgi_variable(ADD_USER_FLAG) ? LOCAL_ADD_USER : 0); + local_flags |= (cgi_variable(DELETE_USER_FLAG) ? LOCAL_DELETE_USER : 0); + local_flags |= (cgi_variable(ENABLE_USER_FLAG) ? LOCAL_ENABLE_USER : 0); + local_flags |= (cgi_variable(DISABLE_USER_FLAG) ? LOCAL_DISABLE_USER : 0); + rslt = change_password(host, cgi_variable(SWAT_USER), cgi_variable(OLD_PSWD), cgi_variable(NEW_PSWD), - cgi_variable(ADD_USER_FLAG)? True : False, - cgi_variable(ENABLE_USER_FLAG)? True : False, - cgi_variable(DISABLE_USER_FLAG)? True : False); + local_flags); - - if (rslt == True) { - printf("

The passwd for '%s' has been changed. \n", cgi_variable(SWAT_USER)); - } else { - printf("

The passwd for '%s' has NOT been changed. \n",cgi_variable(SWAT_USER)); + if(local_flags == 0) { + if (rslt == True) { + printf("

The passwd for '%s' has been changed. \n", cgi_variable(SWAT_USER)); + } else { + printf("

The passwd for '%s' has NOT been changed. \n",cgi_variable(SWAT_USER)); + } } return; @@ -773,6 +783,8 @@ static void passwd_page(void) if (demo_mode || am_root()) { printf("\n", ADD_USER_FLAG); + printf("\n", + DELETE_USER_FLAG); printf("\n", DISABLE_USER_FLAG); printf("\n", @@ -784,7 +796,7 @@ static void passwd_page(void) * Do some work if change, add, disable or enable was * requested. It could be this is the first time through this * code, so there isn't anything to do. */ - if ((cgi_variable(CHG_S_PASSWD_FLAG)) || (cgi_variable(ADD_USER_FLAG)) || + if ((cgi_variable(CHG_S_PASSWD_FLAG)) || (cgi_variable(ADD_USER_FLAG)) || (cgi_variable(DELETE_USER_FLAG)) || (cgi_variable(DISABLE_USER_FLAG)) || (cgi_variable(ENABLE_USER_FLAG))) { chg_passwd(); } -- cgit