diff options
author | Andrew Bartlett <abartlet@samba.org> | 2002-08-20 01:54:28 +0000 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2002-08-20 01:54:28 +0000 |
commit | 8674440d81f703cb59979426c92ed54de8e5f2ed (patch) | |
tree | 033da6bfa721b02c1a087ee478d3593997f30e2a /source3/smbd | |
parent | 03615599919f94c5ed56e9824343b02f4f3e0b71 (diff) | |
download | samba-8674440d81f703cb59979426c92ed54de8e5f2ed.tar.gz samba-8674440d81f703cb59979426c92ed54de8e5f2ed.tar.xz 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.c | 24 | ||||
-rw-r--r-- | source3/smbd/password.c | 156 | ||||
-rw-r--r-- | source3/smbd/service.c | 35 | ||||
-rw-r--r-- | source3/smbd/sesssetup.c | 4 | ||||
-rw-r--r-- | source3/smbd/uid.c | 38 |
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; } |