Remove "userdom_struct user" from "struct user_struct"
[nivanova/samba-autobuild/.git] / source3 / smbd / uid.c
1 /* 
2    Unix SMB/CIFS implementation.
3    uid/user handling
4    Copyright (C) Andrew Tridgell 1992-1998
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21
22 /* what user is current? */
23 extern struct current_user current_user;
24
25 /****************************************************************************
26  Iterator functions for getting all gid's from current_user.
27 ****************************************************************************/
28
29 gid_t get_current_user_gid_first(int *piterator)
30 {
31         *piterator = 0;
32         return current_user.ut.gid;
33 }
34
35 gid_t get_current_user_gid_next(int *piterator)
36 {
37         gid_t ret;
38
39         if (!current_user.ut.groups || *piterator >= current_user.ut.ngroups) {
40                 return (gid_t)-1;
41         }
42
43         ret = current_user.ut.groups[*piterator];
44         (*piterator) += 1;
45         return ret;
46 }
47
48 /****************************************************************************
49  Become the guest user without changing the security context stack.
50 ****************************************************************************/
51
52 bool change_to_guest(void)
53 {
54         static struct passwd *pass=NULL;
55
56         if (!pass) {
57                 /* Don't need to free() this as its stored in a static */
58                 pass = getpwnam_alloc(NULL, lp_guestaccount());
59                 if (!pass)
60                         return(False);
61         }
62         
63 #ifdef AIX
64         /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before 
65            setting IDs */
66         initgroups(pass->pw_name, pass->pw_gid);
67 #endif
68         
69         set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
70         
71         current_user.conn = NULL;
72         current_user.vuid = UID_FIELD_INVALID;
73
74         TALLOC_FREE(pass);
75         pass = NULL;
76         
77         return True;
78 }
79
80 /*******************************************************************
81  Check if a username is OK.
82 ********************************************************************/
83
84 static bool check_user_ok(connection_struct *conn, user_struct *vuser,int snum)
85 {
86         unsigned int i;
87         struct vuid_cache_entry *ent = NULL;
88         bool readonly_share;
89         NT_USER_TOKEN *token;
90
91         for (i=0;i<conn->vuid_cache.entries && i< VUID_CACHE_SIZE;i++) {
92                 if (conn->vuid_cache.array[i].vuid == vuser->vuid) {
93                         ent = &conn->vuid_cache.array[i];
94                         conn->read_only = ent->read_only;
95                         conn->admin_user = ent->admin_user;
96                         return(True);
97                 }
98         }
99
100         if (!user_ok_token(vuser->server_info->unix_name,
101                            vuser->server_info->ptok,
102                            snum))
103                 return(False);
104
105         readonly_share = is_share_read_only_for_token(
106                 vuser->server_info->unix_name, vuser->server_info->ptok,
107                 SNUM(conn));
108
109         token = conn->nt_user_token ?
110                 conn->nt_user_token : vuser->server_info->ptok;
111
112         if (!readonly_share &&
113             !share_access_check(token, lp_servicename(snum),
114                                 FILE_WRITE_DATA)) {
115                 /* smb.conf allows r/w, but the security descriptor denies
116                  * write. Fall back to looking at readonly. */
117                 readonly_share = True;
118                 DEBUG(5,("falling back to read-only access-evaluation due to "
119                          "security descriptor\n"));
120         }
121
122         if (!share_access_check(token, lp_servicename(snum),
123                                 readonly_share ?
124                                 FILE_READ_DATA : FILE_WRITE_DATA)) {
125                 return False;
126         }
127
128         i = conn->vuid_cache.entries % VUID_CACHE_SIZE;
129         if (conn->vuid_cache.entries < VUID_CACHE_SIZE)
130                 conn->vuid_cache.entries++;
131
132         ent = &conn->vuid_cache.array[i];
133         ent->vuid = vuser->vuid;
134         ent->read_only = readonly_share;
135
136         ent->admin_user = token_contains_name_in_list(
137                 vuser->server_info->unix_name, NULL, vuser->server_info->ptok,
138                 lp_admin_users(SNUM(conn)));
139
140         conn->read_only = ent->read_only;
141         conn->admin_user = ent->admin_user;
142
143         return(True);
144 }
145
146 /****************************************************************************
147  Become the user of a connection number without changing the security context
148  stack, but modify the current_user entries.
149 ****************************************************************************/
150
151 bool change_to_user(connection_struct *conn, uint16 vuid)
152 {
153         user_struct *vuser = get_valid_user_struct(vuid);
154         int snum;
155         gid_t gid;
156         uid_t uid;
157         char group_c;
158         bool must_free_token = False;
159         NT_USER_TOKEN *token = NULL;
160         int num_groups = 0;
161         gid_t *group_list = NULL;
162         
163         if (!conn) {
164                 DEBUG(2,("change_to_user: Connection not open\n"));
165                 return(False);
166         }
167
168         /*
169          * We need a separate check in security=share mode due to vuid
170          * always being UID_FIELD_INVALID. If we don't do this then
171          * in share mode security we are *always* changing uid's between
172          * SMB's - this hurts performance - Badly.
173          */
174
175         if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
176            (current_user.ut.uid == conn->uid)) {
177                 DEBUG(4,("change_to_user: Skipping user change - already "
178                          "user\n"));
179                 return(True);
180         } else if ((current_user.conn == conn) && 
181                    (vuser != 0) && (current_user.vuid == vuid) && 
182                    (current_user.ut.uid == vuser->server_info->uid)) {
183                 DEBUG(4,("change_to_user: Skipping user change - already "
184                          "user\n"));
185                 return(True);
186         }
187
188         snum = SNUM(conn);
189
190         if ((vuser) && !check_user_ok(conn, vuser, snum)) {
191                 DEBUG(2,("change_to_user: SMB user %s (unix user %s, vuid %d) "
192                          "not permitted access to share %s.\n",
193                          vuser->server_info->sanitized_username,
194                          vuser->server_info->unix_name, vuid,
195                          lp_servicename(snum)));
196                 return False;
197         }
198
199         if (conn->force_user) /* security = share sets this too */ {
200                 uid = conn->uid;
201                 gid = conn->gid;
202                 group_list = conn->groups;
203                 num_groups = conn->ngroups;
204                 token = conn->nt_user_token;
205         } else if (vuser) {
206                 uid = conn->admin_user ? 0 : vuser->server_info->uid;
207                 gid = vuser->server_info->gid;
208                 num_groups = vuser->server_info->n_groups;
209                 group_list  = vuser->server_info->groups;
210                 token = vuser->server_info->ptok;
211         } else {
212                 DEBUG(2,("change_to_user: Invalid vuid used %d in accessing "
213                          "share %s.\n",vuid, lp_servicename(snum) ));
214                 return False;
215         }
216
217         /*
218          * See if we should force group for this service.
219          * If so this overrides any group set in the force
220          * user code.
221          */
222
223         if((group_c = *lp_force_group(snum))) {
224
225                 token = dup_nt_token(NULL, token);
226                 if (token == NULL) {
227                         DEBUG(0, ("dup_nt_token failed\n"));
228                         return False;
229                 }
230                 must_free_token = True;
231
232                 if(group_c == '+') {
233
234                         /*
235                          * Only force group if the user is a member of
236                          * the service group. Check the group memberships for
237                          * this user (we already have this) to
238                          * see if we should force the group.
239                          */
240
241                         int i;
242                         for (i = 0; i < num_groups; i++) {
243                                 if (group_list[i] == conn->gid) {
244                                         gid = conn->gid;
245                                         gid_to_sid(&token->user_sids[1], gid);
246                                         break;
247                                 }
248                         }
249                 } else {
250                         gid = conn->gid;
251                         gid_to_sid(&token->user_sids[1], gid);
252                 }
253         }
254         
255         /* Now set current_user since we will immediately also call
256            set_sec_ctx() */
257
258         current_user.ut.ngroups = num_groups;
259         current_user.ut.groups  = group_list;   
260
261         set_sec_ctx(uid, gid, current_user.ut.ngroups, current_user.ut.groups,
262                     token);
263
264         /*
265          * Free the new token (as set_sec_ctx copies it).
266          */
267
268         if (must_free_token)
269                 TALLOC_FREE(token);
270
271         current_user.conn = conn;
272         current_user.vuid = vuid;
273
274         DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n",
275                  (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
276   
277         return(True);
278 }
279
280 /****************************************************************************
281  Go back to being root without changing the security context stack,
282  but modify the current_user entries.
283 ****************************************************************************/
284
285 bool change_to_root_user(void)
286 {
287         set_root_sec_ctx();
288
289         DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
290                 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
291
292         current_user.conn = NULL;
293         current_user.vuid = UID_FIELD_INVALID;
294
295         return(True);
296 }
297
298 /****************************************************************************
299  Become the user of an authenticated connected named pipe.
300  When this is called we are currently running as the connection
301  user. Doesn't modify current_user.
302 ****************************************************************************/
303
304 bool become_authenticated_pipe_user(pipes_struct *p)
305 {
306         if (!push_sec_ctx())
307                 return False;
308
309         set_sec_ctx(p->pipe_user.ut.uid, p->pipe_user.ut.gid, 
310                     p->pipe_user.ut.ngroups, p->pipe_user.ut.groups,
311                     p->pipe_user.nt_user_token);
312
313         return True;
314 }
315
316 /****************************************************************************
317  Unbecome the user of an authenticated connected named pipe.
318  When this is called we are running as the authenticated pipe
319  user and need to go back to being the connection user. Doesn't modify
320  current_user.
321 ****************************************************************************/
322
323 bool unbecome_authenticated_pipe_user(void)
324 {
325         return pop_sec_ctx();
326 }
327
328 /****************************************************************************
329  Utility functions used by become_xxx/unbecome_xxx.
330 ****************************************************************************/
331
332 struct conn_ctx {
333         connection_struct *conn;
334         uint16 vuid;
335 };
336  
337 /* A stack of current_user connection contexts. */
338  
339 static struct conn_ctx conn_ctx_stack[MAX_SEC_CTX_DEPTH];
340 static int conn_ctx_stack_ndx;
341
342 static void push_conn_ctx(void)
343 {
344         struct conn_ctx *ctx_p;
345  
346         /* Check we don't overflow our stack */
347  
348         if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
349                 DEBUG(0, ("Connection context stack overflow!\n"));
350                 smb_panic("Connection context stack overflow!\n");
351         }
352  
353         /* Store previous user context */
354         ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
355  
356         ctx_p->conn = current_user.conn;
357         ctx_p->vuid = current_user.vuid;
358  
359         DEBUG(3, ("push_conn_ctx(%u) : conn_ctx_stack_ndx = %d\n",
360                 (unsigned int)ctx_p->vuid, conn_ctx_stack_ndx ));
361
362         conn_ctx_stack_ndx++;
363 }
364
365 static void pop_conn_ctx(void)
366 {
367         struct conn_ctx *ctx_p;
368  
369         /* Check for stack underflow. */
370
371         if (conn_ctx_stack_ndx == 0) {
372                 DEBUG(0, ("Connection context stack underflow!\n"));
373                 smb_panic("Connection context stack underflow!\n");
374         }
375
376         conn_ctx_stack_ndx--;
377         ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
378
379         current_user.conn = ctx_p->conn;
380         current_user.vuid = ctx_p->vuid;
381
382         ctx_p->conn = NULL;
383         ctx_p->vuid = UID_FIELD_INVALID;
384 }
385
386 /****************************************************************************
387  Temporarily become a root user.  Must match with unbecome_root(). Saves and
388  restores the connection context.
389 ****************************************************************************/
390
391 void become_root(void)
392 {
393          /*
394           * no good way to handle push_sec_ctx() failing without changing
395           * the prototype of become_root()
396           */
397         if (!push_sec_ctx()) {
398                 smb_panic("become_root: push_sec_ctx failed");
399         }
400         push_conn_ctx();
401         set_root_sec_ctx();
402 }
403
404 /* Unbecome the root user */
405
406 void unbecome_root(void)
407 {
408         pop_sec_ctx();
409         pop_conn_ctx();
410 }
411
412 /****************************************************************************
413  Push the current security context then force a change via change_to_user().
414  Saves and restores the connection context.
415 ****************************************************************************/
416
417 bool become_user(connection_struct *conn, uint16 vuid)
418 {
419         if (!push_sec_ctx())
420                 return False;
421
422         push_conn_ctx();
423
424         if (!change_to_user(conn, vuid)) {
425                 pop_sec_ctx();
426                 pop_conn_ctx();
427                 return False;
428         }
429
430         return True;
431 }
432
433 bool unbecome_user(void)
434 {
435         pop_sec_ctx();
436         pop_conn_ctx();
437         return True;
438 }