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