Large set of changes to add UNIX account/group management
authorGerald Carter <jerry@samba.org>
Wed, 9 Jul 2003 16:44:47 +0000 (16:44 +0000)
committerGerald Carter <jerry@samba.org>
Wed, 9 Jul 2003 16:44:47 +0000 (16:44 +0000)
to winbindd.  See README.idmap-and-winbind-changes for details.
(This used to be commit 1111bc7b0c7165e1cdf8d90eb49f4c368d2eded6)

26 files changed:
docs/README.idmap-and-winbind-changes [new file with mode: 0644]
packaging/RedHat/samba.spec.tmpl
source3/Makefile.in
source3/auth/auth_util.c
source3/groupdb/mapping.c
source3/include/idmap.h
source3/nsswitch/wb_client.c
source3/nsswitch/wbinfo.c
source3/nsswitch/winbindd.c
source3/nsswitch/winbindd_acct.c [new file with mode: 0644]
source3/nsswitch/winbindd_group.c
source3/nsswitch/winbindd_idmap.c [deleted file]
source3/nsswitch/winbindd_idmap_tdb.c [deleted file]
source3/nsswitch/winbindd_nss.h
source3/nsswitch/winbindd_pam.c
source3/nsswitch/winbindd_passdb.c [deleted file]
source3/nsswitch/winbindd_user.c
source3/nsswitch/winbindd_util.c
source3/param/loadparm.c
source3/rpc_server/srv_samr_nt.c
source3/sam/idmap.c
source3/sam/idmap_ldap.c
source3/sam/idmap_tdb.c
source3/script/mkproto.awk
source3/smbd/uid.c
source3/utils/net_rpc_samsync.c

diff --git a/docs/README.idmap-and-winbind-changes b/docs/README.idmap-and-winbind-changes
new file mode 100644 (file)
index 0000000..a892343
--- /dev/null
@@ -0,0 +1,73 @@
+## Date :      2003-07-09
+## Author:     Gerald (Jerry) Carter <jerry@samba.org>
+## Title:      README.idmap-and-winbind-changes
+
+Introduction
+------------
+
+Beginning with Samba3.0.0beta3, winbindd has been given new account 
+manage functionality equivalent to the 'add user script' family of 
+smb.conf parameters.  The idmap design has also been changed to centralize
+control of foreign SID lookups and matching to UNIX uids and gids.
+
+
+Brief Description of Changes
+----------------------------
+
+1) The sid_to_uid() family of functions (smbd/uid.c) have been reverted 
+   to the 2.2.x design.  This means that when resolving a SID to a UID
+   or similar mapping:
+
+       a) First consult winbindd
+       b) perform a local lookup only if winbindd fails to
+          return a successful answer
+          
+   There are some variations to this, but these two rules generally
+   apply.
+
+2) All idmap lookups have been moved into winbindd.  This means that
+   a server must run winbindd (and support NSS) in order to achieve
+   any mappings of SID to dynamically allocated UNIX ids.  This was 
+   a conscious design choice.
+
+3) New functions have been added to winbindd to emulate the 'add user script'
+   family of smbd functions without requiring that external scripts
+   be defined.  This functionality is controlled by the 'winbind enable local 
+   accounts' smb.conf parameter (enabled by default).
+   
+   However, this account management functionality is only supported in
+   a local tdb (winbindd_idmap.tdb).  If these new UNIX accounts must be 
+   shared among multiple Samba servers (such as a PDC and BDCs), it
+   will be necessary to define your own 'add user script', et. al.
+   programs that place the accounts/groups in some form of directory
+   such as NIS or LDAP.  This requirement was deemed beyond the scope
+   of winbind's account management functions.  Solutions for distributing 
+   UNIX system information have been deployed and tested for many years.
+   We saw no need to reinvent the wheel.
+   
+4) A member of a Samba controlled domain running winbindd is now able to
+   map domain users directly onto existing UNIX accounts while still
+   automatically creating accounts for trusted users and groups.  This
+   behavior is controlled by the 'winbind trusted domains only' smb.conf
+   parameter (disabled by default to provide 2.2.x winbind behavior).
+
+5) Group mapping support is wrapped in the local_XX_to_XX() functions   
+   in smbd/uid.c.  The reason that group mappings are not included
+   in winbindd is because the purpose of Samba's group map is to 
+   match any Windows SID with an existing UNIX group.  These UNIX
+   groups can be created by winbindd (see next section), but the 
+   SID<->gid mapping is retreived by smbd, not winbindd.
+   
+
+Examples
+--------
+
+* security = server running winbindd to allocate accounts on demand
+
+* Samba PDC running winbindd to handle the automatic creation of UNIX 
+  identities for machine trust accounts
+  
+* Automtically creating UNIX user and groups when migrating a Windows NT
+  4.0 PDC to a Samba PDC.  Winbindd must be running when executing
+  'net rpc vampire' for this to work.
+
index d7b1750772d85791dd74e34b6b69b7ff6bc6cc43..4c5a480a27e78924bea545bb36b2609949394aad 100644 (file)
@@ -182,10 +182,12 @@ find $RPM_BUILD_ROOT -name "*.old" -exec rm -f {} \;
 rm -rf $RPM_BUILD_ROOT
 
 %post
-/sbin/chkconfig --add smb
-/sbin/chkconfig --add winbind
-/sbin/chkconfig smb off
-/sbin/chkconfig winbind off
+if [ "$1" -eq "1" ]; then
+       /sbin/chkconfig --add smb
+       /sbin/chkconfig --add winbind
+       /sbin/chkconfig smb off
+       /sbin/chkconfig winbind off
+fi
 
 echo "Looking for old /etc/smb.conf..."
 if [ -f /etc/smb.conf -a ! -f /etc/samba/smb.conf ]; then
index 1e8f27ba07dc52e4390485385add2b0adb4fd330..b2ba1a1b79de0653bfb4aec6c517e53ea217990b 100644 (file)
@@ -593,7 +593,8 @@ WINBINDD_OBJ1 = \
                nsswitch/winbindd_wins.o \
                nsswitch/winbindd_rpc.o \
                nsswitch/winbindd_ads.o \
-               nsswitch/winbindd_dual.o
+               nsswitch/winbindd_dual.o \
+               nsswitch/winbindd_acct.o
 
 WINBINDD_OBJ = \
                $(WINBINDD_OBJ1) $(PASSDB_OBJ) $(GROUPDB_OBJ) \
index 6fc1d772ecf9aeefc7911e7d71063964fe73a89d..51cd1994f91c6e72b05ec9bcd358dd3166395155 100644 (file)
@@ -60,16 +60,23 @@ static int smb_create_user(const char *domain, const char *unix_username, const
 
 void auth_add_user_script(const char *domain, const char *username)
 {
-       struct passwd *pwd=NULL;
-
        /*
         * User validated ok against Domain controller.
         * If the admin wants us to try and create a UNIX
         * user on the fly, do so.
         */
        
-       if(lp_adduser_script() && !(pwd = Get_Pwnam(username))) {
+       if ( lp_adduser_script() ) 
                smb_create_user(domain, username, NULL);
+       else {
+               DEBUG(10,("auth_add_user_script: no 'add user script'.  Asking winbindd\n"));
+               
+               /* should never get here is we a re a domain member running winbindd
+                  However, a host set for 'security = server' might run winbindd for 
+                  account allocation */
+                  
+               if ( !winbind_create_user(username) )
+                       DEBUG(5,("auth_add_user_script: winbindd_create_user() failed\n"));
        }
 }
 
index 5d2d28f152604d755ab7a65af0000df796205e6b..e769b4dd9daf64ced3aed13c09e817342361fe2b 100644 (file)
@@ -719,37 +719,50 @@ int smb_create_group(char *unix_group, gid_t *new_gid)
        int ret;
        int fd = 0;
 
-       pstrcpy(add_script, lp_addgroup_script());
-       if (! *add_script) return -1;
-       pstring_sub(add_script, "%g", unix_group);
-       ret = smbrun(add_script, (new_gid!=NULL) ? &fd : NULL);
-       DEBUG(3,("smb_create_group: Running the command `%s' gave %d\n",add_script,ret));
-       if (ret != 0)
-               return ret;
-
-       if (fd != 0) {
-               fstring output;
-
-               *new_gid = 0;
-               if (read(fd, output, sizeof(output)) > 0) {
-                       *new_gid = (gid_t)strtoul(output, NULL, 10);
-               }
-               close(fd);
-
-               if (*new_gid == 0) {
-                       /* The output was garbage. We assume nobody
-                           will create group 0 via smbd. Now we try to
-                           get the group via getgrnam. */
-
-                       struct group *grp = getgrnam(unix_group);
-                       if (grp != NULL)
-                               *new_gid = grp->gr_gid;
-                       else
-                               return 1;
+       /* defer to scripts */
+       
+       if ( *lp_addgroup_script() ) {
+               pstrcpy(add_script, lp_addgroup_script());
+               pstring_sub(add_script, "%g", unix_group);
+               ret = smbrun(add_script, (new_gid!=NULL) ? &fd : NULL);
+               DEBUG(3,("smb_create_group: Running the command `%s' gave %d\n",add_script,ret));
+               if (ret != 0)
+                       return ret;
+                       
+               if (fd != 0) {
+                       fstring output;
+
+                       *new_gid = 0;
+                       if (read(fd, output, sizeof(output)) > 0) {
+                               *new_gid = (gid_t)strtoul(output, NULL, 10);
+                       }
+                       close(fd);
+
+                       if (*new_gid == 0) {
+                               /* The output was garbage. We assume nobody
+                                   will create group 0 via smbd. Now we try to
+                                  get the group via getgrnam. */
+
+                               struct group *grp = getgrnam(unix_group);
+                               if (grp != NULL)
+                                       *new_gid = grp->gr_gid;
+                               else
+                                       return 1;
+                       }
                }
+               
+               return 0;
        }
 
-       return ret;
+       /* Try winbindd */
+
+       if ( winbind_create_group( unix_group ) ) {
+               DEBUG(3,("smb_create_group: winbindd created the group (%s)\n",
+                       unix_group));
+               return 0;
+       }
+                       
+       return -1;      
 }
 
 /****************************************************************************
@@ -761,12 +774,25 @@ int smb_delete_group(char *unix_group)
        pstring del_script;
        int ret;
 
-       pstrcpy(del_script, lp_delgroup_script());
-       if (! *del_script) return -1;
-       pstring_sub(del_script, "%g", unix_group);
-       ret = smbrun(del_script,NULL);
-       DEBUG(3,("smb_delete_group: Running the command `%s' gave %d\n",del_script,ret));
-       return ret;
+       /* defer to scripts */
+       
+       if ( *lp_delgroup_script() ) {
+               pstrcpy(del_script, lp_delgroup_script());
+               pstring_sub(del_script, "%g", unix_group);
+               ret = smbrun(del_script,NULL);
+               DEBUG(3,("smb_delete_group: Running the command `%s' gave %d\n",del_script,ret));
+               return ret;
+       }
+#if 0  
+       if ( winbind_delete_group( unix_group ) ) {
+               DEBUG(3,("smb_delete_group: winbindd deleted the group (%s)\n",
+                       unix_group));
+               return 0;
+       }
+               
+#endif
+               
+       return -1;
 }
 
 /****************************************************************************
@@ -777,14 +803,27 @@ int smb_set_primary_group(const char *unix_group, const char* unix_user)
        pstring add_script;
        int ret;
 
-       pstrcpy(add_script, lp_setprimarygroup_script());
-       if (! *add_script) return -1;
-       all_string_sub(add_script, "%g", unix_group, sizeof(add_script));
-       all_string_sub(add_script, "%u", unix_user, sizeof(add_script));
-       ret = smbrun(add_script,NULL);
-       DEBUG(3,("smb_set_primary_group: "
-                "Running the command `%s' gave %d\n",add_script,ret));
-       return ret;
+       /* defer to scripts */
+       
+       if ( *lp_setprimarygroup_script() ) {
+               pstrcpy(add_script, lp_setprimarygroup_script());
+               all_string_sub(add_script, "%g", unix_group, sizeof(add_script));
+               all_string_sub(add_script, "%u", unix_user, sizeof(add_script));
+               ret = smbrun(add_script,NULL);
+               DEBUG(3,("smb_set_primary_group: "
+                        "Running the command `%s' gave %d\n",add_script,ret));
+               return ret;
+       }
+
+       /* Try winbindd */
+       
+       if ( winbind_set_user_primary_group( unix_user, unix_group ) ) {
+               DEBUG(3,("smb_delete_group: winbindd set the group (%s) as the primary group for user (%s)\n",
+                       unix_group, unix_user));
+               return 0;
+       }               
+       
+       return -1;
 }
 
 /****************************************************************************
@@ -796,13 +835,26 @@ int smb_add_user_group(char *unix_group, char *unix_user)
        pstring add_script;
        int ret;
 
-       pstrcpy(add_script, lp_addusertogroup_script());
-       if (! *add_script) return -1;
-       pstring_sub(add_script, "%g", unix_group);
-       pstring_sub(add_script, "%u", unix_user);
-       ret = smbrun(add_script,NULL);
-       DEBUG(3,("smb_add_user_group: Running the command `%s' gave %d\n",add_script,ret));
-       return ret;
+       /* defer to scripts */
+       
+       if ( *lp_addusertogroup_script() ) {
+               pstrcpy(add_script, lp_addusertogroup_script());
+               pstring_sub(add_script, "%g", unix_group);
+               pstring_sub(add_script, "%u", unix_user);
+               ret = smbrun(add_script,NULL);
+               DEBUG(3,("smb_add_user_group: Running the command `%s' gave %d\n",add_script,ret));
+               return ret;
+       }
+       
+       /* Try winbindd */
+
+       if ( winbind_add_user_to_group( unix_user, unix_group ) ) {
+               DEBUG(3,("smb_delete_group: winbindd added user (%s) to the group (%s)\n",
+                       unix_user, unix_group));
+               return -1;
+       }       
+       
+       return -1;
 }
 
 /****************************************************************************
@@ -814,13 +866,26 @@ int smb_delete_user_group(const char *unix_group, const char *unix_user)
        pstring del_script;
        int ret;
 
-       pstrcpy(del_script, lp_deluserfromgroup_script());
-       if (! *del_script) return -1;
-       pstring_sub(del_script, "%g", unix_group);
-       pstring_sub(del_script, "%u", unix_user);
-       ret = smbrun(del_script,NULL);
-       DEBUG(3,("smb_delete_user_group: Running the command `%s' gave %d\n",del_script,ret));
-       return ret;
+       /* defer to scripts */
+       
+       if ( *lp_deluserfromgroup_script() ) {
+               pstrcpy(del_script, lp_deluserfromgroup_script());
+               pstring_sub(del_script, "%g", unix_group);
+               pstring_sub(del_script, "%u", unix_user);
+               ret = smbrun(del_script,NULL);
+               DEBUG(3,("smb_delete_user_group: Running the command `%s' gave %d\n",del_script,ret));
+               return ret;
+       }
+       
+       /* Try winbindd */
+
+       if ( winbind_remove_user_from_group( unix_user, unix_group ) ) {
+               DEBUG(3,("smb_delete_group: winbindd removed user (%s) from the group (%s)\n",
+                       unix_user, unix_group));
+               return 0;
+       }
+       
+       return -1;
 }
 
 
