1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-01 05:47:28 +03:00

Large set of changes to add UNIX account/group management

to winbindd.  See README.idmap-and-winbind-changes for details.
(This used to be commit 1111bc7b0c7165e1cdf8d90eb49f4c368d2eded6)
This commit is contained in:
Gerald Carter 2003-07-09 16:44:47 +00:00
parent 816724fb39
commit 16ff7b26f6
26 changed files with 1729 additions and 1146 deletions

View File

@ -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.

View 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

View 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) \

View 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"));
}
}

View 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;
/* 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;
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);
*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;
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;
}

View 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);

View 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;
}

View 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;

View 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" }

View File

@ -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;
}

View File

@ -27,6 +27,34 @@
#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);
/* 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 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) );
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",
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;
}
/* 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 */

View File

@ -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()));
}
}

View File

@ -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;
}

View 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 {

View 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;
}

View File

@ -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
};

View 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);
/* 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 this is our local domain (or no domain), the do a local tdb search */
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 */

View 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;
}

View 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)

View 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);

View 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.
**************************************************************************/

View 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,

View 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,

View File

@ -146,6 +146,10 @@ END {
gotstart = 1;
}
if( $0 ~ /^WINBINDD_PW|^WINBINDD_GR/ ) {
gotstart = 1;
}
if(!gotstart) {
next;
}

View 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);
}

View 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);