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