smbd/uid.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    uid/user handling
00004    Copyright (C) Andrew Tridgell 1992-1998
00005    
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014    GNU General Public License for more details.
00015    
00016    You should have received a copy of the GNU General Public License
00017    along with this program; if not, write to the Free Software
00018    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019 */
00020 
00021 #include "includes.h"
00022 
00023 /* what user is current? */
00024 extern struct current_user current_user;
00025 
00026 /****************************************************************************
00027  Iterator functions for getting all gid's from current_user.
00028 ****************************************************************************/
00029 
00030 gid_t get_current_user_gid_first(int *piterator)
00031 {
00032         *piterator = 0;
00033         return current_user.ut.gid;
00034 }
00035 
00036 gid_t get_current_user_gid_next(int *piterator)
00037 {
00038         gid_t ret;
00039 
00040         if (!current_user.ut.groups || *piterator >= current_user.ut.ngroups) {
00041                 return (gid_t)-1;
00042         }
00043 
00044         ret = current_user.ut.groups[*piterator];
00045         (*piterator) += 1;
00046         return ret;
00047 }
00048 
00049 /****************************************************************************
00050  Become the guest user without changing the security context stack.
00051 ****************************************************************************/
00052 
00053 BOOL change_to_guest(void)
00054 {
00055         static struct passwd *pass=NULL;
00056 
00057         if (!pass) {
00058                 /* Don't need to free() this as its stored in a static */
00059                 pass = getpwnam_alloc(NULL, lp_guestaccount());
00060                 if (!pass)
00061                         return(False);
00062         }
00063         
00064 #ifdef AIX
00065         /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before 
00066            setting IDs */
00067         initgroups(pass->pw_name, pass->pw_gid);
00068 #endif
00069         
00070         set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
00071         
00072         current_user.conn = NULL;
00073         current_user.vuid = UID_FIELD_INVALID;
00074 
00075         TALLOC_FREE(pass);
00076         pass = NULL;
00077         
00078         return True;
00079 }
00080 
00081 /*******************************************************************
00082  Check if a username is OK.
00083 ********************************************************************/
00084 
00085 static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum)
00086 {
00087         unsigned int i;
00088         struct vuid_cache_entry *ent = NULL;
00089         BOOL readonly_share;
00090         NT_USER_TOKEN *token;
00091 
00092         for (i=0;i<conn->vuid_cache.entries && i< VUID_CACHE_SIZE;i++) {
00093                 if (conn->vuid_cache.array[i].vuid == vuser->vuid) {
00094                         ent = &conn->vuid_cache.array[i];
00095                         conn->read_only = ent->read_only;
00096                         conn->admin_user = ent->admin_user;
00097                         return(True);
00098                 }
00099         }
00100 
00101         if (!user_ok_token(vuser->user.unix_name, vuser->nt_user_token, snum))
00102                 return(False);
00103 
00104         readonly_share = is_share_read_only_for_token(vuser->user.unix_name,
00105                                                       vuser->nt_user_token,
00106                                                       SNUM(conn));
00107 
00108         token = conn->nt_user_token ?
00109                 conn->nt_user_token : vuser->nt_user_token;
00110 
00111         if (!readonly_share &&
00112             !share_access_check(token, lp_servicename(snum),
00113                                 FILE_WRITE_DATA)) {
00114                 /* smb.conf allows r/w, but the security descriptor denies
00115                  * write. Fall back to looking at readonly. */
00116                 readonly_share = True;
00117                 DEBUG(5,("falling back to read-only access-evaluation due to "
00118                          "security descriptor\n"));
00119         }
00120 
00121         if (!share_access_check(token, lp_servicename(snum),
00122                                 readonly_share ?
00123                                 FILE_READ_DATA : FILE_WRITE_DATA)) {
00124                 return False;
00125         }
00126 
00127         i = conn->vuid_cache.entries % VUID_CACHE_SIZE;
00128         if (conn->vuid_cache.entries < VUID_CACHE_SIZE)
00129                 conn->vuid_cache.entries++;
00130 
00131         ent = &conn->vuid_cache.array[i];
00132         ent->vuid = vuser->vuid;
00133         ent->read_only = readonly_share;
00134 
00135         ent->admin_user = token_contains_name_in_list(
00136                 vuser->user.unix_name, NULL, vuser->nt_user_token,
00137                 lp_admin_users(SNUM(conn)));
00138 
00139         conn->read_only = ent->read_only;
00140         conn->admin_user = ent->admin_user;
00141 
00142         return(True);
00143 }
00144 
00145 /****************************************************************************
00146  Become the user of a connection number without changing the security context
00147  stack, but modify the current_user entries.
00148 ****************************************************************************/
00149 
00150 BOOL change_to_user(connection_struct *conn, uint16 vuid)
00151 {
00152         user_struct *vuser = get_valid_user_struct(vuid);
00153         int snum;
00154         gid_t gid;
00155         uid_t uid;
00156         char group_c;
00157         BOOL must_free_token = False;
00158         NT_USER_TOKEN *token = NULL;
00159         int num_groups = 0;
00160         gid_t *group_list = NULL;
00161         
00162         if (!conn) {
00163                 DEBUG(2,("change_to_user: Connection not open\n"));
00164                 return(False);
00165         }
00166 
00167         /*
00168          * We need a separate check in security=share mode due to vuid
00169          * always being UID_FIELD_INVALID. If we don't do this then
00170          * in share mode security we are *always* changing uid's between
00171          * SMB's - this hurts performance - Badly.
00172          */
00173 
00174         if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
00175            (current_user.ut.uid == conn->uid)) {
00176                 DEBUG(4,("change_to_user: Skipping user change - already "
00177                          "user\n"));
00178                 return(True);
00179         } else if ((current_user.conn == conn) && 
00180                    (vuser != 0) && (current_user.vuid == vuid) && 
00181                    (current_user.ut.uid == vuser->uid)) {
00182                 DEBUG(4,("change_to_user: Skipping user change - already "
00183                          "user\n"));
00184                 return(True);
00185         }
00186 
00187         snum = SNUM(conn);
00188 
00189         if ((vuser) && !check_user_ok(conn, vuser, snum)) {
00190                 DEBUG(2,("change_to_user: SMB user %s (unix user %s, vuid %d) "
00191                          "not permitted access to share %s.\n",
00192                          vuser->user.smb_name, vuser->user.unix_name, vuid,
00193                          lp_servicename(snum)));
00194                 return False;
00195         }
00196 
00197         if (conn->force_user) /* security = share sets this too */ {
00198                 uid = conn->uid;
00199                 gid = conn->gid;
00200                 group_list = conn->groups;
00201                 num_groups = conn->ngroups;
00202                 token = conn->nt_user_token;
00203         } else if (vuser) {
00204                 uid = conn->admin_user ? 0 : vuser->uid;
00205                 gid = vuser->gid;
00206                 num_groups = vuser->n_groups;
00207                 group_list  = vuser->groups;
00208                 token = vuser->nt_user_token;
00209         } else {
00210                 DEBUG(2,("change_to_user: Invalid vuid used %d in accessing "
00211                          "share %s.\n",vuid, lp_servicename(snum) ));
00212                 return False;
00213         }
00214 
00215         /*
00216          * See if we should force group for this service.
00217          * If so this overrides any group set in the force
00218          * user code.
00219          */
00220 
00221         if((group_c = *lp_force_group(snum))) {
00222 
00223                 token = dup_nt_token(NULL, token);
00224                 if (token == NULL) {
00225                         DEBUG(0, ("dup_nt_token failed\n"));
00226                         return False;
00227                 }
00228                 must_free_token = True;
00229 
00230                 if(group_c == '+') {
00231 
00232                         /*
00233                          * Only force group if the user is a member of
00234                          * the service group. Check the group memberships for
00235                          * this user (we already have this) to
00236                          * see if we should force the group.
00237                          */
00238 
00239                         int i;
00240                         for (i = 0; i < num_groups; i++) {
00241                                 if (group_list[i] == conn->gid) {
00242                                         gid = conn->gid;
00243                                         gid_to_sid(&token->user_sids[1], gid);
00244                                         break;
00245                                 }
00246                         }
00247                 } else {
00248                         gid = conn->gid;
00249                         gid_to_sid(&token->user_sids[1], gid);
00250                 }
00251         }
00252         
00253         /* Now set current_user since we will immediately also call
00254            set_sec_ctx() */
00255 
00256         current_user.ut.ngroups = num_groups;
00257         current_user.ut.groups  = group_list;   
00258 
00259         set_sec_ctx(uid, gid, current_user.ut.ngroups, current_user.ut.groups,
00260                     token);
00261 
00262         /*
00263          * Free the new token (as set_sec_ctx copies it).
00264          */
00265 
00266         if (must_free_token)
00267                 TALLOC_FREE(token);
00268 
00269         current_user.conn = conn;
00270         current_user.vuid = vuid;
00271 
00272         DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n",
00273                  (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
00274   
00275         return(True);
00276 }
00277 
00278 /****************************************************************************
00279  Go back to being root without changing the security context stack,
00280  but modify the current_user entries.
00281 ****************************************************************************/
00282 
00283 BOOL change_to_root_user(void)
00284 {
00285         set_root_sec_ctx();
00286 
00287         DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
00288                 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
00289 
00290         current_user.conn = NULL;
00291         current_user.vuid = UID_FIELD_INVALID;
00292 
00293         return(True);
00294 }
00295 
00296 /****************************************************************************
00297  Become the user of an authenticated connected named pipe.
00298  When this is called we are currently running as the connection
00299  user. Doesn't modify current_user.
00300 ****************************************************************************/
00301 
00302 BOOL become_authenticated_pipe_user(pipes_struct *p)
00303 {
00304         if (!push_sec_ctx())
00305                 return False;
00306 
00307         set_sec_ctx(p->pipe_user.ut.uid, p->pipe_user.ut.gid, 
00308                     p->pipe_user.ut.ngroups, p->pipe_user.ut.groups,
00309                     p->pipe_user.nt_user_token);
00310 
00311         return True;
00312 }
00313 
00314 /****************************************************************************
00315  Unbecome the user of an authenticated connected named pipe.
00316  When this is called we are running as the authenticated pipe
00317  user and need to go back to being the connection user. Doesn't modify
00318  current_user.
00319 ****************************************************************************/
00320 
00321 BOOL unbecome_authenticated_pipe_user(void)
00322 {
00323         return pop_sec_ctx();
00324 }
00325 
00326 /****************************************************************************
00327  Utility functions used by become_xxx/unbecome_xxx.
00328 ****************************************************************************/
00329 
00330 struct conn_ctx {
00331         connection_struct *conn;
00332         uint16 vuid;
00333 };
00334  
00335 /* A stack of current_user connection contexts. */
00336  
00337 static struct conn_ctx conn_ctx_stack[MAX_SEC_CTX_DEPTH];
00338 static int conn_ctx_stack_ndx;
00339 
00340 static void push_conn_ctx(void)
00341 {
00342         struct conn_ctx *ctx_p;
00343  
00344         /* Check we don't overflow our stack */
00345  
00346         if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
00347                 DEBUG(0, ("Connection context stack overflow!\n"));
00348                 smb_panic("Connection context stack overflow!\n");
00349         }
00350  
00351         /* Store previous user context */
00352         ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
00353  
00354         ctx_p->conn = current_user.conn;
00355         ctx_p->vuid = current_user.vuid;
00356  
00357         DEBUG(3, ("push_conn_ctx(%u) : conn_ctx_stack_ndx = %d\n",
00358                 (unsigned int)ctx_p->vuid, conn_ctx_stack_ndx ));
00359 
00360         conn_ctx_stack_ndx++;
00361 }
00362 
00363 static void pop_conn_ctx(void)
00364 {
00365         struct conn_ctx *ctx_p;
00366  
00367         /* Check for stack underflow. */
00368 
00369         if (conn_ctx_stack_ndx == 0) {
00370                 DEBUG(0, ("Connection context stack underflow!\n"));
00371                 smb_panic("Connection context stack underflow!\n");
00372         }
00373 
00374         conn_ctx_stack_ndx--;
00375         ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
00376 
00377         current_user.conn = ctx_p->conn;
00378         current_user.vuid = ctx_p->vuid;
00379 
00380         ctx_p->conn = NULL;
00381         ctx_p->vuid = UID_FIELD_INVALID;
00382 }
00383 
00384 /****************************************************************************
00385  Temporarily become a root user.  Must match with unbecome_root(). Saves and
00386  restores the connection context.
00387 ****************************************************************************/
00388 
00389 void become_root(void)
00390 {
00391         push_sec_ctx();
00392         push_conn_ctx();
00393         set_root_sec_ctx();
00394 }
00395 
00396 /* Unbecome the root user */
00397 
00398 void unbecome_root(void)
00399 {
00400         pop_sec_ctx();
00401         pop_conn_ctx();
00402 }
00403 
00404 /****************************************************************************
00405  Push the current security context then force a change via change_to_user().
00406  Saves and restores the connection context.
00407 ****************************************************************************/
00408 
00409 BOOL become_user(connection_struct *conn, uint16 vuid)
00410 {
00411         if (!push_sec_ctx())
00412                 return False;
00413 
00414         push_conn_ctx();
00415 
00416         if (!change_to_user(conn, vuid)) {
00417                 pop_sec_ctx();
00418                 pop_conn_ctx();
00419                 return False;
00420         }
00421 
00422         return True;
00423 }
00424 
00425 BOOL unbecome_user(void)
00426 {
00427         pop_sec_ctx();
00428         pop_conn_ctx();
00429         return True;
00430 }

Sambaに対してSat Aug 29 21:23:26 2009に生成されました。  doxygen 1.4.7