Move the definition of struct vuid_cache_entry *ent outside blocks.
[amitay/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 #include "system/passwd.h"
22 #include "smbd/smbd.h"
23 #include "smbd/globals.h"
24 #include "../librpc/gen_ndr/netlogon.h"
25 #include "libcli/security/security.h"
26 #include "passdb/lookup_sid.h"
27 #include "auth.h"
28
29 /* what user is current? */
30 extern struct current_user current_user;
31
32 /****************************************************************************
33  Become the guest user without changing the security context stack.
34 ****************************************************************************/
35
36 bool change_to_guest(void)
37 {
38         struct passwd *pass;
39
40         pass = Get_Pwnam_alloc(talloc_tos(), lp_guestaccount());
41         if (!pass) {
42                 return false;
43         }
44
45 #ifdef AIX
46         /* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before 
47            setting IDs */
48         initgroups(pass->pw_name, pass->pw_gid);
49 #endif
50
51         set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
52
53         current_user.conn = NULL;
54         current_user.vuid = UID_FIELD_INVALID;
55
56         TALLOC_FREE(pass);
57
58         return true;
59 }
60
61 /****************************************************************************
62  talloc free the conn->session_info if not used in the vuid cache.
63 ****************************************************************************/
64
65 static void free_conn_session_info_if_unused(connection_struct *conn)
66 {
67         unsigned int i;
68
69         for (i = 0; i < VUID_CACHE_SIZE; i++) {
70                 struct vuid_cache_entry *ent;
71                 ent = &conn->vuid_cache.array[i];
72                 if (ent->vuid != UID_FIELD_INVALID &&
73                                 conn->session_info == ent->session_info) {
74                         return;
75                 }
76         }
77         /* Not used, safe to free. */
78         TALLOC_FREE(conn->session_info);
79 }
80
81 /*******************************************************************
82  Check if a username is OK.
83
84  This sets up conn->session_info with a copy related to this vuser that
85  later code can then mess with.
86 ********************************************************************/
87
88 static bool check_user_ok(connection_struct *conn,
89                         uint64_t vuid,
90                         const struct auth_session_info *session_info,
91                         int snum)
92 {
93         unsigned int i;
94         bool readonly_share;
95         bool admin_user;
96         struct vuid_cache_entry *ent = NULL;
97
98         {
99                 for (i=0; i<VUID_CACHE_SIZE; i++) {
100                         ent = &conn->vuid_cache.array[i];
101                         if (ent->vuid == vuid) {
102                                 free_conn_session_info_if_unused(conn);
103                                 conn->session_info = ent->session_info;
104                                 conn->read_only = ent->read_only;
105                                 return(True);
106                         }
107                 }
108         }
109
110         if (!user_ok_token(session_info->unix_info->unix_name,
111                            session_info->info->domain_name,
112                            session_info->security_token, snum))
113                 return(False);
114
115         readonly_share = is_share_read_only_for_token(
116                 session_info->unix_info->unix_name,
117                 session_info->info->domain_name,
118                 session_info->security_token,
119                 conn);
120
121         if (!readonly_share &&
122             !share_access_check(session_info->security_token,
123                                 lp_servicename(talloc_tos(), snum),
124                                 FILE_WRITE_DATA,
125                                 NULL)) {
126                 /* smb.conf allows r/w, but the security descriptor denies
127                  * write. Fall back to looking at readonly. */
128                 readonly_share = True;
129                 DEBUG(5,("falling back to read-only access-evaluation due to "
130                          "security descriptor\n"));
131         }
132
133         if (!share_access_check(session_info->security_token,
134                                 lp_servicename(talloc_tos(), snum),
135                                 readonly_share ?
136                                 FILE_READ_DATA : FILE_WRITE_DATA,
137                                 NULL)) {
138                 return False;
139         }
140
141         admin_user = token_contains_name_in_list(
142                 session_info->unix_info->unix_name,
143                 session_info->info->domain_name,
144                 NULL, session_info->security_token, lp_admin_users(snum));
145
146         {
147                 ent = &conn->vuid_cache.array[conn->vuid_cache.next_entry];
148
149                 conn->vuid_cache.next_entry =
150                         (conn->vuid_cache.next_entry + 1) % VUID_CACHE_SIZE;
151
152                 TALLOC_FREE(ent->session_info);
153
154                 /*
155                  * If force_user was set, all session_info's are based on the same
156                  * username-based faked one.
157                  */
158
159                 ent->session_info = copy_session_info(
160                         conn, conn->force_user ? conn->session_info : session_info);
161
162                 if (ent->session_info == NULL) {
163                         ent->vuid = UID_FIELD_INVALID;
164                         return false;
165                 }
166
167                 ent->vuid = vuid;
168                 ent->read_only = readonly_share;
169                 free_conn_session_info_if_unused(conn);
170                 conn->session_info = ent->session_info;
171         }
172
173         conn->read_only = readonly_share;
174         if (admin_user) {
175                 DEBUG(2,("check_user_ok: user %s is an admin user. "
176                         "Setting uid as %d\n",
177                         conn->session_info->unix_info->unix_name,
178                         sec_initial_uid() ));
179                 conn->session_info->unix_token->uid = sec_initial_uid();
180         }
181
182         return(True);
183 }
184
185 /****************************************************************************
186  Become the user of a connection number without changing the security context
187  stack, but modify the current_user entries.
188 ****************************************************************************/
189
190 static bool change_to_user_internal(connection_struct *conn,
191                                     const struct auth_session_info *session_info,
192                                     uint64_t vuid)
193 {
194         int snum;
195         gid_t gid;
196         uid_t uid;
197         char group_c;
198         int num_groups = 0;
199         gid_t *group_list = NULL;
200         bool ok;
201
202         snum = SNUM(conn);
203
204         ok = check_user_ok(conn, vuid, session_info, snum);
205         if (!ok) {
206                 DEBUG(2,("SMB user %s (unix user %s) "
207                          "not permitted access to share %s.\n",
208                          session_info->unix_info->sanitized_username,
209                          session_info->unix_info->unix_name,
210                          lp_servicename(talloc_tos(), snum)));
211                 return false;
212         }
213
214         uid = conn->session_info->unix_token->uid;
215         gid = conn->session_info->unix_token->gid;
216         num_groups = conn->session_info->unix_token->ngroups;
217         group_list  = conn->session_info->unix_token->groups;
218
219         /*
220          * See if we should force group for this service. If so this overrides
221          * any group set in the force user code.
222          */
223         if((group_c = *lp_force_group(talloc_tos(), snum))) {
224
225                 SMB_ASSERT(conn->force_group_gid != (gid_t)-1);
226
227                 if (group_c == '+') {
228                         int i;
229
230                         /*
231                          * Only force group if the user is a member of the
232                          * service group. Check the group memberships for this
233                          * user (we already have this) to see if we should force
234                          * the group.
235                          */
236                         for (i = 0; i < num_groups; i++) {
237                                 if (group_list[i] == conn->force_group_gid) {
238                                         conn->session_info->unix_token->gid =
239                                                 conn->force_group_gid;
240                                         gid = conn->force_group_gid;
241                                         gid_to_sid(&conn->session_info->security_token
242                                                    ->sids[1], gid);
243                                         break;
244                                 }
245                         }
246                 } else {
247                         conn->session_info->unix_token->gid = conn->force_group_gid;
248                         gid = conn->force_group_gid;
249                         gid_to_sid(&conn->session_info->security_token->sids[1],
250                                    gid);
251                 }
252         }
253
254         /*Set current_user since we will immediately also call set_sec_ctx() */
255         current_user.ut.ngroups = num_groups;
256         current_user.ut.groups  = group_list;
257
258         set_sec_ctx(uid,
259                     gid,
260                     current_user.ut.ngroups,
261                     current_user.ut.groups,
262                     conn->session_info->security_token);
263
264         current_user.conn = conn;
265         current_user.vuid = vuid;
266
267         DEBUG(5, ("Impersonated user: uid=(%d,%d), gid=(%d,%d)\n",
268                  (int)getuid(),
269                  (int)geteuid(),
270                  (int)getgid(),
271                  (int)getegid()));
272
273         return true;
274 }
275
276 bool change_to_user(connection_struct *conn, uint64_t vuid)
277 {
278         const struct auth_session_info *session_info = NULL;
279         struct user_struct *vuser;
280         int snum = SNUM(conn);
281
282         if (!conn) {
283                 DEBUG(2,("Connection not open\n"));
284                 return(False);
285         }
286
287         vuser = get_valid_user_struct(conn->sconn, vuid);
288
289         if ((current_user.conn == conn) &&
290                    (vuser != NULL) && (current_user.vuid == vuid) &&
291                    (current_user.ut.uid == vuser->session_info->unix_token->uid)) {
292                 DEBUG(4,("Skipping user change - already "
293                          "user\n"));
294                 return(True);
295         }
296
297         if (vuser == NULL) {
298                 /* Invalid vuid sent */
299                 DEBUG(2,("Invalid vuid %llu used on share %s.\n",
300                          (unsigned long long)vuid, lp_servicename(talloc_tos(),
301                                                                   snum)));
302                 return false;
303         }
304
305         session_info = vuser->session_info;
306
307         if (!conn->force_user && vuser == NULL) {
308                 DEBUG(2,("Invalid vuid used %llu in accessing share %s.\n",
309                          (unsigned long long)vuid,
310                          lp_servicename(talloc_tos(), snum)));
311                 return False;
312         }
313
314         return change_to_user_internal(conn, session_info, vuid);
315 }
316
317 static bool change_to_user_by_session(connection_struct *conn,
318                                       const struct auth_session_info *session_info)
319 {
320         SMB_ASSERT(conn != NULL);
321         SMB_ASSERT(session_info != NULL);
322
323         if ((current_user.conn == conn) &&
324             (current_user.ut.uid == session_info->unix_token->uid)) {
325                 DEBUG(7, ("Skipping user change - already user\n"));
326
327                 return true;
328         }
329
330         return change_to_user_internal(conn, session_info, UID_FIELD_INVALID);
331 }
332
333 /****************************************************************************
334  Go back to being root without changing the security context stack,
335  but modify the current_user entries.
336 ****************************************************************************/
337
338 bool smbd_change_to_root_user(void)
339 {
340         set_root_sec_ctx();
341
342         DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
343                 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
344
345         current_user.conn = NULL;
346         current_user.vuid = UID_FIELD_INVALID;
347
348         return(True);
349 }
350
351 /****************************************************************************
352  Become the user of an authenticated connected named pipe.
353  When this is called we are currently running as the connection
354  user. Doesn't modify current_user.
355 ****************************************************************************/
356
357 bool become_authenticated_pipe_user(struct auth_session_info *session_info)
358 {
359         if (!push_sec_ctx())
360                 return False;
361
362         set_sec_ctx(session_info->unix_token->uid, session_info->unix_token->gid,
363                     session_info->unix_token->ngroups, session_info->unix_token->groups,
364                     session_info->security_token);
365
366         return True;
367 }
368
369 /****************************************************************************
370  Unbecome the user of an authenticated connected named pipe.
371  When this is called we are running as the authenticated pipe
372  user and need to go back to being the connection user. Doesn't modify
373  current_user.
374 ****************************************************************************/
375
376 bool unbecome_authenticated_pipe_user(void)
377 {
378         return pop_sec_ctx();
379 }
380
381 /****************************************************************************
382  Utility functions used by become_xxx/unbecome_xxx.
383 ****************************************************************************/
384
385 static void push_conn_ctx(void)
386 {
387         struct conn_ctx *ctx_p;
388
389         /* Check we don't overflow our stack */
390
391         if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
392                 DEBUG(0, ("Connection context stack overflow!\n"));
393                 smb_panic("Connection context stack overflow!\n");
394         }
395
396         /* Store previous user context */
397         ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
398
399         ctx_p->conn = current_user.conn;
400         ctx_p->vuid = current_user.vuid;
401
402         DEBUG(4, ("push_conn_ctx(%llu) : conn_ctx_stack_ndx = %d\n",
403                 (unsigned long long)ctx_p->vuid, conn_ctx_stack_ndx));
404
405         conn_ctx_stack_ndx++;
406 }
407
408 static void pop_conn_ctx(void)
409 {
410         struct conn_ctx *ctx_p;
411
412         /* Check for stack underflow. */
413
414         if (conn_ctx_stack_ndx == 0) {
415                 DEBUG(0, ("Connection context stack underflow!\n"));
416                 smb_panic("Connection context stack underflow!\n");
417         }
418
419         conn_ctx_stack_ndx--;
420         ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
421
422         current_user.conn = ctx_p->conn;
423         current_user.vuid = ctx_p->vuid;
424
425         ctx_p->conn = NULL;
426         ctx_p->vuid = UID_FIELD_INVALID;
427 }
428
429 /****************************************************************************
430  Temporarily become a root user.  Must match with unbecome_root(). Saves and
431  restores the connection context.
432 ****************************************************************************/
433
434 void smbd_become_root(void)
435 {
436          /*
437           * no good way to handle push_sec_ctx() failing without changing
438           * the prototype of become_root()
439           */
440         if (!push_sec_ctx()) {
441                 smb_panic("become_root: push_sec_ctx failed");
442         }
443         push_conn_ctx();
444         set_root_sec_ctx();
445 }
446
447 /* Unbecome the root user */
448
449 void smbd_unbecome_root(void)
450 {
451         pop_sec_ctx();
452         pop_conn_ctx();
453 }
454
455 /****************************************************************************
456  Push the current security context then force a change via change_to_user().
457  Saves and restores the connection context.
458 ****************************************************************************/
459
460 bool become_user(connection_struct *conn, uint64_t vuid)
461 {
462         if (!push_sec_ctx())
463                 return False;
464
465         push_conn_ctx();
466
467         if (!change_to_user(conn, vuid)) {
468                 pop_sec_ctx();
469                 pop_conn_ctx();
470                 return False;
471         }
472
473         return True;
474 }
475
476 bool become_user_by_session(connection_struct *conn,
477                             const struct auth_session_info *session_info)
478 {
479         if (!push_sec_ctx())
480                 return false;
481
482         push_conn_ctx();
483
484         if (!change_to_user_by_session(conn, session_info)) {
485                 pop_sec_ctx();
486                 pop_conn_ctx();
487                 return false;
488         }
489
490         return true;
491 }
492
493 bool unbecome_user(void)
494 {
495         pop_sec_ctx();
496         pop_conn_ctx();
497         return True;
498 }
499
500 /****************************************************************************
501  Return the current user we are running effectively as on this connection.
502  I'd like to make this return conn->session_info->unix_token->uid, but become_root()
503  doesn't alter this value.
504 ****************************************************************************/
505
506 uid_t get_current_uid(connection_struct *conn)
507 {
508         return current_user.ut.uid;
509 }
510
511 /****************************************************************************
512  Return the current group we are running effectively as on this connection.
513  I'd like to make this return conn->session_info->unix_token->gid, but become_root()
514  doesn't alter this value.
515 ****************************************************************************/
516
517 gid_t get_current_gid(connection_struct *conn)
518 {
519         return current_user.ut.gid;
520 }
521
522 /****************************************************************************
523  Return the UNIX token we are running effectively as on this connection.
524  I'd like to make this return &conn->session_info->unix_token-> but become_root()
525  doesn't alter this value.
526 ****************************************************************************/
527
528 const struct security_unix_token *get_current_utok(connection_struct *conn)
529 {
530         return &current_user.ut;
531 }
532
533 /****************************************************************************
534  Return the Windows token we are running effectively as on this connection.
535  If this is currently a NULL token as we're inside become_root() - a temporary
536  UNIX security override, then we search up the stack for the previous active
537  token.
538 ****************************************************************************/
539
540 const struct security_token *get_current_nttok(connection_struct *conn)
541 {
542         if (current_user.nt_user_token) {
543                 return current_user.nt_user_token;
544         }
545         return sec_ctx_active_token();
546 }
547
548 uint64_t get_current_vuid(connection_struct *conn)
549 {
550         return current_user.vuid;
551 }