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