index 47f396e637f6b0e5611d7fda6da37593c23bc41b..7da3718d19721b4d7ff7bda5c2f7377e17c6422d 100644 (file)
@@ -24,7 +24,7 @@
    Boston, MA  02111-1307, USA.   
 */
 
-#define SMB_IDMAP_INTERFACE_VERSION    1
+#define SMB_IDMAP_INTERFACE_VERSION    2
 
 
 #define ID_EMPTY       0x00
@@ -42,6 +42,7 @@ struct idmap_methods {
        /* Called when backend is first loaded */
        NTSTATUS (*init)( char *params );
 
+       NTSTATUS (*allocate_id)(unid_t *id, int id_type);
        NTSTATUS (*get_sid_from_id)(DOM_SID *sid, unid_t id, int id_type);
        NTSTATUS (*get_id_from_sid)(unid_t *id, int *id_type, const DOM_SID *sid);
        NTSTATUS (*set_mapping)(const DOM_SID *sid, unid_t id, int id_type);
index 67548592b2c5679659d51deb88f23a713374233c..26a0e58191f4357cd3745686da25c8e0de162a21 100644 (file)
@@ -367,3 +367,147 @@ BOOL winbind_ping( void )
        return result == NSS_STATUS_SUCCESS;
 }
 
+/**********************************************************************
+ Ask winbindd to create a local user
+**********************************************************************/
+
+BOOL winbind_create_user( const char *name )
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       NSS_STATUS result;
+       
+       if ( !lp_winbind_enable_local_accounts() )
+               return False;
+       
+       if ( !name )
+               return False;
+               
+       DEBUG(10,("winbind_create_user: %s\n", name));
+
+       fstrcpy( request.data.acct_mgt.username, name );
+       fstrcpy( request.data.acct_mgt.groupname, "" );
+       
+       ZERO_STRUCT(response);
+       
+       result = winbindd_request( WINBINDD_CREATE_USER, &request, &response);
+       
+       return result == NSS_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+ Ask winbindd to create a local group
+**********************************************************************/
+
+BOOL winbind_create_group( const char *name )
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       NSS_STATUS result;
+       
+       if ( !lp_winbind_enable_local_accounts() )
+               return False;
+               
+       if ( !name )
+               return False;
+               
+       DEBUG(10,("winbind_create_group: %s\n", name));
+
+       fstrcpy( request.data.acct_mgt.groupname, name );
+       
+       ZERO_STRUCT(response);
+       
+       result = winbindd_request( WINBINDD_CREATE_GROUP, &request, &response);
+       
+       return result == NSS_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+ Ask winbindd to add a user to a local group
+**********************************************************************/
+
+BOOL winbind_add_user_to_group( const char *user, const char *group )
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       NSS_STATUS result;
+       
+       if ( !lp_winbind_enable_local_accounts() )
+               return False;
+               
+       if ( !user || !group )
+               return False;
+               
+       DEBUG(10,("winbind_add_user_to_group: user(%s), group(%s) \n", 
+               user, group));
+               
+       fstrcpy( request.data.acct_mgt.username, user );
+       fstrcpy( request.data.acct_mgt.groupname, group );
+       
+       ZERO_STRUCT(response);
+       
+       result = winbindd_request( WINBINDD_ADD_USER_TO_GROUP, &request, &response);
+       
+       return result == NSS_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+ Ask winbindd to remove a user to a local group
+**********************************************************************/
+
+BOOL winbind_remove_user_from_group( const char *user, const char *group )
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       NSS_STATUS result;
+       
+       if ( !lp_winbind_enable_local_accounts() )
+               return False;
+               
+       if ( !user || !group )
+               return False;
+               
+       DEBUG(10,("winbind_remove_user_from_group: user(%s), group(%s) \n", 
+               user, group));
+               
+       fstrcpy( request.data.acct_mgt.username, user );
+       fstrcpy( request.data.acct_mgt.groupname, group );
+       
+       ZERO_STRUCT(response);
+       
+       result = winbindd_request( WINBINDD_REMOVE_USER_FROM_GROUP, &request, &response);
+       
+       return result == NSS_STATUS_SUCCESS;
+}
+
+/**********************************************************************
+ Ask winbindd to set the primary group for a user local user
+**********************************************************************/
+
+BOOL winbind_set_user_primary_group( const char *user, const char *group )
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       NSS_STATUS result;
+       
+       if ( !lp_winbind_enable_local_accounts() )
+               return False;
+               
+       if ( !user || !group )
+               return False;
+               
+       DEBUG(10,("winbind_set_user_primary_group: user(%s), group(%s) \n", 
+               user, group));
+
+       fstrcpy( request.data.acct_mgt.username, user );
+       fstrcpy( request.data.acct_mgt.groupname, group );
+       
+       ZERO_STRUCT(response);
+       
+       result = winbindd_request( WINBINDD_SET_USER_PRIMARY_GROUP, &request, &response);
+       
+       return result == NSS_STATUS_SUCCESS;
+}
+
+
+
index 9be74c12de70f81570c9177a0977deb6cb805ade..6ebf6effa76c1cc69a7255c7542547c24ce3585a 100644 (file)
@@ -511,6 +511,151 @@ static BOOL wbinfo_auth_crap(char *username)
         return result == NSS_STATUS_SUCCESS;
 }
 
+/******************************************************************
+ create a winbindd user
+******************************************************************/
+
+static BOOL wbinfo_create_user(char *username)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+        NSS_STATUS result;
+
+       /* Send off request */
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       fstrcpy(request.data.acct_mgt.username, username);
+
+       result = winbindd_request(WINBINDD_CREATE_USER, &request, &response);
+       
+       if (response.data.auth.nt_status)
+               d_printf("error code was %s (0x%x)\nerror messsage was: %s\n", 
+                        response.data.auth.nt_status_string, 
+                        response.data.auth.nt_status,
+                        response.data.auth.error_string);
+
+        return result == NSS_STATUS_SUCCESS;
+}
+
+/******************************************************************
+ create a winbindd group
+******************************************************************/
+
+static BOOL wbinfo_create_group(char *groupname)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+        NSS_STATUS result;
+
+       /* Send off request */
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       fstrcpy(request.data.acct_mgt.groupname, groupname);
+
+       result = winbindd_request(WINBINDD_CREATE_GROUP, &request, &response);
+       
+       if (response.data.auth.nt_status)
+               d_printf("error code was %s (0x%x)\nerror messsage was: %s\n", 
+                        response.data.auth.nt_status_string, 
+                        response.data.auth.nt_status,
+                        response.data.auth.error_string);
+
+        return result == NSS_STATUS_SUCCESS;
+}
+
+/******************************************************************
+ parse a string in the form user:group
+******************************************************************/
+
+static BOOL parse_user_group( const char *string, fstring user, fstring group )
+{
+       char *p;
+       
+       if ( !string )
+               return False;
+       
+       if ( !(p = strchr( string, ':' )) )
+               return False;
+               
+       *p = '\0';
+       p++;
+       
+       fstrcpy( user, string );
+       fstrcpy( group, p );
+       
+       return True;
+}
+
+/******************************************************************
+ add a user to a winbindd group
+******************************************************************/
+
+static BOOL wbinfo_add_user_to_group(char *string)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+        NSS_STATUS result;
+
+       /* Send off request */
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       if ( !parse_user_group( string, request.data.acct_mgt.username,
+               request.data.acct_mgt.groupname))
+       {
+               d_printf("Can't parse user:group from %s\n", string);
+               return False;
+       }
+
+       result = winbindd_request(WINBINDD_ADD_USER_TO_GROUP, &request, &response);
+       
+       if (response.data.auth.nt_status)
+               d_printf("error code was %s (0x%x)\nerror messsage was: %s\n", 
+                        response.data.auth.nt_status_string, 
+                        response.data.auth.nt_status,
+                        response.data.auth.error_string);
+
+        return result == NSS_STATUS_SUCCESS;
+}
+
+/******************************************************************
+ remove a user from a winbindd group
+******************************************************************/
+
+static BOOL wbinfo_remove_user_from_group(char *string)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+        NSS_STATUS result;
+
+       /* Send off request */
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       if ( !parse_user_group( string, request.data.acct_mgt.username,
+               request.data.acct_mgt.groupname))
+       {
+               d_printf("Can't parse user:group from %s\n", string);
+               return False;
+       }
+
+       result = winbindd_request(WINBINDD_REMOVE_USER_FROM_GROUP, &request, &response);
+       
+       if (response.data.auth.nt_status)
+               d_printf("error code was %s (0x%x)\nerror messsage was: %s\n", 
+                        response.data.auth.nt_status_string, 
+                        response.data.auth.nt_status,
+                        response.data.auth.error_string);
+
+        return result == NSS_STATUS_SUCCESS;
+}
+
 /* Print domain users */
 
 static BOOL print_domain_users(void)
@@ -705,6 +850,10 @@ int main(int argc, char **argv)
                { "gid-to-sid", 'G', POPT_ARG_INT, &int_arg, 'G', "Converts gid to sid", "GID" },
                { "sid-to-uid", 'S', POPT_ARG_STRING, &string_arg, 'S', "Converts sid to uid", "SID" },
                { "sid-to-gid", 'Y', POPT_ARG_STRING, &string_arg, 'Y', "Converts sid to gid", "SID" },
+               { "create-user", 'c', POPT_ARG_STRING, &string_arg, 'c', "Create a local user account", "name" },
+               { "create-group", 'C', POPT_ARG_STRING, &string_arg, 'C', "Create a local group", "name" },
+               { "add-to-group", 'o', POPT_ARG_STRING, &string_arg, 'o', "Add user to group", "user:group" },
+               { "del-from-group", 'O', POPT_ARG_STRING, &string_arg, 'O', "Remove user from group", "user:group" },
                { "check-secret", 't', POPT_ARG_NONE, 0, 't', "Check shared secret" },
                { "trusted-domains", 'm', POPT_ARG_NONE, 0, 'm', "List trusted domains" },
                { "sequence", 0, POPT_ARG_NONE, 0, OPT_SEQUENCE, "Show sequence numbers of all domains" },
@@ -863,7 +1012,31 @@ int main(int argc, char **argv)
                                        goto done;
                                break;
                        }
