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