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