-               case 'p':
+               case 'c':
+                       if ( !wbinfo_create_user(string_arg) ) {
+                               d_printf("Could not create user account\n");
+                               goto done;
+                       }
+                       break;
+               case 'C':
+                       if ( !wbinfo_create_group(string_arg) ) {
+                               d_printf("Could not create group\n");
+                               goto done;
+                       }
+                       break;
+               case 'o':
+                       if ( !wbinfo_add_user_to_group(string_arg) ) {
+                               d_printf("Could not add user to group\n");
+                               goto done;
+                       }
+                       break;
+               case 'O':
+                       if ( !wbinfo_remove_user_from_group(string_arg) ) {
+                               d_printf("Could not remove user kfrom group\n");
+                               goto done;
+                       }
+                       break;
+               case 'P':
                        if (!wbinfo_ping()) {
                                d_printf("could not ping winbindd!\n");
                                goto done;
index e65b03c30e37942643f1c12d153d2b755bde4109..507b5f7ef7a27eb5e45df6a8776fe1997583630c 100644 (file)
@@ -268,7 +268,16 @@ static struct dispatch_table dispatch_table[] = {
 
        { WINBINDD_WINS_BYNAME, winbindd_wins_byname, "WINS_BYNAME" },
        { WINBINDD_WINS_BYIP, winbindd_wins_byip, "WINS_BYIP" },
-
+       
+       /* UNIX account management functions */
+       { WINBINDD_CREATE_USER,                 winbindd_create_user,           "CREATE_USER"           },
+       { WINBINDD_CREATE_GROUP,                winbindd_create_group,          "CREATE_GROUP"          },
+       { WINBINDD_ADD_USER_TO_GROUP,           winbindd_add_user_to_group,     "ADD_USER_TO_GROUP"     },
+       { WINBINDD_REMOVE_USER_FROM_GROUP,      winbindd_remove_user_from_group,"REMOVE_USER_FROM_GROUP"},
+       { WINBINDD_SET_USER_PRIMARY_GROUP,      winbindd_set_user_primary_group,"SET_USER_PRIMARY_GROUP"},
+       { WINBINDD_DELETE_USER,                 winbindd_delete_user,           "DELETE_USER"           },
+       { WINBINDD_DELETE_GROUP,                winbindd_delete_group,          "DELETE_GROUP"          },
+       
        /* End of list */
 
        { WINBINDD_NUM_CMDS, NULL, "NONE" }
diff --git a/source3/nsswitch/winbindd_acct.c b/source3/nsswitch/winbindd_acct.c
new file mode 100644 (file)
index 0000000..7f4353c
--- /dev/null
@@ -0,0 +1,946 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   Winbind account management functions
+
+   Copyright (C) by Gerald (Jerry) Carter       2003
+   
+   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 "winbindd.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
+#define WBKEY_PASSWD   "WBA_PASSWD"
+#define WBKEY_GROUP    "WBA_GROUP"
+
+#define NUM_PW_FIELDS  7
+#define NUM_GRP_FIELDS 4
+
+/* Globals */
+
+static TDB_CONTEXT *account_tdb;
+
+extern userdom_struct current_user_info;
+
+/*****************************************************************************
+ Initialise auto-account database. 
+*****************************************************************************/
+
+static BOOL winbindd_accountdb_init(void)
+{
+       /* see if we've already opened the tdb */
+       
+       if ( account_tdb )
+               return True;
+               
+       /* Nope.  Try to open it */
+
+       if (!(account_tdb = tdb_open_log(lock_path("winbindd_idmap.tdb"), 0, 
+               TDB_DEFAULT, O_RDWR | O_CREAT, 0600))) 
+       {
+               /* last chance -- maybe idmap has already opened it */
+               if ( !(account_tdb = idmap_tdb_handle()) ) {
+
+                       DEBUG(0, ("winbindd_idmap_init: Unable to open idmap database\n"));
+                       return False;
+               }
+       }
+       
+       /* yeah! */
+       
+       return True;   
+}
+
+/**********************************************************************
+ Convert a string in /etc/passwd format to a struct passwd* entry
+**********************************************************************/
+
+static WINBINDD_PW* string2passwd( char *string )
+{
+       static WINBINDD_PW pw;
+       char *p, *str;
+       char *fields[NUM_PW_FIELDS];
+       int i;
+       
+       if ( !string )
+               return NULL;
+       
+       ZERO_STRUCTP( &pw );
+       
+       DEBUG(10,("string2passwd: converting \"%s\"\n", string));
+       
+       ZERO_STRUCT( fields );
+       
+       for ( i=0, str=string; i<NUM_PW_FIELDS-1; i++ ) {
+               if ( !(p = strchr( str, ':' )) ) {
+                       DEBUG(0,("string2passwd: parsing failure\n"));
+                       return NULL;
+               }
+               *p = '\0';
+               if ( str )
+                       fields[i] = str;
+               str = p + 1;
+       }
+       if ( str ) 
+               fields[i] = str;
+       
+       /* copy fields */
+       
+       fstrcpy( pw.pw_name,   fields[0] );
+       fstrcpy( pw.pw_passwd, fields[1] );
+       pw.pw_uid = atoi(      fields[2] );
+       pw.pw_gid = atoi(      fields[3] );
+       fstrcpy( pw.pw_gecos,  fields[4] );
+       fstrcpy( pw.pw_dir,    fields[5] );
+       fstrcpy( pw.pw_shell,  fields[6] );
+       
+       
+       /* last minute sanity checks */
+       
+       if ( pw.pw_uid==0 || pw.pw_gid==0 ) {
+               DEBUG(0,("string2passwd: Failure! uid==%d, gid==%d\n",
+                       pw.pw_uid, pw.pw_gid));
+               return NULL;
+       }
+       
+       DEBUG(10,("string2passwd: Success\n"));
+
+       return &pw;
+}
+
+/**********************************************************************
+ Convert a struct passwd* to a string formatted for /etc/passwd
+**********************************************************************/
+
+static char* passwd2string( const WINBINDD_PW *pw )
+{
+       static pstring string;
+       int ret;
+       
+       if ( !pw || !pw->pw_name )
+               return NULL;
+       
+       DEBUG(10,("passwd2string: converting passwd struct for %s\n", 
+               pw->pw_name));
+
+       ret = snprintf( string, sizeof(string), "%s:%s:%d:%d:%s:%s:%s",
+               pw->pw_name, 
+               pw->pw_passwd ? pw->pw_passwd : "x",
+               pw->pw_uid,
+               pw->pw_gid,
+               pw->pw_gecos,
+               pw->pw_dir,
+               pw->pw_shell );
+               
+       if ( ret < 0 ) {
+               DEBUG(0,("passwd2string: snprintf() failed!\n"));
+               return NULL;
+       }
+               
+       return string;  
+}
+
+/**********************************************************************
+ Convert a string in /etc/group format to a struct group* entry
+**********************************************************************/
+
+static WINBINDD_GR* string2group( char *string )
+{
+       static WINBINDD_GR grp;
+       char *p, *str;
+       char *fields[NUM_GRP_FIELDS];
+       int i;
+       char **gr_members = NULL;
+       int num_gr_members = 0;
+       
+       if ( !string )
+               return NULL;
+               
+       ZERO_STRUCTP( &grp );
+       
+       DEBUG(10,("string2group: converting \"%s\"\n", string));
+       
+       ZERO_STRUCT( fields );
+       
+       for ( i=0, str=string; i<NUM_GRP_FIELDS-1; i++ ) {
+               if ( !(p = strchr( str, ':' )) ) {
+                       DEBUG(0,("string2group: parsing failure\n"));
+                       return NULL;
+               }
+               *p = '\0';
+               if ( str )
+                       fields[i] = str;
+               str = p + 1;
+       }
+       
+       /* group members */
+       
+       if ( *str ) {
+               /* we already know we have a non-empty string */
+
+               num_gr_members = count_chars(str, ',') + 1;
+               
+               /* if there was at least one comma, then there 
+                  are n+1 members */
+               if ( num_gr_members ) {
+                       fstring buffer;
+                       
+                       gr_members = (char**)smb_xmalloc(sizeof(char*)*num_gr_members+1);
+                       
+                       i = 0;
+                       while ( next_token(&str, buffer, ",", sizeof(buffer)) && i<num_gr_members ) {
+                               gr_members[i++] = smb_xstrdup(buffer);
+                       }
+
+                       gr_members[i]   = NULL;
+               }
+       }
+
+       
+       /* copy fields */
+       
+       fstrcpy( grp.gr_name,   fields[0] );
+       fstrcpy( grp.gr_passwd, fields[1] );
+       grp.gr_gid = atoi(      fields[2] );
+       
+       grp.num_gr_mem = num_gr_members;
+       grp.gr_mem     = gr_members;
+       
+       /* last minute sanity checks */
+       
+       if ( grp.gr_gid == 0 ) {
+               DEBUG(0,("string2group: Failure! gid==%d\n", grp.gr_gid));
+               SAFE_FREE( gr_members );
+               return NULL;
+       }
+       
+       DEBUG(10,("string2group: Success\n"));
+
+       return &grp;
+}
+
+/**********************************************************************
+ Convert a struct group* to a string formatted for /etc/group
+**********************************************************************/
+
+static char* group2string( const WINBINDD_GR *grp )
+{
+       static pstring string;
+       int ret;
+       char *member, *gr_mem_str;
+       int num_members;
+       int i, size;
+       
+       if ( !grp || !grp->gr_name )
+               return NULL;
+       
+       DEBUG(10,("group2string: converting passwd struct for %s\n", 
+               grp->gr_name));
+       
+       if ( grp->num_gr_mem ) {
+               int idx = 0;
+
+               member = grp->gr_mem[0];
+               size = 0;
+               num_members = 0;
+
+               while ( member ) {
+                       size += strlen(member) + 1;
+                       num_members++;
+                       member = grp->gr_mem[num_members];
+               }
+               
+               gr_mem_str = smb_xmalloc(size);
+       
+               for ( i=0; i<num_members; i++ ) {
+                       snprintf( &gr_mem_str[idx], size-idx, "%s,", grp->gr_mem[i] );
+                       idx += strlen(grp->gr_mem[i]) + 1;
+               }
+               /* add trailing NULL (also removes trailing ',' */
+               gr_mem_str[size-1] = '\0';
+       }
+       else {
+               /* no members */
+               gr_mem_str = smb_xmalloc(sizeof(fstring));
+               fstrcpy( gr_mem_str, "" );
+       }
+
+       ret = snprintf( string, sizeof(string)-1, "%s:%s:%d:%s",
+               grp->gr_name, 
+               grp->gr_passwd ? grp->gr_passwd : "*",
+               grp->gr_gid,
+               gr_mem_str );
+               
+       SAFE_FREE( gr_mem_str );
+               
+       if ( ret < 0 ) {
+               DEBUG(0,("group2string: snprintf() failed!\n"));
+               return NULL;
+       }
+               
+       return string;  
+}
+
+/**********************************************************************
+**********************************************************************/
+
+static char* acct_userkey_byname( const char *name )
+{
+       static fstring key;
+       
+       snprintf( key, sizeof(key), "%s/NAME/%s", WBKEY_PASSWD, name );
+       
+       return key;             
+}
+
+/**********************************************************************
+**********************************************************************/
+
+static char* acct_userkey_byuid( uid_t uid )
+{
+       static fstring key;
+       
+       snprintf( key, sizeof(key), "%s/UID/%d", WBKEY_PASSWD, uid );
+       
+       return key;             
+}
+
+/**********************************************************************
+**********************************************************************/
+
+static char* acct_groupkey_byname( const char *name )
+{
+       static fstring key;
+       
+       snprintf( key, sizeof(key), "%s/NAME/%s", WBKEY_GROUP, name );
+       
+       return key;             
+}
+
+/**********************************************************************
+**********************************************************************/
+
+static char* acct_groupkey_bygid( gid_t gid )
+{
+       static fstring key;
+       
+       snprintf( key, sizeof(key), "%s/GID/%d", WBKEY_GROUP, gid );
+       
+       return key;             
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WINBINDD_PW* wb_getpwnam( const char * name )
+{
+       char *keystr;
+       TDB_DATA data;
+       static WINBINDD_PW *pw;
+       
+       if ( !account_tdb && !winbindd_accountdb_init() ) {
+               DEBUG(0,("wb_getpwnam: Failed to open winbindd account db\n"));
+               return NULL;
+       }
+               
+       
+       keystr = acct_userkey_byname( name );
+       
+       data = tdb_fetch_by_string( account_tdb, keystr );
+       
+       pw = NULL;
+       
+       if ( data.dptr ) {
+               pw = string2passwd( data.dptr );
+               SAFE_FREE( data.dptr );
+       }
+               
+       DEBUG(5,("wb_getpwnam: %s user (%s)\n", 
+               (pw ? "Found" : "Did not find"), name ));
+       
+       return pw;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WINBINDD_PW* wb_getpwuid( const uid_t uid )
+{
+       char *keystr;
+       TDB_DATA data;
+       static WINBINDD_PW *pw;
+       
+       if ( !account_tdb && !winbindd_accountdb_init() ) {
+               DEBUG(0,("wb_getpwuid: Failed to open winbindd account db\n"));
+               return NULL;
+       }
+       
+       data = tdb_fetch_by_string( account_tdb, acct_userkey_byuid(uid) );
+       if ( !data.dptr ) {
+               DEBUG(4,("wb_getpwuid: failed to locate uid == %d\n", uid));
+               return NULL;
+       }
+       keystr = acct_userkey_byname( data.dptr );
+
+       SAFE_FREE( data.dptr );
+       
+       data = tdb_fetch_by_string( account_tdb, keystr );
+       
+       pw = NULL;
+       
+       if ( data.dptr ) {
+               pw = string2passwd( data.dptr );
+               SAFE_FREE( data.dptr );
+       }
+
+       DEBUG(5,("wb_getpwuid: %s user (uid == %d)\n", 
+               (pw ? "Found" : "Did not find"), uid ));
+       
+       return pw;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+BOOL wb_storepwnam( const WINBINDD_PW *pw )
+{
+       char *namekey, *uidkey;
+       TDB_DATA data;
+       char *str;
+       int ret = 0;
+       fstring username;
+
+       if ( !account_tdb && !winbindd_accountdb_init() ) {
+               DEBUG(0,("wb_storepwnam: Failed to open winbindd account db\n"));
+               return False;
+       }
+
+       namekey = acct_userkey_byname( pw->pw_name );
+       
+       /* lock the main entry first */
+       
+       if ( tdb_lock_bystring(account_tdb, namekey, 0) == -1 ) {
+               DEBUG(0,("wb_storepwnam: Failed to lock %s\n", namekey));
+               return False;
+       }
+       
+       str = passwd2string( pw );
+
+       data.dptr = str;
+       data.dsize = strlen(str) + 1;   
+
+       if ( (tdb_store_by_string(account_tdb, namekey, data, TDB_REPLACE)) == -1 ) {
+               DEBUG(0,("wb_storepwnam: Failed to store \"%s\"\n", str));
+               ret = -1;
+               goto done;
+       }
+       
+       /* store the uid index */
+       
+       uidkey = acct_userkey_byuid(pw->pw_uid);
+       
+       fstrcpy( username, pw->pw_name );
+       data.dptr = username;
+       data.dsize = strlen(username) + 1;
+       
+       if ( (tdb_store_by_string(account_tdb, uidkey, data, TDB_REPLACE)) == -1 ) {
+               DEBUG(0,("wb_storepwnam: Failed to store uid key \"%s\"\n", str));
+               tdb_delete_by_string(account_tdb, namekey);
+               ret = -1;
+               goto done;
+       }               
+       
+       DEBUG(10,("wb_storepwnam: Success -> \"%s\"\n", str));
+
+done:  
+       tdb_unlock_bystring( account_tdb, namekey );
+       
+       return ( ret == 0 );
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WINBINDD_GR* wb_getgrnam( const char * name )
+{
+       char *keystr;
+       TDB_DATA data;
+       static WINBINDD_GR *grp;
+       
+       if ( !account_tdb && !winbindd_accountdb_init() ) {
+               DEBUG(0,("wb_getgrnam: Failed to open winbindd account db\n"));
+               return NULL;
+       }
+               
+       
+       keystr = acct_groupkey_byname( name );
+       
+       data = tdb_fetch_by_string( account_tdb, keystr );
+       
+       grp = NULL;
+       
+       if ( data.dptr ) {
+               grp = string2group( data.dptr );
+               SAFE_FREE( data.dptr );
+       }
+               
+       DEBUG(5,("wb_getgrnam: %s group (%s)\n", 
+               (grp ? "Found" : "Did not find"), name ));
+       
+       return grp;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+WINBINDD_GR* wb_getgrgid( gid_t gid )
+{
+       char *keystr;
+       TDB_DATA data;
+       static WINBINDD_GR *grp;
+       
+       if ( !account_tdb && !winbindd_accountdb_init() ) {
+               DEBUG(0,("wb_getgrgid: Failed to open winbindd account db\n"));
+               return NULL;
+       }
+       
+       data = tdb_fetch_by_string( account_tdb, acct_groupkey_bygid(gid) );
+       if ( !data.dptr ) {
+               DEBUG(4,("wb_getgrgid: failed to locate gid == %d\n", gid));
+               return NULL;
+       }
+       keystr = acct_groupkey_byname( data.dptr );
+
+       SAFE_FREE( data.dptr );
+       
+       data = tdb_fetch_by_string( account_tdb, keystr );
+       
+       grp = NULL;
+       
+       if ( data.dptr ) {
+               grp = string2group( data.dptr );
+               SAFE_FREE( data.dptr );
+       }
+
+       DEBUG(5,("wb_getgrgid: %s group (gid == %d)\n", 
+               (grp ? "Found" : "Did not find"), gid ));
+       
+       return grp;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+BOOL wb_storegrnam( const WINBINDD_GR *grp )
+{
+       char *namekey, *gidkey;
+       TDB_DATA data;
+       char *str;
+       int ret = 0;
+       fstring groupname;
+
+       if ( !account_tdb && !winbindd_accountdb_init() ) {
+               DEBUG(0,("wb_storepwnam: Failed to open winbindd account db\n"));
+               return False;
+       }
+
+       namekey = acct_groupkey_byname( grp->gr_name );
+       
+       /* lock the main entry first */
+       
+       if ( tdb_lock_bystring(account_tdb, namekey, 0) == -1 ) {
+               DEBUG(0,("wb_storegrnam: Failed to lock %s\n", namekey));
+               return False;
+       }
+       
+       str = group2string( grp );
+
+       data.dptr = str;
+       data.dsize = strlen(str) + 1;   
+
+       if ( (tdb_store_by_string(account_tdb, namekey, data, TDB_REPLACE)) == -1 ) {
+               DEBUG(0,("wb_storegrnam: Failed to store \"%s\"\n", str));
+               ret = -1;
+               goto done;
+       }
+       
+       /* store the gid index */
+       
+       gidkey = acct_groupkey_bygid(grp->gr_gid);
+       
+       fstrcpy( groupname, grp->gr_name );
+       data.dptr = groupname;
+       data.dsize = strlen(groupname) + 1;
+       
+       if ( (tdb_store_by_string(account_tdb, gidkey, data, TDB_REPLACE)) == -1 ) {
+               DEBUG(0,("wb_storegrnam: Failed to store gid key \"%s\"\n", str));
+               tdb_delete_by_string(account_tdb, namekey);
+               ret = -1;
+               goto done;
+       }
+       
+       DEBUG(10,("wb_storegrnam: Success -> \"%s\"\n", str));
+
+done:  
+       tdb_unlock_bystring( account_tdb, namekey );
+       
+       return ( ret == 0 );
+}
+
+/**********************************************************************
+**********************************************************************/
+
+static BOOL wb_addgrpmember( WINBINDD_GR *grp, const char *user )
+{
+       int i;
+       char **members;
+       
+       if ( !grp || !user )
+               return False;
+       
+       for ( i=0; i<grp->num_gr_mem; i++ ) {
+               if ( StrCaseCmp( grp->gr_mem[i], user ) == 0 )
+                       return True;
+       }
+       
+       /* add one new slot and keep an extra for the terminating NULL */
+       members = Realloc( grp->gr_mem, (grp->num_gr_mem+2)*sizeof(char*) );
+       if ( !members )
+               return False;
+               
+       grp->gr_mem = members;
+       grp->gr_mem[grp->num_gr_mem++] = smb_xstrdup(user);
+       grp->gr_mem[grp->num_gr_mem]   = NULL;
+               
+       return True;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+static BOOL wb_delgrpmember( WINBINDD_GR *grp, const char *user )
+{
+       int i;
+       BOOL found = False;
+       
+       if ( !grp || !user )
+               return False;
+       
+       for ( i=0; i<grp->num_gr_mem && !found; i++ ) {
+               if ( StrCaseCmp( grp->gr_mem[i], user ) == 0 ) 
+                       found = True;
+       }
+       
+       if ( !found ) 
+               return False;
+
+       memmove( grp->gr_mem[i], grp->gr_mem[i+1], sizeof(char*)*(grp->num_gr_mem-(i+1)) );
+       grp->num_gr_mem--;
+                               
+       return True;
+}
+
+/**********************************************************************
+**********************************************************************/
+
+static void free_winbindd_gr( WINBINDD_GR *grp )
+{
+       int i;
+
+       if ( !grp )
+               return;
+               
+       for ( i=0; i<grp->num_gr_mem; i++ )
+               SAFE_FREE( grp->gr_mem[i] );
+
+       SAFE_FREE( grp->gr_mem );
+       
+       return;
+}
+
+/**********************************************************************
+ Create a new "UNIX" user for the system given a username
+**********************************************************************/
+
+enum winbindd_result winbindd_create_user(struct winbindd_cli_state *state)
+{
+       char *user, *group;
+       unid_t id;
+       WINBINDD_PW pw;
+       WINBINDD_GR *wb_grp;
+       struct group *unix_grp;
+       gid_t primary_gid;
+       
+       if ( !state->privileged ) {
+               DEBUG(2, ("winbindd_create_user: non-privileged access denied!\n"));
+               return WINBINDD_ERROR;
+       }
+       
+       /* Ensure null termination */
+       state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.username)-1]='\0';
+       state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0';
+       
+       user  = state->request.data.acct_mgt.username;
+       group = state->request.data.acct_mgt.groupname;
+       
+       DEBUG(3, ("[%5d]: create_user user=>(%s), group=>(%s)\n", 
+               state->pid, user, group));
+               
+       if ( !*group )
+               group = lp_template_primary_group();
+               
+       /* validate the primary group
+          1) lookup in local tdb first
+          2) call getgrnam() as a last resort */
+          
+       if ( (wb_grp=wb_getgrnam(group)) != NULL ) {
+               primary_gid = wb_grp->gr_gid;
+               free_winbindd_gr( wb_grp );
+       }
+       else if ( (unix_grp=sys_getgrnam(group)) != NULL ) {
+               primary_gid = unix_grp->gr_gid; 
+       }
+       else {
+               DEBUG(2,("winbindd_create_user: Cannot validate gid for group (%s)\n", group));
+               return WINBINDD_ERROR;
+       }
+
+       /* get a new uid */
+       
+       if ( !NT_STATUS_IS_OK(idmap_allocate_id( &id, ID_USERID)) ) {
+               DEBUG(0,("winbindd_create_user: idmap_allocate_id() failed!\n"));
+               return WINBINDD_ERROR;
+       }
+       
+       /* The substitution of %U and %D in the 'template homedir' is done
+          by lp_string() calling standard_sub_basic(). */
+
+       fstrcpy( current_user_info.smb_name, user );
+       sub_set_smb_name( user );
+       fstrcpy( current_user_info.domain, get_global_sam_name() );
+       
+       /* fill in the passwd struct */
+               
+       fstrcpy( pw.pw_name,   user );
+       fstrcpy( pw.pw_passwd, "x" );
+       fstrcpy( pw.pw_gecos,  user);
+       fstrcpy( pw.pw_dir,    lp_template_homedir() );
+       fstrcpy( pw.pw_shell,  lp_template_shell() );
+       
+       pw.pw_uid = id.uid;
+       pw.pw_gid = primary_gid;
+
+       return ( wb_storepwnam(&pw) ? WINBINDD_OK : WINBINDD_ERROR );
+}
+
+/**********************************************************************
+ Create a new "UNIX" group for the system given a username
+**********************************************************************/
+
+enum winbindd_result winbindd_create_group(struct winbindd_cli_state *state)
+{
+       char *group;
+       unid_t id;
+       WINBINDD_GR grp;
+       
+       if ( !state->privileged ) {
+               DEBUG(2, ("winbindd_create_group: non-privileged access denied!\n"));
+               return WINBINDD_ERROR;
+       }
+       
+       /* Ensure null termination */
+       state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0';  
+       group = state->request.data.acct_mgt.groupname;
+       
+       DEBUG(3, ("[%5d]: create_group (%s)\n", state->pid, group));
+       
+       /* get a new uid */
+       
+       if ( !NT_STATUS_IS_OK(idmap_allocate_id( &id, ID_GROUPID)) ) {
+               DEBUG(0,("winbindd_create_group: idmap_allocate_id() failed!\n"));
+               return WINBINDD_ERROR;
+       }
+       
+       /* fill in the group struct */
+               
+       fstrcpy( grp.gr_name,   group );
+       fstrcpy( grp.gr_passwd, "*" );
+       
+       grp.gr_gid      = id.gid;
+       grp.gr_mem      = NULL; /* start with no members */
+       grp.num_gr_mem  = 0;
+
+       return ( wb_storegrnam(&grp) ? WINBINDD_OK : WINBINDD_ERROR );
+}
+
+/**********************************************************************
+ Add a user to the membership for a group.
+**********************************************************************/
+
+enum winbindd_result winbindd_add_user_to_group(struct winbindd_cli_state *state)
+{
+       WINBINDD_PW *pw;
+       WINBINDD_GR *grp;
+       char *user, *group;
+       BOOL ret;
+       
+       if ( !state->privileged ) {
+               DEBUG(2, ("winbindd_add_user_to_group: non-privileged access denied!\n"));
+               return WINBINDD_ERROR;
+       }
+       
+       /* Ensure null termination */
+       state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0';  
+       state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.username)-1]='\0';    
+       group = state->request.data.acct_mgt.groupname;
+       user = state->request.data.acct_mgt.username;
+       
+       DEBUG(3, ("[%5d]:  add_user_to_group add %s to %s\n", state->pid, 
+               user, group));
+       
+       /* make sure it is a valid user */
+       
+       if ( !(pw = wb_getpwnam( user )) ) {
+               DEBUG(4,("winbindd_add_user_to_group: Cannot add a non-existent user\n"));
+               return WINBINDD_ERROR;
+       }
+       
+       /* make sure it is a valid group */
+       
+       if ( !(grp = wb_getgrnam( group )) ) {
+               DEBUG(4,("winbindd_add_user_to_group: Cannot add a user to a non-extistent group\n"));
+               return WINBINDD_ERROR;  
+       }
+       
+       if ( !wb_addgrpmember( grp, user ) )
+               return WINBINDD_ERROR;
+               
+       ret = wb_storegrnam(grp);
+       
+       free_winbindd_gr( grp );
+       
+       return ( ret ? WINBINDD_OK : WINBINDD_ERROR );
+}
+
+/**********************************************************************
+ Remove a user from the membership of a group
+**********************************************************************/
+
+enum winbindd_result winbindd_remove_user_from_group(struct winbindd_cli_state *state)
+{
+       WINBINDD_GR *grp;
+       char *user, *group;
+       BOOL ret;
+
+       if ( !state->privileged ) {
+               DEBUG(2, ("winbindd_remove_user_from_group: non-privileged access denied!\n"));
+               return WINBINDD_ERROR;
+       }
+       
+       /* Ensure null termination */
+       state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0';  
+       state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.username)-1]='\0';    
+       group = state->request.data.acct_mgt.groupname;
+       user = state->request.data.acct_mgt.username;
+       
+       DEBUG(3, ("[%5d]:  remove_user_to_group delete %s from %s\n", state->pid, 
+               user, group));
+       
+       /* don't worry about checking the username since we're removing it anyways */
+       
+       /* make sure it is a valid group */
+       
+       if ( !(grp = wb_getgrnam( group )) ) {
+               DEBUG(4,("winbindd_remove_user_to_group: Cannot remove a user to a non-extistent group\n"));
+               return WINBINDD_ERROR;  
+       }
+       
+       if ( !wb_delgrpmember( grp, user ) )
+               return WINBINDD_ERROR;
+               
+       ret = wb_storegrnam(grp);
+       
+       free_winbindd_gr( grp );
+       
+       return ( ret ? WINBINDD_OK : WINBINDD_ERROR );
+}
+
+/**********************************************************************
+ Set the primary group membership of a user
+**********************************************************************/
+
+enum winbindd_result winbindd_set_user_primary_group(struct winbindd_cli_state *state)
+{
+       WINBINDD_PW *pw;
+       WINBINDD_GR *grp;
+       char *user, *group;
+
+       if ( !state->privileged ) {
+               DEBUG(2, ("winbindd_set_user_primary_group: non-privileged access denied!\n"));
+               return WINBINDD_ERROR;
+       }
+       
+       /* Ensure null termination */
+       state->request.data.acct_mgt.groupname[sizeof(state->request.data.acct_mgt.groupname)-1]='\0';  
+       state->request.data.acct_mgt.username[sizeof(state->request.data.acct_mgt.username)-1]='\0';    
+       group = state->request.data.acct_mgt.groupname;
+       user = state->request.data.acct_mgt.username;
+       
+       DEBUG(3, ("[%5d]:  set_user_primary_group group %s for user %s\n", state->pid, 
+               group, user));
+       
+       /* make sure it is a valid user */
+       
+       if ( !(pw = wb_getpwnam( user )) ) {
+               DEBUG(4,("winbindd_add_user_to_group: Cannot add a non-existent user\n"));
+               return WINBINDD_ERROR;
+       }
+       
+       /* make sure it is a valid group */
+       
+       if ( !(grp = wb_getgrnam( group )) ) {
+               DEBUG(4,("winbindd_add_user_to_group: Cannot add a user to a non-extistent group\n"));
+               return WINBINDD_ERROR;  
+       }
+       
+       pw->pw_gid = grp->gr_gid;
+
+       free_winbindd_gr( grp );
+               
+       return ( wb_storepwnam(pw) ? WINBINDD_OK : WINBINDD_ERROR );
+}
+
+/**********************************************************************
+ Set the primary group membership of a user
+**********************************************************************/
+
+enum winbindd_result winbindd_delete_user(struct winbindd_cli_state *state)
+{
+       return WINBINDD_ERROR;
+}
+
+/**********************************************************************
+ Set the primary group membership of a user
+**********************************************************************/
+
+enum winbindd_result winbindd_delete_group(struct winbindd_cli_state *state)
+{
+       return WINBINDD_ERROR;
+}
+
+
index 9a969abeaa99b429714fa765bb5e66bfa74a1b13..d67d48d506626cc59cbab01e8791ce41da563153 100644 (file)
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
 
+/*********************************************************************
+*********************************************************************/
+
+static int gr_mem_buffer( char **buffer, char **members, int num_members )
+{
+       int i;
+       int len = 0;
+       int idx = 0;
+
+       if ( num_members == 0 ) {
+               *buffer = NULL;
+               return 0;
+       }
+       
+       for ( i=0; i<num_members; i++ )
+               len += strlen(members[i])+1;
+
+       *buffer = (char*)smb_xmalloc(len);
+       for ( i=0; i<num_members; i++ ) {
+               snprintf( &(*buffer)[idx], len-idx, "%s,", members[i]);
+               idx += strlen(members[i])+1;
+       }
+       /* terminate with NULL */
+       (*buffer)[len-1] = '\0';
+       
+       return len;     
+}
+
 /***************************************************************
  Empty static struct for negative caching.
 ****************************************************************/
@@ -193,6 +221,7 @@ done:
 enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state)
 {
        DOM_SID group_sid;
+       WINBINDD_GR *grp;
        struct winbindd_domain *domain;
        enum SID_NAME_USE name_type;
        fstring name_domain, name_group;
@@ -211,18 +240,38 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state)
        memset(name_group, 0, sizeof(fstring));
 
        tmp = state->request.data.groupname;
-       if (!parse_domain_user(tmp, name_domain, name_group))
-               return WINBINDD_ERROR;
+       
+       parse_domain_user(tmp, name_domain, name_group);
+
+       /* if no domain or our local domain, then do a local tdb search */
+       
+       if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
+               char *buffer = NULL;
+               
+               if ( !(grp=wb_getgrnam(name_group)) ) {
+                       DEBUG(5,("winbindd_getgrnam: lookup for %s\\%s failed\n",
+                               name_domain, name_group));
+                       return WINBINDD_ERROR;
+               }
+               memcpy( &state->response.data.gr, grp, sizeof(WINBINDD_GR) );
 
-       /* don't handle our own domain if we are a DC ( or a member of a Samba domain 
-          that shares UNIX accounts).  This code handles cases where
-          the account doesn't exist anywhere and gets passed on down the NSS layer */
+               gr_mem_len = gr_mem_buffer( &buffer, grp->gr_mem, grp->num_gr_mem );
+               
+               state->response.data.gr.gr_mem_ofs = 0;
+               state->response.length += gr_mem_len;
+               state->response.extra_data = buffer;    /* give the memory away */
+               
+               return WINBINDD_OK;
+       }
 
-       if ( (IS_DC || lp_winbind_trusted_domains_only()) && strequal(name_domain, lp_workgroup()) ) {
-               DEBUG(7,("winbindd_getgrnam: rejecting getpwnam() for %s\\%s since I am on the PDC for this domain\n", 
+       /* should we deal with users for our domain? */
+       
+       if ( lp_winbind_trusted_domains_only() && strequal(name_domain, lp_workgroup())) {
+               DEBUG(7,("winbindd_getgrnam: My domain -- rejecting getgrnam() for %s\\%s.\n", 
                        name_domain, name_group));
                return WINBINDD_ERROR;
        }       
+
        
        /* Get info for the domain */
 
@@ -277,6 +326,7 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state)
 enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state)
 {
        struct winbindd_domain *domain;
+       WINBINDD_GR *grp;
        DOM_SID group_sid;
        enum SID_NAME_USE name_type;
        fstring dom_name;
@@ -293,6 +343,21 @@ enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state)
            (state->request.data.gid > server_state.gid_high))
                return WINBINDD_ERROR;
 
+       /* alway try local tdb lookup first */
+       if ( ( grp=wb_getgrgid(state->request.data.gid)) != NULL ) {
+               char *buffer = NULL;
+               
+               memcpy( &state->response.data.gr, grp, sizeof(WINBINDD_GR) );
+               
+               gr_mem_len = gr_mem_buffer( &buffer, grp->gr_mem, grp->num_gr_mem );
+               
+               state->response.data.gr.gr_mem_ofs = 0;
+               state->response.length += gr_mem_len;
+               state->response.extra_data = buffer;    /* give away the memory */
+               
+               return WINBINDD_OK;
+       }
+
        /* Get rid from gid */
        if (!NT_STATUS_IS_OK(idmap_gid_to_sid(&group_sid, state->request.data.gid))) {
                DEBUG(1, ("could not convert gid %d to rid\n", 
@@ -859,8 +924,12 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
 
        /* Parse domain and username */
 
-       if (!parse_domain_user(state->request.data.username, name_domain, 
-                         name_user))
+       parse_domain_user(state->request.data.username, 
+               name_domain, name_user);
+       
+       /* bail if there is no domain */ 
+       
+       if ( !*name_domain )
                goto done;
 
        /* Get info for the domain */
diff --git a/source3/nsswitch/winbindd_idmap.c b/source3/nsswitch/winbindd_idmap.c
deleted file mode 100644 (file)
index 3b23089..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-/* 
-   Unix SMB/CIFS implementation.
-   Winbind ID Mapping
-   Copyright (C) Tim Potter 2000
-   Copyright (C) Anthony Liguori <aliguor@us.ibm.com>  2003
-
-   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 "winbindd.h"
-
-static struct {
-  const char *name;
-  /* Function to create a member of the idmap_methods list */
-  BOOL (*reg_meth)(struct winbindd_idmap_methods **methods);
-  struct winbindd_idmap_methods *methods;
-} builtin_winbindd_idmap_functions[] = {
-  { "tdb", winbind_idmap_reg_tdb, NULL },
-  { NULL, NULL, NULL }
-};
-
-/* singleton pattern: uberlazy evaluation */
-static struct winbindd_idmap_methods *impl;
-
-static struct winbindd_idmap_methods *get_impl(const char *name)
-{
-  int i = 0;
-  struct winbindd_idmap_methods *ret = NULL;
-
-  while (builtin_winbindd_idmap_functions[i].name && 
-         strcmp(builtin_winbindd_idmap_functions[i].name, name)) {
-    i++;
-  }
-
-  if (builtin_winbindd_idmap_functions[i].name) {
-    if (!builtin_winbindd_idmap_functions[i].methods) {
-      builtin_winbindd_idmap_functions[i].reg_meth(&builtin_winbindd_idmap_functions[i].methods);
-    }
-
-    ret = builtin_winbindd_idmap_functions[i].methods;
-  }
-
-  return ret;
-}
-
-/* Initialize backend */
-BOOL winbindd_idmap_init(void)
-{
-  BOOL ret = False;
-
-  DEBUG(3, ("winbindd_idmap_init: using '%s' as backend\n", 
-            lp_winbind_backend()));
-
-  if (!impl) {
-    impl = get_impl(lp_winbind_backend());
-    if (!impl) {
-      DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n",
-                lp_winbind_backend()));
-    }
-  }
-
-  if (impl) {
-    ret = impl->init();
-  }
-
-  DEBUG(3, ("winbind_idmap_init: returning %s\n", ret ? "true" : "false"));
-
-  return ret;
-}
-
-/* Get UID from SID */
-BOOL winbindd_idmap_get_uid_from_sid(DOM_SID *sid, uid_t *uid)
-{
-  BOOL ret = False;
-
-  if (!impl) {
-    impl = get_impl(lp_winbind_backend());
-    if (!impl) {
-      DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n",
-                lp_winbind_backend()));
-    }
-  }
-
-  if (impl) {
-    ret = impl->get_uid_from_sid(sid, uid);
-  }
-
-  return ret;
-}
-
-/* Get GID from SID */
-BOOL winbindd_idmap_get_gid_from_sid(DOM_SID *sid, gid_t *gid)
-{
-  BOOL ret = False;
-
-  if (!impl) {
-    impl = get_impl(lp_winbind_backend());
-    if (!impl) {
-      DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n",
-                lp_winbind_backend()));
-    }
-  }
-
-  if (impl) {
-    ret = impl->get_gid_from_sid(sid, gid);
-  }
-
-  return ret;
-}
-
-/* Get SID from UID */
-BOOL winbindd_idmap_get_sid_from_uid(uid_t uid, DOM_SID *sid)
-{
-  BOOL ret = False;
-
-  if (!impl) {
-    impl = get_impl(lp_winbind_backend());
-    if (!impl) {
-      DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n",
-                lp_winbind_backend()));
-    }
-  }
-
-  if (impl) {
-    ret = impl->get_sid_from_uid(uid, sid);
-  }
-
-  return ret;
-}
-
-/* Get SID from GID */
-BOOL winbindd_idmap_get_sid_from_gid(gid_t gid, DOM_SID *sid)
-{
-  BOOL ret = False;
-
-  if (!impl) {
-    impl = get_impl(lp_winbind_backend());
-  }
-
-  if (impl) {
-    ret = impl->get_sid_from_gid(gid, sid);
-  } else {
-    DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n",
-              lp_winbind_backend()));
-  }
-
-  return ret;
-}
-
-/* Close backend */
-BOOL winbindd_idmap_close(void)
-{
-  BOOL ret = False;
-
-  if (!impl) {
-    impl = get_impl(lp_winbind_backend());
-  }
-
-  if (impl) {
-    ret = impl->close();
-  } else {
-    DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n",
-              lp_winbind_backend()));
-  }
-
-  return ret;
-}
-
-/* Dump backend status */
-void winbindd_idmap_status(void)
-{
-  if (!impl) {
-    impl = get_impl(lp_winbind_backend());
-  }
-
-  if (impl) {
-    impl->status();
-  } else {
-    DEBUG(0, ("winbindd_idmap_init: could not load backend '%s'\n",
-              lp_winbind_backend()));
-  }
-}
diff --git a/source3/nsswitch/winbindd_idmap_tdb.c b/source3/nsswitch/winbindd_idmap_tdb.c
deleted file mode 100644 (file)
index 12d6972..0000000
+++ /dev/null
@@ -1,459 +0,0 @@
-/* 
-   Unix SMB/CIFS implementation.
-
-   Winbind daemon - user related function
-
-   Copyright (C) Tim Potter 2000
-   Copyright (C) Anthony Liguori 2003
-   
-   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 "winbindd.h"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_WINBIND
-
-/* High water mark keys */
-#define HWM_GROUP  "GROUP HWM"
-#define HWM_USER   "USER HWM"
-
-/* idmap version determines auto-conversion */
-#define IDMAP_VERSION 2
-
-/* Globals */
-static TDB_CONTEXT *idmap_tdb;
-
-/* convert one record to the new format */
-static int tdb_convert_fn(TDB_CONTEXT * tdb, TDB_DATA key, TDB_DATA data,
-                         void *ignored)
-{
-       struct winbindd_domain *domain;
-       char *p;
-       DOM_SID sid;
-       uint32 rid;
-       fstring keystr;
-       fstring dom_name;
-       TDB_DATA key2;
-
-       p = strchr(key.dptr, '/');
-       if (!p)
-               return 0;
-
-       *p = 0;
-       fstrcpy(dom_name, key.dptr);
-       *p++ = '/';
-
-       domain = find_domain_from_name(dom_name);
-       if (!domain) {
-               /* We must delete the old record. */
-               DEBUG(0,
-                     ("winbindd: tdb_convert_fn : Unable to find domain %s\n",
-                      dom_name));
-               DEBUG(0,
-                     ("winbindd: tdb_convert_fn : deleting record %s\n",
-                      key.dptr));
-               tdb_delete(idmap_tdb, key);
-               return 0;
-       }
-
-       rid = atoi(p);
-
-       sid_copy(&sid, &domain->sid);
-       sid_append_rid(&sid, rid);
-
-       sid_to_string(keystr, &sid);
-       key2.dptr = keystr;
-       key2.dsize = strlen(keystr) + 1;
-
-       if (tdb_store(idmap_tdb, key2, data, TDB_INSERT) != 0) {
-               /* not good! */
-               DEBUG(0,
-                     ("winbindd: tdb_convert_fn : Unable to update record %s\n",
-                      key2.dptr));
-               DEBUG(0,
-                     ("winbindd: tdb_convert_fn : conversion failed - idmap corrupt ?\n"));
-               return -1;
-       }
-
-       if (tdb_store(idmap_tdb, data, key2, TDB_REPLACE) != 0) {
-               /* not good! */
-               DEBUG(0,
-                     ("winbindd: tdb_convert_fn : Unable to update record %s\n",
-                      data.dptr));
-               DEBUG(0,
-                     ("winbindd: tdb_convert_fn : conversion failed - idmap corrupt ?\n"));
-               return -1;
-       }
-
-       tdb_delete(idmap_tdb, key);
-
-       return 0;
-}
-
-/*****************************************************************************
- Convert the idmap database from an older version.
-*****************************************************************************/
-static BOOL tdb_idmap_convert(void)
-{
-       int32 vers = tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION");
-       BOOL bigendianheader =
-           (idmap_tdb->flags & TDB_BIGENDIAN) ? True : False;
-
-       if (vers == IDMAP_VERSION)
-               return True;
-
-       if (((vers == -1) && bigendianheader)
-           || (IREV(vers) == IDMAP_VERSION)) {
-               /* Arrggghh ! Bytereversed or old big-endian - make order independent ! */
-               /*
-                * high and low records were created on a
-                * big endian machine and will need byte-reversing.
-                */
-
-               int32 wm;
-
-               wm = tdb_fetch_int32(idmap_tdb, HWM_USER);
-
-               if (wm != -1) {
-                       wm = IREV(wm);
-               } else
-                       wm = server_state.uid_low;
-
-               if (tdb_store_int32(idmap_tdb, HWM_USER, wm) == -1) {
-                       DEBUG(0,
-                             ("tdb_idmap_convert: Unable to byteswap user hwm in idmap database\n"));
-                       return False;
-               }
-
-               wm = tdb_fetch_int32(idmap_tdb, HWM_GROUP);
-               if (wm != -1) {
-                       wm = IREV(wm);
-               } else
-                       wm = server_state.gid_low;
-
-               if (tdb_store_int32(idmap_tdb, HWM_GROUP, wm) == -1) {
-                       DEBUG(0,
-                             ("tdb_idmap_convert: Unable to byteswap group hwm in idmap database\n"));
-                       return False;
-               }
-       }
-
-       /* the old format stored as DOMAIN/rid - now we store the SID direct */
-       tdb_traverse(idmap_tdb, tdb_convert_fn, NULL);
-
-       if (tdb_store_int32(idmap_tdb, "IDMAP_VERSION", IDMAP_VERSION) ==
-           -1) {
-               DEBUG(0,
-                     ("tdb_idmap_convert: Unable to byteswap group hwm in idmap database\n"));
-               return False;
-       }
-
-       return True;
-}
-
-/* Allocate either a user or group id from the pool */
-static BOOL tdb_allocate_id(uid_t * id, BOOL isgroup)
-{
-       int hwm;
-
-       /* Get current high water mark */
-       if ((hwm = tdb_fetch_int32(idmap_tdb,
-                                  isgroup ? HWM_GROUP : HWM_USER)) ==
-           -1) {
-               return False;
-       }
-
-       /* Return next available uid in list */
-       if ((isgroup && (hwm > server_state.gid_high)) ||
-           (!isgroup && (hwm > server_state.uid_high))) {
-               DEBUG(0,
-                     ("winbind %sid range full!\n", isgroup ? "g" : "u"));
-               return False;
-       }
-
-       if (id) {
-               *id = hwm;
-       }
-
-       hwm++;
-
-       /* Store new high water mark */
-       tdb_store_int32(idmap_tdb, isgroup ? HWM_GROUP : HWM_USER, hwm);
-
-       return True;
-}
-
-/* Get a sid from an id */
-static BOOL tdb_get_sid_from_id(int id, DOM_SID * sid, BOOL isgroup)
-{
-       TDB_DATA key, data;
-       fstring keystr;
-       BOOL result = False;
-
-       slprintf(keystr, sizeof(keystr), "%s %d", isgroup ? "GID" : "UID",
-                id);
-
-       key.dptr = keystr;
-       key.dsize = strlen(keystr) + 1;
-
-       data = tdb_fetch(idmap_tdb, key);
-
-       if (data.dptr) {
-               result = string_to_sid(sid, data.dptr);
-               SAFE_FREE(data.dptr);
-       }
-
-       return result;
-}
-
-/* Get an id from a sid */
-static BOOL tdb_get_id_from_sid(DOM_SID * sid, uid_t * id, BOOL isgroup)
-{
-       TDB_DATA data, key;
-       fstring keystr;
-       BOOL result = False;
-
-       /* Check if sid is present in database */
-       sid_to_string(keystr, sid);
-
-       key.dptr = keystr;
-       key.dsize = strlen(keystr) + 1;
-
-       data = tdb_fetch(idmap_tdb, key);
-
-       if (data.dptr) {
-               fstring scanstr;
-               int the_id;
-
-               /* Parse and return existing uid */
-               fstrcpy(scanstr, isgroup ? "GID" : "UID");
-               fstrcat(scanstr, " %d");
-
-               if (sscanf(data.dptr, scanstr, &the_id) == 1) {
-                       /* Store uid */
-                       if (id) {
-                               *id = the_id;
-                       }
-
-                       result = True;
-               }
-
-               SAFE_FREE(data.dptr);
-       } else {
-
-               /* Allocate a new id for this sid */
-               if (id && tdb_allocate_id(id, isgroup)) {
-                       fstring keystr2;
-
-                       /* Store new id */
-                       slprintf(keystr2, sizeof(keystr2), "%s %d",
-                                isgroup ? "GID" : "UID", *id);
-
-                       data.dptr = keystr2;
-                       data.dsize = strlen(keystr2) + 1;
-
-                       tdb_store(idmap_tdb, key, data, TDB_REPLACE);
-                       tdb_store(idmap_tdb, data, key, TDB_REPLACE);
-
-                       result = True;
-               }
-       }
-
-       return result;
-}
-
-/*****************************************************************************
- Initialise idmap database. 
-*****************************************************************************/
-static BOOL tdb_idmap_init(void)
-{
-       SMB_STRUCT_STAT stbuf;
-
-       /* move to the new database on first startup */
-       if (!file_exist(lock_path("idmap.tdb"), &stbuf)) {
-               if (file_exist(lock_path("winbindd_idmap.tdb"), &stbuf)) {
-                       char *cmd = NULL;
-                       
-                       /* lazy file copy */
-                       if (asprintf(&cmd, "cp -p %s/winbindd_idmap.tdb %s/idmap.tdb", lp_lockdir(), lp_lockdir()) != -1) {
-                               system(cmd);
-                               free(cmd);
-                       }
-                       if (!file_exist(lock_path("idmap.tdb"), &stbuf)) {
-                               DEBUG(0, ("idmap_init: Unable to make a new database copy\n"));
-                               return False;
-                       }
-               }
-       }
-
-       /* Open tdb cache */
-       if (!(idmap_tdb = tdb_open_log(lock_path("idmap.tdb"), 0,
-                                      TDB_DEFAULT, O_RDWR | O_CREAT,
-                                      0600))) {
-               DEBUG(0,
-                     ("winbindd_idmap_init: Unable to open idmap database\n"));
-               return False;
-       }
-
-       /* possibly convert from an earlier version */
-       if (!tdb_idmap_convert()) {
-               DEBUG(0, ("winbindd_idmap_init: Unable to open idmap database\n"));
-               return False;
-       }
-
-       /* Create high water marks for group and user id */
-       if (tdb_fetch_int32(idmap_tdb, HWM_USER) == -1) {
-               if (tdb_store_int32
-                   (idmap_tdb, HWM_USER, server_state.uid_low) == -1) {
-                       DEBUG(0,
-                             ("winbindd_idmap_init: Unable to initialise user hwm in idmap database\n"));
-                       return False;
-               }
-       }
-
-       if (tdb_fetch_int32(idmap_tdb, HWM_GROUP) == -1) {
-               if (tdb_store_int32
-                   (idmap_tdb, HWM_GROUP, server_state.gid_low) == -1) {
-                       DEBUG(0,
-                             ("winbindd_idmap_init: Unable to initialise group hwm in idmap database\n"));
-                       return False;
-               }
-       }
-
-       return True;
-}
-
-/* Get a sid from a uid */
-static BOOL tdb_get_sid_from_uid(uid_t uid, DOM_SID * sid)
-{
-       return tdb_get_sid_from_id((int) uid, sid, False);
-}
-
-/* Get a sid from a gid */
-static BOOL tdb_get_sid_from_gid(gid_t gid, DOM_SID * sid)
-{
-       return tdb_get_sid_from_id((int) gid, sid, True);
-}
-
-/* Get a uid from a sid */
-static BOOL tdb_get_uid_from_sid(DOM_SID * sid, uid_t * uid)
-{
-       return tdb_get_id_from_sid(sid, uid, False);
-}
-
-/* Get a gid from a group sid */
-static BOOL tdb_get_gid_from_sid(DOM_SID * sid, gid_t * gid)
-{
-       return tdb_get_id_from_sid(sid, gid, True);
-}
-
-/* Close the tdb */
-static BOOL tdb_idmap_close(void)
-{
-       if (idmap_tdb)
-               return (tdb_close(idmap_tdb) == 0);
-       return True;
-}
-
-
-/* Dump status information to log file.  Display different stuff based on
-   the debug level:
-
-   Debug Level        Information Displayed
-   =================================================================
-   0                  Percentage of [ug]id range allocated
-   0                  High water marks (next allocated ids)
-*/
-
-#define DUMP_INFO 0
-
-static void tdb_idmap_status(void)
-{
-       int user_hwm, group_hwm;
-
-       DEBUG(0, ("winbindd idmap status:\n"));
-
-       /* Get current high water marks */
-
-       if ((user_hwm = tdb_fetch_int32(idmap_tdb, HWM_USER)) == -1) {
-               DEBUG(DUMP_INFO,
-                     ("\tCould not get userid high water mark!\n"));
-       }
-
-       if ((group_hwm = tdb_fetch_int32(idmap_tdb, HWM_GROUP)) == -1) {
-               DEBUG(DUMP_INFO,
-                     ("\tCould not get groupid high water mark!\n"));
-       }
-
-       /* Display next ids to allocate */
-
-       if (user_hwm != -1) {
-               DEBUG(DUMP_INFO,
-                     ("\tNext userid to allocate is %d\n", user_hwm));
-       }
-
-       if (group_hwm != -1) {
-               DEBUG(DUMP_INFO,
-                     ("\tNext groupid to allocate is %d\n", group_hwm));
-       }
-
-       /* Display percentage of id range already allocated. */
-
-       if (user_hwm != -1) {
-               int num_users = user_hwm - server_state.uid_low;
-               int total_users =
-                   server_state.uid_high - server_state.uid_low;
-
-               DEBUG(DUMP_INFO,
-                     ("\tUser id range is %d%% full (%d of %d)\n",
-                      num_users * 100 / total_users, num_users,
-                      total_users));
-       }
-
-       if (group_hwm != -1) {
-               int num_groups = group_hwm - server_state.gid_low;
-               int total_groups =
-                   server_state.gid_high - server_state.gid_low;
-
-               DEBUG(DUMP_INFO,
-                     ("\tGroup id range is %d%% full (%d of %d)\n",
-                      num_groups * 100 / total_groups, num_groups,
-                      total_groups));
-       }
-
-       /* Display complete mapping of users and groups to rids */
-}
-
-struct winbindd_idmap_methods tdb_idmap_methods = {
-       tdb_idmap_init,
-
-       tdb_get_sid_from_uid,
-       tdb_get_sid_from_gid,
-
-       tdb_get_uid_from_sid,
-       tdb_get_gid_from_sid,
-
-       tdb_idmap_close,
-
-       tdb_idmap_status
-};
-
-BOOL winbind_idmap_reg_tdb(struct winbindd_idmap_methods **meth)
-{
-       *meth = &tdb_idmap_methods;
-
-       return True;
-}
index 1ddfb2174ef1d861c0530ed539bd6ffcd26003bb..a2d9e82c7c7516ca56a2ea49ae69ca42a500df1a 100644 (file)
@@ -36,7 +36,7 @@
 
 /* Update this when you change the interface.  */
 
