summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2002-08-20 01:54:28 +0000
committerAndrew Bartlett <abartlet@samba.org>2002-08-20 01:54:28 +0000
commit8674440d81f703cb59979426c92ed54de8e5f2ed (patch)
tree033da6bfa721b02c1a087ee478d3593997f30e2a /source3/smbd
parent03615599919f94c5ed56e9824343b02f4f3e0b71 (diff)
downloadsamba-8674440d81f703cb59979426c92ed54de8e5f2ed.tar.gz
samba-8674440d81f703cb59979426c92ed54de8e5f2ed.tar.bz2
samba-8674440d81f703cb59979426c92ed54de8e5f2ed.zip
Based orginally by work by Kai, this patch moves our NT_TOKEN generation into
our authenticaion code - removing some of the duplication from the current code. This also gets us *much* closer to supporting a real SAM backend, becouse the SAM can give us the right info then. This also changes our service.c code, so that we do a VUID (rather than uid) cache on the connection struct, and do full NT ACL/NT_TOKEN checks (or cached equivilant) on every packet, for the same r or rw mode the whole share was open for. Andrew Bartlett (This used to be commit d8122cee059fc7098bfa7e42e638a9958b3ac902)
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/conn.c24
-rw-r--r--source3/smbd/password.c156
-rw-r--r--source3/smbd/service.c35
-rw-r--r--source3/smbd/sesssetup.c4
-rw-r--r--source3/smbd/uid.c38
5 files changed, 101 insertions, 156 deletions
diff --git a/source3/smbd/conn.c b/source3/smbd/conn.c
index d70e50f899..22407348e8 100644
--- a/source3/smbd/conn.c
+++ b/source3/smbd/conn.c
@@ -131,7 +131,7 @@ void conn_close_all(void)
connection_struct *conn, *next;
for (conn=Connections;conn;conn=next) {
next=conn->next;
- close_cnum(conn, (uint16)-1);
+ close_cnum(conn, conn->vuid);
}
}
@@ -158,6 +158,27 @@ BOOL conn_idle_all(time_t t, int deadtime)
}
/****************************************************************************
+clear a vuid out of the validity cache, and as the 'owner' of a connection.
+****************************************************************************/
+void conn_clear_vuid_cache(uint16 vuid)
+{
+ connection_struct *conn;
+ int i;
+
+ for (conn=Connections;conn;conn=conn->next) {
+ if (conn->vuid == vuid) {
+ conn->vuid = UID_FIELD_INVALID;
+ }
+
+ for (i=0;i<conn->vuid_cache.entries && i< VUID_CACHE_SIZE;i++) {
+ if (conn->vuid_cache.list[i] == vuid) {
+ conn->vuid_cache.list[i] = UID_FIELD_INVALID;
+ }
+ }
+ }
+}
+
+/****************************************************************************
Free a conn structure.
****************************************************************************/
@@ -191,7 +212,6 @@ void conn_free(connection_struct *conn)
conn->ngroups = 0;
}
- delete_nt_token(&conn->nt_user_token);
free_namearray(conn->veto_list);
free_namearray(conn->hide_list);
free_namearray(conn->veto_oplock_list);
diff --git a/source3/smbd/password.c b/source3/smbd/password.c
index cfac7cf695..f3a09e8c64 100644
--- a/source3/smbd/password.c
+++ b/source3/smbd/password.c
@@ -69,6 +69,10 @@ void invalidate_vuid(uint16 vuid)
DLIST_REMOVE(validated_users, vuser);
+ /* clear the vuid from the 'cache' on each connection, and
+ from the vuid 'owner' of connections */
+ conn_clear_vuid_cache(vuid);
+
SAFE_FREE(vuser->groups);
delete_nt_token(&vuser->nt_user_token);
SAFE_FREE(vuser);
@@ -90,95 +94,6 @@ void invalidate_all_vuids(void)
}
/****************************************************************************
- Create the SID list for this user.
-****************************************************************************/
-
-NT_USER_TOKEN *create_nt_token(uid_t uid, gid_t gid, int ngroups, gid_t *groups, BOOL is_guest, NT_USER_TOKEN *sup_tok)
-{
- extern DOM_SID global_sid_World;
- extern DOM_SID global_sid_Network;
- extern DOM_SID global_sid_Builtin_Guests;
- extern DOM_SID global_sid_Authenticated_Users;
- NT_USER_TOKEN *token;
- DOM_SID *psids;
- int i, psid_ndx = 0;
- size_t num_sids = 0;
- fstring sid_str;
-
- if ((token = (NT_USER_TOKEN *)malloc( sizeof(NT_USER_TOKEN) ) ) == NULL)
- return NULL;
-
- ZERO_STRUCTP(token);
-
- /* We always have uid/gid plus World and Network and Authenticated Users or Guest SIDs. */
- num_sids = 5 + ngroups;
-
- if (sup_tok && sup_tok->num_sids)
- num_sids += sup_tok->num_sids;
-
- if ((token->user_sids = (DOM_SID *)malloc( num_sids*sizeof(DOM_SID))) == NULL) {
- SAFE_FREE(token);
- return NULL;
- }
-
- psids = token->user_sids;
-
- /*
- * Note - user SID *MUST* be first in token !
- * se_access_check depends on this.
- */
-
- uid_to_sid( &psids[PRIMARY_USER_SID_INDEX], uid);
- psid_ndx++;
-
- /*
- * Primary group SID is second in token. Convention.
- */
-
- gid_to_sid( &psids[PRIMARY_GROUP_SID_INDEX], gid);
- psid_ndx++;
-
- /* Now add the group SIDs. */
-
- for (i = 0; i < ngroups; i++) {
- if (groups[i] != gid) {
- gid_to_sid( &psids[psid_ndx++], groups[i]);
- }
- }
-
- if (sup_tok) {
- /* Now add the additional SIDs from the supplimentary token. */
- for (i = 0; i < sup_tok->num_sids; i++)
- sid_copy( &psids[psid_ndx++], &sup_tok->user_sids[i] );
- }
-
- /*
- * Finally add the "standard" SIDs.
- * The only difference between guest and "anonymous" (which we
- * don't really support) is the addition of Authenticated_Users.
- */
-
- sid_copy( &psids[psid_ndx++], &global_sid_World);
- sid_copy( &psids[psid_ndx++], &global_sid_Network);
-
- if (is_guest)
- sid_copy( &psids[psid_ndx++], &global_sid_Builtin_Guests);
- else
- sid_copy( &psids[psid_ndx++], &global_sid_Authenticated_Users);
-
- token->num_sids = psid_ndx;
-
- /* Dump list of sids in token */
-
- for (i = 0; i < token->num_sids; i++) {
- DEBUG(5, ("user token sid %s\n",
- sid_to_string(sid_str, &token->user_sids[i])));
- }
-
- return token;
-}
-
-/****************************************************************************
register a uid/name pair as being valid and that a valid password
has been given. vuid is biased by an offset. This allows us to
tell random client vuid's (normally zero) from valid vuids.
@@ -187,8 +102,6 @@ tell random client vuid's (normally zero) from valid vuids.
int register_vuid(auth_serversupplied_info *server_info, const char *smb_name)
{
user_struct *vuser = NULL;
- uid_t uid;
- gid_t gid;
/* Ensure no vuid gets registered in share level security. */
if(lp_security() == SEC_SHARE)
@@ -205,15 +118,6 @@ int register_vuid(auth_serversupplied_info *server_info, const char *smb_name)
ZERO_STRUCTP(vuser);
- if (!IS_SAM_UNIX_USER(server_info->sam_account)) {
- DEBUG(0,("Attempted session setup with invalid user. No uid/gid in SAM_ACCOUNT (flags:%x)\n", pdb_get_init_flag(server_info->sam_account)));
- free(vuser);
- return UID_FIELD_INVALID;
- }
-
- uid = pdb_get_uid(server_info->sam_account);
- gid = pdb_get_gid(server_info->sam_account);
-
/* Allocate a free vuid. Yes this is a linear search... :-) */
while( get_valid_user_struct(next_vuid) != NULL ) {
next_vuid++;
@@ -225,18 +129,38 @@ int register_vuid(auth_serversupplied_info *server_info, const char *smb_name)
DEBUG(10,("register_vuid: allocated vuid = %u\n", (unsigned int)next_vuid ));
vuser->vuid = next_vuid;
- vuser->uid = uid;
- vuser->gid = gid;
+
+ /* the next functions should be done by a SID mapping system (SMS) as
+ * the new real sam db won't have reference to unix uids or gids
+ */
+ if (!IS_SAM_UNIX_USER(server_info->sam_account)) {
+ DEBUG(0,("Attempted session setup with invalid user. No uid/gid in SAM_ACCOUNT (flags:%x)\n", pdb_get_init_flag(server_info->sam_account)));
+ free(vuser);
+ return UID_FIELD_INVALID;
+ }
+
+ vuser->uid = pdb_get_uid(server_info->sam_account);
+ vuser->gid = pdb_get_gid(server_info->sam_account);
+
+ vuser->n_groups = server_info->n_groups;
+ if (vuser->n_groups) {
+ if (!(vuser->groups = memdup(server_info->groups, sizeof(gid_t) * vuser->n_groups))) {
+ DEBUG(0,("register_vuid: failed to memdup vuser->groups\n"));
+ free(vuser);
+ return UID_FIELD_INVALID;
+ }
+ }
+
vuser->guest = server_info->guest;
- fstrcpy(vuser->user.unix_name, pdb_get_username(server_info->sam_account));
- fstrcpy(vuser->user.smb_name, smb_name);
+ fstrcpy(vuser->user.unix_name, pdb_get_username(server_info->sam_account));
+ fstrcpy(vuser->user.smb_name, smb_name);
fstrcpy(vuser->user.domain, pdb_get_domain(server_info->sam_account));
fstrcpy(vuser->user.full_name, pdb_get_fullname(server_info->sam_account));
{
/* Keep the homedir handy */
const char *homedir = pdb_get_homedir(server_info->sam_account);
- const char *unix_homedir = pdb_get_unix_homedir(server_info->sam_account);
+ const char *unix_homedir = pdb_get_unix_homedir(server_info->sam_account); /* should be optained by SMS */
const char *logon_script = pdb_get_logon_script(server_info->sam_account);
if (homedir) {
vuser->homedir = smb_xstrdup(homedir);
@@ -260,19 +184,13 @@ int register_vuid(auth_serversupplied_info *server_info, const char *smb_name)
DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->user.unix_name,vuser->user.full_name));
- vuser->n_groups = 0;
- vuser->groups = NULL;
-
- /* Find all the groups this uid is in and store them.
- Used by change_to_user() */
- initialise_groups(vuser->user.unix_name, vuser->uid, vuser->gid);
- get_current_groups(vuser->gid, &vuser->n_groups, &vuser->groups);
-
- if (server_info->ptok)
- add_supplementary_nt_login_groups(&vuser->n_groups, &vuser->groups, &server_info->ptok);
-
- /* Create an NT_USER_TOKEN struct for this user. */
- vuser->nt_user_token = create_nt_token(vuser->uid, vuser->gid, vuser->n_groups, vuser->groups, vuser->guest, server_info->ptok);
+ if (server_info->ptok) {
+ vuser->nt_user_token = dup_nt_token(server_info->ptok);
+ } else {
+ DEBUG(1, ("server_info does not contain a user_token - cannot continue\n"));
+ free(vuser);
+ return UID_FIELD_INVALID;
+ }
DEBUG(3,("UNIX uid %d is UNIX user %s, and will be vuid %u\n",(int)vuser->uid,vuser->user.unix_name, vuser->vuid));
@@ -451,7 +369,7 @@ static char *validate_group(char *group, DATA_BLOB password,int snum)
Note this is *NOT* used when logging on using sessionsetup_and_X.
****************************************************************************/
-BOOL authorise_login(int snum,char *user, DATA_BLOB password,
+BOOL authorise_login(int snum, fstring user, DATA_BLOB password,
BOOL *guest)
{
BOOL ok = False;
diff --git a/source3/smbd/service.c b/source3/smbd/service.c
index 6f83a2d3b7..7c38cf5793 100644
--- a/source3/smbd/service.c
+++ b/source3/smbd/service.c
@@ -305,6 +305,7 @@ static void set_admin_user(connection_struct *conn)
#endif
) {
conn->admin_user = True;
+ conn->force_user = True; /* Admin users are effectivly 'forced' */
DEBUG(0,("%s logged in as admin user (root privileges)\n",conn->user));
} else {
conn->admin_user = False;
@@ -329,7 +330,6 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
{
struct passwd *pass = NULL;
BOOL guest = False;
- BOOL force = False;
connection_struct *conn;
struct stat st;
fstring user;
@@ -349,7 +349,6 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
if (lp_guest_only(snum)) {
const char *guestname = lp_guestaccount();
guest = True;
- force = True;
pass = getpwnam_alloc(guestname);
if (!pass) {
DEBUG(0,("authorise_login: Invalid guest account %s??\n",guestname));
@@ -397,7 +396,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
return NULL;
}
pass = Get_Pwnam(user);
- conn->force_user = force;
+ conn->force_user = True;
conn->uid = pass->pw_uid;
conn->gid = pass->pw_gid;
string_set(&conn->user, pass->pw_name);
@@ -434,7 +433,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
/*
* If force user is true, then store the
- * given userid and also the primary groupid
+ * given userid and also the groups
* of the user we're forcing.
*/
@@ -492,6 +491,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
gid = nametogid(gname);
if (gid != (gid_t)-1) {
+
/*
* If the user has been forced and the forced group starts
* with a '+', then we only set the group to be the forced
@@ -507,6 +507,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
conn->gid = gid;
DEBUG(3,("Forced group %s\n",gname));
}
+ conn->force_group = True;
} else {
DEBUG(1,("Couldn't find group %s\n",gname));
conn_free(conn);
@@ -524,23 +525,27 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum)));
}
- /* groups stuff added by ih */
- conn->ngroups = 0;
- conn->groups = NULL;
-
- /* Find all the groups this uid is in and
- store them. Used by change_to_user() */
- initialise_groups(conn->user, conn->uid, conn->gid);
- get_current_groups(conn->gid, &conn->ngroups,&conn->groups);
+ if (conn->force_user || conn->force_group) {
+
+ /* groups stuff added by ih */
+ conn->ngroups = 0;
+ conn->groups = NULL;
+
+ /* Find all the groups this uid is in and
+ store them. Used by change_to_user() */
+ initialise_groups(conn->user, conn->uid, conn->gid);
+ get_current_groups(conn->gid, &conn->ngroups,&conn->groups);
- conn->nt_user_token = create_nt_token(conn->uid, conn->gid,
- conn->ngroups, conn->groups,
- guest, NULL);
+ conn->nt_user_token = create_nt_token(conn->uid, conn->gid,
+ conn->ngroups, conn->groups,
+ guest);
+ }
/*
* New code to check if there's a share security descripter
* added from NT server manager. This is done after the
* smb.conf checks are done as we need a uid and token. JRA.
+ *
*/
{
diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c
index 77f93812dd..a49982dcfe 100644
--- a/source3/smbd/sesssetup.c
+++ b/source3/smbd/sesssetup.c
@@ -177,9 +177,9 @@ static int reply_spnego_kerberos(connection_struct *conn,
return ERROR_NT(NT_STATUS_NO_SUCH_USER);
}
- if (!make_server_info_pw(&server_info,pw)) {
+ if (!NT_STATUS_IS_OK(ret = make_server_info_pw(&server_info,pw))) {
DEBUG(1,("make_server_info_from_pw failed!\n"));
- return ERROR_NT(NT_STATUS_NO_MEMORY);
+ return ERROR_NT(ret);
}
sess_vuid = register_vuid(server_info, user);
diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c
index c0bacf8f91..6f91065ceb 100644
--- a/source3/smbd/uid.c
+++ b/source3/smbd/uid.c
@@ -59,18 +59,26 @@ BOOL change_to_guest(void)
static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum)
{
int i;
- for (i=0;i<conn->uid_cache.entries;i++)
- if (conn->uid_cache.list[i] == vuser->uid)
+ for (i=0;i<conn->vuid_cache.entries && i< VUID_CACHE_SIZE;i++)
+ if (conn->vuid_cache.list[i] == vuser->vuid)
return(True);
+ if ((conn->force_user || conn->force_group)
+ && (conn->vuid != vuser->vuid)) {
+ return False;
+ }
+
if (!user_ok(vuser->user.unix_name,snum))
return(False);
- i = conn->uid_cache.entries % UID_CACHE_SIZE;
- conn->uid_cache.list[i] = vuser->uid;
+ if (!share_access_check(conn, snum, vuser, conn->read_only ? FILE_READ_DATA : FILE_WRITE_DATA)) {
+ return False;
+ }
+
+ i = conn->vuid_cache.entries % VUID_CACHE_SIZE;
+ conn->vuid_cache.list[i] = vuser->vuid;
- if (conn->uid_cache.entries < UID_CACHE_SIZE)
- conn->uid_cache.entries++;
+ conn->vuid_cache.entries++;
return(True);
}
@@ -115,27 +123,21 @@ BOOL change_to_user(connection_struct *conn, uint16 vuid)
snum = SNUM(conn);
- if((vuser != NULL) && !check_user_ok(conn, vuser, snum))
- return False;
-
- if (conn->force_user ||
- conn->admin_user ||
- (lp_security() == SEC_SHARE)) {
+ if (conn->force_user) /* security = share sets this too */ {
uid = conn->uid;
gid = conn->gid;
current_user.groups = conn->groups;
current_user.ngroups = conn->ngroups;
token = conn->nt_user_token;
- } else {
- if (!vuser) {
- DEBUG(2,("change_to_user: Invalid vuid used %d\n",vuid));
- return(False);
- }
+ } else if ((vuser) && check_user_ok(conn, vuser, snum)) {
uid = vuser->uid;
gid = vuser->gid;
current_user.ngroups = vuser->n_groups;
current_user.groups = vuser->groups;
token = vuser->nt_user_token;
+ } else {
+ DEBUG(2,("change_to_user: Invalid vuid used %d or vuid not permitted access to share.\n",vuid));
+ return False;
}
/*
@@ -175,7 +177,7 @@ BOOL change_to_user(connection_struct *conn, uint16 vuid)
if (vuser && vuser->guest)
is_guest = True;
- token = create_nt_token(uid, gid, current_user.ngroups, current_user.groups, is_guest, NULL);
+ token = create_nt_token(uid, gid, current_user.ngroups, current_user.groups, is_guest);
must_free_token = True;
}