s3-includes: only include ntdomain.h where needed.
[ira/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 #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 bool change_to_user(connection_struct *conn, uint16 vuid)
235 {
236         const struct auth_serversupplied_info *session_info = NULL;
237         user_struct *vuser;
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
245         if (!conn) {
246                 DEBUG(2,("change_to_user: Connection not open\n"));
247                 return(False);
248         }
249
250         vuser = get_valid_user_struct(conn->sconn, vuid);
251
252         /*
253          * We need a separate check in security=share mode due to vuid
254          * always being UID_FIELD_INVALID. If we don't do this then
255          * in share mode security we are *always* changing uid's between
256          * SMB's - this hurts performance - Badly.
257          */
258
259         if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
260            (current_user.ut.uid == conn->session_info->utok.uid)) {
261                 DEBUG(4,("change_to_user: Skipping user change - already "
262                          "user\n"));
263                 return(True);
264         } else if ((current_user.conn == conn) && 
265                    (vuser != NULL) && (current_user.vuid == vuid) &&
266                    (current_user.ut.uid == vuser->session_info->utok.uid)) {
267                 DEBUG(4,("change_to_user: Skipping user change - already "
268                          "user\n"));
269                 return(True);
270         }
271
272         snum = SNUM(conn);
273
274         session_info = vuser ? vuser->session_info : conn->session_info;
275
276         if (!session_info) {
277                 /* Invalid vuid sent - even with security = share. */
278                 DEBUG(2,("change_to_user: Invalid vuid %d used on "
279                          "share %s.\n",vuid, lp_servicename(snum) ));
280                 return false;
281         }
282
283         if (!check_user_ok(conn, vuid, session_info, snum)) {
284                 DEBUG(2,("change_to_user: SMB user %s (unix user %s, vuid %d) "
285                          "not permitted access to share %s.\n",
286                          session_info->sanitized_username,
287                          session_info->unix_name, vuid,
288                          lp_servicename(snum)));
289                 return false;
290         }
291
292         /* security = share sets force_user. */
293         if (!conn->force_user && !vuser) {
294                 DEBUG(2,("change_to_user: Invalid vuid used %d in accessing "
295                         "share %s.\n",vuid, lp_servicename(snum) ));
296                 return False;
297         }
298
299         /*
300          * conn->session_info is now correctly set up with a copy we can mess
301          * with for force_group etc.
302          */
303
304         uid = conn->session_info->utok.uid;
305         gid = conn->session_info->utok.gid;
306         num_groups = conn->session_info->utok.ngroups;
307         group_list  = conn->session_info->utok.groups;
308
309         /*
310          * See if we should force group for this service.
311          * If so this overrides any group set in the force
312          * user code.
313          */
314
315         if((group_c = *lp_force_group(snum))) {
316
317                 SMB_ASSERT(conn->force_group_gid != (gid_t)-1);
318
319                 if(group_c == '+') {
320
321                         /*
322                          * Only force group if the user is a member of
323                          * the service group. Check the group memberships for
324                          * this user (we already have this) to
325                          * see if we should force the group.
326                          */
327
328                         int i;
329                         for (i = 0; i < num_groups; i++) {
330                                 if (group_list[i]
331                                     == conn->force_group_gid) {
332                                         conn->session_info->utok.gid =
333                                                 conn->force_group_gid;
334                                         gid = conn->force_group_gid;
335                                         gid_to_sid(&conn->session_info->security_token
336                                                    ->sids[1], gid);
337                                         break;
338                                 }
339                         }
340                 } else {
341                         conn->session_info->utok.gid = conn->force_group_gid;
342                         gid = conn->force_group_gid;
343                         gid_to_sid(&conn->session_info->security_token->sids[1],
344                                    gid);
345                 }
346         }
347
348         /* Now set current_user since we will immediately also call
349            set_sec_ctx() */
350
351         current_user.ut.ngroups = num_groups;
352         current_user.ut.groups  = group_list;
353
354         set_sec_ctx(uid, gid, current_user.ut.ngroups, current_user.ut.groups,
355                     conn->session_info->security_token);
356
357         current_user.conn = conn;
358         current_user.vuid = vuid;
359
360         DEBUG(5,("change_to_user uid=(%d,%d) gid=(%d,%d)\n",
361                  (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
362
363         return(True);
364 }
365
366 /****************************************************************************
367  Go back to being root without changing the security context stack,
368  but modify the current_user entries.
369 ****************************************************************************/
370
371 bool change_to_root_user(void)
372 {
373         set_root_sec_ctx();
374
375         DEBUG(5,("change_to_root_user: now uid=(%d,%d) gid=(%d,%d)\n",
376                 (int)getuid(),(int)geteuid(),(int)getgid(),(int)getegid()));
377
378         current_user.conn = NULL;
379         current_user.vuid = UID_FIELD_INVALID;
380
381         return(True);
382 }
383
384 /****************************************************************************
385  Become the user of an authenticated connected named pipe.
386  When this is called we are currently running as the connection
387  user. Doesn't modify current_user.
388 ****************************************************************************/
389
390 bool become_authenticated_pipe_user(struct pipes_struct *p)
391 {
392         if (!push_sec_ctx())
393                 return False;
394
395         set_sec_ctx(p->session_info->utok.uid, p->session_info->utok.gid,
396                     p->session_info->utok.ngroups, p->session_info->utok.groups,
397                     p->session_info->security_token);
398
399         return True;
400 }
401
402 /****************************************************************************
403  Unbecome the user of an authenticated connected named pipe.
404  When this is called we are running as the authenticated pipe
405  user and need to go back to being the connection user. Doesn't modify
406  current_user.
407 ****************************************************************************/
408
409 bool unbecome_authenticated_pipe_user(void)
410 {
411         return pop_sec_ctx();
412 }
413
414 /****************************************************************************
415  Utility functions used by become_xxx/unbecome_xxx.
416 ****************************************************************************/
417
418 static void push_conn_ctx(void)
419 {
420         struct conn_ctx *ctx_p;
421
422         /* Check we don't overflow our stack */
423
424         if (conn_ctx_stack_ndx == MAX_SEC_CTX_DEPTH) {
425                 DEBUG(0, ("Connection context stack overflow!\n"));
426                 smb_panic("Connection context stack overflow!\n");
427         }
428
429         /* Store previous user context */
430         ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
431
432         ctx_p->conn = current_user.conn;
433         ctx_p->vuid = current_user.vuid;
434
435         DEBUG(4, ("push_conn_ctx(%u) : conn_ctx_stack_ndx = %d\n",
436                 (unsigned int)ctx_p->vuid, conn_ctx_stack_ndx ));
437
438         conn_ctx_stack_ndx++;
439 }
440
441 static void pop_conn_ctx(void)
442 {
443         struct conn_ctx *ctx_p;
444
445         /* Check for stack underflow. */
446
447         if (conn_ctx_stack_ndx == 0) {
448                 DEBUG(0, ("Connection context stack underflow!\n"));
449                 smb_panic("Connection context stack underflow!\n");
450         }
451
452         conn_ctx_stack_ndx--;
453         ctx_p = &conn_ctx_stack[conn_ctx_stack_ndx];
454
455         current_user.conn = ctx_p->conn;
456         current_user.vuid = ctx_p->vuid;
457
458         ctx_p->conn = NULL;
459         ctx_p->vuid = UID_FIELD_INVALID;
460 }
461
462 /****************************************************************************
463  Temporarily become a root user.  Must match with unbecome_root(). Saves and
464  restores the connection context.
465 ****************************************************************************/
466
467 void become_root(void)
468 {
469          /*
470           * no good way to handle push_sec_ctx() failing without changing
471           * the prototype of become_root()
472           */
473         if (!push_sec_ctx()) {
474                 smb_panic("become_root: push_sec_ctx failed");
475         }
476         push_conn_ctx();
477         set_root_sec_ctx();
478 }
479
480 /* Unbecome the root user */
481
482 void unbecome_root(void)
483 {
484         pop_sec_ctx();
485         pop_conn_ctx();
486 }
487
488 /****************************************************************************
489  Push the current security context then force a change via change_to_user().
490  Saves and restores the connection context.
491 ****************************************************************************/
492
493 bool become_user(connection_struct *conn, uint16 vuid)
494 {
495         if (!push_sec_ctx())
496                 return False;
497
498         push_conn_ctx();
499
500         if (!change_to_user(conn, vuid)) {
501                 pop_sec_ctx();
502                 pop_conn_ctx();
503                 return False;
504         }
505
506         return True;
507 }
508
509 bool unbecome_user(void)
510 {
511         pop_sec_ctx();
512         pop_conn_ctx();
513         return True;
514 }
515
516 /****************************************************************************
517  Return the current user we are running effectively as on this connection.
518  I'd like to make this return conn->session_info->utok.uid, but become_root()
519  doesn't alter this value.
520 ****************************************************************************/
521
522 uid_t get_current_uid(connection_struct *conn)
523 {
524         return current_user.ut.uid;
525 }
526
527 /****************************************************************************
528  Return the current group we are running effectively as on this connection.
529  I'd like to make this return conn->session_info->utok.gid, but become_root()
530  doesn't alter this value.
531 ****************************************************************************/
532
533 gid_t get_current_gid(connection_struct *conn)
534 {
535         return current_user.ut.gid;
536 }
537
538 /****************************************************************************
539  Return the UNIX token we are running effectively as on this connection.
540  I'd like to make this return &conn->session_info->utok, but become_root()
541  doesn't alter this value.
542 ****************************************************************************/
543
544 const struct security_unix_token *get_current_utok(connection_struct *conn)
545 {
546         return &current_user.ut;
547 }
548
549 const struct security_token *get_current_nttok(connection_struct *conn)
550 {
551         return current_user.nt_user_token;
552 }
553
554 uint16_t get_current_vuid(connection_struct *conn)
555 {
556         return current_user.vuid;
557 }