-#define WINBIND_INTERFACE_VERSION 7
+#define WINBIND_INTERFACE_VERSION 8
 
 /* Socket commands */
 
@@ -99,6 +99,16 @@ enum winbindd_cmd {
        WINBINDD_WINS_BYIP,
        WINBINDD_WINS_BYNAME,
 
+       /* account management commands */
+
+       WINBINDD_CREATE_USER,
+       WINBINDD_CREATE_GROUP,
+       WINBINDD_ADD_USER_TO_GROUP,
+       WINBINDD_REMOVE_USER_FROM_GROUP,
+       WINBINDD_SET_USER_PRIMARY_GROUP,
+       WINBINDD_DELETE_USER,
+       WINBINDD_DELETE_GROUP,
+       
        /* this is like GETGRENT but gives an empty group list */
        WINBINDD_GETGRLST,
 
@@ -111,6 +121,27 @@ enum winbindd_cmd {
        WINBINDD_NUM_CMDS
 };
 
+typedef struct winbindd_pw {
+       fstring pw_name;
+       fstring pw_passwd;
+       uid_t pw_uid;
+       gid_t pw_gid;
+       fstring pw_gecos;
+       fstring pw_dir;
+       fstring pw_shell;
+} WINBINDD_PW;
+
+
+typedef struct winbindd_gr {
+       fstring gr_name;
+       fstring gr_passwd;
+       gid_t gr_gid;
+       int num_gr_mem;
+       int gr_mem_ofs;   /* offset to group membership */
+       char **gr_mem;
+} WINBINDD_GR;
+
+
 #define WBFLAG_PAM_INFO3_NDR           0x0001
 #define WBFLAG_PAM_INFO3_TEXT          0x0002
 #define WBFLAG_PAM_NTKEY               0x0004
@@ -160,6 +191,10 @@ struct winbindd_request {
                        fstring name;       
                } name;
                uint32 num_entries;  /* getpwent, getgrent */
+               struct {
+                       fstring username;
+                       fstring groupname;
+               } acct_mgt;
        } data;
        char null_term;
 };
