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