From 301d51e13a1aa4e633e2da161b0dd260a8a499cd Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 13 Feb 2006 17:08:25 +0000 Subject: r13494: Merge the stuff I've done in head the last days. Volker (This used to be commit bb40e544de68f01a6e774753f508e69373b39899) --- source3/Makefile.in | 8 +- source3/auth/auth_util.c | 66 +++++ source3/groupdb/mapping.c | 17 +- source3/include/passdb.h | 26 ++ source3/lib/system_smbd.c | 77 +----- source3/lib/username.c | 510 ------------------------------------- source3/lib/util_getent.c | 337 ------------------------- source3/passdb/passdb.c | 126 ++++------ source3/passdb/pdb_interface.c | 512 +++++++++++++++++++++++++++++++++++-- source3/rpc_server/srv_samr_nt.c | 527 ++++++++------------------------------- source3/smbd/chgpasswd.c | 2 +- source3/smbd/map_username.c | 178 +++++++++++++ source3/smbd/password.c | 129 ++++++++++ source3/smbd/posix_acls.c | 10 +- source3/smbd/service.c | 2 +- source3/utils/net_groupmap.c | 4 +- source3/utils/net_rpc_samsync.c | 2 +- 17 files changed, 1066 insertions(+), 1467 deletions(-) delete mode 100644 source3/lib/util_getent.c create mode 100644 source3/smbd/map_username.c diff --git a/source3/Makefile.in b/source3/Makefile.in index d8f7dcf519..135c757fd8 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -194,7 +194,7 @@ LIB_OBJ = $(VERSION_OBJ) lib/charcnv.o lib/debug.o lib/fault.o \ lib/interfaces.o lib/pidfile.o lib/replace.o lib/replace1.o \ lib/signal.o lib/system.o lib/sendfile.o lib/time.o \ lib/ufc.o lib/genrand.o lib/username.o \ - lib/util_getent.o lib/util_pw.o lib/access.o lib/smbrun.o \ + lib/util_pw.o lib/access.o lib/smbrun.o \ lib/bitmap.o lib/crc32.o $(SNPRINTF_OBJ) lib/dprintf.o \ lib/xfile.o lib/wins_srv.o \ lib/util_str.o lib/clobber.o lib/util_sid.o lib/util_uuid.o \ @@ -209,7 +209,7 @@ LIB_OBJ = $(VERSION_OBJ) lib/charcnv.o lib/debug.o lib/fault.o \ lib/adt_tree.o lib/gencache.o $(TDB_OBJ) \ lib/module.o lib/events.o lib/ldap_escape.o @CHARSET_STATIC@ \ lib/secdesc.o lib/util_seaccess.o lib/secace.o lib/secacl.o @SOCKWRAP@ \ - libads/krb5_errs.o + libads/krb5_errs.o lib/system_smbd.o LIB_DUMMY_OBJ = lib/dummysmbd.o lib/dummyroot.o LIB_NONSMBD_OBJ = $(LIB_OBJ) $(LIB_DUMMY_OBJ) @@ -326,7 +326,7 @@ PASSDB_OBJ = $(PASSDB_GET_SET_OBJ) passdb/passdb.o passdb/pdb_interface.o \ passdb/util_wellknown.o passdb/util_builtin.o passdb/pdb_compat.o \ passdb/util_unixsids.o passdb/lookup_sid.o \ passdb/login_cache.o @PDB_STATIC@ \ - lib/system_smbd.o lib/account_pol.o lib/privileges.o + lib/account_pol.o lib/privileges.o DEVEL_HELP_WEIRD_OBJ = modules/weird.o CP850_OBJ = modules/CP850.o @@ -386,7 +386,7 @@ SMBD_OBJ_MAIN = smbd/server.o BUILDOPT_OBJ = smbd/build_options.o SMBD_OBJ_SRV = smbd/files.o smbd/chgpasswd.o smbd/connection.o \ - smbd/utmp.o smbd/session.o \ + smbd/utmp.o smbd/session.o smbd/map_username.o \ smbd/dfree.o smbd/dir.o smbd/password.o smbd/conn.o \ smbd/share_access.o smbd/fileio.o \ smbd/ipc.o smbd/lanman.o smbd/negprot.o \ diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c index 1567b6e40b..ad02b24a42 100644 --- a/source3/auth/auth_util.c +++ b/source3/auth/auth_util.c @@ -1018,6 +1018,72 @@ NTSTATUS create_token_from_username(TALLOC_CTX *mem_ctx, const char *username, return result; } +/*************************************************************************** + Build upon create_token_from_username: + + Expensive helper function to figure out whether a user given its name is + member of a particular group. +***************************************************************************/ +BOOL user_in_group_sid(const char *username, const DOM_SID *group_sid) +{ + NTSTATUS status; + uid_t uid; + gid_t gid; + char *found_username; + struct nt_user_token *token; + BOOL result; + + TALLOC_CTX *mem_ctx; + + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return False; + } + + status = create_token_from_username(mem_ctx, username, False, + &uid, &gid, &found_username, + &token); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("could not create token for %s\n", username)); + return False; + } + + result = nt_token_check_sid(group_sid, token); + + talloc_free(mem_ctx); + return result; + +} + +BOOL user_in_group(const char *username, const char *groupname) +{ + TALLOC_CTX *mem_ctx; + DOM_SID group_sid; + NTSTATUS status; + BOOL ret; + + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + DEBUG(0, ("talloc_new failed\n")); + return False; + } + + ret = lookup_name(mem_ctx, groupname, LOOKUP_NAME_ALL, + NULL, NULL, &group_sid, NULL); + talloc_free(mem_ctx); + + if (!ret) { + DEBUG(10, ("lookup_name(%s) failed: %s\n", groupname, + nt_errstr(status))); + return False; + } + + return user_in_group_sid(username, &group_sid); +} + + /*************************************************************************** Make (and fill) a user_info struct from a Kerberos PAC logon_info by conversion to a SAM_ACCOUNT diff --git a/source3/groupdb/mapping.c b/source3/groupdb/mapping.c index 2790d47587..07116f41fb 100644 --- a/source3/groupdb/mapping.c +++ b/source3/groupdb/mapping.c @@ -157,26 +157,26 @@ static BOOL add_mapping_entry(GROUP_MAP *map, int flag) /**************************************************************************** initialise first time the mapping list ****************************************************************************/ -BOOL add_initial_entry(gid_t gid, const char *sid, enum SID_NAME_USE sid_name_use, const char *nt_name, const char *comment) +NTSTATUS add_initial_entry(gid_t gid, const char *sid, enum SID_NAME_USE sid_name_use, const char *nt_name, const char *comment) { GROUP_MAP map; if(!init_group_mapping()) { DEBUG(0,("failed to initialize group mapping\n")); - return(False); + return NT_STATUS_UNSUCCESSFUL; } map.gid=gid; if (!string_to_sid(&map.sid, sid)) { DEBUG(0, ("string_to_sid failed: %s", sid)); - return False; + return NT_STATUS_UNSUCCESSFUL; } map.sid_name_use=sid_name_use; fstrcpy(map.nt_name, nt_name); fstrcpy(map.comment, comment); - return NT_STATUS_IS_OK(pdb_add_group_mapping_entry(&map)); + return pdb_add_group_mapping_entry(&map); } /**************************************************************************** @@ -856,7 +856,7 @@ BOOL get_domain_group_from_sid(DOM_SID sid, GROUP_MAP *map) Create a UNIX group on demand. ****************************************************************************/ -int smb_create_group(char *unix_group, gid_t *new_gid) +int smb_create_group(const char *unix_group, gid_t *new_gid) { pstring add_script; int ret = -1; @@ -901,7 +901,7 @@ int smb_create_group(char *unix_group, gid_t *new_gid) Delete a UNIX group on demand. ****************************************************************************/ -int smb_delete_group(char *unix_group) +int smb_delete_group(const char *unix_group) { pstring del_script; int ret; @@ -947,7 +947,7 @@ int smb_set_primary_group(const char *unix_group, const char* unix_user) Add a user to a UNIX group. ****************************************************************************/ -int smb_add_user_group(char *unix_group, char *unix_user) +int smb_add_user_group(const char *unix_group, const char *unix_user) { pstring add_script; int ret; @@ -1122,8 +1122,7 @@ NTSTATUS pdb_default_create_alias(struct pdb_methods *methods, NTSTATUS pdb_default_delete_alias(struct pdb_methods *methods, const DOM_SID *sid) { - return pdb_delete_group_mapping_entry(*sid) ? - NT_STATUS_OK : NT_STATUS_ACCESS_DENIED; + return pdb_delete_group_mapping_entry(*sid); } NTSTATUS pdb_default_get_aliasinfo(struct pdb_methods *methods, diff --git a/source3/include/passdb.h b/source3/include/passdb.h index 35f377ad86..1f3c8cb28b 100644 --- a/source3/include/passdb.h +++ b/source3/include/passdb.h @@ -262,6 +262,13 @@ struct pdb_methods NTSTATUS (*getsampwnam)(struct pdb_methods *, SAM_ACCOUNT *sam_acct, const char *username); NTSTATUS (*getsampwsid)(struct pdb_methods *, SAM_ACCOUNT *sam_acct, const DOM_SID *sid); + + NTSTATUS (*create_user)(struct pdb_methods *, TALLOC_CTX *tmp_ctx, + const char *name, uint32 acct_flags, + uint32 *rid); + + NTSTATUS (*delete_user)(struct pdb_methods *, TALLOC_CTX *tmp_ctx, + SAM_ACCOUNT *sam_acct); NTSTATUS (*add_sam_account)(struct pdb_methods *, SAM_ACCOUNT *sampass); @@ -279,6 +286,13 @@ struct pdb_methods NTSTATUS (*getgrnam)(struct pdb_methods *methods, GROUP_MAP *map, const char *name); + NTSTATUS (*create_dom_group)(struct pdb_methods *methods, + TALLOC_CTX *mem_ctx, const char *name, + uint32 *rid); + + NTSTATUS (*delete_dom_group)(struct pdb_methods *methods, + TALLOC_CTX *mem_ctx, uint32 rid); + NTSTATUS (*add_group_mapping_entry)(struct pdb_methods *methods, GROUP_MAP *map); @@ -305,6 +319,18 @@ struct pdb_methods DOM_SID **pp_sids, gid_t **pp_gids, size_t *p_num_groups); + NTSTATUS (*set_unix_primary_group)(struct pdb_methods *methods, + TALLOC_CTX *mem_ctx, + SAM_ACCOUNT *user); + + NTSTATUS (*add_groupmem)(struct pdb_methods *methods, + TALLOC_CTX *mem_ctx, + uint32 group_rid, uint32 member_rid); + + NTSTATUS (*del_groupmem)(struct pdb_methods *methods, + TALLOC_CTX *mem_ctx, + uint32 group_rid, uint32 member_rid); + NTSTATUS (*find_alias)(struct pdb_methods *methods, const char *name, DOM_SID *sid); diff --git a/source3/lib/system_smbd.c b/source3/lib/system_smbd.c index 3fc2d69a03..081a07c019 100644 --- a/source3/lib/system_smbd.c +++ b/source3/lib/system_smbd.c @@ -123,14 +123,16 @@ static int sys_getgrouplist(const char *user, gid_t gid, gid_t *groups, int *grp DEBUG(10,("sys_getgrouplist: user [%s]\n", user)); - /* see if we should disable winbindd lookups for local users */ - if (strchr(user, *lp_winbind_separator()) == NULL) { - if ( !winbind_off() ) - DEBUG(0,("sys_getgroup_list: Insufficient environment space " - "for %s\n", WINBINDD_DONT_ENV)); - else - DEBUG(10,("sys_getgrouplist(): disabled winbindd for group " - "lookup [user == %s]\n", user)); + /* This is only ever called for Unix users, remote memberships are + * always determined by the info3 coming back from auth3 or the + * PAC. */ + + if ( !winbind_off() ) { + DEBUG(0,("sys_getgroup_list: Insufficient environment space " + "for %s\n", WINBINDD_DONT_ENV)); + } else { + DEBUG(10,("sys_getgrouplist(): disabled winbindd for group " + "lookup [user == %s]\n", user)); } #ifdef HAVE_GETGROUPLIST @@ -198,62 +200,3 @@ BOOL getgroups_unix_user(TALLOC_CTX *mem_ctx, const char *user, SAFE_FREE(temp_groups); return True; } - -NTSTATUS pdb_default_enum_group_memberships(struct pdb_methods *methods, - TALLOC_CTX *mem_ctx, - SAM_ACCOUNT *user, - DOM_SID **pp_sids, - gid_t **pp_gids, - size_t *p_num_groups) -{ - size_t i; - gid_t gid; - - if ( !sid_to_gid(pdb_get_group_sid(user), &gid) ) - { - uint32 rid; - struct passwd *pwd; - - /* second try, allow the DOMAIN_USERS group to pass */ - - if ( !sid_peek_check_rid( get_global_sam_sid(), pdb_get_group_sid(user), &rid ) ) - return NT_STATUS_NO_SUCH_USER; - - if ( rid != DOMAIN_GROUP_RID_USERS ) { - DEBUG(10, ("sid_to_gid failed\n")); - return NT_STATUS_NO_SUCH_USER; - } - - DEBUG(5,("pdb_default_enum_group_memberships: sid_to_gid() failed but giving " - "free pass to 'Domain Users' as primary group\n")); - - if ( !(pwd = getpwnam_alloc( NULL, pdb_get_username(user) ) ) ) - return NT_STATUS_NO_SUCH_USER; - - gid = pwd->pw_gid; - - TALLOC_FREE( pwd ); - } - - if (!getgroups_unix_user(mem_ctx, pdb_get_username(user), gid, - pp_gids, p_num_groups)) { - return NT_STATUS_NO_SUCH_USER; - } - - if (*p_num_groups == 0) { - smb_panic("primary group missing"); - } - - *pp_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, *p_num_groups); - - if (*pp_sids == NULL) { - talloc_free(*pp_gids); - return NT_STATUS_NO_MEMORY; - } - - for (i=0; i<*p_num_groups; i++) { - gid_to_sid(&(*pp_sids)[i], (*pp_gids)[i]); - } - - return NT_STATUS_OK; -} diff --git a/source3/lib/username.c b/source3/lib/username.c index c04dfd05da..52994557f7 100644 --- a/source3/lib/username.c +++ b/source3/lib/username.c @@ -29,16 +29,6 @@ static struct passwd *uname_string_combinations2(char *s, TALLOC_CTX *mem_ctx, i struct passwd * (*fn) (TALLOC_CTX *mem_ctx, const char *), int N); -/***************************************************************** - Check if a user or group name is local (this is a *local* name for - *local* people, there's nothing for you here...). -*****************************************************************/ - -static BOOL name_is_local(const char *name) -{ - return !(strchr_m(name, *lp_winbind_separator())); -} - /**************************************************************************** Get a users home directory. ****************************************************************************/ @@ -58,161 +48,6 @@ char *get_user_home_dir(const char *user) return(pass->pw_dir); } -/******************************************************************* - Map a username from a dos name to a unix name by looking in the username - map. Note that this modifies the name in place. - This is the main function that should be called *once* on - any incoming or new username - in order to canonicalize the name. - This is being done to de-couple the case conversions from the user mapping - function. Previously, the map_username was being called - every time Get_Pwnam was called. - Returns True if username was changed, false otherwise. -********************************************************************/ - -BOOL map_username(fstring user) -{ - static BOOL initialised=False; - static fstring last_from,last_to; - XFILE *f; - char *mapfile = lp_username_map(); - char *s; - pstring buf; - BOOL mapped_user = False; - char *cmd = lp_username_map_script(); - - if (!*user) - return False; - - if (strequal(user,last_to)) - return False; - - if (strequal(user,last_from)) { - DEBUG(3,("Mapped user %s to %s\n",user,last_to)); - fstrcpy(user,last_to); - return True; - } - - /* first try the username map script */ - - if ( *cmd ) { - char **qlines; - pstring command; - int numlines, ret, fd; - - pstr_sprintf( command, "%s \"%s\"", cmd, user ); - - DEBUG(10,("Running [%s]\n", command)); - ret = smbrun(command, &fd); - DEBUGADD(10,("returned [%d]\n", ret)); - - if ( ret != 0 ) { - if (fd != -1) - close(fd); - return False; - } - - numlines = 0; - qlines = fd_lines_load(fd, &numlines,0); - DEBUGADD(10,("Lines returned = [%d]\n", numlines)); - close(fd); - - /* should be either no lines or a single line with the mapped username */ - - if (numlines) { - DEBUG(3,("Mapped user %s to %s\n", user, qlines[0] )); - fstrcpy( user, qlines[0] ); - } - - file_lines_free(qlines); - - return numlines != 0; - } - - /* ok. let's try the mapfile */ - - if (!*mapfile) - return False; - - if (!initialised) { - *last_from = *last_to = 0; - initialised = True; - } - - f = x_fopen(mapfile,O_RDONLY, 0); - if (!f) { - DEBUG(0,("can't open username map %s. Error %s\n",mapfile, strerror(errno) )); - return False; - } - - DEBUG(4,("Scanning username map %s\n",mapfile)); - - while((s=fgets_slash(buf,sizeof(buf),f))!=NULL) { - char *unixname = s; - char *dosname = strchr_m(unixname,'='); - char **dosuserlist; - BOOL return_if_mapped = False; - - if (!dosname) - continue; - - *dosname++ = 0; - - while (isspace((int)*unixname)) - unixname++; - - if ('!' == *unixname) { - return_if_mapped = True; - unixname++; - while (*unixname && isspace((int)*unixname)) - unixname++; - } - - if (!*unixname || strchr_m("#;",*unixname)) - continue; - - { - int l = strlen(unixname); - while (l && isspace((int)unixname[l-1])) { - unixname[l-1] = 0; - l--; - } - } - - dosuserlist = str_list_make(dosname, NULL); - if (!dosuserlist) { - DEBUG(0,("Unable to build user list\n")); - return False; - } - - if (strchr_m(dosname,'*') || - user_in_list(user, (const char **)dosuserlist)) { - DEBUG(3,("Mapped user %s to %s\n",user,unixname)); - mapped_user = True; - fstrcpy( last_from,user ); - fstrcpy( user, unixname ); - fstrcpy( last_to,user ); - if ( return_if_mapped ) { - str_list_free (&dosuserlist); - x_fclose(f); - return True; - } - } - - str_list_free (&dosuserlist); - } - - x_fclose(f); - - /* - * Setup the last_from and last_to as an optimization so - * that we don't scan the file again for the same user. - */ - fstrcpy(last_from,user); - fstrcpy(last_to,user); - - return mapped_user; -} - /**************************************************************************** * A wrapper for sys_getpwnam(). The following variations are tried: * - as transmitted @@ -334,351 +169,6 @@ struct passwd *Get_Pwnam(const char *user) return ret; } -/**************************************************************************** - Check if a user is in a netgroup user list. If at first we don't succeed, - try lower case. -****************************************************************************/ - -BOOL user_in_netgroup(const char *user, const char *ngname) -{ -#ifdef HAVE_NETGROUP - static char *mydomain = NULL; - fstring lowercase_user; - - if (mydomain == NULL) - yp_get_default_domain(&mydomain); - - if(mydomain == NULL) { - DEBUG(5,("Unable to get default yp domain\n")); - return False; - } - - DEBUG(5,("looking for user %s of domain %s in netgroup %s\n", - user, mydomain, ngname)); - - if (innetgr(ngname, NULL, user, mydomain)) { - DEBUG(5,("user_in_netgroup: Found\n")); - return (True); - } else { - - /* - * Ok, innetgr is case sensitive. Try once more with lowercase - * just in case. Attempt to fix #703. JRA. - */ - - fstrcpy(lowercase_user, user); - strlower_m(lowercase_user); - - DEBUG(5,("looking for user %s of domain %s in netgroup %s\n", - lowercase_user, mydomain, ngname)); - - if (innetgr(ngname, NULL, lowercase_user, mydomain)) { - DEBUG(5,("user_in_netgroup: Found\n")); - return (True); - } - } -#endif /* HAVE_NETGROUP */ - return False; -} - -/**************************************************************************** - Check if a user is in a winbind group. -****************************************************************************/ - -static BOOL user_in_winbind_group(const char *user, const char *gname, - BOOL *winbind_answered) -{ - int i; - gid_t gid, gid_low, gid_high; - BOOL ret = False; - static gid_t *groups = NULL; - static int num_groups = 0; - static fstring last_user = ""; - - *winbind_answered = False; - - if ((gid = nametogid(gname)) == (gid_t)-1) { - DEBUG(0,("user_in_winbind_group: nametogid for group %s " - "failed.\n", gname )); - goto err; - } - - if (!lp_idmap_gid(&gid_low, &gid_high)) { - DEBUG(4, ("winbind gid range not configured, therefore %s " - "cannot be a winbind group\n", gname)); - goto err; - } - - if (gid < gid_low || gid > gid_high) { - DEBUG(4, ("group %s is not a winbind group\n", gname)); - goto err; - } - - /* try to user the last user we looked up */ - /* otherwise fall back to lookups */ - - if ( !strequal( last_user, user ) || !groups ) - { - /* clear any cached information */ - - SAFE_FREE(groups); - fstrcpy( last_user, "" ); - - /* - * Get the gid's that this user belongs to. - */ - - if ((num_groups = winbind_getgroups(user, &groups)) == -1) - return False; - - if ( num_groups == -1 ) - return False; - - if ( num_groups == 0 ) { - *winbind_answered = True; - return False; - } - - /* save the last username */ - - fstrcpy( last_user, user ); - - } - else - DEBUG(10,("user_in_winbind_group: using cached user " - "groups for [%s]\n", user)); - - if ( DEBUGLEVEL >= 10 ) { - DEBUG(10,("user_in_winbind_group: using groups -- ")); - for ( i=0; ipw_gid))) { - DEBUG(10,("user_in_unix_group: group %s is " - "primary group.\n", gname )); - return True; - } - } - - user_list = get_users_in_group(gname); - if (user_list == NULL) { - DEBUG(10,("user_in_unix_group: no such group %s\n", - gname )); - return False; - } - - for (member = user_list; member; member = member->next) { - DEBUG(10,("user_in_unix_group: checking user %s against " - "member %s\n", user, member->unix_name )); - if (strequal(member->unix_name,user)) { - free_userlist(user_list); - return(True); - } - } - - free_userlist(user_list); - return False; -} - -/**************************************************************************** - Check if a user is in a group list. Ask winbind first, then use UNIX. -****************************************************************************/ - -BOOL user_in_group(const char *user, const char *gname) -{ - BOOL winbind_answered = False; - BOOL ret; - - ret = user_in_winbind_group(user, gname, &winbind_answered); - if (!winbind_answered) - ret = user_in_unix_group(user, gname); - - if (ret) - DEBUG(10,("user_in_group: user |%s| is in group |%s|\n", - user, gname)); - return ret; -} - -/**************************************************************************** - Check if a user is in a user list - can check combinations of UNIX - and netgroup lists. -****************************************************************************/ - -BOOL user_in_list(const char *user,const char **list) -{ - if (!list || !*list) - return False; - - DEBUG(10,("user_in_list: checking user %s in list\n", user)); - - while (*list) { - - DEBUG(10,("user_in_list: checking user |%s| against |%s|\n", - user, *list)); - - /* - * Check raw username. - */ - if (strequal(user, *list)) - return(True); - - /* - * Now check to see if any combination - * of UNIX and netgroups has been specified. - */ - - if(**list == '@') { - /* - * Old behaviour. Check netgroup list - * followed by UNIX list. - */ - if(user_in_netgroup(user, *list +1)) - return True; - if(user_in_group(user, *list +1)) - return True; - } else if (**list == '+') { - - if((*(*list +1)) == '&') { - /* - * Search UNIX list followed by netgroup. - */ - if(user_in_group(user, *list +2)) - return True; - if(user_in_netgroup(user, *list +2)) - return True; - - } else { - - /* - * Just search UNIX list. - */ - - if(user_in_group(user, *list +1)) - return True; - } - - } else if (**list == '&') { - - if(*(*list +1) == '+') { - /* - * Search netgroup list followed by UNIX list. - */ - if(user_in_netgroup(user, *list +2)) - return True; - if(user_in_group(user, *list +2)) - return True; - } else { - /* - * Just search netgroup list. - */ - if(user_in_netgroup(user, *list +1)) - return True; - } - } else if (!name_is_local(*list)) { - /* - * If user name did not match and token is not a unix - * group and the token has a winbind separator in the - * name then see if it is a Windows group. - */ - - DOM_SID g_sid; - enum SID_NAME_USE name_type; - BOOL winbind_answered = False; - BOOL ret; - fstring groupname, domain; - - /* Parse a string of the form DOMAIN/user into a - * domain and a user */ - - char *p = strchr(*list,*lp_winbind_separator()); - - DEBUG(10,("user_in_list: checking if user |%s| is in " - "winbind group |%s|\n", user, *list)); - - if (p) { - fstrcpy(groupname, p+1); - fstrcpy(domain, *list); - domain[PTR_DIFF(p, *list)] = 0; - - /* Check to see if name is a Windows group; - Win2k native mode DCs will return domain - local groups; while NT4 or mixed mode 2k - DCs will not */ - - if ( winbind_lookup_name(domain, groupname, - &g_sid, &name_type) - && ( name_type==SID_NAME_DOM_GRP || - (strequal(lp_workgroup(), domain) && - name_type==SID_NAME_ALIAS) ) ) - { - - /* Check if user name is in the - * Windows group */ - ret = user_in_winbind_group( - user, *list, - &winbind_answered); - - if (winbind_answered && ret == True) { - DEBUG(10,("user_in_list: user " - "|%s| is in winbind " - "group |%s|\n", - user, *list)); - return ret; - } - } - } - } - - list++; - } - return(False); -} - /* The functions below have been taken from password.c and slightly modified */ /**************************************************************************** Apply a function to upper/lower case combinations diff --git a/source3/lib/util_getent.c b/source3/lib/util_getent.c deleted file mode 100644 index 7c045fccb2..0000000000 --- a/source3/lib/util_getent.c +++ /dev/null @@ -1,337 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Samba utility functions - Copyright (C) Simo Sorce 2001 - Copyright (C) Jeremy Allison 2001 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - - -/**************************************************************** - Returns a single linked list of group entries. - Use grent_free() to free it after use. -****************************************************************/ - -struct sys_grent * getgrent_list(void) -{ - struct sys_grent *glist; - struct sys_grent *gent; - struct group *grp; - - gent = SMB_MALLOC_P(struct sys_grent); - if (gent == NULL) { - DEBUG (0, ("Out of memory in getgrent_list!\n")); - return NULL; - } - memset(gent, '\0', sizeof(struct sys_grent)); - glist = gent; - - setgrent(); - grp = getgrent(); - if (grp == NULL) { - endgrent(); - SAFE_FREE(glist); - return NULL; - } - - while (grp != NULL) { - int i,num; - - if (grp->gr_name) { - if ((gent->gr_name = SMB_STRDUP(grp->gr_name)) == NULL) - goto err; - } - if (grp->gr_passwd) { - if ((gent->gr_passwd = SMB_STRDUP(grp->gr_passwd)) == NULL) - goto err; - } - gent->gr_gid = grp->gr_gid; - - /* number of strings in gr_mem */ - for (num = 0; grp->gr_mem[num]; num++) - ; - - /* alloc space for gr_mem string pointers */ - if ((gent->gr_mem = SMB_MALLOC_ARRAY(char *, num+1)) == NULL) - goto err; - - memset(gent->gr_mem, '\0', (num+1) * sizeof(char *)); - - for (i=0; i < num; i++) { - if ((gent->gr_mem[i] = SMB_STRDUP(grp->gr_mem[i])) == NULL) - goto err; - } - gent->gr_mem[num] = NULL; - - grp = getgrent(); - if (grp) { - gent->next = SMB_MALLOC_P(struct sys_grent); - if (gent->next == NULL) - goto err; - gent = gent->next; - memset(gent, '\0', sizeof(struct sys_grent)); - } - } - - endgrent(); - return glist; - - err: - - endgrent(); - DEBUG(0, ("Out of memory in getgrent_list!\n")); - grent_free(glist); - return NULL; -} - -/**************************************************************** - Free the single linked list of group entries made by - getgrent_list() -****************************************************************/ - -void grent_free (struct sys_grent *glist) -{ - while (glist) { - struct sys_grent *prev; - - SAFE_FREE(glist->gr_name); - SAFE_FREE(glist->gr_passwd); - if (glist->gr_mem) { - int i; - for (i = 0; glist->gr_mem[i]; i++) - SAFE_FREE(glist->gr_mem[i]); - SAFE_FREE(glist->gr_mem); - } - prev = glist; - glist = glist->next; - SAFE_FREE(prev); - } -} - -/**************************************************************** - Returns a single linked list of passwd entries. - Use pwent_free() to free it after use. -****************************************************************/ - -struct sys_pwent * getpwent_list(void) -{ - struct sys_pwent *plist; - struct sys_pwent *pent; - struct passwd *pwd; - - pent = SMB_MALLOC_P(struct sys_pwent); - if (pent == NULL) { - DEBUG (0, ("Out of memory in getpwent_list!\n")); - return NULL; - } - plist = pent; - - setpwent(); - pwd = getpwent(); - while (pwd != NULL) { - memset(pent, '\0', sizeof(struct sys_pwent)); - if (pwd->pw_name) { - if ((pent->pw_name = SMB_STRDUP(pwd->pw_name)) == NULL) - goto err; - } - if (pwd->pw_passwd) { - if ((pent->pw_passwd = SMB_STRDUP(pwd->pw_passwd)) == NULL) - goto err; - } - pent->pw_uid = pwd->pw_uid; - pent->pw_gid = pwd->pw_gid; - if (pwd->pw_gecos) { - if ((pent->pw_gecos = SMB_STRDUP(pwd->pw_gecos)) == NULL) - goto err; - } - if (pwd->pw_dir) { - if ((pent->pw_dir = SMB_STRDUP(pwd->pw_dir)) == NULL) - goto err; - } - if (pwd->pw_shell) { - if ((pent->pw_shell = SMB_STRDUP(pwd->pw_shell)) == NULL) - goto err; - } - - pwd = getpwent(); - if (pwd) { - pent->next = SMB_MALLOC_P(struct sys_pwent); - if (pent->next == NULL) - goto err; - pent = pent->next; - } - } - - endpwent(); - return plist; - - err: - - endpwent(); - DEBUG(0, ("Out of memory in getpwent_list!\n")); - pwent_free(plist); - return NULL; -} - -/**************************************************************** - Free the single linked list of passwd entries made by - getpwent_list() -****************************************************************/ - -void pwent_free (struct sys_pwent *plist) -{ - while (plist) { - struct sys_pwent *prev; - - SAFE_FREE(plist->pw_name); - SAFE_FREE(plist->pw_passwd); - SAFE_FREE(plist->pw_gecos); - SAFE_FREE(plist->pw_dir); - SAFE_FREE(plist->pw_shell); - - prev = plist; - plist = plist->next; - SAFE_FREE(prev); - } -} - -/**************************************************************** - Add the individual group users onto the list. -****************************************************************/ - -static struct sys_userlist *add_members_to_userlist(struct sys_userlist *list_head, const struct group *grp) -{ - size_t num_users, i; - - /* Count the number of users. */ - for (num_users = 0; grp->gr_mem[num_users]; num_users++) - ; - - for (i = 0; i < num_users; i++) { - struct sys_userlist *entry = SMB_MALLOC_P(struct sys_userlist); - if (entry == NULL) { - free_userlist(list_head); - return NULL; - } - entry->unix_name = (char *)SMB_STRDUP(grp->gr_mem[i]); - if (entry->unix_name == NULL) { - SAFE_FREE(entry); - free_userlist(list_head); - return NULL; - } - DLIST_ADD(list_head, entry); - } - return list_head; -} - -/***************************************************************** - Splits passed user or group name to domain and user/group name parts - Returns True if name was splitted and False otherwise. -*****************************************************************/ - -static BOOL split_domain_and_name(const char *name, char *domain, - char* username) -{ - char *p = strchr(name,*lp_winbind_separator()); - - - /* Parse a string of the form DOMAIN/user into a domain and a user */ - DEBUG(10,("split_domain_and_name: checking whether name |%s| local or " - "not\n", name)); - - if (p) { - fstrcpy(username, p+1); - fstrcpy(domain, name); - domain[PTR_DIFF(p, name)] = 0; - } else if (lp_winbind_use_default_domain()) { - fstrcpy(username, name); - fstrcpy(domain, lp_workgroup()); - } else { - return False; - } - - DEBUG(10,("split_domain_and_name: all is fine, domain is |%s| and " - "name is |%s|\n", domain, username)); - return True; -} - -/**************************************************************** - Get the list of UNIX users in a group. - We have to enumerate the /etc/group file as some UNIX getgrnam() - calls won't do that for us (notably Tru64 UNIX). -****************************************************************/ - -struct sys_userlist *get_users_in_group(const char *gname) -{ - struct sys_userlist *list_head = NULL; - struct group *gptr; - fstring domain; - fstring groupname; - DOM_SID sid; - enum SID_NAME_USE name_type; - - /* No point using winbind if we can't split it in the - first place */ - if (split_domain_and_name(gname, domain, groupname)) { - - /* - * If we're doing this via winbindd, don't do the - * entire group list enumeration as we know this is - * pointless (and slow). - */ - - if (winbind_lookup_name(domain, groupname, &sid, &name_type) - && name_type == SID_NAME_DOM_GRP) { - if ((gptr = (struct group *)getgrnam(gname)) == NULL) - return NULL; - return add_members_to_userlist(list_head, gptr); - } - } - -#if !defined(BROKEN_GETGRNAM) - if ((gptr = (struct group *)getgrnam(gname)) == NULL) - return NULL; - return add_members_to_userlist(list_head, gptr); -#else - /* BROKEN_GETGRNAM - True64 */ - setgrent(); - while((gptr = getgrent()) != NULL) { - if (strequal(gname, gptr->gr_name)) { - list_head = add_members_to_userlist(list_head, gptr); - if (list_head == NULL) - return NULL; - } - } - endgrent(); - return list_head; -#endif -} - -/**************************************************************** - Free list allocated above. -****************************************************************/ - -void free_userlist(struct sys_userlist *list_head) -{ - while (list_head) { - struct sys_userlist *old_head = list_head; - DLIST_REMOVE(list_head, list_head); - SAFE_FREE(old_head->unix_name); - SAFE_FREE(old_head); - } -} diff --git a/source3/passdb/passdb.c b/source3/passdb/passdb.c index 4d20352312..2b1da6ecce 100644 --- a/source3/passdb/passdb.c +++ b/source3/passdb/passdb.c @@ -6,6 +6,7 @@ Copyright (C) Gerald (Jerry) Carter 2000-2001 Copyright (C) Andrew Bartlett 2001-2002 Copyright (C) Simo Sorce 2003 + Copyright (C) Volker Lendecke 2006 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -844,111 +845,70 @@ BOOL algorithmic_pdb_rid_is_user(uint32 rid) Convert a name into a SID. Used in the lookup name rpc. ********************************************************************/ -BOOL lookup_global_sam_name(const char *c_user, int flags, uint32_t *rid, +BOOL lookup_global_sam_name(const char *user, int flags, uint32_t *rid, enum SID_NAME_USE *type) { - fstring user; - SAM_ACCOUNT *sam_account = NULL; - struct group *grp; GROUP_MAP map; - - /* - * user may be quoted a const string, and map_username and - * friends can modify it. Make a modifiable copy. JRA. - */ - - fstrcpy(user, c_user); - - (void)map_username(user); - - if (!NT_STATUS_IS_OK(pdb_init_sam(&sam_account))) { - return False; - } - - /* BEGIN ROOT BLOCK */ - - become_root(); + BOOL ret; /* LOOKUP_NAME_GROUP is a hack to allow valid users = @foo to work * correctly in the case where foo also exists as a user. If the flag * is set, don't look for users at all. */ - if (((flags & LOOKUP_NAME_GROUP) == 0) && - pdb_getsampwnam(sam_account, user)) { - const DOM_SID *user_sid; + if ((flags & LOOKUP_NAME_GROUP) == 0) { + SAM_ACCOUNT *sam_account = NULL; + DOM_SID user_sid; - unbecome_root(); - - user_sid = pdb_get_user_sid(sam_account); - - if (!sid_check_is_in_our_domain(user_sid)) { - DEBUG(0, ("User %s with invalid SID %s in passdb\n", - user, sid_string_static(user_sid))); + if (!NT_STATUS_IS_OK(pdb_init_sam(&sam_account))) { return False; } + + become_root(); + ret = pdb_getsampwnam(sam_account, user); + unbecome_root(); - sid_peek_rid(user_sid, rid); - *type = SID_NAME_USER; + if (ret) { + sid_copy(&user_sid, pdb_get_user_sid(sam_account)); + } + pdb_free_sam(&sam_account); - return True; - } - pdb_free_sam(&sam_account); - - /* - * Maybe it was a group ? - */ - - /* check if it's a mapped group */ - if (pdb_getgrnam(&map, user)) { - - unbecome_root(); + if (ret) { + if (!sid_check_is_in_our_domain(&user_sid)) { + DEBUG(0, ("User %s with invalid SID %s in passdb\n", + user, sid_string_static(&user_sid))); + return False; + } - /* BUILTIN groups are looked up elsewhere */ - if (!sid_check_is_in_our_domain(&map.sid)) { - DEBUG(10, ("Found group %s (%s) not in our domain -- " - "ignoring.", user, - sid_string_static(&map.sid))); - return False; + sid_peek_rid(&user_sid, rid); + *type = SID_NAME_USER; + return True; } - - /* yes it's a mapped group */ - sid_peek_rid(&map.sid, rid); - *type = map.sid_name_use; - return True; } - return False; + /* + * Maybe it is a group ? + */ + + become_root(); + ret = pdb_getgrnam(&map, user); + unbecome_root(); - /* it's not a mapped group */ - grp = getgrnam(user); - if(!grp) { - unbecome_root(); /* ---> exit form block */ + if (!ret) { return False; } - - /* - *check if it's mapped, if it is reply it doesn't exist - * - * that's to prevent this case: - * - * unix group ug is mapped to nt group ng - * someone does a lookup on ug - * we must not reply as it doesn't "exist" anymore - * for NT. For NT only ng exists. - * JFM, 30/11/2001 - */ - - if (pdb_getgrgid(&map, grp->gr_gid)) { - unbecome_root(); /* ---> exit form block */ + + /* BUILTIN groups are looked up elsewhere */ + if (!sid_check_is_in_our_domain(&map.sid)) { + DEBUG(10, ("Found group %s (%s) not in our domain -- " + "ignoring.", user, + sid_string_static(&map.sid))); return False; } - unbecome_root(); - /* END ROOT BLOCK */ - - *rid = pdb_gid_to_group_rid(grp->gr_gid); - *type = SID_NAME_ALIAS; + /* yes it's a mapped group */ + sid_peek_rid(&map.sid, rid); + *type = map.sid_name_use; return True; } @@ -1086,7 +1046,7 @@ NTSTATUS local_password_change(const char *user_name, int local_flags, } if (local_flags & LOCAL_ADD_USER) { - if (pdb_add_sam_account(sam_pass)) { + if (NT_STATUS_IS_OK(pdb_add_sam_account(sam_pass))) { slprintf(msg_str, msg_str_len-1, "Added user %s.\n", user_name); pdb_free_sam(&sam_pass); return NT_STATUS_OK; @@ -1096,7 +1056,7 @@ NTSTATUS local_password_change(const char *user_name, int local_flags, return NT_STATUS_UNSUCCESSFUL; } } else if (local_flags & LOCAL_DELETE_USER) { - if (!pdb_delete_sam_account(sam_pass)) { + if (!NT_STATUS_IS_OK(pdb_delete_sam_account(sam_pass))) { slprintf(err_str,err_str_len-1, "Failed to delete entry for user %s.\n", user_name); pdb_free_sam(&sam_pass); return NT_STATUS_UNSUCCESSFUL; diff --git a/source3/passdb/pdb_interface.c b/source3/passdb/pdb_interface.c index 479ce18c05..c8917b9356 100644 --- a/source3/passdb/pdb_interface.c +++ b/source3/passdb/pdb_interface.c @@ -4,6 +4,7 @@ Copyright (C) Andrew Bartlett 2002 Copyright (C) Jelmer Vernooij 2002 Copyright (C) Simo Sorce 2003 + Copyright (C) Volker Lendecke 2006 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -331,15 +332,141 @@ BOOL pdb_getsampwsid(SAM_ACCOUNT *sam_acct, const DOM_SID *sid) return NT_STATUS_IS_OK(pdb->getsampwsid(pdb, sam_acct, sid)); } -BOOL pdb_add_sam_account(SAM_ACCOUNT *sam_acct) +static NTSTATUS pdb_default_create_user(struct pdb_methods *methods, + TALLOC_CTX *tmp_ctx, const char *name, + uint32 acb_info, uint32 *rid) +{ + SAM_ACCOUNT *sam_pass = NULL; + NTSTATUS status; + + if (Get_Pwnam_alloc(tmp_ctx, name) == NULL) { + pstring add_script; + int add_ret; + + if ((acb_info & ACB_NORMAL) && name[strlen(name)-1] != '$') { + pstrcpy(add_script, lp_adduser_script()); + } else { + pstrcpy(add_script, lp_addmachine_script()); + } + + if (add_script[0] == '\0') { + DEBUG(3, ("Could not find user %s and no add script " + "defined\n", name)); + return NT_STATUS_NO_SUCH_USER; + } + + all_string_sub(add_script, "%u", name, sizeof(add_script)); + add_ret = smbrun(add_script,NULL); + DEBUG(add_ret ? 0 : 3, ("_samr_create_user: Running the " + "command `%s' gave %d\n", + add_script, add_ret)); + } + + /* implicit call to getpwnam() next. we have a valid SID coming out + * of this call */ + + flush_pwnam_cache(); + status = pdb_init_sam_new(&sam_pass, name); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3, ("pdb_init_sam_new failed: %s\n", nt_errstr(status))); + return status; + } + + if (!sid_peek_check_rid(get_global_sam_sid(), + pdb_get_user_sid(sam_pass), rid)) { + DEBUG(0, ("Could not get RID of fresh user\n")); + return NT_STATUS_INTERNAL_ERROR; + } + + /* Disable the account on creation, it does not have a reasonable + * password yet. */ + + acb_info |= ACB_DISABLED; + + pdb_set_acct_ctrl(sam_pass, acb_info, PDB_CHANGED); + + status = pdb_add_sam_account(sam_pass); + + pdb_free_sam(&sam_pass); + + return status; +} + +NTSTATUS pdb_create_user(TALLOC_CTX *mem_ctx, const char *name, uint32 flags, + uint32 *rid) { struct pdb_methods *pdb = pdb_get_methods(False); if ( !pdb ) { - return False; + return NT_STATUS_UNSUCCESSFUL; + } + + return pdb->create_user(pdb, mem_ctx, name, flags, rid); +} + +/**************************************************************************** + Delete a UNIX user on demand. +****************************************************************************/ + +static int smb_delete_user(const char *unix_user) +{ + pstring del_script; + int ret; + + pstrcpy(del_script, lp_deluser_script()); + if (! *del_script) + return -1; + all_string_sub(del_script, "%u", unix_user, sizeof(del_script)); + ret = smbrun(del_script,NULL); + flush_pwnam_cache(); + DEBUG(ret ? 0 : 3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret)); + + return ret; +} + +static NTSTATUS pdb_default_delete_user(struct pdb_methods *methods, + TALLOC_CTX *mem_ctx, + SAM_ACCOUNT *sam_acct) +{ + NTSTATUS status; + + status = pdb_delete_sam_account(sam_acct); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* + * Now delete the unix side .... + * note: we don't check if the delete really happened as the script is + * not necessary present and maybe the sysadmin doesn't want to delete + * the unix side + */ + smb_delete_user( pdb_get_username(sam_acct) ); + + return status; +} + +NTSTATUS pdb_delete_user(TALLOC_CTX *mem_ctx, SAM_ACCOUNT *sam_acct) +{ + struct pdb_methods *pdb = pdb_get_methods(False); + + if ( !pdb ) { + return NT_STATUS_UNSUCCESSFUL; + } + + return pdb->delete_user(pdb, mem_ctx, sam_acct); +} + +NTSTATUS pdb_add_sam_account(SAM_ACCOUNT *sam_acct) +{ + struct pdb_methods *pdb = pdb_get_methods(False); + + if ( !pdb ) { + return NT_STATUS_UNSUCCESSFUL; } - return NT_STATUS_IS_OK(pdb->add_sam_account(pdb, sam_acct)); + return pdb->add_sam_account(pdb, sam_acct); } NTSTATUS pdb_update_sam_account(SAM_ACCOUNT *sam_acct) @@ -358,12 +485,12 @@ NTSTATUS pdb_update_sam_account(SAM_ACCOUNT *sam_acct) return pdb->update_sam_account(pdb, sam_acct); } -BOOL pdb_delete_sam_account(SAM_ACCOUNT *sam_acct) +NTSTATUS pdb_delete_sam_account(SAM_ACCOUNT *sam_acct) { struct pdb_methods *pdb = pdb_get_methods(False); if ( !pdb ) { - return False; + return NT_STATUS_UNSUCCESSFUL; } if (csamuser != NULL) { @@ -371,7 +498,7 @@ BOOL pdb_delete_sam_account(SAM_ACCOUNT *sam_acct) csamuser = NULL; } - return NT_STATUS_IS_OK(pdb->delete_sam_account(pdb, sam_acct)); + return pdb->delete_sam_account(pdb, sam_acct); } NTSTATUS pdb_rename_sam_account(SAM_ACCOUNT *oldname, const char *newname) @@ -434,6 +561,115 @@ BOOL pdb_getgrnam(GROUP_MAP *map, const char *name) return NT_STATUS_IS_OK(pdb->getgrnam(pdb, map, name)); } +static NTSTATUS pdb_default_create_dom_group(struct pdb_methods *methods, + TALLOC_CTX *mem_ctx, + const char *name, + uint32 *rid) +{ + DOM_SID group_sid; + struct group *grp; + + grp = getgrnam(name); + + if (grp == NULL) { + gid_t gid; + + if (smb_create_group(name, &gid) != 0) { + return NT_STATUS_ACCESS_DENIED; + } + + grp = getgrgid(gid); + } + + if (grp == NULL) { + return NT_STATUS_ACCESS_DENIED; + } + + if (pdb_rid_algorithm()) { + *rid = pdb_gid_to_group_rid( grp->gr_gid ); + } else { + if (!pdb_new_rid(rid)) { + return NT_STATUS_ACCESS_DENIED; + } + } + + sid_compose(&group_sid, get_global_sam_sid(), *rid); + + return add_initial_entry(grp->gr_gid, sid_string_static(&group_sid), + SID_NAME_DOM_GRP, name, NULL); +} + +NTSTATUS pdb_create_dom_group(TALLOC_CTX *mem_ctx, const char *name, + uint32 *rid) +{ + struct pdb_methods *pdb = pdb_get_methods(False); + + if ( !pdb ) { + return NT_STATUS_UNSUCCESSFUL; + } + + return pdb->create_dom_group(pdb, mem_ctx, name, rid); +} + +static NTSTATUS pdb_default_delete_dom_group(struct pdb_methods *methods, + TALLOC_CTX *mem_ctx, + uint32 rid) +{ + DOM_SID group_sid; + GROUP_MAP map; + NTSTATUS status; + struct group *grp; + const char *grp_name; + + sid_compose(&group_sid, get_global_sam_sid(), rid); + + if (!get_domain_group_from_sid(group_sid, &map)) { + DEBUG(10, ("Could not find group for rid %d\n", rid)); + return NT_STATUS_NO_SUCH_GROUP; + } + + /* We need the group name for the smb_delete_group later on */ + + if (map.gid == (gid_t)-1) { + return NT_STATUS_NO_SUCH_GROUP; + } + + grp = getgrgid(map.gid); + if (grp == NULL) { + return NT_STATUS_NO_SUCH_GROUP; + } + + /* Copy the name, no idea what pdb_delete_group_mapping_entry does.. */ + + grp_name = talloc_strdup(mem_ctx, grp->gr_name); + if (grp_name == NULL) { + return NT_STATUS_NO_MEMORY; + } + + status = pdb_delete_group_mapping_entry(group_sid); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* Don't check the result of smb_delete_group */ + + smb_delete_group(grp_name); + + return NT_STATUS_OK; +} + +NTSTATUS pdb_delete_dom_group(TALLOC_CTX *mem_ctx, uint32 rid) +{ + struct pdb_methods *pdb = pdb_get_methods(False); + + if ( !pdb ) { + return NT_STATUS_UNSUCCESSFUL; + } + + return pdb->delete_dom_group(pdb, mem_ctx, rid); +} + NTSTATUS pdb_add_group_mapping_entry(GROUP_MAP *map) { struct pdb_methods *pdb = pdb_get_methods(False); @@ -456,15 +692,15 @@ NTSTATUS pdb_update_group_mapping_entry(GROUP_MAP *map) return pdb->update_group_mapping_entry(pdb, map); } -BOOL pdb_delete_group_mapping_entry(DOM_SID sid) +NTSTATUS pdb_delete_group_mapping_entry(DOM_SID sid) { struct pdb_methods *pdb = pdb_get_methods(False); if ( !pdb ) { - return False; + return NT_STATUS_UNSUCCESSFUL; } - return NT_STATUS_IS_OK(pdb->delete_group_mapping_entry(pdb, sid)); + return pdb->delete_group_mapping_entry(pdb, sid); } BOOL pdb_enum_group_mapping(enum SID_NAME_USE sid_name_use, GROUP_MAP **pp_rmap, @@ -510,6 +746,200 @@ NTSTATUS pdb_enum_group_memberships(TALLOC_CTX *mem_ctx, SAM_ACCOUNT *user, pp_sids, pp_gids, p_num_groups); } +static NTSTATUS pdb_default_set_unix_primary_group(struct pdb_methods *methods, + TALLOC_CTX *mem_ctx, + SAM_ACCOUNT *sampass) +{ + struct group *grp; + gid_t gid; + + if (!sid_to_gid(pdb_get_group_sid(sampass), &gid) || + (grp = getgrgid(gid)) == NULL) { + return NT_STATUS_INVALID_PRIMARY_GROUP; + } + + if (smb_set_primary_group(grp->gr_name, + pdb_get_username(sampass)) != 0) { + return NT_STATUS_ACCESS_DENIED; + } + + return NT_STATUS_OK; +} + +NTSTATUS pdb_set_unix_primary_group(TALLOC_CTX *mem_ctx, SAM_ACCOUNT *user) +{ + struct pdb_methods *pdb = pdb_get_methods(False); + + if ( !pdb ) { + return NT_STATUS_UNSUCCESSFUL; + } + + return pdb->set_unix_primary_group(pdb, mem_ctx, user); +} + +/* + * Helper function to see whether a user is in a group. We can't use + * user_in_group_sid here because this creates dependencies only smbd can + * fulfil. + */ + +static BOOL pdb_user_in_group(TALLOC_CTX *mem_ctx, SAM_ACCOUNT *account, + const DOM_SID *group_sid) +{ + DOM_SID *sids; + gid_t *gids; + size_t i, num_groups; + + if (!NT_STATUS_IS_OK(pdb_enum_group_memberships(mem_ctx, account, + &sids, &gids, + &num_groups))) { + return False; + } + + for (i=0; igr_name); + if (group_name == NULL) { + return NT_STATUS_NO_MEMORY; + } + + if (!NT_STATUS_IS_OK(status = pdb_init_sam(&account))) { + return status; + } + + if (!pdb_getsampwsid(account, &member_sid) || + !sid_to_uid(&member_sid, &uid) || + ((pwd = getpwuid_alloc(mem_ctx, uid)) == NULL)) { + return NT_STATUS_NO_SUCH_USER; + } + + if (pdb_user_in_group(mem_ctx, account, &group_sid)) { + return NT_STATUS_MEMBER_IN_GROUP; + } + + /* + * ok, the group exist, the user exist, the user is not in the group, + * we can (finally) add it to the group ! + */ + + smb_add_user_group(group_name, pwd->pw_name); + + if (!pdb_user_in_group(mem_ctx, account, &group_sid)) { + return NT_STATUS_ACCESS_DENIED; + } + + return NT_STATUS_OK; +} + +NTSTATUS pdb_add_groupmem(TALLOC_CTX *mem_ctx, uint32 group_rid, + uint32 member_rid) +{ + struct pdb_methods *pdb = pdb_get_methods(False); + + if ( !pdb ) { + return NT_STATUS_UNSUCCESSFUL; + } + + return pdb->add_groupmem(pdb, mem_ctx, group_rid, member_rid); +} + +static NTSTATUS pdb_default_del_groupmem(struct pdb_methods *methods, + TALLOC_CTX *mem_ctx, + uint32 group_rid, + uint32 member_rid) +{ + DOM_SID group_sid, member_sid; + SAM_ACCOUNT *account = NULL; + GROUP_MAP map; + struct group *grp; + struct passwd *pwd; + const char *group_name; + uid_t uid; + NTSTATUS status; + + sid_compose(&group_sid, get_global_sam_sid(), group_rid); + sid_compose(&member_sid, get_global_sam_sid(), member_rid); + + if (!get_domain_group_from_sid(group_sid, &map) || + (map.gid == (gid_t)-1) || + ((grp = getgrgid(map.gid)) == NULL)) { + return NT_STATUS_NO_SUCH_GROUP; + } + + group_name = talloc_strdup(mem_ctx, grp->gr_name); + if (group_name == NULL) { + return NT_STATUS_NO_MEMORY; + } + + if (!NT_STATUS_IS_OK(status = pdb_init_sam(&account))) { + return status; + } + + if (!pdb_getsampwsid(account, &member_sid) || + !sid_to_uid(&member_sid, &uid) || + ((pwd = getpwuid_alloc(mem_ctx, uid)) == NULL)) { + return NT_STATUS_NO_SUCH_USER; + } + + if (!pdb_user_in_group(mem_ctx, account, &group_sid)) { + return NT_STATUS_MEMBER_NOT_IN_GROUP; + } + + /* + * ok, the group exist, the user exist, the user is in the group, + * we can (finally) delete it from the group! + */ + + smb_delete_user_group(group_name, pwd->pw_name); + + if (pdb_user_in_group(mem_ctx, account, &group_sid)) { + return NT_STATUS_ACCESS_DENIED; + } + + return NT_STATUS_OK; +} + +NTSTATUS pdb_del_groupmem(TALLOC_CTX *mem_ctx, uint32 group_rid, + uint32 member_rid) +{ + struct pdb_methods *pdb = pdb_get_methods(False); + + if ( !pdb ) { + return NT_STATUS_UNSUCCESSFUL; + } + + return pdb->del_groupmem(pdb, mem_ctx, group_rid, member_rid); +} + BOOL pdb_find_alias(const char *name, DOM_SID *sid) { struct pdb_methods *pdb = pdb_get_methods(False); @@ -977,7 +1407,7 @@ static BOOL get_memberuids(TALLOC_CTX *mem_ctx, gid_t gid, uid_t **pp_uids, size { struct group *grp; char **gr; - struct sys_pwent *userlist, *user; + struct passwd *pwd; *pp_uids = NULL; *p_num = 0; @@ -993,15 +1423,14 @@ static BOOL get_memberuids(TALLOC_CTX *mem_ctx, gid_t gid, uid_t **pp_uids, size /* Primary group members */ - userlist = getpwent_list(); - - for (user = userlist; user != NULL; user = user->next) { - if (user->pw_gid != gid) - continue; - add_uid_to_array_unique(mem_ctx, user->pw_uid, pp_uids, p_num); + setpwent(); + while ((pwd = getpwent()) != NULL) { + if (pwd->pw_gid == gid) { + add_uid_to_array_unique(mem_ctx, pwd->pw_uid, + pp_uids, p_num); + } } - - pwent_free(userlist); + endpwent(); /* Secondary group members */ @@ -1048,7 +1477,7 @@ NTSTATUS pdb_default_enum_group_members(struct pdb_methods *methods, uid_to_sid(&sid, uids[i]); if (!sid_check_is_in_our_domain(&sid)) { - DEBUG(1, ("Inconsistent SAM -- group member uid not " + DEBUG(5, ("Inconsistent SAM -- group member uid not " "in our domain\n")); continue; } @@ -1060,6 +1489,44 @@ NTSTATUS pdb_default_enum_group_members(struct pdb_methods *methods, return NT_STATUS_OK; } +NTSTATUS pdb_default_enum_group_memberships(struct pdb_methods *methods, + TALLOC_CTX *mem_ctx, + SAM_ACCOUNT *user, + DOM_SID **pp_sids, + gid_t **pp_gids, + size_t *p_num_groups) +{ + size_t i; + gid_t gid; + + if (!sid_to_gid(pdb_get_group_sid(user), &gid)) { + DEBUG(10, ("sid_to_gid failed\n")); + return NT_STATUS_NO_SUCH_USER; + } + + if (!getgroups_unix_user(mem_ctx, pdb_get_username(user), gid, + pp_gids, p_num_groups)) { + return NT_STATUS_NO_SUCH_USER; + } + + if (*p_num_groups == 0) { + smb_panic("primary group missing"); + } + + *pp_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, *p_num_groups); + + if (*pp_sids == NULL) { + talloc_free(*pp_gids); + return NT_STATUS_NO_MEMORY; + } + + for (i=0; i<*p_num_groups; i++) { + gid_to_sid(&(*pp_sids)[i], (*pp_gids)[i]); + } + + return NT_STATUS_OK; +} + /******************************************************************* Look up a rid in the SAM we're responsible for (i.e. passdb) ********************************************************************/ @@ -1603,6 +2070,8 @@ NTSTATUS make_pdb_method( struct pdb_methods **methods ) (*methods)->getsampwent = pdb_default_getsampwent; (*methods)->getsampwnam = pdb_default_getsampwnam; (*methods)->getsampwsid = pdb_default_getsampwsid; + (*methods)->create_user = pdb_default_create_user; + (*methods)->delete_user = pdb_default_delete_user; (*methods)->add_sam_account = pdb_default_add_sam_account; (*methods)->update_sam_account = pdb_default_update_sam_account; (*methods)->delete_sam_account = pdb_default_delete_sam_account; @@ -1612,12 +2081,17 @@ NTSTATUS make_pdb_method( struct pdb_methods **methods ) (*methods)->getgrsid = pdb_default_getgrsid; (*methods)->getgrgid = pdb_default_getgrgid; (*methods)->getgrnam = pdb_default_getgrnam; + (*methods)->create_dom_group = pdb_default_create_dom_group; + (*methods)->delete_dom_group = pdb_default_delete_dom_group; (*methods)->add_group_mapping_entry = pdb_default_add_group_mapping_entry; (*methods)->update_group_mapping_entry = pdb_default_update_group_mapping_entry; (*methods)->delete_group_mapping_entry = pdb_default_delete_group_mapping_entry; (*methods)->enum_group_mapping = pdb_default_enum_group_mapping; (*methods)->enum_group_members = pdb_default_enum_group_members; (*methods)->enum_group_memberships = pdb_default_enum_group_memberships; + (*methods)->set_unix_primary_group = pdb_default_set_unix_primary_group; + (*methods)->add_groupmem = pdb_default_add_groupmem; + (*methods)->del_groupmem = pdb_default_del_groupmem; (*methods)->find_alias = pdb_default_find_alias; (*methods)->create_alias = pdb_default_create_alias; (*methods)->delete_alias = pdb_default_delete_alias; diff --git a/source3/rpc_server/srv_samr_nt.c b/source3/rpc_server/srv_samr_nt.c index b3be0cccc1..133178bd0d 100644 --- a/source3/rpc_server/srv_samr_nt.c +++ b/source3/rpc_server/srv_samr_nt.c @@ -2410,18 +2410,13 @@ static NTSTATUS can_create(TALLOC_CTX *mem_ctx, const char *new_name) NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREATE_USER *r_u) { - SAM_ACCOUNT *sam_pass=NULL; - fstring account; + char *account; DOM_SID sid; - pstring add_script; POLICY_HND dom_pol = q_u->domain_pol; - UNISTR2 user_account = q_u->uni_name; uint16 acb_info = q_u->acb_info; POLICY_HND *user_pol = &r_u->user_pol; struct samr_info *info = NULL; - BOOL ret; NTSTATUS nt_status; - struct passwd *pw; uint32 acc_granted; SEC_DESC *psd; size_t sd_size; @@ -2450,33 +2445,20 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, return NT_STATUS_INVALID_PARAMETER; } - rpcstr_pull(account, user_account.buffer, sizeof(account), - user_account.uni_str_len*2, 0); - strlower_m(account); + account = rpcstr_pull_unistr2_talloc(p->mem_ctx, &q_u->uni_name); + if (account == NULL) { + return NT_STATUS_NO_MEMORY; + } nt_status = can_create(p->mem_ctx, account); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } - /********************************************************************* - * HEADS UP! If we have to create a new user account, we have to get - * a new RID from somewhere. This used to be done by the passdb - * backend. It has been moved into idmap now. Since idmap is now - * wrapped up behind winbind, this means you have to run winbindd if - * you want new accounts to get a new RID when "enable rid algorithm = - * no". Tough. We now have a uniform way of allocating RIDs - * regardless of what ever passdb backend people may use. --jerry - * (2003-07-10) - *********************************************************************/ - - pw = Get_Pwnam(account); - /* determine which user right we need to check based on the acb_info */ if ( acb_info & ACB_WSTRUST ) { - pstrcpy(add_script, lp_addmachine_script()); se_priv_copy( &se_rights, &se_machine_account ); can_add_account = user_has_privileges( p->pipe_user.nt_user_token, &se_rights ); @@ -2486,7 +2468,6 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, else if ( acb_info & ACB_NORMAL && (account[strlen(account)-1] != '$') ) { - pstrcpy(add_script, lp_adduser_script()); se_priv_copy( &se_rights, &se_add_users ); can_add_account = user_has_privileges( p->pipe_user.nt_user_token, &se_rights ); @@ -2494,7 +2475,6 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, else /* implicit assumption of a BDC or domain trust account here * (we already check the flags earlier) */ { - pstrcpy(add_script, lp_addmachine_script()); if ( lp_enable_privileges() ) { /* only Domain Admins can add a BDC or domain trust */ se_priv_copy( &se_rights, &se_priv_none ); @@ -2512,40 +2492,9 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, if ( can_add_account ) become_root(); - if ( !pw ) { - if (*add_script) { - int add_ret; - - all_string_sub(add_script, "%u", account, - sizeof(add_script)); - add_ret = smbrun(add_script,NULL); - DEBUG(add_ret ? 0 : 3,("_samr_create_user: Running " - "the command `%s' gave %d\n", - add_script, add_ret)); - } - } - - /* implicit call to getpwnam() next. we have a valid SID coming out - * of this call */ + nt_status = pdb_create_user(p->mem_ctx, account, acb_info, + &r_u->user_rid); - flush_pwnam_cache(); - nt_status = pdb_init_sam_new(&sam_pass, account); - - /* this code is order such that we have no unnecessary retuns - out of the admin block of code */ - - if ( NT_STATUS_IS_OK(nt_status) ) { - pdb_set_acct_ctrl(sam_pass, acb_info, PDB_CHANGED); - - if ( !(ret = pdb_add_sam_account(sam_pass)) ) { - pdb_free_sam(&sam_pass); - DEBUG(0, ("could not add user/computer %s to passdb. " - "Check permissions?\n", - account)); - nt_status = NT_STATUS_ACCESS_DENIED; - } - } - if ( can_add_account ) unbecome_root(); @@ -2557,8 +2506,8 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, return nt_status; /* Get the user's SID */ - - sid_copy(&sid, pdb_get_user_sid(sam_pass)); + + sid_compose(&sid, get_global_sam_sid(), r_u->user_rid); make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &usr_generic_mapping, &sid, SAMR_USR_RIGHTS_WRITE_PW); @@ -2574,7 +2523,6 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, /* associate the user's SID with the new handle. */ if ((info = get_samr_info_by_sid(&sid)) == NULL) { - pdb_free_sam(&sam_pass); return NT_STATUS_NO_MEMORY; } @@ -2584,19 +2532,14 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, /* get a (unique) handle. open a policy on it. */ if (!create_policy_hnd(p, user_pol, free_samr_info, (void *)info)) { - pdb_free_sam(&sam_pass); return NT_STATUS_OBJECT_NAME_NOT_FOUND; } /* After a "set" ensure we have no cached display info. */ force_flush_samr_cache(info->disp_info); - r_u->user_rid=pdb_get_user_rid(sam_pass); - r_u->access_granted = acc_granted; - pdb_free_sam(&sam_pass); - return NT_STATUS_OK; } @@ -3097,41 +3040,6 @@ static BOOL set_user_info_18(SAM_USER_INFO_18 *id18, SAM_ACCOUNT *pwd) return True; } -/******************************************************************* - The GROUPSID field in the SAM_ACCOUNT changed. Try to tell unix. - ********************************************************************/ -static BOOL set_unix_primary_group(SAM_ACCOUNT *sampass) -{ - struct group *grp; - gid_t gid; - - if (!sid_to_gid(pdb_get_group_sid(sampass), &gid)) { - DEBUG(2,("Could not get gid for primary group of " - "user %s\n", pdb_get_username(sampass))); - return False; - } - - grp = getgrgid(gid); - - if (grp == NULL) { - DEBUG(2,("Could not find primary group %lu for " - "user %s\n", (unsigned long)gid, - pdb_get_username(sampass))); - return False; - } - - if (smb_set_primary_group(grp->gr_name, - pdb_get_username(sampass)) != 0) { - DEBUG(2,("Could not set primary group for user %s to " - "%s\n", - pdb_get_username(sampass), grp->gr_name)); - return False; - } - - return True; -} - - /******************************************************************* set_user_info_20 ********************************************************************/ @@ -3159,12 +3067,14 @@ static BOOL set_user_info_20(SAM_USER_INFO_20 *id20, SAM_ACCOUNT *pwd) set_user_info_21 ********************************************************************/ -static BOOL set_user_info_21(SAM_USER_INFO_21 *id21, SAM_ACCOUNT *pwd) +static NTSTATUS set_user_info_21(TALLOC_CTX *mem_ctx, SAM_USER_INFO_21 *id21, + SAM_ACCOUNT *pwd) { - + NTSTATUS status; + if (id21 == NULL) { DEBUG(5, ("set_user_info_21: NULL id21\n")); - return False; + return NT_STATUS_INVALID_PARAMETER; } copy_id21_to_sam_passwd(pwd, id21); @@ -3176,33 +3086,38 @@ static BOOL set_user_info_21(SAM_USER_INFO_21 *id21, SAM_ACCOUNT *pwd) * id21. I don't know if they need to be set. --jerry */ - if (IS_SAM_CHANGED(pwd, PDB_GROUPSID)) - set_unix_primary_group(pwd); + if (IS_SAM_CHANGED(pwd, PDB_GROUPSID) && + !NT_STATUS_IS_OK(status = pdb_set_unix_primary_group(mem_ctx, + pwd))) { + return status; + } /* write the change out */ - if(!NT_STATUS_IS_OK(pdb_update_sam_account(pwd))) { + if(!NT_STATUS_IS_OK(status = pdb_update_sam_account(pwd))) { pdb_free_sam(&pwd); - return False; + return status; } pdb_free_sam(&pwd); - return True; + return NT_STATUS_OK; } /******************************************************************* set_user_info_23 ********************************************************************/ -static BOOL set_user_info_23(SAM_USER_INFO_23 *id23, SAM_ACCOUNT *pwd) +static NTSTATUS set_user_info_23(TALLOC_CTX *mem_ctx, SAM_USER_INFO_23 *id23, + SAM_ACCOUNT *pwd) { pstring plaintext_buf; uint32 len; uint16 acct_ctrl; + NTSTATUS status; if (id23 == NULL) { DEBUG(5, ("set_user_info_23: NULL id23\n")); - return False; + return NT_STATUS_INVALID_PARAMETER; } DEBUG(5, ("Attempting administrator password change (level 23) for user %s\n", @@ -3212,12 +3127,12 @@ static BOOL set_user_info_23(SAM_USER_INFO_23 *id23, SAM_ACCOUNT *pwd) if (!decode_pw_buffer(id23->pass, plaintext_buf, 256, &len, STR_UNICODE)) { pdb_free_sam(&pwd); - return False; + return NT_STATUS_INVALID_PARAMETER; } if (!pdb_set_plaintext_passwd (pwd, plaintext_buf)) { pdb_free_sam(&pwd); - return False; + return NT_STATUS_ACCESS_DENIED; } copy_id23_to_sam_passwd(pwd, id23); @@ -3237,24 +3152,28 @@ static BOOL set_user_info_23(SAM_USER_INFO_23 *id23, SAM_ACCOUNT *pwd) if(!chgpasswd(pdb_get_username(pwd), passwd, "", plaintext_buf, True)) { pdb_free_sam(&pwd); - return False; + return NT_STATUS_ACCESS_DENIED; } } } ZERO_STRUCT(plaintext_buf); - if (IS_SAM_CHANGED(pwd, PDB_GROUPSID)) - set_unix_primary_group(pwd); + if (IS_SAM_CHANGED(pwd, PDB_GROUPSID) && + (!NT_STATUS_IS_OK(status = pdb_set_unix_primary_group(mem_ctx, + pwd)))) { + pdb_free_sam(&pwd); + return status; + } - if(!NT_STATUS_IS_OK(pdb_update_sam_account(pwd))) { + if(!NT_STATUS_IS_OK(status = pdb_update_sam_account(pwd))) { pdb_free_sam(&pwd); - return False; + return status; } pdb_free_sam(&pwd); - return True; + return NT_STATUS_OK; } /******************************************************************* @@ -3444,8 +3363,8 @@ NTSTATUS _samr_set_userinfo(pipes_struct *p, SAMR_Q_SET_USERINFO *q_u, SAMR_R_SE dump_data(100, (char *)ctr->info.id23->pass, 516); - if (!set_user_info_23(ctr->info.id23, pwd)) - r_u->status = NT_STATUS_ACCESS_DENIED; + r_u->status = set_user_info_23(p->mem_ctx, + ctr->info.id23, pwd); break; default: @@ -3558,8 +3477,8 @@ NTSTATUS _samr_set_userinfo2(pipes_struct *p, SAMR_Q_SET_USERINFO2 *q_u, SAMR_R_ r_u->status = NT_STATUS_ACCESS_DENIED; break; case 21: - if (!set_user_info_21(ctr->info.id21, pwd)) - return NT_STATUS_ACCESS_DENIED; + r_u->status = set_user_info_21(p->mem_ctx, + ctr->info.id21, pwd); break; case 23: if (!p->session_key.length) { @@ -3569,8 +3488,8 @@ NTSTATUS _samr_set_userinfo2(pipes_struct *p, SAMR_Q_SET_USERINFO2 *q_u, SAMR_R_ dump_data(100, (char *)ctr->info.id23->pass, 516); - if (!set_user_info_23(ctr->info.id23, pwd)) - r_u->status = NT_STATUS_ACCESS_DENIED; + r_u->status = set_user_info_23(p->mem_ctx, + ctr->info.id23, pwd); break; case 26: if (!p->session_key.length) { @@ -3713,70 +3632,6 @@ NTSTATUS _samr_query_aliasmem(pipes_struct *p, SAMR_Q_QUERY_ALIASMEM *q_u, SAMR_ return NT_STATUS_OK; } -static void add_uid_to_array_unique(uid_t uid, uid_t **uids, int *num) -{ - int i; - - for (i=0; i<*num; i++) { - if ((*uids)[i] == uid) - return; - } - - *uids = SMB_REALLOC_ARRAY(*uids, uid_t, *num+1); - - if (*uids == NULL) - return; - - (*uids)[*num] = uid; - *num += 1; -} - - -static BOOL get_memberuids(gid_t gid, uid_t **uids, int *num) -{ - struct group *grp; - char **gr; - struct sys_pwent *userlist, *user; - - *uids = NULL; - *num = 0; - - /* We only look at our own sam, so don't care about imported stuff */ - - winbind_off(); - - if ((grp = getgrgid(gid)) == NULL) { - winbind_on(); - return False; - } - - /* Primary group members */ - - userlist = getpwent_list(); - - for (user = userlist; user != NULL; user = user->next) { - if (user->pw_gid != gid) - continue; - add_uid_to_array_unique(user->pw_uid, uids, num); - } - - pwent_free(userlist); - - /* Secondary group members */ - - for (gr = grp->gr_mem; (*gr != NULL) && ((*gr)[0] != '\0'); gr += 1) { - struct passwd *pw = getpwnam(*gr); - - if (pw == NULL) - continue; - add_uid_to_array_unique(pw->pw_uid, uids, num); - } - - winbind_on(); - - return True; -} - /********************************************************************* _samr_query_groupmem *********************************************************************/ @@ -3931,16 +3786,7 @@ NTSTATUS _samr_del_aliasmem(pipes_struct *p, SAMR_Q_DEL_ALIASMEM *q_u, SAMR_R_DE NTSTATUS _samr_add_groupmem(pipes_struct *p, SAMR_Q_ADD_GROUPMEM *q_u, SAMR_R_ADD_GROUPMEM *r_u) { DOM_SID group_sid; - DOM_SID user_sid; - fstring group_sid_str; - uid_t uid; - struct passwd *pwd; - struct group *grp; - fstring grp_name; - GROUP_MAP map; - NTSTATUS ret; - SAM_ACCOUNT *sam_user=NULL; - BOOL check; + uint32 group_rid; uint32 acc_granted; SE_PRIV se_rights; BOOL can_add_accounts; @@ -3954,53 +3800,11 @@ NTSTATUS _samr_add_groupmem(pipes_struct *p, SAMR_Q_ADD_GROUPMEM *q_u, SAMR_R_AD return r_u->status; } - sid_to_string(group_sid_str, &group_sid); - DEBUG(10, ("sid is %s\n", group_sid_str)); - - if (sid_compare(&group_sid, get_global_sam_sid())<=0) - return NT_STATUS_NO_SUCH_GROUP; - - DEBUG(10, ("lookup on Domain SID\n")); - - if(!get_domain_group_from_sid(group_sid, &map)) - return NT_STATUS_NO_SUCH_GROUP; - - sid_copy(&user_sid, get_global_sam_sid()); - sid_append_rid(&user_sid, q_u->rid); - - ret = pdb_init_sam(&sam_user); - if (!NT_STATUS_IS_OK(ret)) - return ret; - - check = pdb_getsampwsid(sam_user, &user_sid); - - if (check != True) { - pdb_free_sam(&sam_user); - return NT_STATUS_NO_SUCH_USER; - } + DEBUG(10, ("sid is %s\n", sid_string_static(&group_sid))); - /* check a real user exist before we run the script to add a user to a group */ - if (!sid_to_uid(pdb_get_user_sid(sam_user), &uid)) { - pdb_free_sam(&sam_user); - return NT_STATUS_NO_SUCH_USER; - } - - pdb_free_sam(&sam_user); - - if ((pwd=getpwuid_alloc(p->mem_ctx, uid)) == NULL) { - return NT_STATUS_NO_SUCH_USER; - } - - if ((grp=getgrgid(map.gid)) == NULL) { - return NT_STATUS_NO_SUCH_GROUP; - } - - /* we need to copy the name otherwise it's overloaded in user_in_unix_group_list */ - fstrcpy(grp_name, grp->gr_name); - - /* if the user is already in the group */ - if(user_in_unix_group(pwd->pw_name, grp_name)) { - return NT_STATUS_MEMBER_IN_GROUP; + if (!sid_peek_check_rid(get_global_sam_sid(), &group_sid, + &group_rid)) { + return NT_STATUS_INVALID_HANDLE; } se_priv_copy( &se_rights, &se_add_users ); @@ -4010,28 +3814,17 @@ NTSTATUS _samr_add_groupmem(pipes_struct *p, SAMR_Q_ADD_GROUPMEM *q_u, SAMR_R_AD if ( can_add_accounts ) become_root(); - - /* - * ok, the group exist, the user exist, the user is not in the group, - * - * we can (finally) add it to the group ! - */ - - smb_add_user_group(grp_name, pwd->pw_name); + r_u->status = pdb_add_groupmem(p->mem_ctx, group_rid, q_u->rid); + if ( can_add_accounts ) unbecome_root(); /******** END SeAddUsers BLOCK *********/ - /* check if the user has been added then ... */ - if(!user_in_unix_group(pwd->pw_name, grp_name)) { - return NT_STATUS_MEMBER_NOT_IN_GROUP; /* don't know what to reply else */ - } - force_flush_samr_cache(disp_info); - return NT_STATUS_OK; + return r_u->status; } /********************************************************************* @@ -4041,11 +3834,7 @@ NTSTATUS _samr_add_groupmem(pipes_struct *p, SAMR_Q_ADD_GROUPMEM *q_u, SAMR_R_AD NTSTATUS _samr_del_groupmem(pipes_struct *p, SAMR_Q_DEL_GROUPMEM *q_u, SAMR_R_DEL_GROUPMEM *r_u) { DOM_SID group_sid; - DOM_SID user_sid; - SAM_ACCOUNT *sam_pass=NULL; - GROUP_MAP map; - fstring grp_name; - struct group *grp; + uint32 group_rid; uint32 acc_granted; SE_PRIV se_rights; BOOL can_add_accounts; @@ -4064,36 +3853,11 @@ NTSTATUS _samr_del_groupmem(pipes_struct *p, SAMR_Q_DEL_GROUPMEM *q_u, SAMR_R_DE if (!NT_STATUS_IS_OK(r_u->status = access_check_samr_function(acc_granted, SA_RIGHT_GROUP_REMOVE_MEMBER, "_samr_del_groupmem"))) { return r_u->status; } - - if (!sid_check_is_in_our_domain(&group_sid)) - return NT_STATUS_NO_SUCH_GROUP; - - sid_copy(&user_sid, get_global_sam_sid()); - sid_append_rid(&user_sid, q_u->rid); - - if (!get_domain_group_from_sid(group_sid, &map)) - return NT_STATUS_NO_SUCH_GROUP; - - if ((grp=getgrgid(map.gid)) == NULL) - return NT_STATUS_NO_SUCH_GROUP; - - /* we need to copy the name otherwise it's overloaded in user_in_group_list */ - fstrcpy(grp_name, grp->gr_name); - - /* check if the user exists before trying to remove it from the group */ - pdb_init_sam(&sam_pass); - if (!pdb_getsampwsid(sam_pass, &user_sid)) { - DEBUG(5,("User %s doesn't exist.\n", pdb_get_username(sam_pass))); - pdb_free_sam(&sam_pass); - return NT_STATUS_NO_SUCH_USER; - } - /* if the user is not in the group */ - if (!user_in_unix_group(pdb_get_username(sam_pass), grp_name)) { - pdb_free_sam(&sam_pass); - return NT_STATUS_MEMBER_NOT_IN_GROUP; + if (!sid_peek_check_rid(get_global_sam_sid(), &group_sid, + &group_rid)) { + return NT_STATUS_INVALID_HANDLE; } - se_priv_copy( &se_rights, &se_add_users ); can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_rights ); @@ -4103,45 +3867,16 @@ NTSTATUS _samr_del_groupmem(pipes_struct *p, SAMR_Q_DEL_GROUPMEM *q_u, SAMR_R_DE if ( can_add_accounts ) become_root(); - smb_delete_user_group(grp_name, pdb_get_username(sam_pass)); + r_u->status = pdb_del_groupmem(p->mem_ctx, group_rid, q_u->rid); if ( can_add_accounts ) unbecome_root(); /******** END SeAddUsers BLOCK *********/ - /* check if the user has been removed then ... */ - if (user_in_unix_group(pdb_get_username(sam_pass), grp_name)) { - pdb_free_sam(&sam_pass); - return NT_STATUS_ACCESS_DENIED; /* don't know what to reply else */ - } - - pdb_free_sam(&sam_pass); - force_flush_samr_cache(disp_info); - return NT_STATUS_OK; - -} - -/**************************************************************************** - Delete a UNIX user on demand. -****************************************************************************/ - -static int smb_delete_user(const char *unix_user) -{ - pstring del_script; - int ret; - - pstrcpy(del_script, lp_deluser_script()); - if (! *del_script) - return -1; - all_string_sub(del_script, "%u", unix_user, sizeof(del_script)); - ret = smbrun(del_script,NULL); - flush_pwnam_cache(); - DEBUG(ret ? 0 : 3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret)); - - return ret; + return r_u->status; } /********************************************************************* @@ -4154,7 +3889,6 @@ NTSTATUS _samr_delete_dom_user(pipes_struct *p, SAMR_Q_DELETE_DOM_USER *q_u, SAM SAM_ACCOUNT *sam_pass=NULL; uint32 acc_granted; BOOL can_add_accounts; - BOOL ret; DISP_INFO *disp_info = NULL; DEBUG(5, ("_samr_delete_dom_user: %d\n", __LINE__)); @@ -4186,29 +3920,19 @@ NTSTATUS _samr_delete_dom_user(pipes_struct *p, SAMR_Q_DELETE_DOM_USER *q_u, SAM if ( can_add_accounts ) become_root(); - /* First delete the samba side.... - code is order to prevent unnecessary returns out of the admin - block of code */ - - if ( (ret = pdb_delete_sam_account(sam_pass)) == True ) { - /* - * Now delete the unix side .... - * note: we don't check if the delete really happened - * as the script is not necessary present - * and maybe the sysadmin doesn't want to delete the unix side - */ - smb_delete_user( pdb_get_username(sam_pass) ); - } - + r_u->status = pdb_delete_user(p->mem_ctx, sam_pass); + if ( can_add_accounts ) unbecome_root(); /******** END SeAddUsers BLOCK *********/ - if ( !ret ) { - DEBUG(5,("_samr_delete_dom_user:Failed to delete entry for user %s.\n", pdb_get_username(sam_pass))); + if ( !NT_STATUS_IS_OK(r_u->status) ) { + DEBUG(5,("_samr_delete_dom_user: Failed to delete entry for " + "user %s: %s.\n", pdb_get_username(sam_pass), + nt_errstr(r_u->status))); pdb_free_sam(&sam_pass); - return NT_STATUS_CANNOT_DELETE; + return r_u->status; } @@ -4229,16 +3953,10 @@ NTSTATUS _samr_delete_dom_user(pipes_struct *p, SAMR_Q_DELETE_DOM_USER *q_u, SAM NTSTATUS _samr_delete_dom_group(pipes_struct *p, SAMR_Q_DELETE_DOM_GROUP *q_u, SAMR_R_DELETE_DOM_GROUP *r_u) { DOM_SID group_sid; - DOM_SID dom_sid; uint32 group_rid; - fstring group_sid_str; - gid_t gid; - struct group *grp; - GROUP_MAP map; uint32 acc_granted; SE_PRIV se_rights; BOOL can_add_accounts; - BOOL ret; DISP_INFO *disp_info = NULL; DEBUG(5, ("samr_delete_dom_group: %d\n", __LINE__)); @@ -4250,27 +3968,13 @@ NTSTATUS _samr_delete_dom_group(pipes_struct *p, SAMR_Q_DELETE_DOM_GROUP *q_u, S if (!NT_STATUS_IS_OK(r_u->status = access_check_samr_function(acc_granted, STD_RIGHT_DELETE_ACCESS, "_samr_delete_dom_group"))) { return r_u->status; } - - sid_copy(&dom_sid, &group_sid); - sid_to_string(group_sid_str, &dom_sid); - sid_split_rid(&dom_sid, &group_rid); - DEBUG(10, ("sid is %s\n", group_sid_str)); + DEBUG(10, ("sid is %s\n", sid_string_static(&group_sid))); - /* we check if it's our SID before deleting */ - if (!sid_equal(&dom_sid, get_global_sam_sid())) - return NT_STATUS_NO_SUCH_GROUP; - - DEBUG(10, ("lookup on Domain SID\n")); - - if(!get_domain_group_from_sid(group_sid, &map)) - return NT_STATUS_NO_SUCH_GROUP; - - gid=map.gid; - - /* check if group really exists */ - if ( (grp=getgrgid(gid)) == NULL) + if (!sid_peek_check_rid(get_global_sam_sid(), &group_sid, + &group_rid)) { return NT_STATUS_NO_SUCH_GROUP; + } se_priv_copy( &se_rights, &se_add_users ); can_add_accounts = user_has_privileges( p->pipe_user.nt_user_token, &se_rights ); @@ -4280,26 +3984,21 @@ NTSTATUS _samr_delete_dom_group(pipes_struct *p, SAMR_Q_DELETE_DOM_GROUP *q_u, S if ( can_add_accounts ) become_root(); - /* delete mapping first */ - - if ( (ret = pdb_delete_group_mapping_entry(group_sid)) == True ) { - smb_delete_group( grp->gr_name ); - } + r_u->status = pdb_delete_dom_group(p->mem_ctx, group_rid); if ( can_add_accounts ) unbecome_root(); /******** END SeAddUsers BLOCK *********/ - if ( !ret ) { - DEBUG(5,("_samr_delete_dom_group: Failed to delete mapping entry for group %s.\n", - group_sid_str)); - return NT_STATUS_ACCESS_DENIED; + if ( !NT_STATUS_IS_OK(r_u->status) ) { + DEBUG(5,("_samr_delete_dom_group: Failed to delete mapping " + "entry for group %s: %s\n", + sid_string_static(&group_sid), + nt_errstr(r_u->status))); + return r_u->status; } - /* don't check that the unix group has been deleted. Work like - _samr_delet_dom_user() */ - if (!close_policy_hnd(p, &q_u->group_pol)) return NT_STATUS_OBJECT_NAME_INVALID; @@ -4373,15 +4072,11 @@ NTSTATUS _samr_create_dom_group(pipes_struct *p, SAMR_Q_CREATE_DOM_GROUP *q_u, S { DOM_SID dom_sid; DOM_SID info_sid; - fstring name; - fstring sid_string; - struct group *grp; + const char *name; struct samr_info *info; uint32 acc_granted; - gid_t gid; SE_PRIV se_rights; BOOL can_add_accounts; - NTSTATUS result; DISP_INFO *disp_info = NULL; /* Find the policy handle. Open a policy on it. */ @@ -4395,7 +4090,10 @@ NTSTATUS _samr_create_dom_group(pipes_struct *p, SAMR_Q_CREATE_DOM_GROUP *q_u, S if (!sid_equal(&dom_sid, get_global_sam_sid())) return NT_STATUS_ACCESS_DENIED; - unistr2_to_ascii(name, &q_u->uni_acct_desc, sizeof(name)-1); + name = rpcstr_pull_unistr2_talloc(p->mem_ctx, &q_u->uni_acct_desc); + if (name == NULL) { + return NT_STATUS_NO_MEMORY; + } r_u->status = can_create(p->mem_ctx, name); if (!NT_STATUS_IS_OK(r_u->status)) { @@ -4412,35 +4110,7 @@ NTSTATUS _samr_create_dom_group(pipes_struct *p, SAMR_Q_CREATE_DOM_GROUP *q_u, S /* check that we successfully create the UNIX group */ - result = NT_STATUS_ACCESS_DENIED; - if ( (smb_create_group(name, &gid) == 0) && ((grp=getgrgid(gid)) != NULL) ) { - - /* so far, so good */ - - result = NT_STATUS_OK; - - if (pdb_rid_algorithm()) { - r_u->rid = pdb_gid_to_group_rid( grp->gr_gid ); - } else { - if (!pdb_new_rid(&r_u->rid)) { - result = NT_STATUS_ACCESS_DENIED; - } - } - - if (NT_STATUS_IS_OK(result)) { - - /* add the group to the mapping table */ - - sid_copy( &info_sid, get_global_sam_sid() ); - sid_append_rid( &info_sid, r_u->rid ); - sid_to_string( sid_string, &info_sid ); - - /* reset the error code if we fail to add the mapping entry */ - - if ( !add_initial_entry(grp->gr_gid, sid_string, SID_NAME_DOM_GRP, name, NULL) ) - result = NT_STATUS_ACCESS_DENIED; - } - } + r_u->status = pdb_create_dom_group(p->mem_ctx, name, &r_u->rid); if ( can_add_accounts ) unbecome_root(); @@ -4449,13 +4119,14 @@ NTSTATUS _samr_create_dom_group(pipes_struct *p, SAMR_Q_CREATE_DOM_GROUP *q_u, S /* check if we should bail out here */ - if ( !NT_STATUS_IS_OK(result) ) - return result; + if ( !NT_STATUS_IS_OK(r_u->status) ) + return r_u->status; + + sid_compose(&info_sid, get_global_sam_sid(), r_u->rid); if ((info = get_samr_info_by_sid(&info_sid)) == NULL) return NT_STATUS_NO_MEMORY; - /* they created it; let the user do what he wants with it */ info->acc_granted = GENERIC_RIGHTS_GROUP_ALL_ACCESS; @@ -4568,9 +4239,6 @@ NTSTATUS _samr_query_groupinfo(pipes_struct *p, SAMR_Q_QUERY_GROUPINFO *q_u, SAM { DOM_SID group_sid; GROUP_MAP map; - DOM_SID *sids=NULL; - uid_t *uids; - int num=0; GROUP_INFO_CTR *ctr; uint32 acc_granted; BOOL ret; @@ -4593,14 +4261,25 @@ NTSTATUS _samr_query_groupinfo(pipes_struct *p, SAMR_Q_QUERY_GROUPINFO *q_u, SAM return NT_STATUS_NO_MEMORY; switch (q_u->switch_level) { - case 1: + case 1: { + uint32 *members; + size_t num_members; + ctr->switch_value1 = 1; - if(!get_memberuids(map.gid, &uids, &num)) - return NT_STATUS_NO_SUCH_GROUP; - SAFE_FREE(uids); - init_samr_group_info1(&ctr->group.info1, map.nt_name, map.comment, num); - SAFE_FREE(sids); + + become_root(); + r_u->status = pdb_enum_group_members( + p->mem_ctx, &group_sid, &members, &num_members); + unbecome_root(); + + if (!NT_STATUS_IS_OK(r_u->status)) { + return r_u->status; + } + + init_samr_group_info1(&ctr->group.info1, map.nt_name, + map.comment, num_members); break; + } case 3: ctr->switch_value1 = 3; init_samr_group_info3(&ctr->group.info3); diff --git a/source3/smbd/chgpasswd.c b/source3/smbd/chgpasswd.c index e04e902b3a..8f3e7236c4 100644 --- a/source3/smbd/chgpasswd.c +++ b/source3/smbd/chgpasswd.c @@ -1067,7 +1067,7 @@ NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passw pass = Get_Pwnam(username); if (!pass) { - DEBUG(1, ("check_oem_password: Username %s does not exist in system !?!\n", username)); + DEBUG(1, ("change_oem_password: Username %s does not exist in system !?!\n", username)); return NT_STATUS_ACCESS_DENIED; } diff --git a/source3/smbd/map_username.c b/source3/smbd/map_username.c new file mode 100644 index 0000000000..a6025fcf47 --- /dev/null +++ b/source3/smbd/map_username.c @@ -0,0 +1,178 @@ +/* + Unix SMB/CIFS implementation. + Username handling + Copyright (C) Andrew Tridgell 1992-1998 + Copyright (C) Jeremy Allison 1997-2001. + Copyright (C) Volker Lendecke 2006 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/******************************************************************* + Map a username from a dos name to a unix name by looking in the username + map. Note that this modifies the name in place. + This is the main function that should be called *once* on + any incoming or new username - in order to canonicalize the name. + This is being done to de-couple the case conversions from the user mapping + function. Previously, the map_username was being called + every time Get_Pwnam was called. + Returns True if username was changed, false otherwise. +********************************************************************/ + +BOOL map_username(fstring user) +{ + static BOOL initialised=False; + static fstring last_from,last_to; + XFILE *f; + char *mapfile = lp_username_map(); + char *s; + pstring buf; + BOOL mapped_user = False; + char *cmd = lp_username_map_script(); + + if (!*user) + return False; + + if (strequal(user,last_to)) + return False; + + if (strequal(user,last_from)) { + DEBUG(3,("Mapped user %s to %s\n",user,last_to)); + fstrcpy(user,last_to); + return True; + } + + /* first try the username map script */ + + if ( *cmd ) { + char **qlines; + pstring command; + int numlines, ret, fd; + + pstr_sprintf( command, "%s \"%s\"", cmd, user ); + + DEBUG(10,("Running [%s]\n", command)); + ret = smbrun(command, &fd); + DEBUGADD(10,("returned [%d]\n", ret)); + + if ( ret != 0 ) { + if (fd != -1) + close(fd); + return False; + } + + numlines = 0; + qlines = fd_lines_load(fd, &numlines,0); + DEBUGADD(10,("Lines returned = [%d]\n", numlines)); + close(fd); + + /* should be either no lines or a single line with the mapped username */ + + if (numlines) { + DEBUG(3,("Mapped user %s to %s\n", user, qlines[0] )); + fstrcpy( user, qlines[0] ); + } + + file_lines_free(qlines); + + return numlines != 0; + } + + /* ok. let's try the mapfile */ + + if (!*mapfile) + return False; + + if (!initialised) { + *last_from = *last_to = 0; + initialised = True; + } + + f = x_fopen(mapfile,O_RDONLY, 0); + if (!f) { + DEBUG(0,("can't open username map %s. Error %s\n",mapfile, strerror(errno) )); + return False; + } + + DEBUG(4,("Scanning username map %s\n",mapfile)); + + while((s=fgets_slash(buf,sizeof(buf),f))!=NULL) { + char *unixname = s; + char *dosname = strchr_m(unixname,'='); + char **dosuserlist; + BOOL return_if_mapped = False; + + if (!dosname) + continue; + + *dosname++ = 0; + + while (isspace((int)*unixname)) + unixname++; + + if ('!' == *unixname) { + return_if_mapped = True; + unixname++; + while (*unixname && isspace((int)*unixname)) + unixname++; + } + + if (!*unixname || strchr_m("#;",*unixname)) + continue; + + { + int l = strlen(unixname); + while (l && isspace((int)unixname[l-1])) { + unixname[l-1] = 0; + l--; + } + } + + dosuserlist = str_list_make(dosname, NULL); + if (!dosuserlist) { + DEBUG(0,("Unable to build user list\n")); + return False; + } + + if (strchr_m(dosname,'*') || + user_in_list(user, (const char **)dosuserlist)) { + DEBUG(3,("Mapped user %s to %s\n",user,unixname)); + mapped_user = True; + fstrcpy( last_from,user ); + fstrcpy( user, unixname ); + fstrcpy( last_to,user ); + if ( return_if_mapped ) { + str_list_free (&dosuserlist); + x_fclose(f); + return True; + } + } + + str_list_free (&dosuserlist); + } + + x_fclose(f); + + /* + * Setup the last_from and last_to as an optimization so + * that we don't scan the file again for the same user. + */ + fstrcpy(last_from,user); + fstrcpy(last_to,user); + + return mapped_user; +} diff --git a/source3/smbd/password.c b/source3/smbd/password.c index e644550400..0eeb537ded 100644 --- a/source3/smbd/password.c +++ b/source3/smbd/password.c @@ -401,6 +401,135 @@ void add_session_user(const char *user) safe_strcat(session_userlist,suser,len_session_userlist-1); } +/**************************************************************************** + Check if a user is in a netgroup user list. If at first we don't succeed, + try lower case. +****************************************************************************/ + +BOOL user_in_netgroup(const char *user, const char *ngname) +{ +#ifdef HAVE_NETGROUP + static char *mydomain = NULL; + fstring lowercase_user; + + if (mydomain == NULL) + yp_get_default_domain(&mydomain); + + if(mydomain == NULL) { + DEBUG(5,("Unable to get default yp domain\n")); + return False; + } + + DEBUG(5,("looking for user %s of domain %s in netgroup %s\n", + user, mydomain, ngname)); + + if (innetgr(ngname, NULL, user, mydomain)) { + DEBUG(5,("user_in_netgroup: Found\n")); + return (True); + } else { + + /* + * Ok, innetgr is case sensitive. Try once more with lowercase + * just in case. Attempt to fix #703. JRA. + */ + + fstrcpy(lowercase_user, user); + strlower_m(lowercase_user); + + DEBUG(5,("looking for user %s of domain %s in netgroup %s\n", + lowercase_user, mydomain, ngname)); + + if (innetgr(ngname, NULL, lowercase_user, mydomain)) { + DEBUG(5,("user_in_netgroup: Found\n")); + return (True); + } + } +#endif /* HAVE_NETGROUP */ + return False; +} + +/**************************************************************************** + Check if a user is in a user list - can check combinations of UNIX + and netgroup lists. +****************************************************************************/ + +BOOL user_in_list(const char *user,const char **list) +{ + if (!list || !*list) + return False; + + DEBUG(10,("user_in_list: checking user %s in list\n", user)); + + while (*list) { + + DEBUG(10,("user_in_list: checking user |%s| against |%s|\n", + user, *list)); + + /* + * Check raw username. + */ + if (strequal(user, *list)) + return(True); + + /* + * Now check to see if any combination + * of UNIX and netgroups has been specified. + */ + + if(**list == '@') { + /* + * Old behaviour. Check netgroup list + * followed by UNIX list. + */ + if(user_in_netgroup(user, *list +1)) + return True; + if(user_in_group(user, *list +1)) + return True; + } else if (**list == '+') { + + if((*(*list +1)) == '&') { + /* + * Search UNIX list followed by netgroup. + */ + if(user_in_group(user, *list +2)) + return True; + if(user_in_netgroup(user, *list +2)) + return True; + + } else { + + /* + * Just search UNIX list. + */ + + if(user_in_group(user, *list +1)) + return True; + } + + } else if (**list == '&') { + + if(*(*list +1) == '+') { + /* + * Search netgroup list followed by UNIX list. + */ + if(user_in_netgroup(user, *list +2)) + return True; + if(user_in_group(user, *list +2)) + return True; + } else { + /* + * Just search netgroup list. + */ + if(user_in_netgroup(user, *list +1)) + return True; + } + } + + list++; + } + return(False); +} + /**************************************************************************** Check if a username is valid. ****************************************************************************/ diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c index d4dd926089..2befca40c2 100644 --- a/source3/smbd/posix_acls.c +++ b/source3/smbd/posix_acls.c @@ -1015,7 +1015,6 @@ static void apply_default_perms(files_struct *fsp, canon_ace *pace, mode_t type) static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace ) { fstring u_name; - fstring g_name; /* "Everyone" always matches every uid. */ @@ -1028,14 +1027,7 @@ static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace ) return True; fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid)); - fstrcpy(g_name, gidtoname(group_ace->unix_ug.gid)); - - /* - * Due to the winbind interfaces we need to do this via names, - * not uids/gids. - */ - - return user_in_group(u_name, g_name); + return user_in_group_sid(u_name, &group_ace->trustee); } /**************************************************************************** diff --git a/source3/smbd/service.c b/source3/smbd/service.c index cf0116cc09..0fce677ea9 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -473,7 +473,7 @@ static NTSTATUS find_forced_group(BOOL force_user, */ if (force_user && user_must_be_member) { - if (user_in_group(username, groupname)) { + if (user_in_group_sid(username, &group_sid)) { sid_copy(pgroup_sid, &group_sid); *pgid = gid; DEBUG(3,("Forced group %s for member %s\n", diff --git a/source3/utils/net_groupmap.c b/source3/utils/net_groupmap.c index 96a6aa531a..de31ceb1f3 100644 --- a/source3/utils/net_groupmap.c +++ b/source3/utils/net_groupmap.c @@ -312,7 +312,7 @@ static int net_groupmap_add(int argc, const char **argv) fstrcpy( ntgroup, unixgrp ); - if (!add_initial_entry(gid, string_sid, sid_type, ntgroup, ntcomment)) { + if (!NT_STATUS_IS_OK(add_initial_entry(gid, string_sid, sid_type, ntgroup, ntcomment))) { d_fprintf(stderr, "adding entry for group %s failed!\n", ntgroup); return -1; } @@ -494,7 +494,7 @@ static int net_groupmap_delete(int argc, const char **argv) return -1; } - if ( !pdb_delete_group_mapping_entry(sid) ) { + if ( !NT_STATUS_IS_OK(pdb_delete_group_mapping_entry(sid)) ) { d_fprintf(stderr, "Failed to removing group %s from the mapping db!\n", ntgroup); return -1; } diff --git a/source3/utils/net_rpc_samsync.c b/source3/utils/net_rpc_samsync.c index 45fdfbfad3..f8cd0e090d 100644 --- a/source3/utils/net_rpc_samsync.c +++ b/source3/utils/net_rpc_samsync.c @@ -550,7 +550,7 @@ static NTSTATUS fetch_account_info(uint32 rid, SAM_ACCOUNT_INFO *delta) sam_account_from_delta(sam_account, delta); DEBUG(3, ("Attempting to add user SID %s for user %s in the passdb\n", sid_to_string(sid_string, &user_sid), pdb_get_username(sam_account))); - if (!pdb_add_sam_account(sam_account)) { + if (!NT_STATUS_IS_OK(pdb_add_sam_account(sam_account))) { DEBUG(1, ("SAM Account for %s failed to be added to the passdb!\n", account)); return NT_STATUS_ACCESS_DENIED; -- cgit