@@ -189,25 +224,11 @@ struct winbindd_response {
 
                /* getpwnam, getpwuid */
                
-               struct winbindd_pw {
-                       fstring pw_name;
-                       fstring pw_passwd;
-                       uid_t pw_uid;
-                       gid_t pw_gid;
-                       fstring pw_gecos;
-                       fstring pw_dir;
-                       fstring pw_shell;
-               } pw;
+               struct winbindd_pw pw;
 
                /* getgrnam, getgrgid */
 
-               struct winbindd_gr {
-                       fstring gr_name;
-                       fstring gr_passwd;
-                       gid_t gr_gid;
-                       int num_gr_mem;
-                       int gr_mem_ofs;   /* offset to group membership */
-               } gr;
+               struct winbindd_gr gr;
 
                uint32 num_entries; /* getpwent, getgrent */
                struct winbindd_sid {
index 6aaf3bc715074aed96894ecc01d0ff8d1e203c10..8df0f621c0fcf98816f2989e8d037cc5a3bfc401 100644 (file)
@@ -142,8 +142,8 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
 
        /* Parse domain and username */
        
-       if (!parse_domain_user(state->request.data.auth.user, name_domain, 
-                              name_user)) {
+       parse_domain_user(state->request.data.auth.user, name_domain, name_user);
+       if ( !name_domain ) {
                DEBUG(5,("no domain separator (%s) in username (%s) - failing auth\n", lp_winbind_separator(), state->request.data.auth.user));
                result = NT_STATUS_INVALID_PARAMETER;
                goto done;
@@ -444,8 +444,8 @@ enum winbindd_result winbindd_pam_chauthtok(struct winbindd_cli_state *state)
        if (state == NULL)
                return WINBINDD_ERROR;
 
-       if (!parse_domain_user(state->request.data.chauthtok.user, domain, 
-                              user)) {
+       parse_domain_user(state->request.data.chauthtok.user, domain, user);
+       if ( !*domain ) {
                result = NT_STATUS_INVALID_PARAMETER;
                goto done;
        }
diff --git a/source3/nsswitch/winbindd_passdb.c b/source3/nsswitch/winbindd_passdb.c
deleted file mode 100644 (file)
index 456b1af..0000000
+++ /dev/null
@@ -1,360 +0,0 @@
-/* 
-   Unix SMB/CIFS implementation.
-
-   Winbind rpc backend functions
-
-   Copyright (C) Tim Potter 2000-2001,2003
-   Copyright (C) Simo Sorce 2003
-   
-   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 "winbindd.h"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_WINBIND
-
-
-/* Query display info for a domain.  This returns enough information plus a
-   bit extra to give an overview of domain users for the User Manager
-   application. */
-static NTSTATUS query_user_list(struct winbindd_domain *domain,
-                              TALLOC_CTX *mem_ctx,
-                              uint32 *num_entries, 
-                              WINBIND_USERINFO **info)
-{
-       SAM_ACCOUNT *sam_account = NULL;
-       NTSTATUS result;
-       uint32 i;
-
-       DEBUG(3,("pdb: query_user_list\n"));
-
-       if (!NT_STATUS_IS_OK(result = pdb_init_sam(&sam_account))) {
-               return result;
-       }
-
-       i = 0;
-       *info = NULL;
-       
-       if (pdb_setsampwent(False)) {
-       
-               while (pdb_getsampwent(sam_account)) {
-               
-                       /* we return only nua accounts, or we will have duplicates */
-                       if (!idmap_check_sid_is_in_free_range(pdb_get_user_sid(sam_account))) {
-                               continue;
-                       }
-
-                       *info = talloc_realloc(mem_ctx, *info, (i + 1) * sizeof(WINBIND_USERINFO));
-                       if (!(*info)) {
-                               DEBUG(0,("query_user_list: out of memory!\n"));
-                               result = NT_STATUS_NO_MEMORY;
-                               break;
-                       }
-
-                       (*info)[i].user_sid = talloc(mem_ctx, sizeof(DOM_SID));
-                       (*info)[i].group_sid = talloc(mem_ctx, sizeof(DOM_SID));
-                       if (!((*info)[i].user_sid) || !((*info)[i].group_sid)) {
-                               DEBUG(0,("query_user_list: out of memory!\n"));
-                               result = NT_STATUS_NO_MEMORY;
-                               break;
-                       }
-                       sid_copy((*info)[i].user_sid, pdb_get_user_sid(sam_account));
-                       sid_copy((*info)[i].group_sid, pdb_get_group_sid(sam_account));
-
-                       (*info)[i].acct_name = talloc_strdup(mem_ctx, pdb_get_username(sam_account));
-                       (*info)[i].full_name = talloc_strdup(mem_ctx, pdb_get_fullname(sam_account));
-                       if (!((*info)[i].acct_name) || !((*info)[i].full_name)) {
-                               DEBUG(0,("query_user_list: out of memory!\n"));
-                               result = NT_STATUS_NO_MEMORY;
-                               break;
-                       }
-
-                       i++;
-
-                       if (!NT_STATUS_IS_OK(pdb_reset_sam(sam_account))) {
-                               result = NT_STATUS_UNSUCCESSFUL;
-                               break;
-                       }
-               }
-
-               *num_entries = i;
-               result = NT_STATUS_OK;
-       
-       } else {
-               result = NT_STATUS_UNSUCCESSFUL;
-       }
-
-       pdb_free_sam(&sam_account);
-       return result;
-}
-
-/* list all domain groups */
-static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
-                               TALLOC_CTX *mem_ctx,
-                               uint32 *num_entries, 
-                               struct acct_info **info)
-{
-       NTSTATUS result = NT_STATUS_OK;
-
-       DEBUG(3,("pdb: enum_dom_groups (group support not implemented)\n"));
-
-       *num_entries = 0;
-       *info = 0;
-
-       return result;  
-}
-
-/* List all domain groups */
-
-static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
-                               TALLOC_CTX *mem_ctx,
-                               uint32 *num_entries, 
-                               struct acct_info **info)
-{
-       NTSTATUS result = NT_STATUS_OK;
-
-       DEBUG(3,("pdb: enum_local_groups (group support not implemented)\n"));
-
-       *num_entries = 0;
-       *info = 0;
-
-       return result;  
-}
-
-/* convert a single name to a sid in a domain */
-static NTSTATUS name_to_sid(struct winbindd_domain *domain,
-                           TALLOC_CTX *mem_ctx,
-                           const char *name,
-                           DOM_SID *sid,
-                           enum SID_NAME_USE *type)
-{
-       SAM_ACCOUNT *sam_account = NULL;
-       NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
-
-       DEBUG(3,("pdb: name_to_sid name=%s (group support not implemented)\n", name));
-
-       if (NT_STATUS_IS_OK(pdb_init_sam(&sam_account))) {
-               if (!pdb_getsampwnam(sam_account, name)) {
-                       result = NT_STATUS_UNSUCCESSFUL;
-               } else { /* it is a sam user */
-                       sid_copy(sid, pdb_get_user_sid(sam_account));
-                       *type = SID_NAME_USER;
-                       result = NT_STATUS_OK;
-               }
-       }
-
-       pdb_free_sam(&sam_account);
-       return result;  
-}
-
-/*
-  convert a domain SID to a user or group name
-*/
-static NTSTATUS sid_to_name(struct winbindd_domain *domain,
-                           TALLOC_CTX *mem_ctx,
-                           DOM_SID *sid,
-                           char **name,
-                           enum SID_NAME_USE *type)
-{
-       SAM_ACCOUNT *sam_account = NULL;
-       NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
-       uint32 id;
-
-       DEBUG(3,("pdb: sid_to_name sid=%s\n", sid_string_static(sid)));
-
-       if (NT_STATUS_IS_OK(idmap_sid_to_uid(sid, &id, 0))) { /* this is a user */
-
-               if (!NT_STATUS_IS_OK(result = pdb_init_sam(&sam_account))) {
-                       return result;
-               }
-       
-               if (!pdb_getsampwsid(sam_account, sid)) {
-                       pdb_free_sam(&sam_account);
-                       return NT_STATUS_UNSUCCESSFUL;
-               }
-       
-               *name = talloc_strdup(mem_ctx, pdb_get_username(sam_account));  
-               if (!(*name)) {
-                       DEBUG(0,("query_user: out of memory!\n"));
-                       pdb_free_sam(&sam_account);
-                       return NT_STATUS_NO_MEMORY;
-               }
-
-               pdb_free_sam(&sam_account);
-               *type = SID_NAME_USER;
-               result = NT_STATUS_OK;
-
-       } else if (NT_STATUS_IS_OK(idmap_sid_to_gid(sid, &id, 0))) { /* this is a group */
-               
-               DEBUG(3,("pdb: sid_to_name: group support not implemented\n"));
-               result = NT_STATUS_UNSUCCESSFUL;
-       }
-
-       return result;
-}
-
-/* Lookup user information from a rid or username. */
-static NTSTATUS query_user(struct winbindd_domain *domain, 
-                          TALLOC_CTX *mem_ctx, 
-                          DOM_SID *user_sid, 
-                          WINBIND_USERINFO *user_info)
-{
-       SAM_ACCOUNT *sam_account = NULL;
-       NTSTATUS result;
-
-       DEBUG(3,("pdb: query_user sid=%s\n", sid_string_static(user_sid)));
-
-       if (!NT_STATUS_IS_OK(result = pdb_init_sam(&sam_account))) {
-               return result;
-       }
-       
-       if (!pdb_getsampwsid(sam_account, user_sid)) {
-               pdb_free_sam(&sam_account);
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-
-       /* we return only nua accounts, or we will have duplicates */
-       if (!idmap_check_sid_is_in_free_range(user_sid)) {
-               pdb_free_sam(&sam_account);
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-
-       user_info->user_sid = talloc(mem_ctx, sizeof(DOM_SID));
-       user_info->group_sid = talloc(mem_ctx, sizeof(DOM_SID));
-       if (!(user_info->user_sid) || !(user_info->group_sid)) {
-               DEBUG(0,("query_user: out of memory!\n"));
-               pdb_free_sam(&sam_account);
-               return NT_STATUS_NO_MEMORY;
-       }
-       sid_copy(user_info->user_sid, pdb_get_user_sid(sam_account));
-       sid_copy(user_info->group_sid, pdb_get_group_sid(sam_account));
-
-       user_info->acct_name = talloc_strdup(mem_ctx, pdb_get_username(sam_account));
-       user_info->full_name = talloc_strdup(mem_ctx, pdb_get_fullname(sam_account));
-       if (!(user_info->acct_name) || !(user_info->full_name)) {
-               DEBUG(0,("query_user: out of memory!\n"));
-               pdb_free_sam(&sam_account);
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       pdb_free_sam(&sam_account);
-       return NT_STATUS_OK;
-}                                   
-
-/* Lookup groups a user is a member of.  I wish Unix had a call like this! */
-static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
-                                 TALLOC_CTX *mem_ctx,
-                                 DOM_SID *user_sid,
-                                 uint32 *num_groups, DOM_SID ***user_gids)
-{
-       NTSTATUS result = NT_STATUS_OK;
-
-       DEBUG(3,("pdb: lookup_usergroups (group support not implemented)\n"));
-
-       num_groups = 0;
-       user_gids = 0;
-
-       return result;
-}
-
-
-/* Lookup group membership given a rid.   */
-static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
-                               TALLOC_CTX *mem_ctx,
-                               DOM_SID *group_sid, uint32 *num_names, 
-                               DOM_SID ***sid_mem, char ***names, 
-                               uint32 **name_types)
-{
-        NTSTATUS result = NT_STATUS_NOT_IMPLEMENTED;
-
-       DEBUG(3,("pdb: lookup_groupmem (group support not implemented)\n"));
-
-       num_names = 0;
-       sid_mem = 0;
-       names = 0;
-       name_types = 0;
-
-        return result;
-}
-
-/* find the sequence number for a domain */
-static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
-{
-       /* FIXME: we fake up the seq_num untill our passdb support it */
-       static uint32 seq_num;
-
-       DEBUG(3,("pdb: sequence_number\n"));
-
-       *seq = seq_num++;
-
-       return NT_STATUS_OK;
-}
-
-/* get a list of trusted domains */
-static NTSTATUS trusted_domains(struct winbindd_domain *domain,
-                               TALLOC_CTX *mem_ctx,
-                               uint32 *num_domains,
-                               char ***names,
-                               char ***alt_names,
-                               DOM_SID **dom_sids)
-{
-       NTSTATUS result = NT_STATUS_NOT_IMPLEMENTED;
-
-       DEBUG(3,("pdb: trusted_domains (todo!)\n"));
-
-       return result;
-}
-
-/* find the domain sid for a domain */
-static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
-{
-       DEBUG(3,("pdb: domain_sid\n"));
-
-       if (strcmp(domain->name, lp_workgroup())) {
-               return NT_STATUS_INVALID_PARAMETER;
-       } else {
-               sid_copy(sid, get_global_sam_sid());
-               return NT_STATUS_OK;
-       }
-}
-
-/* find alternate names list for the domain 
- * should we look for netbios aliases?? 
-                               SSS     */
-static NTSTATUS alternate_name(struct winbindd_domain *domain)
-{
-       DEBUG(3,("pdb: alternate_name\n"));
-
-       return NT_STATUS_OK;
-}
-
-
-/* the rpc backend methods are exposed via this structure */
-struct winbindd_methods passdb_methods = {
-       False,
-       query_user_list,
-       enum_dom_groups,
-       enum_local_groups,
-       name_to_sid,
-       sid_to_name,
-       query_user,
-       lookup_usergroups,
-       lookup_groupmem,
-       sequence_number,
-       trusted_domains,
-       domain_sid,
-       alternate_name
-};
index 37d92450759abf73e1bc42e945cbf7a5191975d4..7c95ba847050efdf66104840f50778a736b8fe92 100644 (file)
@@ -97,6 +97,7 @@ static BOOL winbindd_fill_pwent(char *dom_name, char *user_name,
 enum winbindd_result winbindd_getpwnam(struct winbindd_cli_state *state) 
 {
        WINBIND_USERINFO user_info;
+       WINBINDD_PW *pw;
        DOM_SID user_sid;
        NTSTATUS status;
        fstring name_domain, name_user;
@@ -112,16 +113,25 @@ enum winbindd_result winbindd_getpwnam(struct winbindd_cli_state *state)
        
        /* Parse domain and username */
 
-       if (!parse_domain_user(state->request.data.username, name_domain, 
-                              name_user))
-               return WINBINDD_ERROR;
+       parse_domain_user(state->request.data.username, 
+               name_domain, name_user);
+       
+       /* if this is our local domain (or no domain), the do a local tdb search */
        
-       /* don't handle our own domain if we are a DC ( or a member of a Samba domain 
-          that shares UNIX accounts).  This code handles cases where
-          the account doesn't exist anywhere and gets passed on down the NSS layer */
+       if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) {
+               if ( !(pw = wb_getpwnam(name_user)) ) {
+                       DEBUG(5,("winbindd_getpwnam: lookup for %s\\%s failed\n",
+                               name_domain, name_user));
+                       return WINBINDD_ERROR;
+               }
+               memcpy( &state->response.data.pw, pw, sizeof(WINBINDD_PW) );
+               return WINBINDD_OK;
+       }
 
-       if ( (IS_DC || lp_winbind_trusted_domains_only()) && strequal(name_domain, lp_workgroup()) ) {
-               DEBUG(7,("winbindd_getpwnam: rejecting getpwnam() for %s\\%s since I am on the PDC for this domain\n", 
+       /* should we deal with users for our domain? */
+       
+       if ( lp_winbind_trusted_domains_only() && strequal(name_domain, lp_workgroup())) {
+               DEBUG(7,("winbindd_getpenam: My domain -- rejecting getpwnam() for %s\\%s.\n", 
                        name_domain, name_user));
                return WINBINDD_ERROR;
        }       
@@ -184,6 +194,7 @@ enum winbindd_result winbindd_getpwuid(struct winbindd_cli_state *state)
 {
        DOM_SID user_sid;
        struct winbindd_domain *domain;
+       WINBINDD_PW *pw;
        fstring dom_name;
        fstring user_name;
        enum SID_NAME_USE name_type;
@@ -200,6 +211,13 @@ enum winbindd_result winbindd_getpwuid(struct winbindd_cli_state *state)
 
        DEBUG(3, ("[%5d]: getpwuid %d\n", state->pid, 
                  state->request.data.uid));
+
+       /* always try local tdb first */
+       
+       if ( (pw = wb_getpwuid(state->request.data.uid)) != NULL ) {
+               memcpy( &state->response.data.pw, pw, sizeof(WINBINDD_PW) );
+               return WINBINDD_OK;
+       }
        
        /* Get rid from uid */
 
index 28da415b9c3a7be91681835eb52ecb75802107c7..1f123e896fe92fa2899247cd72f358e045131d00 100644 (file)
@@ -415,18 +415,22 @@ BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
 {
        char *p = strchr(domuser,*lp_winbind_separator());
 
-       if (!(p || lp_winbind_use_default_domain()))
-               return False;
-       
-       if(!p && lp_winbind_use_default_domain()) {
+       if ( !p ) {
                fstrcpy(user, domuser);
-               fstrcpy(domain, lp_workgroup());
-       } else {
+               
+               if ( lp_winbind_use_default_domain() )
+                       fstrcpy(domain, lp_workgroup());
+               else
+                       fstrcpy( domain, "" );
+       } 
+       else {
                fstrcpy(user, p+1);
                fstrcpy(domain, domuser);
                domain[PTR_DIFF(p, domuser)] = 0;
        }
+       
        strupper_m(domain);
+       
        return True;
 }
 
index e7adce7193fd755c4252c640f8ad162f8c456910..9194274a617514a565c6c4997263fd1f0aca7182 100644 (file)
@@ -165,9 +165,11 @@ typedef struct
        char *szIdmapGID;
        BOOL bEnableRidAlgorithm;
        int AlgorithmicRidBase;
+       char *szTemplatePrimaryGroup;
        char *szTemplateHomedir;
        char *szTemplateShell;
        char *szWinbindSeparator;
+       BOOL bWinbindEnableLocalAccounts;
        BOOL bWinbindEnumUsers;
        BOOL bWinbindEnumGroups;
        BOOL bWinbindUseDefaultDomain;
@@ -1123,10 +1125,12 @@ static struct parm_struct parm_table[] = {
        {"winbind uid", P_STRING, P_GLOBAL, &Globals.szIdmapUID, handle_idmap_uid, NULL, FLAG_ADVANCED | FLAG_DEVELOPER },
        {"idmap gid", P_STRING, P_GLOBAL, &Globals.szIdmapGID, handle_idmap_gid, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
        {"winbind gid", P_STRING, P_GLOBAL, &Globals.szIdmapGID, handle_idmap_gid, NULL, FLAG_ADVANCED | FLAG_DEVELOPER },
+       {"template primary group", P_STRING, P_GLOBAL, &Globals.szTemplatePrimaryGroup, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
        {"template homedir", P_STRING, P_GLOBAL, &Globals.szTemplateHomedir, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
        {"template shell", P_STRING, P_GLOBAL, &Globals.szTemplateShell, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
        {"winbind separator", P_STRING, P_GLOBAL, &Globals.szWinbindSeparator, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
        {"winbind cache time", P_INTEGER, P_GLOBAL, &Globals.winbind_cache_time, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
+       {"winbind enable local accounts", P_BOOL, P_GLOBAL, &Globals.bWinbindEnableLocalAccounts, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
        {"winbind enum users", P_BOOL, P_GLOBAL, &Globals.bWinbindEnumUsers, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
        {"winbind enum groups", P_BOOL, P_GLOBAL, &Globals.bWinbindEnumGroups, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
        {"winbind use default domain", P_BOOL, P_GLOBAL, &Globals.bWinbindUseDefaultDomain, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
@@ -1465,10 +1469,12 @@ static void init_globals(void)
 
        string_set(&Globals.szTemplateShell, "/bin/false");
        string_set(&Globals.szTemplateHomedir, "/home/%D/%U");
+       string_set(&Globals.szTemplatePrimaryGroup, "nobody");
        string_set(&Globals.szWinbindSeparator, "\\");
        string_set(&Globals.szAclCompat, "");
 
        Globals.winbind_cache_time = 300;       /* 5 minutes */
+       Globals.bWinbindEnableLocalAccounts = True;
        Globals.bWinbindEnumUsers = True;
        Globals.bWinbindEnumGroups = True;
        Globals.bWinbindUseDefaultDomain = False;
@@ -1632,10 +1638,12 @@ FN_GLOBAL_STRING(lp_abort_shutdown_script, &Globals.szAbortShutdownScript)
 
 FN_GLOBAL_STRING(lp_wins_hook, &Globals.szWINSHook)
 FN_GLOBAL_STRING(lp_wins_partners, &Globals.szWINSPartners)
+FN_GLOBAL_STRING(lp_template_primary_group, &Globals.szTemplatePrimaryGroup)
 FN_GLOBAL_STRING(lp_template_homedir, &Globals.szTemplateHomedir)
 FN_GLOBAL_STRING(lp_template_shell, &Globals.szTemplateShell)
 FN_GLOBAL_CONST_STRING(lp_winbind_separator, &Globals.szWinbindSeparator)
 FN_GLOBAL_STRING(lp_acl_compatibility, &Globals.szAclCompat)
+FN_GLOBAL_BOOL(lp_winbind_enable_local_accounts, &Globals.bWinbindEnableLocalAccounts)
 FN_GLOBAL_BOOL(lp_winbind_enum_users, &Globals.bWinbindEnumUsers)
 FN_GLOBAL_BOOL(lp_winbind_enum_groups, &Globals.bWinbindEnumGroups)
 FN_GLOBAL_BOOL(lp_winbind_use_default_domain, &Globals.bWinbindUseDefaultDomain)
index e43cf4f759780d37012d2e5a5bc5de0ee1b5a208..dfa3a8b62e096d88bd05d8a6a325f7423857a884 100644 (file)
@@ -2259,17 +2259,13 @@ NTSTATUS _api_samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_
         */
 
        DEBUG(10,("checking account %s at pos %d for $ termination\n",account, strlen(account)-1));
-#if 0
-       if ((acb_info & ACB_WSTRUST) && (account[strlen(account)-1] == '$')) {
-               pstrcpy(add_script, lp_addmachine_script());            
-       } else if ((!(acb_info & ACB_WSTRUST)) && (account[strlen(account)-1] != '$')) {
-               pstrcpy(add_script, lp_adduser_script());
-       } else {
-               DEBUG(0, ("_api_samr_create_user: mismatch between trust flags and $ termination\n"));
-               pdb_free_sam(&sam_pass);
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-#endif
+       
+       /* 
+        * we used to have code here that made sure the acb_info flags 
+        * matched with the users named (e.g. an account flags as a machine 
+        * trust account ended in '$').  It has been ifdef'd out for a long 
+        * time, so I replaced it with this comment.     --jerry
+        */
 
        /* the passdb lookup has failed; check to see if we need to run the
           add user/machine script */
@@ -2295,11 +2291,17 @@ NTSTATUS _api_samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_
                        add_ret = smbrun(add_script,NULL);
                        DEBUG(3,("_api_samr_create_user: Running the command `%s' gave %d\n", add_script, add_ret));
                }
+               else    /* no add user script -- ask winbindd to do it */
+               {
+                       if ( !winbind_create_user( account ) )
+                               DEBUG(3,("_api_samr_create_user: winbind_create_user(%s) failed\n", account));
+               }
                
        }
        
-       nt_status = pdb_init_sam_new(&sam_pass, account);
-       if (!NT_STATUS_IS_OK(nt_status))
+       /* implicit call to getpwnam() next */
+
+       if ( !NT_STATUS_IS_OK(nt_status = pdb_init_sam_new(&sam_pass, account)) )
                return nt_status;
                
        pdb_set_acct_ctrl(sam_pass, acb_info, PDB_CHANGED);
index a8c47ab9ae5e9aa52d5d62a31b40fce90c6c6474..1db89eba24fef79a95bd82c0aa78159842637954 100644 (file)
@@ -251,6 +251,21 @@ NTSTATUS idmap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
        return ret;
 }
 
+/**************************************************************************
+ Get ID from SID. This can create a mapping for a SID to a POSIX id.
+**************************************************************************/
+
+NTSTATUS idmap_allocate_id(unid_t *id, int id_type)
+{
+       /* we have to allocate from the authoritative backend */
+       
+       if ( remote_map )
+               return remote_map->allocate_id( id, id_type );
+
+       return cache_map->allocate_id( id, id_type );
+}
+
+
 /**************************************************************************
  Shutdown maps.
 **************************************************************************/
index d0010d8cd94b31ea5ec2c7e221017d32f34c6386..2901b1fc4995b419a64f05f99dc143d315ce0a75 100644 (file)
@@ -675,6 +675,7 @@ static void ldap_idmap_status(void)
 
 static struct idmap_methods ldap_methods = {
        ldap_idmap_init,
+       ldap_allocate_id,
        ldap_get_sid_from_id,
        ldap_get_id_from_sid,
        ldap_set_mapping,
index 18a082cb848510b28a08614339ac34d04726df11..4643b7db59d01b2987383889958d991e15d01151 100644 (file)
@@ -45,6 +45,20 @@ static struct idmap_state {
        gid_t gid_low, gid_high;               /* Range of gids to allocate */
 } idmap_state;
 
+/**********************************************************************
+ Return the TDB_CONTEXT* for winbindd_idmap.  I **really** feel
+ dirty doing this, but not so dirty that I want to create another 
+ tdb
+***********************************************************************/
+
+TDB_CONTEXT *idmap_tdb_handle( void )
+{
+       if ( idmap_tdb )
+               return idmap_tdb;
+       
+       return NULL;
+}
+
 /* Allocate either a user or group id from the pool */
 static NTSTATUS db_allocate_id(unid_t *id, int id_type)
 {
@@ -111,7 +125,7 @@ static NTSTATUS db_allocate_id(unid_t *id, int id_type)
                        }
                        
                        (*id).gid = hwm;
-                       DEBUG(10,("db_allocate_id: ID_GROUPID (*id).uid = %d\n", (unsigned int)hwm));
+                       DEBUG(10,("db_allocate_id: ID_GROUPID (*id).gid = %d\n", (unsigned int)hwm));
                        
                        break;
                default:
@@ -595,6 +609,7 @@ static void db_idmap_status(void)
 static struct idmap_methods db_methods = {
 
        db_idmap_init,
+       db_allocate_id,
        db_get_sid_from_id,
        db_get_id_from_sid,
        db_set_mapping,
index 194a373caa1db5e24096d08dad05d69d5b8c3253..e91b42a73ae05188a22e00d38ba24f13fddbb620 100644 (file)
@@ -146,6 +146,10 @@ END {
     gotstart = 1;
   }
 
+  if( $0 ~ /^WINBINDD_PW|^WINBINDD_GR/ ) {
+    gotstart = 1;
+  }
+
   if(!gotstart) {
     next;
   }
index 6ca2aa336d3abd1177c904822c9045f7a4e508fa..8d8ce136a9498e97adb7d608cd49664e3dfc2e9f 100644 (file)
@@ -809,17 +809,28 @@ NTSTATUS sid_to_uid(const DOM_SID *psid, uid_t *puid)
        if (fetch_uid_from_cache(puid, psid))
                return NT_STATUS_OK;
 
-       /*
-        * First we must look up the name and decide if this is a user sid.
-        */
+       /* if this is our DIS then go straight to a local lookup */
+       
+       if ( sid_compare_domain(get_global_sam_sid(), psid) == 0 ) {
+               DEBUG(10,("sid_to_uid: my domain (%s) - trying local.\n",
+                       sid_string_static(psid) ));
+               
+               if ( (ret = local_sid_to_uid(puid, psid, &name_type)) == True )
+                       store_uid_sid_cache(psid, *puid);
+               
+               return (ret ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL);
+       }
+       
+
+       /* look up the name and decide if this is a user sid */
 
        if ( (!winbind_lookup_sid(psid, dom_name, name, &name_type)) || (name_type != SID_NAME_USER) ) {
                DEBUG(10,("sid_to_uid: winbind lookup for sid %s failed - trying local.\n",
-                       sid_to_string(sid_str, psid) ));
+                       sid_string_static(psid) ));
 
-               ret = local_sid_to_uid(puid, psid, &name_type);
-               if (ret)
+               if ( (ret = local_sid_to_uid(puid, psid, &name_type)) == True )
                        store_uid_sid_cache(psid, *puid);
+
                return (ret ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL);
        }
 
index 2831645550557bd7990d8550f06581b5223af6fc..4b31c061f393c60be14fe9bb6f2516cfef533017 100644 (file)
@@ -441,10 +441,17 @@ fetch_account_info(uint32 rid, SAM_ACCOUNT_INFO *delta)
                        add_ret = smbrun(add_script,NULL);
                        DEBUG(1,("fetch_account: Running the command `%s' "
                                 "gave %d\n", add_script, add_ret));
-
-                       /* try and find the possible unix account again */
-                       passwd = Get_Pwnam(account);
                }
+               else {
+                       DEBUG(8,("fetch_account_info: no add user/machine script.  Asking winbindd\n"));
+                       if ( !winbind_create_user( account ) )
+                               DEBUG(4,("fetch_account_info: winbind_create_user() failed\n"));
+               }
+               
+               /* try and find the possible unix account again */
+               if ( !(passwd = Get_Pwnam(account)) )
+                       return NT_STATUS_NO_SUCH_USER;
+                       
        }
        
        sid_copy(&user_sid, get_global_sam_sid());
@@ -912,7 +919,7 @@ fetch_sam_entry(SAM_DELTA_HDR *hdr_delta, SAM_DELTA_CTR *delta,
                                &delta->als_mem_info, dom_sid);
                break;
        case SAM_DELTA_DOMAIN_INFO:
-               d_printf("SAMBA_DELTA_DOMAIN_INFO not handled\n");
+               d_printf("SAM_DELTA_DOMAIN_INFO not handled\n");
                break;
        default:
                d_printf("Unknown delta record type %d\n", hdr_delta->type);